为什么GDB和不同的汇编程序给出了不同和错误的jmp地址?

时间:2017-11-09 16:22:28

标签: c assembly x86 gdb

我想在C代码(下面)中运行此程序集jmp 0x8048540来运行位于内存地址0x8048540的函数。但是我遇到了段故障。我决定看看我哪里出错......

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

#define AMOUNT_OF_STUFF 10

//TODO: Ask IT why this is here
void win(){
    system("/bin/cat ./flag.txt");    
}


void vuln(){
    char * stuff = (char *)mmap(NULL, AMOUNT_OF_STUFF, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
    if(stuff == MAP_FAILED){
        printf("Failed to get space. Please talk to admin\n");
        exit(0);
    }
    printf("Give me %d bytes:\n", AMOUNT_OF_STUFF);
    fflush(stdout);
    int len = read(STDIN_FILENO, stuff, AMOUNT_OF_STUFF);
    if(len == 0){
        printf("You didn't give me anything :(");
        exit(0);
    }
    void (*func)() = (void (*)())stuff;
    func();      
}

int main(int argc, char*argv[]){
    printf("My mother told me to never accept things from strangers\n");
    printf("How bad could running a couple bytes be though?\n");
    fflush(stdout);
    vuln();
    return 0;
}

这是地址处的功能:

Dump of assembler code for function win:
   0x08048540 <+0>: push   %ebp
   0x08048541 <+1>: mov    %esp,%ebp
   0x08048543 <+3>: sub    $0x8,%esp
   0x08048546 <+6>: sub    $0xc,%esp
   0x08048549 <+9>: push   $0x8048700
   0x0804854e <+14>:    call   0x80483f0 <system@plt>
   0x08048553 <+19>:    add    $0x10,%esp
   0x08048556 <+22>:    leave  
   0x08048557 <+23>:    ret    
End of assembler dump.

我注意到我的装配工给我的操作码是不一致的。他们给我的跳转地址也与0x8048540的预期地址不同。

根据defuse.ca for x86,我的字符串文字为\xE9\x3C\x85\x04\x08。我看到的地址是0x804853C

但是,根据x86的rasm2,我的字符串文字是\xe9\x3b\x85\x04\x08。我看到的地址是0x804853B

第一个Qn:为什么地址与我的预期地址不同,彼此之间有什么不同?他们都应该为x86提供操作码。

然而,我刚决定使用rasm2的操作码。 然后,我注意到GDB中有些奇怪。 (注意:read()命令读取10个字节到存储器地址0xf7fd3000。

(gdb) x/8x 0xf7fd3000
0xf7fd3000: 0xe9    0x3b    0x85    0x04    0x08    0x00    0x00    0x00
到目前为止,似乎一切顺利。内存地址中的值与rasm2给出的字符串文字相匹配。 然后我决定按照说明查看内存:

(gdb) x/2i 0xf7fd3000
   0xf7fd3000:  jmp    0x1b540
   0xf7fd3005:  add    BYTE PTR [eax],al

哇。为什么要跳转到0x1b540?它只是一个视觉错误吗? 所以我跑了。

但GDB真的跳到了那个地址!

(gdb) si
0x0001b540 in ?? ()
=> 0x0001b540:  Cannot access memory at address 0x1b540

我想也许我犯了一个错误。也许jmp 0x8048540是非法的。但是,根据this source,jmp接受32位指针。

第二季:为什么GDB给我这么荒谬的地址?

有人可以告诉我不同​​地址背后的原因吗?我想要的只是跳转到0x8048540。 defuse.ca给了我0x804853C,rasm2给了我0x804853B,而GDB给了我0x1b540。 T.T

谢谢。

仅供参考,这是来自PicoCTF 2017的Shells挑战。

1 个答案:

答案 0 :(得分:2)

  

&#34; jmp 0x8048540&#34;的机器代码是输入。

那是错的:

在x86 CPU上有不同类型的jmp指令(如jmp ecxecx寄存器获取目标地址)。

立即取值的跳转说明(jmpcalljejae ...)与PC相关:

跳转的目标地址由公式计算:

argument of "jmp" + address of the next instruction

以下代码:

0x12340000 E9 00 00 01 00

反汇编:

0x12340000 jmp 0x12350005

这是按以下方式计算的:

  • jmp指令长5个字节,位于地址0x12340000。所以下一条指令(jmp后面的指令)位于0x12340005。

  • jmp的参数是0x10000和0x12340005 + 0x10000 = 0x12350005。

当然:该指令不仅会像这样反汇编,还会跳转到0x12350005。