Merge pull request #9 from wxsBSD/pe32_plus_and_more

Implement PE32+ and error reporting.
This commit is contained in:
Andrew Ruef 2014-03-07 23:14:40 -05:00
commit f59587712e
7 changed files with 709 additions and 184 deletions

View File

@ -29,20 +29,12 @@ THE SOFTWARE.
using namespace std;
using namespace boost;
template <class T>
static
string to_string(T t, ios_base & (*f)(ios_base&)) {
ostringstream oss;
oss << f << t;
return oss.str();
}
int printExps(void *N, VA funcAddr, std::string &mod, std::string &func) {
cout << "EXP: ";
cout << mod;
cout << "!";
cout << func;
cout << ":";
cout << ": 0x";
cout << to_string<uint32_t>(funcAddr, hex);
cout << endl;
return 0;
@ -95,16 +87,16 @@ int printRsrc(void *N,
if (r.type_str.length())
cout << "Type (string): " << r.type_str << endl;
else
cout << "Type: " << to_string<uint32_t>(r.type, hex) << endl;
cout << "Type: 0x" << to_string<uint32_t>(r.type, hex) << endl;
if (r.name_str.length())
cout << "Name (string): " << r.name_str << endl;
else
cout << "Name: " << to_string<uint32_t>(r.name, hex) << endl;
cout << "Name: 0x" << to_string<uint32_t>(r.name, hex) << endl;
if (r.lang_str.length())
cout << "Lang (string): " << r.lang_str << endl;
else
cout << "Lang: " << to_string<uint32_t>(r.lang, hex) << endl;
cout << "Codepage: " << to_string<uint32_t>(r.codepage, hex) << endl;
cout << "Lang: 0x" << to_string<uint32_t>(r.lang, hex) << endl;
cout << "Codepage: 0x" << to_string<uint32_t>(r.codepage, hex) << endl;
cout << "RVA: " << to_string<uint32_t>(r.RVA, dec) << endl;
cout << "Size: " << to_string<uint32_t>(r.size, dec) << endl;
return 0;
@ -117,7 +109,7 @@ int printSecs(void *N,
bounded_buffer *data)
{
cout << "Sec Name: " << secName << endl;
cout << "Sec Base: " << to_string<uint64_t>(secBase, hex) << endl;
cout << "Sec Base: 0x" << to_string<uint64_t>(secBase, hex) << endl;
cout << "Sec Size: " << to_string<uint64_t>(data->bufLen, dec) << endl;
return 0;
}
@ -130,45 +122,73 @@ int main(int argc, char *argv[]) {
//print out some things
#define DUMP_FIELD(x) \
cout << "" #x << ": 0x"; \
cout << to_string<uint32_t>(p->peHeader.x, hex) << endl;
cout << to_string<uint32_t>(p->peHeader.nt.x, hex) << endl;
#define DUMP_DEC_FIELD(x) \
cout << "" #x << ": "; \
cout << to_string<uint32_t>(p->peHeader.x, dec) << endl;
cout << to_string<uint32_t>(p->peHeader.nt.x, dec) << endl;
DUMP_FIELD(nt.Signature);
DUMP_FIELD(nt.FileHeader.Machine);
DUMP_FIELD(nt.FileHeader.NumberOfSections);
DUMP_DEC_FIELD(nt.FileHeader.TimeDateStamp);
DUMP_FIELD(nt.FileHeader.PointerToSymbolTable);
DUMP_DEC_FIELD(nt.FileHeader.NumberOfSymbols);
DUMP_FIELD(nt.FileHeader.SizeOfOptionalHeader);
DUMP_FIELD(nt.FileHeader.Characteristics);
DUMP_FIELD(nt.OptionalHeader.Magic);
DUMP_DEC_FIELD(nt.OptionalHeader.MajorLinkerVersion);
DUMP_DEC_FIELD(nt.OptionalHeader.MinorLinkerVersion);
DUMP_FIELD(nt.OptionalHeader.SizeOfCode);
DUMP_FIELD(nt.OptionalHeader.SizeOfInitializedData);
DUMP_FIELD(nt.OptionalHeader.SizeOfUninitializedData);
DUMP_FIELD(nt.OptionalHeader.AddressOfEntryPoint);
DUMP_FIELD(nt.OptionalHeader.BaseOfCode);
DUMP_FIELD(nt.OptionalHeader.BaseOfData);
DUMP_FIELD(nt.OptionalHeader.ImageBase);
DUMP_FIELD(nt.OptionalHeader.SectionAlignment);
DUMP_FIELD(nt.OptionalHeader.FileAlignment);
DUMP_DEC_FIELD(nt.OptionalHeader.MajorOperatingSystemVersion);
DUMP_DEC_FIELD(nt.OptionalHeader.MinorOperatingSystemVersion);
DUMP_DEC_FIELD(nt.OptionalHeader.Win32VersionValue);
DUMP_FIELD(nt.OptionalHeader.SizeOfImage);
DUMP_FIELD(nt.OptionalHeader.SizeOfHeaders);
DUMP_FIELD(nt.OptionalHeader.CheckSum);
DUMP_FIELD(nt.OptionalHeader.Subsystem);
DUMP_FIELD(nt.OptionalHeader.DllCharacteristics);
DUMP_FIELD(nt.OptionalHeader.SizeOfStackReserve);
DUMP_FIELD(nt.OptionalHeader.SizeOfStackCommit);
DUMP_FIELD(nt.OptionalHeader.SizeOfHeapReserve);
DUMP_FIELD(nt.OptionalHeader.SizeOfHeapCommit);
DUMP_FIELD(nt.OptionalHeader.LoaderFlags);
DUMP_DEC_FIELD(nt.OptionalHeader.NumberOfRvaAndSizes);
DUMP_FIELD(Signature);
DUMP_FIELD(FileHeader.Machine);
DUMP_FIELD(FileHeader.NumberOfSections);
DUMP_DEC_FIELD(FileHeader.TimeDateStamp);
DUMP_FIELD(FileHeader.PointerToSymbolTable);
DUMP_DEC_FIELD(FileHeader.NumberOfSymbols);
DUMP_FIELD(FileHeader.SizeOfOptionalHeader);
DUMP_FIELD(FileHeader.Characteristics);
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
DUMP_FIELD(OptionalHeader.Magic);
DUMP_DEC_FIELD(OptionalHeader.MajorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader.MinorLinkerVersion);
DUMP_FIELD(OptionalHeader.SizeOfCode);
DUMP_FIELD(OptionalHeader.SizeOfInitializedData);
DUMP_FIELD(OptionalHeader.SizeOfUninitializedData);
DUMP_FIELD(OptionalHeader.AddressOfEntryPoint);
DUMP_FIELD(OptionalHeader.BaseOfCode);
DUMP_FIELD(OptionalHeader.BaseOfData);
DUMP_FIELD(OptionalHeader.ImageBase);
DUMP_FIELD(OptionalHeader.SectionAlignment);
DUMP_FIELD(OptionalHeader.FileAlignment);
DUMP_DEC_FIELD(OptionalHeader.MajorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader.MinorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader.Win32VersionValue);
DUMP_FIELD(OptionalHeader.SizeOfImage);
DUMP_FIELD(OptionalHeader.SizeOfHeaders);
DUMP_FIELD(OptionalHeader.CheckSum);
DUMP_FIELD(OptionalHeader.Subsystem);
DUMP_FIELD(OptionalHeader.DllCharacteristics);
DUMP_FIELD(OptionalHeader.SizeOfStackReserve);
DUMP_FIELD(OptionalHeader.SizeOfStackCommit);
DUMP_FIELD(OptionalHeader.SizeOfHeapReserve);
DUMP_FIELD(OptionalHeader.SizeOfHeapCommit);
DUMP_FIELD(OptionalHeader.LoaderFlags);
DUMP_DEC_FIELD(OptionalHeader.NumberOfRvaAndSizes);
} else {
DUMP_FIELD(OptionalHeader64.Magic);
DUMP_DEC_FIELD(OptionalHeader64.MajorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader64.MinorLinkerVersion);
DUMP_FIELD(OptionalHeader64.SizeOfCode);
DUMP_FIELD(OptionalHeader64.SizeOfInitializedData);
DUMP_FIELD(OptionalHeader64.SizeOfUninitializedData);
DUMP_FIELD(OptionalHeader64.AddressOfEntryPoint);
DUMP_FIELD(OptionalHeader64.BaseOfCode);
DUMP_FIELD(OptionalHeader64.ImageBase);
DUMP_FIELD(OptionalHeader64.SectionAlignment);
DUMP_FIELD(OptionalHeader64.FileAlignment);
DUMP_DEC_FIELD(OptionalHeader64.MajorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader64.MinorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader64.Win32VersionValue);
DUMP_FIELD(OptionalHeader64.SizeOfImage);
DUMP_FIELD(OptionalHeader64.SizeOfHeaders);
DUMP_FIELD(OptionalHeader64.CheckSum);
DUMP_FIELD(OptionalHeader64.Subsystem);
DUMP_FIELD(OptionalHeader64.DllCharacteristics);
DUMP_FIELD(OptionalHeader64.SizeOfStackReserve);
DUMP_FIELD(OptionalHeader64.SizeOfStackCommit);
DUMP_FIELD(OptionalHeader64.SizeOfHeapReserve);
DUMP_FIELD(OptionalHeader64.SizeOfHeapCommit);
DUMP_FIELD(OptionalHeader64.LoaderFlags);
DUMP_DEC_FIELD(OptionalHeader64.NumberOfRvaAndSizes);
}
#undef DUMP_FIELD
#undef DUMP_DEC_FIELD
@ -198,9 +218,14 @@ int main(int argc, char *argv[]) {
cout << endl;
}
cout << "Resources: " << endl;
IterRsrc(p, printRsrc, NULL);
DestructParsedPE(p);
}
else {
cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")" << endl;
cout << "Location: " << GetPEErrLoc() << endl;
}
}
return 0;
}

