Petite 2.1 Patching Tutorial -- by R!SC / May 1999 (almost tut #3 on packed files)

Petite 2.1 (c) 1998-99 Ian Luck

Target file---PETITE.EXE  46,214 bytes  13/05/99
http://www.icl.ndirect.co.uk/petite/



Petite, oh Petite, how i love you....

Wow, 4 months on, and a lot of changes, but 'Petite' is still patcher friendly, decompression
code has seriously been optimized, it packs the import table, the tamper check is still lame
and it has a lovely shell extension now.... its almost a decent packer!!! (well, it is, and its
almost unpack proof)

Well, i downloaded Petite 2.1 a few days ago, but today i got home from work, and thought to
myself i'll just have a look at it, see how much it has changed, see if my old tutorial will
help people patch this version... heh, damn it! it wont, theres been a lot of changes, and
finding the packer exit point was quite a challenge (*g* theres only 0x170 bytes of code to
trace through!!)

Well, tracing for a while, i noticed theres no 'jmp we've finished' or 'jmp eax' or anything to
signify that it has done and is transferring execution to a whole different area of memory. The
unpacker code just jumps around inside itself, and calls inside itself.. hmm..

This is the closest you get to an exit point

0137:004DA042  B800A04D00          MOV     EAX,004DA000     <-- where symbol loader breaks
0137:004DA047  682A1C4100          PUSH    00411C2A
0137:004DA04C  64FF3500000000      PUSH    DWORD PTR FS:[00000000]
0137:004DA053  64892500000000      MOV     FS:[00000000],ESP
0137:004DA05A  669C                PUSHF
0137:004DA05C  60                  PUSHAD
0137:004DA05D  50                  PUSH    EAX
0137:004DA05E  33DB                XOR     EBX,EBX
0137:004DA060  8D9078010000        LEA     EDX,[EAX+00000178]
0137:004DA066  6800004000          PUSH    00400000
0137:004DA06B  8B0A                MOV     ECX,[EDX]
0137:004DA06D  0FBAF11F            BTR     ECX,1F
0137:004DA071  7316                JAE     004DA089
0137:004DA073  8B0424              MOV     EAX,[ESP]
0137:004DA076  FD                  STD
0137:004DA077  8BF0                MOV     ESI,EAX
0137:004DA079  8BF8                MOV     EDI,EAX
0137:004DA07B  037204              ADD     ESI,[EDX+04]
0137:004DA07E  037A08              ADD     EDI,[EDX+08]
0137:004DA081  F3A5                REPZ MOVSD
0137:004DA083  83C20C              ADD     EDX,0C
0137:004DA086  FC                  CLD
0137:004DA087  EBE2                JMP     004DA06B
0137:004DA089  83C210              ADD     EDX,10
0137:004DA08C  8B5AF4              MOV     EBX,[EDX-0C]
0137:004DA08F  85DB                TEST    EBX,EBX
0137:004DA091  74D8                JZ      004DA06B
0137:004DA093  8B0424              MOV     EAX,[ESP]
0137:004DA096  8B7AF8              MOV     EDI,[EDX-08]
0137:004DA099  03F8                ADD     EDI,EAX
0137:004DA09B  52                  PUSH    EDX
0137:004DA09C  8D3401              LEA     ESI,[EAX+ECX]
0137:004DA09F  EB17                JMP     004DA0B8
0137:004DA0A1  58                  POP     EAX              <-- nice
0137:004DA0A2  58                  POP     EAX              <-- a few pops
0137:004DA0A3  58                  POP     EAX
0137:004DA0A4  5A                  POP     EDX
0137:004DA0A5  74C4                JZ      004DA06B         <-- a jz carryon
0137:004DA0A7  E95CFFFFFF          JMP     004DA008         <-- and a jump to a piece of code
                                                            <-- that hasn't been used yet

Well, i set a BPX 4DA0A7, on the JMP 4DA008, then ran the program (F5), but it didn't break :(
so i reloaded it into the symbol loader, and set a BPX 4DA0A5, the JZ 4DA06B, just before the
(hopefully) important jump. F5, it runs / breaks, the jz gets taken, F5, same again, F5, same
thing again, F5, damn! it ran...

I decide to trace after the third break, as on the fourth one, it runs...this is not looking
good.. Reloaded it into the symbol loader, i still have my breakpoint set on 4DA0A5, F5 three
times, then trace with F10, very soon it runs again... do you remember where? oh my god! its
when a MOVSB instruction is executed... how does this work?

0137:004DA0F0  6A00                PUSH    00
0137:004DA0F2  32D2                XOR     DL,DL
0137:004DA0F4  4B                  DEC     EBX
0137:004DA0F5  A4                  MOVSB                <-- this is where the program runs
0137:004DA0F6  33C9                XOR     ECX,ECX
0137:004DA0F8  83FB00              CMP     EBX,00
0137:004DA0FB  7EA4                JLE     004DA0A1
0137:004DA0FD  E8AAFFFFFF          CALL    004DA0AC
0137:004DA102  7217                JB      004DA11B
0137:004DA104  A4                  MOVSB
0137:004DA105  305FFF              XOR     [EDI-01],BL
0137:004DA108  4B                  DEC     EBX
0137:004DA109  EBED                JMP     004DA0F8     <-- this loops back to 4DA0F8 (just to
                                                            let you know for later...)

Yah, i reload it again!! into the symbol loader, clear all previous breakpoints, and set one on
the MOVSB at address 4DA0F5. MOVSB moves a byte from [ESI] to [EDI] and increments them both so
i run the program with F5, and keep on looking at the two important registers on every break.
1,2,3,4,5th F5 it runs... reload it, 1,2,3,4,5th F5 it runs, reload it, F5 1,2,3,4..
ESI=00400000, EDI=00400000, try tracing into it this time with F8, hmm, damn thing runs. How
does this instruction make the program run? where does program execution go to when this
instruction has been executed? well, it doesn't matter, maybe one day i'll know, but for know,
i have all i need, i know that when ESI==00400000, the program has unpacked, and that doing a
MOVSB instruction, i can run the program, so all i need to do is alter the code a bit :)

