Exploit Beginning cracking of (x86) Window's software and software protection


18 Дек 2022
Проверка EDB
  1. Пройдено
Тип уязвимости
Дата публикации
Beginning cracking of (x86) Window's software and software protection
	- without knowing assembly
by Anonymous Author

        I learned how to crack simple programs quite a while before I
learned any assembly language. While it was crude and somewhat hit or
miss, it was an aweful lot of fun. While I now know to some small
extent what I am doing, cracking software protection early on was
practically a training course in analysing things which I didn't
understand. It is not neccessary to be able to write or throughly
understand assembly in order to crack software protection. In the
following article, I intend to teach you, the non cracking community,
a little about cracking and analysing programs.
        There are many very good crackers and reverse engineers out
there, writing excelent cracking tutorials, some of which will be
referenced at the end of this article. The problem is that they all
focus specifically on one piece of software. While I will be doing
this as well, this is intended to be a more general guide, that will
teach some basic techniques.


        The first thing that pops to mind when told that one is going
to be cracking software without knowing assembly, is something along
the line of "Wow! We must be using super 1337 analysing and
decompilation software!"

Dissassembler - Windasm 8.93 or later. You can no longer get this
program from the original vendor,  so you'll have to look for it.
Beware of backdoors and self exploiting versions of this software.
(Wait... why did DEP just catch something?) This is a disassembler.
I will go into the background theory on how it works later. There are
much more advanced disassemblers, such as IDA Pro. I would recomend
against using these as they will become a crutch which will deprive
you of the joy and learning that use a cruder tool will allow you.

Hex Editor - There are a bunch of these, ranging from the simple
(HexPert, HexEdit) to the seriously cool (010 Editor). For our
purposes, a simple hex editor such as hexpert (untimed shareware) is

