/* PEWhack - Corrupts a PE binary to be non-executable but still useful when debugging memory dumps. */ #include #include #include #include #include #include BOOL CorruptDataDirectories(PIMAGE_DOS_HEADER pDosHdr, ULONG DirCount); BOOL CorruptSections(PIMAGE_SECTION_HEADER pSection, ULONG ulSections, PIMAGE_DOS_HEADER ImageBase); BOOL CorruptSections(PIMAGE_SECTION_HEADER pSection, ULONG ulSections, PIMAGE_DOS_HEADER ImageBase) { BOOL ReturnValue = FALSE; ULONG i; for ( i=0; i < ulSections; i++ ) { // .data sections can be killed if ( strncmp(".data", (CHAR*)(pSection[i].Name), 5) == 0 ) { // writeable sections can go away... if ( (pSection[i].Characteristics & IMAGE_SCN_MEM_WRITE) ) { if ( pSection[i].PointerToRawData != 0 ) { ZeroMemory( (VOID*)( (pSection+i)->PointerToRawData + (ULONG_PTR)ImageBase), pSection[i].SizeOfRawData); } pSection[i].PointerToRawData= 0; pSection[i].SizeOfRawData = 0; pSection[i].Characteristics = 0; ReturnValue = TRUE; } } } return(ReturnValue); } // // Verifies an image is a PE binary and, if so, corrupts it to be // non-executable but still useful for debugging memory dumps. // DWORD CorruptFile(LPCTSTR Filename) { DWORD Return = PEWHACK_SUCCESS; HANDLE hFile; HANDLE hFileMap; PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS32 pPe32Header = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; IMAGE_DEBUG_DIRECTORY UNALIGNED *pDebugDir = NULL; ULONG DebugSize; ULONG SectionIndex; hFile = CreateFile( (LPCTSTR)Filename, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); if (hFileMap != NULL) { pDosHeader = (PIMAGE_DOS_HEADER)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0); if (pDosHeader != NULL) { // Verify this is an PE image if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { // // Start by assuming a 32bit binary until we check the machine type // pPe32Header = (PIMAGE_NT_HEADERS32)( (PCHAR)(pDosHeader) + (ULONG)(pDosHeader)->e_lfanew); if (pPe32Header->Signature == IMAGE_NT_SIGNATURE) { // // 32bit header // if (pPe32Header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // Mark the image as non-executable pPe32Header->FileHeader.Characteristics &= ~IMAGE_FILE_EXECUTABLE_IMAGE; // Whack some optional header info pPe32Header->OptionalHeader.SizeOfInitializedData = 0; pPe32Header->OptionalHeader.SizeOfUninitializedData = 0; pPe32Header->OptionalHeader.MajorOperatingSystemVersion = 0xFFFF; // absurdly high pPe32Header->OptionalHeader.MinorOperatingSystemVersion = 0xFFFF; // absurdly high pPe32Header->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN; // Corrupt the section data pSectionHeader = IMAGE_FIRST_SECTION(pPe32Header); CorruptSections(pSectionHeader, pPe32Header->FileHeader.NumberOfSections, pDosHeader); // Corrupt data directories CorruptDataDirectories(pDosHeader, pPe32Header->OptionalHeader.NumberOfRvaAndSizes); pPe32Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0; pPe32Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0; pPe32Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; pPe32Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; // // 64bit header // } else if (pPe32Header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { PIMAGE_NT_HEADERS64 pPe64Header = (PIMAGE_NT_HEADERS64)pPe32Header; // Mark the image as non-executable pPe64Header->FileHeader.Characteristics &= ~IMAGE_FILE_EXECUTABLE_IMAGE; // Whack some optional header info pPe64Header->OptionalHeader.SizeOfInitializedData = 0; pPe64Header->OptionalHeader.SizeOfUninitializedData = 0; pPe64Header->OptionalHeader.MajorOperatingSystemVersion = 0xFFFF; // absurdly high pPe64Header->OptionalHeader.MinorOperatingSystemVersion = 0xFFFF; // absurdly high pPe64Header->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN; // Corrupt the section data pSectionHeader = IMAGE_FIRST_SECTION(pPe64Header); CorruptSections( pSectionHeader, pPe64Header->FileHeader.NumberOfSections, pDosHeader); // Corrupt data directories CorruptDataDirectories(pDosHeader, pPe64Header->OptionalHeader.NumberOfRvaAndSizes); pPe64Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0; pPe64Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0; pPe64Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; pPe64Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; } else { Return = PEWHACK_BAD_ARCHITECTURE; } } else { Return = PEWHACK_BAD_PE_SIG; } } else { Return = PEWHACK_BAD_DOS_SIG; } FlushViewOfFile(pDosHeader, 0); UnmapViewOfFile(pDosHeader); } else { Return = PEWHACK_MAPVIEW_FAILED; } CloseHandle(hFileMap); } else { Return = PEWHACK_CREATEMAP_FAILED; } CloseHandle(hFile); } else { Return = PEWHACK_CREATEFILE_FAILED; } return(Return); } // // Corrupts the data directories of a binary. Machine independent. // BOOL CorruptDataDirectories(PIMAGE_DOS_HEADER pDosHdr, ULONG DirCount) { PIMAGE_SECTION_HEADER pImageSectionHeader = NULL; ULONG Loop; BOOL RetVal = FALSE; for (Loop=0;LoopMisc.PhysicalAddress = 0; pImageSectionHeader->VirtualAddress = 0; pImageSectionHeader->SizeOfRawData = 0; pImageSectionHeader->Characteristics = 0; pImageSectionHeader->PointerToRawData = 0; RetVal = TRUE; break; // // Wholesale corruption of these sections make it impossible // to use the binary with the debugger. It may be worthwhile // to look into limited corruption of each section. // case IMAGE_DIRECTORY_ENTRY_IMPORT: case IMAGE_DIRECTORY_ENTRY_EXPORT: case IMAGE_DIRECTORY_ENTRY_DEBUG: case IMAGE_DIRECTORY_ENTRY_IAT: case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: case IMAGE_DIRECTORY_ENTRY_RESOURCE: break; // // The binaries I've checked so far lack these sections, so I'm // not sure if they're corruptable or not. // case IMAGE_DIRECTORY_ENTRY_EXCEPTION: case IMAGE_DIRECTORY_ENTRY_SECURITY: case IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: case IMAGE_DIRECTORY_ENTRY_TLS: case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: default: break; } } } return(RetVal); }