反汇编测试

1.通过输入gcc -S -o main.s main.c 将下面c程序”week0303学号.c“编译成汇编代码

反汇编测试

反汇编测试

2.使用gdb跟踪汇编代码,在纸上画出f中每一条语句引起的eip(rip),ebp(rbp),esp(rsb),eax(rax)的值和栈的变化情况。提交照片,要有学号信息。

相关知识:
esp:寄存器存放当前线程的栈顶指针
ebp:寄存器存放当前线程的栈底指针
eip:寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。
eax:是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。

一个标准的函数起始代码:

push ebp ;保存当前ebp
mov ebp,esp ;EBP设为当前堆栈指针
sub esp, xxx ;预留xxx字节给函数临时变量.

使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器
这里我遇到了一个问题,有下图的报错

反汇编测试

后来上网查了资料,解决办法是输入命令sudo apt-get install gcc-multilib

反汇编测试

进入之后先在main函数处设置一个断点,再run一下.
反汇编测试

使用disassemble指令获取汇编代码,用i(info) r(registers)指令查看各寄存器的值

反汇编测试

这里我发现了一条陌生的指令,<__x86.get_pc_thunk.ax>,其他的指令都差不多可以理解。

后来上网查了资料,get_pc_thunk.xx是一个子程序,是被调用的,程序调用时,会把调用者的下一条指令的地址压栈保存(用于返回),所以进入get_pc_thunk.xx时,栈顶esp就是调用者的下一条指令地址。

<__x86.get_pc_thunk.ax>这样的一条指令,就类似下面的操作:

__get_pc_thunk.ax:
movel (%esp),%eax
return

就是把esp的内容赋值给eax。

call 0x56556213 <__x86.get_pc_thunk.ax>执行时,会把该指令的下一条指令的地址压栈保存。也就是把指令add 0x2ddd,%eax的地址0x565561ff压入栈中

所以当进入子程序0x56556213<__x86.get_pc_thunk.ax>时,主要是执行:

movel (%esp),%eax

我的单步运行也证明了这一点:

反汇编测试

当调用者call 0x56556213<__x86.get_pc_thunk.ax>执行完毕返回时,将要执行的是:

add 0x2ddd,%eax

这里eax原始值就是该条指令本身的地址(在<__x86.get_pc_thunk.ax>中给eax赋值的)!然后加上0x2ddd,就是在本条指令偏移0x2ddd地址。

所以call 0x56556213<__x86.get_pc_thunk.ax>的意义就是为了获取下一条指令的地址。

利用了调用子程序会将下一条指令地址压栈的特性,提前获取下一条指令的地址。

接着来分析

反汇编测试

由图可知,esp所在的地址为0xffffd0dc,所以此时主函数的栈基址为0xffffd0dc,用x(examine)指令查看内存地址中的值

反汇编测试

结合display命令和寄存器或pc内部变量,做如下设置:display /i $pc,这样在每次执行下一条汇编语句时,都会显示出当前执行的语句。下面展示每一步时%esp、%ebp和堆栈内容的变化:

反汇编测试

执行到call函数时,esp和ebp的地址发生了变化,变为了0xffffd0d8

反汇编测试

运行到即将调用f函数时,call指令将下一条指令的地址入栈,此时%esp,%ebp的值分别为0xffffd0d4和0xffffd0d8:

反汇编测试

这样就真正进入了f函数,下面是f函数的汇编代码

反汇编测试

将上一个函数的基址入栈,从当前%esp开始作为新基址
反汇编测试
反汇编测试

实参的计算在%eax中进行
反汇编测试

通过一步一步调试,我记录了每一步运行时esp、ebp、eip、eax的变化

指令 esp ebp eip eax 堆栈
push %ebp 0xffffd0d0 0xffffd0d8 0x565561ca 0x56558fdc 0x5655620b
mov %esp,%ebp 0xffffd0cc 0xffffd0d8 0x565561cb 0x56558fdc 0xffffd0d8,0x5655620b
sub $0x10,%esp 0xffffd0cc 0xffffd0cc 0x565561cd 0x56558fdc 0xffffd0d8,0x5655620b
call 0x56556213 0xffffd0bc 0xffffd0cc 0x565561d0 0x56558fdc 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
add $0x2e07,%eax 0xffffd0bc 0xffffd0cc 0x565561d5 0x565561d5 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
movl $0x10,-0x4(%epb) 0xffffd0bc 0xffffd0cc 0x565561da 0x56558fdc 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
pushl 0x8(%ebp) 0xffffd0bc 0xffffd0cc 0x565561e1 0x56558fdc 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
call 0x565561ad 0xffffd0b8 0xffffd0cc 0x565561e4 0x56558fdc 0x8,0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
add $0x4,%esp 0xffffd0b8 0xffffd0cc 0x565561e9 0xb 0x8,0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
mov -0x4(%ebp),%edx 0xffffd0bc 0xffffd0cc 0x565561ec 0xb 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
add %edx,%eax 0xffffd0bc 0xffffd0cc 0x565561ef 0xb 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
leave 0xffffd0bc 0xffffd0cc 0x565561f1 0xb 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b
ret 0xffffd0d0 0xffffd0d8 0x565561f2 0xb 0x5655620b

参考:
https://www.k2zone.cn/?p=1911
https://blog.csdn.net/u012060033/article/details/79218909此时

上一篇:信息系统项目管理师优秀论文:项目整体管理


下一篇:ESP8266和腾讯云的使用