May 1998
"Guardian V1.2"
(Dead Listing our way through the code)
Win '95 PROGRAM
Win Code Reversing
 
 
by The Sandman 
 
 
Code Reversing For Beginners 
 
 
 
Program Details
Program Name: guardian.zip
Program Type: Win'95 Security
Program Location: Here or  Here
Program Size: 142K 
 
   
Tools Used:
W32Dasm
HexWork Shop32
Softice - (Only to test out my possible patches.)
 
Rating
Easy ( X )  Medium ( X  )  Hard (    )  Pro (    ) 
There is a crack, a crack in everything. That's how the light gets in.
 
  
 
Guardian V.2
( Dead Listing our way through the code  )
Written by The Sandman
 
 
 
Introduction
 
The author of this utility can be found at: http://www.netexp.net/~mrs/
 
This utility will allow you to limit the access users have to Win'95 by password protecting functions and keys that would otherwise allow people to change the default settings in Win'95..  In fact, this program reminds me of those early Win 3.1 shareware programs, minimal in content and basic looking...
 
About this protection system
 
Registration is via selecting the 'Register' tab where you are then asked to enter:

Name:                         Default value is "Shareware"
Registration Code:  Default value is "Shareware"

When first run the program creates a number of entries in the system registry file at:
HKEY_LOCAL_MACHINE\SOFTWARE\Guardian

Two string entries of interest are:-

Name        "Shareware"
RegCode "Shareware"

The program 'reads' these two values and uses them as 'default' values for the registration screen. The program calculates the Regcode from the name you type in, so in order to get the program registered we have three options.
 
1. Sniff out the Regkey for the name we type in and use this to register the program. A pretty lame thing to do.

2. Find a way to disable the checks the program does on the RegCode each time it is run so that it will accept any Regcode. A much better option.
 
3. Er...Create a Key Generator from the program's own RegCode Generator. The best option to choose but alas, I don't now enough  Assembler to do this *yet*.
This program is not compacted or encrypted in anyway.
 
 
The Essay 
     
This program was *cracked* solely by using the 'Dead Listing' approach, where-by I created a disassembled listing of the target program and then sat down and worked out what part of the code does what and more importantly, why. I used Softice only to test my patches/fixes but always returned to my Dead Listing to see where to go next.
 
If you have read some or all of +ORC's tutorials you will see that his listings are very well documented, but as newbies to all of this we can't possibly yet comment our source code as well as this so we must instead rely on what knowledge we have so far learned and combine this with a little Zen to guide us through this jungle of code.
 
Always remember, just cracking a program and progressing onto another is not enough, we must always try and find different ways to crack the target program, there are always more than one and each will require a different approach to succeed.  By the time we finish cracking a program we should have a pretty good idea how the programmer uses his particular type of protection, this will greatly help us to crack his future releases without us having to re-learn all that we have so far learned to achieve the same goal.
 
OK, were going to crack this Win'95 utility by just examine a 'Dead Listing' of the program itself, and to do this we will use W32Dasm V8.9 or might might want to try looking here for it if you haven't already found a copy.
 
While we don't have the actual source code for the Guardian, we can however use W32Dasm to disassemble the code in a nice and neat format for us so that it will can easily understand how the program works. We still have to work out what's happening in the program but at least we can get to see the whole picture which we wouldn't be able to do in Softice.

Common questions regarding 'Dead Listings' asked by newbies is "When do you use 'Dead Listings' and 'How do you know when to use Dead Listings to crack a program"
 
In answer to these questions I would say that using the Dead Listing approach is like any other method we may chose to use when faced with a new program and want to know as much information about it as possible. Dead Listings is just one of many tools we can use to attack a program with, but is not normally the only tool we should use. As in my particular case with Guardian, when I saw a Dead Listing of it I almost immediately saw a possible location to patch it because the overall layout of the program made it easy for me to follow it. That's the point, if you can follow the program's flow without too much difficulty when viewing a Dead Listing of it then that's half the battle already done for you!. Why make your task more difficult than is really necessary!.
 
Let's continue...

