2013-07-25 18:59:25 -04:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
|
|
|
Copyright (c) 2013 Andrew Ruef
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
*/
|
2013-07-24 17:32:23 -04:00
|
|
|
|
2017-10-19 18:13:35 +02:00
|
|
|
#pragma once
|
|
|
|
|
2017-03-09 19:10:17 +03:00
|
|
|
#include <cstdint>
|
2019-10-14 15:57:54 -04:00
|
|
|
#include <map>
|
2017-03-31 17:01:20 +02:00
|
|
|
#include <string>
|
2013-07-24 17:32:23 -04:00
|
|
|
|
2013-07-26 09:36:05 -04:00
|
|
|
#include "nt-headers.h"
|
2014-03-07 13:18:24 -05:00
|
|
|
#include "to_string.h"
|
|
|
|
|
2017-03-09 19:25:20 +03:00
|
|
|
#ifdef _MSC_VER
|
2019-10-21 09:00:54 -04:00
|
|
|
#define __typeof__(x) std::remove_reference < decltype(x)> ::type
|
2017-03-31 17:01:20 +02:00
|
|
|
#endif
|
2017-03-09 19:25:20 +03:00
|
|
|
|
2017-10-19 18:13:35 +02:00
|
|
|
#define PE_ERR(x) \
|
|
|
|
err = static_cast<pe_err>(x); \
|
|
|
|
err_loc.assign(__func__); \
|
|
|
|
err_loc += ":" + to_string<std::uint32_t>(__LINE__, std::dec);
|
2013-07-26 09:36:05 -04:00
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
#define READ_WORD(b, o, inst, member) \
|
|
|
|
if (!readWord(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
|
|
|
PE_ERR(PEERR_READ); \
|
|
|
|
return false; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define READ_DWORD(b, o, inst, member) \
|
|
|
|
if (!readDword(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
|
|
|
PE_ERR(PEERR_READ); \
|
|
|
|
return false; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define READ_QWORD(b, o, inst, member) \
|
|
|
|
if (!readQword(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
|
|
|
PE_ERR(PEERR_READ); \
|
|
|
|
return false; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define READ_BYTE(b, o, inst, member) \
|
|
|
|
if (!readByte(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
|
|
|
PE_ERR(PEERR_READ); \
|
|
|
|
return false; \
|
|
|
|
}
|
2014-01-17 00:34:58 -05:00
|
|
|
|
2017-04-12 00:24:03 +02:00
|
|
|
#define TEST_MACHINE_CHARACTERISTICS(h, m, ch) \
|
|
|
|
((h.FileHeader.Machine == m) && (h.FileHeader.Characteristics & ch))
|
|
|
|
|
2017-03-03 14:41:14 -05:00
|
|
|
namespace peparse {
|
|
|
|
|
2017-03-09 19:10:17 +03:00
|
|
|
typedef std::uint32_t RVA;
|
|
|
|
typedef std::uint64_t VA;
|
2013-07-24 17:32:23 -04:00
|
|
|
|
2013-07-31 14:04:56 -04:00
|
|
|
struct buffer_detail;
|
|
|
|
|
2013-07-24 17:57:58 -04:00
|
|
|
typedef struct _bounded_buffer {
|
2017-03-31 17:01:20 +02:00
|
|
|
std::uint8_t *buf;
|
2017-03-09 19:10:17 +03:00
|
|
|
std::uint32_t bufLen;
|
2017-03-31 17:01:20 +02:00
|
|
|
bool copy;
|
2017-04-12 00:24:03 +02:00
|
|
|
bool swapBytes;
|
2017-03-31 17:01:20 +02:00
|
|
|
buffer_detail *detail;
|
2013-07-24 17:57:58 -04:00
|
|
|
} bounded_buffer;
|
|
|
|
|
2013-12-24 12:41:59 -05:00
|
|
|
struct resource {
|
2017-10-21 19:45:25 +02:00
|
|
|
resource()
|
|
|
|
: type(0), name(0), lang(0), codepage(0), RVA(0), size(0), buf(nullptr) {
|
|
|
|
}
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
std::string type_str;
|
|
|
|
std::string name_str;
|
|
|
|
std::string lang_str;
|
2017-03-09 19:10:17 +03:00
|
|
|
std::uint32_t type;
|
|
|
|
std::uint32_t name;
|
|
|
|
std::uint32_t lang;
|
|
|
|
std::uint32_t codepage;
|
|
|
|
std::uint32_t RVA;
|
|
|
|
std::uint32_t size;
|
2017-03-31 17:01:20 +02:00
|
|
|
bounded_buffer *buf;
|
2013-12-24 12:41:59 -05:00
|
|
|
};
|
|
|
|
|
2019-10-27 21:36:27 -04:00
|
|
|
#ifndef _PEPARSE_WINDOWS_CONFLICTS
|
2013-12-24 12:41:59 -05:00
|
|
|
// http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx
|
|
|
|
enum resource_type {
|
2017-03-31 17:01:20 +02:00
|
|
|
RT_CURSOR = 1,
|
|
|
|
RT_BITMAP = 2,
|
|
|
|
RT_ICON = 3,
|
|
|
|
RT_MENU = 4,
|
|
|
|
RT_DIALOG = 5,
|
|
|
|
RT_STRING = 6,
|
|
|
|
RT_FONTDIR = 7,
|
|
|
|
RT_FONT = 8,
|
|
|
|
RT_ACCELERATOR = 9,
|
|
|
|
RT_RCDATA = 10,
|
2013-12-24 12:41:59 -05:00
|
|
|
RT_MESSAGETABLE = 11,
|
|
|
|
RT_GROUP_CURSOR = 12, // MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + 11)
|
2017-03-31 17:01:20 +02:00
|
|
|
RT_GROUP_ICON = 14, // MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + 11)
|
|
|
|
RT_VERSION = 16,
|
|
|
|
RT_DLGINCLUDE = 17,
|
|
|
|
RT_PLUGPLAY = 19,
|
|
|
|
RT_VXD = 20,
|
|
|
|
RT_ANICURSOR = 21,
|
|
|
|
RT_ANIICON = 22,
|
|
|
|
RT_HTML = 23,
|
|
|
|
RT_MANIFEST = 24
|
2013-12-24 12:41:59 -05:00
|
|
|
};
|
2019-10-27 21:36:27 -04:00
|
|
|
#endif
|
2013-12-24 12:41:59 -05:00
|
|
|
|
2014-03-07 13:18:24 -05:00
|
|
|
enum pe_err {
|
2017-03-31 17:01:20 +02:00
|
|
|
PEERR_NONE = 0,
|
|
|
|
PEERR_MEM = 1,
|
|
|
|
PEERR_HDR = 2,
|
|
|
|
PEERR_SECT = 3,
|
|
|
|
PEERR_RESC = 4,
|
2014-03-07 13:18:24 -05:00
|
|
|
PEERR_SECTVA = 5,
|
2017-03-31 17:01:20 +02:00
|
|
|
PEERR_READ = 6,
|
|
|
|
PEERR_OPEN = 7,
|
|
|
|
PEERR_STAT = 8,
|
buffer, parse: Fix overread on {d,q,}words
When read 2, 4, or 8 bytes from a bounded_buffer, we only
checked to see if the offset, not the whole span, was in bounds.
This results in an arbitrary memory read of up to 1, 3, or 7 bytes
when the offset is aligned with the very end of the buffer.
2018-09-20 10:57:22 -04:00
|
|
|
PEERR_MAGIC = 9,
|
|
|
|
PEERR_BUFFER = 10,
|
|
|
|
PEERR_ADDRESS = 11,
|
2019-10-21 09:00:54 -04:00
|
|
|
PEERR_SIZE = 12,
|
2014-03-07 13:18:24 -05:00
|
|
|
};
|
|
|
|
|
2017-03-09 19:10:17 +03:00
|
|
|
bool readByte(bounded_buffer *b, std::uint32_t offset, std::uint8_t &out);
|
|
|
|
bool readWord(bounded_buffer *b, std::uint32_t offset, std::uint16_t &out);
|
|
|
|
bool readDword(bounded_buffer *b, std::uint32_t offset, std::uint32_t &out);
|
|
|
|
bool readQword(bounded_buffer *b, std::uint32_t offset, std::uint64_t &out);
|
2019-09-16 17:59:24 -07:00
|
|
|
bool readChar16(bounded_buffer *b, std::uint32_t offset, char16_t &out);
|
2013-07-24 17:57:58 -04:00
|
|
|
|
2013-07-24 18:32:56 -04:00
|
|
|
bounded_buffer *readFileToFileBuffer(const char *filePath);
|
2017-03-31 17:01:20 +02:00
|
|
|
bounded_buffer *
|
|
|
|
splitBuffer(bounded_buffer *b, std::uint32_t from, std::uint32_t to);
|
2013-07-25 15:19:00 -04:00
|
|
|
void deleteBuffer(bounded_buffer *b);
|
2013-11-11 15:09:57 -05:00
|
|
|
uint64_t bufLen(bounded_buffer *b);
|
2013-07-24 18:32:56 -04:00
|
|
|
|
2013-07-24 18:52:38 -04:00
|
|
|
struct parsed_pe_internal;
|
|
|
|
|
2017-10-19 18:13:35 +02:00
|
|
|
typedef struct _pe_header {
|
2019-11-17 01:45:55 +09:00
|
|
|
dos_header dos;
|
2019-10-14 15:57:54 -04:00
|
|
|
rich_header rich;
|
2017-10-19 18:13:35 +02:00
|
|
|
nt_header_32 nt;
|
|
|
|
} pe_header;
|
2013-07-24 19:15:53 -04:00
|
|
|
|
2013-07-24 17:32:23 -04:00
|
|
|
typedef struct _parsed_pe {
|
2017-03-31 17:01:20 +02:00
|
|
|
bounded_buffer *fileBuffer;
|
|
|
|
parsed_pe_internal *internal;
|
|
|
|
pe_header peHeader;
|
2013-07-24 17:32:23 -04:00
|
|
|
} parsed_pe;
|
|
|
|
|
2019-10-14 15:57:54 -04:00
|
|
|
// Resolve a Rich header product id / build number pair to a known
|
|
|
|
// product name
|
|
|
|
typedef std::pair<std::uint16_t, std::uint16_t> ProductKey;
|
2019-11-17 01:45:55 +09:00
|
|
|
const std::string &GetRichObjectType(std::uint16_t prodId);
|
|
|
|
const std::string &GetRichProductName(std::uint16_t buildNum);
|
2019-10-14 15:57:54 -04:00
|
|
|
|
2014-03-07 13:18:24 -05:00
|
|
|
// get parser error status as integer
|
2017-10-19 18:13:35 +02:00
|
|
|
std::uint32_t GetPEErr();
|
2014-03-07 13:18:24 -05:00
|
|
|
|
|
|
|
// get parser error status as string
|
|
|
|
std::string GetPEErrString();
|
|
|
|
|
|
|
|
// get parser error location as string
|
|
|
|
std::string GetPEErrLoc();
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// get a PE parse context from a file
|
2013-07-24 17:32:23 -04:00
|
|
|
parsed_pe *ParsePEFromFile(const char *filePath);
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// destruct a PE context
|
2017-03-31 00:21:20 +02:00
|
|
|
void DestructParsedPE(parsed_pe *p);
|
2013-07-24 17:32:23 -04:00
|
|
|
|
2019-10-14 15:57:54 -04:00
|
|
|
// iterate over Rich header entries
|
|
|
|
typedef int (*iterRich)(void *, rich_entry);
|
|
|
|
void IterRich(parsed_pe *pe, iterRich cb, void *cbd);
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// iterate over the resources
|
2013-12-24 12:41:59 -05:00
|
|
|
typedef int (*iterRsrc)(void *, resource);
|
|
|
|
void IterRsrc(parsed_pe *pe, iterRsrc cb, void *cbd);
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// iterate over the imports by RVA and string
|
2018-09-24 08:10:29 -07:00
|
|
|
typedef int (*iterVAStr)(void *, VA, const std::string &, const std::string &);
|
2013-07-31 13:38:33 -04:00
|
|
|
void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd);
|
2013-07-24 17:35:25 -04:00
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// iterate over relocations in the PE file
|
2013-11-11 15:09:57 -05:00
|
|
|
typedef int (*iterReloc)(void *, VA, reloc_type);
|
2013-07-24 17:35:25 -04:00
|
|
|
void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd);
|
|
|
|
|
2017-03-16 22:18:08 +01:00
|
|
|
// Iterate over symbols (symbol table) in the PE file
|
2017-03-31 17:01:20 +02:00
|
|
|
typedef int (*iterSymbol)(void *,
|
|
|
|
std::string &,
|
2017-10-19 18:13:35 +02:00
|
|
|
std::uint32_t &,
|
|
|
|
std::int16_t &,
|
|
|
|
std::uint16_t &,
|
|
|
|
std::uint8_t &,
|
|
|
|
std::uint8_t &);
|
2017-03-16 22:18:08 +01:00
|
|
|
void IterSymbols(parsed_pe *pe, iterSymbol cb, void *cbd);
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// iterate over the exports
|
2013-11-11 15:09:57 -05:00
|
|
|
typedef int (*iterExp)(void *, VA, std::string &, std::string &);
|
2013-07-31 13:38:33 -04:00
|
|
|
void IterExpVA(parsed_pe *pe, iterExp cb, void *cbd);
|
2013-07-24 17:35:25 -04:00
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// iterate over sections
|
|
|
|
typedef int (*iterSec)(
|
|
|
|
void *, VA secBase, std::string &, image_section_header, bounded_buffer *b);
|
2013-07-24 17:57:58 -04:00
|
|
|
void IterSec(parsed_pe *pe, iterSec cb, void *cbd);
|
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// get byte at VA in PE
|
2017-03-09 19:10:17 +03:00
|
|
|
bool ReadByteAtVA(parsed_pe *pe, VA v, std::uint8_t &b);
|
2013-07-30 19:09:31 -04:00
|
|
|
|
2017-03-31 17:01:20 +02:00
|
|
|
// get entry point into PE
|
2013-11-11 15:09:57 -05:00
|
|
|
bool GetEntryPoint(parsed_pe *pe, VA &v);
|
2018-08-31 08:44:22 -07:00
|
|
|
|
|
|
|
// get machine as human readable string
|
|
|
|
const char *GetMachineAsString(parsed_pe *pe);
|
|
|
|
|
|
|
|
// get subsystem as human readable string
|
|
|
|
const char *GetSubsystemAsString(parsed_pe *pe);
|
2019-10-21 09:00:54 -04:00
|
|
|
|
|
|
|
// get a table or string by its data directory entry
|
2019-10-21 19:51:41 -04:00
|
|
|
bool GetDataDirectoryEntry(parsed_pe *pe,
|
|
|
|
data_directory_kind dirnum,
|
|
|
|
std::vector<std::uint8_t> &raw_entry);
|
2017-03-03 14:41:14 -05:00
|
|
|
} // namespace peparse
|