Program Error When Writing Memory Addresses To Game

I made this program to give me Unlimited health and Unlimited Ammo using offsets.

The error is when I launch the game and click the key bind to change the offsets values to my desired value the game crashes and I have no clue why. I tried to see if the games offsets weren't right. But still doesn't work.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <ctime>

DWORD FindDmaAddy(int PointerLevel, HANDLE hProcHandle, DWORD Offsets[], DWORD BaseAddress);
void WriteToMemory(HANDLE hProcHandle);


std::string GameName = "AssaultCube";
LPCSTR LGameWindow = "AssaultCube";
std::string GameStatus;

bool IsGameAvail;
bool UpdateOnNextRun;

//AMMO VARS
bool AmmoStatus = false; 
BYTE AmmoValue[] = { 0x64 };
DWORD AmmoBaseAddress = { 0x00509B74 };
DWORD AmmoOffsets[] = { 0x0, 0x14, 0x384};

//HEALTH VARS
bool HealthStatus = false;
BYTE HealthValue[] = { 0x39, 0x5, 0x0, 0x0 };
DWORD HealthBaseAddress = { 0x00509B74 };
DWORD HealthOffsets[] = { 0xF8 };


int main() {
	HWND hGameWindow = NULL;
	int timeSinceLastUpdate = clock();
	int GameAvailTMR = clock();
	int onePressTMR = clock();

	DWORD dwProcID = NULL;
	HANDLE hProcHandle = NULL;
	UpdateOnNextRun = true;
	std::string sAmmoStatus = "OFF";
	std::string sHealthStatus = "OFF";

	while (!GetAsyncKeyState(VK_INSERT))
	{
		if (clock() - GameAvailTMR > 100)
		{
			GameAvailTMR = clock();
			IsGameAvail = false;

			hGameWindow = FindWindow(NULL, LGameWindow);
			if (hGameWindow)
			{
				GetWindowThreadProcessId(hGameWindow, &dwProcID);
				if (dwProcID != 0)
				{
					hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcID);
					if (hProcHandle == INVALID_HANDLE_VALUE || hProcHandle == NULL)
					{
						GameStatus = "Failed to open process for valid handle";
					}
					else
					{
						GameStatus = "AssaultCube Ready to hack";
						IsGameAvail = true;
					}
				}
				else
				{
					GameStatus = " Failed to get process ID";
				}
			}
			else
			{
				GameStatus = "AssaultCube Not Found";
			}

			if (UpdateOnNextRun || clock() - timeSinceLastUpdate > 5000)
			{
				system("cls");
				std::cout << "--------------------------------------------------------" << std::endl;
				std::cout << "              AssaultCube Memory Hacker" << std::endl;
				std::cout << "--------------------------------------------------------" << std::endl << std::endl;
				std::cout << "GAME STATUS: " << GameStatus << std::endl << std::endl;
				std::cout << "[F1] Unlmited Ammo ->" << sAmmoStatus << " <- " << std::endl << std::endl;
				std::cout << "[F2] Unlmited Health ->" << sHealthStatus << " <- " << std::endl << std::endl;
				std::cout << "[INSERT] Exit" << std::endl;
				UpdateOnNextRun = false;
				timeSinceLastUpdate = clock();
			}

			if (IsGameAvail)
			{
				WriteToMemory(hProcHandle);
			}
		}
		if (clock() - onePressTMR > 400)
		{
			if (IsGameAvail)
			{
				//ammo
				if (GetAsyncKeyState(VK_F1))
				{
					onePressTMR = clock();
					AmmoStatus = !AmmoStatus;
					UpdateOnNextRun = true;
					if (AmmoStatus)sAmmoStatus = "ON";
					else sAmmoStatus = "OFF";
				}
				//health
				else if (GetAsyncKeyState(VK_F2))
				{
					onePressTMR = clock();
					HealthStatus = !HealthStatus;
					UpdateOnNextRun = true;
					if (HealthStatus)sHealthStatus = "ON";
					else sHealthStatus = "OFF";
				}
			}
		}
	}
	CloseHandle(hProcHandle);
	CloseHandle(hGameWindow);

	return ERROR_SUCCESS;


}

DWORD FindDmaAddy(int PointerLevel, HANDLE hProcHandle, DWORD Offsets[], DWORD BaseAddress)
{
	DWORD pointer = BaseAddress;
	DWORD  pTemp;

	DWORD pointerAddr;
	for (int c = 0; c < PointerLevel; c++)
	{
		if (c == 0)
		{
			ReadProcessMemory(hProcHandle, (LPCVOID)pointer, &pTemp, sizeof(pTemp), NULL);
		}
		pointerAddr = pTemp + Offsets[c];
		ReadProcessMemory(hProcHandle, (LPCVOID)pointer, &pTemp, sizeof(pTemp), NULL);

	}
	return pointerAddr;

}

void WriteToMemory(HANDLE hProcHandle)
{
	DWORD AddressToWrite;
	if (AmmoStatus)
	{
		AddressToWrite = FindDmaAddy(3, hProcHandle, AmmoOffsets, AmmoBaseAddress);
		WriteProcessMemory(hProcHandle, (BYTE*)AddressToWrite, &AmmoValue, sizeof(AmmoValue), NULL);

	}
	if (HealthStatus)
	{
		AddressToWrite = FindDmaAddy(3, hProcHandle, HealthOffsets, HealthBaseAddress);
		WriteProcessMemory(hProcHandle, (BYTE*)AddressToWrite, &HealthValue, sizeof(HealthValue), NULL);
	}
}



Last edited on
You've got a lot more work to do here OP. Assault Cube is open source, it would literally be easier to recompile this program with your changes then continue on this course of action. That being said, for academic purposes, let's dig in.

