From 5edba6f9b45de75ff16a1d47aedd16a10bcadb2f Mon Sep 17 00:00:00 2001 From: Winslow <33692631+senzee1984@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:55:34 -0400 Subject: [PATCH] Update DumpPEFromMemory.cpp --- DumpPEFromMemory/DumpPEFromMemory.cpp | 307 +++++++++++++++----------- 1 file changed, 182 insertions(+), 125 deletions(-) diff --git a/DumpPEFromMemory/DumpPEFromMemory.cpp b/DumpPEFromMemory/DumpPEFromMemory.cpp index b53fb05..16078e9 100644 --- a/DumpPEFromMemory/DumpPEFromMemory.cpp +++ b/DumpPEFromMemory/DumpPEFromMemory.cpp @@ -1,7 +1,8 @@ #include #include #include - +#include +#include #pragma comment(lib, "ntdll.lib") #pragma warning(disable:4996) @@ -14,78 +15,174 @@ EXTERN_C NTSTATUS NTAPI NtQueryInformationProcess( PULONG ReturnLength ); - -BOOL ReadPEFile(LPCSTR lpFileName, PBYTE* pPe, SIZE_T* sPe) { - - HANDLE hFile = INVALID_HANDLE_VALUE; - PBYTE pBuff = NULL; - DWORD dwFileSize = NULL, - dwNumberOfBytesRead = NULL; - - hFile = CreateFileA(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - printf("[!] CreateFileA Failed With Error : %d \n", GetLastError()); - goto _EndOfFunction; - } - - dwFileSize = GetFileSize(hFile, NULL); - if (dwFileSize == NULL) { - printf("[!] GetFileSize Failed With Error : %d \n", GetLastError()); - goto _EndOfFunction; - } - - pBuff = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize); - if (pBuff == NULL) { - printf("[!] HeapAlloc Failed With Error : %d \n", GetLastError()); - goto _EndOfFunction; - } - - if (!ReadFile(hFile, pBuff, dwFileSize, &dwNumberOfBytesRead, NULL) || dwFileSize != dwNumberOfBytesRead) { - printf("[!] ReadFile Failed With Error : %d \n", GetLastError()); - printf("[!] Bytes Read : %d of : %d \n", dwNumberOfBytesRead, dwFileSize); - goto _EndOfFunction; - } - - printf("[+] DONE \n"); - - -_EndOfFunction: - *pPe = (PBYTE)pBuff; - *sPe = (SIZE_T)dwFileSize; - if (hFile) - CloseHandle(hFile); - if (*pPe == NULL || *sPe == NULL) - return FALSE; +BOOL MemoryAllocationSuggestion(DWORD textSize, DWORD otherSectionSize) +{ + printf("\n[!] Suggested memory allocations, please adjust accordingly with other memory allocation APIs and languages\n\n"); + printf("// Allocate memory with RX permission for shellcode stub\n"); + printf("LPVOID buffer = VirtualAlloc(NULL, 0x1000, 0x3000, 0x20);\n"); + printf("// Allocate memory with RW permission for PE Header\n"); + printf("VirtualAlloc(buffer + 0x1000, 0x1000, 0x3000, 0x04);\n"); + printf("// Allocate memory with RX permission for text section\n"); + printf("VirtualAlloc(buffer + 0x2000, 0x%x, 0x3000, 0x20);\n", textSize); + printf("// Allocate memory with RW permission for other sections\n"); + printf("VirtualAlloc(buffer + 0x2000 + 0x%x, 0x%x, 0x3000, 0x20);\n", textSize, otherSectionSize); return TRUE; } - -DWORD ParsePE(PBYTE pPE) +BOOL DumpPEFromMemory(LPCSTR filename, char* outputbin) { - DWORD size = 0; - PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pPE; - if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE) { - return -1; - } + STARTUPINFOA si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); - PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pPE + pImgDosHdr->e_lfanew); - if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE) { - return -1; + if (!CreateProcessA(filename, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { + printf("[!] CreateProcess failed (%d).\n", GetLastError()); + return FALSE; } + printf("[+] Process PID: %lu\n", pi.dwProcessId); + PROCESS_BASIC_INFORMATION pbi; + NTSTATUS status = NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL); - IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader; - if (ImgOptHdr.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) { - return -1; + if (status == 0) + { + printf("[+] PEB Address:%p\n", pbi.PebBaseAddress); + + PVOID imageBaseAddress; + SIZE_T bytesRead; + ReadProcessMemory(pi.hProcess, (PCHAR)pbi.PebBaseAddress + sizeof(PVOID) * 2, &imageBaseAddress, sizeof(PVOID), &bytesRead); + printf("[+] Image Base Address:%p\n", imageBaseAddress); + + DWORD e_lfanew; + ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress+0x3c, &e_lfanew, sizeof(e_lfanew), &bytesRead); + printf("[+] e_lfanew is 0x%x\n", e_lfanew); + + + DWORD imageSize_offset = e_lfanew + 0x50; + DWORD imageSize = 0; + ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress+imageSize_offset, &imageSize, sizeof(imageSize), &bytesRead); + printf("[+] Size Of The Image : 0x%x \n", imageSize); + + DWORD offset_optionalHeaderSize = e_lfanew + 0x14; + WORD optionalHeaderSize; + ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress + offset_optionalHeaderSize, &optionalHeaderSize, sizeof(optionalHeaderSize), &bytesRead); + printf("[+] Size Of Optional Header : 0x%x \n", optionalHeaderSize); + + DWORD offset_sectionHeader = e_lfanew + 0x18 + optionalHeaderSize; + DWORD textSize; + ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress + offset_sectionHeader + 0x8, &textSize, sizeof(textSize), &bytesRead); + textSize = (textSize + 0x0FFF) & ~0x0FFF; + printf("[+] Size Of text Section : 0x%x \n", textSize); + + DWORD otherSectionSize = imageSize - textSize - 0x1000; + otherSectionSize = (otherSectionSize + 0x0FFF) & ~0x0FFF; + printf("[+] Size of other sections of mapped %s is 0x%x\n", filename, otherSectionSize); + MemoryAllocationSuggestion(textSize, otherSectionSize); + + SIZE_T size_of_image = imageSize; + const SIZE_T CHUNK_SIZE = 0xb000; // Chunk size for reading and writing + BYTE buffer[0xb000]; //Number of bytes read each time + SIZE_T totalBytesRead = 0; + + + // Calculate the number of iterations needed + int numIterations = (size_of_image / CHUNK_SIZE) + (size_of_image % CHUNK_SIZE ? 1 : 0); + printf("\n[+] %d iterations are needed\n", numIterations); + + FILE* file = fopen(outputbin, "ab"); // Open file in append mode + if (file == NULL) + { + printf("[!] Failed to open %s for writing\n", outputbin); + exit(1); + } + + for (int iteration = 0; iteration < numIterations; iteration++) + { + BYTE buffer[CHUNK_SIZE]; + SIZE_T offset = iteration * CHUNK_SIZE; + SIZE_T sizeToRead = min(CHUNK_SIZE, size_of_image - offset); + + if (!ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress + offset, &buffer, sizeToRead, &bytesRead)) + { + printf("[!] Error reading memory: %d\n", GetLastError()); + break; + } + + fwrite(buffer, 1, bytesRead, file); + totalBytesRead += bytesRead; + } + + fclose(file); + printf("\n[+] Data successfully written to %s. Total bytes read: 0x%x\n", outputbin, totalBytesRead); + + TerminateProcess(pi.hProcess, 0); + return TRUE; + } + else + { + printf("[!] Query failed\n"); + return FALSE; } - - printf("[+] Size Of The Image : 0x%x \n", ImgOptHdr.SizeOfImage); - size = ImgOptHdr.SizeOfImage; - return size; } +BOOL InflateFromDisk(LPCSTR filename, char* outputbin) +{ + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + printf("[!] CreateFileA Failed With Error : %d \n", GetLastError()); + return FALSE; + } + HANDLE hSection = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, NULL, NULL, NULL); + if (hSection == NULL) { + printf("[!] CreateFileMappingA Failed With Error : %d \n", GetLastError()); + return FALSE; + } + PBYTE PeBase = (PBYTE)MapViewOfFile(hSection, FILE_MAP_READ, NULL, NULL, NULL); + if (PeBase == NULL) { + printf("[!] MapViewOfFile Failed With Error : %d \n", GetLastError()); + return FALSE; + } + + DWORD e_lfanew = *((DWORD*)((BYTE*)PeBase + 0x3c)); + DWORD imageSize = *((DWORD*)((BYTE*)PeBase + e_lfanew + 0x50)); + + DWORD offset_optionalHeaderSize = e_lfanew + 0x14; + WORD optionalHeaderSize = *((WORD*)((BYTE*)PeBase + offset_optionalHeaderSize)); + DWORD offset_sectionHeader = e_lfanew + 0x18 + optionalHeaderSize; + DWORD textSize = *((DWORD*)((BYTE*)PeBase + offset_sectionHeader + 0x8)); + textSize = (textSize + 0x0FFF) & ~0x0FFF; + DWORD otherSectionSize = imageSize - textSize - 0x1000; + otherSectionSize = (otherSectionSize + 0x0FFF) & ~0x0FFF; + + printf("[+] Image base of mapped %s is 0x%x\n", filename, PeBase); + printf("[+] e_lfanew of mapped %s is 0x%x\n", filename, e_lfanew); + printf("[+] imageSize of mapped %s is 0x%x\n", filename, imageSize); + + printf("[+] Size of optinalHeader of mapped %s is 0x%x\n", filename, optionalHeaderSize); + printf("[+] Offset of section Header of mapped %s is 0x%x\n", filename, offset_sectionHeader); + printf("[+] Size of text section of mapped %s is 0x%x\n", filename, textSize); + printf("[+] Size of other sections of mapped %s is 0x%x\n", filename, otherSectionSize); + + MemoryAllocationSuggestion(textSize, otherSectionSize); + + FILE* file = fopen(outputbin, "wb"); + if (file == NULL) + { + printf("[!] Failed to open %s for writing\n", outputbin); + exit(1); + } + fwrite(PeBase, 1, imageSize, file); + fclose(file); + printf("\n[+] Data successfully written to %s\n", outputbin); + CloseHandle(hFile); + CloseHandle(hSection); + return TRUE; +} + int main(int argc, char* argv[]) @@ -94,81 +191,41 @@ int main(int argc, char* argv[]) SIZE_T sPE = NULL; if (argc < 3) { - printf("Usage: DumpPEFromMemoryMemory.exe \nE.g. ReadPEInMemory.exe mimikatz.exe mimikatz.bin\n"); + printf("[!] Usage: DumpPEFromMemoryMemory.exe \nE.g. ReadPEInMemory.exe mimikatz.exe mimikatz.bin\n"); return -1; } LPCSTR filename = argv[1]; char* outputbin = argv[2]; - if (!ReadPEFile(filename, &pPE, &sPE)) { + + char extension[4] = { 0 }; + if (strlen(filename) > 4) //End with .exe or .dll + { + for (int i = 0; i < 3; i++) + { + extension[i] = tolower(filename[strlen(filename) - 3 + i]); + } + } + else + { + printf("[!] Invalid file extension\n"); return -1; } - DWORD size_of_image = ParsePE(pPE); - HeapFree(GetProcessHeap(), NULL, pPE); - - STARTUPINFOA si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - if (!CreateProcessA(filename, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { - printf("CreateProcess failed (%d).\n", GetLastError()); - return 1; + if (strcmp(extension, "exe") == 0) + { + printf("[+] The file is an EXE file\n"); + DumpPEFromMemory(filename, outputbin); } - printf("Process PID: %lu\n", pi.dwProcessId); - PROCESS_BASIC_INFORMATION pbi; - NTSTATUS status = NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL); - - if (status == 0) { - printf("PEB Address:%p\n", pbi.PebBaseAddress); - PVOID imageBaseAddress; - SIZE_T bytesRead; - - ReadProcessMemory(pi.hProcess, (PCHAR)pbi.PebBaseAddress + sizeof(PVOID) * 2, &imageBaseAddress, sizeof(PVOID), &bytesRead); - printf("Image Base Address:%p\n", imageBaseAddress); - - SIZE_T totalSize = size_of_image; //Total size of PE image in memory - const SIZE_T CHUNK_SIZE = 0xb000; // Chunk size for reading and writing - BYTE buffer[0xb000]; //Number of bytes read each time - - - SIZE_T totalBytesRead = 0; - - // Calculate the number of iterations needed - int numIterations = (totalSize / CHUNK_SIZE) + (totalSize % CHUNK_SIZE ? 1 : 0); - - FILE* file = fopen(outputbin, "ab"); // Open file in append mode - if (file == NULL) { - printf("Failed to open %s for writing\n", outputbin); - exit(1); - } - - for (int iteration = 0; iteration < numIterations; iteration++) { - BYTE buffer[CHUNK_SIZE]; - SIZE_T offset = iteration * CHUNK_SIZE; - SIZE_T sizeToRead = min(CHUNK_SIZE, totalSize - offset); - - if (!ReadProcessMemory(pi.hProcess, (PBYTE)imageBaseAddress + offset, &buffer, sizeToRead, &bytesRead)) { - printf("Error reading memory: %d\n", GetLastError()); - break; - } - - fwrite(buffer, 1, bytesRead, file); - totalBytesRead += bytesRead; - } - - fclose(file); - printf("Data successfully written to %s. Total bytes read: 0x%x\n", outputbin, totalBytesRead); + else if(strcmp(extension, "dll") == 0) + { + printf("[+] The file is a DLL file\n"); + InflateFromDisk(filename, outputbin); } - else { - printf("Error"); - } - - if (!TerminateProcess(pi.hProcess, 0)) { - printf("TerminateProcess failed (%d).\n", GetLastError()); - return 1; + else + { + printf("[!] Invalid PE file\n"); + return -1; } return 0;