INTRO / INFO
PROGRAM PhRoZeN CReW '97 CrAcK ME #2
TOOLZ NuMega Softice 3.22, a brain
HANDY REFZ HelpPC, Win32 API Docco
RESULTZ This docco, my Keygen
THANKS To Sandman'sawesome RCE site. This man's page is just awesome for all crackers (beg-pro). Without that page, I wouldn't have cracked this little proggie.
ABBREVIATIONS SI - Softice
ML - Memory Location
HV - Hexadecimal Value
AV - ASCII Value
WTF - What The Fuck!?
ESSAY Shows ya how to crack this little baby, and helps with the logic of writing a KeyGen. I was going to actually write the source code to the my keygen in here also, so that you could see it. But i decided to let you guys try and figure it out. I'll just point you in the right direction. If you want to see the source, please mail me at karnak@apexmail.com All SI commands that i used i'll put in RED.

Before i say any more, i must warn people that this essay is for learning ONLY. You won't gain access to an amazing application, all you will gain is knowledge.

This essay will focus on making a key generator because patching this baby would be a piece of piss and would be no challenge at all. Anyway, keygen's are by far the better solution for any situation.

This essay is targetted at the REAL beginners (just like me), it basically assumes that you know what softice is, and what a breakpoint is, and hopes that you know at least a little bit about x86 assembler. Softice work is a must, so if you dont know much then you'll find tute's on the web. So go search.

The average cracker will probably find that this essay is shit boring. The reason I wrote it like this was because I wanted to find something like this myself, but could never seem to find anything like it. So i thought that i'd follow my own request, and create something that all aspiring crackers can read, understand and learn from.

THE GOODS
OK, now its time to get down to the nitty gritty. This is the first time i've ever tried to write a cracking essay etc.. so please bear with me if its shit.

OK. Upon loading the proggie we can see that the protection is basically a nice little name/serial. I chucked in a username (i used 'karnak'), and a serial (i used 12345). Put in something easy to recognise like WAHOO and 666111666.

