#include #include #include #include #include #include #include #include #include #include #include #include "peview.h" #include "coffview.h" #include "teview.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"}; static const char* GetResourceTypeName(uint32_t id) { switch (id) { case 1: return "RT_CURSOR"; case 2: return "RT_BITMAP"; case 3: return "RT_ICON"; case 4: return "RT_MENU"; case 5: return "RT_DIALOG"; case 6: return "RT_STRING"; case 7: return "RT_FONTDIR"; case 8: return "RT_FONT"; case 9: return "RT_ACCELERATOR"; case 10: return "RT_RCDATA"; case 11: return "RT_MESSAGETABLE"; case 12: return "RT_GROUP_CURSOR"; case 14: return "RT_GROUP_ICON"; case 16: return "RT_VERSION"; case 17: return "RT_DLGINCLUDE"; case 19: return "RT_PLUGPLAY"; case 20: return "RT_VXD"; case 21: return "RT_ANICURSOR"; case 22: return "RT_ANIICON"; case 23: return "RT_HTML"; case 24: return "RT_MANIFEST"; default: return nullptr; } } struct ResourceParseItem { uint64_t tableAddr; uint32_t depth; // 0=root, 1=type children, 2=name children std::string typeName; // resolved at depth 0 std::string resourceName;// resolved at depth 1 uint32_t typeId; // raw type ID uint32_t nameId; // raw name/ID }; 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 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 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 = ""; // 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 usedSectionNames; BinaryReader reader(GetParentView(), LittleEndian); Ref platform; Ref 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> 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> 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 = 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; SetOriginalImageBase(m_peImageBase); m_entryPoint = opt.addressOfEntry; Ref viewSettings = Settings::Instance(); m_extractMangledTypes = viewSettings->Get("analysis.extractTypesFromMangledNames", this); m_simplifyTemplates = viewSettings->Get("analysis.types.templateSimplifier", this); bool platformSetByUser = false; settings = GetLoadSettings(GetTypeName()); if (settings) { if (settings->Contains("loader.imageBase")) m_imageBase = settings->Get("loader.imageBase", this); if (settings->Contains("loader.platform")) { BNSettingsScope scope = SettingsAutoScope; Ref platformOverride = Platform::GetByName(settings->Get("loader.platform", this, &scope)); if (platformOverride) { platform = platformOverride; m_arch = platform->GetArchitecture(); platformSetByUser = (scope == SettingsResourceScope); } } } // 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_EDITION 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; } if (!m_parseOnly) m_logger->LogWarn("Unable to determine architecture. Please open the file with options and select a valid architecture."); return false; } if (!platformSetByUser) platform = platform->GetAssociatedPlatformByAddress(m_entryPoint); 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); BeginBulkAddSegments(); 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) { errno = 0; uint32_t offset = strtoul(name+1, nullptr, 10); if (errno == 0 && offset > 0) { BinaryReader stringReader(GetParentView(), LittleEndian); uint64_t stringTableBase = header.coffSymbolTable + (header.coffSymbolCount * 18); stringReader.Seek(stringTableBase); uint32_t stringTableLen; if (!stringReader.TryRead32(stringTableLen)) { m_logger->LogError("Cannot resolve section name \"%s\": String table has invalid start", name); } else if ((stringTableBase + stringTableLen) > GetParentView()->GetEnd()) { m_logger->LogError("Cannot resolve section name \"%s\": String table is invalid length", name); } else if (stringTableBase + offset < GetParentView()->GetEnd()) { sectionNameReader.Seek(stringTableBase + offset); resolvedName = sectionNameReader.ReadCString(); } else { m_logger->LogError("Cannot resolve section name \"%s\": Offset is past end of string table", name); } } } 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", i, section.name.c_str(), section.virtualSize, 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 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); } } EndBulkAddSegments(); // 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 dosHeaderStruct = dosHeaderBuilder.Finalize(); Ref 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 richMetadataLookupIdentifiers; vector 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> 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> 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 richHeaderStruct = richHeaderBuilder.Finalize(); Ref 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 coffHeaderMachineEnum = coffHeaderMachineBuilder.Finalize(); Ref 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 coffCharacteristicsEnum = coffCharacteristicsBuilder.Finalize(); Ref 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 coffHeaderStruct = coffHeaderBuilder.Finalize(); Ref 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 peMagicEnum = peMagicBuilder.Finalize(); Ref 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 peSubsystemEnum = peSubsystemBuilder.Finalize(); Ref 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 dllCharacteristicsEnum = dllCharacteristicsBuilder.Finalize(); Ref 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 dataDirEntryStruct = dataDirEntryBuilder.Finalize(); Ref 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::value; for (size_t i = 0; i < opt.dataDirCount; i++) { string dirName = (i < std::extent::value) ? imageDirName[i] : imageDirName[dataDirNameCount - 1]; peOptionalHeaderBuilder.AddMember(Type::NamedType(this, dataDirTypeName), dirName + "Entry"); } } string peHdrPrefix = m_is64 ? "pe64" : "pe32"; Ref peOptionalHeaderStruct = peOptionalHeaderBuilder.Finalize(); Ref 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 peSectionFlagsEnum = peSectionFlagsBuilder.Finalize(); Ref 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 sectionHeaderStruct = sectionHeaderBuilder.Finalize(); Ref 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> relocs; BulkSymbolModification bulkSymbolModification(this); 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; bool createSymbol = true; // Some records are just providing debugging information and we should ignore them // TODO: can we recover any useful information from the aux records? // See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records for info provided by aux records if (e_sclass == IMAGE_SYM_CLASS_EXTERNAL && baseType == IMAGE_SYM_DTYPE_FUNCTION) { // Auxiliary Format 1: Function Definitions } else if (e_sclass == IMAGE_SYM_CLASS_FUNCTION) { if (symbolName == ".bf" || symbolName == ".ef") { // Auxiliary Format 2: .bf and .ef Symbols // This entry is providing information about a function's line numbers and should not have a symbol created createSymbol = false; } else if (symbolName == ".lf") { // This entry is providing information about a function's line numbers and should not have a symbol created createSymbol = false; } } else if (e_sclass == IMAGE_SYM_CLASS_EXTERNAL && e_scnum == IMAGE_SYM_UNDEFINED && e_value == 0) { // Auxiliary Format 3: Weak Externals } else if (e_sclass == IMAGE_SYM_CLASS_FILE && symbolName == ".file") { // Auxiliary Format 4: Files // This entry is providing information about a source file and should not have a symbol created createSymbol = false; } else if (e_sclass == IMAGE_SYM_CLASS_STATIC && find_if(m_sections.begin(), m_sections.end(), [&symbolName](const PESection& section) { return section.name == symbolName; }) != m_sections.end()) { // Auxiliary Format 5: Section Definitions // This entry is providing information about a section and should not have a symbol created createSymbol = false; } if (createSymbol) { 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; } } // Skip over 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> libraries; vector> 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 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> 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 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 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 importDirStruct = importDirBuilder.Finalize(); Ref 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; } } const auto& exceptionDir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; if (exceptionDir.size % entrySize) throw PEFormatException("invalid table size"); const auto imageSize = GetEnd() - GetStart(); if ((exceptionDir.virtualAddress > imageSize) || (exceptionDir.size > (imageSize - exceptionDir.virtualAddress))) throw PEFormatException("too many exception entries, table size exceeds available memory range"); numExceptionEntries = exceptionDir.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 exceptionEntryStruct = exceptionEntryBuilder.Finalize(); Ref 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("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 unwindInfoStruct = unwindInfoStructBuilder.Finalize(); Ref 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 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 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 debugDirStruct = debugDirBuilder.Finalize(); Ref 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 assPlatform = platform->GetAssociatedPlatformByAddress(address); AddPESymbol(FunctionSymbol, "", name, address - m_imageBase); auto func = AddFunctionForAnalysis(platform, address); AddToEntryFunctions(func); } 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 tlsDirStruct = tlsDirBuilder.Finalize(); Ref 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> 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 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 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 delayImportDirStruct = delayImportDirBuilder.Finalize(); Ref 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, 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 loadConfigStruct = loadConfigBuilder.Finalize(); Ref 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("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 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(); guardCFCheckFunction += (m_imageBase - m_peImageBase); } uint64_t guardCFDispatchFunction = 0; if (guardCFDispatchFunctionPointer != 0) { reader.Seek(RVAToFileOffset(guardCFDispatchFunctionPointer - m_imageBase)); guardCFDispatchFunction = m_is64 ? reader.Read64() : reader.Read32(); guardCFDispatchFunction += (m_imageBase - m_peImageBase); } 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 gfidsStruct = gfidsBuilder.Finalize(); Ref 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("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 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 exportDirStruct = exportDirBuilder.Finalize(); Ref 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 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 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 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 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; bulkSymbolModification.End(); 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 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); } try { PEDataDirectory dir; // Read resource directory if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_RESOURCE) dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE]; else dir.virtualAddress = 0; if (dir.virtualAddress > 0) { // Create Resource Directory Table Type StructureBuilder resourceDirTableBuilder; resourceDirTableBuilder.AddMember(Type::IntegerType(4, false), "characteristics"); resourceDirTableBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp"); resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "majorVersion"); resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "minorVersion"); resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "numNameEntries"); resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "numIdEntries"); Ref resourceTableStruct = resourceDirTableBuilder.Finalize(); Ref resourceDirTableType = Type::StructureType(resourceTableStruct); QualifiedName resourceDirTableName = string("Resource_Directory_Table"); string resourceDirTableTypeId = Type::GenerateAutoTypeId("pe", resourceDirTableName); QualifiedName resourceDirTableTypeName = DefineType(resourceDirTableTypeId, resourceDirTableName, resourceDirTableType); // Create Resource Directory Entry Type StructureBuilder resourceDirEntryBuilder; resourceDirEntryBuilder.AddMember(Type::IntegerType(4, false), "id"); resourceDirEntryBuilder.AddMember(Type::IntegerType(4, false), "offset"); Ref resourceDirEntryStruct = resourceDirEntryBuilder.Finalize(); Ref resourceDirEntryType = Type::StructureType(resourceDirEntryStruct); QualifiedName resourceDirEntryName = string("Resource_Directory_Table_Entry"); string resourceDirEntryTypeId = Type::GenerateAutoTypeId("pe", resourceDirEntryName); QualifiedName resourceDirEntryTypeName = DefineType(resourceDirEntryTypeId, resourceDirEntryName, resourceDirEntryType); // Create Resource Data Entry Type StructureBuilder resourceDataEntryBuilder; resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "dataRva"); resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "dataSize"); resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "codepage"); resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "reserved"); Ref resourceDataEntryStruct = resourceDataEntryBuilder.Finalize(); Ref resourceDataEntryType = Type::StructureType(resourceDataEntryStruct); QualifiedName resourceDataEntryName = string("Resource_Data_Entry"); string resourceDataEntryTypeId = Type::GenerateAutoTypeId("pe", resourceDataEntryName); QualifiedName resourceDataEntryTypeName = DefineType(resourceDataEntryTypeId, resourceDataEntryName, resourceDataEntryType); // Helper: convert UTF-16LE code units to UTF-8 auto utf16ToUtf8 = [](const std::vector& codeUnits) -> std::string { std::string result; result.reserve(codeUnits.size()); for (uint16_t ch : codeUnits) { if (ch < 0x80) result.push_back(static_cast(ch)); else if (ch < 0x800) { result.push_back(static_cast(0xC0 | (ch >> 6))); result.push_back(static_cast(0x80 | (ch & 0x3F))); } else { result.push_back(static_cast(0xE0 | (ch >> 12))); result.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); result.push_back(static_cast(0x80 | (ch & 0x3F))); } } return result; }; // Helper lambda to read a UTF-16LE resource name string and convert to UTF-8 auto readResourceName = [&](uint64_t nameRva) -> std::string { if (nameRva < dir.virtualAddress || nameRva >= dir.virtualAddress + dir.size) return ""; BinaryReader nameReader(GetParentView(), LittleEndian); nameReader.Seek(RVAToFileOffset(nameRva)); uint16_t nameLen = nameReader.Read16(); if (nameLen == 0 || nameRva + 2 + (nameLen * 2) > dir.virtualAddress + dir.size) return ""; // Define the wide char array data variable DefineDataVariable(m_imageBase + nameRva + 2, Type::ArrayType(Type::WideCharType(2), nameLen)); std::vector codeUnits(nameLen); for (uint16_t i = 0; i < nameLen; i++) codeUnits[i] = nameReader.Read16(); return utf16ToUtf8(codeUnits); }; // Path-tracking BFS traversal of the resource directory tree std::list itemsToParse; itemsToParse.push_back({dir.virtualAddress, 0, "", "", 0, 0}); std::unordered_set visitedTables; uint64_t maxTableCount = 10000; if (settings && settings->Contains("loader.pe.maxResourceDirectoryTableCount")) maxTableCount = settings->Get("loader.pe.maxResourceDirectoryTableCount", this); uint32_t resourceDirectoryTableNum = 0; // Collect resource leaf entries for metadata std::vector>> resourceEntries; // Track used symbol names to handle duplicates std::unordered_map usedSymbolNames; auto makeUniqueSymbolName = [&](const std::string& baseName) -> std::string { auto it = usedSymbolNames.find(baseName); if (it == usedSymbolNames.end()) { usedSymbolNames[baseName] = 1; return baseName; } int count = it->second++; return fmt::format("{}_{}", baseName, count); }; while (!itemsToParse.empty()) { // Check for safety limit to prevent infinite parsing if (resourceDirectoryTableNum >= maxTableCount) { m_logger->LogError("Resource directory parsing exceeded safety limit (%" PRIu64 " tables), possible malformed/malicious file", maxTableCount); break; } ResourceParseItem item = itemsToParse.front(); itemsToParse.pop_front(); // Cycle detection - skip if we've already processed this table if (visitedTables.count(item.tableAddr)) { m_logger->LogWarn("Resource directory cycle detected at RVA 0x%" PRIx64 ", skipping", item.tableAddr); continue; } visitedTables.insert(item.tableAddr); // Bounds check - ensure table address is within resource section if (item.tableAddr < dir.virtualAddress || item.tableAddr >= dir.virtualAddress + dir.size) { m_logger->LogWarn("Resource directory table at RVA 0x%" PRIx64 " is outside resource section bounds", item.tableAddr); continue; } // Read in next directory table reader.Seek(RVAToFileOffset(item.tableAddr)); PEResourceDirectoryTable dirTable; dirTable.characteristics = reader.Read32(); dirTable.timeDateStamp = reader.Read32(); dirTable.majorVersion = reader.Read16(); dirTable.minorVersion = reader.Read16(); dirTable.numNameEntries = reader.Read16(); dirTable.numIdEntries = reader.Read16(); // Build a descriptive symbol name for this directory table std::string tableSymName; if (item.depth == 0) tableSymName = "__pe_rsrc_root"; else if (item.depth == 1) tableSymName = makeUniqueSymbolName(fmt::format("__pe_rsrc_{}", item.typeName)); else tableSymName = makeUniqueSymbolName(fmt::format("__pe_rsrc_{}_{}", item.typeName, item.resourceName)); DefineDataVariable(m_imageBase + item.tableAddr, Type::NamedType(this, resourceDirTableTypeName)); DefineAutoSymbol(new Symbol(DataSymbol, tableSymName, m_imageBase + item.tableAddr, NoBinding)); // All the Name entries precede all the ID entries for the table but we treat them the same // Offsets are relative to the address in the IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory. struct PendingDataEntry { size_t offset; std::string typeName; std::string resourceName; std::string langName; uint32_t typeId; uint32_t nameId; uint32_t langId; }; std::vector pendingDataEntries; size_t numTableEntries = dirTable.numNameEntries + dirTable.numIdEntries; if (numTableEntries > 0) { for (size_t entryNum = 0; entryNum < numTableEntries; entryNum++) { PEResourceDirectoryEntry dirEntry; dirEntry.id = reader.Read32(); dirEntry.offset = reader.Read32(); // Resolve the name/ID for this entry based on depth std::string entryName; uint32_t entryRawId = dirEntry.id & 0x7FFFFFFF; if (dirEntry.id & 0x80000000) { // Name entry — UTF-16LE string at the offset uint64_t nameAddr = dir.virtualAddress + entryRawId; std::string uniName = readResourceName(nameAddr); if (!uniName.empty()) entryName = uniName; else entryName = fmt::format("name_{:x}", entryRawId); } else { // ID entry — resolve based on depth if (item.depth == 0) { // Type ID const char* typeName = GetResourceTypeName(entryRawId); if (typeName) entryName = typeName; else entryName = fmt::format("type_{}", entryRawId); } else if (item.depth == 1) { // Resource name/ID entryName = fmt::format("#{}", entryRawId); } else { // Language ID entryName = fmt::format("lang{}", entryRawId); } } // Build child item context std::string childTypeName = item.typeName; std::string childResourceName = item.resourceName; uint32_t childTypeId = item.typeId; uint32_t childNameId = item.nameId; if (item.depth == 0) { childTypeName = entryName; childTypeId = entryRawId; } else if (item.depth == 1) { childResourceName = entryName; childNameId = entryRawId; } if (dirEntry.offset & 0x80000000) { // Lower 31 bits are address of another table uint64_t nextTableAddr = dir.virtualAddress + (dirEntry.offset ^ 0x80000000); // Bounds check before adding to queue to prevent invalid references if (nextTableAddr >= dir.virtualAddress && nextTableAddr < dir.virtualAddress + dir.size) { itemsToParse.push_back({nextTableAddr, item.depth + 1, childTypeName, childResourceName, childTypeId, childNameId}); } else { m_logger->LogWarn("Resource directory entry points to invalid address 0x%" PRIx64 ", skipping", nextTableAddr); } } else { // Address of data entry (leaf) uint64_t dataEntryAddr = dir.virtualAddress + dirEntry.offset; if (dataEntryAddr >= dir.virtualAddress && dataEntryAddr + sizeof(PEResourceDataEntry) <= dir.virtualAddress + dir.size) { std::string langName; uint32_t langId = 0; if (item.depth >= 2) { // This shouldn't happen in a well-formed PE (depth 2 entries point to data), // but handle gracefully langName = entryName; langId = entryRawId; } else if (item.depth == 1) { // We're at the name level, entry is language langName = entryName; langId = entryRawId; } else { langName = entryName; langId = entryRawId; } pendingDataEntries.push_back({(size_t)dirEntry.offset, childTypeName, childResourceName, langName, childTypeId, childNameId, langId}); } else { m_logger->LogWarn("Resource data entry at offset 0x%" PRIx32 " is outside resource section bounds, skipping", dirEntry.offset); } } } size_t tableEntriesStart = m_imageBase + item.tableAddr + sizeof(PEResourceDirectoryTable); DefineDataVariable(tableEntriesStart, Type::ArrayType(Type::NamedType(this, resourceDirEntryTypeName), numTableEntries)); std::string entriesSymName = tableSymName + "_entries"; DefineAutoSymbol(new Symbol(DataSymbol, entriesSymName, tableEntriesStart, NoBinding)); } // Process data entries (leaves) BinaryReader entryReader(GetParentView(), LittleEndian); for (auto& pending : pendingDataEntries) { entryReader.Seek(RVAToFileOffset(dir.virtualAddress + pending.offset)); PEResourceDataEntry dataEntry; dataEntry.dataRva = entryReader.Read32(); dataEntry.dataSize = entryReader.Read32(); dataEntry.dataCodePage = entryReader.Read32(); dataEntry.reserved = entryReader.Read32(); if (dataEntry.reserved != 0) continue; const uint32_t MAX_REASONABLE_RESOURCE_SIZE = 100 * 1024 * 1024; // 100 MB if (dataEntry.dataSize > MAX_REASONABLE_RESOURCE_SIZE) { m_logger->LogWarn("Resource data size 0x%" PRIx32 " exceeds reasonable limit, skipping", dataEntry.dataSize); continue; } if (dataEntry.dataSize > 0) { uint64_t dataEnd = (uint64_t)dataEntry.dataRva + dataEntry.dataSize; if (dataEnd < dataEntry.dataRva) { m_logger->LogWarn("Resource data RVA 0x%" PRIx32 " + size 0x%" PRIx32 " would overflow, skipping", dataEntry.dataRva, dataEntry.dataSize); continue; } } // Build descriptive path-based symbol names std::string pathPrefix; if (!pending.typeName.empty() && !pending.resourceName.empty() && !pending.langName.empty()) pathPrefix = fmt::format("__pe_rsrc_{}_{}_{}", pending.typeName, pending.resourceName, pending.langName); else if (!pending.typeName.empty() && !pending.resourceName.empty()) pathPrefix = fmt::format("__pe_rsrc_{}_{}", pending.typeName, pending.resourceName); else if (!pending.typeName.empty()) pathPrefix = fmt::format("__pe_rsrc_{}", pending.typeName); else pathPrefix = fmt::format("__pe_rsrc_entry_{}", resourceDirectoryTableNum); size_t entryAddr = m_imageBase + dir.virtualAddress + pending.offset; DefineDataVariable(entryAddr, Type::NamedType(this, resourceDataEntryTypeName)); DefineAutoSymbol(new Symbol(DataSymbol, makeUniqueSymbolName(pathPrefix + "_data_entry"), entryAddr, NoBinding)); if (dataEntry.dataSize > 0) { DefineDataVariable(m_imageBase + dataEntry.dataRva, Type::ArrayType(Type::IntegerType(1, true), dataEntry.dataSize)); DefineAutoSymbol(new Symbol(DataSymbol, makeUniqueSymbolName(pathPrefix + "_data"), m_imageBase + dataEntry.dataRva, NoBinding)); } // Generate preview for parseable resource types std::string preview; if (pending.typeId == 6 && dataEntry.dataSize > 0) // RT_STRING { try { BinaryReader strReader(GetParentView(), LittleEndian); strReader.Seek(RVAToFileOffset(dataEntry.dataRva)); size_t bytesRead = 0; std::vector strings; for (int strIdx = 0; strIdx < 16 && bytesRead < dataEntry.dataSize; strIdx++) { uint16_t strLen = strReader.Read16(); bytesRead += 2; if (strLen == 0) continue; if (bytesRead + strLen * 2 > dataEntry.dataSize) break; std::vector codeUnits(strLen); for (uint16_t i = 0; i < strLen; i++) codeUnits[i] = strReader.Read16(); bytesRead += strLen * 2; std::string s = utf16ToUtf8(codeUnits); if (!s.empty()) strings.push_back(s); } for (size_t i = 0; i < strings.size(); i++) { if (i > 0) preview += ", "; if (preview.size() + strings[i].size() > 200) { preview += "..."; break; } preview += strings[i]; } } catch (...) {} } // Collect metadata for this resource leaf std::map> entry; entry["type"] = new Metadata(pending.typeName); entry["typeId"] = new Metadata((uint64_t)pending.typeId); entry["name"] = new Metadata(pending.resourceName); entry["nameId"] = new Metadata((uint64_t)pending.nameId); entry["language"] = new Metadata(pending.langName); entry["languageId"] = new Metadata((uint64_t)pending.langId); entry["dataRva"] = new Metadata((uint64_t)dataEntry.dataRva); entry["dataSize"] = new Metadata((uint64_t)dataEntry.dataSize); entry["dataAddress"] = new Metadata((uint64_t)(m_imageBase + dataEntry.dataRva)); entry["codepage"] = new Metadata((uint64_t)dataEntry.dataCodePage); entry["preview"] = new Metadata(preview); resourceEntries.push_back(entry); } resourceDirectoryTableNum++; } // Parse RT_VERSION resource and store version info metadata for (auto& resEntry : resourceEntries) { uint64_t typeId = resEntry["typeId"]->GetUnsignedInteger(); if (typeId != 16) // RT_VERSION continue; uint64_t dataSize = resEntry["dataSize"]->GetUnsignedInteger(); if (dataSize < 6 || dataSize > 65536) break; try { BinaryReader vr(GetParentView(), LittleEndian); vr.Seek(RVAToFileOffset(resEntry["dataRva"]->GetUnsignedInteger())); size_t baseOffset = vr.GetOffset(); uint16_t viLength = vr.Read16(); uint16_t viValueLength = vr.Read16(); uint16_t viType = vr.Read16(); (void)viType; // Read and verify "VS_VERSION_INFO" key std::vector keyChars; for (int i = 0; i < 20; i++) { uint16_t ch = vr.Read16(); if (ch == 0) break; keyChars.push_back(ch); } std::string keyStr = utf16ToUtf8(keyChars); if (keyStr != "VS_VERSION_INFO") break; // Align to DWORD boundary size_t pos = vr.GetOffset() - baseOffset; if (pos % 4 != 0) vr.SeekRelative(4 - (pos % 4)); // Parse VS_FIXEDFILEINFO std::map> versionInfo; if (viValueLength >= 52) { uint32_t sig = vr.Read32(); if (sig == 0xFEEF04BD) { vr.Read32(); // dwStrucVersion uint32_t fileVerMS = vr.Read32(); uint32_t fileVerLS = vr.Read32(); uint32_t prodVerMS = vr.Read32(); uint32_t prodVerLS = vr.Read32(); std::string fileVer = fmt::format("{}.{}.{}.{}", (fileVerMS >> 16) & 0xFFFF, fileVerMS & 0xFFFF, (fileVerLS >> 16) & 0xFFFF, fileVerLS & 0xFFFF); std::string prodVer = fmt::format("{}.{}.{}.{}", (prodVerMS >> 16) & 0xFFFF, prodVerMS & 0xFFFF, (prodVerLS >> 16) & 0xFFFF, prodVerLS & 0xFFFF); versionInfo["FileVersion"] = new Metadata(fileVer); versionInfo["ProductVersion"] = new Metadata(prodVer); // Skip rest of VS_FIXEDFILEINFO (7 more DWORDs): // fileFlagsMask, fileFlags, fileOS, fileType, fileSubtype, fileDateMS, fileDateLS for (int i = 0; i < 7; i++) vr.Read32(); } } // Align after VS_FIXEDFILEINFO pos = vr.GetOffset() - baseOffset; if (pos % 4 != 0) vr.SeekRelative(4 - (pos % 4)); // Parse StringFileInfo / VarFileInfo children size_t endOffset = baseOffset + std::min((size_t)viLength, (size_t)dataSize); while ((size_t)vr.GetOffset() + 6 < endOffset) { size_t childBase = vr.GetOffset(); uint16_t childLength = vr.Read16(); uint16_t childValueLength = vr.Read16(); uint16_t childType = vr.Read16(); (void)childValueLength; (void)childType; if (childLength < 6 || childBase + childLength > baseOffset + dataSize) break; // Read child key std::vector childKeyChars; for (int i = 0; i < 30; i++) { if ((size_t)vr.GetOffset() >= childBase + childLength) break; uint16_t ch = vr.Read16(); if (ch == 0) break; childKeyChars.push_back(ch); } std::string childKey = utf16ToUtf8(childKeyChars); if (childKey == "StringFileInfo") { // Align pos = vr.GetOffset() - baseOffset; if (pos % 4 != 0) vr.SeekRelative(4 - (pos % 4)); size_t sfiEnd = childBase + childLength; // Parse StringTable(s) while ((size_t)vr.GetOffset() + 6 < sfiEnd) { size_t stBase = vr.GetOffset(); uint16_t stLength = vr.Read16(); vr.Read16(); // stValueLength vr.Read16(); // stType if (stLength < 6 || stBase + stLength > sfiEnd) break; // Skip StringTable key (language+codepage like "040904b0") for (int i = 0; i < 12; i++) { if ((size_t)vr.GetOffset() >= stBase + stLength) break; uint16_t ch = vr.Read16(); if (ch == 0) break; } // Align pos = vr.GetOffset() - baseOffset; if (pos % 4 != 0) vr.SeekRelative(4 - (pos % 4)); size_t stEnd = stBase + stLength; // Parse individual String entries while ((size_t)vr.GetOffset() + 6 < stEnd) { size_t strBase = vr.GetOffset(); uint16_t strLength = vr.Read16(); uint16_t strValueLength = vr.Read16(); uint16_t strType = vr.Read16(); (void)strType; if (strLength < 6 || strBase + strLength > stEnd) break; // Read key std::vector strKeyChars; for (int i = 0; i < 80; i++) { if ((size_t)vr.GetOffset() >= strBase + strLength) break; uint16_t ch = vr.Read16(); if (ch == 0) break; strKeyChars.push_back(ch); } std::string strKey = utf16ToUtf8(strKeyChars); // Align pos = vr.GetOffset() - baseOffset; if (pos % 4 != 0) vr.SeekRelative(4 - (pos % 4)); // Read value std::string strValue; if (strValueLength > 0 && (size_t)vr.GetOffset() < strBase + strLength) { std::vector valChars; uint16_t charsToRead = strValueLength; for (uint16_t i = 0; i < charsToRead; i++) { if ((size_t)vr.GetOffset() >= strBase + strLength) break; uint16_t ch = vr.Read16(); if (ch == 0) break; valChars.push_back(ch); } strValue = utf16ToUtf8(valChars); } if (!strKey.empty() && !strValue.empty()) versionInfo[strKey] = new Metadata(strValue); // Advance to next String entry vr.Seek(strBase + ((strLength + 3) & ~3)); } // Advance to next StringTable vr.Seek(stBase + ((stLength + 3) & ~3)); } } // Advance to next child vr.Seek(childBase + ((childLength + 3) & ~3)); } if (!versionInfo.empty()) { StoreMetadata("PEVersionInfo", new Metadata(versionInfo), true); // Set preview on this resource entry std::string verPreview; auto fv = versionInfo.find("FileVersion"); if (fv != versionInfo.end()) verPreview = fv->second->GetString(); auto cn = versionInfo.find("CompanyName"); if (cn != versionInfo.end()) { if (!verPreview.empty()) verPreview += " - "; verPreview += cn->second->GetString(); } resEntry["preview"] = new Metadata(verPreview); } } catch (...) {} break; // Only parse first RT_VERSION } // Store resource tree as metadata for programmatic access if (!resourceEntries.empty()) { std::vector> metadataArray; metadataArray.reserve(resourceEntries.size()); for (auto& entry : resourceEntries) metadataArray.push_back(new Metadata(entry)); StoreMetadata("PEResources", new Metadata(metadataArray), true); } } } catch (std::exception& e) { m_logger->LogWarn("Failed to parse resource directory: %s\n", e.what()); } Ref programSettings = Settings::Instance(); if (programSettings->Contains("core.function.analyzeConditionalNoReturns") && opt.subsystem != IMAGE_SUBSYSTEM_NATIVE && ( GetSymbolByRawName("TerminateProcess", GetExternalNameSpace()) || GetSymbolByRawName("_TerminateProcess@8", GetExternalNameSpace()))) { // TerminateProcess is imported and this is a user mode file programSettings->Set("core.function.analyzeConditionalNoReturns", true); } // 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(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> 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 symbolTypeRef; if (libs.size() && ((type == ExternalSymbol) || (type == ImportAddressSymbol) || (type == ImportedDataSymbol))) { QualifiedName n(name); for (auto lib : libs) { Ref 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( [=, this]() { // 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 typeRef = symbolTypeRef; if (m_arch && name.size() > 0) { QualifiedName demangledName; Ref demangledType; if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, nullptr, m_simplifyTemplates)) { shortName = demangledName.GetString(); fullName = shortName; if (demangledType) fullName += demangledType->GetStringAfterName(); if (!typeRef && m_extractMangledTypes && !GetDefaultPlatform()->GetFunctionByName(rawName)) typeRef = demangledType; } else { m_logger->LogDebug("Failed to demangle: '%s'\n", name.c_str()); } } NameSpace ns(dll); if (type == ExternalSymbol) ns = GetExternalNameSpace(); return pair, Ref>( new Symbol(type, shortName, fullName, rawName, address, binding, ns, ordinal), typeRef); }, [this](Symbol* symbol, const Confidence>& 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 PEViewType::Create(BinaryView* data) { try { return new PEView(data); } catch (std::exception& e) { m_logger->LogErrorForException( e, "%s failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } Ref PEViewType::Parse(BinaryView* data) { try { return new PEView(data, true); } catch (std::exception& e) { m_logger->LogErrorForException( e, "%s 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 PEViewType::GetLoadSettingsForData(BinaryView* data) { Ref viewRef = Parse(data); if (!viewRef || !viewRef->Init()) { m_logger->LogWarn("Failed to initialize view of type '%s'. Generating default load settings.", GetName().c_str()); viewRef = data; } Ref settings = GetDefaultLoadSettingsForData(viewRef); // specify default load settings that can be overridden vector overrides = {"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." })"); settings->RegisterSetting("loader.pe.maxResourceDirectoryTableCount", R"({ "title" : "Maximum PE Resource Directory Table Count", "type" : "number", "default" : 10000, "minValue" : 1, "maxValue" : 1000000, "description" : "Maximum number of resource directory tables to parse. This limit prevents infinite loops when processing malformed or malicious PE files with circular resource directory references." })"); return settings; } extern "C" { BN_DECLARE_CORE_ABI_VERSION #ifdef DEMO_EDITION bool PEPluginInit() #else BINARYNINJAPLUGIN bool CorePluginInit() #endif { InitPEViewType(); InitCOFFViewType(); InitTEViewType(); return true; } }