Crack Tutorial by Vizion, 09/97

[TARGET...........]: 

ByteCatcher v1.03 (url : www.save-it.com)

[TOOLS............]: 

W32Dasm v8.9, SoftIce 3.01

[PROTECTION.......]: 

name/registration key type

[REMARK(s)........]: 

This program is probably cracked by a dozen of other persons, this target could be a nice addition to Fravia's "Most Stupid Protection" part of his page

[PRECRaCK NOTES...]: 

I assume that you have some knowledge about ASM and are able to use W32Dasm and SoftIce

[THe KEY..........]:

Ok, here we go. First of all make a dead-listing with W32Dasm to check what .dll files are used,  this is always usefull I was told ;). In WD32asm goto the "Imported Functions" part, there we  see the following :

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules =   13 (decimal)

   Import Module 001: WSOCK32.dll
   Import Module 002: WINMM.dll
   Import Module 003: KERNEL32.dll
   Import Module 004: USER32.dll          <-- interesting, so jump to user32.dll
   Import Module 005: GDI32.dll
   Import Module 006: comdlg32.dll
   Import Module 007: WINSPOOL.DRV
   Import Module 008: ADVAPI32.dll
   Import Module 009: SHELL32.dll
   Import Module 010: COMCTL32.dll
   Import Module 011: oledlg.dll
   Import Module 012: ole32.dll
   Import Module 013: OLEAUT32.dll

....

   Import Module 004: USER32.dll

...

 Addr:0008BD70 hint(0168) Name: IsWindowEnabled
 Addr:0008BD60 hint(01AF) Name: PeekMessageA
 Addr:0008BD4C hint(0245) Name: TranslateMessage
 Addr:0008BD38 hint(0090) Name: DispatchMessageA
 Addr:0008BD2A hint(00C8) Name: EnumWindows
 Addr:0008BD18 hint(013F) Name: GetWindowTextA    <--- interesting
 Addr:0008BD04 hint(00B8) Name: EnumChildWindows
 Addr:0008BCF2 hint(0152) Name: InvalidateRect
 Addr:0008BCE0 hint(01CC) Name: ReleaseCapture
 Addr:0008BCD2 hint(0194) Name: MessageBeep

...

Enough dead-listing for now. We can see that BC (ByteCacther) uses the GetWindowTextA function (also often used is : GetDlgItemTextA). So let's try it... start SI (SoftIce). Load BC and goto Help|About ByteCatcher. Now you'll see a register button in the "About-box". Press it! Ok now enter your information, I used :

registration number : 12121212
name                : Vizion
company name        : VCrackz'97

Press Ok. You'll get the message "Sorry that number is incorrect....". 
Ok, don't panic, get in SI (Ctrl-D), and set a breakpoint on "GetWindowTextA", 

type (in SI) : BPX GetWindowTextA

Get out SI (Ctrl-D, again). Press OK. CA!BOOM you should be back in SI, right in the GetWindowTextA function. Disable the the breakpoint

type (in SI) : BD 0

Press F11 to get back to the BC-code, write down the addr:offset for me it was 001B:0043C184 (addr could be different for you). Ok, back to the dead-listing in W32Dasm, in "Goto|Goto Code Location" use the offset you wrote down. Now you should see the following code :

* Reference To: USER32.GetWindowTextA, Ord:013Fh
                                  |
:0043C17E FF1574AF4800            Call dword ptr [0048AF74]
:0043C184 8B4D10                  mov ecx, dword ptr [ebp+10]
:0043C187 6AFF                    push FFFFFFFF
:0043C189 E87A82FFFF              call 00434408
:0043C18E EB0B                    jmp 0043C19B     <-- jump to 0043C19B

...

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043C18E(U)
|
:0043C19B 5F                      pop edi
:0043C19C 5E                      pop esi
:0043C19D 5D                      pop ebp
:0043C19E C20C00                  ret 000C    <-- return to 00413977 (*)

...

:00413977 8D4E60                  lea ecx, dword ptr [esi+60]
:0041397A 51                      push ecx
:0041397B 68F8030000              push 000003F8
:00413980 57                      push edi
:00413981 E8C9870200              call 0043C14F
:00413986 83C664                  add esi, 00000064
:00413989 56                      push esi
:0041398A 680B040000              push 0000040B
:0041398F 57                      push edi
:00413990 E8BA870200              call 0043C14F
:00413995 5F                      pop edi
:00413996 5E                      pop esi
:00413997 C20400                  ret 0004  <--- return to 00432E0F (*)

...

:00432E0F C7450801000000          mov [ebp+08], 00000001
:00432E16 EB27                    jmp 00432E3F    <--- jump to 00432E3F
:00432E18 B83C2E4300              mov eax, 00432E3C
:00432E1D C3                      ret

...

:00432E3F 8B45E8                  mov eax, dword ptr [ebp-18]
:00432E42 8B4DF4                  mov ecx, dword ptr [ebp-0C]
:00432E45 8987B8000000            mov dword ptr [edi+000000B8], eax
:00432E4B 8B4508                  mov eax, dword ptr [ebp+08]
:00432E4E 5F                      pop edi
:00432E4F 5E                      pop esi
:00432E50 64890D00000000          mov dword ptr fs:[00000000], ecx
:00432E57 5B                      pop ebx
:00432E58 C9                      leave
:00432E59 C20400                  ret 0004    <--- return to 00413A5A (*)

