added a fuck ton of shit

I should have probably done multiple commits, whatever.
I still need to rework reloc_t/things that insert transforms into it...
master
_xeroxz 2 years ago
parent 51d64b44b1
commit 094ed9f15f

@ -59,6 +59,7 @@ list(APPEND Theodosius_SOURCES
"include/decomp/symbol.hpp"
"include/obf/engine.hpp"
"include/obf/pass.hpp"
"include/obf/passes/func_split_pass.hpp"
"include/obf/passes/jcc_rewrite_pass.hpp"
"include/obf/passes/next_inst_pass.hpp"
"include/obf/passes/reloc_transform_pass.hpp"
@ -78,6 +79,7 @@ list(APPEND Theodosius_SOURCES
"src/decomp/routine.cpp"
"src/decomp/symbol.cpp"
"src/obf/engine.cpp"
"src/obf/passes/func_split_pass.cpp"
"src/obf/passes/jcc_rewrite_pass.cpp"
"src/obf/passes/next_inst_pass.cpp"
"src/obf/passes/reloc_transform_pass.cpp"

@ -47,7 +47,7 @@ class hello_world_pass_t : public generic_pass_t {
return &obj;
}
void generic_pass(decomp::symbol_t* sym) override {
void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) override {
spdlog::info("[hello_world_pass_t] symbol name: {}, symbol hash: {}",
sym->name(), sym->hash());
}

@ -39,6 +39,7 @@
#include <theo.hpp>
#include <obf/engine.hpp>
#include <obf/passes/func_split_pass.hpp>
#include <obf/passes/jcc_rewrite_pass.hpp>
#include <obf/passes/next_inst_pass.hpp>
#include <obf/passes/reloc_transform_pass.hpp>
@ -114,16 +115,17 @@ int main(int argc, char* argv[]) {
//
auto engine = theo::obf::engine_t::get();
// add in our hello world pass here
//
engine->add_pass(theo::obf::hello_world_pass_t::get());
// add the rest of the passes in this order. this order is important.
//
engine->add_pass(theo::obf::func_split_pass_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());
// add in our hello world pass here
//
engine->add_pass(theo::obf::hello_world_pass_t::get());
std::string entry_name;
std::cout << "enter the name of the entry point: ";
std::cin >> entry_name;
@ -147,5 +149,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);
spdlog::info("press enter to execute {}", entry_name.c_str());
std::getchar();
reinterpret_cast<void (*)()>(entry_pnt)();
}

@ -139,6 +139,12 @@ class symbol_t {
/// <returns>the type of the symbol.</returns>
sym_type_t type() const;
/// <summary>
/// setter for the type value.
/// </summary>
/// <param name="type">type of symbol.</param>
void type(sym_type_t type);
/// <summary>
/// returns a vector of relocations.
/// </summary>

@ -59,6 +59,10 @@ using allocator_t =
std::function<std::uintptr_t(std::uint32_t,
coff::section_characteristics_t)>;
// symbol table map associated with the symbol table data structure.
//
using sym_map_t = std::map<std::size_t, decomp::symbol_t>;
/// <summary>
/// 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.
@ -82,7 +86,7 @@ class pass_t {
/// allows you to manipulate symbols in a generic manner.
/// </summary>
/// <param name="sym">a symbol of the same type of m_sym_type.</param>
virtual void generic_pass(decomp::symbol_t* sym) = 0;
virtual void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) = 0;
/// <summary>
/// This virtual method is invoked prior to calling the "copier". This allows

@ -0,0 +1,42 @@
// Copyright (c) 2022, _xeroxz
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include <obf/pass.hpp>
namespace theo::obf {
class func_split_pass_t : public generic_pass_t {
explicit func_split_pass_t() : generic_pass_t(decomp::sym_type_t::function) {}
public:
static func_split_pass_t* get();
void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) override;
};
} // namespace theo::obf

@ -64,6 +64,6 @@ class jcc_rewrite_pass_t : public generic_pass_t {
public:
static jcc_rewrite_pass_t* get();
void generic_pass(decomp::symbol_t* sym) override;
void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) override;
};
} // namespace theo::obf

@ -92,7 +92,7 @@ class next_inst_pass_t : public generic_pass_t {
public:
static next_inst_pass_t* get();
void generic_pass(decomp::symbol_t* sym) override;
void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) override;
private:
std::optional<recomp::reloc_t*> has_next_inst_reloc(decomp::symbol_t*);

@ -59,7 +59,7 @@ class reloc_transform_pass_t : public generic_pass_t {
public:
static reloc_transform_pass_t* get();
void generic_pass(decomp::symbol_t* sym) override;
void generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) override;
private:
std::optional<recomp::reloc_t*> has_legit_reloc(decomp::symbol_t* sym);

