/* skape #include #include #define PAGE_SIZE 4096 typedef struct _MemoryRange { char *base; unsigned long length; char *file; struct _MemoryRange *next; } MemoryRange; BOOL createDumpDirectory(char *path); DWORD dumpSegments(HANDLE process, const char *dumpDirectory); int main(int argc, char **argv) { char *dumpDirectory = NULL; HANDLE process = NULL; DWORD pid = 0, segments = 0; int res = 1; do { // Validate arguments if ((argc == 1) || (!(pid = atoi(argv[1])))) { printf("Usage: %s pid [dump directory]\n", argv[0]); break; } // If a dump directory is specified, use it, otherwise default // to the pid. if (argc >= 3) dumpDirectory = argv[2]; else dumpDirectory = argv[1]; // Create the dump directory (make sure it exists) printf("[*] Creating dump directory...%s\n", dumpDirectory); if (!createDumpDirectory(dumpDirectory)) { printf("[-] Creation failed, %.8x.\n", GetLastError()); break; } // Attach to the process printf("[*] Attaching to %lu...\n", pid); if (!(process = OpenProcess(PROCESS_VM_READ, FALSE, pid))) { printf("[-] Attach failed, %.8x.\n", GetLastError()); break; } // Dump segments printf("[*] Dumping segments...\n"); if (!(segments = dumpSegments(process, dumpDirectory))) { printf("[-] Dump failed, %.8x.\n", GetLastError()); break; } printf("[*] Dump completed successfully, %lu segments.\n", segments); res = 0; } while (0); if (process) CloseHandle(process); return res; } /* * Create the directory specified by path, insuring that * all parents exist along the way. * * Just like MakeSureDirectoryPathExists, but portable. */ BOOL createDumpDirectory(char *path) { char *slash = path; BOOL res = TRUE; do { slash = strchr(slash, '\\'); if (slash) *slash = 0; if (!CreateDirectory(path, NULL)) { if ((GetLastError() != ERROR_FILE_EXISTS) && (GetLastError() != ERROR_ALREADY_EXISTS)) { res = FALSE; break; } } if (slash) *slash++ = '\\'; } while (slash); return res; } /* * Dump all mapped segments into the dump directory, one file per * each segment. Finally, create an index of all segments. */ DWORD dumpSegments(HANDLE process, const char *dumpDirectory) { MemoryRange *ranges = NULL, *prevRange = NULL, *currentRange = NULL; char pbuf[PAGE_SIZE], rangeFileName[256]; DWORD segments = 0, bytesRead = 0, cycles = 0; char *current = NULL; FILE *rangeFd = NULL; // Enumerate page by page for (current = 0; ; current += PAGE_SIZE, cycles++) { // If we've wrapped, break out. if (!current && cycles) break; // Invalid page? Cool, reset current range. if (!ReadProcessMemory(process, current, pbuf, sizeof(pbuf), &bytesRead)) { if (currentRange) { prevRange = currentRange; currentRange = NULL; } if (rangeFd) { fclose(rangeFd); rangeFd = NULL; } continue; } // If the current range is not valid, we've hit a new range. if (!currentRange) { // Try to allocate storage for it, if we fail, bust out. if (!(currentRange = (MemoryRange *)malloc(sizeof(MemoryRange)))) { printf("[-] Allocation failure\n"); segments = 0; break; } currentRange->base = current; currentRange->length = 0; currentRange->next = NULL; if (prevRange) prevRange->next = currentRange; else ranges = currentRange; // Finally, open a file for this range _snprintf(rangeFileName, sizeof(rangeFileName) - 1, "%s\\%.8x.rng", dumpDirectory, current); if (!(rangeFd = fopen(rangeFileName, "wb"))) { printf("[-] Could not open range file: %s\n", rangeFileName); segments = 0; break; } // Duplicate the file name for ease of access later currentRange->file = strdup(rangeFileName); // Increment the number of total segments segments++; } // Write to the range file fwrite(pbuf, 1, bytesRead, rangeFd); currentRange->length += bytesRead; } // Now that all the ranges are mapped, dump them to an index file _snprintf(rangeFileName, sizeof(rangeFileName) - 1, "%s\\index.rng", dumpDirectory); if ((rangeFd = fopen(rangeFileName, "w"))) { char cwd[MAX_PATH]; GetCurrentDirectory(sizeof(cwd), cwd); // Enumerate all of the ranges, dumping them into the index file for (currentRange = ranges; currentRange; currentRange = currentRange->next) { fprintf(rangeFd, "%.8x;%lu;%s\\%s\n", currentRange->base, currentRange->length, cwd, currentRange->file ? currentRange->file : ""); } fclose(rangeFd); } else segments = 0; return segments; }