Opcode reference - You are going to need a list of "opcodes" and what
they do. See masm32. (Masm32 has a document called Opcodes.hlp, under
help. You're going to need this.)

Debugger - We're not going to have use for this until much later in
the article. I'd mainly like to concintrate on using a disassembler,
but I will explain some of the use of this tool. Dissassemblers,
especially extremely powerful ones (such as softice) quickly become
crutches as well. I would suggest OllyDbg as a good, simple debugger.

Pad of paper, notepad.exe, or something to take notes on - I always,
always take notes.

masm32 - needed for assembling the crackme. Whatever you do, do NOT
look at the examples that come with this program. The examples are not
in assembly!!! They are actually something called high level assembly,
a bastardization of assembly. Knowing this will not help you at all
when looking at a debugger. Get it from www.masm32.com

ZoneAlarm or other firewall - An lot of software calls out, and tries
to tell the parent company if you have a legit copy. Even if you
don't care about being caught, you should block programs you are
cracking from the internet. Vendors will sometimes deactive cracked
software when it calls out.

Information you will need to know

- You will need to understand at least basic programming. You will
need to be throughly familiar with functions, loops, if/then/else, etc
While you need not be a programming guru, the more you understand
another programming language the more sense this will make.

- You will need to understand hexidecimal. Hexidecimal is base 16,
basically you count going 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, and then
instead of 10, you go A, B, C, D, E, F. The next number after F is 10,
then 11 etc. You're just adding more digits to the number system. Put
the windows calculator in scientific mode and play around with it,
it's just like what you're used to. You can also use it to convert
between decimal (base 10, what your used to), and hexidecimal (base

- You will need to know what assembly language is. You might laugh,
but if you do not understand how assembly relates to machine code,
none of this will make sense.

- You must have the ablity to look up terms you don't understand.
http://en.wikipedia.org is an excelent resource for *anything*
computer related. So if you don't know what an offset is, look it up.

Example programs

        I was initially going to use a piece of commercial software as
an example, I ended up writing my own crackmes as examples. This is so
I could demonstrate, as directly as possible, whats going on.

- Crackme0 is the simplist copy protection I could come up with. It
demonstrates basic cracking techniques. It does not use a real
software key, it only has a built in global variable to tell if it's
been registered or not.
- Crackme1b is a more complex piece of copy protection, intended to
demonstrate removing a nag screen. It is also possible to crack the
copy protection, as well as toy with it in a number of different ways.
This program uses a (very simple) software key.

Disclaimer & Warning

Disclaimer: I am not super leet. While I now understand assembly
language, I am far from good at it. I am also not a good cracker.
There will most likely be a number of technical innaccuracies, but
I am teaching techniques, not a class. Everything I talk about in here
I personally learned and done at one time or another. I am not
resonsible for you ripping off software; all software mentioned is
used as an educational example, and I do not condone or encourage
anyone to do anything listed in this paper. This is for educational
purposes only.

In the beginning

I tricked you, the reader. While you don't need to know assembly, I am
going to teach you a tiny tiny bit, just enough for you to be able to
analyse the program. If you find this entertaining, I highly recomend
that you find a local college or course that will teach you assembly,
so that you'll actually be able to write it, rather than understand a
little. You may want to fire up windasm, and be looking at any random
windows program while you read this part, so you can see examples of
these instructions in use.

I'd also like to add that this may look intimidating, but really is not.

One quick thing - Registers

        While this is not directly related to what we are doing, you
will see these all the time, and need to know at least what they are.
A register is sort of like a variable, but it contains the information
on the processor it's self. There is a limited number of them, some of
which have special functions. They are called (in a 32 bit program)
eax, ebx, ecx, and edx. There are more, for special uses: ebp, esp,
eip. These can moreover be broken up into other registers, for
dealing with smaller amounts of data, or a part of the value in the
register; for example the second half of eax (e stands for extended)
is ax, and ax is made of ah and al. You don't really need to know any
of these, it's just useful for understanding whats going on.

Instructions that you need to know
	jmp (and friends)
Jmp is a very simple instruction. It moves to a new point in the
program. It is unlike programming in C, because you are not using a
function. Say you see the following

	jmp label_b

All you're doing here is moving the point at where the program is
currently executing forward (or backwards) to label_b. blah blah blah
blah is therefore skipped. You should know that when you are looking
at a disassembled program, you will not have a informative label. It
will rather be something like "jmp 4Ch" 4C is a *relative* address.
You take the current possition, add 4C bytes to it and *poof* you have
the new location.

For those interested in the details, or know a little assembly, you
are changing a register called eip (think of a register as sort of a
perminant, changable variable, that stores the information on the
processor). eip always points to where the processor is currently at
in any piece of code. The jmp instruction tells the processor to add
to eip. EIP stands for extended instruction pointer.

cmp is another instruction you will need to know. Any time you see a
cmp, the program is checking if something. It's like an if(blah)
statement in any other language. You cmp something, a register to a
register, a register to a piece of memory, something like that, and
then decide what to do. Cmp will NOT change where you are in memory
(in other words, where you are in the program), it just does the
compairison, hence the next few instructions.

cmp, like everything else in "nasm" style assembly goes from right to
left. The right instruction is compaired to the left one. This isn't
really important here, but it is when you are looking at a mov
statement (later).

The way cmp works is by simple subtraction. Think about the c
statement if(3 == 4). cmp subtracts 4 from 3, and sets some flags.
if(3 == 3) then cmp comes up with 0 - they're equal! It then sets some
flags so that a conditional jump can be made.

Conditional Jumps
a small (incomplete) table of the jump instructions:

	jmp		jump				
	je	==	jump if equal			
	jne	!=	jump if not equal
	jg	>	jump if greater than
	jge	>=	jump if greater than or equal
	jl	<	jump if less than
	jle	<=	jump if less than or equal
	jz	== 0	jump if it's equal to 0
	jnz	!= 0	jump if it's not equal to 0

All these jump instructions work the same as jmp, except that they are
used with a cmp to jump on a condition.

Say you want to say if(haveValidKey != 0) run_the_program();
Thats what all these instructions are for. First the information as to
whether you have a valid key is evaluated (not shown), then the
information is moved to a register, then a compairison is made, then
finally one of the above jump statements is used to decide what to do.

So you should really think
eax = haveValidKey;
if(eax != 0) run_the_program();

This translates in assembly to
mov     eax, word ptr [haveValidKey]    ;have valid key is a variable,
                                        ;it's moved into eax (right to
cmp     eax, 0h                 ;0h is the same as 0. the h part means
                                ;that it's hex
jne     run_the_program         ;run_the_program is the location where
                                ;the good stuff starts

As you can see, the data was moved to eax, a register, then compaired
with 0, then lastly jne was used. jne is Jump Not Equal, aka !=. See
the UnneccessaryInformation for cmp if this confuses you.

Theres one last little thing I should point out, and thats when you're
disassembling a program, you get the exact same assembly code as
above, but with one small difference: you don't get any labels,
comments, or variable names to make things clear.

In a disassembler this would look something like
mov	eax, word ptr [0x4d3db33f]
cmp	eax, 0x0
jne	0x000000BF

0x4d3db33f would be the memory location of the variable that is being
put into eax. 0x4d3db33f is the same as saying 04d3db33fh - I use the
h because that is what masm32 recognises. cmp checks 0, and jne jumps
to the rest of the program if it's != 0

You'll note if you look at the full list of jmp instructions, that
there are a bunch of ones that do pretty much similar things.

Full list of jmp instructions, stolen from an intel opcode reference
(the one that comes with masm32):
	JA     Jump if Above
	JAE    Jump if Above or Equal
	JB     Jump if Below
	JBE    Jump if Below or Equal
	JC     Jump if Carry

	JCXZ   Jump if CX Zero
	JE     Jump if Equal
	JG     Jump if Greater (signed)
	JGE    Jump if Greater or Equal (signed)
	JL     Jump if Less (signed)
	JLE    Jump if Less or Equal (signed)
	JMP    Unconditional Jump (already been covered)

	JNA    Jump if Not Above
	JNAE   Jump if Not Above or Equal
	JNB    Jump if Not Below
	JNBE   Jump if Not Below or Equal
	JNC    Jump if Not Carry
	JNE    Jump if Not Equal
	JNG    Jump if Not Greater (signed)

	JNGE   Jump if Not Greater or Equal (signed)
	JNL    Jump if Not Less (signed)
	JNLE   Jump if Not Less or Equal (signed)
	JNO    Jump if Not Overflow (signed)
	JNP    Jump if No Parity
	JNS    Jump if Not Signed (signed)
	JNZ    Jump if Not Zero

	JO     Jump if Overflow (signed)
	JP     Jump if Parity 
	JPE    Jump if Parity Even
	JPO    Jump if Parity Odd
	JS     Jump if Signed (signed)
	JZ     Jump if Zero

You can ignore all the ones (for what we're doing) that involve parity
(a type of error checking), and overflow (in assembly you can check
for integer overflow and underflow, look it up if you're not familiar
with this).

call is an instruction that does the same thing as calling a function
in any other language. It moves to the new function, and when it is
complete, keeps on going after the point where the call was made.

An example would be
call    destroy_computer        ;destroy_computer is a memory address
                                ;in the program
call	reboot_computer

Say destroy_computer and reboot_computer are functions, this will call
the function to destroy the computer, and when that is done, will go
to reboot computer, to really screw over whoever's computer this is.
Say, is that smoke coming out the back of the monitor?

        You might be wondering about how data is passed to the
functions. While I don't want to go into detail, you need to read
about the stack. It's really facinating - and with a little assembly
knowlage you'll start saying things like "but what if you did xyz,
what would happen..." xyz might be changing the return address, or
some other fun way of messing with the computer. So read about the
stack, and the instructions that use it, push and pop. This is known
as the stdcall - the standard way of calling a function.
        Sometimes you'll see data stored in registers before a calling
a function. This is fastcall, because the computer does not need to
mess around with the stack (except to get where to return to).

mov just moves data from point a to b. You can move it from a register
to a register, register to memory, or vice versa. You just need to be
able to recognise it. mov works from right to left (when dealing with
nasm notation, aka windows assembly. Linux assembly is usually written
in at&t notation, which is backwards. Annoying, huh?)

mov	eax, 0h

puts 0 into eax. You should know that due to the physical constraints
of the computer, you cannot move memory to memory, without first
storing it in a register. This is because if you were to copy memory
to memory, it would have no chance to go through the processor

nop does nothing. Literally. This instruction changes no data,
processes nothing. It's really useful. If you overwrite an annoying
part of a program with nops, that annoying part has just ceased to be.
The nag screen on crackme1 can be removed with nops.

Now the tough part is over, and we can start to have some serious fun.
For people interested in learning more about assembly, I would
recomend the book "Assembly Language, Programming for the IBM PC
Family" by William B Jones. Unfortunetly, the book is all MSDOS
assembly, but all the techniques are the same, and going from 16 bit
dos to 32 bit windows is about as complicated as putting e in front of

First simple example

This is a small program that you are going to crack with your new,
1337 knowlage of assembly. All this program does when run is pop up a
window saying "This software is unregisterable!." All you are going to
do is make the other window pop up, the one that tells you that the
program is registered. There is no way to register this program other
than cracking it. To get the most out of this excersize, assemble the
program in masm32's nice little editor, then disassemble it with
windasm. This is the way you are going to be looking at programs from
now on. This will familiarize you with windasm, with the original
example to look at. Don't freak out if you don't understand all of
this - the point of this whole article is that you don't *need* to
understand all of this to crack it. So assemble this, run, disassemble
in windasm, and prepair to crack it.

; Crackme0.asm by Anon                 
; Modify this program to be registered.

.model flat, stdcall

option casemap:none		;don't worry about this crap

include c:\masm32\include\windows.inc	;masm32 includes for windows api calls and stuff
include c:\masm32\include\kernel32.inc	;this assumes that masm32 is installed to the
include c:\masm32\include\user32.inc	;default directory
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib

.STACK 256h
      ;This is the string table, pretty much. You can find it by going through a program
      ;With a hex editor - you'll find it near the end with all the strings used in the
	DLGCAP    db	"Crackme0",0
	REG        db	"This program is registered",0
	UNREG      db	"Damn - the program isn't registered",0
        ISREG      dd     0 ;This is a global variable that tells us that the program isn't


;Main function - this can actually be called anything, but it's the same as main() 
;This is the part of the program you need to be paying attention to

    mov     eax, ISREG
    cmp     eax, 0           ;The comparison - is the program registered?
    jne     prog_registered     ;if(isreg != 0) goto prog_registered
    jmp     prog_unregistered   ;otherwise it's unregistered

    ;Right here were are loading all the parameters for the dialog box
    ;then calling it, then going to the end
    push    MB_OK   	    ;MB_OK is a value from one of the windows includes
    push    offset DLGCAP   ;These are loading the strings
    push    offset REG
    push    0               ;this is required by the windows MessageBox function
    call    MessageBoxA
    jmp     theend

    push    MB_OK
    push    offset DLGCAP
    push    offset UNREG
    push    0
    call    MessageBoxA
    jmp     theend

    push    0           ;end this program
    call    ExitProcess

End Main

        Look at this program for a second. Think about what parts of
this program could be changed, so that the "This program is
registered" box will appear. As with anything in life, there are
multiple ways to do it.
        Some people might have noticed the global variable ISREG.
Well, what if this variable was 1, indicating that the program is
registered? Because it is a global variable, you can actually find
and change this number. If it is a local or a temporary variable you
cannot do this. So ok, you could change ISREG. That would be the
equivalent in a piece of serious copy protection to changing the
software key to something that works. So change ISREG, run the program
and it's registered.
        But something like this isn't always practical. The variable
will not always be part of memory, easy to locate, or anything like
that. Remember that we are going to be disassembling the program, so
you will not have a nice name of ISREG. In this case we should think
about how we could tamper with the actual compairison and jump. It's
time for a little home made cracka theory.

Magic Spots

        This is my own name for it. I taught myself all this, so
theres probibly a completely different name for it. I call it a magic
spot though. In any piece of copy protected software, the part that
checks the validity of the key on your computer (or even it's
existance), is usually pretty complex.  While you could mess around
with the ways in which it tries to evaluate the key, this is a pain in
the ass because it's complicated, and you don't understand everything
thats going on.
        Fortunetly, for each function that checks the validity of the
key, no matter how complex, there is a point at which the copy
protection mechanism has made it's decision, and there is a cmp
followed by some form of jmp. This is a magic spot. No matter how
many different ways the function is checking it's validity, it will
eventually narrow down to at least one comparison which is asking
"After all that processing, is this valid?" You want it to answer yes.
        Note that in 95% (or more) of copy protected software, there
is only one function checking the validity of the key. This means that
in 95% (or more) of software, there is (at least) one compairison,
that when found and altered, cracks the software.
        The problem is that there are a lot of cmp/jxx so finding the
right one can be difficult. First you need to find where the copy
protection is, and where all the relevant parts of the program are.
We'll go into this later. For now, look at crackme0. This program is
extrememly simple, so finding the exact point in which the final
comparison is made is quite easy. Remember this part? (The h after the
0 just means that it is a hexidecimal number.)

    cmp     eax, 0h           ;The comparison - is the program registered?
    jne     prog_registered

Well thats our magic spot. There is a compare and then if it is
registered (eax != 0) you get the dialog box saying it's registered.
Crackme1 has a more complex example. There are a bunch of things we
could do to this, now that we've located it. You could change the

	cmp	eax, 0FFh	;masm32 likes having a 0 in front of hex numbers between A to F
	jne	prog_registered

I think it's fairly safe to say that eax will not equal FFh (128 in
decimal). In this case, the data being compared to is different, and
the the program will jump to registered. On the other hand, you could
change the logic of the jump. Instead of saying if(ISREG != 0) you
could say if(ISREG == 0).

	cmp	eax, 0h
	je	prog_registered

This can have some slightly weird behavior. In this case, if the
program was originally registered, it will now think it's not
registered. However, if you're stealing this program, you'll get to
use it. Here is a list of some what operators are opposites:

	Orig	Opposite
	je	jne
	jne	je
	jg	jle
	jge	jl
	jl	jge
	jle	jg
	jz	jnz
	jnz	jz

Theres a better way to do it though. You want *everyone* to be able to
use your crack, then why not just change the conditional jump (jne) to
an unconditional one?

	cmp	eax, 0h
	jmp	prog_registered

Woot - it's cracked.

Before I leave this topic, I should note that finding a magic spot
isn't the only way to crack a program. More complicated cracking can
be done - you can say, individually nop out a screen (and it's
parameters! Otherwise you'll mess up the stack and crash the program)
preventing you from using a program, rewrite anything to get new
behavior; many other things. Another thing you could do (not in this
case, but I'll make sure it's possible in some of the other crackmes)
is to overwrite the beginning of the copy protection with a jmp and
have it land at a point directly after the copy protection. Remember
that there are different kinds of jumps depending on how far you want
to go (read opcodes.hlp for the list). There is a major advantage to
using a magic spot however, and that is that the program should work
just as well as had you bought it (copies of all crackmes available

Patching your program

        So you've found exactly what you want to change. You now need
to patch the program. If you look at a program thats disassembled in
windasm, you'll notice that starting on the left, there is a column of
memory addresses, a column of hex, and a column of disassembled code.
The memory addresses have already been explained; it's where the
program wants to be loaded into memory.

While the way that windows loads a program is awfully complex, the
basic idea is that at least parts of it are read from the disk into
memory before it's executed. I keep on talking about what point a
program is at in memory - I'm just talking about the computer going
through this piece of memory and executing the statements. Earlier I
mentioned eip - this register contains the address in memory that the
processor is currently executing at.

Basically what you have to do now is take your modification, and hand
assemble the new instruction and then patch the program with a hex
editor. Fortunetly, this is simple. Assemblers are basically tables of
instructions and what their hex equivalent is. So with the
documention, you can assemble stuff by hand. In this case, we won't be
changing the size of the program (which would require updating some
jmp instructions after the patch), we'll just be overwriting an
        You're going to need something called an opcode table or "bare
hex opcodes to mnemonics" table. There is one in the help section of
masm32. Because you might not want to find this now, I'll give a few
hex opcodes here (recognize this?). I have to explain one more thing
first. These are not the only hex opcodes for these instructions,
they vary depending on the instruction, (sometimes) registers used,
amount of memory being used for arguements to the instruction, and
other factors. All the hex opcodes listed here are for SHORT jumps
(this is what you will see 90% of the time).
	jmp		jump				EB		
	je	==	jump if equal			74
	jne	!=	jump if not equal		75
	jg	>	jump if greater than		7F
	jge	>=	jump if greater than or equal	7D
	jl	<	jump if less than		7C
	jle	<=	jump if less than or equal	7E
	jz	== 0	jump if it's equal to 0		75
	jnz	!= 0	jump if it's not equal to 0	74

	cmp eax, anything				3D
	cmp anyregister, almostanything			81

        nop                                             90
        (recognize this from shellcode?)

The hex opcode given will be followed by the amount to jump (in hex).
You'll note that jz = jne and jnz = je. If you read the unneccessary
information for cmp, you'll see that this is simple due to the way cmp
works. A short jmp will be followed by hex indicating how far to go.
Likewise, a cmp will be followed by the hex of what to compare it to.

        I'm going to demonstrate patching crackme0.exe. In this case
we're going to use the last crack for crackme0, turning a conditional
jump into an unconditional jump. First, disassemble the program in
windasm. You'll notice that while it's really the same, it'll look
somewhat different. Get used to seeing stuff like this. On the
leftmost side there is the memory address, with the hex to the right
of that, and the instructions further right.

    mov	    eax, ISREG
    cmp     eax, 0           ;The comparison - is the program registered?
    jne     prog_registered

now looks like:

:00401000 A148304000              mov eax, dword ptr [00403048]
:00401005 83F800                  cmp eax, 00000000
:00401008 7502                    jne 0040100C

00403048 is the location of ISREG in memory, and 0040100C is the new
location to jump to. Note that the hex for that statement is 7502 - 75
is jne, 02 is how far forward to go (if you count the bytes, start at
the *end* of the instruction).

We want to make jne (75), unconditional (EB). All you have to do is
find the right 75 in the hex editor of your choice, and overwrite it
with EB. Simple, huh? The only catch is in the hex editor you will not
have the same memory addresses. Instead you will have the offset from
the beginning of the file. The easiest thing to do is search for a
long line of hex in the hexeditor. In this case try
A14830400083F8007502. The chances of there being another set of
instructions that long with the same hex is awefully small but
possible. This is how antivirus definitions work, the av looks for an
unchanging piece of code in the program that belongs to malware.
Change the last 75 to the EB.

Ok, you want to be able to calculate where the patch is supposed to
go. In windasm you will see:

Program Entry Point = 00401000 (crackme0.exe File Offset:00001600)

The entry point is where the program is entered NOT the beginning of
the file. The file offset tells you how far the entry point is from
the beginning of the file. Lastly, the hex editor tells you how far
into the file you are. I'm just going to show you the algebra (make
sure your calculator is in hex mode):

a = instruction you want to change
x = offset in the file

x = a - program_entry_point + file_offset_of_program_entry_point

The location of the jne is 401008. Go to x in crackme0.exe (in the hex
Execpt theres a slight problem, it's off... I think that windasm
gives the wrong offset for very small programs.

Memory and stuff

        I feel obligated to explain a little more background
information before going into cracking genuine software that you don't
have the commented source for. When you disassemble a program, the
numbers represent where it's supposed to load in memory. Bizarrely
enough, each program that is compiled has a place in memory where it
usually sits. If this location is taken, it can be moved elsewhere.
Buffer overflows use this a lot - ever notice that your exploit only
works on one particular distribution even though the vulnerablity is
in a particular piece of software? This is because bof (buffer
overflow) frequently need to know where something - the program, a
piece of data or shellcode, or a library - is located. Because each
distribution has different memory locations, you need to find the
correct locations to make the exploit work, and not do something with
the wrong piece of memory.

What part of the program do you want to target?

        Theres almost always more than one way to crack a program. For
example, you could try to crack the part of a program that detects if
it's registered or not. You could also attack the part of the program
that registers the program - and let the register dialog do the hard
part. Those are the best two areas that I know of to attack by
changing magic spots. If, for example, a program restricts features
until you pay for it, you can go around and try to crack that - either
turning on individual features, or find a magic spot where it tries to
detect the copy protection. If it's a time limit, you can do anything
from changing the function that gets the time to always return a time
way in the future, or figure out where it's getting the original time.
        If you learn a bit more of assembly more complex options are
avaliable - you can toy around with adding functions, figuring out
weird pieces of code, modifying parameters of functions, stuff like

Whether you realize it or not, you're hacking a program - the same
mind set applies. While you can go through and do exactly what you
were shown, you can also experement with playing with the program
in strange or unusual ways. The end goal is to get the program to do
what you want, and there are no holds barred in what you're allowed to
try to get it to do that. Try to think of clever, new, or unique ways
of changing the program to alter it's behavior.

Finding the important stuff

        This is the single most important part of cracking using magic
spots. You need to figure out where it is. Strings, Dialogs, unique or
recognisable API calls, and resources (which are not integrated into
windasm, and therefore are harder to track down) are going to be your
way of tracking down the important pieces of code. You can also find
it with a debugger, which will be covered later, along with it's
advantages and disadvantages.
        String references are probibly the easiest way of finding the
parts of code that you want to first look at. Unfortunetly, as time
goes on, you are increasingly unlikely to find a string that leads you
directly to the general area you want to be. Basically, click on a
string in windasm (like "This program has expired") and it'll take you
to the general region you want to be in.
        Dialog boxes - while a dialog will only be listed in windasm
if it's part of the resource table, this is still a useful way of
finding things.
        API calls - There are two ways which these are useful. First,
they kind of comment parts of the code and tell you a little about
whats going on. Also, if there is an api that's probibly being used
for copy protection, you can narrow down the area that you're looking
        Windows resources - Unfortunetly, windasm hasn't been added to
in a long time, and does not have an easy way of telling you when a
windows resource is being referenced. This is still a problem for me;
if anyone has a really good way of figuring out what resources are
being used when in a program, I'd appreciate knowing. When I deal
with something thats using a windows resource, I usually go through
the program with a debugger and keep an eye out for the resource. You
can also figure out where a resource is in memory (inside the
program), by looking at the program's resource table (010 editor is
great for this). You could also spend a lot of time with a hex editor
and the pecoff.doc document - it will tell you where to find this
section of the program. You could then go through and find references
to memory locations that are on the resource table.

Windows APIs sometimes associated with copy protection

        When there is a call to part of the windows API, windasm (and
ollydbg) will tell you what api (basically a microsoft supplied
function) it is. In windasm, use the "imported functions" box to find
a list of api functions used. You should be aware that there exist
ways of loading apis without it being on the program's import table,
but these (with luck) set off antivirus heuristics, and are generally
avoided by vendors.
        Disassembled programs have no programmer comments, but APIs
give good clues as to what a section of code is doing.

MessageBox / MessageBoxA / MessageBoxEx / MessageBoxExA: Everytime you
see a little box pop up like the one in crackme0, it's using a
messagebox. These are frequently used for errors, telling you that
you're license has just expired, and other small bits of information.
Sometimes, if there aren't a whole lot of these, you can go through
and find which messagebox is the one you want.

Anything with the word winsock in it: Winsock is windows sockets -
network stuff. If you don't think you're copy of Ableton Live should
be talking to the internet, then it's probibly passing information to
the company about you.

GetFileSize: Some programs check to make sure that it's size has not
changed (which would indicate that it may have been cracked).

GetLocalTime: You'll see this frequently used to tell when a demo has

GetFileTime: Sometimes programs will figure out if a trial has expired
by reading the creation time of it's self, or another file associated
with the installation.

GetDriveTypeA: Sometimes used as a crude way of making sure that a
program is being run from a cdrom. Even more sophisticated anti
duplication protection will ususally start by checking this.

Reg*: This indicates that the registry is being used at that point.
Sometimes you'll see an associated string or resource telling you what
key is being messed with.

There are way too many to list here, I really just wanted to give the
reader an idea of what to look for.

Using a debugger to find important stuff

        I don't really want to go into how to use a debugger; I
actually didn't start using one until a year ago, but now I can't do
without it. Basically, instead of hunting for clues to take you to an
important spot, you could let the program do it it's self, and tag
along watching. This is one of the many uses of a debugger. The basic
idea is you let the program run until it reaches a point which you
want to find (something visable happens in the program that you know
will be related to copy protection). If you're using OllyDbg, "trace
over" the program, then run it. Tracing traditionally means going
instruction by instruction through a program. As the program executes,
note that you can look at whats happening to registers and stuff. You
can also see a list of calls that were made. When you interrupt the
program at an interesting area, you can use the call stack, and see
what functions led up to that point. Don't be supprised if you see the
program jumping to weird parts of memory, that are outside of the
program. These are generally calls to the windows api.
        You should be aware that you can set a breakpoint in a program
with a debugger - if you'd like to examine the program at a specific
point that you've thought of, set a breakpoint. Then the program will
pause while you examine memory, registers, etc. Combined with a
disassembler, this is awefully useful. Say you're suspicious of a
function that is called right after you press "OK" on a registration
box. In ollydbg press F2, and start stepping through the function. As
you do so, it will show you exactly what is happening with the
program. Try doing this to crackme1b, and watch it do something like
process the key and check it. See if you can find the bizarre bug
using div that the author is completely mistified by.
        I'd also like to note that it's an aweful lot easier to
program in assembly if you have a debugger there for when things
misteriously don't work the way you think they should.
        A debugger is an extremely powerful tool, and makes going
through a complex or simply large program a lot more efficient. It's
also targeted by vendors, who will do anything to fuck it up.

Analysing parameters to calls

        A really dense, hard to read book that contains a lot of
excelent information is "Reversing Secret of Reverse Engineering" by
Eldad Eilam . I never managed to finish it, but the parts I read
taught me a lot. If you don't know assembly, you will get little out
of it.
        Something that the author goes into in length at the beginning
of the book is how to figure out what the parameters are of a function
by looking at paramaters that are used right before a function call. I
don't want to go into anywhere near the detail that Eldad Eilam did,
but you should look at this example:

;calling a function
mov	eax, word ptr[some_mem_location]
push	eax		;parameter 1
push	offset blah	;parameter 2
push	offset blah2	;parameter 3
push	0		;parameter 4
call	some_function.

While I didn't go into it, push and pop are instructions for adding
and removing data from the stack, a piece of memory where you shove
crap you don't want to deal with at that second. When you see a bunch
of pushes before a call, those are parameters that are being passed to
the function. If you go into the function it's self, you will
generally not see a corresponding set of pops. Generally the function
will refer to these by their offset from ebp, the register that holds
the base pointer of the stack (memory location of the stack's bottom
in memory). The stack's location will be fixed back to the way it was
originally when you ret (return) from the function.
        You'll notice one other screwy thing, and thats when the
parameters are used *in the function*, the first parameter appears to
be skipped in memory. That is because when you call the function, call
puts one more thing on the stack - the return address. The ret
instruction uses this to get back to where it was, after the call. See
crackme1.asm for an example. A parameter being used will look like

        mov eax, dword ptr [ebp + 8] ;copy parameter 1 to eax

Parameters will all be ebp + a multiple of 4. Local variables are
frequently made by subtracting from ebp. Remember that ebp is just a
pointer, and that [ebp + 8] is actually accessing the memory
location pointed to by ebp (plus 8).

Tricks the software vendors will use against you

        I don't know all the tricks by a long shot. You'll start to
see them as you go through programs. I highly recomend perminantly
saving any anticracking technique you see - this list will be
invaluble. I don't want to give away too many - you should be finding
these your self.

- Having misleading strings leading to pieces of code. A great example
is the old diabo II game. If you disassemble the main program you'll
see around 6 strings (don't really remember how many) with similar
messages, complaining about the cd not being legit.
- Garbling strings. Look at the recent norton antivirus (standalone)
updates. You'll see gibberish in the string table. If you whats
happening you'll see a string reference, followed by the code to
decode it :). Note that there's another trick used there, which is
commonly used to screw up debuggers, disassemblers, and pretty much
any kind of code analysis.
- Jumping to the middle of an instruction. Sometimes a section of a
program will have an instruction, and the instruction will be garbage
or something (a really good coder could make both do something useful,
but I've never seen this). The jump instruction will place you in an
arguement to the instruction, which the computer will happily
interprite as machine code, rather than an argument to an instruction.
- Weird placement of int. Int stands for interrupt, I won't go into
what it's used for (complex), but you'll see it used for setting
hardware breakpoints. If a debugger somehow runs into one of these it
will stop...
- Spurious exceptions. You'll find a lot of programs unneccessarily
making exceptions and then handling them. An exception is a way of
checking if an error has occured. I can never tell if this is the
result of bad programming, or something deliberately made to annoy me.
Fortunetly you can tell OllyDbg to ignore the exception of your
- Weird instructions. Example:
	test	esi,esi
	jl 	somewhere
I finally wrote a short program to figure out how this one worked.
Basically it's a way of saying jmp. I'd imagine that programs that
analyse program structure and branches would get messed up by this.
- Weird use of threads. A thread is a way of breaking the execution of
a program into several simultanious pieces of running program (think
fork()). Sometimes you'll see threads split off to confuse whoever's
debugging the program.

Getting practice

        Theres no simple way of telling how good the copy protection
is in a program, other than trying it. Really expensive pieces of
software are not a good place to start. Find some shareware programs
(without spyware) and try to crack them. Also, look for "crackme"
online. A lot of people write copy protection programs as tests or
practice. Watch out for occasional malicious code with these. The
first program I cracked was the original norton standalone virus
updates. If you can find one, it's an excelent place to start.
Screensavers are really just programs, and sometimes have simple copy
protection which isn't too hard to crack.

Other programs that will help you a lot

Filemon and Regmon - Sysinternals has a million useful programs. Find
them at www.sysinternals.com. Of particular interest to crackers are
RegMon and FileMon. Filemon will tell you every file that is being
used. Use this to find if the programs trying to find a keyfile or
something. Regmon will tell you everything thats trying to use the
registy, great for tracking down hard to find registry keys. Play
around, they're self explainitory.

Resedit/Reshack - This stands for resource editor, and allows you to
view and modify anything in the program's resource table. The name is
actually kind of a joke, and is named after an old mac program, with
somewhat similar capablities.


Opcodes.hlp by Intel - You'll find this in the help files for masm32.
It is invaluble to a cracker, and contains the most common
instructions, how they work, and their hex equivalents. This is a must

Assembly Language - Programming for the IBM PC family by William B
Jones - I really wish this book wasn't 16 bit and intended for DOS. It
also uses macros for a few common things (_Begin for example). Other
than that, it's an excelent book on programming in assembly.

Intel(R) Architecture Software Developer's Manuals (1-3) - I don't
really recomend trying to read this, but it is almost complete
documentation for every damn thing a x86 processor can do.

Reversing Secrets of Reverse Engineering by Eldad Eilam - This book
contains a lot of really really good information. Unfortunetly, it's
also extremely difficult to read. If you attempt to read it, have
a) whatever book you learned assembly from sitting next to you b) a
lot of time to go through examples c) headache medication and d) a
very long attention span.

