|
|
|
|
|
|
|
|
|
|
||
|
||
|
|
There is a crack, a crack in everything. That's how the light gets in. |
|
|
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.
|
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.....
|
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
|
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.
|
Next | Return to Essay Index | Previous |