2
\$\begingroup\$

Are there better ways to implement what I have done - a Console Memory Hacker for the game Call of Duty Black Ops single player mode. Comments, Performance, Style, anything. And, it needs Multi-Byte Character Set in properties to run without errors.

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

const char* PROCESS_NAME = "BlackOps.exe";
const unsigned short POLL_RATE = 100;

const unsigned int POINTS_ADDRESS = 0x01C0A6C8;
const unsigned int HEALTH_ADDRESS = 0x01A7987C;
const unsigned int CLIP_1_ADDRESS = 0x01C08F00;
const unsigned int AMMO_1_ADDRESS = 0x01C08E88;
const unsigned int CLIP_2_ADDRESS = 0x01C08F18;
const unsigned int AMMO_2_ADDRESS = 0x01C08E98;
const unsigned int GRENADES_ADDRESS = 0x01C08F08;

const unsigned int HACK_POINTS_VALUE = 100000;
const unsigned short HACK_HEALTH_VALUE = 1000;
const unsigned short HACK_CLIP_1_VALUE = 1000;
const unsigned short HACK_AMMO_1_VALUE = 1000;
const unsigned short HACK_CLIP_2_VALUE = 1000;
const unsigned short HACK_AMMO_2_VALUE = 1000;
const unsigned short HACK_GRENADES_VALUE = 10;

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 game process id
    std::cout << "Looking for game..." << std::endl;
    DWORD process_id = NULL;
    while (!process_id)
    {
        process_id = get_process_id_by_process_name(PROCESS_NAME);
        Sleep(POLL_RATE);
    }
    std::cout << "Game found." << std::endl;

    // open game handle
    HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);
    if (process_handle)
    {
        std::cout << "Handle obtained to game" << std::endl;
    }
    else
    {
        std::cout << "Handle not obtained to game." << std::endl;
        exit(1);
    }

    // initialize variables
    bool lock_points = false;
    bool lock_clip_1 = false;
    bool lock_ammo_1 = false;
    bool lock_clip_2 = false;
    bool lock_ammo_2 = false;
    bool lock_health = false;
    bool lock_grenades = false;

    bool update_screen = true;
    while (true)
    {
        // only update screen when needed
        if (update_screen)
        {
            system("cls");
            std::cout << "Call of Duty Black Ops Console Memory Hacker" << std::endl;
            std::cout << "============================================" << std::endl;
            std::cout << " [F1] - (" << (lock_points ? "on ": "off") << ") Lock Points to 100,000" << std::endl;
            std::cout << " [F2] - (" << (lock_clip_1 ? "on ": "off") << ") Lock Clip 1 to 1,000" << std::endl;
            std::cout << " [F3] - (" << (lock_ammo_1 ? "on ": "off") << ") Lock Ammo 1 to 1,000" << std::endl;
            std::cout << " [F4] - (" << (lock_clip_2 ? "on ": "off") << ") Lock Clip 2 to 1,000" << std::endl;
            std::cout << " [F5] - (" << (lock_ammo_2 ? "on ": "off") << ") Lock Ammo 2 to 1,000" << std::endl;
            std::cout << " [F6] - (" << (lock_health ? "on ": "off") << ") Lock Health to 1,000" << std::endl;
            std::cout << " [F7] - (" << (lock_grenades ? "on ": "off") << ") Lock Grenades to 10" << std::endl;
            update_screen = false;
        }

        // check for associated keystrokes to menu
        if (GetAsyncKeyState(VK_F1))
        {
            lock_points = !lock_points;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F2))
        {
            lock_clip_1 = !lock_clip_1;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F3))
        {
            lock_ammo_1 = !lock_ammo_1;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F4))
        {
            lock_clip_2 = !lock_clip_2;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F5))
        {
            lock_ammo_2 = !lock_ammo_2;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F6))
        {
            lock_health = !lock_health;
            update_screen = true;
        }
        if (GetAsyncKeyState(VK_F7))
        {
            lock_grenades = !lock_grenades;
            update_screen = true;
        }

        // perform hack(s) if they are activated
        if (lock_points)
        {
            unsigned int write_value = HACK_POINTS_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)POINTS_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_clip_1)
        {
            unsigned int write_value = HACK_CLIP_1_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)CLIP_1_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_ammo_1)
        {
            unsigned int write_value = HACK_AMMO_1_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)AMMO_1_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_clip_2)
        {
            unsigned int write_value = HACK_CLIP_2_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)CLIP_2_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_ammo_2)
        {
            unsigned int write_value = HACK_AMMO_2_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)AMMO_2_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_health)
        {
            unsigned int write_value = HACK_HEALTH_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)HEALTH_ADDRESS, &write_value, sizeof(write_value), NULL);
        }
        if (lock_grenades)
        {
            unsigned int write_value = HACK_GRENADES_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)GRENADES_ADDRESS, &write_value, sizeof(write_value), NULL);
        }

        // Delay for POLL_RATE before iterating again
        Sleep(POLL_RATE);
    }
}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Good naming of variables and constants.

DRY Code
Applying the DRY coding principle or Don't Repeat Yourself principle would greatly reduce the amount of code that this program has.

There are two very obvious candidates for functions in this program that would decrease the length of this program by at least 20 lines. Reducing the amount of code will make it easier to maintain and reduce the amount of debugging that might be necessary. There is a candidate for a loop as well.

The first candidate for a function is this code:

    // check for associated keystrokes to menu
    if (GetAsyncKeyState(VK_F1))
    {
        lock_points = !lock_points;
        update_screen = true;
    }

The second candidate for a function is this code:

        if (lock_points)
        {
            unsigned int write_value = HACK_POINTS_VALUE;
            WriteProcessMemory(process_handle, (LPVOID)POINTS_ADDRESS, &write_value, sizeof(write_value), NULL);
        }

Just pass in the lock, the address and the value to a function. Code quality is sometimes measured in errors per lines of code. The less code there is, the less the possible number of errors or bugs.

Possible Performance Optimization
The use of std::endl may be slowing the program down. It might be better to use '\n' in most cases. std::endl flushes the output buffer. Flushing the output buffer consumes time and is generally not necessary.

Portability
This may not matter in your particular use case.

Because of the choice of functions the code uses, this code can't port easily to other computers. The address constants may differ on other systems as well.

\$\endgroup\$
2
\$\begingroup\$

@pacmaninbw has gotten most of the issues I saw, but there are a few other things that should be noted.

  • Keep functions short and single-purpose.. Right now you've got all the code inside main(). Each function should have one purpose and do one thing (that makes it easier to test and replace). main should call these functions. Get the process id, get the handle, display the menu and status, poll the keyboard, write to memory according to settings -- each of these should be a separate function.

The menu also has repeated code and should be done with arrays and a loop

  • Keep related data in a data structure.

something like this:

struct hack {
    unsigned int hack_address;
    unsigned short hack_value;
    bool lock;
    string key_name;
    DWORD key_vt;
    string display_name;
};

Then you can declare an array of these:

hack hacktable[7] = {
    { // health
        0x01C0A6C8,
        1000,
        false,
        "F6",
        VT_F6,
        "Health" },
    { // ammo 1
        ...
    },
    ...
};

Then you can loop over this list for all the repeated stuff, either calling functions multiple times or looping within the function as appropriate.

\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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