Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SPOOFED_DISK_SIZE 0x10000000000ull // 1TB
#define RECOVERY_PARTITION_SIZE 0x1f2af000 // Taken from random Win10 install

#define SPOOFED_GPU_RAM_WMI 0xfff00000L // 4293918720; WMI uses lVal (long) so we have an "overflowed" value,
#define SPOOFED_GPU_RAM 0x100000000l // 4GB
#define SPOOFED_GPU_NAME L"NVIDIA GTX 1650"

Expand All @@ -35,6 +36,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

#define SPOOFED_CPU_CORE_NUM 4

#define SPOOFED_REFRESH_RATE 60


struct _g_config {
// name of the pipe to communicate with cuckoo
Expand Down
99 changes: 96 additions & 3 deletions hook_wmi.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#include <stdio.h>
#include "log.h"
#include "misc.h"
#include "config.h"

static int g_last_seen_disk_query = 0;
static int g_last_seen_physicalmemory = 0;


HOOKDEF(HRESULT, WINAPI, WMI_Get,
PVOID _this,
Expand All @@ -10,7 +16,79 @@ HOOKDEF(HRESULT, WINAPI, WMI_Get,
LONG* plFlavor
) {
HRESULT ret;
lasterror_t lasterror;

ret = Old_WMI_Get(_this, wszName, lFlags, pVal, pType, plFlavor);

get_lasterrors(&lasterror);
__try {
if (!ret && !g_config.no_stealth && pVal && wszName) {
if (pVal->vt == VT_BSTR) {
if (!wcsicmp(wszName, L"TotalPhysicalMemory")) {
unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10);
if (actualMemory < SPOOFED_RAM) {
wchar_t wszMemory[16];
memset(wszMemory, 0x0, sizeof(wszMemory));
swprintf_s(wszMemory, sizeof(wszMemory), L"%llu", SPOOFED_RAM);
SysFreeString(pVal->bstrVal);
pVal->bstrVal = SysAllocString(wszMemory);
}
}
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)) {
wchar_t wszMemory[16];
memset(wszMemory, 0x0, sizeof(wszMemory));
swprintf_s(wszMemory, sizeof(wszMemory), L"%llu", (SPOOFED_RAM / 1024));
SysFreeString(pVal->bstrVal);
pVal->bstrVal = SysAllocString(wszMemory);
}
}
else if (g_last_seen_disk_query && !wcsicmp(wszName, L"Size")) {
unsigned long long lSize = wcstoull(pVal->bstrVal, NULL, 10);
if (lSize < SPOOFED_DISK_SIZE - RECOVERY_PARTITION_SIZE) {
wchar_t newSize[16];
memset(newSize, 0x0, sizeof(newSize));
swprintf_s(newSize, sizeof(newSize), L"%llu", SPOOFED_DISK_SIZE - RECOVERY_PARTITION_SIZE);
SysFreeString(pVal->bstrVal);
pVal->bstrVal = SysAllocString(newSize);
}
}
else if (g_last_seen_physicalmemory && !wcsicmp(wszName, L"Capacity")) {
unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10);
if (actualMemory < SPOOFED_RAM) {
wchar_t wszMemory[16];
memset(wszMemory, 0x0, sizeof(wszMemory));
swprintf_s(wszMemory, sizeof(wszMemory), L"%llu", SPOOFED_RAM);
SysFreeString(pVal->bstrVal);
pVal->bstrVal = SysAllocString(wszMemory);
}
}
}
Comment on lines +26 to +68

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a lot of duplicated code for handling VT_BSTR spoofing. The logic for converting a spoofed value to a BSTR and replacing the existing one is repeated multiple times.

To improve maintainability and reduce redundancy, you could extract this logic into a helper function. For example:

static void spoof_bstr_value(VARIANT *pVal, unsigned long long spoofed_value_ull) {
    wchar_t buffer[21]; // Sufficient for a 64-bit unsigned long long
    swprintf_s(buffer, _countof(buffer), L"%llu", spoofed_value_ull);
    SysFreeString(pVal->bstrVal);
    pVal->bstrVal = SysAllocString(buffer);
}

Then you can simplify the code like this:

if (!wcsicmp(wszName, L"TotalPhysicalMemory")) {
    unsigned long long actualMemory = wcstoull(pVal->bstrVal, NULL, 10);
    if (actualMemory < SPOOFED_RAM) {
        spoof_bstr_value(pVal, SPOOFED_RAM);
    }
}

This would make the code much cleaner and easier to maintain.

