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();