Проверка прототипа функции из DLL, Как предотвратить ошибку?

Тема в разделе "WASM.WIN32", создана пользователем DeRekX, 4 июн 2010.

  1. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    поясню проблему со стеком
    Код (Text):
    1. __try {
    2.    func(1)
    компилируется в
    Код (Text):
    1. push ebp
    2. push хз_что_там_еще_в_SEH_фрейме
    3. push exception_handler
    4. push [fs:0]
    5. mov [fs:0], esp
    6. push 1
    7. call [func]
    допустим вызываемая функция имеет неправильное число параметров, и использует параметры как локальные переменные
    Код (Text):
    1. proc func arg1 arg2 arg3
    2. push ebp
    3. mov ebp, esp
    4. sub [arg2], 1  ;эта строчка убьет указатель на следующий SEH-фрейм
    5. sub [arg3], 1  ;а вот эта строчка убьет указатель на exception_handler
     
  2. gorodon

    gorodon New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2009
    Сообщения:
    301
    Могу вам назвать целый класс таких продуктов - называется "Дизассемблеры"
    (упомянутый IDA как раз к этому классу и относится) :)
     
  3. DeRekX

    DeRekX New Member

    Публикаций:
    0
    Регистрация:
    21 июл 2007
    Сообщения:
    98
    Адрес:
    Russia
    gorodon
    Задача: пройти по файлам dll, найти функцию по имени, успешно вызвать
    И не более)
     
  4. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    интересно было попробовать :) но только все равно надо знать какие аргументы функции нужны иначе обращение по нулевому адресу или 0 в качестве значения аргумента но это можно в сех завернуть и вопрос как передавать структуры по значению ну и возвращать 64 битный результат

    Код (Text):
    1. typedef int (WINAPI*MB)(HWND, LPCTSTR, LPCTSTR, UINT);
    2. typedef BOOL (WINAPI*BP)(DWORD, DWORD);
    3. typedef VOID (WINAPI*EP)(UINT);
    4.  
    5.  
    6.  
    7. #define call(addr, ...) \
    8.     syscall(addr, __VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    9.  
    10. void* __cdecl syscall(void *addr, ...)
    11. {
    12.     void *ret_val;
    13.     void *arg1, *arg2, *arg3, *arg4, *arg5, *arg6,
    14.         *arg7, *arg8, *arg9, *arg10, *arg11, *arg12;
    15.     DWORD ebp_var;
    16.     va_list va;
    17.     va_start(va, addr);
    18.     arg1 = va_arg(va, void*);
    19.     arg2 = va_arg(va, void*);
    20.     arg3 = va_arg(va, void*);
    21.     arg4 = va_arg(va, void*);
    22.     arg5 = va_arg(va, void*);
    23.     arg6 = va_arg(va, void*);
    24.     arg7 = va_arg(va, void*);
    25.     arg8 = va_arg(va, void*);
    26.     arg9 = va_arg(va, void*);
    27.     arg10 = va_arg(va, void*);
    28.     arg11 = va_arg(va, void*);
    29.     arg12 = va_arg(va, void*);
    30.     __asm
    31.     {
    32.         mov ebp_var, esp;
    33.         push arg12;
    34.         push arg11;
    35.         push arg10;
    36.         push arg9;
    37.         push arg8;
    38.         push arg7;
    39.         push arg6;
    40.         push arg5;
    41.         push arg4;
    42.         push arg3;
    43.         push arg2;
    44.         push arg1;
    45.         call addr;
    46.         mov ret_val, eax;
    47.         mov esp, ebp_var;
    48.     }
    49.     va_end(va);
    50.     return ret_val;
    51. }
    52.  
    53. int main(void)
    54. {
    55.     MB pfn = (MB)GetProcAddress(LoadLibrary("user32"), "MessageBoxA");
    56.     BP pfnBp = (BP)GetProcAddress(LoadLibrary("kernel32"), "Beep");
    57.     EP pfnEp = (EP)GetProcAddress(LoadLibrary("kernel32"), "ExitProcess");
    58.     printf("%p\n", call(pfn, 0, "test", "hello", MB_OK));
    59.     printf("%p\n", call(pfnBp, 700, 1000));
    60.     call(pfnEp, 0);
    61.     return 0;
    62. }
     
  5. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    DeRekX
    Никак не избежать. Исполнение кода может вызвать крах. Мб там у меня загрузка дрова или есчо что. Задача бред какойто. Используйте хотябы подсчёт crc или типо того, дабы знать что это нужный вам модуль, а не грузите всё подряд.
     
  6. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Clerk
    задача не бред - а типичная задача загрузки плагинов. Скажем как в ольке, смотрятся все длл в папке и вызываются функции инициализации.
    Хотя лучше было бы просто грузить все длл, а длл, если это плагин, вызывала бы функции программы.
     
  7. DeRekX

    DeRekX New Member

    Публикаций:
    0
    Регистрация:
    21 июл 2007
    Сообщения:
    98
    Адрес:
    Russia
    Преположим, что функция написана высококвалифицированными программистами, тщательно протестирована и ошибки в реализации полностью исключаются.

    Наша задача - безопасно вызвать функцию.

    Повторю, задача обеспечения безопасной работы функции не ставится.

    Читайте первый мой пост.
     
  8. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Зачем это нужно? Если ты вызываешь функцию из DLL, ты должен точно знать, какие она принимает параметры, как их принимает (конвенция вызова) и возвращаемое значение. Иначе - смысл?

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

    __try/__except твой, разумеется, не срабатывает, потому что исключение возникает при выходе из ТВОЕЙ функции, поскольку в ней нарушился стек (скорее всего), а блок try/except уже не действует.
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Great
    Не привычно от вас слышать это ;)))
     
  10. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Clerk
    а что я должен был написать ZwWaitForSingleObject или рекомендовать драйвер написать? ))
     
  11. DeRekX

    DeRekX New Member

    Публикаций:
    0
    Регистрация:
    21 июл 2007
    Сообщения:
    98
    Адрес:
    Russia
    Great
    Параметры для функции получаю из одного источника, а саму функцию из другого.

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

    Great
    Этот блок прекрасно работает на тестовом примере.

    К сожалению, по опыту пацанов этот блок не всегда хорошо работает - http://forum.vingrad.ru/forum/s/1d7.../kw-getprocaddress/view-all.html#st_30_view_0
     
  12. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    DeRekX
    Ну а если таким условиям будут удовлетворять 2-ве и более функций, то что дальше то?
    Где смысл?
     
  13. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.551
    Адрес:
    Russia
    DeRekX
    Ну вот вы и ответили на свой вопрос.
    Параметры проверяете на корректность. И имя функции тоже проверяете. И только после этого колите вашу DLL. DLL проверяете по CRC как вам подсказал Clerk.
    И все будет хорошо.
     
  14. gorodon

    gorodon New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2009
    Сообщения:
    301
    Видимо, имеется ввиду задача верификации спецификации dll-ки с кодом самой dll, т.е. проверка правильности документации, описывающей интерфейсы функций....
    Ну если дизассемблер длин вас не устраивает, то, видимо, надо колдовать со стеком, использовать нескоьлко уровней вложенности конструкций __try..... вообщем, try :)
     
  15. DeRekX

    DeRekX New Member

    Публикаций:
    0
    Регистрация:
    21 июл 2007
    Сообщения:
    98
    Адрес:
    Russia
    T800
    Далее их можно вызвать, гарантируя, что из-за несоответсвующих параметров, функция не упадёт.
    Смысл в том, чтобы функция получила те параметры, для которых она и была написана.
    Читайте мой первый пост.

    TermoSINteZ
    Подскажите, каким образом проверить корректность параметров?
    Возможен вариант, что CRC совпадёт c расчётной, а параметры будут неверными.

    gorodon
    Вы всё правильно поняли.
    Описанный блок, к сожалению, невсегда корректно работает (см. ссылку в этой теме), и в общем случае его использовать нельзя.
    Какие могут быть альтернативные варианты?
     
  16. FLASH300

    FLASH300 New Member

    Публикаций:
    0
    Регистрация:
    30 окт 2008
    Сообщения:
    72
    Если есть контроль над вызываемыми функциями то есть пара идей:

    вариант 1: ВСЕ функции адекватно проверяют и не изменяют входные параметры + соглашение __cdecl

    вариант 2: во ВСЕХ функциях в имени хранить количество параметров например MyFunc_20

    PS:Ну и конечно в обоих вариантах __try/__except куда ж без него :)
     
  17. gorodon

    gorodon New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2009
    Сообщения:
    301
    Ну, раз речь идет о проведении автоматизированного тестирования (и/или верификации) то лучший вариант - посдмотреть, как это делают "корифеи":
    HP WinRunner, HP QuickTestProfessional;
    IBM Robot, IBM Functional Tester

    Почему не срабатывает иногда конструкция __try/__except - Clerk, расскажите нам, пожалуйста, об этом?
    Предположу, что при нарушении указателя на стек(?). Один из вариантов обхода проблемы был озвучен - организовать взаимодействие 2 процессов: один(ведущий) получает от второго(ведомого) информацию о результатах теста очередной функции и фиксирует информацию, если ведомый процесс падает, то ведущий процесс фиксирует результат падения при тестировании функции, перезапускает ведомый процесс с указанием начать тестирование со следующей функции...
     
  18. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Бред. Зачем создавать новый процесс, чтобы решить проблему со стеком? Достаточно создать новый стек, или поток.
     
  19. gorodon

    gorodon New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2009
    Сообщения:
    301
    GoldFinch
    Сначала надо правильно обработать возникшее исключение, а потом уже создавать новый стек, поток...
    Автор говорит, что конструкция __try/__except не справляется с этим - предложите универсальную конструкцию на "все случаи жизни" - вот в чем вопрос, собственно...

    DeRekX
    При тестировании обычно используют несколько групп тестов, в том числе предельные условия и запредельные условия. При этом код функции может повредить не только стек, но и любую информацию в процессе (в том числе ваш код)... ну это еще один довод в пользу двух процессов.
     
  20. bohdant

    bohdant New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2008
    Сообщения:
    22
    Я все таки непонял, какое именно применение данной защиты.
    Если просто нужно сделать возможность подключать плагины, при этом обеспечивать надежность системы, то я бы предложил вам использовать отладочную информацию (за неимением рифлекшена).

    Т.е. плагин должен иметь отладочную информацию, а из нее можно взять инфу о параметрах их типах и т.д.