The problem is its always fails with status unsuccesfull.
My Goal is to Hijack a thread from a usermode programm using kernel mode. So my idea was to use the Zw Functions so i used windbg on my vmware and search for the functions then creating patterns for them. In my Kernel Driver i wrote a function to find the ntoskrnl.exe baseaddress and size. then i made a findpattern function to search for this bite patterns in the module.Then i tested it if i manage to find the Function addresses.
const char* moduleName = "ntoskrnl.exe";
ULONG sizeOfModule = 0;
uintptr_t moduleBase = get_kernel_module(moduleName,&sizeOfModule);
if (moduleBase == 0)
{
DbgPrint("Failed to locate module: %s\n", moduleName);
return STATUS_UNSUCCESSFUL;
}
DbgPrint("Module %s located at: 0x%p\n", moduleName, (PVOID)moduleBase);
PUCHAR ModuleStart = (PUCHAR)moduleBase;
PVOID ZwSuspend = (PVOID)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 5D 4F 00 00 50");
DbgPrint("ZwSuspendThread address: 0x%p\n", ZwSuspend);
PVOID ZwResume = (PVOID)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 BD 7C 00 00 50");
DbgPrint("ZwResumeThread address: 0x%p\n", ZwResume);
PVOID ZwOpenThread = (PVOID)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 1D 61 00 00 50");
DbgPrint("ZwOpenThread address: 0x%p\n", ZwOpenThread);
PVOID ZwSetContextThread = (PVOID)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 7D 55 00 00 50");
DbgPrint("ZwtSetContextThread address: 0x%p\n", ZwSetContextThread);
PVOID ZwGetContextThread = (PVOID)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 9D 68 00 00 50");
DbgPrint("ZwGetContextThread address: 0x%p\n", ZwGetContextThread);
Output:
Module ntoskrnl.exe located at: 0xFFFFF80668A00000
ZwSuspendThread from driver address: 0xFFFFF80668DFB910
Found address from Windbg: 0xFFFFF80668DFB910
ZwResumeThread from driver address: 0xFFFFF80668DF8BB0
Found address from Windbg: 0xFFFFF80668DF8BB0
ZwOpenThread from driver address: 0xFFFFF80668DFA750
Found address from Windbg: 0xFFFFF80668DFA750
ZwtSetContextThread from driver address: 0xFFFFF80668DFB2F0
Found address from Windbg: 0xFFFFF80668DFB2F0
ZwGetContextThread from driver address: 0xFFFFF80668DF9FD0
Found address from Windbg: 0xFFFFF80668DF9FD0
As you can see the Driver finds the right address. Then i worked on the Hijack function.
NTSTATUS HijackThread(DWORD threadID, PVOID remoteBuffer)
{
NTSTATUS status = STATUS_SUCCESS;
const char* moduleName = "ntoskrnl.exe";
ULONG sizeOfModule = 0;
uintptr_t moduleBase = get_kernel_module(moduleName,&sizeOfModule);
if (moduleBase == 0)
{
DbgPrint("Failed to locate module: %s\n", moduleName);
return STATUS_UNSUCCESSFUL;
}
PUCHAR ModuleStart = (PUCHAR)moduleBase;
// Get the NtOpenThread function
static ZwOpenThreadPtr ZwOpenThread = (ZwOpenThreadPtr)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 1D 61 00 00 50");
if (ZwOpenThread == NULL)
{
DbgPrint("Failed to get function: ZwOpenThread\n");
return STATUS_UNSUCCESSFUL;
}
// Prepare CLIENT_ID for opening the thread
CLIENT_ID clientId = { 0 };
clientId.UniqueThread = (HANDLE)threadID;
clientId.UniqueProcess = NULL; // Not required for this case
OBJECT_ATTRIBUTES objectAttributes;
InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
HANDLE threadHandle = NULL;
status = ZwOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, &objectAttributes, &clientId);
if (!NT_SUCCESS(status))
{
DbgPrint("Failed to open thread, status: 0x%X\n", status);
return status;
}
// Suspend the thread
static ZwSuspendThreadPtr ZwSuspendThread = (ZwSuspendThreadPtr)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 5D 4F 00 00 50");
if (ZwSuspendThread == NULL)
{
DbgPrint("Failed to get function: ZwSuspendThread\n");
ZwClose(threadHandle);
return STATUS_UNSUCCESSFUL;
}
ULONG suspendCount = 0;
status = ZwSuspendThread(threadHandle, &suspendCount);
if (!NT_SUCCESS(status))
{
DbgPrint("Failed to suspend thread, status: 0x%X\n", status);
ZwClose(threadHandle);
return status;
}
ZwClose(threadHandle);
status = ZwOpenThread(&threadHandle, THREAD_GET_CONTEXT, &objectAttributes, &clientId);
if (!NT_SUCCESS(status)) {
DbgPrint("Failed to reopen thread with THREAD_GET_CONTEXT, status: 0x%X\n", status);
return status;
}
// Get the thread context
static ZwGetContextThreadPtr ZwGetContextThread = (ZwGetContextThreadPtr)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 9D 68 00 00 50");
if (ZwGetContextThread == NULL)
{
DbgPrint("Failed to get function: ZwGetContextThread\n");
ZwClose(threadHandle);
return STATUS_UNSUCCESSFUL;
}
CONTEXT threadContext = { 0 };
threadContext.ContextFlags = CONTEXT_FULL;
status = ZwGetContextThread(threadHandle, &threadContext);
if (!NT_SUCCESS(status))
{
DbgPrint("Failed to get thread context, status: 0x%X\n", status);
ZwClose(threadHandle);
return status;
}
ZwClose(threadHandle);
// Modify the thread's RIP (instruction pointer)
static ZwSetContextThreadPtr ZwSetContextThread = (ZwSetContextThreadPtr)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 7D 55 00 00 50");
if (ZwSetContextThread == NULL)
{
DbgPrint("Failed to get function: ZwSetContextThread\n");
ZwClose(threadHandle);
return STATUS_UNSUCCESSFUL;
}
threadContext.Rip = (DWORD_PTR)remoteBuffer;
status = ZwOpenThread(&threadHandle, THREAD_SET_CONTEXT, &objectAttributes, &clientId);
if (!NT_SUCCESS(status)) {
DbgPrint("Failed to reopen thread with THREAD_SET_CONTEXT, status: 0x%X\n", status);
return status;
}
status = ZwSetContextThread(threadHandle, &threadContext);
if (!NT_SUCCESS(status))
{
DbgPrint("Failed to set thread context, status: 0x%X\n", status);
ZwClose(threadHandle);
return status;
}
ZwClose(threadHandle);
// Resume the thread
static ZwResumeThreadPtr ZwResumeThread = (ZwResumeThreadPtr)FindPattern_Wrapper(ModuleStart, sizeOfModule, "48 8B C4 FA 48 83 EC 10 50 9C 6A 10 48 8D 05 BD 7C 00 00 50");
if (ZwResumeThread == NULL)
{
DbgPrint("Failed to get function: ZwResumeThread\n");
ZwClose(threadHandle);
return STATUS_UNSUCCESSFUL;
}
status = ZwOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, &objectAttributes, &clientId);
if (!NT_SUCCESS(status)) {
DbgPrint("Failed to reopen thread for resuming, status: 0x%X\n", status);
return status;
}
ULONG resumeCount = 0;
status = ZwResumeThread(threadHandle, &resumeCount);
if (NT_SUCCESS(status))
{
DbgPrint("Thread resumed successfully, resume count: %lu\n", resumeCount);
}
else
{
DbgPrint("Failed to resume thread, status: 0x%X\n", status);
}
// Clean up by closing the thread handle
ZwClose(threadHandle);
return status;
}
OpenThread and Suspending was working but it always gave error on ZwGetContextThread:
Failed to get thread context, status: 0xC0000001
Means unsuccesfull. But i dont know why. My Usermode programm finds the ThreadID from Notepad so thats not the problem. Thx for any help.