After entering those details in, start up SI (CTRL+D) and i whack in BPX GetDlgItemTextA (as most beginners do) in the hope that the program uses that windows function to get the text from one of the edit controls. Jump back into windoze ( CTRL+DBC 0. OK, so we need a lower level function that is used to get text out of the edit controls. At this point I decided to try 'HMEMCPY'. Why?? Coz i remembered seeing it in a cracking tutorial WAAAAAAYY back when I first got interested in this stuff. Anyway, it doesn't matter why at this point, all that matters is that it uses it. So back in SI again stick in the breakpoint BPX hmemcpy, and jump back into windows. Press the OK button and ... WHOOSH ... SI should pop right up in front of you.

Good stuff, now we know that the program is starting to get the text from (one of) the controls. This function was called deep down in the dark depths of the windows library, so that's basically where we are currently sitting. Press F11 to take you to the point after the calling of the function, and you'll notice that were are located in part of the USER32 code, keep pressing F12 until you reach the Crackme2 text (you'll go through KERNEL32 also). To make sure you know what i'm doing, this is a quick rundown so far:

    - pressed OK in app
    - SI came up
    - pressed F11
    - pressed F12 16 times

OK, at this point in time it's probably a good idea to get the HV for each character in your name, coz alot of protection schemes use them. I used HelpPC to get mine. Anyway the HV for my username is 6B 61 72 6E 61 6B, and for reference I got the HV for my password too, which is 3039 from this you can get the decimal values. OK, you should be looking at the assembler code that has just grabbed the text from the first of the edit controls ie. your password (12345 in my case). Can't see it?? OK, if you look at the contents of the EAX register ... hmmmm 3039 :-) Strange how thats the HV for my password dont you think?

Right, so that function has just grabbed the password. But where the hell is the username? Lets take a look at a snippet of code from SI:

	
	:004012F1  90                  NOP
	:004012F2  E85F000000          CALL    00401356                 <--- Hmm, interesting
	:004012F7  6A00                PUSH    00
	:004012F9  6A00                PUSH    00
	:004012FB  6A66                PUSH    66
	:004012FD  FF7508              PUSH    DWORD PTR [EBP+08]
	:00401300  E821010000          CALL    USER32!GetDlgItemInt     <--- Hmm, interesting
	:00401305  A3D2214000          MOV     [004021D2],EAX           <--- we are here
	:0040130A  3C00                CMP     AL,00
	:0040130C  743F                JZ      0040134D
	:0040130E  90                  NOP
OK, from this little snippet we can see a few things:

The actual function that extracted our password was 'GetDlgItemInt'. That is what put the value into EAX. Ok guys, enough of this Hmemcpy stuff, lets break on that baby. So in SI we go BC * to get rid of all the breakpoints we have, then BPX GetDlgItemInt. OK, for now lets just disable that breakpoint, BD 0 as there is something a little more interesting before we carry on.

Take a look at ML 004012F2. Seems we have invoked some sort of function/procedure. Now me being the way that I am, if I had coded this thing I would have grabbed the username first. So I guessed that this function could be the lad that does just that. So in SI lets breakpoint on that function call - BPX CS:00401356. Note the 'CS', this makes sure we are pointing to the code segment rather than any other segement (eg Data). Righto, now go back to the app and press OK again. AH HA! SI jumps up and we are right at the start of the function. So lets have a look at this code:

		
	:00401356  33DB                XOR     EBX,EBX                  <--- we are here
	:00401358  8A1DD1214000        MOV     BL,[004021D1]
	:0040135E  B108                MOV     CL,08
	:00401360  2ACB                SUB     CL,BL
	:00401362  BFA9214000          MOV     EDI,004021A9
	:00401367  6603FB              ADD     DI,BX
	:0040136A  B030                MOV     AL,30
	:0040136C  AA                  STOSB
	:0040136D  FEC0                INC     AL
	:0040136F  E2FB                LOOP    0040136C
	:00401371  C60700              MOV     BYTE PTR [EDI],00
	:00401374  C3                  RET
This is quite a simple little doozy. I'll just go through this code briefly. First EBX is cleared, and a valued is loaded into the lower byte of the lower 16 bits of that register. Hmm, is it just me? Or is that value the same as the number of chars in your username? Nah, its not just me :-) So at this point I guessed that they must have already got the value of our username and stored it somewhere. But where? And When? Well, we'll find out the former in just a moment, so we aren't going to care about the latter. Notice the code at ML 00401362? Its loading an address in the EDI register. So lets check out that address by typing in SI DD DS:004021A9. Ah!! Marvellous, there it is! Guess this means we dont need to know where/how we actually extracted this, coz we now know where its kept. OK, now make sure you keep that ML on hand, coz you'll see it a fair bit more later on.

Anyway, that's not all that is going on here. After loading the amount of chars in our name into BL, we seem to be doing something else that is interesting. In a nutshell we are going CL = 8 - BL where BL = length of our name. If I have to go as far as to spell that snippet out any more, then you obviously don't know enough assembler and shouldn't even be reading this yet! So if that's the case, piss off and learn some more and then come back.

OK guys, reading through the rest of the code in this little func we can see that we are moving the DI register to point to ADDRESS_OF_NAME + LENGTH_OF_NAME ie. to the ML directly after our name, and moving the HV of 30 into the AL register. So what is 30? Umm.. my guess is the HV for the character '0' (zero). OK, this bit I found a bit trickier, coz at the time I didn't know what the STOSB instruction did, so I just followed the contents of the MLs and figured it out that way. You are luckier my friend!! I'll tell you what this instruction means in case you dont know it.

STOSB = MOV [EDI], AL; INC EDI;

Pretty groovey huh! After my short days of assembler in UNIX I never thought i'd see something like this! Good stuff Intel! Right, so what the hell are we doing anyway? We are looping CL times. For me that would be 8 - 6 = 2 times. Each time we loop we are moving the current value of AL into the memory location pointed to by EDI.
So in a nutshell, to start with we have karnak. After the first loop we have karnak0, after the second loop we have karnak01, and then we break. So we can see that this little algo pads the username with numbers up to 8 chars. (another eg is prick becomes prick012).

All nice and clear?? Thought so :-) So we now have the value karnak01 (HV 6B 61 72 6E 61 6B 30 31) stored in ML 004021A9. At this point we jump back to the previous section of code, and to avoid having to constantly scroll up and down, i'll paste the code in again just here:

	
	:004012F1  90                  NOP
	:004012F2  E85F000000          CALL    00401356                 <--- Just came back from here
	:004012F7  6A00                PUSH    00                       <--- we are here
	:004012F9  6A00                PUSH    00
	:004012FB  6A66                PUSH    66
	:004012FD  FF7508              PUSH    DWORD PTR [EBP+08]
	:00401300  E821010000          CALL    USER32!GetDlgItemInt     <--- Disabled breakpoint
	:00401305  A3D2214000          MOV     [004021D2],EAX           <--- hmm, interesting
	:0040130A  3C00                CMP     AL,00
	:0040130C  743F                JZ      0040134D
	:0040130E  90                  NOP
