starting to add documentation

- moved obf engine stuff out of theo and into the demo
- started to document theo and how to use it
- TODO: make a demo pass...
master
_xeroxz 3 years ago
parent f1f808081b
commit 8b7229ac75

@ -2,25 +2,56 @@
#include <algorithm>
#include <functional>
#include <map>
#include <vector>
#include <optional>
#include <vector>
#include <decomp/symbol.hpp>
namespace theo::recomp {
/// <summary>
/// this class is a high level wrapper for a hashmap that contains
/// decomp::symbol_t values. the symbol values are references by a hashcode.
/// </summary>
class symbol_table_t {
public:
/// <summary>
/// default constructor. does nothing.
/// </summary>
symbol_table_t() {}
/// <summary>
/// this constructor will populate the m_table private field with symbols.
/// </summary>
/// <param name="syms">vector of decomp::symbol_t</param>
symbol_table_t(const std::vector<decomp::symbol_t>&& syms);
void add_symbol(decomp::symbol_t& sym);
void add_symbols(std::vector<decomp::symbol_t>& syms);
/// <summary>
/// add symbol to m_table
/// </summary>
/// <param name="sym">symbol to be added.</param>
void put_symbol(decomp::symbol_t& sym);
/// <summary>
/// add a vector of symbol to m_table
/// </summary>
/// <param name="syms"></param>
void put_symbols(std::vector<decomp::symbol_t>& syms);
/// <summary>
/// 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
/// </summary>
/// <param name="hash">hashcode of the symbol to get from the symbol table...</param>
/// <returns>returns an optional pointer to a theo::decomp::symbol_t</returns>
std::optional<decomp::symbol_t*> sym_from_hash(std::size_t hash);
std::optional<decomp::symbol_t*> 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);
/// <summary>
/// returns an optional pointer to a symbol given its allocation location.
/// </summary>
/// <param name="allocated_at">the address where the symbol is allocated at.</param>
/// <returns>returns an optional pointer to a theo::decomp::symbol_t</returns>
std::optional<decomp::symbol_t*> sym_from_alloc(std::uintptr_t allocated_at);
void for_each(std::function<void(decomp::symbol_t& sym)> fn);
std::uint32_t size();
@ -28,4 +59,4 @@ class symbol_table_t {
private:
std::map<std::size_t, decomp::symbol_t> m_table;
};
} // namespace theo::comp
} // namespace theo::recomp

@ -19,18 +19,54 @@ extern "C" {
#include <xed-interface.h>
}
/// <summary>
/// The outer most encompassing namespace of this project.
/// </summary>
namespace theo {
/// <summary>
/// tuple of functions used by theo to allocate, copy, and resolve symbols.
/// </summary>
using lnk_fns_t =
std::tuple<recomp::allocator_t, recomp::copier_t, recomp::resolver_t>;
/// <summary>
/// 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.
/// </summary>
class theo_t {
public:
/// <summary>
/// explicit constructor for theo class.
/// </summary>
/// <param name="lib">a vector of bytes consisting of a lib</param>
/// <param name="lnkr_fns"></param>
/// <param name="entry_sym">the name of the function which will be used as the entry point</param>
explicit theo_t(std::vector<std::uint8_t>& lib,
lnk_fns_t lnkr_fns,
const std::string&& entry_sym);
/// <summary>
/// decomposes the lib file and return the number of symbols that are used.
/// </summary>
/// <returns>optional amount of symbols that are used. no value if decomposition fails.</returns>
std::optional<std::uint32_t> decompose();
/// <summary>
/// compose the decomposed module. This will run obfuscation passes, the map and resolve symbols to each other.
/// </summary>
/// <returns>returns the address of the entry point symbol</returns>
std::uintptr_t compose();
/// <summary>
/// given the name of a symbol, it returns the address of where its mapped.
/// </summary>
/// <param name="sym">the name of the symbol</param>
/// <returns>the address of the symbol</returns>
std::uintptr_t resolve(const std::string&& sym);
private:

@ -95,7 +95,7 @@ std::optional<recomp::symbol_table_t*> 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<recomp::symbol_table_t*> 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<recomp::symbol_table_t*> 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<recomp::symbol_table_t*> 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<sym_data_t> entry;
if (!(entry = get_symbol(entry_sym.data())).has_value())
std::optional<sym_data_t> entry = get_symbol(entry_sym.data());
if (!entry.has_value())
return 0u;
std::set<coff::symbol_t*> cache;
@ -241,7 +241,11 @@ std::optional<sym_data_t> 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<routine_t> decomp_t::rtns() {

@ -7,23 +7,13 @@ symbol_table_t::symbol_table_t(const std::vector<decomp::symbol_t>&& 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<decomp::symbol_t>& syms) {
void symbol_table_t::put_symbols(std::vector<decomp::symbol_t>& 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<void(decomp::symbol_t& sym)> fn) {

@ -5,20 +5,6 @@ theo_t::theo_t(std::vector<std::uint8_t>& 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

@ -3,10 +3,16 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <spdlog/spdlog.h>
#include <theo.hpp>
#include <obf/engine.hpp>
#include <obf/passes/jcc_rewrite_pass.hpp>
#include <obf/passes/next_inst_pass.hpp>
#include <obf/passes/reloc_transform_pass.hpp>
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<void (*)()>(entry_pnt)();
}

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

@ -5,4 +5,4 @@ name = "demolib"
condition = "windows"
type = "static"
sources = ["*.cpp"]
compile-options = ["-Xclang -mcmodel=large"]
compile-options = ["-Xclang -mcmodel=large -Xclang -fno-jump-tables /Zc:threadSafeInit-"]
Loading…
Cancel
Save