Создание обратно совместимого перетаскивания в статически связанной DLL - PullRequest
2 голосов
/ 14 июля 2020

У меня есть DLL на основе C, которую я написал несколько лет go для проекта, и она экспортирует набор функций, определяющих API. Теперь мне нужно переписать внутреннее устройство этой DLL, но сохранить API точно таким же.

Пользователь DLL использовал stati c связывание, и он не хочет или не может перекомпилировать свой исполняемый файл.

Я заметил, что RVA экспортируемых функций разные. Насколько я понимаю, это означает, что исполняемый файл не сможет найти функции, если он не будет повторно связан с обновленным файлом lib.

Есть ли в VS2017 способ заставить экспортируемую функцию использовать специфику c RVA? Я проверил формат файла Microsoft LINK DEF и не нашел там опции.

Даже если это возможно, достаточно исправляет RVA, чтобы старый исполняемый файл мог использовать обновленную DLL или есть ли дополнительные сложности, из-за которых это не запускается?

Спасибо.

Ответы [ 2 ]

1 голос
/ 17 июля 2020

Когда вы статически связываете модуль EXE с DLL, вы действительно связываете его с библиотекой импорта DLL (.LIB), созданной вместе с DLL при сборке DLL. Это не то же самое, что связывание с библиотекой stati c, что сбивает с толку, потому что это также файлы .LIB.

Первое, что вам нужно сделать, это выяснить, есть ли у вас EXE модуль имеет запись импорта для указанной DLL с помощью такого инструмента, как Dependency Walker , Dumpbin , pelook или вашего любимого инструмента анализатора PE. Если нет записи импорта DLL, вы, вероятно, связали EXE с библиотекой stati c, как описано в ответе @ HAL9000. Если не считать обратного проектирования EXE, лучше всего перестроить модуль, если это возможно.

В противном случае, если вы найдете импорт для указанной DLL, тогда да, вы можете замените недавно созданную DLL при условии, что у вас те же имена экспорта (функции) и / или порядковые значения, что и у оригинала. Библиотеки DLL находят функцию по именам экспорта и / или порядковым номерам, а не по RVA, которые в данном случае являются лишь внутренней деталью. Независимо от того, загружается ли DLL неявно (из-за того, что она статически связана) во время инициализации процесса (EXE) (до вызова точки входа EXE) или явно (через код с использованием LoadLibrary и т. Д. c.), Весь смысл в том, чтобы быть DLL заключается в том, что этот модуль разработан для динамической замены , а Windows был разработан на основе этой концепции. Внутренние RVA как в EXE (ссылающиеся на DLL), так и в самой DLL не обязательно должны соответствовать значениям старой DLL; эта бухгалтерия автоматически обрабатывается загрузчиком Windows во время процесса, также известного как связывание во время выполнения.

В случае, если EXE связан с указанной DLL, а ТАКЖЕ указывает жестко заданные адреса ( RVA) для экспортируемых функций DLL (процесс, известный как stati c binding), Windows по-прежнему будет проверять, что адреса все еще внутренне отражают правильные значения в загруженной DLL, которая может быть другой обновленной DLL. Это делается с помощью проверки отметки времени в разделе импорта для DLL. Если есть несоответствие, загрузчик Windows выбрасывает все stati c RVA и обновляет их текущими значениями, вызывая небольшое снижение производительности, но программа все равно загружается. FWIW инструмент bind.exe для выполнения этой stati c привязки больше не поставляется с набором инструментов Visual C ++, поскольку прирост производительности в современных версиях Windows минимален. Эта оптимизация раньше была обычной практикой для ускорения времени загрузки, особенно в системных библиотеках DLL, поставляемых ОС, но не должна влиять на то, что вы пытаетесь сделать, так или иначе.

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

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

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

...