From 9cf6cc8f03b37d0d998eb0fed13feaabbfd8daad Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Wed, 6 Apr 2022 13:00:59 -0700 Subject: [PATCH] created a pass system... starting to code transformation system for relocations... --- CMakeLists.txt | 29 +++++++++----- include/comp/comp.hpp | 1 + include/comp/obf/engine.hpp | 18 +++++++++ include/comp/obf/pass.hpp | 21 ++++++++++ include/comp/obf/passes/jcc_rewrite_pass.hpp | 16 ++++++++ include/comp/obf/passes/next_inst_pass.hpp | 16 ++++++++ .../comp/obf/passes/reloc_transform_pass.hpp | 15 +++++++ include/comp/obf/transform/add_op.hpp | 15 +++++++ include/comp/{ => obf}/transform/and_op.hpp | 0 include/comp/obf/transform/operation.hpp | 36 +++++++++++++++++ include/comp/{ => obf}/transform/or_op.hpp | 0 include/comp/{ => obf}/transform/rol_op.hpp | 0 include/comp/{ => obf}/transform/ror_op.hpp | 0 include/comp/{ => obf}/transform/sub_op.hpp | 0 include/comp/obf/transform/transform.hpp | 8 ++++ include/comp/{ => obf}/transform/xor_op.hpp | 0 include/decomp/symbol.hpp | 2 +- include/theo.hpp | 5 +++ src/tests/demolib/main.cpp | 14 ++++--- src/theo/comp/comp.cpp | 17 +++----- src/theo/comp/obf/engine.cpp | 20 ++++++++++ .../theo/comp/obf/passes/jcc_rewrite_pass.cpp | 0 .../theo/comp/obf/passes/next_inst_pass.cpp | 0 .../comp/obf/passes/reloc_transform_pass.cpp | 39 +++++++++++++++++++ src/theo/comp/obf/transform/add_op.cpp | 14 +++++++ .../theo/comp/obf/transform/sub_op.cpp | 0 src/theo/decomp/decomp.cpp | 7 +--- src/theo/decomp/symbol.cpp | 2 +- src/theo/theo.cpp | 18 ++++++++- 29 files changed, 278 insertions(+), 35 deletions(-) create mode 100644 include/comp/obf/engine.hpp create mode 100644 include/comp/obf/pass.hpp create mode 100644 include/comp/obf/passes/jcc_rewrite_pass.hpp create mode 100644 include/comp/obf/passes/next_inst_pass.hpp create mode 100644 include/comp/obf/passes/reloc_transform_pass.hpp create mode 100644 include/comp/obf/transform/add_op.hpp rename include/comp/{ => obf}/transform/and_op.hpp (100%) create mode 100644 include/comp/obf/transform/operation.hpp rename include/comp/{ => obf}/transform/or_op.hpp (100%) rename include/comp/{ => obf}/transform/rol_op.hpp (100%) rename include/comp/{ => obf}/transform/ror_op.hpp (100%) rename include/comp/{ => obf}/transform/sub_op.hpp (100%) create mode 100644 include/comp/obf/transform/transform.hpp rename include/comp/{ => obf}/transform/xor_op.hpp (100%) create mode 100644 src/theo/comp/obf/engine.cpp rename include/comp/obf.hpp => src/theo/comp/obf/passes/jcc_rewrite_pass.cpp (100%) rename include/comp/transform/add_op.hpp => src/theo/comp/obf/passes/next_inst_pass.cpp (100%) create mode 100644 src/theo/comp/obf/passes/reloc_transform_pass.cpp create mode 100644 src/theo/comp/obf/transform/add_op.cpp rename include/comp/transform/operation.hpp => src/theo/comp/obf/transform/sub_op.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bafef4..811da43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/include/comp/comp.hpp b/include/comp/comp.hpp index eb660bf..4924c9f 100644 --- a/include/comp/comp.hpp +++ b/include/comp/comp.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include diff --git a/include/comp/obf/engine.hpp b/include/comp/obf/engine.hpp new file mode 100644 index 0000000..40ca1e6 --- /dev/null +++ b/include/comp/obf/engine.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include + +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 passes; +}; +} // namespace theo::comp::obf \ No newline at end of file diff --git a/include/comp/obf/pass.hpp b/include/comp/obf/pass.hpp new file mode 100644 index 0000000..29b95b3 --- /dev/null +++ b/include/comp/obf/pass.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +#define XED_ENCODER +extern "C" { +#include +#include +} + +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 \ No newline at end of file diff --git a/include/comp/obf/passes/jcc_rewrite_pass.hpp b/include/comp/obf/passes/jcc_rewrite_pass.hpp new file mode 100644 index 0000000..b5b1ecd --- /dev/null +++ b/include/comp/obf/passes/jcc_rewrite_pass.hpp @@ -0,0 +1,16 @@ +#pragma once +#include + +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 \ No newline at end of file diff --git a/include/comp/obf/passes/next_inst_pass.hpp b/include/comp/obf/passes/next_inst_pass.hpp new file mode 100644 index 0000000..594efbc --- /dev/null +++ b/include/comp/obf/passes/next_inst_pass.hpp @@ -0,0 +1,16 @@ +#pragma once +#include + +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 \ No newline at end of file diff --git a/include/comp/obf/passes/reloc_transform_pass.hpp b/include/comp/obf/passes/reloc_transform_pass.hpp new file mode 100644 index 0000000..e3f00d0 --- /dev/null +++ b/include/comp/obf/passes/reloc_transform_pass.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +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 \ No newline at end of file diff --git a/include/comp/obf/transform/add_op.hpp b/include/comp/obf/transform/add_op.hpp new file mode 100644 index 0000000..a01a1ae --- /dev/null +++ b/include/comp/obf/transform/add_op.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +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 native(xed_inst_t* inst, std::size_t imm); +}; +} // namespace theo::comp::obf::transform \ No newline at end of file diff --git a/include/comp/transform/and_op.hpp b/include/comp/obf/transform/and_op.hpp similarity index 100% rename from include/comp/transform/and_op.hpp rename to include/comp/obf/transform/and_op.hpp diff --git a/include/comp/obf/transform/operation.hpp b/include/comp/obf/transform/operation.hpp new file mode 100644 index 0000000..ae6fbe1 --- /dev/null +++ b/include/comp/obf/transform/operation.hpp @@ -0,0 +1,36 @@ +#pragma once +#include +#include + +#define XED_ENCODER +extern "C" { +#include +#include +} + +namespace theo::comp::obf::transform { +using transform_t = std::function; + +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 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 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 \ No newline at end of file diff --git a/include/comp/transform/or_op.hpp b/include/comp/obf/transform/or_op.hpp similarity index 100% rename from include/comp/transform/or_op.hpp rename to include/comp/obf/transform/or_op.hpp diff --git a/include/comp/transform/rol_op.hpp b/include/comp/obf/transform/rol_op.hpp similarity index 100% rename from include/comp/transform/rol_op.hpp rename to include/comp/obf/transform/rol_op.hpp diff --git a/include/comp/transform/ror_op.hpp b/include/comp/obf/transform/ror_op.hpp similarity index 100% rename from include/comp/transform/ror_op.hpp rename to include/comp/obf/transform/ror_op.hpp diff --git a/include/comp/transform/sub_op.hpp b/include/comp/obf/transform/sub_op.hpp similarity index 100% rename from include/comp/transform/sub_op.hpp rename to include/comp/obf/transform/sub_op.hpp diff --git a/include/comp/obf/transform/transform.hpp b/include/comp/obf/transform/transform.hpp new file mode 100644 index 0000000..5bc0f41 --- /dev/null +++ b/include/comp/obf/transform/transform.hpp @@ -0,0 +1,8 @@ +#pragma once +#include +#include +#include + +namespace theo::comp::obf::transform { +std::map operations; +} \ No newline at end of file diff --git a/include/comp/transform/xor_op.hpp b/include/comp/obf/transform/xor_op.hpp similarity index 100% rename from include/comp/transform/xor_op.hpp rename to include/comp/obf/transform/xor_op.hpp diff --git a/include/decomp/symbol.hpp b/include/decomp/symbol.hpp index 2280b30..7f1ccd9 100644 --- a/include/decomp/symbol.hpp +++ b/include/decomp/symbol.hpp @@ -25,7 +25,7 @@ class symbol_t { coff::section_header_t* scn() const; std::vector& data(); coff::symbol_t* sym() const; - sym_type_t sym_type() const; + sym_type_t type() const; std::vector& relocs(); void allocated_at(std::uintptr_t allocated_at); diff --git a/include/theo.hpp b/include/theo.hpp index b673ed2..a5337ae 100644 --- a/include/theo.hpp +++ b/include/theo.hpp @@ -1,8 +1,13 @@ #pragma once #include #include +#include #include +#include +#include +#include + #include #include #include diff --git a/src/tests/demolib/main.cpp b/src/tests/demolib/main.cpp index 61493cd..6003bb3 100644 --- a/src/tests/demolib/main.cpp +++ b/src/tests/demolib/main.cpp @@ -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); } \ No newline at end of file diff --git a/src/theo/comp/comp.cpp b/src/theo/comp/comp.cpp index ddfca46..acf3dee 100644 --- a/src/theo/comp/comp.cpp +++ b/src/theo/comp/comp.cpp @@ -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(sym.data().data() + reloc.offset()) = allocated_at; diff --git a/src/theo/comp/obf/engine.cpp b/src/theo/comp/obf/engine.cpp new file mode 100644 index 0000000..d3c1d15 --- /dev/null +++ b/src/theo/comp/obf/engine.cpp @@ -0,0 +1,20 @@ +#include + +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 \ No newline at end of file diff --git a/include/comp/obf.hpp b/src/theo/comp/obf/passes/jcc_rewrite_pass.cpp similarity index 100% rename from include/comp/obf.hpp rename to src/theo/comp/obf/passes/jcc_rewrite_pass.cpp diff --git a/include/comp/transform/add_op.hpp b/src/theo/comp/obf/passes/next_inst_pass.cpp similarity index 100% rename from include/comp/transform/add_op.hpp rename to src/theo/comp/obf/passes/next_inst_pass.cpp diff --git a/src/theo/comp/obf/passes/reloc_transform_pass.cpp b/src/theo/comp/obf/passes/reloc_transform_pass.cpp new file mode 100644 index 0000000..e40449a --- /dev/null +++ b/src/theo/comp/obf/passes/reloc_transform_pass.cpp @@ -0,0 +1,39 @@ +#include + +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 \ No newline at end of file diff --git a/src/theo/comp/obf/transform/add_op.cpp b/src/theo/comp/obf/transform/add_op.cpp new file mode 100644 index 0000000..7cb1d31 --- /dev/null +++ b/src/theo/comp/obf/transform/add_op.cpp @@ -0,0 +1,14 @@ +#include + +namespace theo::comp::obf::transform { +add_op_t* add_op_t::get() { + static add_op_t obj; + return &obj; +} + +std::vector 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 \ No newline at end of file diff --git a/include/comp/transform/operation.hpp b/src/theo/comp/obf/transform/sub_op.cpp similarity index 100% rename from include/comp/transform/operation.hpp rename to src/theo/comp/obf/transform/sub_op.cpp diff --git a/src/theo/decomp/decomp.cpp b/src/theo/decomp/decomp.cpp index bbd22a0..e066c74 100644 --- a/src/theo/decomp/decomp.cpp +++ b/src/theo/decomp/decomp.cpp @@ -35,7 +35,7 @@ std::optional 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 decomp_t::decompose() { // the linker to allocate space for // them... - // the data is init to all zeros... - // std::vector 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); diff --git a/src/theo/decomp/symbol.cpp b/src/theo/decomp/symbol.cpp index e2d5ed4..b4cf624 100644 --- a/src/theo/decomp/symbol.cpp +++ b/src/theo/decomp/symbol.cpp @@ -41,7 +41,7 @@ std::vector& 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; } diff --git a/src/theo/theo.cpp b/src/theo/theo.cpp index f308ffd..a0682c0 100644 --- a/src/theo/theo.cpp +++ b/src/theo/theo.cpp @@ -3,11 +3,20 @@ namespace theo { theo_t::theo_t(std::vector& 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 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();