TUTORIAL FOR IDCRACKME v.5.0 by The_Dux ======================================= INTRO: A little intro before we start. This is a very very long tutorial so be patient... The length of this is strictly realted with the type of crackme that TORN@DO wrote. I'm not a native english person so... forgive my mistakes. Thanks. TUT: Let's start. As usual we fire up the program and see around to find some button like 'Register', etc. We didn't found anything except two buttons: one enabled (the About) and one disabled (the Request). So we can't insert our data directly to the program. We must reconstruct the registration file manually. Ok, as wrote in the Readme file this is a packed file so we can't disassemble it. Well... Now we have to choose: a) We can debug it directly with SoftIce or similar b) We can unpack it manually and try deadlisting I prefer the first one so i've tried with SoftIce. The first problem that we encounter is that the decription routine is very long and we can only 'step into' to go on otherwise we exit from SoftIce and the program load itself without us... So we can try two things: a) We can set a breakpoint to OpenFile, CreateFile, CreateFileEx, ReadFile and ReadFileEx to intercept the reading or b) We can try another approach that is more nice and 'aristocratic' We try the second one, of course, because we are not novice and we crack with a little of brain, right? So, let's take a look at the main window of the program. We have a dialog, or a window, we don't say, with four main object: two pictures and two buttons. The pictures show some nice text but the button are one enabled and one disabled. This is very important and from here we can start reconstruct the missing key file. How? Be patient... We all know that a button is enabled by a call to the EnableWindow function. Reading our Win32 API references we see that the function take two parameters: hWnd & bEnable. The first one is the handle to the window (or the button, btw) that receive our boolean value (enabled or disabled, 0 or 1) represented by bEnable. Let's think a bit... We can't enable the button from the window nor from the about box so the button is enabled ONLY when we reconstruct the key file... Now that we reverse with word this we set a breakpoint on execution (bpx in SoftIce) at EnableWindow. Launch the program and... voilą SoftIce pop up and put ourseleves in the middle of our beloved function... Think a little again: we have two button so how much call to EnableWindow? Two!! Exit SoftIce with CTRL+D and we reenter immediately in SoftIce. Ok now F11 once to exit from EnableWindow and we fall into the crackme's code. Well. Move around the code and see the GetDlgItem function that retrieve the handle of control (our button). We also see, some lines above, a PUSH 00 that is like PUSH FALSE or PUSH DISABLED. Yes! We found where the routine where button is disabled! Now move the cursor above to see a conditional jump but there are only some pushes... like the beginning of a call. In fact this is a little call that ends some lines below the Call EnableWindow with a RET. Trace till there and see where we return. The lines that we see are few and many INT 3 are there... Let's take a look at the lines above and we see another RET instruction, after another call... Well our experience say us that this is the place where the key file is verified and then something decide how we are (good or bad crackers...). So write down the addres after the first occurrence that is in my machine 401D18. Go up to find some conditional jump that refer to this location and with a lot of surprise we find not one but many conditional jump of this type. Watching the lines above each jump we notice that we have allways a call, a stack adjustment, and a test that verify the value of eax that must be zero or non zero. Ok, now we have founded the reference to the EnableWindow that disable the button. Set a breakpoint to the first call (401BEC) and step into to see what happen. Ok, now we have to trace well the first part of this call cause as we can see we found this initial lines in each call that follow and that return the magic value in eax that decide if we are good or not so good. Here is the code taken from W32Dasm: (Forget the addresses, they are false beacause this is a dump of memory from SoftIce) :00000000 83EC30 sub esp, 00000030 :00000003 33D2 xor edx, edx :00000005 33C0 xor eax, eax :00000007 B907000000 mov ecx, 00000007 :0000000C 88542410 mov byte ptr [esp+10], dl :00000010 57 push edi :00000011 8D7C2415 lea edi, dword ptr [esp+15] :00000015 F3 repz :00000016 AB stosd :00000017 AA stosb :00000018 8D442405 lea eax, dword ptr [esp+05] :0000001C 88542404 mov byte ptr [esp+04], dl :00000020 8910 mov dword ptr [eax], edx :00000022 895004 mov dword ptr [eax+04], edx :00000025 895008 mov dword ptr [eax+08], edx :00000028 6689500C mov word ptr [eax+0C], dx :0000002C B801000000 mov eax, 00000001 :00000031 8A8857D04000 mov cl, byte ptr [eax+0040D057] :00000037 40 inc eax :00000038 80F133 xor cl, 33 :0000003B 83F810 cmp eax, 00000010 :0000003E 884C0412 mov byte ptr [esp+eax+12], cl :00000042 76ED jbe 00000031 :00000044 8D442414 lea eax, dword ptr [esp+14] :00000048 8D4C2404 lea ecx, dword ptr [esp+04] :0000004C 50 push eax :0000004D 6828D74000 push 0040D728 :00000052 51 push ecx :00000053 E858360000 call 000036B0 :00000058 8D4C2410 lea ecx, dword ptr [esp+10] :0000005C 83C40C add esp, 0000000C :0000005F 6824D74000 push 0040D724 :00000064 51 push ecx :00000065 E826360000 call 00003690 :0000006A 83C408 add esp, 00000008 :0000006D 85C0 test eax, eax :0000006F 7413 je 00000084 :00000071 50 push eax :00000072 E829340000 call 000034A0 :00000077 83C404 add esp, 00000004 :0000007A B801000000 mov eax, 00000001 :0000007F 5F pop edi :00000080 83C430 add esp, 00000030 :00000083 C3 ret :00000084 33C0 xor eax, eax :00000086 5F pop edi :00000087 83C430 add esp, 00000030 :0000008A C3 ret Ok, it's all the call but we can slowly learn it's structure. Let's start. Where? From the beginning of course... At the address 0 (is a fake address, remember) we adjust the stack and we set some values (not so important) till 2Ch. Here we set eax to 1 and enter in a loop, repeated 16 times, in wich we get a value from somewhere, we xor it with 33h, and we put the xored value in a buffer. This loop as i said xor an array of data and put the result in another array. For educational purpose here are the crypted and the decrypted arrays: Crypted : avtz`gargz|} (and another char that is 1Dh(can't represent)) Decrypted: REGISTRATION.DAT As you see we decrypt the buffer to get the real name of the key file. So create it! (of course in the same directory) Ok, now back on our code. We know that eax must be non-zero to fake the jz jump just after our breakpoint. We see two RET and after each one eax is filled with different values: 1 for the first RET (at 7Ah) and 0 for the second RET (84h). The only way to go to 84h is with the jump at 6Fh that verify the return value of the above call. We can go through this call and so on and so on... or we can simply guess what this call do. Really I don't know what this call do but i believe that return the handle of file (with a call to OpenFile maybe) and if eax is zero (that is the error code of OpenFile for failed operation) it jump and return a zero that say we are bad crackers. So try it! It's as I said... No matter how the check is done (not because we are lamers but because we can't trace through these calls or our key file never watch the sun light!!). We have reversed almost 50% of the protection, I think, because all the others calls begin as this. Ok now we come back and set another breakpoint to the next call (that now is executed because we have the REGISTRATION.DAT). Well, well, we are still in the night because we have just created the file... NO! Now we go to the next call and see some operations (at the end) that substract 400h (1024d) to a value stored in ebx. Now that we are here we can choose: a) trace the call to find where value ebx is computed b) think a little as TORN@DO and guess what's this We try... b! Ok, now the program know that the key file exist what more? We can check many things but one is the more probable (watching that 400h or 1024d also): the length of our file. Yes, is as said and the length must be 1024 bytes. Try yourself if you don't believe me. I don't have time (and space) to explain those little particulars. so we return with the correct value in eax and set a breakpoint on next call. Go inside, jump the known part, and pay attention to what happens here is that movsx, mov and cmp loop. With the call above we read the entire file (important: the entire file) and we put it onto a buffer pointed by the stack (esp). After little tricks i've founded that the file is stored starting from address [esp+3C]. I've simply putted a 01h byte at the beginning and at the end of our key file and searched for it near the pointer to [esp+eax+38] readed onto the code. This call is the most important part of key file because here we can reconstruct our key file with our name... I have to say that our name is crippled with a simple algorithm that xor every char of our name with the length of name. As we see after some other calls depending on the name we change a handful of byte, but later... So insert our name (crippled of course!!). This time i've crippled a name, Scully, that is the name I usually use to find the serial number. So we can write at the offset 99 of the key-file the crippled name. A little things: the 99 is computed as I said above basing on the beginning of file situated at [esp+3C] and the lines that move our name to a buffer. I can't explain i've said but it isn't so hard. My cryppled name is Uesjj (plus the 7Fh char that i can't represent). The only limit to the name is the length: it must be greater than 3 and lesser than 55 chars. Now we go further and set a breakpoint on next call. The address is 401E90 and I have to say that the last known call (the one that is repeated every call) read from file and place start the buffer at esp+38. In this call we do a simply check to verify the header of the key file that is 9 bytes long. The header is already stored in the exe (decrypted of course!) and is compared with a routine of three line. If you don't find it by yourself here is what it is: 06h 0Ah 15h 07h 13h 10h 0Ah 72h 0Ch As you can see it's a sequence of nine byte. We are done with this call too so set a breakpoint on the next. This call is another check to verify the integrity of our key file. We have 7 bytes that are readed from the buffer (that is always where we put the content of the registration file), xored with some values and then compared with other values. To simplify the tedious job here are the bytes to put at offset 0Ah: 07h 20h 34h 3Eh 09h 07h 0Ah Note: The first 07h is taken from the last reading operation of the call. THEY AREN'T IN SEQUENCE AS IN REG FILE. Ok, next call and set the new breakpoint. In this call we get some other bytes (4) just after the 0Ah of the above call. The byte are compare directly with cmp or tested if they must be zero. Here are they (to put after the last 0Ah, offset 11h): 08 00 00 05 Now we are ready to set the next breakpoint. In this call what we have? The same things as in the above one... We have some value that must be equal to our values xor dummy val. So here are they: (they are 17 starting from offset 15h) 08 05 00 12h 0Ah 12h 03 12h 02 2Ch 43h 08 02 2Ah 0Ah 44h 54h And now what we do? We set a breakpoint on next call... This call is a bit obscure but we resolve it in a while. With this call the crackme check a date stored in the key file with the current date. The key file date must be greater or equal to the current one. We simply store a 07CFh word in our file at the offset 52h and we pass this check. Now we have to look at another value that here appear as unused but in the last call we find some references to this. We can modify it if we want but, you are warned, we have to do more complex math later so believe me, leave 0 this byte that is at the offset 50h. Well... slowly but calm we are here...what more? some more calls... we are about in the middle of the check routine so we must take a rest here... Good rest? well... let's start again with the famous breakpoint on next call. At the beginning of this tute we see the crackme like a heavy slope, now we are in a descent... This call tell us nothing... It simply compares two byte of our code and verify that they are lesser than two values. Ok leave these byte null (0 - at offset 55h & 56h) and go on with next call. Set The Breakpoint. Now a call that will relax ourself and free our mind... We trace till we reach the usual set of known code and then we see a routine, repeated 88 times that compare some value with some other situated at offset 0D0h of our key file. What are these bytes? They are a joke... Here are they: (all uppercase) SUPPORT THE SOFTWARE AUTHORS BY BUYING THE PROGRAMS IF YOU USE THEM AFTER CRACKING THEM! Nice isn't it? Write this words on the file starting from 0D0h and go on. Set The Breakpoint. In this call, with a little different routine to the above one we do the same thing: we compare another handful of bytes. They are (starting from offset 150h): 6;9>>2TJR255<5>=92:8><= Set The Breakpoint. Now begin the part that is a little harder than the previous one. We start generating checksum... Ok, don't be demoralized, it's only math... Well, we begin with a little look around the code: We see a loop repeated 100 times and a division by 0Ah Now I try explain you what happen: Here we compute a checksum (only a sum) of the first 100 bytes. After this we xor it with 7CFh (1999, nice!) and we divide by 0Ah. The result of division must be equal to a byte stored in the key file at the offset 3B0h. We have to do all this maths? Nope, the computer do it for us... We only wait at the line with cmp ecx, eax and write down what we have in eax (the byte of checksum just computed). Now we open the key file and we write this byte to the 3B0h offset. Done. Note: in this call we have a handful of value taken here and there from the key file. Believe me, leave it to zero... Set The Breakpoint. Another call very similar to the above one. We find some more maths... leave the computer alone to do that (hey, it's it job and it do it very quickly...). We wait at the usual cmp reg32, reg32 and write down the addresses. What more? NOTHING. The call that follow do the same job and we have to wait at the cmp reg32, reg32 instruction to find the correct values... Another things: the last call verify that the last byte of the key file is 52h. Don't miss it! FINAL NOTES: We have successfully rebuild the missing key file... what more? A key-gen... Wait, it's a bit longer... For those of you that wasn't able to follow me here is the dump of my REGISTRATION.DAT (Pay attention: don't modify any byte because the final checksum may change!): Taken from HexWorkshop v.2.54 00000000 060A 1507 1310 0A72 0C00 0720 343E 0907 .......r... 4>.. 00000010 0A08 0000 0508 0500 120A 1203 1202 2C43 ..............,C 00000020 0802 2A0A 4454 2101 5269 3A00 0000 0000 ..*.DT!.Ri:..... 00000030 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000040 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000050 0000 07CF 0000 0000 0000 0000 0000 0000 ................ 00000060 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000070 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000080 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000090 0000 0000 0000 0000 0055 6573 6A6A 7F00 .........Uesjj.. 000000A0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000B0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000C0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000D0 5355 5050 4F52 5420 5448 4520 534F 4654 SUPPORT THE SOFT 000000E0 5741 5245 2041 5554 484F 5253 2042 5920 WARE AUTHORS BY 000000F0 4255 5949 4E47 2054 4845 2050 524F 4752 BUYING THE PROGR 00000100 414D 5320 4946 2059 4F55 2055 5345 2054 AMS IF YOU USE T 00000110 4845 4D20 4146 5445 5220 4352 4143 4B49 HEM AFTER CRACKI 00000120 4E47 2054 4845 4D21 0000 0000 0000 0000 NG THEM!........ 00000130 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000140 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000150 363B 393E 3E32 544A 5232 3535 3C35 3E3D 6;9>>2TJR255<5>= 00000160 3932 3A38 3E3C 3D00 0000 0000 0000 0000 92:8><=......... 00000170 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000180 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000190 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001A0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001B0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001C0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001D0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001E0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001F0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000200 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000210 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000220 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000230 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000240 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000250 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000260 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000270 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000280 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000290 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002A0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002B0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002C0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002D0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002E0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002F0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000300 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000310 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000320 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000330 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000340 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000350 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000360 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000370 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000380 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000390 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003A0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003B0 6272 0400 120F 0000 0000 0000 0000 0000 br.............. 000003C0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003D0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003E0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003F0 0000 0000 0000 0000 0000 0000 0000 0052 ...............R Ok, I have finished my very very long tutorial. In the words above I don't say a little things: the objective. Mine is... I can't tell you. If you follow my tutorial step by step and call by call you see a little nice joke from TORN@DO with the main icon. Really cool! The_Dux, 12 July 1999.