This topic is rather interesting to me, so I wrote a complete solution for it. Please, note that does not matter the
original value of the bytes in the file, just the
offset and the
new value at such offset.
This is the code. An explanation and example of its use is below.
Code: Select all
@echo off
setlocal EnableDelayedExpansion
set "file=myCmd.exe"
for %%a in ("%file%") do set "hex=%%~Na.hex"
rem Specify the desired changes as offset:newValue pairs
rem Add left zeros in offsets with less than five digits *only*
rem E.G.: to change "1C8608 E.C.H.O." by "S.H.O.W.":
set "changes=1C8608:53 1C860A:48 1C860C:4F 1C860E:57"
rem Encode file from bin to text hex
certutil -f -encodehex "%file%" "%hex%"
rem Create a list of line-offsets to search for
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 Convert line-offsets to a list of line numbers
set "lines="
for /F "delims=:" %%a in ('findstr /N /I "%offsets%" "%hex%"') do set "lines=!lines! %%a"
rem Process the hex file and perform the desired changes
set "tokens=%%A %%B %%C %%D %%E %%F %%G %%H %%I %%J %%K %%L %%M %%N %%O %%P %%Q"
set "letter=ABCDEFGHIJKLMNOP"
for /F "tokens=1*" %%a in ("%changes%") do set "change=%%a" & set "changes=%%b"
set "last=1"
< "%hex%" (
rem Process target lines
for %%l in (%lines%) do (
rem Copy the lines between target ones
set /A skip=%%l-last, last=%%l+1
for /L %%i in (1,1,!skip!) do (
set /P "line="
echo !line!
)
rem Process the target line
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 Copy the lines after the last target one
findstr "^"
) > temp.hex
del "%hex%"
rem Decode file back from hex to bin
certutil -f -decodehex temp.hex "%file%"
del temp.hex
goto :EOF
:ChangeValue token
set "newVals=!tokens:%1=b!"
for /F "tokens=1-16*" %%A in ("%values%") do set "values=%newVals%"
exit /B
Example of a cmd.exe session that uses previous code:
Code: Select all
C:\Antonio\tests> rem Copy cmd.exe as new local file
C:\Antonio\tests> copy "%comspec%" myCmd.exe
1 archivo(s) copiado(s).
C:\Antonio\tests> rem Encode it as text hex file
C:\Antonio\tests> certutil -encodehex myCmd.exe myCmd.hex
Longitud de entrada = 404992
Longitud de salida = 1894304
CertUtil: -encodehex comando completado correctamente.
C:\Antonio\tests> rem Search for the place where "echo" command is located
C:\Antonio\tests> findstr /I "e.c.h.o" myCmd.hex
1c860 00 00 00 00 00 00 00 00 45 00 43 00 48 00 4f 00 ........E.C.H.O.
C:\Antonio\tests> rem At this place, insert appropriate data in test.bat
C:\Antonio\tests> rem Modify "ECHO" by "SHOW" in myCmd.exe
C:\Antonio\tests> test
Longitud de entrada = 404992
Longitud de salida = 1894304
CertUtil: -encodehex comando completado correctamente.
Longitud de entrada = 1894304
Longitud de salida = 404992
CertUtil: -decodehex comando completado correctamente.
C:\Antonio\tests> rem Test it
C:\Antonio\tests> myCmd
Microsoft Windows [Versión 6.2.9200]
(c) 2012 Microsoft Corporation. Todos los derechos reservados.
C:\Antonio\tests> show Hello world
Hello world
Antonio