Home    Training    Downloads    Tutorials    Arbitary    Get Fate    Proxy Info
 
Training session 26: Reverse Engineering
Difficulty: Medium
Learn some Tecniques of Reverse Engineering
Creator: m101


First thing you will need is a copy of winzip, for my purposes i am using 'WinZip 7.0 SR-1 (1285)' and using Hackers View and Win32DASM to crack. Dont worry if yours isnt the same, the code in all of them is pretty much the same crap so you can crack any version. Since this tutorial is designed to help the not so experienced, its methods are more fiddling than actual cracking, this is to help you understand how programs work aswell as how to crack them.

Make a copy of winzip32.exe and open up the copy in Win32DASM. Run you original copy and see what happens... ARRRG!! That stupid nag screen! For some reason nearly every computer apart from mine that i use, i see that stupid nag screen, its so annoying to have to click 'I Agree' every time i load it. So to fix our little problem, lets look at what options we have available, it appears we can enter a registration code to use it, or we can remove the nag screen. Im personally not a big fan of paying for a registration code, so lets play a bit with the code. Click 'Enter Registration Code...' and lets see what we are given. It appears we have to enter a name and a registration number, so lets enter some bogus information. 'Incomplete or Incorrect Information' Theres our error message, so lets crank up Win32DASM and search the String Data References for our error message. For me the message is String Resource 00654. Double click it and look at we have to play with:
:004080AE 6A01                    push 00000001
:004080B0 EB31                    jmp 004080E3

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00408051(C), :0040805A(C), :00408063(C)
|
:004080B2 E8E5010000              call 0040829C

* Possible Reference to String Resource ID=00654: "Incomplete or incorrect information"
                                  |
:004080B7 688E020000              push 0000028E
:004080BC E89B050200              call 0042865C
:004080C1 59                      pop ecx
:004080C2 50                      push eax
:004080C3 57                      push edi
:004080C4 6A3D                    push 0000003D
Hmmm, it appears that we have three references to this message from within a few lines of each other, so lets go and look at what we can do. Go to the first reference and check out the code:
:00408043 56                      push esi
:00408044 E879160200              call 004296C2
:00408049 803D28D9470000          cmp byte ptr [0047D928], 00
:00408050 59                      pop ecx
:00408051 745F                    je 004080B2
:00408053 803D58D9470000          cmp byte ptr [0047D958], 00
:0040805A 7456                    je 004080B2
:0040805C E8EAFAFFFF              call 00407B4B
:00408061 85C0                    test eax, eax
:00408063 744D                    je 004080B2
:00408065 53                      push ebx
So we have our three comparisons, two of a memory address and one of a diferent nature. The two memory addresses 0047D928 and 0047D958 look rather interesting so lets look at some of the code above to see if we can find what these refer to:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00407F7E(C)
|
:00408006 BB28D94700              mov ebx, 0047D928
:0040800B 6A29                    push 00000029
:0040800D 53                      push ebx

* Possible Reference to Dialog: DialogID_0C82, CONTROL_ID:0C80, ""
                                  |
:0040800E 68800C0000              push 00000C80
:00408013 57                      push edi

* Reference To: USER32.GetDlgItemTextA, Ord:00F5h
                                  |
:00408014 FF150C844600            Call dword ptr [0046840C]
:0040801A 53                      push ebx
:0040801B E879160200              call 00429699
:00408020 59                      pop ecx
:00408021 53                      push ebx
:00408022 E89B160200              call 004296C2
:00408027 59                      pop ecx
:00408028 BE58D94700              mov esi, 0047D958

* Possible Reference to Dialog: DialogID_0AF0, CONTROL_ID:000B, "On &Local hard drives"
                                  |
:0040802D 6A0B                    push 0000000B
:0040802F 56                      push esi

* Possible Reference to Dialog: DialogID_0C82, CONTROL_ID:0C81, ""
                                  |
:00408030 68810C0000              push 00000C81
:00408035 57                      push edi

