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

master
_xeroxz 2 years ago
parent 96c238e24f
commit d744c6b585

@ -35,6 +35,11 @@
namespace theo::obf { 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> /// <summary>
/// singleton obfuscation engine class. this class is responsible for keeping /// singleton obfuscation engine class. this class is responsible for keeping
/// track of the registered passes and the order in which to execute them. /// 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); void add_pass(pass_t* pass);
/// <summary> /// <summary>
/// run all the passes on the symbol. this function will only run a pass if /// invokes the callback for each pass in order.
/// the symbol is the same type as the pass requires.
/// </summary> /// </summary>
/// <param name="sym">symbol to run all passes on.</param> /// <param name="callback">callback to be invoked. the callback is given a
void run(decomp::symbol_t* sym); /// 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: private:
std::vector<pass_t*> passes; std::vector<pass_t*> passes;

@ -44,6 +44,21 @@ extern "C" {
/// </summary> /// </summary>
namespace theo::obf { 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> /// <summary>
/// the pass_t class is a base clase for all passes made. you must override the /// 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. /// 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="sym">The symbol that memory is being allocated for.</param>
/// <param name="size">The size of the symbol that memory is being allocated /// <param name="size">The size of the symbol that memory is being allocated
/// for.</param> /// for.</param>
/// <returns>returns the size of the symbol.</returns> /// <returns>returns the optional address of the allocation, if the pass didnt
virtual std::uint32_t pre_allocation_pass(decomp::symbol_t* sym, /// allocate space for the symbol than this optional value will have no
std::uint32_t size) = 0; /// value.</returns>
virtual std::optional<std::uintptr_t> allocation_pass(
decomp::symbol_t* sym,
std::uint32_t size,
allocator_t& allocator) = 0;
/// <summary> /// <summary>
/// This virtual method is invoked after the call to the "allocator". This /// This virtual method is invoked prior to calling the "copier". This allows
/// allows you to manipulate the symbol after memory has been allocated for /// you to manipulate the symbol prior to it being copied into memory.
/// it.
/// </summary> /// </summary>
/// <param name="dest">Allocation address (can be linear virtual address or /// <param name="sym">Symbol being copied into memory.</param>
/// file offset address)</param> /// <param name="copier">copier lambda that the pass can use. if it does, then
/// <param name="sym">The symbol for which allocation was made for.</param> /// you must return true.</param> <returns>returns true if the copy was done
/// <param name="size">Size of the allocation.</param> /// by the pass. false if copying still needs to be done.</returns>
virtual void post_allocation_pass(decomp::symbol_t* sym, virtual bool copier_pass(decomp::symbol_t* sym, copier_t& copier) = 0;
std::uintptr_t dest,
std::uint32_t size) = 0;
/// <summary> /// <summary>
/// This virtual method is invoked prior to calling the "copier". This allows /// This virtual method is invoked before the call to the "resolver". This
/// you to manipulate the symbol prior to it being copied into memory. /// allows you the manipulate the relocation address and symbol before
/// relocations are made.
/// </summary> /// </summary>
/// <param name="sym">Symbol being copied into memory...</param> /// <param name="sym">The symbol that has the relocation inside of it.</param>
/// <param name="dest">Memory destination of the copy...</param> /// <param name="reloc">The relocation be be applied.</param>
/// <param name="size"></param> /// <param name="allocated_t">The address of the symbol pointed too by the
/// relocation.</param>
/// <returns></returns> /// <returns></returns>
virtual std::uintptr_t pre_copier_pass(decomp::symbol_t* sym, virtual std::optional<std::uintptr_t> resolver_pass(
std::uintptr_t dest, decomp::symbol_t* sym,
std::uint32_t size) = 0; recomp::reloc_t* reloc,
std::uintptr_t allocated_t) = 0;
virtual void post_copier_pass() = 0;
virtual void pre_resolver_pass() = 0;
virtual void post_resolver_pass() = 0;
/// <summary> /// <summary>
/// gets the passes symbol type. /// gets the passes symbol type.

@ -40,10 +40,10 @@ void engine_t::add_pass(pass_t* pass) {
passes.push_back(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) { std::for_each(passes.begin(), passes.end(), [&](pass_t* pass) {
if (sym->type() & pass->sym_type()) 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() { void recomp_t::allocate() {
// map code & data/rdata/bss sections first... // 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) { m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
switch (sym.type()) { switch (sym.type()) {
case decomp::sym_type_t::section: case decomp::sym_type_t::section:
case decomp::sym_type_t::function: case decomp::sym_type_t::function:
case decomp::sym_type_t::instruction: { 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; break;
} }
default: default:
@ -83,7 +94,17 @@ void recomp_t::allocate() {
prot.mem_read = true; prot.mem_read = true;
prot.mem_write = 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() ? reloc_sym.value()->allocated_at()
: m_resolver(reloc.name()); : 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) { if (!allocated_at) {
spdlog::error("failed to resolve reloc from symbol: {} to symbol: {}", spdlog::error("failed to resolve reloc from symbol: {} to symbol: {}",
sym.name(), reloc.name()); sym.name(), reloc.name());
@ -128,23 +158,12 @@ void recomp_t::resolve() {
reloc.offset()) = allocated_at; reloc.offset()) = allocated_at;
break; break;
} }
case decomp::sym_type_t::instruction:
case decomp::sym_type_t::function: { case decomp::sym_type_t::function: {
*reinterpret_cast<std::uintptr_t*>(sym.data().data() + *reinterpret_cast<std::uintptr_t*>(sym.data().data() +
reloc.offset()) = allocated_at; reloc.offset()) = allocated_at;
break; 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: default:
break; break;
} }
@ -155,8 +174,19 @@ void recomp_t::resolve() {
void recomp_t::copy_syms() { void recomp_t::copy_syms() {
// copy symbols into memory using the copier supplied... // 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_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... // run obfuscation engine on all symbols...
// //
auto engine = obf::engine_t::get(); 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.allocate();
m_recmp.resolve(); m_recmp.resolve();

Loading…
Cancel
Save