Tutorial #tE01
URLmaster v3.1 (C) by KARMADROME Software
Defeating the Softguard - A Keygen Attempt
18. Sep. 1999 
by tHE EGOiSTE 
18. Sep. 1999 
* Member of THE MILLENIUM GROUP [TMG] *
 
fra_00xx 
980715 
Sainas 
1100 
NA 
PC

About Urlmaster v3.1
URLmaster is an internet bookmark creator / editor and converter. It is used to create, edit or convert shortcuts that are used by web browsers, without the need to start up the browser itself.

The Protection System - SoftGuard v1.03
Yes, again we have to break a commercial protection system: SoftGuard v1.03 by Software.pair.com - www.soft-guard.com . Latest version is v1.10 I think. Soft-Guard is an ActiveX Control designed for using with Visual Basic 5.0/6.0 applications. Soft-Guard allows authors of shareware applications to easily and quickly add shareware evaluation periods to their applications. With just a few lines of code, authors can add the ability to handle the evaluation periods as well as calculate registration codes to unlock the evaluation period. Soft-Guard keeps track of evaluation period information and registered users in the Windows system registry.
Evaluation information is stored three times in the system registry, all of which are encrypted using different methods. Should a user attempt to edit the information, the evaluation period will be voided as the three locations that the information is stored do not match. Soft-Guard's features were designed to be easily implemented with only a few lines of code.
Soft-Guard generates a unique registration code based upon the user's name, an encryption key set by the programmer, and other optional choices. Registration codes can be formatted to your own style based upon multiple settings. The registration codes are mathematically calculated combining the user's name and the encryption key, and then formatted to your preferences. Soft-Guard also allows for the registration codes to be date sensitive, which also calculates the date into the code. The registration code will then only be valid on the date on which it was created

Shareware Notice
URLmaster is shareware. After 30 days evaluating this software you must purchase this software. The current cost for URLmaster is $15(US). After purchase, you will receive a serial number by e-mail which you use by entering in the relevent boxes in the registration screen. The screen is displayed every time an unregistered copy of URLmaster is run. All being well, URLmaster will be registered. This will remove the time limit and the nag messages.

Tho Cracking is pure fun, better stop giggling until you've reached the end of this essay ;-)
Skill Level
[ ] -Easy [X] -Medium [ ] -Hard [ ] -Punishment 


URLmaster v3.1
Softguard - really guarding your software ?
A Tutorial by tHE EGOiSTE
 

Introduction 

Well, after I quit my 'career' as standalone cracker and joined The Millenium Group, I think
the time is right to offer those of you who are interested in reverse-engineering this little
contribution - another small candle-light in the dark world of protection schemes.
Credits for the HTML Design fly over to +Fravia.   
	   
Required Tools 
- Numega's SoftIce v3.x or higher
- Your favourite Hex-Editor
- IDA Pro 3.8x (Additional)
- Your brain and some ASM and SICE knowledge ;-)
	
Program's URL 

http://karmadrome.prohosting.com/

The Essay 
 
Ok, prepare yourself for a long journey - here we go...

After downloading our target from the above URL, I installed it immediately and opened the
urlmaster.exe with Hex-Workshop (MY favourite Hex Editor ;-)) to catch some additional info
about the file. First thing which hit my eyes was that "MSVBVM60.DLL" String at file offset
0x248. "Hmm, another damn Visual Basic program.." I thought by myself and closed Hex
Workshop. Double-Click on urlmaster.exe, a short time of waiting and a Registration-dialog
popped up and told me that my "evaluation period has expired" (?) - it asked me to register
the program. To manage this it's necessary to provide the program with some data:

Username and Regcode... nothing special.
 
- I entered Username "Freakenstein" and Regcode "305419896" (==12345678H)
- then pressed Ctrl-D to popup SICE and entered "bpx hmemcpy" to set a breakpoint on the
  hmemcpy function.
- pressed F5 -> exit SICE and clicked the "Register" Button in the Registration Dialog.
- WHACK! SICE popped up and I found myself in the kernel at the beginning of hmemcpy().
  Read Razzia's tutorial "How to crack every VB program" to find out more about this
  function.
- traced through the code a few lines by pressing F10 until I reached the following code
  snippet: push ecx
           shr  ecx,02
           repz movsd    ; copy text (DWORD Blocks) from control to es:di 
           pop  ecx
           and  ecx,03
           repz movsb    ; if text dosn't fit DWORD border, copy the rest

- I adjusted the SICE-data window by entering "db es:di" BEFORE the "repz movsd" to have
  a look at the text which is going to be copied...
- F10 until repz movsd has been executed, a look at the data-window let me see:
  "Freakenstein" - 12 bytes in length. Ok, 12 MOD 4=0 - so the following repz movsb won't
  copy any more data, and that's correct of course :)
