diff --git a/config.h b/config.h index 8b1bb20..a144520 100644 --- a/config.h +++ b/config.h @@ -35,6 +35,11 @@ along with this program. If not, see . #define SPOOFED_CPU_CORE_NUM 4 +// Defines to string representation of above vars so we don't need to do useless converts +#define WIDE_SPOOFED_RAM L"4294967296" +#define WIDE_SPOOFED_RAM_IN_KB L"4194304" +#define WIDE_DISK_LOGICAL_SIZE L"1098988720128" // SPOOFED_DISK_SIZE - RECOVERY_PARTITION_SIZE + struct _g_config { // name of the pipe to communicate with cuckoo diff --git a/hook_wmi.c b/hook_wmi.c index f8b7eed..0228fe7 100644 --- a/hook_wmi.c +++ b/hook_wmi.c @@ -1,99 +1,301 @@ #include "log.h" #include "misc.h" +#include + +void SpoofWmiData(const wchar_t* szClassName, const wchar_t* wszName, VARIANT* pVal) { + if (g_config.no_stealth) + return; + + if (!szClassName || !wszName || !pVal) + return; + + // + // Spoofery logic for BSTR (wchar_t *) + // + if (pVal->vt == VT_BSTR && pVal->bstrVal) { + if (!_wcsicmp(pVal->bstrVal, L"Microsoft Basic Display Adapter")) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(SPOOFED_GPU_NAME); + } + else if (!_wcsicmp(wszName, L"TotalPhysicalMemory")) { + unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10); + if (actualMemory < SPOOFED_RAM) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(WIDE_SPOOFED_RAM); + } + } + else if (!_wcsicmp(wszName, L"TotalVisibleMemorySize")) { + unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10); + // actualMemory is in Kilobytes, our spoofed values are in bytes + if (actualMemory < (SPOOFED_RAM / 1024)) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(WIDE_SPOOFED_RAM_IN_KB); + } + } + // + // Logic for BSTR fakery specific to an exact szClassName + // + else if (!_wcsicmp(szClassName, L"Win32_LogicalDisk") && !_wcsicmp(wszName, L"Size")) { + unsigned long long lSize = wcstoull(pVal->bstrVal, NULL, 10); + if (lSize < SPOOFED_DISK_SIZE - RECOVERY_PARTITION_SIZE) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(WIDE_DISK_LOGICAL_SIZE); + } + } + else if (!_wcsicmp(szClassName, L"Win32_PhysicalMemory") && !_wcsicmp(wszName, L"Capacity")) { + unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10); + if (actualMemory < SPOOFED_RAM) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(WIDE_SPOOFED_RAM); + } + } + } + // + // Spoofery logic for I4 (Signed 32-bit integer) + // + else if (pVal->vt == VT_I4) { + if (!_wcsicmp(szClassName, L"Win32_Processor") && !_wcsicmp(wszName, L"ThreadCount")) { + if (pVal->lVal < SPOOFED_CPU_CORE_NUM) + pVal->lVal = SPOOFED_CPU_CORE_NUM; + } + else if (!_wcsicmp(wszName, L"NumberOfCores")) { + if (pVal->lVal < SPOOFED_CPU_CORE_NUM) + pVal->lVal = SPOOFED_CPU_CORE_NUM; + } + else if (!_wcsicmp(wszName, L"NumberOfLogicalProcessors")) { + if (pVal->lVal < SPOOFED_CPU_CORE_NUM) + pVal->lVal = SPOOFED_CPU_CORE_NUM; + } + else if (!_wcsicmp(wszName, L"NumberOfEnabledCore")) { + if (pVal->lVal < SPOOFED_CPU_CORE_NUM) + pVal->lVal = SPOOFED_CPU_CORE_NUM; + } + else if (!_wcsicmp(wszName, L"AdapterRAM")) { + if (SPOOFED_GPU_RAM > 0x7FFFFFFFULL) { + // Mimic overflowing the I4 if you have >2GB of Spoofed GPU RAM + pVal->lVal = 0x7FFFFFFF; + } + else { + // Cast to LONG to avoid compiler warning if SPOOFED_GPU_RAM is >2GB + if (pVal->lVal < (LONG)SPOOFED_GPU_RAM) { + pVal->lVal = (LONG)SPOOFED_GPU_RAM; + } + } + } + } + // + // Spoofery logic for NULL + // + else if (pVal->vt == VT_NULL) { + if (!_wcsicmp(wszName, L"SMBIOSBIOSVersion")) { + pVal->vt = VT_BSTR; + pVal->bstrVal = SysAllocString(L"1.23.1"); + } + } +} HOOKDEF(HRESULT, WINAPI, WMI_Get, - PVOID _this, - LPCWSTR wszName, - LONG lFlags, - VARIANT* pVal, - LONG* pType, - LONG* plFlavor + _In_ PVOID _this, + _In_ LPCWSTR wszName, + _In_ LONG lFlags, + _Out_ VARIANT *pVal, + _Out_opt_ CIMTYPE *pType, + _Out_opt_ LONG *plFlavor ) { HRESULT ret; + WCHAR szClassName[256] = L""; + if (wszName && wcscmp(wszName, L"__CLASS") != 0) { + VARIANT classVariant; + VariantInit(&classVariant); + IWbemClassObject* pWmiObject = (IWbemClassObject*)_this; + HRESULT hr = pWmiObject->lpVtbl->Get(pWmiObject, L"__CLASS", 0, &classVariant, NULL, NULL); + if (SUCCEEDED(hr) && classVariant.vt == VT_BSTR) { + wcscpy_s(szClassName, _countof(szClassName), classVariant.bstrVal); + } + VariantClear(&classVariant); + } + ret = Old_WMI_Get(_this, wszName, lFlags, pVal, pType, plFlavor); - LOQ_hresult("system", "un", "Name", wszName, "Value", pVal); + SpoofWmiData(szClassName, wszName, pVal); + + // Short circuit, return early for things we don't want to log + if (!ret && !g_config.full_logs && wszName) { + if ( + !wcscmp(wszName, L"__GENUS") || + !wcscmp(wszName, L"__PATH") || + !wcscmp(wszName, L"__RELPATH") || + !wcscmp(wszName, L"__SUPERCLASS") || + !wcscmp(wszName, L"SECURITY_DESCRIPTOR") || + !wcscmp(wszName, L"__NAMESPACE") || + !wcscmp(wszName, L"__CLASS") || + !wcscmp(wszName, L"__DERIVATION") + ) { + return ret; + } + } + + LOQ_hresult("system", "unu", "Name", wszName, "Value", pVal, "Class", szClassName); + return ret; +} + +HOOKDEF(HRESULT, WINAPI, WMI_Next, + _In_ PVOID _this, + _In_ LONG lFlags, + _Out_ BSTR *strName, + _Out_ VARIANT *pVal, + _Out_opt_ CIMTYPE *pType, + _Out_opt_ LONG *plFlavor +) { + HRESULT ret = Old_WMI_Next(_this, lFlags, strName, pVal, pType, plFlavor); + + // Return early for some cases we don't want to log / spoof + if (ret != S_OK) + return ret; + + if (!pVal) + return ret; + + if (pVal->vt == VT_NULL) + return ret; + + if (!strName || !*strName) + return ret; + + // If all is well at this point, we should do the spoofs + lasterror_t lasterror; + get_lasterrors(&lasterror); + VARIANT classVariant; + VariantInit(&classVariant); + + __try { + IWbemClassObject* pWmiObject = (IWbemClassObject*)_this; + HRESULT hr = pWmiObject->lpVtbl->Get(pWmiObject, L"__CLASS", 0, &classVariant, NULL, NULL); + WCHAR szClassName[256] = L""; + if (SUCCEEDED(hr) && classVariant.vt == VT_BSTR) { + wcscpy_s(szClassName, _countof(szClassName), classVariant.bstrVal); + } + SpoofWmiData(szClassName, *strName, pVal); + LOQ_hresult("system", "unu", "Name", *strName, "Value", pVal, "Class", szClassName); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + LOQ_hresult("system", "un", "Name", *strName, "Value", pVal); + } + + VariantClear(&classVariant); + set_lasterrors(&lasterror); return ret; } -HOOKDEF_NOTAIL(WINAPI, WMI_ExecQuery, - PVOID _this, - const BSTR strQueryLanguage, - const BSTR strQuery, - LONG lFlags, - PVOID pCtx, - PVOID* ppEnum +HOOKDEF(HRESULT, WINAPI, WMI_ExecQuery, + _In_ PVOID _this, + _In_ const BSTR strQueryLanguage, + _In_ const BSTR strQuery, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _Out_ IEnumWbemClassObject **ppEnum ) { HRESULT ret = 0; - LOQ_hresult("system", "u", "Query", strQuery); - return 0; + LOQ_hresult("system", "uu", "Query", strQuery, "QueryLanguage", strQueryLanguage); + return Old_WMI_ExecQuery(_this, strQueryLanguage, strQuery, lFlags, pCtx, ppEnum); } -HOOKDEF_NOTAIL(WINAPI, WMI_ExecQueryAsync, - PVOID _this, - const BSTR strQueryLanguage, - const BSTR strQuery, - long lFlags, - PVOID pCtx, - PVOID pResponseHandler +HOOKDEF(HRESULT, WINAPI, WMI_ExecQueryAsync, + _In_ PVOID _this, + _In_ const BSTR strQueryLanguage, + _In_ const BSTR strQuery, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResponseHandler ) { HRESULT ret = 0; - LOQ_hresult("system", "u", "Query", strQuery); - return 0; + LOQ_hresult("system", "uu", "Query", strQuery, "QueryLanguage", strQueryLanguage); + return Old_WMI_ExecQueryAsync(_this, strQueryLanguage, strQuery, lFlags, pCtx, pResponseHandler); } -HOOKDEF_NOTAIL(WINAPI, WMI_ExecMethod, - PVOID _this, - const BSTR strObjectPath, - const BSTR strMethodName, - long lFlags, - PVOID pCtx, - PVOID pInParams, - PVOID* ppOutParams, - PVOID* ppCallResult +HOOKDEF(HRESULT, WINAPI, WMI_ExecMethod, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ const BSTR strMethodName, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemClassObject *pInParams, + _Out_ IWbemClassObject **ppOutParams, + _Out_ IWbemCallResult **ppCallResult ) { HRESULT ret = 0; LOQ_hresult("system", "uu", "ObjectPath", strObjectPath, "MethodName", strMethodName); - return 0; + return Old_WMI_ExecMethod(_this, strObjectPath, strMethodName, lFlags, pCtx, pInParams, ppOutParams, ppCallResult); } -HOOKDEF_NOTAIL(WINAPI, WMI_ExecMethodAsync, - PVOID _this, - const BSTR strObjectPath, - const BSTR strMethodName, - long lFlags, - PVOID pCtx, - PVOID pInParams, - PVOID pResponseHandler +HOOKDEF(HRESULT, WINAPI, WMI_ExecMethodAsync, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ const BSTR strMethodName, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemClassObject *pInParams, + _In_ IWbemObjectSink *pResponseHandler ) { HRESULT ret = 0; LOQ_hresult("system", "uu", "ObjectPath", strObjectPath, "MethodName", strMethodName); - return 0; + return Old_WMI_ExecMethodAsync(_this, strObjectPath, strMethodName, lFlags, pCtx, pInParams, pResponseHandler); +} + +HOOKDEF(HRESULT, WINAPI, WMI_GetObject, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _Out_ IWbemClassObject **ppObject, + _Out_ IWbemCallResult **ppCallResult +) { + HRESULT ret = 0; + if (strObjectPath && SysStringLen(strObjectPath) > 0) + LOQ_hresult("system", "u", "ObjectPath", strObjectPath); + else + LOQ_hresult("system", "u", "ObjectPath", L""); + + return Old_WMI_GetObject(_this, strObjectPath, lFlags, pCtx, ppObject, ppCallResult); } -HOOKDEF_NOTAIL(WINAPI, WMI_GetObject, - PVOID _this, - const BSTR strObjectPath, - long lFlags, - PVOID pCtx, - PVOID* ppObject, - PVOID* ppCallResult +HOOKDEF(HRESULT, WINAPI, WMI_GetObjectAsync, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResultHandler ) { HRESULT ret = 0; if (strObjectPath && SysStringLen(strObjectPath) > 0) LOQ_hresult("system", "u", "ObjectPath", strObjectPath); else - LOQ_hresult("system", "u", "ObjectPath", L"[NULL or Empty]"); - return 0; + LOQ_hresult("system", "u", "ObjectPath", L""); + + return Old_WMI_GetObjectAsync(_this, strObjectPath, lFlags, pCtx, pResultHandler); +} + +/* +HOOKDEF(HRESULT, WINAPI, WMI_CreateInstanceEnum, + _In_ PVOID _this, + _In_ const BSTR strFilter, + _In_ long lFlags, + _In_ IWbemContext *pCtx, + _Out_ IEnumWbemClassObject **ppEnum +) { + HRESULT ret = 0; + LOQ_hresult("system", "u", "QueryClass", strFilter); + return Old_WMI_CreateInstanceEnum(_this, strFilter, lFlags, pCtx, ppEnum); } -HOOKDEF_NOTAIL(WINAPI, WMI_GetObjectAsync, - PVOID _this, - const BSTR strObjectPath, - long lFlags, - PVOID pCtx, - PVOID pResultHandler +HOOKDEF(HRESULT, WINAPI, WMI_CreateInstanceEnumAsync, + _In_ PVOID _this, + _In_ const BSTR strFilter, + _In_ long lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResponseHandler ) { HRESULT ret = 0; - LOQ_hresult("system", "u", "ObjectPath", strObjectPath); - return 0; -} \ No newline at end of file + LOQ_hresult("system", "u", "QueryClass", strFilter); + return Old_WMI_CreateInstanceEnumAsync(_this, strFilter, lFlags, pCtx, pResponseHandler); +} +*/ \ No newline at end of file diff --git a/hooks.c b/hooks.c index d024caf..7327024 100644 --- a/hooks.c +++ b/hooks.c @@ -182,15 +182,20 @@ hook_t full_hooks[] = { // WMI Hooks #ifdef _WIN64 HOOK_WITHNAME(fastprox, WMI_Get, "?Get@CWbemObject@@UEAAJPEBGJPEAUtagVARIANT@@PEAJ2@Z"), + HOOK_WITHNAME(fastprox, WMI_Next, "?Next@CWbemObject@@UEAAJJPEAPEAGPEAUtagVARIANT@@PEAJ2@Z"), #else HOOK_WITHNAME(fastprox, WMI_Get, "?Get@CWbemObject@@UAGJPBGJPAUtagVARIANT@@PAJ2@Z"), + HOOK_WITHNAME(fastprox, WMI_Next, "?Next@CWbemObject@@UAGJJPAPAGPAUtagVARIANT@@PAJ2@Z"), #endif - HOOK_NOTAIL(fastprox, WMI_ExecQuery, 6), - HOOK_NOTAIL(fastprox, WMI_ExecMethod, 8), - HOOK_NOTAIL(fastprox, WMI_ExecQueryAsync, 6), - HOOK_NOTAIL(fastprox, WMI_ExecMethodAsync, 7), - HOOK_NOTAIL(fastprox, WMI_GetObject, 6), - HOOK_NOTAIL(fastprox, WMI_GetObjectAsync, 5), + HOOK(fastprox, WMI_ExecQuery), + HOOK(fastprox, WMI_ExecQueryAsync), + HOOK(fastprox, WMI_ExecMethod), + HOOK(fastprox, WMI_ExecMethodAsync), + HOOK(fastprox, WMI_GetObject), + HOOK(fastprox, WMI_GetObjectAsync), + // TODO: Uncomment after adding Yara prolog detection for these non-exported hooks + //HOOK(fastprox, WMI_CreateInstanceEnum), + //HOOK(fastprox, WMI_CreateInstanceEnumAsync), // File Hooks HOOK(ntdll, NtQueryAttributesFile), diff --git a/hooks.h b/hooks.h index abb8074..7903462 100644 --- a/hooks.h +++ b/hooks.h @@ -22,6 +22,7 @@ along with this program. If not, see . #include "ntapi.h" #include #include +#include // // File Hooks @@ -1263,70 +1264,97 @@ HOOKDEF(HRESULT, WINAPI, CoGetObject, // WMI Hooks HOOKDEF(HRESULT, WINAPI, WMI_Get, - PVOID _this, - LPCWSTR wszName, - LONG lFlags, - VARIANT* pVal, - LONG* pType, - LONG* plFlavor -); - -HOOKDEF_NOTAIL(WINAPI, WMI_ExecQuery, - PVOID _this, - const BSTR strQueryLanguage, - const BSTR strQuery, - LONG lFlags, - PVOID pCtx, - PVOID* ppEnum -); - -HOOKDEF_NOTAIL(WINAPI, WMI_ExecQueryAsync, - PVOID _this, - const BSTR strQueryLanguage, - const BSTR strQuery, - LONG lFlags, - PVOID pCtx, - PVOID pResponseHandler -); - -HOOKDEF_NOTAIL(WINAPI, WMI_ExecMethod, - PVOID _this, - const BSTR strObjectPath, - const BSTR strMethodName, - long lFlags, - PVOID pCtx, - PVOID pInParams, - PVOID* ppOutParams, - PVOID* ppCallResult -); - -HOOKDEF_NOTAIL(WINAPI, WMI_ExecMethodAsync, - PVOID _this, - const BSTR strObjectPath, - const BSTR strMethodName, - long lFlags, - PVOID pCtx, - PVOID pInParams, - PVOID pResponseHandler -); - -HOOKDEF_NOTAIL(WINAPI, WMI_GetObject, - PVOID _this, - const BSTR strObjectPath, - LONG lFlags, - PVOID pCtx, - PVOID* ppObject, - PVOID* ppCallResult -); - -HOOKDEF_NOTAIL(WINAPI, WMI_GetObjectAsync, - PVOID _this, - const BSTR strObjectPath, - LONG lFlags, - PVOID pCtx, - PVOID pResultHandler + _In_ PVOID _this, + _In_ LPCWSTR wszName, + _In_ LONG lFlags, + _Out_ VARIANT *pVal, + _Out_opt_ CIMTYPE *pType, + _Out_opt_ LONG *plFlavor +); + +HOOKDEF(HRESULT, WINAPI, WMI_Next, + _In_ PVOID _this, + _In_ LONG lFlags, + _Out_ BSTR wszName, + _Out_ VARIANT *pVal, + _Out_opt_ CIMTYPE *pType, + _Out_opt_ LONG *plFlavor +); + +HOOKDEF(HRESULT, WINAPI, WMI_ExecQuery, + _In_ PVOID _this, + _In_ const BSTR strQueryLanguage, + _In_ const BSTR strQuery, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _Out_ IEnumWbemClassObject **ppEnum +); + +HOOKDEF(HRESULT, WINAPI, WMI_ExecQueryAsync, + _In_ PVOID _this, + _In_ const BSTR strQueryLanguage, + _In_ const BSTR strQuery, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResponseHandler +); + +HOOKDEF(HRESULT, WINAPI, WMI_ExecMethod, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ const BSTR strMethodName, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemClassObject *pInParams, + _Out_ IWbemClassObject **ppOutParams, + _Out_ IWbemCallResult **ppCallResult +); + +HOOKDEF(HRESULT, WINAPI, WMI_ExecMethodAsync, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ const BSTR strMethodName, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemClassObject *pInParams, + _In_ IWbemObjectSink *pResponseHandler +); + +HOOKDEF(HRESULT, WINAPI, WMI_GetObject, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _Out_ IWbemClassObject **ppObject, + _Out_ IWbemCallResult **ppCallResult +); + +HOOKDEF(HRESULT, WINAPI, WMI_GetObjectAsync, + _In_ PVOID _this, + _In_ const BSTR strObjectPath, + _In_ LONG lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResultHandler ); +/* +HOOKDEF(HRESULT, WINAPI, WMI_CreateInstanceEnum, + _In_ PVOID _this, + _In_ const BSTR strFilter, + _In_ long lFlags, + _In_ IWbemContext *pCtx, + _Out_ IEnumWbemClassObject **ppEnum +); + +HOOKDEF(HRESULT, WINAPI, WMI_CreateInstanceEnumAsync, + _In_ PVOID _this, + _In_ const BSTR strFilter, + _In_ long lFlags, + _In_ IWbemContext *pCtx, + _In_ IWbemObjectSink *pResponseHandler +); +*/ + // End of WMI Hooks HOOKDEF(NTSTATUS, WINAPI, NtMapViewOfSection,