Ok guys, as we can see, we then extract the integer value of our password and store in ML 004021D2. After doing this, we do fuck all (JMP) if the extracted password integer value is zero. AH! All nice and clear? I sure hope so, if you can't follow this essay then you really need some help :-)

Righto, we've got our password and username, now what are we going to do with them? Take a look a bit further down and we find:

	
	:00401311  90                  NOP
	:00401312  E85E000000          CALL    00401375                 <--- hmm, interesting
	:00401317  E8A5000000          CALL    004013C1                 <--- hmm, interesting
	:0040131C  85C0                TEST    EAX,EAX                  <--- hmm, interesting
	:0040131E  742D                JZ      0040134D                 <--- hmm, interesting
	:00401320  90                  NOP
	:00401321  90                  NOP
	:00401322  90                  NOP
	:00401323  90                  NOP
	:00401324  6A00                PUSH    00
	:00401326  689F214000          PUSH    0040219F
	:0040132B  683A214000          PUSH    0040213A
	:00401330  FF7508              PUSH    DWORD PTR [EBP+08]
	:00401333  E806010000          CALL    USER32!MessageBoxA
	:00401338  FF7510              PUSH    DWORD PTR [EBP+10]
	:0040133B  FF7508              PUSH    DWORD PTR [EBP+08]
	:0040133E  E8D1000000          CALL    USER32!EndDialog
	:00401343  B801000000          MOV     EAX,00000001
	:00401348  EB08                JMP     00401352
	:0040134A  90                  NOP
	:0040134B  90                  NOP
	:0040134C  90                  NOP
	:0040134D  B800000000          MOV     EAX,00000000
	:00401352  C9                  LEAVE
	:00401353  C21000              RET     0010
I put a fair bit of code in here so we can see the basic principal behind the proggie. Near the top of this code we have calls to 2 functions, and then we have a test and a jump. OK, from this we can see that if after the 2 functions if EAX is NOT zero then we throw up a Message Box, but if its zero what happens? That's right .. fuck all! Don't know about you, but up until now, all that's happened to me when I press OK is ... FUCK ALL! So we put 2 and 2 together and decide that to throw up this message box we need to make EAX something other than zero.

"But I wanna see this message box now!" I hear you cry. Well if you really want to see it now, step through the code using F10 until you reach ML 0040131E. At this point we can see that the Zero Flag is true, so if we change that to false then we should jump. So at this point type R FL Z, and this switches the value in the Zero Flag. Righto, CTRL+D and VOILA! Ahhhh, thats what we want isn't it ;-).

OK, those of you who who wish to stop here and just patch the proggie so that this always happens, go ahead and NOP out the JZ and you'll be right, but I wont be showing you how to do that coz I don't approve of such an easy fix in this instance.

Those battlers out there that wanna learn how to figure out this algo and write a keygen should keep reading, you'll get alot more satisfaction out of cracking the program without having to alter one part of it :-).

