Можно ли вызвать DllMain .exe?

Мой вопрос не совсем совпадает с этим (он не теоретический, есть только основной поток без цикла обработки сообщений, вызовы InitInstance и ExitInstance не подходят).

Я использую консольное приложение без цикла сообщений; это приложение загружает исполняемый файл с функцией LoadLibrary, чтобы оно могло использовать свои экспортированные функции. Плохая новость: функция DllMain exe не вызывается (и я проверил таблицы символов, используя файл def, DllMain отображается правильно); документ говорит, что он вызывается, если загруженный модуль является DLL (также плохой).

Каковы условия (если они существуют), которые могут привести к выполнению функции DllMain исполняемого файла при вызове LoadLibrary (и, возможно, снова при вызове FreeLibrary)?

С наилучшими пожеланиями


person moala    schedule 16.01.2009    source источник


Ответы (4)


Наиболее очевидным условием является то, что процесс, вызывающий LoadLibrary(), явно получает GetProcAddress("DllMain") и затем вызывает его.

person MSalters    schedule 16.01.2009

Условия:

1) Загружаемый двоичный файл был скомпилирован как DLL (при использовании gcc/ld это означает использование опции --shared; если вы используете --shared, результирующий файл будет dll и не будет запускаться, см. ниже)

2) IMAGE_FILE_DLL устанавливается в заголовке PE-файла загружаемого бинарного файла. Если он установлен, файл является dll, и компоновщик Windows вызовет для вас свою функцию DllMain(), когда он свяжет этот файл с вашей программой (не имеет значения, как он связан - LoadLibrary() во время выполнения или -llibraryname во время компиляции). Для этого файл также должен удовлетворять (1). Но с этим флагом загружаемый бинарный файл не будет запускаться. Если IMAGE_FILE_DLL не установлено, DllMain() не будет вызываться при загрузке файла в вашу программу.

Компиляция dll с --shared и последующее ручное удаление IMAGE_FILE_DLL из ее заголовка (т.е. с помощью шестнадцатеричного редактора) не сработает - при запуске будет выполняться только DllMain(), а fdwReason будет неопределённым числом (0x28ffd4 на моей машине).

Обновить

Все файлы DLL и EXE в Windows являются PE-файлами, разница заключается в том, как они связаны и какие флаги установлены в их заголовках. Вот почему я пишу file being loaded, а не dll being loaded.

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

Именование не имеет к этому никакого отношения (вы можете выбрать любое имя, и с некоторыми pexports+dlltool вознями вы можете создать библиотеку импорта для файла .exe и иметь возможность связать его как -lexenamewithoutextension

Чтобы уточнить:

  • if you compile it without --shared:
    • IMAGE_FILE_DLL will not be set in it, it will be runnable, but DllMain() will NOT be called when you link it.
  • if you compile it with --shared:
    • IMAGE_FILE_DLL will be set in it, it will NOT be runnable, but DllMain() will be called when you link it.
  • if you compile it without --shared, then switch on the IMAGE_FILE_DLL flag in it manually:
    • it will NOT be runnable anymore, and no DllMain() will be called when you link it.
  • if you compile it with --shared, then switch off the IMAGE_FILE_DLL flag in it manually:
    • it will be runnable, but DllMain() will be executed instead of main(), and DllMain() will NOT be called when you link it.
person LRN    schedule 13.09.2012
comment
В вопросе конкретно упоминается загрузка исполняемого файла (.exe) с использованием LoadLibrary, а не DLL. Пожалуйста, перечитайте вопрос. - person Ken White; 13.09.2012
comment
Ваше редактирование ничего не меняет. Нигде в вопросе не говорится, что файл был скомпилирован/слинкован как-то иначе, чем файл .exe. (Исполняемые файлы в Windows могут экспортировать функции точно так же, как DLL, без необходимости сначала компилировать их как DLL.) - person Ken White; 13.09.2012
comment
Вопрос заключался в следующем: каковы условия (если они существуют), которые могут привести к выполнению функции DllMain exe при вызове LoadLibrary (и, возможно, снова при вызове FreeLibrary)? Это то, что я отвечаю. Чтобы DllMain() вызывалась автоматически, вы должны скомпилировать двоичный файл как разделяемую библиотеку и установить в нем флаг DLL. - person LRN; 17.09.2012
comment
Вы все еще не поняли мою мысль. :-) Если у вас есть .EXE, то DLLMain не будет автоматически вызываться. Конечно, у вас может быть функция с именем DLLMain, но это все равно, что назвать класс Car и ожидать, что вы сможете использовать его для доступа к врачу. В .EXE нет функции auto-callable DLLMain(), поэтому вы не можете получить ее автоматический вызов при загрузке .EXE с LoadLibrary(). - person Ken White; 17.09.2012
comment
Вы говорите, что он упустил вашу мысль, но затем вы продолжаете делать заявление, которое в основном покрыто его ответом. Ответ от LRN, по-видимому, является надмножеством большей части вашего утверждения. Чего у него не было, так это почему это работает именно так, хотя Мартин упоминает об этом в своем ответе. - person Loduwijk; 31.05.2015

Действительно, имя "DllMain" функции полностью игнорируется Windows (в старой документации API Windows для Windows NT 3.x это указано явно).

При загрузке DLL вызывается не функция DllMain(), а функция, расположенная в точке входа в файл.

Конечно, компоновщик создаст файл DLL таким образом, что DllMain() является этой функцией.

Однако для EXE-файлов функция входа (которая будет вызывать WinMain()) находится в точке входа.

Таким образом, очевидно, что Windows не может вызвать эту функцию при загрузке EXE-файла как DLL.

person Martin Rosenau    schedule 21.08.2013

Завершение хорошего ответа MSalters:

Итак, вызовите «поддельный» DllMain с DLL_XXX_ATTACH сразу после LoadLibrary и с DLL_XXX_DETACH сразу перед FreeLibrary, а остальные вызовы выполните вручную.

Другой следующей реализацией будет сборка и загрузка интерфейсной DLL, которая может автоматически вызывать EXE на поддельном DllMain (я не знаю, сработает ли это); но в ряде случаев это может быть сложнее, чем просто вручную вызвать фальшивую DllMain. (не может LoadLibrary в DllMain)

person moala    schedule 16.01.2009
comment
Вы не можете вызывать LoadLibrary(your.exe) из DllMain в вашей вспомогательной DLL — часть длинного списка вещей, которые вы не можете там делать. Это делает вашу вспомогательную DLL довольно сложной в использовании; это не может быть простой упаковщик/экспедитор, - person MSalters; 19.01.2009