# Basic assembler

Previous Top Next

Originally posted by Dark Byte + addition by Smidge204 Most people think assembler is very difficult, but in fact it's very easy. In this tutorial i'll try to explain how some basic assembler works The processor works with memory and registers. The registers are like memory but a lot faster than memory. Registers are EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI, and the segment registers. (There's also EIP, wich is the Instruction Pointer. It points to the instruction that is about to be executed) Some examples: sub ebx,eax (ebx=00000005,eax=00000002) Lets take it apart in it's most basic elements: opcode param1,param2 The opcode is the instruction telling the processor what to do, in this case decrease the value stored in register ebx with the value stored in register eax. In this case ebx=5 and eax=2 so ebx would be after this instruction 3. (5-3) Also note that whever you see a opcode with 2 parameters: The first parameter is the target of the instruction. The 2nd is the source sub [esi+13],ebx (ebx=00000003,esi=008AB100) In this case you see the first parameter is between brackets. This indicates that instead of registers a memorylocation is being used. The memorylocation is pointed at by whats in between the brackets, in this case esi+13 (Note that the 13 is in hexadecimal) ESI=008AB100 so the address pointed at is 008AB113. This instruction would decrease the value stored at location 008AB113 with the value stored in ebx(wich is 3). If the value at location 008AB113 was 100 then the value stored at 008AB113 after this instruction would be 97. sub [esi+13],63 (esi=008AB100) This is almost the same as above but instead of using a register it uses a direct value. Note that 63 is actually 99 because the instruction is always written using hexadecimal. Lets say the value at 008ab113 is 100 (wich is 64 in hexadecimal) then the value at 008ab113 after execution would be 1 (100-99) sub ebx,[esi+13] (ebx=00000064 esi=008ab100) This instruction decreases the value stored in ebx with the value stored at location 008ab113. (esi+13=008ab100+13=008ab113, in case you forgot)

Up until now i've only used SUB as instruction, but there are lots and lots of other instructions the procesor knows. Lets take a look at MOV, one of the most often used instructions although it's name sugests that it moves data, it just COPYs data from one spot to another. MOV works exactly the same as sub. first parameter is the destination, and second parameter is the source. examples: MOV eax,ebx eax=5,ebx=12 Copies the value stored in ebx into eax

So, if this instruction would be executed eax would be 12. (and ebx would stay 12) MOV [edi+16],eax eax=00000064, edi=008cd200) This instruction will place the value of eax(64hex=100 decimal) at the location of edi+16 (008cd200+16=008cd216). So after instruction the value stored at 008cd216 will be 100 (64 hex) As you see, it works just like the SUB instruction. Then there are also those instructions that only have 1 parameter like inc and dec. example: inc eax :increase the value at eax with 1 dec ecx: decrease the value of ecx with 1 dec [ebp]: Decrease the value stored at the address pointed to by ebp with 1. Right now i've only shown the 32-bit registers (eax, ebx ecx....) but there are also 16-bit register and 8-bit registers that can be used. the 16 bit registers are: AX,BX,CX,DX,SP,BP,SI,DI the 8 bit register are: AH,AL,BH,BL,CH,CL,DH,DL Note that when changing ah or al you'll also change AX, and if you change AX you'll also change EAX, same goes for bl+bh+bx+ebx,ch+cl+cx+ecx,dh+dl+dx+edx You can use them almost the same with the instructions for 32 bit but they will only change 1 (8 bit) or 2(16-bit) bytes, instead of 4 (32-bit) bytes. example: dec al :decreases the 8 bit register al sub [esi+12],al :decreases the 1-byte value stored at the location esi+12 points at with the value of al mov al,[esi+13]:places the 1-byte value stored at the location esi+13 points in the al register. Note that it is IMPOSSIBLE to use a 16 or 8 bit register for instructions that point to an address. eg: mov [al+12],0 will NOT work. There are also 64 and 128 bit registers, but I wont discuss them since they are hardly ever used, and cant be used with the other instructions that also work with 32 bit)

