From 855e460748aa852a85e113af82d010758859d785 Mon Sep 17 00:00:00 2001 From: ergrelet Date: Thu, 17 Feb 2022 23:08:59 +0100 Subject: [PATCH 1/3] Make it clear syscall ids are displayed as hexadecimal in traces --- TraceLog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TraceLog.cpp b/TraceLog.cpp index 5efe31d..7f014c5 100644 --- a/TraceLog.cpp +++ b/TraceLog.cpp @@ -133,7 +133,7 @@ void TraceLog::logSyscall(const ADDRINT base, const ADDRINT rva, const ADDRINT p m_traceFile << std::hex << rva << DELIMITER - << "SYSCALL:" + << "SYSCALL:0x" << std::hex << param << std::endl; m_traceFile.flush(); From 076c54213e0ff9d44b813ec8b6302eb5a8407972 Mon Sep 17 00:00:00 2001 From: ergrelet Date: Thu, 17 Feb 2022 23:11:03 +0100 Subject: [PATCH 2/3] [FEATURE] Add parameter tracing for syscalls --- FuncWatch.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ FuncWatch.h | 33 ++++++++++++++++++++++++--------- README.md | 2 +- TinyTracer.cpp | 36 +++++++++++++++++++++++++++++++++--- Util.cpp | 4 ++-- Util.h | 2 +- 6 files changed, 111 insertions(+), 16 deletions(-) diff --git a/FuncWatch.cpp b/FuncWatch.cpp index ef1f465..1b4d49e 100644 --- a/FuncWatch.cpp +++ b/FuncWatch.cpp @@ -31,6 +31,37 @@ bool WFuncInfo::update(const WFuncInfo &func_info) //--- +bool WSyscallInfo::load(const std::string& sline, char delimiter) +{ + std::vector args; + util::splitList(sline, delimiter, args); + if (args.size() < 3) return false; + // Note: '<' and '>' are used to ensure this cannot overlap with a valid + // file or library name. + if (args[0] != "") return false; + + // Parse syscall ID as a hexadecimal number + const int syscallId = util::loadInt(args[1], true); + if (syscallId < 0) return false; + + this->syscallId = static_cast(syscallId); + this->paramCount = util::loadInt(args[2]); + + return true; +} + +bool WSyscallInfo::update(const WSyscallInfo& syscall_info) +{ + bool isUpdated = false; + if (this->paramCount < syscall_info.paramCount) { + this->paramCount = syscall_info.paramCount; + isUpdated = true; + } + return isUpdated; +} + +//--- + WFuncInfo* FuncWatchList::findFunc(const std::string& dllName, const std::string &funcName) { for (size_t i = 0; i < funcs.size(); i++) @@ -60,6 +91,17 @@ bool FuncWatchList::appendFunc(WFuncInfo &func_info) return true; } +void FuncWatchList::appendSyscall(WSyscallInfo& syscall_info) +{ + auto& it = syscalls.find(syscall_info.syscallId); + if (it == syscalls.end()) { + syscalls[syscall_info.syscallId] = syscall_info; + } + else { + it->second.update(syscall_info); + } +} + size_t FuncWatchList::loadList(const char* filename) { std::ifstream myfile(filename); @@ -72,6 +114,14 @@ size_t FuncWatchList::loadList(const char* filename) while (!myfile.eof()) { myfile.getline(line, MAX_LINE); + // Try to parse as a syscall + WSyscallInfo syscall_info; + if (syscall_info.load(line, ';')) { + appendSyscall(syscall_info); + continue; + } + + // Try to parse as a function WFuncInfo func_info; if (func_info.load(line, ';')) { appendFunc(func_info); diff --git a/FuncWatch.h b/FuncWatch.h index 57c36f5..e427225 100644 --- a/FuncWatch.h +++ b/FuncWatch.h @@ -5,11 +5,11 @@ #include #include #include +#include #include -class WFuncInfo +struct WFuncInfo { -public: WFuncInfo() : paramCount(0) { } @@ -27,10 +27,7 @@ class WFuncInfo bool isValid() const { - if (dllName.length() > 0 && funcName.length() > 0) { - return true; - } - return false; + return dllName.length() > 0 && funcName.length() > 0; } std::string dllName; @@ -38,6 +35,20 @@ class WFuncInfo size_t paramCount; }; +struct WSyscallInfo +{ + WSyscallInfo() : syscallId(0), paramCount(0) + { + } + + bool load(const std::string& line, char delimiter); + + bool update(const WSyscallInfo& syscall_info); + + uint32_t syscallId; + size_t paramCount; +}; + class FuncWatchList { public: FuncWatchList() @@ -49,10 +60,14 @@ class FuncWatchList { } size_t loadList(const char* filename); - bool appendFunc(WFuncInfo &info); - - WFuncInfo* findFunc(const std::string& dllName, const std::string &funcName); std::vector funcs; + std::map syscalls; + +private: + bool appendFunc(WFuncInfo& info); + void appendSyscall(WSyscallInfo& syscall_info); + + WFuncInfo* findFunc(const std::string& dllName, const std::string& funcName); }; diff --git a/README.md b/README.md index 4b5dc73..a5922ff 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A Pin Tool for tracing: + API calls, including [parameters of selected functions](https://github.com/hasherezade/tiny_tracer/wiki/Tracing-parameters-of-functions) + selected instructions: [RDTSC](https://c9x.me/x86/html/file_module_x86_id_278.html), [CPUID](https://c9x.me/x86/html/file_module_x86_id_45.html) -+ inline system calls ++ inline system calls, including parameters of selected syscalls + transition between sections of the traced module (helpful in finding OEP of the packed module) Bypasses the anti-tracing check based on RDTSC. diff --git a/TinyTracer.cpp b/TinyTracer.cpp index 415852d..4c9d49c 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -57,6 +57,8 @@ KNOB KnobWatchListFile(KNOB_MODE_WRITEONCE, "pintool", // Utilities /* ===================================================================== */ +VOID _LogFunctionArgs(const ADDRINT Address, CHAR* name, uint32_t argCount, VOID* arg1, VOID* arg2, VOID* arg3, VOID* arg4, VOID* arg5, VOID* arg6, VOID* arg7, VOID* arg8, VOID* arg9, VOID* arg10); + /*! * A locker class. */ @@ -327,6 +329,27 @@ VOID CpuidCalled(const CONTEXT* ctxt) } } +VOID LogSyscallsArgs(const CONTEXT* ctxt, SYSCALL_STANDARD std, const ADDRINT Address, uint32_t argCount) +{ + VOID* syscall_args[10] = { 0 }; + for (size_t i = 0; i < sizeof(syscall_args) / sizeof(syscall_args[0]); i++) { + syscall_args[i] = reinterpret_cast(PIN_GetSyscallArgument(ctxt, std, i)); + } + + _LogFunctionArgs(Address, + "SYSCALL", argCount, + syscall_args[0], + syscall_args[1], + syscall_args[2], + syscall_args[3], + syscall_args[4], + syscall_args[5], + syscall_args[6], + syscall_args[7], + syscall_args[8], + syscall_args[9]); +} + VOID SyscallCalled(THREADID tid, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) { PinLocker locker; @@ -352,7 +375,7 @@ VOID SyscallCalled(THREADID tid, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) } return PIN_GetSyscallNumber(ctxt, std); }(); - + const IMG currModule = IMG_FindByAddress(address); const bool isCurrMy = pInfo.isMyAddress(address); if (isCurrMy) { @@ -366,6 +389,12 @@ VOID SyscallCalled(THREADID tid, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) traceLog.logSyscall(start, rva, syscallNum); } } + + // Log arguments if needed + const auto& it = g_Watch.syscalls.find(syscallNum); + if (it != g_Watch.syscalls.end()) { + LogSyscallsArgs(ctxt, std, address, it->second.paramCount); + } } ADDRINT _setTimer(const CONTEXT* ctxt, bool isEax) @@ -694,8 +723,9 @@ int main(int argc, char *argv[]) if (KnobWatchListFile.Enabled()) { std::string watchListFile = KnobWatchListFile.ValueString(); if (watchListFile.length()) { - size_t loaded = g_Watch.loadList(watchListFile.c_str()); - std::cout << "Watch " << loaded << " functions\n"; + g_Watch.loadList(watchListFile.c_str()); + std::cout << "Watch " << g_Watch.funcs.size() << " functions\n"; + std::cout << "Watch " << g_Watch.syscalls.size() << " syscalls\n"; } } diff --git a/Util.cpp b/Util.cpp index a1b4f4c..6bb5af6 100644 --- a/Util.cpp +++ b/Util.cpp @@ -103,12 +103,12 @@ static inline void rtrim(std::string &s) rtrim(s); } - int util::loadInt(const std::string &str) + int util::loadInt(const std::string &str, bool as_hex) { int intVal = 0; std::stringstream ss; - ss << std::dec << str; + ss << (as_hex ? std::hex : std::dec) << str; ss >> intVal; return intVal; diff --git a/Util.h b/Util.h index 43d8c0d..77ae0ed 100644 --- a/Util.h +++ b/Util.h @@ -28,5 +28,5 @@ namespace util { // trim from both ends (in place) void trim(std::string &s); - int loadInt(const std::string &str); + int loadInt(const std::string &str, bool as_hex = false); }; From cb0ab9bb07aa9c18b60af8f732dc02f8d5b42d0d Mon Sep 17 00:00:00 2001 From: ergrelet Date: Thu, 17 Feb 2022 23:30:49 +0100 Subject: [PATCH 3/3] Improve 'int 2E' handling for x64 --- TinyTracer.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/TinyTracer.cpp b/TinyTracer.cpp index 4c9d49c..36cf10c 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -354,6 +354,22 @@ VOID SyscallCalled(THREADID tid, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) { PinLocker locker; +#ifdef _WIN64 + // Since Windows 10 TH2, NTDLL's syscall routines have changed: syscalls can + // now be performed with the SYSCALL instruction, and with the INT 2E + // instruction. The ABI is the same in both cases. + if (std == SYSCALL_STANDARD_WINDOWS_INT) { + const auto* insPtr = reinterpret_cast(PIN_GetContextReg(ctxt, REG_INST_PTR)); + uint16_t instruction = 0; + PIN_SafeCopy(&instruction, insPtr, sizeof(instruction)); + if (instruction != 0x2ECD) { // INT 2E + // Not a relevant interrupt, return now. + return; + } + std = SYSCALL_STANDARD_IA32E_WINDOWS_FAST; + } +#endif + const auto address = [&]() -> ADDRINT { if (std == SYSCALL_STANDARD_WOW64) { // Note: In this case, the current instruction address is in a 64-bit @@ -367,14 +383,7 @@ VOID SyscallCalled(THREADID tid, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) return PIN_GetContextReg(ctxt, REG_INST_PTR); }(); - const auto syscallNum = [&]() -> ADDRINT { - if (std == SYSCALL_STANDARD_WINDOWS_INT) { - // Note: Somehow `PIN_GetSyscallNumber` doesn't return the correct - // result in this case. - return PIN_GetContextReg(ctxt, REG_GAX); - } - return PIN_GetSyscallNumber(ctxt, std); - }(); + const ADDRINT syscallNum = PIN_GetSyscallNumber(ctxt, std); const IMG currModule = IMG_FindByAddress(address); const bool isCurrMy = pInfo.isMyAddress(address);