In the last tutorial, I explained how to code cave an offset in memory with a debugger. Now I am going to show you how to make this a stand-alone program.
We are going to use a very popular, mid-strong typed object-oriented programming language: C++!
Tools you will need:
- A C++ compiler, let's use DevC++ (uses minGW).
- Your codecave info from the last tutorial:
Let's open DevC++ and start a new project C++ console application project.
Right now, your source should be:
Code:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
system("PAUSE");
return EXIT_SUCCESS;
}
We are going to need 3 functions to write stuff into Warcraft 3's memory. We will need to include windows.h and Tlhelp32.h for them to work.
We will need to:
- Get the PID for our running Warcraft 3 process
- Enable debug priviledges for that process
- Get Game.dll's base (which is most of the time 6F000000)
We are going to use SD333221's open-source maphack functions for this:
Lets put these function prototypes before our main() function.
DWORD GetPIDForProcess (char* process);
void EnableDebugPriv();
DWORD GetDLLBase(char* DllName, DWORD tPid);
And the functions after the main function.
Code:
DWORD GetPIDForProcess (char* process)
{
BOOL working=0;
PROCESSENTRY32 lppe= {0};
DWORD targetPid=0;
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS ,0);
if (hSnapshot)
{
lppe.dwSize=sizeof(lppe);
working=Process32First(hSnapshot,&lppe);
while (working)
{
if(_stricmp(lppe.szExeFile,process)==0)
{
targetPid=lppe.th32ProcessID;
break;
}
working=Process32Next(hSnapshot,&lppe);
}
}
CloseHandle( hSnapshot );
return targetPid;
}
void EnableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
return;
if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) ){
CloseHandle( hToken );
return;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
CloseHandle( hToken );
}
DWORD GetDLLBase(char* DllName, DWORD tPid)
{
HANDLE snapMod;
MODULEENTRY32 me32;
if (tPid == 0) return 0;
snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, tPid);
me32.dwSize = sizeof(MODULEENTRY32);
if (Module32First(snapMod, &me32)){
do{
if (strcmp(DllName,me32.szModule) == 0){
CloseHandle(snapMod);
return (DWORD) me32.modBaseAddr;
}
}while(Module32Next(snapMod,&me32));
}
CloseHandle(snapMod);
return 0;
}
Now, to write our offset, we will need to use WriteProcessMemory(). Sd333221 uses a custom function called patch that allows the base to be auto-included. Let's use it.
Let's find the PID, and if we can't, exit.
Code:
if(GetPIDForProcess("WAR3.EXE") == 0)
{
system("Pause");
exit(0);
}
If the PID is found, let's enable Debugging priviledges and attempt to open the Warcraft 3 process.
Code:
else
{
EnableDebugPriv();
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, GetPIDForProcess("WAR3.EXE"));
if(hProc)
{
DWORD gameBase = GetDLLBase("Game.dll",GetPIDForProcess("WAR3.EXE"));
DWORD dSize = 0;
We store our game.dll's base and bytes written in DWORD's gameBase and dSize.
Now let's use our patch function. We will need to use it twice.
First jump:
6F39B97D E9 A2 04 4C 00
E9 + A2 + 04 + 4C + 00 = 5 bytes, therefore our dSize will be 5.
And we will write: "\xE9\xA2\x04\x4C\x00"
Since our base is most likely 6F000000, let's substract: 6F39B97D - 6F000000 = 39B97D.
Our address will be 0x39B97D:
Code:
PATCH(0x39B97D,"\xE9\xA2\x04\x4C\x00",5);
if(dSize == 0)
{
cout << "Failed to patch uselessblackground jump to codecave." << endl;
}
For the codecave, we will use the same logic:
6F85BE24 E8 77 4B 7B FF 39 AE 30 03 00 00 90 90 8B CE E8 A8 E8 B3 FF BA 00 00 00 00 E9 54 FB B3 FF
E8 + 77 + 4B + 7B + FF + 39 + AE + 30 + 03 + 00 + 00 + 90 + 90 + 8B + CE + E8 + A8 + E8 + B3 + FF + BA + 00 + 00 + 00 + 00 + E9 + 54 + FB + B3 + FF = 30 bytes
dSize = 30
Address = 0x85BE24 (6F85BE24 - 6F000000)
And we will write: "\xE8\x77\x4B\x7B\xFF\x39\xAE\x30\x03\x00\x00\x90\ x90\x8B\xCE\xE8\xA8\xE8\xB3\xFF\xBA\x00\x00\x00\x0 0\xE9\x54\xFB\xB3\xFF"
Code:
PATCH(0x85BE24,"\xE8\x77\x4B\x7B\xFF\x39\xAE\x30\x03\x00\x00\x90\x90\x8B\xCE\xE8\xA8\xE8\xB3\xFF\xBA\x00\x00\x00\x00\xE9\x54\xFB\xB3\xFF",30);
if(dSize == 0)
{
cout << "Failed to patch uselessblackground codecave." << endl;
}
NOTE: 0x85BE24 should be patched BEFORE 0x39B97D, else if the hack is started in-game, it could possibly crash (it could jump to the empty memory zone and the program will crash).
Let's then close the process handle and pause:
Code:
CloseHandle(hProc);
cout << "Done, goodbye!" << endl;
system("Pause");
exit(1);
}
else
{
cout << "Warcraft 3 could not be opened..." << endl;
system("Pause");
exit(0);
}
}
}
If you tried copy/pasting all the stuff I wrote so far you might encounter some problems compiling unless you have programming experience and know what you are doing.
Here is the full source:
Code:
#include <windows.h>
#include <Tlhelp32.h>
#include <cstdlib>
#include <iostream>
DWORD GetPIDForProcess (char* process);
void EnableDebugPriv();
DWORD GetDLLBase(char* DllName, DWORD tPid);
#define PATCH(i,w,l) WriteProcessMemory(hProc,reinterpret_cast<LPVOID>(gameBase+i),w,l,&dSize)
using namespace std;
int main()
{
if(GetPIDForProcess("WAR3.EXE") == 0)
{
cout <<"Could not find Warcraft 3 process." << endl;
system("Pause");
exit(0);
}
else
{
EnableDebugPriv();
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, GetPIDForProcess("WAR3.EXE"));
if(hProc)
{
DWORD gameBase = GetDLLBase("Game.dll",GetPIDForProcess("WAR3.EXE"));
DWORD dSize = 0;
PATCH(0x85BE24,"\xE8\x77\x4B\x7B\xFF\x39\xAE\x30\x03\x00\x00\x90\x90\x8B\xCE\xE8\xA8\xE8\xB3\xFF\xBA\x00\x00\x00\x00\xE9\x54\xFB\xB3\xFF",30);
if(dSize == 0)
{
cout << "Failed to patch uselessblackground codecave." << endl;
}
PATCH(0x39B97D,"\xE9\xA2\x04\x4C\x00",5);
if(dSize == 0)
{
cout << "Failed to patch uselessblackground jump to codecave." << endl;
}
cout << "Hack injected with success." << endl;
CloseHandle(hProc);
system("Pause");
exit(1);
}
else
{
cout << "Hack failed to inject." << endl;
system("Pause");
exit(0);
}
}
}
DWORD GetPIDForProcess (char* process)
{
BOOL working=0;
PROCESSENTRY32 lppe= {0};
DWORD targetPid=0;
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS ,0);
if (hSnapshot)
{
lppe.dwSize=sizeof(lppe);
working=Process32First(hSnapshot,&lppe);
while (working)
{
if(_stricmp(lppe.szExeFile,process)==0)
{
targetPid=lppe.th32ProcessID;
break;
}
working=Process32Next(hSnapshot,&lppe);
}
}
CloseHandle( hSnapshot );
return targetPid;
}
void EnableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
return;
if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) ){
CloseHandle( hToken );
return;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
CloseHandle( hToken );
}
DWORD GetDLLBase(char* DllName, DWORD tPid)
{
HANDLE snapMod;
MODULEENTRY32 me32;
if (tPid == 0) return 0;
snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, tPid);
me32.dwSize = sizeof(MODULEENTRY32);
if (Module32First(snapMod, &me32)){
do{
if (strcmp(DllName,me32.szModule) == 0){
CloseHandle(snapMod);
return (DWORD) me32.modBaseAddr;
}
}while(Module32Next(snapMod,&me32));
}
CloseHandle(snapMod);
return 0;
}
Copy paste this, compile and run to see if it works.