* Reference To: USER32.GetDlgItemTextA, Ord:00F5h
                                  |
:00408036 FF150C844600            Call dword ptr [0046840C]
:0040803C 56                      push esi
:0040803D E857160200              call 00429699
:00408042 59                      pop ecx
Very interesting, we have two references to GetDlgItemTextA. For those slightly less knowledgable, this is a call to get the information from a field in a form such as our registration information. Since we have two references, we can pretty safely guess that these are both for our code. A GetDlgItemTextA is given in the following state:
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
);
Everything is pushed onto the stack in reverse order, so from this we can tell that we are looking for four push's, the first of which is an integer:
:00408006 BB28D94700              mov ebx, 0047D928
:0040800B 6A29                    push 00000029
:0040800D 53                      push ebx

* Possible Reference to Dialog: DialogID_0C82, CONTROL_ID:0C80, ""
                                  |
:0040800E 68800C0000              push 00000C80
:00408013 57                      push edi

* Reference To: USER32.GetDlgItemTextA, Ord:00F5h
                                  |
:00408014 FF150C844600            Call dword ptr [0046840C]
Heres our first, call, so lets look at it:
:00408006 BB28D94700              mov ebx, 0047D928 <=== Set ebx equal to 0047D928
:0040800B 6A29                    push 00000029 <=== Push our maximum string size to the stack
:0040800D 53                      push ebx <=== Push the address of our input to the stack, this value is now equal to 0047D928
:0040800E 68800C0000              push 00000C80 <=== The identifier of our control
:00408013 57                      push edi <=== The handle of the dialog box
:00408014 FF150C844600            Call dword ptr [0046840C] <=== our call to GetDlgItemTextA
So now we can pretty safely assume that one of our inputs are in 0047D928. By looking at the second GetDlgItemTextA, we can tell that our second piece of information is in 0047D958. Remember those tests we found? Well take a look at the corresponding compares:
:00408043 56                      push esi
:00408044 E879160200              call 004296C2
:00408049 803D28D9470000          cmp byte ptr [0047D928], 00
:00408050 59                      pop ecx
:00408051 745F                    je 004080B2
:00408053 803D58D9470000          cmp byte ptr [0047D958], 00
:0040805A 7456                    je 004080B2
:0040805C E8EAFAFFFF              call 00407B4B
:00408061 85C0                    test eax, eax
:00408063 744D                    je 004080B2
:00408065 53                      push ebx
The first two appear to be testing our inputs to see if they there is actually any input to process, if not its sends us to our error messsage. This means our last compare is the one that tells the program whether we are correct or not. To save you some time, if we were to just change the 'je 004080B2' to 'jne 004080B2' or nop it out, it would be a waste of your time, the code 'would' be accepted, but our nag screen would still come up because there is more than one check inside the program. Look above our test and see that call? Well its probably the place where the program checks the registration code. So lets have a look at our 'call 00407B5B':
* Referenced by a CALL at Addresses:
|:0040108C   , :00401228   , :0040805C   , :0042D0EC   
|
:00407B4B 55                      push ebp
:00407B4C 8BEC                    mov ebp, esp
:00407B4E 81EC08020000            sub esp, 00000208
:00407B54 53                      push ebx
:00407B55 56                      push esi
:00407B56 33F6                    xor esi, esi
:00407B58 803D28D9470000          cmp byte ptr [0047D928], 00
:00407B5F 57                      push edi
:00407B60 0F84A1000000            je 00407C07
:00407B66 8D45EC                  lea eax, dword ptr [ebp-14]
:00407B69 50                      push eax

* Possible StringData Ref from Data Obj ->"c"
                                  |
