diff --git a/Debugger.cpp b/Debugger.cpp index 84984b3..9bcb480 100644 --- a/Debugger.cpp +++ b/Debugger.cpp @@ -1,90 +1,184 @@ #include "Debugger.hpp" +#include #include +#include +#include #include +#include #include #include -#include -Debugger::Debugger(const std::string& prog_name) : program_name(prog_name) { - std::cout << "[+] Debugger initialized for program: " << program_name << "\n"; +Debugger::Debugger(const std::string &prog_name) : program_name(prog_name) { + std::cout << "[+] Debugger initialized for program: " << program_name << "\n"; } void Debugger::run() { - child_pid = fork(); - if (child_pid == 0) { - run_target(); - } else if (child_pid > 0) { - run_debugger(); - } else { - std::cerr << "[!] fork() failed.\n"; - } + child_pid = fork(); + if (child_pid == 0) { + run_target(); + } else if (child_pid > 0) { + run_debugger(); + } else { + std::cerr << "[!] fork() failed.\n"; + } } void Debugger::run_target() { - std::cout << "[+] Child process started.\n"; - ptrace(PTRACE_TRACEME, 0, nullptr, nullptr); - execl(program_name.c_str(), program_name.c_str(), nullptr); + std::cout << "[+] Child process started.\n"; + ptrace(static_cast<__ptrace_request>(PTRACE_TRACEME), 0, nullptr, nullptr); + execl(program_name.c_str(), program_name.c_str(), nullptr); } void Debugger::run_debugger() { - int status; - waitpid(child_pid, &status, 0); - std::cout << "[+] Debugger attached to PID: " << child_pid << "\n"; + int status; + waitpid(child_pid, &status, 0); + std::cout << "[+] Debugger attached to PID: " << child_pid << "\n"; + ptrace(PTRACE_SINGLESTEP, child_pid, nullptr, nullptr); + waitpid(child_pid, &status, 0); + go_until_x0_filled(); + print_registers(child_pid); + get_opcode(); + single_step(); + print_registers(child_pid); + get_opcode(); + std::cout << "[+] Child process exited.\n"; +} - DEBUGING(); +void Debugger::single_step(void){ + int status; - ptrace(PTRACE_CONT, child_pid, nullptr, nullptr); - waitpid(child_pid, &status, 0); + std::cout << "[+] Single stepping...\n"; + ptrace(PTRACE_SINGLESTEP, child_pid, nullptr, nullptr); + waitpid(child_pid, &status, 0); +} - std::cout << "[+] Child process exited.\n"; +void Debugger::go_until_x0_filled(void) +{ + while (1) + { + if (get_x0() != 0) + break ; + single_step(); + } +} + +uint32_t Debugger::get_opcode(void){ + struct user_pt_regs { + uint64_t regs[31]; // x0-x30 + uint64_t sp; // Stack Pointer + uint64_t pc; // Program Counter + uint64_t pstate; // Processor State + } regs; + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + if (ptrace(PTRACE_GETREGSET, child_pid, (void*)NT_PRSTATUS, &io) == -1) { + perror("ptrace(PTRACE_GETREGSET)"); + return 0; + } + return ptrace(PTRACE_PEEKTEXT, child_pid, regs.pc, nullptr); +} + +uint64_t Debugger::get_x0(void) { + struct user_pt_regs { + uint64_t regs[31]; // x0-x30 + uint64_t sp; // Stack Pointer + uint64_t pc; // Program Counter + uint64_t pstate; // Processor State + } regs; + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + if (ptrace(PTRACE_GETREGSET, child_pid, (void*)NT_PRSTATUS, &io) == -1) { + perror("ptrace(PTRACE_GETREGSET)"); + return 0; + } + return regs.regs[0]; // x0 is the first register +} + +uint64_t Debugger::get_pc(void) { + struct user_pt_regs { + uint64_t regs[31]; // x0-x30 + uint64_t sp; // Stack Pointer + uint64_t pc; // Program Counter + uint64_t pstate; // Processor State + } regs; + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + if (ptrace(PTRACE_GETREGSET, child_pid, (void*)NT_PRSTATUS, &io) == -1) { + perror("ptrace(PTRACE_GETREGSET)"); + return 0; + } + return regs.pc; // Return the program counter } void Debugger::breakpoint_list() { - std::cout << "Breakpoints:\n"; - for (const auto& bp : breakpoints) { - std::cout << bp << std::endl; - } + std::cout << "Breakpoints:\n"; + for (const auto &bp : breakpoints) { + std::cout << bp << std::endl; + } } void Debugger::set_breakpoint(pid_t pid, std::intptr_t addr) { - Breakpoint bp(pid, addr); - bp.enable(); - breakpoints.push_back(bp); - std::cout << "[+] Breakpoint set at address: " << std::hex << addr << std::dec << "\n"; + Breakpoint bp(pid, addr); + bp.enable(); + breakpoints.push_back(bp); + std::cout << "[+] Breakpoint set at address: " << std::hex << addr << std::dec + << "\n"; } void Debugger::remove_breakpoint(pid_t pid, std::intptr_t addr) { - auto it = std::remove_if(breakpoints.begin(), breakpoints.end(), - [pid, addr](const Breakpoint& bp) { - return bp.get_address() == addr && bp.is_enabled(); - }); - if (it != breakpoints.end()) { - it->disable(); - breakpoints.erase(it, breakpoints.end()); - std::cout << "[+] Breakpoint removed at address: " << std::hex << addr << std::dec << "\n"; - } else { - std::cout << "[-] No breakpoint found at address: " << std::hex << addr << std::dec << "\n"; - } + auto it = std::remove_if(breakpoints.begin(), breakpoints.end(), + [pid, addr](const Breakpoint &bp) { + return bp.get_address() == addr && bp.is_enabled(); + }); + if (it != breakpoints.end()) { + it->disable(); + breakpoints.erase(it, breakpoints.end()); + std::cout << "[+] Breakpoint removed at address: " << std::hex << addr + << std::dec << "\n"; + } else { + std::cout << "[-] No breakpoint found at address: " << std::hex << addr + << std::dec << "\n"; + } } -void Debugger::DEBUGING() { - std::cout << "[+] Entering debugging loop. Type 'exit' to quit.\n"; - std::string command; - while (true) { - std::cout << "debugger> "; - std::getline(std::cin, command); - if (command == "exit") { - break; - } else if (command == "list") { - breakpoint_list(); - } else if (command.substr(0, 3) == "set") { - std::intptr_t addr = std::stol(command.substr(4), nullptr, 16); - set_breakpoint(child_pid, addr); - } else if (command.substr(0, 6) == "remove") { - std::intptr_t addr = std::stol(command.substr(7), nullptr, 16); - remove_breakpoint(child_pid, addr); - } else { - std::cout << "Unknown command: " << command << "\n"; - } + +// Attention: ce code est spécifique à l'architecture AArch64 +void Debugger::print_registers(pid_t pid) { + struct user_pt_regs { + uint64_t regs[31]; // x0-x30 + uint64_t sp; // Stack Pointer + uint64_t pc; // Program Counter + uint64_t pstate; // Processor State + } regs; + + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + + if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &io) == -1) { + perror("ptrace(PTRACE_GETREGSET)"); + return; } + + std::ios old_fmt(nullptr); + old_fmt.copyfmt(std::cout); + + std::cout << std::hex << std::setfill('0'); + + std::cout << "==== Register Dump (AArch64) ====" << std::endl; + + for (int i = 0; i < 31; i++) { + std::cout << "x" << std::dec << std::setw(2) << std::right << i + << " = 0x" << std::hex << std::setw(16) << regs.regs[i] << "\n"; + } + + std::cout << " sp = 0x" << std::setw(16) << regs.sp << std::endl; + std::cout << " pc = 0x" << std::setw(16) << regs.pc << std::endl; + std::cout << " pstate = 0x" << std::setw(16) << regs.pstate << std::endl; + + std::cout.copyfmt(old_fmt); } + diff --git a/Debugger.hpp b/Debugger.hpp index 2a89ba3..65d3ea3 100644 --- a/Debugger.hpp +++ b/Debugger.hpp @@ -6,6 +6,7 @@ #include #include "Breakpoint.hpp" + class Debugger { public: Debugger(const std::string& prog_name); @@ -14,7 +15,13 @@ public: void set_breakpoint(pid_t pid, std::intptr_t addr); void remove_breakpoint(pid_t pid, std::intptr_t addr); void run(); + void print_registers(pid_t pid); void DEBUGING(void); + void go_until_x0_filled(void); + void single_step(void); + uint64_t get_x0(void); + uint64_t get_pc(void); + uint32_t get_opcode(void); private: void run_target();