So the we have the important information for the patch, we replace the bit of code around /
just before the MOVSB with a JMP MYCODE, then at MYCODE, we check ESI for 00400000, if its
equal, we patch the unpacked code, then do the MOVSB to run the newly patched program, and if
ESI!=00400000 we execute the instructions we replaced with the JMP MYCODE, then jump back..

My idea for the patch is the same as for the old version of Petite, just replace the text
string '$HAREWARE - see REGISTER.TXT for details',0A,00 with something a little more subtle,
like er, 'Patched by R!SC',0A,00

Load petite.exe into a hexeditor, to find a good place for our code, ah, offset 4F0, just after
the imports, enter 'sometext', then leave a bit of space for the code, then at offset 540,
enter 'Patched by R!SC',0A,00 (hmm, 0x11 bytes...)

We have to put a jmp inside of the unpacker code, the file offset for this is 2F2, and since
the jump will take up 5 bytes, we will use half the XOR ECX,ECX instruction aswell, so we have
to NOP the other half of it...

Load petite into the symbol loader again, s 0 l ffffffff 'sometext', we get the address of
where we want to jump to, 4DA2F0... s 0 l ffffffff '$HAREWARE', we get the address we want to
patch, 412B1B, s 0 l ffffffff 'Patched by R!SC', we get the address of our really important
data, 4DA340...

...still in softice...

We have to change these lines 

0137:004DA0F2  32D2                XOR     DL,DL        <-- yah, we recode this bit
0137:004DA0F4  4B                  DEC     EBX
0137:004DA0F5  A4                  MOVSB
0137:004DA0F6  33C9                XOR     ECX,ECX
0137:004DA0F8  83FB00              CMP     EBX,00       <-- where the jump below lands , so we
0137:004DA0FB  7EA4                JLE     004DA0A1       - cant change the code at/after 4DA0F8
0137:004DA0FD  E8AAFFFFFF          CALL    004DA0AC
0137:004DA102  7217                JB      004DA11B
0137:004DA104  A4                  MOVSB
0137:004DA105  305FFF              XOR     [EDI-01],BL
0137:004DA108  4B                  DEC     EBX
0137:004DA109  EBED                JMP     004DA0F8     <-- loop back up

