Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проверка прототипа функции из DLL, Как предотвратить падение при ошибке 
:(
    Опции темы
null56
Дата 2.6.2010, 20:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: нет
Всего: 12



Всем привет
Задача: пройти по файлам dll, найти функцию по имени, успешно вызвать
Решение:
Код

typedef void (__cdecl *my_func)(int, int);

int main()
{
    HINSTANCE module = LoadLibrary(__TEXT("C://my_file.dll"));
    if (module)
    {
        LPCSTR func_name = "testf";
        my_func func_from_dll = (my_func)GetProcAddress(module, func_name);
        if (func_from_dll)
        {
            int a; int b;
            try // не спасет всё равно
            {
                func_from_dll(a, b);
            }
            catch (...)
            {
                printf("Catch");
            }
        }
        else
        {
            //...
        }
        FreeLibrary(module);
    }
    else
    {
        //...
    }
    return 1;
}

Результат: всё по идее хорошо, но если прототип совпадает, а если нет? я так понимаю (и получаю) падение программы. у функции нет контроля над тем, что ты пытаешься загрузить, есть имя в def и адрес, к прототипу любого вида можно привезти
Вопрос: можно ли как - нибудь избежать падения, при динамическом импорте функций из библиотек, при несовпадании прототипов? какие - нибудь дополнительные проверки или другие функции для этих целей.

Надеюсь вопрос понятен, заранее благодарен за помощь
PM MAIL   Вверх
12usver12
Дата 2.6.2010, 21:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 247
Регистрация: 5.1.2007

Репутация: 1
Всего: 1



в отдельном потоке вызывать и ставить хук на завершении функции и смотреть адрес возврата
PM MAIL   Вверх
borisbn
Дата 2.6.2010, 22:43 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 6
Всего: 135



Если библиотеки твои (или сделаны по твоим правилам), то можно в них заменить __cdecl на __stdcall, а также убрать extern "C". В этом случае прототип будет выглядеть как-то так
func_name@4i4i


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Abyx
Дата 2.6.2010, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 2
Всего: 10



проверять esp
PM MAIL   Вверх
null56
Дата 2.6.2010, 22:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: нет
Всего: 12



borisbn, да, библы мои, но никогда не слышал об этом способе

Abyx, а можно по подробнее и что я должен там обнаружить?
PM MAIL   Вверх
xvr
Дата 2.6.2010, 23:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Полной информации о прототипе функции в dll нет. Есть масса способов извлечь некоторую информацию о вызываемой функции. Большую часть их уже озвучили, могу добавить еще:
  •  Если функция С++ (и С++ манглинг не отключен), то прототип однозначно восстанавливается из С++ имени функции
  •  Если осталась отладочная информация, то прототип функции (и не только его) можно извлеч оттуда
  •  Если модель вызова функции была stdcall то размер переметров в стеке будет закодированна в числе после @ в имени функции (func@4 - 4 байта параметров)
  •  Исследовать код функции на предмет пролога и эпилога (требует весьма недюжих познаний во многих областях)

PM MAIL   Вверх
jonie
Дата 2.6.2010, 23:40 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 7
Всего: 118



все игры с стеком справдливы только для win32 (!) это важно....


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Dem_max
Дата 3.6.2010, 06:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 16
Всего: 39



Цитата

Задача: пройти по файлам dll, найти функцию по имени, успешно вызвать


Очень сложно, если нужен контроль параметров вызываемой функции.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Abyx
Дата 3.6.2010, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 2
Всего: 10



borisbn, xvr, при чем тут манглинг?
Если известно имя функции, то очевидно известен ее прототип, в том числе число параметров.
Если функция неправильная, то никакой манглинг тут не поможет.
Импортируется функция вместе с манглингом, GetProcAddress(hlib, "foo@8"), расшифровка никакой новой информации не даст.

Проверка esp позволит узнать правильное ли было количество параметров у функции, после ее вызова, не более того.
PM MAIL   Вверх
GremlinProg
Дата 3.6.2010, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Abyx @  3.6.2010,  12:07 Найти цитируемый пост)
borisbn, xvr, при чем тут манглинг?