You should inject this as a DLL for it to be able to write to the game, nothing about this is "industry standard" but if it were, that's the correct way to do it. This technique seems like it's well documented but the truth is that all of the most popular articles are out of date and won't get you much further than say XP SP2. So the first question is what version of Windows are you running? We have to disable some critical security features so make a backup of your system before going on.

If your running anything later than Windows Vista, you have to run your application from an elevated command prompt and turn on the SE_DEBUG permissions flag. You'll be building two projects with this approach. One is your DLL with more or less the same code you have here with some changes to make it a DLL stub1 instead of a stand alone executable2. This is the very first function that your injector should call:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
HANDLE ActivatePrivilege(TCHAR* Privilege, DWORD ProcID = GetCurrentProcessId())
{
    //std::cout << ProcID << std::endl;

    HANDLE hBasic = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, ProcID);
    //HANDLE hBasic = OpenProcess(TOKEN_ADJUST_PRIVILEGES, TRUE, ProcID);

    HANDLE hOwnProc = NULL;
    HANDLE* hProcToken = new HANDLE;

    LUID PrivilegeUID;

    PLUID_AND_ATTRIBUTES pAddPrivilegeAttribute = new LUID_AND_ATTRIBUTES;

    TOKEN_PRIVILEGES NewTPriv;
        NewTPriv.PrivilegeCount = 1;
        NewTPriv.Privileges[0]  = *pAddPrivilegeAttribute;


    try
    {
        if(hBasic == NULL)
        {
            throw "FAILED TO OPEN TARGET PROCESS ";
        }

        if(!OpenProcessToken(hBasic, TOKEN_ADJUST_PRIVILEGES, hProcToken))
        {
            throw "FAILED TO OPEN TARGET PROCESS WITH TOKEN ADJUSTMENT PRIVILEGES ";
        }

        if(!LookupPrivilegeValue(NULL, Privilege, &PrivilegeUID))
        {
            throw "FAILED TO LOOKUP PRIVILEGE ";
        }


        NewTPriv.Privileges[0].Luid = PrivilegeUID;
        NewTPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;


        if(!AdjustTokenPrivileges(*hProcToken, FALSE, &NewTPriv, 0, NULL, NULL))
        {
            std::cout << "FAILED TO ADJUST TOKEN " << GetLastError();// << "\n\n";
        }

        switch(GetLastError())
        {
            case ERROR_SUCCESS:
            {
                std::cout << "ERROR_SUCCESS! " << Privilege << " ACTIVATED!\n\n";
                break;
            }

            case ERROR_NOT_ALL_ASSIGNED:
            {
                std::cout << "FAILED TO ASSIGN " << Privilege << " TO " << ProcID << "\n";

                break;
            }

            default:
            {
                throw "Unknown Error While Adjusting Privileges: ";
            }
        }
    }
    catch(char* Msg)
    {
        std::cout << "\nActivatePrivilege " << Msg << "ERROR CODE: " << GetLastError() << "\tProcess ID: " << ProcID << std::endl;
        pause();
    }

    //hOwnProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcID);
    hOwnProc = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, ProcID);

    CloseHandle(*hProcToken);
    CloseHandle(hBasic);

    delete pAddPrivilegeAttribute;

    return hOwnProc;
}


Take some time to actually study this code since you're here to learn something. You'll notice two things, first is that this function is more dynamic than you need in that it allows you to activate any privilege available to your injector. The TCHAR array you want to pass in as the first parameter is "SeDebugPrivilege". The second thing you'll notice is that you require a function called "GetProcessID()" for this to work. Here's what that looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
DWORD  GetProcessID(std::string ProcName)
{
    HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    for(unsigned i = 0; i < ProcName.size(); ++i)
    {
        ProcName[i] = tolower(ProcName[i]);
    }

    PROCESSENTRY32 pEntry;
        pEntry.dwSize = sizeof(PROCESSENTRY32);

    if(Process32First(SnapShot, &pEntry) == FALSE)
    {
        std::cout << "FAILED TO FIND FIRST ENTRY: " << GetLastError() << std::endl;

        return NULL;
    }

    do
    {
        std::string EntryName = pEntry.szExeFile;

        for(unsigned i = 0; i < EntryName.size(); ++i)
        {
            EntryName[i] = tolower(EntryName[i]);
        }

        if(ProcName.compare(EntryName) == 0)
        {
            CloseHandle(SnapShot);

            //StealIdentity();

            return pEntry.th32ProcessID;
        }
    }while(Process32Next(SnapShot, &pEntry));

    CloseHandle(SnapShot);

    return pEntry.th32ProcessID;
}


Sine we will be writing into the memory space of another process, we'll also need that processes HANDLE. You get this by calling the "OpenProcess()"3 function and passing in the process ID that we grabbed earlier with 'PROCESS_ALL_ACCESS' as the first parameter.

Let me know when you when you have your DLL stub ready, we can go on from here.

1: https://msdn.microsoft.com/en-us/library/ms235636.aspx

2: ASLR, Address Space Layout Randomization, is going to kick you in the rear here because your statically assigning the addresses to write to. I suggest turning it off because from what I can see, you've got about a week of development on your plate as it is.

3: OpenProcess() - https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx

EDIT: Here are the headers that you'll need
#include <windows.h>
#include <winbase.h>
#include <winnt.h>
#include <Tlhelp32.h>
#include <sddl.h>
#include <winuser.h>
#include <Sspi.h>
#include <Ntsecapi.h>
#include <Ntsecpkg.h>

And the libs:
AdvAPI32.Lib
User32.Lib
Secur32.Lib
Last edited on
Topic archived. No new replies allowed.