to

0137:004DA0F2  E9F9010000          JMP     4DA2F0       <-- Jump to space after the imports
0137:004DA0F7  90                  NOP                  <-- make it look neat, cant leave half an
0137:004DA0F8  83FB00              CMP     EBX, 00        - instruction there
0137:004DA0FB  7EA4                JLE     004DA0A1
0137:004DA0FD  E8AAFFFFFF          CALL    004DA0AC
0137:004DA102  7217                JB      004DA11B
0137:004DA104  A4                  MOVSB
0137:004DA105  305FFF              XOR     [EDI-01],BL
0137:004DA108  4B                  DEC     EBX
0137:004DA109  EBED                JMP     004DA0F8


So follow what i did here inside softice

Break due to Symbol Loader
:a 4da0f2
0137:004DA0F2 jmp 4da2f0
0137:004DA0F7 nop
0137:004DA0F8 <esc>
:a 4da2f0
0137:004DA2F0 cmp esi, 0400000
0137:004DA2F6 jz 4da306
0137:004DA2F8 xor dl,dl
0137:004DA2FA dec ebx
0137:004DA2FB movsb
0137:004DA2FC xor ecx,ecx
0137:004DA2FE jmp 4da0f8
0137:004DA303 nop
0137:004DA304 nop
0137:004DA305 nop
0137:004DA306 pushad
0137:004DA307 mov esi, 4da340
0137:004DA30C mov edi, 412b1b
0137:004DA311 mov ecx, 11
0137:004DA316 rep
0137:004DA317 movsb
0137:004DA318 popad
0137:004DA319 movsb
0137:004DA31A <esc>


See, then dump the memory??? pagein 4da2f0 30 c:\newcode.dat, then copy & paste it over
'sometext' in petite.exe, then replace the code at offset 2F2 with the jump to this new code,
then all is well...

the new code, & instruction bytes...

:u 4da2f0 l 30
0137:004DA2F0  81FE00004000        CMP     ESI,00400000     <-- check see if its finished unpacking
0137:004DA2F6  740E                JZ      004DA306         <-- if yes! jump to patch code
0137:004DA2F8  32D2                XOR     DL,DL            <-- otherwise, do the instructions
0137:004DA2FA  4B                  DEC     EBX                - we replaced with the jmp 4da2f0
0137:004DA2FB  A4                  MOVSB                      -
0137:004DA2FC  33C9                XOR     ECX,ECX            -
0137:004DA2FE  E9F5FDFFFF          JMP     004DA0F8           - and jump back to unpack code
0137:004DA303  90                  NOP
0137:004DA304  90                  NOP
0137:004DA305  90                  NOP
0137:004DA306  60                  PUSHAD                   <-- save the registers
0137:004DA307  BE40A34D00          MOV     ESI,004DA340     <-- source ('Patched by R!SC',0a,00)
0137:004DA30C  BF1B2B4100          MOV     EDI,00412B1B     <-- destination ('$HAREWARE')
0137:004DA311  B911000000          MOV     ECX,00000011     <-- how many bytes we want to copy
0137:004DA316  F3A4                REPZ MOVSB               <-- repeat movs byte thingy
0137:004DA318  61                  POPAD                    <-- restore the registers
0137:004DA319  A4                  MOVSB                    <-- fuck the rest of the code, and 
                                                              - run the program


Sooooo, at file offset 0x2F2, we replace 6 bytes with E9F901000090, then at offset 0x4F0, we 
replace a lot more bytes(42), with
81FE00004000740E32D24BA433C9E9F5FDFFFF90909060BE40A34D00BF1B2B4100B911000000F3A461A4
then at offset 0x540 (which we have already changed, but just to be sure), we replace a few more
bytes with 'Patched by R!SC',0A,00


