Skip to content

Commit c579c0f

Browse files
committed
Initial parsing of PE resources
1 parent 140f7c4 commit c579c0f

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

view/pe/peview.cpp

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <algorithm>
22
#include <cstring>
33
#include <cctype>
4+
#include <list>
45
#include <string.h>
56
#include <inttypes.h>
67
#include <iomanip>
@@ -2619,6 +2620,166 @@ bool PEView::Init()
26192620
DefineRelocation(m_arch, reloc, symbol, reloc.address);
26202621
}
26212622

2623+
try
2624+
{
2625+
//TODO: properly name tables, entries, data entries
2626+
2627+
PEDataDirectory dir;
2628+
// Read resource directory
2629+
if (m_dataDirs.size() > IMAGE_DIRECTORY_ENTRY_RESOURCE)
2630+
dir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE];
2631+
else
2632+
dir.virtualAddress = 0;
2633+
2634+
if (dir.virtualAddress > 0)
2635+
{
2636+
// Create Resource Directory Table Type
2637+
StructureBuilder resourceDirTableBuilder;
2638+
resourceDirTableBuilder.AddMember(Type::IntegerType(4, false), "characteristics");
2639+
resourceDirTableBuilder.AddMember(Type::IntegerType(4, false), "timeDateStamp");
2640+
resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "majorVersion");
2641+
resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "minorVersion");
2642+
resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "numNameEntries");
2643+
resourceDirTableBuilder.AddMember(Type::IntegerType(2, false), "numIdEntries");
2644+
2645+
Ref<Structure> resourceTableStruct = resourceDirTableBuilder.Finalize();
2646+
Ref<Type> resourceDirTableType = Type::StructureType(resourceTableStruct);
2647+
QualifiedName resourceDirTableName = string("Resource_Directory_Table");
2648+
string resourceDirTableTypeId = Type::GenerateAutoTypeId("pe", resourceDirTableName);
2649+
QualifiedName resourceDirTableTypeName = DefineType(resourceDirTableTypeId, resourceDirTableName, resourceDirTableType);
2650+
2651+
// Create Resource Directory Entry Type
2652+
StructureBuilder resourceDirEntryBuilder;
2653+
resourceDirEntryBuilder.AddMember(Type::IntegerType(4, false), "id");
2654+
resourceDirEntryBuilder.AddMember(Type::IntegerType(4, false), "offset");
2655+
2656+
Ref<Structure> resourceDirEntryStruct = resourceDirEntryBuilder.Finalize();
2657+
Ref<Type> resourceDirEntryType = Type::StructureType(resourceDirEntryStruct);
2658+
QualifiedName resourceDirEntryName = string("Resource_Directory_Table_Entry");
2659+
string resourceDirEntryTypeId = Type::GenerateAutoTypeId("pe", resourceDirEntryName);
2660+
QualifiedName resourceDirEntryTypeName = DefineType(resourceDirEntryTypeId, resourceDirEntryName, resourceDirEntryType);
2661+
2662+
// Create Resource Data Entry Type
2663+
StructureBuilder resourceDataEntryBuilder;
2664+
resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "dataRva");
2665+
resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "dataSize");
2666+
resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "codepage");
2667+
resourceDataEntryBuilder.AddMember(Type::IntegerType(4, false), "reserved");
2668+
2669+
Ref<Structure> resourceDataEntryStruct = resourceDataEntryBuilder.Finalize();
2670+
Ref<Type> resourceDataEntryType = Type::StructureType(resourceDataEntryStruct);
2671+
QualifiedName resourceDataEntryName = string("Resource_Data_Entry");
2672+
string resourceDataEntryTypeId = Type::GenerateAutoTypeId("pe", resourceDataEntryName);
2673+
QualifiedName resourceDataEntryTypeName = DefineType(resourceDataEntryTypeId, resourceDataEntryName, resourceDataEntryType);
2674+
2675+
std::list<uint64_t> tableAddrsToParse = {dir.virtualAddress};
2676+
2677+
uint32_t resourceDirectoryTableNum = 0;
2678+
while (!tableAddrsToParse.empty())
2679+
{
2680+
uint64_t tableAddr = tableAddrsToParse.front();
2681+
tableAddrsToParse.pop_front();
2682+
// Read in next directory entry
2683+
reader.Seek(RVAToFileOffset(tableAddr));
2684+
PEResourceDirectoryTable importDirTable;
2685+
importDirTable.characteristics = reader.Read32();
2686+
importDirTable.timeDateStamp = reader.Read32();
2687+
importDirTable.majorVersion = reader.Read16();
2688+
importDirTable.minorVersion = reader.Read16();
2689+
importDirTable.numNameEntries = reader.Read16();
2690+
importDirTable.numIdEntries = reader.Read16();
2691+
2692+
DefineDataVariable(m_imageBase + tableAddr, Type::NamedType(this, resourceDirTableTypeName));
2693+
DefineAutoSymbol(new Symbol(DataSymbol, fmt::format("__resource_directory_table_{}", resourceDirectoryTableNum), m_imageBase + tableAddr, NoBinding));
2694+
2695+
// All the Name entries precede all the ID entries for the table but we treat them the same
2696+
// All entries for the table are sorted in ascending order: the Name entries by case-sensitive string and the ID entries by numeric value.
2697+
// Offsets are relative to the address in the IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory.
2698+
2699+
// Offset value:
2700+
// High bit 0. Address of a Resource Data entry (a leaf).
2701+
// High bit 1. The lower 31 bits are the address of another resource directory table (the next level down).
2702+
2703+
std::vector<size_t> dataEntryOffsets;
2704+
2705+
size_t numTableEntries = importDirTable.numNameEntries + importDirTable.numIdEntries;
2706+
2707+
if (numTableEntries > 0)
2708+
{
2709+
for (size_t entryNum = 0; entryNum < numTableEntries; entryNum++)
2710+
{
2711+
PEResourceDirectoryEntry importDirEntry;
2712+
importDirEntry.id = reader.Read32();
2713+
importDirEntry.offset = reader.Read32();
2714+
2715+
if (importDirEntry.id & 0x80000000)
2716+
{
2717+
// Name entry
2718+
// First 2 bytes of name are length
2719+
2720+
size_t nameAddr = dir.virtualAddress + (importDirEntry.id ^ 0x80000000);
2721+
2722+
BinaryReader nameReader(GetParentView(), LittleEndian);
2723+
nameReader.Seek(RVAToFileOffset(nameAddr));
2724+
2725+
uint16_t nameLen = nameReader.Read16();
2726+
// Plus 2 because it's length-prefixed
2727+
DefineDataVariable(m_imageBase + nameAddr + 2, Type::ArrayType(Type::WideCharType(2), nameLen));
2728+
}
2729+
2730+
if (importDirEntry.offset & 0x80000000)
2731+
{
2732+
// Lower 31 bits are address of another table
2733+
tableAddrsToParse.push_back(dir.virtualAddress + (importDirEntry.offset ^ 0x80000000));
2734+
}
2735+
else
2736+
{
2737+
// Address of data entry
2738+
dataEntryOffsets.push_back(importDirEntry.offset);
2739+
}
2740+
}
2741+
2742+
size_t tableEntriesStart = m_imageBase + tableAddr + sizeof(PEResourceDirectoryTable);
2743+
DefineDataVariable(tableEntriesStart, Type::ArrayType(Type::NamedType(this, resourceDirEntryTypeName), numTableEntries));
2744+
DefineAutoSymbol(new Symbol(DataSymbol, fmt::format("__resource_directory_table_{}_entries", resourceDirectoryTableNum), tableEntriesStart, NoBinding));
2745+
}
2746+
2747+
for(size_t dataEntryNum = 0; dataEntryNum < dataEntryOffsets.size(); dataEntryNum++)
2748+
{
2749+
BinaryReader entryReader(GetParentView(), LittleEndian);
2750+
2751+
size_t entryOffset = dataEntryOffsets[dataEntryNum];
2752+
entryReader.Seek(RVAToFileOffset(dir.virtualAddress + entryOffset));
2753+
PEResourceDataEntry dataEntry;
2754+
dataEntry.dataRva = entryReader.Read32();
2755+
dataEntry.dataSize = entryReader.Read32();
2756+
dataEntry.dataCodePage = entryReader.Read32();
2757+
dataEntry.reserved = entryReader.Read32();
2758+
2759+
if (dataEntry.reserved != 0)
2760+
{
2761+
// Invalid entry, this needs to be 0
2762+
continue;
2763+
}
2764+
2765+
size_t entryAddr = m_imageBase + dir.virtualAddress + entryOffset;
2766+
2767+
DefineDataVariable(entryAddr, Type::NamedType(this, resourceDataEntryTypeName));
2768+
DefineAutoSymbol(new Symbol(DataSymbol, fmt::format("__resource_directory_table_{}_data_entry_{}", resourceDirectoryTableNum, dataEntryNum), entryAddr, NoBinding));
2769+
2770+
//TODO: properly name based on path taken to get here
2771+
DefineDataVariable(m_imageBase + dataEntry.dataRva, Type::ArrayType(Type::IntegerType(1, true), dataEntry.dataSize));
2772+
}
2773+
2774+
resourceDirectoryTableNum++;
2775+
}
2776+
}
2777+
}
2778+
catch (std::exception& e)
2779+
{
2780+
m_logger->LogWarn("Failed to parse resource directory: %s\n", e.what());
2781+
}
2782+
26222783
// Add a symbol for the entry point
26232784
if (m_entryPoint)
26242785
DefineAutoSymbol(new Symbol(FunctionSymbol, "_start", m_imageBase + m_entryPoint));

view/pe/peview.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,30 @@ namespace BinaryNinja
420420
uint32_t Age;
421421
};
422422

423+
struct PEResourceDirectoryTable
424+
{
425+
uint32_t characteristics;
426+
uint32_t timeDateStamp;
427+
uint16_t majorVersion;
428+
uint16_t minorVersion;
429+
uint16_t numNameEntries;
430+
uint16_t numIdEntries;
431+
};
432+
433+
struct PEResourceDirectoryEntry
434+
{
435+
uint32_t id;
436+
uint32_t offset;
437+
};
438+
439+
struct PEResourceDataEntry
440+
{
441+
uint32_t dataRva;
442+
uint32_t dataSize;
443+
uint32_t dataCodePage;
444+
uint32_t reserved;
445+
};
446+
423447
class PEView: public BinaryView
424448
{
425449
bool m_parseOnly, m_backedByDatabase;

0 commit comments

Comments
 (0)