Then there are the JUMPS, LOOPS, and CALLS: JMP: The JMP instruction is the easiest it changes the Instruction Pointer (EIP) to the location the JMP instruction points at and continues from there. There are also conditional jumps that will only change the instruction pointer if a special condition has met. (for example set using the compare instruncion (CMP)) JA=Jump if Above JNA=Ju,p if not above JB=Jump if below JE=Jump if equal JC=Jump if carry and LOTS of other conditional jump LOOP: The loop instruction also points just like the JMP to a memory location, but only jumps to that location if the ECX register is not 0. and of course, there are also special contitional loops: LOOPE:Loop while ecx is not 0 AND the zero flag is not set LOOPZ:same as LOOPE. LOOPNE:Loop while ECX is not 0 AND the zero flag is set. LOOPNZ:Same as LOOPNE

Code: 0 S Carry 1 (Reserved) 2 S Parity 3 (Reserved) 4 S Auxiliary Carry 5 (Reserved) 6 S Zero 7 S Sign 8 X Trap 9 X Interrupt Enable 10 C Direction 11 S Overflow 12 X I/O Privilage (bits 12&13) 13 X 14 X Nested Task 15 (Reserved) 16 X Resume 17 X Virtual 8086

18 X Alignment Check 19 X Virtual Interrupt 20 X Virtual Interrupt Pending 21 X Identification 22 23 | 24 | 25 | 26 |_ (Reserved) 27 | 28 | 29 | 30 | 31 /

Let's go over the status flags, since those are used most often. Overflow: When an operation (Addition, subtraction, multiplication, etc) produces a result that is too big to fit in the register (or memory location) used, the Carry flag is set. (If not, it's cleared automatically) For example, if you're using a 16 bit register and your operation produces a value that won't fit in 16 bits, the carry flag is set. Sign: Set if the result is negative, cleared if positive. This is typically a mirror of MSB (most significant bit) of a value. Zero: Set if result is 0. Auxiliary Carry: Similar to Carry, but it will treat the register/memory location as 3-bits instead of 8, 16 or 32. This is used for BCD (Binary coded decimal) stuff and it generally pretty useless otherwise. Carry: The carry flag is set if the bit one past the lmit of the register/memory location would have been set. For example, mov al, 0xFF then add al, 1 will cause a carry because the 9th bit would have been set. Also note that the overflow and zero flags would be set and sign flag cleared, too!

---------------------------------------------------------------------------------------------------------------------------------------------------

What is the difference in bytetype

Previous Top Next

Originally posted by emperor: 2 Byte means: 00 00 to FF FF this allows only up to 65535, obviously. 4 byte means: 00 00 00 00 to FF FF FF FF (allows up to 4294967295). Now for example you can miss 2 byte values with 4 byte scans: example: value in game is 300 stored in game's memory as 012C If you search for 12C as 2 Byte it will be in your results. If you search for 12C as 4 byte the 2 Bytes before the 012C matter as well. For example the 012C would be after an FF FF. Meaning: FF FF 01 2C is in the memory 01 2C being what you are searching for. However seen as 4 Byte this is not 01 2C (300) but it's FF FF 01 2 C (4294902060) . To my mind for exact value scans you should use the smallest appopirate byte type (for ex if it doesn't rise over 65000 use 2 byte). However since most games multiply it with a certain factor exact value scans are hardly any

useful...when doing an unknown value scan it's up to you to chose the correct bytesize...most commonly used is 4 byte after all. It's nothing new to me seeing games showing a stat up to like 2000-3000 as 4 Byte in a huge number over serveral hundret thousands..however how much a certain game multiplies,adds or substracts, or tries to hide it depends on the game, is therefore sort of unknown therefore i think in many cases the bytesize is also sort of unknown although 4 Byte is always likely. Note doing increase/decrease value scans wouldn't fail even if there were some other bytes before it: for ex FF FF 01 2C is increased by one... ---> FF FF 01 2D increased would still be okay as unknown initial. But if the FF FF also changes to like FE FE then it would screw up the scan.

ASM Basics 1

Previous Top Next

Authored by DABhand

The Basics

Opcodes ===== 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, immediate values. 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

Registers ======

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 EAX FFEEDDCC AX DDCC AH DD AL CC 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 at end 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. eax (ax/ah/al) Accumulator ebx (bx/bh/bl) Base ecx (cx/ch/cl) Counter edx (dx/dh/dl) Data 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 value etc)

