Modern C++ library that parses the portable executable file format. C++ standard library usage is abstracted in deps.hpp so it can be switched out with a custom implementation. It makes use of string views to not create any unnecessary allocations too. The library can be used on any OS, it does not rely on Windows specific headers. The test app is built for Windows though.
To build the test app, run the following commands:
cmake -B build
cmake --build build --config Release
for (const auto& sec : img.sections())
{
std::println("{} rva {} size {} {}{}{}", sec.name(), sec.virtual_address, sec.virtual_size,
sec.characteristics.mem_read ? 'r' : '-', sec.characteristics.mem_write ? 'w' : '-',
sec.characteristics.mem_execute ? 'x' : '-');
}for (const auto& exp : img.exports())
{
std::println("ordinal {} {} {}", exp.ordinal, exp.name, exp.loc.rva());
}for (const auto& imp : img.imports())
{
std::println("{} {} iat {}", imp.module_name,
imp.is_ordinal ? std::format("ordinal {}", imp.ordinal) : std::string{ imp.import_name },
imp.iat_slot.rva());
}for (const auto& imp : img.delay_imports())
{
std::println("{} {} iat {}", imp.module_name,
imp.is_ordinal ? std::format("ordinal {}", imp.ordinal) : std::string{ imp.import_name },
imp.iat_slot.rva());
}for (const auto& func : img.runtime_funcs())
{
// version is a bit field, so it cannot bind to the forwarding ref println takes
std::println("{} - {} version {} codes {} prolog {}{}{}{}", func.begin.rva(), func.end.rva(),
static_cast<std::uint32_t>(func.info->version),
static_cast<std::uint32_t>(func.info->unwind_code_count),
static_cast<std::uint32_t>(func.info->size_of_prolog),
func.info->exception_handler ? " exception" : "", func.info->unwind_handler ? " unwind" : "",
func.info->chain_info ? " chained" : "");
}for (const auto& code : func.info->code_list())
{
std::println("offset {} code {} info {}", static_cast<std::uint32_t>(code.offset),
static_cast<std::uint32_t>(code.code), static_cast<std::uint32_t>(code.info));
}for (const auto& rel : img.relocs())
{
std::println("type {} at {}", static_cast<std::uint32_t>(rel.type), rel.loc.rva());
}for (const auto& callback : img.tls_callbacks())
{
std::println("{}", callback.rva());
}for (const auto& dbg : img.debug_dirs())
{
std::println("type {} size {} rva {}", static_cast<std::uint32_t>(dbg.type), dbg.size_of_data,
dbg.address_of_raw_data);
}