9

Is there a way in Windows to edit a binary file, from the command line? i.e. a way that could be written into a batch file?

I want to be able to edit a single byte, at a known position, in an existing file.

This existing question[1] is solved, but that's a Linux solution. I'm looking for something similar for Windows.

Background

There's a bug in GTA 1 when downloaded from Steam whereby the save-game data file gets corrupted on exit. As a result, the game can be played fine the first time but subsequently crashes. It turns out this can be fixed by changing the 5th byte in the file (i.e. the byte at address 0x04) from x00 to x06[2].

I can do this in Python easily, e.g.:

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)

Ideally though I'd rather do this in a batch job that does the following:

  • fixes the data file
  • launches GTA

I could make something that works for me (using Python), but that wouldn't help random other people who don't have Python (yes I know it's easy to get & install, but still). Similarly, there is a freeware available that claims to do just this, but I don't want to run a random .exe on my PC, and I don't think anyone else should either. For that reason, I'd like to present a batch file, that people can inspect, and - if they're happy with what it does - run for themselves.

Thanks for you help!

[1] CLI: Write byte at address (hexedit/modify binary from the command line)

[2] http://forums.steampowered.com/forums/showthread.php?t=1597746

[edit] Fixed up the Python script, as I found it didn't work as-is (file.read() returns an immutable object, so you can't just update one of the values).

3 Answers 3

11

I think PowerShell is a perfect tool for this task. It's available for XP or higher and is automatically shipped since Windows 7:

Just create a *.ps1 file with this content:

$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"

Note that one has to enable unsigned PowerShell scripts:

  1. Start PowerShell as an administrator

  2. Run this command: Set-ExecutionPolicy RemoteSigned


You could also use VBScript but the script will be somewhat longer because it wasn't designed for reading binary files (you have to use ADODB.Stream objects).

Here is a compilation of helper functions: http://www.motobit.com/tips/detpg_read-write-binary-files/

5
  • Thanks, I've not tried using PowerShell before. I just tried running this example though and it didn't work - I got a powershell window popping up (and stealing focus) and then vanishing, repeatedly - for several minutes. It didn't result in changing the file. When I ran PowerShell directly and typed in the commands you suggested this worked fine. Any idea what's going on? I haven't tried enabling unsigned scripts yet - but I'm not so keen on trying that yet until I know what the problem was, as my PC was unusable until the script decided to stop running.
    – sam
    Commented Apr 5, 2013 at 14:05
  • [update] I have the same issue even after setting the execution policy. I see this if I run from cmd or from powershell.
    – sam
    Commented Apr 5, 2013 at 14:17
  • @sam Which Windows version are you using? Do you use the latest updates? I'm sorry for that strange behaviour. Here is a new version which waits for key presses before executing each command: pastebin.com/5hjHbkBt. Also try executing the script via right-click-->Run with PowerShell in Explorer.
    – ComFreek
    Commented Apr 5, 2013 at 14:17
  • 1
    [update 2] I can run using "powershell -noexit .\script.ps" and that seems to work.
    – sam
    Commented Apr 5, 2013 at 14:30
  • 1
    following a reboot of my PC the original PS script now runs fine (with "powershell script.ps" from cmd.exe). No idea what caused that strange issue.
    – sam
    Commented Apr 5, 2013 at 17:53
2
  1. Generate a file with format you can understand eg. hex code with fc or certutil or decimal with comp.
  2. Search for and replace/edit bytes
  3. Write binary (decoded hex file or edited data in memory) to disk

One solution to patch byte 4 of a file from "Windows command line":

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

Another solution would be to split the file at the byte to replaced, then join with replaced byte. See my answer at the linked post.

Tested in Win10 CMD

2
  • 1
    This is a very weird solution and I'm not sure if would use it, but I upvote for creativity!
    – PhilS
    Commented Nov 21, 2020 at 16:14
  • Thanks @PhilS, the provided code sample tested shows how to "edit a binary file using Windows command line" asked in the question. The given example replaces byte 4 of a file with 0x06. Then launches GTA.
    – Zimba
    Commented Nov 25, 2020 at 9:50
1

What about splitting the original file into three, then merging with your substitute byte in the middle? Split the binary into three pieces (start -> target-1 / target / target+1 -> end) then use COPY to merge the beginning and end chunks with your new byte in the middle.

I've never been able to get DOS (or any Windows Command Prompt) to split a file natively, but the free SPLITS.EXE utility is very good and could be included in your solution. COPY is of course a native command.

I can't find a link to that utility right now, but googling for 'free dos file split utility' yields many hits...

5
  • 1
    But who verifies that SPLITS.EXE is not modified? It could also be a random .exe.
    – ComFreek
    Commented Apr 5, 2013 at 14:01
  • 1
    As ComFreek says, if I was happy to run a random exe I'd just use GTALauncher.exe which fixes the file & launches GTA :-)
    – sam
    Commented Apr 5, 2013 at 14:31
  • Well, given that there's no way to do it in DOS (at least, no way I've ever discovered) you're going to have to ship a helper utility with the script - or just package the solution as an .exe and ship that. I suppose the difference is that if you ship a freely-available 3rd-party utility along with a script, it can be compared against the same utility from other sources (hopefully reputable ones) whereas a custom .exe package cannot. Commented Apr 5, 2013 at 14:43
  • Who said "that there's no way to do it in DOS"? Of course there's a way. edit & debug have been supporting binary in DOS & Windows CMD for decades now.
    – Zimba
    Commented Oct 27, 2020 at 14:17
  • The EDIT and DEBUG utilities are legacy 16-bit programs, incompatible with and no longer shipped with 64-bit Windows. EDIT command-line options (for batch invocation) only initialise the edit environment and do not facilitate operations on the file being edited. DEBUG has no command-line parameters besides the filename of the executable being debugged. But apart from these trivial issues, they're a perfect match for automating binary file manipulation in a modern Windows build. Commented Oct 27, 2020 at 18:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.