Вызов функции по адресу

#c #function-pointers

#c #указатели на функции

Вопрос:

Я пытаюсь изучить несколько различных методов вызова функций по адресу.

 bool gl_draw_text(uint x, uint y, uint color, uint alpha, char *fmt);
  

Я вызываю именно эту функцию. В настоящее время я вызываю ее следующим образом. (И это работает нормально.)

 static void glDrawText(char* text, int x, int y)
{
DWORD func = 0x10057970;

__asm
{
    push text
    push 255
    push 14
    push y
    push x
    call dword ptr [func]
    }
}
  

Метод, который я хочу использовать, — это этот.

 void Hack()
{
    bool (draw*)(uint, uint, uint, uint, char*);
    draw = 0x10057970;
    (draw)(20, 20, 14, 255, "Text");
}
  

Но я не знаю, как правильно передать адрес функции, чтобы она работала компилировалась. ?

Существует также метод, который использует виртуальную функцию, мне любопытно, как работает и этот метод. (Я также могу использовать MS Detours для подключения, а затем вызвать функцию подобным образом, как этот метод работает за кулисами, если вы знаете.)

Итак, чтобы внести ясность, я просто спрашиваю о различных методах выполнения этой задачи, но перечислил несколько, которые мне интересны после прочтения о них, и т.д.

Комментарии:

1. Это не работает или не компилируется? Как правило, фактический адрес функции изменится при перекомпиляции или даже при повторном запуске той же программы.

2. @Neil, это не волшебство, это реальный адрес реальной функции. @aramadia, это, как я уже сказал, проблема с кастингом.

3. @TheMonster Я хочу сказать, откуда вы знаете, что это адрес функции?

4. Потому что я делаю? Не уверен, почему это важно, вы должны просто поверить мне на слово. Но, если вам действительно нужно знать. Я знаю, что это адрес, потому что я взламываю игру, эта функция является частью другой библиотеки DLL, взламывающей ту же игру, я знаю человека, который написал упомянутую другую библиотеку DLL, они сказали мне смещение, где я мог его найти, я отладил .exe, проверил и, конечно же, там это было.

5. @TheMonster Почему я должен верить вам на слово? И DLL можно довольно легко загрузить по другому адресу, в зависимости от множества вещей.

Ответ №1:

Вы всегда можете привести:

 typedef bool (*funcptr)(uint, uint, uint, uint, char*);

funcptr draw = (funcptr)0x10057970;
  

или в C :

 funcptr draw = reinterpret_cast<funcptr>(0x10057970);
  

Однако это совершенно неопределенное поведение.

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

Комментарии:

1. Ну, адрес существует в .exe, который я взламываю, я должен был упомянуть об этом. (На самом деле это часть другой библиотеки DLL, она должна быть добавлена в таблицу экспорта в какой-то момент в будущем, но пока я должен получить к ней доступ следующим образом. Или написать свой собственный, а GL текст — это небольшая боль, чтобы сделать самому.) Спасибо, кстати, я попробую это. 🙂

2. Вы непреднамеренно приняли нетрадиционный синтаксис Theonster, используя (funcptr*) вместо (*funcptr) . Я надеюсь, что используемый вами компилятор не настолько нетрадиционен, чтобы принять это!

3. Я видел asterisk (звездочка недействительности) и т.д. Но не то, что вы предлагаете, также, как я упоминал, я где-то читал об этом методе, но мне было любопытно, как заставить его работать с адресом. (У меня есть свои причины, и это должно работать нормально, эта функция никуда не денется, поверьте мне, она существует уже несколько дней.)

4. Я действительно не понимаю, почему за это проголосовали, поскольку это на самом деле не решает вопрос и, по общему признанию, вызывает UB .

5. @Neil: Все ваши негативные комментарии просто вдохновили меня тоже проголосовать за это. Что тебя здесь гложет?

Ответ №2:

Этот код компилируется (см. http://ideone.com/celq1 ):

 typedef unsigned int uint ;
int main()
{
    bool (*draw)(uint, uint, uint, uint, const char*);
    draw = reinterpret_cast<bool (*)(uint, uint, uint, uint, const char*)>(0x10057970);
    draw(20, 20, 14, 255, "Text");
}
  

Но, конечно, она не запускается 🙂
PS Я изменил char* на const char* , чтобы избавиться от предупреждения компилятора. Похоже, const char* это то, что вы хотите здесь, но это не существенно для идеи.

Отредактировано, чтобы добавить: На самом деле, даже это компилируется, если вы хотите произвести впечатление на своих друзей:

 typedef unsigned int uint ;
int main()
{
    reinterpret_cast<bool (*)(uint, uint, uint, uint, const char*)>(0x10057970)
      (20, 20, 14, 255, "Text");
}
  

Комментарии:

1. Спасибо, это было то, что я искал. 🙂 -Компилируется и работает, как ожидалось.