Run the target program (Guardian) several times, make any notes you feel is necessary about how it runs. We want to try and be familiar with how the program is laid out, noting in particular where the nag screens pop up, what they say, and any fancy bits they may use like a 'counter' of some sort that tells you how many days/uses you have left before it expires etc. Explore the 'Registration Screen', enter both valid and invalid characters like "£$%^&*()_~@?>< into where it expects the password/key code and note down any internal error messages given by the program itself, any runtime errors we can ignore. Runtime error messages are generated by Win'95 itself and often take the form of 'General Protection Fault at Module XXXXXX" and since messages these are not part of the program we won't find any references to them in the target program's code.  Also note how many character's the program lets us type in for the Password/Registration code, it's all useful information.
 
The first thing I always do is to check out the target program's String Data References, these string References are just ascii text in a readable form that are used throughout the program. In W32Dasm we can view these strings simply by clicking on the String Data References button or by selecting the menu option Refs and choosing String Data References.
 
So what are we looking for here?, well, a number of things that when we see it little alarms bells suddenly ring out.  I've seen in some programs a string of numbers all together that resembled a possible Registration Key, hard coded into the program itself without any form of encryption on it, it does still happen!.  We might also see useful clues to references to the locations of any .ini files or the location within the System registry where the program will store it's settings, along with any registration/passwords that the program may use.  It's also a good indication of any form of compaction used on the program if you see garbled up string references. If I had to put into some sort of order of what things I look for when viewing the String data then I would say:-

1. Any sequence of alpha numeric characters that resemble a Keycode, you never know..:)

2. Locations and names of any .ini files and, more importantly, the references to any items of data that gets posted into the system registry file.
 
3. References to any likely 'Beggar off' or 'Thanks for buying' messages, these will help to pin point the associate routines within the program, they are like a neon signs saying 'crack me, crack me" to crackers!.
 
There are others but these are my main considerations.

Right, having looked through the Guardian's String References I didn't see anything that resembled a password/registration key, I didn't expect to see any but it's worth checking all the same.
 
I did see the following though...
 
"G:\"
"Gaurdian"
"Green"
"Guardian"
"H:\"
"I:\"
"Image"
"Incorrect Password!"  <==== Beggar off cracker
"IsControl"
"J:\"
"K:\"
"l"
"L:\"
"Left"
"m/d/yy"
"M:\"
"MAINICON"
"SVWU"
"SysTabControl32"
"T:\"
"TApplication"
"TextHeight"
"Thank you for supporting the shareware " <===== Good Guy Message!
"The new password cannot be blank."
"The Password Entered is Invalid!"
"The Password has been changed!"
"The Passwords do not Match!"
"There is no password set. You "
"This function has been disabled "
"This program cannot be ran from "
"This will disable all security "
"Top"
"TPUtilWindow"
"True"
"You have entered an invalid registration"
 
There are two messages here that deserve further investigation, yes there are others but I have my reasons for choosing these two..:) lets look at the first one, the 'Incorrect Password' message.  Double-Click on this string reference to find out where it is.

 
1. "Incorrect Password"
 

:0042F2E3 8B45FC                  mov eax, dword ptr [ebp-04]
:0042F2E6 8B55F8                  mov edx, dword ptr [ebp-08]
:0042F2E9 E8E242FDFF              call 004035D0
:0042F2EE 7427                    je 0042F317
:0042F2F0 8B45FC                  mov eax, dword ptr [ebp-04]
:0042F2F3 BA8CF34200              mov edx, 0042F38C
:0042F2F8 E8D342FDFF              call 004035D0
:0042F2FD 7509                    jne 0042F308
:0042F2FF 803DC0C6430000          cmp byte ptr [0043C6C0], 00
:0042F306 740F                    je 0042F317
:0042F308 8B45FC                  mov eax, dword ptr [ebp-04]
:0042F30B BAA0F34200              mov edx, 0042F3A0
:0042F310 E8BB42FDFF              call 004035D0

:0042F315 7516                    jne 0042F32D ;Jump to Wrong password
                                               ;routine

:0042F317 A1BCC64300              mov eax, dword ptr [0043C6BC]
:0042F31C E82F2CFFFF              call 00421F50
:0042F321 A1B8C64300              mov eax, dword ptr [0043C6B8]
:0042F326 E82D2CFFFF              call 00421F58
:0042F32B EB0A                    jmp 0042F337 ;Jump to Wrong password
                                               ;routine

* Possible StringData Ref from Code Obj ->"Incorrect Password!"
 
:0042F32D B8B0F34200              mov eax, 0042F3B0
:0042F332 E8E98EFFFF              call 00428220
:0042F337 33C0                    xor eax, eax
:0042F339 5A                      pop edx
:0042F33A 59                      pop ecx
:0042F33B 59                      pop ecx
:0042F33C 648910                  mov dword ptr fs:[eax], edx
:0042F33F 6859F34200              push 0042F359
:0042F344 8D45F4                  lea eax, dword ptr [ebp-0C]
:0042F347 BA03000000              mov edx, 00000003
:0042F34C E81B40FDFF              call 0040336C ;Go and show message.
:0042F351 C3                      ret

For those experienced crackers reading this I know this isn't part of the security system I'm after but demonstrates how I, or anyone in position might make mistakes..:)
 
At first glance it might seem obvious that we have found what we have been looking for, two conditional jumps to our 'Invalid Password' routine, so if we were to re-direct them somehow we could make the program *always* accept our password.  The whole point to a conditional jump is that it controls the way the computer will execute certain blocks of code depending on certain conditions which the programmer has set.  For example, if password is correct then display a 'Thank you for purchasing....' or if the password is incorrect then say 'Invalid Password'.  But if you look at the above code ALL the conditional jumps stay within this block of code,  they only change the sequence of instructions that lead up to our 'Invalid Message' box, so by changing any of them won't bypass the 'invalid Password' message.  If we were to now check how the program gets to the above section of code by searching the dead listing for any calls to this block of code we *might* notice that it gets called very early on in the program, much sooner than we would expect. Placing a Softice breakpoint at :0042F32D within our target program will show that it this section of the code has nothing what-so-ever to do with the protection system, it's in fact to do with the User defined Password set at the start of the program.  The mistake came about by not realizing that 'Incorrect Password' and 'Incorrect Registration' are two different things entirely. Besides, if we really wanted to *break* our own User password for this program we would only have to look in the System Registry file to see what it is..:)
 
 

2. "Thank you for supporting the shareware.."

The only time I know of when a shareware program thanks you for supporting the shareware concept is when you buy a shareware product!.  This sounds like a good place to start sniffing around and with a sign post such as this to guide us our job is going to be quite easy.
 
:00431070 8B55FC                  mov edx, dword ptr [ebp-04]
:00431073 B80C124300              mov eax, 0043120C
:00431078 E8CF26FDFF              call 0040374C
:0043107D 83F806                  cmp eax, 00000006
:00431080 7507                    jne 00431089
:00431082 C605C0C6430001          mov byte ptr [0043C6C0], 01
:00431089 803DC0C6430001          cmp byte ptr [0043C6C0], 01
 
:00431090 0F858E000000            jne 00431124 ;This jump should not ever
                                               ;be 'set' because the
                                               ;cmp instruction is checking
                                               ;to see if the mov
                                               ;instruction really did
                                               ;place a 01 in mem location
                                               ;[0043C6C0]!
 
:00431096 BA18124300              mov edx, 00431218 ;==>"Thank you for.."
:0043109B 8B8300030000            mov eax, dword ptr [ebx+00000300]
:004310A1 E8EE0FFEFF              call 00412094
 
 
Well, here it is, the weak link in this, and many protection systems, a single conditional jump is all that keeps us away from registering our program!.  hard to believe the programmer spent so much time in designing a Registration screen that generates a keycode based on our input when we can now disable the whole process even before we even get into the registration screen to enter our key code. It gets even better but will explain after I've commented on the above snippet of code.
 
The first condition jump at memory location: :00431080 simply jumps over a few instructions but still remains within this section of code. So even if the conditional jump is 'set' or ignored we will still hit the second conditional jump at memory location: :00431090

