From 048d28b28dcaba3b0773c129d8dd63084420b01e Mon Sep 17 00:00:00 2001 From: Nicolas James Date: Thu, 13 Feb 2025 17:29:05 +1100 Subject: initial commit --- src/main.cc | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/main.cc (limited to 'src/main.cc') diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..6c049b5 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,164 @@ +#include "main.hh" + +using pointer_t = std::byte* const; +struct pointer { + const pointer_t address; + const std::byte* const deref; + std::shared_ptr parent; + const size_t start_offset; + const size_t total_offset; +}; +using pointers_t = std::vector>; + +static pointers_t make_pointers(const memory::buffer_t& memory, + const pointers_t& targets, + const void* const start, const int tolerance, + const size_t total_offset) { + + pointers_t ret{}; + for (auto i = 0ul; i < std::size(memory) / sizeof(pointer_t); ++i) { + const auto byte_offset = i * sizeof(pointer_t); + + const std::byte* const deref = [&]() { + std::byte* ret; + std::memcpy(&ret, &memory[byte_offset], sizeof(void*)); + return ret; + }(); + + // -1 is 0xff...etc + if (deref == nullptr || deref > (pointer_t)(-1) - tolerance) { + continue; + } + + const auto lower = std::lower_bound( + std::begin(targets), std::end(targets), deref, + [](const auto& target, const std::byte* const& deref) { + return target->address < deref; + }); + const auto upper = std::upper_bound( + lower, std::end(targets), deref + tolerance, + [](const std::byte* const& deref, const auto& target) { + return deref < target->address; + }); + + std::for_each(lower, upper, [&](const auto& target) { + const auto address = (std::byte*)start + byte_offset; + if (address == target->address || deref == target->deref) { + return; + } + ret.emplace_back(std::make_shared( + pointer{.address = address, + .deref = deref, + .parent = target, + .start_offset = byte_offset, + .total_offset = total_offset + byte_offset})); + }); + } + return ret; +} + +static pointers_t make_pointer_chain(const char* const binary_name, + const pointer_t target, const int depth, + const int tolerance) { + const memory::maps maps{binary_name}; + const pid_t pid = std::stoi(maps.get_pid()); + + pointers_t ret{std::make_shared( + pointer{.address = target, .parent = nullptr})}; + for (int i = 0; i < depth; ++i) { + + size_t total_offset = 0; + pointers_t pointers{}; + for (const auto& map : maps) { + const auto size = static_cast((std::byte*)map.end - + (std::byte*)map.start); + total_offset += size; + if (!map.is_read() || !map.is_write() || !map.is_protected()) { + continue; + } + + const memory::buffer_t memory = + memory::read_buffer(size, pid, map.start); + + std::ranges::move(make_pointers(memory, ret, map.start, tolerance, + total_offset - size), + std::back_inserter(pointers)); + } + + std::cout << "depth: " << i + 1 << " = " << std::size(pointers) + << " chains...\n"; + + if (std::size(pointers) == 0) { + std::cout << "warning: only discovered chains of depth " << i + << '\n'; + break; + } + + ret = std::move(pointers); + } + return ret; +} + +static void do_pointer_scanner(const char* const binary_name, + const pointer_t target, const int depth, + const int tolerance) { + + const auto pointer_chains = + make_pointer_chain(binary_name, target, depth, tolerance); + + for (const auto& chain : pointer_chains) { + std::cout << std::hex << chain->total_offset << " = " << chain->address + << std::dec; + const std::byte* prev = chain->deref; + for (const decltype(chain->parent)* p = &chain->parent; p != nullptr; + p = &(*p)->parent) { + if (*p == nullptr) { + break; + } + + if ((*p)->address != nullptr) { + std::cout << " ] "; + } + if (prev != nullptr) { + std::cout << ((*p)->address - prev); + } + prev = (*p)->deref; + + if ((*p)->address == nullptr) { + break; + } + } + std::cout << '\n'; + } +} + +int main(const int argc, const char* const argv[]) { + if (argc < 3 || argc > 5) { + std::cout << "usage: " << argv[0] + << " BINARY_NAME 0xADDRESS DEPTH=10 " + "TOLERANCE=4096bytes\n"; + return EXIT_SUCCESS; + } + + std::cout.sync_with_stdio(false); + + try { + const char* const binary_name = argv[1]; + const pointer_t address = [&]() { + std::stringstream ss{argv[2]}; + void* ptr; + ss >> std::hex >> ptr; + return static_cast(ptr); + }(); + const int depth = (argc >= 4 ? std::stoi(argv[3]) : 10); + const int tolerance = (argc >= 5 ? std::stoi(argv[4]) : 4096); + + do_pointer_scanner(binary_name, address, depth, tolerance); + } catch (const std::exception& e) { + std::cerr << "unhandled exception!\n what(): " << e.what() << '\n'; + } catch (...) { + std::cerr << "unhandled unknown exception!\n"; + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3