Как в сях переопределить вызов stdcall функций?

Тема в разделе "LANGS.C", создана пользователем intel_x128, 19 сен 2009.

  1. intel_x128

    intel_x128 New Member

    Публикаций:
    0
    Регистрация:
    17 май 2009
    Сообщения:
    345
    Нужно, чтобы функции вызывались вот таким образом:

    т.е. сохранялись все регистры, кроме еах.
    Можно ли как-то это сделать, не писав надстройку над каждой stdcall функцией?

    pushad
    push 0
    call [GetModuleHandleA]
    mov [esp+28], eax
    popad
     
  2. Forever

    Forever Виталий

    Публикаций:
    0
    Регистрация:
    12 апр 2008
    Сообщения:
    244
    Код (Text):
    1. #define CallFunction( Function, ... ) {   \
    2.     __asm pushad                               \
    3.     Function( __VA_ARGS__ );              \
    4.     __asm popad                                \
    5. }
    Правда данный код не пойдет в старых компиляторах. Например в VS2003 выдаст ошибку, что макроса __VA_ARGS__ нету. В VS2005, VS2008 и WDK вроде как работает.
     
  3. ohne

    ohne New Member

    Публикаций:
    0
    Регистрация:
    28 фев 2009
    Сообщения:
    431
    жесть + потеря intellisense
     
  4. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Код (Text):
    1. class registers_keeper
    2. {
    3. public:
    4.  
    5.     __forceinline registers_keeper() { __asm pushad }
    6.     __forceinline ~registers_keeper() { __asm popad }
    7. };
    8.  
    9. #define keep_registers registers_keeper keeper
    10.  
    11. void foo()
    12. {
    13.     keep_registers;
    14.  
    15.     // Бла бла бла
    16. }
    Бугага, да.
     
  5. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    еах надо сохранять. если потоков будет только 1, то лучше в глобальной/статической переменной

    void pusha(){
    static int _eax_;
    __asm{
    mov _eax_,eax ;
    pop eax
    pushad
    push eax
    mov eax,_eax_ ; это если в вызываемую функу надо передать текущий еах
    }
    }

    void popa(){
    static int _eax_;
    static void* r;
    __asm{
    pop r
    mov _eax_,eax
    popad
    mov eax,_eax_
    push r
    }
    }

    не будет работать или может глючить на фреймофых компилерах (правда, из таких знаю только 1, что счас есть. и он не распространен)
    ну и только в один поток
     
  6. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    _basmp_

    И вылетим в ж*пу, поскольку при выходе в стеке не адрес возврата, а сохраненные регистры :)
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    pop eax - вынимает адрес возврата
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    n0name

    Верно. Это я уже туплю под утро))
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    intel_x128
    Можно сделать вместо ручного сохранения регистров автоматически более кошерно. Для этого следует обработать сепшен и сохранить часть контекста.
    1. Сделать не доступной страницу с IAT, прежде перенеся её в буфер. Но тогда следует резервировать в модуле свободное место, ибо код не должен находится в такой странице. Далее при обработке сепшена по доступу к переходнику функции сохранить контекст и выполнить переход вручную, загрузив Eip из копии таблицы.
    2. Лучше чем 1. Модификация IAT, будет рассмотрена как грубый перехват. Загрузка ссылок на наш код, который сохранит контекст и выполнит передачу управления на оригинальный из таблицы.
    3. Самотрассировка. Делаем что угодно с контекстом для каждой инструкции. Медленно и может вызвать проблемы.
    -
    Контекст храним в TEB, точнее указатель на буфер с контекстом.
     
  10. Dukales

    Dukales New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2009
    Сообщения:
    199
    Такой макрос можно использовать как Rvalue и он делает сабж (у меня Borland C++ Builder и там есть переменные _EAX, _EDX, _EBX... и макрос __emit__ и, скорее всего, "не-Borland C++ Builder" будет ущербнее =))
    Код (Text):
    1. #define safe_invoke(f) (__emit__(0x83, 0xEC, 0x04, 0x89, 0xE0, 0x60, 0x50), f, __emit__(0x5F, 0x89, 0x07, 0x61, 0x58), _EAX)
    Код
    Код (Text):
    1. DWORD x = safe_invoke(GetModuleHandleA(0));
    он превращает примерно в следующий
    Код (Text):
    1. DWORD x;
    2. asm
    3. {
    4.  sub ESP, 4            // 0x83, 0xEC, 0x04
    5.  mov EAX, ESP          // 0x89, 0xE0
    6.  pushad                // 0x60
    7.  push EAX              // 0x50
    8. }
    9. GetModuleHandleA(0);
    10. asm
    11. {
    12.  pop EDI               // 0x5F
    13.  mov [EDI], EAX        // 0x89, 0x07
    14.  popad                 // 0x61
    15.  pop EAX               // 0x58
    16. }
    17. x = _EAX;
     
  11. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    функции нужно как __declspec(naked) оформлять, иначе "мусор" на входе и выходе из функции будет
     
  12. intel_x128

    intel_x128 New Member

    Публикаций:
    0
    Регистрация:
    17 май 2009
    Сообщения:
    345
    Clerk
    Спасибо. Наверное самый кошерный вариант. Похучил иат, перебив указатели на свой обработчик.


    PS: По поводу самотрасирровки. Какими апи это все реализуется и где можно прочитать более подробно?
     
  13. Dukales

    Dukales New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2009
    Сообщения:
    199
    Clerk
    А по скорости каково это всё? Какие приемущества над "надстройками"?
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    intel_x128
    Апи никакие не нужны. Единственное это установка векторного обработчика исключений RtlAddVectoredExceptionHandler(). Но есть проблема с загрузкой параметров. Например загрузка ссылки как для функции: lea eax,Var1/push eax, в таком случае следует только средствами компилятора реализовать.
    Dukales
    Не вижу смысла сохранять Ecx и Edx. Касательно скорости - об этом можно не беспокоится, так как не ядерный код. Вы ведь не думаете об задержках связанных с обработкой прерывний и планированием.
     
  15. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Dukales
    взгляните на прагму аух опенваткома ради интереса. она, кроме всего остального позволяет полностью настроить телодвижения при вызове и выходе, способы передачи, мангленье и дофига еще чего.

    Asterix
    в принципе, функция то void(*)(void). так что, по идее, не должно автоматом сгенерить ничего кроме рет. а __declspec(naked) это самодеятельность мс, какового требования в постановке небыло. если уж и мутить с вызовами и нестандартными прагмами, то я, как и писал выше, таки выбрал бы ов, который и позволяет больше и учитет без лишнего рукоприкладства.

    Dukales
    ексепшены надежнее, тк чинят и изменение есп, но медленнее, причем здорово.
    иат - ограничено только статик импортом безо всяких кривохитростей. кроме того ручная правка иат - само по себе кривохитрость.
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    _basmp_
    Уточните: "но медленнее, причем здорово при наличие отладочного порта."
    Для себя отладчик не нужен, достаточно быстро сепшены обрабатываются вы не заметите визуально задержек.
     
  17. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Clerk
    так не написано для чего эта задача нужна. то, что все несется в регистрах, и только пушается/попается не исключает выжимки по быстродействию. хотя для скорости вызов каждой лишней функции - нож в спину. переход. даже 2
     
  18. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    _basmp_
    по идее, а на практике я сталкивался с чудесами
     
  19. intel_x128

    intel_x128 New Member

    Публикаций:
    0
    Регистрация:
    17 май 2009
    Сообщения:
    345
    Есть модуль, экспортирующий 42 функции. Написан на асме. Размер около 2х метров.
    Работает в целом правильно за редким исключением. Не сохраняются edi, esi, ebx. В первоначальном проекте, я так понял, это и не нужно было.


    Если регистры сохранять - все работает чудесно.


    В последствии реализую свой, но пока, за неимением альтернативы, буду юзать этот.
     
  20. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    intel_x128
    edi и esi сохранять обязательно, иначе чудесных глюков вам обеспечено. остальное - по желанию. само апи остальное лихо не сохраняет

    Asterix
    эге. может заголовки прилепить или проинлайнить. надо посмотреть, что компилер слепит. ессно