Skip to content

Instantly share code, notes, and snippets.

@wuyongzheng
Created August 8, 2016 08:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wuyongzheng/510c124c0a245d00d709976046654d6f to your computer and use it in GitHub Desktop.
Save wuyongzheng/510c124c0a245d00d709976046654d6f to your computer and use it in GitHub Desktop.
#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