This second conditional jump will either be 'ignored' because the tests performed on our registration code were found to be correct, therefore it will let the computer execute the instructions beneath it, which in this case tells the program to set about displaying a 'Thank You' message and then make the necessary arrangements to save the registration key in the system registry file for future reference.  However, should the checks on the registration key show we have entered an invalid registration key the jump will be 'set' and will tell the computer to jump to memory location: 431124 where it will inform the User that the registration key is invalid.
 
There are a number of things we can do to *patch* this program, we can change:-
 
jne 00431089       TO    jp 00431082

Which will then always make the computer proceed onto the next line regardless of the results from the cmp instruction above it.

OR, and the one I prefer in this particular case, we can simply Nop (90h) the whole jump out completely.  Some may say that Nop'ng is not the 'ideal' way to crack a program because some programs actually check for this happening, but this program does not, so I will use the Nop method here.

Nop'ng is simply inserting an instruction into the target program that tells the computer that when it encounters that it is to perform  '(N)o (op)eration' or ' do nothing', so no registers or memory locations will be effected by this instruction and is away of 'filling in' empty space within the program. We wouldn't want to effect any registers or memory locations just in case they are needed by the program itself.

Because this conditional jump is not jumping to a local memory address it uses the long form of addressing, so it uses extra memory locations to store the jump address in, so our Nop'ng will cover 6 bytes instead of the normal two used by local condition jumps.

After Nop'ng the above snippet of code will look like this:-

:00431070 8B55FC                  mov edx, dword ptr [ebp-04]
:00431073 B80C124300              mov eax, 0043120C
:00431078 E8CF26FDFF              call 0040374C
:0043107D 83F806                  cmp eax, 00000006
:00431080 7507                    jne 00431089
:00431082 C605C0C6430001          mov byte ptr [0043C6C0], 01
:00431089 803DC0C6430001          cmp byte ptr [0043C6C0], 01
:00431090 90                      Nop
:00431091 90                      Nop
:00431092 90                      Nop
:00431093 90                      Nop
:00431094 90                      Nop
:00431095 90                      Nop
:00431096 BA18124300              mov edx, 00431218 ;==>"Thank you for.."
:0043109B 8B8300030000            mov eax, dword ptr [ebx+00000300]
:004310A1 E8EE0FFEFF              call 00412094
 
Job Done.....
 
The 'Crack' 
 
Using any hex editor load up the file guardian.exe then:-

SEARCH FOR    :-  803DC0C64300010F858E000000
  
00030480 7507C605 C0C64300 01803DC0 C6430001 u.....C...=..C..
00030490 0F858E00 0000BA18 1243008B 83000300 .........C......

REPLACE WITH:-  803DC0C6430001909090909090 

00030480 7507C605 C0C64300 01803DC0 C6430001 u.....C...=..C..
00030490 90909090 9090BA18 1243008B 83000300 .........C......

Once you've run this program, simply run up the REGEDIT utility and go here: HKEY_LOCAL_MACHINE\SOFTWARE\Guardian then change:
 
Name="Shareware' to Name="Your Handle" then
Regcode="Shareware" to Regcode="some numbers like 12345678"
 
Or, if you prefer to create a Crack Loader.....
 
code            segment byte public
  assume cs:code, ds:code

  org 100h
start:
                mov     dx,offset logo          ; Show your logo
                call    write        ; write the message

                call    open_file    ; Guess what ?
                mov filehandle,ax    ; Put the filehandle in "filehandle"

                mov     dx,offset fsize
                call    write        ; write the message

                call    check_size   ; Check the current filesize

                mov     di,offset data ; Point di to data table
                mov     si,offset ofs  ; Point si to offset table
                mov cx,6               ; Loop 6 times for each of our Nops
                mov     dx,offset crackfile
                call    write   ; write the message

crackit:
                push cx   ; Save cx
                call    seek_file   ; Seek in the file
                call    read_file  ; Read one byte and compare
                call    seek_file  ; Seek again (back)
                call    write_file  ; Write the byte

                add     si,4   ; Add 4 to si 2*sizeof(word)
                add     di,2   ; Add 2 to di 2*sizeof(byte)
                pop cx   ; Bring cx back
                loop crackit   ; Loop Crackit

                mov     dx,offset cracksucc
                jmp     short goback

already_patched:
                mov     dx,offset alreadycrk
                jmp     short goback