Hacker Disassembling Uncovered by Kris Kaspersky - This is much easier
to read than Reversing Secrets of Reverse Engineering. I haven't
finished it yet, but so far it's pretty good.

PECOFF.DOC by Microsoft Corporation - This is the "Microsoft Portable
Executable and Common Object File Format Specification" In case you
weren't aware, a windows program is in the PE executable format.
This great little document tells you the format for a windows program,
and allows you to decode and figure out certain things about the
program. It's also fun when playing with a hex editor.

Linux magic file - You can find this on any *nix machine. This useful
file tells you how to figure out what type of file something is by
looking at what it begins with. This is useful when dealing with
anything that has a different type of file embedded in it - for
example installers, self extracting files, etc.

Other people's cracks - This is sort of like looking at the answers
to a question. Find a program, use the crack, and use a binary diff
utility to find out what changed. Disassemble, and then figure out how
the program was modified.


http://www.woodmann.com/fravia/index.htm - While the original site is
gone, this is a mirror. It has many tutorials, guides, pretty much
everything. Also has stuff about writing spiders.

http://www.crackstore.com/ - Has lots of tutorials. To download a
tutorial, use the path given by the error message and append it to
www.crackstore.com. When they changed to a non vhost, they didn't fix
all the links.

http://uninformed.org/ - I'm not sure if these guys want to be linked
to, but it's a really good zine about hacking, exploitation, reverse
engineering, and so forth. It basically fills the void left by phrack.

