diff --git a/dump-pe/main.cpp b/dump-pe/main.cpp index d8b71f8..25cca09 100644 --- a/dump-pe/main.cpp +++ b/dump-pe/main.cpp @@ -119,6 +119,81 @@ int printRelocs(void *N, const VA &relocAddr, const reloc_type &type) { return 0; } +int printDebugs(void *N, + const std::uint32_t &type, + const bounded_buffer *data) { + static_cast(N); + + std::cout << "Debug Directory Type: "; + switch (type) { + case 0: + std::cout << "IMAGE_DEBUG_TYPE_UNKNOWN"; + break; + case 1: + std::cout << "IMAGE_DEBUG_TYPE_COFF"; + break; + case 2: + std::cout << "IMAGE_DEBUG_TYPE_CODEVIEW"; + break; + case 3: + std::cout << "IMAGE_DEBUG_TYPE_FPO"; + break; + case 4: + std::cout << "IMAGE_DEBUG_TYPE_MISC"; + break; + case 5: + std::cout << "IMAGE_DEBUG_TYPE_EXCEPTION"; + break; + case 6: + std::cout << "IMAGE_DEBUG_TYPE_FIXUP"; + break; + case 7: + std::cout << "IMAGE_DEBUG_TYPE_OMAP_TO_SRC"; + break; + case 8: + std::cout << "IMAGE_DEBUG_TYPE_OMAP_FROM_SRC"; + break; + case 9: + std::cout << "IMAGE_DEBUG_TYPE_BORLAND"; + break; + case 10: + std::cout << "IMAGE_DEBUG_TYPE_RESERVED10"; + break; + case 11: + std::cout << "IMAGE_DEBUG_TYPE_CLSID"; + break; + case 12: + std::cout << "IMAGE_DEBUG_TYPE_VC_FEATURE"; + break; + case 13: + std::cout << "IMAGE_DEBUG_TYPE_POGO"; + break; + case 14: + std::cout << "IMAGE_DEBUG_TYPE_ILTCG"; + break; + case 15: + std::cout << "IMAGE_DEBUG_TYPE_MPX"; + break; + case 16: + std::cout << "IMAGE_DEBUG_TYPE_REPRO"; + break; + case 20: + std::cout << "IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS"; + break; + default: + std::cout << "INVALID"; + break; + } + std::cout << "\n"; + std::cout << "Debug Directory Data: "; + for (uint32_t i = 0; i < data->bufLen; i++) { + std::cout << " 0x" << std::hex << static_cast(data->buf[i]); + } + std::cout << "\n"; + + return 0; +} + int printSymbols(void *N, const std::string &strName, const uint32_t &value, @@ -448,6 +523,9 @@ int main(int argc, char *argv[]) { std::cout << "Relocations: " << "\n"; IterRelocs(p, printRelocs, NULL); + std::cout << "Debug Directories: " + << "\n"; + IterDebugs(p, printDebugs, NULL); std::cout << "Symbols (symbol table): " << "\n"; IterSymbols(p, printSymbols, NULL); diff --git a/pe-parser-library/include/pe-parse/nt-headers.h b/pe-parser-library/include/pe-parse/nt-headers.h index 1dc071e..72bf514 100644 --- a/pe-parser-library/include/pe-parse/nt-headers.h +++ b/pe-parser-library/include/pe-parse/nt-headers.h @@ -452,6 +452,17 @@ struct export_dir_table { std::uint32_t OrdinalTableRVA; }; +struct debug_dir_entry { + std::uint32_t Characteristics; + std::uint32_t TimeStamp; + std::uint16_t MajorVersion; + std::uint16_t MinorVersion; + std::uint32_t Type; + std::uint32_t SizeOfData; + std::uint32_t AddressOfRawData; + std::uint32_t PointerToRawData; +}; + enum reloc_type { RELOC_ABSOLUTE = 0, RELOC_HIGH = 1, diff --git a/pe-parser-library/include/pe-parse/parse.h b/pe-parser-library/include/pe-parse/parse.h index 4407ce2..f543143 100644 --- a/pe-parser-library/include/pe-parse/parse.h +++ b/pe-parser-library/include/pe-parse/parse.h @@ -222,6 +222,10 @@ void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd); typedef int (*iterReloc)(void *, const VA &, const reloc_type &); void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd); +// iterate over debug directories in the PE file +typedef int (*iterDebug)(void *, const std::uint32_t &, const bounded_buffer *); +void IterDebugs(parsed_pe *pe, iterDebug cb, void *cbd); + // Iterate over symbols (symbol table) in the PE file typedef int (*iterSymbol)(void *, const std::string &, diff --git a/pe-parser-library/src/parse.cpp b/pe-parser-library/src/parse.cpp index 6afcd43..cd2538f 100644 --- a/pe-parser-library/src/parse.cpp +++ b/pe-parser-library/src/parse.cpp @@ -62,6 +62,11 @@ struct reloc { reloc_type type; }; +struct debugent { + std::uint32_t type; + bounded_buffer *data; +}; + #define SYMBOL_NAME_OFFSET(sn) (static_cast(sn.data >> 32)) #define SYMBOL_TYPE_HI(x) (x.type >> 8) @@ -124,6 +129,7 @@ struct parsed_pe_internal { std::vector relocs; std::vector exports; std::vector symbols; + std::vector debugdirs; }; // String representation of Rich header object types @@ -1806,6 +1812,103 @@ bool getRelocations(parsed_pe *p) { return true; } +bool getDebugDir(parsed_pe *p) { + data_directory debugDir; + if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { + debugDir = p->peHeader.nt.OptionalHeader.DataDirectory[DIR_DEBUG]; + } else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) { + debugDir = p->peHeader.nt.OptionalHeader64.DataDirectory[DIR_DEBUG]; + } else { + return false; + } + + if (debugDir.Size != 0) { + section d; + VA vaAddr; + if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { + vaAddr = + debugDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase; + } else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) { + vaAddr = + debugDir.VirtualAddress + p->peHeader.nt.OptionalHeader64.ImageBase; + } else { + return false; + } + + uint32_t numOfDebugEnts = debugDir.Size / sizeof(debug_dir_entry); + + // + // this will return the rdata section, where the debug directories are + // + if (!getSecForVA(p->internal->secs, vaAddr, d)) { + return false; + } + + // + // get debug directory from this section + // + auto rvaofft = static_cast(vaAddr - d.sectionBase); + + debug_dir_entry emptyEnt; + memset(&emptyEnt, 0, sizeof(debug_dir_entry)); + + for (uint32_t i = 0; i < numOfDebugEnts; i++) { + debug_dir_entry curEnt = emptyEnt; + + READ_DWORD(d.sectionData, rvaofft, curEnt, Characteristics); + READ_DWORD(d.sectionData, rvaofft, curEnt, TimeStamp); + READ_WORD(d.sectionData, rvaofft, curEnt, MajorVersion); + READ_WORD(d.sectionData, rvaofft, curEnt, MinorVersion); + READ_DWORD(d.sectionData, rvaofft, curEnt, Type); + READ_DWORD(d.sectionData, rvaofft, curEnt, SizeOfData); + READ_DWORD(d.sectionData, rvaofft, curEnt, AddressOfRawData); + READ_DWORD(d.sectionData, rvaofft, curEnt, PointerToRawData); + + // are all the fields in curEnt null? then we break + if (curEnt.SizeOfData == 0 && curEnt.AddressOfRawData == 0 && + curEnt.PointerToRawData == 0) { + break; + } + + // + // Get the address of the data + // + VA rawData; + if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { + rawData = + curEnt.AddressOfRawData + p->peHeader.nt.OptionalHeader.ImageBase; + } else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) { + rawData = + curEnt.AddressOfRawData + p->peHeader.nt.OptionalHeader64.ImageBase; + } else { + return false; + } + + // + // Get the section for the data + // + section dataSec; + if (!getSecForVA(p->internal->secs, rawData, dataSec)) { + return false; + } + + debugent ent; + + auto dataofft = static_cast(rawData - dataSec.sectionBase); + ent.type = curEnt.Type; + ent.data = makeBufferFromPointer( + reinterpret_cast(dataSec.sectionData->buf + dataofft), + curEnt.SizeOfData); + + p->internal->debugdirs.push_back(ent); + + rvaofft += sizeof(debug_dir_entry); + } + } + + return true; +} + bool getImports(parsed_pe *p) { data_directory importDir; if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { @@ -2434,6 +2537,13 @@ parsed_pe *ParsePEFromBuffer(bounded_buffer *buffer) { return nullptr; } + if (!getDebugDir(p)) { + deleteBuffer(remaining); + DestructParsedPE(p); + PE_ERR(PEERR_MAGIC); + return nullptr; + } + // Get imports if (!getImports(p)) { deleteBuffer(remaining); @@ -2493,6 +2603,12 @@ void DestructParsedPE(parsed_pe *p) { } } + for (debugent d : p->internal->debugdirs) { + if (d.data != nullptr) { + deleteBuffer(d.data); + } + } + delete p->internal; delete p; return; @@ -2524,6 +2640,16 @@ void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd) { return; } +void IterDebugs(parsed_pe *pe, iterDebug cb, void *cbd) { + std::vector &l = pe->internal->debugdirs; + + for (debugent &d : l) { + if (cb(cbd, d.type, d.data) != 0) { + break; + } + } +} + // Iterate over symbols (symbol table) in the PE file void IterSymbols(parsed_pe *pe, iterSymbol cb, void *cbd) { std::vector &l = pe->internal->symbols;