Basic Assembly Tutorial
Ok whats opcodes? An opcode is an instruction
the processor can understand. For example
SUB and ADD and DIV
The sub instructions subtracts two numbers together.
Most opcodes have operands
SUB destination,source like the following
SUB eax, ecx
SUB has 2 operands. In the case of a subtraction,
a source and a destination. It subtracts the source
value to the destination value and then stores
the result in the destination. Operands can be
of different types: registers, memory locations,
So basically that instruction is this, say for
example eax contained 20 and ecx contained 10
eax = eax - ecx
eax = 20 - 10
eax = 10
Easy that bit huh
Ahhh here is the main force of asm, Registers
contain values and information which is used in
a program to keep track of things, and when new
to ASM it does look messy but the system is practically
efficient. It is honestly
Lets take a look at the main Register used, its
eax. Say it contains the value FFEEDDCCh (the
h means hexidecimal) when working later with softice
u will see hex values alot so get used to it now
Ok Ill show how the registers are constructed
ax, ah, al are part of eax. EAX is a 32-bit register
(available only on 386+), ax contains the lower
16 bits (2 bytes)
of eax, ah contains the high byte of ax, and al
contains the low byte of ax. So ax is 16 bit,
al and ah are 8 bit.
So, in the example above, these are the values
of the registers:
eax = FFEEDDCC (32-bit)
ax = DDCC (16-bit)
ah = DD (8-bit)
al = CC (8-bit)
Understand? I know its alot to take in, but thats
how registers work Heres some more examples of
opcodes and the registers used...
|mov eax, 002130DF
||mov loads a value into a register
|mov cl, ah
||move the high byte of ax (30h) into cl
|sub cl, 10
||substract 10 (dec.) from the value in cl
|mov al, cl
||and store it in the lowest byte of eax
So at start..
eax = 002130DF
eax = 00213026
Did you follow what happened? I hope so, cause
im trying to make this as easy as I can
Ok lets discuss the types of registers, there
is 4 types used mainly (there is others but will
tell about them later)
General Purpose Registers
These 32-bit (and their 16bit and 8bit sub registers)
registers can be used for anything, but their
main purpose is shown after them.
As said these are hardly used nowadays for their
main purpose and is used to ferry arround information
within programs and games (such as scores, health
Segment registers define the segment of memory
that is used. You'll probably won't need them
with win32asm, because windows has a flat memory
system. In dos, memory is divided into segments
of 64kb, so if you want to define a memory address,
you specify a segment, and an offset (like 0172:0500
(segment:offset)). In windows, segments have sizes
of 4gig, so you won't need segments in win. Segments
are always 16-bit registers.
CS code segment
DS data segment
SS stack segment
ES extra segment
FS (only 286+) general purpose segment
GS (only 386+) general purpose segment
Actually, you can use pointer registers as general
purpose registers (except for eip), as long as
you preserve their original values. Pointer registers
are called pointer registers because their often
used for storing memory addresses. Some opcodes
(and also movb,scasb,etc.) use them.
esi (si) Source index
edi (di) Destination index
eip (ip) Instruction pointer
EIP (or IP in 16-bit programs) contains a pointer
to the instruction the processor is about to execute.
So you can't use eip as general purpose registers.
There are 2 stack registers: esp & ebp. ESP
holds the current stack position in memory (more
about this in one of the next tutorials). EBP
is used in functions as pointer to the local variables.
esp (sp) Stack pointer
ebp (bp) Base pointer
How is the memory used within ASM and the layout
of it? Well hopefully this will answer some questions.
Bear in mind there is more advanced things than
what is explained here, but hell you lot arent
advanced, so start from the basics
Lets look at the different types..
In 16-bit programs like for DOS (and Win 3.1),
memory was divided in segments. These segments
have sizes of 64kb. To access memory, a segment
pointer and an offset pointer are needed. The
segment pointer indicates which segment (section
of 64kb) to use, the offset pointer indicates
the place in the segment itself.
Take a look at this
| SEGMENT 1 (64kb) | SEGMENT 2 (64kb) | SEGMENT
3 (64kb) | etc........... |
Hope that shows well
Note that the following explanation is for 16-bit
programs, more on 32-bit later (but don't skip
this part, it is important to understand 32-bits).
The table above is the total memory, divided
in segments of 64kb. There's a maximum of 65536
segments. Now take one of the segments:
| Offset 1 | Offset 2 | Offset 3 | Offset 4 |
Offset 5 | etc....... |
To point to a location in a segment, offsets are
used. An offset is a location inside the segment.
There's a maximum of 65536 offsets per segment.
The notation of an address in memory is:
0145:42A2 (all hex numbers remember )
This means: segment 145, offset 42A2. To see
what is at that address, you first go to segment
145, and then to offset 42A2 in that segment.
Hopefully you remembered to read about those
Segment Registers a while ago on this thread.
CS - Code segment
DS - Data Segment
SS - Stack Segment
ES - Extra Segment
FS - General Purpose
GS - General Purpose <<< Them remember
The names explain their function: code segment
(CS) contains the number of the section where
the current code that is being executed is. Data
segment for the current segment to get data from.
Stack indicates the stack segment (more on the
stacks later), ES, FS, GS are general purpose
registers and can be used for any segment (not
in win32 though).
Pointer registers most of the time hold an offset,
but general purpose registers (ax, bx, cx, dx
etc.) can also be used for this. IP (Pointer register)
indicates the offset (in the CS (code segment))
of the instruction that is currently executed.
SP (Stack register) holds the offset (in the SS
(stack segment)) of the current stack position.
Phew and you thought 16bit memory was hard huh
Sorry if thats all confusing, but its the easiest
way to explain it. Reread it a few times it will
eventually sink into your brain on how memory
works and how it is accessed to be read and written
Now we move to
You have probably noticed that all this about
segments really isn't fun. In 16-bit programming,
segments are essential. Fortunately, this problem
is solved in 32-bit Windows (9x and NT).
You still have segments, but don't care about
them because they aren't 64kb, but 4 GIG. Windows
will probably even crash if you try to change
one of the segment registers.
This is called the flat memory model. There are
only offsets, and they now are 32-bit, so in a
range from 0 to 4,294,967,295. Every location
in memory is indicated only by an offset.
This is really one of the best advantages of
32-bit over 16-bit. So you can forget the segment
registers now and focus on the other registers.
Oh the madness of it all, wow 4 gig bits to work
The Fun Part begins!!!
Here is a list of a few opcodes you will notice
alot of when making trainers or cracking etc.
This instruction is used to move (or actually
copy) a value from one place to another. This
'place' can be a register, a memory location or
an immediate value (only as source value of course).
The syntax of the mov instruction is:
mov destination, source
You can move a value from one register to another
(note that the instruction copies the value, in
spite of its name 'move', to the destination).
mov edx, ecx
The instruction above copies the contents of
ecx to edx. The size of source and destination
should be the same, this instruction for example
is NOT valid:
mov al, ecx ; NOT VALID
This opcode tries to put a DWORD (32-bit) value
into a byte (8-bit). This can't be done by the
mov instruction (there are other instructions
to do this). But these instructions are allowed
because source and destination don't differ in
size, like for example...
mov al, bl
mov cl, dl
mov cx, dx
mov ecx, ebx
Memory locations are indicated with an offset
(in win32, for more info see the previous page).
You can also get a value from a certain memory
location and put it in a register. Take the following
table as example:
||34 35 36 37 38 39 3A 3B 3C 3D
3E 3F 40 41 42
||0D 0A 50 32 44 57 25 7A 5E 72 EF 7D FF AD
(each block represents a byte)
The offset value is indicated as a byte here,
but it is a 32-bit value. Take for example 3A
(which isn't a common value for an offset, but
otherwise the table won't fit...), this also is
a 32-bit value: 0000003Ah. Just to save space,
some unusual and low offsets are used. All values
Look at offset 3A in the table above. The data
at that offset is 25, 7A, 5E, 72, EF, etc. To
put the value at offset 3A in, for example, a
register you use the mov instruction, too:
mov eax, dword ptr [0000003Ah] ... but.......
You will see this more commonly in programs as
mov eax, dword ptr [ecx+45h]
This means ecx+45 will point to the memory location
to take the 32 bit data from, we know its 32bit
because of the dword in the instruction. To take
say 16bit of data we use WORD PTR or 8bit BYTE
PTR, like the following examples..
mov cl, byte ptr [34h] cl will get the value
0Dh (see table above) mov dx, word ptr [3Eh] dx
will get the value 7DEFh (see table above, remember
that the bytes are reversed)
The size sometimes isn't necessary:
mov eax, [00403045h]
because eax is a 32-bit register, the assembler
assumes (and this is the only way to do it, too)
it should take a 32-bit value from memory location
Immediate numbers are also allowed:
mov edx, 5006
This will just make the register edx contain
the value 5006. The brackets, [ and ], are used
to get a value from the memory location between
the brackets, without brackets it is just a value.
A register as memory location is allowed to (it
should be a 32-bit register in 32-bit programs):
mov eax, 403045h ; make eax have the value 403045
mov cx, [eax] ; put the word size value at the
memory location EAX (403045) into register CX.
In mov cx, [eax], the processor first looks what
value (=memory location) eax holds, then what
value is at that location in memory, and put this
word (16 bits because the destination, cx, is
a 16-bit register) into CX.
2. ADD,SUB,MUL and DIV
These are easy to understand Good old maths,
im sure everyone can add and subtract and multiply
Anyways on with the info
The add-opcode has the following syntax:
add destination, source
The calculation performed is destination = destination
+ source. The following forms are allowed:
||add ecx, edx
||add ecx, dword ptr [104h] / add ecx, [edx]
||add eax, 102
||add dword ptr [401231h], 80
||add dword ptr [401231h], edx
This instruction is very simple. It just takes
the source value, adds the destination value to
it and then puts the result in the destination.
Other mathematical instructions are:
SUB destination, source (destination = destination
MUL destination, source (destination = destiantion
DIV source (eax = eax / source, edx = remainer)
Its easy peasy aint it...Or is it
Substraction works the same as add, multiplication
is just dest = dest * source. Division is a little
different Because registers are integer values
(i.e. round numbers, not floating point numbers)
, the result of a division is split in a quotient
and a remainder. For example:
28 / 6 --> quotient = 4, remainder = 4
30 / 9 --> quotient = 3, remainder = 3
97 / 10 --> quotient = 9, remainder = 7
18 / 6 --> quotient = 3, remainder = 0
Now, depending on the size of the source, the
quotient is stored in (a part of) eax, the remainder
in (a part of) edx:
||Quotient stored in
||Remainder Stored in...
||ax / source
||dx:ax* / source
||edx:eax* / source
* = For example: if dx = 2030h, and ax = 0040h,
dx: ax = 20300040h. dx:ax is a dword value where
dx represents the higher word and ax the lower.
Edx:eax is a quadword value (64-bits) where the
higher dword is edx and the lower eax.
The source of the div-opcode can be:
an 8-bit register (al, ah, cl,...)
a 16-bit register (ax, dx, ...)
a 32-bit register (eax, edx, ecx...)
an 8-bit memory value (byte ptr [xxxx])
a 16-bit memory value (word ptr [xxxx])
a 32-bit memory value (dword ptr [xxxx])
The source can not be an immediate value because
then the processor cannot determine the size of
the source operand.
3. BITWISE OPS
These instructions all take a destination and
a source, exept the 'NOT' instruction. Each bit
in the destination is compared to the same bit
in the source, and depending on the instruction,
a 0 or a 1 is placed in the destination bit:
||0 0 1 1
||0 0 1 1
||0 0 1 1
||0 1 0 1
||0 1 0 1
||0 1 0 1
||0 0 0 1
||0 1 1 1
||0 1 1 0
AND sets the output bit to 1 if both the source
and destination bit is 1.
OR sets the output bit if either the source or
destination bit is 1
XOR sets the output bit if the source bit is different
from the destination bit.
NOT inverts the source bit.
mov ax, 3406
mov dx, 13EAh
xor ax, dx
ax = 3406 (decimal), which is 0000110101001110
dx = 13EA (hex), which is 0001001111101010 in
Perform the XOR operation on these bits:
Destination 0000110101001110 (ax)
The new dx is 0001111010100100 (7845 decimal,
1EA5 in hex) after the instruction.
mov ecx, FFFF0000h
FFFF0000 is in binary 11111111111111110000000000000000
(16 1's, 16 0's)
If you take the inverse of every bit, you get:
00000000000000001111111111111111 (16 0's, 16 1's),
which is 0000FFFF in hex.
So ecx is after the NOT operation 0000FFFFh.
The last one is handy for serial generating,
as is XOR. Infact XOR is used more for serials
than any other instruction, widely used for serial
checking in Winzip, Winrar, EA Games, Vivendi
I WONT TELL YOU HOW TO MAKE KEYGENS SO DONT ASK
There are 2 very simple instructions, DEC and
INC. These instructions increase or decrease a
memory location or register with one. Simply put:
inc reg -> reg = reg + 1
dec reg -> reg = reg - 1
inc dword ptr  -> value at 
will increase by one.
dec dword ptr  -> value at 
will decrease by one.
Ahh easy one to understand So is the next one
This instruction does absolutely nothing. This
instruction just occupies space and time. It is
used for filling purposes and patching codes.
6. BIT rotation and shifting
Note: Most of the examples below use 8-bit numbers,
but this is just to make the picture clear.
SHL destination, count
SHR destination, count
SHL and SHR shift a count number of bits in a
register/memlocation left or right.
; al = 01011011 (binary) here
shr al, 3
This means: shift all the bits of the al register
3 places to the right. So al will become 00001011.
The bits on the left are filled up with zeroes
and the bits on the right are shifted out. The
last bit that is shifted out is saved in the carry-flag.
The carry-bit is a bit in the processor's Flags
register. This is not a register like eax or ecx
that you can directly access (although there are
opcodes to do this), but it's contents depend
on the result of the instruction. This will be
explained later, the only thing you'll have to
remember now is that the carry is a bit in the
flag register and that it can be on or off. This
bit equals the last bit shifted out.
shl is the same as shr, but shifts to the left.
; bl = 11100101 (binary) here
shl bl, 2
bl is 10010100 (binary) after the instruction.
The last two bits are filled up with zeroes, the
carry bit is 1, because the bit that was last
shifted out is a 1.
Then there are two other opcodes:
SAL destination, count (Shift Arithmetic Left)
SAR destination, count (Shift Arithmetic Right)
SAL is the same as SHL, but SAR is not quite
the same as SHR. SAR does not shift in zeroes
but copies the MSB (most significant bit - The
first bit if 1 it moves 1 in from the left, if
0 then 0's will be placed from left). Example:
al = 10100110
sar al, 3
al = 11110100
sar al, 2
al = 11111101
bl = 00100110
sar bl, 3
bl = 00000100
This one you may have problems to get to grips
rol destination, count ; rotate left
ror destination, count ; rotate right
rcl destination, count ; rotate through carry
rcr destination, count ; rotate through carry
Rotation looks like shifting, with the difference
that the bits that are shifted out are shifted
in again on the other side:
Example: ror (rotate right)
|Rotate count 3
As you can see in the figure above, the bits are
rotated, i.e. every bit that is pushed out is
shift in again on the other side. Like shifting,
the carry bit holds the last bit that's shifted
out. RCL and RCR are actually the same as ROL
and ROR. Their names suggest that they use the
carry bit to indicate the last shift-out bit,
which is true, but as ROL and ROR do the same,
they do not differ from them.
Quite Straightforward this, I wont go into major
details, it just swaps the values of two registers
about (values, addresses). Like example..
eax = 237h
ecx = 978h
xchg eax, ecx
eax = 978h
ecx = 237h
Anyways end of day 1, if you learn this into
your head the following days will get easier than
harder. This is the basics ive taught you. Learn
Ok whats a Float all about, well its simple,
a float uses REAL values, what is a REAL value?
A REAL value is a number which is not an integer,
i.e. it contains numbers after a decimal point,
like for example a float opcode can work out 5
divided by 4 and give the answer 1.25, also a
REAL value can contain NEGATIVE numbers also like
An integer with the same math problem will report
1 as the quotient with a remainder of 1. So you
can see Floats are very usefull indeed :)
Why are we talking about floats? Some games
and indeed applications will use float values
to either work out monetary values or even in
a game like percentage values and so forth.
Both my latest trainers for Act of War and Settlers
5 (Die Siedler 5) use float values.
Here is a list of opcodes and what they do :)
FLD [source] Pushes a Float Number from
the source onto the top of the FPU Stack.
FST [destination] Copies a Float Number
from the top of the FPU Stack into the destination.
FSTP [destination] Pops a Float Number
from the top of the FPU Stack into the destination.
FLDZ Pushes +0.0 on top of FPU Stack
FLD1 Pushes +1.0 on top of FPU Stack
FLDPI Pushes PI on the top of FPU Stack
FILD [source] Pushes an integer from the
source to the top of the FPU Stack.
FIST [destination] Copies an integer from
the top of the FPU Stack to the destination.
FISTP [destination] Pops an integer from
the top of FPU Stack into the destination.
FCHS Compliments the sign-bit of a float
value located on the top of the FPU Stack or ST(0)
FNOP Performs no FPU Operation.[It's a
2 byte instruction unlike that of NOP which is
a 1 byte instruction.]
FABS Replaces the float value on the top
of the stack with it's absolute value.
FADD [operand] Adds the value of the operand
with the value located on the top of the FPU Stack
and store the result on the top of the FPU Stack.
FCOS/FSIN Replaces the value on the top
of the FPU Stack with it's cosine/sine value.
FDIV [operand] Divide the value on the
top of the FPU Stack with the operand and store
the result on the top of FPU Stack.
FMUL [operand] Multiply the value on the
top of the FPU Stack with the operand and store
the result on top of FPU Stack.
FSUB [operand] Subtract operand value
from the value on top of FPU Stack and store the
result on top of FPU Stack.
FXCHST (index) Exchanges values between
top of FPU Stack and the ST(index) register.
FCOM Compares the float value located
on top if FPU Stack with the operand located in
memory or the FPU Stack.
FCOMP Same as FCOM but pops the float
value from the top of the FPU Stack.
FNSTSW AX Store FPU Status Word in AX.
(Used for Conditions)
Hope thats explanatory enough :)
Before I show an example or two, lets talk about
Stacks. What are they?
Well a stack is used for a temporary location
for values, a game or application may want to
use a register for something else but want to
keep the previous value for
future reference, so the program will PUSH a value
onto the stack for later retrieval.
The stack is 8 small stacks in the 1, so look
at it as a small filing cabinet in a way. Any
of these values can be retrieved by calling for
the stack and its position, like the following
st(0) - always the top of the stack
st(1) - next after top
st(2) - 2nd from the top
st(7) - Bottom of the stack
So when you want to get a value you can if you
know where it is stored, it does become a little
complicated if you keep PUSH'ing values to the
top of the stack as
the previous value is moved down 1. So to take
a value we just POP it back.
PUSH - Places a value on a stack
POP - Removes a value from the stack
But those opcodes are handy for integer values,
what about floats?
The next section will show you.
OK how to PUSH and POP values from the stack,
its not difficult, heres a few examples :)
Say we have a value in a known address which
is a REAL value (so float) and want to add a value
to it? For arguments sake lets say the register
EAX contains the
address 450000h which contains money in a game
and we want to add a value from revenue which
resides in an address contained in register EBX
at 450008h and
then send back to the original address?
Here is how
FLD [eax] - This opcode PUSH's the value
at the address 450000h contained in EAX and pushes
it to the top of the stack
FADD [ebx] - This then adds the value
at the address 450008h contained in EBX with the
value at the top of the stack, then replaces the
value at the top of the stack with the new value
from the FADD opcode.
FSTP [eax] - This then POP's the value
on top of the stack to the address 450000h contained
in the register EAX, where your old money value
was and replaces with new one.
Say now we want to calculate a Health Points
value after taking damage, but wait! The damage
is a float value but health is integer :o So how
does this work out??
Its not difficult ill show you how :) Again we
will use the last registers for this example,
EAX (450000h) contains our Health integer value
and and EBX (450008h)
contains our damage float value.
Here it is
FILD (EAX) - This opcode PUSH's an integer
value to the top of the stack from the address
450000h contained in EAX.
FSUB (EBX) - This subtracts the value
at address 450008h (float) contained in EBX from
the value at the top of the stack.
FISTP (EAX) - This opcode POP's an integer
value from the the top of the stack to the address
450000h contained in EAX. If the REAL value was
higher it will send as an integer of 2, if 1.49
or lower then it will send as 1.
Great huh :) See its not that difficult to understand
This one is a toughy, we have a game but one
of the addresses in the EAX register is needed
for later on, but we also need the EAX register
to work out a new ammo value,
and no other register is free to send the address
to, omg what to do what to do!!
Dont worry, believe in the stacks :) The following
will contain POP and PUSH command :)
So for this example, EAX contains the value 800000h,
the ammo value is contained at the address 450000h
and the EBX contains the address 450008h which
contains the either positive or negative number
to be added to the ammo amount, if negative a
shot was fired, if positive then a reload of the
weapon or ammo picked up.
PUSH EAX - This opcode PUSH's the value
of EAX (notice without the [ ] it moves the value
in EAX to the stack but if it had the [ ] it would
the value contained at the address of the value
in EAX). In this case 800000h is PUSH'd on top
of the stack.
MOV EAX, 450000h - This opcode moves the
value 450000h into the register EAX, which replaces
the old 800000h value.
FILD [EAX] - This opcode as you know will
PUSH the value at the address contained in the
register EAX, see the difference its using the
[ ] so the
game will look at the address 450000h and take
the value there, and the PUSH to the top of the
FADD [EBX] - This again is self explanatory
now, it adds the value at address 450008h with
the value on the stack, if it was a negative number
will decrease the value, if positive increase
it, just basic maths :)
FISTP [EAX] - Again this POP's an integer
value from top of stack to the memory location
contained in EAX, which is 450000h.
CALL 46AEFF - What the hell is this???
I hear you say, wait a bit ill tell you just after
POP EAX - This opcode POP's the original
800000h back into the register EAX, so
the game hasnt lost that value.
OK, the CALL opcode, its a handy opcode for
the fact that if your program or game uses a routine
to work out something but is always used it would
be messy code if we were to keep manually typing
it out not to mention a much bigger file.
The CALL opcode, calls the opcodes at a certain
address to work out the same function it does
later on, so you only need to have that 1 set
of opcodes for the entire program or game, you
just CALL it, saves time and space.
At the end of these opcodes from a CALL will
be an opcode call RET (return) it will make the
program or game go back to where it left off,
in this case to the POP EAX opcode.
Thats end of day 2 :)
Hope you understood and it helped you see how
Any questions just post and ill answer when
Next time I will talk about different Jumps
and Compares :)
After that Ill show you how to code inject to
make a trainer :D But as I said learn these well
and you will understand what im talking about
when code injecting ;)
CONDITIONALS AND JUMPS
Ok this will be the last one for a while to
show you, as they get more and more advanced.
Learning the 3 days very well, should well be
enough to do easy and simple trainers and how
to find the values.
First I want to talk about Flags, what the hell
Well its not that difficult to understand.
The flag register has a set of flags which are
set/unset depending on calculations or other events.
Here is the more important ones.
ZF (Zero flag)
This flag is set when the result of a calculation
is zero (compare is actually a substraction without
saving the results, but setting the flags only).
SF (Sign flag)
If set, the resulting number of a calculation
CF (Carry flag)
The carry flag contains the left-most bit after
OF (Overflow flag)
Indicates an overflow of a calculation, i.e. the
result does not fit in the destination.
There is other flags some which you will never
use so I wont talk about them.
Heres a list of the Opcodes for Jumps
||Jump if above
||CF=0 & ZF=0
||Jump if above or equal
||Jump if below
||Jump if below or equal
||CF=1 or ZF=1
||Jump if carry
||Jump if CX=0
||(is the same as JZ) Jump if equal
||Jump if greater (signed)
||ZF=0 & SF=OF
||Jump if greater or equal (signed)
||Jump if less (signed)
||Jump if less or equal (signed)
||ZF=1 or SF!=OF
||Jump if not above
||CF=1 or ZF=1
||Jump if not above or equal
||Jump if not below
||Jump if not below or equal
||CF=1 & ZF=0
||Jump if not carry
||Jump if not equal
||Jump if not greater (signed)
||ZF=1 or SF!=OF
||Jump if not greater or equal (signed)
||Jump if not less (signed)
||Jump if not less or equal (signed)
||ZF=0 & SF=OF
||Jump if not overflow (signed)
||Jump if no parity
||Jump if not signed (signed)
||Jump if not zero
||Jump if overflow (signed)
||Jump if parity
||Jump if parity even
||Jump if parity odd
||Jump if signed (signed)
||Jump if zero
As you can see, jumps have conditions set to them
from a previous calculation, test or compare.
Look at this example
This little example basically tests two values
to see if they are equal, if so the program will
move the value 1 into the Zero Flag (ZF), thus
allowing the conditional jump (JE) to goto a memory
location to execute opcodes there.
Now if it wasnt equal, the program will move
0 into ZF, and will skip the JE instruction, then
move the value in the EBX register to the EAX
register, forcing to be equal then doing an unconditional
jump (JMP) to the same memory location.
Games can use this, some games have a real address
for values and a (what I like to call) ghost address,
the ghost address is where the value to be shown
on the game is used, but if a check like above
exists, no matter what you force into that address
will revert back to the real one.
Im sure anyone trying to scan memory addresses
for a game may have came up against this at one
Other opcode that can be used is
CMP register, register/value - Compare two values
and move 0 or 1 into appropriate Flags.
Ok thats enough for now, ive taught you basic
ASM opcodes, floats and Conditional Jumps.
This should be all you need to train a game
|How does it