Cruehead CrackMe v1.0 - Local Download (4k).
I always recommend that you try your hand at these CrackMe's, this example by Cruehead will introduce the simplest concept of encryption, specifically the logic operation XOR. So start up the CrackMe and insert some details into the dialog boxes and >bpx Hmemcpy or GetDlgItemTextA, just start stepping with F10 to the following code (you'll go through User & Kernel32):
:00401223 CMP EAX,00000000
:00401226 JE 004011E6 <-- No jump.
:00401228 PUSH 0040218E <-- Name entered.
:0040122D CALL 0040137E <-- Function to trace.
:00401232 PUSH EAX <-- Save XOR result of name on stack.
:00401233 PUSH 0040217E <-- Serial # entered.
:00401238 CALL 004013D8 <-- Function to trace.
:0040123D ADD ESP,04 <-- Stack Tidy.
:00401240 POP EAX
:00401241 CMP EAX,EBX <-- Compare.
:00401243 JZ 0040124C <-- Jump_good_code.
So its very easy to see how this scheme can be beaten, however the purpose of a CrackMe is to fully investigate how the protection works. So lets have a trace of 0040137E & 004013D8.
:0040137E MOV ESI,[ESP+04] <-- Name entered.
:00401382 PUSH ESI <-- Stack it.
:00401383 MOV AL,[ESI] <-- AL = 1st letter of name.
:00401385 TEST AL,AL <-- Was it 0.
:00401387 JZ 0040139C <-- Jump_if_it_was.
:00401389 CMP AL,41 <-- Compare it with 41 or 'A'.
:0040138B JB 004013AC <-- Jump_below_'A'.
:0040138D CMP AL,5A <-- Compare it with 5A or 'Z'.
:0040138F JNB 00401394 <-- Jump_if_not_below_'Z'.
:00401391 INC ESI <-- Name counter.
:00401392 JMP 00401383 <-- Repeat test.
:00401394 CALL 004013D2 <-- Jump here if below 'Z'.
:00401399 INC ESI <-- Name counter.
:0040139A JMP 00401383 <-- Repeat test.
So this portion of code will check whether all of the names characters were indeed letters between A and Z, if the letter is lower case the CALL at 00401394 is executed, that consists of the classic SUB AL,20 i.e. uppercasing routine. So at the end our name is completely uppercased, we continue (still inside CALL 0040137E) with a CALL to function 004013C2.
:004013C2 XOR EDI,EDI <-- EDI=0.
:004013C4 XOR EBX,EBX <-- EBX=0.
:004013C6 MOV BL, BYTE PTR [ESI] <-- Pointer to name.
:004013C8 TEST BL,BL <-- End_of_name_check.
:004013CA JZ 004013D1 <-- Jump_loop_finished.
:004013CC ADD EDI,EBX <-- Add value to EDI which was zero.
:004013CE INC ESI <-- Counter.
:004013CF JMP 004013C6 <-- Loop_again.
So this function will sum up all of the letters in your name and place the result in EDI. In my case:
CRACKZ = 43 + 52 + 41 + 43 + 4B + 5A = 19Eh.
At the end, we have our critical operation:
:004013A2 XOR EDI,00005678 <-- XOR total of name characters.
:004013A8 MOV EAX,EDI <-- Move it to EAX.
In my case the result of this XOR operation is 57E6h, you
should then see that this result is saved away on the stack. Now
lets trace 004013D8:
:004013D8 XOR EAX,EAX <-- EAX=0.
:004013DA XOR EDI,EDI <-- EDI=0.
:004013DC XOR EBX,EBX <-- EBX=0.
:004013DE MOV ESI,[ESP+04] <-- Serial # entered.
:004013E2 MOV AL,0A <-- AL=10.
:004013E4 MOV BL, BYTE PTR [ESI] <-- Pointer to ESI.
:004013E6 TEST BL,BL <-- Check.
:004013E8 JZ 004013F5 <-- Finished_loop.
:004013EA SUB BL,30
:004013ED IMUL EDI,EAX
:004013F0 ADD EDI,EBX <-- EDI used for result storage (again).
:004013F2 INC ESI <-- Name counter.
:004013F3 JMP 004013E2 <-- Repeat.
:004013F5 XOR EDI,00001234 <-- Critical XOR.
:004013FB MOV EBX,EDI <-- Place it in EBX and return for the compare.
Again we have a loop operation, this time upon our entered serial
#, actually all this does is convert our decimal number into
HEX, so with 123456 I get the result 1e240h which is then XOR-ed
with 00001234 to give 1f074h. So for a correct serial # this
result must actually equal 57e6h (the result obtained from the name).
So lets work out my good code:
57E6h XOR 1234h = 45D2h = 17874
a b x
0 0 0
0 1 1
1 0 1
1 1 0
So let me show you how I calculated my result:
5 7 E 6 = (binary) 0101 0111 1110 0110
1 2 3 4 = (binary) 0001 0010 0011 0100
> Result of XOR = 0100 0101 1101 0010 = 45D2h = 17874 decimal.