size_mismatch:
                mov     dx,offset sizemismtch
                jmp     short goback
error:
                mov     dx,offset erroropen
goback:
               call    write   ; write the message
                call     close_file  ; Close the file
                mov     ah,4Ch                  ; Jump back to the operating system
                int     21h
Write           proc    near
                push ax
                mov     ah,9
                int     21h                     ; Display String
                pop ax
                retn
Write           endp

open_file       proc    near
                mov     ah,3Dh
                mov     al,2                    ; open file function 3Dh
                mov     dx,offset filenaam
                int     21h
                jb      error
                retn
open_file       endp

close_file      proc near
                mov     ah,3Eh                  ; close file function 3Eh
                mov     bx,filehandle
                int     21h
                retn
close_file      endp

check_size      proc near
                mov     bx,ax
                mov     ax,4202h
                xor     cx,cx                   ; Check the filelength
                xor     dx,dx
                int     21h
                jb      error
                cmp     ax, lowsize             ; (Lowbyte)
                jne     size_mismatch
                cmp     dx, highsize            ; (Highbyte)
                jne     size_mismatch
                retn
check_size      endp

read_file       proc near
                mov     ah,3fh
                mov     bx,filehandle           ; read file function 3Fh
                mov     cx,1
                mov     dx,offset readbyte
                int     21h
  mov ah,readbyte
                cmp     [di],ah                 ; Compare patched bytes
                jne     already_patched
                jb error
                retn
read_file       endp

write_file      proc near
                mov     ah,40h
                mov     bx,filehandle
                mov     cx,1                    ; write file function 40h
                mov     dx,di
                inc dx
                int     21h
                jb  error
                retn
write_file      endp

seek_file       proc    near
                mov     ah,42h
                mov     al,0
                mov     bx,filehandle     ; move file ptr function 42h
                mov     dx,[si]
                mov cx,[si+2]
                int     21h
  jnc  here
                jmp error
here:
                retn
seek_file       endp
 

filenaam        db      'GUARDIAN.EXE', 0
filehandle      dw      0
lowsize         dw      45568
highsize        dw      5
readbyte        db      0

logo            db      '[PATCH FOR [FILEIN] GENERATED BY RTD_PATCH^MR
                        WiCKED V2.0]', 0Dh, 0Ah
                db      'þ OPENiNG FiLE : ','$'
fsize           db      'OK!',0Dh,0Ah,'þ CHECKiNG FiLESiZE : $'
crackfile       db      'OK!',0Dh,0Ah,'þ CRACKiNG FiLE : $'
cracksucc       db      'OK!',0Dh,0Ah,'þ PATCH SUCCESSFULL!',0Dh,0Ah,'$'
alreadycrk      db      'SJiT!',0Dh,0Ah,'þ FiLE ALREADY PATCHED OR
                        DiFFERENT!',0Dh,0Ah,'$'
sizemismtch     db      'SJiT!',0Dh,0Ah,'þ FiLE iS PACKED OR WRONG
                        VERSiON!',0Dh,0Ah,'$'
erroropen       db      'SJiT!',0Dh,0Ah,'þ CAN', 027h,'T OPEN FiLE
                        !!',0Dh,0Ah,'$'

ofs             dw      1168 , 3 , 1169 , 3 , 1170 , 3 , 1171 , 3
                dw      1172 , 3 , 1173 , 3
data            db      15, 144 , 133, 144 , 142, 144 , 0, 144
                db      0, 144 , 0, 144

code  ends

end start
 
Final Notes 
 
This was a good program *crack*, even if I went a little off track to begin with. It was a good example to help me learn more about the power of using a 'Dead Listing' to work out how a program worked just from following the clues left behind by the programmer.
 
Using a 'Dead Listing' show's up quite clearly, the 'weak' points in a protection system to a point that it almost shout's out to us from the tv screen.

Finally, can anyone see where there is an even better place to crack this program, and, why the crack I've used is only 99.9% successfull!. Will let you work on that one..:) In the meantime I'm going off to get some much need sleep....

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 continue to  produce even *better* software for us to use and more importantly, to continue offering even more challenges to breaking their often weak protection systems.
 
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: 26th May 1998