add PIE binary support by resolving runtime load address
This commit is contained in:
parent
8319383d8e
commit
04e359f710
@ -1,6 +1,9 @@
|
||||
#include "tracer.hpp"
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/wait.h>
|
||||
@ -17,23 +20,19 @@
|
||||
#define DR7_LEN_8 0x2
|
||||
|
||||
void Tracer::setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size) {
|
||||
struct user_regs_struct regs;
|
||||
|
||||
// Read debug registers
|
||||
uint64_t dr7 = ptrace(PTRACE_PEEKUSER, pid,
|
||||
offsetof(struct user, u_debugreg[7]), 0);
|
||||
|
||||
// Use DR0 for our watchpoint
|
||||
ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[0]), address);
|
||||
|
||||
// Configure DR7 for DR0
|
||||
uint64_t dr7 = 0;
|
||||
|
||||
// Set local enable bit for DR0 (bit 0)
|
||||
dr7 |= (1 << 0);
|
||||
|
||||
// Set condition to break on read/write (bits 16-17)
|
||||
// Set condition to break on read/write (bits 16-17 for DR0)
|
||||
dr7 |= (DR7_BREAK_ON_RW << 16);
|
||||
|
||||
// Set length based on size (bits 18-19)
|
||||
// Set length based on size (bits 18-19 for DR0)
|
||||
uint64_t len_code;
|
||||
if (size == 1) len_code = DR7_LEN_1;
|
||||
else if (size == 2) len_code = DR7_LEN_2;
|
||||
@ -42,7 +41,10 @@ void Tracer::setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size)
|
||||
|
||||
dr7 |= (len_code << 18);
|
||||
|
||||
// Write back DR7
|
||||
// Also set GE (bit 9) for exact breakpoint detection
|
||||
dr7 |= (1 << 9);
|
||||
|
||||
// Write DR7
|
||||
ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[7]), dr7);
|
||||
}
|
||||
|
||||
@ -54,6 +56,39 @@ void Tracer::handle_watchpoint_hit(pid_t pid, uint64_t address) {
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
uint64_t Tracer::get_load_address(pid_t pid, const std::string &exec_path) {
|
||||
std::string maps_path = std::format("/proc/{}/maps", pid);
|
||||
std::ifstream maps_file(maps_path);
|
||||
|
||||
if (!maps_file.is_open()) {
|
||||
std::cerr << "Error: Cannot open " << maps_path << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::filesystem::path exec_name = std::filesystem::path(exec_path).filename();
|
||||
std::string line;
|
||||
|
||||
while (std::getline(maps_file, line)) {
|
||||
// Look for executable mapping containing the binary name
|
||||
if (line.find(exec_name.string()) != std::string::npos &&
|
||||
line.find(" r-xp ") != std::string::npos) {
|
||||
// Parse the address range
|
||||
std::istringstream iss(line);
|
||||
std::string addr_range;
|
||||
iss >> addr_range;
|
||||
|
||||
// Extract start address
|
||||
size_t dash_pos = addr_range.find('-');
|
||||
if (dash_pos != std::string::npos) {
|
||||
std::string start_addr_str = addr_range.substr(0, dash_pos);
|
||||
return std::stoull(start_addr_str, nullptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Tracer::watch_variable(const std::string &exec_path, uint64_t address, size_t size) {
|
||||
pid_t pid = fork();
|
||||
|
||||
@ -73,8 +108,15 @@ void Tracer::watch_variable(const std::string &exec_path, uint64_t address, size
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the actual load address (for PIE binaries)
|
||||
uint64_t load_addr = get_load_address(pid, exec_path);
|
||||
uint64_t runtime_addr = load_addr + address;
|
||||
|
||||
std::cout << std::format("Load address: 0x{:x}", load_addr) << std::endl;
|
||||
std::cout << std::format("Runtime address: 0x{:x}", runtime_addr) << std::endl;
|
||||
|
||||
// Set up hardware watchpoint
|
||||
setup_hardware_watchpoint(pid, address, size);
|
||||
setup_hardware_watchpoint(pid, runtime_addr, size);
|
||||
|
||||
// Continue execution and monitor for watchpoint hits
|
||||
ptrace(PTRACE_CONT, pid, 0, 0);
|
||||
@ -97,7 +139,7 @@ void Tracer::watch_variable(const std::string &exec_path, uint64_t address, size
|
||||
offsetof(struct user, u_debugreg[6]), 0);
|
||||
|
||||
if (dr6 & 0x1) { // DR0 triggered
|
||||
handle_watchpoint_hit(pid, address);
|
||||
handle_watchpoint_hit(pid, runtime_addr);
|
||||
|
||||
// Clear DR6
|
||||
ptrace(PTRACE_POKEUSER, pid,
|
||||
|
||||
@ -11,6 +11,7 @@ public:
|
||||
private:
|
||||
void setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size);
|
||||
void handle_watchpoint_hit(pid_t pid, uint64_t address);
|
||||
uint64_t get_load_address(pid_t pid, const std::string &exec_path);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user