Patching EXEs

new topic     » goto parent     » topic index » view thread      » older message » newer message

[I wrote this to the other list. I'd better cross post it here. Don't want
to miss any one.]

George Henry said a while back something about patching EXEs. Below are two
programs which achieve this.

GENPATCH.EX
    takes two files, the old one and the new one and produces a patch file
    >GENPATCH old.exe new.exe patch.dat

The patch file was produced using print.e so isn't space-saving at all.
Perhaps one could come up with a binary form, e.g.
    OFFSET          1 x DWORD
    NUMBER_OF_BYTES 1 x WORD
    BYTES           NUMBER_OF_BYTES x BYTE

PATCHIT.EX
    takes the patch data, the old file and produces a new file
    >PATCHIT patch.dat old.exe new.exe

Initial tests work ok but, of course, if it trashes your life's work, sad.
The code is very raw and took about an hour and a half to figure out. I'd
really appreciate some constructive criticism -- how I could have done it
better, faster, tighter etc.

Bruce M. Axtens
--
"Who of us is mature enough for offspring before the offspring themselves
arrive? The value of marriage is not that adults produce children but that
children produce adults" -- Peter de Vries

GENPATCH.EX
<CODE>
-- genpatch

include get.e
include print.e
--with trace
--trace(2)

puts( 1, "GENPATCH v1.0 (c) Copyright Bruce M. Axtens, 2001.\n" )

sequence patchBlock
patchBlock = {}
integer storeCount
storeCount = 0
integer storeNum
storeNum = -1
procedure store( integer offset, integer byte )
    if offset = storeNum + 1 then
    patchBlock[ length( patchBlock ) ][ 2 ] &= byte
    storeNum = offset
    else
    patchBlock = append( patchBlock, { offset, {byte} } )
    storeNum = offset
    end if
end procedure

sequence cl
sequence bin1, bin2, patch
cl = command_line()
if length( cl ) < 5 then
    puts( 1, "Syntax:\n\tgenpatch <binary1> <binary2> <patchname>\n" )
    abort( 1 )
end if

bin1 = cl[ 3 ]
bin2 = cl[ 4 ]
patch = cl[ 5 ]

integer hbin1, hbin2, hpatch

hbin1 = open( bin1, "rb" )
if hbin1 = -1 then
    puts( 1, "Could not open " & bin1 & "\n" )
    abort( 2 )
end if

hbin2 = open( bin2, "rb" )
if hbin2 = -1 then
    puts( 1, "Could not open " & bin2 & "\n" )
    abort( 3 )
end if

hpatch = open( patch, "w" )

constant EOBIN1 = 1, EOBIN2 = 2
sequence res
integer bin1byte, bin2byte
integer status
integer offset
offset  = 1

while 1 do
    res = get_bytes( hbin1, 1 )
    if length( res ) = 0 then
    status = EOBIN1
    exit
    end if
    bin1byte = res[ 1 ]

    res = get_bytes( hbin2, 1 )
    if length( res ) = 0 then
    status = EOBIN2
    exit
    end if
    bin2byte = res[ 1 ]

    if bin1byte != bin2byte then
    store( offset, bin2byte )
    storeCount += 1
    end if

    offset += 1

end while
trace(2)
if status = EOBIN1 then
    while 1 do
    res = get_bytes( hbin2, 1 )
    if length( res ) = 0 then
        exit
    end if
    store( offset, res[ 1 ] )
    storeCount += 1
    offset += 1
    end while
elsif status = EOBIN2 then
    --
end if
close( hbin1 )
close( hbin2 )
print( hpatch, patchBlock )
close( hpatch )
printf( 1, "%d changes after comparing %s with %s stored in %s.\n", {
storeCount, bin1, bin2, patch } )
</CODE>

PATCHIT.EX
<CODE>
include get.e
--with trace
--trace(2)
puts( 1, "PATCHIT v1.0 (c) Copyright Bruce M. Axtens, 2001.\n" )

integer patchCount
patchCount = 0

sequence patchBlock

sequence cl
sequence patch, bin1, bin2
cl = command_line()
if length( cl ) < 5 then
    puts( 1, "Syntax:\n\tpatchit <patchname> <binary1> <binary2>\n" )
    abort( 1 )
end if

patch = cl[ 3 ]
bin1 = cl[ 4 ]
bin2 = cl[ 5 ]

integer hbin1, hbin2, hpatch

hbin1 = open( bin1, "rb" )
if hbin1 = -1 then
    puts( 1, "Could not open " & bin1 & "\n" )
    abort( 2 )
end if

hbin2 = open( bin2, "wb" )
if hbin2 = -1 then
    puts( 1, "Could not open " & bin2 & "\n" )
    abort( 3 )
end if

hpatch = open( patch, "r" )

patchBlock = get( hpatch )
if patchBlock[ 1 ] != GET_SUCCESS then
    puts( 1, "Could not load the patch information\n" )
    abort( 4 )
end if
patchBlock = patchBlock[ 2 ]
sequence res
atom bin1byte
integer offset
offset  = 0
integer patched
patched = 0
integer eopatch
eopatch = 0
integer looper
looper = 1
trace(2)
while 1 do
    for i = 1 to looper do
    res = get_bytes( hbin1, 1 )
    offset += 1
    end for
    if length( res ) = 0 then
    exit
    end if
    bin1byte = res[ 1 ]
    patched = 0
    for i = 1 to length( patchBlock ) do
    if patchBlock[ i][ 1 ] > offset then
        looper = 1
        exit
    end if
    if offset = patchBlock[ i ][ 1 ] then
        puts( hbin2, patchBlock[ i ][ 2 ] )
        patchCount += 1
        looper = length( patchBlock[ i ][ 2 ] )
        patchBlock = patchBlock[ 2 .. length( patchBlock ) ]
        if length( patchBlock ) = 0 then
        eopatch = 1
        end if
        patched = 1
        exit
    end if
    end for

    if patched = 0 then
    puts( hbin2, bin1byte )
    end if

    if eopatch then
    exit
    end if
end while
close( hbin1 )
if length( patchBlock ) > 0 then
    puts( hbin2, patchBlock[ length( patchBlock ) ][ 2 ] )
    patchCount += 1
end if
close( hbin2 )
close( hpatch )
printf( 1, "%d patches in %s applied to %s to give %s.\n", { patchCount,
patch, bin1, bin2 } )
</CODE>

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu