Skip to content

Instantly share code, notes, and snippets.

@japajoe
Created February 11, 2025 04:53
Show Gist options
  • Save japajoe/c5d8299966baaecb2905340725ff6fa3 to your computer and use it in GitHub Desktop.
Save japajoe/c5d8299966baaecb2905340725ff6fa3 to your computer and use it in GitHub Desktop.
Reads exported symbols from a DLL file
//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*>(&section), 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