如何检测使用LoadLibraryEx

时间:2019-07-05 15:54:50

标签: c++ .net process clr

我需要使用GetModuleHandleGetModuleFileName之类的Windows函数来确定是否在执行代码的同一进程中加载​​了特定的dll。

我正在寻找的一个模块是System.Windows.Forms.dll,但是即使将其加载到进程中……ProcessEx showing WindowsForms dll(在这里您可以使用Process Explorer看到它)

GetModuleHandle仍然找不到它!

    HMODULE modHandle = GetModuleHandle(L"System.Windows.Forms.dll");

GetModuleHandle fails

GetLastError()返回ERROR_MOD_NOT_FOUND

  

如果函数成功,则返回值是指定模块的句柄。   如果函数失败,则返回值为NULL。

我认为这可能与CLR如何加载这些dll有关。我在LoadLibraryEx上看到一条注释,如果使用LOAD_LIBRARY_AS_DATAFILE标志,则:

  

如果使用此值,则系统会将文件映射到调用中   进程的虚拟地址空间,就好像它是数据文件一样。没有什么是   完成执行或准备执行映射文件。因此,你   无法调用诸如GetModuleFileName,GetModuleHandle或   带有此DLL的GetProcAddress。

也许这是我的问题,但无论原因如何,有人知道使用本机/ c ++代码在进程中查找托管DotNet dll的方法吗?

谢谢!

编辑: 根据Castorix在评论中的建议,我尝试使用EnumProcessModules:

    HMODULE modules[100];
    void* hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, GetCurrentProcessId());
    if (hProcess)
    {
        DWORD bytesNeeded;
        BOOL rc = EnumProcessModules(hProcess, modules, sizeof(modules), &bytesNeeded);
        if (rc)
        {
            int count = (int)(bytesNeeded / sizeof(HMODULE));
            for (int i = 0; i < count; i++)
            {
                wchar_t moduleName[260];
                GetModuleFileName(modules[i], moduleName, 260);
            }
        }
    }
    CloseHandle(hProcess);

此代码找到很多模块,但找不到System.Windows.Forms.dll enter image description here

2 个答案:

答案 0 :(得分:1)

好的,这是一个答案的尝试(或者实际上只是太长的评论,对不起)。

就个人而言,我从未在Process Explorer窗格中看到托管的.NET DLL,但可能看起来不够辛苦/不够频繁。但是,我可以(并且始终可以看到)是NGENed图像(*.ni.dll)。

enter image description here

请注意这里还存在System.Data.dll,它不是NGENed的,而是混合模式的程序集,其中包含本机代码和托管代码。

因此可以得出一个结论,您在这里只能看到NGENed模式和混合模式“程序集”,因为它们仍然是由LoadLibraryLoadLibraryEx加载的。

也请注意我的评论,为了便于访问,我在这里复制了它:

  

我认为CLR不使用LoadLibrary,这可以解释为什么   无法使用您描述的API“查看”它们。事实上,   CLR 4 Does Not Use LoadLibrary to Load Assemblies   是相关的博客条目。您可以随时检查来源   (CoreCLR,但不重要),特别是关于它是如何完成的。一世   没有真正好的地方,但是你可以开始   here   然后从中去。请改用ICorDebug接口。

以下是上面链接的博客条目中的一些相关引语:

  

您可能会问自己:…谁在乎?好,首先很好   要知道。我还没有注意到上述公共服务公告。   这是实现细节,但是,CLR程序集甚至没有   保证使用文件实现,更不用说DLL文件了   使用LoadLibrary Win32 API加载的特定格式。

     

但是,有几种工具和方案需要依赖   CLR使用LoadLibrary加载程序集。例如,   如果您想知道加载了哪些.NET程序集,则最高为CLR 4   在您的过程中,相当可靠的启发式方法是   Sysinternals Process Explorer并查看给定的DLLs视图   处理。如您在此处看到的那样,这不适用于CLR 4:

坦率地说,我不知道Process Explorer如何在您的情况下显示程序集(不是NGENed和非混合模式)-您看到的 appart正在查看CLR2进程。但是,请记住,PE不仅使用Win32 API。它还使用WMI,可能还直接使用CLR获取更多信息。例如,“进程属性/.NET程序集”和“进程属性/.NET性能”选项卡最有可能分别使用ICorDebug / ICorProfile和性能计数器/ ETW。

您可能还需要使用这些接口中的一个,或通常使用unmanaged Debugging APIunmanaged API中的其他接口。

无论是什么原因,我都不认为EnumProcessModules等会因为上述原因而使您到达那里。

答案 1 :(得分:0)

要添加到上述答案中并提供相关代码;无法使用EnumProcessModules之类的本机函数来检测非ngeneded的DotNet dll,而不得不使用C ++接口连接CLR。

这里有更多信息:https://blogs.msdn.microsoft.com/calvin_hsia/2013/12/05/use-reflection-from-native-c-code-to-run-managed-code/与该特定问题最相关的代码是:

    HRESULT GetAssemblyFromAppDomain(_AppDomain* pAppDomain, LPCWSTR wszAssemblyName, _Deref_out_opt_ _Assembly **ppAssembly)
    {
      *ppAssembly = NULL;
      // get the assemblies into a safearray
      SAFEARRAY *pAssemblyArray = NULL;
      HRESULT hr = pAppDomain->GetAssemblies(&pAssemblyArray);
      if (FAILED(hr)) 
      {
        return hr;
      }
      // put the safearray into a smart ptr, so it gets released
      CComSafeArray<IUnknown*>    csaAssemblies;
      csaAssemblies.Attach(pAssemblyArray);

      size_t cchAssemblyName = wcslen(wszAssemblyName);

      long cAssemblies = csaAssemblies.GetCount();
      for (long i=0; i<cAssemblies; i++)
      {
        CComPtr<_Assembly> spAssembly;
        spAssembly = csaAssemblies[i];
        if (spAssembly == NULL) 
          continue;
        CComBSTR cbstrAssemblyFullName;
        hr = spAssembly->get_FullName(&cbstrAssemblyFullName);
        if (FAILED(hr)) 
          continue;
        // is it the one we want?
        if (cbstrAssemblyFullName != NULL && 
          _wcsnicmp(cbstrAssemblyFullName, 
          wszAssemblyName, 
          cchAssemblyName) == 0)
        {
          *ppAssembly = spAssembly.Detach();
          hr = S_OK;
          break;
        }
      }
      if (*ppAssembly == 0)
      {
        hr = E_FAIL;
      }
      return hr;
    }

这里有一些有关CLR接口的信息: