Aug 1998
"Advanced Disk Catalog"
( 'Fake  Routines And Patching A DLL File'  )
Win Code Reversing
by The Sandman 
Code Reversing For Beginners 
Program Details
Program Name:
Program Type: Disk Utility
Program Location: Here 
Program Size: 1.2 Mb 
Tools Used:
 Softice V3.2 - Win'95 Debugger
W32Dasm V8.9 - Win'95 Dissembler
Easy ( X  )  Medium ( X  )  Hard (    )  Pro (    ) 
There is a crack, a crack in everything. That's how the light gets in.
Advance Disk Catalog V1.02b
( 'Fake Routines And patching A .DLL File'  )
Written by The Sandman
The author of Advance Disk Catalog  says:-
"Are you tired to remember which disk the particular file is on? Advanced Disk Catalog (ADC) is an easy to use tool with explorer-like interface which allows you to catalog the drives: floppy disks, hard drives (including network ones), optical disks, CD-ROMs, ZIP disks etc.

With ADC you are able to:

· Organise volumes, folders and files into categories;
· Add comment to each file, folder and disk;
· Analyse ZIP, ARJ, ARC and CAB archives, including self-extracting ones;
· Search for files/folders using file name names;
· Search for files in archives (registered version only);
· Generate customizable reports;
· Search for duplicated files;
· Extract description and version number from executable modules (EXE/DLL);
· Delete indifidual files and folders from the catalogs;
· Hide individual files in the catalog"
About this protection system
This program is a 30 day trial program, with a nag screen shown each time you run this program.

This program expects the User to enter a valid 32 alpha-numeric serial number, although it the actual code within the program has been coded to handle a 40 alpha-numeric serial number (for future releases?)

On successful registration the program creates the following entry in your System registry File:-

HKEY_LOCAL_MACHINE\Software\Elcom\Advance Disk Catalog\

Creating many sub entries but the sub entry we're interested in is found at:

HKEY_LOCAL_MACHINE\Software\Elcom\Advance Disk Catalog\Registration

