学习计时:共xxx小时 读书:参考资料:课本 代码: 作业: 博客:参考博客:闫佳歆(特此声明) |
一、学习目标 |
1. 理解逆向的概念以及
2. 掌握X86汇编基础,能够阅读(反)汇编代码
3. 了解ISA(指令集体系结构)
4. 理解函数调用栈帧的概念,并能用GDB进行调试
|
二、学习资源 |
1. 教材:第三章《程序的机器级表示》,详细学习指导见这:重点是3.7,3.11 2. 课程资料:https://www.shiyanlou.com/courses/413 实验四,课程邀请码:W7FQKW4Y 3. 教材中代码运行、思考一下,读代码的学习方法见这。 |
三、学习方法 |
1. 进度很重要:必须跟上每周的进度,阅读,练习,问答,项目。我会认真对待每一位同学,请你不要因为困难半途而废。 2. 问答很重要:遇到知识难点请多多提问,这是你的权利更是您对自己负责的义务。问答到博客园讨论小组:http://group.cnblogs.com/103791/
3. 实践很重要:解决书中习题,实践书中实例,完成每周项目,才算真的消化了这本好书。通过实验楼环境或自己安装的虚拟机在实践中进行学习
4. 实验报告很重要:详细记录你完成项目任务的思路,获得老师点评和帮助自己复习。学习完成后在博客园中(http://www.cnblogs.com/)把学习过程通过博客发表,博客标题“学号-信息安全系统设计基础第五周学习总结”
|
四、学习任务 |
1. 阅读教材,完成课后练习(书中有参考答案) 3.1-3.7中练习,重点:3.1,3.3,3.5,3.6,3.9,3.14,3.15,3.16,3.22,3.23,3.27,3.29,3.30,3.33,3.34 2. 考核:练习题把数据变换一下 3. 实验:需要动手的到实验楼中练习一下 4. 深化、实践题目,额外加分
|
五、后续学习预告(可选): |
第四章《处理器体系结构》 |
六、学习过程 |
第三章 程序的机器级表示一、教材导读本章学习内容是汇编语言,现在直接写汇编的机会不多了,但一定要能读懂,信息安全的核心思维方式“逆向”在这有很好很直接的体现,反汇编就是直接的逆向工程。 本章重点是3.7,但没有3.1-3.6的基础也是不行,如果想真正的提高动手能力,3.11如何用GDB调试汇编要好好练习一下,不过大多GDB技巧大家都会了。 3.1-3.7中练习,重点:3.1,3.3,3.5,3.6,3.9,3.14,3.15,3.16,3.22,3.23,3.27,3.29,3.30,3.33,3.34
练习: x的高32位为xh,低32位为xl。 y的符号位扩展成32位之后为ys(ys为0或者-1)。 dest_h = (xl*ys)_l + (xh*y)_l + (xl*y)_h dest_l = (xl*y)_l 注意,所有的乘法都是unsigned*unsigned。 也就是说对于 1*(-1),如果存入两个寄存器中,那么高32位是0,低32位是-1。 相当于 1*(UNSIGNED_MAX)。
p104, p105: X86 寻址方式经历三代:
p106: ISA的定义,ISA需要大家能总结规律,举一反三,比如能对比学习ARM的ISA;PC寄存器要好好理解; p107: gcc -S xxx.c -o xxx.s 获得汇编代码,也可以用objdump -d xxx 反汇编; 注意函数前两条和后两条汇编代码,所有函数都有,建立函数调用栈帧,应该理解、熟记。
p108: 二进制文件可以用od 命令查看,也可以用gdb的x命令查看。 有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看
p109: gcc -S 产生的汇编中可以把 以”.“开始的语句都删除了再阅读 p110: 了解Linux和Windows的汇编格式有点区别:ATT格式和Intel格式 p111: 表中不同数据的汇编代码后缀 p112: 这几个寄存器要深入理解,知道它们的用处。esi edi可以用来操纵数组,esp ebp用来操纵栈帧。 对于寄存器,特别是通用寄存器中的eax,ebx,ecx,edx,大家要理解32位的eax,16位的ax,8位的ah,al都是独立的,我们通过下面例子说明:
p113: 结合表,深入理解各种 寻址方式;理解操作数的三种类型:立即数、寄存器、存储器; 掌握有效地址的计算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s p114: MOV相当于C语言的赋值”=“,注意ATT格式中的方向, 另外注意不能从内存地址直接MOV到另一个内存地址,要用寄存器中转一下。能区分MOV,MOVS,MOVZ,掌握push,pop p115/p116: 栈帧与push pop; 注意栈顶元素的地址是所有栈中元素地址中最低的。 p117: 指针就是地址;局部变量保存在寄存器中。 p119: 结合表理解一下算术和逻辑运算, 注意目的操作数都是什么类型 特别注意一下减法是谁减去谁 注意移位操作移位量可以是立即数或%cl中的数 p123: 结合C语言理解一下控制部分,也就是分支(if/switch),循环语句(while, for)如何实现的。考验大家举一反三的学习能力。控制中最核心的是跳转语句:有条件跳转p128(实现if,switch,while,for),无条件跳转jmp(实现goto) p124: 有条件跳转的条件看状态寄存器(教材上叫条件码寄存器) 注意leal不改变条件码寄存器 思考一下:CMP和SUB用在什么地方 p125: SET指令根据t=a-b的结果设置条件码 p127: 跳转与标号 p130/p131: if-else 的汇编结构 p132/p133: do-while p134/p135: while p137/p138: for p144/p145: switch p149: IA32通过栈来实现过程调用。掌握栈帧结构,注意函数参数的压栈顺序. p150/p151: call/ret; 函数返回值存在%eax中 p174: bt/frame/up/down :关于栈帧的gdb命令
1.数据格式 · 由于是从16位体系结构扩展成32位,intel用术语字(word)表示16位数据类型,因此32位为双字(double words),64位数为4字(quad words)。 · 以下是比较容易模糊的数据类型大小: 32位机上:float 4 long int 4 double 8 longlong 8 char* 4 unsigned long 4 64位机上:float 4 long int 8 double 8 longlong 8 char* 8 unsigned long 8 另外,GCC 用long double表示扩展精度(10字节),出于存储器性能考虑,会被存储为12字节
2.访问信息 · 一个IA32 CPU包含一组8个存储32位值的寄存器,用以存整数数据和指针:eax,ecx,edx,ebx,esi,edi esp,ebp。 大多数情况下前六个都用作通用寄存器,eax,ecx,edx的存储和恢复惯例不同于ebx,edi,esi(前三者为被调用者保存,后三者为调用者保存,详见3.7.3); 最后两个用于存储指针,由于在过处理中非常重要,分别指向栈帧的顶部和底部,必须保持。
3.计算机machine-level programming重要的两类抽象 一个重要抽象,是将format and behavior of a machine-level program抽象形成instruction set architecture,即ISA(指令集体系结构) 对于ISA,要有以下基本观念:IA32的ISA和x86-64的ISA,以及其他大多数ISA,在抽象时都将指令按顺序执行抽象。 但是处理器的硬件可以并发地执行许多指令,并且采用了一些safeguards来确保并行执行之后的结果和一条一条顺序执行的结果一样。 第二个重要抽象,是将整个计算机中的memory system用虚拟地址来抽象,使得memory system就好像一个“连续”的字节块。
4.反汇编 通常,编写程序是利用高级语言如C,Pascal等语言进行编程的,后再经过编译程序生成可以 被计算机系统 直接执行的执行文件。
5.操作数指示符 操作数:指示出执行一个操作中要引用的源数据值,以及放置结果的目标位置。 操作数的三种类型:立即数、寄存器、存储器 结果存放的两种可能:寄存器中、存储器中
6.寻址方式: (1)立即数寻址方式 格式:$后加用标准c表示法表示的整数,如$0xAFF (2)寄存器寻址方式 如%eax,与汇编中学过的AX寄存器类比。 (3)存储器寻址方式
7.算术和逻辑操作 这类操作符大致分为四个小类: 1、加载有交地址(leal),通常用来执行简单算术操作,目前还不太懂这个与mov的区别 2、一元或二元操作:incl decl negl notl addl subl imull xorl orl andl 3、移位操作 :sall==shll(填0) sarl(算术右移,填符号位) shrl(逻辑右移,填0) 4、特殊算术操作:imull(有符号64位乘法) mull(无符号64位乘法) cltd(转换为四字) idivl(有符号除法) divl(无符号除法)
8.gcc编译器编译流程: ·C预处理器扩展源代码; ·编译器产生两个源代码的汇编代码 p1.s p2.s ·汇编器将汇编代码转换成二进制目标代码文件 p1.o p2.o ·链接器将两个目标代码文件与实现库函数的代码合并,并产生可执行代码p
9.push&pop (1)堆栈 需要注意两点: 1.后进先出 2.栈指针指向栈顶元素 3.栈朝低地址方向增长 (2)压栈push 指令格式——PUSH r16/m16/seg 指令功能 第一步:SP←SP-2 ;堆栈指针SP上移 第二步:(SS):(SP)←r16/m16/seg ;字操作数存入堆栈顶部 注意 堆栈操作必须至少以字为单位,这时栈顶指针-2 如果压入的是双字,栈顶指针-4 (3)出栈pop 指令格式——POP r16/m16/seg 第一步:r16/m16/seg← (SS):(SP) ;栈顶的一个字传送到指定的目的操作数 第二步:SP←SP+2 ;堆栈指针SP下移,指向新的栈顶 栈顶指针变化同压栈。
10.循环 ·do-while 一般形式如下:
do
语句;
while(表达式);
·while 一般形式如下:
while(表达式)
·for for语句是循环控制结构中使用最广泛的一种循环控制语句,特别适合已知循环次数的情况。
一般形式如下:
for ( [表达式 1]; [表达式 2 ]; [表达式3] )
|
七、遇到的问题及解决 |
1.抽象的概念理解的不是很清晰。比如这句:将整个计算机中的memory system用虚拟地址来抽象,使得memory system就好像一个“连续”的字节块。
2.如何快速读懂反汇编的汇编代码? 链接:http://www.zhihu.com/question/22299883
|
八、其他 |
1、指针其实是地址,间接引用指针就是将该指针放在一个寄存器中 ,然后在间接存储器引用中引用这个寄存器 2、局部变量通常保存在寄存器中,而不是存储器 |