This action might not be possible to undo. Are you sure you want to continue?
Chapter 1 Chapter 2 Chapter 3 Chapter 4 Chapter 5 Chapter 6 Chapter 7 Chapter 8
overview some tips on how to use the debugger some basic cracking techniques walk through of an easy crack how to use the disk editor other cracking tools source code to a simple byte patcher conclusion
Programs included at the end of this guide Section 1 Section 2 Section 3 uuencoded cracking tool another uuencoded cracking tool uuencoded program to crack for the walk through
CHAPTER 1 OVERVIEW -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=You might be wondering what type of programming skills you need to become a cracker. Knowing a higher level language such as Basic, Pascal, or C++ will help you somewhat in that you will have an understanding of what's involved in the process of writing a program and how certain aspects of a program function. If you don't have any programming skills at all, you have a long road ahead of you. But even if you can program in a high level language, in order to crack you have to know assembly... It really doesn't matter what language a program was written in in order to crack it, because all programs do the same thing. And that is issue commands to the microprocessor. And all programs when broken down to their simplest form are nothing more than a collection of 80XXX instructions and program specific data. This is the level of assembly language. In assembly you have total control of the system. This is also the level that the debugger operates at. You don't have to become a master at assembly to crack a program, but it helps. You do need to learn some rudimentary principles, and you absolutely have to become familiar with the registers of the cpu and how the 8088 instruction set uses them. There is no way around this. How proficient you are at assembly will determine how good of a cracker you become. You can get by on learning a few basic instructions, how to use a debugger, and one or two simple techniques. This will allow you to remove a
few shareware nag screens, and maybe you'll luck out and remove the copy protection from a game or two, but that's it. As soon as a programmer throws some anti-debugging code into a program or starts revectoring interrupts, you'll be whining for someone to post a crack for this or that... And you can forget about ever learning to crack windows programs. It's much much easier to learn to crack in DOS than windows. DOS is the easiest environment to debug in. This guide will focus on DOS programs as cracking windows apps is a little bit overwhelming unless you are already an experienced cracker. And if you are, your wasting your time by reading this. This manual is geared towards the raw beginner who has no clue as to where to start and needs a little hand holding in order to get going. There are several good beginners manuals out there, but most of them assume a person has at least some experience in cracking or knows how to use the different tools of the cracker, and the raw beginner usually becomes frustrated with them very quickly because they don't understand the concepts contained in them. I wrote this guide as sort of a primer for the beginner to read before reading the more comprehensive guides. I tried to keep it as simple as possible and left a great deal of information out so as not to overwhelm anyone with too much information at once. Hopefully after reading this guide it will be easier for the beginner to understand the concepts of the more arcane guides out there. So if you are reading this and it seems a little bit remedial, remember, at one time you didn't know what a debugger was used for either. Now in case your not familiar with the debugger and disk editor and what their different roles in cracking are, I'll give a brief explanation of each. As these are the crackers most used tools. The debugger is what you will use to actually crack the program. When you load a program you wish to crack into the debugger, it will load the program and stop at the first instruction to be executed within the code segment. Or, you can also optionally break into an already running program and it will halt the program at the instruction you broke into it at and await further input from you. At this point, you are in control of the program. You can then dynamically interact with the program and run it one line of code at a time, and see exactly what the program is doing in real time as each line of code is executed. You will also be able to re-assemble instructions (in memory only), edit the contents of memory locations, manipulate the cpu's registers, and see the effects your modifications have on the program as it's running. This is also where all your system crashes will occur... There is a lot of trial and error involved in cracking. As stated above, the debugger will only modify the program while it's up and running in memory. In order to make permanent changes, you need to load the program file to be patched into the disk editor and permanently write the changes you've made to disk. A detailed explanation of how to do this will be made in chapter 5. So, with this in mind, you need a few essential tools... The first one is a good debugger. The original draft of this guide gave explicit instructions on how to use my favorite debugger. After considerable deliberation, I decided to re-write it and make the instructions more generic so you could apply them to most any debugger. You will also need a disk editor, it doesn't matter which one you use as long as it will load the program file, search for and edit the
bytes you want to change. I uuencoded a few cracking tools that you will find indespensible and placed them at the end of this guide. I won't go into the use of the cracking tools right now. But believe me, you absolutely need one of them, and the other one will save you a lot of effort. I also uuencoded the program that we will crack in the walk through and included it in this guide as well. As you get better, you'll have to write programs that will implement your patches if you decide to distribute them. The patches themselves don't have to be written in assembly. The source code I included in this manual for the byte patcher is the first patcher program I ever wrote, and is extremely simple. It's written in assembly because that's the only language I know how to program in. but if you are already proficient in a higher level language, it should be trivial for you to duplicate it's methods in your preferred language.
CHAPTER 2 SOME TIPS ON HOW TO USE THE DEBUGGER -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=Ok, before I begin, I'd just like to stress how important it is that you know at least some assembly before trying to continue. If you don't, you will get lost pretty quick from here on out. Comprehension of the base 16 (hexadecimal) number system is also required. I'm not about to give a remedial course on assembly or hex math, that would take too long and I'd probably leave too many questions un-answered. Besides, there is enough information on them available from a myriad of other sources. So, from now on in this guide, I'm assuming you have a fair working knowledge of assembly and hexadecimal. If I say something you don't understand or you cannot grasp some concept, look it up somewhere... I've tried to make this section as generic as possible. I used general descriptions when explaining HOTKEYS and COMMANDS as different debuggers will use different keys and command syntax to implement these functions. You should be able to translate these instructions to the actual key strokes and commands that your debugger uses... If you don't know how to use a debugger, PAY ATTENTION!!! If you already know how to use a debugger you can skip this section as it is only a general overview of different windows and functions designed for the absolute beginner who has no clue as to what he is looking at. The reason I included this section is because most manuals for debuggers tell you how to use the various features of the debugger, but they don't give any insight on how to apply those features, as they assume the person reading them already knows how to debug a program. First, I'll give an overview on the different windows that most debuggers use. REGISTER WINDOW: The register window contains the general purpose and flags registers of the cpu. You will notice that the general purpose registers contain hexadecimal
values. These values are just what happened to be in there when you brought up the debugger. you will also notice that some of the flags are highlighted while some are not. Usually, the highlighted flags are the ones that are SET. While the ones that are not highlighted are CLEARED. The layout of this window will vary from debugger to debugger, but they all basically are the same. From this window you will be able to manipulate the contents of the cpu's registers. some debuggers accomplish this by clicking on the register to modify with the mouse and then entering a new value. Other more powerful debuggers use a command line interface, you'll have to discover how your debugger goes about this yourself. You can change the values of the registers while debugging a program in order to change the behavior of the running program. Say you come across a JNZ instruction (jump if not zero), that instruction makes the decision on whether or not to make the jump based on the state of the (Z)ero flag. You can modify the condition of the (Z)ero flag in order to alter the flow of the programs code. By the same token, you can modify the general purpose registers in the same manner. Say the AX register contains 0000, and the program bases it's actions on that value, modifying the AX register to contain a new value will also have the effect of modifing the flow of the code. After you become comfortable with using a debugger you'll begin to appreciate just how powerful this window is, and you'll aslo discover soon enough just how totally it can screw your system. DATA WINDOW: The data window will display data as it exists in memory. From this window you can usually display, search, edit, fill, and clear entire ranges of memory. The two most common commands for this window are display and edit. The search command is also useful in cracking. But for the level of debugging I'll be teaching you in this guide, we won't make much use of this window. You have a lot to learn before this window becomes an asset to you. CODE WINDOW: The code window is the window in which you will interact with the running program. This is the most complex window, and it is where the bulk of debugging occurs. I'll just go over some keystrokes and a few commands here, as the majority of learning how to use this window will come when I show you how to crack a program. The layout of the window is pretty simple, the colon in the middle of them to the far left of address:offset of that line of code. Each line instruction that the program will issue to the parameters for that instruction. The registers the current instruction waiting to be executed segment and instruction pointer). group of 8 numbers with the the window is the of code in this window is an microprocessor, and the that contain the address for are the CS:IP registers (code
You will also notice a group of hex numbers to the right of the addresses, this group of numbers is the hexadecimal equivalent of the mnemonic instructions (pronounced new-mon-ik). The next group of words and numbers to the right of the hex numbers are the mnemonic instructions themselves. HOTKEYS AND COMMANDS:
Now we'll move onto the HOTKEYS. I won't go into all of them, only the most useful ones, same for the commands. The RESTORE USER SCREEN KEY: This key will toggle the display between the debugger and the program you are debugging without actually returning control to the program itself. it's useful to check what the program is doing from time to time, especially after stepping over a CALL. The HERE KEY: This key is the non-sticky breakpoint key. To use it, Place the cursor on a line of code and hit it. The program will then run until it reaches that line. When (and if) the program reaches that line, program execution will halt, control will be returned to the debugger and the breakpoint will be removed. The TRACE KEY: This key will execute one line of code at a time and will trace into all calls loops and interrupts. The BREAKPOINT KEY: This is the sticky breakpoint key. This will enable a permanent (sticky) breakpoint on the line of code that the cursor is on. When a sticky breakpoint is enabled, program execution will halt and control will be returned to the debugger every time that line of code is encountered within the running program until you manually remove it. The SINGLE STEP KEY: The most used key on the keyboard. This key will execute one line of code at a time but will not trace into calls loops or interrupts. When you step over a call interrupt or loop with this key, all the code contained within the sub-routine is executed before control is returned to the debugger. If the program never returns from the sub-routine, you will lose control and the program will execute as normal. The RUN KEY: This key will return control to the program being debugged and allow it to execute as normal. Control will not be returned to the debugger unless a breakpoint that you've set is encountered. Now for a few commands. The GO TO command functions like the HERE key in that it will insert a non-sticky breakpoint at the specified address. When you enter this command the debugger will return control to the program until the line of code you specified in the GO TO command is reached. When (and if) the CS:IP registers equal the address you typed in, the program will halt, control will be returned to the debugger and the breakpoint will be removed. You might be wondering why you would want to type all this in when you can just hit the HERE KEY instead. The answer is this; the HERE KEY is great if you want to set a local breakpoint. By a local breakpoint I mean that the breakpoint you want to set is somewhat close to your current location in the program. But what if you want to set a breakpoint on a line of code that isn't in the current code segment? You wouldn't want to use the HERE KEY cause the address is no where near the point you are at in the program. This, among other uses is where the GO TO command comes in. The ASSEMBLE command is the command you will use to re-write the programs instructions. This command will allow you to assemble new instructions beginning at the address you type in, or at the current CS:IP. The instructions you enter will replace (in memory only) the existing program code at the address you specified. This is another method you will use to alter the
running program to behave as you wish and not as the programmer intended it to. EXAMPLE: Lets say that there is a line of code that reads JNZ 04FC, and we want to change it to read JMP 04FC. You would issue the ASSEMBLE command and specify the address of the code you wish to change, then type in JMP 04FC. Now the line of code in the code window who's address you specified in the ASSEMBLE command will be overwritten with the code you typed in. Some debuggers automatically default to the address contained in the CS:IP for this command. There are a whole host of other commands available in this window depending on what debugger you are using, including commands to set breakpoints on interrupts, memory locations, commands that list and clear breakpoints, commands to un-assemble instructions etc etc... Well, that's pretty much it on debuggers without going into explicit instructions for specific debuggers. The only other thing I can tell you is that the more you use it, the easier it'll get. Don't expect to become familiar with it right away. As with anything, practice makes perfect. It's taken me 5 years and thousands of hours of debugging to reach the level I'm at now. And I still learn something new, or re-learn something I forgot on just about every program I crack.
CHAPTER 3: SOME BASIC CRACKING TECHNIQUES -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=The first thing I want to do before going into some simple techniques is to explain the purpose of one of the uuencoded cracking tools at the end of this guide. And also to go over some general procedures you should perform before actually loading a program you wish to crack into the debugger. Nowadays a lot of programmers will compress the executable files of their programs to save space and to make it difficult for people who don't know any better to hack those files. There are a lot of losers out there who will get ahold of a program and lacking any skill or talent of their own, will load the program into a disk editor and hex edit their name into it. Or they will make other similarly feeble modifications. This is the reason I encrypt all of the cracks that I distribute. The routines I write are not that hard to defeat, but I figure anyone with the skill to crack them is far above having to hack their name into them... Ok, back to the file, the name of the program is UNP and it is an executable file expander. It's purpose is to remove the compression envelope from executable programs. And it supports most of the compression routines currently in use... A lot of the compression routines will cause a debugger to lock up if you try to step through the compressed file, especially PKLITE v1.15. And seeing as how the file is compressed, if you load it into a disk editor it will just look like a bunch of garbage and you'll not be able to find the bytes you want to edit anyway. UNP is very easy to use, just type UNP [filename] and if there is any type of compression envelope that UNP understands on the file, UNP will remove it. You can then load the file into a debugger and hack away...
But before you load a program into the debugger you should run the program a few times and get a feel for it. You want to see how the protection is implemented. Whether it's nag or delay screens and at what point in the program they fist appear, or where in the program does the first mention of being unregistered or an evaluation copy appear? This is important. Because before the program displays the first mention of being unregistered, it has to do the protection check. and this is where you will usually want to concentrate. Also look for registered functions being disabled, and sometimes date expirations. The program could also be looking for a registration key. In the case of commercial software what type of copy protection is used? Is it a doc check, or does the program want you to input a serial number before it will install itself? Once you see how and where the offending routines are implemented you can begin to develop an overall strategy on the best approach to circumvent them. It's also a good idea to read the docs, you can pick up a lot of useful info from doc files. There are basically three categories that shareware programs fall into... They are begware, crippleware, and deadware. The begware category is comprised of programs that have all the registered features enabled but every time you run them they will display screens that bug you to register. This is usually the easiest form of protection to remove and it's the type I'll go over in the walk through. The crippleware category is comprised of programs that in the unregistered version have certain functions disabled, and maybe nag screens as well. This type of protection can be more complex, but often times is just as easy to defeat as a simple nag screen. The deadware category is comprised of programs that are totally stripped of the code for the registered features so there is really nothing to crack. A good example of this is DOOM by ID software. You can get the shareware version just about anywhere, however no matter how much you hack at it you cannot make it into the commercial version cause it only contains the code for the first episode. The sample code fragments in this section are not taken from actual programs. I just made them up off the top of my head while I was writting this guide, and there are bound to be some errors in them. Please dont write me and tell me this, I already know it. Most forms of copy protection have one weak spot, and this is the spot you will concentrate on. They have to perform the protection check and then make a decision based on the results of that check. And that decision is usually a conditional jump. If the check was good the program will go in one direction, if it was bad it will go somewhere else. So, you've run the program through a few times and you know at what point the routines you want to modify first appear, you've also run UNP on it and have removed any compression envelopes. Now you load the program into the debugger and wonder what to do next... What you want to do is to step through the code until something significant happens like a nag screen gets displayed, or a doc check comes up or the program tells you that the function you just tried to use is only available in the registered version. When you reach that point you can then start to evaluate what portion of code to begin studying.
Let's say you have a program that displays a nag screen and you want to remove it. You step through the program until the nag screen pops up, you now think you know the location of the instructions that are causing it to be displayed. So you reload the program and trace back to a point a few instructions before the call to the nag screen, and this is what you see: 09D8:0140 09D8:0145 09D8:0148 09D8:014B CMP BYTE PTR [A76C],00 JNZ 014B CALL 0C50 MOV AH,18
Now, let's assume that the memory location referenced by the first line of code does indeed contain 00 and that it is the default value placed in there by the programmer to indicate that the program is unregistered. The first line of code is checking the value contained in the memory location to see if it is 00 or not. If the location does contain 00, the compare instruction will cause the Zero flag to be set. If the location contains any other value than 00, the Zero flag will be cleared. The second line of code makes the decision on how to proceed based on results of the compare instruction. The JNZ instruction will make the the fourth line of code if the zero flag is cleared. This will bypass to the nag screen on the third line. If the zero flag is set, no jump occur and the call will be made. the jump to the call will
The third line of code contains the call to the nag screen. If it is executed the nag screen will be displayed. The fourth line of code is just the next instruction in the program. Once you have found and analyzed this piece of code within the program, you can now decide on how to bypass the call on the third line. There is no single way to do this. I can think of a half dozen different ways to patch the program so it will not make the call. But there is a best way... First, you could just replace the JNZ 014B with JMP 014B. This is an unconditional jump and it will bypass the call on the third line no matter what the memory location that the first line of code is referencing contains. You could also change it to read JZ 014B so that the jump will be made if the location contains 00, and not the other way around. You could even change the CMP BYTE PTR [A76C],00 instruction to JMP 014B. Or you could just NOP out the call on the third line altogether seeing as how it's a local call. By a local call I mean that the code contained within the call resides in the same code segment as the call instruction itself. This is an intersegment call. You will see other calls that reference lines of code outside of the current code segment. These are intrasegment calls, and have to be handled differently. They will look something like CALL 0934:0AC5, or CALL FAR 0002. I'll go over how to handle intrasegment calls later on. NOP is short for no op-code, and it is a valid instruction that the microprocessor understands. It is only one byte in length, and the call instruction is three bytes in length. So if you wanted to nop out the call instruction you would have to enter the NOP instruction three times in order to replace it. And if you replaced the CMP BYTE PTR [A76C],00 with JMP 014B, you would have to pad it out with a few nop's as well.
The compare instruction is 5 bytes and the jump instruction is only 2 bytes, so you would have to add 3 nops in order to equal the length of the original compare instruction. Otherwise you would throw off the address of every instruction after it in the program and end up with a bunch of unintelligible garbage. Not to mention a major system crash... When the NOP instruction is encountered no operations will take place and the CS:IP will then be incremented to the next instruction to be executed. A lot of compilers leave nop's in the code all the time and it's a great instruction you can use to wipe out entire lines of code with. The above methods of bypassing the call are called 'dirty' cracks in that they have only modified the end result of the protection check and have done nothing to alter the actual protection check itself. All the techniques I showed you above are only implemented after the check is made. They will bypass the nag screen, but what if the program also has registered features that are disabled or displays another nag screen upon exit? The above methods only remove the original nag screen and don't address the reason the screen is being displayed in the first place. A much cleaner way to crack the above piece of code would modify the cause and not the effect. And could be written like this: original code 09D8:0140 09D8:0145 09D8:0148 09D8:014B CMP BYTE PTR [A76C],00 JNZ 014B CALL 0C50 MOV AH,18 new code 09D8:0140 09D8:0145 09D8:0148 09D8:014B MOV BYTE PTR [A76C],01 JMP 014B CALL 0C50 MOV AH,18
Remember that the protection check is basing it's actions on the value contained in the memory location that the first line of code is checking. The original code displayed the nag screen if the value of that location was 00, meaning it was unregistered. So that means a value of 01 indicates a registered copy. It could be the other way around as well, it just depends on how the programmer worded the source code. But we know in this case that 00=false so 01=true. These are Boolean expressions and most compilers use the AX register to return these values. By changing the first line from CMP BYT PTR [A76C],00 to MOV BYTE PTR [A76C],01 the program no longer performs the protection check. Instead, it places the correct value in the memory location to indicate a registered copy. Now if the program checks that memory location again later on it will think that it is registered and activate all of it's disabled features, or not display a second nag screen upon it's exit if it has one. I changed the second line of code to an unconditional jump because the compare instruction on the first line no longer exists, and the conditional jump on the second line may still access the call to the nag screen on the third line if the Z flag was already set before the old compare instruction was encountered. Don't think that all programs are this easy, they're not. I just over-simplified this example for instructional purposes. And I really wouldn't patch the code like that, although the last method should work fine for all registered features to be enabled. Remember I told you there was a best way to crack this? What I would actually do is to trace further back into the program and find
the line of code that sets up the memory location referenced by line one of the code for the protection check in the first place and modify it there. This is an example of a 'clean' crack. I just did it in the above manner to try and show you the difference between clean and dirty cracks without totally confusing you. And to give you a general idea on how to creatively modify existing code. If you are using soft ice as your debugger, an easy way to find the instruction that sets up the memory location for the protection check is to set a breakpoint on the location when it gets 00 written to it. The syntax would be BPM XXXX:XXXX W EQ 00, where XXXX:XXXX is the address of the memory location referenced by the compare instruction on line 1. Now when the program wrote 00 to that memory location, soft ice will pop up and the CS:IP will be sitting at the next instruction after the one that wrote 00 to the memory location. You will now be able to evaluate the code around the instruction that writes to the memory location and decide on how to proceed. This also could just be a general purpose location that the program uses for generic references (especially if it's in the stack segment), and it could write 00 to it several times throughout the course of the program for a variety of different functions. You should let the program run normally after soft ice broke in to see if it will trigger the breakpoint again. If it doesn't you know that the location is only used for the protection check. But if the breakpoint gets triggered several more times, you will have to figure out which set of instructions are being used to set up for the protection check before proceeding. The above examples were based on shareware programs. Now I'll go over a few techniques to remove copy protection from commercial games that have doc checks in them as the methods are slightly different... shareware programs are usually coded so that they check a variable in memory before deciding if they are registered or not and how to proceed. Commercial games with doc checks take a different approach as they check nothing before calling the copy protection. It always gets called every time you play the game no matter what. As a result, the doc check routine is usually easier to find, and there are basically two types of doc checks... The passive check, and the active check. The passive doc check is easier to defeat than the active. In the passive doc check, the program will issue a call to the copy protection routine. And if it is unsuccessful will either abort the program, or loop back to the beginning of the routine and give you a few more tries before aborting. The entire protection routine will be included in a single call, so merely nopping out or bypassing the call will be sufficient to remove the copy protection. A few good examples of this are Spear of Destiny by ID, and the Incredible Machine by Sierra. Yes I know that they are old, but if you happen to have a copy of either one laying around they are excellent examples of passive doc checks to practice on. Look at the following piece of code: 0277:01B5 0277:01B8 0277:01B9 0277:01BA MOV [AF56],AX PUSH BX PUSH CX CALL 0234
0277:01BD POP CX 0277:01BE POP BX 0277:01BF JMP 0354 The first three lines of code are just setting up for the call, the call on the fourth line is the protection check itself. It will display the input window asking for a word from the manual, will perform the protection check, and will display an error message if you input the wrong word. It can also optionally give you a few more tries if you type in the wrong word. If you fail the protection check, the program will abort without ever having returned from the call. The fifth, sixth, and seventh lines are the next instructions to be executed if the protection check was successful and the program returns from the call. This type of protection is trivial to defeat, all you have to do is the following: original code 0277:01B5 0277:01B8 0277:01B9 0277:01BA 0277:01BD 0277:01BE 0277:01BF MOV [AF56],AX PUSH BX PUSH CX CALL 0234 POP CX POP BX JMP 0354 new code 0277:01B5 0277:01B8 0277:01B9 0277:01BA 0277:01BB 0277:01BC 0277:01BD 0277:01BE 0277:01BF MOV [AF56],AX PUSH BX PUSH CX NOP NOP NOP POP CX POP BX JMP 0354
Simply nopping out the call to the protection routine will be sufficient to crack this type of doc check. No window asking for input will appear, and the program will continue on as if you had entered the correct word from the manual. Remember that I told you that the NOP instruction is only one byte in length, so you have to enter as many nop's as it takes to equal the length of the code you are modifying. The active doc check is more complex. The program will issue the check and unlike the passive protection, will set a variable in memory somewhere and reference it later on in the program. You can crack this type of protection somewhat using the methods for the passive check and it might run fine for a while. But if you didn't crack it right, later on when the next episode gets loaded or you reach a crucial point in the game, the program will reference a memory location and bring up the copy protection again, or abort. This type of protection is more akin to how most shareware programs operate and MUST be done with a CLEAN crack. Look at the following piece of code: 0234:0B54 0234:0B57 0234:0B58 0234:0B60 0234:0B61 0234:0B62 0234:0B63 0234:0B68 0234:0B6A 0234:0B6C MOV CX,0003 DEC CX JCXZ 031A PUSH CX PUSH DS PUSH ES CALL 035F:112D OR AL,AL JNZ 0B6E JMP 0B57 ;Sets up to give you three tries ;deducts one for every time through the loop ;when CX=0000, program will abort ;just setting up for the call ; " " ; " " ;call to input window and validation routine ;seeing if check was successful ;yes, continue on with the program ;no, set up for another try
0234:0B6E CALL 8133
;next line in the program if check was good
The above code is the outer loop of the protection routine. Look at the call on the seventh line and the compare instruction on the eighth line. When the call to the input routine or in the case of shareware, the check routine is paired with a compare instruction in this manner, You can bet that the program set a memory variable somewhere inside the call. Especially suspicious is the unconditional jump on line 10 that jumps backwards in the code. This won't always be the case as no two programs are alike, and simply changing line 9 of the code from JNZ 0B6E to JMP 0B6E to force the program to run even if you fail the doc check may allow the program to run just fine. Let's say that this is how you patched the program and it runs. Great, your work is done... But what if before the first level loads, or at some other point within the program the input window pops up again asking for a word from the manual? You realize that you should have patched it right in the first place as you now have to go back in there and fix it. This is why so many groups have to release crack fixes, they patch the program in a hurried manner and don't even run it all the way through to see if it's going to work. Ok, back to the problem at hand... The above method of patching the program didn't work, so you now have to load the program back into the debugger and trace into the call on line seven to see whats going on in there. And you can't NOP this kind of call out either, this is an intrasegment call. Certain things in programs get assigned dynamic memory locations, and intrasegment calls are one of those things. When the program gets executed, the code segment, data segment, extra segment, and stack segment get assigned their respective addresses based on the memory map of your computer. And when a program does a FAR call (a call to a segment of memory outside the current code segment), The program goes to the address that was assigned to that segment at run time. The CS, DS, ES, and SS will be different on every computer for the same program. And seeing as how these addresses don't get assigned until run time, the actual bytes for the addresses of far calls don't exist in the program file as it resides on your disk. That's why you can't just NOP a CALL FAR instruction out. However, the bytes for calls that are within the same segment of code as the calling instructions themselves will be contained within the file as it resides on disk. And that is because even though the program doesn't get the addresses for the actual segments until run time, the offsets within those segments will always be the same. Back to the example, let's say you've traced into the call on line seven and this is what you see: 035F:112D 035F:1131 035F:1135 035F:1137 MOV CMP JNZ [324F],BX ; BYTE PTR [BX+06],03 ; just some error checking 0339 ; ; call to the input window that ; asks you to type a word in from ;the manual
035F:113A 035F:113D 035F:1140 035F:1144 035F:1148 035F:114C 035F:114F 035F:1151 035F:1154 035F:1159 035F:115E 035F:1161 035F:1166 035F:116B 035F:116C 035F:116D 035F:116E
MOV MOV MOV MOV MOV REPE JCXZ JMP MOV MOV JMP MOV MOV
DI, ES,DX DS,BX SI, CX, CMPSB 1154 1161 AX,0001 ,AX 116B AX,0000 ,AX
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
this routine is comparing the word you typed in to a word in memory that the program is referencing. As long as the bytes match the loop will continue. This is the routine that sets the memory variable. 01 will be placed in it if you typed in the correct word. 00 will be placed in it if you typed in the wrong word. setup to return from call " " " " return from call
POP ES POP DS POP CX RETF
Again, this code is over simplified as I figured all of the code would be overwhelming and really is not needed to get my point across. And as I've stated before, every program will be different anyway, so the actual code wouldn't help you. Instead, I want to give you a general overview on what to look out for. So, what do you think is the best way to patch the above piece of code? Take a few minutes to study the code and formulate some ideas before reading on. Then compare your methods to mine. And remember, as with any code there is no single way. But as always, there is a best way... I'll go over few of them one at a time, starting with the dirtiest and finishing up with the cleanest. The dirtiest crack for this piece of code also happens to be the method you will use to nop out intrasegment calls. It really isn't nopping out, but seeing as how you can't nop it out, just let the program make the call and change the first line of the code within the call to RETF. This will return from the call without ever having executed any of the code contained within it. In the case of registers needing to be restored as in the above code, change the first line of code to jump to the part of the routine that restores the registers for the return. However, in the above example if you use this method and just return from the call without executing any of the code, you will also have to patch the outer loop as well. Remember that this call only displays the input window and sets the memory variable. The outer loop of the routine makes the decision on how to proceed based on the results of the call. To do this, you would change line one of the call from MOV [324F],BX to JMP 116B. This will restore the registers and return from the call without ever having executed any of the code within the call. But seeing as none of the code got executed, you'll have to patch line 9 of the outer loop from JNZ 0B6E to JMP 0B6E as you now need an unconditional jump to force the program to continue. This doesn't address the problem of the memory variable though, and the program won't be completely cracked. That's why if you did it like this you would end up releasing a fix. A cleaner crack would be to change line 11 of the call from JCXZ 1154 to JMP
1154. Now when the window pops up and asks for a word, it will set the correct memory variable and the program will run no matter what word you type in. This method is still not desirable because the end user will get the input window and have to type something every time they play the game. The cleanest way to crack this, and the way I would do it is to change line 4 of the call from CALL F157 to JMP 1154. This method will totally bypass the input window, place the correct variable in memory and return from the call without the end user ever having seen even a hint of copy protection. With this method, the outer loop does not need to be patched cause the program now thinks that it displayed the input window and the correct word was typed in. Now when the program checks that memory variable later on, it will think that you successfully passed the original check and skip the second protection check. There is also an added benefit to the last method... Some games will bring up the protection check between each and every level of the game even though you type the correct word in every time. But if you've completely killed the routine as in the last example, you'll never be bothered by it again no matter how many times the program tries to bring it up. Please be aware of the fact that these are not the only methods that programmers will use in copy protection schemes. These are just the basics and there are several variations on these routines. The only way to be able to know what any given routine is doing at any time is to master assembly language. Before we move onto the walk though, there is one other technique I want to go over with you. And that is how to get out of a loop. You will get stuck in loops constantly during the course of debugging a program and knowing how to get out of them will save you a lot of time and frustration. You will find that programs contain loops within loops within loops etc... Some loops can execute hundreds of times before the program will advance, especially ones that draw screens. When you realize that you are stuck in a loop, execute the loop several times and keep an eye on the highest address the loop reaches before jumping backwards within the code. Once you have found the end of the loop, write down the address of the jump that re-executes the loop, and then look for conditional jumps inside the loop that will put you past the address of that backwards jump. You will want to set a breakpoint on the address this instruction jumps to and then let the program run normally. The HERE KEY is excellent for this type of situation. If you guessed right, control will be returned to the debugger when the program reaches that instruction. If you guessed wrong, you will lose control of the program and will have reload it and try again. This is where writing down the address comes in handy, just reload the program and then issue the GO TO command and supply it the address of the backwards jump that you wrote down. The program will run until it reaches that address and control will then be returned to the debugger. This will save you from having to trace all the way through the code again in order to reach the point where you lost control of the program in the first place. You could just use sticky breakpoints instead, but what you will end up with is a half dozen or so breakpoints in as many different locations in the code, and it's very easy to loose track as to which breakpoint is which.
That's why I use non-sticky breakpoints and write down the address I'm currently at before executing suspicious looking calls and jumps. My desk is usually scattered with scraps of paper filled with notes and addresses. I only use sticky breakpoints for specific situations. It's much easier to just reload the program and use the GO TO command to get back to the point in the program where I lost control.
CHAPTER 4 WALK THROUGH OF AN EASY CRACK -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=First of all, I want to go over some of the criteria I used in choosing the program I used for the walk through. An important factor was the programs size. I want to keep this manual as small as possible, and I chose the program that is included in this guide because among other things it is the smallest one I could find that best illustrated the example of a simple nag screen. Whether or not the program was one that you would actually find useful was not a consideration, as you should eventually be able to crack just about any program you wish if your serious about cracking. If you come across a program that has you stumped, leave it alone for a while and then try again after you've cracked something else. You may find that whatever you were having problems with is now easier to understand. Before we start I want to go over one other thing. When you load a program into a debugger, the debugger will load the program and halt at the very first instruction to be executed within the program. You can also at this point let the program run normally and then break back into it at a later point. When you use the second method it will halt the program at the current instruction and return control to the debugger, but you may not end up in the program itself. You could have broken into the program while it was in the middle of executing either a DOS or BIOS interrupt, and the code you are in belongs to either DOS or BIOS and not the program you are debugging. You can tell by looking at the addresses of the instructions in the code window where you are, low segment addresses indicate you are in DOS, and addresses that start with FXXX indicate a BIOS routine. If you break into the program while it is in one of these interrupt routines you will have to trace your way back into the programs code, this will usually be indicated by an IRET (interrupt return) instruction. When you do get back to the program code, you will then have to trace your way back to the top of the call that issued the interrupt you broke into. Then you may also have to trace back to the top of that call, and to the top of that call, etc etc, until you reach the top level of the program. After you've done this a few times you'll begin to recognize when you've gotten back to the main flow of the program... On the other hand, when you load a program into the debugger and begin stepping through the code from the very first instruction to be executed within the program, you have the best picture on the overall flow of the program as you are sitting on top of everything. But some programs don't access the copy protection until they are further along in the code. In this case, it's best to let the program run normally and then break into it at a later point. Otherwise, you will have a ton of code to trace through before the protection routine is accessed, and this can become quite tedious. Which method you choose will be determined after you've run the
program through a few times and decide how and where you want to break into it. One last thing, DOS will always load a program into the same memory range provided that no other programs are run in the interim. It's important that you always boot with the same config files and don't run any other memory resident programs between cracking sessions. If you load a program into the debugger and start tracing, then quit. And before The next time you load that same program into the debugger, you boot with a different config or load a memory resident program that you didn't have loaded the first time you started cracking that program, the segment addresses will change and the addresses you wrote down will be useless. This is because the memory map of your computer will change. When I boot with my debugging config (when I use my DOS debugger, Windows manages memory differently and these steps are not needed), the only things I load are a mouse driver, 4DOS, my debugger and ansi.sys (needed for cracking bbs doors). This way I'm assured that the program I want to crack gets loaded into the same memory region every time I run it, providing I don't run any other memory resident programs before loading the program to be cracked into the debugger. Take soft ice as an example, if you load a program into it using LDR.EXE and begin debugging, then later on you decide to just execute the program and break into it without first loading it with LDR.EXE, the segment addresses will change. That's because LDR.EXE is a program and using it will throw the segment addresses off by one word as opposed to just breaking into an already running program without first loading it with LDR.EXE. The program we will crack is budget minder, it is an extremely simple crack (it took me about 2 minutes to crack it) and is ideal for the lesson on how to remove nag screens from otherwise fully functional programs. It also deals with intrasegment calls, so it serves a dual purpose. That's another reason I chose it for the lesson. From now on, when I say step, step through, or step over, I want you to use the SINGLE STEP key. When I say trace, I want you to use the TRACE key once and only once!!!! The TRACE key is a highly specialized key and is not intended to be used multiple times like the SINGLE STEP key. If you don't follow these instructions, your gonna get lost... OK, once you've run budget minder a few times you will notice that it displays a nag screen before the main program is executed. You will also notice that this nag screen is the only type of protection that the program has. It doesn't contain any features that are disabled, nor does it display an additional nag screen upon exit. It's okay to apply a dirty crack to this program as all you want to do is kill the nag screen, so you have a little more leeway on how to patch it. And if you want to try different methods of patching it than the ones I give, it should still work fine. That was the most important factor in my decision to use this program for the lesson. I wanted to walk you through a program so you would become comfortable with it's flow, and I also wanted the program to be easy enough so that once you became familiar with it, there was enough room for you to experiment and try out your own methods. In this case, it's best to load the program into the debugger and start
stepping through it right away. The protection is implemented very close to the beginning of the program, and this method of loading the program will put you right on top of everything. Allowing the program to run and breaking into it later on will not serve any useful purpose. You'll just end up having to trace your way back to the top. Besides, the nag screen comes up so fast you'll probably miss it if you try the second method anyway. Before you load it into the debugger, run UNP on BUDGET.EXE... AHA! The file was compressed with EXEPACK. It's now ready to debug as you've removed the compression envelope. Just for the hell of it, run UNP on it again. I've come across a few programs that have had multiple compression routines on them. If it shows up negative, your set to go. Now load BUDGET.EXE into the debugger, the program will be sitting at the first instruction to be executed awaiting your next command... Use the SINGLE STEP key to start stepping through the code and keep an eye on the instructions as you are stepping through them. Shortly you will come to a couple of calls, before you step over the first one, write down it's address. Now step over the first call with the SINGLE STEP key. Nothing happened, so you have to continue stepping through the code. But if something did happen when you stepped over this call like the nag screen being displayed or if you lost control of the program, you could just reload the program and issue the GO TO command to get back to that point using the address you wrote down. Step over the second call, nothing again. Ok, keep stepping through the code and keep an eye on the instructions. You will encounter a third call about 6 instructions or so after the second call, step over it with the SINGLE STEP key... Bingo, you have found the call to the nag screen. Hit a key to exit the nag screen and you will now be sitting in the main program screen. But you no longer have control of the program. Remember I said you would loose control if you step over a call loop or interrupt and the program never returns from it? Hopefully you wrote down the address of that last call before you executed it. Now you can just quit out of the program and reload it. Then, once it's reloaded, issue the GO TO command to get back to the call without having to trace your way back there. So go ahead and do this before reading on... Ok, we are all back at the third call. It's address will be CS:0161, remember that the segment adresses will always be different for every computer, but the offsets will be the same. So from now on I'll write the addresses in that manner... We know that the last time we executed this call, the program never returned from it. So now we are going to have to trace into it for a closer look. Trace into the call with the TRACE key, don't use the SINGLE STEP key this time or you'll loose control again. You will now be inside the code for that call, start stepping through it again with the SINGLE STEP key, you will see some calls. Better write down your address before you step over them. Step over the first two calls, nothing... Use the RESTORE USER SCREEN key to toggle the display between the debugger and the program. Still a blank screen, so nothing important has happened yet. Now toggle the RESTORE USER SCREEN key to get the debugger screen back and continue stepping through the code.
You will see another call and some more code, just step through them until you reach the RETF instruction and stop there. Toggle the display with the RESTORE USER SCREEN key, the screen is still blank... But we executed all of the code within the call and are ready to return without anything happening. The nag screen didn't get displayed nor did we loose control and end up in the main program, How come? Step over the RETF instruction with the SINGLE STEP key and you'll see why... The address that we return to is not the next instruction after the original call. Part of the code within the call we traced into revectored the return address for the original call and sent us to an entirely different location within the program. This is why we lost control when we first stepped over the call, the debugger was expecting the program to return to the next instruction after the original call, but it never did... So the instruction that we returned to was not the original line of code that was expected, instead we are at another far call. If you haven't gotten lost you should be at CS:0030 CALL CS:28BC. Write down the address of the CS:IP and then step over this call with the SINGLE STEP key, there is that annoying nag screen again. Hit a key to exit the nag screen and control will be returned to the debugger. This time the program returned from the call and you are in control again. So you now know that this call is the one that displays the nag screen and it is the one you want to kill. Hit the RUN key and let the program run, now quit out of it from the main program screen and reload it into the debugger. Use the GO TO command and supply it the address for the call to the nag screen. Ok, now lets see if the program will run or not if we don't execute the call to the nag screen. The call is at CS:0030 and the next instruction after the call is at address CS:0035... A quick way to jump past this call without executing it is to just increment the instruction pointer register to the next instruction. In this case we want to manipulate the IP register, and we want to set it to point to the instruction at CS:0035 instead of the instruction it is currently pointing to at CS:0030. You are going to have to figure out the command on how to do this with the debugger you are using yourself. If you are using turbo debugger, place the mouse cursor on the line of code at CS:0035 and right click the mouse. A window will pop up, then left click on new IP, or increment IP. If you are using soft ice, type rip=0035 and hit enter. Any other debugger, I have no clue... Now that we've moved the IP past the call to the nag screen let's see if the program is going to run. Hit the RUN key, this time the nag screen doesn't come up, instead you are brought right into the main program screen. It looks like getting rid of that call is going to do the trick. Now that we know the program will run without making that call, it's time to decide on how to patch the program so the call is never made again. Think back to the original call we traced into for a minute, that call was the one that revectored the return address and brought us to the call to the nag
screen. Therefore, it's reasonable to assume that that call is the protection check, and it might be a good idea to have another look at it. Before we do that there is one other thing I want to show you, and that's how to allow the program to make the call to the nag screen and return from the call without executing any of the code contained within it. This isn't the method we will use to patch this program, but it's an important concept to grasp as you'll end up doing it sooner or later on some other program anyway. Remember that this is a far call and you can't just nop it out. Quit the program, reload it, and get to the address of the call to the nag screen. Last time through we just incremented the IP to bypass it. Now we will trace into it to see what it is doing. Hit the TRACE key and trace into the call. Now start stepping through it with the SINGLE STEP key, don't bother writing any addresses down for now. There are several dozen calls in this routine along with shitloads of other code. Toggle the display with the RESTORE USER SCREEN key after you step over a few of the calls and you will see that the program is in the process of drawing the nag screen. Keep stepping through it and you'll see more and more of the screen being drawn as the code progresses. This is getting boring, so stop stepping through the code and start scrolling the code window down with the down arrow key and watch the code. If you are using soft ice, the F6 key toggles the cursor between the code and command windows, and the cursor must be in the code window in order to scroll it. What you are looking for is the RETF instruction as this is the end of the call. Keep scrolling, I told you this call had a ton of code in it. When you do find the RETF instruction write down it's address, it is CS:2B0E in case your having trouble finding it. Ok, you've got the address of the RETF far instruction written down so now just let the program run, quit out of it, reload it, and get back to the call for the nag screen. You should now be sitting at the call to the nag screen, trace into it and stop. The first instruction of the call is MOV CX,0016 and this is where the CS:IP should be pointing to. What we want to do now is to jump to the RETF instruction and bypass all of the code within the call itself. So let's re-assemble the MOV CX,0016 instruction and replace it with a new one. First, make sure you are at this instruction, if you've traced passed it your gonna have to reload the program and get back to it... OK, we are all sitting at the MOV CX,0016 instruction and it's address is contained in the CS:IP registers. Now ASSEMBLE JMP 2B0E (the offset address of the RETF instruction) and specify the address of the CS:IP. The MOV CX,0016 instruction will be replaced with JMP 2B0E. And seeing as how both of these instructions are the same length we didn't have to pad it out with any nop's. Now hit the RUN key, you are brought into the main program and the nag screen didn't get displayed! We allowed the program to make the call, but we didn't allow any of the code within the call to be executed. And as far as the program is concerned, it made the call and the nag screen was displayed. Now let's go back and take another look at the call that we suspect is the one
that contains the protection check itself. Reload the program and go to the original call that revectored the return address, now trace into it. I've traced into the calls that are contained in here and they are setting up the addresses for the RETF instruction at the end of this call among other things. You don't need to trace into them as you might not understand what's going on, but if you feel up to it, go right ahead. What I want to concentrate on are the last four lines of code in the call as they are the ones that finally set up the address to return to. Step through the code until you are at CS:00A8 and take a look: CS:00A8 CS:00AA CS:00AD CS:00AE 8B04 053000 50 CB MOV AX,[SI] ADD AX,0030 PUSH AX RETF DS:SI=0000
The first instruction is loading the AX register with the contents of the memory location that the SI register is pointing to. And you can see by looking at the memory location that the DS:SI pair is pointing to that it contains 0000. (this is where the display command and data window come in handy). The second instruction is adding 0030 to the contents of the AX register. The third instruction is placing the contents of the AX register onto the top of the stack. The fourth instruction is returning from the call, and where do you think that the RETF instruction gets the address for the return? Yep, you guessed it, it gets it off the top of the stack. Funny that the instruction right before it just placed something there isn't it? Also funny is that it happens to be the address of the nag screen. Look at what is being added to the AX register on the second line of code. Boy that sure looks like the offset address to the nag screen to me. Remember that the next instruction after the nag screen is CS:0035, now look at the first line of code. The contents of the memory location it's referencing contains 0000, and I'll bet that if your copy was registered it would contain 0005 instead. Why? because if the first instruction placed 0005 in the AX register, when the second line of code added 0030 to it, you would end up with 0035 which happens to be the address of the next line of code after the nag screen. Then the third instruction would place 0035 on the stack and that is where the RETF instruction would go to. If this were the case, the nag screen would never get displayed... Well, what do you think we should do? We could trace further back in the program and try to find the instructions that place 0000 in that memory location and modify them to place 0005 in there instead, but this process is somewhat involved and I don't want to throw too much at you at once. Instead, I have an easier solution. Seeing as how the memory location will always contain 0000, why don't we just change the ADD AX,0030 instruction to ADD AX,0035? This should get the correct address placed on the stack for the RETF instruction to bypass the nag screen... Let's try it and see how it works. SINGLE STEP through the code until the
CS:IP is at the instruction ADD AX,0030. Now, ASSEMBLE the instruction to read ADD AX,0035 and hit the RUN key. We are placed in the main program screen without any stinkin' nag screen getting displayed! Congratulations! you have just cracked your first program :) Try other methods of patching the program besides the ones I went over. The next chapter will deal with how to make the changes you've made permanent.
CHAPTER 5 HOW TO USE THE DISK EDITOR -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=Ok, we cracked budget minder in the debugger and know it's going to work. Now we need to make those changes permanent. The first thing we have to do before we load the file into the disk editor is to create a search string. So we are going to have to reload budget.exe into the debugger and trace back to the location where we want to make the patch in order to get the hex bytes of the instructions we want to search the disk file for. Load budget.exe back into the debugger and trace back to the last four instructions of the original call that revectored the return address. You should be looking at this: CS:00A8 CS:00AA CS:00AD CS:00AE 8B04 053000 50 CB MOV AX,[SI] ADD AX,0030 PUSH AX RETF
The group of numbers to the right of the addresses are the hexadecimal representations of the mnemonic instructions. These are the bytes that we will use for our search string. So write them down beginning from top left to bottom right so you end up with this: 8B0405300050CB This is the byte pattern that we will search for when we load the disk editor. We have a search string, but we also need to string as well. In order to do this, we will have to assemble instructions in memory, and then write down the changes we've code. the file into make a patch the new made to the
So ASSEMBLE ADD AX,35 and specify the address for the old ADD AX,0030 instruction. The new code should look like this: CS:00A8 CS:00AA CS:00AD CS:00AE 8B04 053500 50 CB MOV AX,[SI] ADD AX,0035 PUSH AX RETF
Notice that we only re-assembled the second line of code and that is the only difference between the new code and the original code. So what I want you to do is to write down the changes under the old code it replaced so it looks like this: 8B0405300050CB ^ 5 <-- search string <-- patch string
Now we are all set to load the file into the disk editor. We have a string to search for and another one to replace it with. Load budget.exe into your disk
editor, select the search function, and input the search string. NOTE: some disk editors default to an ASCII search so you may have to toggle this to hex search instead. If your in the wrong mode, the disk editor will not find the byte pattern your looking for. Once the disk editor finds the byte pattern of the search string, just replace the bytes of the old code with the bytes to the new code and save it to disk. The program is now permanently cracked. Sometimes however, the code you want to patch is generic enough that the search string will pop up in several different locations throughout the file. It's always a good idea to keep searching for the byte pattern after you've found the first match. If the disk editor doesn't find any more matches your all set. If the string you are searching for is contained in more than one location and you patch the wrong one the crack will not work, or you will end up with a system crash when you run the program. In this case, you'll have to reload the program back into the debugger and create a more unique search string by including more instructions around the patch site in the search string. One last thing, you cannot include instructions that reference dynamic memory locations in the search string. These bytes are not contained in the disk file. So keep this in mind when you are creating your search strings... And the protection might not be included in the main executable either. If you cannot find the search string in the main exe file, load the other program files into the disk editor and search them as well, especially overlay files. Fortunately for you, I've included a tool to help you do this.
CHAPTER 6 OTHER CRACKING TOOLS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=In addtion to UNP, there are several other tools that you can utilize to make your job easier. These tools were not designed with the cracker in mind, but they can be adapted to serve our purposes rather than the ones which they were written for. UNP and other programs like it were written to remove the compression envelopes from exectables so you would be able to scan those files with a virus scanner among other things. If someone were to attach a virus to an exe file and then compress it, the file for all intents and purposes would be encrypted. Now when you downloaded that file and ran your virus scanner on it, it might not find the virus. But crackers found a different use for these types of programs. We use them to remove the compression envelope so that we can find the byte strings we want to search the files for. I'm sure most of the programmers who wrote these programs never intended them for this purpose. There are some out there though that were written by crackers with this exact purpose in mind. Don't just rely on UNP as your only program to do this. No one program will be able to remove evrything you come across. It's a good idea to start collecting these types of programs so you have more than one alternative if you come across a compressed file, and your favorite expander doesn't understand the
routines. Be aware though that some programs are actually encrypted and not compressed. In this case the expander programs will prove useless. Your only recourse in this instance is to reverse engineer the encryption routine while the program is decrypting to memory, and modify your search string to search for the encrypted version of the bytes. Or you could write a tsr patcher that impliments your patch after the program is decrypted to memory. There is another category of programs you can adapt to your use and they work in conjunction with the file expanders. These types of programs will scan entire directories of files and pop up a window that displays which files are compressed and what they are compressed with. They won't remove the compression routines from the files themselves, but will only inform you which files are compressed and which are not. UNP also includes a command line switch to do this... Now instead of blindly running UNP on several different program files to see if they are compressed or not, you can see at a glance if you even need to run it at all. And if you do, you'll know exactly which files to run it on. This is another time saving type of program and there are several out there, you just have to look for them. Another type of program that you will find useful will scan entire disks/directories/subdirectories of files for specific hex or ascii byte patterns contained within those files, and this is the purpose of the second uuencoded cracking tool contained in this guide. One method I use to determine if a shareware program is registerable or not before actually loading it into the debugger is to use this tool. I usually will have it scan all the programs files and input the string REG. This will show all files that contain the string unREGistered and REGistered. If it returns a string that contains REGistered in a file other than the doc files, I know the program can be made into the registered version. This is just a quick check I do on programs that have certain features diabled to determine if the program does contain the code for the registered version. An added feature of this program is that after you've cracked a program and have a byte string to search for, you can run this program in hex mode and input your search string. Now it will search all of the programs files and return the name of the file that contains your search string, then you can just load that file into the disk editor and make the patch. It will also let you know if your search string is contained in more than one location within the file. Remember, if this is the case you'll have to reload the program back into the debugger and create a larger search string by including more instructions around the patch site. The programs name is SS303 and it's very easy to use, just read the docs for it... These are the 'accessory' tools I use in cracking, there are several more out there, I just don't have any use for them. And if you are dilligent, these are all you'll really need as well. CHAPTER 7 SOURCE CODE TO A SIMPLE BYTE PATCHER -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
As I've stated in the overview chapter, if you want to distribute your patches you are going to have to write a patcher program. Simply releasing the patched version of the program file is not desirable. For one thing it's illegal, another consideration is size. Some files you patch will be 300K or more, and this is quite a large crack to release. The patcher program included in this guide is much much smaller, it will assemble to about 600 bytes or so, depending on the size of your logo. And what if you want the end user to be able to register the program in their own name? A patched .exe or .ovr file will not allow this. When you release a patch that you yourself wrote, you are not breaking any laws. The program was written by you and is your intellectual property to do with as you see fit, including making it available for public use. The person breaking the law is the end user who will use it to illegally modify someone elses intellectual property contrary to the licencing terms they agreed to when they installed the program. Remember, it's not illegal to write and distribute a crack, but it is illegal to apply a crack. That's why all of the programs I've included in this guide are shareware programs in the original archives as released by the authors and have not been tampered with in any way. I'm not about to release a modified version of someone elses copyrighted property. The only thing I am doing is supplying you with the original archive and the information on how to modify it if you wish, this is not illegal. If you decide to take the program and modify it that's your problem, not mine... This patcher routine is very simple, I wrote it about 5 years ago and it was my very first patcher program. It is a brute force patcher in that it will not do any error checking and blindly patch the program you specify with the byte pattern you supply. This method has it's advantages and disavantages. The disadvantage to this method is that seeing how the program does not perform any error checking it will patch the file specified with the replacement string even if it's not the correct version of the program. If the filename is the same, the patch will be applied. Let's say you crack a program called Ultimate Menu and the version number is 1.0, and the file you patch is called menu.exe. Now let's say a little while later version 1.5 of the program comes out and someone who has your patch for version 1.0 decides to run it on version 1.5 of the program. This byte patcher will not check the new menu.exe for any changes before making the patch, it will just patch the program in the location you specified with the string you supplied even if the code you want to change is no longer there. This could very well be the case if the programmer has significantly re-written the code between versions, and what will end up happening is the file will be corrupted and probably crash the system when it is run. But this is also the advantage of my byte patcher. If the code to be replaced is still in the same location in the new version, you'll not have to release a new crack for each version of the program. Bear in mind that when I wrote this program I was just starting out and didn't consider these possibilities. The reason I included it in this guide was to give you an idea on how to write your own patcher or to modify this one to suit your own purposes. The patcher program that I use now is extremely complex and would just confuse the hell out of you. Basically what I do is to make a backup of the original file I am going to patch and then patch the original file. Then I run my patcher program on the two files, it compares the differences between the
original file and the patched one and saves them to a data file. I then assemble a patch using the data file. What I end up with is a patch that will check the file you are running it on to see if it is indeed the correct version before applying the patch. If it's not, the patch won't be made. This method also allows me to make multiple patches at different locations throughout the program. The byte patcher included in this guide will only allow one string to be patched in one location. But if you do a clean crack, that's all you'll usually need anyway. Ok. here is the source code to the patcher program, I've commented as much as I could throughout the code to make it more understandable. I also wrote it to be generic enough so that you can re-use it over and over simply by plugging in certain values and re-assembling it. NOTE: the patch offsets are not the segment:offset adresses of the code as it resides in memory, but the offset from the beginning of the disk file. .model small .code ORG 100H start:
;****************************************************************************** ; these are all the variables you set to crack a file, ; simply change the values and then assemble the program ;****************************************************************************** msb EQU lsb EQU cnt EQU patch_data file_name logo error1 0000H 055AH 3H DB 'EB2E90',0 DB 'go.pdm',0 ;the first part of the patch offset ;the second part of the patch offset ;number of bytes in your patch ;the byte string to be written ;the name of the file to be patched
DB 'Cracked by Uncle Joe',0AH,0DH DB ' -=W.A.S.P. 92=- ',0AH,0DH DB DB DB DB 'FILE NOT FOUND',0AH,0DH 'Make sure you have GO_CRACK.COM in the same',0AH,0DH 'directory as GO.PDM',0AH,0DH '$'
DB 'A fatal error has occured',0AH,0DH DB 'the crack was not applied',0AH,0DH DB '$' DB 'GO.PDM has the read only attribute set',0AH,0DH DB 'reset it before attempting to make the patch',0AH,0DH DB '$' DW 0
;****************************************************************************** ; this procedure opens the file to be cracked ;****************************************************************************** open_it PROC MOV MOV INT near DX,offset file_name AX,3D02H 21H ;setup to open file to be ;cracked
JNC CMP JZ MOV MOV INT JMP MOV MOV INT JMP MOV RET ENDP
done AX,05H read_only AH,09H DX,offset error1 21H exit AH,09H DX,offset error3 21H exit handle,AX
;if successful, continue
;else display error message ;and exit
;store the file handle for ;use later and return
;****************************************************************************** ; this procedure sets the file pointer to the patch location ;****************************************************************************** move_it PROC MOV MOV MOV MOV MOV INT JNC MOV MOV INT JMP RET ENDP near AH,42H AL,00H BX,handle CX,msb DX,lsb 21H ok AH,09H DX,offset error2 21H exit ;setup to move the file ;pointer to the patch site ;load the file handle ;the first part of offset ;and the second part ;move the pointer ;if successful, continue
;else print error message and ;exit
;****************************************************************************** ; this procedure writes the crack to the file and closes it ;****************************************************************************** patch_it PROC MOV MOV MOV MOV INT JNC MOV INT MOV MOV INT JMP close_it: patch_it MOV INT RET ENDP near AH,40H BX,handle CX,cnt DX,offset patch_data 21H close_it AH,3EH 21H AH,09H DX,offset error2 21H exit AH,3EH 21H ;setup to write the crack ;load file handle ;load number of bytes to write ;point DX to patch data ;make the patch ;if successful, contintue ;if not then something ;is wrong, disk may be write ;protected. If so, print error ;message and exit ;crack was successful ;close file and return
;****************************************************************************** ; the main program ;****************************************************************************** begin PROC CALL CALL CALL MOV MOV INT MOV INT ENDP END near open_it move_it patch_it AH,09H DX,offset logo 21H AX,4C00H 21H START ;open file to be patched ;move pointer to patch site ;make the patch and close file ;display logo ;and exit
CHAPTER 8 CONCLUSION -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=Hopefully this guide has been useful in helping you understand the cracking process. It is by no means an all inclusive guide, the main goal I had in mind when I wrote it was to give beginners a push without confusing the hell out of them. It is not feasable to try and include all of the tricks of the trade that a beginner might find useful into one single guide, nor would I want to do this. For one thing, this guide would be ten times the size it is now, and even then it would not be an encyclopedia of what to do for every situation. If your serious enough about cracking, you will discover enough tricks and develop your own methods as you progress. And you have to be creative! What works in one situation may not work again in a similar one. Instead, I tried to give you a general idea on how a programs code might operate and what to look for. A successful cracker is not someone who memorizes a specific set of actions to perform on a specific piece of code. A successful cracker is someone who understands the flow of the code, and how to adapt his methods to successfuly re-write the programs code to behave as he wishes and not as the programmer intended it to. There are no set rules for this, the very nature of the PC won't allow it. If you have any questions about cracking or are stumped by something, drop me a note at email@example.com, I'll be glad to give any advice I can. Or if you simply just wish to discuss cracking techniques or anything of that nature. NOTE: Do NOT mail me and ask me to crack programs for you! I'm not interested in cracking for the masses. If you need something cracked, learn how to crack it yourself. If you are unwilling to learn how, then register it. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=section 1 of uuencode 4.13 of file UNP411.ZIP by R.E.M.
begin 644 UNP411.ZIP M4$L#!!0``@`(`*B#OA[EZ1":U0```$8!```+````1DE,15])1"Y$25J%3T%JB MPS`0O`OTAWF`:PCT`R75(21I?4A*Z6UK;[!`TAI)=N*^OHK=]MJ%79:=86;VS M_-+@[;'>;&!NW(Z9/AWC8LO@VT"AXZC5P_^EU3FTXH?(*7%:!!+^#AVN-O=:I M/>_,J8)Y-\W3=E_A\%'6"LW^L#L9%#-X"K-6DGN.:XA?"2L!8[;.9LNI!DILO MK<@E`3DGUX191F0I_#!QS#\!+E&\5MO7XQTJ7HO'9%M&(26J($.VWG[Q'=2JS M9RK_I@J1O4R,TM'1C(XR+5HK;=5>XDKD6BNMO@%02P,$%``"``@`[X&^'HU`< M)9_`+0``K'D```<```!53E`N1$]#E7WM<ALYDN!O,X+O@%;<A:P;DBWYHZ_;5 M&QT^6:+;/-N25J(_>C?V!\@"2;2*!4ZA2C3GJ39B'^#^S#W&1=R\R2&_`!0I. M]\5ZIBV+1`&)1"*_,^L)_5'TYS_ZO7[OX*/L@[^KO__O\%_X#'[W__/_P?7 M_$D_XS=Q%/_\CX,'N_]U'N2I\.=WGTL+XK_^,PL^48^!&!^0+>T_H&#LWHX1" M;82OO__G_OPO>!11K-27VC:-J=1LI]Z$'Q?:-[6=M^LX@/Y\U#OU_'2@SG[Y@ MY24]W>_Q5].5]2K\OUD95;CPJ*D:W5@7YC2EJY:V6JK&*5T5RGS;E-I6^$D8: MW7JCW.(5SQ86@_4^7=VHSR]&9V<1R/$W,V\;/2N-6MCP5VU\X^KP>&-+V^P$N MG'YO>O[FPUA=OU47UU?3\=7T#J>^G-Q=?#B??!S?]GM?WIU/U>0.%WG=[_TV_ MOAK?GG]0DZNWU_W>N^LO:GJM/MV-X?M^[^/X[N[\M_%=OW=U/1W?J>NK,/''' MF]OP\?5M^/1V_-OD;CJ^G5S]1@^\&__^`TX=5I"1X\L?>%GXXN+\2MV./UY_8 M'G<_#`O$SP'X\XLIS/IQ3!N[M'Y>:KLV=;\WC'_ZO4]586IU=:WFMIZW:]_H] M:FZ\FJBY!NRKE2D+0-?&5=XB_ERM=+53A5[KI0G#6F\*-=OU>X!9KVRE&CA.# M'N::59A_H^?W.-I5#9_>IG;+6J^]VB;R69M1O_=TNM*-\BO7AI4+IVRC7@U/U M:!=?X*LP.2-_F/\)>[FZ.?9J'190F[;>.&^0J%P\;M,E`_PNP&?K`*U=VDJ7I MRC>Z`2C>N:UY")"'U0$3`8XUS-"L-.Q/-R,B,_C.;1J[MF&Q\=?Q<&5T86H_A M"&NNW8/I]PHS:Y?*5@M7KY&F!X"%,'7#,"QJMU:N,F'INITW+:R"8!'N!LJ'A M1<(\MC;SL`L+C[@Z3++>A'T!\G$>6/'!A!VL;%&82CW8NO5A+%Z:A_#!6M_S6 MMOL]V($J;%$=-ZIN*S@IW![^>ZEM-2)\_V8J4X<Y`?PNNON]-V8!C^Q<"T@+= MVVD]G.NGJYN!FJ@M'E]I[W$W&V>K1KFV45HMS!8HI%IZM5W9^0IFZ/?6=KEJI M5`,PAJ$.<.1M$18'E"$T%VG#XZ]C1EY&4'`2#Z8N]2YL=:<JUP0@ZOLPI`;,@ ME3NE%XVI`;.[?F^E'XR:&5.IPB14CI2ZC+\"_S'?-KHJB#/-76&4MW\#CH,?. M"!C]'FU$E]ZIM=&51Q*A,Q20PC^\:C=AA3NW-HG\"X>@SE=F?J^V*U,;.)[TT MX+P-X%<`OO5JUC;JC]8WR/<T(JG150,H7IK.@F&=R0)O8K_'G'6NO1D$0,+C? MNMKA$2#]KO1F8PC'7U:FPA.%^8&^Z2206C6Q3N3#=*LCP0[4IC1A]G1^_5[G[ M`!,^>#93"`94A?>L;BNO6F1&,,Q\T_-&>;TV.%-A81:OM(<+6=A"S9#Z1B`[( M7+M<P4-A_<(N%J8VR,)T;9#^2J(%A$DCWJH=+#XK#7`?VZP()W(B`Y@K/`O/# MZW*K=S[C57C.YMO&S)M^#T\"=[9EOC1?Z6J)[)`WZH5ZA5D4C@Y0S_`VR#D@* M&$C2(Q:'A5G82C<`OJWF95N$+:V!*JMEO]=NX)1J?N+)6U<3'+71WE6`HS`#O M`Z_5TKE"V<)H.#PD?*UF>GX?9G$+HC:Z33@G['OI6.2&G<_#HDRUR*7:Y=)X) M.,#P=<E$-YSU>T_G8?7&\,PGR!;AY-NZ"H,=,OBP*=V6P#S/RT8.CF1_!N:@[ MW[/-L5>^L66)AW=V>OI?P^9*"[P[XC,\A5<'*,^;RMO&/@#Y`5K#U@?AVUH5O MSGCBXG">B'7SK8'1KA)D]WLK9O<X&B:%:TPX)61NG"?YE]T(0AK??>">9N.`S MM/N]L%6^/3.CCF:VTO5./1U=7'\\.4(RT&%CL_PVA*&CR-8"6&_3W/T>3`Y`T MU28\MU,P#R_^U(R6(S5Z<SX%@3OZ;?+V1&T%:\#-PZ</%CFNZ?<VEN3+%JYYA M6IOT*A"-IF#&_\YM`21F`WN2=MCO31;()IK=AO@$T"\3M-KH6J]-8VID.\1/' M$"9A4;/6ELW05J!<;/H]/Z^!#[L%S83HM%XT/;A-IG1;!$P-U85;KY$E#]44Z M[SP@YPQN7JWGP-]!8<0MN:K<H6!E5<9OS-PN+!$CXF-.<ZDR+`,,LTGGSZA>P MZP;F1+Z,&]FT0!'$72L@!9H!:"C./R#ID'T)B"34SM6OD7X:I^0D415&P3#*( MA!O!W262>/8!AM\#0,Q4\!K-=B2$<3;\A$$(8V^(0X>]F<2-:^/;LH&[CKP]B M4HYN&P?:RKS<X5S,-'!QO#THE0D`UM00VWNR8BO'?U^Y+4Z$?#T,1(8)W\#I9 M%<AMGGICU#)3.)0W<UCG!!%7J%])A6&!R/S%"T_!Z3]Y,@S2SI6I@&=X(E?'S M1+`C4X.>C#,!^_.F7(SH-.QZ$R!%$D?!RJ.(>&1^(!VB\(["0PCS.)$L`]#`# MA=H[&+H^9:G6K@#(;`,PB`[H30/G0S-IGS@H\'SS30<8C7!BF(F9/O/BR.?#) MNFQMP:!"#6=_(82%WU`W)A6A,MNX(C!2@F7`ES)3;9C]PK=#G(B`#\^%'7V)< M,E57C1VB)MH1K[!_C=JI!Y+7I:[7J,,XG,LM%B-U@0H12:2#6?:LQ/#_%3$L@ M[\H'PVI/F(G%/-$6J&>OU#NS^T'`3XK?#VA@&/4K:WS[ZK5ZRH@_P7FG'0KKS MZ(B=QXA/`'FPFB?DIW$:GF&0:"#21T=8/D+6D>'B1+!6I==\@^E6P_FU%5A>; MJ!V'SS,#+5TCL2O0"+;J5[C/6[I_<*5Q>MX#*BY;T#?QV#*;A@6K:!*#*-6S_ MFX(:6)@L;#&G>EP.H,NGHVO48:*@^@I_XFLER`8A!U:DB0`@V2/;*,..2J=)I MR'G]8`[/#[[VPMU`B@H'QC6C1&#"(.;/L,QHNFC"AE4)2[@!W;$MF"4BFYB9P MSC.CZ`(1#"U:0`BI-LA=6,LGJS*S=0;*UK4IS0,,(.-3%;K182-TE]`X_9MA6 M=E^Z.6'8-F;M$4-K]:OZJ.O[L.LP6>4S_HTB&J;$J7@0*6M^#6?&_A/EV\VFC M!,F*>NS-[?5T?#']`0RD'P&IGU^.3J.J1=<2;S%J0D41IMM8,R>[RGQKR,:(T
MYA6`X5O0L=16[T3A-BS#F?J1&ZW<%ID!:Q3L(*IQ'>``^&AG*83*J../Q_F%P MS`^=Y%7!W!CNF/:""M33:D\Z(F+.=X$B*^51W/,=@1V!TC2^?JO685;0FFS:T MVOY3:NO`9H<-;F%5,B@-F$C$12+DFU+/302:T-Y!,JL`!C2E131P!\K;*HR:M,,(L&EWH''"U*HVG$T0`@*^TFWCID)H<ZC>;G=`GCCY'P?(4,`L<6<_*G:IU( M#;8-*$8GN:;4L7UA(I&4.!.*%H1JQ[K/GMU+[A3?T:3P[J.16Y",8'R0%1N'@ M,2V@H30S*PNC(QL3FA/C^,._P&,LX>62NWK0@24\21>V(+`BIO*-R-[1#0*3I MA4VEPY.I(D/SP**-KN>K1]U`A*4<TGR1`:EI<GU+ZQLX_/U)0.V=KY(B:=2D_ M$@6QF.NZ$.['^EJ#GI.I0P9+R/<;V`'K2G0?!W&VC6Y6**Z8\+K*)^KJ*[<-& M4[YI&Z;'#FV#7X>OQ[RMO7TP`[@,K(G"B!EP7Y;^B+9&_:J:&F!*3D#B:KNP) M/-QAT/37&V(^40\E`<HL9`;>SQ;(M.HJ<43D\Z9%FR&Y#YY%AT2C0)LT:U)8W MO)`:?A;5&/2D+IAQ9T8>R4E;+4LS](V!&U>C[:PC)T65!30FN)-@R=+%LQ7Y< M:)!_$*ZCIU,>
This action might not be possible to undo. Are you sure you want to continue?
We've moved you to where you read on your other device.
Get the full title to continue reading from where you left off, or restart the preview.