diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-05-02 19:38:33 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-02 19:38:33 +0200 |
| commit | 87979899ce833ca477bb563b84e3698224119dab (patch) | |
| tree | df67a0724de4c76ce594222747220c233c3bc7f5 /dev/LibDebugger | |
| parent | 3afc481dc64a07fe7fcaff9ce7a12a492c3ec8e7 (diff) | |
| parent | fb12b9730d78052f5cafbd84fbc9a830a22cec17 (diff) | |
Merge pull request #4 from nekernel-org/dev
0.0.1
Diffstat (limited to 'dev/LibDebugger')
| -rw-r--r-- | dev/LibDebugger/DebuggerContract.h | 72 | ||||
| -rw-r--r-- | dev/LibDebugger/NeKernelContract.h | 63 | ||||
| -rw-r--r-- | dev/LibDebugger/POSIXMachContract.h | 214 | ||||
| -rw-r--r-- | dev/LibDebugger/src/POSIXMachContract.cc | 189 |
4 files changed, 295 insertions, 243 deletions
diff --git a/dev/LibDebugger/DebuggerContract.h b/dev/LibDebugger/DebuggerContract.h index 5d4f728..0f4bc10 100644 --- a/dev/LibDebugger/DebuggerContract.h +++ b/dev/LibDebugger/DebuggerContract.h @@ -1,42 +1,44 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ #pragma once -#include <iostream> +#include <cstdint> +#include <string> #include <unordered_map> -namespace LibDebugger -{ - typedef uint64_t ProcessID; - typedef char* CAddress; - - /// \brief Debugger contract class in C++, as per the design states. - /// \author Amlal El Mahrouss - class DebuggerContract - { - public: - explicit DebuggerContract() = default; - virtual ~DebuggerContract() = default; - - public: - DebuggerContract& operator=(const DebuggerContract&) = default; - DebuggerContract(const DebuggerContract&) = default; - - public: - virtual bool Attach(ProcessID pid) noexcept = 0; - virtual bool Break(CAddress addr) noexcept = 0; - virtual bool Continue() noexcept = 0; - virtual bool Detach() noexcept = 0; - - virtual std::unordered_map<uintptr_t, uintptr_t>& Get() - { - return m_breakpoints; - } - - protected: - pid_t m_pid; - std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; - }; -} // namespace LibDebugger::POSIX +namespace LibDebugger { +class DebuggerContract; + +/// \brief Process ID +typedef uint64_t ProcessID; + +/// \brief Address type, a la BSD. +typedef char* CAddress; + +/// \brief Debugger contract class in C++, as per the design states. +/// \author Amlal El Mahrouss +class DebuggerContract { + public: + explicit DebuggerContract() = default; + virtual ~DebuggerContract() = default; + + public: + DebuggerContract& operator=(const DebuggerContract&) = default; + DebuggerContract(const DebuggerContract&) = default; + + public: + virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept = 0; + virtual bool Breakpoint(std::string symbol) noexcept = 0; + virtual bool Break() noexcept = 0; + virtual bool Continue() noexcept = 0; + virtual bool Detach() noexcept = 0; + + virtual std::unordered_map<uintptr_t, uintptr_t>& Get() { return m_breakpoints; } + + protected: + ProcessID m_pid; + std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; +}; +} // namespace LibDebugger diff --git a/dev/LibDebugger/NeKernelContract.h b/dev/LibDebugger/NeKernelContract.h new file mode 100644 index 0000000..8e54ab2 --- /dev/null +++ b/dev/LibDebugger/NeKernelContract.h @@ -0,0 +1,63 @@ + +/*** + (C) 2025 Amlal El Mahrouss + */ + +#ifndef LD_NEKERNEL_CONTRACT_H +#define LD_NEKERNEL_CONTRACT_H + +#include <LibDebugger/DebuggerContract.h> + +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <unistd.h> + +#define kDebugUnboundPort 0x0FEED + +#define kDebugMag0 'K' +#define kDebugMag1 'D' +#define kDebugMag2 'B' +#define kDebugMag3 'G' + +#define kDebugSourceFile 23 +#define kDebugLine 33 +#define kDebugTeam 43 +#define kDebugEOP 49 + +namespace LibDebugger::NeKernel { +class NeKernelContract; + +namespace Detail { + class NeKernelPortHeader; + + inline constexpr size_t kDebugTypeLen = 256U; + + typedef char rt_debug_type[kDebugTypeLen]; + + class NeKernelPortHeader final { + public: + int16_t fPort; + int16_t fPortBsy; + }; +} // namespace Detail + +class NeKernelContract : public DebuggerContract { + public: + NeKernelContract(); + virtual ~NeKernelContract(); + + // Override additional methods from DebuggerContract + virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept override; + virtual bool Breakpoint(std::string symbol) noexcept override; + virtual bool Break() noexcept override; + virtual bool Continue() noexcept override; + virtual bool Detach() noexcept override; + + private: + std::string m_ip_address; + std::string m_port; +}; +} // namespace LibDebugger::NeKernel + +#endif // LD_NEKERNEL_CONTRACT_H
\ No newline at end of file diff --git a/dev/LibDebugger/POSIXMachContract.h b/dev/LibDebugger/POSIXMachContract.h index 6ff083f..5904cd2 100644 --- a/dev/LibDebugger/POSIXMachContract.h +++ b/dev/LibDebugger/POSIXMachContract.h @@ -1,144 +1,158 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ #pragma once -#ifdef _WIN32 -#error Windows doesn't have a POSIX/Mach subsystem, please combine with windows instead. -#endif +#ifdef __APPLE__ /// @file POSIXMachContract.h -/// @brief POSIX/Mach debugger. +/// @brief POSIX Mach debugger. +#include <LibCompiler/Defines.h> #include <LibDebugger/DebuggerContract.h> +#include <stdint.h> #include <sys/ptrace.h> #include <sys/types.h> -#include <sys/wait.h> #include <sys/user.h> +#include <sys/wait.h> #include <unistd.h> -#include <stdint.h> -#ifdef __APPLE__ +#include <filesystem> +#include <iostream> + +#include <dlfcn.h> +#include <mach-o/dyld.h> #include <mach/mach.h> #include <mach/mach_error.h> +#include <signal.h> -#define PTRACE_ATTACH PT_ATTACHEXC -#define PTRACE_DETACH PT_DETACH +LC_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, + vm_offset_t data, mach_msg_type_number_t dataCnt); + +LC_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, + mach_vm_size_t size, boolean_t set_maximum, + vm_prot_t new_protection); + +#define PTRACE_ATTACH PT_ATTACHEXC +#define PTRACE_DETACH PT_DETACH #define PTRACE_POKETEXT PT_WRITE_I -#define PTRACE_CONT PT_CONTINUE +#define PTRACE_CONT PT_CONTINUE #define PTRACE_PEEKTEXT PT_READ_I -#endif -namespace LibDebugger::POSIX -{ - /// \brief POSIXMachContract engine interface class in C++ - /// \author Amlal El Mahrouss - class POSIXMachContract final : public DebuggerContract - { - public: - explicit POSIXMachContract() = default; - ~POSIXMachContract() override = default; - - public: - POSIXMachContract& operator=(const POSIXMachContract&) = default; - POSIXMachContract(const POSIXMachContract&) = default; - - public: - bool Attach(ProcessID pid) noexcept override - { -#ifdef __APPLE__ - if (pid == 0) - return false; +namespace LibDebugger::POSIX { +/// \brief POSIXMachContract engine interface class in C++ +/// \author Amlal El Mahrouss +class POSIXMachContract : public DebuggerContract { + public: + explicit POSIXMachContract() = default; + ~POSIXMachContract() override = default; - this->m_pid = pid; - return true; -#else + public: + POSIXMachContract& operator=(const POSIXMachContract&) = default; + POSIXMachContract(const POSIXMachContract&) = default; - if (ptrace(PTRACE_ATTACH, pid, nullptr, 0) == -1) - { - return false; - } + public: + BOOL Attach(std::string path, std::string argv, ProcessID& pid) noexcept override { + pid = fork(); - this->m_pid = pid; + if (pid == 0) { + if (argv.empty()) { + ptrace(PT_TRACE_ME, 0, nullptr, 0); + kill(getpid(), SIGSTOP); + } - waitpid(m_pid, nullptr, 0); + std::vector<char*> argv_arr; - return true; -#endif - } + argv_arr.push_back(const_cast<char*>(path.c_str())); + argv_arr.push_back(const_cast<char*>(argv.c_str())); + argv_arr.push_back(nullptr); - bool Break(CAddress addr) noexcept override - { -#ifdef __APPLE__ - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - kern_return_t ret = task_suspend(task); + execv(path.c_str(), argv_arr.data()); - return ret == KERN_SUCCESS; -#else - uintptr_t original_data = ptrace(PTRACE_PEEKTEXT, m_pid, addr, 0); + _exit(1); + } - if (original_data == -1) - { - return false; - } + m_path = path; + m_pid = pid; - constexpr uint8_t kInt3x86 = 0xCC; + pid = this->m_pid; - uintptr_t data_with_int3 = (original_data & ~0xFF) | kInt3x86; // Insert INT3 (0xCC) + return true; + } - if (ptrace(PTRACE_POKETEXT, m_pid, addr, data_with_int3) == -1) - { - return false; - } + void SetPath(std::string path) noexcept { + if (path.empty()) { + return; + } - m_breakpoints[reinterpret_cast<uintptr_t>(addr)] = original_data; // Store original data + m_path = path; + } - return true; -#endif - } + BOOL Breakpoint(std::string symbol) noexcept override { + if (!m_path.empty() && std::filesystem::exists(m_path) && + std::filesystem::is_regular_file(m_path)) { + auto handle = dlopen(m_path.c_str(), RTLD_LAZY); - bool Continue() noexcept override - { -#ifdef __APPLE__ - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - kern_return_t ret = task_resume(task); + if (handle == nullptr) { + return false; + } - return ret == KERN_SUCCESS; -#else - if (ptrace(PTRACE_CONT, m_pid, nullptr, 0) == -1) - { + auto addr = dlsym(handle, symbol.c_str()); - return false; - } + if (addr == nullptr) { + return false; + } - int status; - waitpid(m_pid, &status, 0); + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); - return WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP; -#endif - } + uint32_t brk_inst = 0xD43E0000; - bool Detach() noexcept override - { -#ifdef __APPLE__ - this->Continue(); + mach_vm_protect(task, (mach_vm_address_t) addr, sizeof(uint32_t), false, + VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); + mach_vm_write(task, (mach_vm_address_t) addr, (vm_offset_t) &brk_inst, sizeof(addr)); - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); + return true; + } - kern_return_t kr = mach_port_deallocate(mach_task_self(), task); + return false; + } - return kr = KERN_SUCCESS; -#else - return ptrace(PTRACE_DETACH, m_pid, nullptr, 0) == -1; -#endif - } + BOOL Break() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t ret = task_suspend(task); + + return ret == KERN_SUCCESS; + } + + BOOL Continue() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t ret = task_resume(task); - private: - ProcessID m_pid{0}; - }; -} // namespace LibDebugger::POSIX + return ret == KERN_SUCCESS; + } + + BOOL Detach() noexcept override { + this->Continue(); + + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t kr = mach_port_deallocate(mach_task_self(), task); + + return kr = KERN_SUCCESS; + } + + private: + ProcessID m_pid{0}; + std::string m_path; +}; +} // namespace LibDebugger::POSIX + +#endif diff --git a/dev/LibDebugger/src/POSIXMachContract.cc b/dev/LibDebugger/src/POSIXMachContract.cc index 4e7212c..2753e9a 100644 --- a/dev/LibDebugger/src/POSIXMachContract.cc +++ b/dev/LibDebugger/src/POSIXMachContract.cc @@ -1,129 +1,102 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ +#ifdef __APPLE__ + #include <LibCompiler/Defines.h> -#include <Vendor/Dialogs.h> #include <LibDebugger/POSIXMachContract.h> +#include <Vendor/Dialogs.h> #include <cstdint> +#include <iostream> #include <string> -#ifndef _WIN32 - -static bool kKeepRunning = false; +static BOOL kKeepRunning = false; static LibDebugger::POSIX::POSIXMachContract kDebugger; -static pid_t kPID = 0L; -static LibDebugger::CAddress kActiveAddress = nullptr; +static LibDebugger::ProcessID kPID = 0L; +static LibDebugger::CAddress kActiveAddress = nullptr; +static std::string kPath = ""; + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +#define kStdOut (std::cout << kRed << "dbg: " << kWhite) /// @internal /// @brief Handles CTRL-C signal on debugger. -static void dbgi_ctrlc_handler(std::int32_t _) -{ - if (!kPID) - { - return; - } +static void dbgi_ctrlc_handler(std::int32_t _) { + if (!kPID) { + return; + } - auto list = kDebugger.Get(); + auto list = kDebugger.Get(); - kDebugger.Break(kActiveAddress); + kDebugger.Break(); - pfd::notify("Debugger Event", "Breakpoint hit!"); + pfd::notify("Debugger Event", "Breakpoint hit!"); - kKeepRunning = false; + kKeepRunning = false; } -LIBCOMPILER_MODULE(DebuggerPOSIX) -{ - pfd::notify("Debugger Event", "NeKernel Debugger\n(C) 2025 Amlal El Mahrouss, all rights reserved."); - - if (argc >= 3 && std::string(argv[1]) == "-p" && - argv[2] != nullptr) - { - kPID = std::stoi(argv[2]); - kDebugger.Attach(kPID); - } - - ::signal(SIGINT, dbgi_ctrlc_handler); - - while (YES) - { - if (kKeepRunning) - { - continue; - } - - std::string cmd; - std::getline(std::cin, cmd); - - if (cmd == "c" || - cmd == "cont" || - cmd == "continue") - { - kDebugger.Continue(); - kKeepRunning = true; - - std::cout << "[+] Continuing...\n"; - pfd::notify("Debugger Event", "Continuing..."); - } - - if (cmd == "d" || - cmd == "detach") - kDebugger.Detach(); - - if (cmd == "attach" || - cmd == "pid" || - cmd == "a") - { - std::cout << "[?] Enter a PID to attach on: "; - - std::getline(std::cin, cmd); - kPID = std::stoi(cmd.c_str()); - - pfd::notify("Debugger Event", "Attach process: " + std::to_string(kPID)); - - kDebugger.Attach(kPID); - } - - if (cmd == "exit") - { - if (kPID > 0) - kDebugger.Detach(); - - break; - } - -#ifndef __APPLE__ - if (cmd == "break" || - cmd == "b") - { - std::cout << "[?] Enter an address/symbol to add a break on: "; - - std::getline(std::cin, cmd); - - auto addr = std::stoul(cmd.c_str(), nullptr, 16); - - try - { - pfd::notify("Debugger Event", "Add Breakpoint at: " + std::to_string(addr)); - } - catch (...) - { - pfd::notify("Debugger Event", "Add Breakpoint at: " + cmd); - } - - LibDebugger::CAddress breakpoint_addr = reinterpret_cast<LibDebugger::CAddress>(addr); - - if (breakpoint_addr) - { - kActiveAddress = breakpoint_addr; - kDebugger.Break(kActiveAddress); - } - } -#endif // ifndef __APPLE__ - } - - return EXIT_SUCCESS; +LIBCOMPILER_MODULE(DebuggerMachPOSIX) { + pfd::notify("Debugger Event", + "Userland Debugger\n(C) 2025 Amlal El Mahrouss, all rights reserved."); + + if (argc >= 3 && std::string(argv[1]) == "-p" && argv[2] != nullptr) { + kPath = argv[2]; + kDebugger.SetPath(kPath); + + kStdOut << "[+] Path set to: " << kPath << "\n"; + } + + ::signal(SIGINT, dbgi_ctrlc_handler); + + while (YES) { + if (kKeepRunning) { + continue; + } + + std::string cmd; + std::getline(std::cin, cmd); + + if (cmd == "c" || cmd == "cont" || cmd == "continue") { + if (kDebugger.Continue()) { + kKeepRunning = true; + + kStdOut << "[+] Continuing...\n"; + + pfd::notify("Debugger Event", "Continuing..."); + } + } + + if (cmd == "d" || cmd == "detach") kDebugger.Detach(); + + if (cmd == "start") { + kStdOut << "[?] Enter a argument to use: "; + std::getline(std::cin, cmd); + + kDebugger.Attach(kPath, cmd, kPID); + } + + if (cmd == "exit") { + if (kPID > 0) kDebugger.Detach(); + + break; + } + + if (cmd == "break" || cmd == "b") { + kStdOut << "[?] Enter a symbol to break on: "; + + std::getline(std::cin, cmd); + + if (kDebugger.Breakpoint(cmd)) { + pfd::notify("Debugger Event", "Add Breakpoint at: " + cmd); + } + } + } + + return EXIT_SUCCESS; } #endif
\ No newline at end of file |