- So, no need to be interrupted by that bpx hmemcpy anymore. "bc *" cleared it (and all
  the other bpx's which were maybe set) away. 
- from here I traced through the code by pressing F10 and F12 until I finally left the
  kernel and the following MSVBVM60 Module and landed directly in the code section of
  another Module called "SOFTGUARD6!" 
- Softguard ??? Hmm, never heard about that -> F5, exit SICE. A MessageBox appeared "The
  Registrationcode you've entered is not correct for Freakenstein. Please try again." Of
  course I was gonna try it again. Hehe. But before that I did a little search using
  Altavista and finally found the Homepage of Sofware.pair.com - the home of Softguard.
  Read the info I got from there at the top of this tutorial.
- Went offline and repeated the above steps until I found myself in the SOFTGUARD6
  Module again. After reading all the stuff about encryption and time dependent codes
  at the Softguard manufacturer site I prepared myself for a long and hard fight...
  
- I came from         :           CS:11027B79  CALL [ECX+000000A0] ; Get Username
  actual code position:           CS:11027B7F  CMP  EAX,EDI  
                                                .
- looked some lines below and saw CS:11027BB4  CALL [ECX+000000A0] ; Get Regcode
                                                .
  I suspected "Get Regcode" for the last call, checked it and was right :-)

- A few F10's later I found the following lines of code:
 
  CS:11027BD2  mov  ecx, [EBP-2C]                ; address of my Regcode
  CS:11027BD5  mov  edi, [MSVBVM60!__vbaLenBstr] ; vb-lstrlen function
  CS:11027BDB  push ecx
  CS:11027BDC  call edi                          ; Returns length of Regcode -> eax
             . 
  CS:11027BE8  push edx
  CS:11027BE9  neg  ebx
  CS:11027BEB  call edi                          ; Returns length of Username -> eax
             .
  Note that both strings, Username and Regcode, have already been converted to UNICODE
  ( see MultiByteToWideChar()- function) at this point of time. So, don't expect
  "Freakenstein" but:
  "F",0,"r",0,"e",0,"a",0,"k",0,"e",0,"n",0,"s",0,"t",0,"e",0,"i",0,"n",0

- Ok, after I knew that the program has determined both String-lengths, I started tracing
  (F10) trough the code again... hundreds of lines later after I traced through the kernel,
  MSVBVM60 Module, kernel, MSVBVM60... I finally reached SOFTGUARD6 module again:

  I came from:     CS:11011253  call  [ecx+000002B0]  ; Registration Dialog/Length check
  and landed here: CS:11011259  test  eax, eax        ; Actual position
                               .

  It seemed to me that those "call  [exx+00000xxx]" lines are worth concentrating on.

- I kept that in mind and just found another one of those calls after some F10's:

  CS:110114D9  call  [ecx+00000874]
               .
 
- This time I used F8 to single step into that call so that I could see what's going on
  there. F8 again and the following jmp lead me directly to these lines of code:
 
  CS:11019540  push  ebp
  CS:11019541  mov   ebp,esp
  CS:11019543  sub   esp,08
              .
              .

- Some F10's/F8's later(I traced *every* call, except the __vba function calls, I found)
  I reached this (most important) call: CS:11019AC7  CALL  [EDX+00000844]

- F8 to step in and F8 once again to execute the following jmp, brought me to a routine at
  CS:1100DCB0 which is our 'MAIN' KEYCHECK routine es I figured out later...

 At this point of time we're DEEP in the body of that Softguard - Too late to stop!
    But don't worry. The fun-part just begun...
    
* IMPORTANT NOTE: Please take this 'tracing through the code' serious! You should know
  what's going on and keep a sharp look at the register-changes for the WHOLE time you
  work on that program. Some additional looking at the memory beeing accessed should be
  obvious. Every miss of an important value, a quickly traced 'call ...' because you're
  maybe bored can lead you directly to a GAME OVER - This means that nice "Registration
  code is not correct"- Message Box. So, pay attention! ;-) *	
  

- Ok, let's go on. 
  Remember our actual position ? No ? It's CS:1100DCB0. I continued tracing from here and
  found the following important (and of course MAGIC :-)) calls:
    
  1. CS:1100DD94  CALL  [EDX+000008A0] ; Removes all Chars <20h or >7Eh from Username
                                       ; and set new Namelength if necessary
  2. CS:1100DDD1  CALL  [EDX+000008A4] ; 'Scramble' Username, here: Freakenstein->nFireetaske
                                       ; I'll explain the "how to" later...
  3. CS:1100DE08  CALL  110247F0h      ; Build decimal codes from Chars of Scrambled Username
                                       ; and XOR every Char of a constant Key_1 (34 bytes long)
                                       ; with one char from these codes. Result: Key_2 (34b.) 
                                       ; If decimal-code length is <34 reset offset to 0 again...
  4. CS:1100DF30  CALL  [EDX+00000898] ; Reverse byte order of Key_2

  5. CS:1100E04F  -> Begin of loop which builds decimal codes from chars of Key_2 and stores
                     them in a buffer [B]
  

