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;
}