Предотвращение переполнения стека в библиотеках-оболочках - PullRequest
6 голосов
/ 03 мая 2010

У меня есть программа, в которую я добавляю полноэкранные эффекты постобработки. У меня нет исходного кода для программы (она проприетарна, хотя разработчик и отправил мне копию символов отладки в формате .map). У меня есть код для написанных и работающих эффектов, никаких проблем.

Моя проблема сейчас связана с двумя.

До сих пор я пробовал два метода:

Используйте Detours для изменения таблицы импорта исходной программы. Это прекрасно работает и гарантированно будет стабильным, но пользователю, с которым я говорил, это неудобно, требуется установка (помимо извлечения архива), и возникает вопрос, допустимо ли исправление программы с помощью Detours в соответствии с условиями лицензионного соглашения. Итак, эта опция отсутствует.

Другой вариант - традиционная DLL-замена. Я упаковал OpenGL (opengl32.dll), и мне нужна программа, чтобы загрузить мою DLL вместо системной копии (просто поместите ее в папку программы с правильным именем, это легко).

Затем мне нужна моя DLL для загрузки Cg-фреймворка и среды выполнения (которая зависит от OpenGL) и некоторых других вещей. Когда Cg загружается, он вызывает некоторые из моих функций, которые вызывают функции Cg, и я склонен к переполнению стека и бесконечным циклам. Мне нужно иметь возможность включить библиотеки DLL Cg в подкаталог и по-прежнему использовать их функции (не уверен, что моя таблица импорта DLL может указывать на DLL в подкаталоге) или мне нужно динамически связать их (что я я бы предпочел не делать этого, просто чтобы упростить процесс сборки), что-то, чтобы заставить их ссылаться на файл системы (а не на мою собственную замену).

Вся цепочка: Программа загружает DLL A (с именем opengl32.dll). DLL A загружает Cg.dll и динамически связывает (GetProcAddress) с sysdir / opengl32.dll. Теперь мне нужно, чтобы Cg.dll также ссылался на sysdir / opengl32.dll, , а не DLL A.

Как бы это было сделано? Редактировать: Как это можно сделать легко без использования GetProcAddress? Если ничто иное не сработает, я хочу вернуться к этому, но я бы предпочел не делать этого, если это вообще возможно.

Edit2: Я только что наткнулся на функцию SetDllDirectory в документах MSDN (при совершенно не связанном поиске). На первый взгляд это выглядит так, как мне нужно. Это правильно, или я ошибаюсь? (сейчас проверить)

Edit3: Я решил эту проблему, действуя немного иначе. Вместо того, чтобы бросать OpenGL32.dll, я переименовал мою DLL в DInput.dll. Мало того, что он имеет преимущество в том, что экспортирует одну функцию вместо более чем 120 (для программы, Cg и GLEW), мне не нужно беспокоиться о функциях, запускающихся обратно (я могу связываться с OpenGL как обычно) , Чтобы попасть на вызовы, которые мне нужно перехватить, я использую Detours. В целом, это работает намного лучше. Этот вопрос, тем не менее, все еще является интересной проблемой (и, надеюсь, будет полезен всем, кто пытается делать сумасшедшие вещи в будущем). Оба ответа хороши, так что я еще не уверен, что выбрать ...

Ответы [ 2 ]

1 голос
/ 04 мая 2010

Вы можете использовать магию контекстов активации, чтобы попытаться решить вашу проблему.

Многое зависит от погоды, у сторонних компонентов в вашей системе уже есть манифесты - и насколько фальсификация этих манифестов может представлять собой нарушение лицензии.

Чтобы решить проблемы с версиями DLL, в Windows XP появилась технология, называемая контекстами активации. Иногда известный как параллельные сборки, или даже что-то ужасное, как Изоляция приложений

Чтобы суммировать много чтения в маленьком пространстве: манифесты - это фрагменты данных XML, которые могут описывать сборку или описывать зависимость от сборок. Сборка - это манифест, плюс его dll.

Причина, по которой это существует, заключается в том, что сборка может принять простую dll. «comctl32.dll» и его номер версии (v6), и создайте объект с более уникальным именем, чтобы можно было безопасно установить несколько версий простой библиотеки DLL в одном месте. Сборки предназначены для установки в C:\Windows\WinSxS.

Когда файл манифеста описывает dll в сборке, он называется манифестом сборки. И обычно имеет другое имя для DLL.

Когда файл манифеста описывает сборки, используемые dll или exe, он называется манифестом приложения и обычно внедряется как ресурс RT_MANIFEST - в EXE с res id 1, в Dlls с res id 2 - или на диске в виде файла с именем «appname.exe.manifest» / «dllname.dll.2.manifest». Манифесты приложения определяют то, что называется контекстом активации - это в основном пространство имен, в котором Windows будет искать вещи. Каждый манифест создает контекст активации. Каждый контекст активации имеет отображение простых имен dll в сборках.

Итак, если вы создаете сборку с вашим файлом opengl32.dll и создаете контекст активации для файла app.exe, ссылающегося (локальный файл opengl32.dll), то, возможно, все остальные DLL может (и будет) продолжать использовать файл систем opengl32.dll, несмотря на тот факт, что имена очень похожи coff .

Проблема в том, что res-id манифеста приложения - 1 - означает, что он используется для создания контекста активации процесса по умолчанию - поэтому ВСЕ dll, не имеющие собственных явных манифестов (Cg?), Будут искать обработайте пространство по умолчанию и найдите, что opengl32.dll

Таким образом, вы должны создать манифесты для каждой dll, которая еще не встраивает их, убедившись, что просто НЕ ссылаетесь на вашу сборку opengl32.dll, что должно позволить затем вернуться к порядку поиска по умолчанию и найдите его в обычном каталоге system32.

это означает, что ваш файл opengl32.dll не может быть в папке exe, так как в этой папке выполняется поиск dll-файлов перед system32 (факт, на который вы полагаетесь для перехвата).

Нас спасает довольно простой порядок поиска, который система использует при поиске сборок. сначала он ищет в WinSxS. Ваш Opengl32.dll не будет там, установка там является серьезной проблемой. Затем он ищет в папке exe-файла подпапку с именем сборки, ТО затем он ищет в папке exe-файла непосредственно манифест сборки.

Это означает, что вы можете создать сборку, которая называется что-то вроде: "OpenGLHook" И ваша структура папок будет выглядеть так:

\appfolder\
  app.exe
  app.exe.manifest                  - contains a dependentAssembly node to OpenGLHook
  OpenGLHook\OpenGLHook.manifest    - contains a file name=opengl32.dll
  OpenGLHook\opengl32.dll           - your hook dll
  yourimpl.dll                      - your implementation dll that linkgs to cg.dll
  cg.dll                            - cg libraries
  cg.dll.2.manifest                 - a stub manifest you put together to ensure cg
                                      doesnt use the app default activation ctx.

Хм, удачи?

1 голос
/ 04 мая 2010

SetDllDirectory, вероятно, не будет работать. Cg.dll скорее всего просто ссылки на OpenGL.dll. Когда ОС загружает Cg.dll, она видит, что уже загружен модуль с этим именем (вашим), поэтому связывает Cg с этим, вместо того, чтобы искать какую-то другую копию. Таким образом, порядок поиска, который SetDllDirectory изменяет, даже не вступает в игру, потому что ОС не выполняет поиск.

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

...