没有第三方工具,一个.bat文件怎么能'converted'转.exe呢?

How can a .bat file be 'converted' to .exe without third party tools?

有很多理由想要 'convert' .bat.exe - hide/obfuscate 实现、密码、资源路径、从批处理创建服务文件 ... 主要是为了让您的工作看起来比实际情况更复杂、更重要。

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

那么如果您想 'convert' 一个批处理文件到 .exe 而不需要外部软件怎么办? (转换在引号中,因为我认为没有真正的方法可以将批处理文件编译为可执行文件。有太多滥用的曲折技术和广泛使用的错误,我知道的所有工具实际上都创建了一个临时 .bat文件然后调用它 )

一个非常明显的方法是使用 IEXPRESS - 一种古老的内置工具,可以创建自解压包并能够执行 post 解压命令。 所以这里是 IEXPRESS sed-directive/.bat 文件,它创建一个自解压 .exe 和打包的 .bat。 它接受两个参数 - 您要转换的 .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%exe.sed" >nul

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


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

;del /q /f "%temp%exe.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 文件 content.Will 使用 .bat 文件内容创建另一个 jscript.net 并在编译后创建一个新的 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 和 etc.You 也可以检查 jsc.exe 等功能编译选项以查看其他功能(如添加资源)。

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

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

bat2exejs.bat example.bat example.exe

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

  1. Select 'Create new Self Extraction Directive file'
  2. Select 'Extract files and run an installation command'
  3. 任意命名包
  4. 'No prompt' 对于 'Confirmation prompt'
  5. 'Do not display a license' 对于 'License agreement'
  6. 单击 'Add' 找到 'Packaged files',从那里 select bat/cmd 文件
  7. 然后在 'Install Program' 文本框中 'Install Program to Launch',键入 cmd /c,然后是 bat/cmd 文件的全名,(例如:emptyrecyclebin.bat => cmd /c emptyrecyclebin.bat)
  8. 保持 'Post Install Command' 不变
  9. 'Hidden' 对于 'Show window'
  10. 'No message' 对于 'Finished message'
  11. 点击'Browse',然后select下载exe到哪里
  12. 启用'Hide File Extracting Progress Animation from User'
  13. 禁用'Store files using Long File Name inside Package'
  14. 绝对 'No restart' 'Configure restart'
  15. 如果以后想更快地重新编译,请保存 SED
  16. 然后创建包!命令window应该快速出现和消失
  17. 导航到你下载exe的地方,andenjoy!

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

例如,您可以用 C# 编写一个(我不是 C#-Pro,这实际上是我的第一个程序,我从 this other Whosebug 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.

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

请参阅此 link 以了解用于重新启动不同版本 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 文件中,该文件将在 opened/run 时解包并执行脚本,例如。 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 操作系统的主机。

以上所有方法都不会以任何方式保护您的源代码。我最近在新闻中看到一篇新闻稿,说的是一个不依赖于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%

编译代码后 运行s 快了一倍,我没有注意到在任务管理器中有任何对 cmd.exe 的调用。此外,我 运行 进程监视器发现在 运行ning 期间没有创建临时文件。这让我相信这个编译器对源代码提供了更好的保护。