Patching EXEs
- Posted by "Bruce M. Axtens" <lpcd at CYBER.NET.PK> Feb 02, 2001
- 522 views
[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>