L ZZZZZZ RRRRR SSSSS L Z R R S L aaa Z aaa R R u u S L a Z a RRRRR u u SSSSS XX L aaaa Z aaaa R R u u S XXXX L a a Z a a R R u u S XXXXXX LLLLLLL aaaaa ZZZZZZZ aaaaa R R uuuuu SSSSSS XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXX XXXXXX XXXX proudly presents his 19.Cracking Tutorial (04.07.1999) XX Cruehead's CrackMe 1.0 I. Introduction I.1 Tools you need for my tutorial II. The "Kick the nag" approach VI. BTW VII. All Tutorials by LaZaRuS I. Welcome to my 20st cracking tutorial. I.1 W32Dasm 8.9 Cruehead's CrackMe 1.0 II. Thanx Cruehead. I thought first that this one will be pretty easy and could be done in one minute. But I fastly saw that I would have to follow the serial calculation. So I needed two minutes ;) Whatever, let's start. (Although there's no need to disassemble it (as you say), I only have W32Dasm on this computer and my SICE is 900km away from here :( So I have to break this rule). Load CrackMe.exe in W32Dasm. You will see some string references. The most important is "Great work, mate!". Search for it and you see this: * Referenced by a CALL at Address: |:0040124C | :0040134D 6A30 push 00000030 * Possible StringData Ref from Data Obj ->"Good work!" | :0040134F 6829214000 push 00402129 * Possible StringData Ref from Data Obj ->"Great work, mate!" | :00401354 6834214000 push 00402134 :00401359 FF7508 push [ebp+08] * Reference To: USER32.MessageBoxA, Ord:0000h | :0040135C E8D9000000 Call 0040143A :00401361 C3 ret We can easily see that this messagebox is called from :0040124C. So let's have a look at this passage. :00401240 58 pop eax ;; load one value :00401241 3BC3 cmp eax, ebx ;; compare two values :00401243 7407 je 0040124C ;; if same, then jump to "Well done" message :00401245 E818010000 call 00401362 ;; call "wrong" message :0040124A EB9A jmp 004011E6 ;; go on * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401243(C) | :0040124C E8FC000000 call 0040134D ;; call "well done" messagebox :00401251 EB93 jmp 004011E6 ;; go on So pretty obviously: Either eax or ebx should contain the correct serial and the other register should contain the value you have entered, then. When you try it you will see that is not this way. So we have to follow how these two values are calculated. :00401228 688E214000 push 0040218E ;; 40218E contains the name you entered :0040122D E84C010000 call 0040137E ;; calculates first value :00401232 50 push eax ;; saves first value :00401233 687E214000 push 0040217E ;; saves serial you entered :00401238 E89B010000 call 004013D8 ;; calculates second value :0040123D 83C404 add esp, 00000004 :00401240 58 pop eax ;; loads first value :00401241 3BC3 cmp eax, ebx ;; compare first with second value :00401243 7407 je 0040124C ;; if same, then jump to "Well done" The first call is this: * Referenced by a CALL at Address: |:0040122D | :0040137E 8B742404 mov esi, dword ptr [esp+04] ;; esi=name :00401382 56 push esi ;; save name * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00401392(U), :0040139A(U) | :00401383 8A06 mov al, byte ptr [esi] ;; mov first letter in al :00401385 84C0 test al, al ;; al=0 ? :00401387 7413 je 0040139C ;; if so, then exit loop :00401389 3C41 cmp al, 41 ;; al<41? (41h=65=A) :0040138B 721F jb 004013AC ;; if so, then "Wrong" :0040138D 3C5A cmp al, 5A ;; if al >= 5A (5A=90=Z) :0040138F 7303 jnb 00401394 ;; if so, then jump :00401391 46 inc esi ;; point to next letter :00401392 EBEF jmp 00401383 ;; loop * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040138F(C) | :00401394 E839000000 call 004013D2 ;; ASCII(letter) - 20h :00401399 46 inc esi ;; point to next letter :0040139A EBE7 jmp 00401383 ;; loop * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401387(C) | :0040139C 5E pop esi ;; load name again :0040139D E820000000 call 004013C2 ;; see below :004013A2 81F778560000 xor edi, 00005678 ;; XOR value with 5678h :004013A8 8BC7 mov eax, edi ;; save value in eax :004013AA EB15 jmp 004013C1 ;; go on * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040138B(C) | :004013AC 5E pop esi ;; show a "Wrong" MessageBox :004013AD 6A30 push 00000030 * Possible StringData Ref from Data Obj ->"No luck!" | :004013AF 6860214000 push 00402160 * Possible StringData Ref from Data Obj ->"No luck there, mate!" | :004013B4 6869214000 push 00402169 :004013B9 FF7508 push [ebp+08] * Reference To: USER32.MessageBoxA, Ord:0000h | :004013BC E879000000 Call 0040143A * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004013AA(U) | :004013C1 C3 ret Let's explain: This passage does nothing but converting the name you entered to capital letters. LaZaRuS will be LAZARUS after this passage. Eh, not really. I assume Cruehead made a mistake coding this passage. LaZaRuS will be LA:ARUS after this passage. In my opinion the following line: :0040138F 7303 jnb 00401394 ;; if so, then jump must be :0040138F 7?03 jb 00401394 ;; if so, then jump Then the name would be converted correctly. I'll ask Cruehead when I meet him next time. So let's have a look at the call :0040139D * Referenced by a CALL at Address: |:0040139D | :004013C2 33FF xor edi, edi ;; erase edi :004013C4 33DB xor ebx, ebx ;; erase ebx * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004013CF(U) | :004013C6 8A1E mov bl, byte ptr [esi] ;; bl = 1st char of conv. name :004013C8 84DB test bl, bl ;; bl=0? :004013CA 7405 je 004013D1 ;; if so, then exit loop :004013CC 03FB add edi, ebx ;; edi=edi + 1st letter :004013CE 46 inc esi ;; point to next letter :004013CF EBF5 jmp 004013C6 ;; loop * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004013CA(C) | :004013D1 C3 ret ;; return from call This passage will add all ASCII values of each letter of the converted string. For LA:ARUS this will be: 4C+41+3A+41+52+55+53 (hex values). This is 202h. When you return from the call this value will be XORed with 5678h. The result is 547Ah. This is one of the values that are compared at the end. So, let's look for the other. The important call is at :00401238. If you enter, you will see this: * Referenced by a CALL at Address: |:00401238 | :004013D8 33C0 xor eax, eax ;; erase eax :004013DA 33FF xor edi, edi ;; erase edi :004013DC 33DB xor ebx, ebx ;; erase ebx :004013DE 8B742404 mov esi, dword ptr [esp+04] ;; esi=serial * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004013F3(U) | :004013E2 B00A mov al, 0A ;;-------------- This one just :004013E4 8A1E mov bl, byte ptr [esi] ;; | copies the serial :004013E6 84DB test bl, bl ;; | you entered to edi :004013E8 740B je 004013F5 ;; | I entered 666999 :004013EA 80EB30 sub bl, 30 ;; | so edi will :004013ED 0FAFF8 imul edi, eax ;; | contain A2D77 (the :004013F0 03FB add edi, ebx ;; | hex-value of my :004013F2 46 inc esi ;; | serial) at the end :004013F3 EBED jmp 004013E2 ;;-------------- * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004013E8(C) | :004013F5 81F734120000 xor edi, 00001234 ;; XORes the serial with 1234h :004013FB 8BDF mov ebx, edi ;; saves second value in ebx :004013FD C3 ret ;; return from call The value I get is A3F43h (A2D77h XOR 1234h). That's obviously not the same as 547Ah which I got as first value. The first value is unchangable (as I want to reg it with LaZaRuS), so let's have a look at the second one. We know: [All letters of name added] XOR 5678h == Serial XOR 1234h 547Ah == Serial XOR 1234h -> serial = 547Ah XOR 1234h serial = 464E We have to convert this value back to decimal: 17998 So at the end we have: Name: LaZaRuS Code: 17998 I. BTW Greets to: tKC, Ed!son, Moral Insanity, +Sandman, Fravia+ and everyone at #cracking4newbies, +Sandman's forum and Fravia+'s forum. VII. All tutorials by LaZaRuS