【发布时间】:2015-03-16 20:11:15
【问题描述】:
我正在编写一个从头开始生成 shell 的漏洞利用程序。 (即用于缓冲区溢出)。我面临的问题之一是让 jmp 语句起作用。我的理解是jmp指令是相对于ip的。但是,当我尝试在内联汇编中运行以下命令时,我会跳转到绝对地址。
jmp 0x28 #in inline GCC will jump to address 0x28 not 0x28 relative to the ip
我解决这个问题的一种方法是使用 IP 作为指令的一部分,如下所示:
jmp *0x28(%rip) #will jump to address 0x28 relative to the ip
但是,当我这样做时,我在 jmp 上遇到了分段错误
整个汇编代码如下:
void main() {
__asm__(
"jmp *0x28(%rip) \n"
"popq %rax \n"
"movw $0x0, 0x0(%rax) #add null termination \n"
"movq %rax,0x8(%rax) #set up argv in memory \n"
"movq $0, 0x10(%rax) \n"
"mov $0x0, %edx #set up arg 3 \n"
"mov %rax, %rsi \n"
"add $0x8, %rsi \n"
"mov %rax,%rdi \n"
"mov $0x3b,%eax \n"
"syscall \n"
"call *-0x2e(%rip) \n"
".string \"/bin/sh\""
);
}
GDB 的反汇编输出是:
Dump of assembler code for function main:
0x00000000004004ac <+0>: push %rbp
0x00000000004004ad <+1>: mov %rsp,%rbp
0x00000000004004b0 <+4>: jmpq *0x28(%rip) # 0x4004de <main+50>
0x00000000004004b6 <+10>: pop %rax
0x00000000004004b7 <+11>: movw $0x0,(%rax)
0x00000000004004bc <+16>: mov %rax,0x8(%rax)
0x00000000004004c0 <+20>: movq $0x0,0x10(%rax)
0x00000000004004c8 <+28>: mov $0x0,%edx
0x00000000004004cd <+33>: mov %rax,%rsi
0x00000000004004d0 <+36>: add $0x8,%rsi
0x00000000004004d4 <+40>: mov %rax,%rdi
0x00000000004004d7 <+43>: mov $0x3b,%eax
0x00000000004004dc <+48>: syscall
0x00000000004004de <+50>: callq *-0x2e(%rip) # 0x4004b6 <main+10>
0x00000000004004e4 <+56>: (bad)
0x00000000004004e5 <+57>: (bad)
0x00000000004004e6 <+58>: imul $0x5d006873,0x2f(%rsi),%ebp
0x00000000004004ed <+65>: retq
End of assembler dump.
我在第一条指令jmp *0x28(%rip) 上得到一个段错误,尽管 GDB 说它会转到正确的地址。
有趣的是,如果我在 call *-0x2e(%rip) 之前放置一个标签,然后 jmp 就可以了。地址将是绝对的,不会产生 jmp 处的分段错误。
使用标签的C代码:
void main() {
__asm__(
"jmp my_hack \n"
"popq %rax \n"
"movw $0x0, 0x0(%rax) #add null termination \n"
"movq %rax,0x8(%rax) #set up argv in memory \n"
"movq $0, 0x10(%rax) \n"
"mov $0x0, %edx #set up arg 3 \n"
"mov %rax, %rsi \n"
"add $0x8, %rsi \n"
"mov %rax,%rdi \n"
"mov $0x3b,%eax \n"
"syscall \n"
"my_hack: \n"
"call *-0x2e(%rip) \n"
".string \"/bin/sh\""
);
}
产生的反汇编
Dump of assembler code for function main:
0x00000000004004ac <+0>: push %rbp
0x00000000004004ad <+1>: mov %rsp,%rbp
0x00000000004004b0 <+4>: jmp 0x4004da <main+46>
0x00000000004004b2 <+6>: pop %rax
0x00000000004004b3 <+7>: movw $0x0,(%rax)
0x00000000004004b8 <+12>: mov %rax,0x8(%rax)
0x00000000004004bc <+16>: movq $0x0,0x10(%rax)
0x00000000004004c4 <+24>: mov $0x0,%edx
0x00000000004004c9 <+29>: mov %rax,%rsi
0x00000000004004cc <+32>: add $0x8,%rsi
0x00000000004004d0 <+36>: mov %rax,%rdi
0x00000000004004d3 <+39>: mov $0x3b,%eax
0x00000000004004d8 <+44>: syscall
0x00000000004004da <+46>: callq *-0x2e(%rip) # 0x4004b2 <main+6>
0x00000000004004e0 <+52>: (bad)
0x00000000004004e1 <+53>: (bad)
0x00000000004004e2 <+54>: imul $0x5d006873,0x2f(%rsi),%ebp
0x00000000004004e9 <+61>: retq
End of assembler dump.
上述反汇编中使用标签的跳转不会产生分段错误。在0x00000000004004da 执行的调用将。
谁能解释为什么在 jmp 中使用 rip 会导致分段错误?
如何使用 GCC 内联汇编完成相对跳转/调用?我不知道如何检查汇编器,但我很确定我正在使用 GAS(在他们的 wiki 上它说它是默认的 GCC 汇编器)。在相关问题中有建议使用 jmp .+0x28 等语法,但这将导致绝对跳转而不是相对跳转。
【问题讨论】: