From 1d1b631f122ebc14ea2d8fae438ba3ecd1ec9a88 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Wed, 19 Jan 2022 03:32:04 -0800 Subject: [PATCH 1/4] [REFACT] Fetch return address from the stack instad of from a passed arg (less accurate but much faster) --- TinyTracer.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/TinyTracer.cpp b/TinyTracer.cpp index b1388e5..8a644fb 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -146,13 +146,23 @@ bool isWatchedAddress(const ADDRINT Address) // Analysis routines /* ===================================================================== */ +ADDRINT getReturnFromTheStack(const CONTEXT* ctx) +{ + if (!ctx) return UNKNOWN_ADDR; + + ADDRINT returnAddr = UNKNOWN_ADDR; + const ADDRINT stackPtr = (ADDRINT)PIN_GetContextReg(ctx, REG_STACK_PTR); + if (PIN_CheckReadAccess((ADDRINT*)stackPtr)) { + returnAddr = *(ADDRINT*)stackPtr; + } + return returnAddr; +} -VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndirect, ADDRINT returnAddr = UNKNOWN_ADDR) +VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndirect, const CONTEXT* ctx = NULL) { // validate the return address: - if (returnAddr != UNKNOWN_ADDR && !PIN_CheckReadAccess((void*)returnAddr)) { - returnAddr = UNKNOWN_ADDR; - } + const ADDRINT returnAddr = getReturnFromTheStack(ctx); + const bool isTargetMy = pInfo.isMyAddress(addrTo); const bool isCallerMy = pInfo.isMyAddress(addrFrom); @@ -269,10 +279,10 @@ VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndir } } -VOID SaveTransitions(const ADDRINT prevVA, const ADDRINT Address, BOOL isIndirect, const ADDRINT RetAddress) +VOID SaveTransitions(const ADDRINT prevVA, const ADDRINT Address, BOOL isIndirect, const CONTEXT* ctx) { PinLocker locker; - _SaveTransitions(prevVA, Address, isIndirect, RetAddress); + _SaveTransitions(prevVA, Address, isIndirect, ctx); } VOID RdtscCalled(const CONTEXT* ctxt) @@ -531,7 +541,7 @@ VOID InstrumentInstruction(INS ins, VOID *v) IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BOOL, isIndirect, - IARG_RETURN_IP, + IARG_CONTEXT, IARG_END ); From b1fcb2b46963ee77cdb138a01cbfe775c279656a Mon Sep 17 00:00:00 2001 From: hasherezade Date: Wed, 19 Jan 2022 03:58:18 -0800 Subject: [PATCH 2/4] [REFACT] Fetch return address only if the call is coming from a shellcode --- TinyTracer.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/TinyTracer.cpp b/TinyTracer.cpp index 8a644fb..24cbb82 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -20,7 +20,7 @@ #include "FuncWatch.h" #define TOOL_NAME "TinyTracer" -#define VERSION "2.0" +#define VERSION "2.0-a" #include "Util.h" #include "Settings.h" @@ -160,15 +160,10 @@ ADDRINT getReturnFromTheStack(const CONTEXT* ctx) VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndirect, const CONTEXT* ctx = NULL) { - // validate the return address: - const ADDRINT returnAddr = getReturnFromTheStack(ctx); - const bool isTargetMy = pInfo.isMyAddress(addrTo); const bool isCallerMy = pInfo.isMyAddress(addrFrom); - bool isFromTraced = isWatchedAddress(addrFrom); // is the call from the traced shellcode? - bool isRetToTraced = isWatchedAddress(returnAddr); // does it return into the traced area? IMG targetModule = IMG_FindByAddress(addrTo); IMG callerModule = IMG_FindByAddress(addrFrom); @@ -229,20 +224,23 @@ VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndir /** save the transition when a shellcode returns to a traced area from an API call: */ - if (isRetToTraced //returns to the traced area - && !isFromTraced && !IMG_Valid(callerModule) // from an untraced shellcode... - && isTargetPeModule // ...which was was a proxy for making an API call + if (!isFromTraced && !IMG_Valid(callerModule) // from an untraced shellcode... + && isTargetPeModule // ...into an API call ) { - const std::string func = get_func_at(addrTo); - const std::string dll_name = IMG_Name(targetModule); - const ADDRINT pageRet = get_base(returnAddr); - const ADDRINT RvaFrom = addr_to_rva(addrFrom); - const ADDRINT base = isTargetMy ? 0 : get_base(addrFrom); + // was the shellcode a proxy for making an API call? + const ADDRINT returnAddr = getReturnFromTheStack(ctx); + bool isRetToTraced = isWatchedAddress(returnAddr); // does it return into the traced area? + if (isRetToTraced) { + const std::string func = get_func_at(addrTo); + const std::string dll_name = IMG_Name(targetModule); + const ADDRINT pageRet = get_base(returnAddr); + const ADDRINT RvaFrom = addr_to_rva(addrFrom); + const ADDRINT base = isTargetMy ? 0 : get_base(addrFrom); - traceLog.logCallRet(base, RvaFrom, pageRet, returnAddr, dll_name, func); + traceLog.logCallRet(base, RvaFrom, pageRet, returnAddr, dll_name, func); + } } - /** trace indirect calls to your own functions */ From 07bcd5c2ba95f78dfb17d92f5beb9154b75d756b Mon Sep 17 00:00:00 2001 From: hasherezade Date: Wed, 19 Jan 2022 04:12:56 -0800 Subject: [PATCH 3/4] [REFACT] Use constant instead of repeating check (isCallerPeModule) --- TinyTracer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TinyTracer.cpp b/TinyTracer.cpp index 24cbb82..e9e720d 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -167,6 +167,7 @@ VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndir IMG targetModule = IMG_FindByAddress(addrTo); IMG callerModule = IMG_FindByAddress(addrFrom); + const bool isCallerPeModule = IMG_Valid(callerModule); const bool isTargetPeModule = IMG_Valid(targetModule); /** @@ -190,7 +191,7 @@ VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndir /** trace calls from witin a shellcode: */ - if (m_Settings.followShellcode && !IMG_Valid(callerModule)) { + if (m_Settings.followShellcode && !isCallerPeModule) { if (m_Settings.followShellcode == SHELLC_FOLLOW_ANY || isFromTraced) { const ADDRINT pageFrom = query_region_base(addrFrom); @@ -224,8 +225,9 @@ VOID _SaveTransitions(const ADDRINT addrFrom, const ADDRINT addrTo, BOOL isIndir /** save the transition when a shellcode returns to a traced area from an API call: */ - if (!isFromTraced && !IMG_Valid(callerModule) // from an untraced shellcode... + if (!isFromTraced && !isCallerPeModule // from an untraced shellcode... && isTargetPeModule // ...into an API call + && ctx //the context was passed: we can check the return ) { // was the shellcode a proxy for making an API call? From ad9653c4aafa549ce565b6dd7c66f20167b91c12 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Wed, 19 Jan 2022 04:51:59 -0800 Subject: [PATCH 4/4] [NOBIN] Added run_me version with benchmark --- install32_64/run_me_benchmark.bat | 135 ++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 install32_64/run_me_benchmark.bat diff --git a/install32_64/run_me_benchmark.bat b/install32_64/run_me_benchmark.bat new file mode 100644 index 0000000..4c175ae --- /dev/null +++ b/install32_64/run_me_benchmark.bat @@ -0,0 +1,135 @@ +@echo off +rem This script is to be used from the context menu + +set TARGET_APP=%~1 +set PE_TYPE=%~2 +set IS_ADMIN=%~3 + +if "%TARGET_APP%"=="" goto display_args +if "%PE_TYPE%"=="" goto display_args +goto run_it + +:display_args +echo Run a process with TinyTracer, and trace the selected module +echo It is recommended to run this script via installed context menu +echo Required args: [target app] [pe type: dll or exe] +pause +goto finish + +:run_it +echo PIN is trying to run the app: +echo "%TARGET_APP%" + +rem PIN_DIR is your root directory of Intel Pin +set PIN_DIR=C:\pin\ + +rem PIN_TOOLS_DIR is your directory with this script and the Pin Tools +set PIN_TOOLS_DIR=C:\pin\source\tools\tiny_tracer\install32_64\ + +set PINTOOL32=%PIN_TOOLS_DIR%\TinyTracer32.dll +set PINTOOL64=%PIN_TOOLS_DIR%\TinyTracer64.dll +set PINTOOL=%PINTOOL32% + +rem TRACED_MODULE - by default it is the main module, but it can be also a DLL within the traced process +set TRACED_MODULE=%TARGET_APP% + +set TAG_FILE="%TRACED_MODULE%.tag" + +rem The ini file specifying the settings of the tracer +set SETTINGS_FILE=%PIN_TOOLS_DIR%\TinyTracer.ini + +rem WATCH_BEFORE - a file with a list of functions which's parameters will be logged before execution +rem The file must be a list of records in a format: [dll_name];[func_name];[parameters_count] +set WATCH_BEFORE=%PIN_TOOLS_DIR%\params.txt + +set DLL_LOAD32=%PIN_TOOLS_DIR%\dll_load32.exe +set DLL_LOAD64=%PIN_TOOLS_DIR%\dll_load64.exe + +if exist %PIN_TOOLS_DIR%\kdb_check.exe ( + %PIN_TOOLS_DIR%\kdb_check.exe + if NOT %errorlevel% EQU 0 ( + echo Disable Kernel Mode Debugger before running the PIN tool! + pause + exit + ) +) + +%PIN_TOOLS_DIR%\pe_check.exe "%TARGET_APP%" +if %errorlevel% == 32 ( + echo 32bit selected + set PINTOOL=%PINTOOL32% + set DLL_LOAD=%DLL_LOAD32% +) +if %errorlevel% == 64 ( + echo 64bit selected + set PINTOOL=%PINTOOL64% + set DLL_LOAD=%DLL_LOAD64% +) + +rem The exports that you want to call from a dll, in format: [name1];[name2] or [#ordinal1];[#ordinal2] +set DLL_EXPORTS="" + +rem The arguments that you want to pass to the run executable +set EXE_ARGS="" + +echo Target module: "%TRACED_MODULE%" +echo Tag file: %TAG_FILE% +if [%IS_ADMIN%] == [A] ( + echo Elevation requested +) + +set ADMIN_CMD=%PIN_TOOLS_DIR%\sudo.vbs + +set DLL_CMD=%PIN_DIR%\pin.exe -t %PINTOOL% -m "%TRACED_MODULE%" -o %TAG_FILE% -s %SETTINGS_FILE% -b "%WATCH_BEFORE%" -- "%DLL_LOAD%" "%TARGET_APP%" %DLL_EXPORTS% +set EXE_CMD=%PIN_DIR%\pin.exe -t %PINTOOL% -m "%TRACED_MODULE%" -o %TAG_FILE% -s %SETTINGS_FILE% -b "%WATCH_BEFORE%" -- "%TARGET_APP%" "%EXE_ARGS%" + + +set start=%time% + +;rem "Trace EXE" +if [%PE_TYPE%] == [exe] ( + if [%IS_ADMIN%] == [A] ( + %ADMIN_CMD% %EXE_CMD% + ) else ( + %EXE_CMD% + ) +) +;rem "Trace DLL" +if [%PE_TYPE%] == [dll] ( + if [%IS_ADMIN%] == [A] ( + %ADMIN_CMD% %DLL_CMD% + ) else ( + %DLL_CMD% + ) +) + +set end=%time% + +set options="tokens=1-4 delims=:.," +for /f %options% %%a in ("%start%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100 +for /f %options% %%a in ("%end%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100 + +set /a hours=%end_h%-%start_h% +set /a mins=%end_m%-%start_m% +set /a secs=%end_s%-%start_s% +set /a ms=%end_ms%-%start_ms% +if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms% +if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs% +if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins% +if %hours% lss 0 set /a hours = 24%hours% +if 1%ms% lss 100 set ms=0%ms% + +:: Mission accomplished +set /a totalsecs = %hours%*3600 + %mins%*60 + %secs% +echo command took %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total) + + +if [%IS_ADMIN%] == [A] ( + rem In Admin mode, a new console should be created. Pause only if it failed, in order to display the error: + if NOT %ERRORLEVEL% EQU 0 pause +) else ( + if %ERRORLEVEL% EQU 0 echo [OK] PIN tracing finished: the traced application terminated. + rem Pausing script after the application is executed is useful to see all eventual printed messages and for troubleshooting + pause +) +:finish