使用Windows命令行编辑二进制文件是否可行?

9

在Windows中,有没有一种从命令行编辑二进制文件的方法?也就是说,有没有一种可以编写成批处理文件的方式?

我想要能够在已有文件中的一个已知位置编辑单个字节。

已经有人提出了类似的问题[1]并找到了Linux解决方案,但我正在寻找类似于Windows的解决方案。

背景

当从Steam下载GTA 1时会出现一个错误,保存游戏数据文件在退出时会被损坏。因此,游戏可以正常运行第一次,但随后会崩溃。事实证明,这可以通过将文件中的第5个字节(即地址0x04处的字节)从x00更改为x06来修复[2]。

我可以很容易地用Python完成这个任务,例如:

with open("PLAYER_A.DAT", "rb") as f:
    bytes = f.read()
bytes = bytes[:4] + '\x06' + bytes[5:]
with open("PLAYER_A.DAT", "wb") as g:
    for b in bytes: g.write(b)

理想情况下,我更愿意使用批处理作业来完成以下操作:
- 修复数据文件 - 启动GTA
我可以使用Python创建适用于自己的程序,但这并不能帮助其他不具备Python技能的人(是的,我知道安装Python很容易,但仍然存在困难)。同样,有一个免费软件可以做到这一点,但我不想在我的电脑上运行一个未知的.exe文件,也不建议其他人这样做。出于这个原因,我希望提供一个批处理文件,让大家可以检查,并且如果他们对它的功能满意,就可以自己运行。
谢谢您的帮助!
[1] CLI: Write byte at address (hexedit/modify binary from the command line) [2] http://forums.steampowered.com/forums/showthread.php?t=1597746 [编辑] 修改了Python脚本,因为发现它不能直接使用(file.read()返回一个不可变对象,因此无法更新其中一个值)。
3个回答

11

我认为PowerShell是完成这项任务的完美工具。它适用于XP或更高版本,并自Windows 7以来自动安装:

只需创建一个具有如下内容的*.ps1文件:

$bytes = [System.IO.File]::ReadAllBytes("PLAYER_A.DAT");
$bytes[4] = 0x06;

[System.IO.File]::WriteAllBytes("PLAYER_A.DAT", $bytes);
& "C:\Path-To-GTA1-Exe-File.exe"

请注意,需要启用未签名的PowerShell脚本:

  1. 以管理员身份启动PowerShell

  2. 运行以下命令:Set-ExecutionPolicy RemoteSigned


您也可以使用VBScript,但是该脚本会比较长,因为它不是为读取二进制文件而设计的(您必须使用ADODB.Stream对象)。

下面是一些辅助函数的汇编:http://www.motobit.com/tips/detpg_read-write-binary-files/


谢谢,我以前没有尝试过使用PowerShell。不过我刚刚尝试运行了这个例子,但是它没有起作用 - 我得到了一个弹出的PowerShell窗口(并且窗口一直在重复弹出和消失)- 持续了几分钟。它没有改变文件。当我直接运行PowerShell并输入您建议的命令时,它可以正常工作。有什么想法吗?我还没有尝试启用未签名的脚本 - 但在我知道问题所在之前,我不太想尝试,因为我的电脑在脚本停止运行之前无法使用。 - sam
[更新] 即使我设置了执行策略,我仍然遇到相同的问题。无论我是从命令提示符还是从 PowerShell 运行,都会看到这个问题。 - sam
@sam 你用的是哪个Windows版本?你有最新的更新吗?很抱歉出现了奇怪的行为。这里有一个新版本,它在执行每个命令之前都会等待按键:http://pastebin.com/5hjHbkBt。另外,尝试通过右键单击资源管理器中的“使用PowerShell运行”来执行脚本。 - ComFreek
1
[更新2] 我可以使用“powershell -noexit .\script.ps”运行,这似乎有效。 - sam
1
在我的电脑重新启动后,原始的PS脚本现在可以正常运行(通过从cmd.exe运行“powershell script.ps”)。不知道是什么原因导致了这个奇怪的问题。 - sam

2
  1. 生成一个你能理解的格式的文件,例如:使用fccertutil生成十六进制代码,或使用comp生成十进制代码。
  2. 搜索并替换/编辑字节
  3. 将二进制文件(解码后的十六进制文件或内存中编辑过的数据)写入磁盘

从“Windows命令行”中修改文件的第4个字节的一种解决方案:

echo Dim fso : Set fso = CreateObject("Scripting.FileSystemObject") > tmp.vbs
echo Set file = fso.OpenTextFile("PLAYER_A.DAT") >> tmp.vbs
echo set fsize = fso.GetFile("PLAYER_A.DAT") >> tmp.vbs
echo Dim out : Set out = fso.CreateTextFile("GTA.exe", true) >> tmp.vbs
echo data = file.Read(3) : out.write(data) : file.Skip(1) >> tmp.vbs
echo data = "06" : out.write chr("&H" ^& data) >> tmp.vbs
echo data = file.Read(fsize.Size) : out.write(data) >> tmp.vbs
echo file.Close >> tmp.vbs
echo out.Close >> tmp.vbs
cscript //nologo tmp.vbs & del tmp.vbs
start /b cmd /c GTA.exe

另一种解决方案是将文件在需要替换的字节处拆分,然后用替换的字节进行连接。请查看我在链接帖子中的答案。

在Win10 CMD中测试过。


1
这是一个非常奇怪的解决方案,我不确定是否会使用它,但我会点赞以示创意! - PhilS
感谢@PhilS,提供的代码示例经过测试,展示了如何在Windows命令行中“编辑二进制文件”,这也是问题中所询问的。给出的示例将文件的第4个字节替换为0x06,然后启动GTA。 - Zimba

1
将原文件分成三个部分,然后使用您替代字节在中间合并?将二进制文件分为三个部分(起始 -> 目标-1 / 目标 / 目标+1 -> 结尾),然后使用COPY将开头和结尾的块与您的新字节合并到中间。
我从未能够使DOS(或任何Windows命令提示符)本地拆分文件,但免费的SPLITS.EXE实用程序非常好,可以包含在您的解决方案中。 COPY当然是一个本地命令。
我现在找不到该实用程序的链接,但是谷歌搜索“免费dos文件拆分实用程序”会产生许多结果...

1
但是谁能验证SPLITS.EXE没有被修改?它也可能是一个随机的.exe文件。 - ComFreek
1
正如ComFreek所说,如果我愿意运行一个随机的exe文件,我只需使用GTALauncher.exe来修复文件并启动GTA :-) - sam
好的,鉴于在DOS中没有办法做到这一点(至少我从未发现过),你将不得不在脚本中附带一个辅助工具,或者只需将解决方案打包为.exe并进行分发。我想区别在于,如果您随脚本一起提供一个免费可用的第三方实用程序,则可以将其与其他来源(希望是有声誉的)的相同实用程序进行比较,而自定义的.exe软件包则无法进行比较。 - Eight-Bit Guru
谁说“在DOS中没有办法做到这一点”?当然有办法。editdebug工具在DOS和Windows CMD中几十年来一直支持二进制。 - Zimba
EDIT和DEBUG实用程序是遗留的16位程序,与64位Windows不兼容,并且不再随其一起发行。EDIT命令行选项(用于批处理调用)仅初始化编辑环境,不便于对正在编辑的文件进行操作。DEBUG除了被调试的可执行文件的文件名之外,没有命令行参数。但是除了这些微不足道的问题,它们非常适合在现代Windows构建中自动化二进制文件操作。 - Eight-Bit Guru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接