我想在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挑战。
答案 0 :(得分:2)
&#34;
jmp 0x8048540
&#34;的机器代码是输入。
那是错的:
在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。