华中科技大学计算机系统基础实验报告

更新时间:2024-05-02 01:01:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

课程实验报告

课程名称:计算机系统基础

专业班级: 学号: 姓名: 指导教师:

报告日期:2016年5月 24日

计算机科学与技术学院

1

目录

实验1: ...................................................................................................... 2 实验2: ...................................................................................................... 9 实验3: .................................................................................................... 23 实验总结 ................................................................................................... 32

2

实验1: 数据表示

1.1 实验概述

本实验的目的是更好地熟悉和掌握计算机中整数和浮点数的二进制编码表示。

实验中,你需要解开一系列编程“难题”——使用有限类型和数量的运算操作实现一组给定功能的函数,在此过程中你将加深对数据二进制编码表示的了解。 实验语言:c; 实验环境: linux

1.2 实验内容

需要完成 bits.c 中下列函数功能,具体分为三大类:位操作、补码运算和浮点数操作。

1.3 实验设计

源码如下: /*

* lsbZero - set 0 to the least significant bit of x * Example: lsbZero(0x87654321) = 0x87654320 * Legal ops: ! ~ & ^ | + <<>> * Max ops: 5 * Rating: 1 */

int lsbZero(int x) {

//x右移一位再左移一位实现把最低有效位置0 x = x>>1; x = x<<1; return x; } /*

* byteNot - bit-inversion to byte n from word x * Bytes numbered from 0 (LSB) to 3 (MSB)

* Examples: getByteNot(0x12345678,1) = 0x1234A978 * Legal ops: ! ~ & ^ | + <<>> * Max ops: 6 * Rating: 2

1

*/

int byteNot(int x, int n) {

//x第n个字节每位都和1异或实现取反 int y = 0xff; n = n<<3; y = y<

* byteXor - compare the nth byte of x and y, if it is same, return 0, if not, return 1

* example: byteXor(0x12345678, 0x87654321, 1) = 1 *

byteXor(0x12345678, 0x87344321, 2) = 0

* Legal ops: ! ~ & ^ | + <<>> * Max ops: 20 * Rating: 2 */

int byteXor(int x, int y, int n) {

//把x和y的第n个字节取出来异或,再转换为逻辑的0和1 n = n<<3; x = x>>n; y = y>>n; x = x&(0xff); y = y&(0xff); return !!(x^y); } /*

* logicalAnd - x && y * Legal ops: ! ~ & ^ | + <<>> * Max ops: 20 * Rating: 3 */

2

int logicalAnd(int x, int y) {

//把x和y分别转化为逻辑的0和1,再相与 x = (!(!x))&(!(!y)); return x; } /*

* logicalOr - x || y

* Legal ops: ! ~ & ^ | + <<>> * Max ops: 20 * Rating: 3 */

int logicalOr(int x, int y) {

//把x和y分别转化为逻辑的0和1,再相或 x = (!(!x))|(!(!y)); return x; } /*

* rotateLeft - Rotate x to the left by n * Can assume that 0 <= n <= 31

* Examples: rotateLeft(0x87654321,4) = 0x76543218 * Legal ops: ~ & ^ | + <<>> ! * Max ops: 25 * Rating: 3 */

int rotateLeft(int x, int n) {

//先构造低n位为1,高(32-n)位为0的数z,x左移n位后的数加上x右移(32-n)位的数&z即可 int z;

z = ~(((1<<31)>>31)<>(32+(~n+1)))&z)+(x<

* parityCheck - returns 1 if x contains an odd number of 1's * Examples: parityCheck(5) = 0, parityCheck(7) = 1

3

实验2: Binary Bombs

2.1 实验概述

本实验中,你要使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。

一个“binary bombs”(二进制炸弹,下文将简称为炸弹)是一个Linux可执行C程序,包含了6个阶段(phase1~phase6)。炸弹运行的每个阶段要求你输入一个特定的字符串,若你的输入符合程序预期的输入,该阶段的炸弹就被“拆除”,否则炸弹“爆炸”并打印输出\字样。实验的目标是拆除尽可能多的炸弹层次。

每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增:

* 阶段1:字符串比较 * 阶段2:循环 * 阶段3:条件/分支 * 阶段4:递归调用和栈 * 阶段5:指针

* 阶段6:链表/指针/结构

另外还有一个隐藏阶段,但只有当你在第4阶段的解之后附加一特定字符串后才会出现。

为了完成二进制炸弹拆除任务,你需要使用gdb调试器和objdump来反汇编炸弹的可执行文件,并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用,进而设法“推断”出拆除炸弹所需的目标字符串。这可能需要你在每一阶段的开始代码前和引爆炸弹的函数前设置断点,以便于调试。

实验语言:C语言 实验环境:linux

2.2 实验内容

反汇编bomb,得到汇编代码,根据汇编代码完成拆炸弹任务。

9

2.2.1 阶段1 字符串比较

1.任务描述:找到与输入的字符串进行比较的存储的字符串的首地址,进而得到存储的字符串,得到结果。

2.实验设计:根据反汇编代码一步一步分析,具体见实验过程。 3.实验过程:

将bomb反汇编输出到asm.txt文件中,在反汇编代码中查找phase_1的位置:

从上面的语句可以看出所需要的两个变量是存在于?p所指的堆栈存储单元里,在main函数中:

得知êx里存储的是调用read_line()函数后返回的结果,就是输入的字符串,所以得知和用户输入字符串比较的字符串的存储地址为0x804a204,可用gdb查看这个地址存储的数据内容:

10

翻译过后的结果为The future will be better tomorrow. 4.实验结果:

可见结果正确。

2.2.2 阶段2 循环

1.任务描述:完成炸弹2的拆除

2.实验设计:观察分析phase_2代码,使用gdb调试分析结果 3.实验过程:找到phase_2代码:

11

由read_six_numbers知是要输入6个数字,观察:

可知输入的第一个和第二个必须依次为0,1

观察这两个循环可知只有当输入的数为前两个数之和时才不会bomb,故得到序列0,1,1,2,3,5

4.实验结果:输入上述序列后得:

12

可知结果正确。

2.2.3 阶段3 条件/分支 1.任务描述:完成炸弹3的拆除

2.实验设计:观察分析phase_3代码,使用gdb调试分析结果 3.实验过程:找到phase_3代码如下:

08048c0a : 8048c0a: 8048c0d: 8048c11: 8048c15: 8048c19: 8048c1d: 8048c21: 8048c25:

83 ec 3c sub $0x3c,%esp 8d 44 24 2c lea 0x2c(%esp),êx 89 44 24 10 mov êx,0x10(%esp) 8d 44 24 27 lea 0x27(%esp),êx 89 44 24 0c mov êx,0xc(%esp) 8d 44 24 28 lea 0x28(%esp),êx 89 44 24 08 mov êx,0x8(%esp) c7 44 24 04 4e a2 04 movl $0x804a24e,0x4(%esp)

由此行代码查看输入内容:

可知输入的依次是数字、字符、数字

8048c43: 8048c48: … 8048d43:

83 7c 24 28 07 cmpl $0x7,0x28(%esp) 0f 87 f5 00 00 00 ja 8048d43

e8 8d 04 00 00 call 80491d5

13

观察循环部分:

由此知当退出循环的条件是取出的数eax为15,而且循环次数为15次

由于115=12+3+7+11+13+9+4+8+10+1+2+14+6+15=a(5)+a(12)......+a(6) 最后得到的ecx值是115,输入的初始数组下标为5。 所以答案为:5 115

4.实验结果:

可知结果正确。

2.2.6 阶段6 phase_6

1.任务描述:拆除一个关于链表/指针/结构的炸弹。 2.实验设计:

19

初步静态分析,此阶段代码有些过长,所以单纯通过静态调试跟踪有些困难,因此我首先找到几个循环体,通过静态调试跟踪和动态调试跟踪的方法来确认循环体的功能,最后将循环体结合起来,拆除此阶段炸断。 3.实验过程:

由于代码较长,为便于分析,先总结一下,phase_6分为:参数读取,一个双层循环,三个单层循环。

首先是参数读取:

由此可见,readsix_number所有参数均小于6且不相等。 由于后面代码部分过多,便采用gdb单步执行来了解代码的功能。 在此,观察到后面:

可以看到输入六个数字的初始地址值在0x804c13c,再由for循环中: 8048ebf: 8b 52 08 mov 0x8(íx),íx

可以看出六个数字按8个字节的顺序进行排列,因此分别调用gdb查看

(0x804c13c)

*(0x804c13c+0x8)

*(*(0x804c13c+0x8)+0x8)

、、

*(*(*(0x804c13c+0x8)+0x8)+0x8) *(*(*(*(0x804c13c+0x8)+0x8)+0x8)+0x8)

*(*(*(*(*(0x804c13c+0x8)+0x8)+0x8)+0x8)+0x8) 的值即可。

20

如图所示:

在下面检测链表值时,要求链表值从大到小排列。由上图可以看出,链表原本各个位置的值按顺序排列位:292 385 c6 3db 7e 308。 按从小到大顺序排列应该为:7ec62923083853db。 由此可以看出,用户应该输入:5 3 1 6 2 4。

4.实验结果:

21

可见结果正确。

1.3 实验小结

本次实验熟悉了obj、gdb的各种操作,对数据在计算机中的存储有了更加清晰的认识,更加加深了对汇编代码的理解,对循环、分支、数组指针结构在机器内部的存储有了更深刻的认识。

22

实验3: 缓冲区溢出攻击

3.1 实验概述

本实验的目的在于加深对IA-32函数调用规则和栈结构的具体理解。实验的主要内容是对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击(buffer overflow attacks),也就是设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为,例如将给定的字节序列插入到其本不应出现的内存位置等。本次实验需要你熟练运用gdb、objdump、gcc等工具完成。

实验中你需要对目标可执行程序BUFBOMB分别完成5个难度递增的缓冲区溢出攻击。5个难度级分别命名为Smoke(level 0)、Fizz(level 1)、Bang(level 2)、Boom(level 3)和Nitro(level 4),其中Smoke级最简单而Nitro级最困难。

实验语言:c;实验环境:linux

3.2 实验内容

设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为。 3.2.0 阶段0 smoke

1.任务描述:将getbuf函数执行return后执行test函数改为执行smoke函数。 2.实验设计:首先根据反汇编代码求得buf离返回地址的字节距离,确定要填充几个字节,然后找到smoke函数的起始地址,把这个地址填入buf末尾,即可实现该功能。

3.实验过程:首先通过gdb工具对bufbomb文件进行反汇编,查看getbuf的汇编代码:

23

本文来源:https://www.bwwdw.com/article/9z4g.html

Top