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:
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.
Following the instructions, I find that the password length is 7:
After that I arrived the first check of password using VirtualProtect function.
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'.
Following the success jump of VirtualProtect, I find a loop that searches for '52h' meaning push edx in 32bit assembly.
At this part, we arrive at the core of Morph. Morph contains many numbers of dead codes.
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.
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.
Then I've found another two decoded bytes using ebx for code alteration:
[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':
There are other two direct tips here:
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:
The register edx can be altered to eax, ebx or ecx. This crackme is very nicely and beautiful.