Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble passing a C# string from userland to kernelmode C and using it to find specific LDR_DATA_TABLE_ENTRY

I am having difficulty comparing a string passed from usermode type LPWSTR to a LDR table entry type UNICODE_STRING

Kernel 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;

This struct is passed to the kernel via deviceiocontrol. The counterpart userland struct is as follows:

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;
}

Where the String ModuleName is Marshaled as LPWStr.

ModuleName is the desired search term for the loaded module in a process. Now, here's where things get tricky. The string I have access to via the _LDR_DATA_TABLE_ENTRY is a UNICODE_STRING. I want to compare this UNICODE_STRING with my LPWSTR.

I have tried the following and it did not work:

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


    }
}

I've also tried wcscmp, and a few other things. I'm not sure how I can compare these two properly. I've added some minor pseudocode to the function to provide additional context on what I'm looking to do.

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;
like image 892
Ben Avatar asked Jun 05 '20 04:06

Ben


People also ask

What is passing reference C?

Passing by by reference refers to a method of passing the address of an argument in the calling function to a corresponding parameter in the called function. In C, the corresponding parameter in the called function must be declared as a pointer type.

Is call by reference possible in C?

Values of variables are passed by the Simple technique. Pointer variables are necessary to define to store the address values of variables. Note: In C, we use pointers to achieve call by reference. In C++, we can either use pointers or references for pass by reference.

How arguments are passed to a function using references in C?

To pass a value by reference, argument pointers are passed to the functions just like any other value. So accordingly you need to declare the function parameters as pointer types as in the following function swap(), which exchanges the values of the two integer variables pointed to, by their arguments.


1 Answers

In this call below:

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

This function takes an additional argument which you are not passing. Please refer to https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlcompareunicodestring

like image 158
Catch22 Avatar answered Oct 06 '22 18:10

Catch22