Well, the tutorial started off so good, then it all went? ahem, sorry, but if you understand
whats been said so far, you are now able to patch petite 2.1, the weirdest compressor i have
come across...

Just a couple of file dumps follow, to make sure you know where to patch..

000002F0 6A 00 E9 F9 01 00 00 90 83 FB 00 7E A4 E8 AA FF j..........~....  <-- the jump mycode

000004D0 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E 64 6C 6C 2.dll.user32.dll  <-- end of imports
000004E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000004F0 81 FE 00 00 40 00 74 0E 32 D2 4B A4 33 C9 E9 F5 ....@.t.2.K.3...  <-- mycode
00000500 FD FF FF 90 90 90 60 BE 40 A3 4D 00 BF 1B 2B 41 ......`.@.M...+A
00000510 00 B9 11 00 00 00 F3 A4 61 A4 00 00 00 00 00 00 ........a.......
00000520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000540 50 61 74 63 68 65 64 20 62 79 20 52 21 53 43 0A Patched by R!SC.  <-- mydata
00000550 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................


The tamper check is pretty much the same as for petite 1.3a, but harder to locate..
in Petite 2.1 it is at RVA 411D9B (but will change from program to program)

:u 411d90 l 50
0137:00411D90  D3C3                ROL     EBX,CL
0137:00411D92  83C604              ADD     ESI,04
0137:00411D95  49                  DEC     ECX
0137:00411D96  75F6                JNZ     00411D8E         <-- loop calculate checksum??
0137:00411D98  395804              CMP     [EAX+04],EBX     <-- check it
0137:00411D9B  7408                JZ      00411DA5         <-- jump if equal not tampered with
0137:00411D9D  83C42A              ADD     ESP,2A
0137:00411DA0  E970820C00          JMP     004DA015         <-- otherwise, jump back to unpack code
0137:00411DA5  BEA4160100          MOV     ESI,000116A4       - and NAG user
0137:00411DAA  8B8D00010000        MOV     ECX,[EBP+00000100]
0137:00411DB0  03F5                ADD     ESI,EBP

I can only trigger the tamper check if i alter the pe-header, altering the unpacker code does
not alter the calculated checksum, so you don't really have to worry about it..


R!SC 19th May 1999, risc@notme.com, http://csir.cjb.net 

(yah, your packer friendly cracker, wonder what happened to my Neolite tutorial? hmm, it may come
along, probably do one for aspack / upx / wwpack aswell)


oops, i missed a bit....

i packed a few programs with petite 2.1, and traced through them, noticed that without a
commandline, the unpacker code is slightly different.. 

'petite notepad.exe -r* -9' (compress all resources but icons..best compression level)
the unpackcode was the same as in petite.exe

'petite notepad.exe -3' (compression level 3)
the unpackcode was the same as in petite.exe

'petite notepad.exe -r*' (normal compression, with resources)
the unpackcode had changed (fig.1)

'petite notepad.exe'
the unpackcode had changed (fig.1)

Fig.1
instead of using a 'MOVSB' & ESI & EDI==00400000,
it uses 'MOV     [EDI],AL' & EAX & EDI==00400000...

0137:0040C1D3  55                  PUSH    EBP
0137:0040C1D4  8BEC                MOV     EBP,ESP
0137:0040C1D6  8807                MOV     [EDI],AL
0137:0040C1D8  81ECD8BA0000        SUB     ESP,0000BAD8
0137:0040C1DE  8D8D887FFFFF        LEA     ECX,[EBP+FFFF7F88]

from the PUSH EBP to the end of the MOV [EDI],AL, you have 5 bytes, where the jump can go,
then jump to code a bit like this

CMP EAX,00400000
JZ PATCHIT
PUSH EBP
MOV EBP,ESP
MOV [EDI],AL
JMP 40C1D8
PATCHIT:
MOV WORD PTR [BLAHBLAH],BLAH
MOV [EDI],AL


well, thats it for me.. i'm outta here, i think i have about finished

R!SC - 21st May 1999 - http://csir.cjb.net
