Есть адрес виртуальной функции. Как вызвать функцию?

Тема в разделе "LANGS.C", создана пользователем Ezrah, 28 сен 2011.

  1. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Есть RAW адрес виртуальной функции Y некоторого класса X. Как вызвать X::Y?
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Объявить указатель на метод, и вызывать. ^)
     
  3. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    Y не может быть вызвана "вне" объекта. Т.е. придётся либо создать экземпляр класса X и тогда всё просто, если объект создать неполучается, то и Y вызвать неполучится в общем случае. Если функция Y никак не взаимодействует с X, то можно просто вызвать Y как обычную функцию(не забыв что это thiscall).
     
  4. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    А все компиляторы одинаково формируют методы? или все же общего стандарта нет?
     
  5. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Не всё так просто.
    // By default, C++ member functions use the __thiscall calling convention.
    // In order to Detour a member function, both the trampoline and the detour
    // must have exactly the same calling convention as the target function.
    // Unfortunately, the VC compiler does not support a __thiscall, so the only
    // way to create legal detour and trampoline functions is by making them
    // class members of a "detour" class.
    //
    // In addition, C++ does not support converting a pointer to a member
    // function to an arbitrary pointer. To get a raw pointer, the address of
    // the member function must be moved into a temporrary member-function
    // pointer, then passed by taking it's address, then de-referencing it.
    // Fortunately, the compiler will optimize the code to remove the extra
    // pointer operations.
    //
    // If X::Target is a virtual function, the following code will *NOT* work
    // because &X::Target is the address of a thunk that does a virtual call,
    // not the real address of the X::Target. You can get the real address
    // of X::Target by looking directly in the VTBL for class X, but there
    // is no legal way to 1) get the address of X's VTBL or 2) get the offset
    // of ::Target within that VTBL. You can of course, figure these out for
    // a particular class and function, but there is no general way to do so.


    Код (Text):
    1. //////////////////////////////////////////////////////////////// Target Class.
    2. //
    3. class CMember
    4. {
    5.   public:
    6.     void Target(void);
    7. };
    8.  
    9. void CMember::Target(void)
    10. {
    11.     printf("  CMember::Target!   (this:%p)\n", this);
    12. }
    13.  
    14. //////////////////////////////////////////////////////////////// Detour Class.
    15. //
    16. class CDetour /* add ": public CMember" to enable access to member variables... */
    17. {
    18.   public:
    19.     void Mine_Target(void);
    20.     static void (CDetour::* Real_Target)(void);
    21.  
    22.     // Class shouldn't have any member variables or virtual functions.
    23. };
    24.  
    25. void CDetour::Mine_Target(void)
    26. {
    27.     printf("  CDetour::Mine_Target! (this:%p)\n", this);
    28.     (this->*Real_Target)();
    29. }
    30.  
    31. void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))&CMember::Target;
    Вот меня интересует как можно то же самое провернуть для частного случая без извращений с vftbl.
     
  6. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Пусть с использованием ассемблерных вставок
     
  7. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Если это MS VC то соглашение будет thiscall, первым в стеке пойдет указатель на экземпляр класса. Его придется создать. По крайней мере, реализовать те поля, которые будут обрабатываться в методе.
     
  8. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Y на самом деле никак не взаимодействует с X, но скастить число к указателю на __thisall не получается.
     
  9. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Если бы он передавался через стек всё было бы элементарно. Объявляем как __stdcall и первым параметром передаём указатель на объект класса. Но он передаётся через регистр ecx.
     
  10. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    __asm {
    mov ecx, MyClass
    push arg1
    push arg2
    mov edx, MyMethod
    call edx}
     
  11. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Можно задать вопрос по-другому. Как переменной-члену класса, являющейся указателем на виртуальный метод класса, присвоить константу без особых извращений.
     
  12. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Squash
    В принципе, годно, но теряется наглядность. Оставлю на крайний случай, если ничего лучше придумать не получится.
    Спасибо.
     
  13. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Указатели на методы в виртуальной таблице задаются на этапе компиляции и находятся в неизменяемой секции виртуальной памяти.
    Без извращений не получится.
    Для наглядности можно ассемблерную вставку спрятать в метод вашего класса.
     
  14. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Как-то так :)
    Код (Text):
    1. typedef struct _MyClass
    2. {
    3.     virtual void MyMethod1 (void);
    4.     virtual void MyMethod2 (void);
    5.  
    6. } MyClass;
    7. ...
    8.  
    9.     struct
    10.     {
    11.         DWORD pMethod1;
    12.         DWORD pMethod2;
    13.     } myvtbl;
    14.  
    15.     myvtbl.pMethod1 = 0x34562389;
    16.     myvtbl.pMethod2 = 0x45678545;
    17.  
    18.     MyClass* pmc = (MyClass*)new DWORD[1];
    19.     *(void**)pmc = (void*)(&myvtbl);
    20.  
    21.     (pmc)->MyMethod2 ();
    Почти без извращений.
     
  15. Psionic

    Psionic Member

    Публикаций:
    0
    Регистрация:
    25 сен 2008
    Сообщения:
    156
    Squash
    OMG
    А не слишком-ли развратно?
    Что мешает написать так:
    Код (Text):
    1. virtual int method(int arg1, int arg2)
    2. {
    3. void* _p=(void*)this;
    4. __asm
    5. {
    6. push arg1
    7. push arg2
    8. mov ecx, _p
    9. call youradressfunk
    10. mov _p, eax
    11. }
    12. return (int)_p;
    13. }
     
  16. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Ничто не мешает. См. выше
     
  17. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Дело в том, что класс не мой. Объект класса находится в другом процессе, к которому я подгружаю DLL. Инжект сплайсингом с помощью сторонней библиотеки (Microsoft Detours). Указатель на реальную функцию сохраняется в глобальной переменной. Чтобы вызвать ее из функции-хука, нужно правильно объявить указатель. В этом проблема. Можно вызвать ее с помощью вставки, но хотелось бы этого он возможности избежать.
    ЗЫ
    У каждого своя мера извращенности :)
     
  18. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Я такие штуки решаю через union, все всегда работало - делаешь что-то типа

    union Convert
    {
    void* Raw;
    PointerToMemberType MemberPtr;
    };

    не по стандарту, но на вижле стабильно работает, еще можно для надежности статик ассерт поставить на то что размеры совпадают
     
  19. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    а блин, там виртуальная функция, тогда так не покатит
     
  20. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ezrah
    Напишите фейковый класс и используйте его методы.