- Explanation of how to build these "decimal code" Strings follows later!

- Well, that was a far step in the right direction :-) What now follows is the generation
  of the FINAL KEY -> Key_F which will be compared later to the Regcode I entered
  in the Registration Dialog. The Key-generation works as follows:

  URLmaster v3.1 uses an ASCII-MASK to generate Key_F. After the loop at CS:1100E04F
  I landed into another loop at CS:1100E196 which generates Key_F by using the Chars
  from Buffer [B] and this mysterious ASCII-MASK. Here's the MASK and a short ex-
  planation of the Chars it consists of:
  
  UR###-#^#-###^^
  
  This Mask represents the format a valid Regcode MUST have. "U", "R" and "-" are constant.
  The key must contain them in same format as they appear in the MASK. Each "#" represents
  a decimal number between 0 and 9 (30h-39h) and every "^" represents an UPPERCASE letter
  ranging from "A" to "Z".
   
  You should be able to find that out by yourself while tracing through that loop at
  CS:1100E196. Hint: have a look at the memory location
  eax points to, after __vbaStrCat or __vbaStrVarMove function-calls...
  
  Generation of the "#"'s (the numbers)
  
  Well, that's pretty easy! The routine takes these values directly from Buffer [B]:
    
  01."#" ==> 01.Char from [B] 
  02."#" ==> 02.Char from [B]
  03."#" ==> 03.Char from [B]
  04."#" ==> 04.Char from [B]
  05."#" ==> 07.Char from [B]
  06."#" ==> 08.Char from [B]
  07."#" ==> 09.Char from [B]
  08."#" ==> 10.Char from [B]
  
  Generation of the "^"'s (the letters)
 
  01."^" ==> 05. and 06. Char from [B] ==> swap order (e.g. "49" -> "94") ==> ASCII to REAL8 
         ==> Check range of REAL8 value and adjust it if necessary ==> REAL8 to INT ==> INT
         to ASCII (THE letter)==> uppercase letter 
  02."^" ==> 11. and 12. Char from [B] =>... see 01.
  03."^" ==> 13. and 14. Char from [B] =>... see 01.
 
  That's all. Key_F has been generated. Name: Freakenstein - Regcode: UR851-2T4-641UY

  But I'm not finished yet. There're some important questions left I think ;-)
  
- That range-check/Letter calculation routine which contains all that floating point stuff is
  located at CS:1101D804. It uses rtcR8ValFromBstr function to convert the two-digit
  decimal ASCII-String to a REAL8 floating point value X. I examined that routine, and here's
  a summary of what it does (in same order as it appears in the routine):
  
  X = our REAL8 value
  
  IF X >=65 AND <=90 => DONE!
  IF X >=97 AND <=99 => DONE!
  IF X >=00 AND <=22 => ADD X,100 =>DONE!
  IF X >=91 AND <=96 => SUB X,6   =>DONE!
  IF X >=23 AND <=44 => ADD X,42  =>DONE!
  IF X >=45 AND <=64 => ADD X,52  =>DONE!
  
  Believe it or not (better check by yourself - Hehe) - this routine needs about 160(!) lines
  of code to do these few checks and a few additional error-checks (Invalid Operation, Zero
  Divide and Overflow). You see that the whole range of a possible value from a 2-digit decimal
  number is checked. (0-99). Before exiting that routine the final value (REAL8) will be
  converted to INT using the __vbaFpI4 function and then to a Char (our Letter) by using
  the rtcVarBstrFromAnsi function. This letter will be always changed to UPPERCASE ("a" -> "A")
  
  If you want to rip this HUGE check routine for your keygen, use IDA Pro to disassemble 
  the file 'softguard.ocx'. You'll find it in your WINDOWS\SYSTEM directory. For the number- 
  conversions you can use the following functions from MSVCRT.LIB:
  
      atof() -> Decimal String to float
     _gcvt() -> Float to Decimal String
      atoi() -> Decimal String to int
  
  Once examined that damn routine I reduced these 160 lines to a selfmade routine which doesn't
  use any floating point operations and which only consists of a few lines. Decide by yourself
  which routine you want to use. Here comes mine:
  
.DATA
add_tab db 23 dup(100)  ; add 100 to values from 00 - 22
        db 22 dup(42)   ; add 42  to values from 23 - 44
        db 20 dup(52)   ; add 52  to values from 45 - 64
        db 26 dup(0)    ; add 0   to values from 65 - 90
        db 6 dup(-6)    ; add -6  to values from 91 - 96
        db 3 dup(0)     ; add 0   to values from 97 - 99
