diff --git a/include/recomp/symbol_table.hpp b/include/recomp/symbol_table.hpp index 162007f..36a6e22 100644 --- a/include/recomp/symbol_table.hpp +++ b/include/recomp/symbol_table.hpp @@ -2,25 +2,56 @@ #include #include #include -#include #include +#include #include namespace theo::recomp { +/// +/// this class is a high level wrapper for a hashmap that contains +/// decomp::symbol_t values. the symbol values are references by a hashcode. +/// class symbol_table_t { public: + + /// + /// default constructor. does nothing. + /// symbol_table_t() {} + + /// + /// this constructor will populate the m_table private field with symbols. + /// + /// vector of decomp::symbol_t symbol_table_t(const std::vector&& syms); - void add_symbol(decomp::symbol_t& sym); - void add_symbols(std::vector& syms); + /// + /// add symbol to m_table + /// + /// symbol to be added. + void put_symbol(decomp::symbol_t& sym); + /// + /// add a vector of symbol to m_table + /// + /// + void put_symbols(std::vector& syms); + + /// + /// returns an optional pointer to a symbol from the symbol table given the symbols hash (hash of its name) + /// the hash is produced by theo::decomp::symbol_t::hash + /// + /// hashcode of the symbol to get from the symbol table... + /// returns an optional pointer to a theo::decomp::symbol_t std::optional sym_from_hash(std::size_t hash); - std::optional sym_from_alloc(std::uintptr_t allocated_at); - void update(std::size_t hash, decomp::symbol_t& sym); - void update(std::size_t hash, std::uintptr_t allocated_at); + /// + /// returns an optional pointer to a symbol given its allocation location. + /// + /// the address where the symbol is allocated at. + /// returns an optional pointer to a theo::decomp::symbol_t + std::optional sym_from_alloc(std::uintptr_t allocated_at); void for_each(std::function fn); std::uint32_t size(); @@ -28,4 +59,4 @@ class symbol_table_t { private: std::map m_table; }; -} // namespace theo::comp \ No newline at end of file +} // namespace theo::recomp \ No newline at end of file diff --git a/include/theo.hpp b/include/theo.hpp index 7b3a976..3711aa9 100644 --- a/include/theo.hpp +++ b/include/theo.hpp @@ -19,18 +19,54 @@ extern "C" { #include } +/// +/// The outer most encompassing namespace of this project. +/// namespace theo { + +/// +/// tuple of functions used by theo to allocate, copy, and resolve symbols. +/// using lnk_fns_t = std::tuple; +/// +/// the main class which encapsulates a symbol table, decomp, and recomp +/// objects. This class is a bridge that connects all three: decomp, obf, +/// recomp. +/// +/// You will create an object of this type when using theo. +/// class theo_t { public: + + /// + /// explicit constructor for theo class. + /// + /// a vector of bytes consisting of a lib + /// + /// the name of the function which will be used as the entry point explicit theo_t(std::vector& lib, lnk_fns_t lnkr_fns, const std::string&& entry_sym); + /// + /// decomposes the lib file and return the number of symbols that are used. + /// + /// optional amount of symbols that are used. no value if decomposition fails. std::optional decompose(); + + /// + /// compose the decomposed module. This will run obfuscation passes, the map and resolve symbols to each other. + /// + /// returns the address of the entry point symbol std::uintptr_t compose(); + + /// + /// given the name of a symbol, it returns the address of where its mapped. + /// + /// the name of the symbol + /// the address of the symbol std::uintptr_t resolve(const std::string&& sym); private: diff --git a/src/decomp/decomp.cpp b/src/decomp/decomp.cpp index 2f1a479..5930473 100644 --- a/src/decomp/decomp.cpp +++ b/src/decomp/decomp.cpp @@ -95,7 +95,7 @@ std::optional decomp_t::decompose( decomp::routine_t rtn(sym, img, scn, fn, dcmp_type); auto syms = rtn.decompose(); - m_syms->add_symbols(syms); + m_syms->put_symbols(syms); } else if (sym->storage_class == coff::storage_class_id::public_symbol || sym->storage_class == coff::storage_class_id::private_symbol) { auto scn = img->get_section(sym->section_index - 1); @@ -140,7 +140,7 @@ std::optional decomp_t::decompose( decomp::symbol_t new_scn_sym(img, scn_sym_name, 0, scn_data, scn, {}, relocs, sym_type_t::section); - m_syms->add_symbol(new_scn_sym); + m_syms->put_symbol(new_scn_sym); } // create a symbol for the data... @@ -149,7 +149,7 @@ std::optional decomp_t::decompose( sym->value, {}, scn, sym, {}, sym_type_t::data); - m_syms->add_symbol(new_sym); + m_syms->put_symbol(new_sym); } } else if (sym->storage_class == coff::storage_class_id:: @@ -162,7 +162,7 @@ std::optional decomp_t::decompose( decomp::symbol_t bss_sym(img, symbol_t::name(img, sym).data(), {}, data, {}, sym, {}, sym_type_t::data); - m_syms->add_symbol(bss_sym); + m_syms->put_symbol(bss_sym); } }); @@ -189,8 +189,8 @@ std::uint32_t decomp_t::next_sym(coff::image_t* img, } std::uint32_t decomp_t::ext_used_syms(const std::string&& entry_sym) { - std::optional entry; - if (!(entry = get_symbol(entry_sym.data())).has_value()) + std::optional entry = get_symbol(entry_sym.data()); + if (!entry.has_value()) return 0u; std::set cache; @@ -241,7 +241,11 @@ std::optional decomp_t::get_symbol(const std::string_view& name) { if (sym->has_section()) return {{img, sym, size}}; } - return {{img, sym, size}}; + + if (img && sym) + return {{img, sym, size}}; + + return {}; } std::vector decomp_t::rtns() { diff --git a/src/recomp/symbol_table.cpp b/src/recomp/symbol_table.cpp index 137ed53..3242021 100644 --- a/src/recomp/symbol_table.cpp +++ b/src/recomp/symbol_table.cpp @@ -7,23 +7,13 @@ symbol_table_t::symbol_table_t(const std::vector&& syms) { }); } -void symbol_table_t::add_symbol(decomp::symbol_t& sym) { +void symbol_table_t::put_symbol(decomp::symbol_t& sym) { m_table.insert({sym.hash(), sym}); } -void symbol_table_t::add_symbols(std::vector& syms) { +void symbol_table_t::put_symbols(std::vector& syms) { std::for_each(syms.begin(), syms.end(), - [&](decomp::symbol_t sym) { add_symbol(sym); }); -} - -void symbol_table_t::update(std::size_t hash, decomp::symbol_t& sym) { - m_table.insert({hash, sym}); -} - -void symbol_table_t::update(std::size_t hash, std::uintptr_t allocated_at) { - auto v = m_table.at(hash); - v.allocated_at(allocated_at); - m_table.insert({hash, v}); + [&](decomp::symbol_t sym) { put_symbol(sym); }); } void symbol_table_t::for_each(std::function fn) { diff --git a/src/theo.cpp b/src/theo.cpp index 5b237b4..59e4f1e 100644 --- a/src/theo.cpp +++ b/src/theo.cpp @@ -5,20 +5,6 @@ theo_t::theo_t(std::vector& lib, lnk_fns_t lnkr_fns, const std::string&& entry_sym) : m_dcmp(lib, &m_sym_tbl), m_recmp(&m_dcmp), m_entry_sym(entry_sym) { - // init enc/dec tables only once... add obfuscation passes to the engine... - // - 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 = obf::engine_t::get(); - engine->add_pass(obf::reloc_transform_pass_t::get()); - engine->add_pass(obf::next_inst_pass_t::get()); - engine->add_pass(obf::jcc_rewrite_pass_t::get()); - } - m_recmp.allocator(std::get<0>(lnkr_fns)); m_recmp.copier(std::get<1>(lnkr_fns)); m_recmp.resolver(std::get<2>(lnkr_fns)); @@ -48,8 +34,10 @@ std::uintptr_t theo_t::compose() { } std::uintptr_t theo_t::resolve(const std::string&& sym) { - return m_sym_tbl.sym_from_hash(decomp::symbol_t::hash(sym)) - .value() - ->allocated_at(); + auto val = m_sym_tbl.sym_from_hash(decomp::symbol_t::hash(sym)); + if (!val.has_value()) + return {}; + + return val.value()->allocated_at(); } } // namespace theo \ No newline at end of file diff --git a/tests/demo/main.cpp b/tests/demo/main.cpp index 66f13a8..2b22b22 100644 --- a/tests/demo/main.cpp +++ b/tests/demo/main.cpp @@ -3,10 +3,16 @@ #include #include +#include #include #include +#include +#include +#include +#include + namespace fs = std::filesystem; int main(int argc, char* argv[]) { @@ -56,7 +62,24 @@ int main(int argc, char* argv[]) { return result; }; - theo::theo_t t(fdata, {allocator, copier, resolver}, "main"); + // init enc/dec tables only once... important that this is done before adding + // obfuscation passes to the engine... + // + xed_tables_init(); + + // order matters, the order in which the pass is added is the order they + // will be executed! + // + auto engine = theo::obf::engine_t::get(); + engine->add_pass(theo::obf::reloc_transform_pass_t::get()); + engine->add_pass(theo::obf::next_inst_pass_t::get()); + engine->add_pass(theo::obf::jcc_rewrite_pass_t::get()); + + std::string entry_name; + std::cout << "enter the name of the entry point: "; + std::cin >> entry_name; + + theo::theo_t t(fdata, {allocator, copier, resolver}, entry_name.data()); auto res = t.decompose(); if (!res.has_value()) { @@ -66,7 +89,8 @@ int main(int argc, char* argv[]) { spdlog::info("decomposed {} symbols...", res.value()); auto entry_pnt = t.compose(); - spdlog::info("entry point address: {:X}", entry_pnt); - std::getchar(); + spdlog::info("entry point address: {:X}, press enter to execute it...", + entry_pnt); + reinterpret_cast(entry_pnt)(); } \ No newline at end of file diff --git a/tests/demolib/CMakeLists.txt b/tests/demolib/CMakeLists.txt index 7c8a7ac..8824ef1 100644 --- a/tests/demolib/CMakeLists.txt +++ b/tests/demolib/CMakeLists.txt @@ -52,7 +52,7 @@ if(WIN32) # windows source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${demolib_SOURCES}) target_compile_options(demolib PUBLIC - "-Xclang -mcmodel=large" + "-Xclang -mcmodel=large -Xclang -fno-jump-tables /Zc:threadSafeInit-" ) unset(CMKR_TARGET) diff --git a/tests/demolib/cmake.toml b/tests/demolib/cmake.toml index 584fd6f..293b853 100644 --- a/tests/demolib/cmake.toml +++ b/tests/demolib/cmake.toml @@ -5,4 +5,4 @@ name = "demolib" condition = "windows" type = "static" sources = ["*.cpp"] -compile-options = ["-Xclang -mcmodel=large"] \ No newline at end of file +compile-options = ["-Xclang -mcmodel=large -Xclang -fno-jump-tables /Zc:threadSafeInit-"] \ No newline at end of file