starting to add documentation

- moved obf engine stuff out of theo and into the demo
- started to document theo and how to use it
- TODO: make a demo pass...
master
_xeroxz 2 years ago
parent f1f808081b
commit 8b7229ac75

@ -2,25 +2,56 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <map> #include <map>
#include <vector>
#include <optional> #include <optional>
#include <vector>
#include <decomp/symbol.hpp> #include <decomp/symbol.hpp>
namespace theo::recomp { namespace theo::recomp {
/// <summary>
/// this class is a high level wrapper for a hashmap that contains
/// decomp::symbol_t values. the symbol values are references by a hashcode.
/// </summary>
class symbol_table_t { class symbol_table_t {
public: public:
/// <summary>
/// default constructor. does nothing.
/// </summary>
symbol_table_t() {} symbol_table_t() {}
/// <summary>
/// this constructor will populate the m_table private field with symbols.
/// </summary>
/// <param name="syms">vector of decomp::symbol_t</param>
symbol_table_t(const std::vector<decomp::symbol_t>&& syms); symbol_table_t(const std::vector<decomp::symbol_t>&& syms);
void add_symbol(decomp::symbol_t& sym); /// <summary>
void add_symbols(std::vector<decomp::symbol_t>& syms); /// add symbol to m_table
/// </summary>
/// <param name="sym">symbol to be added.</param>
void put_symbol(decomp::symbol_t& sym);
/// <summary>
/// add a vector of symbol to m_table
/// </summary>
/// <param name="syms"></param>
void put_symbols(std::vector<decomp::symbol_t>& syms);
/// <summary>
/// returns an optional pointer to a symbol from the symbol table given the symbols hash (hash of its name)
/// the hash is produced by theo::decomp::symbol_t::hash
/// </summary>
/// <param name="hash">hashcode of the symbol to get from the symbol table...</param>
/// <returns>returns an optional pointer to a theo::decomp::symbol_t</returns>
std::optional<decomp::symbol_t*> sym_from_hash(std::size_t hash); std::optional<decomp::symbol_t*> sym_from_hash(std::size_t hash);
std::optional<decomp::symbol_t*> sym_from_alloc(std::uintptr_t allocated_at);
void update(std::size_t hash, decomp::symbol_t& sym); /// <summary>
void update(std::size_t hash, std::uintptr_t allocated_at); /// returns an optional pointer to a symbol given its allocation location.
/// </summary>
/// <param name="allocated_at">the address where the symbol is allocated at.</param>
/// <returns>returns an optional pointer to a theo::decomp::symbol_t</returns>
std::optional<decomp::symbol_t*> sym_from_alloc(std::uintptr_t allocated_at);
void for_each(std::function<void(decomp::symbol_t& sym)> fn); void for_each(std::function<void(decomp::symbol_t& sym)> fn);
std::uint32_t size(); std::uint32_t size();
@ -28,4 +59,4 @@ class symbol_table_t {
private: private:
std::map<std::size_t, decomp::symbol_t> m_table; std::map<std::size_t, decomp::symbol_t> m_table;
}; };
} // namespace theo::comp } // namespace theo::recomp

@ -19,18 +19,54 @@ extern "C" {
#include <xed-interface.h> #include <xed-interface.h>
} }
/// <summary>
/// The outer most encompassing namespace of this project.
/// </summary>
namespace theo { namespace theo {
/// <summary>
/// tuple of functions used by theo to allocate, copy, and resolve symbols.
/// </summary>
using lnk_fns_t = using lnk_fns_t =
std::tuple<recomp::allocator_t, recomp::copier_t, recomp::resolver_t>; std::tuple<recomp::allocator_t, recomp::copier_t, recomp::resolver_t>;
/// <summary>
/// the main class which encapsulates a symbol table, decomp, and recomp
/// objects. This class is a bridge that connects all three: decomp, obf,
/// recomp.
///
/// You will create an object of this type when using theo.
/// </summary>
class theo_t { class theo_t {
public: public:
/// <summary>
/// explicit constructor for theo class.
/// </summary>
/// <param name="lib">a vector of bytes consisting of a lib</param>
/// <param name="lnkr_fns"></param>
/// <param name="entry_sym">the name of the function which will be used as the entry point</param>
explicit theo_t(std::vector<std::uint8_t>& lib, explicit theo_t(std::vector<std::uint8_t>& lib,
lnk_fns_t lnkr_fns, lnk_fns_t lnkr_fns,
const std::string&& entry_sym); const std::string&& entry_sym);
/// <summary>
/// decomposes the lib file and return the number of symbols that are used.
/// </summary>
/// <returns>optional amount of symbols that are used. no value if decomposition fails.</returns>
std::optional<std::uint32_t> decompose(); std::optional<std::uint32_t> decompose();
/// <summary>
/// compose the decomposed module. This will run obfuscation passes, the map and resolve symbols to each other.
/// </summary>
/// <returns>returns the address of the entry point symbol</returns>
std::uintptr_t compose(); std::uintptr_t compose();
/// <summary>
/// given the name of a symbol, it returns the address of where its mapped.
/// </summary>
/// <param name="sym">the name of the symbol</param>
/// <returns>the address of the symbol</returns>
std::uintptr_t resolve(const std::string&& sym); std::uintptr_t resolve(const std::string&& sym);
private: private:

@ -95,7 +95,7 @@ std::optional<recomp::symbol_table_t*> decomp_t::decompose(
decomp::routine_t rtn(sym, img, scn, fn, dcmp_type); decomp::routine_t rtn(sym, img, scn, fn, dcmp_type);
auto syms = rtn.decompose(); auto syms = rtn.decompose();
m_syms->add_symbols(syms); m_syms->put_symbols(syms);
} else if (sym->storage_class == coff::storage_class_id::public_symbol || } else if (sym->storage_class == coff::storage_class_id::public_symbol ||
sym->storage_class == coff::storage_class_id::private_symbol) { sym->storage_class == coff::storage_class_id::private_symbol) {
auto scn = img->get_section(sym->section_index - 1); auto scn = img->get_section(sym->section_index - 1);
@ -140,7 +140,7 @@ std::optional<recomp::symbol_table_t*> decomp_t::decompose(
decomp::symbol_t new_scn_sym(img, scn_sym_name, 0, scn_data, scn, {}, decomp::symbol_t new_scn_sym(img, scn_sym_name, 0, scn_data, scn, {},
relocs, sym_type_t::section); relocs, sym_type_t::section);
m_syms->add_symbol(new_scn_sym); m_syms->put_symbol(new_scn_sym);
} }
// create a symbol for the data... // create a symbol for the data...
@ -149,7 +149,7 @@ std::optional<recomp::symbol_table_t*> decomp_t::decompose(
sym->value, {}, scn, sym, {}, sym->value, {}, scn, sym, {},
sym_type_t::data); sym_type_t::data);
m_syms->add_symbol(new_sym); m_syms->put_symbol(new_sym);
} }
} else if (sym->storage_class == } else if (sym->storage_class ==
coff::storage_class_id:: coff::storage_class_id::
@ -162,7 +162,7 @@ std::optional<recomp::symbol_table_t*> decomp_t::decompose(
decomp::symbol_t bss_sym(img, symbol_t::name(img, sym).data(), {}, data, decomp::symbol_t bss_sym(img, symbol_t::name(img, sym).data(), {}, data,
{}, sym, {}, sym_type_t::data); {}, sym, {}, sym_type_t::data);
m_syms->add_symbol(bss_sym); m_syms->put_symbol(bss_sym);
} }
}); });
@ -189,8 +189,8 @@ std::uint32_t decomp_t::next_sym(coff::image_t* img,
} }
std::uint32_t decomp_t::ext_used_syms(const std::string&& entry_sym) { std::uint32_t decomp_t::ext_used_syms(const std::string&& entry_sym) {
std::optional<sym_data_t> entry; std::optional<sym_data_t> entry = get_symbol(entry_sym.data());
if (!(entry = get_symbol(entry_sym.data())).has_value()) if (!entry.has_value())
return 0u; return 0u;
std::set<coff::symbol_t*> cache; std::set<coff::symbol_t*> cache;
@ -241,7 +241,11 @@ std::optional<sym_data_t> decomp_t::get_symbol(const std::string_view& name) {
if (sym->has_section()) if (sym->has_section())
return {{img, sym, size}}; return {{img, sym, size}};
} }
return {{img, sym, size}};
if (img && sym)
return {{img, sym, size}};
return {};
} }
std::vector<routine_t> decomp_t::rtns() { std::vector<routine_t> decomp_t::rtns() {

@ -7,23 +7,13 @@ symbol_table_t::symbol_table_t(const std::vector<decomp::symbol_t>&& syms) {
}); });
} }
void symbol_table_t::add_symbol(decomp::symbol_t& sym) { void symbol_table_t::put_symbol(decomp::symbol_t& sym) {
m_table.insert({sym.hash(), sym}); m_table.insert({sym.hash(), sym});
} }
void symbol_table_t::add_symbols(std::vector<decomp::symbol_t>& syms) { void symbol_table_t::put_symbols(std::vector<decomp::symbol_t>& syms) {
std::for_each(syms.begin(), syms.end(), std::for_each(syms.begin(), syms.end(),
[&](decomp::symbol_t sym) { add_symbol(sym); }); [&](decomp::symbol_t sym) { put_symbol(sym); });
}
void symbol_table_t::update(std::size_t hash, decomp::symbol_t& sym) {
m_table.insert({hash, sym});
}
void symbol_table_t::update(std::size_t hash, std::uintptr_t allocated_at) {
auto v = m_table.at(hash);
v.allocated_at(allocated_at);
m_table.insert({hash, v});
} }
void symbol_table_t::for_each(std::function<void(decomp::symbol_t& sym)> fn) { void symbol_table_t::for_each(std::function<void(decomp::symbol_t& sym)> fn) {

@ -5,20 +5,6 @@ theo_t::theo_t(std::vector<std::uint8_t>& lib,
lnk_fns_t lnkr_fns, lnk_fns_t lnkr_fns,
const std::string&& entry_sym) const std::string&& entry_sym)
: m_dcmp(lib, &m_sym_tbl), m_recmp(&m_dcmp), m_entry_sym(entry_sym) { : m_dcmp(lib, &m_sym_tbl), m_recmp(&m_dcmp), m_entry_sym(entry_sym) {
// init enc/dec tables only once... add obfuscation passes to the engine...
//
if (static std::atomic_bool v = true; v.exchange(false)) {
xed_tables_init();
// order matters, the order in which the pass is added is the order they
// will be executed!
//
auto engine = obf::engine_t::get();
engine->add_pass(obf::reloc_transform_pass_t::get());
engine->add_pass(obf::next_inst_pass_t::get());
engine->add_pass(obf::jcc_rewrite_pass_t::get());
}
m_recmp.allocator(std::get<0>(lnkr_fns)); m_recmp.allocator(std::get<0>(lnkr_fns));
m_recmp.copier(std::get<1>(lnkr_fns)); m_recmp.copier(std::get<1>(lnkr_fns));
m_recmp.resolver(std::get<2>(lnkr_fns)); m_recmp.resolver(std::get<2>(lnkr_fns));
@ -48,8 +34,10 @@ std::uintptr_t theo_t::compose() {
} }
std::uintptr_t theo_t::resolve(const std::string&& sym) { std::uintptr_t theo_t::resolve(const std::string&& sym) {
return m_sym_tbl.sym_from_hash(decomp::symbol_t::hash(sym)) auto val = m_sym_tbl.sym_from_hash(decomp::symbol_t::hash(sym));
.value() if (!val.has_value())
->allocated_at(); return {};
return val.value()->allocated_at();
} }
} // namespace theo } // namespace theo

@ -3,10 +3,16 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <iostream>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <theo.hpp> #include <theo.hpp>
#include <obf/engine.hpp>
#include <obf/passes/jcc_rewrite_pass.hpp>
#include <obf/passes/next_inst_pass.hpp>
#include <obf/passes/reloc_transform_pass.hpp>
namespace fs = std::filesystem; namespace fs = std::filesystem;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@ -56,7 +62,24 @@ int main(int argc, char* argv[]) {
return result; return result;
}; };
theo::theo_t t(fdata, {allocator, copier, resolver}, "main"); // init enc/dec tables only once... important that this is done before adding
// obfuscation passes to the engine...
//
xed_tables_init();
// order matters, the order in which the pass is added is the order they
// will be executed!
//
auto engine = theo::obf::engine_t::get();
engine->add_pass(theo::obf::reloc_transform_pass_t::get());
engine->add_pass(theo::obf::next_inst_pass_t::get());
engine->add_pass(theo::obf::jcc_rewrite_pass_t::get());
std::string entry_name;
std::cout << "enter the name of the entry point: ";
std::cin >> entry_name;
theo::theo_t t(fdata, {allocator, copier, resolver}, entry_name.data());
auto res = t.decompose(); auto res = t.decompose();
if (!res.has_value()) { if (!res.has_value()) {
@ -66,7 +89,8 @@ int main(int argc, char* argv[]) {
spdlog::info("decomposed {} symbols...", res.value()); spdlog::info("decomposed {} symbols...", res.value());
auto entry_pnt = t.compose(); auto entry_pnt = t.compose();
spdlog::info("entry point address: {:X}", entry_pnt); spdlog::info("entry point address: {:X}, press enter to execute it...",
std::getchar(); entry_pnt);
reinterpret_cast<void (*)()>(entry_pnt)(); reinterpret_cast<void (*)()>(entry_pnt)();
} }

@ -52,7 +52,7 @@ if(WIN32) # windows
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${demolib_SOURCES}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${demolib_SOURCES})
target_compile_options(demolib PUBLIC target_compile_options(demolib PUBLIC
"-Xclang -mcmodel=large" "-Xclang -mcmodel=large -Xclang -fno-jump-tables /Zc:threadSafeInit-"
) )
unset(CMKR_TARGET) unset(CMKR_TARGET)

@ -5,4 +5,4 @@ name = "demolib"
condition = "windows" condition = "windows"
type = "static" type = "static"
sources = ["*.cpp"] sources = ["*.cpp"]
compile-options = ["-Xclang -mcmodel=large"] compile-options = ["-Xclang -mcmodel=large -Xclang -fno-jump-tables /Zc:threadSafeInit-"]
Loading…
Cancel
Save