May 1998
"JavaScript Scrambler V1.11"
( Using the memory echo crack  )
Win '95 PROGRAM
Win Code Reversing
 
 
by The Sandman 
 
 
Code Reversing For Beginners 
 
 
 
Program Details
Program Name: Scram111.zip
Program Type: Javascript Code Protection
Program Location: Here or  Here
Program Size: 136K 
 
   
Tools Used:
Softice 3.2 - Debugger
W32Dasm V8.9- Disassembler
 
Rating
Easy ( X )  Medium (   )  Hard (    )  Pro (    ) 
There is a crack, a crack in everything. That's how the light gets in.
 
  
 
JavaScript Scrambler V1.11
( Using the memory echo crack  )
Written by The Sandman
 
 
 
Introduction
 
The author(s) of this utility can be found at:  http://members.tripod.com/~tier
 
The author says:

"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."
 
About this protection system
 
Registration is via selecting the 'Register' tab.. Here you will be asked to enter:-

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.
     
The Essay 
     
I was reading one of +ORC's  tutorials a few days ago and one part in particular interested me greatly. +ORC explained briefly about 'Memory Echo's' and 'Memory Dumps' where the real passwords (as generated by the target program itself) could be accessed easily if you knew where to find them.  Like most newbies I read this section and then carried on with reading the rest of the tutorial, little realizing that a few days later I would *discover* this technique for myself and use it successfully to make a very interesting *crack*.  I didn't plan on using this particular technique, it just presented itself as the *best* method to do this *crack*.  Firstly, here's the section of text I read in +Orc's tutorial:-

"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.....
 
The 'Crack' 
 
Load up jsscram.exe into your favourite hex editor and
SEARCH for the hex string: "EB35B8A0414300"

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
 
 
Final Notes 
 
This program might be on the basic side but I learnt a hell-of-a-lot of about cracking registration/serial programs but more importantly, the memory echoing of the password/serial number that we can exploit to our own advantages.
 
Once I had located the memory location of where the program generates our real serial number I confirmed this by placing a Softice bpm (break point on memory access RW) on this area to confirm that this was the area the program uses, and not an area that could be used to confuse us, then quickly found that it was after the 'Beggar off cracker' message that the program erases the password in memory.  Then all I had to do was check that the program didn't alter the base address of the ebp register before I had chance to use the  mov eax, dword ptr [ebp-0C] instruction, it didn't, so it was safe to proceed and use this new instruction.

We didn't have to know anything about 'Direct memory addressing' or 'Indirect memory addressing to work out why one instruction differs with the other, or that the ebp register is used like a sliding ruler by the target program, where simply by specifying an offset to the base address of the ebp register we can address memory locations above and below it. The patching we did, replacing one 'direct memory addressing' instruction with an 'Indirect memory addressing' can certainly make the difference to a crack.
    
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: 27th May 1998