|
|
|
|
|
|
|
|
|
|
||
|
||
|
|
There is a crack, a crack in everything. That's how the light gets in. |
|
"A utility for all JavaScript programmers
who are fed up with the fact, that their source code can be stolen and
simply modified. JavaScript Scrambler will scramble any
script source code until it is almost
impossible to comprehend for others."
|
Name
:
Serial No :
The registration code is based on what you type in for your name/handle,
it also varies in size (total No of alpha numeric characters) but usually
takes the form of: 1234-567-89
Once registered, the program saves the name & registration code
at:
C:\Windows\JSScrambler.ini file and takes the form of:
[JavaScript Scrambler]
Name=The Sandman
Serial Number=1936-957-76
Don't be lame and use my registration key, use one of you own.
|
"Inside almost all protection routines, as you have already learned, there is a moment when on the stack the ECHO of the real, "correct" passnumber or password appears. The location of this ECHO varies, but most of the time it'll be in a range of +- 0x90 bytes from one of the locations where the user input dwells. This is due to datadump windows constraints inside the tools used by the protectionists... but this use is bound to diminish... especially after this lesson :=)
The
trick of this lesson: [data_constraint], or "password proximity", bases
on the protectionist's need to keep an eye on the protection "working"
when he assembles it. He must "see" the relationships between USER INPUT
NUMBER, USER INPUT TRANSFORMED and the CORRECT NUMBER ANSWER (in our jargon:
the "Bingo").
These
relationships must be constantly checked In order to debug the protection
code. Mostly they will dwell TOGETHER inside a small stack area, allowing
them to be "seen" in the SAME watchwindow. Most of the time, therefore,
the "ECHO" will "materialize" shortly not very far away from one of the
locations of the USER INPUT."
To some of you, the underlined text sounds
a bit 'double-Dutch' (excuse the pun master) because our knowledge of Assembler
may be still weak, so let me try and explain what +ORC is saying here and
elaborate somewhat on it at the same time.
You probably already
know, that in programs that use a 'Password' or 'Registration Key' it MUST
be able to compare your entered password/Reg key with the one IT
expects you to have entered. Now, in order to do this the target
program (the one we want to crack) has to either, have the correct password
already at hand ( hard coded into the program it self) or, it has to generate
one itself in order to check your entered password/Reg Key. OK so
far?.
Here's where it gets interesting...
When it comes to
the actual checking of passwords/Reg keys the program usually has to place
them both very close by in the computer's memory and then it does the checking.
At this stage we are NOT concerned with the way the target program
creates or checks these passwords/Reg Keys, what does concern us that if
the target program can *see* both of these passwords/reg keys then why
can't we make use of this fact and get the target program to SHOW US
the real password/Regkey instead of telling us that our password/reg Key
was invalid!.
Up until now, I've
always gone for the 'Compare and Jump'
method to *crack* programs, which has meant I've always made my *cracks*
after
the target program has performed the validation check to the Password/Reg
Key. It would be here that I would do the 'Nop' (90h) or change the
conditional jump ( example Jnz ) into a full jump (example Jmp).
One of the most
popular *crack* methods for Registration Key\Serial No programs seems to
be making 'Key Generators*, whereby the cracker will create a small program
that, when the User enters a name into it this program it will generate
a valid key registration that the User can then use to register the target
program with. But this involves having to understand how the target
program works, more importantly, the algorithm it uses to create these
registration\serial numbers. As newbies, this might seem a little too difficult
but what-if there was a much *better* way to do the same job as these 'Key
Generators' AND requires very little understanding of Assembler!.
Lets proceed on
with cracking JavaScript Scrambler and incorporate our new crack method
into it..
Firstly, I created a 'Dead Listing' of the target program using W32Dasm, then checked the String Data Resources for any obvious 'Serial numbers', none present, but found a curious reference to the string "HEGRTZUINQYAXLPSWBMFOCDJKV,.- " which looks like a serial number and which, I'm now sure is used by the program itself during the process of creating the valid serial numbers.
Because I usually go for the 'Compare then Jump' crack method when the program decides to either jump to the 'Beggar off' routine or the 'Thank you for purchasing....' routine I double-clicked on the string reference: "The serial number you entered, "
This then brought me to this very interesting block of code (will explain why shortly):-
*
Referenced by a (C)onditional Jump at Addresses:00433F82(C),:00433FA0(C)
:0043406D B8A0414300
mov eax, 004341A0 ;"The serial number
; you entered was wrong"
:00434072 E86DB1FFFF
call 0042F1E4
:00434077 33D2
xor edx, edx
:00434079 8B832C020000
mov eax, dword ptr [ebx+0000022C]
Look, there are two places in the target program (:00433f82 and :00433FA0 ) that decides if the serial number we enter is wrong, so lets go and find them. From their offset location they are very close to each other..:)
TAKE A LOOK AT THIS!. The protectionist
has kept all his code together, was easier for him to test and debug it
and certainly makes our task to *crack* it easier too..:)
What we have here are our two conditional
jumps to the 'Beggar off Cracker' routines, we also have the routine that
creates the SScramble.ini file for when our serial is found to be correct
and which, places into our entered User name and Serial No.
:00433F82 0F8EE5000000
jle 0043406D ; Tell cracker to Beggar off
:00433F88 8D4DF4
lea ecx, dword ptr [ebp-0C]
:00433F8B 8B55FC
mov edx, dword ptr [ebp-04] ;Our
User Name Loc
:00433F8E 8BC3
mov eax, ebx
:00433F90 E81BFAFFFF
call 004339B0 :Generarte
our Serial No
:00433F95 8B45F4
mov eax, dword ptr [ebp-0C];points to the
;'real' serial No
:00433F98 8B55F8
mov edx, dword ptr [ebp-08]
:00433F9B E8A0FBFCFF
call 00403B40
:00433FA0 0F85C7000000
jne 0043406D ;Tell cracker to Beggar
off
;if serial No wrong, else
;lets create an .ini file
;and store the User's name
;and serial No in it.
:00433FA6 C6054859430001
mov byte ptr [00435948], 01
|
:00433FAD B9D4404300
mov ecx, 004340D4 ;Name of our .ini file
;is JSScramble.ini
:00433FB2 B201
mov dl, 01
:00433FB4 A1D4F34200
mov eax, dword ptr [0042F3D4]
:00433FB9 E872B4FFFF
call 0042F430 ;Create
our .ini file
:00433FBE 8BF0
mov esi, eax
:00433FC0 8B45FC
mov eax, dword ptr [ebp-04]
:00433FC3 50
push eax
:00433FC4 B9EC404300
mov ecx, 004340EC ;Save "Name=" to the
;.ini file
:00433FC9 BAFC404300
mov edx, 004340FC
:00433FCE 8BC6
mov eax, esi
:00433FD0 E8EFB4FFFF
call 0042F4C4 ;Save to .ini file our
;user Name/handle
:00433FD5 8B45F8
mov eax, dword ptr [ebp-08]
:00433FD8 50
push eax
:00433FD9 B91C414300
mov ecx, 0043411C ;Save "Serial Number="
;to the .ini
file
:00433FDE BAFC404300
mov edx, 004340FC
:00433FE3 8BC6
mov eax, esi
:00433FE5 E8DAB4FFFF
call 0042F4C4 ;Save to .ini file our
;our serial No.
:00433FEA 8BC6
mov eax, esi
:00433FEC E85FEDFCFF
call 00402D50
:00433FF1 B834414300
mov eax, 00434134 'Display 'thank you' mesg
:00433FF6 E8E9B1FFFF
call 0042F1E4
If, like me you 'Nop' (90h) the two conditional jumps at memory offsets:-
:00433FA0 0F85C7000000
jne 0043406D
:00433F82 0F8EE5000000
jle 0043406D
then when you enter your fake serial number the program will accept it and proceed to create the SScramble.ini file with your name\handle along with your fake serial number. I hasten to add here that this does NOT then make the program registered, since when you run the program again it will load in the serial number from the .ini file and checks to see if indeed the serial is correct, which it isn't so it will then assume it's still unregistered. Nice try though, some programs do actually save the 'Real' serial number to the .ini file instead of the fake one but not this one..:( Back to square one.
If we were to continue with this plan of
attack then we would then now have to search through the target program
and disable the check that it does on our fake serial number when it's
first run, but isn't this getting a bit complicated, after all, there are
much better ways to deal with this program..
It was at THIS point that what +ORC was
saying about "Memory Echo's" suddenly began to make sense, I could feel
something different about this program that made me think twice about my
plan of attack towards this protection system.
When I was in Softice I single stepped
my way through the above code, watching what happened with my fake
serial number and still being able to see the 'real' serial being formed
character by character and here I was, watching both of these at the same
time in one small softice window.
Let's take another look at that 'Beggar off cracker'
routine:-
*
Referenced by a (C)onditional Jump at Addresses:00433F82(C),:00433FA0(C)
:0043406D B8A0414300
mov eax, 004341A0 ;"The serial number
; you entered was wrong"
:00434072 E86DB1FFFF
call 0042F1E4
:00434077 33D2
xor edx, edx
:00434079 8B832C020000
mov eax, dword ptr [ebx+0000022C]
:0043407F E86868FEFF
call 0041A8EC ;Create
a messagebox
:00434084 33D2
xor edx, edx
:00434086 8B8330020000
mov eax, dword ptr [ebx+00000230]
It's creating a message box on the screen which tells us that our serial number was wrong, and if you look at this message in memory it ends with a '0' byte, signifying to the messagebox routine that it's the end of the message, and if you look at the 'real' serial number in memory then that too also ends with this '0' byte. Can you feel it yet?.
The real serial number
which is stored in memory is, to the computer like the 'beggar off cracker'
text, so why not get the 'Beggar off cracker' routine to show this real
serial number instead of it telling us to beggar off!.
All we need to do is
pre-load the memory location of the 'Real' serial number instead of the
'Beggar off' message, so my first attempt was to change the memory location
of the 'beggar off' message and have it 'pointing' to the location of the
'Real' serial number. This was achieved by changing:
:0043406D
mov eax, 004341A0 ;==>Location of 'beggar off'
messg.
TO
:0043406D
mov eax, 007A8594 ;Now points to the 'real' serial
No.
This worked once, and the 'real' serial
was displayed correctly instead of the 'Beggar off' message but running
the program again resulted in garbage being shown instead.
Running Softice showed me that the memory
location of the 'real' serial number as well as my input was now being
stored in a different memory location to what it was a minute ago!. What
gives?. Then I thought, well if this is happening then how does the
program know where to always look for the real serial number if its memory
location is always changing due what other programs is currently in memory..
Re-examining this section of code again
under Softice again suddenly showed me the answer I sought.
:00433F82 0F8EE5000000
jle 0043406D ; Tell cracker to Beggar off
:00433F88 8D4DF4
lea ecx, dword ptr [ebp-0C]
:00433F8B 8B55FC
mov edx, dword ptr [ebp-04]
:00433F8E 8BC3
mov eax, ebx
:00433F90 E81BFAFFFF
call 004339B0
:00433F95 8B45F4
mov eax, dword ptr [ebp-0C];This instruction
;ALWAYS points to
;the memory
;location of our
;'real' serial No!
:00433F98 8B55F8
mov edx, dword ptr [ebp-08]
:00433F9B E8A0FBFCFF
call 00403B40
So, if the mov
eax, dword ptr [ebp-0C] instruction always knows where in memory
our 'real' serial is, then why can't I use it instead of the using
mov
eax, 007A8594 and just pad the now, free
spaces created when we used an instruction taking fewer bytes than the
one we just replace with a few Nop's (90h)!!!
So that's what I did, and it worked!.. So now if you enter the wrong
serial number the target program now tells you what you should have typed
in, much better than the 'old' 'beggar off' message..:) So now we not only
*cracked* the program but we've also turned it into our very own 'Serial
key Generator'!.
Job Done.....
|
00033450 83F80100 008B10FF
52508B93 EC010000 ........RP......
00033460 8B83E801 0000E845
D2FFFFEB 35B8A041 .......E....5..A
00033470 4300E86D
B1FFFF33 D28B832C 020000E8 C..m...3...,....
Now REPLACE the following HIGHLIGHTED bytes:
00033450 83F80100 008B10FF
52508B93 EC010000 ........RP......
00033460 8B83E801 0000E845
D2FFFFEB 358B45F4 .......E....5.E.
00033470 9090E86D
B1FFFF33 D28B832C 020000E8 ...m...3...,....
Or, if you prefere, you can use this crack
loader, which I made using RTD'S PATCH ENGiNE V2.0 - Thanks guys..:)
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,5 ; Loop 5 times for each of the replaced bytes
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 'JSSCRAM.EXE', 0
filehandle dw 0
lowsize
dw 62976
highsize
dw 3
readbyte
db 0
logo
db '[PATCH FOR [FILEIN] GENERATED BY THE SANDMAN', 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'
db ' DiFFERENT!',0Dh,0Ah,'$'
sizemismtch
db 'SJiT!',0Dh,0Ah,'þ FiLE iS PACKED
OR WRONG'
db ' VERSiON!',0Dh,0Ah,'$'
erroropen
db 'SJiT!',0Dh,0Ah,'þ CAN', 027h,'T
OPEN FiLE'
db '!!',0Dh,0Ah,'$'
ofs
dw 13421 , 3 , 13422 , 3 , 13423 , 3 , 13424 , 3
dw 13425 , 3
data
db 184, 139 , 160, 69 , 65, 244 , 67, 144
db 0, 144
code ends
end start
|