Level : intermediate
~~~~~~~~~~~~~~~~~
Unpacking SecuROM 4.xx
~~~~~~~~~~~~~~~~~
My sister's son brought me yesterday one CD with interactive flash stories for kids. He wanted to watch that on my computer. Since loading of CD material in working memory was slow, I burned image with Nero to my hard drive. I thought that it would be much faster than wait while CD finds right files. But image just wouldn't run. I just cursed it and placed original CD back into drive and I left kid to watch those stories. Today after lunch, I was bored and curious so I decided to throw quick look on original CD. I was pleasantly surprised - main executable was packed by SecuROM.
1. Introduction
I say pleasantly because I never before had in my hands original CD protected with SecuROM. I know that this is old version, but what can I do? But I'm also surprised that Nero 6 couldn't burn working image. I thought that Nero can do that?!? I have some other tools like Alcohol 120%, Dameon tools, but I don't have experience with burning these kind of software. I just don't play these new games that comes on CD-DVD (I like emulators, you know; MAME, WinUAE, ZNES, etc.). Ok, let's start I'm writing this tutorial while unpacking so it won't go into depth of SecuROM. Hell I even don't know will I finish it! Maybe I will fail to unpack SecuROM I hope not. Let's go!
The CD name is CROTALES and it contains Croatian tales from known writer (in Croatia) Ivana Brlic-Mazuranic. I doubt that readers of this tutorial will find this CD somewhere, but protector was used allot in games from 2-3 years ago (2003-2004). I think that current version of SecuROM is 7. CD contains .swf files and one executable file START.EXE. That file is nothing more than macromedia flash player protected with SecuROM. Cracking this CD is not hard, we can play .swf files in any browser. But we are interested in SecuROM.
First information I got from PEID 0.94:
SecuROM 4.x.x.x - 5.x.x.x -> Sony DADC [Overlay]
If you are interested in exact version, you can use Yates SecuROM/SafeDisc version detector (for older versions):
SecuROM - 4.84.00 0001
Or you could manually search for version information. With some hex editor, search for "AddD" string in file:
0017A000 41 64 64 44 03 00 00 00 34 2E 38 34 2E 30 30 00 AddD...4.84.00.
0017A010 30 30 30 31 A2 20 19 27 C8 27 A3 2C F2 2D 1E 3D 0001˘.'Č'Ł,ň-=
How image looks in memory? Let's see:
Memory map
Address Size Owner Section Contains Type Access Initial Mapped as
00400000 00001000 START PE header Imag R RWE
00401000 00097000 START .text code Imag R RWE
00498000 0000B000 START .rdata code Imag R RWE
004A3000 000D0000 START .data code Imag R RWE
00573000 00001000 START .data1 data Imag R RWE
00574000 00001000 START .CRT Imag R RWE
00575000 00031000 START .cms_t SFX Imag R RWE
005A6000 0007E000 START .cms_d Imag R RWE
00624000 00003000 START .idata imports Imag R RWE
00627000 00016000 START .rsrc resources Imag R RWE
Obviously protector's sections are .data1, .CRT, .cms_t and .idata. EP of protector code looks like common MSVC++ 6.0 OEP:
0059C490 > 55 PUSH EBP
0059C491 8BEC MOV EBP,ESP
0059C493 6A FF PUSH -1
0059C495 68 48A26000 PUSH START.0060A248
0059C49A 68 24C25900 PUSH START.0059C224
0059C49F 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
0059C4A5 50 PUSH EAX
0059C4A6 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
0059C4AD 83EC 58 SUB ESP,58
0059C4B0 53 PUSH EBX
0059C4B1 56 PUSH ESI
0059C4B2 57 PUSH EDI ; ntdll.7C910738
0059C4B3 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
0059C4B6 FF15 EC476200 CALL DWORD PTR DS:[<&kernel32.GetVersion>; kernel32.GetVersion
0059C4BC 33D2 XOR EDX,EDX ; ntdll.KiFastSystemCallRet
0059C4BE 8AD4 MOV DL,AH
0059C4C0 8915 10766100 MOV DWORD PTR DS:[617610],EDX ; ntdll.KiFastSystemCallRet
0059C4C6 8BC8 MOV ECX,EAX
0059C4C8 81E1 FF000000 AND ECX,0FF
0059C4CE 890D 0C766100 MOV DWORD PTR DS:[61760C],ECX
0059C4D4 C1E1 08 SHL ECX,8
0059C4D7 03CA ADD ECX,EDX ; ntdll.KiFastSystemCallRet
0059C4D9 890D 08766100 MOV DWORD PTR DS:[617608],ECX
0059C4DF C1E8 10 SHR EAX,10
0059C4E2 A3 04766100 MOV DWORD PTR DS:[617604],EAX
0059C4E7 33F6 XOR ESI,ESI
0059C4E9 56 PUSH ESI
0059C4EA E8 E5120000 CALL START.0059D7D4
...
...
If we take a look in the first section (where it should be original EP) we can see that section is not encrypted. SecuROM protection consist from CD check, OEP code encryption and import protection. It is not hard to fool SecuROM so it thinks that CD is inside, but that is useless. SecuROM needs some information stored on CD that will decrypt OEP code! And that information cannot be read and copied to another CD, or to hard drive (there my Nero 6 failed). To crack SecuROM we need original CD. So I pushed back CD into drive.
2. Finding OEP and decrypting
This is very easy thing to do if we have original CD. These versions of SecuROM are CD copy protections. They doesn't have anti-debug tricks so decrypting OEP code and breaking there is a joke. To quick find OEP, I placed bp on GetDriveTypeA. After stopping, it resumed in new loaded DLL (DLL extracted in temp folder). I was here:
2000110D 66:3D 0500 CMP AX,5
20001111 75 0F JNZ SHORT sintfnt.20001122
20001113 8B4C24 28 MOV ECX,DWORD PTR SS:[ESP+28] ; START.0061A520
20001117 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24] ; START.006215D0
2000111B 8919 MOV DWORD PTR DS:[ECX],EBX
2000111D 8B08 MOV ECX,DWORD PTR DS:[EAX]
2000111F 41 INC ECX
20001120 8908 MOV DWORD PTR DS:[EAX],ECX
20001122 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10]
20001126 D1E9 SHR ECX,1
20001128 4B DEC EBX
20001129 894C24 10 MOV DWORD PTR SS:[ESP+10],ECX
2000112D ^79 8F JNS SHORT sintfnt.200010BE
2000112F 8B5424 24 MOV EDX,DWORD PTR SS:[ESP+24] ; START.006215D0
20001133 33C0 XOR EAX,EAX
20001135 5F POP EDI ; START.00403000
20001136 5E POP ESI ; START.00403000
20001137 8B0A MOV ECX,DWORD PTR DS:[EDX]
20001139 5D POP EBP ; START.00403000
2000113A 85C9 TEST ECX,ECX
2000113C 0F9FC0 SETG AL
2000113F 5B POP EBX ; START.00403000
20001140 83C4 10 ADD ESP,10
20001143 C2 0800 RETN 8
After RETN 8 I was here, back in START.EXE:
00582994 85C0 TEST EAX,EAX
00582996 75 3B JNZ SHORT START.005829D3
00582998 FF15 F4A76100 CALL DWORD PTR DS:[61A7F4] ; sintfnt.FGDM32
0058299E 833D C4C35C00 00 CMP DWORD PTR DS:[5CC3C4],0
005829A5 74 1E JE SHORT START.005829C5
005829A7 68 94216000 PUSH START.00602194 ; ASCII "70015A56C550882901D183BCD7CDD288E72EC775B8161D9AB F56"
005829AC 68 C0F26100 PUSH START.0061F2C0
005829B1 E8 7F800100 CALL START.0059AA35
005829B6 83C4 08 ADD ESP,8
005829B9 68 C0F26100 PUSH START.0061F2C0
005829BE 6A 20 PUSH 20
005829C0 E8 EB3DFFFF CALL START.005767B0
005829C5 6A 01 PUSH 1
005829C7 E8 342DFFFF CALL START.00575700
005829CC 6A 01 PUSH 1
005829CE E8 4B7C0100 CALL START.0059A61E
005829D3 833D C4C35C00 00 CMP DWORD PTR DS:[5CC3C4],0
005829DA 74 2E JE SHORT START.00582A0A
This version of SecuROM has easy to spot OEP jump. Scrolling down couple pages I sow it:
00582EB6 B8 A0704600 MOV EAX,START.004670A0
00582EBB 90 NOP
00582EBC 90 NOP
00582EBD 50 PUSH EAX
00582EBE EB 08 JMP SHORT START.00582EC8
00582EC0 58 POP EAX
00582EC1 A1 38946100 MOV EAX,DWORD PTR DS:[619438]
00582EC6 -FFE0 JMP EAX ; Can it be more obvious !?!
00582EC8 A3 38946100 MOV DWORD PTR DS:[619438],EAX
00582ECD A3 40C96100 MOV DWORD PTR DS:[61C940],EAX
00582ED2 833D CC746100 00 CMP DWORD PTR DS:[6174CC],0
00582ED9 74 19 JE SHORT START.00582EF4
00582EDB A1 6EBE6100 MOV EAX,DWORD PTR DS:[61BE6E]
00582EE0 83E0 02 AND EAX,2
00582EE3 85C0 TEST EAX,EAX
00582EE5 74 0D JE SHORT START.00582EF4
OEP of this file looks pretty weird:
004670A0 . 83EC 44 SUB ESP,44
004670A3 . 56 PUSH ESI ; START.00404120
004670A4 . FF15 609E5A00 CALL DWORD PTR DS:[5A9E60] ; START.0057D010
004670AA . 8BF0 MOV ESI,EAX ; START.004670A0
004670AC . 8A06 MOV AL,BYTE PTR DS:[ESI]
004670AE . 3C 22 CMP AL,22
004670B0 . 75 1C JNZ SHORT START.004670CE
004670B2 . 8A46 01 MOV AL,BYTE PTR DS:[ESI+1]
004670B5 . 46 INC ESI ; START.00404120
004670B6 . 3C 22 CMP AL,22
004670B8 . 74 0C JE SHORT START.004670C6
004670BA > 84C0 TEST AL,AL
004670BC . 74 08 JE SHORT START.004670C6
004670BE . 8A46 01 MOV AL,BYTE PTR DS:[ESI+1]
004670C1 . 46 INC ESI ; START.00404120
004670C2 . 3C 22 CMP AL,22
004670C4 .^75 F4 JNZ SHORT START.004670BA
004670C6 > 803E 22 CMP BYTE PTR DS:[ESI],22
004670C9 . 75 0F JNZ SHORT START.004670DA
004670CB . 46 INC ESI ; START.00404120
004670CC . EB 0C JMP SHORT START.004670DA
004670CE > 3C 20 CMP AL,20
004670D0 . 7E 08 JLE SHORT START.004670DA
004670D2 > 8A46 01 MOV AL,BYTE PTR DS:[ESI+1]
004670D5 . 46 INC ESI ; START.00404120
004670D6 . 3C 20 CMP AL,20
004670D8 .^7F F8 JG SHORT START.004670D2
004670DA > 8A06 MOV AL,BYTE PTR DS:[ESI]
004670DC . 84C0 TEST AL,AL
004670DE . 74 0C JE SHORT START.004670EC
004670E0 > 3C 20 CMP AL,20
004670E2 . 7F 08 JG SHORT START.004670EC
004670E4 . 8A46 01 MOV AL,BYTE PTR DS:[ESI+1]
004670E7 . 46 INC ESI ; START.00404120
004670E8 . 84C0 TEST AL,AL
004670EA .^75 F4 JNZ SHORT START.004670E0
004670EC > 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4]
004670F0 . C74424 30 0000>MOV DWORD PTR SS:[ESP+30],0
004670F8 . 50 PUSH EAX ; START.004670A0
004670F9 . FF15 609E5A00 CALL DWORD PTR DS:[5A9E60] ; START.0057D010
004670FF . F64424 30 01 TEST BYTE PTR SS:[ESP+30],1
00467104 . 74 0B JE SHORT START.00467111
00467106 . 8B4424 34 MOV EAX,DWORD PTR SS:[ESP+34]
0046710A . 25 FFFF0000 AND EAX,0FFFF
0046710F . EB 05 JMP SHORT START.00467116
00467111 > B8 0A000000 MOV EAX,0A
3. Imports
More than half of imports in main executable now leads to same address. For example, first import that will be triggered:
004670A4 . FF15 609E5A00 CALL DWORD PTR DS:[5A9E60] ; START.0057D010
Protection used is just custom function that calculates what import should be triggered from a specified offset. It seams that it doesn't need original CD to be in drive for this. I didn't go in details. After tracing into that call, I scrolled down couple pages again and found one (of two) JMP EAX that jumps to correct import:
0057D010 55 PUSH EBP
0057D011 8BEC MOV EBP,ESP
0057D013 81EC B4000000 SUB ESP,0B4
0057D019 53 PUSH EBX
0057D01A 56 PUSH ESI ; START.00404120
0057D01B 57 PUSH EDI ; START.00403000
0057D01C 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX ; START.004670A0
0057D01F 895D A4 MOV DWORD PTR SS:[EBP-5C],EBX
0057D022 894D 8C MOV DWORD PTR SS:[EBP-74],ECX
0057D025 8955 EC MOV DWORD PTR SS:[EBP-14],EDX ; ntdll.KiFastSystemCallRet
0057D028 8975 84 MOV DWORD PTR SS:[EBP-7C],ESI ; START.00404120
0057D02B 897D E8 MOV DWORD PTR SS:[EBP-18],EDI ; START.00403000
0057D02E 896D F4 MOV DWORD PTR SS:[EBP-C],EBP
0057D031 8965 C4 MOV DWORD PTR SS:[EBP-3C],ESP
0057D034 8B45 04 MOV EAX,DWORD PTR SS:[EBP+4] ; START.0059C55E
0057D037 8945 A8 MOV DWORD PTR SS:[EBP-58],EAX ; START.004670A0
0057D03A 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; START.00400000
0057D03D 8945 90 MOV DWORD PTR SS:[EBP-70],EAX ; START.004670A0
0057D040 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C]
0057D043 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX ; START.004670A0
0057D046 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
0057D049 8945 DC MOV DWORD PTR SS:[EBP-24],EAX ; START.004670A0
0057D04C 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
0057D04F 8945 B4 MOV DWORD PTR SS:[EBP-4C],EAX ; START.004670A0
0057D052 8B45 18 MOV EAX,DWORD PTR SS:[EBP+18] ; ntdll.7C910738
0057D055 8945 D0 MOV DWORD PTR SS:[EBP-30],EAX ; START.004670A0
0057D058 833D 2C736100 00 CMP DWORD PTR DS:[61732C],0
0057D05F 75 09 JNZ SHORT START.0057D06A
0057D061 833D 30736100 00 CMP DWORD PTR DS:[617330],0
0057D068 74 18 JE SHORT START.0057D082
0057D06A A1 28736100 MOV EAX,DWORD PTR DS:[617328]
0057D06F 83E8 01 SUB EAX,1
0057D072 A3 28736100 MOV DWORD PTR DS:[617328],EAX ; START.004670A0
0057D077 833D 28736100 00 CMP DWORD PTR DS:[617328],0
0057D07E 7F 02 JG SHORT START.0057D082
0057D080 -FFE0 JMP EAX ; START.004670A0
0057D082 8B45 04 MOV EAX,DWORD PTR SS:[EBP+4] ; START.0059C55E
0057D085 8945 C8 MOV DWORD PTR SS:[EBP-38],EAX ; START.004670A0
0057D088 60 PUSHAD
0057D089 68 00AD6100 PUSH START.0061AD00
0057D08E FF15 D0D66100 CALL DWORD PTR DS:[61D6D0] ; ntdll.RtlEnterCriticalSection
0057D094 C745 A0 00000000 MOV DWORD PTR SS:[EBP-60],0
0057D09B EB 09 JMP SHORT START.0057D0A6
...
scroooooooolling down
...
0057DD08 50 PUSH EAX ; START.004670A0
0057DD09 8B4D D8 MOV ECX,DWORD PTR SS:[EBP-28] ; ntdll.7C910738
0057DD0C 51 PUSH ECX
0057DD0D E8 7EF2FFFF CALL START.0057CF90
0057DD12 61 POPAD
0057DD13 8B45 CC MOV EAX,DWORD PTR SS:[EBP-34] ; ntdll.7C97E4C0
0057DD16 8BF0 MOV ESI,EAX ; START.004670A0
0057DD18 8B06 MOV EAX,DWORD PTR DS:[ESI]
0057DD1A 5F POP EDI ; 0012FFB0
0057DD1B 5E POP ESI ; 0012FFB0
0057DD1C 5B POP EBX ; 0012FFB0
0057DD1D 8BE5 MOV ESP,EBP
0057DD1F 5D POP EBP ; 0012FFB0
0057DD20 -FFE0 JMP EAX ; Jump to import!!!
0057DD22 6A 00 PUSH 0
...
I'm not sure, but maybe there is some timer check inside. My target crushed on some exception after pausing olly, but if I just run it within Olly (after reaching OEP) it runs fine.
Imports that are not redirected point to original IAT section:
00497DB0 $-FF25 10844900 JMP DWORD PTR DS:[498410] ; comdlg32.GetOpenFileNameA
We can see that IAT is filled with good imports:
00498000 F0 6B DD 77 83 78 DD 77 1B 76 DD 77 49 6F DE 77 .k.w.x.w.v.wIo.w
00498010 BB D5 DF 77 E7 EB DD 77 00 00 00 00 B9 45 F4 77 ...w...w.....E.w
00498020 E4 68 F1 77 D5 5F F1 77 4B 4C F2 77 84 48 F4 77 .h.w._.wKL.w.H.w
00498030 7C F7 F1 77 F7 47 F4 77 CB 4C F2 77 00 65 F2 77 |..w.G.w.L.w.e.w
...
cut
...
00498410 1E 31 3B 76 D8 7C 3C 76 CD 46 3D 76 00 00 00 00 .1;v.|<v.F=v....
00498420 D3 85 52 77 C0 41 4F 77 09 60 52 77 E0 D1 52 77 ..Rw.AOw.`Rw..Rw
00498430 68 20 4F 77 4C 20 4F 77 00 00 00 00 h OwL Ow....
And that ordinals and names are not destroyed:
004A0F30 A4 0F 0A 00 00 00 00 00 57 53 4F 43 4B 33 32 2E ........WSOCK32.
004A0F40 64 6C 6C 00 0F 00 43 6F 43 72 65 61 74 65 49 6E dll...CoCreateIn
004A0F50 73 74 61 6E 63 65 00 00 31 00 43 6F 49 6E 69 74 stance..1.CoInit
004A0F60 69 61 6C 69 7A 65 00 00 59 00 43 6F 55 6E 69 6E ialize..Y.CoUnin
004A0F70 69 74 69 61 6C 69 7A 65 00 00 1B 00 43 6F 46 72 itialize....CoFr
004A0F80 65 65 55 6E 75 73 65 64 4C 69 62 72 61 72 69 65 eeUnusedLibrarie
...
cut
...
004A2030 00 00 9D 00 77 61 76 65 49 6E 43 6C 6F 73 65 00 ....waveInClose.
004A2040 AB 00 77 61 76 65 49 6E 55 6E 70 72 65 70 61 72 ..waveInUnprepar
004A2050 65 48 65 61 64 65 72 00 A8 00 77 61 76 65 49 6E eHeader...waveIn
004A2060 52 65 73 65 74 00 57 49 4E 4D 4D 2E 64 6C 6C 00 Reset.WINMM.dll.
Probably IMAGE_IMPORT_DESCRYPTORS are also untouched. That is very sloppy work by SecuROM because it makes easier IAT rebuilding. I wrote script that finds all calls to import algo , places EIP value there, runs, stops on JMP EAX, grabs import , search for that import in IAT, and then it change CALL destination to that import in IAT. But SecuROM maybe has some trick because target was crushing multiple times so I had to rebuild imports part-by-part. But After I have done with restoring calls, I dumped file to disk, then I used ImpREC to create new IAT. We could even repair IAT without ImpREC, but that would take more time. SecuROM uses WriteProcessMemory to write imports in IAT.
4. Fixing dump
After dumping and using ImpREC I double clicked on dumped file. Macromedia player window opened, but it just stud there without running stories. That is no wonder since macromedia files have overlay. Overlay is some extra data attached at the end of file. That data is not loaded in memory because that data is not registered in PE header as a part of last section. Overlay is usual thing with macromedia files. Since ImpREC created new last section, macromedia player cannot find overlay data (which is now before last section). To fix this problem we need just to attach overlay back at the end of file. How to do it? You calculate size of that overlay, then you use hex editor to copy and paste it at the end of file. Or you can just attach whole original file back to the end of dumped one. After I fixed overlay problem, I double clicked on dump and it worked just fine And wow, do you know how faster it runs without SecuROM layer ?!? Much faster because SecuROM must unpack temp files, load couple dlls, pass protection layer, pass that import algo, but searching and reading special data on CD is the slowest part.
5. The End
Btw, SecuROM has created couple DLL's in temp file. They are packed with PEtite except 16-bit file which is packed with PKLITE:
CmdLineExt02.dll
SIntf16.dll
SIntf32.dll
SIntfNT.dll
In some versions this files can be found in windowssystem32 folder. Don't know purpose of these files (I didn't waste time on them).
And that was my first SecuROM unpacking. It was not hard , I guess that newer versions are harder. The most interesting part of SecuROM should be that "unreadable" data on disc, but I needed to return CD so I just find the quickest way to remove protection.