我正在尝试使用一个名为PsGetContextThread的未记录函数从驱动程序中检索用户模式线程的上下文,我知道这可能来自usermode,但我有理由从内核执行此操作,这是不可协商的请不要偏离那个。现在回到主题,调试时下面的代码包含一个有效的线程,一切看起来都不错,但它返回无效的错误代码C0000005这是ACCESS_VIOLATION但我不知道这个代码如何触发它,并希望得到一些帮助来解决因为我已经坚持了很长一段时间。
NTSTATUS GetThreadContext(PETHREAD thread) {
KPROCESSOR_MODE mode = UserMode;
CONTEXT context;
UNICODE_STRING setContextString, getContextString;
pPsGetContextThread PsGetContextThread;
NTSTATUS status = STATUS_SUCCESS;
RtlInitUnicodeString(&getContextString, L"PsGetContextThread");
RtlZeroMemory(&context, sizeof(CONTEXT));
PsGetContextThread = (pPsGetContextThread)MmGetSystemRoutineAddress(&getContextString);
context.ContextFlags = CONTEXT_FULL;
status = PsGetContextThread(thread, &context, mode);
if (!NT_SUCCESS(status)) {
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
如果有人知道接下来要尝试什么或有任何建议,请在下面发帖。
答案 0 :(得分:0)
是的,@ HarryJohnston说得对,当我们指定UserMode
PsGetContextThread
时,检查&context
是否是有效的用户模式指针。所以我们需要传递有效的用户模式指针。我们可以通过调用ZwAllocateVirtualMemory
来获取它 - 使用此代码 - 这是有效的
NTSTATUS GetThreadContext(PETHREAD thread, PCONTEXT ctx)
{
#if 0
typedef NTSTATUS (NTAPI* GETSETCONTEXTTHREAD)(PETHREAD, PCONTEXT,MODE);
static GETSETCONTEXTTHREAD PsGetContextThread;
static BOOLEAN bInit;
if (!bInit)
{
STATIC_UNICODE_STRING(aPsGetContextThread, "PsGetContextThread");
PsGetContextThread = (GETSETCONTEXTTHREAD)MmGetSystemRoutineAddress(&aPsGetContextThread);
bInit = TRUE;
}
if (!PsGetContextThread)
{
return STATUS_PROCEDURE_NOT_FOUND;
}
#endif
CONTEXT * BaseAddress = 0;
SIZE_T Size = sizeof(CONTEXT);
NTSTATUS status = ZwAllocateVirtualMemory(NtCurrentProcess(), (void**)&BaseAddress, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
if (0 <= status)
{
BaseAddress->ContextFlags = ctx->ContextFlags;
if (0 <= (status = PsGetContextThread(thread, BaseAddress, UserMode)))
{
memcpy(ctx, BaseAddress, sizeof(CONTEXT));
}
ZwFreeVirtualMemory(NtCurrentProcess(), (void**)&BaseAddress, &Size, MEM_RELEASE);
}
return status;
}
并且认为你不需要使用MmGetSystemRoutineAddress
但是静态导入PsGetContextThread
,但是如果你想要在运行时获得这个指针 - 不需要每次都这样做 - 但只需要一次。指向函数static
答案 1 :(得分:0)
您混淆了第三个参数-它不声明要获取用户模式线程上下文还是内核模式线程上下文,它仅表示原始调用是从用户模式还是内核模式进行的。这样,您无需在用户模式下调用该函数并将数据从用户复制到内核。只需使用KernelMode调用它并使用内核内存即可。
NTSTATUS GetThreadContext(PETHREAD thread, PCONTEXT ctx)
{
#if 0
typedef NTSTATUS (NTAPI* GETSETCONTEXTTHREAD)(PETHREAD, PCONTEXT,MODE);
static GETSETCONTEXTTHREAD PsGetContextThread = NULL;
if (NULL == PsGetContextThread )
{
STATIC_UNICODE_STRING(aPsGetContextThread, "PsGetContextThread");
PsGetContextThread = (GETSETCONTEXTTHREAD)MmGetSystemRoutineAddress(&aPsGetContextThread);
}
if (NULL == PsGetContextThread)
{
return STATUS_PROCEDURE_NOT_FOUND;
}
#endif
return PsGetContextThread(thread, ctx, KernelMode);
}