Phil CK

Access Process Memory

Last updated on

Accessing data from another process on Windows is quite easy. This is quite handy for debugging, I’m currently trying to create a tool to inspect the state of another app. In my case I have a console app, which I want a Debug GUI for.

Say I have an app with a struct holding some data like this.

struct foo {
    uint64_t id;
    int data_a;
    int data_b;
    int data_c;
};

// Lets say we initialized it like this.

struct foo f = {
    .id = 13909120352667777000,
    .data_a = 123,
    .data_b = 234,
    .data_c = 345
};

Now if a process (app) has this data in memory, we can use another app to scan for 13909120352667777000, then we can pull out the location in memory of the struct.


#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>

#pragma comment(lib, "psapi")

int main()
{   
        /* Setup */

        HANDLE token_handle = NULL;

        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token_handle)) {
                printf("Failed OpenProcessToken\n");
                return EXIT_FAILURE;
        }

        LUID luid = {0};

        if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
                printf("Failed LookupPrivilegeValue\n");
                return EXIT_FAILURE;
        }

        TOKEN_PRIVILEGES tp = {
                .PrivilegeCount = 1,
                .Privileges[0].Luid = luid,
                .Privileges[0].Attributes = SE_PRIVILEGE_ENABLED,
        };

        if (!AdjustTokenPrivileges(token_handle, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)) {
                printf("Failed AdjustTokenPrivileges\n");
                return EXIT_FAILURE;
        }

        PROCESSENTRY32 pe32 = {
                .dwSize = sizeof(pe32),
        };
        
        HANDLE hsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
        if(Process32First( hsnapshot, &pe32 ) ) {
                do {
                        if(strcmp( pe32.szExeFile, "pod_game_loop_func_test.exe" ) == 0)
                        break;
                } while( Process32Next(hsnapshot, &pe32 ));
        }
    
        if(hsnapshot != INVALID_HANDLE_VALUE) {
                CloseHandle( hsnapshot );
        }
        
        /* PID and handle */

        DWORD pid = pe32.th32ProcessID;
        HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_VM_READ , FALSE, pid);
    
        /* Search for data */

        MEMORY_BASIC_INFORMATION mbi = {0};
        unsigned char* addr = 0;

        uint64_t find = 13909120352667777000; /* searching for this value */

        while(VirtualQueryEx(phandle, addr, &mbi, sizeof(mbi)))
        {
                DWORD skip_flags = PAGE_NOACCESS | PAGE_GUARD;

                if(mbi.State == MEM_COMMIT && !(mbi.Protect & skip_flags))
                {
                        /* Output some info about this region of memory */

                        if (mbi.Protect & PAGE_READONLY) {
                                printf("R,");
                        }
                        if (mbi.Protect & PAGE_READWRITE) {
                                printf("RW,");
                        }

                        printf(" - Base Address %p, Reigion Size %d\n", mbi.BaseAddress, (int)mbi.RegionSize);

                        /* Search for the value we are after */

                        unsigned char *curr = addr;
                        unsigned char *end = curr + mbi.RegionSize;

                        while(curr && curr < end) {

                                struct cast {
                                        uint64_t guid;
                                        int a;
                                        int b;
                                        int c;
                                };

                                struct cast c = {0};
                                SIZE_T str_size = sizeof(c);
                                SIZE_T read = 0;

                                (void)ReadProcessMemory(phandle, (BYTE*)curr, &c, str_size, &read);

                                if(find == c.guid) {
                                        printf("\nFound %d %d %d\n", c.a, c.b, c.c);
                                }

                                curr += 1; /* move by one byte */
                        }

                }

                addr += mbi.RegionSize;
        }
    
        return 0;
}