ZaiRoN
December 27th, 2006, 16:38
This time the problems arise when you have to change one or more bytes because the entire VM instructions are surrounded by a nasty anti-patch check. I don't describe the VM used in the crackme but I'll focus my attention over the instruction I want to patch, the good/bad boy conditional jump:
Code:
0041562B mov ecx, [ebx+eax] ;
0041562E mov eax, [ebx+50h] ; Take the parameters needed by the current test instruction
00415631 mov edx, [ebx+eax] ;
; Virtual Machine instruction
00415634 xor eax, eax
00415636 cmp ecx, edx ; compare the right and the fake serial
00415638 jnz short loc_41563B ; Jump if serial is not right
0041563A inc eax ; Here if the serial is right
; Store the result into the Virtual Machine
0041563B mov ecx, [ebx+4Ch]
0041563E mov [ebx+ecx], eax
The idea is to patch the conditional jump at 415638 letting it to accept any serial, the new instruction would be:
If you try to patch the instruction the crackme won't run anymore because an exception will occour. As I said before there are some anti-patch checks; the crackme uses the VM instructions in his anti-patch cheching routine and you can't patch the VM's instructions. So, what can I do? The first thing to do is to start looking at the code which lead me to the snippet above:
Code:
0040D8DB mov eax, [esi] ; esi = 41555B
0040D8DD mov ecx, 8
0040D8E2 mov edx, [esi+ecx*4] ; Takes dword from 41557B to 41555F
0040D8E5 xor edx, [ebx+28h] ; [ebx+28h] is updated after each VM instruction
0040D8E8 add edx, [ebx+14h] ; [ebx+14h] = 40CF60, it's always the same value
0040D8EB xor eax, [edx] ; xor eax with a dword taken from the VM data
0040D8ED loop loc_40D8E2 ; The loop is used to find out the offset of the next instruction
0040D8EF pop dword ptr [ebx+28h]
0040D8F2 add eax, [ebx+14h] ; eax = 40CF60 + value_obtained_from_the_loop
0040D8F5 jmp eax ; jump to the check serial snippet
This is the last part of the VM instruction that preceed the check I showed you above. Obviously the snippet above is called many times (because an instruction is called many times

) and each time the loop (40D8E2/40D8ED) extracts the offset of the next instruction. The next instruction address is obtained adding the offset to the base address (which is 40CF60). Well, seems to be unpatchable or atleast very hard to patch but there's a little flow in it.
Maybe you can't patch a byte of a generic VM instruction but you can surely patch something else, I'm talking about the dwords from 41555F to 41557B. Firstly these bytes are not inside a VM instruction, they won't be executed; secondly they are not used in the code, I mean they are not used in the various anti-patch routines. So, I can change them a little. I don't need to change all the bytes, one dword is enough.
The idea is to create a new VM instruction, almost similar to the one I wanted to patch. The new instruction will have:
instead of:
In this way I always pass through the good boy. I'll add the new instruction's bytes starting from address 409704.
Now, let's see how can I do such a change. First of all, it's better to look at the last iteraction of the loop:
Code:
xor edx, [ebx+28h] <-- 24CA1F46 ^ [41555F] = 24CA1F46 ^ 24CA4311 = 5C57
add edx, [ebx+14h] <-- 5C57 + 40CF60 = 412BB7
xor eax, [edx] <------ D8EEEC32 ^ [412BB7] = D8EEEC32 ^ D8EE6AB9 = 868B
add eax, [ebx+14h] <-- 868b + 40CF60 = 4155EB
Ok, this is the normal situation. As I said before the new instruction is at 409704 so if I want to find the new value of [41555F] I have to go backward:
Code:
409704 - 40CF60 = FFFFC7A4
FFFFC7A4 ^ D8EEEC32 = 27112B96 <--- I'll put 0x27112B96 at [409700]. It's the new [412BB7]
409700 - 40CF60 = FFFFC7A0
FFFFC7A0 ^ 24CA1F46 = DB35D8E6 <-- I'll put 0xDB35D8E6 at [41555F]
Crackme solved!