Program : DiskFactory/32 v2.10 Cracked by : drlan [ME97] Date : 10/17/97 URL : www.shareware.com Protection : Very simple name and validation code Audience : Newbies Tools needed : SoftIce 3.x, Hex editor While much of this has been covered elsewhere, I'm going to include it again here to make this a comprehensive "newbie" tutorial. This has been blatantly plagarized from various sources. So, giving credit where credit is due: Thanks go to ED!SON, Razzia, Romeo and the rest of the cracking greats who published earlier essays for newbies covering much of this introductory info. For starters, you'll need to assemble your cracking toolkit. You'll find most of these resources on the web, or by asking senior crackers. These represent the tools we use most frequently, subject to some personal preference. The version listed is current as of this writing. Debugger : NuMega SoftIce 3.21 for Windows 95 (best by far!) : or Borland Turbo Debugger, Microsoft CodeView, Watcom, etc. Disassembler : W32Dasm 8.9 : or IDA 3.64, Sourcer 7.0, etc. Hex Editor : PS Edit 4.40 (small, fast, DOS) : or Hiew 5.66, Hex Workshop 2.53, Ultra Edit 4.40c, etc. Resource editor: Borland Resource Workshop 4.5 Assembler : Borland Turbo Assembler (TASM/TLINK) : or Microsoft MASM Registry watch : Shetef WinExpose/Registry 1.0 : or RegMon File I/O watch : Shetef WinExpose/IO 2.0 : or FileMon File Viewer : Inso Quick View Plus 4.0 There are lots of other tools and everyone has their personal favorites. But, this represents what I would consider a minimum set of tools for a serious cracking student. Get W32Dasm installed. You'll use it to dis-assemble programs, to have a look a the source code. This approach is called "dead listing." The live and the dead listing approach have their merits and you'll probably use them both. It's analagous to reading a road map (dead listing) vs. just driving around and checking things out (live cracking). Sometimes you may need to combine both methods. Get SoftIce installed. You'll use it to crack live. It allows you to step through a program that is running and allows you to view/change memory locations, registers, flags, etc. You can set breakpoints on execution, memory ranges, interrupts, etc. SoftIce will become your best friend. After you install SoftIce, you need to edit the WINICE.DAT file to make sure that certain "symbol exports" are enabled. You do this by removing the semicolon (;) from the front of the line. Here is a copy of my WINICE.DAT. ; General Variables NMI=ON SIWVIDRANGE=ON LOWERCASE=OFF ; Disable lowercase assembly MOUSE=ON ; Enable mouse NOLEDS=OFF ; Disable led switching NOPAGE=OFF PENTIUM=ON ; Pentium op-codes THREADP=ON ; Follow thread process VERBOSE=ON ECHOKEYS=OFF PHYSMB=32 ; Exact memory size SYM=512 ; Memory allocated to symbols HST=128 ; Memory allocated to history TRA=128 ; Memory allocated to back trace buffer MACROS=32 ; Startup Sequence INIT="lines 60;ww;wl;wr;wd 24;wc 24;code on;x;" ; Funtion Keys F1="h;" F2="^wr;" F3="^src;" F4="^rs;" F5="^x;" F6="^ec;" F7="^here;" F8="^t;" ; Step into functions (Trace) F9="^bpx;" ; Set breakpoint F10="^p;" ; Step over functions (Procedure) F11="^G @SS:ESP;" ; Step out of function F12="^p ret;" ; RETurn from caller SF3="^format;" CF8="^XT;" CF9="TRACE OFF;" CF10="^XP;" CF11="SHOW B;" CF12="TRACE B;" AF1="^wr;" AF2="^wd;" AF3="^wc;" AF4="^ww;" AF5="CLS;" AF8="^XT R;" AF11="^dd dataaddr->0;" AF12="^dd dataaddr->4;" CF1="altscr off; lines 60; wc 32; wd 8;" CF2="^wr;^wd;^wc;" ; WINICE.DAT ; (SIW95\WINICE.DAT) ; for use with SoftICE Version 3.0 (Windows 95) ; 14 Aug 1996 ; ************************************************************************* ; If your have MORE than 32MB of physical memory installed, change ; the PHYSMB line to the correct # of Megabytes. ; If you have LESS than 32MB you can save a bit of memory by ; specifying the correct # of Megabytes ; Example: PHYSMB=32 ; ************************************************************************* ; ***** Examples of sym files that can be included if you have the SDK ***** ; Change the path to the appropriate drive and directory ;LOAD=c:\win95\system\user.exe ;LOAD=c:\win95\system\gdi.exe ;LOAD=c:\win95\system\krnl386.exe ;LOAD=c:\win95\system\mmsystem.dll ;LOAD=c:\win95\system\win386.exe ; ***** Examples of export symbols that can be included ***** ; Change the path to the appropriate drive and directory ;EXP=c:\win95\system\vga.drv ;EXP=c:\win95\system\vga.3gr ;EXP=c:\win95\system\sound.drv ;EXP=c:\win95\system\mouse.drv ;EXP=c:\win95\system\netware.drv ;EXP=c:\win95\system\system.drv ;EXP=c:\win95\system\keyboard.drv ;EXP=c:\win95\system\toolhelp.dll ;EXP=c:\win95\system\shell.dll ;EXP=c:\win95\system\commdlg.dll ;EXP=c:\win95\system\olesvr.dll ;EXP=c:\win95\system\olecli.dll ;EXP=c:\win95\system\mmsystem.dll ;EXP=c:\win95\system\winoldap.mod ;EXP=c:\win95\progman.exe ;EXP=c:\win95\drwatson.exe ; ***** Examples of export symbols that can be included for Windows 95 ***** ; Change the path to the appropriate drive and directory EXP=c:\win95\system\kernel32.dll EXP=c:\win95\system\user32.dll EXP=c:\win95\system\gdi32.dll EXP=c:\win95\system\advapi32.dll ;EXP=c:\win95\system\comdlg32.dll ;EXP=c:\win95\system\shell32.dll ;EXP=c:\win95\system\shell232.dll ;EXP=c:\win95\system\comctl32.dll ;EXP=c:\win95\system\crtdll.dll ;EXP=c:\win95\system\version.dll ;EXP=c:\win95\system\netlib32.dll ;EXP=c:\win95\system\msshrui.dll ;EXP=c:\win95\system\msnet32.dll ;EXP=c:\win95\system\mspwl32.dll ;EXP=c:\win95\system\mpr.dll The important export symbol lines to enable are: EXP=c:\win95\system\kernel32.dll EXP=c:\win95\system\user32.dll EXP=c:\win95\system\gdi32.dll EXP=c:\win95\system\advapi32.dll Here's a very brief summary of SoftIce commands. You can find detailed help files on the web, or via help within the program. I suggest you download the users' guide and command reference. ? ; print a number, or the value of a register, in hex and decimal D ; display (data/ASCII or hexadecimal values) BL ; list all current breakpoints BC ; clear breakpoints (BC 0 - clears breakpoint 0, BC * - clears all) BD ; disable breakpoints BE ; enable breakpoints BPX ; breakpoint on execution BPM ; breakpoint on memory (read/write) BPR ; breakpoint on memory range BPMB ; breakpoint on memory byte BPINT ; breakpoint on interrupt (e.g., BPINT 21, BPINT 3) BPIO ; breakpoint on io (useful for dongle cracking) F4 ; view user screen F5 ; enter/exit SoftICE screen (same as Ctrl-D) F8 ; step into a function (same as T - trace) F10 ; step over a function (executes the line of code) F11 ; step out of a function (throws you back at the caller) F12 ; return to caller (same as P RET - process to next RETurn) Here are some various breakpoints useful in our trade. For the "enter your name and reg code" type dialogs GetDlgItemText ; 16 bit GetDlgItemTextA ; 32 bit GetWindowText ; 16 bit GetWindowTextA ; 32 bit GetDlgItemInt When you get a message that the serial number is wrong MessageBeep SendMessage ; 16 bit SendMessageA ; 32 bit For "nag screens" MessageBox ; 16 bit MessageBoxA ; 32 bit DialogBox DialogBoxParam ; 16 bit DialogBoxParamA ; 32 bit For string comparisons lstrlen lstrcmp For registry settings RegSetValueEx RegSetValueExA RegQueryValue RegQueryValueEx RegQueryValueExA GetPrivateProfileString GetPrivateProfileStringA GetProfileString GetProfileStringA GetStartupInfo For date limits GetLocalTime GetSystemTime For nags that pop up after some amount of time SetTimer KillTimer When GetWindowText, GetDigItemText and GetDlgItemInt fail, try Hmemcpy - or - BMSG window-handle [L] [begin-msg [end-msg ]] [IF expression] [DO "command1;command2;..."] window-handle HWND value returned from CreateWindow or CreateWindowEX. begin-msg Single Windows message or lower message number in a range of Windows messages. If you do not specify a range with an end- msg, only the begin-msg will cause a break. Note: For both begin-msg and end-msg, the message numbers can be specified either in hexadecimal or by using the actual ASCII names of the messages, for example, WM_QUIT. end-msg Higher message number in a range of Windows messages. L Logs messages to the SoftICE Command window. c= Breakpoint trigger count. IF expression Conditional expression: the expression must evaluate to TRUE (non-zero) for the breakpoint to trigger. DO command Breakpoint action: A series of SoftICE commands can execute when the breakpoint triggers. I've found the BMSG approach very useful when nothing else seemed to work. To use this approach, first you need to find the "window-handle" of your target. So, with the registration screen up, toggle over to SoftICE (Ctrl-D) and first do a TASK. This will show you what programs are running. Look for the name of your target. Then do an HWND target_name (where target_name is the name of your program). These windows are hierarchical and usually your the one you're looking for is the first one in the list. Also watch for things like "EDIT." These are good to break on, too. Once you've found the window-handle, you can set your "windows message" breakpoint. I don't normally use a "begin-msg" and an "end-msg." I just use one of the commands that I know will pop. Here are some of my favorites: bmsg xxx wm_command ; where xxx is the window-handle bmsg xxx wm_gettext ; returned by HWND program_name bmsg xxx wm_lbuttonup bmsg xxx wm_lbuttondown There are lots and lots of other nifty features and functions of SoftICE. Again, I encourage you to find and download the users' guide and the command reference (and check them out). "Ok, I have everything installed and I can toggle in and out of SoftICE using Ctrl-D... Teach me to crack." This lesson will be very basic, but I will introduce some intermediate "cracking techniques," like how to "fix" a program to turn it into its own "key generator." So, grab some popcorn and a mug full of your favorite frosty beverage and prepare to crack! Our target is DiskFactory/32 v2.10. You should be able to find it in one of the shareware archives like www.windows95.com, www.shareware.com, etc. Install the program and run it a few times to get a feel for its behavior and to see how it's protected (e.g., nag screens, registration, date limit, etc). You'll find that this one pops up a nag screen asking you to register when you run it and upon exit. Go ahead and click on the Register button. Enter your name and some bogus validation code. Unless you are the luckiest person on earth and guessed the correct validation code, the program will complain that you entered an invalid code. Ok, so now our job is to break into the program when it reads in the values we typed. Then we want to trace through the code until it compares our code with the "correct" code. Sometimes this is simple and the comparison is only a few lines away from where it reads the data. Other times, you may have to wade through a bunch of code to get to the right spot. Our target is one of the easy ones... Remember from above, we listed a few of the more common breakpoints that will help us in this type of situation. This is a 32-bit program, so we might try any of these SoftIce breakpoints. bpx GetWindowTextA bpx GetDlgItemTextA bpx GetDlgItemInt I'll save you some trouble... Let's use bpx GetDlgItemTextA. First run the program. Then select register. Type in your name and type something in the validation code field, but don't click on OK yet. Now toggle over to SoftICE using Ctrl-D. Type bpx GetDlgItemTextA. Type BL to see that your breakpoint is indeed set. Then press Ctrl-D (or F5) to toggle back to your program. Click on OK and SoftICE will pop. You should be looking at a SoftICE screen and should actually be in the USER32.DLL. You can tell this by looking at the bottom of the SoftICE screen. This will show you which program is currently active. You'll often see KERNEL32, USER32, GDI32, and your program. This is because typically the program makes calls to the Windows 32 API set instead of implementing all the code itself. You'll also see other DLL names here, like the Visual BASIC and Visual C++ runtime libraries, other program DLLs, etc. The reason you are currently in the USER32.DLL is because the program made an API call (GetDlgItemTextA) which happens to be implemented in USER32.DLL. You want to get out of the USER32.DLL and back into your program. The best way to do that from here is to press F11. This will "step out of the current function" and throw you back at the calling code. Go ahead and press F11. If everything is going according to plan, you should now be back in the target. Again, you can tell be looking at the bottom of the SoftICE screen. It should now say DSKFAC32 (with some other text). This is good, but so far we've only read in the name we entered. Go ahead and press F5 (or type Ctrl-D) to leave SoftICE and continue running the program. It will break again immediately. This time it has read in the validation code you entered. Again, press F11 to get out of the USER32.DLL and back into the target. You will land in a section of code that looks something like this (again, this is the second call to GetDlgItemTextA). This excerpt is from a "dead listing" created using W32Dasm 8.9. * Reference To: USER32.GetDlgItemTextA, Ord:00EDh | :0040DF8B FF1534F74200 Call dword ptr [0042F734] * Possible StringData Ref from Data Obj ->"-" | :0040DF91 68E8744200 push 004274E8 ; second F11 brings you here :0040DF96 6880AC4200 push 0042AC80 :0040DF9B E8A0050100 call 0041E540 :0040DFA0 83C408 add esp, 00000008 :0040DFA3 8945FC mov dword ptr [ebp-04], eax :0040DFA6 837DFC00 cmp dword ptr [ebp-04], 00000000 :0040DFAA 0F85E7000000 jne 0040E097 :0040DFB0 6A00 push 00000000 :0040DFB2 6A00 push 00000000 :0040DFB4 682D010000 push 0000012D :0040DFB9 8B4508 mov eax, dword ptr [ebp+08] :0040DFBC 50 push eax * Reference To: USER32.GetDlgItemInt, Ord:00ECh ; convert the | ; "string" we :0040DFBD FF1504F74200 Call dword ptr [0042F704] ; entered to an :0040DFC3 A370AC4200 mov dword ptr [0042AC70], eax ; integer value :0040DFC8 A150734200 mov eax, dword ptr [00427350] :0040DFCD 50 push eax :0040DFCE 6838AC4200 push 0042AC38 ; calculate the :0040DFD3 E87B060000 call 0040E653 ; ver 1.x serial :0040DFD8 83C408 add esp, 00000008 :0040DFDB 0FB7C0 movzx eax, ax :0040DFDE 3B0570AC4200 cmp eax, dword ptr [0042AC70] ; does it match? :0040DFE4 0F8521000000 jne 0040E00B ; no, jump bad guy :0040DFEA 6A04 push 00000004 :0040DFEC 6870AC4200 push 0042AC70 :0040DFF1 6A04 push 00000004 :0040DFF3 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Validation Code" | :0040DFF5 68EC744200 push 004274EC :0040DFFA A148734200 mov eax, dword ptr [00427348] :0040DFFF 50 push eax * Reference To: ADVAPI32.RegSetValueExA, Ord:00ECh | :0040E000 FF1570F44200 Call dword ptr [0042F470] :0040E006 E987000000 jmp 0040E092 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040DFE4(C) | :0040E00B 6838AC4200 push 0042AC38 * Reference To: KERNEL32.lstrlenA, Ord:02A3h ; count string length | :0040E010 FF15A0F54200 Call dword ptr [0042F5A0] :0040E016 50 push eax :0040E017 6838AC4200 push 0042AC38 ; calculate the :0040E01C E8D6090000 call 0040E9F7 ; upgrade serial :0040E021 83C408 add esp, 00000008 :0040E024 3B0570AC4200 cmp eax, dword ptr [0042AC70] ; does it match? :0040E02A 0F8521000000 jne 0040E051 ; no, jump bad guy :0040E030 6A04 push 00000004 :0040E032 6870AC4200 push 0042AC70 :0040E037 6A04 push 00000004 :0040E039 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Validation Code" | :0040E03B 68FC744200 push 004274FC :0040E040 A14C734200 mov eax, dword ptr [0042734C] :0040E045 50 push eax * Reference To: ADVAPI32.RegSetValueExA, Ord:00ECh | :0040E046 FF1570F44200 Call dword ptr [0042F470] :0040E04C E941000000 jmp 0040E092 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040E02A(C) | :0040E051 6838AC4200 push 0042AC38 * Reference To: KERNEL32.lstrlenA, Ord:02A3h ; count string length | :0040E056 FF15A0F54200 Call dword ptr [0042F5A0] :0040E05C 50 push eax :0040E05D 6838AC4200 push 0042AC38 ; calculate current :0040E062 E8AF040000 call 0040E516 ; ver serial number :0040E067 83C408 add esp, 00000008 :0040E06A 3B0570AC4200 cmp eax, dword ptr [0042AC70] ; does it match? :0040E070 0F851C000000 jne 0040E092 ; no, jump bad guy :0040E076 6A04 push 00000004 :0040E078 6870AC4200 push 0042AC70 :0040E07D 6A04 push 00000004 :0040E07F 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Validation Code" | :0040E081 680C754200 push 0042750C :0040E086 A14C734200 mov eax, dword ptr [0042734C] :0040E08B 50 push eax * Reference To: ADVAPI32.RegSetValueExA, Ord:00ECh | :0040E08C FF1570F44200 Call dword ptr [0042F470] * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0040E006(U), :0040E04C(U), :0040E070(C) | :0040E092 E9F6000000 jmp 0040E18D So, what's happening in all this mess? Well, the second GetDlgItemTextA reads in the validation code we entered (as a string). Then the call to GetDlgItemInt converts the string to an integer value and then stores the value in variable (actually it stores it at a memory location [0042AC70]). This memory location probably refers to some variable that was coded in a higher level language (like C++). Press F10 (step) until you get to this section. * Reference To: USER32.GetDlgItemInt, Ord:00ECh ; convert the | ; "string" we :0040DFBD FF1504F74200 Call dword ptr [0042F704] ; entered to an :0040DFC3 A370AC4200 mov dword ptr [0042AC70], eax ; integer value After you press F10 on the CALL line, then type ? EAX. This will print the value contained in the EAX register. You should notice that this is the value you entered in the validation code box. Now continue pressing F10 a few more times until you come to: :0040DFCE 6838AC4200 push 0042AC38 ; calculate the :0040DFD3 E87B060000 call 0040E653 ; ver 1.x serial :0040DFD8 83C408 add esp, 00000008 :0040DFDB 0FB7C0 movzx eax, ax :0040DFDE 3B0570AC4200 cmp eax, dword ptr [0042AC70] ; does it match? :0040DFE4 0F8521000000 jne 0040E00B ; no, jump bad guy This CALL calculates the value for a version 1.x serial number. Then it compares that with the code you entered. If it doesn't match it jumps on and calculates an "upgrade" serial number. Again it compares this with the value you entered and makes a conditional jump depending on whether or not they match. And finally it calculates a serial number for the current version and compares it with the code you entered. If these don't match, we jump to the nagging "you entered an invalid code..." dialog. So, if you type ? EAX right after executing the CALL 0040E516 (line cs:0040E062) you will see the correct serial number (validation code). CS stands for code segment. This may be different on your machine, but on mine my CS for this program was 0137. Don't go back to the program and enter the correct serial number (YET). Now that we know where in the program the correct serial number calculated, we can set a neat breakpoint in SoftICE and create all the serials we want. First clear all your existing breakpoints by typing BC *. Now let's set our new (neat) breakpoint. Make sure you're still sitting on or around the above code section and set the following breakpoint: bpx cs:0040E067 do "? eax" This will break on the line right after the CALL which calculates the current version serial number and when it breaks it will print the correct value (which is contained in the EAX register). After you get the breakpoint set, toggle back over to the registration and enter the name you wish to find the serial for. Then enter a bogus serial (even just one character) and click on OK. SoftICE will pop and will print the correct serial number for you at the bottom of the screen. It's the decimal (middle) value you're looking for. For example, using drlan as the name, my registration code was 22971975. Write down your serial, then press F5 or Ctrl-D to continue running the program. Since you entered an "invalid" serial number it will bitch and give you a chance to enter another one. Go ahead and generate as many as you'd like. Ok, normally once we've found a serial number we don't crack any further. But, I want to teach you a few tricks here, so I'll bend the rules a little. Let's think about how we could actually crack the executable. Now, to understand this you're going to need some knowledge of Assembler programming (which I suggest you develop to become a proficient cracker). Look at the section that calculates the current version validation code and then compares it to the one we entered. Here it is again: :0040E05C 50 push eax :0040E05D 6838AC4200 push 0042AC38 ; calculate current :0040E062 E8AF040000 call 0040E516 ; ver serial number :0040E067 83C408 add esp, 00000008 :0040E06A 3B0570AC4200 cmp eax, dword ptr [0042AC70] ; does it match? :0040E070 0F851C000000 jne 0040E092 ; no, jump bad guy :0040E076 6A04 push 00000004 :0040E078 6870AC4200 push 0042AC70 :0040E07D 6A04 push 00000004 :0040E07F 6A00 push 00000000 As with anything, there are a number of ways to approach this. But consider this: we have 12 bytes of code that we could change to make it do something more to our liking. The lines that compare our code to the correct code and then makes the conditional jump. If the codes match, it will not make the jump. So, we really don't need to make the comparison. And we certainly do not want to make the jump. Simply reversing the jump (changing jne into je, or blatantly using NOP) is one approach we might consider. However, this will simply write the wrong code to the registry and we still won't be registered. It will write the code, then go back and read it again and check it. So, simply eliminating the jne won't help us. Let's put on our thinking/cracking caps... Let's use some of those 12 bytes and "put the right code where it belongs." What we're going to do is let the program calculate the correct code for us (built in key generator). Then rather than comparing the correct code with the code we entered, we'll just move the correct code into the location where our code is stored and we'll skip that nasty jne. Actually we'll only need 5 bytes for this, so we'll let it make the comparison, then we'll replace the jne 0040E092 with our own instructions. Change: :0040E070 0F851C000000 jne 0040E092 Into: :0040E070 A370AC4200 mov [0042AC70], eax :0040E075 90 nop This MOVes the correct code (contained in register EAX) into the memory location for the code we entered. Now they match! Notice we had to add one NOP (No OPeration) to pad to 6 bytes. We have to replace the same number of bytes and the jne 0040E092 was 6 bytes. You can do this live in SoftICE by pressing F10 until you are on the line you want to change (cs:0040E070). Then type A (to assemble in our new instructions). In the SoftICE command window, type: A mov [0042ac70], eax nop Press ESC Press F5 or Ctrl-D to continue running the program. Viola, it's registered! Do a Help, About and you'll see your name and the correct serial number. Is this fun, or what? Since we faked it into using the correct serial number, it will write this information to the registry and stay there, so it will stay registered and there really isn't any need to create a crack/patch. If you want to play around and "unregister" it, just go into the registry and delete the following entry: [HKEY_LOCAL_MACHINE\SOFTWARE\Accurate Technologies\DiskFactory32\2.0] Validation Code Now it will pop up the registration nag again and allow you to experiment. If you really want to crack/patch the executable, just fire up your favorite hex editor. You need to use a search string from the code a few lines above where we're going to crack (to find a unique match). So, here is the search and replace information. E8AF04000083C4083B0570AC42000F851C000000 ; search xxxxxxxxxxxxxxxxxxxxxxxxxxxxA370AC420090 ; replace The 'x' pattern is only a place holder. Don't change any of those values. They're just in there to make the search string unique for easy location. Just change the last 6 bytes. That's it for this lesson. Hope this was fun and instructional. Disclaimer: THIS ESSAY IS FOR EDUCATIONAL PURPOSES ONLY. ANY USE, MIS-USE OR ILLEGAL ACTIVITY IS THE SOLE RESPONSIBILITY OF THE READER. GreetZ: Everyone in [ME97/C4N], PC97, UCF, fravia, gthorne, +ORC, Razzia! drlan