Segment Registers ============ 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

Pointer Registers =========== 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.

Stack 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

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

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

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

-------------------SEGMENT 1(64kb)---------------------|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: SEGMENT:OFFSET For example: 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 too Now we move to

32-bit Windows ========== 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 with

The Fun Part begins!!! Its THE OPCODES ========= Here is a list of a few opcodes you will notice alot of when making trainers or cracking etc. 1. MOV

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: offset 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 data 0D 0A 50 32 44 57 25 7A 5E 72 EF 7D FF AD C7 (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 are hexcodes. 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 403045. 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 hex. 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. Phew

DWORD (32-bits) edx:eax* / source EAX EDX * = 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: Instruction AND OR XOR NOT Source Bit |0 0 1 1|0 0 1 1|0 0 1 1|0 1| Destination Bit |0 1 0 1|0 1 0 1|0 1 0 1|X X| Output Bit |0 0 0 1|0 1 1 1|0 1 1 0|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. An example: mov ax, 3406 mov dx, 13EAh xor ax, dx ax = 3406 (decimal), which is 0000110101001110 in binary. dx = 13EA (hex), which is 0001001111101010 in binary. Perform the XOR operation on these bits:

Source 0001001111101010 (dx) Destination 0000110101001110 (ax) Output 0001111010100100 (new dx) The new dx is 0001111010100100 (7845 decimal, 1EA5 in hex) after the instruction. Another example: mov ecx, FFFF0000h not ecx

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 Universalis I WONT TELL YOU HOW TO MAKE KEYGENS SO DONT ASK :) 4. INC/DEC(REMENTS) 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 [103405] -> value at [103405] will increase by one. dec dword ptr [103405] -> value at [103405] will decrease by one. Ahh easy one to understand So is the next one

5. NOP 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. Shifting functions SHL destination, count SHR destination, count SHL and SHR shift a count number of bits in a register/memlocation left or right. Example: ; 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 with Rotation functions rol destination, count ; rotate left ror destination, count ; rotate right rcl destination, count ; rotate through carry left rcr destination, count ; rotate through carry right 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)

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Before 1 0 0 1 1 0 1 1 Rotate count 3 1 0 0 1 1 0 1 1 (Shift out) Result 0 1 1 1 0 0 1 1 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.

7. Exchange 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 em well.

ASM Basics 2

Previous Top Next

Authored by DABhand

FLOATS ======

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

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.

FLOAT OPCODES =============

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) Register. 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?

STACKS ======

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.

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

FLOAT EXAMPLES ==============

OK how to PUSH and POP values from the stack, its not difficult, heres a few examples :)

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

Example 2 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 1.50 or 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 :)

Example 3 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 move 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 stack. 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 it 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 things work.

Any questions just post and ill answer when available :)

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

ASM Basics 3

Previous Top Next

Authored by DABhand

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 are flags??? Well its not that difficult to understand.

Flag registers ==============

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 is negative. CF (Carry flag) The carry flag contains the left-most bit after calculations. 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.

Jumps =====

Heres a list of the Opcodes for Jumps