View File

@ -38,6 +38,9 @@ THE SOFTWARE.
using namespace boost;
using namespace std;
extern ::uint32_t err;
extern ::string err_loc;
struct buffer_detail {
#ifdef WIN32
HANDLE file;
@ -94,6 +97,21 @@ bool readDword(bounded_buffer *b, ::uint32_t offset, ::uint32_t &out) {
return true;
}
//TODO: perform endian swap as needed
bool readQword(bounded_buffer *b, ::uint32_t offset, ::uint64_t &out) {
if(b == NULL) {
return false;
}
if(offset >= b->bufLen) {
return false;
}
::uint64_t *tmp = (::uint64_t *)(b->buf+offset);
out = *tmp;
return true;
}
bounded_buffer *readFileToFileBuffer(const char *filePath) {
#ifdef WIN32
@ -120,6 +138,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
int fd = open(filePath, O_RDONLY);
if(fd == -1) {
PE_ERR(PEERR_OPEN);
return NULL;
}
#endif
@ -128,6 +147,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
bounded_buffer *p = new bounded_buffer();
if(p == NULL) {
PE_ERR(PEERR_MEM);
return NULL;
}
@ -136,6 +156,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
if(d == NULL) {
delete p;
PE_ERR(PEERR_MEM);
return NULL;
}
memset(d, 0, sizeof(buffer_detail));
@ -149,6 +170,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
if(hMap == NULL) {
CloseHandle(h);
PE_ERR(PEERR_MEM);
return NULL;
}
@ -157,6 +179,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
LPVOID ptr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(ptr == NULL) {
PE_ERR(PEERR_MEM);
return NULL;
}
@ -172,6 +195,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
close(fd);
delete d;
delete p;
PE_ERR(PEERR_STAT);
return NULL;
}
@ -181,6 +205,7 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
close(fd);
delete d;
delete p;
PE_ERR(PEERR_MEM);
return NULL;
}

View File

