Tutorial by dihux
____________________________________
Target.: CoSH's Crackme 3

Remarks: N/A

Task...: Keygenning

TutDate: 12.2002

Tools..: SOFTICE, MASM

You can find this crackme at www.crackmes.de, but that shouldn't be
necessary since I've included it in the zip file. If you don't have
the tools I've listed, go and download them.

http://www.cracktools.com
http://www.protools.cjb.net
http://www.exetools.com
http://www.google.com - search engine

The crackme has a name field, a serial field and two buttons. Type a
name and a bogus serial. NOTE: Name must be longer than 5 characters.
Hit the Check button, "one of the details..." ok for now. Just store
the message somewhere inside your head a while, you'll get use of it
later. Lets try softice. If you don't know how to work with softice,
go and learn it first. Then read on.

Set breakpoints on the usual ones. GetDlgItemTextA and GetWindowTextA.
Check, Softice breaks. Where are we? Look at the code window's bottom
line. It says, USER32!.text+XXXX. Ok we're in user32.dll. Skip call,F12.
Hmm, now we're in the mfc42.dll. Now we know that CoSH coded this
crackme with MFC. What is MFC?


[CUT FROM THE .NET HELP FILES]
The Microsoft Foundation Class Library is an application framework for
programming in Microsoft Windows. Written in C++, MFC provides much of
the code necessary for managing windows, menus, and dialog boxes;
performing basic input/output; storing collections of data objects; and
so on. All you need to do is add your application-specific code into
this framework. Given the nature of C++ class programming, it is easy
to extend or override the basic functionality that the MFC framework
supplies.

The MFC framework is a powerful approach that lets you build upon the
work of expert programmers for Windows. MFC shortens development time;
makes code more portable; provides tremendous support without reducing
programming freedom and flexibility; and gives easy access to "hard to
program" user-interface elements and technologies, like Active technology,
OLE, and Internet programming. Furthermore, MFC simplifies database
programming through Data Access Objects (DAO) and Open Database
Connectivity (ODBC), and network programming through Windows Sockets. MFC
makes it easy to program features like property sheets ("tab dialogs"),
print preview, and floating, customizable toolbars.
[END CUT]


Skip call again. We're now in crackme3. Good.

001B:00401533  CALL      MFC42!ORD_0F22 // call to getwindowtexta
001B:00401538  MOV       ECX,[EBP-20] // from here
001B:0040153B  ADD       ECX,000000E4
001B:00401541  PUSH      ECX
001B:00401542  MOV       ECX,[EBP-20]
001B:00401545  ADD       ECX,60
001B:00401548  CALL      MFC42!ORD_0F22
001B:0040154D  MOV       EDX,[EBP-20]
001B:00401550  ADD       EDX,000000E0
001B:00401556  PUSH      EDX
001B:00401557  LEA       ECX,[EBP-1C]
001B:0040155A  CALL      MFC42!ORD_035A
001B:0040155F  MOV       EAX,[EBP-20]
001B:00401562  ADD       EAX,000000E4
001B:00401567  PUSH      EAX
001B:00401568  LEA       ECX,[EBP-10]
001B:0040156B  CALL      MFC42!ORD_035A // to here. Unimportant code

Just a waste of code, ignore it. The next part is more important.

001B:00401570  XOR       EAX,EAX
001B:00401572  XOR       EBX,EBX
001B:00401574  XOR       ECX,ECX
001B:00401576  MOV       ECX,00000001
001B:0040157B  XOR       EDX,EDX
001B:0040157D  MOV       EAX,[EBP-1C]

Set eax,ebx and ecx to NULL/0. Put the value 0x1 into ecx
Set edx to NULL/0. [EBP-1C] points to a buffer which has
the name. Move pointer to eax.

001B:00401580  MOV       BL,[EAX]
001B:00401582  XOR       BL,CL
001B:00401584  MOV       [EAX],BL
001B:00401586  INC       ECX
001B:00401587  INC       EAX
001B:00401588  CMP       BYTE PTR [EAX],00
001B:0040158B  JNZ       00401580

Mov byte in eax to bl. Xor bl with cl.
Mov xored byte to [eax] which is the pointer to our name.
Increase ecx and eax with one.'x+=1'. Is the current byte 00 ?
If not take next byte. Else continue.

That was the first part.

001B:0040158D  XOR       EAX,EAX
001B:0040158F  XOR       EBX,EBX
001B:00401591  XOR       ECX,ECX
001B:00401593  MOV       ECX,0000000A
001B:00401598  XOR       EDX,EDX
001B:0040159A  MOV       EAX,[EBP-10]

Almost the same as earlier. Set eax,ebx,ecx and edx to NULL/0. Mov 0xA
which is 10 in decimal into ecx. [EBP-10] is a pointer to the serial.
Move the pointer to eax.

001B:0040159D  MOV       BL,[EAX]
001B:0040159F  XOR       BL,CL
001B:004015A1  MOV       [EAX],BL
001B:004015A3  INC       ECX
001B:004015A4  INC       EAX
001B:004015A5  CMP       BYTE PTR [EAX],00
001B:004015A8  JNZ       0040159D

Move byte in [eax] to bl.
xor bl with cl. mov xored byte to [eax]
add one to ecx and eax. is the current byte 0x00 ?
if not take next byte. else continue

That was the second part.

001B:004015AA  MOV       EAX,[EBP-1C]
001B:004015AD  MOV       EDX,[EBP-10]

Mov ebp-1c pointer to eax. This is the namebuffer. But if you do "d ebp-1c"
in sice you won't see your name, and if you do ebp-10 you won't see your serial.
Why? It's because both name and serial have been 'made into something else'
when you arrive here. Encrypted in other words.

001B:004015B0  XOR       ECX,ECX
001B:004015B2  MOV       BL,[EAX]
001B:004015B4  MOV       CL,[EDX]
001B:004015B6  CMP       BL,CL
001B:004015B8  JNZ       004015C3
001B:004015BA  INC       EAX
001B:004015BB  INC       EDX
001B:004015BC  CMP       BYTE PTR [EAX],00
001B:004015BF  JNZ       004015B0

This is the comparing routine. It compares your name and serial, which
are both crypted. That means, the length must be equal or else it'll
never be correct. And the the crypted name must match the crypted serial.
To get a valid serial we'd have to code a keygen. And we'll do just that.

But first, some basic asm.

AX - The Accumulator
BX - The Base register
CX - The Counter
DX - The Data Register

These are all 16bit registers. You can store 2 bytes in a 16 bit register.

EAX
EBX
ECX
EDX

These are 32bit registers. You can store 4 bytes in a 32 bit register.

The E infront of AX,BX,CX and DX means extended.

AH
BH
CH
DH
AL
BL
CL
DL

These are 8bit registers. You can store only byte in a 8bit register.

EAX is related to AX,AH and AL
EBX is related to BX,BH and BL
ECX is related to CX,CH and CL
EDX is related to DX,DH and DL

I'll show you an example.

mov eax,DEADBEEFh

eax now holds the value DEADBEEFh
ax holds the 16 last bits in eax which is BEEFh
ah is the eight first bits in ax which is BEh
and al is the 8 last bits in ax which is EFh

eax=double word
ax=lower word in eax, two last bytes
ah,al=ah higher byte in ax,al lower byte in ax

I hope you understand this. It's really important stuff.

Now to the keygen. I'll comment the source. Only relevant code here.
---------------------------------------------------------------------
        invoke GetDlgItemTextA,hWnd,IDC_NAME,offset NameBuf,16h
        cmp al,6
        jb tooshort
	cmp al,15h
	jz toolong
        xor eax,eax
        xor ebx,ebx
        xor edx,edx
        mov ecx,00000001
        mov eax,offset NameBuf
