removed linker.cpp from demo file, fixed how i parse libs

2.0
_xeroxz 4 years ago
parent f1a6393e00
commit 0c421e5050

@ -85,13 +85,12 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="linker\linker.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="msrexec.cpp" /> <ClCompile Include="msrexec.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="ia32.hpp" /> <ClInclude Include="ia32.hpp" />
<ClInclude Include="linker\linker.hpp" /> <ClInclude Include="linker.hpp" />
<ClInclude Include="loadup.hpp" /> <ClInclude Include="loadup.hpp" />
<ClInclude Include="msrexec.hpp" /> <ClInclude Include="msrexec.hpp" />
<ClInclude Include="raw_driver.hpp" /> <ClInclude Include="raw_driver.hpp" />

@ -14,9 +14,6 @@
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="linker\linker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="msrexec.cpp"> <ClCompile Include="msrexec.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -28,9 +25,6 @@
<ClInclude Include="loadup.hpp"> <ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="linker\linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp"> <ClInclude Include="utils.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -49,6 +43,9 @@
<ClInclude Include="theo.h"> <ClInclude Include="theo.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MASM Include="syscall_handler.asm"> <MASM Include="syscall_handler.asm">

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include "../utils.hpp" #include "utils.hpp"
namespace lnk namespace lnk
{ {

@ -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;
}
}
}

@ -3,7 +3,7 @@
#include "vdm.hpp" #include "vdm.hpp"
#include "msrexec.hpp" #include "msrexec.hpp"
#include "theo.h" #include "theo.h"
#include "linker/linker.hpp" #include "linker.hpp"
using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>; using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>;
using objs_buffer_t = std::vector<lnk::obj_buffer_t>; using objs_buffer_t = std::vector<lnk::obj_buffer_t>;

@ -86,13 +86,12 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="linker\linker.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="vdm_ctx\vdm_ctx.cpp" /> <ClCompile Include="vdm_ctx\vdm_ctx.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="linker.hpp" />
<ClInclude Include="loadup.hpp" /> <ClInclude Include="loadup.hpp" />
<ClInclude Include="linker\linker.hpp" />
<ClInclude Include="utils.hpp" /> <ClInclude Include="utils.hpp" />
<ClInclude Include="vdm\raw_driver.hpp" /> <ClInclude Include="vdm\raw_driver.hpp" />
<ClInclude Include="vdm\vdm.hpp" /> <ClInclude Include="vdm\vdm.hpp" />

@ -17,17 +17,11 @@
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="linker\linker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vdm_ctx\vdm_ctx.cpp"> <ClCompile Include="vdm_ctx\vdm_ctx.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="linker\linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp"> <ClInclude Include="utils.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -43,5 +37,8 @@
<ClInclude Include="loadup.hpp"> <ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include "../utils.hpp" #include "utils.hpp"
namespace lnk namespace lnk
{ {

@ -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;
}
}
}

@ -2,7 +2,7 @@
#include <filesystem> #include <filesystem>
#include "theo.h" #include "theo.h"
#include "linker/linker.hpp" #include "linker.hpp"
#include "vdm_ctx/vdm_ctx.hpp" #include "vdm_ctx/vdm_ctx.hpp"
using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>; using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>;

@ -86,11 +86,10 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="linker\linker.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="linker\linker.hpp" /> <ClInclude Include="linker.hpp" />
<ClInclude Include="theo.h" /> <ClInclude Include="theo.h" />
<ClInclude Include="utils.hpp" /> <ClInclude Include="utils.hpp" />
</ItemGroup> </ItemGroup>

@ -14,19 +14,16 @@
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="linker\linker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="linker\linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="theo.h"> <ClInclude Include="theo.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="utils.hpp"> <ClInclude Include="utils.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -6,7 +6,6 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <map> #include <map>
#include "../utils.hpp"
namespace lnk namespace lnk
{ {

@ -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;
}
}
}

@ -4,7 +4,7 @@
#include <filesystem> #include <filesystem>
#include "theo.h" #include "theo.h"
#include "linker/linker.hpp" #include "linker.hpp"
using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>; using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>;
using objs_buffer_t = std::vector<lnk::obj_buffer_t>; using objs_buffer_t = std::vector<lnk::obj_buffer_t>;