@ -35,6 +35,7 @@ const boost::uint16_t MZ_MAGIC = 0x5A4D;
const boost::uint32_t NT_MAGIC = 0x00004550;
const boost::uint16_t NUM_DIR_ENTRIES = 16;
const boost::uint16_t NT_OPTIONAL_32_MAGIC = 0x10B;
const boost::uint16_t NT_OPTIONAL_64_MAGIC = 0x20B;
const boost::uint16_t NT_SHORT_NAME_LEN = 8;
const boost::uint16_t DIR_EXPORT = 0;
const boost::uint16_t DIR_IMPORT = 1;
@ -162,10 +163,49 @@ struct optional_header_32 {
data_directory DataDirectory[NUM_DIR_ENTRIES];
};
/*
* This is used for PE32+ binaries. It is similar to optional_header_32
* except some fields don't exist here (BaseOfData), and others are bigger.
*/
struct optional_header_64 {
boost::uint16_t Magic;
boost::uint8_t MajorLinkerVersion;
boost::uint8_t MinorLinkerVersion;
boost::uint32_t SizeOfCode;
boost::uint32_t SizeOfInitializedData;
boost::uint32_t SizeOfUninitializedData;
boost::uint32_t AddressOfEntryPoint;
boost::uint32_t BaseOfCode;
boost::uint64_t ImageBase;
boost::uint32_t SectionAlignment;
boost::uint32_t FileAlignment;
boost::uint16_t MajorOperatingSystemVersion;
boost::uint16_t MinorOperatingSystemVersion;
boost::uint16_t MajorImageVersion;
boost::uint16_t MinorImageVersion;
boost::uint16_t MajorSubsystemVersion;
boost::uint16_t MinorSubsystemVersion;
boost::uint32_t Win32VersionValue;
boost::uint32_t SizeOfImage;
boost::uint32_t SizeOfHeaders;
boost::uint32_t CheckSum;
boost::uint16_t Subsystem;
boost::uint16_t DllCharacteristics;
boost::uint64_t SizeOfStackReserve;
boost::uint64_t SizeOfStackCommit;
boost::uint64_t SizeOfHeapReserve;
boost::uint64_t SizeOfHeapCommit;
boost::uint32_t LoaderFlags;
boost::uint32_t NumberOfRvaAndSizes;
data_directory DataDirectory[NUM_DIR_ENTRIES];
};
struct nt_header_32 {
boost::uint32_t Signature;
file_header FileHeader;
optional_header_32 OptionalHeader;
optional_header_64 OptionalHeader64;
boost::uint16_t OptionalMagic;
};
/*

View File

@ -32,7 +32,7 @@ using namespace boost;
struct section {
string sectionName;
::uint32_t sectionBase;
::uint64_t sectionBase;
bounded_buffer *sectionData;
image_section_header sec;
};
@ -62,6 +62,34 @@ struct parsed_pe_internal {
list<exportent> exports;
};
::uint32_t err = 0;
std::string err_loc;
static const char *pe_err_str[] = {
"None",
"Out of memory",
"Invalid header",
"Invalid section",
"Invalid resource",
"Unable to get section for VA",
"Unable to read data",
"Unable to open",
"Unable to stat",
"Bad magic"
};
int GetPEErr() {
return err;
}
string GetPEErrString() {
return pe_err_str[err];
}
string GetPEErrLoc() {
return err_loc;
}
bool getSecForVA(list<section> &secs, VA v, section &sec) {
for(list<section>::iterator it = secs.begin(), e = secs.end();
it != e;
@ -69,8 +97,8 @@ bool getSecForVA(list<section> &secs, VA v, section &sec) {
{
section s = *it;
::uint32_t low = s.sectionBase;
::uint32_t high = low + s.sec.Misc.VirtualSize;
::uint64_t low = s.sectionBase;
::uint64_t high = low + s.sec.Misc.VirtualSize;
if(v >= low && v < high) {
sec = s;
@ -286,7 +314,14 @@ bool getSections( bounded_buffer *b,
thisSec.sectionName.push_back((char)c);
}
thisSec.sectionBase = nthdr.OptionalHeader.ImageBase+curSec.VirtualAddress;
if (nthdr.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
thisSec.sectionBase = nthdr.OptionalHeader.ImageBase + curSec.VirtualAddress;
} else if (nthdr.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
thisSec.sectionBase = nthdr.OptionalHeader64.ImageBase + curSec.VirtualAddress;
} else {
PE_ERR(PEERR_MAGIC);
}
thisSec.sec = curSec;
::uint32_t lowOff = curSec.PointerToRawData;
::uint32_t highOff = lowOff+curSec.SizeOfRawData;
@ -301,10 +336,6 @@ bool getSections( bounded_buffer *b,
bool readOptionalHeader(bounded_buffer *b, optional_header_32 &header) {
READ_WORD(b, 0, header, Magic);
if(header.Magic != NT_OPTIONAL_32_MAGIC) {
return false;
}
READ_BYTE(b, 0, header, MajorLinkerVersion);
READ_BYTE(b, 0, header, MinorLinkerVersion);
READ_DWORD(b, 0, header, SizeOfCode);
@ -354,6 +385,57 @@ bool readOptionalHeader(bounded_buffer *b, optional_header_32 &header) {
return true;
}
bool readOptionalHeader64(bounded_buffer *b, optional_header_64 &header) {
READ_WORD(b, 0, header, Magic);
READ_BYTE(b, 0, header, MajorLinkerVersion);
READ_BYTE(b, 0, header, MinorLinkerVersion);
READ_DWORD(b, 0, header, SizeOfCode);
READ_DWORD(b, 0, header, SizeOfInitializedData);
READ_DWORD(b, 0, header, SizeOfUninitializedData);
READ_DWORD(b, 0, header, AddressOfEntryPoint);
READ_DWORD(b, 0, header, BaseOfCode);
READ_QWORD(b, 0, header, ImageBase);
READ_DWORD(b, 0, header, SectionAlignment);
READ_DWORD(b, 0, header, FileAlignment);
READ_WORD(b, 0, header, MajorOperatingSystemVersion);
READ_WORD(b, 0, header, MinorOperatingSystemVersion);
READ_WORD(b, 0, header, MajorImageVersion);
READ_WORD(b, 0, header, MinorImageVersion);
READ_WORD(b, 0, header, MajorSubsystemVersion);
READ_WORD(b, 0, header, MinorSubsystemVersion);
READ_DWORD(b, 0, header, Win32VersionValue);
READ_DWORD(b, 0, header, SizeOfImage);
READ_DWORD(b, 0, header, SizeOfHeaders);
READ_DWORD(b, 0, header, CheckSum);
READ_WORD(b, 0, header, Subsystem);
READ_WORD(b, 0, header, DllCharacteristics);
READ_QWORD(b, 0, header, SizeOfStackReserve);
READ_QWORD(b, 0, header, SizeOfStackCommit);
READ_QWORD(b, 0, header, SizeOfHeapReserve);
READ_QWORD(b, 0, header, SizeOfHeapCommit);
READ_DWORD(b, 0, header, LoaderFlags);
READ_DWORD(b, 0, header, NumberOfRvaAndSizes);
for(::uint32_t i = 0; i < header.NumberOfRvaAndSizes; i++) {
::uint32_t c = (i*sizeof(data_directory));
c += _offset(optional_header_64, DataDirectory[0]);
::uint32_t o;
o = c + _offset(data_directory, VirtualAddress);
if(readDword(b, o, header.DataDirectory[i].VirtualAddress) == false) {
return false;
}
o = c + _offset(data_directory, Size);
if(readDword(b, o, header.DataDirectory[i].Size) == false) {
return false;
}
}
return true;
}
bool readFileHeader(bounded_buffer *b, file_header &header) {
READ_WORD(b, 0, header, Machine);
READ_WORD(b, 0, header, NumberOfSections);
@ -374,6 +456,7 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) {
::uint32_t pe_magic;
::uint32_t curOffset =0;
if(readDword(b, curOffset, pe_magic) == false || pe_magic != NT_MAGIC) {
PE_ERR(PEERR_READ);
return false;
}
@ -382,6 +465,7 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) {
splitBuffer(b, _offset(nt_header_32, FileHeader), b->bufLen);
if(fhb == NULL) {
PE_ERR(PEERR_MEM);
return false;
}
@ -390,17 +474,41 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) {
return false;
}
/*
* The buffer is split using the OptionalHeader offset, even if it turns
* out to be a PE32+. The start of the buffer is at the same spot in the
* buffer regardless.
*/
bounded_buffer *ohb =
splitBuffer(b, _offset(nt_header_32, OptionalHeader), b->bufLen);
if(ohb == NULL) {
deleteBuffer(fhb);
PE_ERR(PEERR_MEM);
return false;
}
if(readOptionalHeader(ohb, header.OptionalHeader) == false) {
deleteBuffer(ohb);
deleteBuffer(fhb);
/*
* Read the Magic to determine if it is 32 or 64.
*/
if (readWord(ohb, 0, header.OptionalMagic) == false) {
PE_ERR(PEERR_READ);
return false;
}
if (header.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
if(readOptionalHeader(ohb, header.OptionalHeader) == false) {
deleteBuffer(ohb);
deleteBuffer(fhb);
return false;
}
} else if (header.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
if(readOptionalHeader64(ohb, header.OptionalHeader64) == false) {
deleteBuffer(ohb);
deleteBuffer(fhb);
return false;
}
} else {
PE_ERR(PEERR_MAGIC);
return false;
}
@ -419,15 +527,18 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
::uint16_t tmp = 0;
::uint32_t curOffset = 0;
if(readWord(file, curOffset, tmp) == false) {
PE_ERR(PEERR_READ);
return false;
}
if(tmp != MZ_MAGIC) {
PE_ERR(PEERR_MAGIC);
return false;
}
//read the offset to the NT headers
::uint32_t offset;
if(readDword(file, _offset(dos_header, e_lfanew), offset) == false) {
PE_ERR(PEERR_READ);
return false;
}
curOffset += offset;
@ -435,11 +546,28 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
//now, we can read out the fields of the NT headers
bounded_buffer *ntBuf = splitBuffer(file, curOffset, file->bufLen);
if(readNtHeader(ntBuf, p.nt) == false) {
// err is set by readNtHeader
return false;
}
/*
* Need to determine if this is a PE32 or PE32+ binary and use the
# correct size.
*/
::uint32_t rem_size;
if (p.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
// signature + file_header + optional_header_32
rem_size = sizeof(::uint32_t) + sizeof(file_header) + sizeof(optional_header_32);
} else if (p.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
// signature + file_header + optional_header_64
rem_size = sizeof(::uint32_t) + sizeof(file_header) + sizeof(optional_header_64);
} else {
PE_ERR(PEERR_MAGIC);
return false;
}
//update 'rem' to point to the space after the header
rem = splitBuffer(ntBuf, sizeof(nt_header_32), ntBuf->bufLen);
rem = splitBuffer(ntBuf, rem_size, ntBuf->bufLen);
deleteBuffer(ntBuf);
return true;
@ -450,6 +578,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
parsed_pe *p = new parsed_pe();
if(p == NULL) {
PE_ERR(PEERR_MEM);
return NULL;
}
@ -458,6 +587,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
if(p->fileBuffer == NULL) {
delete p;
// err is set by readFileToFileBuffer
return NULL;
}
@ -466,6 +596,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
if(p->internal == NULL) {
deleteBuffer(p->fileBuffer);
delete p;
PE_ERR(PEERR_MEM);
return NULL;
}
@ -474,6 +605,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
if(getHeader(p->fileBuffer, p->peHeader, remaining) == false) {
deleteBuffer(p->fileBuffer);
delete p;
// err is set by getHeader
return NULL;
}
@ -482,6 +614,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
deleteBuffer(remaining);
deleteBuffer(p->fileBuffer);
delete p;
PE_ERR(PEERR_SECT);
return NULL;
}
@ -489,18 +622,35 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
deleteBuffer(remaining);
deleteBuffer(p->fileBuffer);
delete p;
PE_ERR(PEERR_RESC);
return NULL;
}
//get exports
data_directory exportDir =
p->peHeader.nt.OptionalHeader.DataDirectory[DIR_EXPORT];
data_directory exportDir;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
exportDir = p->peHeader.nt.OptionalHeader.DataDirectory[DIR_EXPORT];
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
exportDir = p->peHeader.nt.OptionalHeader64.DataDirectory[DIR_EXPORT];
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(exportDir.Size != 0) {
section s;
::uint32_t addr =
exportDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
VA addr;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
addr = exportDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
addr = exportDir.VirtualAddress + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(getSecForVA(p->internal->secs, addr, s) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -512,13 +662,23 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(export_dir_table, NameRVA),
nameRva) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
::uint32_t nameVA = nameRva + p->peHeader.nt.OptionalHeader.ImageBase;
VA nameVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
nameVA = nameRva + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
nameVA = nameRva + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
section nameSec;
if(getSecForVA(p->internal->secs, nameVA, nameSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -527,6 +687,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
::uint8_t c;
do {
if(readByte(nameSec.sectionData, nameOff, c) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -544,6 +705,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(export_dir_table, NumberOfNamePointers),
numNames) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
@ -554,14 +716,23 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(export_dir_table, NamePointerRVA),
namesRVA) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
::uint32_t namesVA =
namesRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section namesSec;
VA namesVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
namesVA = namesRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
namesVA = namesRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
section namesSec;
if(getSecForVA(p->internal->secs, namesVA, namesSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -573,13 +744,23 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(export_dir_table, ExportAddressTableRVA),
eatRVA) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
VA eatVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
eatVA = eatRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
eatVA = eatRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
::uint32_t eatVA =
eatRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section eatSec;
if(getSecForVA(p->internal->secs, eatVA, eatSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -591,6 +772,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(export_dir_table, OrdinalBase),
ordinalBase) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
@ -601,13 +783,23 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
ordinalTableRVA) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
VA ordinalTableVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
ordinalTableVA = ordinalTableRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
ordinalTableVA = ordinalTableRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
::uint32_t ordinalTableVA =
ordinalTableRVA + p->peHeader.nt.OptionalHeader.ImageBase;
section ordinalTableSec;
if(getSecForVA(p->internal->secs, ordinalTableVA, ordinalTableSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -619,14 +811,24 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
namesOff+(i*sizeof(::uint32_t)),
curNameRVA) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
::uint32_t curNameVA =
curNameRVA + p->peHeader.nt.OptionalHeader.ImageBase;
VA curNameVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
curNameVA = curNameRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
curNameVA = curNameRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
section curNameSec;
if(getSecForVA(p->internal->secs, curNameVA, curNameSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -636,6 +838,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
do {
if(readByte(curNameSec.sectionData, curNameOff, d) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -653,6 +856,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
ordinalOff+(i*sizeof(uint16_t)),
ordinal) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
@ -661,6 +865,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
::uint32_t symRVA;
if(readDword(eatSec.sectionData, eatOff+eatIdx, symRVA) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -669,7 +874,16 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
(symRVA < exportDir.VirtualAddress+exportDir.Size));
if(isForwarded == false) {
::uint32_t symVA = symRVA + p->peHeader.nt.OptionalHeader.ImageBase;
::uint32_t symVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
symVA = symRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
symVA = symRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
exportent a;
a.addr = symVA;
@ -682,17 +896,33 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
}
//get relocations, if exist
data_directory relocDir =
p->peHeader.nt.OptionalHeader.DataDirectory[DIR_BASERELOC];
data_directory relocDir;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
relocDir = p->peHeader.nt.OptionalHeader.DataDirectory[DIR_BASERELOC];
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
relocDir = p->peHeader.nt.OptionalHeader64.DataDirectory[DIR_BASERELOC];
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(relocDir.Size != 0) {
section d;
::uint32_t vaAddr =
relocDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
VA vaAddr;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
vaAddr = relocDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
vaAddr = relocDir.VirtualAddress + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(getSecForVA(p->internal->secs, vaAddr, d) == false) {
deleteBuffer(remaining);
deleteBuffer(p->fileBuffer);
delete p;
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -704,6 +934,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(reloc_block, PageRVA),
pageRva) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
@ -711,6 +942,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
rvaofft+_offset(reloc_block, BlockSize),
blockSize) == false)
{
PE_ERR(PEERR_READ);
return NULL;
}
@ -725,6 +957,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
::uint16_t offset;
if(readWord(d.sectionData, rvaofft, block) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -734,8 +967,15 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
offset = block & ~0xf000;
//produce the VA of the relocation
::uint32_t relocVA = pageRva + offset +
p->peHeader.nt.OptionalHeader.ImageBase;
::uint32_t relocVA;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
relocVA = pageRva + offset + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
relocVA = pageRva + offset + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
//store in our list
reloc r;
@ -750,18 +990,34 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
}
//get imports
data_directory importDir =
p->peHeader.nt.OptionalHeader.DataDirectory[DIR_IMPORT];
data_directory importDir;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
importDir = p->peHeader.nt.OptionalHeader.DataDirectory[DIR_IMPORT];
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
importDir = p->peHeader.nt.OptionalHeader64.DataDirectory[DIR_IMPORT];
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(importDir.Size != 0) {
//get section for the RVA in importDir
section c;
::uint32_t addr =
importDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
VA addr;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
addr = importDir.VirtualAddress + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
addr = importDir.VirtualAddress + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(getSecForVA(p->internal->secs, addr, c) == false) {
deleteBuffer(remaining);
deleteBuffer(p->fileBuffer);
delete p;
PE_ERR(PEERR_READ);
return NULL;
}
@ -785,11 +1041,19 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
}
//then, try and get the name of this particular module...
::uint32_t name =
curEnt.NameRVA + p->peHeader.nt.OptionalHeader.ImageBase;
VA name;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
name = curEnt.NameRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
name = curEnt.NameRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
section nameSec;
if(getSecForVA(p->internal->secs, name, nameSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -798,6 +1062,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
::uint8_t c;
do {
if(readByte(nameSec.sectionData, nameOff, c) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -810,39 +1075,75 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
}while(true);
//then, try and get all of the sub-symbols
::uint32_t lookupVA;
VA lookupVA;
if(curEnt.LookupTableRVA != 0) {
lookupVA =
curEnt.LookupTableRVA + p->peHeader.nt.OptionalHeader.ImageBase;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
lookupVA = curEnt.LookupTableRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
lookupVA = curEnt.LookupTableRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
} else if(curEnt.AddressRVA != 0 ) {
lookupVA =
curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
lookupVA = curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
lookupVA = curEnt.AddressRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
}
section lookupSec;
if(getSecForVA(p->internal->secs, lookupVA, lookupSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
::uint32_t lookupOff = lookupVA - lookupSec.sectionBase;
::uint64_t lookupOff = lookupVA - lookupSec.sectionBase;
::uint32_t offInTable = 0;
do {
::uint32_t val;
if(readDword(lookupSec.sectionData, lookupOff, val) == false) {
VA valVA = 0;
::uint8_t ord = 0;
::uint16_t oval = 0;
::uint32_t val32 = 0;
::uint64_t val64 = 0;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
if(readDword(lookupSec.sectionData, lookupOff, val32) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
if(val32 == 0) {
break;
}
ord = (val32 >> 31);
oval = (val32 & ~0xFFFF0000);
valVA = val32 + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
if(readQword(lookupSec.sectionData, lookupOff, val64) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
if(val64 == 0) {
break;
}
ord = (val64 >> 63);
oval = (val64 & ~0xFFFF0000);
valVA = val64 + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
if(val == 0) {
break;
}
//check and see if high bit is set
if(val >> 31 == 0) {
if(ord == 0) {
//import by name
string symName;
section symNameSec;
::uint32_t valVA = val + p->peHeader.nt.OptionalHeader.ImageBase;
if(getSecForVA(p->internal->secs, valVA, symNameSec) == false) {
PE_ERR(PEERR_SECTVA);
return NULL;
}
@ -852,6 +1153,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
::uint8_t d;
if(readByte(symNameSec.sectionData, nameOff, d) == false) {
PE_ERR(PEERR_READ);
return NULL;
}
@ -866,23 +1168,32 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
//okay now we know the pair... add it
importent ent;
ent.addr = offInTable +
curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
ent.addr = offInTable + curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
ent.addr = offInTable + curEnt.AddressRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
ent.symbolName = symName;
ent.moduleName = modName;
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;
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
ent.addr = offInTable + curEnt.AddressRVA + p->peHeader.nt.OptionalHeader.ImageBase;
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
ent.addr = offInTable + curEnt.AddressRVA + p->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
ent.symbolName = symName;
ent.moduleName = modName;
@ -890,8 +1201,16 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
p->internal->imports.push_back(ent);
}
lookupOff += sizeof(::uint32_t);
offInTable += sizeof(::uint32_t);
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
lookupOff += sizeof(::uint32_t);
offInTable += sizeof(::uint32_t);
} else if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
lookupOff += sizeof(::uint64_t);
offInTable += sizeof(::uint64_t);
} else {
PE_ERR(PEERR_MAGIC);
return NULL;
}
} while(true);
offt += sizeof(import_dir_entry);
@ -978,6 +1297,7 @@ bool ReadByteAtVA(parsed_pe *pe, VA v, ::uint8_t &b) {
section s;
if(getSecForVA(pe->internal->secs, v, s) == false) {
PE_ERR(PEERR_SECTVA);
return false;
}
@ -991,7 +1311,14 @@ bool GetEntryPoint(parsed_pe *pe, VA &v) {
if(pe != NULL) {
nt_header_32 *nthdr = &pe->peHeader.nt;
v = nthdr->OptionalHeader.AddressOfEntryPoint + nthdr->OptionalHeader.ImageBase;
if (nthdr->OptionalMagic == NT_OPTIONAL_32_MAGIC) {
v = nthdr->OptionalHeader.AddressOfEntryPoint + nthdr->OptionalHeader.ImageBase;
} else if (nthdr->OptionalMagic == NT_OPTIONAL_64_MAGIC) {
v = nthdr->OptionalHeader64.AddressOfEntryPoint + nthdr->OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return false;
}
return true;
}

View File

@ -28,30 +28,47 @@ THE SOFTWARE.
#include <boost/cstdint.hpp>
#include "nt-headers.h"
#include "to_string.h"
#define PE_ERR(x) \
err = (pe_err) x; \
err_loc.assign(__func__); \
err_loc += ":" + to_string<std::uint32_t>(__LINE__, dec);
#define READ_WORD(b, o, inst, member) \
if(readWord(b, o+_offset(__typeof__(inst), member), inst.member) == false) { \
PE_ERR(PEERR_READ); \
return false; \
}
#define READ_DWORD(b, o, inst, member) \
if(readDword(b, o+_offset(__typeof__(inst), member), inst.member) == false) { \
PE_ERR(PEERR_READ); \
return false; \
}
#define READ_QWORD(b, o, inst, member) \
if(readQword(b, o+_offset(__typeof__(inst), member), inst.member) == false) { \
PE_ERR(PEERR_READ); \
return false; \
}
#define READ_DWORD_PTR(b, o, inst, member) \
if(readDword(b, o+_offset(__typeof__(*inst), member), inst->member) == false) { \
PE_ERR(PEERR_READ); \
return false; \
}
#define READ_BYTE(b, o, inst, member) \
if(readByte(b, o+_offset(__typeof__(inst), member), inst.member) == false) { \
PE_ERR(PEERR_READ); \
return false; \
}
/* This variant returns NULL instead of false. */
#define READ_DWORD_NULL(b, o, inst, member) \
if(readDword(b, o+_offset(__typeof__(inst), member), inst.member) == false) { \
PE_ERR(PEERR_READ); \
return NULL; \
}
@ -105,9 +122,23 @@ enum resource_type {
RT_MANIFEST = 24
};
enum pe_err {
PEERR_NONE = 0,
PEERR_MEM = 1,
PEERR_HDR = 2,
PEERR_SECT = 3,
PEERR_RESC = 4,
PEERR_SECTVA = 5,
PEERR_READ = 6,
PEERR_OPEN = 7,
PEERR_STAT = 8,
PEERR_MAGIC = 9
};
bool readByte(bounded_buffer *b, boost::uint32_t offset, boost::uint8_t &out);
bool readWord(bounded_buffer *b, boost::uint32_t offset, boost::uint16_t &out);
bool readDword(bounded_buffer *b, boost::uint32_t offset, boost::uint32_t &out);
bool readQword(bounded_buffer *b, boost::uint32_t offset, boost::uint64_t &out);
bounded_buffer *readFileToFileBuffer(const char *filePath);
bounded_buffer *splitBuffer(bounded_buffer *b, boost::uint32_t from, boost::uint32_t to);
@ -126,6 +157,15 @@ typedef struct _parsed_pe {
pe_header peHeader;
} parsed_pe;
// get parser error status as integer
int GetPEErr();
// get parser error status as string
std::string GetPEErrString();
// get parser error location as string
std::string GetPEErrLoc();
//get a PE parse context from a file
parsed_pe *ParsePEFromFile(const char *filePath);

View File

@ -29,7 +29,7 @@
#include <structmember.h>
#include "parse.h"
#define PEPY_VERSION "0.1"
#define PEPY_VERSION "0.2"
/* These are used to across multiple objects. */
#define PEPY_OBJECT_GET(OBJ, ATTR) \
@ -43,6 +43,12 @@ static PyObject *pepy_##OBJ##_get_##ATTR(PyObject *self, void *closure) { \
(setter) pepy_attr_not_writable, \
(char *) #DOC, NULL }
/* 'OPTIONAL' references the fact that these are from the Optional Header */
#define OBJECTGETTER_OPTIONAL(ATTR, DOC) \
{ (char *) #ATTR, (getter) pepy_parsed_get_optional_##ATTR, \
(setter) pepy_attr_not_writable, \
(char *) #DOC, NULL }
static PyObject *pepy_error;
typedef struct {
@ -103,7 +109,7 @@ typedef struct {
/* None of the attributes in these objects are writable. */
static int pepy_attr_not_writable(PyObject *self, PyObject *value, void *closure) {
PyErr_SetString(PyExc_TypeError, "Attribute not writable");
PyErr_SetString(PyExc_TypeError, "Attribute not writable.");
return -1;
}
@ -761,7 +767,7 @@ int section_callback(void *cbd, VA base, std::string &name, image_section_header
}
if (pepy_section_init((pepy_section *) sect, tuple, NULL) == -1) {
PyErr_SetString(pepy_error, "Unable to init new section");
PyErr_SetString(pepy_error, "Unable to init new section.");
return 1;
}
@ -806,7 +812,7 @@ int resource_callback(void *cbd, resource r) {
}
if (pepy_resource_init((pepy_resource *) rsrc, tuple, NULL) == -1) {
PyErr_SetString(pepy_error, "Unable to init new resource");
PyErr_SetString(pepy_error, "Unable to init new resource.");
return 1;
}
@ -851,7 +857,7 @@ int import_callback(void *cbd, VA addr, std::string &name, std::string &sym) {
}
if (pepy_import_init((pepy_import *) imp, tuple, NULL) == -1) {
PyErr_SetString(pepy_error, "Unable to init new section");
PyErr_SetString(pepy_error, "Unable to init new section.");
return 1;
}
@ -896,7 +902,7 @@ int export_callback(void *cbd, VA addr, std::string &mod, std::string &func) {
}
if (pepy_export_init((pepy_export *) exp, tuple, NULL) == -1) {
PyErr_SetString(pepy_error, "Unable to init new section");
PyErr_SetString(pepy_error, "Unable to init new section.");
return 1;
}
@ -945,7 +951,7 @@ int reloc_callback(void *cbd, VA addr, reloc_type type) {
}
if (pepy_relocation_init((pepy_relocation *) reloc, tuple, NULL) == -1) {
PyErr_SetString(pepy_error, "Unable to init new section");
PyErr_SetString(pepy_error, "Unable to init new section.");
return 1;
}
@ -972,44 +978,86 @@ static PyObject *pepy_parsed_get_relocations(PyObject *self, PyObject *args) {
#define PEPY_PARSED_GET(ATTR, VAL) \
static PyObject *pepy_parsed_get_##ATTR(PyObject *self, void *closure) { \
PyObject *ret = PyInt_FromLong(((pepy_parsed *) self)->pe->peHeader.VAL); \
PyObject *ret = PyInt_FromLong(((pepy_parsed *) self)->pe->peHeader.nt.VAL); \
if (!ret) \
PyErr_SetString(PyExc_AttributeError, "Error getting attribute"); \
PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \
return ret; \
}
PEPY_PARSED_GET(signature, nt.Signature)
PEPY_PARSED_GET(machine, nt.FileHeader.Machine)
PEPY_PARSED_GET(numberofsections, nt.FileHeader.NumberOfSections)
PEPY_PARSED_GET(timedatestamp, nt.FileHeader.TimeDateStamp)
PEPY_PARSED_GET(numberofsymbols, nt.FileHeader.NumberOfSymbols)
PEPY_PARSED_GET(characteristics, nt.FileHeader.Characteristics)
PEPY_PARSED_GET(magic, nt.OptionalHeader.Magic)
PEPY_PARSED_GET(majorlinkerver, nt.OptionalHeader.MajorLinkerVersion)
PEPY_PARSED_GET(minorlinkerver, nt.OptionalHeader.MinorLinkerVersion)
PEPY_PARSED_GET(codesize, nt.OptionalHeader.SizeOfCode);
PEPY_PARSED_GET(initdatasize, nt.OptionalHeader.SizeOfInitializedData);
PEPY_PARSED_GET(uninitdatasize, nt.OptionalHeader.SizeOfUninitializedData);
PEPY_PARSED_GET(entrypointaddr, nt.OptionalHeader.AddressOfEntryPoint);
PEPY_PARSED_GET(baseofcode, nt.OptionalHeader.BaseOfCode);
PEPY_PARSED_GET(baseofdata, nt.OptionalHeader.BaseOfData);
PEPY_PARSED_GET(imagebase, nt.OptionalHeader.ImageBase);
PEPY_PARSED_GET(sectionalignement, nt.OptionalHeader.SectionAlignment);
PEPY_PARSED_GET(filealingment, nt.OptionalHeader.FileAlignment);
PEPY_PARSED_GET(majorosver, nt.OptionalHeader.MajorOperatingSystemVersion);
PEPY_PARSED_GET(minorosver, nt.OptionalHeader.MinorOperatingSystemVersion);
PEPY_PARSED_GET(win32ver, nt.OptionalHeader.Win32VersionValue);
PEPY_PARSED_GET(imagesize, nt.OptionalHeader.SizeOfImage);
PEPY_PARSED_GET(headersize, nt.OptionalHeader.SizeOfHeaders);
PEPY_PARSED_GET(checksum, nt.OptionalHeader.CheckSum);
PEPY_PARSED_GET(subsystem, nt.OptionalHeader.Subsystem);
PEPY_PARSED_GET(dllcharacteristics, nt.OptionalHeader.DllCharacteristics);
PEPY_PARSED_GET(stackreservesize, nt.OptionalHeader.SizeOfStackReserve);
PEPY_PARSED_GET(stackcommitsize, nt.OptionalHeader.SizeOfStackCommit);
PEPY_PARSED_GET(heapreservesize, nt.OptionalHeader.SizeOfHeapReserve);
PEPY_PARSED_GET(heapcommitsize, nt.OptionalHeader.SizeOfHeapCommit);
PEPY_PARSED_GET(loaderflags, nt.OptionalHeader.LoaderFlags);
PEPY_PARSED_GET(rvasandsize, nt.OptionalHeader.NumberOfRvaAndSizes);
PEPY_PARSED_GET(signature, Signature)
PEPY_PARSED_GET(machine, FileHeader.Machine)
PEPY_PARSED_GET(numberofsections, FileHeader.NumberOfSections)
PEPY_PARSED_GET(timedatestamp, FileHeader.TimeDateStamp)
PEPY_PARSED_GET(numberofsymbols, FileHeader.NumberOfSymbols)
PEPY_PARSED_GET(characteristics, FileHeader.Characteristics)
PEPY_PARSED_GET(magic, OptionalMagic)
/*
* This is used to get things from the optional header, which can be either
* the PE32 or PE32+ version, depending upon the magic value. Technically
* the magic is stored in the OptionalHeader, but to make life easier pe-parse
* stores the value in nt_header_32 along with the appropriate optional header.
* This is why "magic" is handled above, and not here.
*/
#define PEPY_PARSED_GET_OPTIONAL(ATTR, VAL) \
static PyObject *pepy_parsed_get_optional_##ATTR(PyObject *self, void *closure) { \
PyObject *ret = NULL; \
if (((pepy_parsed *) self)->pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { \
ret = PyInt_FromLong(((pepy_parsed *) self)->pe->peHeader.nt.OptionalHeader.VAL); \
if (!ret) \
PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \
} else if (((pepy_parsed *) self)->pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) { \
ret = PyInt_FromLong(((pepy_parsed *) self)->pe->peHeader.nt.OptionalHeader64.VAL); \
if (!ret) \
PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \
} else { \
PyErr_SetString(pepy_error, "Bad magic value."); \
} \
return ret; \
}
PEPY_PARSED_GET_OPTIONAL(majorlinkerver, MajorLinkerVersion)
PEPY_PARSED_GET_OPTIONAL(minorlinkerver, MinorLinkerVersion)
PEPY_PARSED_GET_OPTIONAL(codesize, SizeOfCode);
PEPY_PARSED_GET_OPTIONAL(initdatasize, SizeOfInitializedData);
PEPY_PARSED_GET_OPTIONAL(uninitdatasize, SizeOfUninitializedData);
PEPY_PARSED_GET_OPTIONAL(entrypointaddr, AddressOfEntryPoint);
PEPY_PARSED_GET_OPTIONAL(baseofcode, BaseOfCode);
PEPY_PARSED_GET_OPTIONAL(imagebase, ImageBase);
PEPY_PARSED_GET_OPTIONAL(sectionalignement, SectionAlignment);
PEPY_PARSED_GET_OPTIONAL(filealingment, FileAlignment);
PEPY_PARSED_GET_OPTIONAL(majorosver, MajorOperatingSystemVersion);
PEPY_PARSED_GET_OPTIONAL(minorosver, MinorOperatingSystemVersion);
PEPY_PARSED_GET_OPTIONAL(win32ver, Win32VersionValue);
PEPY_PARSED_GET_OPTIONAL(imagesize, SizeOfImage);
PEPY_PARSED_GET_OPTIONAL(headersize, SizeOfHeaders);
PEPY_PARSED_GET_OPTIONAL(checksum, CheckSum);
PEPY_PARSED_GET_OPTIONAL(subsystem, Subsystem);
PEPY_PARSED_GET_OPTIONAL(dllcharacteristics, DllCharacteristics);
PEPY_PARSED_GET_OPTIONAL(stackreservesize, SizeOfStackReserve);
PEPY_PARSED_GET_OPTIONAL(stackcommitsize, SizeOfStackCommit);
PEPY_PARSED_GET_OPTIONAL(heapreservesize, SizeOfHeapReserve);
PEPY_PARSED_GET_OPTIONAL(heapcommitsize, SizeOfHeapCommit);
PEPY_PARSED_GET_OPTIONAL(loaderflags, LoaderFlags);
PEPY_PARSED_GET_OPTIONAL(rvasandsize, NumberOfRvaAndSizes);
/*
* BaseOfData is only in PE32, not PE32+. Thus, it uses a non-standard
* getter function compared to the other shared fields.
*/
static PyObject *pepy_parsed_get_optional_baseofdata(PyObject *self, void *closure) {
PyObject *ret = NULL;
if (((pepy_parsed *) self)->pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
ret = PyInt_FromLong(((pepy_parsed *) self)->pe->peHeader.nt.OptionalHeader.BaseOfData);
if (!ret)
PyErr_SetString(PyExc_AttributeError, "Error getting attribute.");
} else if (((pepy_parsed *) self)->pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
PyErr_SetString(PyExc_AttributeError, "Not available on PE32+.");
} else {
PyErr_SetString(pepy_error, "Bad magic value.");
}
return ret;
}
static PyGetSetDef pepy_parsed_getseters[] = {
OBJECTGETTER(parsed, signature, "PE Signature"),
@ -1019,31 +1067,34 @@ static PyGetSetDef pepy_parsed_getseters[] = {
OBJECTGETTER(parsed, numberofsymbols, "Number of symbols"),
OBJECTGETTER(parsed, characteristics, "Characteristics"),
OBJECTGETTER(parsed, magic, "Magic"),
OBJECTGETTER(parsed, majorlinkerver, "Major linker version"),
OBJECTGETTER(parsed, minorlinkerver, "Minor linker version"),
OBJECTGETTER(parsed, codesize, "Size of code"),
OBJECTGETTER(parsed, initdatasize, "Size of initialized data"),
OBJECTGETTER(parsed, uninitdatasize, "Size of uninitialized data"),
OBJECTGETTER(parsed, entrypointaddr, "Address of entry point"),
OBJECTGETTER(parsed, baseofcode, "Base address of code"),
OBJECTGETTER(parsed, baseofdata, "Base address of data"),
OBJECTGETTER(parsed, imagebase, "Image base address"),
OBJECTGETTER(parsed, sectionalignement, "Section alignment"),
OBJECTGETTER(parsed, filealingment, "File alignment"),
OBJECTGETTER(parsed, majorosver, "Major OS version"),
OBJECTGETTER(parsed, minorosver, "Minor OS version"),
OBJECTGETTER(parsed, win32ver, "Win32 version"),
OBJECTGETTER(parsed, imagesize, "Size of image"),
OBJECTGETTER(parsed, headersize, "Size of headers"),
OBJECTGETTER(parsed, checksum, "Checksum"),
OBJECTGETTER(parsed, subsystem, "Subsystem"),
OBJECTGETTER(parsed, dllcharacteristics, "DLL characteristics"),
OBJECTGETTER(parsed, stackreservesize, "Size of stack reserve"),
OBJECTGETTER(parsed, stackcommitsize, "Size of stack commit"),
OBJECTGETTER(parsed, heapreservesize, "Size of heap reserve"),
OBJECTGETTER(parsed, heapcommitsize, "Size of heap commit"),
OBJECTGETTER(parsed, loaderflags, "Loader flags"),
OBJECTGETTER(parsed, rvasandsize, "Number of RVA and sizes"),
OBJECTGETTER_OPTIONAL(majorlinkerver, "Major linker version"),
OBJECTGETTER_OPTIONAL(minorlinkerver, "Minor linker version"),
OBJECTGETTER_OPTIONAL(codesize, "Size of code"),
OBJECTGETTER_OPTIONAL(initdatasize, "Size of initialized data"),
OBJECTGETTER_OPTIONAL(uninitdatasize, "Size of uninitialized data"),
OBJECTGETTER_OPTIONAL(entrypointaddr, "Address of entry point"),
OBJECTGETTER_OPTIONAL(baseofcode, "Base address of code"),
OBJECTGETTER_OPTIONAL(imagebase, "Image base address"),
OBJECTGETTER_OPTIONAL(sectionalignement, "Section alignment"),
OBJECTGETTER_OPTIONAL(filealingment, "File alignment"),
OBJECTGETTER_OPTIONAL(majorosver, "Major OS version"),
OBJECTGETTER_OPTIONAL(minorosver, "Minor OS version"),
OBJECTGETTER_OPTIONAL(win32ver, "Win32 version"),
OBJECTGETTER_OPTIONAL(imagesize, "Size of image"),
OBJECTGETTER_OPTIONAL(headersize, "Size of headers"),
OBJECTGETTER_OPTIONAL(checksum, "Checksum"),
OBJECTGETTER_OPTIONAL(subsystem, "Subsystem"),
OBJECTGETTER_OPTIONAL(dllcharacteristics, "DLL characteristics"),
OBJECTGETTER_OPTIONAL(stackreservesize, "Size of stack reserve"),
OBJECTGETTER_OPTIONAL(stackcommitsize, "Size of stack commit"),
OBJECTGETTER_OPTIONAL(heapreservesize, "Size of heap reserve"),
OBJECTGETTER_OPTIONAL(heapcommitsize, "Size of heap commit"),
OBJECTGETTER_OPTIONAL(loaderflags, "Loader flags"),
OBJECTGETTER_OPTIONAL(rvasandsize, "Number of RVA and sizes"),
/* Base of data is only available in PE32, not PE32+. */
{ (char *) "baseofdata", (getter) pepy_parsed_get_optional_baseofdata,
(setter) pepy_attr_not_writable,
(char *) "Base address of data", NULL },
{ NULL }
};
@ -1110,6 +1161,7 @@ static PyTypeObject pepy_parsed_type = {
static PyObject *pepy_parse(PyObject *self, PyObject *args) {
PyObject *parsed;
int ret;
char *err_str = NULL;
parsed = pepy_parsed_new(&pepy_parsed_type, NULL, NULL);
if (!parsed) {
@ -1119,8 +1171,15 @@ static PyObject *pepy_parse(PyObject *self, PyObject *args) {
ret = pepy_parsed_init((pepy_parsed *) parsed, args, NULL);
if (ret < 0) {
if (ret == -2)
PyErr_SetString(pepy_error, "Unable to parse PE file.");
if (ret == -2) {
// error (loc)
size_t len = GetPEErrString().length() + GetPEErrLoc().length() + 4;
err_str = (char *) malloc(len);
if (!err_str)
return PyErr_NoMemory();
snprintf(err_str, len, "%s (%s)", GetPEErrString().c_str(), GetPEErrLoc().c_str());
PyErr_SetString(pepy_error, err_str);
}
else
PyErr_SetString(pepy_error, "Unable to init new parsed object.");
return NULL;

View File

@ -7,7 +7,12 @@ import binascii
from hashlib import md5
p = pepy.parse(sys.argv[1])
try:
p = pepy.parse(sys.argv[1])
except pepy.error as e:
print e
sys.exit(1)
print "Magic: %s" % hex(p.magic)
print "Signature: %s" % hex(p.signature)
print "Machine: %s" % hex(p.machine)
@ -22,7 +27,11 @@ print "Size of initialized data: %s" % hex(p.initdatasize)
print "Size of uninitialized data: %s" % hex(p.uninitdatasize)
print "Address of entry point: %s" % hex(p.entrypointaddr)
print "Base address of code: %s" % hex(p.baseofcode)
print "Base address of data: %s" % hex(p.baseofdata)
try:
print "Base address of data: %s" % hex(p.baseofdata)
except:
# Not available on PE32+, ignore it.
pass
print "Image base address: %s" % hex(p.imagebase)
print "Section alignment: %s" % hex(p.sectionalignement)
print "File alignment: %s" % hex(p.filealingment)