diff --git a/capemon.c b/capemon.c index 8cb30234..b8cae308 100644 --- a/capemon.c +++ b/capemon.c @@ -562,6 +562,7 @@ void init_private_heap(void) } extern CRITICAL_SECTION readfile_critsec, g_mutex, g_writing_log_buffer_mutex, g_interactive_debugger_lock; +lookup_t g_wmi_locator_lookup; BOOLEAN g_dll_main_complete; OSVERSIONINFOA g_osverinfo; @@ -608,6 +609,9 @@ BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) // read the config settings read_config(); + // initialize dynamic polymorphic WMI spoofing strings + InitWmiSpoofStrings(); + if (g_config.standalone) { // initialize these because some hooks behave badly when they are empty if (!g_config.w_analyzer[0]) { diff --git a/config.c b/config.c index 6255ecb7..4b13db76 100644 --- a/config.c +++ b/config.c @@ -1453,6 +1453,34 @@ void parse_config_line(char* line) if (g_config.hook_watch) DebugOutput("Config: Hook watch enabled.\n"); } + else if (!stricmp(key, "wmi-board-vendor")) { + strncpy_s(g_config.board_vendor, _countof(g_config.board_vendor), value, _TRUNCATE); + DebugOutput("Config: WMI board vendor set to %s.\n", g_config.board_vendor); + } + else if (!stricmp(key, "wmi-board-product")) { + strncpy_s(g_config.board_product, _countof(g_config.board_product), value, _TRUNCATE); + DebugOutput("Config: WMI board product set to %s.\n", g_config.board_product); + } + else if (!stricmp(key, "wmi-board-serial")) { + strncpy_s(g_config.board_serial, _countof(g_config.board_serial), value, _TRUNCATE); + DebugOutput("Config: WMI board serial set to %s.\n", g_config.board_serial); + } + else if (!stricmp(key, "wmi-disk-model")) { + strncpy_s(g_config.disk_model, _countof(g_config.disk_model), value, _TRUNCATE); + DebugOutput("Config: WMI disk model set to %s.\n", g_config.disk_model); + } + else if (!stricmp(key, "wmi-disk-serial")) { + strncpy_s(g_config.disk_serial, _countof(g_config.disk_serial), value, _TRUNCATE); + DebugOutput("Config: WMI disk serial set to %s.\n", g_config.disk_serial); + } + else if (!stricmp(key, "wmi-bios-vendor")) { + strncpy_s(g_config.bios_vendor, _countof(g_config.bios_vendor), value, _TRUNCATE); + DebugOutput("Config: WMI BIOS vendor set to %s.\n", g_config.bios_vendor); + } + else if (!stricmp(key, "wmi-bios-serial")) { + strncpy_s(g_config.bios_serial, _countof(g_config.bios_serial), value, _TRUNCATE); + DebugOutput("Config: WMI BIOS serial set to %s.\n", g_config.bios_serial); + } else if (!stricmp(key, "sleep-skip-seconds")) { g_config.sleep_skip_seconds = (int)strtoul(value, NULL, 10); DebugOutput("Config: Sleep skip seconds set to %d.\n", g_config.sleep_skip_seconds); @@ -1504,6 +1532,13 @@ void read_config(void) g_config.loaderlock_scans = 1; g_config.spoofed_cpu_count = SPOOFED_CPU_CORE_NUM; g_config.syscall = 1; + strncpy_s(g_config.board_vendor, _countof(g_config.board_vendor), "ASUSTeK COMPUTER INC.", _TRUNCATE); + strncpy_s(g_config.board_product, _countof(g_config.board_product), "PRIME Z390-A", _TRUNCATE); + strncpy_s(g_config.board_serial, _countof(g_config.board_serial), "190442345001294", _TRUNCATE); + strncpy_s(g_config.disk_model, _countof(g_config.disk_model), "Samsung SSD 860 EVO 500GB", _TRUNCATE); + strncpy_s(g_config.disk_serial, _countof(g_config.disk_serial), "S3Y1NX0K412941X", _TRUNCATE); + strncpy_s(g_config.bios_vendor, _countof(g_config.bios_vendor), "American Megatrends Inc.", _TRUNCATE); + strncpy_s(g_config.bios_serial, _countof(g_config.bios_serial), "System Serial Number", _TRUNCATE); g_config.sleep_skip_seconds = 10; StepLimit = SINGLE_STEP_LIMIT; diff --git a/config.h b/config.h index 047be9de..454ac551 100644 --- a/config.h +++ b/config.h @@ -336,6 +336,13 @@ struct _g_config { int trace_times; char *trace_into_api[EXCLUSION_MAX]; int hook_watch; + char board_vendor[128]; + char board_product[128]; + char board_serial[128]; + char disk_model[128]; + char disk_serial[128]; + char bios_vendor[128]; + char bios_serial[128]; int sleep_skip_seconds; }; diff --git a/docs/configuration.md b/docs/configuration.md index 561ad164..4bae84c6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -75,6 +75,13 @@ They are typically defined in the analysis configuration file (e.g., `config.ini | `fake-rdtsc` | Boolean | Enable fake RDTSC (Read Time-Stamp Counter) results. | | `nop-rdtscp` | Boolean | NOP (No Operation) the RDTSCP instruction. | | `cpu-count` | Integer | Spoof the number of CPU cores (default: 4). | +| `wmi-board-vendor` | String | Spoof the motherboard manufacturer returned via WMI Win32_BaseBoard queries (default: "ASUSTeK COMPUTER INC."). | +| `wmi-board-product` | String | Spoof the motherboard product model returned via WMI Win32_BaseBoard queries (default: "PRIME Z390-A"). | +| `wmi-board-serial` | String | Spoof the motherboard serial number returned via WMI Win32_BaseBoard queries (default: "190442345001294"). | +| `wmi-disk-model` | String | Spoof the physical disk drive model returned via WMI Win32_DiskDrive queries (default: "Samsung SSD 860 EVO 500GB"). | +| `wmi-disk-serial` | String | Spoof the physical disk drive serial number returned via WMI Win32_DiskDrive queries (default: "S3Y1NX0K412941X"). | +| `wmi-bios-vendor` | String | Spoof the BIOS manufacturer returned via WMI Win32_BIOS queries (default: "American Megatrends Inc."). | +| `wmi-bios-serial` | String | Spoof the BIOS serial number returned via WMI Win32_BIOS queries (default: "System Serial Number"). | | `ntdll-protect` | Boolean | Enable write protection on `ntdll.dll` code (enabled by default). | | `ntdll-unhook` | Boolean | Enable protection against `ntdll` unhooking (via `NtReadFile`). | | `ntdll-remap` | Boolean | Enable `ntdll` remapping protection. | diff --git a/hook_com.c b/hook_com.c index e3a41019..9ad5da3c 100644 --- a/hook_com.c +++ b/hook_com.c @@ -40,7 +40,7 @@ BOOL ContainsNamespace(const wchar_t* resource, const wchar_t* target) { return FALSE; } -__declspec(thread) BOOL bHookViaWbemLocator; +#include "hooks.h" HOOKDEF(HRESULT, WINAPI, WbemLocator_ConnectServer, _In_ PVOID _this, _In_ const BSTR strNetworkResource, @@ -63,9 +63,9 @@ HOOKDEF(HRESULT, WINAPI, WbemLocator_ConnectServer, ContainsNamespace(strNetworkResource, L"ROOT\\Microsoft\\Windows\\TaskScheduler") )) { - bHookViaWbemLocator = TRUE; + SetHookViaWbemLocator(TRUE); set_com_hooks(NULL, NULL, *ppNamespace); - bHookViaWbemLocator = FALSE; + SetHookViaWbemLocator(FALSE); } LOQ_hresult("com", "uu", "NetworkResource", strNetworkResource, "User", strUser); diff --git a/hook_wmi.c b/hook_wmi.c index fec80b93..3424bc85 100644 --- a/hook_wmi.c +++ b/hook_wmi.c @@ -3,6 +3,60 @@ #include "config.h" #include +static BSTR g_wmi_board_vendor = NULL; +static BSTR g_wmi_board_product = NULL; +static BSTR g_wmi_board_serial = NULL; +static BSTR g_wmi_disk_model = NULL; +static BSTR g_wmi_disk_serial = NULL; +static BSTR g_wmi_bios_vendor = NULL; +static BSTR g_wmi_bios_serial = NULL; + +void InitWmiSpoofStrings(void) { + int len; + + len = MultiByteToWideChar(CP_ACP, 0, g_config.board_vendor, -1, NULL, 0); + if (len > 0) { + g_wmi_board_vendor = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.board_vendor, -1, g_wmi_board_vendor, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.board_product, -1, NULL, 0); + if (len > 0) { + g_wmi_board_product = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.board_product, -1, g_wmi_board_product, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.board_serial, -1, NULL, 0); + if (len > 0) { + g_wmi_board_serial = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.board_serial, -1, g_wmi_board_serial, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.disk_model, -1, NULL, 0); + if (len > 0) { + g_wmi_disk_model = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.disk_model, -1, g_wmi_disk_model, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.disk_serial, -1, NULL, 0); + if (len > 0) { + g_wmi_disk_serial = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.disk_serial, -1, g_wmi_disk_serial, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.bios_vendor, -1, NULL, 0); + if (len > 0) { + g_wmi_bios_vendor = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.bios_vendor, -1, g_wmi_bios_vendor, len); + } + + len = MultiByteToWideChar(CP_ACP, 0, g_config.bios_serial, -1, NULL, 0); + if (len > 0) { + g_wmi_bios_serial = SysAllocStringLen(NULL, len - 1); + MultiByteToWideChar(CP_ACP, 0, g_config.bios_serial, -1, g_wmi_bios_serial, len); + } +} + void SpoofWmiData(const wchar_t* szClassName, const wchar_t* wszName, VARIANT* pVal) { if (g_config.no_stealth) return; @@ -50,6 +104,44 @@ void SpoofWmiData(const wchar_t* szClassName, const wchar_t* wszName, VARIANT* p pVal->bstrVal = SysAllocString(WIDE_SPOOFED_RAM); } } + else if (!_wcsicmp(szClassName, L"Win32_BaseBoard")) { + if (!_wcsicmp(wszName, L"Manufacturer") && g_wmi_board_vendor) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_board_vendor); + } + else if (!_wcsicmp(wszName, L"Product") && g_wmi_board_product) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_board_product); + } + else if (!_wcsicmp(wszName, L"SerialNumber") && g_wmi_board_serial) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_board_serial); + } + } + else if (!_wcsicmp(szClassName, L"Win32_DiskDrive")) { + if (!_wcsicmp(wszName, L"Model") && g_wmi_disk_model) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_disk_model); + } + else if (!_wcsicmp(wszName, L"SerialNumber") && g_wmi_disk_serial) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_disk_serial); + } + } + else if (!_wcsicmp(szClassName, L"Win32_BIOS")) { + if (!_wcsicmp(wszName, L"Manufacturer") && g_wmi_bios_vendor) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_bios_vendor); + } + else if (!_wcsicmp(wszName, L"SerialNumber") && g_wmi_bios_serial) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(g_wmi_bios_serial); + } + else if (!_wcsicmp(wszName, L"ReleaseDate")) { + SysFreeString(pVal->bstrVal); + pVal->bstrVal = SysAllocString(L"20220412000000.000000+000"); + } + } } // // Spoofery logic for I4 (Signed 32-bit integer) diff --git a/hooks.c b/hooks.c index bb358e06..5c600df7 100644 --- a/hooks.c +++ b/hooks.c @@ -1949,7 +1949,6 @@ int set_IWbemServices_hooks(PVOID pComObject, hook_t* hook) { return -1; } -extern __declspec(thread) BOOL bHookViaWbemLocator; void set_com_hooks(REFCLSID rclsid, REFIID riid, PVOID pComObject) { if (!com_hooks_initialized) { init_com_hooks(); diff --git a/hooks.h b/hooks.h index ca867d68..056fc02f 100644 --- a/hooks.h +++ b/hooks.h @@ -23,6 +23,7 @@ along with this program. If not, see . #include #include #include "hook_trace.h" +#include "lookup.h" #include #pragma comment(lib, "wbemuuid.lib") @@ -1331,7 +1332,7 @@ HOOKDEF(HRESULT, WINAPI, WMI_Get, HOOKDEF(HRESULT, WINAPI, WMI_Next, _In_ PVOID _this, _In_ LONG lFlags, - _Out_ BSTR wszName, + _Out_ BSTR *strName, _Out_ VARIANT *pVal, _Out_opt_ CIMTYPE *pType, _Out_opt_ LONG *plFlavor @@ -4224,4 +4225,12 @@ HOOKDEF(DWORD, WINAPI, MapFileAndCheckSumA, _Out_ PDWORD CheckSum ); +void InitWmiSpoofStrings(void); + +// Per-thread "hooking via IWbemLocator" flag. Uses the lock-free lookup table +// (LOOKUP_THREAD idiom) instead of TLS, matching the SafeLookup convention. +extern lookup_t g_wmi_locator_lookup; +#define bHookViaWbemLocator (*(BOOL *)LOOKUP_THREAD(&g_wmi_locator_lookup, BOOL)) +#define SetHookViaWbemLocator(val) (bHookViaWbemLocator = (BOOL)(val)) + #include "hook_vbscript.h"