4
0
mirror of https://github.com/QuasarApp/pe-parse.git synced 2025-05-11 18:59:34 +00:00
This commit is contained in:
munin 2013-11-11 15:09:57 -05:00
parent 42cf2a4bb0
commit 5531d3a249
7 changed files with 416 additions and 70 deletions

@ -1,7 +1,7 @@
include_directories(${pe-parse_SOURCE_DIR}/parser-library)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../parser-library)
add_executable( dump-prog
dump.cpp )
target_link_libraries( dump-prog
parser-library )
pe-parser-library )

@ -37,14 +37,25 @@ string to_string(T t, ios_base & (*f)(ios_base&)) {
return oss.str();
}
void printImports(void *N, VA impAddr, string &modName, string &symName) {
int printExps(void *N, VA funcAddr, std::string &mod, std::string &func) {
cout << "EXP: ";
cout << mod;
cout << "!";
cout << func;
cout << ":";
cout << to_string<uint32_t>(funcAddr, hex);
cout << endl;
return 0;
}
int printImports(void *N, VA impAddr, string &modName, string &symName) {
cout << "0x" << to_string<uint32_t>(impAddr, hex);
cout << " " << modName << "!" << symName;
cout << endl;
return;
return 0;
}
void printRelocs(void *N, VA relocAddr, reloc_type type) {
int printRelocs(void *N, VA relocAddr, reloc_type type) {
cout << "TYPE: ";
switch(type) {
case ABSOLUTE:
@ -75,14 +86,19 @@ void printRelocs(void *N, VA relocAddr, reloc_type type) {
cout << " VA: 0x" << to_string<VA>(relocAddr, hex) << endl;
return;
return 0 ;
}
void printSecs(void *N, RVA secBase, string &secName, bounded_buffer *data) {
int printSecs(void *N,
VA secBase,
string &secName,
image_section_header s,
bounded_buffer *data)
{
cout << "Sec Name: " << secName << endl;
cout << "Sec Base: " << to_string<uint64_t>(secBase, hex) << endl;
cout << "Sec Size: " << to_string<uint64_t>(data->bufLen, dec) << endl;
return;
return 0;
}
int main(int argc, char *argv[]) {
@ -136,23 +152,30 @@ int main(int argc, char *argv[]) {
#undef DUMP_FIELD
#undef DUMP_DEC_FIELD
cout << "Imports: " << endl;
IterImpVAString(p, printImports, NULL);
cout << "Relocations: " << endl;
IterRelocs(p, printRelocs, NULL);
cout << "Sections: " << endl;
IterSec(p, printSecs, NULL);
cout << "Exports: " << endl;
IterExpVA(p, printExps, NULL);
//read the first 8 bytes from the entry point and print them
cout << "First 8 bytes from entry point (0x";
VA entryPoint = p->peHeader.nt.OptionalHeader.AddressOfEntryPoint +
p->peHeader.nt.OptionalHeader.ImageBase;
cout << to_string<VA>(entryPoint, hex);
cout << "):" << endl;
for(int i = 0; i < 8; i++) {
::uint8_t b;
ReadByteAtVA(p, i+entryPoint, b);
cout << " 0x" << to_string<uint32_t>(b, hex);
}
VA entryPoint;
if(GetEntryPoint(p, entryPoint)) {
cout << "First 8 bytes from entry point (0x";
cout << to_string<VA>(entryPoint, hex);
cout << "):" << endl;
for(int i = 0; i < 8; i++) {
::uint8_t b;
ReadByteAtVA(p, i+entryPoint, b);
cout << " 0x" << to_string<uint32_t>(b, hex);
}
cout << endl;
cout << endl;
}
DestructParsedPE(p);
}

@ -1,3 +1,3 @@
add_library(parser-library
add_library(pe-parser-library
buffer.cpp
parse.cpp)

@ -26,21 +26,32 @@ THE SOFTWARE.
#include <string.h>
#include "parse.h"
#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#endif
using namespace boost;
using namespace std;
struct buffer_detail {
#if 1
int fd;
#ifdef WIN32
HANDLE file;
HANDLE sec;
#else
int fd;
#endif
};
bool readByte(bounded_buffer *b, ::uint32_t offset, ::uint8_t &out) {
if(b == NULL) {
return false;
}
if(offset >= b->bufLen) {
return false;
}
@ -53,6 +64,10 @@ bool readByte(bounded_buffer *b, ::uint32_t offset, ::uint8_t &out) {
//TODO: perform endian swap as needed
bool readWord(bounded_buffer *b, ::uint32_t offset, ::uint16_t &out) {
if(b == NULL) {
return false;
}
if(offset >= b->bufLen) {
return false;
}
@ -65,6 +80,10 @@ bool readWord(bounded_buffer *b, ::uint32_t offset, ::uint16_t &out) {
//TODO: perform endian swap as needed
bool readDword(bounded_buffer *b, ::uint32_t offset, ::uint32_t &out) {
if(b == NULL) {
return false;
}
if(offset >= b->bufLen) {
return false;
}
@ -77,7 +96,26 @@ bool readDword(bounded_buffer *b, ::uint32_t offset, ::uint32_t &out) {
bounded_buffer *readFileToFileBuffer(const char *filePath) {
#if 1
#ifdef WIN32
HANDLE h = CreateFileA(filePath,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(h == INVALID_HANDLE_VALUE) {
return NULL;
}
DWORD fileSize = GetFileSize(h, NULL);
if(fileSize == INVALID_FILE_SIZE) {
CloseHandle(h);
return NULL;
}
#else
//only where we have mmap / open / etc
int fd = open(filePath, O_RDONLY);
@ -104,7 +142,28 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
p->detail = d;
//only where we have mmap / open / etc
#if 1
#ifdef WIN32
p->detail->file = h;
HANDLE hMap = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL);
if(hMap == NULL) {
CloseHandle(h);
return NULL;
}
p->detail->sec = hMap;
LPVOID ptr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(ptr == NULL) {
return NULL;
}
p->buf = (::uint8_t *)ptr;
p->bufLen = fileSize;
p->copy = false;
#else
p->detail->fd = fd;
struct stat s = {0};
@ -130,44 +189,15 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
p->copy = false;
#endif
#ifdef BUF_RAW
//open the file in binary mode
ifstream inFile(filePath, ios::in|ios::binary|ios::ate);
if(inFile.is_open()) {
size_t fileSize = inFile.tellg();
if(fileSize == 0) {
delete p;
return NULL;
}
p->buf = (::uint8_t *)malloc(fileSize);
if(p->buf == NULL) {
delete p;
return NULL;
}
memset(p->buf, 0, fileSize);
p->bufLen = fileSize;
p->copy = false;
inFile.seekg(0, ios::beg);
inFile.read((char *)p->buf, fileSize);
inFile.close();
} else {
delete p;
return NULL;
}
#endif
return p;
}
//split buffer inclusively from from to to by offset
bounded_buffer *splitBuffer(bounded_buffer *b, ::uint32_t from, ::uint32_t to) {
if(b == NULL) {
return NULL;
}
//safety checks
if(to < from || to > b->bufLen) {
return NULL;
@ -193,10 +223,13 @@ void deleteBuffer(bounded_buffer *b) {
}
if(b->copy == false) {
#ifdef WIN32
UnmapViewOfFile(b->buf);
CloseHandle(b->detail->sec);
CloseHandle(b->detail->file);
#else
munmap(b->buf, b->bufLen);
close(b->detail->fd);
#ifdef BUF_RAW
free(b->buf);
#endif
}
@ -205,3 +238,6 @@ void deleteBuffer(bounded_buffer *b) {
return;
}
uint64_t bufLen(bounded_buffer *b) {
return b->bufLen;
}

@ -52,6 +52,45 @@ const boost::uint16_t DIR_IAT = 12;
const boost::uint16_t DIR_DELAY_IMPORT = 13;
const boost::uint16_t DIR_COM_DESCRIPTOR = 14;
const boost::uint32_t IMAGE_SCN_TYPE_NO_PAD = 0x00000008;
const boost::uint32_t IMAGE_SCN_CNT_CODE = 0x00000020;
const boost::uint32_t IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
const boost::uint32_t IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
const boost::uint32_t IMAGE_SCN_LNK_OTHER = 0x00000100;
const boost::uint32_t IMAGE_SCN_LNK_INFO = 0x00000200;
const boost::uint32_t IMAGE_SCN_LNK_REMOVE = 0x00000800;
const boost::uint32_t IMAGE_SCN_LNK_COMDAT = 0x00001000;
const boost::uint32_t IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000;
const boost::uint32_t IMAGE_SCN_GPREL = 0x00008000;
const boost::uint32_t IMAGE_SCN_MEM_FARDATA = 0x00008000;
const boost::uint32_t IMAGE_SCN_MEM_PURGEABLE = 0x00020000;
const boost::uint32_t IMAGE_SCN_MEM_16BIT = 0x00020000;
const boost::uint32_t IMAGE_SCN_MEM_LOCKED = 0x00040000;
const boost::uint32_t IMAGE_SCN_MEM_PRELOAD = 0x00080000;
const boost::uint32_t IMAGE_SCN_ALIGN_1BYTES = 0x00100000;
const boost::uint32_t IMAGE_SCN_ALIGN_2BYTES = 0x00200000;
const boost::uint32_t IMAGE_SCN_ALIGN_4BYTES = 0x00300000;
const boost::uint32_t IMAGE_SCN_ALIGN_8BYTES = 0x00400000;
const boost::uint32_t IMAGE_SCN_ALIGN_16BYTES = 0x00500000;
const boost::uint32_t IMAGE_SCN_ALIGN_32BYTES = 0x00600000;
const boost::uint32_t IMAGE_SCN_ALIGN_64BYTES = 0x00700000;
const boost::uint32_t IMAGE_SCN_ALIGN_128BYTES = 0x00800000;
const boost::uint32_t IMAGE_SCN_ALIGN_256BYTES = 0x00900000;
const boost::uint32_t IMAGE_SCN_ALIGN_512BYTES = 0x00A00000;
const boost::uint32_t IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000;
const boost::uint32_t IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000;
const boost::uint32_t IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000;
const boost::uint32_t IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
const boost::uint32_t IMAGE_SCN_ALIGN_MASK = 0x00F00000;
const boost::uint32_t IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
const boost::uint32_t IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
const boost::uint32_t IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
const boost::uint32_t IMAGE_SCN_MEM_NOT_PAGED = 0x08000000;
const boost::uint32_t IMAGE_SCN_MEM_SHARED = 0x10000000;
const boost::uint32_t IMAGE_SCN_MEM_EXECUTE = 0x20000000;
const boost::uint32_t IMAGE_SCN_MEM_READ = 0x40000000;
const boost::uint32_t IMAGE_SCN_MEM_WRITE = 0x80000000;
struct dos_header {
boost::uint16_t e_magic;
boost::uint16_t e_cblp;
@ -153,6 +192,20 @@ struct import_dir_entry {
boost::uint32_t AddressRVA;
};
struct export_dir_table {
boost::uint32_t ExportFlags;
boost::uint32_t TimeDateStamp;
boost::uint16_t MajorVersion;
boost::uint16_t MinorVersion;
boost::uint32_t NameRVA;
boost::uint32_t OrdinalBase;
boost::uint32_t AddressTableEntries;
boost::uint32_t NumberOfNamePointers;
boost::uint32_t ExportAddressTableRVA;
boost::uint32_t NamePointerRVA;
boost::uint32_t OrdinalTableRVA;
};
enum reloc_type {
ABSOLUTE = 0,
HIGH = 1,

@ -25,6 +25,7 @@ THE SOFTWARE.
#include <list>
#include "parse.h"
#include "nt-headers.h"
#include <to_string.h>
using namespace std;
using namespace boost;
@ -42,6 +43,12 @@ struct importent {
string moduleName;
};
struct exportent {
VA addr;
string symbolName;
string moduleName;
};
struct reloc {
VA shiftedAddr;
reloc_type type;
@ -51,6 +58,7 @@ struct parsed_pe_internal {
list<section> secs;
list<importent> imports;
list<reloc> relocs;
list<exportent> exports;
};
bool getSecForVA(list<section> &secs, VA v, section &sec) {
@ -86,7 +94,9 @@ bool getSections( bounded_buffer *b,
::uint32_t o = i*sizeof(image_section_header);
for(::uint32_t k = 0; k < NT_SHORT_NAME_LEN; k++) {
readByte(b, o+k, curSec.Name[k]);
if(readByte(b, o+k, curSec.Name[k]) == false) {
return false;
}
}
#define READ_WORD(x) \
if(readWord(b, o+_offset(image_section_header, x), curSec.x) == false) { \
@ -281,7 +291,9 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
//start by reading MZ
::uint16_t tmp = 0;
::uint32_t curOffset = 0;
readWord(file, curOffset, tmp);
if(readWord(file, curOffset, tmp) == false) {
return false;
}
if(tmp != MZ_MAGIC) {
return false;
}
@ -345,6 +357,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
delete p;
return NULL;
}
//get exports
data_directory exportDir =
p->peHeader.nt.OptionalHeader.DataDirectory[DIR_EXPORT];
@ -357,6 +370,181 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
return NULL;
}
::uint32_t rvaofft = addr - s.sectionBase;
//get the name of this module
::uint32_t nameRva;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, NameRVA),
nameRva) == false)
{
return NULL;
}
::uint32_t nameVA = nameRva + p->peHeader.nt.OptionalHeader.ImageBase;
section nameSec;
if(getSecForVA(p->internal->secs, nameVA, nameSec) == false) {
return NULL;
}
::uint32_t nameOff = nameVA - nameSec.sectionBase;
string modName;
::uint8_t c;
do {
if(readByte(nameSec.sectionData, nameOff, c) == false) {
return NULL;
}
if(c == 0) {
break;
}
modName.push_back(c);
nameOff++;
}while(true);
//now, get all the named export symbols
::uint32_t numNames;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, NumberOfNamePointers),
numNames) == false)
{
return NULL;
}
if(numNames > 0) {
//get the names section
::uint32_t namesRVA;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, NamePointerRVA),
namesRVA) == false)
{
return NULL;
}
::uint32_t namesVA =
namesRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section namesSec;
if(getSecForVA(p->internal->secs, namesVA, namesSec) == false) {
return NULL;
}
::uint32_t namesOff = namesVA - namesSec.sectionBase;
//get the EAT section
::uint32_t eatRVA;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, ExportAddressTableRVA),
eatRVA) == false)
{
return NULL;
}
::uint32_t eatVA =
eatRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section eatSec;
if(getSecForVA(p->internal->secs, eatVA, eatSec) == false) {
return NULL;
}
::uint32_t eatOff = eatVA - eatSec.sectionBase;
//get the ordinal base
::uint32_t ordinalBase;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, OrdinalBase),
ordinalBase) == false)
{
return NULL;
}
//get the ordinal table
::uint32_t ordinalTableRVA;
if(readDword( s.sectionData,
rvaofft+_offset(export_dir_table, OrdinalTableRVA),
ordinalTableRVA) == false)
{
return NULL;
}
::uint32_t ordinalTableVA =
ordinalTableRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section ordinalTableSec;
if(getSecForVA(p->internal->secs, ordinalTableVA, ordinalTableSec) == false) {
return NULL;
}
::uint32_t ordinalOff = ordinalTableVA - ordinalTableSec.sectionBase;
for(::uint32_t i = 0; i < numNames; i++) {
::uint32_t curNameRVA;
if(readDword( namesSec.sectionData,
namesOff+(i*sizeof(::uint32_t)),
curNameRVA) == false)
{
return NULL;
}
::uint32_t curNameVA =
curNameRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section curNameSec;
if(getSecForVA(p->internal->secs, curNameVA, curNameSec) == false) {
return NULL;
}
::uint32_t curNameOff = curNameVA - curNameSec.sectionBase;
string symName;
::uint8_t d;
do {
if(readByte(curNameSec.sectionData, curNameOff, d) == false) {
return NULL;
}
if(d == 0) {
break;
}
symName.push_back(d);
curNameOff++;
}while(true);
//now, for this i, look it up in the ExportOrdinalTable
::uint16_t ordinal;
if(readWord(ordinalTableSec.sectionData,
ordinalOff+(i*sizeof(uint16_t)),
ordinal) == false)
{
return NULL;
}
//::uint32_t eatIdx = ordinal - ordinalBase;
::uint32_t eatIdx = (ordinal*sizeof(uint32_t));
::uint32_t symRVA;
if(readDword(eatSec.sectionData, eatOff+eatIdx, symRVA) == false) {
return NULL;
}
bool isForwarded =
((symRVA >= exportDir.VirtualAddress) &&
(symRVA < exportDir.VirtualAddress+exportDir.Size));
if(isForwarded == false) {
::uint32_t symVA = symRVA + p->peHeader.nt.OptionalHeader.ImageBase;
exportent a;
a.addr = symVA;
a.symbolName = symName;
a.moduleName = modName;
p->internal->exports.push_back(a);
}
}
}
}
//get relocations, if exist
@ -487,7 +675,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
break;
}
modName.push_back(c);
modName.push_back(toupper(c));
nameOff++;
}while(true);
@ -556,6 +744,20 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
p->internal->imports.push_back(ent);
} else {
//import by ordinal
//mask out 'val' so that oval is the low 16 bits of 'val'
::uint16_t oval = (val & ~0xFFFF0000);
string symName =
"ORDINAL_" + modName + "_" + to_string<uint32_t>(oval, dec);
importent ent;
ent.addr = offInTable +
curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
ent.symbolName = symName;
ent.moduleName = modName;
p->internal->imports.push_back(ent);
}
lookupOff += sizeof(::uint32_t);
@ -584,7 +786,9 @@ void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd) {
for(list<importent>::iterator it = l.begin(), e = l.end(); it != e; ++it) {
importent i = *it;
cb(cbd, i.addr, i.moduleName, i.symbolName);
if(cb(cbd, i.addr, i.moduleName, i.symbolName) != 0) {
break;
}
}
return;
@ -596,7 +800,9 @@ void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd) {
for(list<reloc>::iterator it = l.begin(), e = l.end(); it != e; ++it) {
reloc r = *it;
cb(cbd, r.shiftedAddr, r.type);
if(cb(cbd, r.shiftedAddr, r.type) != 0) {
break;
}
}
return;
@ -604,6 +810,15 @@ void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd) {
//iterate over the exports by VA
void IterExpVA(parsed_pe *pe, iterExp cb, void *cbd) {
list<exportent> &l = pe->internal->exports;
for(list<exportent>::iterator it = l.begin(), e = l.end(); it != e; ++it) {
exportent i = *it;
if(cb(cbd, i.addr, i.moduleName, i.symbolName)) {
break;
}
}
return;
}
@ -617,7 +832,9 @@ void IterSec(parsed_pe *pe, iterSec cb, void *cbd) {
++sit)
{
section s = *sit;
cb(cbd, s.sectionBase, s.sectionName, s.sectionData);
if(cb(cbd, s.sectionBase, s.sectionName, s.sec, s.sectionData) != 0) {
break;
}
}
return;
@ -635,3 +852,16 @@ bool ReadByteAtVA(parsed_pe *pe, VA v, ::uint8_t &b) {
return readByte(s.sectionData, off, b);
}
bool GetEntryPoint(parsed_pe *pe, VA &v) {
if(pe != NULL) {
nt_header_32 *nthdr = &pe->peHeader.nt;
v = nthdr->OptionalHeader.AddressOfEntryPoint + nthdr->OptionalHeader.ImageBase;
return true;
}
return false;
}

@ -30,7 +30,7 @@ THE SOFTWARE.
#include "nt-headers.h"
typedef boost::uint32_t RVA;
typedef boost::uint32_t VA;
typedef boost::uint64_t VA;
struct buffer_detail;
@ -48,6 +48,7 @@ bool readDword(bounded_buffer *b, boost::uint32_t offset, boost::uint32_t &out);
bounded_buffer *readFileToFileBuffer(const char *filePath);
bounded_buffer *splitBuffer(bounded_buffer *b, boost::uint32_t from, boost::uint32_t to);
void deleteBuffer(bounded_buffer *b);
uint64_t bufLen(bounded_buffer *b);
struct parsed_pe_internal;
@ -68,22 +69,25 @@ parsed_pe *ParsePEFromFile(const char *filePath);
void DestructParsedPE(parsed_pe *pe);
//iterate over the imports by RVA and string
typedef void (*iterVAStr)(void *, VA, std::string &, std::string &);
typedef int (*iterVAStr)(void *, VA, std::string &, std::string &);
void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd);
//iterate over relocations in the PE file
typedef void (*iterReloc)(void *, VA, reloc_type);
typedef int (*iterReloc)(void *, VA, reloc_type);
void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd);
//iterate over the exports
typedef void (*iterExp)(void *, VA, std::string &, std::string &);
typedef int (*iterExp)(void *, VA, std::string &, std::string &);
void IterExpVA(parsed_pe *pe, iterExp cb, void *cbd);
//iterate over sections
typedef void (*iterSec)(void *, RVA secBase, std::string &, bounded_buffer *b);
typedef int (*iterSec)(void *, VA secBase, std::string &, image_section_header, bounded_buffer *b);
void IterSec(parsed_pe *pe, iterSec cb, void *cbd);
//get byte at VA in PE
bool ReadByteAtVA(parsed_pe *pe, VA v, boost::uint8_t &b);
//get entry point into PE
bool GetEntryPoint(parsed_pe *pe, VA &v);
#endif