summaryrefslogtreecommitdiff
path: root/view/pe/peview.cpp
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
commit828fff839f4e4de3e9582405dfec567531000ebc (patch)
treeee0db0607edb0c76c653078672201c85e8a96d19 /view/pe/peview.cpp
parent47894a1ce20090849ad304c68e6c0b889665eda3 (diff)
Move view modules into the API repo
Diffstat (limited to 'view/pe/peview.cpp')
-rw-r--r--view/pe/peview.cpp2970
1 files changed, 2970 insertions, 0 deletions
diff --git a/view/pe/peview.cpp b/view/pe/peview.cpp
new file mode 100644
index 00000000..794cb5d6
--- /dev/null
+++ b/view/pe/peview.cpp
@@ -0,0 +1,2970 @@
+#include <algorithm>
+#include <cstring>
+#include <cctype>
+#include <string.h>
+#include <inttypes.h>
+#include <iomanip>
+#include <mutex>
+#include <sstream>
+#include <type_traits>
+#include <utility>
+#include "peview.h"
+#include "coffview.h"
+
+#define STRING_READ_CHUNK_SIZE 32
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+static PEViewType* g_peViewType = nullptr;
+static const char* imageDirName[] = { "exportTable", "importTable", "resourceTable", "exceptionTable", "certificateTable", "baseRelocationTable", "debug", "architecture", "globalPtr", "tlsTable", "loadConfigTable", "boundImport", "iat", "delayImportDescriptor", "clrRuntimeHeader", "reserved"};
+
+void BinaryNinja::InitPEViewType()
+{
+ static PEViewType type;
+ BinaryViewType::Register(&type);
+ g_peViewType = &type;
+}
+
+// String representation of Rich header object types
+static const string kProdId_C = "[ C ]";
+static const string kProdId_CPP = "[C++]";
+static const string kProdId_RES = "[RES]";
+static const string kProdId_IMP = "[IMP]";
+static const string kProdId_EXP = "[EXP]";
+static const string kProdId_ASM = "[ASM]";
+static const string kProdId_LNK = "[LNK]";
+static const string kProdId_UNK = "[ ? ]";
+
+static const std::map<uint16_t, string> ProductIdMap = {
+ {0x0000, kProdId_UNK},
+ {0x0002, kProdId_IMP},
+ {0x0004, kProdId_LNK},
+ {0x0006, kProdId_RES},
+ {0x000A, kProdId_C},
+ {0x000B, kProdId_CPP},
+ {0x000F, kProdId_ASM},
+ {0x0015, kProdId_C},
+ {0x0016, kProdId_CPP},
+ {0x0019, kProdId_IMP},
+ {0x001C, kProdId_C},
+ {0x001D, kProdId_CPP},
+ {0x003D, kProdId_LNK},
+ {0x003F, kProdId_EXP},
+ {0x0040, kProdId_ASM},
+ {0x0045, kProdId_RES},
+ {0x005A, kProdId_LNK},
+ {0x005C, kProdId_EXP},
+ {0x005D, kProdId_IMP},
+ {0x005E, kProdId_RES},
+ {0x005F, kProdId_C},
+ {0x0060, kProdId_CPP},
+ {0x006D, kProdId_C},
+ {0x006E, kProdId_CPP},
+ {0x0078, kProdId_LNK},
+ {0x007A, kProdId_EXP},
+ {0x007B, kProdId_IMP},
+ {0x007C, kProdId_RES},
+ {0x007D, kProdId_ASM},
+ {0x0083, kProdId_C},
+ {0x0084, kProdId_CPP},
+ {0x0091, kProdId_LNK},
+ {0x0092, kProdId_EXP},
+ {0x0093, kProdId_IMP},
+ {0x0094, kProdId_RES},
+ {0x0095, kProdId_ASM},
+ {0x009A, kProdId_RES},
+ {0x009B, kProdId_EXP},
+ {0x009C, kProdId_IMP},
+ {0x009D, kProdId_LNK},
+ {0x009E, kProdId_ASM},
+ {0x00AA, kProdId_C},
+ {0x00AB, kProdId_CPP},
+ {0x00C9, kProdId_RES},
+ {0x00CA, kProdId_EXP},
+ {0x00CB, kProdId_IMP},
+ {0x00CC, kProdId_LNK},
+ {0x00CD, kProdId_ASM},
+ {0x00CE, kProdId_C},
+ {0x00CF, kProdId_CPP},
+ {0x00DB, kProdId_RES},
+ {0x00DC, kProdId_EXP},
+ {0x00DD, kProdId_IMP},
+ {0x00DE, kProdId_LNK},
+ {0x00DF, kProdId_ASM},
+ {0x00E0, kProdId_C},
+ {0x00E1, kProdId_CPP},
+ {0x00FF, kProdId_RES},
+ {0x0100, kProdId_EXP},
+ {0x0101, kProdId_IMP},
+ {0x0102, kProdId_LNK},
+ {0x0103, kProdId_ASM},
+ {0x0104, kProdId_C},
+ {0x0105, kProdId_CPP}
+};
+
+
+// Mapping of Rich header build number to version strings
+static const std::map<uint16_t, const string> ProductMap = {
+ // Source: https://github.com/dishather/richprint/blob/master/comp_id.txt
+ {0x0000, "Imported Functions"},
+ {0x0684, "VS97 v5.0 SP3 cvtres 5.00.1668"},
+ {0x06B8, "VS98 v6.0 cvtres build 1720"},
+ {0x06C8, "VS98 v6.0 SP6 cvtres build 1736"},
+ {0x1C87, "VS97 v5.0 SP3 link 5.10.7303"},
+ {0x5E92, "VS2015 v14.0 UPD3 build 24210"},
+ {0x5E95, "VS2015 UPD3 build 24213"},
+
+ // http://bytepointer.com/articles/the_microsoft_rich_header.htm
+ {0x0BEC, "VS2003 v7.1 Free Toolkit .NET build 3052"},
+ {0x0C05, "VS2003 v7.1 .NET build 3077"},
+ {0x0FC3, "VS2003 v7.1 | Windows Server 2003 SP1 DDK build 4035"},
+ {0x1C83, "MASM 6.13.7299"},
+ {0x178E, "VS2003 v7.1 SP1 .NET build 6030"},
+ {0x1FE8, "VS98 v6.0 RTM/SP1/SP2 build 8168"},
+ {0x1FE9, "VB 6.0/SP1/SP2 build 8169"},
+ {0x20FC, "MASM 6.14.8444"},
+ {0x20FF, "VC++ 6.0 SP3 build 8447"},
+ {0x212F, "VB 6.0 SP3 build 8495"},
+ {0x225F, "VS 6.0 SP4 build 8799"},
+ {0x2263, "MASM 6.15.8803"},
+ {0x22AD, "VB 6.0 SP4 build 8877"},
+ {0x2304, "VB 6.0 SP5 build 8964"},
+ {0x2306, "VS 6.0 SP5 build 8966"},
+ // {0x2346, "MASM 6.15.9030 (VS.NET 7.0 BETA 1)"},
+ {0x2346, "VS 7.0 2000 Beta 1 build 9030"},
+ {0x2354, "VS 6.0 SP5 Processor Pack build 9044"},
+ {0x2426, "VS2001 v7.0 Beta 2 build 9254"},
+ {0x24FA, "VS2002 v7.0 .NET build 9466"},
+ {0x2636, "VB 6.0 SP6 / VC++ build 9782"},
+ {0x26E3, "VS2002 v7.0 SP1 build 9955"},
+ {0x520D, "VS2013 v12.[0,1] build 21005"},
+ {0x521E, "VS2008 v9.0 build 21022"},
+ {0x56C7, "VS2015 v14.0 build 22215"},
+ {0x59F2, "VS2015 v14.0 build 23026"},
+ {0x5BD2, "VS2015 v14.0 UPD1 build 23506"},
+ {0x5D10, "VS2015 v14.0 UPD2 build 23824"},
+ {0x5E97, "VS2015 v14.0 UPD3.1 build 24215"},
+ {0x7725, "VS2013 v12.0 UPD2 build 30501"},
+ {0x766F, "VS2010 v10.0 build 30319"},
+ {0x7809, "VS2008 v9.0 SP1 build 30729"},
+ {0x797D, "VS2013 v12.0 UPD4 build 31101"},
+ {0x9D1B, "VS2010 v10.0 SP1 build 40219"},
+ {0x9EB5, "VS2013 v12.0 UPD5 build 40629"},
+ {0xC497, "VS2005 v8.0 (Beta) build 50327"},
+ {0xC627, "VS2005 v8.0 | VS2012 v11.0 build 50727"},
+ {0xC751, "VS2012 v11.0 Nov CTP build 51025"},
+ {0xC7A2, "VS2012 v11.0 UPD1 build 51106"},
+ {0xEB9B, "VS2012 v11.0 UPD2 build 60315"},
+ {0xECC2, "VS2012 v11.0 UPD3 build 60610"},
+ {0xEE66, "VS2012 v11.0 UPD4 build 61030"},
+ {0x5E9A, "VS2015 v14.0 build 24218"},
+ {0x61BB, "VS2017 v14.1 build 25019"},
+
+ // https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd
+ {0x2264, "VS 6 [SP5,SP6] build 8804"},
+ {0x23D8, "Windows XP SP1 DDK"},
+ {0x0883, "Windows Server 2003 DDK"},
+ {0x08F4, "VS2003 v7.1 .NET Beta build 2292"},
+ {0x9D76, "Windows Server 2003 SP1 DDK (for AMD64)"},
+ {0x9E9F, "VS2005 v8.0 Beta 1 build 40607"},
+ {0xC427, "VS2005 v8.0 Beta 2 build 50215"},
+ {0xC490, "VS2005 v8.0 build 50320"},
+ {0x50E2, "VS2008 v9.0 Beta 2 build 20706"},
+ {0x501A, "VS2010 v10.0 Beta 1 build 20506"},
+ {0x520B, "VS2010 v10.0 Beta 2 build 21003"},
+ {0x5089, "VS2013 v12.0 Preview build 20617"},
+ {0x515B, "VS2013 v12.0 RC build 20827"},
+ {0x527A, "VS2013 v12.0 Nov CTP build 21114"},
+ {0x7674, "VS2013 v12.0 UPD2 RC build 30324"},
+ {0x63A3, "VS2017 v15.3.3 build 25507"},
+ {0x63C6, "VS2017 v15.4.4 build 25542"},
+ {0x63CB, "VS2017 v15.4.5 build 25547"},
+
+ // https://walbourn.github.io/visual-studio-2015-update-2/
+ {0x5D6E, "VS2015 v14.0 UPD2 build 23918"},
+
+ // https://walbourn.github.io/visual-studio-2017/
+ {0x61B9, "VS2017 v15.[0,1] build 25017"},
+ {0x63A2, "VS2017 v15.2 build 25019"},
+
+ // https://walbourn.github.io/vs-2017-15-5-update/
+ {0x64E6, "VS2017 v15 build 25830"},
+ {0x64E7, "VS2017 v15.5.2 build 25831"},
+ {0x64EA, "VS2017 v15.5.[3,4] build 25834"},
+ {0x64EB, "VS2017 v15.5.[5,6,7] build 25835"},
+
+ // https://walbourn.github.io/vs-2017-15-6-update/
+ {0x6610, "VS2017 v15.6.[0,1,2] build 26128"},
+ {0x6611, "VS2017 v15.6.[3,4] build 26129"},
+ {0x6613, "VS2017 v15.6.6 build 26131"},
+ {0x6614, "VS2017 v15.6.7 build 26132"},
+
+ // https://devblogs.microsoft.com/visualstudio/visual-studio-2017-update/
+ {0x6723, "VS2017 v15.1 build 26403"},
+
+ // https://walbourn.github.io/vs-2017-15-7-update/
+ {0x673C, "VS2017 v15.7.[0,1] build 26428"},
+ {0x673D, "VS2017 v15.7.2 build 26429"},
+ {0x673E, "VS2017 v15.7.3 build 26430"},
+ {0x673F, "VS2017 v15.7.4 build 26431"},
+ {0x6741, "VS2017 v15.7.5 build 26433"},
+
+ // https://walbourn.github.io/visual-studio-2019/
+ {0x6B74, "VS2019 v16.0.0 build 27508"},
+
+ // https://walbourn.github.io/vs-2017-15-8-update/
+ {0x6866, "VS2017 v15.8.0 build 26726"},
+ {0x6869, "VS2017 v15.8.4 build 26729"},
+ {0x686A, "VS2017 v15.8.9 build 26730"},
+ {0x686C, "VS2017 v15.8.5 build 26732"},
+
+ // https://walbourn.github.io/vs-2017-15-9-update/
+ {0x698F, "VS2017 v15.9.[0,1] build 27023"},
+ {0x6990, "VS2017 v15.9.2 build 27024"},
+ {0x6991, "VS2017 v15.9.4 build 27025"},
+ {0x6992, "VS2017 v15.9.5 build 27026"},
+ {0x6993, "VS2017 v15.9.7 build 27027"},
+ {0x6996, "VS2017 v15.9.11 build 27030"},
+ {0x6997, "VS2017 v15.9.12 build 27031"},
+ {0x6998, "VS2017 v15.9.14 build 27032"},
+ {0x699A, "VS2017 v15.9.16 build 27034"},
+
+ // https://walbourn.github.io/vs-2019-update-3/
+ {0x6DC9, "VS2019 v16.3.2 UPD3 build 28105"},
+
+ // https://walbourn.github.io/visual-studio-2013-update-3/
+ {0x7803, "VS2013 v12.0 UPD3 build 30723"},
+
+ // experimentation
+ {0x685B, "VS2017 v15.8.? build 26715"},
+
+ {27508, "VS2019 v16.0.0 build 27508"},
+
+ // https://walbourn.github.io/vs-2019-update-1/
+ {27702, "VS2019 v16.1.2 build 27702"},
+
+ // https://walbourn.github.io/vs-2019-update-2/
+ {27905, "VS2019 v16.2.3 build 27905"},
+
+ // https://walbourn.github.io/vs-2019-update-3/
+ {28105, "VS2019 v16.3.2 build 28105"},
+
+ // https://walbourn.github.io/vs-2019-update-4/
+ {28314, "VS2019 v16.4.0 build 28314"},
+ {28315, "VS2019 v16.4.3 build 28315"},
+ {28316, "VS2019 v16.4.4 build 28316"},
+ {28319, "VS2019 v16.4.6 build 28319"},
+
+ // https://walbourn.github.io/vs-2019-update-5/
+ {28610, "VS2019 v16.5.0 build 28610"},
+ {28611, "VS2019 v16.5.1 build 28611"},
+ {28612, "VS2019 v16.5.2 build 28612"},
+ {28614, "VS2019 v16.5.4 build 28614"},
+
+ // https://walbourn.github.io/vs-2019-update-6/
+ {28805, "VS2019 v16.6.0 build 28805"},
+ {28806, "VS2019 v16.6.1 build 28806"},
+
+ // https://walbourn.github.io/vs-2019-update-7/
+ {29110, "VS2019 v16.7.0 build 29110"},
+ {29111, "VS2019 v16.7.1 build 29111"},
+ {29112, "VS2019 v16.7.5 build 29112"},
+
+ // https://walbourn.github.io/vs-2019-update-8/
+ {29333, "VS2019 v16.8.0 build 29333"},
+ {29334, "VS2019 v16.8.2 build 29334"},
+ {29335, "VS2019 v16.8.3 build 29335"},
+ {29336, "VS2019 v16.8.4 build 29336"},
+ {29337, "VS2019 v16.8.5 build 29337"},
+
+ // https://walbourn.github.io/vs-2019-update-9/
+ {29910, "VS2019 v16.9.0 build 29910"},
+ {29911, "VS2019 v16.9.1 build 29911"},
+ {29912, "VS2019 v16.9.2 build 29912"},
+ {29913, "VS2019 v16.9.3 build 29913"},
+ {29914, "VS2019 v16.9.4 build 29914"},
+ {29915, "VS2019 v16.9.5 build 29915"},
+
+ // https://walbourn.github.io/vs-2019-update-10/
+ {30037, "VS2019 v16.10.0 build 30037"},
+ {30038, "VS2019 v16.10.2 build 30038"},
+ {30040, "VS2019 v16.10.4 build 30040"},
+
+ // https://walbourn.github.io/vs-2019-update-11/
+ {30133, "VS2019 v16.11.0 build 30133"},
+ {30136, "VS2019 v16.11.4 build 30136"},
+ {30137, "VS2019 v16.11.6 build 30137"},
+ {30138, "VS2019 v16.11.8 build 30138"},
+ {30139, "VS2019 v16.11.9 build 30139"},
+ {30140, "VS2019 v16.11.10 build 30140"},
+ {30141, "VS2019 v16.11.11 build 30141"},
+ {30142, "VS2019 v16.11.12 build 30142"},
+ {30143, "VS2019 v16.11.13 build 30143"},
+ {30145, "VS2019 v16.11.14 build 30145"},
+ {30146, "VS2019 v16.11.16 build 30146"},
+ {30147, "VS2019 v16.11.19 build 30147"},
+ {30148, "VS2019 v16.11.24 build 30148"},
+
+ // https://walbourn.github.io/visual-studio-2022/
+ {30705, "VS2022 17.0.0 build 30705"},
+ {30706, "VS2022 17.0.2 build 30706"},
+ {30709, "VS2022 17.0.5 build 30709"},
+
+ // https://walbourn.github.io/vs-2022-update-1/
+ {31104, "VS2022 17.1.0 build 31104"},
+ {31105, "VS2022 17.1.2 build 31105"},
+ {31106, "VS2022 17.1.4 build 31106"},
+ {31107, "VS2022 17.1.6 build 31107"},
+
+ // https://walbourn.github.io/vs-2022-update-2/
+ {31328, "VS2022 v17.2.0 build 31328"},
+ {31329, "VS2022 v17.2.1 build 31329"},
+ {31332, "VS2022 v17.2.5 build 31332"},
+
+ // https://walbourn.github.io/vs-2022-update-3/
+ {31629, "VS2022 v17.3.0 build 31629"},
+ {31630, "VS2022 v17.3.4 build 31630"},
+
+ // https://walbourn.github.io/vs-2022-update-4/
+ {31933, "VS2022 17.4.0 build 31933"},
+ {31935, "VS2022 17.4.2 build 31935"},
+ {31937, "VS2022 17.4.3 build 31937"},
+ {31942, "VS2022 17.4.5 build 31942"},
+
+ // https://walbourn.github.io/vs-2022-update-5/
+ {32215, "VS2022 17.5.0 build 32215"},
+ {32216, "VS2022 17.5.3 build 32216"},
+ {32217, "VS2022 17.5.4 build 32217"},
+};
+
+static const string kUnknownProduct = "<unknown>";
+
+// Returns a stringified Rich header object type given a product id
+const string &GetRichObjectType(uint16_t prodId) {
+
+ auto it = ProductIdMap.find(prodId);
+ if (it != ProductIdMap.end()) {
+ return it->second;
+ } else {
+ return kProdId_UNK;
+ }
+}
+
+// Returns a stringified Rich header product name given a build number
+const string &GetRichProductName(uint16_t buildNum) {
+
+ auto it = ProductMap.find(buildNum);
+ if (it != ProductMap.end()) {
+ return it->second;
+ } else {
+ return kUnknownProduct;
+ }
+}
+
+static string GetDebugTypeName(int type)
+{
+ switch (type)
+ {
+ case IMAGE_DEBUG_TYPE_UNKNOWN: return "debug_type_unknown";
+ case IMAGE_DEBUG_TYPE_COFF: return "debug_type_coff";
+ case IMAGE_DEBUG_TYPE_CODEVIEW: return "debug_type_codeview";
+ case IMAGE_DEBUG_TYPE_FPO: return "debug_type_fpo";
+ case IMAGE_DEBUG_TYPE_MISC: return "debug_type_misc";
+ case IMAGE_DEBUG_TYPE_EXCEPTION: return "debug_type_exception";
+ case IMAGE_DEBUG_TYPE_FIXUP: return "debug_type_fixup";
+ case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: return "debug_type_omap_to_src";
+ case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: return "debug_type_omap_from_src";
+ case IMAGE_DEBUG_TYPE_BORLAND: return "debug_type_borland";
+ case IMAGE_DEBUG_TYPE_RESERVED10: return "debug_type_reserved10";
+ case IMAGE_DEBUG_TYPE_CLSID: return "debug_type_clsid";
+ case IMAGE_DEBUG_TYPE_VC_FEATURE: return "debug_type_vc_feature";
+ case IMAGE_DEBUG_TYPE_POGO: return "debug_type_pogo";
+ case IMAGE_DEBUG_TYPE_ILTCG: return "debug_type_iltcg";
+ case IMAGE_DEBUG_TYPE_MPX: return "debug_type_mpx";
+ case IMAGE_DEBUG_TYPE_REPRO: return "debug_type_repro";
+ case IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS: return "debug_type_ex_dll_characteristics";
+ default: return string("debug_type_unknown(") + string(std::to_string(type)) + string(")");
+ }
+}
+
+
+PEView::PEView(BinaryView* data, bool parseOnly) : BinaryView("PE", data->GetFile(), data), m_parseOnly(parseOnly)
+{
+ CreateLogger("BinaryView");
+ m_logger = CreateLogger("BinaryView.PEView");
+ m_backedByDatabase = data->GetFile()->IsBackedByDatabase("PE");
+}
+
+
+bool PEView::Init()
+{
+ std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
+ map<string, size_t> usedSectionNames;
+
+ BinaryReader reader(GetParentView(), LittleEndian);
+ Ref<Platform> platform;
+
+ Ref<Settings> settings;
+ PEHeader header;
+ PEOptionalHeader opt;
+ memset(&opt, 0, sizeof(opt));
+
+ try
+ {
+ // Read PE offset
+ reader.Seek(0x3c);
+ uint32_t peOfs = reader.Read32();
+
+ // Read Rich header
+ vector<pair<uint32_t, uint32_t>> richValues;
+ const uint32_t richHeaderBase = 0x80;
+ if (peOfs > richHeaderBase)
+ {
+ reader.Seek(richHeaderBase);
+ for (uint32_t i = 0; i < ((peOfs - richHeaderBase) / 8); i++)
+ {
+ uint32_t var1 = reader.Read32();
+ uint32_t var2 = reader.Read32();
+ richValues.push_back({var1, var2});
+ }
+ }
+
+ // Read PE header
+ reader.Seek(peOfs);
+ header.magic = reader.Read32();
+ header.machine = reader.Read16();
+ header.sectionCount = reader.Read16();
+ header.timestamp = reader.Read32();
+ header.coffSymbolTable = reader.Read32();
+ header.coffSymbolCount = reader.Read32();
+ header.optionalHeaderSize = reader.Read16();
+ header.characteristics = reader.Read16();
+ m_logger->LogDebug(
+ "PEHeader:\n"
+ "\tmagic: 0x%08x\n"
+ "\tmachine: 0x%04x\n"
+ "\tsectionCount: 0x%04x\n"
+ "\ttimestamp: 0x%08x\n"
+ "\tcoffSymbolTable: 0x%08x\n"
+ "\tcoffSymbolCount: 0x%08x\n"
+ "\toptionalHeaderSize: 0x%04x\n"
+ "\tcharacteristics: 0x%04x %s, %s, %s\n",
+ header.magic,
+ header.machine,
+ header.sectionCount,
+ header.timestamp,
+ header.coffSymbolTable,
+ header.coffSymbolCount,
+ header.optionalHeaderSize,
+ header.characteristics,
+ header.characteristics & 1 ? "No Relocations" : "",
+ header.characteristics & 2 ? "Executable" : "",
+ header.characteristics & 0x2000 ? "Dll" : "Unknown");
+
+ uint64_t optionalHeaderOffset = reader.GetOffset();
+ // Read optional header
+ opt.magic = reader.Read16();
+ opt.majorLinkerVersion = reader.Read8();
+ opt.minorLinkerVersion = reader.Read8();
+ opt.sizeOfCode = reader.Read32();
+ opt.sizeOfInitData = reader.Read32();
+ opt.sizeOfUninitData = reader.Read32();
+ opt.addressOfEntry = reader.Read32();
+ opt.baseOfCode = reader.Read32();
+
+ m_logger->LogDebug(
+ "PEOptionalHeader:\n"
+ "\tmagic %04x (%s-bit)\n"
+ "\tmajorLinkerVersion: %02x\n"
+ "\tminorLinkerVersion: %02x\n"
+ "\tsizeOfCode: %08x\n"
+ "\tsizeOfInitData: %08x\n"
+ "\tsizeOfUninitData: %08x\n"
+ "\taddressOfEntry: %08x\n"
+ "\tbaseOfCode: %08x\n",
+ opt.magic, opt.magic == 0x10b ? "32" : opt.magic == 0x20b ? "64" : "??",
+ opt.majorLinkerVersion,
+ opt.minorLinkerVersion,
+ opt.sizeOfCode,
+ opt.sizeOfInitData,
+ opt.sizeOfUninitData,
+ opt.addressOfEntry,
+ opt.baseOfCode);
+
+ if (opt.magic == 0x10b) // 32-bit
+ {
+ m_is64 = false;
+ opt.baseOfData = reader.Read32();
+ opt.imageBase = reader.Read32();
+ opt.sectionAlign = reader.Read32();
+ opt.fileAlign = reader.Read32();
+ opt.majorOSVersion = reader.Read16();
+ opt.minorOSVersion = reader.Read16();
+ opt.majorImageVersion = reader.Read16();
+ opt.minorImageVersion = reader.Read16();
+ opt.majorSubsystemVersion = reader.Read16();
+ opt.minorSubsystemVersion = reader.Read16();
+ opt.win32Version = reader.Read32();
+ opt.sizeOfImage = reader.Read32();
+ opt.sizeOfHeaders = reader.Read32();
+ opt.checksum = reader.Read32();
+ opt.subsystem = reader.Read16();
+ opt.dllCharacteristics = reader.Read16();
+ opt.sizeOfStackReserve = reader.Read32();
+ opt.sizeOfStackCommit = reader.Read32();
+ opt.sizeOfHeapReserve = reader.Read32();
+ opt.sizeOfHeapCommit = reader.Read32();
+ opt.loaderFlags = reader.Read32();
+ opt.dataDirCount = reader.Read32();
+ }
+ else if (opt.magic == 0x20b) // 64-bit
+ {
+ m_is64 = true;
+ opt.baseOfData = 0;
+ opt.imageBase = reader.Read64();
+ opt.sectionAlign = reader.Read32();
+ opt.fileAlign = reader.Read32();
+ opt.majorOSVersion = reader.Read16();
+ opt.minorOSVersion = reader.Read16();
+ opt.majorImageVersion = reader.Read16();
+ opt.minorImageVersion = reader.Read16();
+ opt.majorSubsystemVersion = reader.Read16();
+ opt.minorSubsystemVersion = reader.Read16();
+ opt.win32Version = reader.Read32();
+ opt.sizeOfImage = reader.Read32();
+ opt.sizeOfHeaders = reader.Read32();
+ opt.checksum = reader.Read32();
+ opt.subsystem = reader.Read16();
+ opt.dllCharacteristics = reader.Read16();
+ opt.sizeOfStackReserve = reader.Read64();
+ opt.sizeOfStackCommit = reader.Read64();
+ opt.sizeOfHeapReserve = reader.Read64();
+ opt.sizeOfHeapCommit = reader.Read64();
+ opt.loaderFlags = reader.Read32();
+ opt.dataDirCount = reader.Read32();
+ }
+ else
+ {
+ m_logger->LogError("invalid PE optional header type");
+ return false;
+ }
+
+ map<string, Ref<Metadata>> metadataMap = {
+ {"Machine", new Metadata((uint64_t) header.machine)},
+ {"Characteristics", new Metadata((uint64_t) header.characteristics)},
+ {"Magic", new Metadata((uint64_t) opt.magic)},
+ {"MajorLinkerVersion", new Metadata((uint64_t) opt.majorLinkerVersion)},
+ {"MinorLinkerVersion", new Metadata((uint64_t) opt.minorLinkerVersion)},
+ {"MajorOSVersion", new Metadata((uint64_t) opt.majorOSVersion)},
+ {"MinorOSVersion", new Metadata((uint64_t) opt.minorOSVersion)},
+ {"MajorImageVersion", new Metadata((uint64_t) opt.majorImageVersion)},
+ {"MajorImageVersion", new Metadata((uint64_t) opt.majorImageVersion)},
+ {"MinorSubsystemVersion", new Metadata((uint64_t) opt.minorSubsystemVersion)},
+ {"MinorSubsystemVersion", new Metadata((uint64_t) opt.minorSubsystemVersion)},
+ {"Subsystem", new Metadata((uint64_t) opt.subsystem)},
+ {"DllCharacteristics", new Metadata((uint64_t) opt.dllCharacteristics)},
+ };
+
+ Ref<Metadata> metadata = new Metadata(metadataMap);
+
+ platform = g_peViewType->RecognizePlatform(header.machine, LittleEndian, GetParentView(), metadata);
+
+ // set m_arch early so the to make it available for the demangler
+ m_arch = platform ? platform->GetArchitecture() : g_peViewType->GetArchitecture(header.machine, LittleEndian);
+ if (!m_arch)
+ {
+ // There is no registered architecture for this header.machine likely malware doing something funky
+ // assume x86/x86_64
+ m_arch = g_peViewType->GetArchitecture(opt.magic == 0x20b ? 0x8664 : 0x14c, LittleEndian);
+ m_logger->LogWarn(
+ "This binary doesn't specify its architecture. Defaulting to x86. If this isn't correct please "
+ "re-open with 'with options' and specify the correct architecture.");
+ }
+ if (!platform)
+ platform = g_peViewType->GetPlatform(opt.subsystem, m_arch);
+ if (!platform)
+ platform = m_arch->GetStandalonePlatform();
+
+ m_imageBase = m_peImageBase = opt.imageBase;
+ SetOriginalBase(m_peImageBase);
+ m_entryPoint = opt.addressOfEntry;
+
+ Ref<Settings> viewSettings = Settings::Instance();
+ m_extractMangledTypes = viewSettings->Get<bool>("analysis.extractTypesFromMangledNames", this);
+ m_simplifyTemplates = viewSettings->Get<bool>("analysis.types.templateSimplifier", this);
+
+ settings = GetLoadSettings(GetTypeName());
+ if (settings && settings->Contains("loader.imageBase") && settings->Contains("loader.architecture")) // handle overrides
+ {
+ m_imageBase = settings->Get<uint64_t>("loader.imageBase", this);
+
+ Ref<Architecture> arch = Architecture::GetByName(settings->Get<string>("loader.architecture", this));
+ if (!m_arch || (arch && (arch->GetName() != m_arch->GetName())))
+ m_arch = arch;
+ }
+
+ // Apply architecture and platform
+ if (!m_arch)
+ {
+ switch (header.machine)
+ {
+ case 0x14c:
+ m_logger->LogError("Support for PE architecture 'x86' is not present");
+ break;
+ case 0x1c0:
+ m_logger->LogError("Support for PE architecture 'armv7' is not present");
+ break;
+ case 0x8664:
+ m_logger->LogError("Support for PE architecture 'x86_64' is not present");
+ break;
+ case 0xaa64:
+ #ifndef DEMO_VERSION
+ m_logger->LogError("Support for PE architecture 'arm64' is not present");
+ #else
+ m_logger->LogError("Binary Ninja free does not support PE architecture 'arm64'. "
+ "Purchase Binary Ninja to unlock all features.");
+ #endif
+ break;
+ default:
+ m_logger->LogError("PE architecture '0x%x' is not supported", header.machine);
+ break;
+ }
+ return false;
+ }
+
+
+ platform = platform->GetAssociatedPlatformByAddress(m_entryPoint);
+
+ if (settings && settings->Contains("loader.platform")) // handle overrides
+ {
+ Ref<Platform> platformOverride = Platform::GetByName(settings->Get<string>("loader.platform", this));
+ if (platformOverride)
+ platform = platformOverride;
+ }
+
+ SetDefaultPlatform(platform);
+ SetDefaultArchitecture(platform->GetArchitecture());
+
+ bool fileAlignmentValid = ((opt.fileAlign >= 0x200) && (opt.fileAlign <= 0x10000)) ? (opt.fileAlign & (opt.fileAlign - 1)) == 0 : false;
+ uint32_t resolvedSectionAlignment = fileAlignmentValid ? opt.sectionAlign : (header.machine == IMAGE_FILE_MACHINE_IA64) ? 0x2000 : 0x1000;
+ uint32_t resolvedFileAlignment = fileAlignmentValid ? opt.fileAlign : 0x200;
+ if (!fileAlignmentValid)
+ m_logger->LogWarn("PE has invalid FileAlignment with value: 0x%x", opt.fileAlign);
+ m_sizeOfHeaders = opt.sizeOfHeaders;
+ if (opt.sizeOfHeaders % resolvedFileAlignment)
+ m_sizeOfHeaders = (opt.sizeOfHeaders + resolvedFileAlignment) & ~(resolvedFileAlignment - 1);
+ m_relocatable = (opt.dllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) > 0;
+ m_logger->LogDebug(
+ "OptionalHeaderComponents:\n"
+ "\topt.baseOfData %08lx\n"
+ "\topt.imageBase %016lx\n"
+ "\topt.sectionAlign %08lx\n"
+ "\topt.fileAlign %08lx\n"
+ "\topt.majorOSVersion %04hx\n"
+ "\topt.minorOSVersion %04hx\n"
+ "\topt.majorImageVersion %04hx\n"
+ "\topt.minorImageVersion %04hx\n"
+ "\topt.majorSubsystemVersion %04hx\n"
+ "\topt.minorSubsystemVersion %04hx\n"
+ "\topt.win32Version %08lx\n"
+ "\topt.sizeOfImage %08lx\n"
+ "\topt.sizeOfHeaders %08lx\n"
+ "\topt.checksum %08lx\n"
+ "\topt.subsystem %04hx\n"
+ "\topt.dllCharacteristics %04hx\n"
+ "\topt.sizeOfStackReserve %016lx\n"
+ "\topt.sizeOfStackCommit %016lx\n"
+ "\topt.sizeOfHeapReserve %016lx\n"
+ "\topt.sizeOfHeapCommit %016lx\n"
+ "\topt.loaderFlags %08lx\n"
+ "\topt.dataDirCount %016llx\n"
+ "\topt.imageBase %016llx\n"
+ "\topt.sizeOfHeaders %08lx\n"
+ "\topt.addressOfEntry %08lx\n",
+ opt.baseOfData,
+ opt.imageBase,
+ opt.sectionAlign,
+ opt.fileAlign,
+ opt.majorOSVersion,
+ opt.minorOSVersion,
+ opt.majorImageVersion,
+ opt.minorImageVersion,
+ opt.majorSubsystemVersion,
+ opt.minorSubsystemVersion,
+ opt.win32Version,
+ opt.sizeOfImage,
+ opt.sizeOfHeaders,
+ opt.checksum,
+ opt.subsystem,
+ opt.dllCharacteristics,
+ opt.sizeOfStackReserve,
+ opt.sizeOfStackCommit,
+ opt.sizeOfHeapReserve,
+ opt.sizeOfHeapCommit,
+ opt.loaderFlags,
+ opt.dataDirCount,
+ opt.imageBase,
+ opt.sizeOfHeaders,
+ opt.addressOfEntry);
+
+ // PE Optional Header Validation
+ if (opt.dataDirCount > 16)
+ {
+ m_logger->LogWarn("PE Optional Header: NumberOfRvaAndSizes exceeds allowable size. Truncating count: %d to 16.",
+ opt.dataDirCount);
+ opt.dataDirCount = 16;
+ }
+
+ // Read data directories
+ for (uint32_t i = 0; i < opt.dataDirCount; i++)
+ {
+ PEDataDirectory dir;
+ dir.virtualAddress = reader.Read32();
+ dir.size = reader.Read32();
+ m_dataDirs.push_back(dir);
+ }
+
+ // Add extra segment to hold header so that it can be viewed. This must be first so
+ // that real sections take priority.
+ if (header.sectionCount)
+ AddAutoSegment(m_imageBase, m_sizeOfHeaders, 0, m_sizeOfHeaders, SegmentReadable);
+ else
+ {
+ uint64_t sizeOfImage = opt.sizeOfImage;
+ if (opt.sizeOfImage % resolvedSectionAlignment)
+ sizeOfImage = (opt.sizeOfImage + resolvedSectionAlignment) & ~(resolvedSectionAlignment - 1);
+ uint64_t dataLength = GetParentView()->GetEnd();
+ dataLength = std::min(std::max((uint64_t)m_sizeOfHeaders, sizeOfImage), dataLength);
+ AddAutoSegment(m_imageBase, sizeOfImage, 0, dataLength, SegmentReadable);
+ }
+ reader.Seek(optionalHeaderOffset + header.optionalHeaderSize);
+ // Read sections
+ BinaryReader sectionNameReader(GetParentView(), LittleEndian);
+ for (uint16_t i = 0; i < header.sectionCount; i++)
+ {
+ PESection section;
+ m_logger->LogDebug("Offset: %lx\n", reader.GetOffset());
+ char name[9];
+ memset(name, 0, sizeof(name));
+ reader.Read(name, 8);
+ string resolvedName = name;
+ if (name[0] == '/' && header.coffSymbolTable)
+ {
+ uint32_t stringTableBase = header.coffSymbolTable + (header.coffSymbolCount * 18);
+ errno = 0;
+ uint32_t offset = strtoul(name+1, nullptr, 10);
+ if (errno == 0 && offset > 0 && stringTableBase + offset < GetParentView()->GetEnd())
+ {
+ sectionNameReader.Seek(stringTableBase + offset);
+ resolvedName = sectionNameReader.ReadCString();
+ }
+ }
+ section.name = resolvedName;
+ if (section.name == ".reloc")
+ m_relocatable = true;
+
+ section.virtualSize = reader.Read32();
+ section.virtualAddress = reader.Read32();
+ section.sizeOfRawData = reader.Read32();
+ section.pointerToRawData = reader.Read32();
+ if (fileAlignmentValid && (section.pointerToRawData & (resolvedFileAlignment - 1)))
+ {
+ m_logger->LogWarn("PE section[%u] violates file alignment: pointerToRawData: 0x%x. Aligning to 0x%x.", i,
+ section.pointerToRawData, resolvedFileAlignment);
+ section.pointerToRawData &= ~(resolvedFileAlignment - 1);
+ }
+ section.pointerToRelocs = reader.Read32();
+ section.pointerToLineNumbers = reader.Read32();
+ section.relocCount = reader.Read16();
+ section.lineNumberCount = reader.Read16();
+ section.characteristics = reader.Read32();
+
+ if (section.virtualSize == 0)
+ {
+ section.virtualSize = section.sizeOfRawData;
+ }
+ m_sections.push_back(section);
+
+ uint32_t flags = 0;
+ if (section.characteristics & 0x80000000)
+ flags |= SegmentWritable;
+ if (section.characteristics & 0x40000000)
+ flags |= SegmentReadable;
+ if (section.characteristics & 0x20000000)
+ flags |= SegmentExecutable;
+ if (section.characteristics & 0x80)
+ flags |= SegmentContainsData;
+ if (section.characteristics & 0x40)
+ flags |= SegmentContainsData;
+ if (section.characteristics & 0x20)
+ flags |= SegmentContainsCode;
+
+
+ m_logger->LogDebug(
+ "Section [%d]\n"
+ "\tsection.name %s\n"
+ "\tsection.virtualSize: %lx\n"
+ "\tsection.virtualAddress: %lx\n"
+ "\tsection.sizeOfRawData: %lx\n"
+ "\tsection.pointerToRawData: %lx\n"
+ "\tsection.pointerToRelocs: %lx\n"
+ "\tsection.pointerToLineNumbers: %lx\n"
+ "\tsection.relocCount: %hx\n"
+ "\tsection.lineNumberCount: %hx\n"
+ "\tsection.characteristics: %lx\n"
+ "\tsection.virtualSize: %lx\n",
+ i, section.name.c_str(),
+ section.virtualAddress,
+ section.sizeOfRawData,
+ section.pointerToRawData,
+ section.pointerToRelocs,
+ section.pointerToLineNumbers,
+ section.relocCount,
+ section.lineNumberCount,
+ section.characteristics);
+
+ m_logger->LogDebug("Segment: Vaddr: %08" PRIx64 " Vsize: %08" PRIx64 " Offset: %08" PRIx64 " Rawsize: %08" PRIx64
+ " %c%c%c %s\n",
+ section.virtualAddress + m_imageBase,
+ section.virtualSize,
+ section.pointerToRawData,
+ section.sizeOfRawData,
+ (flags & SegmentExecutable) > 0 ? 'x':'-',
+ (flags & SegmentReadable) > 0 ? 'r':'-',
+ (flags & SegmentWritable) > 0 ? 'w':'-',
+ section.name.c_str());
+
+ if (!section.virtualSize)
+ continue;
+
+ AddAutoSegment(section.virtualAddress + m_imageBase, section.virtualSize, section.pointerToRawData, section.sizeOfRawData, flags);
+
+ BNSectionSemantics semantics = DefaultSectionSemantics;
+ uint32_t pFlags = flags & 0x7;
+ if (pFlags == (SegmentReadable | SegmentExecutable))
+ semantics = ReadOnlyCodeSectionSemantics;
+ else if (pFlags == SegmentReadable)
+ semantics = ReadOnlyDataSectionSemantics;
+ else if (pFlags == (SegmentReadable | SegmentWritable))
+ semantics = ReadWriteDataSectionSemantics;
+
+ // FIXME: For now everride semantics for well known section names and warn about the semantic promotion
+ static map<string, BNSectionSemantics> promotedSectionSemantics =
+ {
+ {"text", ReadOnlyCodeSectionSemantics},
+ {"code", ReadOnlyCodeSectionSemantics},
+ {"rdata", ReadOnlyDataSectionSemantics},
+ {"data", ReadWriteDataSectionSemantics},
+ {"bss", ReadWriteDataSectionSemantics}
+ };
+ string shortName = section.name;
+ if (shortName.length() && shortName[0] == '.')
+ shortName.erase(shortName.begin());
+ transform(shortName.begin(), shortName.end(), shortName.begin(), ::tolower);
+ if (auto itr = promotedSectionSemantics.find(shortName); (itr != promotedSectionSemantics.end()) && (itr->second != semantics))
+ {
+ m_logger->LogInfo("%s section semantics have been promoted to facilitate analysis.", section.name.c_str());
+ semantics = itr->second;
+ }
+
+ auto emplaced = usedSectionNames.emplace(section.name, 1);
+ if (emplaced.second)
+ {
+ AddAutoSection(section.name, section.virtualAddress + m_imageBase, section.virtualSize, semantics);
+ }
+ else
+ {
+ stringstream ss;
+ ss << section.name << "_" << ++emplaced.first->second;
+ AddAutoSection(ss.str(), section.virtualAddress + m_imageBase, section.virtualSize, semantics);
+ }
+ }
+
+ // Finished for parse only mode
+ if (m_parseOnly)
+ return true;
+
+ // Add the entry point as a function if the architecture is supported
+ if (m_entryPoint)
+ AddEntryPointForAnalysis(platform, m_imageBase + m_entryPoint);
+
+ // Create various PE header yypes
+
+ // Create MS-DOS Header Type
+ StructureBuilder dosHeaderBuilder;
+ dosHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 2), "e_magic");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_cblp");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_cp");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_crlc");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_cparhdr");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_minalloc");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_maxalloc");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_ss");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_sp");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_csum");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_ip");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_cs");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_lfarlc");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_ovno");
+ dosHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 8), "e_res1");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_oemid");
+ dosHeaderBuilder.AddMember(Type::IntegerType(2, false), "e_oeminfo");
+ dosHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 20), "e_res2");
+ dosHeaderBuilder.AddMember(Type::IntegerType(4, false), "e_lfanew");
+
+ Ref<Structure> dosHeaderStruct = dosHeaderBuilder.Finalize();
+ Ref<Type> dosHeaderType = Type::StructureType(dosHeaderStruct);
+ QualifiedName dosHeaderName = string("DOS_Header");
+ string dosHeaderTypeId = Type::GenerateAutoTypeId("pe", dosHeaderName);
+ QualifiedName dosHeaderTypeName = DefineType(dosHeaderTypeId, dosHeaderName, dosHeaderType);
+ DefineDataVariable(m_imageBase, Type::NamedType(this, dosHeaderTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__dos_header", m_imageBase, NoBinding));
+ DefineDataVariable(m_imageBase + 0x40, Type::VoidType());
+ DefineAutoSymbol(new Symbol(DataSymbol, "__dos_stub", m_imageBase + 0x40, NoBinding));
+
+ // Create Rich Header Type
+ // TODO move decoded rich info to comments once comments work with linear view
+ if (richValues.size() >= 4)
+ {
+ bool validRichHeader = false;
+ uint32_t xorKey = richValues[0].second;
+ uint32_t entryIdx;
+ vector<uint64_t> richMetadataLookupIdentifiers;
+ vector<string> richMetadataLookupNames;
+ for (const auto& [id, name] : ProductMap)
+ {
+ richMetadataLookupIdentifiers.push_back(id);
+ richMetadataLookupNames.push_back(name);
+ }
+ StoreMetadata("RichHeaderLookupIdentifiers", new Metadata(richMetadataLookupIdentifiers), true);
+ StoreMetadata("RichHeaderLookupNames", new Metadata(richMetadataLookupNames), true);
+
+ vector<Ref<Metadata>> richMetadata;
+ for (entryIdx = 0; entryIdx < richValues.size(); entryIdx++)
+ {
+ if ((richValues[entryIdx].first == 0x68636952) && (richValues[entryIdx].second == xorKey))
+ {
+ validRichHeader = true;
+ break;
+ }
+
+ richValues[entryIdx].first ^= xorKey;
+ richValues[entryIdx].second ^= xorKey;
+ if (entryIdx > 1) // Skip the first 2 entries as they don't contain interesting information
+ {
+ map<string, Ref<Metadata>> entryMetadata = {
+ {string("ObjectTypeValue"), new Metadata((uint64_t)richValues[entryIdx].first >> 16)},
+ {string("ObjectTypeName"), new Metadata(GetRichObjectType(richValues[entryIdx].first >> 16))},
+ {string("ObjectVersionValue"), new Metadata((uint64_t)richValues[entryIdx].first & 0xffff)},
+ {string("ObjectVersionName"), new Metadata(GetRichProductName(richValues[entryIdx].first & 0xffff))},
+ {string("ObjectCount"), new Metadata((uint64_t)richValues[entryIdx].second)}
+ };
+ richMetadata.push_back(new Metadata(entryMetadata));
+ }
+ if (!entryIdx && richValues[entryIdx].first != 0x536e6144)
+ break;
+ }
+
+ if (validRichHeader)
+ {
+ StoreMetadata("RichHeader", new Metadata(richMetadata), true);
+ StructureBuilder richHeaderBuilder;
+ richHeaderBuilder.AddMember(Type::IntegerType(4, false), "e_magic__DanS");
+ richHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(4, false), 3), "e_align");
+
+ for (uint32_t i = 2; i < entryIdx; i++)
+ {
+ stringstream ss;
+ ss << "e_entry_id" << std::dec << i-2 << "__" << std::hex << std::setw(8) << std::setfill('0') << richValues[i].first;
+ richHeaderBuilder.AddMember(Type::IntegerType(4, false), ss.str());
+ ss.str("");
+ ss.clear();
+ ss << "e_entry_count" << std::dec << i-2 << "__" << richValues[i].second;
+ richHeaderBuilder.AddMember(Type::IntegerType(4, false), ss.str());
+ }
+
+ richHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 4), "e_magic");
+ richHeaderBuilder.AddMember(Type::IntegerType(4, false), "e_checksum");
+
+ Ref<Structure> richHeaderStruct = richHeaderBuilder.Finalize();
+ Ref<Type> richHeaderType = Type::StructureType(richHeaderStruct);
+ QualifiedName richHeaderName = string("Rich_Header");
+ string richHeaderTypeId = Type::GenerateAutoTypeId("pe", richHeaderName);
+ QualifiedName richHeaderTypeName = DefineType(richHeaderTypeId, richHeaderName, richHeaderType);
+ DefineDataVariable(m_imageBase + richHeaderBase, Type::NamedType(this, richHeaderTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__rich_header", m_imageBase + richHeaderBase, NoBinding));
+ }
+ }
+
+ // Create COFF Header Type
+ EnumerationBuilder coffHeaderMachineBuilder;
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_UNKNOWN", IMAGE_FILE_MACHINE_UNKNOWN);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_AM33", IMAGE_FILE_MACHINE_AM33);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_AMD64", IMAGE_FILE_MACHINE_AMD64);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_ARM", IMAGE_FILE_MACHINE_ARM);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_ARM64", IMAGE_FILE_MACHINE_ARM64);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_ARMNT", IMAGE_FILE_MACHINE_ARMNT);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_EBC", IMAGE_FILE_MACHINE_EBC);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_I386", IMAGE_FILE_MACHINE_I386);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_IA64", IMAGE_FILE_MACHINE_IA64);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_M32R", IMAGE_FILE_MACHINE_M32R);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_MIPS16", IMAGE_FILE_MACHINE_MIPS16);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_MIPSFPU", IMAGE_FILE_MACHINE_MIPSFPU);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_MIPSFPU16", IMAGE_FILE_MACHINE_MIPSFPU16);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_POWERPC", IMAGE_FILE_MACHINE_POWERPC);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_POWERPCFP", IMAGE_FILE_MACHINE_POWERPCFP);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_R4000", IMAGE_FILE_MACHINE_R4000);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_RISCV32", IMAGE_FILE_MACHINE_RISCV32);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_RISCV64", IMAGE_FILE_MACHINE_RISCV64);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_RISCV128", IMAGE_FILE_MACHINE_RISCV128);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_SH3", IMAGE_FILE_MACHINE_SH3);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_SH3DSP", IMAGE_FILE_MACHINE_SH3DSP);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_SH4", IMAGE_FILE_MACHINE_SH4);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_SH5", IMAGE_FILE_MACHINE_SH5);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_THUMB", IMAGE_FILE_MACHINE_THUMB);
+ coffHeaderMachineBuilder.AddMemberWithValue("IMAGE_FILE_MACHINE_WCEMIPSV2", IMAGE_FILE_MACHINE_WCEMIPSV2);
+
+ Ref<Enumeration> coffHeaderMachineEnum = coffHeaderMachineBuilder.Finalize();
+ Ref<Type> coffHeaderMachineEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), coffHeaderMachineEnum, 2, false);
+ string coffHeaderMachineEnumName = "coff_machine";
+ string coffHeaderMachineEnumId = Type::GenerateAutoTypeId("pe", coffHeaderMachineEnumName);
+ QualifiedName coffHeaderMachineEnumTypeName = DefineType(coffHeaderMachineEnumId, coffHeaderMachineEnumName, coffHeaderMachineEnumType);
+
+ EnumerationBuilder coffCharacteristicsBuilder;
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_RELOCS_STRIPPED", IMAGE_FILE_RELOCS_STRIPPED);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_EXECUTABLE_IMAGE", IMAGE_FILE_EXECUTABLE_IMAGE);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_LINE_NUMS_STRIPPED", IMAGE_FILE_LINE_NUMS_STRIPPED);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_LOCAL_SYMS_STRIPPED", IMAGE_FILE_LOCAL_SYMS_STRIPPED);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_AGGRESIVE_WS_TRIM", IMAGE_FILE_AGGRESIVE_WS_TRIM);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_LARGE_ADDRESS_AWARE", IMAGE_FILE_LARGE_ADDRESS_AWARE);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_BYTES_REVERSED_LO", IMAGE_FILE_BYTES_REVERSED_LO);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_32BIT_MACHINE", IMAGE_FILE_32BIT_MACHINE);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_DEBUG_STRIPPED", IMAGE_FILE_DEBUG_STRIPPED);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP", IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_NET_RUN_FROM_SWAP", IMAGE_FILE_NET_RUN_FROM_SWAP);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_SYSTEM", IMAGE_FILE_SYSTEM);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_DLL", IMAGE_FILE_DLL);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_UP_SYSTEM_ONLY", IMAGE_FILE_UP_SYSTEM_ONLY);
+ coffCharacteristicsBuilder.AddMemberWithValue("IMAGE_FILE_BYTES_REVERSED_HI", IMAGE_FILE_BYTES_REVERSED_HI);
+
+ Ref<Enumeration> coffCharacteristicsEnum = coffCharacteristicsBuilder.Finalize();
+ Ref<Type> coffCharacteristicsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), coffCharacteristicsEnum, 2, false);
+ string coffCharacteristicsEnumName = "coff_characteristics";
+ string coffCharacteristicsEnumId = Type::GenerateAutoTypeId("pe", coffCharacteristicsEnumName);
+ QualifiedName coffCharacteristicsEnumTypeName = DefineType(coffCharacteristicsEnumId, coffCharacteristicsEnumName, coffCharacteristicsEnumType);
+
+ // TODO decorate members with comments once comments work with linear view
+ StructureBuilder coffHeaderBuilder;
+ coffHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 4), "magic");
+ coffHeaderBuilder.AddMember(Type::NamedType(this, coffHeaderMachineEnumTypeName), "machine");
+ coffHeaderBuilder.AddMember(Type::IntegerType(2, false), "numberOfSections");
+ coffHeaderBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
+ coffHeaderBuilder.AddMember(Type::IntegerType(4, false), "pointerToSymbolTable");
+ coffHeaderBuilder.AddMember(Type::IntegerType(4, false), "numberOfSymbols");
+ coffHeaderBuilder.AddMember(Type::IntegerType(2, false), "sizeOfOptionalHeader");
+ coffHeaderBuilder.AddMember(Type::NamedType(this, coffCharacteristicsEnumTypeName), "characteristics");
+
+ Ref<Structure> coffHeaderStruct = coffHeaderBuilder.Finalize();
+ Ref<Type> coffHeaderType = Type::StructureType(coffHeaderStruct);
+ QualifiedName coffHeaderName = string("COFF_Header");
+ string coffHeaderTypeId = Type::GenerateAutoTypeId("pe", coffHeaderName);
+ QualifiedName coffHeaderTypeName = DefineType(coffHeaderTypeId, coffHeaderName, coffHeaderType);
+ DefineDataVariable(m_imageBase + peOfs, Type::NamedType(this, coffHeaderTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__coff_header", m_imageBase + peOfs, NoBinding));
+
+ EnumerationBuilder peMagicBuilder;
+ peMagicBuilder.AddMemberWithValue("PE_ROM_IMAGE", 0x107);
+ peMagicBuilder.AddMemberWithValue("PE_32BIT", 0x10b);
+ peMagicBuilder.AddMemberWithValue("PE_64BIT", 0x20b);
+
+ Ref<Enumeration> peMagicEnum = peMagicBuilder.Finalize();
+ Ref<Type> peMagicEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), peMagicEnum, 2, false);
+ string peMagicEnumName = "pe_magic";
+ string peMagicEnumId = Type::GenerateAutoTypeId("pe", peMagicEnumName);
+ QualifiedName peMagicEnumTypeName = DefineType(peMagicEnumId, peMagicEnumName, peMagicEnumType);
+
+ EnumerationBuilder peSubsystemBuilder;
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_UNKNOWN", IMAGE_SUBSYSTEM_UNKNOWN);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_NATIVE", IMAGE_SUBSYSTEM_NATIVE);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_WINDOWS_GUI", IMAGE_SUBSYSTEM_WINDOWS_GUI);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_WINDOWS_CUI", IMAGE_SUBSYSTEM_WINDOWS_CUI);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_OS2_CUI", IMAGE_SUBSYSTEM_OS2_CUI);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_POSIX_CUI", IMAGE_SUBSYSTEM_POSIX_CUI);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_NATIVE_WINDOWS", IMAGE_SUBSYSTEM_NATIVE_WINDOWS);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_WINDOWS_CE_GUI", IMAGE_SUBSYSTEM_WINDOWS_CE_GUI);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_EFI_APPLICATION", IMAGE_SUBSYSTEM_EFI_APPLICATION);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_EFI_ROM", IMAGE_SUBSYSTEM_EFI_ROM);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_XBOX", IMAGE_SUBSYSTEM_XBOX);
+ peSubsystemBuilder.AddMemberWithValue("IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION);
+
+ Ref<Enumeration> peSubsystemEnum = peSubsystemBuilder.Finalize();
+ Ref<Type> peSubsystemEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), peSubsystemEnum, 2, false);
+ string peSubsystemEnumName = "pe_subsystem";
+ string peSubsystemEnumId = Type::GenerateAutoTypeId("pe", peSubsystemEnumName);
+ QualifiedName peSubsystemEnumTypeName = DefineType(peSubsystemEnumId, peSubsystemEnumName, peSubsystemEnumType);
+
+ EnumerationBuilder dllCharacteristicsBuilder;
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_0001", IMAGE_DLLCHARACTERISTICS_0001);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_0002", IMAGE_DLLCHARACTERISTICS_0002);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_0004", IMAGE_DLLCHARACTERISTICS_0004);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_0008", IMAGE_DLLCHARACTERISTICS_0008);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA", IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE", IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY", IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_NX_COMPAT", IMAGE_DLLCHARACTERISTICS_NX_COMPAT);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_NO_ISOLATION", IMAGE_DLLCHARACTERISTICS_NO_ISOLATION);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_NO_SEH", IMAGE_DLLCHARACTERISTICS_NO_SEH);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_NO_BIND", IMAGE_DLLCHARACTERISTICS_NO_BIND);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_APPCONTAINER", IMAGE_DLLCHARACTERISTICS_APPCONTAINER);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_WDM_DRIVER", IMAGE_DLLCHARACTERISTICS_WDM_DRIVER);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_GUARD_CF", IMAGE_DLLCHARACTERISTICS_GUARD_CF);
+ dllCharacteristicsBuilder.AddMemberWithValue("IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE", IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE);
+
+ Ref<Enumeration> dllCharacteristicsEnum = dllCharacteristicsBuilder.Finalize();
+ Ref<Type> dllCharacteristicsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), dllCharacteristicsEnum, 2, false);
+ string dllCharacteristicsEnumName = "pe_dll_characteristics";
+ string dllCharacteristicsEnumId = Type::GenerateAutoTypeId("pe", dllCharacteristicsEnumName);
+ QualifiedName dllCharacteristicsEnumTypeName = DefineType(dllCharacteristicsEnumId, dllCharacteristicsEnumName, dllCharacteristicsEnumType);
+
+ // Create PE Optional Header Type
+ StructureBuilder peOptionalHeaderBuilder;
+ peOptionalHeaderBuilder.AddMember(Type::NamedType(this, peMagicEnumTypeName), "magic");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(1, false), "majorLinkerVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(1, false), "minorLinkerVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfCode");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfInitializedData");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfUninitializedData");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "addressOfEntryPoint");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "baseOfCode");
+ if (!m_is64)
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "baseOfData");
+ size_t opFieldSize = m_is64 ? 8 : 4;
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(opFieldSize, false), "imageBase");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sectionAlignment");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "fileAlignment");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "majorOperatingSystemVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "minorOperatingSystemVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "majorImageVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "minorImageVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "majorSubsystemVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(2, false), "minorSubsystemVersion");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "win32VersionValue");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfImage");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfHeaders");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "checkSum");
+ peOptionalHeaderBuilder.AddMember(Type::NamedType(this, peSubsystemEnumTypeName), "subsystem");
+ peOptionalHeaderBuilder.AddMember(Type::NamedType(this, dllCharacteristicsEnumTypeName), "dllCharacteristics");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(opFieldSize, false), "sizeOfStackReserve");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(opFieldSize, false), "sizeOfStackCommit");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(opFieldSize, false), "sizeOfHeapReserve");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(opFieldSize, false), "sizeOfHeapCommit");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "loaderFlags");
+ peOptionalHeaderBuilder.AddMember(Type::IntegerType(4, false), "numberOfRvaAndSizes");
+
+ if (opt.dataDirCount)
+ {
+ StructureBuilder dataDirEntryBuilder;
+ dataDirEntryBuilder.AddMember(Type::IntegerType(4, false), "virtualAddress");
+ dataDirEntryBuilder.AddMember(Type::IntegerType(4, false), "size");
+
+ Ref<Structure> dataDirEntryStruct = dataDirEntryBuilder.Finalize();
+ Ref<Type> dataDirEntryType = Type::StructureType(dataDirEntryStruct);
+ QualifiedName dataDirName = string("PE_Data_Directory_Entry");
+ string dataDirTypeId = Type::GenerateAutoTypeId("pe", dataDirName);
+ QualifiedName dataDirTypeName = DefineType(dataDirTypeId, dataDirName, dataDirEntryType);
+ size_t dataDirNameCount = std::extent<decltype(imageDirName)>::value;
+ for (size_t i = 0; i < opt.dataDirCount; i++)
+ {
+ string dirName = (i < std::extent<decltype(imageDirName)>::value) ? imageDirName[i] : imageDirName[dataDirNameCount - 1];
+ peOptionalHeaderBuilder.AddMember(Type::NamedType(this, dataDirTypeName), dirName + "Entry");
+ }
+
+ }
+
+ string peHdrPrefix = m_is64 ? "pe64" : "pe32";
+ Ref<Structure> peOptionalHeaderStruct = peOptionalHeaderBuilder.Finalize();
+ Ref<Type> peOptionalHeaderType = Type::StructureType(peOptionalHeaderStruct);
+ QualifiedName peOptionalHeaderName = m_is64 ? string("PE64_Optional_Header") : string("PE32_Optional_Header");
+ string peOptionalHeaderTypeId = Type::GenerateAutoTypeId("pe", peOptionalHeaderName);
+ QualifiedName peOptionalHeaderTypeName = DefineType(peOptionalHeaderTypeId, peOptionalHeaderName, peOptionalHeaderType);
+ DefineDataVariable(m_imageBase + optionalHeaderOffset, Type::NamedType(this, peOptionalHeaderTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__" + peHdrPrefix + "_optional_header", m_imageBase + optionalHeaderOffset, NoBinding));
+
+ EnumerationBuilder peSectionFlagsBuilder;
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_RESERVED_0001", IMAGE_SCN_RESERVED_0001);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_RESERVED_0002", IMAGE_SCN_RESERVED_0002);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_RESERVED_0004", IMAGE_SCN_RESERVED_0004);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_TYPE_NO_PAD", IMAGE_SCN_TYPE_NO_PAD);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_RESERVED_0010", IMAGE_SCN_RESERVED_0010);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_CNT_CODE", IMAGE_SCN_CNT_CODE);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_CNT_INITIALIZED_DATA", IMAGE_SCN_CNT_INITIALIZED_DATA);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_CNT_UNINITIALIZED_DATA", IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_LNK_OTHER", IMAGE_SCN_LNK_OTHER);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_LNK_INFO", IMAGE_SCN_LNK_INFO);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_RESERVED_0400", IMAGE_SCN_RESERVED_0400);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_LNK_REMOVE", IMAGE_SCN_LNK_REMOVE);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_LNK_COMDAT", IMAGE_SCN_LNK_COMDAT);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_GPREL", IMAGE_SCN_GPREL);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_PURGEABLE", IMAGE_SCN_MEM_PURGEABLE);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_16BIT", IMAGE_SCN_MEM_16BIT);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_LOCKED", IMAGE_SCN_MEM_LOCKED);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_PRELOAD", IMAGE_SCN_MEM_PRELOAD);
+ // TODO fix the bug that causes flags to not be displayed when these are added to the enumeration
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_1BYTES", IMAGE_SCN_ALIGN_1BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_2BYTES", IMAGE_SCN_ALIGN_2BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_4BYTES", IMAGE_SCN_ALIGN_4BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_8BYTES", IMAGE_SCN_ALIGN_8BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_16BYTES", IMAGE_SCN_ALIGN_16BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_32BYTES", IMAGE_SCN_ALIGN_32BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_64BYTES", IMAGE_SCN_ALIGN_64BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_128BYTES", IMAGE_SCN_ALIGN_128BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_256BYTES", IMAGE_SCN_ALIGN_256BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_512BYTES", IMAGE_SCN_ALIGN_512BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_1024BYTES", IMAGE_SCN_ALIGN_1024BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_2048BYTES", IMAGE_SCN_ALIGN_2048BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_4096BYTES", IMAGE_SCN_ALIGN_4096BYTES);
+ // peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_ALIGN_8192BYTES", IMAGE_SCN_ALIGN_8192BYTES);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_LNK_NRELOC_OVFL", IMAGE_SCN_LNK_NRELOC_OVFL);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_DISCARDABLE", IMAGE_SCN_MEM_DISCARDABLE);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_NOT_CACHED", IMAGE_SCN_MEM_NOT_CACHED);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_NOT_PAGED", IMAGE_SCN_MEM_NOT_PAGED);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_SHARED", IMAGE_SCN_MEM_SHARED);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_EXECUTE", IMAGE_SCN_MEM_EXECUTE);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_READ", IMAGE_SCN_MEM_READ);
+ peSectionFlagsBuilder.AddMemberWithValue("IMAGE_SCN_MEM_WRITE", IMAGE_SCN_MEM_WRITE);
+
+ Ref<Enumeration> peSectionFlagsEnum = peSectionFlagsBuilder.Finalize();
+ Ref<Type> peSectionFlagsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), peSectionFlagsEnum, 4, false);
+ string peSectionFlagsEnumName = "pe_section_flags";
+ string peSectionFlagsEnumId = Type::GenerateAutoTypeId("pe", peSectionFlagsEnumName);
+ QualifiedName peSectionFlagsEnumTypeName = DefineType(peSectionFlagsEnumId, peSectionFlagsEnumName, peSectionFlagsEnumType);
+
+ if (header.sectionCount)
+ {
+ StructureBuilder sectionHeaderBuilder;
+ sectionHeaderBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 8), "name");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "virtualSize");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "virtualAddress");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeOfRawData");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "pointerToRawData");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "pointerToRelocations");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "pointerToLineNumbers");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(2, false), "numberOfRelocations");
+ sectionHeaderBuilder.AddMember(Type::IntegerType(2, false), "numberOfLineNumbers");
+ sectionHeaderBuilder.AddMember(Type::NamedType(this, peSectionFlagsEnumTypeName), "characteristics");
+
+ Ref<Structure> sectionHeaderStruct = sectionHeaderBuilder.Finalize();
+ Ref<Type> sectionHeaderStructType = Type::StructureType(sectionHeaderStruct);
+ QualifiedName sectionHeaderName = string("Section_Header");
+ string sectionHeaderTypeId = Type::GenerateAutoTypeId("pe", sectionHeaderName);
+ QualifiedName sectionHeaderTypeName = DefineType(sectionHeaderTypeId, sectionHeaderName, sectionHeaderStructType);
+
+ size_t sectionHeaderOffset = optionalHeaderOffset + header.optionalHeaderSize;
+ DefineDataVariable(m_imageBase + sectionHeaderOffset, Type::ArrayType(Type::NamedType(this, sectionHeaderTypeName), header.sectionCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__section_headers", m_imageBase + sectionHeaderOffset, NoBinding));
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogError("Failed to parse PE headers: %s\n", e.what());
+ return false;
+ }
+
+ vector<pair<BNRelocationInfo, string>> relocs;
+ BeginBulkModifySymbols();
+ m_symbolQueue = new SymbolQueue();
+ m_symExternMappingMetadata = new Metadata(KeyValueDataType);
+
+ try
+ {
+ // Process COFF symbol table
+ if (header.coffSymbolCount)
+ {
+ BinaryReader stringReader(GetParentView(), LittleEndian);
+ uint64_t stringTableBase = header.coffSymbolTable + (header.coffSymbolCount * 18);
+ stringReader.Seek(stringTableBase);
+ if ((stringTableBase + stringReader.Read32()) > GetParentView()->GetEnd())
+ {
+ throw PEFormatException("invalid COFF string table size");
+ }
+
+ for (size_t i = 0; i < header.coffSymbolCount; i++)
+ {
+ reader.Seek(header.coffSymbolTable + (i * 18));
+ uint32_t e_zeroes = reader.Read32();
+ uint32_t e_offset = reader.Read32();
+ uint32_t e_value = reader.Read32();
+ uint16_t e_scnum = reader.Read16();
+ uint16_t e_type = reader.Read16();
+ uint8_t e_sclass = reader.Read8();
+ uint8_t e_numaux = reader.Read8();
+
+ uint64_t virtualAddress = 0;
+ switch (e_scnum)
+ {
+ case IMAGE_SYM_UNDEFINED:
+ case (uint16_t)IMAGE_SYM_ABSOLUTE:
+ case (uint16_t)IMAGE_SYM_DEBUG:
+ break;
+ default:
+ if (size_t(e_scnum - 1) < m_sections.size())
+ virtualAddress = m_sections[size_t(e_scnum - 1)].virtualAddress + e_value;
+ break;
+ }
+
+ // read symbol name
+ string symbolName;
+ if (virtualAddress)
+ {
+ if (e_zeroes)
+ {
+ stringReader.Seek(header.coffSymbolTable + (i * 18));
+ symbolName = stringReader.ReadCString(8);
+ }
+ else
+ {
+ stringReader.Seek(stringTableBase + e_offset);
+ symbolName = stringReader.ReadCString();
+ }
+ }
+
+ BNSymbolBinding binding;
+ switch (e_sclass)
+ {
+ case IMAGE_SYM_CLASS_EXTERNAL:
+ case IMAGE_SYM_CLASS_STATIC:
+ binding = LocalBinding;
+ break;
+ default:
+ binding = NoBinding;
+ break;
+ }
+
+ // if (virtualAddress)
+ // m_logger->LogError("RawOffset:0x%x StorageClass:%u Type:%x NumAux:%x VA: 0x%x section:%x %s",
+ // header.coffSymbolTable + (i * 18), e_sclass, e_type, e_numaux, virtualAddress + m_imageBase, e_scnum,
+ // symbolName.c_str()); else m_logger->LogError("RawOffset:0x%x StorageClass:%u Type:%x NumAux:%x VA: 0x%x
+ // section:%x value: %x", header.coffSymbolTable + (i * 18), e_sclass, e_type, e_numaux, virtualAddress
+ // + m_imageBase, e_scnum, e_value);
+
+ uint8_t baseType = (e_type >> 4) & 0x3;
+ switch (baseType)
+ {
+ case IMAGE_SYM_DTYPE_NULL: // no derived type
+ {
+ if (virtualAddress)
+ AddPESymbol(DataSymbol, "", symbolName, virtualAddress, binding);
+ break;
+ }
+ case IMAGE_SYM_DTYPE_POINTER: // pointer to base type
+ {
+ break;
+ }
+ case IMAGE_SYM_DTYPE_FUNCTION: // function that returns base type
+ {
+ //LogError("%x StorageClass:%u Type:%x NumAux:%x COFF_DT_FCN at %x section:%x %s ", header.coffSymbolTable + (i * 18), e_sclass, e_type, e_numaux, virtualAddress + m_imageBase, e_scnum, symbolName.c_str());
+ if (virtualAddress)
+ AddPESymbol(FunctionSymbol, "", symbolName, virtualAddress, binding);
+ break;
+ }
+ case IMAGE_SYM_DTYPE_ARRAY: // array of base type
+ {
+ break;
+ }
+ default:
+ break;
+ }
+
+ // TODO handle auxiliary entries
+ i += e_numaux;
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogError("Failed to parse COFF symbol table: %s\n", e.what());
+ }
+
+ try
+ {
+ PEDataDirectory dir;
+ // Read import directory
+ if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_IMPORT)
+ dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_IMPORT];
+ else
+ dir.virtualAddress = 0;
+
+ if (dir.virtualAddress > 0)
+ {
+ size_t numImportEntries = 0;
+ vector<Ref<Metadata>> libraries;
+ vector<Ref<Metadata>> libraryFound;
+ while (true)
+ {
+ // Read in next directory entry
+ reader.Seek(RVAToFileOffset(dir.virtualAddress + (numImportEntries * 20)));
+ PEImportDirectoryEntry importDirEntry;
+ importDirEntry.lookup = reader.Read32();
+ importDirEntry.timestamp = reader.Read32();
+ importDirEntry.forwardChain = reader.Read32();
+ importDirEntry.nameAddress = reader.Read32();
+ importDirEntry.iat = reader.Read32();
+
+ // Windows PE loader ignores the dir.size; instead, it looks for the first
+ // Import_Directory_Table that has a null nameAddress to stop the iteration
+ if (importDirEntry.nameAddress == 0)
+ {
+ if (numImportEntries + 1 != dir.size / 20)
+ m_logger->LogWarn(
+ "The number of Import_Directory_Table reported by the Data Directories is different from "
+ "its correct amount. "
+ "There are actually %d Import_Directory_Table in the file, but SizeOfImportTable reports "
+ "%d. "
+ "The PE parsing continues with the actual number of Import_Directory_Table",
+ numImportEntries + 1, dir.size / 20);
+ break;
+ }
+
+ // Read name of imported DLL, and trim extension for creating symbol name
+ importDirEntry.name = ReadString(importDirEntry.nameAddress);
+ Ref<ExternalLibrary> externLib = GetExternalLibrary(importDirEntry.name);
+ if (!externLib)
+ {
+ externLib = AddExternalLibrary(importDirEntry.name, {}, true);
+ }
+ libraries.push_back(new Metadata(string(importDirEntry.name)));
+ string lowerName = importDirEntry.name;
+ std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
+ [](unsigned char c){ return std::tolower(c); });
+
+ vector<Ref<TypeLibrary>> typeLibs = platform->GetTypeLibrariesByName(lowerName);
+ for (const auto& typeLib : typeLibs)
+ {
+ // Check if the type library is already added
+ if (GetTypeLibrary(typeLib->GetName()))
+ continue;
+ AddTypeLibrary(typeLib);
+
+ m_logger->LogDebug("pe: adding type library for '%s': %s (%s)", lowerName.c_str(),
+ typeLib->GetName().c_str(), typeLib->GetGuid().c_str());
+ }
+
+ Ref<Metadata> ordinals;
+ if (typeLibs.size())
+ {
+ for (const auto& typeLib : typeLibs)
+ {
+ char ordinal_subsystem[64];
+ snprintf(ordinal_subsystem, sizeof(ordinal_subsystem), "ordinals_%hu_%hu", opt.majorOSVersion, opt.minorOSVersion);
+ ordinals = typeLib->QueryMetadata("ordinals");
+ libraryFound.push_back(new Metadata(string(typeLib->GetName())));
+ if (ordinals && ordinals->IsString())
+ ordinals = typeLib->QueryMetadata(ordinals->GetString());
+
+ if (ordinals && !ordinals->IsKeyValueStore())
+ ordinals = nullptr;
+ }
+ }
+ else
+ libraryFound.push_back(new Metadata(string("")));
+
+
+ size_t dotPos = importDirEntry.name.rfind('.');
+ string dllName;
+ if (dotPos == string::npos)
+ dllName = importDirEntry.name;
+ else
+ dllName = importDirEntry.name.substr(0, dotPos);
+
+ // Create Import DLL Name Type
+ DefineDataVariable(m_imageBase + importDirEntry.nameAddress, Type::ArrayType(Type::IntegerType(1, true), importDirEntry.name.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__import_dll_name(" + dllName + ")", m_imageBase + importDirEntry.nameAddress, NoBinding));
+
+ // Parse list of imported functions
+ uint32_t entryOffset = importDirEntry.lookup;
+ uint32_t iatOffset = importDirEntry.iat;
+
+ if ((entryOffset == 0) && (iatOffset != 0))
+ entryOffset = iatOffset;
+
+ // TODO: entryOffset and iatOffset point to two copies of the same data
+ // We should make this second unused data a structure containing this information information
+ // and default it to collapsed...IDA Just doesn't show anything at all
+ m_logger->LogDebug("Name: %s\n", dllName.c_str());
+ while (true)
+ {
+ uint64_t entry;
+ bool isOrdinal;
+ if (m_is64)
+ {
+ entry = Read64(entryOffset);
+ isOrdinal = (entry & 0x8000000000000000LL) != 0;
+ entry &= 0x7fffffffffffffffLL;
+ DefineDataVariable(m_imageBase + entryOffset, Type::IntegerType(8, false));
+ }
+ else
+ {
+ entry = Read32(entryOffset);
+ isOrdinal = (entry & 0x80000000) != 0;
+ entry &= 0x7fffffff;
+ DefineDataVariable(m_imageBase + entryOffset, Type::IntegerType(4, false));
+ }
+ m_logger->LogDebug("Entry 0x%llx isOrdinal: %s\n", entry, isOrdinal ? "True" : "False");
+
+ if ((!isOrdinal) && (entry == 0))
+ break;
+
+ string func;
+ uint16_t ordinal;
+ if (isOrdinal)
+ {
+ ordinal = (uint16_t)entry;
+ string ordString = to_string(ordinal);
+ Ref<Metadata> ordInfo = nullptr;
+
+ if (ordinals)
+ ordInfo = ordinals->Get(ordString);
+
+ if (ordInfo && ordInfo->IsString())
+ func = ordInfo->GetString();
+ else
+ func = "Ordinal_" + dllName + "_" + to_string((int)entry);
+ }
+ else
+ {
+ ordinal = Read16(entry);
+ func = ReadString(entry + 2);
+ DefineDataVariable(m_imageBase + entry, Type::IntegerType(2, false));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__export_name_ptr_table_" + to_string(numImportEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entry, NoBinding));
+ DefineDataVariable(m_imageBase + entry + 2, Type::ArrayType(Type::IntegerType(1, true), func.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__import_name_" + to_string(numImportEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entry + 2, NoBinding));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__import_lookup_table_" + to_string(numImportEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entryOffset, NoBinding));
+ }
+ m_logger->LogDebug("FuncString: %s\n", func.c_str());
+ AddPESymbol(ImportAddressSymbol, dllName, func, iatOffset, NoBinding, ordinal, typeLibs);
+ AddPESymbol(ExternalSymbol, dllName, func, 0, NoBinding, ordinal, typeLibs);
+
+ if (externLib)
+ m_symExternMappingMetadata->SetValueForKey(func, new Metadata(externLib->GetName()));
+
+ BNRelocationInfo reloc;
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.nativeType = -1;
+ reloc.address = m_imageBase + iatOffset;
+ reloc.size = m_is64 ? 8 : 4;
+ reloc.pcRelative = false;
+ reloc.base = m_imageBase - m_peImageBase;
+ reloc.external = true;
+ relocs.push_back({reloc, func});
+ entryOffset += m_is64 ? 8 : 4;
+ iatOffset += m_is64 ? 8 : 4;
+ }
+
+ numImportEntries++;
+ }
+
+ StoreMetadata("Libraries", new Metadata(libraries), true);
+ StoreMetadata("LibraryFound", new Metadata(libraryFound), true);
+ if (numImportEntries)
+ {
+ // Create Import Directory Table Type
+ StructureBuilder importDirBuilder;
+ importDirBuilder.AddMember(Type::IntegerType(4, false), "importLookupTableRva");
+ importDirBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
+ importDirBuilder.AddMember(Type::IntegerType(4, false), "forwarderChain");
+ importDirBuilder.AddMember(Type::IntegerType(4, false), "nameRva");
+ importDirBuilder.AddMember(Type::IntegerType(4, false), "importAddressTableRva");
+
+ Ref<Structure> importDirStruct = importDirBuilder.Finalize();
+ Ref<Type> importDirType = Type::StructureType(importDirStruct);
+ QualifiedName importDirName = string("Import_Directory_Table");
+ string importDirTypeId = Type::GenerateAutoTypeId("pe", importDirName);
+ QualifiedName importDirTypeName = DefineType(importDirTypeId, importDirName, importDirType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_IMPORT].virtualAddress, Type::ArrayType(Type::NamedType(this, importDirTypeName), numImportEntries + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__import_directory_entries", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_IMPORT].virtualAddress, NoBinding));
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse import directory: %s\n", e.what());
+ }
+
+ try
+ {
+ if ((m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_EXCEPTION) && m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].size)
+ {
+ // Create Exception Directory Table Entry Type
+ size_t entrySize;
+ size_t numExceptionEntries;
+ StructureBuilder exceptionEntryBuilder;
+ switch (header.machine)
+ {
+ case IMAGE_FILE_MACHINE_AMD64:
+ case IMAGE_FILE_MACHINE_IA64:
+ {
+ entrySize = 12;
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "beginAddress");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "endAddress");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "unwindInformation");
+ break;
+ }
+ case IMAGE_FILE_MACHINE_MIPSFPU:
+ case IMAGE_FILE_MACHINE_R4000:
+ case IMAGE_FILE_MACHINE_WCEMIPSV2:
+ {
+ entrySize = 20;
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "beginAddress");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "endAddress");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "exceptionHandler");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "handlerData");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "prologEndAddress");
+ break;
+ }
+ default:
+ {
+ entrySize = 8;
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "beginAddress");
+ exceptionEntryBuilder.AddMember(Type::IntegerType(4, false), "otherInformation");
+ break;
+ }
+ }
+
+ if (m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].size % entrySize)
+ throw PEFormatException("invalid table size");
+ numExceptionEntries = m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].size / entrySize;
+
+ // This DataVariable can end up creating a large array and rendering this in LinearView currently has performance implications
+ // So instead we just create separate structures not in an array
+ Ref<Structure> exceptionEntryStruct = exceptionEntryBuilder.Finalize();
+ Ref<Type> exceptionEntryType = Type::StructureType(exceptionEntryStruct);
+ QualifiedName exceptionEntryName = string("Exception_Directory_Entry");
+ string exceptionEntryTypeId = Type::GenerateAutoTypeId("pe", exceptionEntryName);
+ QualifiedName exceptionEntryTypeName = DefineType(exceptionEntryTypeId, exceptionEntryName, exceptionEntryType);
+ for (size_t i = 0; i < numExceptionEntries; i++)
+ {
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].virtualAddress + (entrySize * i), Type::NamedType(this, exceptionEntryTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__exception_directory_entries(" + string(std::to_string(i)) + ")", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].virtualAddress + (entrySize * i), NoBinding));
+ }
+
+ // parse exception table and add functions
+ bool processExceptionTable = true;
+ if (settings && settings->Contains("loader.pe.processExceptionTable"))
+ processExceptionTable = settings->Get<bool>("loader.pe.processExceptionTable", this);
+ if (processExceptionTable)
+ {
+ StructureBuilder unwindInfoStructBuilder;
+ unwindInfoStructBuilder.AddMember(Type::IntegerType(1, false), "VersionAndFlag");
+ unwindInfoStructBuilder.AddMember(Type::IntegerType(1, false), "SizeOfProlog");
+ unwindInfoStructBuilder.AddMember(Type::IntegerType(1, false), "CountOfUnwindCodes");
+ unwindInfoStructBuilder.AddMember(Type::IntegerType(1, false), "FrameRegisterAndFrameRegisterOffset");
+
+ Ref<Structure> unwindInfoStruct = unwindInfoStructBuilder.Finalize();
+ Ref<Type> unwindInfoStructType = Type::StructureType(unwindInfoStruct);
+ QualifiedName unwindInfoName = string("UNWIND_INFO");
+ string unwindInfoTypeId = Type::GenerateAutoTypeId("pe", unwindInfoName);
+ QualifiedName unwindInfo = DefineType(unwindInfoTypeId, unwindInfoName, unwindInfoStructType);
+
+ BinaryReader unwindReader(GetParentView(), LittleEndian);
+ for (size_t i = 0; i < numExceptionEntries; i++)
+ {
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].virtualAddress + (i * entrySize)));
+ uint32_t beginAddress = reader.Read32();
+ switch (header.machine)
+ {
+ case IMAGE_FILE_MACHINE_AMD64:
+ case IMAGE_FILE_MACHINE_IA64:
+ {
+ reader.SeekRelative(4); // EndAddress
+ uint32_t unwindRva = reader.Read32();
+ DefineDataVariable(m_imageBase + unwindRva, Type::NamedType(this, unwindInfo));
+ unwindReader.Seek(RVAToFileOffset(unwindRva));
+ uint32_t unwindInformation = unwindReader.Read32();
+ uint8_t unwindCodeCount = (unwindInformation >> 16) & 0xff;
+ if (unwindCodeCount > 0)
+ DefineDataVariable(m_imageBase + unwindRva + 4, Type::ArrayType(Type::IntegerType(2, false), unwindCodeCount));
+
+ auto current = m_imageBase + unwindRva + 4 + (unwindCodeCount * 2);
+ if (current % 4 != 0)
+ current += 4 - (current % 4); // Align to DWORD
+
+ if (unwindInformation & (UNW_FLAG_CHAININFO << 3))
+ {
+ DefineDataVariable(current, Type::NamedType(this, exceptionEntryTypeName));
+ continue;
+ }
+ else if ((unwindInformation & (UNW_FLAG_UHANDLER << 3)) || (unwindInformation & (UNW_FLAG_EHANDLER << 3)))
+ {
+ DefineDataVariable(current, Type::IntegerType(4, false));
+ // unwindReader.Seek(RVAToFileOffset(unwindRva + 8 + (unwindCodeCount * 2)));
+ // uint32_t count = unwindReader.Read32();
+ // DefineDataVariable(current + 4, Type::ArrayType(Type::IntegerType(4, false), 3));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ uint64_t exceptionEntry = m_imageBase + beginAddress;
+ Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(exceptionEntry);
+ AddFunctionForAnalysis(targetPlatform, exceptionEntry);
+ }
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse exception directory: %s\n", e.what());
+ }
+
+ try
+ {
+ if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_DEBUG)
+ {
+ PEDataDirectory dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_DEBUG];
+ if (dir.size >= sizeof(DebugDirectory))
+ {
+
+ m_logger->LogDebug("Parsing IMAGE_DIRECTORY_ENTRY_DEBUG: %08x", dir.size);
+ for (uint32_t i = 0; i < dir.size / sizeof(DebugDirectory); i++)
+ {
+ reader.Seek(RVAToFileOffset(dir.virtualAddress + i * sizeof(DebugDirectory)));
+ DebugDirectory debugDir;
+ reader.Read(&debugDir, sizeof(DebugDirectory));
+
+ m_logger->LogDebug(
+ "DebugDirectory:\n"
+ "\tcharacteristics: %08x\n"
+ "\ttimeDateStamp: %08x\n"
+ "\tmajorVersion: %08x\n"
+ "\tminorVersion: %08x\n"
+ "\ttype: %08x\n"
+ "\tsizeOfData: %08x\n"
+ "\taddressOfRawData: %08x\n"
+ "\tpointerToRawData: %08x\n",
+ debugDir.characteristics,
+ debugDir.timeDateStamp,
+ debugDir.majorVersion,
+ debugDir.minorVersion,
+ debugDir.type,
+ debugDir.sizeOfData,
+ RVAToFileOffset(debugDir.addressOfRawData, false),
+ debugDir.pointerToRawData
+ );
+
+ if (!debugDir.addressOfRawData)
+ continue;
+
+ if (debugDir.type == IMAGE_DEBUG_TYPE_CODEVIEW) // PDB Information
+ {
+ auto type = TypeBuilder::IntegerType(4, false);
+ type.SetIntegerTypeDisplayType(CharacterConstantDisplayType);
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData, type.Finalize());
+ DefineAutoSymbol(new Symbol(DataSymbol, "debugInfoType", m_imageBase + debugDir.addressOfRawData, NoBinding));
+
+
+ reader.Seek(RVAToFileOffset(debugDir.addressOfRawData));
+ uint32_t signature = reader.Read32();
+ StoreMetadata("DEBUG_INFO_TYPE", new Metadata((uint64_t)signature), true);
+ if (signature == 0x53445352) // SDSR
+ {
+ vector<uint8_t> guid(16);
+ reader.Read(&guid[0], 16);
+ uint32_t age = reader.Read32();
+ StoreMetadata("PDB_GUID", new Metadata(guid), true);
+ StoreMetadata("PDB_AGE", new Metadata((uint64_t)age), true);
+ string pdbFileName = reader.ReadCString();
+ StoreMetadata("PDB_FILENAME", new Metadata(pdbFileName), true);
+ m_logger->LogInfo("PDBFileName: %s\n", pdbFileName.c_str());
+
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData + 4, Type::ArrayType(Type::IntegerType(1, false), 16));
+ DefineAutoSymbol(new Symbol(DataSymbol, "PDBGuid", m_imageBase + debugDir.addressOfRawData + 4, NoBinding));
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData + 20, Type::IntegerType(4, false));
+ DefineAutoSymbol(new Symbol(DataSymbol, "PDBAge", m_imageBase + debugDir.addressOfRawData + 20, NoBinding));
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData + 24, Type::ArrayType(Type::IntegerType(1, true), pdbFileName.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "PDBFileName", m_imageBase + debugDir.addressOfRawData + 24, NoBinding));
+ }
+ }
+ else if (debugDir.type == IMAGE_DEBUG_TYPE_RESERVED10)
+ {
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData, Type::IntegerType(4, false));
+ DefineAutoSymbol(new Symbol(DataSymbol, "debugTypeReserved", m_imageBase + debugDir.addressOfRawData, NoBinding));
+ }
+ else
+ {
+ DefineDataVariable(m_imageBase + debugDir.addressOfRawData, Type::ArrayType(Type::IntegerType(1, false), debugDir.sizeOfData));
+ string name = GetDebugTypeName(debugDir.type);
+ DefineAutoSymbol(new Symbol(DataSymbol, name, m_imageBase + debugDir.addressOfRawData, NoBinding));
+ }
+ }
+
+ // Create Debug Directory Type
+ StructureBuilder debugDirBuilder;
+ debugDirBuilder.AddMember(Type::IntegerType(4, false), "characteristics");
+ debugDirBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
+ debugDirBuilder.AddMember(Type::IntegerType(2, false), "majorVersion");
+ debugDirBuilder.AddMember(Type::IntegerType(2, false), "minorVersion");
+ EnumerationBuilder debugType;
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_UNKNOWN", IMAGE_DEBUG_TYPE_UNKNOWN);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_COFF", IMAGE_DEBUG_TYPE_COFF);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_CODEVIEW", IMAGE_DEBUG_TYPE_CODEVIEW);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_FPO", IMAGE_DEBUG_TYPE_FPO);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_MISC", IMAGE_DEBUG_TYPE_MISC);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_EXCEPTION", IMAGE_DEBUG_TYPE_EXCEPTION);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_FIXUP", IMAGE_DEBUG_TYPE_FIXUP);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_OMAP_TO_SRC", IMAGE_DEBUG_TYPE_OMAP_TO_SRC);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_OMAP_FROM_SRC", IMAGE_DEBUG_TYPE_OMAP_FROM_SRC);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_BORLAND", IMAGE_DEBUG_TYPE_BORLAND);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_RESERVED10", IMAGE_DEBUG_TYPE_RESERVED10);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_CLSID", IMAGE_DEBUG_TYPE_CLSID);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_VC_FEATURE", IMAGE_DEBUG_TYPE_VC_FEATURE);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_POGO", IMAGE_DEBUG_TYPE_POGO);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_ILTCG", IMAGE_DEBUG_TYPE_ILTCG);
+ debugType.AddMemberWithValue("IMAGE_DEBUG_TYPE_MPX", IMAGE_DEBUG_TYPE_MPX);
+ debugDirBuilder.AddMember(Type::EnumerationType(debugType.Finalize(), 4), "type");
+ debugDirBuilder.AddMember(Type::IntegerType(4, false), "sizeOfData");
+ debugDirBuilder.AddMember(Type::IntegerType(4, false), "addressOfRawData");
+ debugDirBuilder.AddMember(Type::IntegerType(4, false), "pointerToRawData");
+
+ size_t numDebugEntries = dir.size / 24;
+ Ref<Structure> debugDirStruct = debugDirBuilder.Finalize();
+ Ref<Type> debugDirType = Type::StructureType(debugDirStruct);
+ QualifiedName debugDirName = string("Debug_Directory_Table");
+ string debugDirTypeId = Type::GenerateAutoTypeId("pe", debugDirName);
+ QualifiedName debugDirTypeName = DefineType(debugDirTypeId, debugDirName, debugDirType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_DEBUG].virtualAddress, Type::ArrayType(Type::NamedType(this, debugDirTypeName), numDebugEntries));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__debug_directory_entries", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_DEBUG].virtualAddress, NoBinding));
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse debug directory: %s\n", e.what());
+ }
+
+ try
+ {
+ if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_TLS)
+ {
+ PEDataDirectory dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_TLS];
+ if (dir.size != 0)
+ {
+ reader.Seek(RVAToFileOffset(dir.virtualAddress));
+ ImageTLSDirectory tlsEntry;
+ if (m_is64)
+ {
+ tlsEntry.startAddressOfRawData = reader.Read64();
+ tlsEntry.endAddressOfRawData = reader.Read64();
+ tlsEntry.addressOfIndex = reader.Read64();
+ tlsEntry.addressOfCallBacks = reader.Read64();
+ tlsEntry.sizeOfZeroFill = reader.Read32();
+ tlsEntry.characteristics = reader.Read32();
+ }
+ else
+ {
+ tlsEntry.startAddressOfRawData = reader.Read32();
+ tlsEntry.endAddressOfRawData = reader.Read32();
+ tlsEntry.addressOfIndex = reader.Read32();
+ tlsEntry.addressOfCallBacks = reader.Read32();
+ tlsEntry.sizeOfZeroFill = reader.Read32();
+ tlsEntry.characteristics = reader.Read32();
+ }
+
+ m_logger->LogDebug(
+ "Parsing IMAGE_DIRECTORY_ENTRY_TLS: %08x\n"
+ "\tstartAddressOfRawData %016x\n"
+ "\tendAddressOfRawData %016x\n"
+ "\taddressOfIndex %016x\n"
+ "\taddressOfCallBacks %016x\n"
+ "\tsizeOfZeroFill %08x\n"
+ "\tcharacteristics %08x\n",
+ dir.size,
+ tlsEntry.startAddressOfRawData,
+ tlsEntry.endAddressOfRawData,
+ tlsEntry.addressOfIndex,
+ tlsEntry.addressOfCallBacks,
+ tlsEntry.sizeOfZeroFill,
+ tlsEntry.characteristics
+ );
+
+ uint64_t address = 0;
+ uint32_t i = 0;
+ try
+ {
+ // TODO: I'm pretty sure we're going to have to change this
+ // when we deal with relocations properly
+ reader.Seek(RVAToFileOffset(tlsEntry.addressOfCallBacks - m_peImageBase));
+ while (true)
+ {
+ if (m_is64)
+ address = reader.Read64();
+ else
+ address = reader.Read32();
+
+ if (address == 0)
+ break;
+
+ // This address is a VA, we must handle the relocation by ourselves
+ address += (m_imageBase - m_peImageBase);
+
+ char name[64];
+ snprintf(name, sizeof(name), "_TLS_Entry_%x", i++);
+ if (m_arch)
+ {
+ if (IsOffsetBackedByFile(address))
+ {
+ m_logger->LogInfo("Found TLS entrypoint %s: 0x%" PRIx64, name, address);
+ Ref<Platform> assPlatform = platform->GetAssociatedPlatformByAddress(address);
+ AddPESymbol(FunctionSymbol, "", name, address - m_imageBase);
+ }
+ else
+ m_logger->LogInfo("Found TLS entrypoint %s: 0x%" PRIx64 " however it is not backed by file!",
+ name, address);
+ }
+ }
+ }
+ catch (std::exception&)
+ {
+ m_logger->LogWarn("TLS data is malformed");
+ }
+
+ // Create TLS Directory Type
+ size_t opFieldSize = m_is64 ? 8 : 4;
+ StructureBuilder tlsDirBuilder;
+ tlsDirBuilder.SetPacked(true);
+ tlsDirBuilder.AddMember(Type::IntegerType(opFieldSize, false), "rawDataStartVirtualAddress");
+ tlsDirBuilder.AddMember(Type::IntegerType(opFieldSize, false), "rawDataEndVirtualAddress");
+ tlsDirBuilder.AddMember(Type::IntegerType(opFieldSize, false), "addressOfIndex");
+ tlsDirBuilder.AddMember(Type::IntegerType(opFieldSize, false), "addressOfCallbacks");
+ tlsDirBuilder.AddMember(Type::IntegerType(4, false), "sizeOfZeroFill");
+ tlsDirBuilder.AddMember(Type::IntegerType(4, false), "characteristics");
+
+ Ref<Structure> tlsDirStruct = tlsDirBuilder.Finalize();
+ Ref<Type> tlsDirType = Type::StructureType(tlsDirStruct);
+ QualifiedName tlsDirName = string("TLS_Directory");
+ string tlsDirTypeId = Type::GenerateAutoTypeId("pe", tlsDirName);
+ QualifiedName tlsDirTypeName = DefineType(tlsDirTypeId, tlsDirName, tlsDirType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_TLS].virtualAddress, Type::NamedType(this, tlsDirTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__tls_directory", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_TLS].virtualAddress, NoBinding));
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse TLS directory: %s\n", e.what());
+ }
+
+ try
+ {
+ PEDataDirectory dir;
+ if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
+ dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
+ else
+ dir.virtualAddress = 0;
+
+ if (dir.virtualAddress > 0)
+ {
+ size_t numImportDelayEntries = 0;
+
+ while (true)
+ {
+ // Read in next delay directory entry
+ reader.Seek(RVAToFileOffset(dir.virtualAddress + (numImportDelayEntries * 32)));
+ DelayImportDescriptorEntry entry;
+ entry.attributes = reader.Read32();
+ entry.name = reader.Read32();
+ entry.moduleHandle = reader.Read32();
+ entry.delayImportAddressTable = reader.Read32();
+ entry.delayImportNameTable = reader.Read32();
+ entry.boundDelayImportTable = reader.Read32();
+ entry.unloadDelayImportTable = reader.Read32();
+ entry.timestamp = reader.Read32();
+
+ if (entry.name == 0)
+ {
+ if (numImportDelayEntries + 1 != dir.size / 32)
+ m_logger->LogWarn(
+ "The number of Import_Directory_Table reported by the Data Directories is different from "
+ "its correct amount. "
+ "There are actually %d Import_Directory_Table in the file, but SizeOfImportTable reports %d. "
+ "The PE parsing continues with the actual number of Import_Directory_Table",
+ numImportDelayEntries + 1, dir.size / 32);
+ break;
+ }
+
+ // https://reverseengineering.stackexchange.com/questions/16261/should-the-delay-import-directory-contain-virtual-addresses
+ // When the attributes has the lowest bit set, the addresses are RVA.
+ // For older binaries, e.g., those generated by VC 6.0, the lowest bit is zero, and the addresses are VA.
+ bool isAddrRVA = entry.attributes & PE_DLATTR_RVA;
+ if (!isAddrRVA)
+ {
+ entry.name -= m_imageBase;
+ entry.moduleHandle -= m_imageBase;
+ entry.delayImportAddressTable -= m_imageBase;
+ entry.delayImportNameTable -= m_imageBase;
+ entry.boundDelayImportTable -= m_imageBase;
+ entry.unloadDelayImportTable -= m_imageBase;
+ }
+
+ string entryName = ReadString(entry.name);
+ string lowerName = entryName;
+ std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
+ [](unsigned char c){ return std::tolower(c); });
+
+
+ vector<Ref<TypeLibrary>> typeLibs = platform->GetTypeLibrariesByName(lowerName);
+ for (const auto& typeLib : typeLibs)
+ {
+ // Check if the type library is already added
+ if (GetTypeLibrary(typeLib->GetName()))
+ continue;
+ AddTypeLibrary(typeLib);
+
+ m_logger->LogDebug("pe: adding type library for '%s': %s (%s)", lowerName.c_str(),
+ typeLib->GetName().c_str(), typeLib->GetGuid().c_str());
+ }
+
+ Ref<Metadata> ordinals;
+ for (const auto& typeLib : typeLibs)
+ ordinals = typeLib->QueryMetadata("ordinals");
+ if (ordinals && !ordinals->IsKeyValueStore())
+ ordinals = nullptr;
+
+ size_t dotPos = entryName.rfind('.');
+ string dllName;
+ if (dotPos == string::npos)
+ dllName = entryName;
+ else
+ dllName = entryName.substr(0, dotPos);
+
+ // Create Delay Import DLL Name Type
+ DefineDataVariable(m_imageBase + entry.name, Type::ArrayType(Type::IntegerType(1, true), entryName.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__delay_import_dll_name_" + to_string(numImportDelayEntries) + "(" + dllName + ")", m_imageBase + entry.name, NoBinding));
+
+ // Parse delay import name table
+ uint32_t entryOffset = entry.delayImportNameTable;
+ uint32_t iatOffset = entry.delayImportAddressTable;
+ while (true)
+ {
+ uint64_t entry;
+ bool isOrdinal;
+ if (m_is64)
+ {
+ entry = Read64(entryOffset);
+ isOrdinal = (entry & 0x8000000000000000LL) != 0;
+ entry &= 0x7fffffffffffffffLL;
+ DefineDataVariable(m_imageBase + entryOffset, Type::IntegerType(8, false));
+ }
+ else
+ {
+ entry = Read32(entryOffset);
+ isOrdinal = (entry & 0x80000000) != 0;
+ entry &= 0x7fffffff;
+ DefineDataVariable(m_imageBase + entryOffset, Type::IntegerType(4, false));
+ }
+ m_logger->LogDebug("Entry 0x%llx isOrdinal: %s\n", entry, isOrdinal ? "True" : "False");
+
+ if ((!isOrdinal) && (entry == 0))
+ break;
+
+ if (!isAddrRVA)
+ entry -= m_imageBase;
+
+ string func;
+ uint16_t ordinal;
+ if (isOrdinal)
+ {
+ ordinal = (uint16_t)entry;
+ string ordString = to_string(ordinal);
+ Ref<Metadata> ordInfo = nullptr;
+
+ if (ordinals)
+ ordInfo = ordinals->Get(ordString);
+
+ if (ordInfo && ordInfo->IsString())
+ func = ordInfo->GetString();
+ else
+ func = "Ordinal_" + dllName + "_" + to_string((int)entry);
+ }
+ else
+ {
+ ordinal = Read16(entry);
+ func = ReadString(entry + 2);
+ DefineDataVariable(m_imageBase + entry, Type::IntegerType(2, false));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__delay_export_name_ptr_table_" + to_string(numImportDelayEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entry, NoBinding));
+ DefineDataVariable(m_imageBase + entry + 2, Type::ArrayType(Type::IntegerType(1, true), func.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__delay_import_name_" + to_string(numImportDelayEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entry + 2, NoBinding));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__delay_import_lookup_table_" + to_string(numImportDelayEntries) + "(" + dllName + ":" + func + ")", m_imageBase + entryOffset, NoBinding));
+ }
+ m_logger->LogDebug("FuncString: %s\n", func.c_str());
+ AddPESymbol(ImportAddressSymbol, dllName, func, iatOffset, NoBinding, ordinal, typeLibs);
+ AddPESymbol(ExternalSymbol, dllName, func, 0, NoBinding, ordinal, typeLibs);
+ BNRelocationInfo reloc;
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.nativeType = -1;
+ reloc.address = m_imageBase + iatOffset;
+ reloc.size = m_is64 ? 8 : 4;
+ reloc.pcRelative = false;
+ reloc.base = m_imageBase - m_peImageBase;
+ reloc.external = true;
+ relocs.push_back({reloc, func});
+ entryOffset += m_is64 ? 8 : 4;
+ iatOffset += m_is64 ? 8 : 4;
+ }
+
+ numImportDelayEntries++;
+ }
+
+ if (numImportDelayEntries)
+ {
+ // Create Delay Import Descriptor Type
+ StructureBuilder delayImportDirBuilder;
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "attributes");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "name");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "moduleHandle");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "delayImportAddressTable");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "delayImportNameTable");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "boundDelayImportTable");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "unloadDelayImportTable");
+ delayImportDirBuilder.AddMember(Type::IntegerType(4, false), "timestamp");
+
+ Ref<Structure> delayImportDirStruct = delayImportDirBuilder.Finalize();
+ Ref<Type> delayImportDirType = Type::StructureType(delayImportDirStruct);
+ QualifiedName delayImportDirName = string("Delay_Import_Directory");
+ string delayImportDirTypeId = Type::GenerateAutoTypeId("pe", delayImportDirName);
+ QualifiedName delayImportDirTypeName = DefineType(delayImportDirTypeId, delayImportDirName, delayImportDirType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].virtualAddress, Type::ArrayType(Type::NamedType(this, delayImportDirTypeName), numImportDelayEntries + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__delay_import_directory_entries", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].virtualAddress, NoBinding));
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse Delay Import Descriptor directory: %s\n", e.what());
+ }
+
+ try
+ {
+ if ((m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) && (m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].size >= 40))
+ {
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress));
+ uint32_t loadConfigSize = reader.Read32();
+ if (!loadConfigSize || (loadConfigSize > 0x80))
+ loadConfigSize = m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].size;
+
+ // Create Load Configuration Directory Table Type
+ StructureBuilder loadConfigBuilder;
+ size_t opFieldSize = m_is64 ? 8 : 4;
+ loadConfigBuilder.SetPacked(true);
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "characteristics");
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
+ loadConfigBuilder.AddMember(Type::IntegerType(2, false), "majorVersion");
+ loadConfigBuilder.AddMember(Type::IntegerType(2, false), "minorVersion");
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "globalFlagsClear");
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "globalFlagsSet");
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "criticalSectionDefaultTimeout");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "deCommitFreeBlockThreshold");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "deCommitTotalFreeThreshold");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "lockPrefixTable");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "maximumAllocationSize");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "virtualMemoryThreshold");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "processAffinityMask");
+ loadConfigBuilder.AddMember(Type::IntegerType(4, false), "processHeapFlags");
+ loadConfigBuilder.AddMember(Type::IntegerType(2, false), "csdVersion");
+ loadConfigBuilder.AddMember(Type::IntegerType(2, false), "reserved");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "editList");
+ loadConfigBuilder.AddMember(Type::IntegerType(opFieldSize, false), "securityCookie");
+
+ // 32-bit images specify a size of 0x40 for compatability reasons
+ size_t curSize = (m_is64 ? 0x70 : 0x40);
+ vector<pair<Ref<Type>, string>> fields = {
+ {Type::IntegerType(opFieldSize, false), "seHandlerTable" },
+ {Type::IntegerType(opFieldSize, false), "seHandlerCount" },
+ {Type::IntegerType(opFieldSize, false), "guardCFCheckFunctionPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardCFDispatchFunctionPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardCFFunctionTable" },
+ {Type::IntegerType(opFieldSize, false), "guardCFFunctionCount" },
+ {Type::IntegerType(4, false), "guardFlags" },
+ {Type::IntegerType(2, false), "Flags" },
+ {Type::IntegerType(2, false), "Catalog" },
+ {Type::IntegerType(4, false), "CatalogOffset" },
+ {Type::IntegerType(4, false), "Reserved" },
+ {Type::IntegerType(opFieldSize, false), "guardAddressTakenIatEntryTable" },
+ {Type::IntegerType(opFieldSize, false), "guardAddressTakenIatEntryCount" },
+ {Type::IntegerType(opFieldSize, false), "guardLongJumpTargetTable" },
+ {Type::IntegerType(opFieldSize, false), "guardLongJumpTargetCount" },
+ {Type::IntegerType(opFieldSize, false), "dynamicValueRelocTable" },
+ {Type::IntegerType(opFieldSize, false), "CHPEMetadataPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardRFFailureRoutine" },
+ {Type::IntegerType(opFieldSize, false), "guardRFFailureRoutineFunctionPointer" },
+ {Type::IntegerType(4, false), "dynamicValueRelocTableOffset" },
+ {Type::IntegerType(2, false), "dynamicValueRelocTableSection" },
+ {Type::IntegerType(2, false), "reserved2" },
+ {Type::IntegerType(opFieldSize, false), "guardRFVerifyStackPointerFunctionPointer" },
+ {Type::IntegerType(4, false), "hotPatchTableOffset" },
+ {Type::IntegerType(4, false), "reserved3" },
+ {Type::IntegerType(opFieldSize, false), "enclaveConfigurationPointer" },
+ {Type::IntegerType(opFieldSize, false), "volatileMetadataPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardEHContinuationTable" },
+ {Type::IntegerType(opFieldSize, false), "guardEHContinuationCount" },
+ {Type::IntegerType(opFieldSize, false), "guardXFGCheckFunctionPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardXFGDispatchFunctionPointer" },
+ {Type::IntegerType(opFieldSize, false), "guardXFGTableDispatchFunctionPointer" },
+ {Type::IntegerType(opFieldSize, false), "castGuardOsDeterminedFailureMode" },
+ {Type::IntegerType(opFieldSize, false), "guardMemcpyFunctionPointer" }
+ };
+
+ for (const auto& [type, name] : fields)
+ {
+ curSize += type->GetWidth();
+ if (curSize > loadConfigSize)
+ break;
+ loadConfigBuilder.AddMember(type, name);
+ }
+
+ Ref<Structure> loadConfigStruct = loadConfigBuilder.Finalize();
+ Ref<Type> loadConfigType = Type::StructureType(loadConfigStruct);
+ QualifiedName loadConfigName = string("Load_Configuration_Directory_Table");
+ string loadConfigTypeId = Type::GenerateAutoTypeId("pe", loadConfigName);
+ QualifiedName loadConfigTypeName = DefineType(loadConfigTypeId, loadConfigName, loadConfigType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress, Type::NamedType(this, loadConfigTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__load_configuration_directory_table", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress, NoBinding));
+
+ // parse securityCookie
+ size_t securityCookieOffset = m_is64 ? 88 : 60;
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress + securityCookieOffset));
+ auto securityCookieAddress = m_is64 ? reader.Read64() : reader.Read32();
+ // The securityCookieAddress reported by the file is a VA, which does not account for rebase. We must
+ // calculate the rebased value for it.
+ securityCookieAddress += (m_imageBase - m_peImageBase);
+ m_logger->LogDebug("securityCookieAddress: 0x%" PRIx64, securityCookieAddress);
+ DefineDataVariable(securityCookieAddress, Type::IntegerType(m_is64 ? 8 : 4, false));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__security_cookie", securityCookieAddress, NoBinding));
+
+ // parse SEH table
+ size_t seHandlerTableTableOffset = m_is64 ? 96 : 64;
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress + seHandlerTableTableOffset));
+ uint64_t seHandlerTable = m_is64 ? reader.Read64() : reader.Read32();
+ seHandlerTable += (m_imageBase - m_peImageBase);
+ m_logger->LogDebug("seHandlerTable: 0x%" PRIx64, seHandlerTable);
+ uint64_t seHandlerCount = m_is64 ? reader.Read64() : reader.Read32();
+ if (seHandlerTable && seHandlerCount)
+ {
+ DefineDataVariable(seHandlerTable, Type::ArrayType(Type::IntegerType(4, false), seHandlerCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__seh_table", seHandlerTable, NoBinding));
+
+ bool processSehTable = true;
+ if (settings && settings->Contains("loader.pe.processSehTable"))
+ processSehTable = settings->Get<bool>("loader.pe.processSehTable", this);
+ if (processSehTable)
+ {
+ reader.Seek(RVAToFileOffset(seHandlerTable - m_imageBase));
+ for (size_t i = 0; i < seHandlerCount; i++)
+ {
+ uint64_t sehEntry = m_imageBase + reader.Read32();
+ Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(sehEntry);
+ AddFunctionForAnalysis(targetPlatform, sehEntry);
+ // TODO possibly auto name these entries
+ //DefineAutoSymbol(new Symbol(FunctionSymbol, "__seh_entry_" + to_string(i), sehEntry));
+ }
+ }
+ }
+
+ // parse CFG table
+ if ((loadConfigSize >= (uint32_t)(m_is64 ? 0x94 : 0x40)) && (m_is64 || (opt.dllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)))
+ {
+ size_t cfgFields = m_is64 ? 112 : 72;
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].virtualAddress + cfgFields));
+
+ uint64_t guardCFCheckFunctionPointer = m_is64 ? reader.Read64() : reader.Read32();
+ if (guardCFCheckFunctionPointer != 0)
+ {
+ guardCFCheckFunctionPointer += (m_imageBase - m_peImageBase);
+ m_logger->LogDebug("guardCFCheckFunctionPointer: 0x%" PRIx64, guardCFCheckFunctionPointer);
+ }
+ uint64_t guardCFDispatchFunctionPointer = m_is64 ? reader.Read64() : reader.Read32();
+ if (guardCFDispatchFunctionPointer != 0)
+ {
+ guardCFDispatchFunctionPointer += (m_imageBase - m_peImageBase);
+ m_logger->LogDebug("guardCFDispatchFunctionPointer: 0x%" PRIx64, guardCFDispatchFunctionPointer);
+ }
+ uint64_t guardCFFunctionTable = m_is64 ? reader.Read64() : reader.Read32();
+ uint64_t guardCFFunctionCount = m_is64 ? reader.Read64() : reader.Read32();
+ uint32_t guardFlags = reader.Read32();
+
+ uint64_t guardCFCheckFunction = 0;
+ if (guardCFCheckFunctionPointer != 0)
+ {
+ reader.Seek(RVAToFileOffset(guardCFCheckFunctionPointer - m_imageBase));
+ guardCFCheckFunction = m_is64 ? reader.Read64() : reader.Read32();
+ }
+
+ uint64_t guardCFDispatchFunction = 0;
+ if (guardCFDispatchFunctionPointer != 0)
+ {
+ reader.Seek(RVAToFileOffset(guardCFDispatchFunctionPointer - m_imageBase));
+ guardCFDispatchFunction = m_is64 ? reader.Read64() : reader.Read32();
+ }
+
+ auto functionPointer = Type::PointerType(platform->GetArchitecture(), Type::FunctionType(Type::VoidType(), platform->GetDefaultCallingConvention(), {}));
+ auto guardCFCheckFunctionType = Type::FunctionType(Type::VoidType(),
+ platform->GetDefaultCallingConvention(),
+ {
+ FunctionParameter("", functionPointer)
+ });
+ auto pointerGuardCFCheckFunctionType = Type::PointerType(platform->GetArchitecture(), guardCFCheckFunctionType);
+
+ if (guardCFCheckFunctionPointer != 0)
+ {
+ auto guardCFCheckPointerSymbol = new Symbol(DataSymbol, "__guard_check_icall_fptr", guardCFCheckFunctionPointer, NoBinding);
+ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), guardCFCheckPointerSymbol, pointerGuardCFCheckFunctionType);
+ }
+
+ if (guardCFDispatchFunctionPointer != 0)
+ {
+ auto guardCFCheckDispatchSymbol = new Symbol(DataSymbol, "__guard_dispatch_icall_fptr", guardCFDispatchFunctionPointer, NoBinding);
+ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), guardCFCheckDispatchSymbol, pointerGuardCFCheckFunctionType);
+ }
+
+ if (guardCFCheckFunction != 0)
+ {
+ auto guardCFCheckSymbol = new Symbol(FunctionSymbol, "_guard_check_icall", guardCFCheckFunction, NoBinding);
+ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), guardCFCheckSymbol, guardCFCheckFunctionType);
+ }
+
+ if (guardCFDispatchFunction != 0)
+ {
+ auto guardCFDispatchSymbol = new Symbol(FunctionSymbol, "_guard_dispatch_icall_nop", guardCFDispatchFunction, NoBinding);
+ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), guardCFDispatchSymbol, guardCFCheckFunctionType);
+ }
+
+ if (guardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT)
+ {
+ size_t mdSize = ((guardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT);
+
+ // Create GFIDS Table Type
+ if (mdSize)
+ {
+ StructureBuilder gfidsBuilder;
+ gfidsBuilder.SetPacked(true);
+ gfidsBuilder.AddMember(Type::IntegerType(4, false), "rvAddr");
+ gfidsBuilder.AddMember(Type::IntegerType(mdSize, false), "metadata");
+
+ Ref<Structure> gfidsStruct = gfidsBuilder.Finalize();
+ Ref<Type> gfidsTableType = Type::StructureType(gfidsStruct);
+ QualifiedName gfidsTableName = string("Guard_Control_Flow_Function_Table");
+ string gfidsTypeId = Type::GenerateAutoTypeId("pe", gfidsTableName);
+ QualifiedName gfidsTypeName = DefineType(gfidsTypeId, gfidsTableName, gfidsTableType);
+ DefineDataVariable(guardCFFunctionTable, Type::ArrayType(Type::NamedType(this, gfidsTypeName), guardCFFunctionCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__gfids_table", guardCFFunctionTable, NoBinding));
+ }
+ else
+ {
+ DefineDataVariable(guardCFFunctionTable, Type::ArrayType(Type::IntegerType(4, false), guardCFFunctionCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__gfids_table", guardCFFunctionTable, NoBinding));
+ }
+
+ bool processCfgTable = true;
+ if (settings && settings->Contains("loader.pe.processCfgTable"))
+ processCfgTable = settings->Get<bool>("loader.pe.processCfgTable", this);
+ if (processCfgTable)
+ {
+ reader.Seek(RVAToFileOffset(guardCFFunctionTable - m_peImageBase));
+ for (size_t i = 0; i < guardCFFunctionCount; i++)
+ {
+ uint64_t cfgAddr = m_imageBase + reader.Read32();
+ Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(cfgAddr);
+ AddFunctionForAnalysis(targetPlatform, cfgAddr);
+ for (size_t mdIdx = 0; mdIdx < mdSize; mdIdx++)
+ {
+ auto value = reader.Read8();
+ if (mdIdx == 0 && (value & IMAGE_GUARD_FLAG_FID_XFG) != 0)
+ {
+ DefineDataVariable(cfgAddr - 8, Type::IntegerType(8, false));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse load configuration directory: %s\n", e.what());
+ }
+
+ try
+ {
+ if ((m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_EXPORT) && (m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].size >= 40))
+ {
+ PEExportDirectory dir;
+ reader.Seek(RVAToFileOffset(m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].virtualAddress));
+ dir.characteristics = reader.Read32();
+ dir.timestamp = reader.Read32();
+ dir.majorVersion = reader.Read16();
+ dir.minorVersion = reader.Read16();
+ dir.dllNameAddress = reader.Read32();
+ dir.base = reader.Read32();
+ dir.functionCount = reader.Read32();
+ dir.nameCount = reader.Read32();
+ dir.addressOfFunctions = reader.Read32();
+ dir.addressOfNames = reader.Read32();
+ dir.addressOfNameOrdinals = reader.Read32();
+
+ // Create Export Directory Table Type
+ StructureBuilder exportDirBuilder;
+ exportDirBuilder.SetPacked(true);
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "exportFlags");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
+ exportDirBuilder.AddMember(Type::IntegerType(2, false), "majorVersion");
+ exportDirBuilder.AddMember(Type::IntegerType(2, false), "minorVersion");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "nameRva");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "ordinalBase");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "addressTableEntries");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "numberOfNamePointers");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "exportAddressTableRva");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "namePointerRva");
+ exportDirBuilder.AddMember(Type::IntegerType(4, false), "ordinalTableRva");
+
+ Ref<Structure> exportDirStruct = exportDirBuilder.Finalize();
+ Ref<Type> exportDirType = Type::StructureType(exportDirStruct);
+ QualifiedName exportDirName = string("Export_Directory_Table");
+ string exportDirTypeId = Type::GenerateAutoTypeId("pe", exportDirName);
+ QualifiedName exportDirTypeName = DefineType(exportDirTypeId, exportDirName, exportDirType);
+ DefineDataVariable(m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].virtualAddress, Type::NamedType(this, exportDirTypeName));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__export_directory_table", m_imageBase + m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].virtualAddress, NoBinding));
+
+ // Read name of imported DLL, and trim extension for creating symbol name
+ string dllName = ReadString(dir.dllNameAddress);
+ size_t strPos = dllName.rfind('.');
+ string dllShortName = (strPos != string::npos) ? dllName.substr(0, strPos) : dllName;
+ DefineDataVariable(m_imageBase + dir.dllNameAddress, Type::ArrayType(Type::IntegerType(1, true), dllName.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__pe_" + dllShortName + "_export_dll_name", m_imageBase + dir.dllNameAddress, NoBinding));
+
+ string tableName = "__pe_" + dllShortName + "_export_address_table";
+ DefineDataVariable(m_imageBase + dir.addressOfFunctions, Type::ArrayType(Type::IntegerType(4, false), dir.functionCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, tableName, m_imageBase + dir.addressOfFunctions, NoBinding));
+
+ vector<uint32_t> funcs;
+ reader.Seek(RVAToFileOffset(dir.addressOfFunctions));
+ funcs.reserve(dir.functionCount);
+ for (uint32_t i = 0; i < dir.functionCount; i++)
+ funcs.push_back(reader.Read32());
+
+ vector<uint32_t> nameAddrs;
+ if (dir.addressOfNames != 0)
+ {
+ string tableName = "__pe_" + dllShortName + "_export_name_pointer_table";
+ DefineDataVariable(m_imageBase + dir.addressOfNames, Type::ArrayType(Type::IntegerType(4, false), dir.nameCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, tableName, m_imageBase + dir.addressOfNames, NoBinding));
+
+ nameAddrs.reserve(dir.nameCount);
+ reader.Seek(RVAToFileOffset(dir.addressOfNames));
+ for (uint32_t i = 0; i < dir.nameCount; i++)
+ nameAddrs.push_back(reader.Read32());
+ }
+
+ vector<uint16_t> nameOrdinals;
+ if (dir.addressOfNameOrdinals != 0)
+ {
+ string tableName = "__pe_" + dllShortName + "_export_ordinal_table";
+ DefineDataVariable(m_imageBase + dir.addressOfNameOrdinals, Type::ArrayType(Type::IntegerType(2, false), dir.nameCount));
+ DefineAutoSymbol(new Symbol(DataSymbol, tableName, m_imageBase + dir.addressOfNameOrdinals, NoBinding));
+
+ nameOrdinals.reserve(dir.nameCount);
+ reader.Seek(RVAToFileOffset(dir.addressOfNameOrdinals));
+ for (uint32_t i = 0; i < dir.nameCount; i++)
+ nameOrdinals.push_back(reader.Read16());
+ }
+
+ map<uint16_t, string> namesByOrdinal;
+ for (uint32_t i = 0; i < dir.nameCount; i++)
+ {
+ if (i >= nameOrdinals.size())
+ break;
+ if (i >= nameAddrs.size())
+ break;
+
+ string name = ReadString(nameAddrs[i]);
+ namesByOrdinal[nameOrdinals[i]] = name;
+
+ DefineDataVariable(m_imageBase + nameAddrs[i], Type::ArrayType(Type::IntegerType(1, true), name.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__export_name(" + name + ")", m_imageBase + nameAddrs[i], NoBinding));
+ }
+
+ // Create symbols for the exports
+ uint32_t exportTableStart = m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].virtualAddress;
+ uint32_t exportTableEnd = exportTableStart + m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXPORT].size;
+ for (uint32_t i = 0; i < dir.functionCount; i++)
+ {
+ uint32_t rvAddr = funcs[i];
+ if (rvAddr == 0)
+ continue;
+ string name;
+ auto nameIter = namesByOrdinal.find(i);
+ if (nameIter == namesByOrdinal.end())
+ {
+ char buff[32];
+ snprintf(buff, sizeof(buff), "ordinal_%u", i + dir.base);
+ name = buff;
+ }
+ else
+ {
+ name = nameIter->second;
+ }
+ uint32_t characteristics = GetRVACharacteristics(rvAddr);
+
+ if ((rvAddr >= exportTableStart) && (rvAddr < exportTableEnd))
+ {
+ string forwarderName = ReadString(rvAddr);
+ DefineDataVariable(m_imageBase + rvAddr, Type::ArrayType(Type::IntegerType(1, true), forwarderName.size() + 1));
+ DefineAutoSymbol(new Symbol(DataSymbol, "__forwarder_name(" + forwarderName + ")", m_imageBase + rvAddr, GlobalBinding,
+ NameSpace(DEFAULT_INTERNAL_NAMESPACE), i + dir.base));
+ }
+ else
+ {
+ if ((characteristics & (PE_ATTR_CODE | PE_ATTR_EXEC)) != 0)
+ AddPESymbol(FunctionSymbol, "", name, rvAddr, GlobalBinding, i + dir.base);
+ else if (characteristics != 0)
+ AddPESymbol(DataSymbol, "", name, rvAddr, GlobalBinding, i + dir.base);
+ //else // TODO need to handle other data symbols
+ }
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse export directory: %s\n", e.what());
+ }
+
+ m_symbolQueue->Process();
+ delete m_symbolQueue;
+ m_symbolQueue = nullptr;
+
+ EndBulkModifySymbols();
+
+ StoreMetadata("SymbolExternalLibraryMapping", m_symExternMappingMetadata, true);
+
+ try
+ {
+ if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_BASERELOC)
+ {
+ PEDataDirectory dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ // Check if there is a '.reloc' section that is different than this directory entry
+ vector<PEDataDirectory> dirs = { m_dataDirs[IMAGE_DIRECTORY_ENTRY_BASERELOC]};
+ auto section = find_if(m_sections.begin(), m_sections.end(), [](const PESection& section) { return section.name == ".reloc"; });
+ if (section != m_sections.end())
+ {
+ if (section->virtualAddress != dir.virtualAddress)
+ dirs.push_back({ section->virtualAddress, section->sizeOfRawData });
+ }
+ for (auto& dir : dirs)
+ {
+ if (dir.size == 0 || dir.virtualAddress == 0)
+ continue;
+
+ reader.Seek(RVAToFileOffset(dir.virtualAddress));
+ uint64_t size = 0;
+ while (size < dir.size)
+ {
+ ImageBaseRelocation baseReloc;
+ baseReloc.VirtualAddress = reader.Read32() + m_imageBase;
+ baseReloc.SizeOfBlock = reader.Read32();
+ if (baseReloc.SizeOfBlock < 8)
+ break;
+ if (baseReloc.SizeOfBlock == 8)
+ {
+ size += baseReloc.SizeOfBlock;
+ continue;
+ }
+ size_t nEntries = (baseReloc.SizeOfBlock - 8) / sizeof(uint16_t);
+ uint16_t* relocEntries = new uint16_t[nEntries];
+ if (relocEntries)
+ {
+ reader.Read(relocEntries, nEntries * sizeof(uint16_t));
+ for (size_t i = 0; i < nEntries; i++)
+ {
+ BNRelocationInfo reloc;
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.nativeType = relocEntries[i] >> 12;
+ if (!reloc.nativeType) // IMAGE_REL_BASED_ABSOLUTE relocations are skipped/used for padding
+ continue;
+ reloc.address = baseReloc.VirtualAddress + (relocEntries[i] & 0xfff);
+ reloc.size = m_is64 ? 8 : 4;
+ reloc.pcRelative = false;
+ reloc.base = m_imageBase - m_peImageBase;
+ DefineRelocation(m_arch, reloc, 0, reloc.address);
+ }
+ delete[] relocEntries;
+ }
+ size += baseReloc.SizeOfBlock;
+ }
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogWarn("Failed to parse relocation directory: %s\n", e.what());
+ }
+
+ for (auto& [reloc, name] : relocs)
+ {
+ if (auto symbol = GetSymbolByRawName(name, GetExternalNameSpace()); symbol)
+ DefineRelocation(m_arch, reloc, symbol, reloc.address);
+ }
+
+ // Add a symbol for the entry point
+ if (m_entryPoint)
+ DefineAutoSymbol(new Symbol(FunctionSymbol, "_start", m_imageBase + m_entryPoint));
+ std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+ double t = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() / 1000.0;
+ m_logger->LogInfo("PE parsing took %.3f seconds\n", t);
+
+ return true;
+}
+
+
+uint64_t PEView::RVAToFileOffset(uint64_t offset, bool except)
+{
+ for (auto& i : m_sections)
+ {
+ if ((offset >= i.virtualAddress) &&
+ (offset < (i.virtualAddress + i.sizeOfRawData)) && (i.virtualSize != 0))
+ {
+ uint64_t progOfs = offset - i.virtualAddress;
+ return i.pointerToRawData + progOfs;
+ }
+ }
+
+ if (!except)
+ return offset;
+
+ throw PEFormatException("encountered invalid offset");
+}
+
+
+uint32_t PEView::GetRVACharacteristics(uint64_t offset)
+{
+ for (auto& i : m_sections)
+ {
+ if ((offset >= i.virtualAddress) && (offset < (i.virtualAddress + i.virtualSize)) && (i.virtualSize != 0))
+ return i.characteristics;
+ }
+ return 0;
+}
+
+
+string PEView::ReadString(uint64_t rva)
+{
+ uint64_t offset = RVAToFileOffset(rva);
+ string result;
+ char data[STRING_READ_CHUNK_SIZE];
+ while (true)
+ {
+ size_t len = GetParentView()->Read(data, offset, STRING_READ_CHUNK_SIZE);
+ if (len == 0)
+ break;
+
+ size_t i;
+ for (i = 0; i < len; i++)
+ {
+ if (data[i] == 0)
+ break;
+ }
+
+ result += string(&data[0], &data[i]);
+ if (i < len)
+ break;
+ offset += len;
+ }
+ return result;
+}
+
+
+uint16_t PEView::Read16(uint64_t rva)
+{
+ uint64_t ofs = RVAToFileOffset(rva);
+ BinaryReader reader(GetParentView(), LittleEndian);
+ reader.Seek(ofs);
+ return reader.Read16();
+}
+
+
+uint32_t PEView::Read32(uint64_t rva)
+{
+ uint64_t ofs = RVAToFileOffset(rva);
+ BinaryReader reader(GetParentView(), LittleEndian);
+ reader.Seek(ofs);
+ return reader.Read32();
+}
+
+
+uint64_t PEView::Read64(uint64_t rva)
+{
+ uint64_t ofs = RVAToFileOffset(rva);
+ BinaryReader reader(GetParentView(), LittleEndian);
+ reader.Seek(ofs);
+ return reader.Read64();
+}
+
+
+// The addr is RVA
+void PEView::AddPESymbol(BNSymbolType type, const string& dll, const string& name, uint64_t addr,
+ BNSymbolBinding binding, uint64_t ordinal, vector<Ref<TypeLibrary>> libs)
+{
+ // Don't create symbols that are present in the database snapshot now
+ if (type != ExternalSymbol && m_backedByDatabase)
+ return;
+
+ // If name is empty, symbol is not valid
+ if (name.size() == 0)
+ return;
+
+ // Ensure symbol is within the executable
+ if (type != ExternalSymbol)
+ {
+ bool ok = false;
+ for (auto& i : m_sections)
+ {
+ if ((addr >= i.virtualAddress) && (addr < (i.virtualAddress + i.virtualSize)))
+ {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ return;
+ }
+
+ auto address = type == ExternalSymbol ? addr : m_imageBase + addr;
+ Ref<Type> symbolTypeRef;
+
+ if (libs.size() && ((type == ExternalSymbol) || (type == ImportAddressSymbol) || (type == ImportedDataSymbol)))
+ {
+ QualifiedName n(name);
+ for (auto lib : libs)
+ {
+ Ref<TypeLibrary> appliedLib = lib;
+ symbolTypeRef = ImportTypeLibraryObject(appliedLib, n);
+ if (symbolTypeRef)
+ {
+ m_logger->LogDebug("pe: type library '%s' found hit for '%s'", lib->GetGuid().c_str(), name.c_str());
+ RecordImportedObjectLibrary(GetDefaultPlatform(), address, appliedLib, n);
+ }
+ }
+ }
+
+ m_symbolQueue->Append(
+ [=]() {
+ // If name does not start with alphabetic character or symbol, prepend an underscore
+ string rawName = name;
+ if (!(((name[0] >= 'A') && (name[0] <= 'Z')) || ((name[0] >= 'a') && (name[0] <= 'z')) || (name[0] == '_')
+ || (name[0] == '?') || (name[0] == '$') || (name[0] == '@')))
+ rawName = "_" + name;
+
+ string shortName = rawName;
+ string fullName = rawName;
+ Ref<Type> typeRef = symbolTypeRef;
+
+ if (m_arch && name.size() > 0)
+ {
+ QualifiedName demangleName;
+ Ref<Type> demangledType;
+ if (name[0] == '?')
+ {
+ if (DemangleMS(m_arch, name, demangledType, demangleName, m_simplifyTemplates))
+ {
+ shortName = demangleName.GetString();
+ fullName = shortName + demangledType->GetStringAfterName();
+ if (!typeRef && m_extractMangledTypes && !GetDefaultPlatform()->GetFunctionByName(rawName))
+ typeRef = demangledType;
+ }
+ else
+ {
+ m_logger->LogDebug("Failed to demangle: '%s'\n", name.c_str());
+ }
+ }
+ else if (IsGNU3MangledString(rawName))
+ {
+ if (DemangleGNU3(m_arch, rawName, demangledType, demangleName, m_simplifyTemplates))
+ {
+ shortName = demangleName.GetString();
+ fullName = shortName;
+ if (demangledType)
+ fullName += demangledType->GetStringAfterName();
+ if (!typeRef && m_extractMangledTypes && !GetDefaultPlatform()->GetFunctionByName(rawName))
+ typeRef = demangledType;
+ }
+ else
+ {
+ m_logger->LogDebug("Failed to demangle name: '%s'\n", rawName.c_str());
+ }
+ }
+ // Not a mangled string
+ }
+
+ NameSpace ns(dll);
+ if (type == ExternalSymbol)
+ ns = GetExternalNameSpace();
+
+ return pair<Ref<Symbol>, Ref<Type>>(
+ new Symbol(type, shortName, fullName, rawName, address, binding, ns, ordinal),
+ typeRef);
+ },
+ [this](Symbol* symbol, Type* type) {
+ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), symbol, type);
+ });
+}
+
+
+uint64_t PEView::PerformGetEntryPoint() const
+{
+ return m_imageBase + m_entryPoint;
+}
+
+
+size_t PEView::PerformGetAddressSize() const
+{
+ return m_is64 ? 8 : 4;
+}
+
+
+PEViewType::PEViewType() : BinaryViewType("PE", "PE")
+{
+ m_logger = LogRegistry::CreateLogger("BinaryView");
+}
+
+
+Ref<BinaryView> PEViewType::Create(BinaryView* data)
+{
+ try
+ {
+ return new PEView(data);
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what());
+ return nullptr;
+ }
+}
+
+
+Ref<BinaryView> PEViewType::Parse(BinaryView* data)
+{
+ try
+ {
+ return new PEView(data, true);
+ }
+ catch (std::exception& e)
+ {
+ m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what());
+ return nullptr;
+ }
+}
+
+
+bool PEViewType::IsTypeValidForData(BinaryView* data)
+{
+ // Check MZ header signature
+ DataBuffer sig = data->ReadBuffer(0, 2);
+ if (sig.GetLength() != 2)
+ return false;
+ if (memcmp(sig.GetData(), "MZ", 2) != 0)
+ return false;
+
+ BinaryReader reader(data, LittleEndian);
+
+ // Read PE offset
+ uint32_t peOfs;
+ reader.Seek(0x3c);
+ if (!reader.TryRead32(peOfs))
+ return false;
+
+ // Check PE signature
+ DataBuffer peSig = data->ReadBuffer(peOfs, 4);
+ if (peSig.GetLength() != 4)
+ return false;
+ if (memcmp(peSig.GetData(), "PE\0\0", 4) != 0)
+ return false;
+
+ // Check optional header signature
+ uint16_t magic;
+ reader.Seek(peOfs + 24);
+ if (!reader.TryRead16(magic))
+ return false;
+
+ return (magic == 0x10b) || (magic == 0x20b);
+}
+
+
+Ref<Settings> PEViewType::GetLoadSettingsForData(BinaryView* data)
+{
+ Ref<BinaryView> viewRef = Parse(data);
+ if (!viewRef || !viewRef->Init())
+ {
+ m_logger->LogError("View type '%s' could not be created", GetName().c_str());
+ return nullptr;
+ }
+
+ Ref<Settings> settings = GetDefaultLoadSettingsForData(viewRef);
+
+ // specify default load settings that can be overridden
+ vector<string> overrides = {"loader.architecture", "loader.imageBase", "loader.platform"};
+ if (!viewRef->IsRelocatable())
+ settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable.");
+
+ for (const auto& override : overrides)
+ {
+ if (settings->Contains(override))
+ settings->UpdateProperty(override, "readOnly", false);
+ }
+
+ // register additional settings
+ settings->RegisterSetting("loader.pe.processCfgTable",
+ R"({
+ "title" : "Process PE Control Flow Guard Table",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Add function starts sourced from the Control Flow Guard (CFG) table to the core for analysis."
+ })");
+
+ settings->RegisterSetting("loader.pe.processExceptionTable",
+ R"({
+ "title" : "Process PE Exception Handling Table",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Add function starts sourced from the Exception Handling table (.pdata) to the core for analysis."
+ })");
+
+ settings->RegisterSetting("loader.pe.processSehTable",
+ R"({
+ "title" : "Process PE Structured Exception Handling Table",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Add function starts sourced from the Structured Exception Handling (SEH) table to the core for analysis."
+ })");
+
+ return settings;
+}
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+
+#ifdef DEMO_VERSION
+ bool PEPluginInit()
+#else
+ BINARYNINJAPLUGIN bool CorePluginInit()
+#endif
+ {
+ InitPEViewType();
+ InitCOFFViewType();
+ return true;
+ }
+}