replacing a hex sequence in a binary file with a hybrid .bat?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: replacing a hex sequence in a binary file with a hybrid .bat?

#16 Post by dbenham » 25 Oct 2018 04:00

Oops, I spoke too soon.

I didn't read your code carefully enough to realize you rely on the offset address to identify the lines to modify.

Also, those offsets don't work for my version of cmd.exe (Windows 10) When I ran your posted code it successfully made the changes at your offsets, but who knows what it did :twisted:

My ECHO offset begins at 30A10, but when I modified the changes variable appropriately, the script failed to make any change at all :?

I haven't tried to debug the code.

Note that JREPL works quite well, without needing to determine any offset. And it is fast.

Code: Select all

jrepl "E\x00C\x00H\x00O\x00" "S\x00H\x00O\x00W\x00" /xseq /m /f "%comspec%" /o myCmd.exe

Dave Benham

stondesign
Posts: 22
Joined: 23 Oct 2018 17:28

Re: replacing a hex sequence in a binary file with a hybrid .bat?

#17 Post by stondesign » 25 Oct 2018 07:00

the code of first is on windows 10 that windows 7 but not to adapt the changes ...

let's face it maybe we understand the error

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: replacing a hex sequence in a binary file with a hybrid .bat?

#18 Post by dbenham » 30 Oct 2018 22:10

Bad news about use of FINDSTR to output the remainder after the last substitution - it is unreliable because FINDSTR cannot process lines greater than 8191 bytes long when the input is piped or redirected.

I've got a pair of patchBin scripts based on CERTUTIL that work very well, and are reasonably fast. They rely on two little known facts that were documented on DosTips:

1) CERTUTIL /ENCODEHEX has an optional format argument that can eliminate newlines from the output, and can output the hex as one continuous stream without spaces, or as hex pairs delimited by exactly one space.

2) In the absence of newlines, SET /P will read exactly 1023 bytes, or the remainder of the file, whichever is smaller.

By processing 1023 input bytes at a time (via 2 or 3 SET /P statements) the following scripts need far fewer reads and writes, so the performance is significantly improved over Aacini's method that includes the address and the ASCII in the hex output and has only 16 input bytes per line.

My scripts would theoretically have a max input file size of 2 GB due to SET /A limits, but CERTUTIL /EncodeHex limits the output to 102,400,000 bytes.

This first script has no space delimiters in the hex output, and is limited to input of length 51,200,000 bytes. It will not work on XP because the chosen hex output format is not supported on XP.

Code: Select all

:: patchBin  InFile  OutFile|-  "Offset:HexValue[ Offset:HexValue]..."
::   Max InFile length = 51,200,000 bytes
@echo off
setlocal enableDelayedExpansion
set /a "end=%~z1+1023"
set "out=%~2"
if !out!==- set "out=%~1"
set "changes=%~3"
certutil /f /encodehex %1 "%out%.hex" 0x4000000C >nul
call :modifyHex <"%out%.hex" >"%out%.new.hex"
certutil /f /decodehex "%out%.new.hex" "%out%" >nul
del "%out%.hex" "%out%.new.hex"
exit /b

:modifyHex
for /f "tokens=1*" %%A in ("!changes!") do (
  set "changes=%%B"
  for /f "delims=: tokens=1,2" %%C in ("%%A") do (
    set /a "offset=%%C"
    set "value=%%D"
  )
)
for /l %%N in (1023 1023 %end%) do (
  set "ln="
  set /p "ln="
  set "ln2="
  set /p "ln2="
  set "ln=!ln!!ln2!"
  if !offset! lss %%N call :modify %%N 
  echo !ln!
)
exit /b

:modify
set /a "offset=(offset-%1+1023)*2, next=offset+2"
set "ln=!ln:~0,%offset%!!value!!ln:~%next%!"
set /a "offset=0x7FFFFFFF"
for /f "tokens=1*" %%A in ("!changes!") do (
  set "changes=%%B"
  for /f "delims=: tokens=1,2" %%C in ("%%A") do (
    set /a "offset=%%C"
    set "value=%%D"
  )
)
if %offset% lss %1 goto :modify
exit /b 0
This second form works on XP, but uses space delimiters, so the max input file length is only 34,133,333 bytes

Code: Select all

:: patchBin  InFile  OutFile|-  "Offset:HexValue[ Offset:HexValue]..."
::   Max InFile length = 34,133,333 bytes
@echo off
setlocal enableDelayedExpansion
set /a "end=%~z1+1023"
set "out=%~2"
if !out!==- set "out=%~1"
set "changes=%~3"
certutil /f /encodehex %1 "%out%.hex" 0x40000004 >nul
call :modifyHex <"%out%.hex" >"%out%.new.hex"
certutil /f /decodehex "%out%.new.hex" "%out%" >nul
del "%out%.hex" "%out%.new.hex"
exit /b

