parent
f1a6393e00
commit
0c421e5050
Binary file not shown.
@ -1,301 +0,0 @@
|
|||||||
#include "linker.hpp"
|
|
||||||
|
|
||||||
namespace lnk
|
|
||||||
{
|
|
||||||
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
std::uint32_t result =
|
|
||||||
section_headers[sym.section_number - 1].SizeOfRawData;
|
|
||||||
|
|
||||||
// loop over all symbols in this object...
|
|
||||||
// find the next symbol inside of the same section...
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
if (symbol_table[idx].SectionNumber == sym.section_number)
|
|
||||||
if (symbol_table[idx].Value > sym.section_offset && symbol_table[idx].Value < result)
|
|
||||||
result = symbol_table[idx].Value;
|
|
||||||
|
|
||||||
return result - sym.section_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_map_symbols(std::string map_path) -> map_symbols_t
|
|
||||||
{
|
|
||||||
std::ifstream map_file(map_path);
|
|
||||||
|
|
||||||
if (!map_file.is_open())
|
|
||||||
return { {}, {} };
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
map_symbols_t result;
|
|
||||||
while (std::getline(map_file, line))
|
|
||||||
{
|
|
||||||
const auto colon_index = line.find(":");
|
|
||||||
if (colon_index == std::string::npos)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto section_number =
|
|
||||||
std::strtoul(line.substr(1,
|
|
||||||
colon_index).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
const auto section_offset =
|
|
||||||
std::strtoull(line.substr(
|
|
||||||
colon_index + 1, 16).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
auto symbol = line.substr(
|
|
||||||
colon_index + 16 + 8,
|
|
||||||
line.length() - (colon_index + 16 + 7));
|
|
||||||
|
|
||||||
symbol[symbol.length()] = '\0';
|
|
||||||
result[symbol] = { section_number, section_offset };
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> lib_file;
|
|
||||||
utils::open_binary_file(lib_path, lib_file);
|
|
||||||
|
|
||||||
// archive header magic bytes are not correct...
|
|
||||||
if (strncmp((char*)lib_file.data(),
|
|
||||||
IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto archive_headers =
|
|
||||||
reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
lib_file.data() + sizeof IMAGE_ARCHIVE_START - 1);
|
|
||||||
|
|
||||||
while (reinterpret_cast<std::uint8_t*>(archive_headers) < lib_file.data() + lib_file.size())
|
|
||||||
{
|
|
||||||
// some absolutely fucked up shit I have to
|
|
||||||
// do since the linker is off by 1 sometimes...
|
|
||||||
// this sounds weird... I know it sounds weird... its weird...
|
|
||||||
if (archive_headers->Name[0] == '\n')
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) + 1);
|
|
||||||
|
|
||||||
// refer to https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#archive-member-headers
|
|
||||||
// for details on the "name" field... in short `/` means its a linker header
|
|
||||||
// `//` means that it is the string table, and finally `/n` n being the index into the string table...
|
|
||||||
// so in short: if the first byte isnt a `/` and the second byte is not a space or the first byte
|
|
||||||
// is not a forward slash then this archive header is for an obj...
|
|
||||||
if ((archive_headers->Name[0] == '/' &&
|
|
||||||
archive_headers->Name[1] != '\x20' &&
|
|
||||||
archive_headers->Name[1] != '/') || archive_headers->Name[0] != '/')
|
|
||||||
{
|
|
||||||
const auto obj_size = std::atoi(
|
|
||||||
reinterpret_cast<const char*>(archive_headers->Size));
|
|
||||||
|
|
||||||
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!obj_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto obj_begin = reinterpret_cast<void*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> obj{};
|
|
||||||
obj.resize(obj_size);
|
|
||||||
|
|
||||||
memcpy(obj.data(), obj_begin, obj_size);
|
|
||||||
objs.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
std::atoi(reinterpret_cast<char*>(
|
|
||||||
archive_headers->Size)) + sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace section
|
|
||||||
{
|
|
||||||
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, section_name, strlen(section_name) - 1))
|
|
||||||
return section_headers + idx;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!callback(section_headers + idx, obj))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace sym
|
|
||||||
{
|
|
||||||
auto get_relocs(obj_buffer_t& obj) -> std::vector<image_reloc_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<image_reloc_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
{
|
|
||||||
if (section_headers[idx].PointerToRelocations)
|
|
||||||
{
|
|
||||||
// for some reason the compiler makes some empty sections...
|
|
||||||
if (!section_headers[idx].SizeOfRawData)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over sections that we will not be using...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_LNK_REMOVE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over discardable sections...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip both the .pdata and the .xdata sections... these are used for exceptions...
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".pdata", strlen(".pdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".xdata", strlen(".xdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto reloc_dir =
|
|
||||||
reinterpret_cast<PIMAGE_RELOCATION>(
|
|
||||||
section_headers[idx].PointerToRelocations + obj.data());
|
|
||||||
|
|
||||||
for (auto reloc_idx = 0u; reloc_idx <
|
|
||||||
section_headers[idx].NumberOfRelocations; ++reloc_idx)
|
|
||||||
{
|
|
||||||
image_reloc_t entry;
|
|
||||||
entry.file_offset =
|
|
||||||
reloc_dir[reloc_idx].VirtualAddress +
|
|
||||||
section_headers[idx].PointerToRawData;
|
|
||||||
|
|
||||||
if (symbol_table[reloc_dir[reloc_idx].SymbolTableIndex].N.Name.Short)
|
|
||||||
entry.resolve_symbol_name =
|
|
||||||
std::string((char*)symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.ShortName);
|
|
||||||
else
|
|
||||||
entry.resolve_symbol_name = std::string(
|
|
||||||
string_table + symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.Name.Long);
|
|
||||||
|
|
||||||
entry.type = reloc_dir[reloc_idx].Type;
|
|
||||||
result.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<symbol_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
{
|
|
||||||
// skip section symbols... we only want
|
|
||||||
// .data, .rdata, and executable (function) symbols...
|
|
||||||
if (symbol_table[idx].StorageClass != IMAGE_SYM_CLASS_EXTERNAL
|
|
||||||
|| !symbol_table[idx].SectionNumber)
|
|
||||||
{
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_t symbol;
|
|
||||||
if (symbol_table[idx].N.Name.Short)
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string((char*)symbol_table[idx].N.ShortName);
|
|
||||||
else
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string(string_table +
|
|
||||||
symbol_table[idx].N.Name.Long);
|
|
||||||
|
|
||||||
symbol.file_offset = section_headers[symbol_table[
|
|
||||||
idx].SectionNumber - 1].PointerToRawData + symbol_table[idx].Value;
|
|
||||||
|
|
||||||
symbol.section_number = symbol_table[idx].SectionNumber;
|
|
||||||
symbol.section_offset = symbol_table[idx].Value;
|
|
||||||
symbol.type = symbol_table[idx].Type;
|
|
||||||
symbol.size = get_symbol_size(symbol, obj);
|
|
||||||
|
|
||||||
const auto section_name =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
section_headers[symbol_table[idx].SectionNumber - 1].Name);
|
|
||||||
|
|
||||||
if (!strncmp(section_name, ".theo2", sizeof(".theo2") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::encrypt;
|
|
||||||
else if (!strncmp(section_name, ".theo1", sizeof(".theo1") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::mutate;
|
|
||||||
else if (!strncmp(section_name, ".theo", sizeof(".theo") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::obfuscate;
|
|
||||||
else
|
|
||||||
symbol.obfuscate_type = (theo_type)NULL;
|
|
||||||
|
|
||||||
// there can be more then one aux symbols...
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
result.push_back(symbol);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
@ -1,301 +0,0 @@
|
|||||||
#include "linker.hpp"
|
|
||||||
|
|
||||||
namespace lnk
|
|
||||||
{
|
|
||||||
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
std::uint32_t result =
|
|
||||||
section_headers[sym.section_number - 1].SizeOfRawData;
|
|
||||||
|
|
||||||
// loop over all symbols in this object...
|
|
||||||
// find the next symbol inside of the same section...
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
if (symbol_table[idx].SectionNumber == sym.section_number)
|
|
||||||
if (symbol_table[idx].Value > sym.section_offset && symbol_table[idx].Value < result)
|
|
||||||
result = symbol_table[idx].Value;
|
|
||||||
|
|
||||||
return result - sym.section_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_map_symbols(std::string map_path) -> map_symbols_t
|
|
||||||
{
|
|
||||||
std::ifstream map_file(map_path);
|
|
||||||
|
|
||||||
if (!map_file.is_open())
|
|
||||||
return { {}, {} };
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
map_symbols_t result;
|
|
||||||
while (std::getline(map_file, line))
|
|
||||||
{
|
|
||||||
const auto colon_index = line.find(":");
|
|
||||||
if (colon_index == std::string::npos)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto section_number =
|
|
||||||
std::strtoul(line.substr(1,
|
|
||||||
colon_index).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
const auto section_offset =
|
|
||||||
std::strtoull(line.substr(
|
|
||||||
colon_index + 1, 16).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
auto symbol = line.substr(
|
|
||||||
colon_index + 16 + 8,
|
|
||||||
line.length() - (colon_index + 16 + 7));
|
|
||||||
|
|
||||||
symbol[symbol.length()] = '\0';
|
|
||||||
result[symbol] = { section_number, section_offset };
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> lib_file;
|
|
||||||
utils::open_binary_file(lib_path, lib_file);
|
|
||||||
|
|
||||||
// archive header magic bytes are not correct...
|
|
||||||
if (strncmp((char*)lib_file.data(),
|
|
||||||
IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto archive_headers =
|
|
||||||
reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
lib_file.data() + sizeof IMAGE_ARCHIVE_START - 1);
|
|
||||||
|
|
||||||
while (reinterpret_cast<std::uint8_t*>(archive_headers) < lib_file.data() + lib_file.size())
|
|
||||||
{
|
|
||||||
// some absolutely fucked up shit I have to
|
|
||||||
// do since the linker is off by 1 sometimes...
|
|
||||||
// this sounds weird... I know it sounds weird... its weird...
|
|
||||||
if (archive_headers->Name[0] == '\n')
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) + 1);
|
|
||||||
|
|
||||||
// refer to https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#archive-member-headers
|
|
||||||
// for details on the "name" field... in short `/` means its a linker header
|
|
||||||
// `//` means that it is the string table, and finally `/n` n being the index into the string table...
|
|
||||||
// so in short: if the first byte isnt a `/` and the second byte is not a space or the first byte
|
|
||||||
// is not a forward slash then this archive header is for an obj...
|
|
||||||
if ((archive_headers->Name[0] == '/' &&
|
|
||||||
archive_headers->Name[1] != '\x20' &&
|
|
||||||
archive_headers->Name[1] != '/') || archive_headers->Name[0] != '/')
|
|
||||||
{
|
|
||||||
const auto obj_size = std::atoi(
|
|
||||||
reinterpret_cast<const char*>(archive_headers->Size));
|
|
||||||
|
|
||||||
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!obj_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto obj_begin = reinterpret_cast<void*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> obj{};
|
|
||||||
obj.resize(obj_size);
|
|
||||||
|
|
||||||
memcpy(obj.data(), obj_begin, obj_size);
|
|
||||||
objs.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
std::atoi(reinterpret_cast<char*>(
|
|
||||||
archive_headers->Size)) + sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace section
|
|
||||||
{
|
|
||||||
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, section_name, strlen(section_name) - 1))
|
|
||||||
return section_headers + idx;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!callback(section_headers + idx, obj))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace sym
|
|
||||||
{
|
|
||||||
auto get_relocs(obj_buffer_t& obj) -> std::vector<image_reloc_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<image_reloc_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
{
|
|
||||||
if (section_headers[idx].PointerToRelocations)
|
|
||||||
{
|
|
||||||
// for some reason the compiler makes some empty sections...
|
|
||||||
if (!section_headers[idx].SizeOfRawData)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over sections that we will not be using...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_LNK_REMOVE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over discardable sections...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip both the .pdata and the .xdata sections... these are used for exceptions...
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".pdata", strlen(".pdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".xdata", strlen(".xdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto reloc_dir =
|
|
||||||
reinterpret_cast<PIMAGE_RELOCATION>(
|
|
||||||
section_headers[idx].PointerToRelocations + obj.data());
|
|
||||||
|
|
||||||
for (auto reloc_idx = 0u; reloc_idx <
|
|
||||||
section_headers[idx].NumberOfRelocations; ++reloc_idx)
|
|
||||||
{
|
|
||||||
image_reloc_t entry;
|
|
||||||
entry.file_offset =
|
|
||||||
reloc_dir[reloc_idx].VirtualAddress +
|
|
||||||
section_headers[idx].PointerToRawData;
|
|
||||||
|
|
||||||
if (symbol_table[reloc_dir[reloc_idx].SymbolTableIndex].N.Name.Short)
|
|
||||||
entry.resolve_symbol_name =
|
|
||||||
std::string((char*)symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.ShortName);
|
|
||||||
else
|
|
||||||
entry.resolve_symbol_name = std::string(
|
|
||||||
string_table + symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.Name.Long);
|
|
||||||
|
|
||||||
entry.type = reloc_dir[reloc_idx].Type;
|
|
||||||
result.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<symbol_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
{
|
|
||||||
// skip section symbols... we only want
|
|
||||||
// .data, .rdata, and executable (function) symbols...
|
|
||||||
if (symbol_table[idx].StorageClass != IMAGE_SYM_CLASS_EXTERNAL
|
|
||||||
|| !symbol_table[idx].SectionNumber)
|
|
||||||
{
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_t symbol;
|
|
||||||
if (symbol_table[idx].N.Name.Short)
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string((char*)symbol_table[idx].N.ShortName);
|
|
||||||
else
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string(string_table +
|
|
||||||
symbol_table[idx].N.Name.Long);
|
|
||||||
|
|
||||||
symbol.file_offset = section_headers[symbol_table[
|
|
||||||
idx].SectionNumber - 1].PointerToRawData + symbol_table[idx].Value;
|
|
||||||
|
|
||||||
symbol.section_number = symbol_table[idx].SectionNumber;
|
|
||||||
symbol.section_offset = symbol_table[idx].Value;
|
|
||||||
symbol.type = symbol_table[idx].Type;
|
|
||||||
symbol.size = get_symbol_size(symbol, obj);
|
|
||||||
|
|
||||||
const auto section_name =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
section_headers[symbol_table[idx].SectionNumber - 1].Name);
|
|
||||||
|
|
||||||
if (!strncmp(section_name, ".theo2", sizeof(".theo2") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::encrypt;
|
|
||||||
else if (!strncmp(section_name, ".theo1", sizeof(".theo1") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::mutate;
|
|
||||||
else if (!strncmp(section_name, ".theo", sizeof(".theo") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::obfuscate;
|
|
||||||
else
|
|
||||||
symbol.obfuscate_type = (theo_type)NULL;
|
|
||||||
|
|
||||||
// there can be more then one aux symbols...
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
result.push_back(symbol);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
@ -1,301 +0,0 @@
|
|||||||
#include "linker.hpp"
|
|
||||||
|
|
||||||
namespace lnk
|
|
||||||
{
|
|
||||||
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
std::uint32_t result =
|
|
||||||
section_headers[sym.section_number - 1].SizeOfRawData;
|
|
||||||
|
|
||||||
// loop over all symbols in this object...
|
|
||||||
// find the next symbol inside of the same section...
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
if (symbol_table[idx].SectionNumber == sym.section_number)
|
|
||||||
if (symbol_table[idx].Value > sym.section_offset && symbol_table[idx].Value < result)
|
|
||||||
result = symbol_table[idx].Value;
|
|
||||||
|
|
||||||
return result - sym.section_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_map_symbols(std::string map_path) -> map_symbols_t
|
|
||||||
{
|
|
||||||
std::ifstream map_file(map_path);
|
|
||||||
|
|
||||||
if (!map_file.is_open())
|
|
||||||
return { {}, {} };
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
map_symbols_t result;
|
|
||||||
while (std::getline(map_file, line))
|
|
||||||
{
|
|
||||||
const auto colon_index = line.find(":");
|
|
||||||
if (colon_index == std::string::npos)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto section_number =
|
|
||||||
std::strtoul(line.substr(1,
|
|
||||||
colon_index).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
const auto section_offset =
|
|
||||||
std::strtoull(line.substr(
|
|
||||||
colon_index + 1, 16).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
auto symbol = line.substr(
|
|
||||||
colon_index + 16 + 8,
|
|
||||||
line.length() - (colon_index + 16 + 7));
|
|
||||||
|
|
||||||
symbol[symbol.length()] = '\0';
|
|
||||||
result[symbol] = { section_number, section_offset };
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> lib_file;
|
|
||||||
utils::open_binary_file(lib_path, lib_file);
|
|
||||||
|
|
||||||
// archive header magic bytes are not correct...
|
|
||||||
if (strncmp((char*)lib_file.data(),
|
|
||||||
IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto archive_headers =
|
|
||||||
reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
lib_file.data() + sizeof IMAGE_ARCHIVE_START - 1);
|
|
||||||
|
|
||||||
while (reinterpret_cast<std::uint8_t*>(archive_headers) < lib_file.data() + lib_file.size())
|
|
||||||
{
|
|
||||||
// some absolutely fucked up shit I have to
|
|
||||||
// do since the linker is off by 1 sometimes...
|
|
||||||
// this sounds weird... I know it sounds weird... its weird...
|
|
||||||
if (archive_headers->Name[0] == '\n')
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) + 1);
|
|
||||||
|
|
||||||
// refer to https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#archive-member-headers
|
|
||||||
// for details on the "name" field... in short `/` means its a linker header
|
|
||||||
// `//` means that it is the string table, and finally `/n` n being the index into the string table...
|
|
||||||
// so in short: if the first byte isnt a `/` and the second byte is not a space or the first byte
|
|
||||||
// is not a forward slash then this archive header is for an obj...
|
|
||||||
if ((archive_headers->Name[0] == '/' &&
|
|
||||||
archive_headers->Name[1] != '\x20' &&
|
|
||||||
archive_headers->Name[1] != '/') || archive_headers->Name[0] != '/')
|
|
||||||
{
|
|
||||||
const auto obj_size = std::atoi(
|
|
||||||
reinterpret_cast<const char*>(archive_headers->Size));
|
|
||||||
|
|
||||||
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!obj_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto obj_begin = reinterpret_cast<void*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> obj{};
|
|
||||||
obj.resize(obj_size);
|
|
||||||
|
|
||||||
memcpy(obj.data(), obj_begin, obj_size);
|
|
||||||
objs.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
std::atoi(reinterpret_cast<char*>(
|
|
||||||
archive_headers->Size)) + sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace section
|
|
||||||
{
|
|
||||||
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, section_name, strlen(section_name) - 1))
|
|
||||||
return section_headers + idx;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!callback(section_headers + idx, obj))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace sym
|
|
||||||
{
|
|
||||||
auto get_relocs(obj_buffer_t& obj) -> std::vector<image_reloc_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<image_reloc_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
{
|
|
||||||
if (section_headers[idx].PointerToRelocations)
|
|
||||||
{
|
|
||||||
// for some reason the compiler makes some empty sections...
|
|
||||||
if (!section_headers[idx].SizeOfRawData)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over sections that we will not be using...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_LNK_REMOVE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over discardable sections...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip both the .pdata and the .xdata sections... these are used for exceptions...
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".pdata", strlen(".pdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".xdata", strlen(".xdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto reloc_dir =
|
|
||||||
reinterpret_cast<PIMAGE_RELOCATION>(
|
|
||||||
section_headers[idx].PointerToRelocations + obj.data());
|
|
||||||
|
|
||||||
for (auto reloc_idx = 0u; reloc_idx <
|
|
||||||
section_headers[idx].NumberOfRelocations; ++reloc_idx)
|
|
||||||
{
|
|
||||||
image_reloc_t entry;
|
|
||||||
entry.file_offset =
|
|
||||||
reloc_dir[reloc_idx].VirtualAddress +
|
|
||||||
section_headers[idx].PointerToRawData;
|
|
||||||
|
|
||||||
if (symbol_table[reloc_dir[reloc_idx].SymbolTableIndex].N.Name.Short)
|
|
||||||
entry.resolve_symbol_name =
|
|
||||||
std::string((char*)symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.ShortName);
|
|
||||||
else
|
|
||||||
entry.resolve_symbol_name = std::string(
|
|
||||||
string_table + symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.Name.Long);
|
|
||||||
|
|
||||||
entry.type = reloc_dir[reloc_idx].Type;
|
|
||||||
result.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<symbol_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
{
|
|
||||||
// skip section symbols... we only want
|
|
||||||
// .data, .rdata, and executable (function) symbols...
|
|
||||||
if (symbol_table[idx].StorageClass != IMAGE_SYM_CLASS_EXTERNAL
|
|
||||||
|| !symbol_table[idx].SectionNumber)
|
|
||||||
{
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_t symbol;
|
|
||||||
if (symbol_table[idx].N.Name.Short)
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string((char*)symbol_table[idx].N.ShortName);
|
|
||||||
else
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string(string_table +
|
|
||||||
symbol_table[idx].N.Name.Long);
|
|
||||||
|
|
||||||
symbol.file_offset = section_headers[symbol_table[
|
|
||||||
idx].SectionNumber - 1].PointerToRawData + symbol_table[idx].Value;
|
|
||||||
|
|
||||||
symbol.section_number = symbol_table[idx].SectionNumber;
|
|
||||||
symbol.section_offset = symbol_table[idx].Value;
|
|
||||||
symbol.type = symbol_table[idx].Type;
|
|
||||||
symbol.size = get_symbol_size(symbol, obj);
|
|
||||||
|
|
||||||
const auto section_name =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
section_headers[symbol_table[idx].SectionNumber - 1].Name);
|
|
||||||
|
|
||||||
if (!strncmp(section_name, ".theo2", sizeof(".theo2") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::encrypt;
|
|
||||||
else if (!strncmp(section_name, ".theo1", sizeof(".theo1") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::mutate;
|
|
||||||
else if (!strncmp(section_name, ".theo", sizeof(".theo") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::obfuscate;
|
|
||||||
else
|
|
||||||
symbol.obfuscate_type = (theo_type)NULL;
|
|
||||||
|
|
||||||
// there can be more then one aux symbols...
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
result.push_back(symbol);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,301 +0,0 @@
|
|||||||
#include "linker.hpp"
|
|
||||||
|
|
||||||
namespace lnk
|
|
||||||
{
|
|
||||||
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
std::uint32_t result =
|
|
||||||
section_headers[sym.section_number - 1].SizeOfRawData;
|
|
||||||
|
|
||||||
// loop over all symbols in this object...
|
|
||||||
// find the next symbol inside of the same section...
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
if (symbol_table[idx].SectionNumber == sym.section_number)
|
|
||||||
if (symbol_table[idx].Value > sym.section_offset && symbol_table[idx].Value < result)
|
|
||||||
result = symbol_table[idx].Value;
|
|
||||||
|
|
||||||
return result - sym.section_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_map_symbols(std::string map_path) -> map_symbols_t
|
|
||||||
{
|
|
||||||
std::ifstream map_file(map_path);
|
|
||||||
|
|
||||||
if (!map_file.is_open())
|
|
||||||
return { {}, {} };
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
map_symbols_t result;
|
|
||||||
while (std::getline(map_file, line))
|
|
||||||
{
|
|
||||||
const auto colon_index = line.find(":");
|
|
||||||
if (colon_index == std::string::npos)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto section_number =
|
|
||||||
std::strtoul(line.substr(1,
|
|
||||||
colon_index).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
const auto section_offset =
|
|
||||||
std::strtoull(line.substr(
|
|
||||||
colon_index + 1, 16).c_str(), NULL, 16);
|
|
||||||
|
|
||||||
auto symbol = line.substr(
|
|
||||||
colon_index + 16 + 8,
|
|
||||||
line.length() - (colon_index + 16 + 7));
|
|
||||||
|
|
||||||
symbol[symbol.length()] = '\0';
|
|
||||||
result[symbol] = { section_number, section_offset };
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> lib_file;
|
|
||||||
utils::open_binary_file(lib_path, lib_file);
|
|
||||||
|
|
||||||
// archive header magic bytes are not correct...
|
|
||||||
if (strncmp((char*)lib_file.data(),
|
|
||||||
IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto archive_headers =
|
|
||||||
reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
lib_file.data() + sizeof IMAGE_ARCHIVE_START - 1);
|
|
||||||
|
|
||||||
while (reinterpret_cast<std::uint8_t*>(archive_headers) < lib_file.data() + lib_file.size())
|
|
||||||
{
|
|
||||||
// some absolutely fucked up shit I have to
|
|
||||||
// do since the linker is off by 1 sometimes...
|
|
||||||
// this sounds weird... I know it sounds weird... its weird...
|
|
||||||
if (archive_headers->Name[0] == '\n')
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) + 1);
|
|
||||||
|
|
||||||
// refer to https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#archive-member-headers
|
|
||||||
// for details on the "name" field... in short `/` means its a linker header
|
|
||||||
// `//` means that it is the string table, and finally `/n` n being the index into the string table...
|
|
||||||
// so in short: if the first byte isnt a `/` and the second byte is not a space or the first byte
|
|
||||||
// is not a forward slash then this archive header is for an obj...
|
|
||||||
if ((archive_headers->Name[0] == '/' &&
|
|
||||||
archive_headers->Name[1] != '\x20' &&
|
|
||||||
archive_headers->Name[1] != '/') || archive_headers->Name[0] != '/')
|
|
||||||
{
|
|
||||||
const auto obj_size = std::atoi(
|
|
||||||
reinterpret_cast<const char*>(archive_headers->Size));
|
|
||||||
|
|
||||||
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!obj_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const auto obj_begin = reinterpret_cast<void*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> obj{};
|
|
||||||
obj.resize(obj_size);
|
|
||||||
|
|
||||||
memcpy(obj.data(), obj_begin, obj_size);
|
|
||||||
objs.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
archive_headers = reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(archive_headers) +
|
|
||||||
std::atoi(reinterpret_cast<char*>(
|
|
||||||
archive_headers->Size)) + sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace section
|
|
||||||
{
|
|
||||||
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, section_name, strlen(section_name) - 1))
|
|
||||||
return section_headers + idx;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
if (!callback(section_headers + idx, obj))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace sym
|
|
||||||
{
|
|
||||||
auto get_relocs(obj_buffer_t& obj) -> std::vector<image_reloc_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<image_reloc_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSections; ++idx)
|
|
||||||
{
|
|
||||||
if (section_headers[idx].PointerToRelocations)
|
|
||||||
{
|
|
||||||
// for some reason the compiler makes some empty sections...
|
|
||||||
if (!section_headers[idx].SizeOfRawData)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over sections that we will not be using...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_LNK_REMOVE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip over discardable sections...
|
|
||||||
if (section_headers[idx].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip both the .pdata and the .xdata sections... these are used for exceptions...
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".pdata", strlen(".pdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!strncmp((char*)section_headers[idx].Name, ".xdata", strlen(".xdata") - 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto reloc_dir =
|
|
||||||
reinterpret_cast<PIMAGE_RELOCATION>(
|
|
||||||
section_headers[idx].PointerToRelocations + obj.data());
|
|
||||||
|
|
||||||
for (auto reloc_idx = 0u; reloc_idx <
|
|
||||||
section_headers[idx].NumberOfRelocations; ++reloc_idx)
|
|
||||||
{
|
|
||||||
image_reloc_t entry;
|
|
||||||
entry.file_offset =
|
|
||||||
reloc_dir[reloc_idx].VirtualAddress +
|
|
||||||
section_headers[idx].PointerToRawData;
|
|
||||||
|
|
||||||
if (symbol_table[reloc_dir[reloc_idx].SymbolTableIndex].N.Name.Short)
|
|
||||||
entry.resolve_symbol_name =
|
|
||||||
std::string((char*)symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.ShortName);
|
|
||||||
else
|
|
||||||
entry.resolve_symbol_name = std::string(
|
|
||||||
string_table + symbol_table[reloc_dir[
|
|
||||||
reloc_idx].SymbolTableIndex].N.Name.Long);
|
|
||||||
|
|
||||||
entry.type = reloc_dir[reloc_idx].Type;
|
|
||||||
result.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>
|
|
||||||
{
|
|
||||||
const auto coff_header =
|
|
||||||
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
|
|
||||||
|
|
||||||
const auto section_headers =
|
|
||||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
obj.data() + sizeof IMAGE_FILE_HEADER);
|
|
||||||
|
|
||||||
const auto symbol_table =
|
|
||||||
reinterpret_cast<PIMAGE_SYMBOL>(
|
|
||||||
coff_header->PointerToSymbolTable + obj.data());
|
|
||||||
|
|
||||||
const auto string_table =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
reinterpret_cast<std::uintptr_t>(symbol_table) +
|
|
||||||
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
|
|
||||||
|
|
||||||
std::vector<symbol_t> result;
|
|
||||||
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
|
|
||||||
{
|
|
||||||
// skip section symbols... we only want
|
|
||||||
// .data, .rdata, and executable (function) symbols...
|
|
||||||
if (symbol_table[idx].StorageClass != IMAGE_SYM_CLASS_EXTERNAL
|
|
||||||
|| !symbol_table[idx].SectionNumber)
|
|
||||||
{
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_t symbol;
|
|
||||||
if (symbol_table[idx].N.Name.Short)
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string((char*)symbol_table[idx].N.ShortName);
|
|
||||||
else
|
|
||||||
symbol.symbol_name =
|
|
||||||
std::string(string_table +
|
|
||||||
symbol_table[idx].N.Name.Long);
|
|
||||||
|
|
||||||
symbol.file_offset = section_headers[symbol_table[
|
|
||||||
idx].SectionNumber - 1].PointerToRawData + symbol_table[idx].Value;
|
|
||||||
|
|
||||||
symbol.section_number = symbol_table[idx].SectionNumber;
|
|
||||||
symbol.section_offset = symbol_table[idx].Value;
|
|
||||||
symbol.type = symbol_table[idx].Type;
|
|
||||||
symbol.size = get_symbol_size(symbol, obj);
|
|
||||||
|
|
||||||
const auto section_name =
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
section_headers[symbol_table[idx].SectionNumber - 1].Name);
|
|
||||||
|
|
||||||
if (!strncmp(section_name, ".theo2", sizeof(".theo2") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::encrypt;
|
|
||||||
else if (!strncmp(section_name, ".theo1", sizeof(".theo1") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::mutate;
|
|
||||||
else if (!strncmp(section_name, ".theo", sizeof(".theo") - 1))
|
|
||||||
symbol.obfuscate_type = theo_type::obfuscate;
|
|
||||||
else
|
|
||||||
symbol.obfuscate_type = (theo_type)NULL;
|
|
||||||
|
|
||||||
// there can be more then one aux symbols...
|
|
||||||
if (symbol_table[idx].NumberOfAuxSymbols)
|
|
||||||
idx += symbol_table[idx].NumberOfAuxSymbols;
|
|
||||||
|
|
||||||
result.push_back(symbol);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue