From 8bdd5e3eed929bafcfd012f28067a433b49987e5 Mon Sep 17 00:00:00 2001 From: Andrea Naspi Date: Wed, 16 Aug 2023 16:51:20 +0200 Subject: [PATCH] AntiVM implementation: WMI query parameters tracing (#41) * [FEATURE] AntiVM: added initial files * [FEATURE] AntiVM: bug fix * [FEATURE] AntiVm: WMI query hooking * [FEATURE] AntiVm: WMI parameters tracing * [FEATURE] AntiVm: removed redundant types/arguments * [FEATURE] AntiVm: updated TinyTracer project files * [FEATURE] AntiVm: resetted VS platform toolset * Merge Anti-VM feature --- AntiVm.h | 21 +++++ Antivm.cpp | 178 ++++++++++++++++++++++++++++++++++++ Settings.cpp | 7 +- Settings.h | 2 + TinyTracer.cpp | 13 +++ TinyTracer.vcxproj | 2 + TinyTracer_Pin3.18.vcxproj | 4 +- TinyTracer_Pin3.25.vcxproj | 4 +- install32_64/TinyTracer.ini | 1 + 9 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 AntiVm.h create mode 100644 Antivm.cpp diff --git a/AntiVm.h b/AntiVm.h new file mode 100644 index 0000000..95b7f15 --- /dev/null +++ b/AntiVm.h @@ -0,0 +1,21 @@ +#pragma once + +#include "pin.H" + +//* ==================================================================== */ +// Helpers +/* ===================================================================== */ +#define GET_STR_TO_UPPER(c, buf, bufSize) do { \ + size_t i; \ + for (i = 0; i < bufSize; i++) { \ + (buf)[i] = toupper((c)[i]); \ + if ((c)[i] == '\0') break; \ + } \ +} while (0) + +//* ==================================================================== */ +// Prototypes +/* ===================================================================== */ +namespace AntiVm { + VOID MonitorAntiVmFunctions(IMG Image); +}; \ No newline at end of file diff --git a/Antivm.cpp b/Antivm.cpp new file mode 100644 index 0000000..0e49e4a --- /dev/null +++ b/Antivm.cpp @@ -0,0 +1,178 @@ +#include "AntiVm.h" + +#include +#include +#include +#include + +#include "ProcessInfo.h" +#include "Util.h" +#include "TraceLog.h" +#include "Settings.h" +#include "PinLocker.h" +#include "TinyTracer.h" + +#include "win/win_paths.h" + +#define ANTIVM_LABEL "[ANTIVM] --> " + +using namespace LEVEL_PINCLIENT; + +/* ================================================================== */ +// Global variables used by AntiVm +/* ================================================================== */ +#define PATH_BUFSIZE 512 +#define WMI_NUMBER_CORES "NUMBEROFCORES" +#define WMI_PROCESSOR "PROCESSORID" +#define WMI_SIZE "SIZE" +#define WMI_DEVICE_ID "DEVICEID" +#define WMI_MAC_ADDRESS "MACADDRESS" +#define WMI_TEMPERATURE "CURRENTTEMPERATURE" +#define WMI_SERIAL "SERIALNUMBER" +#define WMI_MODEL "MODEL" +#define WMI_MANUFACTURER "MANUFACTURER" +#define WMI_GPU_ADAPTER "ADAPTERCOMPATIBILITY" +#define WMI_PRODUCT "PRODUCT" +#define WMI_NAME "NAME" + +typedef VOID AntiVmCallBack(const ADDRINT addr, const CHAR* name, uint32_t argCount, VOID* arg1, VOID* arg2, VOID* arg3, VOID* arg4, VOID* arg5, VOID* arg6); + +/* ==================================================================== */ +// Log info with AntiVm label +/* ==================================================================== */ + +VOID LogAntiVm(const WatchedType wType, const ADDRINT Address, const char* msg, const char* link = nullptr) +{ + if (!msg) return; + if (wType == WatchedType::NOT_WATCHED) return; + + std::stringstream ss; + ADDRINT rva = UNKNOWN_ADDR; + if (wType == WatchedType::WATCHED_MY_MODULE) { + rva = addr_to_rva(Address); // convert to RVA + } + else if (wType == WatchedType::WATCHED_SHELLCODE) { + const ADDRINT start = query_region_base(Address); + rva = Address - start; + if (start != UNKNOWN_ADDR) { + ss << "> " << std::hex << start << "+"; + } + } + if (rva == UNKNOWN_ADDR) return; + + ss << std::hex << rva << TraceLog::DELIMITER << ANTIVM_LABEL << msg; + if (link) { + ss << TraceLog::DELIMITER << link; + } + traceLog.logLine(ss.str()); +} + +/* ==================================================================== */ +// Process API calls (related to AntiVm techniques) +/* ==================================================================== */ + +VOID AntiVm_WmiQueries(const ADDRINT addr, const CHAR* name, uint32_t argCount, VOID* arg1, VOID* arg2, VOID* arg3, VOID* arg4, VOID* arg5, VOID* arg6) +{ + if (!argCount) return; + + PinLocker locker; + const WatchedType wType = isWatchedAddress(addr); + if (wType == WatchedType::NOT_WATCHED) return; + + using namespace WINDOWS; + + LPCWSTR wmi_query = (LPCWSTR)arg2; + + if (wmi_query == NULL) return; + + char wmi_query_field[PATH_BUFSIZE]; + GET_STR_TO_UPPER(wmi_query, wmi_query_field, PATH_BUFSIZE); + + if (util::iequals(wmi_query_field, WMI_NUMBER_CORES) || util::iequals(wmi_query_field, WMI_PROCESSOR)) { + return LogAntiVm(wType, addr, "^ WMI query - number of CPU cores", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_SIZE)) { + return LogAntiVm(wType, addr, "^ WMI query - hard disk size", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_DEVICE_ID)) { + return LogAntiVm(wType, addr, "^ WMI query - device ID", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_MAC_ADDRESS)) { + return LogAntiVm(wType, addr, "^ WMI query - MAC address", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_TEMPERATURE)) { + return LogAntiVm(wType, addr, "^ WMI query - system temperatures", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_SERIAL)) { + return LogAntiVm(wType, addr, "^ WMI query - BIOS serial number", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_MODEL) || util::iequals(wmi_query_field, WMI_MANUFACTURER)) { + return LogAntiVm(wType, addr, "^ WMI query - system model and/or manufacturer", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_GPU_ADAPTER)) { + return LogAntiVm(wType, addr, "^ WMI query - video controller adapter", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } + else if (util::iequals(wmi_query_field, WMI_PRODUCT) || util::iequals(wmi_query_field, WMI_NAME)) { + return LogAntiVm(wType, addr, "^ WMI query - system device names", + "https://evasions.checkpoint.com/techniques/wmi.html#generic-wmi-queries"); + } +} + +/* ==================================================================== */ +// Add single hooking function +/* ==================================================================== */ + +bool AntiVmAddCallbackBefore(IMG Image, char* fName, uint32_t argNum, AntiVmCallBack callback) +{ + const size_t argMax = 6; + if (argNum > argMax) argNum = argMax; + + RTN funcRtn = RTN_FindByName(Image, fName); + if (RTN_Valid(funcRtn)) { + RTN_Open(funcRtn); + + RTN_InsertCall(funcRtn, IPOINT_BEFORE, AFUNPTR(callback), + IARG_RETURN_IP, + IARG_ADDRINT, fName, + IARG_UINT32, argNum, + IARG_FUNCARG_ENTRYPOINT_VALUE, 0, + IARG_FUNCARG_ENTRYPOINT_VALUE, 1, + IARG_FUNCARG_ENTRYPOINT_VALUE, 2, + IARG_FUNCARG_ENTRYPOINT_VALUE, 3, + IARG_FUNCARG_ENTRYPOINT_VALUE, 4, + IARG_FUNCARG_ENTRYPOINT_VALUE, 5, + IARG_END + ); + + RTN_Close(funcRtn); + return true; + } + + return false; +} + +/* ==================================================================== */ +// Add to monitored functions all the API calls or WMI queries needed for AntiVM. +// Called by ImageLoad +/* ==================================================================== */ + +VOID AntiVm::MonitorAntiVmFunctions(IMG Image) +{ + // API needed to trace WMI queries + const std::string dllName = util::getDllName(IMG_Name(Image)); + if (util::iequals(dllName, "fastprox")) { +#ifdef _WIN64 + AntiVmAddCallbackBefore(Image, "?Get@CWbemObject@@UEAAJPEBGJPEAUtagVARIANT@@PEAJ2@Z", 6, AntiVm_WmiQueries); +#else + AntiVmAddCallbackBefore(Image, "?Get@CWbemObject@@UAGJPBGJPAUtagVARIANT@@PAJ2@Z", 6, AntiVm_WmiQueries); +#endif + } +} \ No newline at end of file diff --git a/Settings.cpp b/Settings.cpp index ff2ece5..1a3f392 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -19,6 +19,7 @@ #define HOOK_SLEEP "HOOK_SLEEP" #define LOG_INDIRECT "LOG_INDIRECT_CALLS" #define KEY_ANTIDEBUG "ANTIDEBUG" +#define KEY_ANTIVM "ANTIVM" #define KEY_USE_DEBUG_SYMBOLS "USE_DEBUG_SYMBOLS" t_shellc_options ConvertShcOption(int value) @@ -154,6 +155,10 @@ bool fillSettings(Settings &s, std::string line) s.antidebug = ConvertAntidebugOption(val); isFilled = true; } + if (util::iequals(valName, KEY_ANTIVM)) { + s.antivm = loadBoolean(valStr, s.antivm); + isFilled = true; + } if (util::iequals(valName, KEY_USE_DEBUG_SYMBOLS)) { s.useDebugSym = loadBoolean(valStr, s.useDebugSym); isFilled = true; @@ -189,7 +194,7 @@ bool Settings::saveINI(const std::string &filename) myfile << SLEEP_TIME << DELIM << this->sleepTime << "\r\n"; myfile << LOG_INDIRECT << DELIM << this->logIndirect << "\r\n"; myfile << KEY_ANTIDEBUG << DELIM << this->antidebug << "\r\n"; - + myfile << KEY_ANTIVM << DELIM << this->antivm << "\r\n"; myfile.close(); return true; } diff --git a/Settings.h b/Settings.h index 946f4c5..8f714a8 100644 --- a/Settings.h +++ b/Settings.h @@ -71,6 +71,7 @@ class Settings { logIndirect(false), hexdumpSize(8), antidebug(ANTIDEBUG_DISABLED), + antivm(false), useDebugSym(false) { } @@ -91,6 +92,7 @@ class Settings { bool hookSleep; size_t sleepTime; t_antidebug_options antidebug; + bool antivm; // Trace Anti-VM techniques (WMI queries) bool useDebugSym; SyscallsTable syscallsTable; //Syscalls table: mapping the syscall ID to the function name diff --git a/TinyTracer.cpp b/TinyTracer.cpp index 4e9904b..7c038a9 100644 --- a/TinyTracer.cpp +++ b/TinyTracer.cpp @@ -30,15 +30,21 @@ #define USE_ANTIDEBUG +#define USE_ANTIVM #ifndef _WIN32 #undef USE_ANTIDEBUG // works only for Windows! +#undef USE_ANTIVM #endif #ifdef USE_ANTIDEBUG #include "AntiDebug.h" #endif +#ifdef USE_ANTIVM +#include "AntiVm.h" +#endif + /* ================================================================== */ // Global variables /* ================================================================== */ @@ -818,6 +824,13 @@ VOID ImageLoad(IMG Image, VOID *v) AntiDbg::MonitorAntiDbgFunctions(Image); } #endif +#ifdef USE_ANTIVM + // ANTIVM: Register Function instrumentation needed for AntiVm + if (m_Settings.antivm) { + // Register functions + AntiVm::MonitorAntiVmFunctions(Image); + } +#endif } static void OnCtxChange(THREADID threadIndex, diff --git a/TinyTracer.vcxproj b/TinyTracer.vcxproj index 21b138c..f141002 100644 --- a/TinyTracer.vcxproj +++ b/TinyTracer.vcxproj @@ -279,6 +279,7 @@ + @@ -290,6 +291,7 @@ + diff --git a/TinyTracer_Pin3.18.vcxproj b/TinyTracer_Pin3.18.vcxproj index 9b1de86..bb334be 100644 --- a/TinyTracer_Pin3.18.vcxproj +++ b/TinyTracer_Pin3.18.vcxproj @@ -279,6 +279,7 @@ + @@ -289,6 +290,7 @@ + @@ -301,4 +303,4 @@ - + \ No newline at end of file diff --git a/TinyTracer_Pin3.25.vcxproj b/TinyTracer_Pin3.25.vcxproj index 6b861a1..3558f0b 100644 --- a/TinyTracer_Pin3.25.vcxproj +++ b/TinyTracer_Pin3.25.vcxproj @@ -279,6 +279,7 @@ + @@ -289,6 +290,7 @@ + @@ -301,4 +303,4 @@ - + \ No newline at end of file diff --git a/install32_64/TinyTracer.ini b/install32_64/TinyTracer.ini index bd5c3f6..dad41ea 100644 --- a/install32_64/TinyTracer.ini +++ b/install32_64/TinyTracer.ini @@ -19,3 +19,4 @@ SLEEP_TIME=10 ; 1 : Standard ; 2 : Deep (may lead to some false positives) ANTIDEBUG=0 +ANTIVM=0 \ No newline at end of file