From 6b96c725eedd5b88208a79bff9545dabbfe6bc9a Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Sat, 4 Apr 2026 13:56:17 +0200 Subject: [PATCH] Replaced post-link finalizer with pre-link patchcompile --- CMakeLists.txt | 2 +- finalize/CMakeLists.txt | 5 - finalize/finalize.cpp | 293 -------------------- finalize/symbol_collection.cpp | 65 ----- finalize/symbol_collection.h | 17 -- patchcompile/CMakeLists.txt | 2 + {finalize => patchcompile}/accumulation.cpp | 2 - {finalize => patchcompile}/accumulation.h | 12 - patchcompile/emit.cpp | 144 ++++++++++ patchcompile/emit.h | 4 + patchcompile/patchcompile.cpp | 93 +++++++ pinpoint/stage0/target.cpp | 2 + plan.txt | 3 - selfpatch/CMakeLists.txt | 2 +- selfpatch/src/selfpatch.c | 36 +-- selfpatch/src/spslr_program.h | 65 +++-- subject/CMakeLists.txt | 65 +++-- 17 files changed, 341 insertions(+), 471 deletions(-) delete mode 100644 finalize/CMakeLists.txt delete mode 100644 finalize/finalize.cpp delete mode 100644 finalize/symbol_collection.cpp delete mode 100644 finalize/symbol_collection.h create mode 100644 patchcompile/CMakeLists.txt rename {finalize => patchcompile}/accumulation.cpp (98%) rename {finalize => patchcompile}/accumulation.h (89%) create mode 100644 patchcompile/emit.cpp create mode 100644 patchcompile/emit.h create mode 100644 patchcompile/patchcompile.cpp delete mode 100644 plan.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e8fb27e..f1cfa57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,6 @@ set(CMAKE_CXX_COMPILER g++-16 CACHE FILEPATH "C++ compiler" FORCE) project(SelfPatchSLR LANGUAGES C CXX) add_subdirectory(pinpoint) -add_subdirectory(finalize) +add_subdirectory(patchcompile) add_subdirectory(selfpatch) add_subdirectory(subject) diff --git a/finalize/CMakeLists.txt b/finalize/CMakeLists.txt deleted file mode 100644 index ab0d620..0000000 --- a/finalize/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -find_package(LIEF REQUIRED) - -add_executable(spslr_finalize finalize.cpp accumulation.cpp symbol_collection.cpp) -target_link_libraries(spslr_finalize PRIVATE LIEF::LIEF) -set_target_properties(spslr_finalize PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO) diff --git a/finalize/finalize.cpp b/finalize/finalize.cpp deleted file mode 100644 index 460ea92..0000000 --- a/finalize/finalize.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -#include "accumulation.h" -#include "symbol_collection.h" - -#include - -/* -Notes: - Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top - Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together - To begin with, anonymous types are not allowed for randomization (later solved with hash(type) instead of name)! -*/ - -using namespace LIEF::ELF; - -static bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector& program); - -int main(int argc, char** argv) { - static option long_options[] = { - { "help", no_argument, 0, 0 }, - { "bin", required_argument, 0, 0 }, - { "out", required_argument, 0, 0 }, - { "strip", no_argument, 0, 0 }, - { 0, 0, 0, 0 } - }; - - int option_index = 0; - int c; - - std::vector spslr_files; - std::string bin_file, out_file; - - while ((c = getopt_long(argc, argv, "hb:o:", long_options, &option_index)) == 0) { - const option& opt = long_options[option_index]; - std::string optname { opt.name }; - - if (optname == "help") { - std::cout << "To use spslr_finalize, supply these 3 arguments:" << std::endl; - std::cout << " --bin= (the binary compiled with spslr_pinpoint to be finalized)" << std::endl; - std::cout << " --out= (the finalized binary file to be written)" << std::endl; - std::cout << " ... (one or more .spslr metadata files)" << std::endl; - return 0; - } else if (optname == "bin") { - bin_file = std::string{ optarg }; - } else if (optname == "out") { - out_file = std::string{ optarg }; - } else if (optname == "strip") { - std::cerr << "Symbol stripping (--strip) is not yet implemented!" << std::endl; - return 1; - } else { - std::cerr << "Invalid option, try \"--help\"!" << std::endl; - return 1; - } - } - - if (bin_file.empty()) { - std::cerr << "Missing input file path, supply it via --bin=!" << std::endl; - return 1; - } - - if (out_file.empty()) { - std::cerr << "Missing output file path, supply it via --out=!" << std::endl; - return 1; - } - - for (int i = optind; i < argc; ++i) - spslr_files.emplace_back(argv[i]); - - if (spslr_files.empty()) { - std::cerr << "Missing spslr files! Pass one or more .spslr files as positional arguments." << std::endl; - return 1; - } - - if (!accumulate(spslr_files)) { - std::cerr << "Failed to accumulate data from spslr directory!" << std::endl; - return 1; - } - - std::cout << "Gathered a total of " << targets.size() << " distinct targets from " - << units.size() << " compilation units!" << std::endl; - - std::unique_ptr bin = Parser::parse(bin_file); - if (!bin) { - std::cerr << "Failed to parse binary \"" << bin_file << "\"!" << std::endl; - return 1; - } - - if (!collect_symbols(bin)) { - std::cerr << "Failed to collect symbols from \"" << bin_file << "\"!" << std::endl; - return 1; - } - - if (!associate_symbols()) { - std::cerr << "Failed to associate symbols with accumulated data!" << std::endl; - return 1; - } - - // Find __spslr_program as anchor of relative addressing in patcher program - if (!global_syms.symbols.contains("__spslr_program")) { - std::cerr << "Unable to locate \"__spslr_program\"!" << std::endl; - return 1; - } - - uint64_t spslr_program_ptr_address = global_syms.symbols.at("__spslr_program"); - - // Serialize patcher program - std::vector patcher_program; - if (!assemble_patcher_program(spslr_program_ptr_address, patcher_program)) { - std::cerr << "Failed to assemble patcher program!" << std::endl; - return 1; - } - - std::cout << "Generated patcher program of 0x" << std::hex << patcher_program.size() - << std::dec << " bytes!" << std::endl; - - // Add new section ".spslr" with patcher program - - uint64_t page_align = 0x1000; - for (const auto& seg : bin->segments()) { - if (seg.type() == Segment::TYPE::LOAD) { - if (seg.alignment() > page_align) page_align = seg.alignment(); - } - } - - uint64_t max_end_vaddr = 0; - for (const auto& seg : bin->segments()) { - if (seg.type() == Segment::TYPE::LOAD) { - uint64_t endv = seg.virtual_address() + seg.virtual_size(); - if (endv > max_end_vaddr) max_end_vaddr = endv; - } - } - - uint64_t new_vaddr = max_end_vaddr; - if (new_vaddr % page_align != 0) - new_vaddr += page_align - (new_vaddr % page_align); - - std::cout << "Adding patcher program at 0x" << std::hex << new_vaddr << std::dec << std::endl; - - Segment new_seg; - new_seg.type(Segment::TYPE::LOAD); - new_seg.flags(Segment::FLAGS::R); //(ELF_SEGMENT_FLAGS::PF_R); - new_seg.alignment(page_align); - new_seg.file_offset(0); // Writer decides where to put it - new_seg.virtual_address(new_vaddr); - new_seg.content(patcher_program); - new_seg.virtual_size(patcher_program.size()); - - bin->add(new_seg); - - // Set __spslr_program to (new_vaddr - &__spslr_program) - for (Segment& seg : bin->segments()) { - uint64_t start = seg.virtual_address(); - uint64_t end_mem = start + seg.virtual_size(); - - if (spslr_program_ptr_address >= start && spslr_program_ptr_address < end_mem) { - uint64_t offset_within_seg = spslr_program_ptr_address - start; - uint64_t min_needed = offset_within_seg + sizeof(uint64_t); - - if (min_needed > seg.physical_size()) - seg.physical_size(min_needed); - - break; - } - } - - uint64_t relative_new_vaddr = new_vaddr - spslr_program_ptr_address; - std::vector program_ptr_bytes; - program_ptr_bytes.resize(8); - std::memcpy(program_ptr_bytes.data(), &relative_new_vaddr, 8); - bin->patch_address(spslr_program_ptr_address, program_ptr_bytes); - - // Output final program - Builder builder{ *bin }; - builder.build(); - builder.write(out_file); - - std::cout << "Wrote final binary to \"" << out_file << "\"" << std::endl; - - return 0; -} - -bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector& program) { - uint8_t buf[sizeof(SPSLR_INST)]; - - auto append_inst = [&](const SPSLR_INST& inst) -> bool { - int n = spslr_inst_dump(&inst, buf); - if (n < 0) { - std::cerr << "Failed to dump patcher instruction!" << std::endl; - return false; - } - - std::size_t program_ptr = program.size(); - - program.resize(program.size() + n); - std::memcpy(program.data() + program_ptr, buf, n); - return true; - }; - - SPSLR_INST inst; - - // Dump all targets, their fields and command randomization - for (const auto& [tuid, target] : targets) { - inst.opcode = SPSLR_TARGET; - inst.op0.target_uid = tuid; - inst.op1.target_size = target.size; - inst.op2.target_fieldcnt = target.fields.size(); - - if (!append_inst(inst)) - return false; - - for (const auto& [foff, field] : target.fields) { - inst.opcode = SPSLR_FIELD; - inst.op0.field_offset = field.offset; - inst.op1.field_size = field.size; - inst.op2.field_alignment = field.alignment; - inst.op3.field_flags = field.flags; // Note -> This should be done explicitely with SPSLR_FLAG_FIELD_FIXED - - if (!append_inst(inst)) - return false; - } - - inst.opcode = SPSLR_RANDOMIZE; - inst.op0.randomize_target = tuid; - - if (!append_inst(inst)) - return false; - } - - // Dump ipins with addresses relative to vaddr_pivot - auto append_ipin = [&](const CU& cu, const IPIN& ipin) -> bool { - inst.opcode = SPSLR_IPATCH; - inst.op0.ipatch_ptr = ipin.hit->vaddr - vaddr_pivot; - inst.op1.ipatch_size = ipin.imm_size; - inst.op2.ipatch_target = cu.local_targets.at(ipin.local_target); - - std::cout << "IPIN found at 0x" << std::hex << ipin.hit->vaddr << std::dec << std::endl; - - if (!targets.at(inst.op2.ipatch_target).fields.contains(ipin.field_offset)) - return false; - - inst.op3.ipatch_field = targets.at(inst.op2.ipatch_target).fields.at(ipin.field_offset).idx; - return append_inst(inst); - }; - - // Dump dpins with addresses relative to vaddr_pivot and components ordered by level - auto append_dpin = [&](const CU& cu, const DPIN& dpin) -> bool { - std::list sorted_components = dpin.components; - sorted_components.sort([](const DPIN::COMPONENT& a, const DPIN::COMPONENT& b) { - return a.level > b.level; // Descending order - }); - - for (const DPIN::COMPONENT& comp : sorted_components) { - inst.opcode = SPSLR_DPATCH; - inst.op0.dpatch_ptr = dpin.hit->vaddr + comp.offset - vaddr_pivot; - inst.op1.dpatch_target = cu.local_targets.at(comp.target); - - std::cout << "DPIN found at 0x" << std::hex << dpin.hit->vaddr << std::dec << std::endl; - - if (!append_inst(inst)) - return false; - } - - return true; - }; - - // Dump all pins - for (const auto& [cu_uid, cu] : units) { - for (const auto& [ipin_sym, ipin] : cu.ipins) { - if (!append_ipin(cu, ipin)) - return false; - } - - for (const auto& [dpin_sym, dpin] : cu.dpins) { - if (!append_dpin(cu, dpin)) - return false; - } - } - - // Exit patcher program - inst.opcode = SPSLR_EXIT; - if (!append_inst(inst)) - return false; - - return true; -} diff --git a/finalize/symbol_collection.cpp b/finalize/symbol_collection.cpp deleted file mode 100644 index 7225dbc..0000000 --- a/finalize/symbol_collection.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "symbol_collection.h" -#include "accumulation.h" - -#include - -using namespace LIEF::ELF; - -GlobalSymtab global_syms; - -bool collect_symbols(const std::unique_ptr& bin) { - if (!bin) - return false; - - global_syms.symbols.clear(); - - for (const Symbol& sym : bin->symbols()) { - if (sym.name().empty()) - continue; - - if (sym.type() != Symbol::TYPE::OBJECT && - sym.type() != Symbol::TYPE::NOTYPE) - continue; - - if (sym.binding() != Symbol::BINDING::GLOBAL) - continue; - - VADDR vaddr = sym.value(); - - if (global_syms.symbols.contains(sym.name())) { - std::cerr << "Duplicate global symbol \"" << sym.name() << "\"!" << std::endl; - return false; - } - - global_syms.symbols.emplace(sym.name(), vaddr); - } - - return true; -} - -bool associate_symbols() { - for (auto& [cu_uid, cu] : units) { - for (auto& [ipin_sym, ipin] : cu.ipins) { - if (!global_syms.symbols.contains(ipin_sym)) { - std::cerr << "Unable to locate global ipin symbol \"" << ipin_sym << "\"" << std::endl; - return false; - } - - ipin.hit.emplace(); - ipin.hit->vaddr = global_syms.symbols.at(ipin_sym); - } - - for (auto& [dpin_sym, dpin] : cu.dpins) { - if (!global_syms.symbols.contains(dpin_sym)) { - std::cerr << "Unable to locate global dpin symbol \"" << dpin_sym << "\"" << std::endl; - return false; - } - - dpin.hit.emplace(); - dpin.hit->vaddr = global_syms.symbols.at(dpin_sym); - } - } - - return true; -} - diff --git a/finalize/symbol_collection.h b/finalize/symbol_collection.h deleted file mode 100644 index 2d4150c..0000000 --- a/finalize/symbol_collection.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include -#include -#include -#include - -using VADDR = uint64_t; - -struct GlobalSymtab { - std::unordered_map symbols; -}; - -extern GlobalSymtab global_syms; - -bool collect_symbols(const std::unique_ptr& bin); -bool associate_symbols(); - diff --git a/patchcompile/CMakeLists.txt b/patchcompile/CMakeLists.txt new file mode 100644 index 0000000..d51b2f1 --- /dev/null +++ b/patchcompile/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(spslr_patchcompile patchcompile.cpp accumulation.cpp emit.cpp) +set_target_properties(spslr_patchcompile PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO) diff --git a/finalize/accumulation.cpp b/patchcompile/accumulation.cpp similarity index 98% rename from finalize/accumulation.cpp rename to patchcompile/accumulation.cpp index 38dab43..6669b11 100644 --- a/finalize/accumulation.cpp +++ b/patchcompile/accumulation.cpp @@ -37,8 +37,6 @@ static bool global_target_field_cmp(const TARGET& a, const TARGET& b) { } static bool global_target_cmp(const TARGET& a, const TARGET& b) { - // Note -> Later, use hash of type (generated by pinpoint plugin) - if (a.name != b.name) return false; diff --git a/finalize/accumulation.h b/patchcompile/accumulation.h similarity index 89% rename from finalize/accumulation.h rename to patchcompile/accumulation.h index e56f99b..b3cef64 100644 --- a/finalize/accumulation.h +++ b/patchcompile/accumulation.h @@ -9,23 +9,13 @@ #include struct IPIN { - struct HIT { - uint64_t vaddr; - }; - std::string symbol; std::size_t local_target; std::size_t field_offset; std::size_t imm_size; - - std::optional hit; }; struct DPIN { - struct HIT { - uint64_t vaddr; - }; - struct COMPONENT { std::size_t offset; std::size_t level; @@ -34,8 +24,6 @@ struct DPIN { std::string symbol; std::list components; - - std::optional hit; }; struct FIELD { diff --git a/patchcompile/emit.cpp b/patchcompile/emit.cpp new file mode 100644 index 0000000..1d312d8 --- /dev/null +++ b/patchcompile/emit.cpp @@ -0,0 +1,144 @@ +#include "emit.h" +#include "accumulation.h" + +#include + +static bool emit_header(std::ostream& out); +static bool emit_target_header(std::ostream& out, std::size_t uid, std::size_t size, std::size_t fieldcnt); +static bool emit_target_field(std::ostream& out, std::size_t offset, std::size_t size, std::size_t alignment, std::size_t flags); +static bool emit_target_randomize(std::ostream& out, std::size_t uid); +static bool emit_target(std::ostream& out, std::size_t uid, const TARGET& target); +static bool emit_ipin(std::ostream& out, const CU& cu, const IPIN& ipin); +static bool emit_dpin_component(std::ostream& out, std::size_t target, const std::string& sym, std::size_t offset); +static bool emit_dpin(std::ostream& out, const CU& cu, const DPIN& dpin); +static bool emit_exit(std::ostream& out); + +bool emit_patcher_program_asm(std::ostream& out) { + if (!emit_header(out)) + return false; + + // Dump all targets + for (const auto& [uid, target] : targets) { + if (!emit_target(out, uid, target)) + return false; + } + + // Dump all pins + for (const auto& [uid, cu] : units) { + for (const auto& [sym, pin] : cu.ipins) { + if (!emit_ipin(out, cu, pin)) + return false; + } + + for (const auto& [sym, pin] : cu.dpins) { + if (!emit_dpin(out, cu, pin)) + return false; + } + } + + // Exit patcher program + if (!emit_exit(out)) + return false; + + return true; +} + +bool emit_header(std::ostream& out) { + out << ".section .spslr,\"a\",@progbits\n"; + out << ".balign 1\n"; + out << ".globl __spslr_program\n"; + out << ".type __spslr_program, @object\n"; + out << "__spslr_program:\n"; + return !!out; +} + +bool emit_target_header(std::ostream& out, std::size_t uid, std::size_t size, std::size_t fieldcnt) { + out << "\t.byte " << OPCODE_SPSLR_TARGET << "\n"; + out << "\t.long " << uid << "\n"; + out << "\t.long " << size << "\n"; + out << "\t.long " << fieldcnt << "\n"; + return !!out; +} + +bool emit_target_field(std::ostream& out, std::size_t offset, std::size_t size, std::size_t alignment, std::size_t flags) { + out << "\t.byte " << OPCODE_SPSLR_FIELD << "\n"; + out << "\t.long " << offset << "\n"; + out << "\t.long " << size << "\n"; + out << "\t.long " << alignment << "\n"; + out << "\t.long " << flags << "\n"; + return !!out; +} + +bool emit_target_randomize(std::ostream& out, std::size_t uid) { + out << "\t.byte " << OPCODE_SPSLR_RANDOMIZE << "\n"; + out << "\t.long " << uid << "\n"; + return !!out; +} + +bool emit_target(std::ostream& out, std::size_t uid, const TARGET& target) { + if (!emit_target_header(out, uid, target.size, target.fields.size())) + return false; + + for (const auto& [off, field] : target.fields) { + // Note -> Might want to do explicit flag mapping from pinpoint to selfpatch + if (!emit_target_field(out, field.offset, field.size, field.alignment, field.flags)) + return false; + } + + if (!emit_target_randomize(out, uid)) + return false; + + return true; +} + +bool emit_ipin(std::ostream& out, const CU& cu, const IPIN& ipin) { + std::size_t global_target = cu.local_targets.at(ipin.local_target); + + if (!targets.contains(global_target)) + return false; + + const TARGET& target = targets.at(global_target); + + if (!target.fields.contains(ipin.field_offset)) + return false; + + const FIELD& field = target.fields.at(ipin.field_offset); + + out << "\t.byte " << OPCODE_SPSLR_IPATCH << "\n"; + out << "\t.quad " << ipin.symbol << "\n"; + out << "\t.long " << ipin.imm_size << "\n"; + out << "\t.long " << global_target << "\n"; + out << "\t.long " << field.idx << "\n"; + return !!out; +} + +bool emit_dpin_component(std::ostream& out, std::size_t target, const std::string& sym, std::size_t offset) { + out << "\t.byte " << OPCODE_SPSLR_DPATCH << "\n"; + out << "\t.quad " << sym; + if (offset != 0) + out << " + " << offset; + out << "\n"; + out << "\t.long " << target << "\n"; + return !!out; +} + +bool emit_dpin(std::ostream& out, const CU& cu, const DPIN& dpin) { + std::list sorted_components = dpin.components; + sorted_components.sort([](const DPIN::COMPONENT& a, const DPIN::COMPONENT& b) { + return a.level > b.level; // Descending order to handle deeper nested first + }); + + for (const DPIN::COMPONENT& component : sorted_components) { + std::size_t global_target = cu.local_targets.at(component.target); + if (!emit_dpin_component(out, global_target, dpin.symbol, component.offset)) + return false; + } + + return true; +} + +bool emit_exit(std::ostream& out) { + out << "\t.byte " << OPCODE_SPSLR_EXIT << "\n"; + return !!out; +} + diff --git a/patchcompile/emit.h b/patchcompile/emit.h new file mode 100644 index 0000000..a6f1612 --- /dev/null +++ b/patchcompile/emit.h @@ -0,0 +1,4 @@ +#pragma once +#include + +bool emit_patcher_program_asm(std::ostream& out); diff --git a/patchcompile/patchcompile.cpp b/patchcompile/patchcompile.cpp new file mode 100644 index 0000000..5b497fb --- /dev/null +++ b/patchcompile/patchcompile.cpp @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +#include "accumulation.h" +#include "emit.h" + +/* +Notes: + Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top + Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together +*/ + +int main(int argc, char** argv) { + static option long_options[] = { + { "help", no_argument, 0, 0 }, + { "out", required_argument, 0, 0 }, + { 0, 0, 0, 0 } + }; + + int option_index = 0; + int c; + + std::vector spslr_files; + std::string out_file; + + while ((c = getopt_long(argc, argv, "h:o:", long_options, &option_index)) == 0) { + const option& opt = long_options[option_index]; + std::string optname { opt.name }; + + if (optname == "help") { + std::cout << "To use spslr_patchcompile, supply these arguments:" << std::endl; + std::cout << " --out= (the compiled asm file to be written)" << std::endl; + std::cout << " ... (one or more .spslr metadata files)" << std::endl; + return 0; + } else if (optname == "out") { + out_file = std::string{ optarg }; + } else { + std::cerr << "Invalid option, try \"--help\"!" << std::endl; + return 1; + } + } + + if (out_file.empty()) { + std::cerr << "Missing output file path, supply it via --out=!" << std::endl; + return 1; + } + + for (int i = optind; i < argc; ++i) + spslr_files.emplace_back(argv[i]); + + if (spslr_files.empty()) { + std::cerr << "Missing spslr files! Pass one or more .spslr files as positional arguments." << std::endl; + return 1; + } + + if (!accumulate(spslr_files)) { + std::cerr << "Failed to accumulate data from spslr directory!" << std::endl; + return 1; + } + + std::cout << "Gathered a total of " << targets.size() << " distinct targets from " + << units.size() << " compilation units!" << std::endl; + + std::filesystem::path out_path { out_file }; + if (out_path.has_parent_path()) { + std::error_code ec; + std::filesystem::create_directories(out_path.parent_path(), ec); + if (ec) { + std::cerr << "failed to create output directory '" + << out_path.parent_path().string() + << "': " << ec.message() << "\n"; + return 1; + } + } + + std::ofstream out(out_path); + if (!out) { + std::cerr << "Failed to open output file!" << std::endl; + return 1; + } + + if (!emit_patcher_program_asm(out)) { + std::cerr << "Failed to write emit patcher program!" << std::endl; + return 1; + } + + return 0; +} + diff --git a/pinpoint/stage0/target.cpp b/pinpoint/stage0/target.cpp index 3e23492..81d74ce 100644 --- a/pinpoint/stage0/target.cpp +++ b/pinpoint/stage0/target.cpp @@ -271,6 +271,7 @@ static bool field_map_add(std::map& map, const T TargetType::Field tmp_field; tmp_field.offset = field.offset; tmp_field.size = (field.size == 0 ? 1 : field.size); + tmp_field.alignment = (field.alignment == 0 ? 1 : field.alignment); tmp_field.flags = (field.size == 0 ? TargetType::Field::FLAG_DANGEROUS : 0) | field.flags; // Overlaps are dangerous -> remove and integrate into member @@ -289,6 +290,7 @@ static bool field_map_add(std::map& map, const T tmp_field.flags |= (existing_field.flags | TargetType::Field::FLAG_DANGEROUS); tmp_field.offset = combined_offset; + tmp_field.alignment = std::min(tmp_field.alignment, existing_field.alignment); tmp_field.size = combined_size; // Erase overlapping member diff --git a/plan.txt b/plan.txt deleted file mode 100644 index f6e48a7..0000000 --- a/plan.txt +++ /dev/null @@ -1,3 +0,0 @@ -Move patcher generation to pre-link stage - - Aggregate meta data files - - Generate patcher object file than links against symbols diff --git a/selfpatch/CMakeLists.txt b/selfpatch/CMakeLists.txt index 00befad..a9c837b 100644 --- a/selfpatch/CMakeLists.txt +++ b/selfpatch/CMakeLists.txt @@ -5,4 +5,4 @@ target_include_directories(spslr_selfpatch PUBLIC $ ) -target_include_directories(spslr_finalize PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_program.h +target_include_directories(spslr_patchcompile PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_program.h diff --git a/selfpatch/src/selfpatch.c b/selfpatch/src/selfpatch.c index 658278f..c391e12 100644 --- a/selfpatch/src/selfpatch.c +++ b/selfpatch/src/selfpatch.c @@ -6,18 +6,7 @@ #include "targets.h" #include "patcher.h" -const uint8_t* __spslr_program = NULL; - -static void* spslr_ptr_absolute(uint64_t relative) { - // To allow ASLR, all patcher addresses are relative to &__spslr_program - return ((uint8_t*)&__spslr_program) + relative; -} - -static void spslr_init_program_ptr() { - // Finalizer patches __spslr_program to be the relative offset from &__spslr_program to the program - uint64_t relative = (uint64_t)__spslr_program; - __spslr_program = (const uint8_t*)spslr_ptr_absolute(relative); -} +extern const uint8_t __spslr_program[]; static int spslr_do(const struct SPSLR_INST* inst) { if (!inst) @@ -27,18 +16,18 @@ static int spslr_do(const struct SPSLR_INST* inst) { static uint32_t pending_fields_target = 0; if (pending_fields) { - if (inst->opcode != SPSLR_FIELD) { + if (inst->op != SPSLR_FIELD) { fprintf(stderr, "spslr_do encountered non field instruction where a field instruction was expected\n"); return -1; } pending_fields--; - } else if (inst->opcode == SPSLR_FIELD) { + } else if (inst->op == SPSLR_FIELD) { fprintf(stderr, "spslr_do encountered field instruction where none was expected\n"); return -1; } - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: pending_fields = inst->op2.target_fieldcnt; pending_fields_target = inst->op0.target_uid; @@ -49,27 +38,22 @@ static int spslr_do(const struct SPSLR_INST* inst) { case SPSLR_RANDOMIZE: return spslr_randomize(inst->op0.randomize_target); case SPSLR_IPATCH: - return spslr_ipatch(spslr_ptr_absolute(inst->op0.ipatch_ptr), inst->op1.ipatch_size, + return spslr_ipatch((void*)(uintptr_t)inst->op0.ipatch_ptr, inst->op1.ipatch_size, inst->op2.ipatch_target, inst->op3.ipatch_field); case SPSLR_DPATCH: - return spslr_dpatch(spslr_ptr_absolute(inst->op0.dpatch_ptr), inst->op1.dpatch_target); + return spslr_dpatch((void*)(uintptr_t)inst->op0.dpatch_ptr, inst->op1.dpatch_target); default: return -1; } } void spslr_selfpatch() { - if (!__spslr_program) { - fprintf(stderr, "spslr_selfpatch has no patcher program (finalize this binary to use SPSLR)\n"); - return; - } - - spslr_init_program_ptr(); + const uint8_t* pc = __spslr_program; int sz; struct SPSLR_INST inst; - while ((sz = spslr_inst_load(&inst, __spslr_program)) > 0) { - if (inst.opcode == SPSLR_EXIT) { + while ((sz = spslr_inst_load(&inst, pc)) > 0) { + if (inst.op == SPSLR_EXIT) { spslr_targets_clear(); return; } @@ -79,7 +63,7 @@ void spslr_selfpatch() { exit(1); } - __spslr_program += sz; + pc += sz; } fprintf(stderr, "spslr_selfpatch encountered invalid instruction\n"); diff --git a/selfpatch/src/spslr_program.h b/selfpatch/src/spslr_program.h index 38679bc..3c9dbd4 100644 --- a/selfpatch/src/spslr_program.h +++ b/selfpatch/src/spslr_program.h @@ -6,7 +6,14 @@ #define SPSLR_FLAG_FIELD_FIXED 1 -enum SPSLR_OPCODE { +#define OPCODE_SPSLR_TARGET 1 +#define OPCODE_SPSLR_FIELD 2 +#define OPCODE_SPSLR_RANDOMIZE 3 +#define OPCODE_SPSLR_IPATCH 4 +#define OPCODE_SPSLR_DPATCH 5 +#define OPCODE_SPSLR_EXIT 6 + +enum SPSLR_OP { SPSLR_TARGET, // uid, size, field count SPSLR_FIELD, // offset, size, alignment, flags SPSLR_RANDOMIZE, // target uid @@ -16,7 +23,7 @@ enum SPSLR_OPCODE { }; struct SPSLR_INST { - enum SPSLR_OPCODE opcode; + enum SPSLR_OP op; union { uint32_t target_uid; @@ -49,19 +56,19 @@ static inline int spslr_inst_dump_opcode(const struct SPSLR_INST* inst, uint8_t* if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: - *buf = 1; return 1; + *buf = OPCODE_SPSLR_TARGET; return 1; case SPSLR_FIELD: - *buf = 2; return 1; + *buf = OPCODE_SPSLR_FIELD; return 1; case SPSLR_RANDOMIZE: - *buf = 3; return 1; + *buf = OPCODE_SPSLR_RANDOMIZE; return 1; case SPSLR_IPATCH: - *buf = 4; return 1; + *buf = OPCODE_SPSLR_IPATCH; return 1; case SPSLR_DPATCH: - *buf = 5; return 1; + *buf = OPCODE_SPSLR_DPATCH; return 1; case SPSLR_EXIT: - *buf = 6; return 1; + *buf = OPCODE_SPSLR_EXIT; return 1; default: return -1; } @@ -72,18 +79,18 @@ static inline int spslr_inst_load_opcode(struct SPSLR_INST* inst, const uint8_t* return -1; switch (*buf) { - case 1: - inst->opcode = SPSLR_TARGET; return 1; - case 2: - inst->opcode = SPSLR_FIELD; return 1; - case 3: - inst->opcode = SPSLR_RANDOMIZE; return 1; - case 4: - inst->opcode = SPSLR_IPATCH; return 1; - case 5: - inst->opcode = SPSLR_DPATCH; return 1; - case 6: - inst->opcode = SPSLR_EXIT; return 1; + case OPCODE_SPSLR_TARGET: + inst->op = SPSLR_TARGET; return 1; + case OPCODE_SPSLR_FIELD: + inst->op = SPSLR_FIELD; return 1; + case OPCODE_SPSLR_RANDOMIZE: + inst->op = SPSLR_RANDOMIZE; return 1; + case OPCODE_SPSLR_IPATCH: + inst->op = SPSLR_IPATCH; return 1; + case OPCODE_SPSLR_DPATCH: + inst->op = SPSLR_DPATCH; return 1; + case OPCODE_SPSLR_EXIT: + inst->op = SPSLR_EXIT; return 1; default: return -1; } @@ -96,7 +103,7 @@ static inline int spslr_inst_dump_op0(const struct SPSLR_INST* inst, uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: DUMP_OP_RET(inst->op0.target_uid); case SPSLR_FIELD: @@ -118,7 +125,7 @@ static inline int spslr_inst_load_op0(struct SPSLR_INST* inst, const uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: LOAD_OP_RET(inst->op0.target_uid); case SPSLR_FIELD: @@ -140,7 +147,7 @@ static inline int spslr_inst_dump_op1(const struct SPSLR_INST* inst, uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: DUMP_OP_RET(inst->op1.target_size); case SPSLR_FIELD: @@ -161,7 +168,7 @@ static inline int spslr_inst_load_op1(struct SPSLR_INST* inst, const uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: LOAD_OP_RET(inst->op1.target_size); case SPSLR_FIELD: @@ -182,7 +189,7 @@ static inline int spslr_inst_dump_op2(const struct SPSLR_INST* inst, uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: DUMP_OP_RET(inst->op2.target_fieldcnt); case SPSLR_FIELD: @@ -202,7 +209,7 @@ static inline int spslr_inst_load_op2(struct SPSLR_INST* inst, const uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_TARGET: LOAD_OP_RET(inst->op2.target_fieldcnt); case SPSLR_FIELD: @@ -222,7 +229,7 @@ static inline int spslr_inst_dump_op3(const struct SPSLR_INST* inst, uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_FIELD: DUMP_OP_RET(inst->op3.field_flags); case SPSLR_IPATCH: @@ -241,7 +248,7 @@ static inline int spslr_inst_load_op3(struct SPSLR_INST* inst, const uint8_t* bu if (!inst || !buf) return -1; - switch (inst->opcode) { + switch (inst->op) { case SPSLR_FIELD: LOAD_OP_RET(inst->op3.field_flags); case SPSLR_IPATCH: diff --git a/subject/CMakeLists.txt b/subject/CMakeLists.txt index 9fd4e16..17b8811 100644 --- a/subject/CMakeLists.txt +++ b/subject/CMakeLists.txt @@ -1,37 +1,68 @@ -add_executable(subject main.c second.c sub/second.c) -target_include_directories(subject PRIVATE .) -add_dependencies(subject spslr_pinpoint spslr_finalize spslr_selfpatch) -target_link_libraries(subject PRIVATE spslr_selfpatch) +set(SUBJECT_SRC + main.c + second.c + sub/second.c +) set(SUBJECT_SPSLR_METADIR "${CMAKE_CURRENT_BINARY_DIR}/spslr") set(SUBJECT_SPSLR_SRCROOT "${CMAKE_CURRENT_SOURCE_DIR}") -target_compile_options(subject PRIVATE -O1 -fplugin=$ -fdump-tree-separate_offset -fdump-tree-asm_offset - -fplugin-arg-spslr_pinpoint-srcroot=${SUBJECT_SPSLR_SRCROOT} - -fplugin-arg-spslr_pinpoint-metadir=${SUBJECT_SPSLR_METADIR}) - file(MAKE_DIRECTORY "${SUBJECT_SPSLR_METADIR}") -# Apply spslr_finalizer to subject +add_library(subject_objs OBJECT ${SUBJECT_SRC}) +target_include_directories(subject_objs PRIVATE .) +target_link_libraries(subject_objs PRIVATE spslr_selfpatch) +add_dependencies(subject_objs spslr_pinpoint) -get_target_property(SUBJECT_SOURCES subject SOURCES) +target_compile_options(subject_objs PRIVATE + -O1 + -fplugin=$ + -fplugin-arg-spslr_pinpoint-srcroot=${SUBJECT_SPSLR_SRCROOT} + -fplugin-arg-spslr_pinpoint-metadir=${SUBJECT_SPSLR_METADIR} +) set(SUBJECT_SPSLR_FILES "") -foreach(src IN LISTS SUBJECT_SOURCES) +foreach(src IN LISTS SUBJECT_SRC) get_filename_component(abs_src "${src}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") file(RELATIVE_PATH rel_src "${SUBJECT_SPSLR_SRCROOT}" "${abs_src}") file(TO_CMAKE_PATH "${rel_src}" rel_src) list(APPEND SUBJECT_SPSLR_FILES "${SUBJECT_SPSLR_METADIR}/${rel_src}.spslr") endforeach() +set(SUBJECT_SPSLR_ASM "${CMAKE_CURRENT_BINARY_DIR}/subject_spslr_program.S") +set(SUBJECT_SPSLR_OBJ "${CMAKE_CURRENT_BINARY_DIR}/subject_spslr_program.o") + add_custom_command( - TARGET subject - POST_BUILD - COMMAND $ - --bin=$ - --out=${CMAKE_BINARY_DIR}/subject_final + OUTPUT "${SUBJECT_SPSLR_ASM}" + COMMAND $ + --out=${SUBJECT_SPSLR_ASM} ${SUBJECT_SPSLR_FILES} - COMMAND chmod +x ${CMAKE_BINARY_DIR}/subject_final + DEPENDS + spslr_patchcompile + $ VERBATIM ) +add_custom_command( + OUTPUT "${SUBJECT_SPSLR_OBJ}" + COMMAND ${CMAKE_C_COMPILER} + -c "${SUBJECT_SPSLR_ASM}" + -o "${SUBJECT_SPSLR_OBJ}" + DEPENDS "${SUBJECT_SPSLR_ASM}" + VERBATIM +) + +set_source_files_properties("${SUBJECT_SPSLR_OBJ}" PROPERTIES + GENERATED TRUE + EXTERNAL_OBJECT TRUE +) + +add_executable(subject + $ + "${SUBJECT_SPSLR_OBJ}" +) + +target_include_directories(subject PRIVATE .) +target_link_libraries(subject PRIVATE spslr_selfpatch) +add_dependencies(subject spslr_selfpatch) +