c - PsGetContextThread 返回 C0000005(ACCESS_VIOLATION)

标签 c windows driver internals

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

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

最佳答案

是的,@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,但如果您无论如何想在运行时获取此指针 - 不需要每次都这样做 - 但只需一次。使指针指向函数静态

关于c - PsGetContextThread 返回 C0000005(ACCESS_VIOLATION),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41901723/

相关文章:

c - 多线程 Linux 程序没有给出预期的输出

c++ - 如何在 Windows 上使用 C 或 C++ 发送 IM

.net - 从 system::String 转换为 std::string

c++ - 带有 _T 宏的 C++ 中的字符串文字

c++ - C/C++ 中的大小写标签问题

windows - Windows 上的 Git 和文件属性

c - 如何调试驱动程序加载错误?

linux - 专有 Linux 内核驱动程序是否有任何 kill_proc() 替代品?

php - PDO MSSQL 服务器 - 未找到驱动程序

c - <stdio.h> vs <math.h> - 为什么你必须链接一个而不是另一个?