9
\$\begingroup\$

This is a simple speed hack I created for Call of Duty World at War. It uses a pointer, SPEED_ADDRESS with an offset, SPEED_OFFSET1 to find the address I intend to write to. I'm not very well versed in using offsets. The code I provided does work, but I feel there's probably a better way of dealing with offsets. For instance, I'm using #define constants for storing the offset - is that a bad approach?

And just so everyone knows, I've only done this on single-player mode, and it probably only works in single-player mode.

Source.cpp

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>

#define PROCESS_NAME "CoDWaW.exe"
#define POLL_RATE 100

#define SPEED_MODULE_NAME "CoDWaW.exe"
#define SPEED_ADDRESS 0x014ECF50
#define SPEED_OFFSET1 0x10

DWORD get_module_pointer(LPSTR module_name_, DWORD process_id_)
{ 
        MODULEENTRY32 module_entry = {sizeof(MODULEENTRY32)};
        HANDLE modules_snapshot;
        DWORD module_pointer = 0;

        modules_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process_id_);
        if (Module32First(modules_snapshot, &module_entry))
        {
            do
            {
                if(!strcmp(module_entry.szModule, module_name_))
                {
                    module_pointer = (DWORD)module_entry.modBaseAddr;
                    break;
                }
            } while (Module32Next(modules_snapshot, &module_entry));
        }

        // clean up resources
        CloseHandle(modules_snapshot);

        return module_pointer;
}

DWORD get_process_id_by_process_name(const char* process_name_)
{
    PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
    HANDLE processes_snapshot;
    DWORD process_id = 0;

    // search for the process name
    processes_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (Process32First(processes_snapshot, &process_entry))
    {
        do
        {
            if (!strcmp(process_entry.szExeFile, process_name_))
            {
                process_id = process_entry.th32ProcessID;
                break;
            }
        } while (Process32Next(processes_snapshot, &process_entry));
    }

    // clean up resources
    CloseHandle(processes_snapshot);

    return process_id;
}

int main(int argc_, char** argv_)
{
    // get the handle to the game
    std::cout << "Retrieving handle to game." << std::endl;
    DWORD process = NULL;
    while (process == NULL)
    {
        process = get_process_id_by_process_name(PROCESS_NAME);
    }

    HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process);

    // check if a valid handle was obtained
    if (process_handle != NULL)
    {
        bool speed_hack_on = false;

        while (true)
        {
            system("cls");
            std::cout << "Call of Duty World at War Speed Hack 2" << std::endl;
            std::cout << "======================================" << std::endl;
            std::cout << " F10.) - Set Player Speed to " << (speed_hack_on ? "190" : "800") << std::endl;

            SHORT keypress;

            keypress = GetAsyncKeyState(VK_F10);
            if (keypress)
            {
                speed_hack_on = !speed_hack_on;

                // get initial module address
                DWORD module_address = get_module_pointer(SPEED_MODULE_NAME, process);

                // add to the module address, the speed pointer address
                DWORD speed_pointer_address = module_address + SPEED_ADDRESS;

                // read whats at the speed_pointer_address
                DWORD read_buffer;
                ReadProcessMemory(process_handle, (LPVOID)speed_pointer_address, &read_buffer, sizeof(read_buffer), NULL);

                // apply the offset to what is found in the read_buffer
                DWORD speed_address = read_buffer + SPEED_OFFSET1;

                // speed_address is now the actual speed address we want to write to
                if (speed_hack_on)
                {
                    int write_value = 800;
                    WriteProcessMemory(process_handle, (LPVOID)speed_address, &write_value, sizeof(write_value), NULL);
                }
                else
                {
                    int write_value = 190;
                    WriteProcessMemory(process_handle, (LPVOID)speed_address, &write_value, sizeof(write_value), NULL);
                }
            }
        }
    }
}
\$\endgroup\$
13
\$\begingroup\$

Do your pointer arithmetic on pointer types

Working with pointer offsets is best done using char* instead of DWORD. This way, you know that the size of the pointer will be set to whatever architecture you are compiling against, instead of assuming that you will always be dealing with the lower 4Gb of memory.

Do as little work as possible in you inner loop

Why are you calling get_module_pointer() every single time the hack is triggered?

You should resolve the address once, and then just reuse the same pointer over and over again.

Just use typed constants

Instead of using defines, just use const variables, it's basically the same thing, but you can put move them inside of a namespace if/when you want.

#define PROCESS_NAME "CoDWaW.exe"
#define POLL_RATE 100

#define SPEED_MODULE_NAME "CoDWaW.exe"
#define SPEED_ADDRESS 0x014ECF50
#define SPEED_OFFSET1 0x10

becomes:

const char* const PROCESS_NAME "CoDWaW.exe"
const int POLL_RATE 100

const char* const SPEED_MODULE_NAME = "CoDWaW.exe"
char* const SPEED_ADDRESS = 0x014ECF50
const std::ptr_diff_t SPEED_OFFSET1 = 0x10
\$\endgroup\$
  • \$\begingroup\$ Since this is C++ code it would make more sense to use constexpr variables instead of const; they are closer to C macros (which aren't the same thing as const variables). \$\endgroup\$ – John Doe Nov 21 '17 at 8:00
  • \$\begingroup\$ @JohnDoe OP has made no indication as to which version of the standard he's operating under, so I chose to be a bit conservative. It's also worth noting that constexpr does literally nothing in this context. It's only useful if the constant is being computed. \$\endgroup\$ – Frank Nov 21 '17 at 8:11
  • 1
    \$\begingroup\$ const int a, unless static or optimized out, is a symbol named a which exists in a symbol table and occupies a location in memory. constexpr int a is a constant expression which is used "in place". Usually it does not allocate any storage (although it's not guaranteed). \$\endgroup\$ – John Doe Nov 21 '17 at 9:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.