|
1 | 1 | #include <algorithm> |
2 | 2 | #include <cstring> |
3 | 3 | #include <cctype> |
| 4 | +#include <list> |
4 | 5 | #include <string.h> |
5 | 6 | #include <inttypes.h> |
6 | 7 | #include <iomanip> |
@@ -2619,6 +2620,166 @@ bool PEView::Init() |
2619 | 2620 | DefineRelocation(m_arch, reloc, symbol, reloc.address); |
2620 | 2621 | } |
2621 | 2622 |
|
| 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 | + |
2622 | 2783 | // Add a symbol for the entry point |
2623 | 2784 | if (m_entryPoint) |
2624 | 2785 | DefineAutoSymbol(new Symbol(FunctionSymbol, "_start", m_imageBase + m_entryPoint)); |
|
0 commit comments