OK, lets take a look at the code in that first function F10 until you reach the function call and then F8 to step into the function as see this:

	
	:00401375  33C9                XOR     ECX,ECX                  <--- Start Of Function
	:00401377  BEA9214000          MOV     ESI,004021A9
	:0040137C  8BFE                MOV     EDI,ESI
	:0040137E  AC                  LODSB                            <--- WTF?!
	:0040137F  F7D1                NOT     ECX
	:00401381  8A99B1214000        MOV     BL,[ECX+004021B1]
	:00401387  F7D1                NOT     ECX
	:00401389  02C3                ADD     AL,BL
	:0040138B  AA                  STOSB
	:0040138C  FEC1                INC     CL
	:0040138E  80F904              CMP     CL,04
	:00401391  75EB                JNZ     0040137E
	:00401393  B904000000          MOV     ECX,00000004
	:00401398  BEA9214000          MOV     ESI,004021A9
	:0040139D  8BFE                MOV     EDI,ESI
	:0040139F  83C704              ADD     EDI,04
	:004013A2  F2A4                REPNZ MOVSB                      <--- WTF?!
	:004013A4  BEA9214000          MOV     ESI,004021A9
	:004013A9  8BFE                MOV     EDI,ESI
	:004013AB  B908000000          MOV     ECX,00000008
	:004013B0  AC                  LODSB
	:004013B1  F7D1                NOT     ECX
	:004013B3  8A99DF214000        MOV     BL,[ECX+004021DF]
	:004013B9  F7D1                NOT     ECX
	:004013BB  32C3                XOR     AL,BL
	:004013BD  AA                  STOSB
	:004013BE  E2F0                LOOP    004013B0
	:004013C0  C3                  RET                              <--- End Of Function
Firstly, I'll just explain the WTFs:

LOSB = MOV [ESI], AL; INC ESI;
REPNZ MOVSB = Loop from current EDI and ESI locations ECX times, and copy value from ESI to EDI

This code is pretty tricky to follow if you dont really understand assembler, so I'm going to do my best explaining it without completely boring myself to death! The first 3 lines clear one register, and load our username into both the ESI and EDI registers. We then iterate 4 times (CMP CL,04) through ESI, and add the HV of the character in our username (that is being pointed to by ESI) to something else. So what is that something? Well, we have a counter going from 1 to 4, but during that time we are using the NOT of this counter to extract other values. This loops through -1 to -4 also, and uses this as an offset to 004021B1, this result is the address of an ML in which a character is fetched from. Now if we look close enough we can see that 004021B1 = 004021A9 + 8. So what the hell are we doing? We are looping through the first 4 and last 4 chars of our name, and adding them together.
Here is a graphical representation:

	1st time through:
	
		karnak01
		^      *
	
	EDI = ^ + *

	2nd time through:
	
		karnak01
		 ^    *
	
	EDI+1 = ^ + *

	3rd time through:
	
		karnak01
		  ^  *
	
	EDI+2 = ^ + *

	4th time through:
	
		karnak01
		   ^*
	
	EDI+3 = ^ + *

	
So in my case I have the values 9C 91 DC CF. We then reset EDI and ESI with the location of our username, add 4 to EDI, and loop 4 times (counting with ECX, incrementing EDI) and copy from ESI to EDI. This means that we no longer have karnak01 in that ML, rather we have the values 9C 91 DC CF 9C 91 DC CF

Righto, at this point the program gets ready to muck around with these generated values. Again we reset ESI and EDI to our username ML and set ECX to 8. Using LODSB we iterate through the memory location starting at 004021DF, and are XORing the values in that location with our other generated values. All of a sudden this isn't looking so hard is it? We store these values in EDI as we go (ie the same original location that our username was in) through this loop. After the loop my values are CC F9 AF A0 C6 F4 B3 9E.

Well done guys, you've just figured out what the hell is going on with your username, and are now ready to piss around with the password. You've gone through most of the harder stuff.

Now, lets have a look at the other function F12 to run until the next RET statement and then F8 to step into the next function and see this:

	
	:004013C1  A1D2214000          MOV     EAX,[004021D2]           <--- Start Of Function
	:004013C6  8A0DA9214000        MOV     CL,[004021A9]
	:004013CC  D3C0                ROL     EAX,CL                   <--- WTF?!
	:004013CE  8B0DAE214000        MOV     ECX,[004021AE]
	:004013D4  33C1                XOR     EAX,ECX
	:004013D6  8B1DAA214000        MOV     EBX,[004021AA]
	:004013DC  8AC8                MOV     CL,AL
	:004013DE  D3CB                ROR     EBX,CL                   <--- WTF?!
	:004013E0  33C3                XOR     EAX,EBX
	:004013E2  B800000000          MOV     EAX,00000000             <--- BAD!!!
	:004013E7  7506                JNZ     004013EF
	:004013E9  90                  NOP
	:004013EA  90                  NOP
	:004013EB  90                  NOP
	:004013EC  90                  NOP
	:004013ED  FEC0                INC     AL                       <--- Good :-)
	:004013EF  C3                  RET                              <--- End Of Function
