Hey Its Cr4zi8 here and I am going to be showing you how to hack games in a 3 part tutorial (there may be a 4th not sure yet). Welcome to part I in which I am going to show you how to create a simple external memory hack. First here is a list of what you need.
For the this part:
⦁ Windows (vm or installed on a hardrive)
⦁ An Installation of Assault Cube
⦁ Cheat Engine >=6.4
⦁ A text editor of some kind I use sublime text
⦁ A C compiler mingw, lcc etc
For future parts:
⦁ OllyDbg 1.10
Good to have:
⦁ aadp4olly (for getting by anti debugging solutions that might be implemented on commercial games)
Before we get started I would also recommend adding this to your arguments inside the assaultcube.bat file "-t -w 800 -h 600", just because we are going to be messing around with a bunch of windows.
Things you should probably know (not completely nesscary I suppose)
⦁ Rudimentary understanding of ASM
⦁ C Programming
⦁ Memory Structure
⦁ Programming with the Windows API
Introduction to Memory hacks: The concept of memory hacks is fairly easy to grasp especially with a demonstration. So the idea of a Memory hack is generally, to access the games process memory in order to change values therefore affecting the status of the player in game or to read values in order to gain an unfair advantage. Memory hacks can do things such as give health or ammo, change the players position, or give other players positions (depending on the game).
Hacking Assault Cube: The first step in creating a memory hack is to find the adressess that you need to write to. For this we are going to use Cheat Engine. So open up assault Cube and Cheat Engine then attach Cheat Engine to ac_client.exe. The first address I am going to show how to find is the adress for the variable holding your ammo count. To do this first start a new scan, then search for the amount of ammo you currently have. Next take two shots and do another search with your new ammo count(click next scan). Continue this process until you have narrowed it down to two addresses. Add the top value (double click on it). Change the value by double click on the value column of the memory record in the record window. Make this value some number and see if it changes your ammo ingame. If it does change ingame then the top one was the correct address otherwise add the bottom address from the search and try it with that address. Great we have found the address of the variable holding the ammo count. Unfortunately this address will constantly change because of how virtual memory works so now we have to find a permanent pointer to this value.
Cheat Engine makes finding this pointer relatively easy. Right click on the memory record and select find what access this address. There will be a couple of asm instructions in the debugger window but these are not what we are looking for these are just used for displaying the value. To find the value we want take a shot then return to the window. The decrement instruction is the one we are looking for. This instruction decrements your ammo when you take a shot double click on it. (As a side note record the address of the decrement instruction for later.) Cheat engine will find the value of a pointer to this address. So we search this value in Cheat Engine. Add the address manually and make sure to check the box designating it a pointer and add no offset because there is none in the instruction. Continue to repeat this process on the pointer until you reach a static address(green). Record the address and its offsets.
Now the process needs to be repeated for the health variable. Unfortunately assault cube dos not provide a command to hurt yourself so you have to hurt yourself by ingame means such as standing by a grenade. So do a first scan for 100 and then find a grenade on the map you were loaded into and hurt yourself with it. Do the next scan with your new health value. Continue to do this until you have two values once again add the top one and change the value.
Repeat the process of finding a static pointer.
Explained using pictures for visual learners:First we search our starting value for ammo which if you are using the assault rifle is 20
Next in game take three shots and search the new ammo value with next scan.
In some cases you will need to repeat that process to get two results. Since we narrowed it down to two add the top one and change the ammo value, then see if it changes in game.
It did in this case if it had not we would have tried the other value.
Next right click the record then click find what accesses this address; do not select the instructions that appear. First take a couple of shots then select the decrement instruction. After doing that you will be presented with a screen like this. Notice that the offset for this address is 0 (nothing added to esi). Record the offset then copy the value that is needed to find the address.
Search the value, make sure to check the hex box.
Since there is only one add it as a pointer.
Now find what accesses this pointer, record the offset(14), and copy the value.
Search the value.
Since there are multiple addresses start by adding the top address with both offsets.
This pointer turned out to be a dead end.
Therefore we move on to the next address found.
Once again find what accesses it after shooting.
Record the offset in your list(374,14,0). Now search this new value.
Alright we have found a stable address.
0051E20C offsets: 374,14,0
Repeat this for health:
0x00509B74 offsets: F8 (yours will probably be different depending on architecture etcc).
Programming the Hack: The first thing we need to do to gain control of the game is to gain a handle linked to the process. To do this I wrote a method called getHandle.
/*
* Returns a Handle for process matching pname
*/
HANDLE getHandle(char pname[])
{
DWORD dwPid=0;
HANDLE proc, hProc;
PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
while(!dwPid)
{
printf("Searching for ac process...\n");
printf("Make sure the game is running!\n");
hProc=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(Process32First(hProc, &pe32))//place process in pe32
{
do
{
if(!strcmp(pe32.szExeFile,pname))//compare pe32 pname to the pname
{
dwPid=pe32.th32ProcessID;//set pid to the pid of the process if the process names matched
break;
}
}while(Process32Next(hProc,&pe32));//move to next process
}
sleep(10);
}
proc=OpenProcess (PROCESS_ALL_ACCESS,FALSE,dwPid);//open process Handle
return proc;//return the Handle
}
After we have a handle of the process we will need to calculate the dynamic adressess for this I wrote the method offCalc.
DWORD offCalc(DWORD b, DWORD offs[], int size, HANDLE proc)
{
DWORD base=b;
DWORD ptemp;
int i;
for(i=0;i<size;i++)//loops through offsets
{
ReadProcessMemory(proc, (LPCVOID)base,&ptemp,sizeof(ptemp),NULL);//reads the next adress into ptemp
base=ptemp+offs;//adds ptemp to the offset
printf("0x%x+%x=%x\n",ptemp, offs, base);//prints debugging info
}
return base;//return address
}
After we have the dynamic adressess all that is left is to write the values into their addresses.
int writeVal(HANDLE proc, DWORD addr,BYTE *val)
{
return WriteProcessMemory(proc,(BYTE*)addr,val,4,NULL);//write the value to the proc at addr
}
This is all tied together in main.
int main()
{
BYTE setval[]={0x64,0x00,0x00,0x00};//100 in hex because of little endian
HANDLE proc=NULL;//handle for the process
DWORD health={0x00509B74};//static adress for health
DWORD haddr;
DWORD offh[]={0xF8};//offsets health
DWORD ammo={0x0051E20C};//static adress for ammo
DWORD aaddr;
DWORD offa[]={0x374, 0x14, 0x00};//offsets for ammo
char gameName[]="ac_client.exe";//name of the process
proc=getHandle(gameName);//set proc to the Handle gained by get Handle
if(proc!=0)//check if proc was retrieved
{
haddr=offCalc(health,offh,1,proc);//calculate the dynamic address and set haddrr
aaddr=offCalc(ammo,offa,3,proc);//calculate the dynamic adress of and set aaddr
int check1;//bool for write status
int check2;//bool for write status
while(1==1)//infinite loop cause im lazy
{
check1=writeVal(proc,haddr,setval);//write the val for health and place the status in check 1
check2=writeVal(proc,aaddr,setval);//write the val for ammo and place the status in check 2
if(!check1&&!check2)//print error adressess if write returns 0
{
if(!check1)
printf("Error writing to 0x%x",haddr);
if(!check2)
printf("Error writing to 0x%x",aaddr);
}
}
}
}
Final Code:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
//function prototypes
DWORD offCalc(DWORD b, DWORD offs[], int size, HANDLE proc);
HANDLE getHandle(char windowname[]);
int writeVal(HANDLE proc, DWORD addr,BYTE *val);
int main()
{
BYTE setval[]={0x64,0x00,0x00,0x00};//100 in hex because of little endian
HANDLE proc=NULL;//handle for the process
DWORD health={0x00509B74};//static adress for health
DWORD haddr;
DWORD offh[]={0xF8};//offsets health
DWORD ammo={0x0051E20C};//static adress for ammo
DWORD aaddr;
DWORD offa[]={0x374, 0x14, 0x00};//offsets for ammo
char gameName[]="ac_client.exe";//name of the process
proc=getHandle(gameName);//set proc to the Handle gained by get Handle
if(proc!=0)//check if proc was retrieved
{
haddr=offCalc(health,offh,1,proc);//calculate the dynamic address and set haddrr
aaddr=offCalc(ammo,offa,3,proc);//calculate the dynamic adress of and set aaddr
int check1;//bool for write status
int check2;//bool for write status
while(1==1)//infinite loop cause im lazy
{
check1=writeVal(proc,haddr,setval);//write the val for health and place the status in check 1
check2=writeVal(proc,aaddr,setval);//write the val for ammo and place the status in check 2
if(!check1&&!check2)//print error adressess if write returns 0
{
if(!check1)
printf("Error writing to 0x%x",haddr);
if(!check2)
printf("Error writing to 0x%x",aaddr);
}
}
}
}
int writeVal(HANDLE proc, DWORD addr,BYTE *val)
{
return WriteProcessMemory(proc,(BYTE*)addr,val,4,NULL);//write the value to the proc at addr
}
/*
* Returns a Handle for process matching pname
*/
HANDLE getHandle(char pname[])
{
DWORD dwPid=0;
HANDLE proc, hProc;
PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
while(!dwPid)
{
printf("Searching for ac process...\n");
printf("Make sure the game is running!\n");
hProc=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(Process32First(hProc, &pe32))//place process in pe32
{
do
{
if(!strcmp(pe32.szExeFile,pname))//compare pe32 pname to the pname
{
dwPid=pe32.th32ProcessID;//set pid to the pid of the process if the process names matched
break;
}
}while(Process32Next(hProc,&pe32));//move to next process
}
sleep(10);
}
proc=OpenProcess (PROCESS_ALL_ACCESS,FALSE,dwPid);//open process Handle
return proc;//return the Handle
}
/*
* Returns the adress with calculated offsets
*/
DWORD offCalc(DWORD b, DWORD offs[], int size, HANDLE proc)
{
DWORD base=b;
DWORD ptemp;
int i;
for(i=0;i<size;i++)//loops through offsets
{
ReadProcessMemory(proc, (LPCVOID)base,&ptemp,sizeof(ptemp),NULL);//reads the next adress into ptemp
base=ptemp+offs;//adds ptemp to the offset
printf("0x%x+%x=%x\n",ptemp, offs, base);//prints debugging info
}
return base;//return address
}
Thanks for reading the next part will be on internal hacks with dll injection.
UPDATE:
Part 2 on the way