при декорировании например C++ прототип и кодируется именем функции,
stdcall - тоже, но в меньшей степени: тут можно определить только размер фрейма

так что манглинг тут многое может прояснить,
конечно, все можно получить из отладочной секции, но доступ к имени гораздо проще,

рекомендую декорирование C++ взять на контроль, если надо обязательно знать прототип,
в vs есть утилитка undname.exe и есть соответствующая API

недостаток у них только есть небольшой: слишком длинные имена не распознают, это особенно актуально при экспорте шаблонных имплементаций


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Abyx
Дата 3.6.2010, 10:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 2
Всего: 10



Как я понимаю, у ТСа проблема в том, что он не уверен, что функция в длл будет иметь ожидаемый прототип.
Например - длл это плагин, написанный сторонним разработчиком на другом языке.
В этом случае, ТС может специфицировать что функция имеет прототип
extern "C" void __stdcall foo(int a, int b);
соответственно в таблице экспорта длл должно быть имя "foo@8"

но человек пишущий длл, может писать ее на другом языке, и напишет
Код

proc foo x, y, z
....
export foo as "foo@8"


Добавлено @ 10:43
какбэ от того что ТС напишет
Код

typedef void (__stdcall *my_func)(int, int);
.............
        LPCSTR func_name = "testf@8";
        my_func func_from_dll = (my_func)GetProcAddress(module, func_name);

ничего не поменяется


кроме того что это усложнит жизнь тому кто пишет длл

Это сообщение отредактировал(а) Abyx - 3.6.2010, 10:45
PM MAIL   Вверх
null56
Дата 3.6.2010, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: нет
Всего: 12



Abyx, да про это и речь, что там вообще может быть всё что угодно, те же 8 байт параметров и та же функция... а в функции происходит работа вообще с другими типами... Мне нужна длл с моими четкими параметрами (TCHAR *, std :: vector<std::basic_string<TCHAR> > &) = те же 8 байтов (для 32 бит)
Но GremlinProg,  xvr, про декорирование имен говорят, сейчас читаю и пытаюсь понять, зашит ли там при сборке длл прототип, если да, то это как раз то что нужно....
http://en.wikipedia.org/wiki/Name_mangling
PM MAIL   Вверх
Abyx
Дата 3.6.2010, 10:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 2
Всего: 10



Цитата(null56 @  3.6.2010,  10:48 Найти цитируемый пост)
зашит ли там при сборке длл прототип

только в С или в С++ у конкретного компилятора.

если используете msvc - пишите в длл у функции __declspec(dllexport), и импортируйте получившееся имя

Это сообщение отредактировал(а) Abyx - 3.6.2010, 10:52
PM MAIL   Вверх
GremlinProg
Дата 3.6.2010, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Abyx @  3.6.2010,  12:37 Найти цитируемый пост)

но человек пишущий длл, может писать ее на другом языке, и напишет
Код

proc foo x, y, z
....
export foo as "foo@8"


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

гораздо проще приложение может упасть в самой библиотеке :)

try-except не защитит только от ошибки со стеком, т.к. она фатальна в любой ситуации,
все остальное поймает


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Abyx
Дата 3.6.2010, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 2
Всего: 10



восстановление ebp решает все ошибки со стеком %)
т.е. try сохраняет ebp, и при отлове эксепшена ebp восстанавливается, а в эпилоге функции восстанавливается и esp
собственно если в функции есть ebp-фрейм, на ошибки с esp можно не обращать внимания, лишь бы esp не поднимался выше нижней границы фрейма

Это сообщение отредактировал(а) Abyx - 3.6.2010, 11:09
PM MAIL   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0605 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.