You are on page 1of 29

A beginners Guide to Cracking

Chapter 1 overview
Chapter 2 some tips on how to use the debugger
Chapter 3 some basic cracking techniques
Chapter 4 walk through of an easy crack
Chapter 5 how to use the disk editor
Chapter 6 other cracking tools
Chapter 7 source code to a simple byte patcher
Chapter 8 conclusion

Programs included at the end of this guide

Section 1 uuencoded cracking tool
Section 2 another uuencoded cracking tool
Section 3 uuencoded program to crack for the walk through

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

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.

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

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.

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 group of 8 numbers with the
colon in the middle of them to the far left of the window is the
address:offset of that line of code. Each line of code in this window is an
instruction that the program will issue to the microprocessor, and the
parameters for that instruction. The registers that contain the address for
the current instruction waiting to be executed are the CS:IP registers (code
segment and instruction pointer).
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.
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
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
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
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
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.

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
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 CMP BYTE PTR [A76C],00
09D8:0145 JNZ 014B
09D8:0148 CALL 0C50
09D8:014B 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 the
results of the compare instruction. The JNZ instruction will make the jump to
the fourth line of code if the zero flag is cleared. This will bypass the call
to the nag screen on the third line. If the zero flag is set, no jump will
occur and the call will be made.
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 new code
09D8:0140 CMP BYTE PTR [A76C],00 09D8:0140 MOV BYTE PTR [A76C],01
09D8:0145 JNZ 014B 09D8:0145 JMP 014B
09D8:0148 CALL 0C50 09D8:0148 CALL 0C50
09D8:014B MOV AH,18 09D8:014B 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
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
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 MOV [AF56],AX
0277:01B8 PUSH BX
0277:01B9 PUSH CX
0277:01BA 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
original code new code
0277:01B5 MOV [AF56],AX 0277:01B5 MOV [AF56],AX
0277:01B8 PUSH BX 0277:01B8 PUSH BX
0277:01B9 PUSH CX 0277:01B9 PUSH CX
0277:01BA CALL 0234 0277:01BA NOP
0277:01BD POP CX 0277:01BB NOP
0277:01BE POP BX 0277:01BC NOP
0277:01BF JMP 0354 0277:01BD POP CX
0277:01BE POP BX
0277:01BF 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 MOV CX,0003 ;Sets up to give you three tries
0234:0B57 DEC CX ;deducts one for every time through the loop
0234:0B58 JCXZ 031A ;when CX=0000, program will abort
0234:0B60 PUSH CX ;just setting up for the call
0234:0B61 PUSH DS ; " "
0234:0B62 PUSH ES ; " "
0234:0B63 CALL 035F:112D ;call to input window and validation routine
0234:0B68 OR AL,AL ;seeing if check was successful
0234:0B6A JNZ 0B6E ;yes, continue on with the program
0234:0B6C JMP 0B57 ;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
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 MOV [324F],BX ;
035F:1131 CMP BYTE PTR [BX+06],03 ; just some error checking
035F:1135 JNZ 0339 ;
035F:1137 CALL F157 ; call to the input window that
; asks you to type a word in from
;the manual
035F:113A MOV DI,[0332] ; this routine is comparing the
035F:113D MOV ES,DX ; word you typed in to a word
035F:1140 MOV DS,BX ; in memory that the program is
035F:1144 MOV SI,[0144] ; referencing. As long as the
035F:1148 MOV CX,[0097] ; bytes match the loop will
035F:114C REPE CMPSB ; continue.
035F:114F JCXZ 1154 ; This is the routine that sets
035F:1151 JMP 1161 ; the memory variable. 01 will be
035F:1154 MOV AX,0001 ; placed in it if you typed in
035F:1159 MOV [0978],AX ; the correct word. 00 will be
035F:115E JMP 116B ; placed in it if you typed in
035F:1161 MOV AX,0000 ; the wrong word.
035F:1166 MOV [0978],AX ;
035F:116B POP ES ; setup to return from call
035F:116C POP DS ; " "
035F:116D POP CX ; " "
035F:116E RETF ; return from call

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

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
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
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
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
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
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
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 8B04 MOV AX,[SI] DS:SI=0000
CS:00AA 053000 ADD AX,0030
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
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.

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 8B04 MOV AX,[SI]
CS:00AA 053000 ADD AX,0030
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 file into
the disk editor. We have a search string, but we also need to make a patch
string as well. In order to do this, we will have to assemble the new
instructions in memory, and then write down the changes we've 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 8B04 MOV AX,[SI]
CS:00AA 053500 ADD AX,0035
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 <-- search string
5 <-- 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.


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

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
ORG 100H
start: JMP begin
; these are all the variables you set to crack a file,
; simply change the values and then assemble the program
msb EQU 0000H ;the first part of the patch offset
lsb EQU 055AH ;the second part of the patch offset
cnt EQU 3H ;number of bytes in your patch
patch_data DB 'EB2E90',0 ;the byte string to be written
file_name DB 'go.pdm',0 ;the name of the file to be patched
logo DB 'Cracked by Uncle Joe',0AH,0DH
DB ' -=W.A.S.P. 92=- ',0AH,0DH
DB 'Make sure you have GO_CRACK.COM in the same',0AH,0DH
DB 'directory as GO.PDM',0AH,0DH
DB '$'
error2 DB 'A fatal error has occured',0AH,0DH
DB 'the crack was not applied',0AH,0DH
DB '$'
error3 DB 'GO.PDM has the read only attribute set',0AH,0DH
DB 'reset it before attempting to make the patch',0AH,0DH
DB '$'
handle DW 0
; this procedure opens the file to be cracked
open_it PROC near
MOV DX,offset file_name ;setup to open file to be
MOV AX,3D02H ;cracked
JNC done ;if successful, continue
JZ read_only
MOV AH,09H ;else display error message
MOV DX,offset error1 ;and exit
JMP exit
read_only: MOV AH,09H
MOV DX,offset error3
JMP exit
done: MOV handle,AX ;store the file handle for
RET ;use later and return
open_it ENDP
; this procedure sets the file pointer to the patch location
move_it PROC near
MOV AH,42H ;setup to move the file
MOV AL,00H ;pointer to the patch site
MOV BX,handle ;load the file handle
MOV CX,msb ;the first part of offset
MOV DX,lsb ;and the second part
INT 21H ;move the pointer
JNC ok ;if successful, continue
MOV DX,offset error2
INT 21H ;else print error message and
JMP exit ;exit
ok: RET
move_it ENDP
; this procedure writes the crack to the file and closes it
patch_it PROC near
MOV AH,40H ;setup to write the crack
MOV BX,handle ;load file handle
MOV CX,cnt ;load number of bytes to write
MOV DX,offset patch_data ;point DX to patch data
INT 21H ;make the patch
JNC close_it ;if successful, contintue
MOV AH,09H ;if not then something
MOV DX,offset error2 ;is wrong, disk may be write
INT 21H ;protected. If so, print error
JMP exit ;message and exit
close_it: MOV AH,3EH ;crack was successful
INT 21H ;close file and return
patch_it ENDP
; the main program
begin PROC near
CALL open_it ;open file to be patched
CALL move_it ;move pointer to patch site
CALL patch_it ;make the patch and close file
MOV DX,offset logo ;display logo
exit: MOV AX,4C00H ;and exit
begin ENDP

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
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, I'll be glad to give any advice I can. Or if
you simply just wish to discuss cracking techniques or anything of that
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