Code = "Your serial number goes in here"
Where the program will eventually store your serial number in.
The Essay 
When I originally began cracking this babe I wanted to locate where in the program it create it's 32 alpha-numeric serial number, it's not hard coded into the program so it must generate this each time the User tries to Register this program.  By chance though, while surfing the web I came across the serial number for this program (no I wasn't looking for serial numbers) so I decided to try and see if this program could be easily patched instead.  One of the best places to patch a program such as this, is in the routine that checks your serial number against the one it expects.  The reason being is this:-

1.  In programs such as this, it is more than likely to use the SAME serial number checking routine to check to see if the User has entered in a valid serial number and  THEN every time you first run this program, where it will then read your serial number from the System registry file or .ini file ( which ever it uses to store your serial number) before deciding if the program is still Shareware or has been registered.
2.  In cases described above, a simple patch to a conditional jump is all that is required.

When I created a 'Dead Listing' of this program it was missing many of the shareware text messages that I knew this program used, so it must then get this information from somewhere else, another file perhaps, like a .DLL maybe!.
Sure enough, a quick look in the directory where Advanced Disk catalog resides, shows another file, a .DLL no less called Validate.DLL

While W32Dasm shows us a memory offset address for the assembly code in our 'Dead Listing'


:00401784 6A50             push 00000050
|<----->| <-----------------------------------Memory offset value

These 'offsets' address will be DIFFERENT when you come to using Softice because .DLL files are placed higher in the computer's memory than what W32dasm is able to figure out.

This therefore makes following a dead listing much harder when using Softice to trace through the code, since the memory offsets shown in Softice will be totally different to that shown in your dead listing.  The only thing that remains the same is the sequence of Assembly code instructions.

So for this essay I will continue to use the memory offsets provided by W32Dasm but when you come to using Softice these WILL be different.

Right, fire up W32Dasm and create a 'Dead Listing' of the Validate.DLL file.

Search for the text string: "Thank you for registering!"
* Referenced by a CALL at Address: :004018F7
:00401784 6A50             push 00000050
:00401786 689C344100       push 0041349C
:0040178B 6A64             push 00000064 ;="Quite enough to try..Sorry.."
:0040178D A194344100       mov eax, dword ptr [00413494]
:00401792 50               push eax
:00401793 E8B7DC0000       Call USER32.LoadStringA
:00401798 6A50             push 00000050
:0040179A 68EC344100       push 004134EC
:0040179F 6A65             push 00000065 ;"Thank you for registering!"
:004017A1 8B1594344100     mov edx, dword ptr [00413494]
:004017A7 52               push edx
Notice that there are NO conditional jumps before in this code snippet, so obviously the program has already decided that our serial was correct before it arrived to this routine. So we now have to back-track a little through the code until we come to a section of code that has some sort of conditional jump that will either execute the 'Beggar Off Cracker' routine' or to the one above, our 'Good Cracker' routine.

Our most important clue to where we must look is given by W32Dasm, where it shows:-

* Referenced by a CALL at Address: :004018F7

This tells us that our 'Good Cracker' routine gets executed at memory offset :004018F7, so lets take a look at this section of code:-

* Referenced by a (C)onditional Jump at Address :004018C5(C)
:004018CE 8B4D08           mov ecx, dword ptr [ebp+08]
:004018D1 890D94344100     mov dword ptr [00413494], ecx
:004018D7 6800400000       push 00004000
:004018DC 6A04             push 00000004
:004018DE E864DA0000       Call KERNEL32.GetProcessHeap
:004018E3 50               push eax
:004018E4 E8DAD90000       Call KERNEL32.HeapAlloc
:004018E9 8BF0             mov esi, eax
:004018EB 893578024100     mov dword ptr [00410278], esi
:004018F1 85F6             test esi, esi
:004018F3 7502             jne 004018F7  ;Our good Cracker Routine
:004018F5 33DB             xor ebx, ebx
:004018F7 E888FEFFFF       call 00401784 ;Our good Cracker Routine
:004018FC EB1D             jmp 0040191B

Now that we've arrived here this still isn't what we're looking for, because while it does have a conditional jump statement the program will STILL end up at our 'Good Cracker' routine wether or not the conditional jump statement is 'set' or 'not' because the 'Call' instruction below it will make sure of that.  So we must back-track further into the program and again W32Dasm shows us where to go next:-
* Referenced by a (C)onditional Jump at Address :004018C5(C)

One thing worth mentioning here, it's been pretty easy so far to back-track our way through the program because these routines are called from just one memory location, however, some programs may have two or more places which calls these types of routines and we would then have to check them all out, so that we don't miss anything important.
As it happens the above routine gets called by this section of code, which happens to sit right above it:-

:004018BD E852090000       call 00402214 ;Check our serial number.
                                         ;Returns with either:=
                                         ;eax=0 (Serial No invalid)
                                         ;eax=1 (Serial No valid)
:004018C2 59               pop ecx       ;Restore contents of ecx register
:004018C3 85C0             test eax, eax ;eax=0?
:004018C5 7507             jne 004018CE  ;Jump if eax not equal to '0'
:004018C7 6A00             push 00000000 ;
:004018C9 E813DA0000       Call KERNEL32.ExitProcess

What's important here is that the Call 00402214 returns with a value in the eax register, either a '0' or a '1'.  Now, if you've read some of my other essay's then you'll know that *most* shareware programs uses a memory location (it doesn't matter exactly where ) as a sort of flag, which if this memory location has a value of say '0' then the program knows it's running in Shareware Mode, but if, during the serial number validation the program finds your serial number to be correct, then it will place a value of '1', signifying that it has been registered.  Using the values '0' or '1' dates back to the old days of programming in binary, where numbers were represented in series of 1's and 0's.
OK, lets follow where the Call 00402214 takes us shall we..
*** Serial Checking Routine ***
* Referenced by a CALL at Address: :004018BD
:00402214 55               push ebp
:00402215 8BEC             mov ebp, esp
:00402217 51               push ecx
:00402218 E87ED10000       Call KERNEL32.GetVersion
:0040221D 85C0             test eax, eax
:0040221F 7D3E             jge 0040225F ;Serial Ok, so lets register prog.
:00402221 33C0             xor eax, eax ;Set eax to '0' (Shareware Mode)
:00402223 A340364100       mov dword ptr [00413640], eax ;Still Shareware
:00402228 A1700C4100       mov eax, dword ptr [00410C70]
:0040222D 85C0             test eax, eax
:0040222F 7438             je 00402269 ;Beggar Off Cracker
:00402231 8D55FE           lea edx, dword ptr [ebp-02]
:00402234 52               push edx
:00402235 50               push eax
:00402236 8B4D08           mov ecx, dword ptr [ebp+08]
:00402239 51               push ecx
:0040223A E889FEFFFF       call 004020C8
:0040223F 83C40C           add esp, 0000000C
:00402242 85C0             test eax, eax
:00402244 7423             je 00402269 ;Beggar Off Cracker
:00402246 668B45FE         mov ax, word ptr [ebp-02]
:0040224A 663B05740C4100   cmp ax, word ptr [00410C74]
:00402251 0F94C2           sete dl
:00402254 83E201           and edx, 00000001
:00402257 891540364100     mov dword ptr [00413640], edx ;Set *Reg Flag*
:0040225D EB0A             jmp 00402269 ;Beggar Off Cracker
:0040225F C705403641000100 mov dword ptr [00413640], 00000001 ;*REGISTRED!*
:00402269 A140364100       mov eax, dword ptr [00413640] ;GET EAX VALUE
:0040226E 59               pop ecx ;Restore registers
:0040226F 5D               pop ebp ;
:00402270 C3               ret ;Return to previous routine

There are two places in the above routine that the program can become fully *Registered*.. The first place the program decides that the serial is valid is near the beginning of this routine, where at:-

:0040221F         jge 0040255F will take the program directly to:-
:0040225F    mov dword ptr [00413640] , 00000001 where it saves the value '1' in a memory location designated by the program as the Shareware/Registered flag.

If, during this checking of our serial number the program finds our serial number is invalid, then it skips over the assembly instruction mov dword ptr [00413640] , 00000001 thereby leaving this memory location with the default value of '0', which is the default Shareware mode.

So our 'patch' is a simple one, we patch the jge 0040255F instruction into a jmp 0040255F so that the program ALWAYS accepts whatever serial number we give it.


We've been had!.  In reality this does not seem to happen.  Had we carried out this 'patch' then we would have found that it wouldn't work.  It seems all the code we've just examined is there to mis-lead us away from the 'real' routines, which look almost identical in places to the *real* ones used by the program!.  So dis-regard EVERYTHING shown above and only follow what is now being described.

Lets get softice to show us the way..

1. Start up Advanced Disk catalog and select the 'Register' button.
2. Type in anything you want for the serial number.
3. Press Ctrl-D to fire up Softice.
4. Type bpx messageboxa  then type x to leave Softice.
5. Now click on the 'OK' button.

Softice now breaks at the beginning of the system function messageboxa routine.

6. Press 'F11' key once and click the 'OK' button to the message 'The Code is invalid'.

Softice now displays the following code snippet...

Remember, the memory offset values shown by W32dasm will NOT match what Softice shows us, but the actual sequence of assembly instructions will still be the same. This is why I used :F8XXXXXX in place of any memory offsets shown by W32Dasm because that's where Validate.DLL gets loaded to on my puter.

* Referenced by a (C)onditional Jump at Address: 0040142D(C)
:F8XXXXXX 6A30            push 00000030
:F8XXXXXX 683C354100      push :F8XXXXXX
:F8XXXXXX 68DC354100      push :F8XXXXXX
:F8XXXXXX E8B4DF0000      Call USER32.GetFocus
:F8XXXXXX 50              push eax
:F8XXXXXX E89CDF0000      Call USER32.MessageBoxA
:F8XXXXXX FF0588344100    inc dword ptr [F8XXXXXX] ;Increase No of attempts
                                                   ;to register this prog.
:F8XXXXXX A188344100      mov eax, dword ptr [F8XXXXXX]
:F8XXXXXX 83F805          cmp eax, 00000005        ;user tried 5 times?
:F8XXXXXX 7E1E            jle F8XXXXXX             ;No? then carry on
:F8XXXXXX 6A10            push 00000010            ;else exit program
:F8XXXXXX 683C354100      push F8XXXXXX
:F8XXXXXX 689C344100      push F8XXXXXX

From this we see that we're in the 'Beggar off cracker' message routine, so lets see where in our 'Dead Listing' this same section of code is and follow that from there. We don't want to lose any newbies reading this essay..:)

We don't need Softice anymore, so type x to leave then quit Advance Disk Catalog and lets get back to our dead listing again. We used Softice to help us confirmed the *real* starting point in the code, and since Softice Breaks on the messageboxa function called by the above code we know for sure that this section of code is *real* and not placed by the programmers to fool us..

From our dead listing we quickly find that our starting point is here:-

* Referenced by a (C)onditional Jump at Address :0040142D(C)
:00401496 6A30             push 00000030
:00401498 683C354100       push 0041353C
:0040149D 68DC354100       push 004135DC
:004014A2 E8B4DF0000       Call USER32.GetFocus
:004014A7 50               push eax
:004014A8 E89CDF0000       Call USER32.MessageBoxA
:004014AD FF0588344100     inc dword ptr [00413488];Count No of attempts
                                                   ;we make at guessing the
                                                   ;serial number.
:004014B3 A188344100       mov eax, dword ptr [00413488] ;Save this number
:004014B8 83F805           cmp eax, 00000005  ;Have we tried 5 times?
:004014BB 7E1E             jle 004014DB       ;no? then jump
:004014BD 6A10             push 00000010      ;else exit the program.
:004014BF 683C354100       push 0041353C
:004014C4 689C344100       push 0041349C

Notice how similar the above code is to the one described near the start of this essay?.  Rest assured that this is the *real* routine.

Our dead listing tells us that the above routine  was called from memory location 0040142D, so lets take a closer look at this section of code..

:00401425 E8FE040000       call 00401928 ;Go check our Serial Number.
                                         ;Returns with either:=
                                         ;eax=0 (Serial No invalid)
                                         ;eax=1 (Serial No valid)
:0040142A 59               pop ecx
:0040142B 85C0             test eax, eax ;eax=0?
:0040142D 7467             je 00401496   ;yes? then Beggar off cracker

Before the program takes us to the 'beggar off cracker' routine it first checks our serial number, which it does with the Call 00401928 instruction. Lets follow this call and see where it takes us..

* Referenced by a CALL at Addresses: 004012BE, :00401425, :0040166C
:00401928 55               push ebp
:00401929 8BEC             mov ebp, esp
:0040192B 8B4508           mov eax, dword ptr [ebp+08]
:0040192E 50               push eax
:0040192F E8A0040000       call 00401DD4
:00401934 59               pop ecx
:00401935 5D               pop ebp
:00401936 C3               ret

Since there are no conditional jumps here we can be certain that this routine is not what we're after, however, the call 00401DD4 looks interesting and since this is the only place the program can go we too shall follow it..

* Referenced by a CALL at Address: :0040192F
:00401DD4 55               push ebp
:00401DD5 8BEC             mov ebp, esp
:00401DD7 83C4C0           add esp, FFFFFFC0
:00401DDA 53               push ebx
:00401DDB 56               push esi
:00401DDC 8B5D08           mov ebx, dword ptr [ebp+08]
:00401DDF 85DB             test ebx, ebx
:00401DE1 7507             jne 00401DEA ;Follow this jump
:00401DE3 33C0             xor eax, eax
:00401DE5 E988000000       jmp 00401E72
* Referenced by a (C)onditional Jump at Address :00401DE1(C)
:00401DEA 8A13             mov dl, byte ptr [ebx]
:00401DEC 84D2             test dl, dl
:00401DEE 7504             jne 00401DF4 ;Follow this jump
:00401DF0 33C0             xor eax, eax
:00401DF2 EB7E             jmp 00401E72

* Referenced by a (C)onditional Jump at Address: :00401DEE(C)
:00401DF4 6A40             push 00000040
:00401DF6 6A00             push 00000000
:00401DF8 8D55C0           lea edx, dword ptr [ebp-40]
:00401DFB 52               push edx
:00401DFC E8CB2A0000       call 004048CC
:00401E01 83C40C           add esp, 0000000C
:00401E04 53               push ebx
:00401E05 E8EE2B0000       call 004049F8
:00401E0A 59               pop ecx
:00401E0B 83F840           cmp eax, 00000040
:00401E0E 7E05             jle 00401E15 ;Follow this jump
:00401E10 B840000000       mov eax, 00000040

;By checking with Softice I found that this routine is called every time ;this program is first run and also to validate the serial number when the ;User tries to register Advanced Catalog Disk.

* Referenced by a (C)onditional Jump at Address :00401E0E(C)
:00401E15 50               push eax
:00401E16 53               push ebx
:00401E17 8D55C0           lea edx, dword ptr [ebp-40]
:00401E1A 52               push edx
:00401E1B E83C2A0000       call 0040485C
:00401E20 83C40C           add esp, 0000000C
:00401E23 8D4DD0           lea ecx, dword ptr [ebp-30]
:00401E26 51               push ecx
:00401E27 E8B0FEFFFF       call 00401CDC
:00401E2C 59               pop ecx
:00401E2D 8BD8             mov ebx, eax
:00401E2F 8D45D8           lea eax, dword ptr [ebp-28]
:00401E32 50               push eax
:00401E33 E8DCFEFFFF       call 00401D14
:00401E38 59               pop ecx
:00401E39 8BF0             mov esi, eax
:00401E3B 56               push esi
:00401E3C 53               push ebx
:00401E3D E836000000       call 00401E78
:00401E42 83C408           add esp, 00000008
:00401E45 85DB             test ebx, ebx
:00401E47 7420             je 00401E69 ;Invalid serial, keep as Shareware
                                       ;This also makes a great place to
                                       ;patch this program!.
:00401E49 85F6             test esi, esi
:00401E4B 741C             je 00401E69 ;Invalid serial, keep as Shareware
:00401E4D 8D45E0           lea eax, dword ptr [ebp-20]
:00401E50 50               push eax
:00401E51 E8F6FEFFFF       call 00401D4C
:00401E56 59               pop ecx
:00401E57 85C0             test eax, eax
:00401E59 740E             je 00401E69 ;Invalid serial, keep as Shareware
:00401E5B 8D55C0           lea edx, dword ptr [ebp-40]
:00401E5E 52               push edx
:00401E5F E82CFFFFFF       call 00401D90
:00401E64 59               pop ecx
:00401E65 85C0             test eax, eax
:00401E67 7504             jne 00401E6D ;Go register this program!
:00401E69 33C0             xor eax, eax
:00401E6B EB05             jmp 00401E72 ;Invalid serial, keep as Shareware

* Referenced by a (C)onditional Jump at Address: :00401E67(C)

:00401E6D B801000000       mov eax, 00000001 ;This sets our eax register
                                             ;to '1'.
                                             ;This is where the program
                                             ;actually registers itself!.

* Referenced by a (C)onditional Jump at Addresses:
:00401DE5(U), :00401DF2(U), :00401E6B(U)
:00401E72 5E               pop esi
:00401E73 5B               pop ebx
:00401E74 8BE5             mov esp, ebp
:00401E76 5D               pop ebp
:00401E77 C3               ret

Looking at the 'Serial Checking' routine we can see several conditional jumps that direct the program AWAY from executing the mov eax, 00000001 instruction, which is what assigns the eax register with that all important value of '1' which it later saves into a memory location that is treated as a flag to let it  know wether it should run in Shareware mode or Registered mode after it has checked our serial number.

Finally, in order to 'patch' this program we should change the FIRST conditional jump instruction that would normaly ignore the rest of the serial checking instructions so that it will ALWAYS jump directly to our mov eax, 00000001 instruction, thereby making sure that the program always runs in REGISTERED MODE.
Job Done.
The Patch 
Load up adc.exe into your favorite Hex-Editor ( I prefer hexWorkshop-32) but just about any Hex-Editor will do..

If you intend on using this program beyond it's evaluation period then please BUY IT!
Final Notes 
This might seem at first, a hard essay to follow and  to some extent it is, but valuable lessons can be learned from it.

While be able to read and understand dead listings is one thing,  we have to also make sure we understand the possible short falls of using this source of information on it's own.  We have to understand our tools weaknesses as well as their strengths.

 W32Dasm does not handle .DLL files very well, so if you create a dead listing of a .DLL then always remember that the memory offsets shown in your dead listing will not be the same when you come to using Softice to trace through the same .DLL file. Should you also come across a .DLL file such as the one described in this essay that has two sets of almost identical routines, then make sure you don't get these confused when you have to re-adjust your offsets from Softice back into the ones used by W32Dasm.
My thanks and gratitude goes to:-
Fravia+ for providing possibly the greatest source of Reverse Engineering
knowledge on the Web.
+ORC for showing me the light at the end of the tunnel.
Ob Duh 
Do I really have to remind you all that by buying and NOT stealing the software you use will ensure that these software houses will be encouraged to producing even *better* software for us to use and enjoy.

Ripping off software through serials and cracks is for lamers..
If your looking for cracks or serial numbers from these pages then your wasting your time, try searching elsewhere on the Web under Warze, Cracks etc.

 Next   Return to Essay Index   Previous 

Essay by:          The Sandman
Page Created: 2nd August 1998