http://win32assembly.online.fr/tutorials.html - Check out _Masta_'s
assembly tutorials. Iczelion's are kinda high level assembly (as in
the language, not the difficulty), and while contain good information,
should be initially avoided.

; Crackme0.asm by Anon                 
; Modify this program to be registered.

.model flat, stdcall

option casemap:none		;don't worry about this crap

include c:\masm32\include\windows.inc	;masm32 includes for windows api calls and stuff
include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib

.STACK 256h
      ;This is the string table, pretty much. You can find it by going through a program
      ;With a hex editor - you'll find it near the end with all the strings used in the
	DLGCAP    db	"Crackme0",0
	REG        db	"This program is registered",0
	UNREG      db	"Damn - the program isn't registered",0
      ISREG      dd     0 ;This is a global variable that tells us that the program isn't registered


;Main function - this can actually be called anything, but it's the same as main()
Main PROC 
; This is the part of the program you need to be paying attention to

    mov     eax, ISREG
    cmp     eax, 0           ;The comparison - is the program registered?
    jne     prog_registered     ;if(isreg != 0) goto prog_registered
    jmp     prog_unregistered   ;otherwise it's unregistered

    ;Right here were are loading all the parameters for the dialog box, then calling it, then going to the end
    push    MB_OK   ;MB_OK is a value from one of the windows includes
    push    offset DLGCAP   ;These are loading the strings
    push    offset REG
    push    0               ;this is required by the MessageBox function
    call    MessageBoxA
    jmp     theend

    push    MB_OK
    push    offset DLGCAP
    push    offset UNREG
    push    0
    call    MessageBoxA
    jmp     theend

    push    0           ;end this program
    call    ExitProcess

End Main

; Crackme1.asm by Anon, Simple Nag Screen
; Modify this program to be registered.
; This is an example of several things:
; -It has a nag screen which can be removed
; -It has a built in, incorrect key. You can
; crack the main program to accept the key,
; crack the function that checks the key (a
; little different) or crack the main function, 
; so that it thinks a correct key has been
; given.
; -A keygen can be made for this program
; A correct key:

.model flat, stdcall

option casemap:none		;don't worry about this crap

include c:\masm32\include\windows.inc	;masm32 includes for windows api calls and stuff
include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib

.STACK 1024h
    DLGCAP      db	"Crackme1",0
    RUN         db	"You are now past the nag screen",0
    UNREG       db	"Buy our damn software!",0
;    WRONGKEY    dd      1, 2, 3, 4, 5, 6, 7, 8      ;You'd usually see the key loaded from a file, registry key, or resource   
    WRONGKEY    dd      7FDCh, 7FDCh, 7FDCh, 7FDCh, 7FDCh, 7FDCh, 7FDCh, 7FDCh
    KEYSIZE     EQU     8

    mov     eax, offset WRONGKEY
    push    eax
    call    ChkRegistered   ;returns in ebx
    cmp     ebx, 1
    je      mainprog
    push    MB_OK
    push    offset DLGCAP
    push    offset UNREG
    push    0
    call    MessageBoxA

    push    MB_OK
    push    offset DLGCAP
    push    offset RUN
    push    0
    call    MessageBoxA

    push    0           ;end this program
    call    ExitProcess

