WEB开发网
开发学院软件开发VC 通用 Thunk 阅读

通用 Thunk

 2008-05-25 21:39:20 来源:WEB开发网   
核心提示: 2.转移指令的目的地许多转移指令的目的地使用“到源的偏移量”来表示比如:当CPU 执行到0xFF000000 处的指令时, 指令像这个样子:0xFF000000 : 0xE9 0x33 0x55 0x77 0x990xFF000005 : ...0xE9 是一个 J

2.转移指令的目的地

许多转移指令的目的地使用“到源的偏移量”来表示

比如:当CPU 执行到0xFF000000 处的指令时, 指令像这个样子:0xFF000000 : 0xE9 0x33 0x55 0x77 0x99
0xFF000005 : ...

0xE9 是一个 JMP 指令,紧接着的4字节将被解释为偏移

offset = 0x99775533 (在Intel x86 机器上,低字节存储在低地址上) = -1720232653

源 (src) = 0xFF000000 (JMP指令的地址) = 4278190080

目的地 (dst) = src+offset+5 (JMP占1字节,偏移占4字节) = 4278190080 – 1720232653 +5 = 2557957432 = 0x98775538

所以在指令 “ JMP -1720232653 “ 之后,下一条被执行的指令将在

0x98775538 : ...

基于这点,我们可以实现2个方法:

void SetTransterDST(
void *src  /* the address of transfer instruction*/
,int dst   /* the destination*/ ) {
  unsigned char *op = static_cast<unsigned char *>(src);
  switch (*op++) {
  case 0xE8:  // CALL offset (dword)
  case 0xE9:  // JMP offset (dword)
    {
      int *offset = reinterpret<int*>(op);
      *offset = dst – reinterpret<int>(src) - sizeof(*op)*1 – sizeof(int);
    }
    break;
  case 0xEB:   // JMP offset (byte)
    ...
    break;
  case ...:
    ...
    break;
  default :
    assert(!”not complete!”);
  }
}
int GetTransnferDST(const void *src) {
  const unsigned char *op = static_cast< const unsigned char *>(src);
  switch (*op++) {
  case 0xE8:   //CALL offset (dword)
  case 0xE9:   //JMP offset (dword)
    {
      const int *offset = reinterpret_cast<const int*>(op);
      return *offset + PointerToInt32(src) + sizeof(*op) +sizeof(int);
    }
    break;
  case 0xEB:   // JMP offset(byte)
      ...
    break;
  case ...:
      ...
    break;
  default:
    assert(!”not complete!”);
    break;
  }
  return 0;
}
  更多详细信息 见 ThunkBase.cpp 3.栈的生长在Win32平台下,栈朝着低地址生长。也就是说,当栈增加N ESP就减少N,反之亦然。我们来设计这个类class ThisToStd
{
public:
ThisToStd(const void *Obj = 0,int memFunc = 0);
const void *Attach(const void *newObj);
int Attach(int newMemFunc);
private:
#pragma pack( push , 1) // 强制编译器使用1字节长度对齐结构
unsigned char MOV_ECX;
const void *m_this;
unsigned char JMP;
const int m_memFunc;
#pragma pack( pop ) // 恢复对齐
};
ThisToStd:: ThisToStd(const void *Obj,int memFunc)
: MOV_ECX(0xB9),JMP(0xE9) {
 Attach(Obj); // 设置this指针
Attach(memFunc); // 设置成员函数地址(使用偏移)
}
const void* ThisToStd::Attach(const void *newObj) {
 const void *oldObj = m_this;
 m_this = newObj;
 return oldObj;
}
int ThisToStd::Attach(int newMemFunc) {
 int oldMemFunc = GetTransferDST(&JMP);
SetTransferDST(&JMP,newMemFunc);
return oldMemFunc;
}
我们以如下方式使用这个类 :typedef void ( __stdcall * fun1)(int);
class C { public : void __thiscall fun1(int){} };
C obj;
ThisToStd thunk;
thunk.Attach(&obj); // 假设 &obj = OBJ_ADD
int memFunc = PointerToInt32(&C::fun1); //假设memFunc = MF_ADD
thunk.Attach(memFunc); // thunk.m_memFunc 将被设置为MF_ADD – (&t.JMP)-5
fun1 fun = reinterpret_cast<fun1>(&thunk); //假设 &thunk = T_ADD
fun(1212); // 与 obj.fun(1212) 有同样效果
它是如何工作的,当CPU执行到 fun(1212); 机器码如下:PUSH 1212;
CALL DWORD PTR [fun];
0x50000 : … ; 假设 RET_ADD = 0x50000
// CALL DOWRD PTR [fun] 与CALL(0xE8) offset(dword) 不同
//我们只需要知道: 它将RET_ADD压栈,然后跳转到T_ADD

上一页  1 2 3 4 5 6 7 8 9  下一页

Tags:通用 Thunk

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接