Как определить модуль, загруженный с помощью LoadLibraryEx - PullRequest
0 голосов
/ 05 июля 2019

Мне нужно использовать функцию Windows, такую ​​как GetModuleHandle или GetModuleFileName , чтобы узнать, загружена ли конкретная 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 или GetProcAddress с этой DLL.

Может быть, это моя проблема, но независимо от причины - кто-нибудь знает способ найти управляемую DLL DotNet впроцесс с использованием собственного кода / c ++?

Спасибо!

РЕДАКТИРОВАТЬ: Основываясь на предложениях 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 ]

1 голос
/ 11 июля 2019

ОК, это попытка ответа (или просто слишком длинный комментарий, извините).

Лично я никогда не видел управляемых .NET DLL на панели Process Explorer, но, возможно, не имелискал / достаточно часто.Однако то, что я могу (и всегда мог видеть), это изображения NGENed (*.ni.dll).

enter image description here

Обратите внимание также на наличие System.Data.dllздесь, который не является NGENed, но представляет собой сборку в смешанном режиме и содержит как собственный, так и управляемый код.

Таким образом, можно сделать вывод, что вы можете видеть здесь только «сборки» NGENed и смешанного режима, потому что онипо-прежнему загружаются LoadLibrary или LoadLibraryEx.

Также обратите внимание на мой комментарий, который я воспроизвожу здесь для более легкого доступа:

Я думаю, что CLR не использует LoadLibrary, котораяобъяснил бы, почему вы не можете «видеть» их, используя API, которые вы описали.Фактически, CLR 4 не использует LoadLibrary для загрузки сборок - это релевантная запись в блоге.Вы всегда можете проверить источники (CoreCLR, но это не имеет значения), в частности, о том, как это делается.У меня нет действительно хорошего места, но вы могли бы начать здесь и затем уйти от него.Вместо этого используйте интерфейс ICorDebug.

Вот некоторые соответствующие цитаты из записи в блоге, указанной выше:

Вы можете спросить себя:… кого это волнует?Ну, во-первых, это приятно знать.Я не заметил объявления о государственной службе выше.Однако это подробности реализации - сборки CLR даже не гарантируются для реализации с использованием файлов, не говоря уже о файлах DLL в определенном формате, которые загружаются с помощью LoadLibrary Win32 API.

Однако существует несколько инструментов.и сценарии, основанные на том факте, что CLR загружает сборки с помощью LoadLibrary.Например, до CLR 4, если вы хотите узнать, какие сборки .NET были загружены в ваш процесс, достаточно надежной эвристикой будет запуск Sysinternals Process Explorer и просмотр представления DLL данного процесса.Это не работает для CLR 4, как вы можете видеть здесь:

Честно говоря, я не знаю, как Process Explorer удается отображать сборки (не NGENed и не смешанный режим) в вашем случае - appart от вас наблюдают за процессом CLR2 .Однако учтите, что PE использует не только Win32 API.Он также использует WMI и, вероятно, также использует CLR напрямую для получения дополнительной информации.Например, на вкладках «Свойства процесса / Сборки .NET» и «Свойства процесса / Производительность .NET» скорее всего используются ICorDebug / ICorProfile и счетчики производительности / ETW соответственно.

Возможно, вам придется использоватьна один из этих интерфейсов, или что-то еще из неуправляемого API отладки или неуправляемого API в целом.

Что бы это ни было, я не думаю, чтоEnumProcessModules и т. Д. Доставит вас по вышеуказанным причинам.

0 голосов
/ 15 июля 2019

Добавить к ответу выше и предоставить соответствующий код;было невозможно использовать встроенную функцию, такую ​​как EnumProcessModules, для обнаружения не-ngen'ов dll-сетей DotNet, и вместо этого мне пришлось использовать интерфейсы 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:

...