Opcode Meaning Condition JA Jump if above CF=0 & ZF=0 JAE Jump if above or equal CF=0 JB Jump if below CF=1 JBE Jump if below or equal CF=1 or ZF=1 JC Jump if carry CF=1 JCXZ Jump if CX=0 register CX=0 JE (is the same as JZ) Jump if equal ZF=1 JG Jump if greater (signed) ZF=0 & SF=OF JGE Jump if greater or equal (signed) SF=OF JL Jump if less (signed) SF!=OF JLE Jump if less or equal (signed) ZF=1 or SF!=OF JMP Unconditional Jump JNA Jump if not above CF=1 or ZF=1 JNAE Jump if not above or equal CF=1 JNB Jump if not below CF=0 JNBE Jump if not below or equal CF=1 & ZF=0 JNC Jump if not carry CF=0 JNE Jump if not equal ZF=0 JNG Jump if not greater (signed) ZF=1 or SF!=OF JNGE Jump if not greater or equal (signed) SF!=OF JNL Jump if not less (signed) SF=OF JNLE Jump if not less or equal (signed) ZF=0 & SF=OF JNO Jump if not overflow (signed) OF=0 JNP Jump if no parity PF=0 JNS Jump if not signed (signed) SF=0 JNZ Jump if not zero ZF=0 JO Jump if overflow (signed) OF=1

JP Jump if parity PF=1 JPE Jump if parity even PF=1 JPO Jump if paity odd PF=0 JS Jump if signed (signed) SF=1 JZ Jump if zero ZF=1

As you can see, jumps have conditions set to them from a previous calculation, test or compare.

Look at this example

TEST EAX,EBX JE 004822FFh MOV EAX,EBX JMP 004822FFh

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 point. 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 :)

Searching Tip

Previous Top Next

Originally posted by Smidge204

When searching for a value in memory using the scan, here are a few pointers to find the value quickly: 1) If the value is known, but the format is not (ie: Byte, 2 Bytes, 4 Bytes...) search for the smallest type that will hold the data. For example, if the value you want is 60, search for bytes. If the value is 1224, search for 2 Byte values, etc. The idea being that if the actual format is larger (You searched for 2 byte values but it's actually a 4 byte values) then the other bytes would be 0 anyway and the value would still be found. But if you search for a 4 byte value when it's really less, you might never find it because you're reading nearby bytes as well that might screw up your search!

2) If the value is unknown, use the "Unknown initial value" scan along with method 1 (ie: always use bytes unless you happen to know it's size). Then do something that changes it's value. Once the value has changed, repeat the scan using "Changed values". This will filter out all the crap. Now go back into the game and do a bunch of stuff that DOESN'T change the value, if possible. Now repeat the scan for "Unchanged values". This will filter out stuff like position values, timers and counters. Keep repeating until you've widdled down the searches to a managable amount, then add all the results to your list and keep an eye on them as the game runs. Remove anything that changes when it logically shouldn't. Anything that's left, try plugging in random values and see if something happens!

3) If you've found a bunch of good values, and youre looking for information that is somewhat related (Such as Lives and money, or whatever) , try restricting your search range to within a few kilobytes of the known value either way. This is especially powerful when looking for values in tables (High score list, for example) since they tend to be right next to eachother.

4) Use "Bigger than" and "Smaller than" as often as possible, especially after scans for changed or unchanged values. This can generally wittle down the results pretty fast.

5) Use arrays to peek at multiple byte values at once. Useful for detecing patterns!

6) Sometimes string values are not stored as ASCII strings, so the "Text" search doesn't work. For example, "A" might be stored as 0x01 instead of 41. If that's the case, and you have control over the value in-game (character name?) then try these steps: -Set the character name -Search for "Unknown initial value" -Change name -Search for "Changed values" (Repeat above two steps to eliminate as much junk as possible. See also tip #2) -Change name to all the same characters. ie: "AAAAAAA". Try to max out the space you're given. -Search one more time for changed values. If you've increased the number of displayed results enough to get a list, scroll down and see if you have a bunch of consecutive memory locations that have the same value. (Should be the same as the length of the string!) -Add the first address to your list as an array equal to the length of the string you entered. -Change name to an easily identifiable pattern. ie: "ABCDEFG" -See if the bytes in your array changed to a similar pattern. If so, start mapping the characters to their values and you're done! Once you have the character map, you can use it to "translate" other text you couldn't find before. Simply search for an array of bytes and enter in the expected values of each letter in order.

Hope that helps! =SMidge=

Code Injection and the auto assembler

Previous Top Next

when jumping back, just to make it easy....)

injectHealthReader: push eax //save eax, not really needed here since eax gets changed anyhow, but it's a good habbit to save and restore registers lea eax,[esi+ecx*4] //this instruction places the result of esi+ecx*4 into eax mov [playerhealthaddress],eax pop eax //restore the register, again, not needed here, but good habbit to do originalhealthreadercode: //label defining the original code, can be used to jump into or just skip, not needed here mov eax,[esi+ecx*4] //read health mov ecx,[esi+edx*4+4] //read something else, my gues, armor jmp returnHealthReader //jump back to the original game code, when done successfull, it wont crash...

As you see to specify a exact address just type it in ended with a ':' . Everything you type in after that will get assembled on and after that address (the jump and nops in this case, and the definition of the returnHealthReader:, which is in it's own turn also a address specifier, but doesn't change the current address) This code introduces labels, they are basicly identifiers specifying a address where thay have been placed. you can't just use a label though, you'll first have to declare it using the label(labelname) function. I usually declare labels right after the part where I alloc memory. so, right after the alloc I have this code to get the code above working: Code: label(returnHealthReader) //tell the assembler than returnHealthReader is a valid identifier, so dont bug out label(originalhealthreadercode) //same as above

now when you run the game the address of your health will get stored into the location of playerhealthaddress. You can already use this with cheat engine, because the auto assembler will tell you the address, but the allocation will change each time, so making a table for other people won't work, they'd have to fill in the address each time themselves. (I dont find that a problem but somehow some people do....)

injectHealthWriter: //do a check if esi+ecx*4 matches the address stored in playerhealthaddress //if it matches, skip the original code, if it doesn't just execute it //save the registers we use, and before I forget, do not touch esp between saving and restoring the registers unless //it's to read something(like parameters), in which case you'll have to adjust the offset //also, dont change the registers that you use to find the address push eax push ebx mov eax,[playerhealthaddress] lea ebx,[esi+ecx*4] cmp eax,ebx je itstheplayer //not the player pop ebx //I think I could have doen this before the je, but better safe than sorry pop eax jmp originaldecreasehealthcode

itstheplayer: pop ebx //restore the registers, keep in mind to restore the registers in reverse order pop eax jmp returnHealthWriter //dont execute the original code, return imeadiatly originaldecreasehealthcode: sub edx,eax mov [esi+ecx*4],edx jmp returnHealthWriter

again, I used a few labels to make it easier for me but, that also means I'd have to declare them, else the assembler will complain it doesn't recognize them so: Code: label(returnHealthWriter) label(itstheplayer) label(originaldecreasehealthcode)

and I prefer adding declarations at the top.

So, the complete auto assembler script would look like: Code: alloc(injectHealthReader,1024) //creates a identifier called injecthealthreader that points to a block of 1024 bytes alloc(injectHealthWriter,1024) //2nd code cave to handle the code of the decrease health code, for easy management alloc(playerhealthaddress,4) //this will hold the address of health, a 4 byte value (pointer, in 64 bit this'll have to be 8 bytes) label(returnHealthReader) //tell the assembler than returnHealthReader is a valid identifier, so dont bug out label(originalhealthreadercode) //same as above label(returnHealthWriter) label(itstheplayer) label(originaldecreasehealthcode)

//---------------------------------------// Healthreader //---------------------------------------00405000: jmp InjectHealthAddress //jump to the codecave nop //nops for the lost space nop returnHealthReader: //this is the label that is used to return to the address (so you dont have to write down 00405007 when jumping back, just to make it easy....)

injectHealthReader: push eax //save eax, not really needed here since eax gets changed anyhow, but it's a good habbit to save and restore registers lea eax,[esi+ecx*4] //this instruction places the result of esi+ecx*4 into eax mov [playerhealthaddress],eax pop eax //restore the register, again, not needed here, but good habbit to do originalhealthreadercode: //label defining the original code, can be used to jump into or just skip, not needed here mov eax,[esi+ecx*4] //read health mov ecx,[esi+edx*4+4] //read something else, my gues, armor jmp returnHealthReader //jump back to the original game code, when done successfull, it wont crash...