As per usual i'll explain the WTFs:

ROR X, Y = Roll bits in X right Y times
ROL X, Y = Roll bits in X left Y times

eg.
EAX=5B D0 18 5A
EAX=0101 1011 1101 0000 0001 1000 0101 1010
ROR EAX, 5
EAX=0111 1010 0000 0011 0000 1011 0100 1011
EAX=7A 03 0B 4B

OK, lets see whats happening at the start of this little proc. We can see that we are loading the value of our password into EAX, and load the first of our generated values (in my case CC - I'll refer to this later as ZVALUE) into CL. Then we roll our EAX bitmask left CL times. So our first generated value is being used as a roll counter. Next we are putting the last 3 values of the generated code (in my case 9E B3 F4 - I'll refer to this later as XVALUE) into ECX, and XORing them with the now rolled value in EAX. Now we load into EBX the generated values 2-5 (in my case C6 A0 Af F9 - I'll refer to this later as YVALUE), and MOV the current LAST value of EAX into CL (MOV CL, AL). This value is then used as a roll counter for the values in EBX. So EBX's bitmask is rolled left CL times.

Now comes the big test. By looking at the code we can see that if EAX and EBX are different, then we set EAX to zero and jump to the end of the routine. If EAX == EBX then set EAX to zero, skip the jump and then increment EAX. THIS IS WHAT WE WANT! Remember? After returning to this function, EAX is tested, and if its zero then we skip the message box. So we want the INC AL instruction to run! Therefore we now have to find a way to make EAX = EBX and we're done!

THE KEYGEN
OK people, congratulations, you've managed to stick with me throughout this lovely ordeal, and now know what the program is doing with your username and password. Now comes the tricky bit, working the KeyGen :-). Before we start working on the code its important to take a step back and try and see how we would approach this. It's not just a simple matter of writing a quick program, firstly we have to try and get our heads around the logic first so that when we code it, we know its behaving. So here's the program's key testing algorithm (in a C-ish Psuedo):

	
	FirstValue = PassWord RolledRightBy ZVALUE
	FirstValue = FirstValue XOR XVALUE
	
	OtherValue = LastHexValue in FirstValue
	
	SecondValue = YVALUE RolledLeftBy OtherValue
	
	If FirstValue == SecondValue Then
		WAHOO
	else
		BOOHOO
	end if
	
Keeping up? Sure hope so, now this was the deciding factor for me. This was the hardest part of the whole process. I knew what was going on, but for some reason i couldn't think of how the hell to do this process backwards. Why? Well when i first looked at it I thought "Fuck, this thing uses not only a mixture of generated values, but a mixture of parts of those generated values to get OTHER generated values. At first it just seemed way over my head, but then the 'Logical' Karnak woke up and took a look.

If we have a look at the SecondValue we can see that the only thing thats going on is a ROL. We know YVALUE, but we dont know OtherValue. OK, but since we are only rolling this value, the actual bitmask AFTER the roll is still the same bitmask, just swivelled a bit. So, if we think about it, OtherValue's bitmask must also be just a swivelled version of YVALUE. We just need to find out the extent of the swivel. With this ROL function, there are only 32 possible different orders for one bitmask (since we're dealing with 32 bits). Its the last 8 bits of the bitmask that tell us the ROL anyway! So, if we grab the YVALUE, and roll it by one bit (creating PVALUE), we grab the last 8 bits of PVALUE, and roll YVALUE by those 8 bits (creating QVALUE). If QVALUE == PVALUE then we can just do the reverse process of FirstValue on PVALUE and we'll get a serial!

I know its hard to get the mind round, but read it a few more times if you are having a bit of trouble understanding it, and you'll soon see what i mean.

OK guys, that about concludes my first essay. I hope you have found it as informative as i planned it to be. As already said i thought i'd leave you guys to try and figure out the source for the keygen, coz its a very good excercise. If you are really desperate and want to see my source please send a mail to the address at the top of this page and let me know.

Thanks for taking the time to read this essay!

Happy Cracking!

-=+ Karnak +=-