@ -220,7 +220,6 @@
<ClInclude Include="asmjit\x86\x86operand.h" /> <ClInclude Include="asmjit\x86\x86operand.h" />
<ClInclude Include="asmjit\x86\x86rapass_p.h" /> <ClInclude Include="asmjit\x86\x86rapass_p.h" />
<ClInclude Include="theo.h" /> <ClInclude Include="theo.h" />
<ClInclude Include="ia32.hpp" />
<ClInclude Include="linker\linker.hpp" /> <ClInclude Include="linker\linker.hpp" />
<ClInclude Include="obfuscation\obfuscation.hpp" /> <ClInclude Include="obfuscation\obfuscation.hpp" />
<ClInclude Include="utils.hpp" /> <ClInclude Include="utils.hpp" />

@ -232,9 +232,6 @@
<ClInclude Include="Zydis\Internal\String.h"> <ClInclude Include="Zydis\Internal\String.h">
<Filter>Header Files\Zydis\Internal</Filter> <Filter>Header Files\Zydis\Internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ia32.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Zydis\Decoder.h"> <ClInclude Include="Zydis\Decoder.h">
<Filter>Header Files\Zydis</Filter> <Filter>Header Files\Zydis</Filter>
</ClInclude> </ClInclude>

File diff suppressed because it is too large Load Diff

@ -1,4 +1,6 @@
#include "linker.hpp" #include "linker.hpp"
using obj_info_t = std::pair<PIMAGE_ARCHIVE_MEMBER_HEADER, std::uint32_t>;
using lib_info_t = std::map<unsigned long, obj_info_t>;
namespace lnk namespace lnk
{ {
@ -66,58 +68,35 @@ namespace lnk
std::vector<std::uint8_t> lib_file; std::vector<std::uint8_t> lib_file;
utils::open_binary_file(lib_path, lib_file); utils::open_binary_file(lib_path, lib_file);
// archive header magic bytes are not correct... if (strncmp(reinterpret_cast<const char*>(lib_file.data()),
if (strncmp((char*)lib_file.data(),
IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1)) IMAGE_ARCHIVE_START, sizeof IMAGE_ARCHIVE_START - 1))
return false; return false;
auto archive_headers = const auto linker_header =
reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>( reinterpret_cast<unsigned long*>(
lib_file.data() + sizeof IMAGE_ARCHIVE_START - 1); lib_file.data() + (sizeof IMAGE_ARCHIVE_START - 1) +
sizeof IMAGE_ARCHIVE_MEMBER_HEADER);
while (reinterpret_cast<std::uint8_t*>(archive_headers) < lib_file.data() + lib_file.size()) lib_info_t offsets;
{ for (auto idx = 1u; idx < _byteswap_ulong(linker_header[0]); ++idx)
// im not doing alignment correctly, i cannot find
// anything online about it either, this "works" for now, but it will probably not
// on other linkers... (linker makes the .lib iirc)
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( const auto archive_header =
reinterpret_cast<const char*>(archive_headers->Size)); reinterpret_cast<PIMAGE_ARCHIVE_MEMBER_HEADER>(
lib_file.data() + _byteswap_ulong(linker_header[idx]));
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
break;
if (!obj_size)
break;
const auto obj_begin = reinterpret_cast<void*>( const auto obj_size = std::atoi(reinterpret_cast<const char*>(archive_header->Size));
reinterpret_cast<std::uintptr_t>(archive_headers) + offsets[_byteswap_ulong(linker_header[idx])] = { archive_header, obj_size };
sizeof IMAGE_ARCHIVE_MEMBER_HEADER); }
std::vector<std::uint8_t> obj{}; for (auto& [file_offset, obj_info] : offsets)
obj.resize(obj_size); {
const auto obj_start = lib_file.data() +
file_offset + sizeof IMAGE_ARCHIVE_MEMBER_HEADER;
memcpy(obj.data(), obj_begin, obj_size); objs.push_back(obj_buffer_t(
objs.push_back(obj); obj_start, obj_start + obj_info.second));
} }
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; return true;
} }

@ -18,7 +18,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include "ia32.hpp"
#define DBG_PRINT(format, ...) \ #define DBG_PRINT(format, ...) \
std::printf(format, __VA_ARGS__ ) std::printf(format, __VA_ARGS__ )

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include "../utils.hpp" #include "utils.hpp"
namespace lnk namespace lnk
{ {

@ -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…
Cancel
Save