//---------------------------------------// Health decreaser //----------------------------------------

00421000: jmp injectHealthWriter //overwrite the original code with a jump. returnHealthWriter: //just declare it here, it'll get address 00421005, so a jmp returnHealthWriter will get converted to jmp 00421005

injectHealthWriter: //do a check if esi+ecx*4 matches the address stored in playerhealthaddress //if it matches, skip the original code, if it doesn't just execute it //save the registers we use, and before I forget, do not touch esp between saving and restoring the registers unless //it's to read something(like parameters), in which case you'll have to adjust the offset //also, dont change the registers that you use to find the address push eax push ebx

mov eax,[playerhealthaddress] lea ebx,[esi+ecx*4] cmp eax,ebx je itstheplayer //not the player pop ebx //I think I could have doen this before the je, but better safe than sorry pop eax jmp originaldecreasehealthcode

itstheplayer: pop ebx //restore the registers, keep in mind to restore the registers in reverse order pop eax jmp returnHealthWriter //dont execute the original code, return imeadiatly originaldecreasehealthcode: sub edx,eax mov [esi+ecx*4],edx jmp returnHealthWriter

Please be aware that I havn't tested this in ce yet, I've been writing this in notepad on a pc that doesnt have ce installed, so there may be a few syntax errors, and some of the code I've written can surely be optimised, but I hope you get the general idea. Also, there's a bug in ce 5.0 where you can't use small identiers that can apear in the name of another identifier. (e.g weirdmemlocxxx and memloc can't be used at the same time, because memloc fits in weirdmemlocxxx) But if you use normal names for identifiers this wont couse a problem, and I recommend identifiers of more than 4 characters, else it may happen you get the name of a assembler instruction and accidentally overwrite that when used. _____________________ The other method of using code injection is finding if there are differences between the player data and opponent data. Lets say that if it's the player [esi+ecx*4+14] contains a 1 otherwhise a 0. you can then do a check if that is set or not, if so, skip, otherwhise, decrease health Code: alloc(injectHealthWriter,1024) //2nd code cave to handle the code of the decrease health code, for easy management label(returnHealthWriter) label(itstheplayer) label(originaldecreasehealthcode)

//---------------------------------------// Health decreaser //----------------------------------------

00421000: jmp injectHealthWriter //overwrite the original code with a jump. returnHealthWriter: //just declare it here, it'll get address 00421005, so a jmp returnHealthWriter will get converted to jmp 00421005

injectHealthWriter: push eax mov eax,[esi+ecx*4+14] cmp eax,1 je itstheplayer //not the player pop eax jmp originaldecreasehealthcode

itstheplayer: pop eax //restore the register jmp returnHealthWriter //dont execute the original code, return imeadiatly originaldecreasehealthcode: sub edx,eax mov [esi+ecx*4],edx jmp returnHealthWriter

3D pinball for windows (pointer+code)

Previous Top Next

Originally posted by me. (no not me, but the user called me) this is to try answer the most common questions from people new to cheat engine using 3d pinball for windows space cadet as an example,,, it might be an idea to print this and other tuts so its easier to work through them,,, ( this game gives you some free balls so be on the look out for that during this tut ) start 3D PINBALL FOR WINDOWS ,, and wait for the first ball to deploy start cheat engine click on the flashing icon in the top left of cheat engine in the bottom of process list window double click on PINBALL.EXE to attache the game to cheat engine in the value box type in 3 go into the pinball game and lose a ball wait for the next ball to be deployed go back into cheat engine type 2 into the value box click on the next scan button I got the address A9FEE6 yours may be different ok I'll double click on the found address A9FEE6 to add it to the bottom pane click on the checkbox to freeze this address go back into the PINBALL GAME lose some balls to see if its the right address if you have got it right you'll have infinite balls

