20145210《信息安全系统设计基础》第05周学习总结

20145210《信息安全系统设计基础》第05周学习总结

教材内容总结

1.X86 寻址方式经历三代:
•DOS时代的平坦模式,不区分用户空间和内核空间,很不安全
•8086的分段模式
•IA32的带保护模式的平坦模式

2.Intel与ATT格式的不同:
•Intel代码省略了指示大小的后缀
•Intel代码省略了寄存器名字前的“%”符号
•Intel代码用不同的方式来描述存储器中的位置。
•在带有多个操作数的指令情况下,列出操作数的顺序相反

3.64位机器上想要得到32代码:gcc -m32 -S xxx.c
4.MAC OS中没有objdump, 有个基本等价的命令otool
5.Ubuntu中 gcc -S code.c (不带-O1) 产生的代码更接近教材中代码(删除"."开头的语句)

6.二进制文件可以用od 命令查看,也可以用gdb的x命令查看。
有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看:
od code.o | more
od code.o > code.txt

7.操作数的三种类型:
•立即数,也就是常数值。
•在ATT格式的汇编代码中,立即数的书写方式是“”后跟一个用标准C表示法表示的整数。任何一个能放进32 位字中的数值都可以用做立即数,不过汇编器在可能时会使用一个或两个字节的编码。

8.寄存器,表示某个寄存器的内容
9.存储器,根据计算出来的地址(有效地址)访问某个存储器的位置。
10.有效地址的计算方式: Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
(注意:ATT格式中的方向:第一个是源操作数,第二个是目的操作数)

11.栈
•后进先出原则
•push压栈,pop出栈
•栈顶:总是从这端插入和删除元素
•栈顶元素的地址是最低的
•栈指针%esp保存着栈顶元素的地址

12.lean指令
•lean是加载有效地址指令
•指令形式实际上并没有引用存储器,它的第一个操作数其实是将有效地址写入到目的操作数
•可以为后面的存储器引用产生指针,简洁的表述普通算数操作。

13.目的操作数必须是一个寄存器。

14.过程
过程调用:
•进入,为过程的局部变量分配空间
•将数据(以过程参数和返回值的形式)和控制从代码的一部分传递到另一部分。
•退出,释放这些空间。

15.转移控制
call
•call指令和转移指令相似,同样分直接和间接,直接调用的目标是标号,间接调用的目标是*后面跟一个操作数指示符,和JMP一样。
•call指令的效果是将返回地址入栈,并跳转到被调用过程的起始处。返回地址是还在程序中紧跟在call后面的那条指令的地址。
ret
•ret指从栈中弹出地址,并跳转到这个位置。
•在上学期的汇编语言学习中,call和ret常被用来进行子函数、子模块的调用。

实验楼代码练习:

将C语言文件编译成汇编文件并查看汇编文件内的内容:

删除以.开头的语句之后:

注释栈帧情况:

反汇编代码分析:

首先进入gdb调试环境,在虚拟机上输入如下命令生成带有调试信息的elf文件,然后进入gdb调试:

(gdb)layout asm
(gdb)b main

然后使用

(gdb)si

逐条指令执行并观察寄存器变化:

分析结果如下:
对于main函数:

pushl %ebp
movl %esp,%ebp

把当前的ebp值入栈,再把ebp入栈后的esp中的值放入ebp,此时,esp和ebp都指向同一个内存地址,此时栈中的情况如图:

pushl $8  //当前esp减4,然后把宽度为4的数值10放入esp当前指向的内存中
call SY  //调用函数指令,把当前eip的值入栈,然后跳转到SY函数的第一条指令开始执行
addl $4,%esp

此时栈中的情况如图:

对于SY函数:

pushl %ebp
movl %esp,%ebp
  //保存当前栈环境,为SY函数开辟新的栈空间
pushl 8(%ebp)  //把当前ebp中的数值加8后作为内存地址,并把该内存地址指向的内存空间的数值“10”放入栈中
call YSY  //调用函数指令,当前eip入栈,跳转到YSY的第一条指令
addl $4,%esp

首先保存当前栈环境,为SY函数开辟新的栈空间
再把当前ebp中的数值加8后作为内存地址,并把该内存地址指向的内存空间的数值“8”放入栈中
再调用函数指令,当前eip入栈,跳转到YSY的第一条指令
此时栈中情况如图:

对于YSY函数:

pushl %ebp
movl %esp,%ebp
  //保存当前栈环境,开辟新的栈空间
movl 8(%ebp),%eax  //将ebp中数值加8后作为内存地址,并将该内存地址指向的内存空间的数值8放入eax寄存器中
addl $3,%eax  //将把eax中的值加3再放回eax
popl %ebp  //从栈中获取旧的esp值,并放入ebp寄存器
ret  //从esp所指内存处获取值作为eip,然后跳转到eip中存放的地址继续执行

此时,函数YSY已经返回,其返回值存储在eax寄存器中,返回值为11
此时栈中情况如图:

返回到函数SY中:

addl $4,%esp  //回收栈空间,栈空间收缩4个字节
leave  //释放SY函数使用的栈空间
ret  //函数SY返回,程序回到main函数继续执行

此时eax函数存放的是函数SY的返回值11,栈中情况如图:

回到main函数继续执行:

addl $4,%esp  //栈收缩4个字节,回收栈空间
addl $1,%eax  //将eax中的值加1后放回eax,执行后eax中的值为12
leave
ret

通过gdb单步调试及print /x $***可以查询到相应寄存器的内容以及执行的指令

得到%ebp,%esp,eax寄存器的变化:

教材学习中遇到的问题

练习3.2:指令后缀主要根据什么来确定?参照了教材的例子以及练习题的答案,对于指令后缀的确定还是找不到标准

代码托管情况

代码托管链接

原文地址:https://www.cnblogs.com/20145210ysy/p/5967752.html