"CD-Cops v1.76" |
Published by Tsehp |
|
Tools:
|
It is another ready made CD protection. Actually I spent a lot of time on this protection. Unpacking it, was very hard for me.It has a lot of debugger checks exceptions etc. However, 2 weeks ago I have started to think with fresh mind and here it is complete code for unpacking.
|
There is a superb essay about CD-Cops by mcLallo it helped me so much to understand the basics of this protection. I suggest you to read it first before looking this tutorial. Most of the info he said is still true at least in v1.75. We will try to unpack Vitamin Lise which is protected by CD-Cops v1.76.In its Kur/Dao folder it has three important files which are CD-Cops file.
il.HEL renamed 16 bit NE file il.W_X renamed 32bit PE file il.QZ_ renamed 32bit PE file
They execute il.HEL file with CreateProcess, then il.HEL file do main CD checks.il.HEL do all protection when everything is OK i.e. serial, CD layout, no debugger, .. it creates a registry entry according to result of timeGetTime and it runs .il.QZ_ with command parameter which is based on result of GetTickCount. For detailed information about this please look at mcLallo's essay. il.QZ_ file then push il.W_X and use CreateProcess api.After it comes below nice routine.
loc_40EEEB: ; CODE XREF: sub_40EEBC+53j ; sub_40EEBC+57j ... push 0FFFFFFFFh ; dwMilliseconds lea eax, [esp+64h+dwProcessId] push eax ; lpDebugEvent call WaitForDebugEvent neg eax sbb eax, eax neg eax cmp ds:byte_411774, 0 jz short loc_40EF11 test al, al jnz short loc_40EF11 call sub_40ED4C jmp short loc_40EEEB ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ loc_40EF11: ; CODE XREF: sub_40EEBC+48j ; sub_40EEBC+4Cj test al, al jz short loc_40EEEB mov eax, esp ; call sub_40EDA0 ;decryption proc cmp [ESP+60h+dwProcessId], 5 jnz short loc_40EF3D dec ds:dword_4105C4 cmp ds:dword_4105C4, 0 jz short loc_40EF4F mov edx, [ESP+4] cmp edx, ds:dword_41177C jz short loc_40EF4F loc_40EF3D: ; CODE XREF: sub_40EEBC+64j push eax ; dwContinueStatus mov eax, [ESP+0Ch] push eax ; dwThreadId mov eax, [ESP+0Ch] push eax ; dwProcessId call ContinueDebugEvent ;When this function runs, program runs jmp short loc_40EEEB
In order to dump this, you can bpx on WaitFordebugEvent and you can dump it before calling ContinueDebugEvent api.You will have virgin executable. I thought that maybe api hooking can be done but as I said earlier il.HEL is 16 bit NE file and all api hook stuff I know works on PE files.I then thought that maybe I can write some program which do same job like il.HEL and run il.QZ_ but unfortunately commandline parameter is based on some constant which is different for every CD-Cops protected exe and it is crypted in exe. Only solution I can think of is to put Global Hook which cant be unloaded until you restart like SafeHard example in EliCZ's ApiHook library.You can hook ContinueDebugEvent api.You will have processid,threadid.You can suspendthread and readprocess memory to some allocated memory and write it back to disk.
So, I started to trace what sub_40EDA0 function do. I have traced it, and it always crashed. I am not familiar with antidebugging and exception stuff so I don't know what was happened. So how this program decrypt .W_X file It must use some file apis or some process apis like ReadProcessMemory, WriteProcessMemory. I have but bpx on ReadProcessMemory.It stopped when I look to the buffer I saw that it reads all sections and check their names.Then it read first section which was .text to memory and compared is name to .text and CODE. After this comparison.It read all .text section to virtually allocated memory.
I started to trace very closely because we are very close to unpacking rutine.After a while I saw this
017F:0040EC1F B810064100 MOV EAX,00410610 017F:0040EC24 8B0D0C064100 MOV ECX,[0041060C] 017F:0040EC2A 8A18 MOV BL,[EAX] 017F:0040EC2C 80F35A XOR BL,5A 017F:0040EC2F 885C11FF MOV [EDX+ECX-01],BL 017F:0040EC33 42 INC EDX 017F:0040EC34 40 INC EAX 017F:0040EC35 83FA4A CMP EDX,4A 017F:0040EC38 75EA JNZ 0040EC24 017F:0040EC3A 53 PUSH EBX 017F:0040EC3B 56 PUSH ESI 017F:0040EC3C 57 PUSH EDI 017F:0040EC3D 8B75FC MOV ESI,[EBP-04] 017F:0040EC40 0335E0184100 ADD ESI,[004118E0] ;allocated mem 017F:0040EC46 8B15D8054100 MOV EDX,[004105D8] ;0 ? 017F:0040EC4C 8B3D081A4100 MOV EDI,[00411A08] ;imgbase 017F:0040EC52 033DF4174100 ADD EDI,[004117F4] ;virt offset of code 017F:0040EC58 033DE0184100 ADD EDI,[004118E0] ;0 ? 017F:0040EC5E 8B0DE4184100 MOV ECX,[004118E4] ;code size 017F:0040EC64 E32F JECXZ 0040EC95 017F:0040EC66 8B05E8194100 MOV EAX,[004119E8] ;some constant 017F:0040EC6C 83050C06410002 ADD DWORD PTR [0041060C],02 017F:0040EC73 55 PUSH EBP 017F:0040EC74 BD04000000 MOV EBP,00000004 017F:0040EC79 FF150C064100 CALL [0041060C] ;Here is code unpacking rutine ..When you trace in to this you will see below MOV EBX,0FFFFFFFFh OR EDX,EDX JZ LOC_00B78AA6 LOC_00B78A9B: CMP EDI,[EDX] JBE LOC_00B78AA4 ADD EDX,04 JMP LOC_00B78A9B LOC_00B78AA4: MOV EBX,[EDX] LOC_00B78AA6: CMP EDI,EBX JZ LOC_00B78ABC ADD [ESI],AL ROR BYTE PTR [ESI],1 XOR EAX,EDI ROL EAX,1 JB LOC_00B78AB6 SUB AH,AL LOC_00B78AB6: INC ESI INC EDI LOOP LOC_00B78AA6 JMP LOC_00B78AD8 LOC_00B78ABC: ROR AL,1 JAE LOC_00B78AC6 SUB AL,98h XOR AL,01Ch JMP LOC_00B78ACC LOC_00B78AC6: XOR AH,0C3h SUB AH,0AFh LOC_00B78ACC: ADD ESI,EBP ADD EDI,EBP ADD EDX,EBP MOV EBX,[EDX] SUB ECX,EBP LOC_00B78AD8: ret
Everything is clear but a constant at 4119E8. I have run target again and put bpm on this memory location.At first break I saw this
mov ds:dword_4119E8, eax mov eax, ds:dword_4119E8 ;MZ header of QZ_ file add eax, 80h ;+80h mov ds:dword_411A58, eax mov edx, ds:dword_411A58 ;This are points to famous product string SEBIT_XXXX mov eax, [edx] ;take word xor eax, 72A96FB3h ; ror eax, 7 add eax, [edx+4] neg eax sub eax, [edx+2] mov ds:dword_4119EC, eax
I thought where this constant comes from but it was false alarm.I think it is some kind of checksum.After that point it reads .CRC key from registry and I guess it compares this two hash. At second brake I saw this
mov ds:dword_4119E8, eax
eax was the string which was put in the registry by il.HEL At third break I saw this
call sub_40D984 and eax, 0FFFF00FFh mov ds:dword_411A64, eax ;another mystery mov eax, ds:dword_411A60 ;this is the result of WinMM.timeGetTime movzx edx, word ptr ds:dword_4119E8 ;string at .CRCreg key sub eax, edx shr eax, 10h movzx edx, word ptr ds:dword_4119E8+2 xor eax, edx movzx eax, ax ; this was always same for me. xor eax, ds:dword_411A64 mov ds:dword_4119E8, eax
If you read mcLallo's essay, created registry string is based on timegettime function and product checksum which is the addition of all chars.So actually a number at dword_4119E8 is equal to dword_411A64 xor product checksum.We know how to calculate checksum let's find where dword_411A64 comes from. If you trace into sub_40D984 function you will see this
push eax ; lpFindFileData mov eax, edi call sub_403974 push eax ; lpFileName points to il.W_X file call FindFirstFileA mov esi, eax mov [ebx+14h], esi cmp esi, 0FFFFFFFFh jz short loc_406BC4 ;file not exist mov eax, ebx call sub_406B20 ;trace into this function ...... loc_406B40: ; CODE XREF: sub_406B20+6j ; sub_406B20+17j mov eax, [ebx+18h] and eax, [ebx+10h] jnz short loc_406B28 push ESP ; lpLocalFileTime lea eax, [ebx+2Ch] push eax ; lpFileTime call FileTimeToLocalFileTime push ebx ; lpFatTime lea eax, [ebx+2] push eax ; lpFatDate lea eax, [ESP+10h+FileTime] push eax ; lpFileTime call FileTimeToDosDateTime
So it searchs w_x file and use date of files as encryption keys.At this point we know how to unpack code section let's go to .data section
Again but bpx on ReadProcessMemory and stop when Data section is read to virtually allocated memory.After very short period of time you will see this.
017F:0040EACC 8B55FC MOV EDX,[EBP-04] ;data offset 017F:0040EACF 8B4DF8 MOV ECX,[EBP-08] ;data size 017F:0040EAD2 D1E9 SHR ECX,1 017F:0040EAD4 E320 JECXZ 0040EAF6 017F:0040EAD6 0FB705461A4100 MOVZX EAX,WORD PTR [00411A46] ;data key 017F:0040EADD 2802 SUB [EDX],AL 017F:0040EADF C0C404 ROL AH,04 017F:0040EAE2 006201 ADD [EDX+01],AH 017F:0040EAE5 C0C404 ROL AH,04 017F:0040EAE8 663102 XOR [EDX],AX 017F:0040EAEB 66D1C0 ROL AX,1 017F:0040EAEE 7302 JAE 0040EAF2 017F:0040EAF0 00C4 ADD AH,AL 017F:0040EAF2 42 INC EDX 017F:0040EAF3 42 INC EDX 017F:0040EAF4 E2E7 LOOP 0040EADD
Where this data key comes ? This time it comes from the exe it self.It is the NumberOfLinenumbers of data section.
OK we know how to decrypt code and data section what come next ? yes finding OEP.Fortunately IAT is not crypted.We again put bpx on ReadProcessMemory and trace it. We are looking something which changes our OEP when OEP is read to memory put bpm on this memory location.You will see something like below
mov edx, ds:dword_4117A0 ;memlocation MZ+20h not edx ;not mov eax, ds:dword_41179C cmp edx, eax jz short loc_40E872 mov eax, ds:dword_411A4C mov ds:dword_411A50, eax jmp short loc_40E882 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ loc_40E872: ; CODE XREF: CODE:0040E864j xor eax, 5A5A5A5Ah ;xor it we have OEP now! add eax, ds:dword_411778 ;add to imagebase.
Ok at this point we know all information to write our unpacker.I have written one and you can download from here. It has source in it. Beware that my coding style is very bad.If you find any error or bugs please let me know.Also if you find other versions unpack and OEP rutines please notify me. Thanks
Greetings:First of all, renaTgaD,MbR, and my group mates,CYDONIA,Iczelion, +Tsehp, +Splaj, Kayaker, and all great guys on RCE board, my old friends at PNC and PGC, Daemon,The Unknown One and all unpacker authors who are kind to release sources.