SmperFidelis has reported a post.
Reason:
Forum: Computing
Assigned Moderators: SuF
Posted by: Psychonaut Soul
Original Content:
Reason:
Post: A beginners Guide to CrackingBlackhat/against rules.
Forum: Computing
Assigned Moderators: SuF
Posted by: Psychonaut Soul
Original Content:
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 group of 8 numbers with the
colon in the middle of them to the far left of the window is the
addressffset 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.
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 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
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 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
following:
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.











