diff --git a/include/obf/engine.hpp b/include/obf/engine.hpp index 2f3f574..73f6a44 100644 --- a/include/obf/engine.hpp +++ b/include/obf/engine.hpp @@ -35,6 +35,11 @@ namespace theo::obf { +/// +/// callback used by obfuscation engine to run passes... +/// +using engine_callback_t = std::function; + /// /// singleton obfuscation engine class. this class is responsible for keeping /// track of the registered passes and the order in which to execute them. @@ -59,11 +64,12 @@ class engine_t { void add_pass(pass_t* pass); /// - /// run all the passes on the symbol. this function will only run a pass if - /// the symbol is the same type as the pass requires. + /// invokes the callback for each pass in order. /// - /// symbol to run all passes on. - void run(decomp::symbol_t* sym); + /// callback to be invoked. the callback is given a + /// pointer to the pass. + /// symbol to run callbacks on. + void for_each(decomp::symbol_t* sym, engine_callback_t callback); private: std::vector passes; diff --git a/include/obf/pass.hpp b/include/obf/pass.hpp index 0c9088f..a3f0a30 100644 --- a/include/obf/pass.hpp +++ b/include/obf/pass.hpp @@ -44,6 +44,21 @@ extern "C" { /// namespace theo::obf { +/// +/// a function which is called by recomp_t to copy symbols into memory. +/// +using copier_t = std::function; + +/// +/// a function which is called to allocate space for a symbol. +/// +/// the first param is the size of the symbol, the second param is the +/// characteristics of the section which the symbol is allocated in. +/// +using allocator_t = + std::function; + /// /// the pass_t class is a base clase for all passes made. you must override the /// pass_t::run virtual function and declare the logic of your pass there. @@ -77,39 +92,38 @@ class pass_t { /// The symbol that memory is being allocated for. /// The size of the symbol that memory is being allocated /// for. - /// returns the size of the symbol. - virtual std::uint32_t pre_allocation_pass(decomp::symbol_t* sym, - std::uint32_t size) = 0; + /// returns the optional address of the allocation, if the pass didnt + /// allocate space for the symbol than this optional value will have no + /// value. + virtual std::optional allocation_pass( + decomp::symbol_t* sym, + std::uint32_t size, + allocator_t& allocator) = 0; /// - /// This virtual method is invoked after the call to the "allocator". This - /// allows you to manipulate the symbol after memory has been allocated for - /// it. + /// This virtual method is invoked prior to calling the "copier". This allows + /// you to manipulate the symbol prior to it being copied into memory. /// - /// Allocation address (can be linear virtual address or - /// file offset address) - /// The symbol for which allocation was made for. - /// Size of the allocation. - virtual void post_allocation_pass(decomp::symbol_t* sym, - std::uintptr_t dest, - std::uint32_t size) = 0; + /// Symbol being copied into memory. + /// copier lambda that the pass can use. if it does, then + /// you must return true. returns true if the copy was done + /// by the pass. false if copying still needs to be done. + virtual bool copier_pass(decomp::symbol_t* sym, copier_t& copier) = 0; /// - /// This virtual method is invoked prior to calling the "copier". This allows - /// you to manipulate the symbol prior to it being copied into memory. + /// This virtual method is invoked before the call to the "resolver". This + /// allows you the manipulate the relocation address and symbol before + /// relocations are made. /// - /// Symbol being copied into memory... - /// Memory destination of the copy... - /// + /// The symbol that has the relocation inside of it. + /// The relocation be be applied. + /// The address of the symbol pointed too by the + /// relocation. /// - virtual std::uintptr_t pre_copier_pass(decomp::symbol_t* sym, - std::uintptr_t dest, - std::uint32_t size) = 0; - - virtual void post_copier_pass() = 0; - - virtual void pre_resolver_pass() = 0; - virtual void post_resolver_pass() = 0; + virtual std::optional resolver_pass( + decomp::symbol_t* sym, + recomp::reloc_t* reloc, + std::uintptr_t allocated_t) = 0; /// /// gets the passes symbol type. diff --git a/src/obf/engine.cpp b/src/obf/engine.cpp index 37b7b81..0cce9a5 100644 --- a/src/obf/engine.cpp +++ b/src/obf/engine.cpp @@ -40,10 +40,10 @@ void engine_t::add_pass(pass_t* pass) { passes.push_back(pass); } -void engine_t::run(decomp::symbol_t* sym) { +void engine_t::for_each(decomp::symbol_t* sym, engine_callback_t callback) { std::for_each(passes.begin(), passes.end(), [&](pass_t* pass) { if (sym->type() & pass->sym_type()) - pass->run(sym); + callback(sym, pass); }); } diff --git a/src/recomp/recomp.cpp b/src/recomp/recomp.cpp index eb6b166..9b92f65 100644 --- a/src/recomp/recomp.cpp +++ b/src/recomp/recomp.cpp @@ -40,12 +40,23 @@ recomp_t::recomp_t(decomp::decomp_t* dcmp, void recomp_t::allocate() { // map code & data/rdata/bss sections first... // + static const auto engine = obf::engine_t::get(); m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) { switch (sym.type()) { case decomp::sym_type_t::section: case decomp::sym_type_t::function: case decomp::sym_type_t::instruction: { - sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics)); + engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) { + if (sym->allocated_at()) + return; + + auto res = pass->allocation_pass(sym, sym->size(), m_allocator); + if (res.has_value()) + sym->allocated_at(res.value()); + }); + + if (!sym.allocated_at()) + sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics)); break; } default: @@ -83,7 +94,17 @@ void recomp_t::allocate() { prot.mem_read = true; prot.mem_write = true; - sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics)); + engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) { + if (sym->allocated_at()) + return; + + auto res = pass->allocation_pass(sym, sym->size(), m_allocator); + if (res.has_value()) + sym->allocated_at(res.value()); + }); + + if (!sym.allocated_at()) + sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics)); } } }); @@ -112,6 +133,15 @@ void recomp_t::resolve() { ? reloc_sym.value()->allocated_at() : m_resolver(reloc.name()); + // run passes related to post symbol relocation... + // + static const auto engine = obf::engine_t::get(); + engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) { + auto res = pass->resolver_pass(sym, &reloc, allocated_at); + if (res.has_value()) + allocated_at = res.value(); + }); + if (!allocated_at) { spdlog::error("failed to resolve reloc from symbol: {} to symbol: {}", sym.name(), reloc.name()); @@ -128,23 +158,12 @@ void recomp_t::resolve() { reloc.offset()) = allocated_at; break; } + case decomp::sym_type_t::instruction: case decomp::sym_type_t::function: { *reinterpret_cast(sym.data().data() + reloc.offset()) = allocated_at; break; } - case decomp::sym_type_t::instruction: { - auto& transforms = reloc.get_transforms(); - std::for_each( - transforms.begin(), transforms.end(), - [&](std::pair& t) { - allocated_at = (*t.first)(allocated_at, t.second); - }); - - *reinterpret_cast(sym.data().data() + - reloc.offset()) = allocated_at; - break; - } default: break; } @@ -155,8 +174,19 @@ void recomp_t::resolve() { void recomp_t::copy_syms() { // copy symbols into memory using the copier supplied... // + static const auto engine = obf::engine_t::get(); m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) { - m_copier(sym.allocated_at(), sym.data().data(), sym.data().size()); + bool cpy = false; + engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) { + if (cpy) + return; + // returns true if the copy was done for this symbol... + // + cpy = pass->copier_pass(sym, m_copier); + }); + + if (!cpy) + m_copier(sym.allocated_at(), sym.data().data(), sym.data().size()); }); } diff --git a/src/theo.cpp b/src/theo.cpp index ef00722..90afaa3 100644 --- a/src/theo.cpp +++ b/src/theo.cpp @@ -57,7 +57,11 @@ std::uintptr_t theo_t::compose() { // run obfuscation engine on all symbols... // auto engine = obf::engine_t::get(); - m_sym_tbl.for_each([&](decomp::symbol_t& sym) { engine->run(&sym); }); + m_sym_tbl.for_each([&](decomp::symbol_t& sym) { + engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) { + pass->pre_recomp_pass(sym); + }); + }); m_recmp.allocate(); m_recmp.resolve();