click on the poiter checkbox and you will see the ADD ADDRESS window change where it says ADDRESS OF POINTER type in our address 9A4356 and in the OFFSET [HEX] box type in 146 ,,,,,,,,, remember [esi + 00000146] and hit the ok button hopefully a new address with should look like this in the bottom pane No description P->00A9FEE6 4 bytes 0x00000003 or how ever many balls you got left you can freeze the number of balls from this pointer now,,,,, in games that use Dynamic Memory Allocation ,,, DMA and use the same code to change things for you and the enemies,, pointers are usfull -----------------------------------ok a couple of things 1) this game don't use dma ,, but its an easy game to practice on 2) Its free and most people have it 3) so for newcomers it gives an idea of how to use the basic search / pointer / and advanced options well as they say thats my two cents

Basic packet editing
Basic Packet editing with Cheat Engine

Previous Top Next

This is just an example tutorial describing how to do basic packet editing with Cheat Engine. It's main purpose is to show that you don't have to use other tools when packet editing. (Sure, it helps and is easier, but CE can do it as well) Let's say you want to change in outgoing packet data the word "hello" with the word "idiot". First gather all needed information and discuss some basic api calling mechanics: Packet data is sent using ws2_32.dll's send api . To target this api's location you have to use ws2_32!send as name, else ce will pick winsock32's send export, which is not what you want Next you have to know that the 2nd parameter contains the pointer to the buffer that is being sent. Let's first get into windows api calling mechanics. Parameter passing is done by pushing the parameters in reverse order on the stack, followed by a call to the send api., which pushes the next instruction's address on the stack as well. Because each push decreases esp with 4 bytes, the parameters will actually appear in the correct order, making it [esp] point to the return address, [esp+4] holds the first parameter (socket), [esp+8] holds the 2nd parameter (pointer to buffer containing data), [esp+c] holds the length of that buffer, etc... To packet edit you'll have to hook the send api and inspect and manipulate the parameters and buffers sent. In short, code injection at ws2_32!send, get the address of the send buffer, get the length, scan that buffer for the word hello, and if found, replace that with the word idiot The following code snipet is an example of basic packet editing. (Nothing fancy, but does the job) alloc(newmem,2048) //2kb should be enough

label(returnhere) label(originalcode) label(exit) label(repeat) label(repeat2) label(nomatch) label(nomatch2) label(endofroutine) alloc(texttoscan,5) //non 5.4.4 alloc(texttoreplacewith,5) define(stringlength,5) texttoscan: db 'hello' texttoreplacewith: db 'idiot' ws2_32!send: jmp newmem returnhere: newmem: //this is allocated memory, you have read,write,execute access //place your code here //start off with a stackframe push ebp mov ebp,esp //lets save the used registers push eax push ecx push esi push edi

mov esi,[ebp+0c] //buffer (I might have said esp+8 in the post, but due to the added stackframe(push ebp), it's all shifted 4 bytes) mov edi,texttoscan mov ecx,[ebp+10] //length of buffer cmp ecx,stringlength jl endofroutine sub ecx,stringlength-1

repeat: //edit: because 5.4 doesn't support cmp byte [esi],'t' I have to do it different than in 5.4.4 push ecx mov ecx,stringlength-1 repeat2: /*

sure, it compares from the back to front, but as long as it checks it's a match I don't care */ mov al,[esi+ecx] cmp al,[edi+ecx] jne nomatch2 loop repeat2

//still here, so a match push esi push edi mov edi,esi //I want the found buffer to be the destination, not source mov esi,texttoreplacewith mov ecx,stringlength rep movsb //move the byte stored at [esi] into [edi] ecx times (so move texttoreplacewith to the found string pop edi pop esi nomatch2: pop ecx nomatch: inc esi loop repeat endofroutine: //undo any register change pop edi pop esi pop ecx pop eax /* undo stackframe. Ok, in this situation the stackframe of the original function could have been used, but I try to keep it understandable to readers. */ mov esp,ebp pop ebp originalcode: mov edi,edi push ebp mov ebp,esp exit: jmp returnhere