...

:00413A5A 8B465C                  mov eax, dword ptr [esi+5C]

* Possible StringData Ref from Data Obj ->"98437856278"
                                  |
:00413A5D 68FCF34700              push 0047F3FC
:00413A62 50                      push eax
:00413A63 E8B87F0000              call 0041BA20    <--- interesting
:00413A68 83C408                  add esp, 00000008
:00413A6B 85C0                    test eax, eax    <--- interesting
:00413A6D 7552                    jne 00413AC1     <--- jump if not equal
:00413A6F 57                      push edi                       
:00413A70 E84E6B0300              call 0044A5C3
:00413A75 8B4E5C                  mov ecx, dword ptr [esi+5C]
:00413A78 8B7804                  mov edi, dword ptr [eax+04]
:00413A7B 51                      push ecx

...

Ok, now what do we see,

* Possible StringData Ref from Data Obj ->"98437856278"

Now it can't be that simple can it :). Well let's presume we didn't see that... 
So now let's check the call (press F8 in SI, to enter the call) to 0041BA20 :

* Referenced by a CALL at Addresses:
|:00401F56   , :00401FD5   , :0040288C   , :00404296   , :00404C23   
|:004065F2   , :00406608   , :0040CA6A   , :0040CB2B   , :0040DDA1   
|:0040DDC3   , :00413A00   , :00413A63   , :00415BDB   , :00415BF1   
|:004163C5   , :00416841   , :0041701E   , :00417516   , :00417571   
|:00417BF1   , :004184D8   , :0042F9D8   , :0042FE23   , :0042FE3B   
|:0044082E   , :00443416   , :00443478   , :004434E2   , :0044369E   
|:00443764   , :0044382A   , :00447A16   , :0044D0CF   , :00454429   
|:0045B11E   
|
:0041BA20 A144764800              mov eax, dword ptr [00487644]
:0041BA25 53                      push ebx
:0041BA26 55                      push ebp
:0041BA27 33ED                    xor ebp, ebp
:0041BA29 56                      push esi
:0041BA2A 3BC5                    cmp eax, ebp
:0041BA2C 57                      push edi
:0041BA2D 7541                    jne 0041BA70
:0041BA2F 8B742418                mov esi, dword ptr [esp+18]  <--- move good value to esi
:0041BA33 8B442414                mov eax, dword ptr [esp+14]  <--- move your value to eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041BA5D(C)
|
:0041BA37 8A10                    mov dl, byte ptr [eax]       <--- get first char
:0041BA39 8A1E                    mov bl, byte ptr [esi]       <--- get first char 
:0041BA3B 8ACA                    mov cl, dl
:0041BA3D 3AD3                    cmp dl, bl                   <--- compare
:0041BA3F 7525                    jne 0041BA66                 <--- jump if not equal
:0041BA41 84C9                    test cl, cl
:0041BA43 0F84C7000000            je 0041BB10                  <--- jump if equal
:0041BA49 8A5001                  mov dl, byte ptr [eax+01]  
:0041BA4C 8A5E01                  mov bl, byte ptr [esi+01]        
:0041BA4F 8ACA                    mov cl, dl
:0041BA51 3AD3                    cmp dl, bl
:0041BA53 7511                    jne 0041BA66
:0041BA55 83C002                  add eax, 00000002            <--- add +2 to eax and esi
:0041BA58 83C602                  add esi, 00000002
:0041BA5B 84C9                    test cl, cl
:0041BA5D 75D8                    jne 0041BA37                 <--- jump if not equal
:0041BA5F 33C0                    xor eax, eax       
:0041BA61 5F                      pop edi                           
:0041BA62 5E                      pop esi
:0041BA63 5D                      pop ebp
:0041BA64 5B                      pop ebx
:0041BA65 C3                      ret                          <--- get out of call

...

Ok, interesting! Not? Well this part of the code you should run and check in SI, be sure to keep an eye on the values in dl an bl. Ok, you followed the code? You'll have noticed that's here where your code and the good registration code are compared. Your code will be in eax and the good one in esi. Try a "db esi" in SI and see what you get, now remember the line :

* Possible StringData Ref from Data Obj ->"98437856278". 

Well yes, the one and only good registration code is hard-coded in the program.
Well that's for finding the good key, what was very easy.

(*) you can get all the return addresses when you trace through the code in SI, by using F10, I suggest you do that...

[GREETZ...........]:

All people on #cracking4newbies and #cracking, members of Mexelite`97/c4n
Fravia for his (awesome) home page, Razzi, +ORC, and many others for there great tutorials

[FiNAL NOTE.......]:

This is my first tutorial, so I hope you where able to follow and to understand my way of thinking and working. Probably there some other ways to "pinpoint" the moment when your key is compared with the good one. But I thought for this target the basic (use F10 in SI) tracing was the easiest one. If you're a starter just like me, I suggest you read as many tutorials as possible. And try to crack everything you can lay your hands on. There will be more failure then succes, but like we say : No Pain No Gain!

A hard-coded key like in BC is almost never used but plain simple compare of 2 keys and the call&test routine are used very often.

So that's all folks, hope you enjoyed it and learned something,

Vizion.