2016-10-29 4 views
1

이 포인터를 정적 멤버 함수에 바인딩하는 C++ 및 Win32 API를 사용하여 썽크를 만들려고합니다. 콜백 함수로 사용할 수 있습니다.C++에서 썽크를 사용하여 정적 멤버 함수에이 포인터를 바인딩하는 방법

이제는 x64에서 작동하는 썽크가 있습니다.이 포인터의 주소에 r9 레지스터 (함수의 4 번째 매개 변수에 해당) 값을 설정하면 작동합니다.

하지만 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) 

그리고 여기 썽크 사용하는 클래스의 :

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

[mcve]를 입력하십시오. – IInspectable

답변

0

이 오류는 stdcall 규칙에 의해 발생합니다. Caller는 호출 수신자가 4 개의 인수를 정리하는 동안 eslept가 잘못된 위치로 이동하는 동안 callee가 3 개의 인수를 정리할 것을 기대합니다. 또한 발신자가 사용하고 있기 때문에 esp+10h에 쓸 수 없습니다.

이제 대체 아이디어가 있습니다. ecxthis으로 설정하고 멤버 함수를 직접 호출 할 수는 없습니까? (stdcall 규칙을 사용하는 경우)?

업데이트 : 또는 This을 정적 멤버 함수의 첫 번째 인수로 넣을 수 있으므로 스택 위쪽에 가장 가깝습니다. thunk는 스택을 수정하여 4 개의 인수가있는 stdcall 함수 호출처럼 보이게 할 수 있습니다. 모양은 다음과 같습니다.

pop eax 
push This 
push eax 
jmp func 
+0

'stdcall'은 레지스터를 사용하지 않으므로,'this' 포인터를'ECX'에 놓을 수 없습니다. 첫 번째 매개 변수로 스택에 전달되어야합니다. ECX에'this '를 넣는'thiscall'을 생각하고 있습니다 (또한'thiscall'은 컴파일러에서 이식 할 수 없지만'stdcall'은 –

+0

입니다) 여기에 썽크/정적 멤버 함수 콤보 포인트가 있습니다 'thiscall' 규칙을 사용하는 비 정적 멤버 함수를 호출하십시오. 제 제안은 비 정적 멤버 함수를 직접 호출하려고 시도하는 것이 었습니다. 'thiscall' 이식성에 대한 공정한 점; 'stdcall '에 대한 나의 발언도 그와 관련이있다. 나는 그것을 올바르게 무시하지 않았 음을 알았다. 'stdcall'은 "ecx"에서'this'를 제외하고는'stdcall'과 똑같이 동작하는''thiscall '을 의미하지만, MSVC/gcc가 정확히 그렇게하도록하는'__thiscall'을 사용함으로써 완화 될 수 있습니다 –

+0

@ AndreyTurkin 나는 이것을 callback_user 함수가 더 이상 작동하지 않기 때문에 첫 번째 인자로 넣을 수 없다. – weedguy

관련 문제