有很多理由希望将.bat
“转换”为.exe
- 隐藏/混淆实现,密码,资源路径,从批处理文件创建服务......主要是为了让您的工作看起来比复杂和重要它真的是。
不想使用第三方工具的原因也很多。
那么如果你想在没有外部软件的情况下将批处理文件“转换”为.exe
呢? (转换是引号,因为我认为没有真正的方法将批处理文件编译成可执行文件。有太多滥用的错误技术和广泛使用的错误,我知道的所有工具实际上创建了一个临时的.bat
文件,然后调用它))
一个非常明显的方法是使用IEXPRESS--一种古老的内置工具,可以创建自解压包,并且能够执行提取后命令。所以这里是IEXPRESS sed-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文件,并将调用它。并将接受命令行参数。(解释可能看起来很复杂,但事实上它很简单):
@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库足够强大,可以添加隐藏启动,加密等功能。您还可以检查jsc.exe编译选项以查看其他功能(如添加资源) )。
我保证会对.NET方法的每一项改进提出建议:-)
更新:第二个脚本已更改,现在可以通过双击启动转换后的bat文件中的exe。它使用与以前脚本相同的界面:
bat2exejs.bat example.bat example.exe
我知道如何手动将bat / cmd转换为exe,确保bat / cmd文件名只包含字母和数字。以管理员身份打开'IExpress Wizard'。
cmd /c
,然后输入bat / cmd文件的全名,(例如:emptyrecyclebin.bat
=> cmd /c emptyrecyclebin.bat
)您还可以开发一个简单的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.bat旁边的MySuperApp.cs中,然后用csc.exe /target:winexe MySuperApp.cs
编译它(甚至可以添加/win32icon:MySuperApp.ico
来添加一个花哨的图标)它将生成一个MySuperApp.exe。
启动MySuperApp.exe
将调用MySuperApp.bat(具有相同名称的bat文件)。
csc.exe
(应该?)是present on every Windows machine。