::::::::::::::::::::: m E X / c 4 N T U T O R I A L D I V I S I O N :::::::::::::::::::::::::: Tutor : CoRN2 Editor : Notepad (fullscreen 800x600 wit' wordwrap) Audience : Beginners an' Newbies :) Greets : mEx'98 members, and any other leeto's I know... ;) Target : Winzip 4-6.2/6.3 SR1 Rev Date : 21/03/98 Check out our homepage, http://mex98.home.ml.org/ WARNING: Some of you may be offended by this tutorial, in that it points out /everything/ if you can't handle this.. try something a little harder... :) This program barely warrants even being tutored, as anyone who benefits from this tutorial will discover at a later date. Having said this, for the complete newbie, this should provide a nice insight into both cracking, and SoftIce. Its intended as a 'first tutorial you should read' type thing :) Sorry if it sucks. Lets begin our cracking journey. Firstly, we gotta find out if our target is in fact 'crackable'. Generally if it is we'll find a place to enter our registration details. Best place to look is for a specific menu for it.. no, ok, lets try the 'About Winzip' option (under help) ooooooh there it is! 'Register Winzip'. w00t! We click on this, and find ourself presented with a two field window, one asking for our name, the other for our serial number which we paid for Now that we know what kind of protection we'll be working with, we can make a few assumptions. (1) That the program will read in the two strings, and perform some kind of wizardry on our entered 'name' turning it into a /valid/ serial number. (2) Once this has happened, the program will compare the serial number which it generated with the serial number which we entered. (3) If these don't match, it will consequently tell us to 'feck off', otherwise thank us for registering. Now it should be obvious that we can register the program, without buying a serial number from them. But how to start? Almost everything in windows is handled by 'API Functions' (API stands for Applications Programming Interface if you're interested) These basically tell your 'clever' operating system how to work. Thanks to the miracles of SoftIce we can instruct it to halt a program dead in its tracks if it attempts to access any of these API functions. This is what we'll do. Most 32-bit string input functions (Winzip is a 32-bit program, hence it uses 32-bit API calls) are handled by one of two API functions, either: GetDlgItemTextA or GetWindowTextA So we'll instruct SoftIce to break whenever a program tries to call (in otherwords access) either of these API calls. So, break into SoftIce (CTRL-D) you'll be looking at a lot of crap. Type: : BPX GetDlgItemTextA : BPX GetWindowTextA (BPX Stands for 'BreakPoint on Execute', essentially it tells SoftIce To 'Break' into the program whenever the parameter (in this case GetDlgItemTextA/GetWindowTextA) is 'Executed', simple huh?) Now go back to our program, nothing happens huh? well it shouldn't :) Type in your details, for the purpose of example, I'll use: Name: CoRN2 [mE'98/C4N] Registration #: 111222333 Now click the OK button. We're back in SoftIce. SoftIce tells us that there was a 'Break Due To BPX USER32!GetDlgItemTextA'. Good. In the code window you'll see that USER32!GetDlgItemTextA is highlighted, this tells us that we're at the beginning of the API function. Looking down at the bottom border will tell us where in the wonderful world of windows that we are, USER32!.text+xxxx. We want to get to the winzip code (since we're not trying to crack USER32) Press F11, or type P RET Ok, Now checking the bottom of the code window we see we're in ___________, cool. Now a bit of knowledge, looking up the API function, GetDlgItemText (note that the 'A' is dropped, it simply donates a 32-bit version of the function, GetDlgItemText is a 16-bit function, the parameters are identical) in our trusty Win32.Hlp we find: -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- The GetDlgItemTextA function retrieves the title or text associated with a control in a dialog box. UINT GetDlgItemText{ // The Function Name HWND hDlg, // handle of the dialog box. } int nIDDlgItem, // identifier of control. } Function LPTSTR lpString, // address of buffer for text. } Parameters int MaxCount // maximum size of string. } }; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Ok. In assembly, any parameters that a function takes, are PUSHed onto an area of memory known as the STACK. Think of the STACK as like a stack of plates, except its on the ceiling. The first thing PUSHed onto the stack, is the LAST thing to be POPped off the stack by the function. If you think about this carefully you'll see that this means that the parameters must be pushed in reverse order for the function to interpret them properly. Now that we know this, lets apply it to our target. Here is roughly what you should be looking at: :0040B3F4 6A28 push 00000028 // MaxCount :0040B3F6 68B0C24D00 push 004DC2B0 // Address of text buffer (*) :0040B3FB 68800C0000 push 00000C80 // Identifier of control :0040B400 FF7508 push [ebp+08] // Handle of dialog box :0040B403 FF15C8FA4D00 Call [USER32!GetDlgItemTextA] :0040B409 6A0A push 0000000A <-- You Are Here :) (*) Note that in Winzip6.3 SR1 they changed this address to 471258 ... wow, that should stop us cracking it huh? This should illustrate the above paragraph a bit. As you can see, each parameter is PUSH'ed onto the stack in reverse order, then the API function is called. Since we know that text was read from the registration window, why don't we see what it was? type : D 4DC2B0 (*) For Winzip6.3 SR1 do : D 471258 In the data window, we'll see (at the far right), 'CoRN2 [mE'98/C4N]', cool, so we know where our name is stored, scribble down that address for reference :) Now lets let the program run a little more, CTRL-D. Bang, back into SoftIce, again we're in USER32.text+xxxx (bottom of code window) and at the beginning of GetDlgItemTextA as before. F11 (or P RET) Back into ___________, ok, lets repeat the above process. Do it. :) This time we find the address 4DA4A0 is of interest ( 46F578 in Winzip6.3 SR1 ), whats stored there? find out as before. Hmmm, '111222333', looks a bit like the registration code we entered, huh? Now we know that program could proceed in a few different ways, but at some point, the valid code will be compared with our dodgy one. Wouldn't it be cool if we could tell SoftIce to break whenever a certain range of memory is accessed?! (ie, our dodgy serial number) We can! (what a surprise) But this time we want to BPR ( Break Point on Range ) rather than BPX. The format for this command is: BPR R/W Well, we know our starting address, its 4DA4A0, now the ending address will be 4DA4A0 + the length of the string. In this case the length of the string is 9 characters. So the ending address is 4DA4A9. R/W lets us specify whether we want to break on a READ operation ( when the program reads a part of our code ), a WRITE operation ( guess... ) or both. If this isn't specified, then the default is both. So now, type: : BPR 4DA4A0 4DA4A9 (*) BPR 46F578 46F581 <-- Winzip6.3 SR1 (NOTE: If you're a bit crap at hexadecimal addition (or a lazy bugger), then you can tell SoftIce to do the work for you, like this: : BPR 4DA4A0 4DA4A0+9 (*) BPR 46F578 46F578+9 <-- Winzip6.3 SR1 Simple huh? Ok, now we've set up a trap on our code, lets just hope that it works... CTRL-D. Boom, SoftIce at the following line: :0040B42D 0FB605A0A44D00 movzx eax, byte ptr [004DA4A0] <-- Here. (*) :0040B434 85C0 test eax, eax <-- See (1) :0040B436 0F840D000000 je 0040B449 <-- JUMP if zero flag set. (*) Do I really need to put this??? bah, would be movzx eax, byte ptr [0046F578] for Winzip6.3SR1 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (1) A billion people have asked me what the fuck TEST does. It performs a logical AND between the two parameters. Logically AND'ing anything with itself, gives itself, for example: FFFF0000 AND FFFF0000 = FFFF0000 As you can see, it doesn't do shit, except UPDATE THE FLAGS. In otherwords, if EAX happened to be zero, then: 00000000 AND 00000000 = 00000000 which sets the ZERO FLAG. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Ok, The line we're at copies the value of the first digit of our dodgy serial number into EAX, then the test will basically decide whether or not the value of it is zero. A character with the value of zero is known as a NULL character, ie it has no value. If the first character of a string is NULL then it is logical that the rest of the string is empty too. How could you enter no character as the first digit of your registration number?! (NOTE: a SPACE has the ASCII (character code) value of 20h (hex)) If it is zero, then the jump at :0040B436 is executed. A bit of thought will tell us that these three lines are check to see if either of the fields (name or registration #) were left empty, if they were, then winzip tells you so. This obviously isn't what we're looking for. CTRL-D. Up pops SoftIce again, now we're here: :004607C0 8A06 mov al, byte ptr [esi] <-- Here. :004607C2 46 inc esi :004607C3 8A27 mov ah, byte ptr [edi] :004607C5 47 inc edi :004607C6 38C4 cmp ah, al :004607C8 74F2 je 004607BC (*) je 004465EC for winzip6.3 SR1 Now /this/ looks promising! :) Firstly (004607C0) copies the character value that is stored at ESI into AL, take a look at ESI, type: : D ESI wow, its our code (unsurprisingly, since SoftIce broke due to a read access on the memory range we specified...) Next (4607C2) we increment ESI, this moves us to the next character in our dodgy registration key. Ok, now (4607C3) the character value at EDI is copied into AH. Then these two values are compared (4607C6). Hmmmm, smells a bit like serial number check to me... : D EDI Wait a moment!? Here we see the number '30612380' and this is being compared, digit by digit to our dodgy serial number!!! :) Scribble the number down!!! :) Ok, so we're trembling with excitement, lets remove all of our breakpoints and return to Winzip to try it out! :) : BC * This clears all of our breakpoints, lets get back to windows. Enter our details as before, but entering the serial we found. Wayhay! it worked!!! woohoo, pat yourself on the back etc... Hopefully this tutorial will have given you an insight into cracking, and more importantly the usage of SoftIce. Next time we'll target the same program once more, but try to create a key generator which will calculate the appropriate code for any name entered. Fun huh? As always, any comments, suggestions, or beer-money, send to CoRN02@Bigfoot.Com Good luck in your own journey... --CoRN2 [mE'98/C4N] ::::::::::::::::::::: m E X / c 4 N T U T O R I A L D I V I S I O N ::::::::::::::::::::::::::