grrr 'Securom, another damn Addendum' tools: tasm5.0, softICE 3.23 with memory dumper (icedump?), hex editor, procdump, RPPv1.2i.. btw, my target, loader.exe 920,991bytes 27/05/99, compressed with 'Petite'(v1.4??) from the game 'Outcast' by Appeal/Infogrames www.outcast-game.com (nice target, as 50% of the time doesnt want to run with the correct cd in anyway.) hello.. hi r!sc, wassup?? hi, i have been playin with securom.. i loved pedros tutorial on it (http://crknotez.cjb.net), and this helped me crack a few securom games, but, alas, i think sony have updated securom, so pedros tutorial dont help much now.. remember how if it knew you had been debugging it, and it refused to run anymore, until a reboot?? well, this sucks, and there were a few safe breakpoints you could use before, bpx writeprocessmemory, bpx getdrivetypea, erm, well, it knows about these now, and refuses to run.. alas, we run into a few problems.. :D well, are you a reverse engineer or a mouse?? hehe, we aint afraid of no securom.. say i wanna bpx on writeprocessmemory, to find out where it decrypts the data in the programs code, i get one break, the first one where it decrypts some securom code, then no more, the program runs in a continous loop, ctrl-alt-del to kill it, then it wont run again.. say i wanna avoid the code decryption part of it, and break on the getdrivetypea, no no no, if you have any nice breakpoints set, it just doesnt run, and after clearing them, it still doesnt run.. stuff i noticed, cms16.dll, cms32_95.dll & cms32_nt.dll are inside the program, and wrote to disk when its executed.. probably to stop people tampering with them.. :D if it knows you have been debugging it, it exits without closing the file handle to cms16.dll. try deleting it, you get a nice error, 'Cannot delete cms16: The specified file is being used by windows'. well, theres a clue, maybe.. clear all breakpoints, bpx createfilea.. run ya securom protected game: first few breaks arnt important.. windows loading the file, then a short pause, where it gets decompressed, then these are the ones we want, the first opens itself, the second? cms16.dll? the third, cms16.dll.. wait, take a look at this code.. 0137:005A1298 50 PUSH EAX <-- ptr to x:\xx\cms16.dll 0137:005A1299 FF1534685C00 CALL [KERNEL32!CreateFileA] 0137:005A129F 8945DC MOV [EBP-24],EAX 0137:005A12A2 837DDCFF CMP DWORD PTR [EBP-24],-01 <-- its already there, and 0137:005A12A6 753B JNZ 005A12E3 - cant be opened again.. 0137:005A12A8 C70580645C0000000000MOV DWORD PTR [005C6480],00000000 0137:005A12B2 6A00 PUSH 00 0137:005A12B4 6A00 PUSH 00 0137:005A12B6 6A03 PUSH 03 0137:005A12B8 6A00 PUSH 00 0137:005A12BA 6A00 PUSH 00 0137:005A12BC 6800000080 PUSH 80000000 0137:005A12C1 8D8D38FFFFFF LEA ECX,[EBP-00C8] 0137:005A12C7 51 PUSH ECX <-- same ptr to cms16.dll 0137:005A12C8 FF1534685C00 CALL [KERNEL32!CreateFileA] 0137:005A12CE 8945DC MOV [EBP-24],EAX 0137:005A12D1 837DDCFF CMP DWORD PTR [EBP-24],-01 <-- oh crap, its still -1 0137:005A12D5 750A JNZ 005A12E1 - but forcing this jump 0137:005A12D7 6A00 PUSH 00 - it will run again :D 0137:005A12D9 E8022C0000 CALL 005A3EE0 0137:005A12DE 83C404 ADD ESP,04 0137:005A12E1 EB0A JMP 005A12ED 0137:005A12E3 C70580645C0001000000MOV DWORD PTR [005C6480],00000001 0137:005A12ED 8B15C4675C00 MOV EDX,[005C67C4] well, see, it tries to create this file, and if it fails, return code FFFFFFFF, it exits.. if we trick it, make it think it could create this file, just by forcing either of these jumps, it runs again :D so not all is lost.. oops, we still cant bpx writeprocessmemory, or bpx getdrivetypea, so things are trickier, but not impossible.. what i noticed about the older versions of securom, it decrypts 20kb of program code, around the original entry point, then checks the disk, and if the correct one is in, it decrypts 200h bytes more of code at the original entry point.. the other code it decrypts wasnt important, as this was securom code.. theory, trace petite until it has unpacked the program, dump the memory, bpx on the exit point of the securom code, and when you reach it, dump the memory again, and just do a file compare, you should find a nice 20kb block of decrypted code in the second dump.. arrgh! how to bpx on the exit point of the securom code?? heh, dont ph34r, 'tis easy :D i expect you to have already fucked up the program, so it wont run anymore, and we have to make it run by changing one of the jumps after the call to createfilea, 'cms16.dll'.. good.. i used my dodgy process patcher to make a loader that fixed this for me.. T=10000: F=loader.exe: O=securomfix_cc.exe: P=5A12A6/75/CC: ; 0137:005A12A6 753B JNZ 005A12E3 $ changing this to a EB makes it run all the time, but i wanted to break here, so i change it to a CC, an int 03, then in softice, bpint 03, x. run the loader.. hey, when it breaks, dont forget to change the CC to an EB..e eip eb.. okay, when it breaks, and you have changed your int 03 to a jmp, just make your code window nice and big, and scroll, ctrl-page-down. this is where we could normally break, but bpx getdrivetypea or just bpx 5a25a2, it knows about them and stops running.. bad, keep scrolling 0137:005A259B 52 PUSH EDX 0137:005A259C FF15E04F5C00 CALL [KERNEL32!GetDiskFreeSpaceA] 0137:005A25A2 8D8548FCFFFF LEA EAX,[EBP-03B8] 0137:005A25A8 50 PUSH EAX 0137:005A25A9 FF15004B5C00 CALL [KERNEL32!GetDriveTypeA] 0137:005A25AF 83F805 CMP EAX,05 look, another place we could normally break, but, alas, we cant no more.. keep scrolling.. 0137:005A28E0 8D9548FCFFFF LEA EDX,[EBP-03B8] 0137:005A28E6 52 PUSH EDX 0137:005A28E7 FF15E04F5C00 CALL [KERNEL32!GetDiskFreeSpaceA] 0137:005A28ED 8D8548FCFFFF LEA EAX,[EBP-03B8] 0137:005A28F3 50 PUSH EAX 0137:005A28F4 FF15004B5C00 CALL [KERNEL32!GetDriveTypeA] 0137:005A28FA 83F805 CMP EAX,05 Yippee!! this is another place where we would break, many many pages of code have passed before us, and we know, this is where the securom code ends, and jumps to the proper program :D 0137:005A31A8 B8A1535000 MOV EAX,005053A1 0137:005A31AD 90 NOP 0137:005A31AE 90 NOP 0137:005A31AF 50 PUSH EAX 0137:005A31B0 EB03 JMP 005A31B5 0137:005A31B2 58 POP EAX 0137:005A31B3 FFE0 JMP EAX hmm, good news, we can bpx here 0137:005A31B3 FFE0 JMP EAX, and all is well.. the program still works fine :D yah.. fine!! heres another lame loader to help us on our way.. T=10000: F=loader.exe: O=securom.cc.jmp.eax.exe: ;P=5A12A6/75/EB: ; heh, my pc crashed for some reason, so this isnt needed yet :) P=5A31B3/FF/CC: ; i just wanna break on the securom exit point, the jmp eax.. $ nice one r!sc, almost time to be destructive :D now, using this loader, when softice breaks on the int 03, we can get our decrypted code, what about our dodgy calls?? remember older securom? call dword ptr [securom] for every import? and if you traced over it, the nice securom code replaced [securom] with the actual address of the import in out IAT somewhere in memory? hehe, well, buggered if this works now :( look here.. this is my original program entry point, see 005053C7.. thats the api call GetVersion, but it calls the securom code, which in time, jmp's to GetVersion, trace into one of the calls, then scroll the code window until a jmp eax.. put a breakpoint on this.. and run it.. 0137:005053A1 55 PUSH EBP 0137:005053A2 8BEC MOV EBP,ESP 0137:005053A4 6AFF PUSH FF 0137:005053A6 6810EB5100 PUSH 0051EB10 0137:005053AB 68C0525000 PUSH 005052C0 0137:005053B0 64A100000000 MOV EAX,FS:[00000000] 0137:005053B6 50 PUSH EAX 0137:005053B7 64892500000000 MOV FS:[00000000],ESP 0137:005053BE 83EC58 SUB ESP,58 0137:005053C1 53 PUSH EBX 0137:005053C2 56 PUSH ESI 0137:005053C3 57 PUSH EDI 0137:005053C4 8965E8 MOV [EBP-18],ESP 0137:005053C7 FF1528C25A00 CALL [005AC228] <-- call [securom] ... 0137:005053CD 33D2 XOR EDX,EDX 0137:005053CF 8AD4 MOV DL,AH 0137:005053D1 891594585900 MOV [00595894],EDX 0137:005053D7 8BC8 MOV ECX,EAX 0137:005053D9 81E1FF000000 AND ECX,000000FF 0137:005053DF 890D90585900 MOV [00595890],ECX my 'jmp eax' was at 59F16F Break due to BPX #0137:0059F16F (ET=286.97 microseconds) :?eax BFF9137C 3220771708 (-1074195588) "¿ù|" :what eax The value BFF9137C is (a) KERNEL32!GetVersion <-- ahh now, theory, petite unpacks the code, and unpacks a real import address table :D, we just gotta find the real IAT in memory, search for the correct imports for our calls, and fix the calls to call our import table instead of the securom code.. :s 400000 l ffffffff 7c 13 f9 bf Pattern found at 0137:0051B110 (0011B110) :s Pattern found at 0137:005C6530 (001C6530) :s Pattern found at 0137:005CA3E8 (001CA3E8) :s Pattern found at 0137:0095067C (0055067C) well, we got four choices at the moment, i trace the unpacker code, and stop just before the securom code runs.. then search again.. :s 400000 l ffffffff 7c 13 f9 bf Pattern found at 0137:005CA3E8 (001CA3E8) yippee, it only finds one.. so if i edit this line.. 0137:005053C7 FF1528C25A00 CALL [005AC228] to 0137:005053C7 FF15E8A35C00 CALL [KERNEL32!GetVersion] ; CALL [005CA3E8] thats one call fixed, only about 300 left to go :) lets code something.. WHOOPS, i coded something, fixed everything, dumped the memory, copied and pasted it into my previous dump, and it worked ok.. but.. it didnt work on win95 (i am working with win98).. further debugging revealed some code like this.. 015F:00508FE0 55 PUSH EBP 015F:00508FE1 8B2D68B15100 MOV EBP,[KERNEL32!CloseProfileUserMapping] 015F:00508FE7 56 PUSH ESI 015F:00508FE8 57 PUSH EDI 015F:00508FE9 33DB XOR EBX,EBX 015F:00508FEB 33F6 XOR ESI,ESI 015F:00508FED 33FF XOR EDI,EDI 015F:00508FEF 3BC3 CMP EAX,EBX 015F:00508FF1 7533 JNZ 00509026 015F:00508FF3 FFD5 CALL EBP see this line : 015F:00508FE1 8B2D68B15100 MOV EBP,[KERNEL32!CloseProfileUserMapping] its really MOV EBX, DWORD PTR [0051B168], moving an api address from the first IAT we found.. the one thats not their when its unpacked.. securom didnt mess with this, as its not a direct call to the IAT.. well, i unpacked the executable with procdump.. ran it with loader32, and checked out the memory at 51B168, it contained 72981200.. obviously, as this is replaced with the linear address of the api function, this was my 'broken' first thunk.. i searched the unpacked exe for 72981200, and found two places, one just before all the imported function names, and the other one i had found before, further studying of the exe with my hex editor, i located the start of the import table.. the list of my image_import_descriptors, 8 of them, followed by 14h null bytes.. the terminating descriptor :D yippee!! just use procdumps pe editor, edit the directory structure, point the import table to the real one.. for this program, it was 528ed8, - imagebase makes 128ed8.. okay, running it with loader32 again, checking out address 51b168, yes, its been written over with the linear address of the correct api function.. great.. halfway their.. lets code something again.. ;------------------------------------------------------------------------------ ; R!SC's dodgy call fixer for 'newer' securom ; (c) august 27th 1999 risc@notme.com ; tasm32 /mx /m3 /z /q call_fix ; tlink32 -x /Tpe /aa /c call_fix,call_fix ; copy and paste the code into compressed securom executable.. i like the pe header.. ; break on the jmp eax (in the securom code, jmp orig_entry_point) ; recode the 'jmp eax' in the call [securom] code to jmp ebx ; i3here on, faults on ; copy the code to a empty part of memory.. m 400300 l 60 530000, r eip 530000, run it :0 .486P .Model Flat .code main: call @1 ; please excuse my first attempt at kinda relocatable code @1: pop ebx mov esi, ebx add ebx, offset here-offset @1 ; return address from jmp [5ac228] add esi, offset boring-offset @1 mov edx, 401000h mov ecx, 51b000h-401000h ; iat begins at 51b000, so code hopefully ends before it search_loop: cmp [edx], 0c22815ffh ; search pattern for CALL [005AC228] jne try_again cmp word ptr [edx+4],005ah ; - jne try_again lea eax, [edx+6] ; get the address which would be pushed onto the stack pushad push eax ;jmp dword ptr [5ac228h] db 0ffh,25h,28h,0c2h,5ah,0 ; jmp blah.. here: ; k, we return here from securom code, the api address is in EAX mov edx, 51b000h ; start address of my *real* IAT, first thunk.. search_iat: cmp [edx],eax jz got_match inc edx cmp edx, 51b2a0h jne search_iat pop eax ; safty, if it cant find a match for whats in EAX in our IAT popad int 03 ; match wasnt found, break on the int 03, write down the address in EDX jmp try_again ; and fix it by hand.. got_match: mov [esi+4],edx ; save the addr of the import address we got a match for pop eax popad mov eax, [esi+4] ; retrive the address of the import in our IAT mov [edx+2], eax ; paste it over the 005ac228 in the call [securom] try_again: inc edx mov [esi],edx ; store the last addr EDX was on.. (in case of any problems..) dec ecx jne search_loop int 03 nop boring: end main ;------------------------------------------------------------------------------ right, compile it, hex edit it and hex edit the compressed securom exe, cut and paste the code from the call fixer into the securom executable somewhere.. i chose file offset 300h, in the pe header.. run your loader which breaks on the securom exit point. move the code from the pe header to somewhere else.. m 400300 l 100 530000 , r eip 530000.. put a bpx on JMP [005AC228], and run it. when you get a break, trace into the jmp, and scroll your code window until you see some code like this.. 015F:0059F15E 83C408 ADD ESP,08 015F:0059F161 61 POPAD 015F:0059F162 8B45F4 MOV EAX,[EBP-0C] 015F:0059F165 8BF0 MOV ESI,EAX 015F:0059F167 8B06 MOV EAX,[ESI] 015F:0059F169 5F POP EDI 015F:0059F16A 5E POP ESI 015F:0059F16B 5B POP EBX 015F:0059F16C 8BE5 MOV ESP,EBP 015F:0059F16E 5D POP EBP 015F:0059F16F FFE0 JMP EAX then change the jmp eax, which would jmp to the api call, to jmp ebx.. to jump back to our call fixing routine :a 59f16f 0137:0059F16F jmp ebx bc*, i3here on, faults on, cause we wanna trap any errors, and softice to break if it hits either of our int 03's.. welp, anyway, run the code, and cross your fingers.. i got a some errors, three calls returned invalid addresses, so i couldnt find them in my IAT, and two calls caused a crash.. with faults on, softice caught the crash, and all i had to do was look in memory location at the end of my code, where i store the address counter, to see what call crashed it.. 502bdd crashed it, and after fixing that, 50ce1c crashed it, so when i run it again, i edit those memory locations, replacing the FF 15 with CC 15, which stopped the code finding the correct byte pattern, thus stopping the crash, and investigate those calls by hand.. it popped up at this int 03 three times aswell.. int 03 ; match wasnt found, break on the int 03, write down the address in EDX jmp try_again ; and fix it by hand.. just write down the address in edx, and carry on, we can investigate those calls by hand aswell.. bad calls were 507c39, 50a324 & 50e0be, so run the program with your break on the securom exit point, edit the eip to point to one of those dodgy call's, and trace, break on the jmp eax.. and search for the api address in your IAT by hand :D, after all the calls are fixed, dump the memory, pagein 400000 11b000 c:\callsfixed.dat .. copy and paste this into the file you unpacked with procdump, and fixed the IAT address in the pe-header.. cross your fingers, run it :D hey, it works :P thats it!! securom is a bit more fun this time around, but if it wasnt for Pedro and +Xoanon, i doubt this tutorial would have been possible. In the three or so days this crack took me, i have learnt quite a lot, and hopefully, you, have learnt something from it aswell.. R!SC 27th August '99