winapi — Как связать этот указатель со статической функцией-членом, используя thunk в Stack Overflow

Я пытаюсь создать thunk с C ++ и Win32 API, который привязывает этот указатель к статической функции-члену, поэтому я могу использовать эту функцию в качестве обратного вызова.

Теперь у меня есть рабочий thunk для x64, он работает, устанавливая значение регистра r9 (соответствует 4-му параметру функции) по адресу этого указателя.

Но у меня проблема с thunk для x86, я пытался установить значение [esp + 10h] (также соответствует 4-му параметру).

Вот этот звук:

#pragma pack(push, 1)
struct THUNK {
DWORD mov;               // mov dword ptr[esp+10h], pThis
DWORD pThis;
BYTE  jmp;               // jmp relproc
DWORD relproc;
}
#pragma pack(pop)

А вот класс, который использует thunk:

class foo {
void callback_impl(int a, int b, int c) {
...
}
static void __stdcall callback(int a, int b, int c, foo *This) {
This->callback_impl(a, b, c);
}
public:
THUNK *thunk;
foo() {
thunk = (THUNK*)VirtualAlloc(NULL, sizeof(THUNK), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
thunk->mov = 0x102444C7;
thunk->pThis = (DWORD)this;
thunk->jmp = 0xe9;
thunk->relproc = DWORD((INT_PTR)&foo::callback - ((INT_PTR)thunk + sizeof(THUNK)));
FlushInstructionCache(GetCurrentProcess(), this, sizeof(THUNK));
}
~foo() {
VirtualFree(thunk, sizeof(THUNK), MEM_DECOMMIT);
}
};

И вот пользователь обратного вызова:

void callback_user(void(__stdcall *callback)(int, int, int)) {
...
}

// foo f;
// callback_user((void(__stdcall*)(int, int, int))f.thunk);

Однако, когда я запустил программу, это дало мне ошибку:

Ошибка проверки времени выполнения # 0 — значение ESP не было должным образом сохранено при вызове функции. Это обычно является результатом вызова функции, объявленной с одним соглашением о вызовах с указателем функции, объявленным с другим соглашением о вызовах.

Как я могу решить эту проблему?
Благодарю.

1

Решение

Эта ошибка вызвана соглашением stdcall. Вызывающий ожидает, что вызываемый объект очистит стек из 3 аргументов, в то время как вызываемый объект (ваш обратный вызов) очистит 4 аргумента, заставляя esp перейти в неправильное место. Также вы не можете просто написать esp+10h потому что вызывающий может использовать его.

Теперь вот альтернативная идея: вы не можете просто установить ecx в this и вызвать функцию-член напрямую (при условии, что она использует соглашение stdcall)?

ОБНОВЛЕНИЕ: Или вы можете поставить This в качестве первого аргумента вашей статической функции-члена, чтобы она была ближе к вершине стека; затем можно изменить стек, чтобы он выглядел как stdcall вызов функции с 4 аргументами. Это будет выглядеть примерно так

pop eax
push This
push eax
jmp func
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]