Tutorial by dihux
____________________________________
Target.: ArturDents Crackme2

Remarks: www.crackmes.de
         
Task...: Keygen
         
TutDate: 8-9.nov.2002

Tools..: IDA

This tutorial will not be hard to follow. It's written for newbies.
IDA-Interactive DisAssembler

Run the crackme. You should see a name field and a serial field.
There are three buttons. One Exit-,one About- and one Checkbutton.
Before you type anything in both name and serial field, try to check
first and see if we get any messages etc. Yup. Our name must be at
least 5 characters long. Well, ok then. Type something with 4< chars.
e.g dihux(5 chars) and check. Nothing happens. We are now enough
known with our target. We can proceed.

Now it's time to disassemble the crackme. Do that in the disassembler
you like the most. I prefer using IDA. So, disassemble the crackme.
First thing we do is looking up the message we
got earlier "....at least five char...". Search\Text or simply ALT+T then
the search dialog will pop up. With this dialog you can search through
the disassembled file for whatever you want. We want to search for that
string as I mentioned. Type "at least five" and you will be taken to
00403044. Notice that there are several of strings here. The one at
00403027 looks very interesting. We'll check that later. Now take your
mouse over aYourNameMustBe at 403044 so that the blinking cursor will
be on it. Then press X. Another dialog pops up. This time it's a xref
dialog that shows us where this string is being used and how many
times it is being used. Only one reference here. Select it and press OK.

.text:004010FC                 push    ebp
.text:004010FD                 mov     ebp, esp
.text:004010FF                 push    14h             
.text:00401101                 push    offset unk_403080       // buffer
.text:00401106                 push    0BB8h                   /* identifies
                                                                  which control
                                                                  it should take
                                                                  text from */
.text:0040110B                 push    [ebp+hWnd]              // pushes hWnd
.text:0040110E                 call    GetDlgItemTextA         // calls getdlgitemtexta
.text:00401113                 mov     esi, eax
.text:00401115                 lea     eax, [ecx]
.text:00401117                 cmp     esi, 5                  /* we know from the error
                                                                  we got when we checked
                                                                  without any chars that
                                                                  this is our name */
.text:0040111A                 jge     short loc_401134
.text:0040111C                 push    40h                     // msgbox type. e.g MB_OK
.text:0040111E                 push    offset aArturdentsCrac  // caption
.text:00401123                 push    offset aYourNameMustBe  // Yup, our msg
.text:00401128                 push    [ebp+hWnd]
.text:0040112B                 call    MessageBoxA

This is pretty straight forward. But, I'll explain anyway. To get the
text from the name field into a buffer the author of this crackme has
used an api called GetDlgItemTextA. This api needs four arguments to
work with or else it won't work.

UINT GetDlgItemText(
    HWND hDlg,		// handle of dialog box
    int nIDDlgItem,	// identifier of control
    LPTSTR lpString,	// address of buffer for text
    int nMaxCount 	// maximum size of string
   );

NOTE: In disassebled code this will appear in reversed order

That means:
push nMaxCount
push lpString
push nIDDlgItem
call GetDlgItemText

That is how the getdlgitemtexta api works. The return value from this
api, if it succeeds, is the length of the string. The return value is
stored in eax. Which you can see is moved right to esi after the call
at 0040110E(mov esi,eax is equal to esi=eax). On 00401117 it compares
our namelength with five. If esi is greater or equal with 5 then jump
away from the message and continue. Now, go back to all those strings.
And check out that "aYeahYouDidIt   db 'Yeah, you did it!',0". It is
used once. Let us go there and take a look.

.text:00401134 loc_401134:                            
.text:00401134                 push    14h             
.text:00401136                 push    offset unk_403280 
.text:0040113B                 push    0BB9h           
.text:00401140                 push    [ebp+hWnd]      
.text:00401143                 call    GetDlgItemTextA
.text:00401148                 mov     eax, offset unk_403080
.text:0040114D                 mov     ebx, offset unk_403280
.text:00401152                 mov     ecx, esi
.text:00401154 
.text:00401154 loc_401154:                             
.text:00401154                 mov     dl, [eax]
.text:00401156                 sub     dl, cl
.text:00401158                 cmp     [ebx], dl
.text:0040115A                 jnz     short locret_401174
.text:0040115C                 inc     eax
.text:0040115D                 inc     ebx
.text:0040115E                 loop    loc_401154
.text:00401160                 push    40h             
.text:00401162                 push    offset aArturdentsCrac 
.text:00401167                 push    offset aYeahYouDidIt 
.text:0040116C                 push    [ebp+hWnd]      
.text:0040116F                 call    MessageBoxA
.text:00401174 
.text:00401174 locret_401174:                         
.text:00401174                                         
.text:00401174                 leave
.text:00401175                 retn    4

