2016-10-29 1 views
1

Ich versuche, ein Thunk mit C++ und Win32-API zu erstellen, die diesen Zeiger statische Elementfunktion bindet, so dass ich diese Funktion als Rückruf verwenden kann.Wie binden Sie diesen Zeiger an statische Member-Funktion mit Thunk in C++

Jetzt habe ich eine funktionierende Thunk für x64, es funktioniert, indem Sie den Wert von R9-Register (entspricht 4. Parameter einer Funktion) an die Adresse dieses Zeigers.

Aber ich habe ein Problem mit Thunk für x86, ich habe versucht, den Wert von [esp + 10h] (entspricht auch der 4. Parameter).

Hier ist der Thunk:

#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) 

Und hier ist die Klasse, die die Thunk verwendet:

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); 
    } 
}; 

Benutzer Und hier ist der Rückruf:

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

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

Allerdings, wenn ich das lief Programm, es gab mir den Fehler:

Fehler bei der Laufzeitprüfung # 0 - Der Wert von ESP wurde bei einem Funktionsaufruf nicht ordnungsgemäß gespeichert. Dies ist normalerweise ein Ergebnis des Aufrufs einer Funktion, die mit einer Aufrufkonvention deklariert wurde, mit einem Funktionszeiger, der mit einer anderen Aufrufkonvention deklariert wurde.

Wie kann ich dieses Problem lösen?
Danke.

+1

Bitte geben Sie eine [MCVE]. – IInspectable

Antwort

0

Dieser Fehler wird durch die Konvention stdcall verursacht. Anrufer erwartet, dass Angerufener 3 Argumente im Wert von Stack bereinigt, während callee (Ihr Callback) 4 Argumente aufräumt, die bewirken, dass esp an den falschen Ort geht. Sie können auch nicht einfach in esp+10h schreiben, da der Aufrufer es möglicherweise verwendet.

Jetzt hier ist alternative Idee: können Sie nicht gerade setzen ecx zu this und Memberfunktion direkt aufrufen (sofern es stdcall Konvention verwendet)?

UPDATE: Oder Sie können This als ein erstes Argument zu Ihrer statischen Member-Funktion, so dass es am nächsten zu einem Stack-Top; thunk kann dann den Stapel so ändern, dass er wie ein stdcall Funktionsaufruf mit 4 Argumenten aussieht. Es wird ungefähr so ​​aussehen:

pop eax 
push This 
push eax 
jmp func 
+0

'stdcall' verwendet keine Register, also nein, Sie können den 'this'-Zeiger nicht in' ECX' setzen, er muss als erster Parameter auf dem Stack übergeben werden. Sie denken stattdessen an 'thiscall', was 'this' in' ECX' setzt (auch 'thiscall' ist nicht portierbar über Compiler, aber' stdcall' ist) –

+0

Der ganze Punkt der thunk/static member function combo ist hier Aufruf nicht-statische Member-Funktion, die 'thiscall' Konvention verwendet - mein Vorschlag war es, diese nicht-statische Member-Funktion direkt aufzurufen. Fairer Punkt auf 'thiscall' Portabilität; meine Bemerkung über 'stdcall' war darüber auch. Ich merke jetzt, dass ich es nicht richtig formuliert habe; Mit "stdcall" meinte ich "thiscall", das genau wie "stdcall" funktioniert, außer "this" in "ecx". Das kann jedoch durch '__thiscall' gemildert werden, was MSVC/gcc dazu zwingen sollte, genau das zu tun. –

+0

@ AndreyTurkin Ich kann das nicht als erstes Argument verwenden, sonst würde die 'callback_user'-Funktion nicht mehr funktionieren – weedguy

Verwandte Themen