
                 Crackme for newbies #1 - by woody^drn

Here is a crackme made in c++, I've compiled the program, so you can
see some of the variables ... thought it might be helpfull for some of
the newbies around. This time I'll try to show you how file checking
and reading is done.

Lets start the program ... it says "u n r e g i s t e r e d ! !" ..
Well lets load it into w32dasm. There are 3 places where it writes
unregistered:

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"
                                  |
:004104A9 68D7004200              push 004200D7

and ...

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"
                                  |
:0041054C 68F4004200              push 004200F4

and the last ...

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"
                                  |
:0041059B 6811014200              push 00420111


Lets check the first place where it will write the string.

:00410483 6A20                    push 00000020

* Possible StringData Ref from Data Obj ->"register.dat"
                                  |
:00410485 68CA004200              push 004200CA
:0041048A 6A00                    push 00000000
:0041048C 8D8570FFFFFF            lea eax, dword ptr [ebp+FFFFFF70]
:00410492 50                      push eax

* Reference To: cw3215.ifstream::ifstream(const char*,int,int),Ord:0000h
                                  |
:00410493 E8F4050000              Call 00410A8C
:00410498 83C414                  add esp, 00000014
:0041049B 8B8570FFFFFF            mov eax, dword ptr [ebp+FFFFFF70]
:004104A1 F6400C86                test [eax+0C], 86
:004104A5 7433                    je 004104DA
:004104A7 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"

Okay .. it looks for a file called "register.dat", then it call the
command ifstream(). But just before that it "lea eax, dword ptr ..."
and pushes eax. It's just like a messageboxa, it pushes all the variable
and strings it needs to open the file.

Then it check if the file is there, test [eax+0c],86 ... if the file
isn't there eax+0c will not be 86h. Lets create the file ..
Okay .. the file is there now, so lets see whats on 4104DA:

:004104DA 6A0A                    push 0000000A
:004104DC 6A13                    push 00000013
:004104DE 8D853CFFFFFF            lea eax, dword ptr [ebp+FFFFFF3C]
:004104E4 50                      push eax
:004104E5 8D45B4                  lea eax, dword ptr [ebp-4C]
:004104E8 50                      push eax

* Reference To: cw3215.istream::getline(char*,int,char), Ord:0000h
                                  |
:004104E9 E8B6050000              Call 00410AA4
:004104EE 83C410                  add esp, 00000010
:004104F1 6A0A                    push 0000000A
:004104F3 6A13                    push 00000013
:004104F5 8D8528FFFFFF            lea eax, dword ptr [ebp+FFFFFF28]
:004104FB 50                      push eax
:004104FC 8D45B4                  lea eax, dword ptr [ebp-4C]
:004104FF 50                      push eax

* Reference To: cw3215.istream::getline(char*,int,char), Ord:0000h
                                  |
:00410500 E89F050000              Call 00410AA4
:00410505 83C410                  add esp, 00000010
:00410508 33DB                    xor ebx, ebx
:0041050A EB17                    jmp 00410523

It reads two lines from the file, the first line is the name and the
second is the serial for the name. well lets write two lines in the
file, I write woody and 111666111.

First it puts the text in line 1 into [ebp+FFFFFF3C], and the second
line into [ebp+FFFFFF28]. When it has read those two lines, it will jump
to 410523.

:00410523 8D853CFFFFFF            lea eax, dword ptr [ebp+FFFFFF3C]
:00410529 50                      push eax

* Reference To: cw3215._strlen, Ord:0000h
                                  |
:0041052A E833050000              Call 00410A62
:0041052F 59                      pop ecx
:00410530 3BC3                    cmp eax, ebx
:00410532 73D8                    jnb 0041050C
:00410534 33F6                    xor esi, esi
:00410536 33DB                    xor ebx, ebx
:00410538 EB4B                    jmp 00410585