Note: Instead of editing the actual buffer you might want to create a new buffer and pass that on to the send api. That'll allow for longer texts, and won't mess up if the program actually uses read-only buffers for the send api

Percentage scans and compare to saved results Originally posted by Geri Open the CE tutorial and proceed to Step 2. Open CE and attach it to the tutorial. Now You have 100 health. We will find this value by using the percentage scan in CE. Start an unknown initial value scan. Now click on the hit me button and you loose some health. I have 96 health now.

Previous Top Next

Click on the Scan type dropdown menu and choose the last option, "Compare to first scan". This means that in the next searches, the values will not be compared to the last search result, but always to the first scan result, which is in our case 100 for our value. The next step is to choose "Value between..." search and click on the between % checkbox. What will this option do exactly? It will check all values which are x-y% of the value that we use for comparing. At the moment, this means it will scan for values which are x-y% of the first scan result. Why is this good for us? We have made the first scan when our value was 100. This value is the 100%. Our value at the moment is 96. It isn't hard to calculate that our value is the 96% of the first scan result. To find our value, we type in 95 and 97 in the fields so CE will find all values that are 95-97% of the first scan result. Hit next scan and You can see that we have only a few results. Probably You can see that the value is in the list, but just for fun, repeat the process again. Click on "Hit me" a few times. Now I have 78 health. I need to find the value. 78 is obviously 78% of the first scan result which was 100. So I make a scan with "Value between...", between% and I type in 77 and 79. Awesome I have found my value already. This example was easy because we have seen the value and we knew that it is not multiplied with any number. You may think this was a stupid example. But wait a minute. What happens if the value is stored in some tricky way, like when it is multiplied with 8 for flash games? Well of course since we have searched for x-y% of the value, it doesn't matter if the values are multiplied, you will find them easily using this method. With a flash game, it would have worked this way (not in all flash games, but in some of them). You have 100 health and it is stored like 800 in the memory. You do a first scan. Then your health is decreasing to 96 (which is in fact 768 in the memory). You search for 96% (95-97%). Then you loose some health again and you see you have 78 health (which is in fact 624 in the memory). You search for 78% (77-79%) and bingo. You have found your value. Did you know it is multiplied? No. Did you find it just by searching for x percentage of the first scan result which was 100%? Yes, you have found it easily and it would have worked even if the value is multiplied with 200, 1000 or even 4748 in the memory.

I hope you realize that this feature is VERY useful when you don't know if a value is multiplied or not and you have no idea what is the multiplier value. In many cases, this will help to find timers and other tricky values which are usually multiplied.

And now, we will check what happens if we don't see the exact value that we are looking for. Proceed to Step 3 in the Tutorial. You can see a health bar only, but you don't know the exact number. What you see however, is that the health bar is full. This means that the health bar is filled to 100% at the moment. Now start an unknown initial value search. Click on Hit me a few times and You loose some health. Now choose Compare to first scan again, then choose "Value between..." and between %. Look at your health bar. You have lost some health, try to guess how much % health do you have from the full bar. My bar is filled to about 85-95% so I have about 85-95% of the full health. Ok, I search for 85-95%. Click on Hit me again a few times to loose health. Ok now my health bar is somewhere between 60 and 80%. I search for 60-80%. Bingo. I have found my value already, but if you don't have it yet, continue searching until you find it. Why is this useful when you could just simply use increased/decreased search? If you have ever tried to find a graphically displayed timer or a progress bar in some game, where you did not have the option to stop the value and all you could do is to keep searching for decreased value all the time, then think about how easy would have been to just search for the progress bar this way.

As a final word, I need to mention that a decreasing health bar or progress bar doesn't mean that the value is decreasing. It may happen that it is constantly increasing until it will reach a certain value. But even in this case, you can still use the % scan, just be a bit clever. Utilize this feature when you are stuck with increased/decreased changed/unchanged value searches, because this will save you many times. Probably this feature is one of the most useful options in CE 6 for beginners and advanced users alike.