to_int  db 0,0,0        ; buffer holds 2 digit Decimal-value for Letter-calc., ends with NULL
.CODE  
CalcLetter PROC
        call    atoi, offset to_int             ; decimal-string to int
        add     esp, 4                          ; correct stack
        lea     esi, add_tab
        mov     bl, byte ptr[esi+eax]           ; get value to add
        add     al, bl                          ; adjust
        and     eax, 0DFh                       ; to UPPERCASE
        RET
CalcLetter ENDP


- Ok. Now the final "secret" behind that key-calculation: The Username-'Scrambling'.

  Do you remember ? "Freakenstein" becomes "nFireetaske" - How ? Simple:
  
  1. Get Namelength
  2. Eliminate Char at position Namelength/2+1 -> Zero it!
     You've just divided the Name into 2 parts: "Freake" and "stein"
  3. Begin from Start of "Freake" and from the End of "stein" 
  4. Save "n" in destination buffer and decrease actual string-offset
  5. Save "F" in destination buffer and increase actual string-offset
  6. increase offset to destination buffer by 2
  7. loop until (the eliminated) 0-byte is reached and save last value
     which is non-zero (here: "e") at actual position of destination buffer.

 Here's my solution for this:
 
 ScrambleUserName PROC
        lea     esi, userinput      ; buffer which holds username
        mov     edi, esi
        lea     edx, scr_buff       ; destination buffer
        mov     ecx, nlen
        add     edi, ecx
        dec     edi
        shr     ecx, 1               ; length/2
        and     byte ptr[esi+ecx], 0 ; eliminate Char at Length/2+1
@@loop: mov     al, [esi]
        mov     ah, [edi]
        test    ah, ah
        je      @@out               ; exit loop if NULL byte has been reached
        mov     [edx], ah
        mov     [edx+1], al
        add     edx, 2
        inc     esi
        dec     edi 
        jmp     @@loop
@@out:  mov     [edx], al           ; store last non-zero value
        and     byte ptr[edx+1], 0  ; set byte after scrambled name to NULL
        RET
ScrambleUserName ENDP

Other questions left ? Here're the answers:

- The konstant Key which the author uses for encryption is this:
  db "^iAi>?FgxmU8r@obiwankenobiQGOGqeMe" - length: 34 Bytes
  It can be easily found in memory while tracing through the code. Greets
  to all Star Wars fans - have you noticed "obiwankenobi" ? :-)

- That "building of decimal codes" I told you of earlier, works as follows:
  Get value (e.g. 41h for "A") => 41h (65 Dec.) => convert to String "65" (36h,35h)
   
  That's all I think. I hope I could give you an answer to most of your questions.
  If you're not satisfied yet -> Try to find the answer by yourself. Make a Keygen!
  As you've seen it's not too hard.
    
  Seems that we're done :-) Here is a little Step by Step Summary for a Keygen:  
 
 1. Check length of Username - A length with less than 2 chars won't work
 2. Remove all Chars <20h or >7Eh from Username and adjust namelength if necessary
    Example: "ABC§DE" - length 6,  becomes: "ABCDE" - length 5 ("§"=A7h) 
 3. Scramble Username
 4. Build Decimal-codes of scrambled name e.g. "ABCs" --> "656667115"
 5. XOR the konstant key "^iAi>?FgxmU8r@obiwankenobiQGOGqeMe" with that Decimal-codes
    Byte by Byte. 34 times. If Decimal Code is <34 and you reached its end just begin
    from the start again... :-)
 6. Reverse byte order from Key_2 you got as result in Step 5. That means save that key
    from End to Start while increasing pointer to destination buffer.
 7. Build Decimal-codes of that reversed Key_2
 8. Generate valid key which has this format: UR###-#^#-###^^. Read above to find
    out how to...
 9. Keyoutput.
 A. Have fun :-)
 
 Furthermore don't call me stupid. I know that you can combine Steps 5 and 6 by storing
 the results of the XOR operations in reversed order -from End to Start-, but I just
 want to show you the way SoftGuard does this ;-) 
 
Final Notes 
 Another commercial protection system proved that it's just a waste of money to buy these
 so called "SECURITY" products. Of course there're some good commercial protection systems
 available, but Softguard is definately none of them. I know that it is very configurable
 and that it showed just a few of its features in URLmaster 3.1, but I had a look at the
 product (latest Demo version) as well, played around with it and came to the conclusion
 that it can't provide a *good* protection for a program... Some weeks ago I designed a
 Serial-based software protection which uses RC4 algorithm combined with some CRC's in less
 than 3 hours. This is only ONE of uncountable protection schemes on which 99.9% of all
 Crackers would break their balls on :-)
 
 Shareware-authors: Think about that! Use your brain and create your own protection
 schemes!
 
	

To contact me, visit #TMG on Efnet

END