无法将 C# 字符串从用户态传递到内核模式 C 并使用它来查找特定的 LDR_DATA_TABLE_ENTRY

Posted

技术标签:

【中文标题】无法将 C# 字符串从用户态传递到内核模式 C 并使用它来查找特定的 LDR_DATA_TABLE_ENTRY【英文标题】:Trouble passing a C# string from userland to kernelmode C and using it to find specific LDR_DATA_TABLE_ENTRY 【发布时间】:2020-09-24 06:03:36 【问题描述】:

我在比较从用户模式类型 LPWSTR 传递的字符串与 LDR 表条目类型 UNICODE_STRING 时遇到困难

内核 C:

struct 
    int pid;
    int user_pid;
    int size;
    int protection_mode;
    int allocation_type;
    void* address;
    void* write_buffer;
    LPWSTR module_name;

userland_operation;

这个结构体通过 deviceiocontrol 传递给内核。对应的用户态结构如下:

public struct MemOperation

    public int Pid;
    public int UserPid;
    public int Size;
    public int protection_mode;
    public int allocation_type;
    public IntPtr Addr;
    public IntPtr WriteBuffer;
    [MarshalAs(UnmanagedType.LPWStr)] public String ModuleName;

字符串 ModuleName 被编组为 LPWStr。

ModuleName 是进程中已加载模块的所需搜索词。现在,这就是事情变得棘手的地方。我可以通过_LDR_DATA_TABLE_ENTRY 访问的字符串是UNICODE_STRING。我想将此 UNICODE_STRING 与我的 LPWSTR 进行比较。

我尝试了以下方法,但没有成功:


    UNICODE_STRING str;
    RtlInitUnicodeString(&str, module_name) // module name is the userland passed string LPWSTR
    if (RtlCompareUnicodeString(&str, &module_ldr->BaseDllName, TRUE) 


    

我也尝试过 wcscmp 和其他一些东西。我不确定如何正确比较这两者。我在函数中添加了一些次要的伪代码,以提供关于我要做什么的额外上下文。

NTSTATUS GetModuleList(HANDLE PID, PVOID UserBuffer, LPWSTR module_name) 
    KAPC_STATE APC;
    __try 
        PEPROCESS TargetProcess;

        PsLookupProcessByProcessId(PID, &TargetProcess);

        PPEB Peb = PsGetProcessPeb(TargetProcess);

        if (!Peb)
            return STATUS_INVALID_PARAMETER;

        KeStackAttachProcess(TargetProcess, &APC);

        UINT64 Ldr = (UINT64)Peb + PEBLDR_OFFSET;
        ProbeForRead((CONST PVOID)Ldr, 8, 8);

        PLIST_ENTRY ModListHead = (PLIST_ENTRY)(*(PULONG64)Ldr + PEBLDR_MEMORYLOADED_OFFSET);
        ProbeForRead((CONST PVOID)ModListHead, 8, 8);

        PLIST_ENTRY Module = ModListHead->Flink;

        while (ModListHead != Module) 
            LDR_DATA_TABLE_ENTRY* Module_Ldr = (LDR_DATA_TABLE_ENTRY*)(Module);

    //psuedo  if (module_name is in Module_Ldr->BaseDllName) // the comparison, where BaseDllName is type UNICODE_STRING

            Module = Module->Flink;
        
        KeUnstackDetachProcess(&APC);
        ObDereferenceObject(TargetProcess);
        return STATUS_SUCCESS;

【问题讨论】:

UNICODE_STRING 是结构。 LPWSTR 不是。见:docs.microsoft.com/en-us/windows/win32/api/subauth/… 【参考方案1】:

在下面的调用中:

if (RtlCompareUnicodeString(&str, &module_ldr->BaseDllName) 

此函数采用您未传递的附加参数。 请参考https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlcompareunicodestring

【讨论】:

对不起,代码确实有第三个参数。在发布问题之前我已经重写了其中的一部分,所以我在这里手动重新输入了评论中的一些代码,忘记包含第三个参数。

以上是关于无法将 C# 字符串从用户态传递到内核模式 C 并使用它来查找特定的 LDR_DATA_TABLE_ENTRY的主要内容,如果未能解决你的问题,请参考以下文章

C# 读写文件从用户态切到内核态,到底是个什么流程?

windows内核态调用readfile

零拷贝技术

用户态和内核态的区别是啥

将字符串从 C++/CLI 类库传递到 C#

用户态内核态