Tutorial Cracking :|
Target : ResizeImage v3.3
Tool : SoftIce v4.05, QBASIC)
At first, launch SoftICe.
Then launch our target, ResizeImage.exe !
A popup window shows up (called a nag-screen) asking to enter a name and a serial.
Well, we'll try to find how this protection is running.
Let's enter HarvestR as a name and 12121212 as a serial.
Don't click the OK button yet, but hit CTRL & D to bring up SoftICe.
We'll define a breakpoint, using the classical BPX GetWindowTextA.
Hit CTRL-D again to go back to the program.
Click OK and... SoftICe pop up, with the words:
Break due to BPX USER32!GetWindowTextA
Well, as we entered 2 fields (name and serial), let's type CTRL-D again.
SoftIce pops again with the same words than above.
We should begin to trace the code from here, but while cracking this program,
I saw that another GetWindowTextA call was done, so, to avoid you to trace in crappy code,
just type again CTRL-D.
Now we're at the right place, were the breakpoint bringed us. (if u hit CTRL-D one more time,
you'll get the message "wrong key", meaning you missed the interesting part... the calculation of the true code).
Hit F11 key to go back to the code that called the GetWindowTextA API.
You must see, in the code window title, ResizeImage!.text......, and, under that, the begining of our code.
You should see hex value where I put xxxx, but as it can be different on each computer,
I'll use this way to paste the code here.
xxxx:00436280 CALL [USER32!GetWindowTextA] <---- our breakpoint (3rd)
xxxx:00436286 push FF
xxxx:00436288 mov ecx, [ebp+10]
xxxx:0043628B call 00433DA5
xxxx:00436290 jmp 0043629D
We can step over the CALL at 0043628B (using F10) cause we won't find any interesting thing in it, then we jump to 0043629D
xxxx:0043629D pop edi <--------- we jump here
xxxx:0043629E pop esi
xxxx:0043629F pop ebp
xxxx:004362A0 ret 000C
continuing to use F10, we come back from the call (RET 000C) and we land in the following code:
xxxx:00406550 call 00436251
xxxx:00406555 pop edi <----- we are back here, from the CALL above
xxxx:00406556 pop esi
xxxx:00406557 ret 0004
continuing (yep, back from another call...) we arrive here:
xxxx:00432974 call [eax+0000008C]
xxxx:0043297A mov [ebp-18], 00000001 <---- we arrive here, back from the CALL
... several other lines of code here ...
xxxx:004329A3 ret 0004
continuing again, lots of CALL :)
xxxx:00406580 call 0043292C
xxxx:00406585 mov edi, [ebx] <--------- we are here this time...
Use F10 to pass the line 406585. then type D EDI, and you'll see our name in the data window.
It seems we are in the right place...
xxxx:00406587 mov ecx, FFFFFFFF
xxxx:0040658C sub eax, eax
xxxx:00406590 not ecx
xxxx:00406592 dec ecx
That's becoming interesting. This code will calculate the number of characters we entered as name.
This number will be stored in ecx. Just after we have:
xxxx:00406593 je 004066A4
If ecx=0 (no name entered) then jump to the line 4066A4, if not, continue:
xxxx:00406599 mov edi, [esi+5C]
Hit F10 to pass the line 406599. then type D EDI. Bingo, our fake serial is here.
Seems like we're on the right way.
xxxx:0040659C mov ecx, FFFFFFFF
xxxx:004065A1 sub eax, eax
xxxx:004065A5 not ecx
xxxx:004065A7 dec ecx
xxxx:004065A8 je 004066A4
Again, the test to define the length of the serial, and verifying it's not empty.
As our is 8 characters, we can continue:
xxxx:004065AE push 00000000
xxxx:004065B0 mov ecx, ebx
xxxx:004065B2 call 00433D50
We now meet a CALL. you can pass over it, no interesting code inside... use F10 to step over.
We continue and meet another CALL :
xxxx:004065B7 push eax
xxxx:004065B8 mov ecx, esi
xxxx:004065BA call 004066E0 <----------- interesting :)
Let's go into this code. Just type F8 to step into the jump. We can see:
xxxx:004066E0 sub esp, 0000002C
xxxx:004066E3 mov [esp], 00000005 *
xxxx:004066EB mov [esp+04], 00000003 *
xxxx:004066F3 mov [esp+08], 00000007 *
xxxx:004066FB mov [esp+0C], 00000001 *
Hmm, that's really strange... The program is storing some fixed values... Well,
we'd better remember that... 5, 3, 7, 1. We could see them later.
xxxx:00406703 push ebx
xxxx:00406704 push esi
xxxx:00406705 push edi
And now, another strange line.
xxxx:00406706 mov ebx, 12345678 *
storing the hex number 12345678 in EBX register... well, let's see more...:
xxxx:0040670B mov [esp+20], 00000002 *
xxxx:00406713 mov [esp+24], 00000006 *
xxxx:0040671B push ebp
xxxx:0040671C push 00000009
xxxx:0040671E mov [esp+30], 00000004 *
hmmm, some other hard coded numbers: 2, 6 and 4. Well, I think we'll meet them again later.
These numbers are not here without a reason, I presume.
xxxx:00406726 xor ebp, ebp *
xxxx:00406728 mov [esp+24], ebp *
Hop, do not forget this one... with the XOR, we know that now EBP=0, and it's stored too... hmm,
resuming what we met earlier, we have: 5, 3, 7, 1, 0, 2, 6, 4. well, could be an special ordered suite...
like "shaking" numbers from 0 to 7, no ? I you want to see the exact order where this numbers are in,
just type ED ESP+24, and hit CURSOR UP.
In the data window, you'll see something like:
xxxx:0068E874 00000005 00000003 00000007 00000001
xxxx:0068E884 00000000 00000002 00000006 00000004
Well, now it's time to be on the next line, wich is a CALL
xxxx:0040672C call 0041DFB0
nothing interesting here, several other CALLs inside, but nothing we need...
Let's pass over it with F10, to be on the following lines :
xxxx:00406731 mov edx, dword ptr [esp+44]
Hmmm, let's type D EDX, and we see that our name HarvestR is in the data window.
Well as we suppose that the serial number is build from our name, maybe that's becoming interesting.
xxxx:00406735 add esp, 00000004
xxxx:00406738 mov esi, eax
xxxx:0040673A mov edi, edx
xxxx:0040673C mov ecx, FFFFFFFF
xxxx:00406741 sub eax, eax
xxxx:00406745 not ecx
xxxx:00406747 dec ecx
xxxx:00406748 je 00406764
Hmm, how long is our name ? more than 0 ? good, let's continue
xxxx:0040674A inc ebp
Wait... EBP is now equal to 1... maybe a counter ?
xxxx:0040674B mov edi, edx
xxxx:0040674D movsx eax, byte ptr [edx+ebp-01] *
Hehehe, this line 0040674D is really interesting. We know that EBP=1 for now.
So, in EAX, will be loaded the byte (because of MOVSX instruction) at EDX+EBP-01,
which for now is equal to EDX+1-01, equal to EDX... :) Well, EDX is where is stored our name,
so it looks like the calculation is beginning. EX is now 48, the hex value for letter H.
xxxx:00406752 add ebx, eax
Bingo !!! You remember the line 00406706 [if no, just scroll up :)] ? EBX=12345678, and,
now we have EBX=EBX+EAX, so we have EBX=12345678+48. Our piece of code just added the hex value
of the first letter of our name to ebx... let's see further.
xxxx:00406754 mov ecx, FFFFFFFF
xxxx:00406759 sub eax, eax
xxxx:0040675D not ecx
xxxx:0040675F dec ecx
xxxx:00406760 cmp ecx, ebp
xxxx:00406762 ja 0040674A
Well, the code recalculates again the lenght of our name (still 8) and compare it to
the value of EBP (which is 1, as we saw sooner). While EBP < ECX, we loop to the line 0040674A.
ebp=2 (INC EBP)
eax=61 (hex value for a)
ebp=3 (INC EBP)
eax=72 (hex value for r)
8th Loop (and last one)
ebp=8 (INC EBP)
eax=52 (hex value for R)
basis + H a r v e s t R
Well, I hope you followed me here :).
The value in EBX is now 123459A7 (don't forget our addition is in hexa, not in decimal).
Let's examine what's happening after that.
We are now on the line:
xxxx:00406762 ja 0040674A
But this time, as ECX=EBP, we won't jump and continue bellow:
xxxx:00406764 lea eax, dword ptr [esp+30]
xxxx:00406768 push ebx
xxxx:00406769 push 00442854
xxxx:0040676E push eax
xxxx:0040676F call 0041D2F0
In line 00406768, it saves EBX, for a further use of it. We can bypass the CALL at 40676F
using F10 key, then continue here:
xxxx:00406774 add esp, 0000000C
xxxx:00406777 xor eax, eax
Bellow is another loop, from 406779 to 406789. Hehe, this part is really interesting for us...
it's creating the key we need to register our program. Let's have a look at it.
xxxx:00406779 mov ecx, dword ptr [esp+4*eax+10]
This move in ECX the value at ESP+10 (because EAX=0). Typing D ECX will show you the value 5...
remember the suite of numbers we met earlier ? 5, 3, 7, 1, 0, 4, 6, 2....
xxxx:0040677D inc eax
xxxx:0040677E cmp eax, 00000008
if EAX=8, we're in the last loop
xxxx:00406781 mov cl, byte ptr [esp+ecx+30]
xxxx:00406785 mov byte ptr [eax+esi-01], cl
xxxx:00406789 jb 00406779 <----- Loop while EAX < 8
These two lines are creating the final serial (the one we need to register the proggy).
CL= 9 (the number that is at [ESP+30] + 5)
store CL in [EAX+ESI-1] (=ESI)
CL= 4 (the number that is at [ESP+30] + 3)
store CL in [EAX+ESI-1] (=ESI+1)
CL= 7 (the number that is at [ESP+30] + 7)
store CL in [EAX+ESI-1] (=ESI+2)
CL= 3 (the number that is at [ESP+30] + 2)
store CL in [EAX+ESI-1] (=ESI+7)
Let's resume what happened.
We have our magic number 123459A7 and the suite 5, 3, 7, 1, 0, 4, 6, 2.
With the loop above, the program move each number to his final position:
- get the number at position ESP+330+5, store it at ESI (=9)
- get the number at position ESP+330+3, store it at ESI+1 (=4)
- get the number at position ESP+330+7, store it at ESI+2 (=7)
- get the number at position ESP+330+1, store it at ESI+3 (=2)
- get the number at position ESP+330+0, store it at ESI+4 (=1)
- get the number at position ESP+330+2, store it at ESI+5 (=3)
- get the number at position ESP+330+6, store it at ESI+6 (=A)
- get the number at position ESP+330+4, store it at ESI+7 (=5)
Our final serial is 947213A5.
Now we know how to calculate it, and that's the same scheme for all the names we could enter.
Here is the source of a QBASIC keygen (I know, you could thing strange I use this old language,
but it'll be easy for everyone to convert it to any other language).
I have added comments for some lines bellow:
---[ QBASIC CODE ]---
1) | CLS
2) | LOCATE 2, 1
3) | COLOR 3, 0: PRINT TAB(24); "Resize Image v3.3 «Serial Maker»"
4) | COLOR 7, 0: PRINT TAB(30); "by "; : COLOR 15, 0: PRINT "HarvestR CIA '98"; :
5) | LOCATE 5, 15: PRINT "Enter you Name : "; : COLOR 15, 0: LINE INPUT ; name$
6) | TmpVal# = 305419896
7) | FOR i = 1 TO LEN(name$)
8) | TmpVal# = TmpVal# + ASC(MID$(name$, i, 1))
9) | NEXT i
10) | TmpVal$ = HEX$(TmpVal#)
11) | FOR i = 0 TO 7
12) | code$(i) = MID$(TmpVal$, i, 1)
13) | NEXT i
14) | serial$ = code$(5) + code$(3) + code$(7) + code$(1) + code$(0) + code$(2) + code$(6)
15) | LOCATE 6, 15: COLOR 7, 0: PRINT "Your serial is : "; : COLOR 7, 4: PRINT " ";
---[ CODE EXPLANATION ]---
Lines 1 to 5 : display a short message and ask the user to enter his name.
Line 6 : declare TmpVal# = 305419896. Why ? Because that's the decimal value
of 12345678 hex :)
Lines 7 to 9 : add the ASCII value of each characters of the name to TmpVal#
Line 10 : convert the decimal value of TmpVal# into hex, puting them in a string.
Lines 11 to 13 : create a string called code$(i) for each number of our magic number
Line 14 : create the final serial by moving each number in the right place, according
to the suite we found (5,3,7,1,0,2,6,4)
Line 15 : display the final serial
Now you can register ResizeImage 3.3 with any name you want.
To unregister and try with another name, just delete resizeImage.ini in you Windows directory.