ChkRegistered PROC
; params: ChkRegistered(int *key)
; returns whether its registered in ebx
; clobbers eax, ebx, ecx, and edx (damn you mul!)
; this is a very simple key check, see if you can
; write a keygen!
key          equ     [ebp + 8]  ;read the end of "Analysing parameters to calls"
;kend        equ     [ebp + 12]    ;this is now unneccessary, the keysize is fixed by KEYSIZE

    push    ebp
    mov     ebp, esp

    mov     ecx, 0      ;loop counter is ecx
    cmp     ecx, KEYSIZE
    jge     endchkregloop

    push    ecx         ;this section comes up with the location of the current element
    mov     edx, 0      ;ecx * 4 + offset key
    mov     eax, ecx
    push    ecx
    mov     ecx, 4
    mul     ecx
    pop     ecx 
    mov     ecx, eax
    add     ecx, key

    mov     eax, [ecx]         ;ecx should contain the memory location of the current element
    shl     eax, 1             ;super secret reverse keygen algorythm!
    xor     eax, 0FFFFh        ;check the size on the second arguement

    mov     edx, 0    ;when using div or idiv, quotient is in eax, remainder in edx
    mov     ecx, 7    ;eax is already set
    idiv    ecx       ;divide by 7 - end of super secret reverse keygen algorythm
    cmp     edx, 0    ;remember, edx is the remainder. I'm basically doing % 7
    jne     notreg
    pop     ecx         ;restore ecx to the counter
    inc     ecx
    jmp     chkregloop

    mov     ebx, 1
    mov     esp, ebp
    pop     ebp
    ret     4

    mov     ebx, 0
    mov     esp, ebp
    pop     ebp
    ret     4
ChkRegistered ENDP

End Main

# milw0rm.com [2006-12-29]

Похожие темы