如何获取动态生成的X86_64以返回相对于RIP/RBP的值

问题描述:

我正在尝试读取内存中相对于X86_64上的%rip的值。在我的第一个例子中,我只是想读如何获取动态生成的X86_64以返回相对于RIP/RBP的值

如果我使用C下面的代码,我可以调用它,并得到正确的结果(\x....C3C9):

void * test() { 
    __asm("mov 0(%rip), %rax"); 
} 

生成的代码如下:

0000000000400624 <test>: 
    400624: 55      push %rbp 
    400625: 48 89 e5    mov %rsp,%rbp 
    400628: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax  # 40062f <test+0xb> 
    40062f: c9      leaveq 
    400630: c3      retq 

如果我现在不过直接把这个代码在内存中,并执行它,我收到了段错误,而我希望阅读\x0000C3C9

int main() 
{ 
    int codesize = 9; 
    unsigned char * code = (unsigned char*)malloc(1024); 
    memcpy(code, "\x48\x8B\x5\x0\x0\x0\x0\xC9\xC3\x00\x00", codesize + 2); 
    mprotect(code, codesize, PROT_EXEC | PROT_READ); 
    goto *code; 
} 

我做错了什么?

编辑 答案是,我不应该使用mallocmmap分配一个页对齐的内存区域:

(unsigned char*)mmap(NULL, 1024, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_SHARED, -1, 0); 

当然,我应该检查调用的返回值到mprotect。它返回-1标记它失败。

+0

我被人谁又被删除了他的评论评论,但是他引导我正确的方向。他说得对,“保护”失败了(愚蠢的我,我应该检查)。我猜'malloc'(显然)不会返回与页面边界对齐的内存。通过使用'(unsigned char *)mmap(NULL,1024,PROT_WRITE | PROT_READ,MAP_ANONYMOUS | MAP_SHARED,-1,0);'它确实有效。 – tverwaes 2011-05-06 00:28:07

+1

如果您将'PROT_EXEC'添加到'mmap'调用中,则不需要'mprotect'。 – 2011-05-06 00:31:40

+0

因为我读过某些内核不允许同时使用'PROT_WRITE'和'PROT_EXEC'的情况,所以我没有这样做。我误解了吗? – tverwaes 2011-05-06 00:36:12

您最有可能在mprotect()调用期间获得SIGSEGV。如果由malloc()返回的内存的代码执行被操作系统禁止(最有可能的是如果你没有使用一些古老的内核),mprotect()只是段错误。这不是一个错误,它是一个功能。

+0

'mprotect'不会段错误。实际上它会成功,但如果它不能成功,它将返回-1并设置“errno”。 – 2011-05-06 00:26:21

+0

实际上,如果参数不是页面对齐,但会返回一个错误,而不是段错误。随后的代码然后段错误。 – 2011-05-06 00:32:03

+0

是的,就我所知,这是问题所在。我只是习惯使用静态字符串而不是'malloc',这似乎工作。我猜静态字符串是页面对齐的,但malloc的字符串不是。 – tverwaes 2011-05-06 00:35:21

ret指令基本上是pop value from the stack; goto value

当你goto <your_code>ret最终得到执行的问题是,你有垃圾的堆(也许ret指令试图goto 9因为codesize是在堆栈的顶部,谁知道变量...)上。

基本上,它不起作用,因为你不正确地使用你的asm代码片段。

请问你在做什么?我能帮助:)


测试程序,让您的RIP:

static inline unsigned long get_rip(void) 
{ 
    unsigned long val; 
    asm volatile(
     "call 1f\n" 
     "1: popq %0\n" 
     : "=r"(val)); 
    return val; 
} 

int main() 
{ 
    printf("rip = %p\n", (void *)get_rip()); 
    return 0; 
} 
+0

为什么堆栈上会有垃圾?当我'goto '我还没有碰到堆栈,所以我只是在运行它,就好像它直接在'main'函数中一样。我正在研究一个Smalltalk - > ASM编译器(用Smalltalk编写),因为我想完全摆脱虚拟机。 X86_64似乎是一个开始的好地方。很多东西都可以学习,但很有趣:) – tverwaes 2011-05-06 00:40:49

+0

发布了一段代码片段,告诉你如何获得rip值:) – 2011-05-06 00:44:29

+1

'retq'前面的'leaveq'指令应该使堆栈指针指向main的返回地址()',假设'main()'使用了一个普通的函数序言。 – caf 2011-05-06 01:08:54