diff options
| author | Hunter Kvalevog <hunter@kvog.sh> | 2026-06-18 14:16:07 -0500 |
|---|---|---|
| committer | Hunter Kvalevog <hunter@kvog.sh> | 2026-06-18 19:42:55 -0500 |
| commit | f5f267418f27c26e87074ba2ab74d2913932c67f (patch) | |
| tree | 7b488f2b547fb9371f379e86048507b57900c0cd /mempoke | |
| parent | 118647ee2e1f7a5fc7250a0cbfca986340be2988 (diff) | |
Diffstat (limited to 'mempoke')
| -rwxr-xr-x | mempoke/build.sh | 4 | ||||
| -rw-r--r-- | mempoke/mempoke-injector.c | 153 | ||||
| -rw-r--r-- | mempoke/mempoke-target.c | 67 |
3 files changed, 224 insertions, 0 deletions
diff --git a/mempoke/build.sh b/mempoke/build.sh new file mode 100755 index 0000000..ed4c5a8 --- /dev/null +++ b/mempoke/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +mkdir -p bin +cc -o bin/mempoke-target -Wall -Wextra -Wpedantic -O0 -g ./mempoke-target.c +cc -o bin/mempoke-injector -Wall -Wextra -Wpedantic -O0 -g ./mempoke-injector.c diff --git a/mempoke/mempoke-injector.c b/mempoke/mempoke-injector.c new file mode 100644 index 0000000..2d1c4a9 --- /dev/null +++ b/mempoke/mempoke-injector.c @@ -0,0 +1,153 @@ +// ================================================================================================ +// Example showing how to read/write process memory remotely. +// +// License: +// Copyright (c) 2026 Hunter Kvalevog +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE. +// ================================================================================================ + +#define _GNU_SOURCE + +#ifdef _WIN32 +# include <windows.h> +# include <psapi.h> +# include <tlhelp32.h> +#endif + +#ifdef __linux__ +# include <dirent.h> +# include <sys/uio.h> +#endif + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct ProcessHandle ProcessHandle; +struct ProcessHandle +{ + int pid; + uintptr_t base; +#ifdef _WIN32 + HANDLE handle; +#endif +}; + +static inline void open_target_process(ProcessHandle *p) +{ +#ifdef _WIN32 + // ref: https://docs.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + assert(snap != INVALID_HANDLE_VALUE); + + PROCESSENTRY32 pe = { .dwSize = sizeof(PROCESSENTRY32) }; + Process32First(snap, &pe); + + do { + if (!strcmp(pe.szExeFile, "mempoke-target.exe")) { + p->pid = pe.th32ProcessID; + p->handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, p->pid); + assert(p->handle && "failed to open process"); + + // First module is always the exe itself + HMODULE exe = 0; + DWORD needed = 0; + if (!EnumProcessModules(p->handle, &exe, sizeof(exe), &needed)) { + assert(0 && "EnumProcessModules failed"); + } + p->base = (uintptr_t)exe; + + return; + } + } while (Process32Next(snap, &pe)); +#endif +#ifdef __linux__ + DIR *proc = opendir("/proc"); + + struct dirent *d; + while ((d = readdir(proc))) { + pid_t pid = (pid_t)atoi(d->d_name); + if (pid <= 0) + continue; + + char comm[256]; + snprintf(comm, sizeof(comm), "/proc/%d/comm", pid); + + FILE *f = fopen(comm, "r"); + if (!f) + continue; + + if (fgets(comm, sizeof(comm), f) && !strncmp(comm, "mempoke-target", 14)) { + p->pid = pid; + + char maps_path[64]; + snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps", p->pid); + + FILE *maps = fopen(maps_path, "r"); + fscanf(maps, "%" SCNxPTR "-", &p->base); + fclose(maps); + fclose(f); + return; + } + + fclose(f); + } +#endif + assert(0 && "couldn't find process"); +} + +int main(int argc, const char **argv) +{ + const uintptr_t offset = (argc > 1) ? strtoull(argv[1], 0, 0) : 0; + if (!offset) { + printf("Usage: %s <offset>\n example: %s 0x1234\n", argv[0], argv[0]); + return 1; + } + + ProcessHandle p; + open_target_process(&p); + + printf("target process: pid=%d base=0x%" PRIxPTR "\n", p.pid, p.base); + + int num = 0; + uintptr_t tgt = p.base + offset; + +#ifdef _WIN32 + if (!ReadProcessMemory(p.handle, (LPCVOID)tgt, &num, sizeof(num), 0)) { + assert(0 && "ReadProcessMemory failed"); + } +#endif +#ifdef __linux__ + struct iovec iov_rsrc = { .iov_base = (void *)tgt, .iov_len = sizeof(num) }; + struct iovec iov_rdst = { .iov_base = &num, .iov_len = sizeof(num) }; + if (process_vm_readv(p.pid, &iov_rdst, 1, &iov_rsrc, 1, 0) != sizeof(num)) { + assert(0 && "process_vm_readv failed"); + } +#endif + + printf("tgtnum = %d\n", num); + + num += 1; + +#ifdef _WIN32 + if (!WriteProcessMemory(p.handle, (LPVOID)tgt, &num, sizeof(num), 0)) { + assert(0 && "WriteProcessMemory failed"); + } +#endif +#ifdef __linux__ + struct iovec iov_wsrc = { .iov_base = &num, .iov_len = sizeof(num) }; + struct iovec iov_wdst = { .iov_base = (void *)tgt, .iov_len = sizeof(num) }; + if (process_vm_writev(p.pid, &iov_wsrc, 1, &iov_wdst, 1, 0) != sizeof(num)) { + assert(0 && "process_vm_writev failed"); + } +#endif +} + diff --git a/mempoke/mempoke-target.c b/mempoke/mempoke-target.c new file mode 100644 index 0000000..2c34780 --- /dev/null +++ b/mempoke/mempoke-target.c @@ -0,0 +1,67 @@ +// ================================================================================================ +// Example showing how to read/write process memory remotely. +// +// License: +// Copyright (c) 2026 Hunter Kvalevog +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE. +// ================================================================================================ + +#ifdef _WIN32 +# include <windows.h> +#endif + +#ifdef __linux__ +# include <unistd.h> +#endif + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> + +int tgtnum = 1; + +static inline uintptr_t get_process_base_address(void) +{ + uintptr_t base = 0; +#ifdef _WIN32 + base = (uintptr_t)GetModuleHandleW(0); +#endif +#ifdef __linux__ + FILE *maps = fopen("/proc/self/maps", "r"); + fscanf(maps, "%" SCNxPTR "-", &base); + fclose(maps); +#endif + assert(base); + return base; +} + +static inline void sleep_ms(unsigned ms) +{ +#ifdef _WIN32 + Sleep(ms); +#endif +#ifdef __linux__ + usleep(ms * 1000); +#endif +} + +int main(int argc, const char **argv) +{ + (void)argc; + (void)argv; + + printf("offset: 0x%" PRIxPTR "\n", (uintptr_t)&tgtnum - get_process_base_address()); + sleep_ms(3000); + + while (1) { + sleep_ms(1000); + printf("tgtnum: %d\n", tgtnum); + } +} + |