Skip to content

Commit

Permalink
Merge pull request #22 from ergrelet/feature/syscall_parameters_tracing
Browse files Browse the repository at this point in the history
Implement syscall parameters tracing
  • Loading branch information
hasherezade authored Feb 18, 2022
2 parents 235773f + cb0ab9b commit d619060
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 25 deletions.
50 changes: 50 additions & 0 deletions FuncWatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,37 @@ bool WFuncInfo::update(const WFuncInfo &func_info)

//---

bool WSyscallInfo::load(const std::string& sline, char delimiter)
{
std::vector<std::string> 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] != "<SYSCALL>") 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<uint32_t>(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++)
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
33 changes: 24 additions & 9 deletions FuncWatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#include <vector>

class WFuncInfo
struct WFuncInfo
{
public:
WFuncInfo() : paramCount(0)
{
}
Expand All @@ -27,17 +27,28 @@ 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;
std::string funcName;
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()
Expand All @@ -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<WFuncInfo> funcs;
std::map<uint32_t, WSyscallInfo> syscalls;

private:
bool appendFunc(WFuncInfo& info);
void appendSyscall(WSyscallInfo& syscall_info);

WFuncInfo* findFunc(const std::string& dllName, const std::string& funcName);
};

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
61 changes: 50 additions & 11 deletions TinyTracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ KNOB<std::string> 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.
*/
Expand Down Expand Up @@ -327,10 +329,47 @@ 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<VOID*>(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;

#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<ADDRINT*>(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
Expand All @@ -344,15 +383,8 @@ 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);
if (isCurrMy) {
Expand All @@ -366,6 +398,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)
Expand Down Expand Up @@ -694,8 +732,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";
}
}

Expand Down
2 changes: 1 addition & 1 deletion TraceLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

0 comments on commit d619060

Please sign in to comment.