Экспорт функции из ехе-файла

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

25 дек 2007, 14:25

Koduc писал(а): Придется видимо копать в сторону загрузки exe из памяти..
Ни у кого нет загрузчика из памяти с нормальными коментариями? :) А то где ни посмотришь, везде непонятные махинации со сдвигами..
А что тебе это даст? Запустить процесс, и внедриться в него - это не одно и то же! Ну предположим, что ты запустишь процесс не из файла на диске, а из ресурсов своего приложения... И что??? Он всё равно будет выполняться в отдельном адресном пространстве, на то он и процесс. Если ты хочешь чтобы одно приложение стало программным сервером для других приложений, значит его нужно сделать таковым с помощью тех средств, которые предоставляет для этого операционная система и среда программирования. Иначе какой смысл вообще городить весь этот огород?
Koduc
Сообщения: 22
Зарегистрирован: 10 сен 2007, 01:33
Контактная информация:

25 дек 2007, 15:17

Почему в разных адресных пространствах? Первоначально стоял вопрос об экспорте функций из ехе файла. После чего длл экспортирует эту функцию и приложение уже использует. О запуске отдельного процесса речи не идет..
А загрузка ехе из памяти - там как раз все функции нужные: импорт функций, расчет дельта-смещения. Обработать ехе в памяти, но просто не запускать его, а использовать экспортируемые функции.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

25 дек 2007, 19:43

Написал ответ сарзу же, но забыл его отправить. Привожу его полностью. Если с кем-то пересекусь, то заранее извиняюсь:

1. Почему экспортируемую функцию содержит exe файл? Вообще-то в таких случаях принято делать dll файл.
2. При экспорте принято делать extern "C" для того, чтобы имена функций не манглились. В этом случае при импорте в GetProcAddress достаточно будет указать строку "Start_all", что значительно более правильно, так как разные С++ компиляторы могут по разному манглить С++ декларацию функции и код, вследствии этого, становится непереносимым.
3. Во время экспорта, ты использовал __declspec(dllexport), что, между прочим, включает PASCAL вызов функций (прямой порядок загрузки параметров в стек и удаление параметров из стека внутри функции). А при импорте почему-то __declspec(dllimport) не указываешь и компилятор думаем, что функцию нужно вызывать, как C функцию (обратная загрузка параметров в стек и удаление параметров из стека снаружи функции). Из-за этого и летит access violation.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Koduc
Сообщения: 22
Зарегистрирован: 10 сен 2007, 01:33
Контактная информация:

25 дек 2007, 23:54

По пунктам:
1. можно было бы длл - не стояло бы самого такого вопроса..
2. Это я на примере так сделал, в рабочем коде это всё по уму будет ;)
3. Или я что-то не понимаю или.. Во всех примерах которые я встречал делается экспорт по __declspec(dllexport), потом простой вызов по адресу из GetProcAddress.
А __declspec(dllimport) используется чаще при наличии .lib файла.
Про тз я писал чуть выше, необходима такая реализация, когда через плагин в виде dll подгружается плагин в виде ехе, со своими экспортируемыми функциями.
---
PS: врочем с импортом из .lib модуля не работает точно так же, как и другими методами ;)
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

26 дек 2007, 09:54

Romeo писал(а):3. Во время экспорта, ты использовал __declspec(dllexport), что, между прочим, включает PASCAL вызов функций (прямой порядок загрузки параметров в стек и удаление параметров из стека внутри функции). А при импорте почему-то __declspec(dllimport) не указываешь и компилятор думаем, что функцию нужно вызывать, как C функцию (обратная загрузка параметров в стек и удаление параметров из стека снаружи функции).
Таки, по-моему, это не есть так. __declspec(dllimport) никак не связан с calling convention. Для "паскалевской" модели вызова указывается WINAPI.

MSDN:
WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.

К тому же в данном случае функция без параметров, так что в через стек вообще ничего не передается. Т.е. в данном случае даже с несовпадающими calling conventions все равно бы не упало бы.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

26 дек 2007, 11:19

На счёт смены конвеншенов вызова функции при использовании __declspec(dllexport) я всё-таки погорячился. В этом BBB прав. Но использовать __declspec(dllimport) во время импорта все же нужно, я на этом настаиваю. Это парные спецификаторы и они обязаны использоваться парно, то есть либо и там и там, либо ни там, ни там. Самый главный аргумент - это то, что спецификатор __declspec не является частью ANSI стандарта и его контент может быть всегда изменён когда угодно и как угодно уважаемым Microsoft.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Koduc
Сообщения: 22
Зарегистрирован: 10 сен 2007, 01:33
Контактная информация:

26 дек 2007, 13:01

Доковырялся дизасемблером до причин вылета. При LoadLibrary ехе проецируется в память (точнее его ImageBase как я понимаю) по адресу, как привило большему или меньшему чем 0х0040000 (стандартное для ехе файлов). Точка входа в экспортируемую функцию определяется корректно. Но уже после входа в функцию имеем ссылки на данные и на функции, как если бы этот ехе загрузился по адресу 0х0040000.
Как можно с наименьшими трудовыми и временными затратами эти смещения исправить? Секцию .reloc в файл включаю, но для ехе это видимо не играет роли..
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

26 дек 2007, 13:28

Romeo писал(а):Но использовать __declspec(dllimport) во время импорта все же нужно, я на этом настаиваю.
Так ведь у него же описана НЕ импортируемая функция, тип функции (typedef). Че-то, никогда в этом случае (в описании типа функции), вроде никаких директив импорта не ставилось. Я так понимаю, dllimport - это вообще больше для линкера, а не для компилятора.

А экспортировать ф-ии можно вообще без __declspec(dllexport), если описать их как экспортируемые в *.DEF-файле проекта.

-------------------------------

Koduc,
тупая кондовая мысль. Скорее, это бред и вряд ли поожет, но вдруг. А если у твоего файла поменять расширение с EXE на DLL?
Koduc
Сообщения: 22
Зарегистрирован: 10 сен 2007, 01:33
Контактная информация:

26 дек 2007, 13:49

Я думал меня одного такие мысли посещают ;) нет, не работает ;(
00A81000 push 0
00A81002 push offset _heap_term+0E0h (00403010)
00A81007 push offset _heap_term+0E0h (00403010)
00A8100C push 0
00A8100E call dword ptr [_setenvp+24h (00402044)]

вот вызов экспортируемой функции.. видно что сылки ведут далеко за пределы загруженных данных.. Но сама функция корректна (вызов messagebox'a с 4 параметрами) ;)
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

26 дек 2007, 14:07

Koduc,
вот тут еще что-то похожее обсуждают:
http://forum.sources.ru/index.php?showtopic=200132

Даже есть исходник простейшего загрузчика

Я сильно не вникал, но вот любопытное сообщение #13 (может, и в смом деле возможно "преобразовать" EXE в DLL):

Что бы ЕХЕ превратить в ДЛЛ - единственное, что надо сделать - заменить в
FileHeader поле Characteristics на соответствуещее длл. И добавить релоки, но тут уже смотря что нужно будет делать и какой EXE-файл...
Ответить