How to fix a Access Violation Error for thread hijacking technique?

-3

I'm fairly new to thread injection and am learning the technique through a book called "Game Hacking: Developing Autonomous Bot for Online Games." Chapter 7 highlights 3 injection techniques (thread injection, thread hijacking, and DLL injection).

Currently, I'm having trouble getting my thread hijacking code to work, because I keep running into an Access Violation Error when running my code. I've tried running as admin and the error still persists. Could anyone sift through my code and give me a reason why this error keeps popping up? I'm using Visual Studios 2019.

Exception thrown at 0x00000024 in GameHacking.exe: 0xC0000005: Access violation executing location 0x00000024.

Thanks and Happy Halloween!

#include <windows.h>
#include <tlhelp32.h>
#include <string>

using namespace std;

// function being referenced by injector
DWORD printStringManyTimes(int times, const char* string)
{
    for (int i = 0; i < times; i++)
        printf(string);
    return 0;
}

// THIS FUNCTION WORKS JUST FINE
void injectCodeUsingThreadInjection(HANDLE process, LPVOID func, int times, const char* string)
{
    BYTE codeCave[20] = {
        0xFF, 0x74, 0x24, 0x04, // PUSH DWORD PTR[ESP+0x4]
        0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
        0xB8, 0x00, 0x00, 0x00, 0x00, // MOV EAX, 0x0
        0xFF, 0xD0, // CALL EAX
        0x83, 0xC4, 0x08, // ADD ESP, 0x08
        0xC3 // RETN
    };

    // copy values to the shellcode
    memcpy(&codeCave[5], &times, 4);
    memcpy(&codeCave[10], &func, 4);


    // allocate memory for the code cave
    int stringlen = strlen(string) + 1;
    int fulllen = stringlen + sizeof(codeCave);
    LPVOID remoteString = VirtualAllocEx(process, NULL, fulllen, MEM_COMMIT, PAGE_EXECUTE);
    LPVOID remoteCave = (LPVOID)((DWORD)remoteString + stringlen);

    if (remoteString) {
        // write the code cave
        WriteProcessMemory(process, remoteString, string, stringlen, NULL);
        WriteProcessMemory(process, remoteCave, codeCave, sizeof(codeCave), NULL);

        // run the thread
        HANDLE thread = CreateRemoteThread(process, NULL, NULL,
            (LPTHREAD_START_ROUTINE)remoteCave,
            remoteString, NULL, NULL);
        WaitForSingleObject(thread, INFINITE);
        VirtualFreeEx(process, remoteString, fulllen, MEM_RELEASE);
        CloseHandle(thread);
    }   
}


// I know this function is redundant because the PID is already 
// found in the main function, but I wanted to first copy what 
// the book outlines in order to test how it works
DWORD GetProcessThreadID(HANDLE Process)
{
    THREADENTRY32 entry;
    entry.dwSize = sizeof(THREADENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

    if (Thread32First(snapshot, &entry) == TRUE)
    {
        DWORD PID = GetProcessId(Process);
        while (Thread32Next(snapshot, &entry) == TRUE)
        {
            if (entry.th32OwnerProcessID == PID)
            {
                CloseHandle(snapshot);
                return entry.th32ThreadID;
            }
        }
    }
    CloseHandle(snapshot);
    return NULL;
}

// THIS IS THE FUNCTION GIVING ME PROBLEMS
void injectCodeUsingThreadHijacking(HANDLE process, LPVOID func, int times, const char* string) {
    BYTE codeCave[31] = {
        0x06, //PUSHAD
        0x9C, //PUSHFD
        0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
        0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
        0xB8, 0x00, 0x00, 0x00, 0x00, // MOV EAX, 0x0
        0xFF, 0xD0, // CALL EAX
        0x83, 0xC4, 0x08, // ADD ESP, 0x08
        0x9D, //POPFD
        0x61, //POPAD
        0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
        0xC3 // RETN
    };

    // allocate memory for the code cave
    int stringlen = strlen(string) + 1;
    int fulllen = stringlen + sizeof(codeCave);
    LPVOID remoteString = VirtualAllocEx(process, NULL, fulllen, MEM_COMMIT, PAGE_EXECUTE);
    LPVOID remoteCave = (LPVOID)((DWORD)remoteString + stringlen);

    // suspend the thread and query its control context
    DWORD threadID = GetProcessThreadID(process);
    HANDLE thread = OpenThread(THREAD_ALL_ACCESS, false, threadID); //(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT)
    SuspendThread(thread);

    CONTEXT threadContext;
    threadContext.ContextFlags = CONTEXT_CONTROL;
    GetThreadContext(thread, &threadContext);

    // copy values to the shellcode (happens late because we need values from allocation)
    memcpy(&codeCave[3], &remoteString, 4);
    memcpy(&codeCave[8], &times, 4);
    memcpy(&codeCave[13], &func, 4);
    memcpy(&codeCave[25], &threadContext.Eip, 4);

    // write the code cave
    WriteProcessMemory(process, remoteString, string, stringlen, NULL);
    WriteProcessMemory(process, remoteCave, codeCave, sizeof(codeCave), NULL);

    //hijack the thread
    threadContext.Eip = (DWORD)remoteCave;
    threadContext.ContextFlags = CONTEXT_CONTROL;
    SetThreadContext(thread, &threadContext);
    ResumeThread(thread);

    //clean
    CloseHandle(thread);
}

DWORD WINAPI hijackThread(LPVOID lpParam)
{
    injectCodeUsingThreadHijacking((HANDLE)lpParam, &printStringManyTimes, 2, "hijacked\n");
    return 1;
}


int main() {
    string myTitle;

    cout << "What is the process you are looking for? ";
    cin >> myTitle;

    DWORD PID = -1;
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == true) {
        while (Process32Next(snapshot, &entry) == true) {
            cout << entry.szExeFile << endl;
            string binPath = entry.szExeFile;
            if (binPath.find(myTitle) != string::npos) {
                cout << endl << myTitle << " has the pid " << entry.th32ProcessID << endl;
                PID = entry.th32ProcessID;
                break;
            }
        }
    }
    if (PID == -1) {
        printf("\n%s was not found in the process list.\n", myTitle);
        return -1;
    }
    CloseHandle(snapshot);

    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    if (process == INVALID_HANDLE_VALUE) {
        printf("Failed to open PID %d, error code %lu", PID, GetLastError());
    }

    // Inject code into self using thread injection
    injectCodeUsingThreadInjection(process,&printStringManyTimes, 2, "injected\n");

    // inject code into self using thread hijacking
    //   we need to do it from a secondary thread or else
    //   the hijacking code would hijack itself.. which
    //   doesn't work
    CreateThread(NULL, 0, hijackThread, process, 0, NULL);

    while (true) {
        Sleep(100);
    }

    CloseHandle(process);
    return 0;
}
c++
multithreading
code-injection
asked on Stack Overflow Nov 1, 2020 by LunarManure

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0