Mic*_*alm 6 c compiler-construction assembly gcc reverse-engineering
我正在尝试用c为学生写一个缓冲区溢出练习.
通常,堆栈帧由函数参数,返回地址,基指针和局部变量组成.但我发现,有时候附加的寄存器会与基指针一起保存.我从课堂上记得,calee保存的寄存器必须在使用之前保存.但有些情况下,C代码的编译会产生汇编,这会毫无目的地保存和使用寄存器.请向我解释这个行为.
假设主要功能
int main (int argc, char** argv) {
func();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
和功能
void func() {
char buf[5];
strcpy(buf,"AAAA");
strcpy(buf,"BBBB");
}
Run Code Online (Sandbox Code Playgroud)
如果我使用gdb调试生成的可执行文件
break func
run
info frame
Run Code Online (Sandbox Code Playgroud)
一切都很好,堆栈框架只包含ebp和eip.
如果我使用
void func() {
char buf[5];
gets(buf);
}
Run Code Online (Sandbox Code Playgroud)
我明白了
Saved registers:
ebx at 0xffffd1cc, ebp at 0xffffd1d0, eip at 0xffffd1d4
Run Code Online (Sandbox Code Playgroud)
那么ebx是否另外保存在堆栈框架中?为什么?如果我跑
disas func
Run Code Online (Sandbox Code Playgroud)
我明白了
Dump of assembler code for function func:
0x56555730 <+0>: push %ebp
0x56555731 <+1>: mov %esp,%ebp
0x56555733 <+3>: push %ebx
0x56555734 <+4>: sub $0x8,%esp
0x56555737 <+7>: call 0x5655576e <__x86.get_pc_thunk.ax>
0x5655573c <+12>: add $0x18c4,%eax
=> 0x56555741 <+17>: lea -0x9(%ebp),%edx
0x56555744 <+20>: push %edx
0x56555745 <+21>: mov %eax,%ebx
0x56555747 <+23>: call 0x56555590 <gets@plt>
0x5655574c <+28>: add $0x4,%esp
0x5655574f <+31>: nop
0x56555750 <+32>: mov -0x4(%ebp),%ebx
0x56555753 <+35>: leave
0x56555754 <+36>: ret
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
所以ebx得救了.好.但它用于什么?在调用gets()之前,eax在ebx中移动.但之后没有使用它.在离开和返回之前,旧的ebx刚从堆栈中恢复.这似乎毫无用处.顺便说一句.是什么call get_pc_thunk
东西?
可比行为,如果我使用printf而不是gets:
void func() {
char buf[5];
strcpy(buf, "AAAA");
printf("%s",buf);
}
Run Code Online (Sandbox Code Playgroud)
gdb输出:
(gdb) info frame
Stack level 0, frame at 0xffffd1d8:
eip = 0x56555741 in func (/home/mischa/stuff/test/test.c:35); saved eip = 0x56555779
called by frame at 0xffffd1e0
source language c.
Arglist at 0xffffd1d0, args:
Locals at 0xffffd1d0, Previous frame's sp is 0xffffd1d8
Saved registers:
ebx at 0xffffd1cc, ebp at 0xffffd1d0, eip at 0xffffd1d4
(gdb) disas func
Dump of assembler code for function func:
0x56555730 <+0>: push %ebp
0x56555731 <+1>: mov %esp,%ebp
0x56555733 <+3>: push %ebx
0x56555734 <+4>: sub $0x8,%esp
0x56555737 <+7>: call 0x56555780 <__x86.get_pc_thunk.ax>
0x5655573c <+12>: add $0x18c4,%eax
=> 0x56555741 <+17>: movl $0x41414141,-0x9(%ebp)
0x56555748 <+24>: movb $0x0,-0x5(%ebp)
0x5655574c <+28>: lea -0x9(%ebp),%edx
0x5655574f <+31>: push %edx
0x56555750 <+32>: lea -0x17f0(%eax),%edx
0x56555756 <+38>: push %edx
0x56555757 <+39>: mov %eax,%ebx
0x56555759 <+41>: call 0x565555a0 <printf@plt>
0x5655575e <+46>: add $0x8,%esp
0x56555761 <+49>: nop
0x56555762 <+50>: mov -0x4(%ebp),%ebx
0x56555765 <+53>: leave
0x56555766 <+54>: ret
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释一下吗?
我使用cmake进行编译,使用以下CMakeLists.txt:
cmake_minimum_required (VERSION 2.8)
# projectname is the same as the main-executable
project(test)
# compile with 32 bit
add_definitions('-m32')
# Disable compiler optimization
add_definitions('-O0')
# include debugging information
add_definitions('-g')
# Align items on the stack to 4 bytes. This makes stuff easier.
# See https://stackoverflow.com/questions/1061818/stack-allocation-padding-and-alignment
add_definitions('-mpreferred-stack-boundary=2')
# disable compiler buffer overflow protection
add_definitions('-z execstack -z norelro -fno-stack-protector')
# executable source code
add_executable(test test.c)
Run Code Online (Sandbox Code Playgroud)
cmake似乎使用gcc.
R..*_*R.. 11
您的编译器工具链已经配置(可能由您的发行版),以生成默认情况下位置无关的可执行文件(PIE).在32位x86上,为了使位置无关的代码能够调用可能与调用者位于不同库中的函数,必须ebx
在调用时加载调用模块的GOT的地址.这是ABI的要求.由于ebx
是x86 ABI中的调用保存寄存器,调用者必须先保存并稍后将其恢复,然后再返回自己的调用者.
我在前一段时间写的关于这个主题的文章可能是有用的:
在最近的gcc版本中,新-fno-plt
选项可以通过内联来自GOT的负载而不是使用依赖的PLT来避免此问题ebx
.
归档时间: |
|
查看次数: |
900 次 |
最近记录: |