Now it will load the first line into eax, and the push the text in
line 1. Then it calls strlen which is a command that will see how many
characters there are in the line (eax). It xored ebx just before it
jumped here, so now it will compare eax with ebx. My first line was
woody, and it has 5 chars, so eax will be 4 (it starts with 0 .. 0,1,2,3
,4 .. that's five chars .....!). After comparing those two numbers
it will jump if eax is higher than ebx (jnb jump if not below), so
the program will jump here. Lets check whats there at 41050C:

:0041050C 0FBE841D3CFFFFFF        movsx eax, byte ptr [ebp+ebx-000000C4]
:00410514 50                      push eax
:00410515 E85AFBFFFF              call 00410074
:0041051A 59                      pop ecx
:0041051B 88841D14FFFFFF          mov byte ptr [ebp+ebx-000000EC], al
:00410522 43                      inc ebx

Here it moves the char from the first line into eax, it's ebp+ebx-0c4,
and ebx is zero now. Then it calls 410074, lets check what it does:

:00410074 55                      push ebp
:00410075 8BEC                    mov ebp, esp
:00410077 83C4F0                  add esp, FFFFFFF0
:0041007A 53                      push ebx
:0041007B 56                      push esi
:0041007C 57                      push edi
:0041007D 8B5508                  mov edx, dword ptr [ebp+08]
:00410080 B848024200              mov eax, 00420248
:00410085 BB40024200              mov ebx, 00420240

* Possible StringData Ref from Data Obj ->"0123456789ABCDEF0123456701"
                                  |
:0041008A BE70004200              mov esi, 00420070

This is kinda hard to explain, but when you execute the call, it just
takes the pushed char and makes the hex value of it. Like my name
woody is 77 6F 6F 64 79, but this time is only the first char (w) and
that is 77. The call returns the hex value in eax, more precise al.

So after that it moves al into ebp+ebx-0ec at line 41051B, and then
increses ebx (next char) ..

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041050A(U)
|
:00410523 8D853CFFFFFF            lea eax, dword ptr [ebp+FFFFFF3C]
:00410529 50                      push eax

* Reference To: cw3215._strlen, Ord:0000h
                                  |
:0041052A E833050000              Call 00410A62
:0041052F 59                      pop ecx
:00410530 3BC3                    cmp eax, ebx
:00410532 73D8                    jnb 0041050C
:00410534 33F6                    xor esi, esi
:00410536 33DB                    xor ebx, ebx
:00410538 EB4B                    jmp 00410585

Now we're back to the strlen again, it moves the first line into eax,
and compares the length of line 1 to ebx, ebx is now 1 .. but my first
line is 5 bytes long (4 ebx). So it will jump to 41050C again.

It will do this until ebx is equal to the length of line 1. After that
it xors esi and ebx. So now we have our name in hex at ebp+ebx-0ec.

It's finished with this routine, so it jumps to 410585. Lets check that
out:

:00410585 8D8528FFFFFF            lea eax, dword ptr [ebp+FFFFFF28]
:0041058B 50                      push eax

* Reference To: cw3215._strlen, Ord:0000h
                                  |
:0041058C E8D1040000              Call 00410A62
:00410591 59                      pop ecx
:00410592 3BC3                    cmp eax, ebx
:00410594 73A4                    jnb 0041053A
:00410596 4E                      dec esi
:00410597 7435                    je 004105CE
:00410599 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"
                                  |
:0041059B 6811014200              push 00420111
:004105A0 FF37                    push dword ptr [edi]

Okay .. remember when the program loaded those two lines, it moved the
lines into ebp+fffff3c and ebp+fffff28. fffff3c was the first line and
fffff28 was the second. So what it does here is move the second line
into eax, then it pushes eax and calls the strlen. The call returns the
length of the string in eax, then it compares eax to ebx .. and ebx is
zero and my second line was 111666111. and eax would now be 8.
Now it will jump if eax is greater than ebx, infact it says - jump if
eax is not below ebx, and eax is not below ebx so it will jump to 4105CE

:0041053A 8A841D14FFFFFF          mov al, byte ptr [ebp+ebx-000000EC]
:00410541 3A841D28FFFFFF          cmp al, byte ptr [ebp+ebx-000000D8]
:00410548 7435                    je 0041057F
:0041054A 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"U N R E G I S T E R E D ! !"
                                  |
:0041054C 68F4004200              push 004200F4

Here it moves the hex value of our name into al, then it compares al
with our password/serial. But it doesn't take the hole number, only
the first byte ... the first char in my name is w, and the hex value of
that is 77, so it takes the first byte in the hex - 7, and the decimal
for 7 is 37 in hex .. understand ?? sure you do :)

Now it compares 37 with my password which was 111666111, the value for 1
is 31 in hex, so the first number in our serial should be 37, but it's
31 (1 in decimal). The program will jump to 41057F if the numbers was
equal .. but it isn't so it will display the unregged message. So
lets go change our serial. woody -> 77 6F 6F 64 79 -> 76667.

Now the program jumps to 41057F. Lets check it out:

:0041057F BE01000000              mov esi, 00000001

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041057D(U)
|
:00410584 43                      inc ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00410538(U)
|
:00410585 8D8528FFFFFF            lea eax, dword ptr [ebp+FFFFFF28]
:0041058B 50                      push eax

* Reference To: cw3215._strlen, Ord:0000h
                                  |
:0041058C E8D1040000              Call 00410A62
:00410591 59                      pop ecx
:00410592 3BC3                    cmp eax, ebx
:00410594 73A4                    jnb 0041053A
:00410596 4E                      dec esi
:00410597 7435                    je 004105CE

And we're back to the strlen, it just moves 1 into esi and increses ebx
(next char) and compares eax (length of password) to ebx.
Lets say we're done matching the name in hex to the password, then it
will jump to 4105CE:

:004105CE 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"R E G I S T E R E D ! !"
                                  |
:004105D0 682E014200              push 0042012E

Nice :)

So the password for my name is 76667 ... easy ?


-wOODY^dRN

