diff --git a/Debug.cpp b/Debug.cpp index f05fee3..25d4f1a 100644 --- a/Debug.cpp +++ b/Debug.cpp @@ -14,9 +14,14 @@ #include "Debug.hpp" +#include #include #include #include +#include +#include +#include +#include #define BUFFER_SIZE 128 @@ -29,6 +34,7 @@ namespace krikkel using std::time; using std::localtime; using std::strftime; + using std::min; Debug::Debug() { @@ -87,6 +93,160 @@ namespace krikkel logFile.flush(); } + std::string Debug::peekData(pid_t shellPid, void *data, size_t length) + { + std::string result; + + for(int index = 0; index < length / sizeof(long); ++index) + { + long datum = ptrace(PTRACE_PEEKDATA, shellPid, ((char *) data) + index * sizeof(long)); + if(length == -1) + { + size_t datumLength = strnlen((char *) &datum, sizeof(long)); + result += string((char *) &datum, datumLength); + if(datumLength < sizeof(long)) + break; + } + else + result += string((char *) &datum, sizeof(long)); + } + + return result; + } + + std::string Debug::formatToAddress(unsigned long long address) + { + char addressString[17]; + + snprintf(addressString, 17, "%016llx", address); + + return string("0x") + addressString; + } + + void Debug::logPtraceSysCall(pid_t shellPid, uint16_t sysCallId, bool returnedFromSysCall, unsigned long long result, unsigned long long firstArgument, unsigned long long secondArgument, unsigned long long thirdArgument, unsigned long long fourthArgument, std::string fileName, int lineNo, std::string functionName) + { + const static uint8_t maxStringLength = 32; + string message = "syscall: "; + + string sysCallName; + if(sysCallId < MAX_NUMBER_OF_SYSCALLS) + sysCallName = syscalls[sysCallId]; + if(sysCallName.empty()) + sysCallName = "syscall" + std::to_string(sysCallId); + + + switch(sysCallId) + { + case SYS_read: + if(returnedFromSysCall) + message += (result == -1 ? "-1" : std::to_string((size_t) result)) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", \"" + (returnedFromSysCall ? __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) : "") + + (maxStringLength < thirdArgument || returnedFromSysCall == true ? "[…]" : "") + "\"" + + ", " + std::to_string((size_t) thirdArgument) + + ")"; + break; + case SYS_write: + if(returnedFromSysCall) + message += (result == -1 ? "-1" : std::to_string((size_t) result)) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) + + (maxStringLength < thirdArgument || returnedFromSysCall == true ? "[…]" : "") + "\"" + + ", " + std::to_string((size_t) thirdArgument) + + ")"; + break; + case SYS_close: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ")"; + break; + case SYS_stat: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(\"" + peekData(shellPid, (char *) firstArgument, -1) + "\"" + + ", " + formatToAddress(secondArgument) + + ")"; + break; + case SYS_fstat: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", " + formatToAddress(secondArgument) + + ")"; + break; + case SYS_openat: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + ((int) firstArgument == AT_FDCWD ? string("AT_FDCWD") : std::to_string((int) firstArgument)) + + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, -1)) + "\"" + + ", " + std::to_string((int) thirdArgument) + + ")"; + break; + case SYS_rt_sigprocmask: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", " + formatToAddress(secondArgument) + + ", " + formatToAddress(thirdArgument) + + ", " + std::to_string((size_t) fourthArgument) + + ")"; + break; + case SYS_access: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + peekData(shellPid, (char *) firstArgument, -1) + + ", " + std::to_string((int) secondArgument) + + ")"; + break; + case SYS_dup2: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", " + std::to_string((int) secondArgument) + + ")"; + break; + case SYS_fcntl: + if(returnedFromSysCall) + message += std::to_string((int) result) + " = "; + message += sysCallName + + "(" + std::to_string((int) firstArgument) + + ", " + (secondArgument == 0 ? string("F_DUP_FD") : std::to_string((int) secondArgument)) + + ", …" + + ")"; + break; +/* case SYS_fstat: + struct stat statbuf; + message += "(" + std::to_string(firstArgument) + + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) + + (maxStringLength < thirdArgument ? "[…]" : "") + "\"" + + ", " + std::to_string((size_t) thirdArgument) + + ")"; + break; +*/ default: + if(returnedFromSysCall) + message += (result == -1 ? "-1" : std::to_string(result)) + " = "; + message += sysCallName + + "(" + formatToAddress(firstArgument) + + ", " + formatToAddress(secondArgument) + + ", " + formatToAddress(thirdArgument) + + ", " + formatToAddress(fourthArgument) + + ")"; + } + // source: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ + + log(message, fileName, lineNo, functionName); + } + Debug *Debug::getInstance() { static Debug *debug = new Debug(); diff --git a/Debug.hpp b/Debug.hpp index eeff7bb..56d8281 100644 --- a/Debug.hpp +++ b/Debug.hpp @@ -26,17 +26,22 @@ namespace krikkel Debug(); std::string getTimestamp(); std::string getUname(); + std::string peekData(pid_t shellPid, void *data, size_t length); + std::string formatToAddress(unsigned long long address); public: void log(std::string message, std::string fileName, int lineNo , std::string functionName); + void logPtraceSysCall(pid_t shellPid, uint16_t sysCallId, bool returnedFromSysCall, unsigned long long result, unsigned long long firstArgument, unsigned long long secondArgument, unsigned long long thirdArgument, unsigned long long fourthArgument, std::string fileName, int lineNo, std::string functionName); static Debug *getInstance(); }; } -#define __debug_log(message) krikkel::Debug::getInstance()\ - ->log(message, __FILE__, __LINE__, __func__) +#define __debug_log(message) \ + krikkel::Debug::getInstance()->log(message, __FILE__, __LINE__, __func__) +#define __debug_log_ptrace_syscall(shellPid, sysCallId, returnedFromSysCall, result, firstArgument, secondArgument, thirdArgument, fourthArgument) \ + krikkel::Debug::getInstance()->logPtraceSysCall(shellPid, sysCallId, returnedFromSysCall, result, firstArgument, secondArgument, thirdArgument, fourthArgument, __FILE__, __LINE__, __func__); /// @todo need an explanation on why and how to use this /// this is the complete opposite of self-explanatory @@ -104,7 +109,7 @@ namespace krikkel if(std::isprint(character, loc) && character != '<') \ result += character; \ else \ - result += '<' + std::to_string(character) + '>'; \ + result += '<' + std::to_string((unsigned char) character) + '>'; \ } \ return result; \ })(__bytes)