Created
February 11, 2025 04:53
-
-
Save japajoe/c5d8299966baaecb2905340725ff6fa3 to your computer and use it in GitHub Desktop.
Reads exported symbols from a DLL file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //Generated by DeepSeek R1 | |
| #include <iostream> | |
| #include <fstream> | |
| #include <vector> | |
| #include <cstdint> | |
| #include <string> | |
| #include <iomanip> | |
| using namespace std; | |
| #pragma pack(push, 1) | |
| struct IMAGE_DOS_HEADER { | |
| uint16_t e_magic; | |
| uint16_t e_cblp; | |
| uint16_t e_cp; | |
| uint16_t e_crlc; | |
| uint16_t e_cparhdr; | |
| uint16_t e_minalloc; | |
| uint16_t e_maxalloc; | |
| uint16_t e_ss; | |
| uint16_t e_sp; | |
| uint16_t e_csum; | |
| uint16_t e_ip; | |
| uint16_t e_cs; | |
| uint16_t e_lfarlc; | |
| uint16_t e_ovno; | |
| uint16_t e_res[4]; | |
| uint16_t e_oemid; | |
| uint16_t e_oeminfo; | |
| uint16_t e_res2[10]; | |
| uint32_t e_lfanew; | |
| }; | |
| struct IMAGE_FILE_HEADER { | |
| uint16_t Machine; | |
| uint16_t NumberOfSections; | |
| uint32_t TimeDateStamp; | |
| uint32_t PointerToSymbolTable; | |
| uint32_t NumberOfSymbols; | |
| uint16_t SizeOfOptionalHeader; | |
| uint16_t Characteristics; | |
| }; | |
| struct IMAGE_DATA_DIRECTORY { | |
| uint32_t VirtualAddress; | |
| uint32_t Size; | |
| }; | |
| struct IMAGE_EXPORT_DIRECTORY { | |
| uint32_t Characteristics; | |
| uint32_t TimeDateStamp; | |
| uint16_t MajorVersion; | |
| uint16_t MinorVersion; | |
| uint32_t Name; | |
| uint32_t Base; | |
| uint32_t NumberOfFunctions; | |
| uint32_t NumberOfNames; | |
| uint32_t AddressOfFunctions; | |
| uint32_t AddressOfNames; | |
| uint32_t AddressOfNameOrdinals; | |
| }; | |
| struct IMAGE_SECTION_HEADER { | |
| uint8_t Name[8]; | |
| uint32_t VirtualSize; | |
| uint32_t VirtualAddress; | |
| uint32_t SizeOfRawData; | |
| uint32_t PointerToRawData; | |
| uint32_t PointerToRelocations; | |
| uint32_t PointerToLinenumbers; | |
| uint16_t NumberOfRelocations; | |
| uint16_t NumberOfLinenumbers; | |
| uint32_t Characteristics; | |
| }; | |
| #pragma pack(pop) | |
| uint32_t rva_to_offset(const vector<IMAGE_SECTION_HEADER>& sections, uint32_t rva) { | |
| for (const auto& section : sections) { | |
| if (rva >= section.VirtualAddress && | |
| rva < section.VirtualAddress + section.SizeOfRawData) { | |
| return (rva - section.VirtualAddress) + section.PointerToRawData; | |
| } | |
| } | |
| return 0; | |
| } | |
| int main(int argc, char* argv[]) { | |
| if (argc != 2) { | |
| cerr << "Usage: " << argv[0] << " <dll file>\n"; | |
| return 1; | |
| } | |
| ifstream file(argv[1], ios::binary); | |
| if (!file) { | |
| cerr << "Error opening file\n"; | |
| return 1; | |
| } | |
| IMAGE_DOS_HEADER dos_header; | |
| file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header)); | |
| if (dos_header.e_magic != 0x5A4D) { | |
| cerr << "Not a valid DOS header\n"; | |
| return 1; | |
| } | |
| file.seekg(dos_header.e_lfanew, ios::beg); | |
| char pe_sig[4]; | |
| file.read(pe_sig, 4); | |
| if (pe_sig[0] != 'P' || pe_sig[1] != 'E' || pe_sig[2] != 0 || pe_sig[3] != 0) { | |
| cerr << "Not a valid PE signature\n"; | |
| return 1; | |
| } | |
| IMAGE_FILE_HEADER file_header; | |
| file.read(reinterpret_cast<char*>(&file_header), sizeof(file_header)); | |
| uint16_t magic; | |
| file.read(reinterpret_cast<char*>(&magic), 2); | |
| if (magic != 0x10b && magic != 0x20b) { | |
| cerr << "Unsupported PE format\n"; | |
| return 1; | |
| } | |
| file.seekg((magic == 0x10b) ? 94 : 110, ios::cur); | |
| IMAGE_DATA_DIRECTORY export_dir; | |
| file.read(reinterpret_cast<char*>(&export_dir), sizeof(export_dir)); | |
| if (export_dir.VirtualAddress == 0) { | |
| cerr << "No exports found\n"; | |
| return 1; | |
| } | |
| vector<IMAGE_SECTION_HEADER> sections(file_header.NumberOfSections); | |
| for (auto& section : sections) { | |
| file.read(reinterpret_cast<char*>(§ion), sizeof(section)); | |
| } | |
| uint32_t export_offset = rva_to_offset(sections, export_dir.VirtualAddress); | |
| if (!export_offset) { | |
| cerr << "Export directory not found\n"; | |
| return 1; | |
| } | |
| file.seekg(export_offset, ios::beg); | |
| IMAGE_EXPORT_DIRECTORY export_table; | |
| file.read(reinterpret_cast<char*>(&export_table), sizeof(export_table)); | |
| vector<uint32_t> name_rvas(export_table.NumberOfNames); | |
| uint32_t names_offset = rva_to_offset(sections, export_table.AddressOfNames); | |
| file.seekg(names_offset, ios::beg); | |
| file.read(reinterpret_cast<char*>(name_rvas.data()), name_rvas.size() * sizeof(uint32_t)); | |
| vector<uint16_t> ordinals(export_table.NumberOfNames); | |
| uint32_t ordinals_offset = rva_to_offset(sections, export_table.AddressOfNameOrdinals); | |
| file.seekg(ordinals_offset, ios::beg); | |
| file.read(reinterpret_cast<char*>(ordinals.data()), ordinals.size() * sizeof(uint16_t)); | |
| vector<uint32_t> function_rvas(export_table.NumberOfFunctions); | |
| uint32_t functions_offset = rva_to_offset(sections, export_table.AddressOfFunctions); | |
| file.seekg(functions_offset, ios::beg); | |
| file.read(reinterpret_cast<char*>(function_rvas.data()), function_rvas.size() * sizeof(uint32_t)); | |
| cout << "Exported Symbols:\n"; | |
| for (size_t i = 0; i < export_table.NumberOfNames; ++i) { | |
| uint32_t name_offset = rva_to_offset(sections, name_rvas[i]); | |
| file.seekg(name_offset, ios::beg); | |
| string name; | |
| getline(file, name, '\0'); | |
| uint16_t ordinal = ordinals[i] + export_table.Base; | |
| cout << "0x" << hex << setw(4) << setfill('0') << ordinal << " " << name << "\n"; | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment