Получить DLL-файл для COM-объекта без использования CLSID и реестра в C++

Можно ли получить DLL-имя файла для загруженного COM-объекта без использования CLSID и поиска в реестре?

у меня есть IUnknown или в моем случае IBaseFilter указатель интерфейса и теперь я хочу получить DLL-имя файла, который создал этот COM-объект. Можно ли использовать адрес точки объекта для обратного просмотра загруженного модуля, в котором он был создан? А потом получить HMODULE использовать его в GetModuleFileName,

2 ответа

Решение

Естественно, используя только некоторые хаки. Сам объект находится в куче, которая является общей, но вы могли видеть, где находится его виртуальная таблица - он должен быть почти всегда в разделе данных только для чтения двоичного файла создателя.

Итак, загрузите первый указатель в объекте, так как там находятся указатели виртуальных таблиц в Windows COM ABI:

IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);

Тогда я изначально предложил сделать цирк с EnumProcessModules() например, здесь, позвоните GetModuleInformation() на каждом модуле и проверьте, если vtbl указатель попадает в его диапазоны памяти. Тупой я забыл про VirtualQueryEx()так что лучше сделай, как Роман описал в своем ответе.

Конечно, все это может работать только для внутрипроцессных COM-объектов и там, где не задействованы прокси-серверы. Я предполагаю, что это все еще может быть полезным в вашем случае DirectShow, хотя.

Также смотрите комментарий об использовании IPersist::GetClassId() и поиск в реестре, он должен применяться к большинству фильтров DirectShow.

У Йиркхи хороший ответ, и у меня есть два примечания:

  1. Фильтры DirectShow обычно являются COM-объектами старой школы C++ с таблицей виртуальных методов, находящейся в сегменте кода, без прокси-кода-заглушки, пока мы находимся внутри одного процесса. То есть, хаки разрешения модуля из указателя интерфейса работают хорошо.

  2. Есть более легкая замена EnumProcessModules/GetModuleInformation пройтись по списку модулей. VirtualQueryEx может найти базовый адрес DLL напрямую:

const VOID* pvVirtualTable = *((const VOID**) pBaseFilter);
MEMORY_BASIC_INFORMATION Information;
if(VirtualQueryEx(GetCurrentProcess(), pvVirtualTable, &Information,
  sizeof Information))
{
  TCHAR pszPath[MAX_PATH] = { 0 };
  if(GetModuleFileName((HMODULE) Information.AllocationBase, pszPath,
    _countof(pszPath)))
  {

PS Это то, что мы также делаем как в DirectShowSpy здесь, так и в GraphStudioNext.

Другие вопросы по тегам