【问题标题】:How can a .bat file be 'converted' to .exe without third party tools?如何在没有第三方工具的情况下将 .bat 文件“转换”为 .exe?
【发布时间】:2015-03-26 07:09:36
【问题描述】:

想要将.bat“转换”为.exe 的原因有很多——隐藏/混淆实现、密码、资源路径、从批处理文件创建服务......主要是为了让你的工作看起来比实际更复杂和重要。

不想使用第三方工具的原因也很多。

如果您想在没有外部软件的情况下将批处理文件“转换”为.exe,该怎么办? (转换用引号引起来,因为我认为没有真正的方法可以将批处理文件编译为可执行文件。有太多滥用的扭曲技术和错误被广泛使用,我知道的所有工具实际上都会创建一个临时的.bat 文件和然后调用它)

【问题讨论】:

  • 一个 .exe 可以被黑客入侵。不是隐藏密码的安全方法。而且我不同意 .exe 让我的工作看起来更重要或更复杂。
  • @Blam - 一切都可以被黑客入侵。这只是比其他任何东西都更容易混淆。
  • @npocmaka 你一直很忙! :) 我喜欢自我提问/回答帖子。谁投票结束这个需要撤回他的投票。
  • 我不喜欢自我提问/回答帖子,但这是一个非常好的帖子,因为它鼓励我发布自己的答案(而不是解释有关该主题的所有内容)+1 :)我同意 rojo 的评论!
  • @Aacini ,Dave 的What are the undocumented features and limitations of the Windows FINDSTR command? 怎么样。对我来说,这是 StackOverFlow 上的 BEST 自我问答!

标签: .net iexpress batch-file


【解决方案1】:

一个非常明显的方法是使用IEXPRESS - 这是一个古老的内置工具,可以创建自解压包并能够执行解压后的命令。 所以这是IEXPRESSsed-directive/.bat 文件,它创建了一个带有打包.bat 的自解压.exe。 它接受两个参数 - 您要转换的 .bat 文件和目标可执行文件:

 ;@echo off
; rem https://github.com/npocmaka/batch.scripts/edit/master/hybrids/iexpress/bat2exeIEXP.bat
;if "%~2" equ "" (
; echo usage: %~nx0 batFile.bat target.Exe
;)
;set "target.exe=%__cd__%%~2"
;set "batch_file=%~f1"
;set "bat_name=%~nx1"
;set "bat_dir=%~dp1"

;copy /y "%~f0" "%temp%\2exe.sed" >nul

