|
||
|
|
|
|
| |
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. |
|
|
||
|
|
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 |
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!