else if (pVal->vt == VT_I4) {
if (!wcsicmp(wszName, L"NumberOfCores")) {
if (pVal->lVal < SPOOFED_CPU_CORE_NUM)
pVal->lVal = SPOOFED_CPU_CORE_NUM;
}
else if (!wcsicmp(wszName, L"AdapterRAM")) {
if (pVal->lVal < SPOOFED_GPU_RAM) {
pVal->lVal = SPOOFED_GPU_RAM_WMI;
}
}
else if (!wcsicmp(wszName, L"MaxRefreshRate")) {
if (pVal->lVal < SPOOFED_REFRESH_RATE) {
pVal->lVal = SPOOFED_REFRESH_RATE;
}
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
;
}
set_lasterrors(&lasterror);

LOQ_hresult("system", "un", "Name", wszName, "Value", pVal);
return ret;
}
Expand All @@ -24,7 +102,23 @@ HOOKDEF_NOTAIL(WINAPI, WMI_ExecQuery,
PVOID* ppEnum
) {
HRESULT ret = 0;
LOQ_hresult("system", "u", "Query", strQuery);

// Reset these on new query
g_last_seen_disk_query = 0;
g_last_seen_physicalmemory = 0;

if (!ret && !g_config.no_stealth && strQuery) {
if (!_wcsnicmp(strQuery, L"SELECT ", 7)) {
if (wcsistr(strQuery, L" FROM Win32_LogicalDisk")) {
g_last_seen_disk_query = 1;
//pipe("INFO:setting g_last_seen_disk_query");
}
else if (wcsistr(strQuery, L" FROM Win32_PhysicalMemory")) {
g_last_seen_physicalmemory = 1;
}
}
}
LOQ_hresult("system", "uu", "Query", strQuery, "QueryLanguage", strQueryLanguage);
return 0;
Comment on lines 104 to 122

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The WMI_ExecQuery hook is implemented as a NOTAIL hook that always returns 0 without calling the original IWbemServices::ExecQuery function. This means that no WMI query will actually be executed, and no results will be returned.

As a consequence, the logic in New_WMI_Get that relies on the g_last_seen_disk_query and g_last_seen_physicalmemory flags will never be triggered, because WMI_Get is called on objects from the query result, which will be empty.

To fix this, WMI_ExecQuery must be changed to call the original function. This involves:

  1. Changing the hook definition in hooks.c from HOOK_NOTAIL(fastprox, WMI_ExecQuery, 6) to HOOK(fastprox, WMI_ExecQuery). I understand hooks.c is not in this PR, but this change is necessary for the feature to work.
  2. Updating hook_wmi.c to use HOOKDEF instead of HOOKDEF_NOTAIL and calling Old_WMI_ExecQuery.
  3. The check if (!ret && ...) is also redundant as ret is always 0 at that point.

I've provided a suggested implementation for the function body below. Note that this also requires changing HOOKDEF_NOTAIL(WINAPI, WMI_ExecQuery, ...) to HOOKDEF(HRESULT, WINAPI, WMI_ExecQuery, ...) in hook_wmi.c.

	HRESULT ret;

	// Reset these on new query
	g_last_seen_disk_query = 0;
	g_last_seen_physicalmemory = 0;

	if (!g_config.no_stealth && strQuery) {
		if (!_wcsnicmp(strQuery, L"SELECT ", 7)) {
			if (wcsistr(strQuery, L" FROM Win32_LogicalDisk")) {
				g_last_seen_disk_query = 1;
				//pipe("INFO:setting g_last_seen_disk_query");
			}
			else if (wcsistr(strQuery, L" FROM Win32_PhysicalMemory")) {
				g_last_seen_physicalmemory = 1;
			}
		}
	}

	ret = Old_WMI_ExecQuery(_this, strQueryLanguage, strQuery, lFlags, pCtx, ppEnum);

	LOQ_hresult("system", "uu", "Query", strQuery, "QueryLanguage", strQueryLanguage);
	return ret;

}

Expand Down Expand Up @@ -66,7 +160,6 @@ HOOKDEF_NOTAIL(WINAPI, WMI_ExecMethodAsync,
PVOID pResponseHandler
) {
HRESULT ret = 0;
LOQ_hresult("system", "uu", "ObjectPath", strObjectPath, "MethodName", strMethodName);
return 0;
}

Expand All @@ -82,7 +175,7 @@ HOOKDEF_NOTAIL(WINAPI, WMI_GetObject,
if (strObjectPath && SysStringLen(strObjectPath) > 0)
LOQ_hresult("system", "u", "ObjectPath", strObjectPath);
else
LOQ_hresult("system", "u", "ObjectPath", L"[NULL or Empty]");
LOQ_hresult("system", "u", "ObjectPath", L"");
return 0;
}

Expand Down