C関数を期待するレガシーAPIにメンバー関数を使用できるように、「サンキング」を使用しようとしています。これと同様のソリューションを使用しようとしています。これはこれまでの私のサンク構造です:
struct Thunk
{
byte mov; // ↓
uint value; // mov esp, 'value' <-- replace the return address with 'this' (since this thunk was called with 'call', we can replace the 'pushed' return address with 'this')
byte call; // ↓
int offset; // call 'offset' <-- we want to return here for ESP alignment, so we use call instead of 'jmp'
byte sub; // ↓
byte esp; // ↓
byte num; // sub esp, 4 <-- pop the 'this' pointer from the stack
//perhaps I should use 'ret' here as well/instead?
} __attribute__((packed));
次のコードは、このサンク構造を使用する私のテストです (ただし、まだ機能していません)。
#include <iostream>
#include <sys/mman.h>
#include <cstdio>
typedef unsigned char byte;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
#include "thunk.h"
template<typename Target, typename Source>
inline Target brute_cast(const Source s)
{
static_assert(sizeof(Source) == sizeof(Target));
union { Target t; Source s; } u;
u.s = s;
return u.t;
}
void Callback(void (*cb)(int, int))
{
std::cout << "Calling...\n";
cb(34, 71);
std::cout << "Called!\n";
}
struct Test
{
int m_x = 15;
void Hi(int x, int y)
{
printf("X: %d | Y: %d | M: %d\n", x, y, m_x);
}
};
int main(int argc, char * argv[])
{
std::cout << "Begin Execution...\n";
Test test;
Thunk * thunk = static_cast<Thunk*>(mmap(nullptr, sizeof(Thunk),
PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0));
thunk->mov = 0xBC; // mov esp
thunk->value = reinterpret_cast<uint>(&test);
thunk->call = 0xE8; // call
thunk->offset = brute_cast<uint>(&Test::Hi) - reinterpret_cast<uint>(thunk);
thunk->offset -= 10; // Adjust the relative call
thunk->sub = 0x83; // sub
thunk->esp = 0xEC; // esp
thunk->num = 0x04; // 'num'
// Call the function
Callback(reinterpret_cast<void (*)(int, int)>(thunk));
std::cout << "End execution\n";
}
そのコードを使用すると; 関数内でセグメンテーション違反が発生しTest::Hi
ます。理由は明らかですが (GDB でスタックを分析すると)、これを修正する方法がわかりません。スタックが正しく配置されていません。
x
引数にはガベージが含まれていますが、y
引数にはthis
ポインターが含まれています (Thunk
コードを参照)。これは、スタックが 8 バイトずれていることを意味しますが、なぜそうなのかはまだわかりません。なぜこれが起こっているのか誰にもわかりますか?x
とをそれぞれy
含む必要が34
あり71
ます。
注: これがすべてのシナリオ (MI や VC++ の thiscall 規則など) で機能するわけではないことは承知していますが、この機能を利用できるかどうかを確認したいと考えています。
編集:明らかに、静的関数を使用できることも知っていますが、これはもっと難しいことだと思います...