2017-2018-1 20155336 《信息安全系统设计基础》第五周学习总结
学习目标
- 理解逆向的概念
- 掌握X86汇编基础,能够阅读(反)汇编代码
- 了解ISA(指令集体系结构)
- 理解函数调用栈帧的概念,并能用GDB进行调试
教材学习内容总结
-
本章概述:
本周学习了c提供的抽象层下面的东西,了解机器级编程。通过编译器产生机器级程序的汇编代码表示,我们了解了编译器和它的优化能力,还有一些机器、数据类型和指令集。机器级程序和它们的汇编代码表示与C程序的差别很大。程序是以指令序列来表示的,每条指令都完成一个单独的操作。编译器必须使用多条指令来产生和操作各种数据结构。
用字节代码作为程序的低级表示,优点是相同的代码可以在许多不同的机器上执行。 -
x86经历的寻址方式:
- DOS时代的平坦模式,不区分用户空间和内核空间,不安全。
- 8086的分段模式
- IA32的带保护模式的平坦模式。
-
程序编码和数据格式:
- 使用GCC编译时候命令行中加入 -o1使用第一级优化 、-o2使用第二级优化
- gcc -S xxx.c -o xxx.s获得汇编代码,也可以用objdump -d xxx反汇编; 注意函数前两条和后两条汇编代码,所有函数都有,建立函数调用栈帧。
- b:8位、w:16位、l:32位。
- 注意: 64位机器上想要得到32代码:gcc -m32 -S xxx.c
- 格式的注解:ATT和Intel汇编代码格式。
- 理解寄存器%eax、%ecx、%edx、%ebx为通用寄存器,%esi和%edi可以用来操作数组,%esp和%edp可以操作指针。
- MOV指令是使用最频繁的指令,注意不能直接从一个内存地址MOV到另一个内存地址,要在寄存器中中转一下。
- 注意栈顶元素的地址是所有栈中元素地址中最低的。
- 指针就是地址,局部变量保存在寄存器中。
-
算数和逻辑操作:
- leal指令,加载有效地址,是movl指令的一个变形
- 一元操作只有一个操作数,既是源又是目的。
- 注意二元操作,源操作数是第一个,目的操作数是第二个,注意减法操作后-前
- 移位操作先可以给出移位量,第二项再给出要移位的数值。
-
控制:
- 用jump指令可以改变一组机器代码指令的执行顺序。对于switch语句可以采用jump table跳转表来完成跳转。
- 条件码寄存器用来设置跳转的条件位的。
- leal不改变条件码寄存器。
- SET指令根据计算t=a-b设置条件码。
- 有条件跳转(if、while、for)注意看条件码寄存器和无条件跳转(goto)。
- if-else结构:使用了goto语句。
- 循环结构:do-while是最基本的循环结构,其他的循环首先会转换成do-while来产生循环代码。每次循环会测试表达式,如果测试为真(非零)继续循环。c语言中三种形式的循环do-while、while和for都可以用一种简单策略来翻译,产生包含一个或多个条件分支的代码。控制条件转移为循环翻译成机器代码提供了基本机制。
- switch的jt表中引用&&作为新的指针,执行switch语句的关键步骤是通过跳转表来访问代码位置。
-
过程:
- IA32程序用程序栈来支持过程调用。注意:栈是向低地址增长的。
- 栈帧结构:用来传递参数、储存返回信息、保存寄存器、以及本地存储
- call/ret; 函数返回值存在%eax中
- leave指令可以使栈做好返回的准备
- 程序寄存器是唯一能被所有过程共享的资源。
教材学习中的问题和解决过程
-
对于数据格式的知识
在书p111页给了数据格式,在汇编代码的后缀。在之后学习mov指令的时候,其中有一个指令movl $Ox4050,%eax ,可是在之后使用中发现movl指令对于双精度浮点数可以进行传送。后来看书,知道了汇编代码也使用后缀‘l’`来表示4字节整数和8字节双精度浮点数。其实并不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。
-
对于寻址模式
首先在对于%eax和(%eax)有点疑问,不知道二者样子相同,二者具体有什么不同,后来通过看书上p113的表格,其中有寄存器Ea,操作数值是R[Ea],储存器(Ea)操作数值是M[R[Ea]]。虽然二者看起来样子很相似,但本质还是不一样的,一个是寄存器,另一个则表示缓存器,二者所代表的值也是不同的。
-
对于栈
栈在数据结构中就有所接触,遵循先进后出的原则。但是对于为什么栈底的地址大,栈顶的地址值小?如果这样那么栈就不会很大吗?通过网上百度,解决了这一问题。在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在Windows下栈的大小是固定的空间(1M或2M)超过栈的剩余空间会提示overflow。就类似于数组中的内个i,stack[i],入栈后i-1,出栈后i+1,i始终指向栈顶。
-
对于Switch语句
起初书上给的例子是有开关100、102~104、106,通过汇编代码,首先将106与100做差值运算,这样就会简化汇编语言的操作。可是对于这个例子102 开关之后没有break;既没有跳出语句,会继续操作103的代码,汇编语言是怎么实现的?通过自己动手操作了书上的例子后,两种情况有不同的目的地址,将这两个代码块都汇总到将result加11的代码,这样就解决了问题。
代码练习以及问题
-
P107
- 利用vim编写一个xxx.c文件
- gcc -S xxx.c得到汇编文件xxx.s
- 利用vim进入xxx.s或者利用cat xxx.s查看xxx.s的内容
-
P108反汇编练习
- 利用gcc -c xxx.c产生二进制文件xxx.o
- 利用objdump -d xxx.o来看到反汇编后的内容
-
教材P121练习题3.9验算反馈
- 练习题给出汇编代码,要求补全C语言代码,补全后,下图为实际验算
课后作业中的问题和解决过程
-
习题3.1
其中有一个是260(%ecx,%edc)计算值,一直把260当作十进制运算,可是没有结果,后来发现运算时需要将其转换为16进制再次参与运算,这样260=Ox104这样答案也就得到了。
-
习题3.2
指令的补全,对于mov指令格式为mov s,d,将s传送给d。但是对于MOV %eax,(%eax) 为什么是MOVL而不是MOVW?后来知道%ax为寄存器16位,%eax是扩展寄存器32位,这样就需要传送双字,就需要MOVL指令。
-
习题3.29
对于switch语句的汇编代码,最初在做的时候存在序号问题,后来仔细查阅了解C语言中case对应的序号对应着跳转表中的序号,要注意的是候跳转表中的序号从0开始的!
代码托管
其他(感悟、思考等,可选)
这周在本章下了很多时间,也补了很多汇编语言的功课,总之还是要去认认真真去对待每一个章节的知识点,这样才能融汇贯通。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 4/9 | 30/90 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:15小时
-
实际学习时间:15小时
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)