;(echo()>>"%temp%\2exe.sed"
;(echo(AppLaunched=cmd.exe /c "%bat_name%")>>"%temp%\2exe.sed"
;(echo(TargetName=%target.exe%)>>"%temp%\2exe.sed"
;(echo(FILE0="%bat_name%")>>"%temp%\2exe.sed"
;(echo([SourceFiles])>>"%temp%\2exe.sed"
;(echo(SourceFiles0=%bat_dir%)>>"%temp%\2exe.sed"
;(echo([SourceFiles0])>>"%temp%\2exe.sed"
;(echo(%%FILE0%%=)>>"%temp%\2exe.sed"


;iexpress /n /q /m %temp%\2exe.sed

;del /q /f "%temp%\2exe.sed"
;exit /b 0

[Version]
Class=IEXPRESS
SEDVersion=3
[Options]
PackagePurpose=InstallApp
ShowInstallProgramWindow=0
HideExtractAnimation=1
UseLongFileName=1
InsideCompressed=0
CAB_FixedSize=0
CAB_ResvCodeSigning=0
RebootMode=N
InstallPrompt=%InstallPrompt%
DisplayLicense=%DisplayLicense%
FinishMessage=%FinishMessage%
TargetName=%TargetName%
FriendlyName=%FriendlyName%
AppLaunched=%AppLaunched%
PostInstallCmd=%PostInstallCmd%
AdminQuietInstCmd=%AdminQuietInstCmd%
UserQuietInstCmd=%UserQuietInstCmd%
SourceFiles=SourceFiles

[Strings]
InstallPrompt=
DisplayLicense=
FinishMessage=
FriendlyName=-
PostInstallCmd=<None>
AdminQuietInstCmd=
UserQuietInstCmd=

示例:

bat2exeIEXP.bat  myBatFile.bat MyExecutable.exe

这应该几乎可以在每台 Windows 机器上运行,但有一个主要限制 - 您不能将参数传递给创建的 .exe 文件

所以另一种可能的方法是查看 .NET 编译器(同样应该在几乎每台 win 机器上都可用)。我选择了 Jscript.net 。 这是一个混合的jscript.net/.bat 脚​​本,它将读取 .batch 文件内容。将使用 .bat 文件内容创建另一个 jscript.net,编译后将在 temp 文件夹中创建一个新的 bat 文件并调用it.And 将接受命令行参数。(解释可能看起来很复杂,但实际上很简单):

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal

del %~n0.exe /q /s >nul 2>nul

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

%~n0.exe  "%jsc%" %*
del /q /f %~n0.exe 1>nul 2>nul 
endlocal & exit /b %errorlevel%
*/

//https://github.com/npocmaka/batch.scripts/blob/master/hybrids/.net/bat2exe.bat
import System;
import System;
import System.IO;
import  System.Diagnostics;


var arguments:String[] = Environment.GetCommandLineArgs();
if (arguments.length<3){
    Console.WriteLine("Path to cmd\bat file not given");
    Environment.Exit(1);
}

var binName=Path.GetFileName(arguments[2])+".exe";
if(arguments.length>3){
    binName=Path.GetFileName(arguments[3]);
}
var batchContent:byte[]= File.ReadAllBytes(arguments[2]);
var compilerLoc=arguments[1];

var content="["

for (var i=0;i<batchContent.length-1;i++){
    content=content+batchContent[i]+","
}
content=content+batchContent[batchContent.length-1]+"]";
var temp=Path.GetTempPath();
var dt=(new Date()).getTime();
var tempJS=temp+"\\2exe"+dt+".js";


var toCompile="\r\n\
import System;\r\n\
import System.IO;\r\n\
import  System.Diagnostics;\r\n\
var batCommandLine:String='';\r\n\
//Remove the executable name from the command line\r\n\
try{\r\n\
var arguments:String[] = Environment.GetCommandLineArgs();\r\n\
batCommandLine=Environment.CommandLine.substring(arguments[0].length,Environment.CommandLine.length);\r\n\
}catch(e){}\r\n\
var content2:byte[]="+content+";\r\n\
var dt=(new Date()).getTime();\r\n\
var temp=Path.GetTempPath();\r\n\
var nm=Process.GetCurrentProcess().ProcessName.substring(0,Process.GetCurrentProcess().ProcessName.length-3);\r\n\
var tempBatPath=Path.Combine(temp,nm+dt+'.bat');\r\n\
File.WriteAllBytes(tempBatPath,content2);\r\n\
var pr=System.Diagnostics.Process.Start('cmd.exe','/c '+' '+tempBatPath+' '+batCommandLine);\r\n\
pr.WaitForExit();\r\n\
File.Delete(tempBatPath);\r\n\
";

File.WriteAllText(tempJS,toCompile);
var pr=System.Diagnostics.Process.Start(compilerLoc,'/nologo /out:"'+binName+'" "'+tempJS+'"');
pr.WaitForExit();
File.Delete(tempJS);

它是一个 POC,但 .NET System.Diagnostics 和 System.IO 库功能强大,可以添加隐藏启动、enctiption 等功能。您还可以查看 jsc.exe 编译选项以查看其他功能(比如添加资源)。

我保证对 .NET 方法的每一项改进都投赞成票 :-)

更新:第二个脚本已更改,现在可以双击启动转换后的bat文件中的exe。它使用与之前脚本相同的界面:

bat2exejs.bat example.bat example.exe

【讨论】:

  • 这种情况下如何处理相对路径?
  • @Serob_b - 您能否提供有关您的问题的更多详细信息。 iexpress 脚本使用 ;set "batch_file=%~f1" 将路径转换为完全限定路径 - 如果您需要更具体的内容,可以从另一个调整路径的脚本中调用它
【解决方案2】:

我知道如何手动将 bat/cmd 转换为 exe,确保 bat/cmd 文件名只包含字母和数字。以管理员身份打开“IExpress Wizard”。

  1. 选择“创建新的自解压指令文件”
  2. 选择“提取文件并运行安装命令”
  3. 为包命名
  4. “确认提示”的“无提示”
  5. “许可协议”的“不显示许可”
  6. 点击“打包文件”的“添加”,从那里选择 bat/cmd 文件
  7. 然后在“Install Program to Launch”的“Install Program”文本框中,输入cmd /c,后跟bat/cmd文件的全名,(例如:emptyrecyclebin.bat => cmd /c emptyrecyclebin.bat)李>
  8. 保持“安装后命令”不变
  9. “显示窗口”的“隐藏”
  10. “已完成消息”的“无消息”
  11. 点击“浏览”,然后选择将 exe 下载到的位置
  12. 启用“隐藏文件从用户提取进度动画”
  13. 禁用“使用包内的长文件名存储文件”
  14. “配置重启”肯定是“不重启”
  15. 如果您想稍后更快地重新编译它,请保存 SED
  16. 然后创建包!命令窗口应该快速出现和消失
  17. 导航到您将 exe 下载到的位置,并且享受

【讨论】:

    【解决方案3】:

    以上所有方法都不会以任何方式保护您的源代码。我最近在新闻中看到了一个关于不依赖 CMD.exe 的新编译器的新闻稿。我不确切知道它是如何工作的,但它不会在运行时创建临时文件。 https://www.prlog.org/12882479-the-worlds-first-true-compiler-for-batch-files.html

    使用 IEXPRESS 制作一种 SFX 存档,它没有达到使用密码隐藏源代码的主要目标。所有其他“编译器”的工作原理类似——将脚本解压缩到一个临时文件夹并通过 cmd.exe 运行它。新闻稿声称是真正的编译,所以我下载了试用版并编写了一个原始脚本来测量速度:

    @echo off
    set startTime=%time%     
    set counter=0     
    :main_loop
    echo %counter%
    set /a counter=counter+1
    if %counter% LEQ 10000 goto main_loop
    
    echo Start Time: %startTime%
    echo Finish Time: %time%
    

    编译后代码运行速度提高了一倍,我没有注意到任务管理器中对 cmd.exe 的任何调用。此外,我运行了 Process Monitor,发现它在运行时没有创建临时文件。这让我相信这个编译器为源代码提供了更好的保护。

    【讨论】:

    • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
    【解决方案4】:

    您还可以开发一个简单的 exe,它只调用您的 bat 脚本。

    例如,您可以用 C# 编写一个(我不是 C#-Pro,这实际上是我的第一个程序,我从 this other Stackoverflow post 复制了很多。):

    using System;
    using System.Diagnostics;
    using System.Windows.Forms;
    using System.IO;
    
    class BatCaller {
        static void Main() {
            var batFile = System.Reflection.Assembly.GetEntryAssembly().Location.Replace(".exe", ".bat");
            if (!File.Exists(batFile)) {
                MessageBox.Show("The launch script could not be found.", "Critical error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                System.Environment.Exit(42);
            }
            var processInfo = new ProcessStartInfo("cmd.exe", "/c \"" + batFile + "\"");
            processInfo.CreateNoWindow = true;
            processInfo.UseShellExecute = false;
            processInfo.RedirectStandardError = true;
            processInfo.RedirectStandardOutput = true;
    
            var process = Process.Start(processInfo);
    
            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output>>" + e.Data);
            process.BeginOutputReadLine();
    
            process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error>>" + e.Data);
            process.BeginErrorReadLine();
    
            process.WaitForExit();
    
            Console.WriteLine("ExitCode: {0}", process.ExitCode);
            process.Close();
        }
    }
    

    如果你将上面的代码存储到 MySuperApp.cs 中,就在 MySuperApp.bat 旁边,然后用 csc.exe /target:winexe MySuperApp.cs 编译它(甚至可能添加 /win32icon:MySuperApp.ico 来添加一个精美的图标),它将生成一个 MySuperApp.exe。

    启动 MySuperApp.exe 将调用 MySuperApp.bat(具有相同名称的 bat 文件)。

    csc.exe(应该?)是present on every Windows machine

    【讨论】:

    • 目标平台是否需要安装.NET Framework?
    • 不,.NET 仅在构建 exe 时才需要。
    【解决方案5】:

    不同版本的 Windows 对相同的批处理文件命令有不同的效果,并且某些命令仅限于某些 Windows 系统,例如。 findstrshutdown.
    顺便说一句,Win 10 CMD 不允许在命令行上更改 SETLOCAL。可以用于批处理文件。

    查看此链接以了解用于重新启动不同版本 Windows 的不同命令: https://www.computerhope.com/issues/ch000321.htm

    因此,如果您要在 Win 98 上编译脚本并在 Win 8.1 上运行,您会得到意想不到的结果,或者脚本甚至可能无法运行。 在此处查看命令列表: https://www.ionos.com/digitalguide/server/know-how/windows-cmd-commands/

    出于这个原因,每个版本的 Windows 都需要不同的编译器,最好能生成可以在尽可能多的 CPU 芯片上运行的二进制代码(通用),并使用相同的指令集。大多数程序提供的解决方法是将脚本包装在一个 exe 文件中,该文件将在打开/运行时解包并执行脚本,例如。 Bat_To_Exe_Converter、Bat2Exe、BatchCompiler、iexpress 或 Winzip: https://support.winzip.com/hc/en-us/articles/115011794948-What-is-a-Self-Extracting-Zip-File-

    为了解决这个可移植性问题,虚拟机变得越来越流行,因此 Java 和相关脚本的兴起。

    但是,这仍然是解释代码,并且不如编译代码快。即使是来自虚拟机的字节码(中间码)也需要编译,即使它是(JIT): https://aboullaite.me/understanding-jit-compiler-just-in-time-compiler/

    简而言之,您可以获得一个 exe 文件,其中包含一个可由命令处理器解释的脚本,但它不是本机可执行文件,这意味着它不会在 Windows 操作系统没有主机的情况下运行系统。

    【讨论】:

      猜你喜欢
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 2022-11-21
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      相关资源
      最近更新 更多