mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
implement hal table validation
This commit is contained in:
parent
d6bc82f6e9
commit
1e2e41f76e
11 changed files with 613 additions and 241 deletions
|
@ -11,7 +11,7 @@ open source anti cheat (lol) which I made for fun.
|
|||
- DPC stackwalking via RtlCaptureStackBackTrace
|
||||
- Handle stripping via obj callbacks
|
||||
- Process handle table enumeration
|
||||
- System module verification
|
||||
- System module device object verification
|
||||
- System module .text integrity checks (see known issues)
|
||||
- Unlinked process detection
|
||||
- Removed thread PspCidTable entry detection
|
||||
|
@ -20,6 +20,7 @@ open source anti cheat (lol) which I made for fun.
|
|||
- EPT hook detection (currently detects hyperdbg and DdiMon)
|
||||
- Driver integrity checks both locally and over server
|
||||
- Hypervisor detection
|
||||
- HalDispatch and HalPrivateDispatch routine validation
|
||||
|
||||
# planned features
|
||||
|
||||
|
@ -35,7 +36,7 @@ open source anti cheat (lol) which I made for fun.
|
|||
- pcileech firmware detection
|
||||
- testing program to test the features
|
||||
- simple user mode logger + usermode logging overhaul
|
||||
- some more which i cant think of
|
||||
- data ptr detction (+ chained data ptr walking)
|
||||
|
||||
# example
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
#define REPORT_APC_STACKWALK 110
|
||||
#define REPORT_DPC_STACKWALK 120
|
||||
#define REPORT_DATA_TABLE_ROUTINE 130
|
||||
|
||||
/*
|
||||
* Generic macros that allow you to quickly determine whether
|
||||
|
|
|
@ -432,11 +432,6 @@ end:
|
|||
return status;
|
||||
}
|
||||
|
||||
GetSystemModuleValidationContext(_Out_ PSYS_MODULE_VAL_CONTEXT* Context)
|
||||
{
|
||||
*Context = &driver_config.sys_val_context;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
|
@ -521,6 +516,11 @@ GetDriverDeviceObject()
|
|||
return driver_config.device_object;
|
||||
}
|
||||
|
||||
GetSystemModuleValidationContext(_Out_ PSYS_MODULE_VAL_CONTEXT* Context)
|
||||
{
|
||||
*Context = &driver_config.sys_val_context;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
|
|
|
@ -405,21 +405,11 @@ MapDiskImageIntoVirtualAddressSpace(_Inout_ PHANDLE Sec
|
|||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
/*
|
||||
* It is of utmost importants to mark SectionHandle as null after closing the
|
||||
* handle from inside this function since an error has occured. The reason this is
|
||||
* so important is because we are not responsible for freeing the function if it
|
||||
* succeeds and even if it fails, we still allocate a value to the handle via
|
||||
* ZwCreateSection. Meaning when the caller goes to check if the handle is null, it
|
||||
* will not be null and will cause a double free.
|
||||
*/
|
||||
/* caller is responsible for closing handle on success, therefore null it */
|
||||
DEBUG_ERROR("ZwMapViewOfSection failed with status %x", status);
|
||||
|
||||
ZwClose(file_handle);
|
||||
ZwClose(*SectionHandle);
|
||||
|
||||
*SectionHandle = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -436,22 +426,7 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
|
|||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Since the windows documentation for the BCrypt functions contain the worst variable
|
||||
* naming scheme in existence, I will try to explain what they do. (for my sake and any
|
||||
* readers who also aren't smart enough to understand their otherworldy naming convention)
|
||||
*
|
||||
* algo_handle: handle to our BCrypt algorithm
|
||||
* hash_handle: handle to our BCrypt hash
|
||||
* bytes_copied: number of bytes that were copied to the output buffer when using
|
||||
* BCryptGetProperty resulting_hash_size: this is the size of the final buffer hash, it
|
||||
* should be equal to 32 (sizeof SHA256 hash) hash_object_size: the size of the buffer that
|
||||
* will temporarily store our hash object hash_object: pointer to the buffer storing our
|
||||
* hash object which is used to hash our buffer resulting_hash: pointer to the buffer that
|
||||
* stores the resulting hash of our buffer, this is what we care about
|
||||
*/
|
||||
|
||||
NTSTATUS status = STATUS_ABANDONED;
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
BCRYPT_ALG_HANDLE algo_handle = NULL;
|
||||
BCRYPT_HASH_HANDLE hash_handle = NULL;
|
||||
ULONG bytes_copied = 0;
|
||||
|
@ -1350,7 +1325,7 @@ UINT64
|
|||
MeasureReads(_In_ PVOID Address, _In_ ULONG Count)
|
||||
{
|
||||
UINT64 read_average = 0;
|
||||
UINT64 old_irql;
|
||||
UINT64 old_irql = 0;
|
||||
|
||||
MeasureInstructionRead(Address);
|
||||
|
||||
|
@ -1562,242 +1537,250 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
|
|||
}
|
||||
}
|
||||
|
||||
//NTSTATUS
|
||||
//ValidateSystemModules()
|
||||
// NTSTATUS
|
||||
// ValidateSystemModules()
|
||||
//{
|
||||
// NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
// BOOLEAN bstatus = FALSE;
|
||||
// ANSI_STRING ansi_string = {0};
|
||||
// UNICODE_STRING path = {0};
|
||||
// ULONG section_size = 0;
|
||||
// HANDLE section_handle = NULL;
|
||||
// PVOID section = NULL;
|
||||
// PVOID disk_buffer = NULL;
|
||||
// ULONG disk_buffer_size = 0;
|
||||
// PVOID disk_hash = NULL;
|
||||
// ULONG disk_hash_size = 0;
|
||||
// UINT64 disk_text_base = 0;
|
||||
// UINT64 memory_text_base = 0;
|
||||
// ULONG memory_text_size = 0;
|
||||
// PVOID memory_hash = NULL;
|
||||
// ULONG memory_hash_size = 0;
|
||||
// PVOID memory_buffer = NULL;
|
||||
// ULONG memory_buffer_size = 0;
|
||||
// ULONG result = 0;
|
||||
// PEPROCESS process = NULL;
|
||||
// KAPC_STATE apc_state = {0};
|
||||
// SYSTEM_MODULES modules = {0};
|
||||
// PRTL_MODULE_EXTENDED_INFO module_info = NULL;
|
||||
// PIMAGE_SECTION_HEADER disk_text_header = NULL;
|
||||
// PIMAGE_SECTION_HEADER memory_text_header = NULL;
|
||||
// NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
// BOOLEAN bstatus = FALSE;
|
||||
// ANSI_STRING ansi_string = {0};
|
||||
// UNICODE_STRING path = {0};
|
||||
// ULONG section_size = 0;
|
||||
// HANDLE section_handle = NULL;
|
||||
// PVOID section = NULL;
|
||||
// PVOID disk_buffer = NULL;
|
||||
// ULONG disk_buffer_size = 0;
|
||||
// PVOID disk_hash = NULL;
|
||||
// ULONG disk_hash_size = 0;
|
||||
// UINT64 disk_text_base = 0;
|
||||
// UINT64 memory_text_base = 0;
|
||||
// ULONG memory_text_size = 0;
|
||||
// PVOID memory_hash = NULL;
|
||||
// ULONG memory_hash_size = 0;
|
||||
// PVOID memory_buffer = NULL;
|
||||
// ULONG memory_buffer_size = 0;
|
||||
// ULONG result = 0;
|
||||
// PEPROCESS process = NULL;
|
||||
// KAPC_STATE apc_state = {0};
|
||||
// SYSTEM_MODULES modules = {0};
|
||||
// PRTL_MODULE_EXTENDED_INFO module_info = NULL;
|
||||
// PIMAGE_SECTION_HEADER disk_text_header = NULL;
|
||||
// PIMAGE_SECTION_HEADER memory_text_header = NULL;
|
||||
//
|
||||
// DEBUG_VERBOSE("Beginning to validate system modules.");
|
||||
// DEBUG_VERBOSE("Beginning to validate system modules.");
|
||||
//
|
||||
// status = GetSystemModuleInformation(&modules);
|
||||
// status = GetSystemModuleInformation(&modules);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("GetSystemModuleInformation failed with status %s", status);
|
||||
// return status;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("GetSystemModuleInformation failed with status %s", status);
|
||||
// return status;
|
||||
// }
|
||||
//
|
||||
// /*
|
||||
// * Since ntoskrnl itself is a process, we skip it here - we will validate it elsewhere.
|
||||
// */
|
||||
// for (INT index = 1; index < modules.module_count; index++)
|
||||
// {
|
||||
// module_info = (PRTL_MODULE_EXTENDED_INFO)((UINT64)modules.address +
|
||||
// index * sizeof(RTL_MODULE_EXTENDED_INFO));
|
||||
// /*
|
||||
// * Since ntoskrnl itself is a process, we skip it here - we will validate it elsewhere.
|
||||
// */
|
||||
// for (INT index = 1; index < modules.module_count; index++)
|
||||
// {
|
||||
// module_info = (PRTL_MODULE_EXTENDED_INFO)((UINT64)modules.address +
|
||||
// index *
|
||||
// sizeof(RTL_MODULE_EXTENDED_INFO));
|
||||
//
|
||||
// RtlInitAnsiString(&ansi_string, module_info->FullPathName);
|
||||
// RtlInitAnsiString(&ansi_string, module_info->FullPathName);
|
||||
//
|
||||
// if (!ansi_string.Buffer)
|
||||
// {
|
||||
// DEBUG_ERROR("RtlInitAnsiString failed with status %x", status);
|
||||
// ansi_string.Buffer = NULL;
|
||||
// ansi_string.Length = 0;
|
||||
// ansi_string.MaximumLength = 0;
|
||||
// continue;
|
||||
// }
|
||||
// if (!ansi_string.Buffer)
|
||||
// {
|
||||
// DEBUG_ERROR("RtlInitAnsiString failed with status %x", status);
|
||||
// ansi_string.Buffer = NULL;
|
||||
// ansi_string.Length = 0;
|
||||
// ansi_string.MaximumLength = 0;
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// status = RtlAnsiStringToUnicodeString(&path, &ansi_string, TRUE);
|
||||
// status = RtlAnsiStringToUnicodeString(&path, &ansi_string, TRUE);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("RtlAnsiStringToUnicodeString failed with status %x", status);
|
||||
// path.Buffer = NULL;
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("RtlAnsiStringToUnicodeString failed with status %x",
|
||||
// status); path.Buffer = NULL; goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// status = MapDiskImageIntoVirtualAddressSpace(
|
||||
// §ion_handle, §ion, &path, §ion_size);
|
||||
// status = MapDiskImageIntoVirtualAddressSpace(
|
||||
// §ion_handle, §ion, &path, §ion_size);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("MapDiskImageIntoVirtualAddressSpace failed with status %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("MapDiskImageIntoVirtualAddressSpace failed with status %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// status = StoreModuleExecutableRegionsInBuffer(
|
||||
// &disk_buffer, section, section_size, &disk_buffer_size);
|
||||
// status = StoreModuleExecutableRegionsInBuffer(
|
||||
// &disk_buffer, section, section_size, &disk_buffer_size);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("StoreModuleExecutableRegionsInBuffer failed with status %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("StoreModuleExecutableRegionsInBuffer failed with status %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// /*
|
||||
// * For win32k and related modules, because they are 32bit for us to read the memory
|
||||
// * we need to attach to a 32 bit process. A simple check is that the 32 bit image
|
||||
// * base wont be a valid address, while this is hacky it works. Then we simply attach
|
||||
// * to a 32 bit address space, in our case winlogon, which will allow us to perform
|
||||
// * the copy.
|
||||
// */
|
||||
// if (!MmIsAddressValid(module_info->ImageBase))
|
||||
// {
|
||||
// DEBUG_VERBOSE(
|
||||
// "Win32k related module found, acquiring 32 bit address space...");
|
||||
// /*
|
||||
// * For win32k and related modules, because they are 32bit for us to read the
|
||||
// memory
|
||||
// * we need to attach to a 32 bit process. A simple check is that the 32 bit image
|
||||
// * base wont be a valid address, while this is hacky it works. Then we simply
|
||||
// attach
|
||||
// * to a 32 bit address space, in our case winlogon, which will allow us to
|
||||
// perform
|
||||
// * the copy.
|
||||
// */
|
||||
// if (!MmIsAddressValid(module_info->ImageBase))
|
||||
// {
|
||||
// DEBUG_VERBOSE(
|
||||
// "Win32k related module found, acquiring 32 bit address space...");
|
||||
//
|
||||
// EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process);
|
||||
// EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process);
|
||||
//
|
||||
// if (!process)
|
||||
// goto free_iteration;
|
||||
// if (!process)
|
||||
// goto free_iteration;
|
||||
//
|
||||
// KeStackAttachProcess(process, &apc_state);
|
||||
// KeStackAttachProcess(process, &apc_state);
|
||||
//
|
||||
// status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
|
||||
// module_info->ImageBase,
|
||||
// module_info->ImageSize,
|
||||
// &memory_buffer_size);
|
||||
// status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
|
||||
// module_info->ImageBase,
|
||||
// module_info->ImageSize,
|
||||
// &memory_buffer_size);
|
||||
//
|
||||
// KeUnstackDetachProcess(&apc_state);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
|
||||
// module_info->ImageBase,
|
||||
// module_info->ImageSize,
|
||||
// &memory_buffer_size);
|
||||
// }
|
||||
// KeUnstackDetachProcess(&apc_state);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
|
||||
// module_info->ImageBase,
|
||||
// module_info->ImageSize,
|
||||
// &memory_buffer_size);
|
||||
// }
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("StoreModuleExecutableRegionsInbuffer 2 failed with status %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("StoreModuleExecutableRegionsInbuffer 2 failed with status
|
||||
// %x",
|
||||
// status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// disk_text_base = (UINT64)disk_buffer + sizeof(INTEGRITY_CHECK_HEADER) +
|
||||
// sizeof(IMAGE_SECTION_HEADER);
|
||||
// disk_text_base = (UINT64)disk_buffer + sizeof(INTEGRITY_CHECK_HEADER) +
|
||||
// sizeof(IMAGE_SECTION_HEADER);
|
||||
//
|
||||
// memory_text_base = (UINT64)((UINT64)memory_buffer + sizeof(INTEGRITY_CHECK_HEADER) +
|
||||
// sizeof(IMAGE_SECTION_HEADER));
|
||||
// memory_text_base = (UINT64)((UINT64)memory_buffer +
|
||||
// sizeof(INTEGRITY_CHECK_HEADER) +
|
||||
// sizeof(IMAGE_SECTION_HEADER));
|
||||
//
|
||||
// disk_text_header =
|
||||
// (PIMAGE_SECTION_HEADER)((UINT64)disk_buffer + sizeof(INTEGRITY_CHECK_HEADER));
|
||||
// disk_text_header =
|
||||
// (PIMAGE_SECTION_HEADER)((UINT64)disk_buffer +
|
||||
// sizeof(INTEGRITY_CHECK_HEADER));
|
||||
//
|
||||
// memory_text_header =
|
||||
// (PIMAGE_SECTION_HEADER)((UINT64)memory_buffer + sizeof(INTEGRITY_CHECK_HEADER));
|
||||
// memory_text_header =
|
||||
// (PIMAGE_SECTION_HEADER)((UINT64)memory_buffer +
|
||||
// sizeof(INTEGRITY_CHECK_HEADER));
|
||||
//
|
||||
// if (!disk_text_base || !memory_text_base || !disk_buffer || !memory_buffer ||
|
||||
// !MmIsAddressValid(disk_buffer) || !MmIsAddressValid(memory_buffer))
|
||||
// {
|
||||
// DEBUG_ERROR("Buffer(s) are null. An error has occured.");
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!disk_text_base || !memory_text_base || !disk_buffer || !memory_buffer ||
|
||||
// !MmIsAddressValid(disk_buffer) || !MmIsAddressValid(memory_buffer))
|
||||
// {
|
||||
// DEBUG_ERROR("Buffer(s) are null. An error has occured.");
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// if (disk_text_header->SizeOfRawData != memory_text_header->SizeOfRawData)
|
||||
// {
|
||||
// DEBUG_WARNING("Executable section sizes differ between images.");
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (disk_text_header->SizeOfRawData != memory_text_header->SizeOfRawData)
|
||||
// {
|
||||
// DEBUG_WARNING("Executable section sizes differ between images.");
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// status = ComputeHashOfBuffer(
|
||||
// disk_text_base, disk_text_header->SizeOfRawData, &disk_hash, &disk_hash_size);
|
||||
// status = ComputeHashOfBuffer(
|
||||
// disk_text_base, disk_text_header->SizeOfRawData, &disk_hash,
|
||||
// &disk_hash_size);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("ComputeHashOfBuffer failed with status %s", status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("ComputeHashOfBuffer failed with status %s", status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// status = ComputeHashOfBuffer(memory_text_base,
|
||||
// memory_text_header->SizeOfRawData,
|
||||
// &memory_hash,
|
||||
// &memory_hash_size);
|
||||
// status = ComputeHashOfBuffer(memory_text_base,
|
||||
// memory_text_header->SizeOfRawData,
|
||||
// &memory_hash,
|
||||
// &memory_hash_size);
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("ComputeHashOfBuffer failed with status %x", status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// DEBUG_ERROR("ComputeHashOfBuffer failed with status %x", status);
|
||||
// goto free_iteration;
|
||||
// }
|
||||
//
|
||||
// if (!MmIsAddressValid(memory_hash) || !MmIsAddressValid(disk_hash))
|
||||
// goto free_iteration;
|
||||
// if (!MmIsAddressValid(memory_hash) || !MmIsAddressValid(disk_hash))
|
||||
// goto free_iteration;
|
||||
//
|
||||
// result = RtlCompareMemory(memory_hash, disk_hash, memory_hash_size);
|
||||
// result = RtlCompareMemory(memory_hash, disk_hash, memory_hash_size);
|
||||
//
|
||||
// if (result = memory_text_header->SizeOfRawData)
|
||||
// DEBUG_VERBOSE("Module executable sections are valid for the module: %s",
|
||||
// module_info->FullPathName);
|
||||
// else
|
||||
// DEBUG_WARNING("Module regions are not valid for module: %s",
|
||||
// module_info->FullPathName);
|
||||
// if (result = memory_text_header->SizeOfRawData)
|
||||
// DEBUG_VERBOSE("Module executable sections are valid for the module: %s",
|
||||
// module_info->FullPathName);
|
||||
// else
|
||||
// DEBUG_WARNING("Module regions are not valid for module: %s",
|
||||
// module_info->FullPathName);
|
||||
//
|
||||
// free_iteration:
|
||||
// free_iteration:
|
||||
//
|
||||
// if (memory_buffer)
|
||||
// ExFreePoolWithTag(memory_buffer, POOL_TAG_INTEGRITY);
|
||||
// if (memory_buffer)
|
||||
// ExFreePoolWithTag(memory_buffer, POOL_TAG_INTEGRITY);
|
||||
//
|
||||
// if (memory_hash)
|
||||
// ExFreePoolWithTag(memory_hash, POOL_TAG_INTEGRITY);
|
||||
// if (memory_hash)
|
||||
// ExFreePoolWithTag(memory_hash, POOL_TAG_INTEGRITY);
|
||||
//
|
||||
// if (disk_buffer)
|
||||
// ExFreePoolWithTag(disk_buffer, POOL_TAG_INTEGRITY);
|
||||
// if (disk_buffer)
|
||||
// ExFreePoolWithTag(disk_buffer, POOL_TAG_INTEGRITY);
|
||||
//
|
||||
// if (disk_hash)
|
||||
// ExFreePoolWithTag(disk_hash, POOL_TAG_INTEGRITY);
|
||||
// if (disk_hash)
|
||||
// ExFreePoolWithTag(disk_hash, POOL_TAG_INTEGRITY);
|
||||
//
|
||||
// free_section:
|
||||
// free_section:
|
||||
//
|
||||
// if (section_handle)
|
||||
// ZwClose(section_handle);
|
||||
// if (section_handle)
|
||||
// ZwClose(section_handle);
|
||||
//
|
||||
// if (section)
|
||||
// ZwUnmapViewOfSection(ZwCurrentProcess(), section);
|
||||
// if (section)
|
||||
// ZwUnmapViewOfSection(ZwCurrentProcess(), section);
|
||||
//
|
||||
// /*
|
||||
// * Its times like this where you see why allocating all local variables at the
|
||||
// * beginning of the function may not be so ideal...
|
||||
// */
|
||||
// if (path.Buffer)
|
||||
// {
|
||||
// RtlFreeUnicodeString(&path);
|
||||
// path.Buffer = NULL;
|
||||
// path.Length = 0;
|
||||
// path.MaximumLength = 0;
|
||||
// }
|
||||
// /*
|
||||
// * Its times like this where you see why allocating all local variables at the
|
||||
// * beginning of the function may not be so ideal...
|
||||
// */
|
||||
// if (path.Buffer)
|
||||
// {
|
||||
// RtlFreeUnicodeString(&path);
|
||||
// path.Buffer = NULL;
|
||||
// path.Length = 0;
|
||||
// path.MaximumLength = 0;
|
||||
// }
|
||||
//
|
||||
// ansi_string.Buffer = NULL;
|
||||
// ansi_string.Length = 0;
|
||||
// ansi_string.MaximumLength = 0;
|
||||
// ansi_string.Buffer = NULL;
|
||||
// ansi_string.Length = 0;
|
||||
// ansi_string.MaximumLength = 0;
|
||||
//
|
||||
// section_handle = NULL;
|
||||
// section = NULL;
|
||||
// memory_buffer = NULL;
|
||||
// memory_hash = NULL;
|
||||
// disk_buffer = NULL;
|
||||
// disk_hash = NULL;
|
||||
// }
|
||||
// section_handle = NULL;
|
||||
// section = NULL;
|
||||
// memory_buffer = NULL;
|
||||
// memory_hash = NULL;
|
||||
// disk_buffer = NULL;
|
||||
// disk_hash = NULL;
|
||||
// }
|
||||
//
|
||||
// if (modules.address)
|
||||
// ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
|
||||
// if (modules.address)
|
||||
// ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
|
||||
//
|
||||
// return status;
|
||||
//}
|
||||
// return status;
|
||||
// }
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
|
@ -2010,8 +1993,8 @@ SystemModuleVerificationDispatchFunction(_In_ PDEVICE_OBJECT DeviceObje
|
|||
* Multithreaded delayed priority work items improve 1% lows by 25% and reduces average PC latency
|
||||
* by 10% compared to traditional multithreading. This is important as having high average fps but
|
||||
* low 1% lows just leads to stuttery gameplay which in competitive multiplayer games is simply not
|
||||
* alright. Overall still room for improvement but from a statistical and feel which the gameplay is
|
||||
* much smoother (tested in cs2).
|
||||
* alright. Overall still room for improvement but from a statistical and feel standpoint which the
|
||||
* gameplay is much smoother (tested in cs2).
|
||||
*
|
||||
* A potential idea for further improvement is finding the cores with the least cpu usages and
|
||||
* setting the worker threads affinity accordingly.
|
||||
|
@ -2046,10 +2029,12 @@ InitialiseSystemModuleVerificationContext(PSYS_MODULE_VAL_CONTEXT Context)
|
|||
Context->complete = FALSE;
|
||||
Context->dispatcher_info = dispatcher_array;
|
||||
Context->module_info = modules.address;
|
||||
Context->current_count = 0;
|
||||
Context->total_count = modules.module_count;
|
||||
Context->block_size = VALIDATION_BLOCK_SIZE;
|
||||
|
||||
/* skip hal.dll and ntosrnl.exe */
|
||||
Context->current_count = 2;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -2129,7 +2114,7 @@ SystemModuleVerificationDispatcher()
|
|||
context->work_items[index] = work_item;
|
||||
}
|
||||
|
||||
DEBUG_VERBOSE("Finished validating modules via dispatcher threads");
|
||||
DEBUG_VERBOSE("All worker threads dispatched for system module validation.");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -489,11 +489,6 @@ _Dispatch_type_(IRP_MJ_CLOSE) NTSTATUS
|
|||
|
||||
DEBUG_INFO("Handle to driver closed.");
|
||||
|
||||
/*
|
||||
* For now its fine, but this will need to be moved to our process load callbacks
|
||||
* since right now anyone can open a handle to our driver and then close it lol
|
||||
*/
|
||||
|
||||
/* we also lose reports here, so sohuld pass em into the irp before freeing */
|
||||
FreeGlobalReportQueueObjects();
|
||||
ProcCloseClearProcessConfiguration();
|
||||
|
|
345
driver/modules.c
345
driver/modules.c
|
@ -195,8 +195,9 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
|||
#endif
|
||||
|
||||
/*
|
||||
* TODO: this needs to be refactored to just return the entry not the whole fukin thing
|
||||
* TODO: return ntstatus and pass result in an out parameter
|
||||
* This returns a reference to an entry in the system modules array retrieved via
|
||||
* GetSystemModuleInformation. It's important to remember we don't free the modules once we retrieve
|
||||
* this reference, and instead only free them when we are done using it.
|
||||
*/
|
||||
PRTL_MODULE_EXTENDED_INFO
|
||||
FindSystemModuleByName(_In_ LPCSTR ModuleName, _In_ PSYSTEM_MODULES SystemModules)
|
||||
|
@ -802,6 +803,29 @@ IsInstructionPointerInInvalidRegion(_In_ UINT64 RIP,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
IsInstructionPointerInsideModule(_In_ UINT64 Rip,
|
||||
_In_ PRTL_MODULE_EXTENDED_INFO Module,
|
||||
_Out_ PBOOLEAN Result)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (!Rip || !Module || !Result)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
UINT64 base = (UINT64)Module->ImageBase;
|
||||
UINT64 end = base + Module->ImageSize;
|
||||
|
||||
if (Rip >= base && Rip <= end)
|
||||
{
|
||||
*Result = TRUE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
*Result = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* todo: i think we should split this function up into each analysis i.e one for the interrupted
|
||||
* rip, one for the cid etc.
|
||||
|
@ -894,7 +918,8 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules,
|
|||
}
|
||||
else
|
||||
{
|
||||
DEBUG_VERBOSE("Thread: %llx was found in PspCidTable", NmiContext[core].kthread);
|
||||
DEBUG_VERBOSE("Thread: %llx was found in PspCidTable",
|
||||
NmiContext[core].kthread);
|
||||
}
|
||||
|
||||
if (NmiContext[core].user_thread)
|
||||
|
@ -1041,6 +1066,12 @@ HandleNmiIOCTL(_Inout_ PIRP Irp)
|
|||
SYSTEM_MODULES system_modules = {0};
|
||||
PNMI_CONTEXT nmi_context = NULL;
|
||||
|
||||
status = ValidateHalDispatchTables();
|
||||
|
||||
/* do we continue ? probably. */
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateHalDispatchTables failed with status %x", status);
|
||||
|
||||
nmi_context = ExAllocatePool2(POOL_FLAG_NON_PAGED,
|
||||
KeQueryActiveProcessorCount(0) * sizeof(NMI_CONTEXT),
|
||||
NMI_CONTEXT_POOL);
|
||||
|
@ -1549,5 +1580,313 @@ end:
|
|||
if (context)
|
||||
ExFreePoolWithTag(context, POOL_TAG_DPC);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* todo: walk the chain of pointers to prevent jmp chaining */
|
||||
STATIC
|
||||
NTSTATUS
|
||||
ValidateTableDispatchRoutines(_In_ PVOID* Base,
|
||||
_In_ UINT32 Entries,
|
||||
_In_ PSYSTEM_MODULES Modules,
|
||||
_Out_ PVOID* Routine)
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
BOOLEAN flag = FALSE;
|
||||
|
||||
for (UINT32 index = 0; index < Entries; index++)
|
||||
{
|
||||
if (!Base[index])
|
||||
continue;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(Base[index], Modules, &flag);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("IsInstructionPointerInInvalidRegion failed with status %x",
|
||||
status);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
*Routine = Base[index];
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* windows version info: https://www.techthoughts.info/windows-version-numbers/
|
||||
*
|
||||
* sizes:
|
||||
* https://www.vergiliusproject.com/kernels/x64/Windows%2011/22H2%20(2022%20Update)/HAL_PRIVATE_DISPATCH
|
||||
*/
|
||||
#define HAL_PRIVATE_DISPATCH_W11_22H2_SIZE 0x4f0
|
||||
#define HAL_PRIVATE_DISPATCH_W10_22H2_SIZE 0x4b0
|
||||
|
||||
#define WINDOWS_10_MAX_BUILD_NUMBER 19045
|
||||
|
||||
STATIC
|
||||
UINT32
|
||||
GetHalPrivateDispatchTableRoutineCount(_In_ PRTL_OSVERSIONINFOW VersionInfo)
|
||||
{
|
||||
if (VersionInfo->dwBuildNumber <= WINDOWS_10_MAX_BUILD_NUMBER)
|
||||
return (HAL_PRIVATE_DISPATCH_W10_22H2_SIZE / sizeof(UINT64)) - 1;
|
||||
else
|
||||
return (HAL_PRIVATE_DISPATCH_W11_22H2_SIZE / sizeof(UINT64)) - 1;
|
||||
}
|
||||
|
||||
STATIC
|
||||
NTSTATUS
|
||||
ValidateHalPrivateDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules)
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
PVOID table = NULL;
|
||||
UNICODE_STRING string = RTL_CONSTANT_STRING(L"HalPrivateDispatchTable");
|
||||
PVOID* base = NULL;
|
||||
RTL_OSVERSIONINFOW os_info = {0};
|
||||
UINT32 count = 0;
|
||||
|
||||
DEBUG_VERBOSE("Validating HalPrivateDispatchTable.");
|
||||
|
||||
table = MmGetSystemRoutineAddress(&string);
|
||||
|
||||
if (!table)
|
||||
return status;
|
||||
|
||||
status = GetOsVersionInformation(&os_info);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("GetOsVersionInformation failed with status %x", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
base = (UINT64)table + sizeof(UINT64);
|
||||
count = GetHalPrivateDispatchTableRoutineCount(&os_info);
|
||||
|
||||
status = ValidateTableDispatchRoutines(base, count, Modules, Routine);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ValidateTableDispatchRoutines failed with status %x", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
NTSTATUS
|
||||
ValidateHalDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules)
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
BOOLEAN flag = FALSE;
|
||||
|
||||
*Routine = NULL;
|
||||
|
||||
DEBUG_VERBOSE("Validating HalDispatchTable.");
|
||||
|
||||
/*
|
||||
* Since windows exports all the function pointers inside the HalDispatchTable, we may
|
||||
* aswell make use of them and validate it this way. While it definitely is ugly, it is the
|
||||
* safest way to do it.
|
||||
*
|
||||
* What if there are 2 invalid routines? hmm.. tink.
|
||||
*/
|
||||
status = IsInstructionPointerInInvalidRegion(HalQuerySystemInformation, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalQuerySystemInformation;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalSetSystemInformation, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalSetSystemInformation;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalQueryBusSlots, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalQueryBusSlots;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalReferenceHandlerForBus, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalReferenceHandlerForBus;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalReferenceBusHandler, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalReferenceBusHandler;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalDereferenceBusHandler, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalDereferenceBusHandler;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalInitPnpDriver, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalInitPnpDriver;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalInitPowerManagement, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalInitPowerManagement;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalGetDmaAdapter, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalGetDmaAdapter;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalGetInterruptTranslator, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalGetInterruptTranslator;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalStartMirroring, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalStartMirroring;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalEndMirroring, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalEndMirroring;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalMirrorPhysicalMemory, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalMirrorPhysicalMemory;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalEndOfBoot, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalEndOfBoot;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalMirrorVerify, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalMirrorVerify;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalGetCachedAcpiTable, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalGetCachedAcpiTable;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalSetPciErrorHandlerCallback, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalSetPciErrorHandlerCallback;
|
||||
else
|
||||
return status;
|
||||
|
||||
status = IsInstructionPointerInInvalidRegion(HalGetPrmCache, Modules, &flag);
|
||||
|
||||
if (!flag && NT_SUCCESS(status))
|
||||
*Routine = HalGetPrmCache;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
ReportDataTableInvalidRoutine(_In_ TABLE_ID TableId, _In_ UINT64 Address)
|
||||
{
|
||||
PDATA_TABLE_ROUTINE_REPORT report = ExAllocatePool2(
|
||||
POOL_FLAG_NON_PAGED, sizeof(DATA_TABLE_ROUTINE_REPORT), POOL_TAG_INTEGRITY);
|
||||
|
||||
if (!report)
|
||||
return;
|
||||
|
||||
DEBUG_WARNING(
|
||||
"Invalid data table routine found. Table: %lx, Address: %llx", TableId, Address);
|
||||
|
||||
report->address = Address;
|
||||
report->id = TableId;
|
||||
report->id = REPORT_DATA_TABLE_ROUTINE;
|
||||
RtlCopyMemory(report->routine, Address, DATA_TABLE_ROUTINE_BUF_SIZE);
|
||||
|
||||
InsertReportToQueue(report);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
ValidateHalDispatchTables()
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
SYSTEM_MODULES modules = {0};
|
||||
PVOID routine1 = NULL;
|
||||
PVOID routine2 = NULL;
|
||||
|
||||
status = GetSystemModuleInformation(&modules);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ValidateHalDispatchTable(&routine1, &modules);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ValidateHalDispatchTable failed with status %x", status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (routine1)
|
||||
ReportDataTableInvalidRoutine(HalDispatch, routine1);
|
||||
else
|
||||
DEBUG_VERBOSE("HalDispatch dispatch routines are valid.");
|
||||
|
||||
status = ValidateHalPrivateDispatchTable(&routine2, &modules);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ValidateHalPrivateDispatchTable failed with status %x", status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (routine2)
|
||||
ReportDataTableInvalidRoutine(HalPrivateDispatch, routine2);
|
||||
else
|
||||
DEBUG_VERBOSE("HalPrivateDispatch dispatch routines are valid.");
|
||||
|
||||
end:
|
||||
if (modules.address)
|
||||
ExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
|
||||
|
||||
return status;
|
||||
}
|
|
@ -7,7 +7,24 @@
|
|||
#include "common.h"
|
||||
#include "queue.h"
|
||||
|
||||
typedef struct NMI_CALLBACK_FAILURE
|
||||
typedef enum _TABLE_ID
|
||||
{
|
||||
HalDispatch = 0,
|
||||
HalPrivateDispatch
|
||||
} TABLE_ID;
|
||||
|
||||
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
|
||||
|
||||
typedef struct _DATA_TABLE_ROUTINE_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
TABLE_ID id;
|
||||
UINT64 address;
|
||||
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
|
||||
|
||||
} DATA_TABLE_ROUTINE_REPORT, *PDATA_TABLE_ROUTINE_REPORT;
|
||||
|
||||
typedef struct _NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
|
@ -20,10 +37,10 @@ typedef struct NMI_CALLBACK_FAILURE
|
|||
|
||||
typedef struct _DPC_STACKWALK_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
UINT32 report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
|
||||
} DPC_STACKWALK_REPORT, *PDPC_STACKWALK_REPORT;
|
||||
|
||||
|
@ -110,4 +127,7 @@ FlipKThreadMiscFlagsFlag(_In_ PKTHREAD Thread, _In_ ULONG FlagIndex, _In_ BOOLEA
|
|||
NTSTATUS
|
||||
DispatchStackwalkToEachCpuViaDpc();
|
||||
|
||||
NTSTATUS
|
||||
ValidateHalDispatchTables();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -317,7 +317,7 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
|
|||
}
|
||||
}
|
||||
|
||||
if (process == NULL)
|
||||
if (!process)
|
||||
break;
|
||||
|
||||
DEBUG_VERBOSE("Found process via pt walk: %llx", (UINT64)process);
|
||||
|
|
|
@ -277,6 +277,16 @@ HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp)
|
|||
|
||||
total_size += sizeof(DPC_STACKWALK_REPORT);
|
||||
break;
|
||||
|
||||
case REPORT_DATA_TABLE_ROUTINE:
|
||||
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(DATA_TABLE_ROUTINE_REPORT));
|
||||
|
||||
total_size += sizeof(DATA_TABLE_ROUTINE_REPORT);
|
||||
break;
|
||||
}
|
||||
|
||||
/* QueuePop frees the node, but we still need to free the returned data */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
#define REPORT_APC_STACKWALK 110
|
||||
#define REPORT_DPC_STACKWALK 120
|
||||
#define REPORT_DATA_TABLE_ROUTINE 130
|
||||
|
||||
#define TEST_STEAM_64_ID 123456789;
|
||||
|
||||
|
@ -214,6 +215,22 @@ struct DPC_STACKWALK_REPORT
|
|||
UINT64 invalid_rip;
|
||||
CHAR driver[4096];
|
||||
};
|
||||
|
||||
enum TABLE_ID
|
||||
{
|
||||
HalDispatch = 0,
|
||||
HalPrivateDispatch
|
||||
};
|
||||
|
||||
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
|
||||
|
||||
struct DATA_TABLE_ROUTINE_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
TABLE_ID id;
|
||||
UINT64 address;
|
||||
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -244,6 +244,10 @@ kernelmode::Driver::QueryReportQueue()
|
|||
ReportTypeFromReportQueue<DPC_STACKWALK_REPORT>(
|
||||
buffer, &total_size, &hidden_report);
|
||||
break;
|
||||
case REPORT_DATA_TABLE_ROUTINE:
|
||||
ReportTypeFromReportQueue<DATA_TABLE_ROUTINE_REPORT>(
|
||||
buffer, &total_size, &hidden_report);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue