expanded the pass system, added more places where passes can run...

master
_xeroxz 3 years ago
parent 96c238e24f
commit d744c6b585

@ -35,6 +35,11 @@
namespace theo::obf {
/// <summary>
/// callback used by obfuscation engine to run passes...
/// </summary>
using engine_callback_t = std::function<void(decomp::symbol_t*, pass_t*)>;
/// <summary>
/// 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);
/// <summary>
/// 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.
/// </summary>
/// <param name="sym">symbol to run all passes on.</param>
void run(decomp::symbol_t* sym);
/// <param name="callback">callback to be invoked. the callback is given a
/// pointer to the pass.</param>
/// <param name="sym">symbol to run callbacks on.</param>
void for_each(decomp::symbol_t* sym, engine_callback_t callback);
private:
std::vector<pass_t*> passes;

@ -44,6 +44,21 @@ extern "C" {
/// </summary>
namespace theo::obf {
/// <summary>
/// a function which is called by recomp_t to copy symbols into memory.
/// </summary>
using copier_t = std::function<void(std::uintptr_t, void*, std::uint32_t)>;
/// <summary>
/// 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.
/// </summary>
using allocator_t =
std::function<std::uintptr_t(std::uint32_t,
coff::section_characteristics_t)>;
/// <summary>
/// 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 {
/// <param name="sym">The symbol that memory is being allocated for.</param>
/// <param name="size">The size of the symbol that memory is being allocated
/// for.</param>
/// <returns>returns the size of the symbol.</returns>
virtual std::uint32_t pre_allocation_pass(decomp::symbol_t* sym,
std::uint32_t size) = 0;
/// <returns>returns the optional address of the allocation, if the pass didnt
/// allocate space for the symbol than this optional value will have no
/// value.</returns>
virtual std::optional<std::uintptr_t> allocation_pass(
decomp::symbol_t* sym,
std::uint32_t size,
allocator_t& allocator) = 0;
/// <summary>
/// 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.
/// </summary>
/// <param name="dest">Allocation address (can be linear virtual address or
/// file offset address)</param>
/// <param name="sym">The symbol for which allocation was made for.</param>
/// <param name="size">Size of the allocation.</param>
virtual void post_allocation_pass(decomp::symbol_t* sym,
std::uintptr_t dest,
std::uint32_t size) = 0;
/// <param name="sym">Symbol being copied into memory.</param>
/// <param name="copier">copier lambda that the pass can use. if it does, then
/// you must return true.</param> <returns>returns true if the copy was done
/// by the pass. false if copying still needs to be done.</returns>
virtual bool copier_pass(decomp::symbol_t* sym, copier_t& copier) = 0;
/// <summary>
/// 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.
/// </summary>
/// <param name="sym">Symbol being copied into memory...</param>
/// <param name="dest">Memory destination of the copy...</param>
/// <param name="size"></param>
/// <param name="sym">The symbol that has the relocation inside of it.</param>
/// <param name="reloc">The relocation be be applied.</param>
/// <param name="allocated_t">The address of the symbol pointed too by the
/// relocation.</param>
/// <returns></returns>
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<std::uintptr_t> resolver_pass(
decomp::symbol_t* sym,
recomp::reloc_t* reloc,
std::uintptr_t allocated_t) = 0;
/// <summary>
/// gets the passes symbol type.

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

@ -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<std::uintptr_t*>(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<obf::transform::transform_t*, std::uint32_t>& t) {
allocated_at = (*t.first)(allocated_at, t.second);
});
*reinterpret_cast<std::uintptr_t*>(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());
});
}

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

Loading…
Cancel
Save