Search site: 

| Home | PC Cheat Codes | Game Patch Updates | PC Game Trainers | PC Game Tools | Game Patch Fixes | Articles | Discussion Forums | Contact |

Trainer Tutorials

Latest Forum Discussions:

This section of the site is dedicated to Trainer Tutorials to help everyone get a better understanding of how Game Trainers are made and how they function.

Making a Mass Kill Trainer Tutorial

Making a Mass Kill

Target:
Crimsonland version 1.9.8
http://www.crimsonland.com

Tools:
-Softice
-Tsearch 1.6b (http://fly.to/mtc/)
-Code Cave Chaos (http://www.s-i-n.com/chaos/)

Objectives:
With One hit kill hacks being all the rage these days, we will take it a step further and turn a one hit kill into a kill all mass killer.

Begin:
The first step is that we have to find the routine that deals with the enemy health. A good idea would be to get the DOCTOR perk (0x48E6C0 = 1), which allows you to see enemy health by holding your mouse cursor over them. The problem at the beginning of the game is that enemies die off too quickly to be able to search for health, so wait until level 1.5 ( Alien Dens ) and shoot at those big red white enemy spawners.

Doing the standard dec / inc search you should have come up with something in the 499xxx range, then put a breakpoint (bpm w) / autohack it.

You should pop up at the monster health routine:

:004200DD D99E34944900 fstp dword ptr [esi+0x499434]

--- side note ---
The fst and fstp instructions copy the value on the top of the floating point register stack to another floating point register or to a 32, 64, or 80 bit memory variable. When copying data to a 32 or 64 bit memory variable, the 80 bit extended precision value on the top of stack is rounded to the smaller format as specified by the rounding control bits in the FPU control register.
The fstp instruction pops the value off the top of stack when moving it to the destination location. It does this by incrementing the top of stack pointer in the status register after accessing the data in st(0). If the destination operand is a floating point register, the FPU stores the value at the specified register number before popping the data off the top of the stack.

Executing an fstp st(0) instruction effectively pops the data off the top of stack with no data transfer. Examples:

fst mem_32
fstp mem_64
fstp mem_64[ebx*8]
fst mem_80
fst st(2)
fstp st(1)

The command at 004200DD is just basically storing a number from the stack at the address of esi+0x499434.
--- end side note ---



Take a look at the registers and jot down some notes. F5 out of Softice and attack a different monster. Try to understand what is going on in those registers when you get popped back into SI due to attacking the monsters. You will also see at the far right that DS: holds the memory address of what you are currently attacking, then the number after the equal sign is the value of their health in hex.

--- side note ---
If you want to convert it to
a dec type:

? xxxxxxxx ; where xxxxxxxx is the number after the equal sign. You will notice that it is a large value like 1140457472, this is because it is in DWord (4 bytes) format. To get the float version of it, either change it from 4 Bytes to Float in TSearch or divide it by 2280914.944
--- end side note ---


You will see the following pattern as you go through a bunch of times:
EDI ESI
00 00
01 98
02 130
03 1c8
04 260
05 2f8
06 390

It can be inferred that when monsters spawn, they are assigned an ID number based on the order in which they were spawned. Also each Monster struct is 0x98 bytes apart in memory.

--- side note ---
A struct (structure) is simply a way of grouping several variables under one name like below:

struct Monster
{
float xposition;
float yposition;
float health;

float speed;

};

//example usage Monster.health=100;
--- end side note ---


Now that we know what is going on at

:004200DD D99E34944900 fstp dword ptr [esi+0x499434]

we want full control of what happens in this function. So now it is time to jump to a code cave and rewrite the function to fit our needs.

Use Code Cave Chaos to find an empty code cave.

For this project I chose to put my stuff @ 0x46cb58.

Load up TSearch and open up the Easy Script section, its time for some coding fun. Make sure you have the latest version of TSearch which supports labels inside of EasyScript.

//-- code start ---
// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//recreates the instruction that we destoryed
fstp dword ptr [esi+0x499434]
//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

So with that code above we created a jump to our code cave, which just recreated the original fstp instruction. At this point nothing has changed except that when you attack a monster, the game now goes through our function before returning back to the games own code.

So now let us add some code that will cause the current monster's life to be set to 0 when it passes through our function.

!GREEN COLOR INDICATES NEW CODE THIS TIME AROUND!
!BLUE COLOR INDICATES STUFF THAT WAS DEACTIVATED OR DELETED!
!NEW COMMENTS ARE THIS COLOR!

//-- code start ---
// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//recreates the instruction that we destoryed
//we are going to replace this with a mov instruction
//fstp dword ptr [esi+0x499434]
//move the value of 0 into the pointer, thus killing current monster
mov dword ptr [esi+0x499434], 0x0
//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

Okay, there you have it. When a monster is attacked, its health will be replaced with 0 and it will die. However this is not good enough, we would like to be able to kill all monsters at once. The monster's health pointer is [esi+0x499434], so if we were able to go through the whole list of created monsters and replace their health with 0, then they all would die when one was attacked.

Remember how I made you pay attention to those two registers? EDI & ESI? Now we are going to use them in a loop to help point to the proper memory address of the monster's health and then we will write a 0 into it to kill them.

//-- code start ---
// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//pushes all registers so that they are backed up
//on the stack so we can pop them back later so that we have no
//adverse effects on the game

pushad
//set esi to 0
xor esi, esi
//set edi to 0
xor
edi, edi

//creates a label so that we can jump back to it by name
//when we need to loop back through our little function again

@loop:


//move the value of 0 into the pointer, thus killing current monster
mov dword ptr [esi+0x499434], 0x0

//Since ESI*EDI*0x98+0x499434 = current monster's hp
//load effective address is the most efficient way of doing this.
//ESI now equals esi+0x98
lea esi, dword ptr [esi+0x98]
//increases EDI by 1, thus pointing to the next monster
inc edi
//compares edi and 300, which is how many times it should loop
//this accounts for all the monsters that could ever spawn in the
//game at once. I choose 300 cause 500 crashed the game =P

cmp edi, 0x12c
//if edi is not yet at its 300th run through the loop then go to the
//code at the label @loop: (LOOK UP!).

jne @loop

//pop all registers so that they are at the value they were at right before
//we started messing with them.

popad

//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

So this time around we backed up the registers so that we could reuse them at the end of our function, just incase we modified any of them during our code.

Then we created a loop that looped 300 times, increasing the value of EDI until it reached 300 - all the while writing 0 to the health address of each creature as it goes through the loop.


Conclusion:
For the most part games store players and enemies an arrays of structs so once you find a pointer for health you can do some math and go through memory and write new values there.
In the case here, EDI (0,1,2,...) * ESI (0x98) + 0x499434 pointed to the health of the current monster. We modified it so that it would go through and write 0 to each Monster.health address. When a monster is attacked by the player, the game jumps to our code and writes 0 to all currently spawned monsters - killing them all for one. The only glitch is you only get exp for what you kill with your bullet, but that's a story for another time.


DOWNLOAD COMPILED VERSION OF CODE
DOWNLOAD EASYSCRIPT VERSION OF CODE

//--FINAL CODE BELOW--//

offset 004200dd
jmp
@myfunction
nop
@home:

offset 46cb58
@myfunction:
pushad
xor esi, esi
xor edi, edi
@loop:
mov dword ptr [esi+0x499434], 0x0
lea esi, dword ptr [esi+0x98]
inc edi
cmp edi, 0x12c
jne @loop
popad

jmp @home

 

^chaos^
idxchaos@hotmail.com
http://www.s-i-n.com/chaos/

^chaos^
November 15th, 2003

chaos world (c) 2003
Do not distribute as your own

Copyright (1998) 2004 - 2016 GamePatchPlanet.com. All Rights Reserved. Privacy Policy Disclaimer