我想在 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 不同。
根据 x86 的 defuse.ca,我的字符串文字是 \xE9\x3C\x85\x04\x08
。我看到的地址是0x804853C
但是,根据 x86 的 rasm2,我的字符串文字是 \xe9\x3b\x85\x04\x08
。我看到的地址是0x804853B
第一个问题:为什么地址与我的预期地址不同,而且彼此之间差异如此之大?他们都应该为 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 挑战。
最佳答案
The machine code for "
jmp 0x8048540
" is the input.
这是错误的:
在 x86 CPU 上有不同种类的 jmp
指令(比如 jmp ecx
从 ecx
寄存器获取目标地址)。
跳转指令(jmp
, call
, je
, jae
...)但是值是 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。
关于c - 为什么 GDB 和不同的汇编程序给出不同的错误 jmp 地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47206807/