:00407B6A 6860F44600              push 0046F460
:00407B6F E84F9CFFFF              call 004017C3
:00407B74 59                      pop ecx
:00407B75 8D85F8FDFFFF            lea eax, dword ptr [ebp+FFFFFDF8]
:00407B7B 59                      pop ecx
We have four calls to this address, from this we can assume that these are our other checks. If we follow the code and ignore any calls and conditional jumps we come to:
:00407BFB E89C060000              call 0040829C
:00407C00 83257CB0470000          and dword ptr [0047B07C], 00000000

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00407B60(C)
|
:00407C07 33C0                    xor eax, eax
:00407C09 E9B3000000              jmp 00407CC1
Generally an xor eax, eax is used in serial generation to return a bad result to a test, so lets follow the jump:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00407C09(U)
|
:00407CC1 5F                      pop edi
:00407CC2 5E                      pop esi
:00407CC3 5B                      pop ebx
:00407CC4 C9                      leave
:00407CC5 C3                      ret
Just as i guessed, we have our return from the call. So lets go back and have a play with that xor eax, eax. The corresponding location in our program is 00007007. Crack open Hiew and go to this location in the program. F4, F3, F5, 7007 [enter]. Press F3 to edit, what we will do it make eax always greater than zero. Put the cursor at the start of that line and change 33 to 40 which will increment eax so it is definately greater than zero, and then change the C0 to 90 to get rid of it. Although using nops in this situation is rather lame, for educational purposes, it helps to stop confusion. Press F9 to update the file and then quit Hiew. Run our program and look, wow, no nag screen at all, the program still appears to be unregistered, but we have succeeded in removing that damn annoying nag screen!

Every once and a while i find myself at someones place without all of my tools and needing to crack something. In cases such as these, i am without my lovely Softice to debug values as they are changed, and Win32DASM's debugging features are extremely pathetic, so i will teach you a way to do it with minimal changes to the code. First lets examine to code to create a message box:
int MessageBox(
 HWND  hWnd,                          // handle of owner window
 LPCTSTR  lpText,                     // address of text in message box
 LPCTSTR  lpCaption,                  // address of title of message box  
 UINT  uType                          // style of message box
);
We need four fields, so lets replace our cracked copy of winzip with an uncracked one and have a look around in the code for an example message box. Go to 'Function > Imports' and look for MessageBoxA. Double click it and go through until you find a nice one to examine:
:0043E8F2 6A10                    push 00000010

* Possible StringData Ref from Data Obj ->"WinZip"
                                  |
:0043E8F4 68B80C4700              push 00470CB8
:0043E8F9 56                      push esi
:0043E8FA FF3508B84700            push dword ptr [0047B808]

* Reference To: USER32.MessageBoxA, Ord:0195h
                                  |
:0043E900 FF15EC834600            Call dword ptr [004683EC]
This ones reference to 'Winzip' tells us from its position on the stack that it is the window title. Remember those two memory addresses with our information in them? Well lets check which field corresponds to our information. Although this is rather pointless, it teaches you ways to modify programs to give you the information we want. Go back to the error message and scroll up till you see:
* Reference To: USER32.GetDlgItemTextA, Ord:00F5h
                                  |
:00408036 FF150C844600            Call dword ptr [0046840C]
:0040803C 56                      push esi
Get the hex location of the 'push esi' line and crack open Hiew again. Change it to the following based on our previous message box:
6A10				  push 00000010
6828D94700			  push 0047D928
6858D94700			  push 0047D958
FF3508B84700			  push dword ptr [0047B808]
FF15EC834600			  Call dword ptr [004683EC]
So first we push the style of the box, then our first value as the title of the message box, then the second as the content, and finally the handle of the owning window. Now save your work and load up Winzip again. Since we editted the input routine for our registration form, click register and enter some bogus information. Wow! Our information is displayed in a nice neat message box. Even tho the program crashes after this, we have forced the program to tell us values we normally couldnt find out without debugging the process using another program. To check other values, all we have to do is change the value that is pushed onto the stack and it will be revealed. Hopefully you have gained a little more knowledge from this and can apply it to other situations, there are many other ways to crack winzip, but ill let you find some of them...
Name

URL or Email

Message