wibo/test/test_ntquery.c

145 lines
4.9 KiB
C

#include <windows.h>
#include <winternl.h>
#include <wchar.h>
#include <string.h>
#include "test_assert.h"
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_INFO_LENGTH_MISMATCH
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#endif
#ifndef STATUS_INVALID_INFO_CLASS
#define STATUS_INVALID_INFO_CLASS ((NTSTATUS)0xC0000003L)
#endif
typedef NTSTATUS(NTAPI *NtQueryInformationProcess_t)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
static WCHAR wide_to_upper(WCHAR ch) {
if (ch >= L'a' && ch <= L'z') {
return ch - (WCHAR)32;
}
return ch;
}
static int wide_cmp_case_insensitive(const WCHAR *lhs, const WCHAR *rhs) {
while (*lhs && *rhs) {
WCHAR a = wide_to_upper(*lhs);
WCHAR b = wide_to_upper(*rhs);
if (a != b) {
break;
}
++lhs;
++rhs;
}
return (int)wide_to_upper(*lhs) - (int)wide_to_upper(*rhs);
}
static const WCHAR *skip_nt_path_prefix(const WCHAR *path) {
if (!path) {
return path;
}
if (path[0] == L'\\' && path[1] == L'?' && path[2] == L'?' && path[3] == L'\\') {
return path + 4;
}
return path;
}
static NtQueryInformationProcess_t load_ntquery(void) {
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (!ntdll) {
ntdll = LoadLibraryW(L"ntdll.dll");
}
TEST_CHECK(ntdll != NULL);
FARPROC proc = GetProcAddress(ntdll, "NtQueryInformationProcess");
TEST_CHECK(proc != NULL);
NtQueryInformationProcess_t fn = NULL;
TEST_CHECK(sizeof(fn) == sizeof(proc));
memcpy(&fn, &proc, sizeof(fn));
return fn;
}
static void test_basic_information(NtQueryInformationProcess_t fn) {
PROCESS_BASIC_INFORMATION info;
ULONG returnLength = 0;
NTSTATUS status = fn(GetCurrentProcess(), ProcessBasicInformation, &info, sizeof(info), &returnLength);
TEST_CHECK_EQ((NTSTATUS)STATUS_SUCCESS, status);
TEST_CHECK(returnLength >= sizeof(info));
TEST_CHECK_EQ((ULONG_PTR)GetCurrentProcessId(), info.UniqueProcessId);
TEST_CHECK(info.PebBaseAddress != NULL);
TEST_CHECK_EQ(STILL_ACTIVE, (DWORD)info.ExitStatus);
}
static void test_wow64_information(NtQueryInformationProcess_t fn) {
ULONG_PTR wow64 = (ULONG_PTR)0xDEADBEEF;
ULONG returnLength = 0;
NTSTATUS status = fn(GetCurrentProcess(), ProcessWow64Information, &wow64, sizeof(wow64), &returnLength);
TEST_CHECK_EQ((NTSTATUS)STATUS_SUCCESS, status);
TEST_CHECK_EQ((ULONG)sizeof(ULONG_PTR), returnLength);
BOOL isWow64 = FALSE;
if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) {
TEST_CHECK(wow64 != 0);
} else {
TEST_CHECK_EQ((ULONG_PTR)0, wow64);
}
}
static void test_image_file_name(NtQueryInformationProcess_t fn) {
unsigned char buffer[sizeof(UNICODE_STRING) + 1024];
ULONG returnLength = 0;
NTSTATUS status = fn(GetCurrentProcess(), ProcessImageFileName, buffer, sizeof(buffer), &returnLength);
TEST_CHECK_EQ((NTSTATUS)STATUS_SUCCESS, status);
TEST_CHECK(returnLength > sizeof(UNICODE_STRING));
UNICODE_STRING *u = (UNICODE_STRING *)buffer;
TEST_CHECK(u->Buffer != NULL);
TEST_CHECK(u->Length % sizeof(WCHAR) == 0);
int charCount = (int)(u->Length / sizeof(WCHAR));
WCHAR from_ntquery[512];
TEST_CHECK(charCount < (int)(sizeof(from_ntquery) / sizeof(from_ntquery[0])));
memcpy(from_ntquery, u->Buffer, u->Length);
from_ntquery[charCount] = L'\0';
WCHAR expected[512];
DWORD len = GetModuleFileNameW(NULL, expected, (DWORD)(sizeof(expected) / sizeof(expected[0])));
TEST_CHECK(len > 0);
const WCHAR *normalized_expected = skip_nt_path_prefix(expected);
const WCHAR *normalized_actual = skip_nt_path_prefix(from_ntquery);
TEST_CHECK_MSG(wide_cmp_case_insensitive(normalized_expected, normalized_actual) == 0,
"expected %ls, got %ls", normalized_expected, normalized_actual);
}
static void test_invalid_lengths(NtQueryInformationProcess_t fn) {
PROCESS_BASIC_INFORMATION info;
ULONG returnLength = 0;
NTSTATUS status = fn(GetCurrentProcess(), ProcessBasicInformation, &info, sizeof(info) - 1, &returnLength);
TEST_CHECK_EQ((NTSTATUS)STATUS_INFO_LENGTH_MISMATCH, status);
TEST_CHECK_EQ((ULONG)sizeof(PROCESS_BASIC_INFORMATION), returnLength);
ULONG_PTR wow64 = 0;
status = fn(GetCurrentProcess(), ProcessWow64Information, &wow64, sizeof(wow64) - 1, &returnLength);
TEST_CHECK_EQ((NTSTATUS)STATUS_INFO_LENGTH_MISMATCH, status);
}
static void test_invalid_class(NtQueryInformationProcess_t fn) {
ULONG dummy = 0;
NTSTATUS status = fn(GetCurrentProcess(), (PROCESSINFOCLASS)1234, &dummy, sizeof(dummy), NULL);
TEST_CHECK_EQ((NTSTATUS)STATUS_INVALID_INFO_CLASS, status);
}
int main(void) {
NtQueryInformationProcess_t fn = load_ntquery();
test_basic_information(fn);
test_wow64_information(fn);
test_image_file_name(fn);
test_invalid_lengths(fn);
test_invalid_class(fn);
return 0;
}