Skip to content

Commit

Permalink
Merge pull request #173 from trailofbits/yarden/debug-dirs
Browse files Browse the repository at this point in the history
parse debug directories
  • Loading branch information
yardenshafir authored Nov 14, 2022
2 parents 29220c9 + 7d8d717 commit abfb09e
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
78 changes: 78 additions & 0 deletions dump-pe/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(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<int>(data->buf[i]);
}
std::cout << "\n";

return 0;
}

int printSymbols(void *N,
const std::string &strName,
const uint32_t &value,
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions pe-parser-library/include/pe-parse/nt-headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions pe-parser-library/include/pe-parse/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 &,
Expand Down
126 changes: 126 additions & 0 deletions pe-parser-library/src/parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::uint32_t>(sn.data >> 32))
#define SYMBOL_TYPE_HI(x) (x.type >> 8)

Expand Down Expand Up @@ -124,6 +129,7 @@ struct parsed_pe_internal {
std::vector<reloc> relocs;
std::vector<exportent> exports;
std::vector<symbol> symbols;
std::vector<debugent> debugdirs;
};

// String representation of Rich header object types
Expand Down Expand Up @@ -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<std::uint32_t>(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<std::uint32_t>(rawData - dataSec.sectionBase);
ent.type = curEnt.Type;
ent.data = makeBufferFromPointer(
reinterpret_cast<std::uint8_t *>(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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<debugent> &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<symbol> &l = pe->internal->symbols;
Expand Down

0 comments on commit abfb09e

Please sign in to comment.