Hello, i did some testing with the library, it seems good so far, altough i have a little error.
I modified the ExHook like this, the reason is, that the given sample can only activate on processes which are already running. so i moved the code for activation to the
"InitTarget" Function, which works so far. on the main i activate it on a process ("activator.exe") trough which i can then send a command (syscall 1032) once i want it to activate on another process ("notepad.exe").
the whole thing works on my cloudvm running windows server datacenter 2019 1809 build. But when i test on my bare metal pc's (win10 pro/home 1803/1909) on none of them it works completely it initializes successfully on the activator.exe but when that thing sends the 1032 syscall it gets stuck forever in the kernel code spamming the dbgprintf of the Systemwideexceptionhandler and Sysexitintercept.
#include "NtInternals.h"
#include "ByePG.h"
void SysExitIntercept(PETHREAD Thread);
LONG SystemWideExceptionHandler(CONTEXT* ContextRecord, EXCEPTION_RECORD* ExceptionRecord);
SYSTEM_PROCESS_INFORMATION* QueryProcessInformation();
NTSTATUS InitTarget(wchar_t name[255]);
extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
NTSTATUS Status = ByePgInitialize(SystemWideExceptionHandler, FALSE);
if (!NT_SUCCESS(Status)) return Status;
return InitTarget(L"activator.exe");
}
#define kprintf(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__)
void SysExitIntercept(PETHREAD Thread)
{
kprintf("\n1");
// Get trap frame
//
KTRAP_FRAME* TrapFrame = PsGetBaseTrapFrame(Thread);
KTRAP_FRAME* ThrTrapFrame = PsGetTrapFrame(Thread);
if (TrapFrame != ThrTrapFrame) return;
// Check if it's a service frame
//
if (TrapFrame->ExceptionActive == 2)
{
kprintf("\n2");
kprintf("SYSCALL %d [%p, %p, %p, %p]\n", PsGetSystemCallNumber(Thread), TrapFrame->Rcx, TrapFrame->Rdx, TrapFrame->R8, TrapFrame->R9);
if (PsGetSystemCallNumber(Thread) == 1032)
{
kprintf("\n3");
InitTarget("notepad.exe");
return;
}
kprintf("\n4");
}
kprintf("\n5");
return;
}
LONG SystemWideExceptionHandler(CONTEXT* ContextRecord, EXCEPTION_RECORD* ExceptionRecord)
{
// Only handle exceptions raised at <= DISPATCH_LEVEL (ignoring EFLAGS.IF)
//
kprintf("\n6");
if (KeGetCurrentIrql() > DISPATCH_LEVEL) return EXCEPTION_EXECUTE_HANDLER;
kprintf("\n7");
// Access violation
//
if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
{
kprintf("\n8");
/*
KiCopyCountersWorker proc near
mov [rsp+arg_0], rbx
mov [rsp+arg_18], rsi
push rdi
sub rsp, 30h
mov rdi, rdx
mov rsi, rcx
mov rbx, [rdx+8] <-- Exception occurs here
*/
// Verify that it was raised at target instruction
//
if (MmIsAddressValid(ExceptionRecord->ExceptionAddress))
{
kprintf("\n9");
UCHAR* Instruction = (UCHAR*)ExceptionRecord->ExceptionAddress;
if (Instruction[3] == 0x08)
{
kprintf("\n10");
/*
jmp short $+2 <-- Epilogue start
mov rbx, [rsp+38h+arg_0]
mov rsi, [rsp+38h+arg_18]
add rsp, 30h
pop rdi
retn
KiCopyCountersWorker endp
*/
// Skip to epilogue
//
while (Instruction[0] != 0xEB ||
Instruction[1] != 0x00) Instruction++;
ContextRecord->Rip = (ULONG64)Instruction + 2;
kprintf("\n11");
// Inject a call to our routine
//
ContextRecord->Rsp -= 0x8;
*(ULONG64*)ContextRecord->Rsp = ContextRecord->Rip;
ContextRecord->Rip = (ULONG64)&SysExitIntercept;
kprintf("\n12");
// Continue execution
//
return EXCEPTION_CONTINUE_EXECUTION;
}
}
}
kprintf("\n13");
return EXCEPTION_EXECUTE_HANDLER;
}
SYSTEM_PROCESS_INFORMATION* QueryProcessInformation()
{
// Allocate buffer of estimated size
//
ULONG BufferSize = 0x10000;
void* Buffer = ExAllocatePool(NonPagedPool, BufferSize);
while (true)
{
// Try to query system information
//
NTSTATUS Status = ZwQuerySystemInformation(SystemProcessInformation, Buffer, BufferSize, &BufferSize);
// If size is too small:
//
if (Status == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool(Buffer);
Buffer = ExAllocatePool(NonPagedPool, BufferSize);
}
else
{
// If failed, free the buffer and return nullptr:
//
if (!NT_SUCCESS(Status))
{
ExFreePool(Buffer);
return nullptr;
}
// Else cast the buffer to relevant type and return it:
//
else
{
return PSYSTEM_PROCESS_INFORMATION(Buffer);
}
}
}
}
NTSTATUS InitTarget(wchar_t name[255])
{
UNICODE_STRING TargetImageName;
RtlInitUnicodeString(&TargetImageName, name);
SYSTEM_PROCESS_INFORMATION* Spi = QueryProcessInformation();
if (void* Buffer = Spi)
{
// Iterate each process
//
while (Spi->NextEntryOffset)
{
// If matches target image:
//
if (!RtlCompareUnicodeString(&Spi->ImageName, &TargetImageName, FALSE))
{
// Resolve EPROCESS
//
PEPROCESS Process = nullptr;
PsLookupProcessByProcessId(Spi->UniqueProcessId, &Process);
if (Process)
{
kprintf("Target process instance [PID: %llu, EPROCESS: %p]\n", Spi->UniqueProcessId, Process);
// Iterate each thread
//
for (int i = 0; i < Spi->NumberOfThreads; i++)
{
// Resolve ETHREAD
//
PETHREAD Thread = nullptr;
PsLookupThreadByThreadId(Spi->Threads[i].ClientId.UniqueThread, &Thread);
if (Thread)
{
kprintf("-- Thread [TID: %llu, ETHREAD: %p]\n", Spi->Threads[i].ClientId.UniqueThread, Thread);
// Set CycleProfiling flag
//
DISPATCHER_HEADER* DpcHdr = (DISPATCHER_HEADER*)Thread;
DpcHdr->CycleProfiling = 1;
// Dereference ETHREAD
//
ObDereferenceObject(Thread);
}
}
// Dereference EPROCESS
//
ObDereferenceObject(Process);
}
}
Spi = PSYSTEM_PROCESS_INFORMATION((char*)Spi + Spi->NextEntryOffset);
}
// Free the buffer and report success
//
ExFreePool(Buffer);
return STATUS_SUCCESS;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}