created a pass system... starting to code transformation system for

relocations...
3.0
_xeroxz 2 years ago
parent c666bf8dbe
commit 9cf6cc8f03

@ -55,22 +55,33 @@ set(Theodosius_SOURCES "")
list(APPEND Theodosius_SOURCES
"include/comp/comp.hpp"
"include/comp/obf.hpp"
"include/comp/obf/engine.hpp"
"include/comp/obf/pass.hpp"
"include/comp/obf/passes/jcc_rewrite_pass.hpp"
"include/comp/obf/passes/next_inst_pass.hpp"
"include/comp/obf/passes/reloc_transform_pass.hpp"
"include/comp/obf/transform/add_op.hpp"
"include/comp/obf/transform/and_op.hpp"
"include/comp/obf/transform/operation.hpp"
"include/comp/obf/transform/or_op.hpp"
"include/comp/obf/transform/rol_op.hpp"
"include/comp/obf/transform/ror_op.hpp"
"include/comp/obf/transform/sub_op.hpp"
"include/comp/obf/transform/transform.hpp"
"include/comp/obf/transform/xor_op.hpp"
"include/comp/reloc.hpp"
"include/comp/symbol_table.hpp"
"include/comp/transform/add_op.hpp"
"include/comp/transform/and_op.hpp"
"include/comp/transform/operation.hpp"
"include/comp/transform/or_op.hpp"
"include/comp/transform/rol_op.hpp"
"include/comp/transform/ror_op.hpp"
"include/comp/transform/sub_op.hpp"
"include/comp/transform/xor_op.hpp"
"include/decomp/decomp.hpp"
"include/decomp/routine.hpp"
"include/decomp/symbol.hpp"
"include/theo.hpp"
"src/theo/comp/comp.cpp"
"src/theo/comp/obf/engine.cpp"
"src/theo/comp/obf/passes/jcc_rewrite_pass.cpp"
"src/theo/comp/obf/passes/next_inst_pass.cpp"
"src/theo/comp/obf/passes/reloc_transform_pass.cpp"
"src/theo/comp/obf/transform/add_op.cpp"
"src/theo/comp/obf/transform/sub_op.cpp"
"src/theo/comp/symbol_table.cpp"
"src/theo/decomp/decomp.cpp"
"src/theo/decomp/routine.cpp"

@ -1,4 +1,5 @@
#pragma once
#include <comp/obf/engine.hpp>
#include <comp/symbol_table.hpp>
#include <decomp/decomp.hpp>

@ -0,0 +1,18 @@
#pragma once
#include <algorithm>
#include <comp/obf/pass.hpp>
#include <vector>
namespace theo::comp::obf {
class engine_t {
explicit engine_t(){};
public:
static engine_t* get();
void add_pass(pass_t* pass);
void run(decomp::symbol_t* sym);
private:
std::vector<pass_t*> passes;
};
} // namespace theo::comp::obf

@ -0,0 +1,21 @@
#pragma once
#include <spdlog/spdlog.h>
#include <decomp/symbol.hpp>
#define XED_ENCODER
extern "C" {
#include <xed-decode.h>
#include <xed-interface.h>
}
namespace theo::comp::obf {
class pass_t {
public:
explicit pass_t(decomp::sym_type_t sym_type) : m_sym_type(sym_type){};
virtual void run(decomp::symbol_t* sym) = 0;
decomp::sym_type_t sym_type() { return m_sym_type; }
private:
decomp::sym_type_t m_sym_type;
};
} // namespace theo::comp::obf

@ -0,0 +1,16 @@
#pragma once
#include <comp/obf/pass.hpp>
namespace theo::comp::obf {
class jcc_rewrite_pass_t : public pass_t {
explicit jcc_rewrite_pass_t() : pass_t(decomp::sym_type_t::inst_split){};
public:
static jcc_rewrite_pass_t* get() {
static jcc_rewrite_pass_t obj;
return &obj;
}
void run(decomp::symbol_t* sym){};
};
} // namespace theo::comp::obf

@ -0,0 +1,16 @@
#pragma once
#include <comp/obf/pass.hpp>
namespace theo::comp::obf {
class next_inst_pass_t : public pass_t {
explicit next_inst_pass_t() : pass_t(decomp::sym_type_t::inst_split){};
public:
static next_inst_pass_t* get() {
static next_inst_pass_t obj;
return &obj;
}
void run(decomp::symbol_t* sym){};
};
} // namespace theo::comp::obf

@ -0,0 +1,15 @@
#pragma once
#include <comp/obf/pass.hpp>
namespace theo::comp::obf {
class reloc_transform_pass_t : public pass_t {
explicit reloc_transform_pass_t() : pass_t(decomp::sym_type_t::inst_split){};
public:
static reloc_transform_pass_t* get();
void run(decomp::symbol_t* sym);
private:
bool has_legit_reloc(decomp::symbol_t* sym);
};
} // namespace theo::comp::obf

@ -0,0 +1,15 @@
#pragma once
#include <comp/obf/transform/operation.hpp>
namespace theo::comp::obf::transform {
class add_op_t : operation_t {
explicit add_op_t()
: operation_t([&](std::size_t val,
std::size_t imm) -> std::size_t { return val + imm; },
type_t::add_op) {}
public:
static add_op_t* get();
std::vector<std::uint8_t> native(xed_inst_t* inst, std::size_t imm);
};
} // namespace theo::comp::obf::transform

@ -0,0 +1,36 @@
#pragma once
#include <functional>
#include <map>
#define XED_ENCODER
extern "C" {
#include <xed-decode.h>
#include <xed-interface.h>
}
namespace theo::comp::obf::transform {
using transform_t = std::function<std::size_t(std::size_t, std::size_t)>;
class operation_t {
public:
enum type_t { add_op, sub_op, and_op, or_op, rol_op, ror_op, xor_op };
explicit operation_t(transform_t op, type_t type)
: m_transform(op), m_type(type) {}
virtual std::vector<std::uint8_t> native(xed_inst_t* inst,
std::size_t imm) = 0;
type_t inverse() { return m_inverse_op[m_type]; }
transform_t get_transform() { return m_transform; }
private:
transform_t m_transform;
type_t m_type;
std::map<type_t, type_t> m_inverse_op = {
{add_op, sub_op}, {sub_op, add_op}, {and_op, or_op}, {or_op, and_op},
{rol_op, ror_op}, {ror_op, rol_op}, {xor_op, xor_op}};
};
} // namespace theo::comp::obf::transform

@ -0,0 +1,8 @@
#pragma once
#include <comp/obf/transform/add_op.hpp>
#include <comp/obf/transform/operation.hpp>
#include <comp/obf/transform/sub_op.hpp>
namespace theo::comp::obf::transform {
std::map<operation_t::type_t, operation_t*> operations;
}

@ -25,7 +25,7 @@ class symbol_t {
coff::section_header_t* scn() const;
std::vector<std::uint8_t>& data();
coff::symbol_t* sym() const;
sym_type_t sym_type() const;
sym_type_t type() const;
std::vector<comp::reloc_t>& relocs();
void allocated_at(std::uintptr_t allocated_at);

@ -1,8 +1,13 @@
#pragma once
#include <spdlog/spdlog.h>
#include <comp/comp.hpp>
#include <comp/obf/engine.hpp>
#include <decomp/decomp.hpp>
#include <comp/obf/passes/reloc_transform_pass.hpp>
#include <comp/obf/passes/next_inst_pass.hpp>
#include <comp/obf/passes/jcc_rewrite_pass.hpp>
#include <optional>
#include <tuple>
#include <vector>

@ -1,9 +1,9 @@
#define OBF __declspec(code_seg(".obf"))
extern "C" int MessageBoxA(void* hWnd,
char* lpText,
char* lpCaption,
void* uType);
char* lpText,
char* lpCaption,
void* uType);
struct test_t {
char buff[0x2000];
@ -14,6 +14,10 @@ test_t t = {};
OBF extern "C" void EntryPoint() {
t.buff[0] = 1;
t.buff[1] = 2;
MessageBoxA(nullptr, "Hello World", "Hello World", nullptr);
MessageBoxA(nullptr, "Hello World 1", "Hello World 1", nullptr);
if (t.buff[0])
MessageBoxA(nullptr, "Hello World", "Hello World", nullptr);
if (t.buff[1])
MessageBoxA(nullptr, "Hello World 1", "Hello World 1", nullptr);
}

@ -12,16 +12,11 @@ void comp_t::allocate() {
// map code & data/rdata/bss sections first...
//
m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
switch (sym.sym_type()) {
switch (sym.type()) {
case decomp::sym_type_t::section:
case decomp::sym_type_t::function: {
sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics));
break;
}
case decomp::sym_type_t::function:
case decomp::sym_type_t::inst_split: {
// TODO: call into reloc_t static methods to generate random code to
// obfuscate relocations...
//
sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics));
break;
}
default:
@ -32,7 +27,7 @@ void comp_t::allocate() {
// then map data/rdata/bss symbols to the allocated sections...
//
m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
if (sym.sym_type() == decomp::sym_type_t::data) {
if (sym.type() == decomp::sym_type_t::data) {
// if the symbol has a section then we will refer to the allocation made
// for that section...
//
@ -59,7 +54,7 @@ void comp_t::allocate() {
prot.mem_read = true;
prot.mem_write = true;
sym.allocated_at(m_allocator(sym.size(), prot));
sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics));
}
}
});
@ -94,7 +89,7 @@ void comp_t::resolve() {
assert(allocated_at);
}
switch (sym.sym_type()) {
switch (sym.type()) {
case decomp::sym_type_t::function: {
*reinterpret_cast<std::uintptr_t*>(sym.data().data() +
reloc.offset()) = allocated_at;

@ -0,0 +1,20 @@
#include <comp/obf/engine.hpp>
namespace theo::comp::obf {
engine_t* engine_t::get() {
static engine_t obj;
return &obj;
}
void engine_t::add_pass(pass_t* pass) {
passes.push_back(pass);
}
void engine_t::run(decomp::symbol_t* sym) {
std::for_each(passes.begin(), passes.end(), [&](pass_t* pass) {
if (sym->type() == pass->sym_type())
pass->run(sym);
});
}
} // namespace theo::comp::obf

@ -0,0 +1,39 @@
#include <comp/obf/passes/reloc_transform_pass.hpp>
namespace theo::comp::obf {
reloc_transform_pass_t* reloc_transform_pass_t::get() {
static reloc_transform_pass_t obj;
return &obj;
}
void reloc_transform_pass_t::run(decomp::symbol_t* sym) {
if (!has_legit_reloc(sym))
return;
spdlog::info("adding transformations to relocation in symbol: {}",
sym->name());
xed_error_enum_t err;
xed_decoded_inst_t inst;
xed_state_t istate{XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b};
xed_decoded_inst_zero_set_mode(&inst, &istate);
if ((err = xed_decode(&inst, sym->data().data(), sym->data().size())) !=
XED_ERROR_NONE) {
spdlog::error("failed to decode instruction, reason: {} in symbol: {}",
xed_error_enum_t2str(err), sym->name());
assert(err == XED_ERROR_NONE);
}
};
bool reloc_transform_pass_t::has_legit_reloc(decomp::symbol_t* sym) {
auto res = // see if there are any relocations with offset not equal to
// zero... relocations with zero mean its a relocation to the next
// instruction...
std::find_if(sym->relocs().begin(), sym->relocs().end(),
[&](reloc_t& reloc) -> bool { return reloc.offset(); });
return res != sym->relocs().end();
}
} // namespace theo::comp::obf

@ -0,0 +1,14 @@
#include <comp/obf/transform/add_op.hpp>
namespace theo::comp::obf::transform {
add_op_t* add_op_t::get() {
static add_op_t obj;
return &obj;
}
std::vector<std::uint8_t> add_op_t::native(xed_inst_t* inst, std::size_t imm) {
auto op = xed_inst_operand(inst, 0);
auto reg = xed_operand_reg(op);
return {};
}
} // namespace theo::comp::obf::transform

@ -35,7 +35,7 @@ std::optional<comp::symbol_table_t*> decomp_t::decompose() {
.append("!")
.append(std::to_string(img->file_header.timedate_stamp));
// hash the name of the section + the index + thhe timestamp of the obj
// hash the name of the section + the index + the timestamp of the obj
// file it is in...
//
m_scn_hash_tbl.insert({scn, decomp::symbol_t::hash(scn_sym_name)});
@ -122,12 +122,7 @@ std::optional<comp::symbol_table_t*> decomp_t::decompose() {
// the linker to allocate space for
// them...
// the data is init to all zeros...
//
std::vector<std::uint8_t> data(sym->value, 0);
// the symbol is data, it has no section...
//
decomp::symbol_t bss_sym(sym->name.to_string(img->get_strings()).data(),
{}, data, {}, sym, {}, sym_type_t::data);

@ -41,7 +41,7 @@ std::vector<std::uint8_t>& symbol_t::data() {
return m_data;
}
sym_type_t symbol_t::sym_type() const {
sym_type_t symbol_t::type() const {
return m_sym_type;
}

@ -3,11 +3,20 @@
namespace theo {
theo_t::theo_t(std::vector<std::uint8_t>& lib, lnk_fns_t lnkr_fns)
: m_dcmp(lib, &m_sym_tbl), m_cmp(&m_dcmp) {
// init enc/dec tables only once...
// init enc/dec tables only once... add obfuscation passes to the engine...
//
if (static std::atomic_bool v = true; v.exchange(false))
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 = comp::obf::engine_t::get();
engine->add_pass(comp::obf::reloc_transform_pass_t::get());
engine->add_pass(comp::obf::next_inst_pass_t::get());
engine->add_pass(comp::obf::jcc_rewrite_pass_t::get());
}
m_cmp.allocator(std::get<0>(lnkr_fns));
m_cmp.copier(std::get<1>(lnkr_fns));
m_cmp.resolver(std::get<2>(lnkr_fns));
@ -28,6 +37,11 @@ std::optional<std::uint32_t> theo_t::decompose() {
}
std::uintptr_t theo_t::compose(const std::string&& entry_sym) {
// run obfuscation engine on all symbols...
//
auto engine = comp::obf::engine_t::get();
m_sym_tbl.for_each([&](decomp::symbol_t& sym) { engine->run(&sym); });
m_cmp.allocate();
m_cmp.resolve();
m_cmp.copy_syms();

Loading…
Cancel
Save