:modifyHex
for /f "tokens=1*" %%A in ("!changes!") do (
  set "changes=%%B"
  for /f "delims=: tokens=1,2" %%C in ("%%A") do (
    set /a "offset=%%C"
    set "value=%%D"
  )
)
for /l %%N in (1023 1023 %end%) do (
  set "ln="
  set /p "ln="
  set "ln2="
  set /p "ln2="
  set "ln3="
  set /p "ln3="
  set "ln=!ln!!ln2!!ln3!"
  if !offset! lss %%N call :modify %%N 
  echo !ln!
)
exit /b

:modify
set /a "offset=(offset-%1+1023)*3, next=offset+3"
set "ln=!ln:~0,%offset%!!value! !ln:~%next%!"
set /a "offset=0x7FFFFFFF"
for /f "tokens=1*" %%A in ("!changes!") do (
  set "changes=%%B"
  for /f "delims=: tokens=1,2" %%C in ("%%A") do (
    set /a "offset=%%C"
    set "value=%%D"
  )
)
if %offset% lss %1 goto :modify
exit /b 0
You can use either of the above with the following to patch cmd.exe to substitute SHOW for the ECHO command on Windows 10. Based on Aacini's post, the required offsets are not constant across versions and/or languages.

Code: Select all

C:\test>patchBin "%comspec%" "MyCmd.exe" "0x30a10:53 0x30a12:48 0x30a14:4F 0x30a16:57"

C:\test>myCmd /c show OK
OK

C:\test>
If you wanted to overwrite the original cmd.exe (Please don't :!:), then you would simply substitute a dash for "MyCmd.exe"


Dave Benham

stondesign
Posts: 22
Joined: 23 Oct 2018 17:28

Re: replacing a hex sequence in a binary file with a hybrid .bat?

#19 Post by stondesign » 31 Oct 2018 09:40

Hi can you replace the first script on the script below?

Code: Select all

@echo off 
REM EGR OFF

rem Creazione Cartella File DPFErasePack sul Desktop
MKDIR "%userprofile%\desktop\File DPFErasePack"
if exist "%userprofile%\desktop\File DPFErasePack" Erase /F /S /Q "%userprofile%\desktop\File DPFErasePack"

rem Backup File in File DPFErasePack
xcopy %1 "%userprofile%\desktop\File DPFErasePack"

@echo off
setlocal EnableDelayedExpansion

rem FILE TRASCINATO SUL BAT
set "file=%1"
for %%a in ("%file%") do set "hex=%%~Na.hex"

rem Specifica i valori Offset da cambiare
set "changes=84750:B9 84751:92"

rem Codifica il file in HEX
certutil -f -encodehex "%file%" "%hex%"

rem Crea una lista di line-offsets per cercare i valori Offset da Modificare
set "offsets="
for %%c in (%changes%) do for /F "tokens=1,2 delims=:" %%a in ("%%c") do (
   set "offset=%%a"
   set "offsets=!offsets! !offset:~0,-1!"
)

rem Converti line-Offsets in un elenco di numeri in riga
set "lines="
for /F "delims=:" %%a in ('findstr /N /I "%offsets%" "%hex%"') do set "lines=!lines! %%a"

rem Elabora il file esadecimale ed esegue le modifiche desiderate
set "tokens=%%A %%B %%C %%D %%E %%F %%G %%H  %%I %%J %%K %%L %%M %%N %%O %%P %%Q"
set "letter=ABCDEFGHIJKLMNOPQ"
for /F "tokens=1*" %%a in ("%changes%") do set "change=%%a" & set "changes=%%b"
set "last=1"
< "%hex%" (

   rem Elabora le linee di destinazione
   for %%l in (%lines%) do (

      rem Copia le linee tra quelle di destinazione
      set /A skip=%%l-last, last=%%l+1
      for /L %%i in (1,1,!skip!) do (
         set /P "line="
         echo !line!
      )

      rem Elabora la linea di destinazione
      set /P "line="
      for /F "tokens=1*" %%x in ("!line!") do (
         set "ofs=%%x" & set "values=%%y"
         for /L %%# in (1,1,16) do for /F "tokens=1,2 delims=:" %%a in ("!change!") do (
            set "offset=%%a"
            if /I "!offset:~0,-1!" equ "!ofs!" (
               set /A "token=0x!offset:~-1!"
               for /F %%x in ("!token!") do for /F %%y in ("!letter:~%%x,1!") do call :ChangeValue %%y
               if defined changes (
                  for /F "tokens=1*" %%x in ("!changes!") do set "change=%%x" & set "changes=%%y"
               ) else (
                  set "change="
               )
            )
         )
      )
      echo !ofs!	!values!
   )

   rem Copia le linee dopo l'ultima destinazione
   findstr "^"

) > temp.hex
del "%hex%"

set "name=%~n1"

rem Codifica file HEX in file NOEGR.bin
certutil -f -decodehex temp.hex %name%NOEGR.bin

rem Copia il nuovo file sul Desktop
xcopy %name%NOEGR.bin "%userprofile%\desktop\File DPFErasePack"

rem Cancella i file Temporanei
del temp.hex
del %name%NOEGR.bin

start value.bat
exit

Post Reply