This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <psapi.h> // for GetMappedFileName | |
#include <stdio.h> | |
static const struct memprot_name_type { | |
unsigned int value; | |
const char *short_name; | |
const char *desc; | |
} memprot_names[] = { | |
{PAGE_NOACCESS, "noa", "PAGE_NOACCESS (cannot dump)"}, | |
{PAGE_READONLY, "ro", "PAGE_READONLY"}, | |
{PAGE_READWRITE, "rw", "PAGE_READWRITE"}, | |
{PAGE_WRITECOPY, "wc", "PAGE_WRITECOPY"}, | |
{PAGE_EXECUTE, "x", "PAGE_EXECUTE (cannot dump)"}, | |
{PAGE_EXECUTE_READ, "rx", "PAGE_EXECUTE_READ"}, | |
{PAGE_EXECUTE_READWRITE, "rwx", "PAGE_EXECUTE_READWRITE"}, | |
{PAGE_EXECUTE_WRITECOPY, "xwc", "PAGE_EXECUTE_WRITECOPY"}, | |
{PAGE_GUARD, "g", "PAGE_GUARD (cannot dump)"}, | |
{PAGE_NOCACHE, "nc", "PAGE_NOCACHE"}, | |
{PAGE_WRITECOMBINE, "wb", "PAGE_WRITECOMBINE"}, | |
{PAGE_REVERT_TO_FILE_MAP, "f", "PAGE_REVERT_TO_FILE_MAP"}, | |
{0x40000000, "t", "PAGE_TARGETS_INVALID"}, | |
}; | |
const char *memprot_name (unsigned int mem_protect) | |
{ | |
static char buff[100]; | |
buff[0] = '\0'; | |
int i; | |
for (i = 0; i < sizeof(memprot_names) / sizeof(memprot_names[0]); i ++) { | |
if (memprot_names[i].value & mem_protect) { | |
if (buff[0]) | |
strncat(buff, ",", sizeof(buff)); | |
strncat(buff, memprot_names[i].short_name, sizeof(buff)); | |
} | |
} | |
return buff; | |
} | |
const char *memtype_name (unsigned int mem_type) | |
{ | |
switch (mem_type) { | |
case MEM_IMAGE: return "i"; | |
case MEM_MAPPED: return "m"; | |
case MEM_PRIVATE: return "p"; | |
default: return "?"; | |
} | |
} | |
int dump_to_file (HANDLE proc, char *addr, size_t size, const char *outpath) | |
{ | |
static char *buffer = NULL; | |
const int BUFFER_SIZE = 16 * 1024; | |
if (buffer == NULL) | |
buffer = malloc(BUFFER_SIZE); | |
FILE *fp = NULL; // delay file creation until first successful vm read | |
size_t curr = 0; | |
while (curr < size) { | |
size_t len = size - curr < BUFFER_SIZE ? size - curr : BUFFER_SIZE; | |
size_t bytes_read; | |
if (ReadProcessMemory(proc, addr + curr, buffer, len, &bytes_read) == 0) { | |
fprintf(stderr, "error: ReadProcessMemory %p error\n", addr + curr); | |
goto errout; | |
} | |
if (bytes_read != len) { | |
fprintf(stderr, "error: ReadProcessMemory %p error1\n", addr + curr); | |
goto errout; | |
} | |
if (fp == NULL) | |
fp = fopen(outpath, "wb"); | |
if (fp == NULL) { | |
fprintf(stderr, "error: can't create output file %s\n", outpath); | |
goto errout; | |
} | |
fwrite(buffer, len, 1, fp); | |
curr += len; | |
} | |
if (fp) fclose(fp); | |
return 0; | |
errout: | |
if (fp) fclose(fp); | |
return 1; | |
} | |
void do_list (int pid) | |
{ | |
HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); | |
if (proc == NULL) { | |
fprintf(stderr, "error: OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , 0, %d) failed\n", pid); | |
return; | |
} | |
SYSTEM_INFO sysinfo; | |
GetSystemInfo(&sysinfo); | |
char *addr = sysinfo.lpMinimumApplicationAddress; | |
while (addr < sysinfo.lpMaximumApplicationAddress) { | |
MEMORY_BASIC_INFORMATION meminfo; | |
if (VirtualQueryEx(proc, addr, &meminfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) { | |
fprintf(stderr, "VirtualQueryEx(%p) failed.\n", addr); | |
break; | |
} | |
if (meminfo.RegionSize == 0) { | |
fprintf(stderr, "VirtualQueryEx(%p) failed. RegionSize=0\n", addr); | |
break; | |
} | |
if (meminfo.State != MEM_COMMIT) goto next; | |
char file_name[512]; | |
file_name[0] = ' '; | |
if (GetMappedFileName(proc, addr, file_name+1, sizeof(file_name)-1) == 0) | |
file_name[0] = '\0'; | |
printf("base=%08p addr=%08p size=0x%Ix prot=%s type=%s%s\n", | |
meminfo.AllocationBase, | |
meminfo.BaseAddress, | |
meminfo.RegionSize, | |
memprot_name(meminfo.Protect), | |
memtype_name(meminfo.Type), | |
file_name); | |
next: | |
addr += meminfo.RegionSize; | |
} | |
} | |
void do_dump1 (int pid, void *addr, size_t size, const char *filename) | |
{ | |
HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); | |
if (proc == NULL) { | |
printf("error: OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , 0, %d) failed\n", pid); | |
return; | |
} | |
dump_to_file(proc, addr, size, filename); | |
} | |
void do_dump (int pid, char *filters[], int nfilter) | |
{ | |
DWORD filter_mask = 0; | |
int i; | |
for (i = 0; i < nfilter; i ++) { | |
if (strcmp(filters[i], "writable") == 0) | |
filter_mask |= PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; | |
else if (strcmp(filters[i], "executable") == 0) | |
filter_mask |= PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; | |
else if (strcmp(filters[i], "ro" ) == 0) filter_mask |= PAGE_READONLY; | |
else if (strcmp(filters[i], "rw" ) == 0) filter_mask |= PAGE_READWRITE; | |
else if (strcmp(filters[i], "wc" ) == 0) filter_mask |= PAGE_WRITECOPY; | |
else if (strcmp(filters[i], "rx" ) == 0) filter_mask |= PAGE_EXECUTE_READ; | |
else if (strcmp(filters[i], "rxw") == 0) filter_mask |= PAGE_EXECUTE_READWRITE; | |
else if (strcmp(filters[i], "xwc") == 0) filter_mask |= PAGE_EXECUTE_WRITECOPY; | |
else | |
fprintf(stderr, "unknown filter %s\n", filters[i]); | |
} | |
if (nfilter == 0) | |
nfilter = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; | |
HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); | |
if (proc == NULL) { | |
fprintf(stderr, "error: OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , 0, %d) failed\n", pid); | |
return; | |
} | |
SYSTEM_INFO sysinfo; | |
GetSystemInfo(&sysinfo); | |
char *addr = sysinfo.lpMinimumApplicationAddress; | |
while (addr < sysinfo.lpMaximumApplicationAddress) { | |
MEMORY_BASIC_INFORMATION meminfo; | |
if (VirtualQueryEx(proc, addr, &meminfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) { | |
fprintf(stderr, "VirtualQueryEx(%p) failed.\n", addr); | |
break; | |
} | |
if (meminfo.RegionSize == 0) { | |
fprintf(stderr, "VirtualQueryEx(%p) failed. RegionSize=0\n", addr); | |
break; | |
} | |
if (meminfo.State == MEM_COMMIT && (meminfo.Protect & filter_mask) && !(meminfo.Protect & PAGE_GUARD)) { | |
char filename[64]; | |
snprintf(filename, sizeof(filename), "dump-%d-%08p.bin", pid, addr); | |
dump_to_file(proc, addr, meminfo.RegionSize, filename); | |
} | |
addr += meminfo.RegionSize; | |
} | |
} | |
void usage (const char *cmd) | |
{ | |
printf("Usage:\n"); | |
printf(" %s help\n", cmd); | |
printf(" %s list <pid>\n", cmd); | |
printf(" %s dump <pid> [filter1] [filter2] ...\n", cmd); | |
printf(" %s dump1 <pid> <addr-in-hex> <size-in-hex> <outfile>\n", cmd); | |
printf("Example:\n"); | |
printf(" %s list 4235\n", cmd); | |
printf(" %s dump 4235 rw\n", cmd); | |
printf(" %s dump 4235 rx rwx\n", cmd); | |
printf(" %s dump1 4235 77BA0000 107000 ntdll-code.dat\n", cmd); | |
printf("Filters:\n"); | |
int i; | |
for (i = 0; i < sizeof(memprot_names)/sizeof(memprot_names[0]); i ++) | |
printf(" %3s: %s\n", memprot_names[i].short_name, memprot_names[i].desc); | |
printf(" writable: same for \"rw wc rwx xwc\"\n"); | |
printf(" executable: same for \"rx rwx xwc\"\n"); | |
} | |
int main (int argc, char *argv[]) | |
{ | |
if (argc == 3 && strcmp(argv[1], "list") == 0) { | |
do_list(atoi(argv[2])); | |
} else if (argc >= 3 && strcmp(argv[1], "dump") == 0) { | |
do_dump(atoi(argv[2]), argv+3, argc-3); | |
} else if (argc == 6 && strcmp(argv[1], "dump1") == 0) { | |
if (sizeof(void *) == sizeof(long)) | |
#ifdef _WIN64 | |
do_dump1(atoi(argv[2]), (void *)strtoll(argv[3], NULL, 16), strtoll(argv[4], NULL, 16), argv[5]); | |
#else | |
do_dump1(atoi(argv[2]), (void *)strtol(argv[3], NULL, 16), strtol(argv[4], NULL, 16), argv[5]); | |
#endif | |
} else { | |
usage(argv[0]); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment