【问题标题】:PsGetContextThread returning C0000005(ACCESS_VIOLATION)PsGetContextThread 返回 C0000005(ACCESS_VIOLATION)
【发布时间】:2017-06-13 14:13:15
【问题描述】:

我正在尝试使用一个名为 PsGetContextThread 的未记录函数从驱动程序中检索用户模式线程的上下文,我知道这可以从用户模式执行,但我有理由从内核执行此操作,这是不可协商的,所以请不要绕道。现在回到主题,调试时下面的代码包含一个有效的线程,一切对我来说看起来都很好,但它返回无效,错误代码 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;
}

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

【问题讨论】:

  • 只是为了了解您的工作:您使用 undocumented 函数,该函数旨在从 user 模式调用,从 kernel 模式。你想知道为什么它不起作用?注意到什么了吗?
  • @Olaf 你错了,PsGetContextThread 不应该从用户模式调用......它是内核导出的一部分,可以由驱动程序调用。指向函数的指针是有效的,它的调用本身在状态变量中返回 ACCESS_VIOLATION
  • 我怀疑问题在于您传递的是内核模式地址&context,但指定了UserMode。当UserMode 被指定时,PsGetContextThread 做的第一件事就是检查&context 是一个有效的用户模式指针。请尝试指定 KernelMode
  • @HarryJohnston - 是的,你绝对正确,在&context 的内核模式地址中指定了UserMode 的问题。但是指定KernelMode 而是根据意义将 for 作为另一个上下文。如果我们正好需要UserMode - 首先需要分配用户模式地址并使用它

标签: c windows driver internals


【解决方案1】:

是的,@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

【讨论】:

    【解决方案2】:

    您混淆了第三个参数-它没有说明您是获取用户模式线程上下文还是内核模式线程上下文,它仅暗示原始调用是从用户模式还是从内核模式进行的。因此,您不需要使用用户模式调用该函数并将数据从用户复制到内核。只需使用 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      • 2016-06-28
      相关资源
      最近更新 更多