title: Trouble passing a C# string from userland to kernelmode C and using it to find specific LDR_DATA_TABLE_ENTRY
body: <p>I am having difficulty comparing a string passed from usermode type LPWSTR to a LDR table entry type UNICODE_STRING</p>
  <p>Kernel C:</p>
  <pre><code>struct {
      int pid;
      int user_pid;
      int size;
      int protection_mode;
      int allocation_type;
      void* address;
      void* write_buffer;
      LPWSTR module_name;
  }
  userland_operation;
  </code></pre>
  <p>This struct is passed to the kernel via deviceiocontrol. The counterpart userland struct is as follows:</p>
  <pre><code>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;
  }
  </code></pre>
  <p>Where the String <code>ModuleName</code> is Marshaled as LPWStr.</p>
  <p><code>ModuleName</code> 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 <code>_LDR_DATA_TABLE_ENTRY</code> is a <code>UNICODE_STRING</code>. I want to compare this UNICODE_STRING with my LPWSTR.</p>
  <p>I have tried the following and it did not work:</p>
  <pre><code>{
      UNICODE_STRING str;
      RtlInitUnicodeString(&amp;str, module_name) // module name is the userland passed string LPWSTR
      if (RtlCompareUnicodeString(&amp;str, &amp;module_ldr-&gt;BaseDllName, TRUE) {
  
  
      }
  }
  </code></pre>
  <p>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.</p>
  <pre class="lang-cpp prettyprint-override"><code>NTSTATUS GetModuleList(HANDLE PID, PVOID UserBuffer, LPWSTR module_name) {
      KAPC_STATE APC;
      __try {
          PEPROCESS TargetProcess;
  
          PsLookupProcessByProcessId(PID, &amp;TargetProcess);
  
          PPEB Peb = PsGetProcessPeb(TargetProcess);
  
          if (!Peb)
              return STATUS_INVALID_PARAMETER;
  
          KeStackAttachProcess(TargetProcess, &amp;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-&gt;Flink;
  
          while (ModListHead != Module) {
              LDR_DATA_TABLE_ENTRY* Module_Ldr = (LDR_DATA_TABLE_ENTRY*)(Module);
  
      //psuedo  if (module_name is in Module_Ldr-&gt;BaseDllName) // the comparison, where BaseDllName is type UNICODE_STRING
  
              Module = Module-&gt;Flink;
          }
          KeUnstackDetachProcess(&amp;APC);
          ObDereferenceObject(TargetProcess);
          return STATUS_SUCCESS;
  </code></pre>