lop1:
        mov bl, byte ptr [eax]
        xor bl,cl
        mov byte ptr [eax],bl
        inc eax
        inc ecx
        cmp byte ptr [eax],00
        jnz lop1
        xor eax,eax
        xor ebx,ebx
        xor edx,edx
        mov ecx, 0000000Ah
        mov eax,offset NameBuf
lop2:        
        mov bl, byte ptr [eax]
        xor bl,cl
        mov byte ptr [eax],bl
        inc ecx
        inc eax
        cmp byte ptr [eax],00
        jnz lop2
	popad
	invoke SetDlgItemText, [hWnd], IDC_SERIAL, ADDR NameBuf
---------------------------------------------------------------------
I made the source as identical to the original routine as possible. So
it would be easy to understand. I could have used only one loop for example.

I use GetDlgItemTextA to get the text from the namefield. It takes the 21 first
bytes and adds a 00 to the 22nd one. The returnvalue from GetDlgItemTextA is
the namelenght. I've limited the len to 20 chars. Buffers in C++ doesn't really
have limitchecks btw. If len = 21 chars go away.
Set eax,ebx and edx to NULL. Move 1 into ecx.
Move name into eax. move byte in eax to bl. xor bl with cl.
move xored byte to [eax]. INCrease eax and ecx. done? no, take next else continue.
set eax,ebx and edx to NULL.move 0xA to ecx which is 10 in decimal.
move eax crypted name. If we want to generate a valid serial we'll have to use
the serial encryption routine on our crypted name. So therefor mov eax, offset NameBuf.
I bet you know what the rest does.pushad and popad just pushes and pops the general
registers on and off the stack. Display the text with SetDlgItemTextA.
One thing I haven't explained yet is the minimum lenght. Take a look here:

.text:004014E0                 lea     ecx, [ebp-10h]
.text:004014E3                 call    ??0CString@@QAE@XZ ; CString::CString(void)
.text:004014E8                 mov     byte ptr [ebp-4], 1
.text:004014EC                 mov     ecx, [ebp-20h]
.text:004014EF                 add     ecx, 0A0h
.text:004014F5                 call    ?GetWindowTextLengthA@CWnd@@QBEHXZ ; CWnd::GetWindowTextLengthA(void)
.text:004014FA                 mov     [ebp-14h], eax
.text:004014FD                 cmp     dword ptr [ebp-14h], 5
.text:00401501                 jg      short loc_401508
.text:00401503                 jmp     loc_4015C3
.text:00401508 ; ---------------------------------------------------------------------------
.text:00401508 
.text:00401508 loc_401508:                             ; CODE XREF: .text:00401501j
.text:00401508                 mov     ecx, [ebp-20h]
.text:0040150B                 add     ecx, 60h
.text:0040150E                 call    ?GetWindowTextLengthA@CWnd@@QBEHXZ ; CWnd::GetWindowTextLengthA(void)
.text:00401513                 mov     [ebp-18h], eax
.text:00401516                 cmp     dword ptr [ebp-18h], 5
.text:0040151A                 jg      short loc_401521
.text:0040151C                 jmp     loc_4015C3
.text:00401521 ; ---------------------------------------------------------------------------
.text:00401521 
.text:00401521 loc_401521:                             ; CODE XREF: .text:0040151Aj
.text:00401521                 mov     eax, [ebp-20h]
.text:00401524                 add     eax, 0E0h


And the c++ source. Only relevant code here too.
---------------------------------------------------------------------
case IDC_GENERATE:
{
        len=GetDlgItemText(hWnd,IDC_NAME,Name,22);
        if(len<6 || len>20){
        	MessageBox(hWnd,"Min lenght=6 Max lenght=20",0,MB_OK);
        return 0;
        }
        for (a=1,b=0xA,i=0;Name[i];i++,a++,b++){
        	Name[i]=(Name[i]^a)^b;
        }
        SetDlgItemText(hWnd,IDC_SERIAL,Name);
}
---------------------------------------------------------------------
Here I've killed one loop and 'melted' the loops together.

That's all.
______________________
EFnet @ #New2Cracking
dihux - 2002






