// retrieve the export directory structure for a given module, // using information from the various headers IMAGE_EXPORT_DIRECTORY *getExportDir(HMODULE module) { if (!module && CACHED_EXPORT_DIR) return CACHED_EXPORT_DIR; IMAGE_NT_HEADERS *nt_header = getNtHeader(module); IMAGE_DATA_DIRECTORY *datadir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (datadir->Size == 0) return NULL; // no export directory void *result = rva_to_addr(datadir->VirtualAddress, module); if (!module) /* i.e. "self" */ CACHED_EXPORT_DIR = result; return result; }
bool getPDBFiles(const QString &peExecutableFileName, QStringList *rc, QString *errorMessage) { HANDLE hFile = NULL; HANDLE hFileMap = NULL; void *fileMemory = 0; bool success = false; rc->clear(); do { // Create a memory mapping of the file hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { *errorMessage = QString::fromLatin1("Cannot open '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMap == NULL) { *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if (!fileMemory) { *errorMessage = QString::fromLatin1("Cannot map '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage); if (!ntHeaders) break; int debugSectionCount; IMAGE_DEBUG_DIRECTORY *debugDir; if (!getDebugDirectory(ntHeaders, fileMemory, &debugDir, &debugSectionCount, errorMessage)) return false; if (debugSectionCount) collectPDBfiles(fileMemory, debugDir, debugSectionCount, rc); success = true; } while(false); if (fileMemory) UnmapViewOfFile(fileMemory); if (hFileMap != NULL) CloseHandle(hFileMap); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return success; }
// retrieve section header IMAGE_SECTION_HEADER *getSectionHeader(HMODULE module, int index) { IMAGE_NT_HEADERS *nt_header = getNtHeader(module); if (index < 1 || index > nt_header->FileHeader.NumberOfSections) { error("getSectionHeader(%p, %d): invalid section index", module, index); return NULL; } // the array of section descriptors starts right after the NT header, // so calculate the offset (= header's size) IMAGE_SECTION_HEADER *result = (void*)nt_header + sizeof("ULONG") + sizeof("IMAGE_FILE_HEADER") + nt_header->FileHeader.SizeOfOptionalHeader; return (result + (index - 1)); }
// returns the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag inline bool getDynamicBase(HMODULE module) { IMAGE_NT_HEADERS *nt_header = getNtHeader(module); return (nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0; }
// Read a PE executable and determine dependent libraries, word size // and debug flags. bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibrariesIn, unsigned *wordSizeIn, bool *isDebugIn, bool isMinGW) { bool result = false; HANDLE hFile = NULL; HANDLE hFileMap = NULL; void *fileMemory = 0; if (dependentLibrariesIn) dependentLibrariesIn->clear(); if (wordSizeIn) *wordSizeIn = 0; if (isDebugIn) *isDebugIn = false; do { // Create a memory mapping of the file hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { *errorMessage = QString::fromLatin1("Cannot open '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMap == NULL) { *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if (!fileMemory) { *errorMessage = QString::fromLatin1("Cannot map '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } const IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage); if (!ntHeaders) break; const unsigned wordSize = ntHeaderWordSize(ntHeaders); if (wordSizeIn) *wordSizeIn = wordSize; bool debug = false; if (wordSize == 32) { const IMAGE_NT_HEADERS32 *ntHeaders32 = reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders); if (!isMinGW) { debug = ntHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; } else { // Use logic that's used e.g. in objdump / pfd library debug = !(ntHeaders32->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED); } if (dependentLibrariesIn) *dependentLibrariesIn = readImportSections(ntHeaders32, fileMemory, errorMessage); } else { const IMAGE_NT_HEADERS64 *ntHeaders64 = reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders); if (!isMinGW) { debug = ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; } else { // Use logic that's used e.g. in objdump / pfd library debug = !(ntHeaders64->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED); } if (dependentLibrariesIn) *dependentLibrariesIn = readImportSections(ntHeaders64, fileMemory, errorMessage); } if (isDebugIn) *isDebugIn = debug; result = true; if (optVerboseLevel > 1) std::wcout << __FUNCTION__ << ": " << peExecutableFileName << ' ' << wordSize << " bit, debug: " << debug << '\n'; } while (false); if (fileMemory) UnmapViewOfFile(fileMemory); if (hFileMap != NULL) CloseHandle(hFileMap); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return result; }