PsGetContextThread返回C0000005(ACCESS_VIOLATION)

时间:2017-01-27 19:36:44

标签: c windows driver internals

我正在尝试使用一个名为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;
}

如果有人知道接下来要尝试什么或有任何建议,请在下面发帖。

2 个答案:

答案 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);
}