Skip to content

Commit abfb09e

Browse files
authored
Merge pull request #173 from trailofbits/yarden/debug-dirs
parse debug directories
2 parents 29220c9 + 7d8d717 commit abfb09e

File tree

4 files changed

+219
-0
lines changed

4 files changed

+219
-0
lines changed

dump-pe/main.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,81 @@ int printRelocs(void *N, const VA &relocAddr, const reloc_type &type) {
119119
return 0;
120120
}
121121

122+
int printDebugs(void *N,
123+
const std::uint32_t &type,
124+
const bounded_buffer *data) {
125+
static_cast<void>(N);
126+
127+
std::cout << "Debug Directory Type: ";
128+
switch (type) {
129+
case 0:
130+
std::cout << "IMAGE_DEBUG_TYPE_UNKNOWN";
131+
break;
132+
case 1:
133+
std::cout << "IMAGE_DEBUG_TYPE_COFF";
134+
break;
135+
case 2:
136+
std::cout << "IMAGE_DEBUG_TYPE_CODEVIEW";
137+
break;
138+
case 3:
139+
std::cout << "IMAGE_DEBUG_TYPE_FPO";
140+
break;
141+
case 4:
142+
std::cout << "IMAGE_DEBUG_TYPE_MISC";
143+
break;
144+
case 5:
145+
std::cout << "IMAGE_DEBUG_TYPE_EXCEPTION";
146+
break;
147+
case 6:
148+
std::cout << "IMAGE_DEBUG_TYPE_FIXUP";
149+
break;
150+
case 7:
151+
std::cout << "IMAGE_DEBUG_TYPE_OMAP_TO_SRC";
152+
break;
153+
case 8:
154+
std::cout << "IMAGE_DEBUG_TYPE_OMAP_FROM_SRC";
155+
break;
156+
case 9:
157+
std::cout << "IMAGE_DEBUG_TYPE_BORLAND";
158+
break;
159+
case 10:
160+
std::cout << "IMAGE_DEBUG_TYPE_RESERVED10";
161+
break;
162+
case 11:
163+
std::cout << "IMAGE_DEBUG_TYPE_CLSID";
164+
break;
165+
case 12:
166+
std::cout << "IMAGE_DEBUG_TYPE_VC_FEATURE";
167+
break;
168+
case 13:
169+
std::cout << "IMAGE_DEBUG_TYPE_POGO";
170+
break;
171+
case 14:
172+
std::cout << "IMAGE_DEBUG_TYPE_ILTCG";
173+
break;
174+
case 15:
175+
std::cout << "IMAGE_DEBUG_TYPE_MPX";
176+
break;
177+
case 16:
178+
std::cout << "IMAGE_DEBUG_TYPE_REPRO";
179+
break;
180+
case 20:
181+
std::cout << "IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS";
182+
break;
183+
default:
184+
std::cout << "INVALID";
185+
break;
186+
}
187+
std::cout << "\n";
188+
std::cout << "Debug Directory Data: ";
189+
for (uint32_t i = 0; i < data->bufLen; i++) {
190+
std::cout << " 0x" << std::hex << static_cast<int>(data->buf[i]);
191+
}
192+
std::cout << "\n";
193+
194+
return 0;
195+
}
196+
122197
int printSymbols(void *N,
123198
const std::string &strName,
124199
const uint32_t &value,
@@ -448,6 +523,9 @@ int main(int argc, char *argv[]) {
448523
std::cout << "Relocations: "
449524
<< "\n";
450525
IterRelocs(p, printRelocs, NULL);
526+
std::cout << "Debug Directories: "
527+
<< "\n";
528+
IterDebugs(p, printDebugs, NULL);
451529
std::cout << "Symbols (symbol table): "
452530
<< "\n";
453531
IterSymbols(p, printSymbols, NULL);

pe-parser-library/include/pe-parse/nt-headers.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,17 @@ struct export_dir_table {
452452
std::uint32_t OrdinalTableRVA;
453453
};
454454

455+
struct debug_dir_entry {
456+
std::uint32_t Characteristics;
457+
std::uint32_t TimeStamp;
458+
std::uint16_t MajorVersion;
459+
std::uint16_t MinorVersion;
460+
std::uint32_t Type;
461+
std::uint32_t SizeOfData;
462+
std::uint32_t AddressOfRawData;
463+
std::uint32_t PointerToRawData;
464+
};
465+
455466
enum reloc_type {
456467
RELOC_ABSOLUTE = 0,
457468
RELOC_HIGH = 1,

pe-parser-library/include/pe-parse/parse.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd);
222222
typedef int (*iterReloc)(void *, const VA &, const reloc_type &);
223223
void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd);
224224

225+
// iterate over debug directories in the PE file
226+
typedef int (*iterDebug)(void *, const std::uint32_t &, const bounded_buffer *);
227+
void IterDebugs(parsed_pe *pe, iterDebug cb, void *cbd);
228+
225229
// Iterate over symbols (symbol table) in the PE file
226230
typedef int (*iterSymbol)(void *,
227231
const std::string &,

pe-parser-library/src/parse.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ struct reloc {
6262
reloc_type type;
6363
};
6464

65+
struct debugent {
66+
std::uint32_t type;
67+
bounded_buffer *data;
68+
};
69+
6570
#define SYMBOL_NAME_OFFSET(sn) (static_cast<std::uint32_t>(sn.data >> 32))
6671
#define SYMBOL_TYPE_HI(x) (x.type >> 8)
6772

@@ -124,6 +129,7 @@ struct parsed_pe_internal {
124129
std::vector<reloc> relocs;
125130
std::vector<exportent> exports;
126131
std::vector<symbol> symbols;
132+
std::vector<debugent> debugdirs;
127133
};
128134

129135
// String representation of Rich header object types
@@ -1806,6 +1812,103 @@ bool getRelocations(parsed_pe *p) {
18061812
return true;
18071813
}
18081814

1815+
bool getDebugDir(parsed_pe *p) {
1816+
data_directory debugDir;
1817+
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
1818+
debugDir = p->peHeader.nt.OptionalHeader.DataDirectory[DIR_DEBUG];
1819+
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
1820+
debugDir = p->peHeader.nt.OptionalHeader64.DataDirectory[DIR_DEBUG];
1821+
} else {
1822+
return false;
1823+
}
1824+
1825+
if (debugDir.Size != 0) {
1826+
section d;
1827+
VA vaAddr;
1828+
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
1829+
vaAddr =
1830+
debugDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
1831+
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
1832+
vaAddr =
1833+
debugDir.VirtualAddress + p->peHeader.nt.OptionalHeader64.ImageBase;
1834+
} else {
1835+
return false;
1836+
}
1837+
1838+
uint32_t numOfDebugEnts = debugDir.Size / sizeof(debug_dir_entry);
1839+
1840+
//
1841+
// this will return the rdata section, where the debug directories are
1842+
//
1843+
if (!getSecForVA(p->internal->secs, vaAddr, d)) {
1844+
return false;
1845+
}
1846+
1847+
//
1848+
// get debug directory from this section
1849+
//
1850+
auto rvaofft = static_cast<std::uint32_t>(vaAddr - d.sectionBase);
1851+
1852+
debug_dir_entry emptyEnt;
1853+
memset(&emptyEnt, 0, sizeof(debug_dir_entry));
1854+
1855+
for (uint32_t i = 0; i < numOfDebugEnts; i++) {
1856+
debug_dir_entry curEnt = emptyEnt;
1857+
1858+
READ_DWORD(d.sectionData, rvaofft, curEnt, Characteristics);
1859+
READ_DWORD(d.sectionData, rvaofft, curEnt, TimeStamp);
1860+
READ_WORD(d.sectionData, rvaofft, curEnt, MajorVersion);
1861+
READ_WORD(d.sectionData, rvaofft, curEnt, MinorVersion);
1862+
READ_DWORD(d.sectionData, rvaofft, curEnt, Type);
1863+
READ_DWORD(d.sectionData, rvaofft, curEnt, SizeOfData);
1864+
READ_DWORD(d.sectionData, rvaofft, curEnt, AddressOfRawData);
1865+
READ_DWORD(d.sectionData, rvaofft, curEnt, PointerToRawData);
1866+
1867+
// are all the fields in curEnt null? then we break
1868+
if (curEnt.SizeOfData == 0 && curEnt.AddressOfRawData == 0 &&
1869+
curEnt.PointerToRawData == 0) {
1870+
break;
1871+
}
1872+
1873+
//
1874+
// Get the address of the data
1875+
//
1876+
VA rawData;
1877+
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
1878+
rawData =
1879+
curEnt.AddressOfRawData + p->peHeader.nt.OptionalHeader.ImageBase;
1880+
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
1881+
rawData =
1882+
curEnt.AddressOfRawData + p->peHeader.nt.OptionalHeader64.ImageBase;
1883+
} else {
1884+
return false;
1885+
}
1886+
1887+
//
1888+
// Get the section for the data
1889+
//
1890+
section dataSec;
1891+
if (!getSecForVA(p->internal->secs, rawData, dataSec)) {
1892+
return false;
1893+
}
1894+
1895+
debugent ent;
1896+
1897+
auto dataofft = static_cast<std::uint32_t>(rawData - dataSec.sectionBase);
1898+
ent.type = curEnt.Type;
1899+
ent.data = makeBufferFromPointer(
1900+
reinterpret_cast<std::uint8_t *>(dataSec.sectionData->buf + dataofft),
1901+
curEnt.SizeOfData);
1902+
1903+
p->internal->debugdirs.push_back(ent);
1904+
1905+
rvaofft += sizeof(debug_dir_entry);
1906+
}
1907+
}
1908+
1909+
return true;
1910+
}
1911+
18091912
bool getImports(parsed_pe *p) {
18101913
data_directory importDir;
18111914
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
@@ -2434,6 +2537,13 @@ parsed_pe *ParsePEFromBuffer(bounded_buffer *buffer) {
24342537
return nullptr;
24352538
}
24362539

2540+
if (!getDebugDir(p)) {
2541+
deleteBuffer(remaining);
2542+
DestructParsedPE(p);
2543+
PE_ERR(PEERR_MAGIC);
2544+
return nullptr;
2545+
}
2546+
24372547
// Get imports
24382548
if (!getImports(p)) {
24392549
deleteBuffer(remaining);
@@ -2493,6 +2603,12 @@ void DestructParsedPE(parsed_pe *p) {
24932603
}
24942604
}
24952605

2606+
for (debugent d : p->internal->debugdirs) {
2607+
if (d.data != nullptr) {
2608+
deleteBuffer(d.data);
2609+
}
2610+
}
2611+
24962612
delete p->internal;
24972613
delete p;
24982614
return;
@@ -2524,6 +2640,16 @@ void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd) {
25242640
return;
25252641
}
25262642

2643+
void IterDebugs(parsed_pe *pe, iterDebug cb, void *cbd) {
2644+
std::vector<debugent> &l = pe->internal->debugdirs;
2645+
2646+
for (debugent &d : l) {
2647+
if (cb(cbd, d.type, d.data) != 0) {
2648+
break;
2649+
}
2650+
}
2651+
}
2652+
25272653
// Iterate over symbols (symbol table) in the PE file
25282654
void IterSymbols(parsed_pe *pe, iterSymbol cb, void *cbd) {
25292655
std::vector<symbol> &l = pe->internal->symbols;

0 commit comments

Comments
 (0)