Here is the solution I sent to crackmes.de, the crackme is easy but really enjoyable. You can find the crackme at http://www.crackmes.de/users/hmx0101/crappy_fun/
Intro
The crackme is packed with an home-made custom packer. When you run the file, the unpacking process starts and when it stops you should have the original file running on your system. This time it doesn’t happen, the crackme crashes. It’s our job to identify the reason behind the crash, and once you have fixed the file you can search for the right serial.
How to locate where the error occours
What the hell causes the crash? This is the main question, but the real problem is: how to locate where the error occours in an easy way?
You can start analysing the file from the beginning to the end, that’s the right way but it can take a lot of time. I prefer to take another way starting from the crash.
As you know, running the file you’ll obtain a crash. The error box doesn’t help me too much because it shows an error offset at 00059a5a, and looking at the original exe file I didn’t get anything useful at that address. I decided to take a look at the crash dump file generated by the OS. The file I’m referring to is named user.dmp and it’s located under Dr Watson folder. It contains the information of the last occourred crash, the one I’m interested to. To retrieve some information from the file you can load it into Windbg. The classical “!analyze -v” will reveal some hidden info (I copy&paste only some lines):
DEFAULT_BUCKET_ID: BAD_INSTRUCTION_PTR LAST_CONTROL_TRANSFER: from 00405bf9 to 00059a5a STACK_TEXT: WARNING: Frame IP not in any known module. Following frames may be wrong. 0013ff98 00405bf9 00000000 5d4d0000 00454fe0 0x59a5a 0013ffbc 00469e0b 7c817067 00390032 00390038 CrappyFun+0x5bf9 00400000 00000000 000f0004 0000ffff 000000b8 CrappyFun+0x69e0b FOLLOWUP_IP: CrappyFun+5bf9 00405bf9 2c50 sub al,50h
- DEFAULT_BUCKET_ID
the DEFAULT_BUCKET_ID field shows the general category of failures that this failure belongs to. The name of the category says it all.
- LAST_CONTROL_TRANSFER
it shows the last call on the stack. In this case, seems like the code at address 0×405Bf9 called a function at 0×59A5A
- STACK_TEXT
it shows a stack trace of the faulting component.
- FOLLOWUP_IP
When !analyze determines the instruction that has probably caused the error, it displays it in the FOLLOWUP_IP field.
I think Windbg is not able to produce a good output, seems like there are some errors inside the output generated by the debugging tool. I don’t think the error occours at 405BF9, I think it occours at the previous instruction which is something like “Call 00059a5a”. I got this idea looking at the STACK_TEXT contents.
Windbg shows the code from the original unpacked file, so if you want to inspect the code around 0×405BF9 you have to dump the exe. You can dump it when the error box appears. Here’s the unpacked snippet:
405BF2 push 0 405BF4 call sub_405B24 405BF9 mov ds:dword_458664, eax 405B24 jmp ds:dword_4591E4 4591E4 dword_4591E4 dd 59A5Ah
Bingo! The error occours inside the call at 405BF4. Now I only have to find out what 0×59A5A represents. If you are using IDA you’ll see:
4591D8 dword_4591D8 dd 59A30h ; DATA XREF: sub_405B3C 4591DC dword_4591DC dd 59A3Eh ; DATA XREF: sub_405B34 4591E0 dword_4591E0 dd 59A4Ch ; DATA XREF: sub_405B2C 4591E4 dword_4591E4 dd 59A5Ah ; DATA XREF: sub_405B24
These addresses are referenced by instructions like:
jmp ds:dword_0045xxxx
It’s pretty obvious now, these are not-resolved functions. That’s why the exe crashes.
Presumably the point to fix resides inside the procedure used to resolve the API. A good and quick way consist of using some clever breakpoints on functions like LoadLibrary/GetProcAddress; after some minutes I got the right point to patch.
This is how I solved the first point (fix the unpacked file). I think it’s the fastest way because you start looking through the loader having in mind what you are looking for.
Before giving out what to patch I’ll spend some words on the loader. I’m writing a solution and I’ll try to give you a sort of detailed analysis of the packer too.
The packer
The packer has a linear loader, it makes everything easy. The loader starts with an RDTSC trick, it’s located inside the first ten lines of code. The check is performed here:
00469C2B CMP EAX,0FFF
00469C30 JNB CrappyFu.00469E04
00469C36 CALL CrappyFu.00469C3B
If the program reveals the presence of a debugger you won’t pass through 469C36. So, if you want to continue studying the exe you firstly have to get rid of this check.
Just after the initial check you can find a decryption loop:
00469C54 MOV EBX,CrappyFu.00469C72 // Initial address 00469C59 MOV ECX,384 // Number of bytes to decrypt 00469C5E MOV AL,9A // 00469C60 XOR BYTE PTR DS:[ECX+EBX],AL // Xor decryption 00469C63 MOV AL,BYTE PTR DS:[ECX+EBX] // Decrypted byte is used to decrypt the next one 00469C66 LOOPD SHORT CrappyFu.00469C60 // Jump up for the next byte to decrypt
The packer’s code was encrypted using a xor operation. When the loop ends you have the packer’s code in front of your eyes, the first thing you should see is an anti debug trick:
00469C68 MOV EAX,DWORD PTR FS:[18] 00469C6F MOV EAX,DWORD PTR DS:[EAX+30] 00469C73 MOVZX EAX,BYTE PTR DS:[EAX+2] 00469C78 CMP EAX,1 00469C7B JE CrappyFu.00469E04
The good old IsBeingDebugged check. You should know how to pass it. It’s the second trick, and if you want to continue analyzing the exe remember to avoid it too. Moreover you’ll have to avoid the next one too:
00469CAA XOR ECX,ECX 00469CAC ADD ECX,10 00469CAF MOV EBX,77FFFFFF 00469CB4 MOV EAX,DWORD PTR FS:[EBX+88000019] // eax = 7FFDE000... fs:[18] 00469CBB MOV EAX,DWORD PTR DS:[EAX+ECX*2+10] // It's IsDebuggerPresent check!!! 00469CBF MOVZX EAX,BYTE PTR DS:[EAX+2] // 00469CC3 NOT EAX 00469CC5 AND EAX,1 00469CC8 MOV EBX,EAX // ebx = 0 if you are debugging the file 00469CCA PUSH 0C3FBF6 // Push a dword value 00469CCF CALL CrappyFu.00469CD4 00469CD4 SUB DWORD PTR SS:[ESP],33 // Fix the return value 00469CD8 MOV ESI,ESP // 00469CDA ADD ESI,4 // esi -> value pushed at 469CCA 00469CDD JMP ESI // jump to esi
A nice antidebug trick. It’s an IsDebuggerPresent check with an unusual check. In the previous check there’s a compare between the value stored inside eax and 1; this time the check is a little bit writhed.
“PUSH 0C3FBF6″ seems like a simple push of a dword value, but if you check carefully the next instructions you’ll discover the real meaning of the dword value:
0012FFC0 F6FB IDIV BL // F6 FB 0012FFC2 C3 RETN // C3 0012FFC3 0069 EB ADD BYTE PTR DS:[ECX-15],CH // 00
The author uses an idiv instruction as a final check, if you are debugging the file bl will be 0 and the idiv instruction will raise an exception. Otherwise, you wont have any error and the packer will proceed without any problems.
The next step performed by the packer is another decryption loop. This time it’s not so easy like the first one we saw at the beginning but it’s not hard to understand how it works. The decryption routine decrypts the code section. The decryption uses a dinamically allocated buffer, allocated using VirtualAlloc; since of I should know where the crash occours I’m not interested in this decryption by now. If you want to check the routine pay attention on the antidebug trick, there’s a breakpoint check.
Ok, we are at the end of the loader. The last part of the code is between 0×469E0B and 469F05 addresses. The snippet starts with:
00469E0B PUSHAD
00469E0C JMP SHORT CrappyFu.00469E12
ending with:
00469EFD PUSH 54FD0 //
00469F02 ADD DWORD PTR SS:[ESP],EBP // I guess oep is at 4054FD0
00469F05 RETN //
However, the code between these two address perform some steps:
- decrypt a lot of strings (again, xor decryption)
- retrieve addresses of API
I’m near the solution. Let’s take a look at the routine used to retrieve the addresses (I removed parts of the code):
00469E85 CMP DWORD PTR DS:[EDX],0 // Is there another address to retrieve? EDX = 0x459118 00469E88 JE SHORT CrappyFu.00469EE3 // No: jump out ... 00469EA7 PUSH EAX // eax -> current function ... 00469EC4 PUSH EBX 00469EC5 CALL ESI // GetProcAddress applied to the current function ... 00469EC9 TEST EAX,EAX // Address ok? 00469ECB JE CrappyFu.00469E04 // Jump if error occours 00469ED1 CMP BYTE PTR DS:[EAX],0CC // Is there a bpx on the first byte of the current function? 00469ED4 JE CrappyFu.00469E04 // Yes: error! 00469EDA JMP SHORT CrappyFu.00469EDE // No: jump... !?! 00469EDC MOV DWORD PTR DS:[EDX],EAX // NOT EXECUTED 00469EDE ADD EDX,4 // Update edx 00469EE1 JMP SHORT CrappyFu.00469E85
Do you remember why the crash occours? The file crashes because there’s a problem with the value stored inside 4591E4. At 469E85 edx has the value 459118, pretty near the address of the suspicious dword. This is a big hint, I’m in front of the bugged code.
The snippet is a classical piece of code used to fix imported functions, there’s only a strange thing inside this snippet; I’m referring to code around 469EDA. What does it happen to the retrieved address? Nothing… it’s simply discarded!
How to fix it?
I decided to nop the jump instruction at 469EDA. I want to change:
00469ED4 0F84 2AFFFFFF JE CrappyFu.00469E04 00469EDA EB 02 JMP SHORT CrappyFu.00469EDE 00469EDC 8902 MOV DWORD PTR DS:[EDX],EAX
into:
00469ED4 0F84 2AFFFFFF JE zai_Crap.00469E04 00469EDA 90 NOP 00469EDB 90 NOP 00469EDC 8902 MOV DWORD PTR DS:[EDX],EAX
Do you remember the initial xor decryption? This is what I have to solve:
Byte to find ^ *key* = decrypted_byte byte_463EDB ^ 0x89 = 0x90 --> byte_463EDB = 0x19 byte_463EDA ^ 0x90 = 0x90 --> byte_463EDA = 0x00 byte_463ED9 ^ 0x90 = 0xFF --> byte_463ED9 = 0x6F
You can modify the original exe file patching the bytes between 463ED9/463EDB with 0×6F, 0×00 and 0×19 (offset 0×334D9/0×334DB). Now I have a working crackme.
Task 2: the right serial
The crackme is a Delphi application, Dede will tell you everything about the file. The serial check routine starts at 0×454C98 (TForm1_Button1Click). It gets the serial, length must be 6 chars long. The main procedure starts from 0×45475C; it’s a really long procedure. I have to say I wanted to give up, but it’s more easy than it seems. There are mainly 3 functions called many times. The functions I’m referring to are Multiply, Add and Sub; here are some snippets taken from the code:
454773 mov dl, [ebp+s_6]
454776 mov ecx, 4
45477B mov eax, 6 // Multiplier
454780 call Multiply // Execute: eax * dl
45480B pop edx
45480C call add // Execute: eax + edx
454821 pop edx
454822 call sub // Execute: eax – edx
Try stepping a little inside the procedure and you’ll surely get the main point of the routine. If yuo have Ida you don’t have to step a single line because you can understandd everything from the dead list.
The entire procedure is used to create a system of linear equations, 6 equations in 6 variables:
1 * s1 + 3 * s2 + 2 * s3 – 3 * s4 – 4 * s5 – 6 * s6 = -453
2 * s1 – 7 * s2 + 3 * s3 + 7 * s4 + 2 * s5 + 1 * s6 = 849
7 * s1 + 9 * s2 – 6 * s3 – 4 * s4 – 6 * s5 + 7 * s6 = -218
5 * s1 + 2 * s2 + 4 * s3 + 2 * s4 + 4 * s5 – 1 * s6 = 1643
3 * s1 – 1 * s2 + 1 * s3 – 1 * s4 + 1 * s5 – 1 * s6 = 192
8 * s1 – 2 * s2 + 1 * s3 + 1 * s4 – 4 * s5 + 1 * s6 = 134
where s1..s6 are the 6 chars from the serial. The final check is done calling 6 functions sequentially. Each function performs 1 check. First function checks 1° equation (it must be equal to -453), 2° function checks 2° equation (it must be equal to 849) and so on…
I think you can easily find out how the checks are done.
Is it possible to solve the system?
Rank is 6, there’s only 1 solution. When I was at uni I was able to solve such systems in a short time, but now I’m a bit rusty. I could use the elementary method: substitution… I preferred to use an automatic engine. The result is:
s1 = 70 : F
s2 = 97 : a
s3 = 105 : i
s4 = 114 : r
s5 = 121 : y
s6 = 33 : !
The right serial is Fairy!
June 16, 2009 at 2:57 pm
I would recommend the antispyware solution from Orbasoft to anyone.
I spent a lot of time searching for a good scanner at an affordable price. I tired many different ones before I found Orbasoft Antispyware but when I tired it I was very happy with the results. I would recommend the antispyware solution from Orbasoft to anyone searching for a great scan that works just as well as Norton and many of the others that you would pay more for. Visit http://www.orbasoft.com to find out more and to give this scan a try just like I did. I’m sure you will love it as much as I do.