A few days ago, I did the Morph crackme of Crackmes.de. Morph is a 32 bits windows executable (Visual C++).
Morph: PE32 executable (console) Intel 80386, for MS Windows
The function _main begins in a strange manner:
.text:00401863 push esi .text:00401864 nop .text:00401865 nop .text:00401866 nop ... .text:00401880 nop .text:00401881 nop .text:00401882 pop esi
Actually Morph contains a lots of junk code like this, I just ignored them while debugging. Then I arrived at a switch of 22 cases. ds:off_402D8C contains a list of offsets that point to different parts of code. Each part of code pushes a character on the stack and print it. This is how 'What is the password?' is printed.
VirtualProtect has four parameters. Here the 7th letter of password is used to created the second parameter 'dwSize' that defines the memory size for function VirutalProtect. If this size exceeds program limit, VirtualProtect will fail and return 0. Otherwise, VirtualProtect returns 1. We need that VirtualProtect returns 1 in order to continue code execution. So I know password[6] is equal or smaller than 'E'.
At this part, we arrive at the core of Morph. Morph contains many numbers of dead codes.
.text:004014F3 push edx .text:004014F3 ; .text:004014F4 db 0CCh ; ¦ .text:004014F5 db 0CCh ; ¦ ...... .text:00401511 db 0CCh ; ¦ .text:00401512 ; .text:00401512 pop edx
The dead code begins with 'push edx' and ends with 'pop edx'. Once Morph have found a chunck of dead code, it will call the decode function at address 0x401170. This function call _rand to generate random number. srand is called previously with time() as parameter. There is no vuln for random generation. One random number is used to alter decoded code.
call _rand mov ebx, eax and ebx, 80000003h ; %4
ebx contains random_number%4. The first byte of dead code is the effective address of ebx+50h. Only four values are possilbe: 50h -> push eax, 51h -> push ebx, 52h -> push ecx, 53h -> push edx. The last byte of dead codes is bl+ 58h that is pop eax, ebx, ecx, or edx. This is the very wise part of Morph, as its name indicates, even with correct password, it can have four different versions. I have a conclusion that wherever ebx(or bl) apprears, the decoded instructions must have something to do with eax, ebx, ecx, edx.
[edi+5] is the 6th letter of the password. This must generate a pair of push and pop and I've password[5]='D'. When I go over these dead codes, some tips are left.
pw_cp and pw_cp2 are respectively the first and second word of password. So we can see that password[2] must be equal to password[5]. Great, now I know password[2]=password[5]='D'. Later I figure that we can know for sure that password[5]='D':
We have password[4]='O' and password[3]='M'. If you enter a password ('??DMODE')that passes all above checks, the program will crash unless you have the correct password. There are still the first and second letter that are unknown. In the following loop, the process of decoding is random. At the left side, password[4]='O' is used and unpacked code can be dec eax, ebx, ecx or edx. At the right side, I suppose that it will have the reverse operation of dec, that is inc. So password[0]='G'. Until now there is only one letter left 'G?DMODE'. It didn't find out logically the second letter. However, the pattern 'G?DMODE' looks like 'GODMODE' and with a great chance, my guess was correct!
With the correct password, I figured out the trick of the second letter. This letter was used to generate the opcode 'CMP eax (ebx, ecx, or edx), 10h' whose size is three bytes. Finally one version of the decoded dead code is:
.text:00401FA7 push edx .text:00401FA8 mov edx, offset $LN26 .text:00401FAD cmp edx, 10h .text:00401FB0 jz near ptr 8050B8h ; it never jmp .text:00401FB6 push edx .text:00401FB7 inc edx .text:00401FB8 inc edx .text:00401FB9 inc edx .text:00401FBA inc edx .text:00401FBB inc edx .text:00401FBC dec edx .text:00401FBD inc edx .text:00401FBE dec edx .text:00401FBF dec edx .text:00401FC0 dec edx .text:00401FC1 inc edx .text:00401FC2 inc edx .text:00401FC3 inc edx .text:00401FC4 inc edx .text:00401FC5 pop edx .text:00401FC6 pop edx .text:00401FC7 push eax
The register edx can be altered to eax, ebx or ecx. This crackme is very nicely and beautiful.