summaryrefslogtreecommitdiffhomepage
path: root/dev/LibDebugger
diff options
context:
space:
mode:
Diffstat (limited to 'dev/LibDebugger')
-rw-r--r--dev/LibDebugger/DebuggerContract.h72
-rw-r--r--dev/LibDebugger/NeKernelContract.h63
-rw-r--r--dev/LibDebugger/POSIXMachContract.h214
-rw-r--r--dev/LibDebugger/src/POSIXMachContract.cc189
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