This takes our name and stores it in a buffer.
If you trace with softice here you will see that 403080
contains your name and 403280 is holding your bogus serial. And be
aware of that it only takes the 13h/0x13/19 first characters in both
cases, if there are more characters left in the name or the serial
field they will be ignored. We will have to take that into consideration
when coding our coming keygen. The reason why these two calls to
getdlgitemtexta takes 0x14 instead of 13h as I said is beacause it
needs one extra byte to finish of the string. So it'll take 0x13 chars.

At 00401148, after the call, our name is moved to eax. After that our
serial is moved to ebx. Our namelength is still stored in esi when we
arrive here, but just before the serial routine that begins at 401154
its contents is moved to ecx. Ecx will act like a counter for us. Ecx 
is very often used when it comes to loops etc. Because the loop opcode
decreases ecx with one each time it loops.And when ecx is 0 it'll stop
looping and continue.

.text:00401154 loc_401154:                             
.text:00401154                 mov     dl, [eax]
.text:00401156                 sub     dl, cl
.text:00401158                 cmp     [ebx], dl
.text:0040115A                 jnz     short locret_401174
.text:0040115C                 inc     eax
.text:0040115D                 inc     ebx
.text:0040115E                 loop    loc_401154

This is the whole serial routine. Very easy algo indeed. But it can give
some newbies some problems. This doesn't generate any matching serial
string to our name, but takes each character and makes some operations
with it and compares it to a character in our serial. 

mov dl,[eax]; This will take the current character(byte) in [eax] and put it
in dl.

sub dl, cl; this is a subtraction between dl and cl. dl-cl.
dl=byte of the current letter in eax.
cl=the current value of the last eight bits in cx, that could be hard
to understand. I will try to explain in detail. ECX is a 32bit register.
CX is a 16bit register and both CH and CL are 8bit registers.

_____________________________________________
|                    ECX                    |
|                     |         CX          |
----------------------|----------------------
| 00000000 | 00000000 | 00000000 | 00000000 |
|                     |    CH         CL    |


ECX has 32bits, that means 32 times 0.
CX has 16bits
CH and CL has 8bits
00000000000000000000000000000000 = 32bits
0000000000000000 = 16 bits
00000000 = 8 bits

CX is the 16 last bits of ECX
CH is the eight first bits of CX
CL is the eight last bits of CX

ECX is capable of storing values up to 0xFFFFFFFF
CX is capable of storing values up to 0xFFFF
CH is capable of storing values up to 0xFF
CL is capable of storing values up to 0xFF

Well, we got a little off track now. But this is very important for
future development.

The getdlgitemtexta api gets text up to 0x14 which is 20 in decimal.
That means 19characters+'0'. So namelength will not be larger than
0x13 which is 19 in dec. Therefor is CL used. Because it is capable
of handling numbers from 0-255(255=0xFF) and because it is faster
too. So now you know exactly how sub dl,cl works in this case.

cmp [ebx], dl; this simply compares the current byte in ebx with dl

jnz     short locret_401174; if not [ebx]==dl then go away. Returns.

inc     eax; finished with first character. increase so that next char
             will be in [eax]

inc     ebx; same as above, but one little difference. this is our serial
             and it increases so that next char in serial will be in [ebx]
             so from this we know that serial length must be equal to the
             name length or else the serial won't be right whatever you do.
             except patching. but that isn't allowed.

loop    loc_401154; decreases ECX and loops to loc_401154 till ECX is zero.

If this loop succeeds, then your serial is good. 

Keygen:

C++ solution:
       {
        hLen=GetDlgItemText(hWnd,IDC_NAME,Name,21);
        if(hLen<5){
		MessageBox(hWnd,"Your name must be at least 5 characters long.",0,MB_OK);
		return 0;
	}
	if(hLen>0x15){
		MessageBox(hWnd,"Max 19 characters.",0,MB_OK);
		return 0;
	}
        for (i=0;Name[i];i++,hLen--){
        	Name[i]=Name[i]-hLen;
        }
        SetDlgItemText(hWnd,IDC_SERIAL,Name);
        }
/*
i and hLen are integers
Name is char
hLen = namelength
check if name if lower than 5 chars
check if name==0x14
loop(for)
Set serial
*/

ASM Solution:
        invoke GetDlgItemTextA,[hWnd],IDC_NAME,offset NameBuf,15h
        cmp eax,5
        jb tooshort
        cmp eax,14h
        je toolong
        mov ecx,eax 
        mov eax, offset NameBuf
lop:
        mov dl, byte ptr [eax]
        sub dl,cl
        mov byte ptr [eax],dl
        inc eax
        loop lop

        invoke SetDlgItemTextA,[hWnd],IDC_SERIAL,offset NameBuf
        jmp rett
        
	toolong:
        invoke	SetDlgItemTextA, [hWnd], IDC_SERIAL, ADDR TooLong
        jmp rett
        
	tooshort:
        invoke	SetDlgItemTextA, [hWnd], IDC_SERIAL, ADDR TooShort

COMMENT %
NameBuf has got a size of 21 bytes.
%

I will not include full source. You don't need more
information to make a keygen out of this crackme now.
______________________
EFnet @ #New2Cracking
dihux - 2002