@ -81,30 +81,7 @@ class reloc_t {
/// too.</param>
void offset(std::uint32_t offset) { m_offset = offset; }
/// <summary>
/// adds a transformation to be applied to the relocation prior to writing it
/// into the symbol.
/// </summary>
/// <param name="entry">a pair containing a lambda function that when executed
/// transforms a relocation. the second value in the pair is a random value
/// which is passed to the lambda.</param>
void add_transform(
std::pair<obf::transform::transform_t*, std::uint32_t> entry) {
m_transforms.push_back(entry);
}
/// <summary>
/// gets the vector of transformation.
/// </summary>
/// <returns>returns the vector of transformations.</returns>
std::vector<std::pair<obf::transform::transform_t*, std::uint32_t>>&
get_transforms() {
return m_transforms;
}
private:
std::vector<std::pair<obf::transform::transform_t*, std::uint32_t>>
m_transforms;
std::string m_sym_name;
std::size_t m_hash;
std::uint32_t m_offset;

@ -99,6 +99,12 @@ class symbol_table_t {
/// <returns>returns the size of the symbol table.</returns>
std::uint32_t size();
/// <summary>
/// getter for underlying symbol hash map.
/// </summary>
/// <returns>returns the symbol hashmap.</returns>
std::map<std::size_t, decomp::symbol_t>& get();
private:
std::map<std::size_t, decomp::symbol_t> m_table;
};

@ -81,6 +81,10 @@ sym_type_t symbol_t::type() const {
return m_sym_type;
}
void symbol_t::type(sym_type_t type) {
m_sym_type = type;
}
void symbol_t::allocated_at(std::uintptr_t allocated_at) {
m_allocated_at = allocated_at;
}

@ -0,0 +1,135 @@
// Copyright (c) 2022, _xeroxz
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include <obf/passes/func_split_pass.hpp>
namespace theo::obf {
func_split_pass_t* func_split_pass_t::get() {
static func_split_pass_t obj;
return &obj;
}
void func_split_pass_t::generic_pass(decomp::symbol_t* sym,
sym_map_t& sym_tbl) {
std::uint32_t offset = {};
xed_error_enum_t err;
xed_decoded_inst_t instr;
std::vector<decomp::symbol_t> result;
xed_state_t istate{XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b};
xed_decoded_inst_zero_set_mode(&instr, &istate);
// keep looping over the function, lower the number of bytes each time...
//
while ((err = xed_decode(&instr, sym->data().data() + offset,
sym->data().size() - offset)) == XED_ERROR_NONE) {
// symbol name is of the format: symbol@instroffset, I.E: main@11...
//
auto new_sym_name = decomp::symbol_t::name(sym->img(), sym->sym());
// first instruction doesnt need the @offset...
//
if (offset)
new_sym_name.append("@").append(std::to_string(offset));
std::vector<recomp::reloc_t> relocs;
auto scn_relocs = reinterpret_cast<coff::reloc_t*>(
sym->scn()->ptr_relocs + reinterpret_cast<std::uint8_t*>(sym->img()));
// find if this instruction has a relocation or not...
// if so, return the reloc_t...
//
auto reloc = std::find_if(
scn_relocs, scn_relocs + sym->scn()->num_relocs,
[&](coff::reloc_t reloc) {
return reloc.virtual_address >= sym->sym()->value + offset &&
reloc.virtual_address <
sym->sym()->value + offset +
xed_decoded_inst_get_length(&instr);
});
// if there is indeed a reloc for this instruction...
//
if (reloc != scn_relocs + sym->scn()->num_relocs) {
auto sym_reloc = sym->img()->get_symbol(reloc->symbol_index);
auto sym_name = decomp::symbol_t::name(sym->img(), sym_reloc);
auto sym_hash = decomp::symbol_t::hash(sym_name.data());
auto reloc_offset = reloc->virtual_address - sym->sym()->value - offset;
relocs.push_back(
recomp::reloc_t(reloc_offset, sym_hash, sym_name.data()));
}
// add a reloc to the next instruction...
// note that the offset is ZERO... comp_t will understand that
// relocs with offset ZERO means the next instructions...
//
auto next_inst_sym = decomp::symbol_t::name(sym->img(), sym->sym())
.append("@")
.append(std::to_string(
offset + xed_decoded_inst_get_length(&instr)));
relocs.push_back(recomp::reloc_t(0, decomp::symbol_t::hash(next_inst_sym),
next_inst_sym.data()));
// get the instructions bytes
//
std::vector<std::uint8_t> inst_bytes(
sym->data().data() + offset,
sym->data().data() + offset + xed_decoded_inst_get_length(&instr));
result.push_back(decomp::symbol_t(sym->img(), new_sym_name, offset,
inst_bytes, sym->scn(), sym->sym(),
relocs, decomp::sym_type_t::instruction));
// after creating the symbol and dealing with relocs then print the
// information we have concluded...
//
char buff[255];
offset += xed_decoded_inst_get_length(&instr);
xed_format_context(XED_SYNTAX_INTEL, &instr, buff, sizeof buff, NULL, NULL,
NULL);
spdlog::info("[func_split_pass_t] {}: {}", new_sym_name, buff);
// need to set this so that instr can be used to decode again...
xed_decoded_inst_zero_set_mode(&instr, &istate);
}
// remove the relocation to the next symbol from the last instruction
//
auto& last_inst = result.back();
auto& last_inst_relocs = last_inst.relocs();
last_inst_relocs.erase(last_inst_relocs.end() - 1);
// insert the split instructions into the symbol table.
//
for (auto& symbol : result) {
auto itr = sym_tbl.find(symbol.hash());
if (itr != sym_tbl.end())
itr->second = symbol;
else
sym_tbl.insert({symbol.hash(), symbol});
}
}
} // namespace theo::obf

@ -37,7 +37,8 @@ jcc_rewrite_pass_t* jcc_rewrite_pass_t::get() {
return &obj;
}
void jcc_rewrite_pass_t::generic_pass(decomp::symbol_t* sym) {
void jcc_rewrite_pass_t::generic_pass(decomp::symbol_t* sym,
sym_map_t& sym_tbl) {
std::int32_t disp = {};
xed_decoded_inst_t inst;
xed_state_t istate{XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b};
@ -77,7 +78,7 @@ void jcc_rewrite_pass_t::generic_pass(decomp::symbol_t* sym) {
// run next_inst_pass on this symbol to generate the transformations for the
// relocation to the jcc branch dest instruction...
next_inst_pass_t::get()->generic_pass(sym);
next_inst_pass_t::get()->generic_pass(sym, sym_tbl);
}
};
} // namespace theo::obf

@ -36,7 +36,7 @@ next_inst_pass_t* next_inst_pass_t::get() {
return &obj;
}
void next_inst_pass_t::generic_pass(decomp::symbol_t* sym) {
void next_inst_pass_t::generic_pass(decomp::symbol_t* sym, sym_map_t& sym_tbl) {
std::optional<recomp::reloc_t*> reloc;
if (!(reloc = has_next_inst_reloc(sym)).has_value())
return;

@ -36,7 +36,8 @@ reloc_transform_pass_t* reloc_transform_pass_t::get() {
return &obj;
}
void reloc_transform_pass_t::generic_pass(decomp::symbol_t* sym) {
void reloc_transform_pass_t::generic_pass(decomp::symbol_t* sym,
sym_map_t& sym_tbl) {
std::optional<recomp::reloc_t*> reloc;
if (!(reloc = has_legit_reloc(sym)).has_value())
return;

@ -69,6 +69,10 @@ std::optional<decomp::symbol_t*> symbol_table_t::sym_from_alloc(
: std::optional<decomp::symbol_t*>{};
}
std::map<std::size_t, decomp::symbol_t>& symbol_table_t::get() {
return m_table;
}
std::uint32_t symbol_table_t::size() {
return m_table.size();
}

@ -54,12 +54,34 @@ std::optional<std::uint32_t> theo_t::decompose() {
}
std::uintptr_t theo_t::compose() {
// run obfuscation engine on all symbols...
//
auto engine = obf::engine_t::get();
auto& sym_tbl = m_sym_tbl.get();
// run obfuscation engine on function symbols...
//
m_sym_tbl.for_each([&](decomp::symbol_t& sym) {
engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) {
if (sym->type() == decomp::sym_type_t::function)
pass->generic_pass(sym, sym_tbl);
});
});
// run obfuscation engine on instruction symbols...
//
m_sym_tbl.for_each([&](decomp::symbol_t& sym) {
engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) {
if (sym->type() == decomp::sym_type_t::instruction)
pass->generic_pass(sym, sym_tbl);
});
});
// run obfuscation engine on all other symbols...
//
m_sym_tbl.for_each([&](decomp::symbol_t& sym) {
engine->for_each(&sym, [&](decomp::symbol_t* sym, obf::pass_t* pass) {
pass->generic_pass(sym);
if (sym->type() != decomp::sym_type_t::instruction &&
sym->type() != decomp::sym_type_t::function)
pass->generic_pass(sym, sym_tbl);
});
});

Loading…
Cancel
Save