如何在x64中创建thunk?

时间:2015-09-05 13:38:19

标签: c assembly 32bit-64bit

我发现很好example how to create thunk for closure,但它是32位版本:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

struct env {
  int x;
};

struct __attribute__((packed)) thunk {
  unsigned char push;
  struct env * env_addr;
  unsigned char call;
  signed long call_offset;
  unsigned char add_esp[3];
  unsigned char ret;
};

struct thunk default_thunk = {0x68, 0, 0xe8, 0, {0x83, 0xc4, 0x04}, 0xc3};

typedef void (* cfunc)();

struct thunk * make_thunk(struct env * env, void * code)
{
  struct thunk * thunk = (struct thunk *)mmap(0,sizeof(struct thunk), PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  *thunk = default_thunk;
  thunk->env_addr = env;
  thunk->call_offset = code - (void *)&thunk->add_esp[0]; // Pretty!                                                                               
  mprotect(thunk,sizeof(struct thunk), PROT_EXEC);
  return thunk;
}


void block(struct env * env) {
  env->x += 1;
  printf ("block: x is %d\n", env->x);
}

cfunc foo (int x)
{
  struct env * env = (struct env *)malloc(sizeof(struct env));
  env->x = x;

  printf ("x is %d\n",env->x);

  return (cfunc)make_thunk(env,(void *)&block);
}

int main() {
  cfunc c = foo(5);

  c();
  c();
}

如何为64位版本重写它?

我正在使用Linux x86_64。我已经能够用gcc -m32进行交叉编译,这非常有效。

1 个答案:

答案 0 :(得分:5)

以下代码旨在与Linux上的GCC一起使用,并且应支持32位和64位编译。

protected void DataList1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {

        e.Row.Attributes.Add("onclick", "this.style.backgroundColor='Red'");
        e.Row.Attributes.Add("onmouseout", "this.style.backgroundColor='Blue'");



    }
}

假设操作系统正在使用System V 64bit ABI(使用哪种Linux)调用约定,那么将传递给函数的第一个参数将在寄存器#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> struct env { int x; }; #if __x86_64__ struct __attribute__((packed)) thunk { unsigned char mov[2]; struct env * env_addr; unsigned char movrax[2]; void (*call_address)(); unsigned char jmp[2]; }; struct thunk default_thunk = {{0x48, 0xbf}, 0x0, {0x48, 0xb8}, 0x0, {0xff, 0xe0} }; #elif __i386__ struct __attribute__((packed)) thunk { unsigned char push; struct env * env_addr; unsigned char call; signed long call_offset; unsigned char add_esp[3]; unsigned char ret; }; struct thunk default_thunk = {0x68, 0, 0xe8, 0, {0x83, 0xc4, 0x04}, 0xc3}; #else #error Architecture unsupported #endif typedef void (* cfunc)(); struct thunk * make_thunk(struct env * env, void * code) { struct thunk * thunk = (struct thunk *)mmap(0,sizeof(struct thunk), PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); *thunk = default_thunk; #if __x86_64__ thunk->env_addr = env; thunk->call_address = code; /* Pretty! */ #else thunk->env_addr = env; thunk->call_offset = code - (void *)&thunk->add_esp[0]; /* Pretty! */ #endif mprotect(thunk,sizeof(struct thunk), PROT_EXEC); return thunk; } void block(struct env * env) { env->x += 1; printf ("block: x is %d\n", env->x); } cfunc foo (int x) { struct env * env = (struct env *)malloc(sizeof(struct env)); env->x = x; printf ("x is %d\n",env->x); return (cfunc)make_thunk(env,(void *)&block); } int main() { cfunc c = foo(5); c(); c(); return 0; } 中。然后我们只需要%rdi环境地址(mov)到env_addr,然后执行%rdi。该调用使用call间接跳转到绝对位置。所以指令序列看起来像(at&amp; t语法):

%rax