课程实验报告课程名称:计算机系统基础专业班级:学号:姓名:指导教师:报告日期:年月日计算机科学与技术学院目录实验1: (1)实验2: (7)实验3: (24)实验总结 (34)实验1:数据表示1.1 实验概述实验目的:更好地熟悉和掌握计算机中整数和浮点数的二进制编码表示。
实验目标:加深对数据二进制编码表示的了解。
实验要求:使用有限类型和数量的运算操作实现一组给定功能的函数。
实验语言:c。
实验环境:linux1.2 实验内容需要完成bits.c中下列函数功能,具体分为三大类:位操作、补码运算和浮点数操作。
1)位操作表1列出了bits.c中一组操作和测试位组的函数。
其中,“级别”栏指出各函数的难度等级(对应于该函数的实验分值),“功能”栏给出函数应实现的输出(即功能),“约束条件”栏指出你的函数实现必须满足的编码规则(具体请查看bits.c中相应函数注释),“最多操作符数量”指出你的函数实现中允许使用的操作符的最大数量。
你也可参考tests.c中对应的测试函数来了解所需实现的功能,但是注意这些测试函数并不满足目标函数必须遵循的编码约束条件,只能用做关于目标函数正确行为的参考。
表1 位操作题目列表2)补码运算表2列出了bits.c中一组使用整数的补码表示的函数。
可参考bits.c中注释说明和tests.c中对应的测试函数了解其更多具体信息。
表2 补码运算题目列表3)浮点数操作表3列出了bits.c中一组浮点数二进制表示的操作函数。
可参考bits.c中注释说明和tests.c中对应的测试函数了解其更多具体信息。
注意float_abs的输入参数和返回结果(以及float_f2i函数的输入参数)均为unsigned int类型,但应作为单精度浮点数解释其32 bit二进制表示对应的值。
表3 浮点数操作题目列表表示,当输入参数是NaN 时,返回NaN 号整型操作,包括||,&&以及if,while控制结构4 float_f2i 返回浮点数‘f’的强制整型转换“(int)f”表示仅能使用任何整型/无符号整型操作,包括||,&&以及if,while控制结构301.3 实验设计根据题目要求,选择合适的操作符来编写代码。
具体设计参考实验过程中的代码注释。
1.4 实验过程阅读相应的函数要求,利用合适的操作符编写代码。
如下:1.lsbZero函数:图1.12.byteNot函数:图1.23.byteXor函数:图1.34.logicalAnd函数:图1.45.logicalOr函数:图1.5 6.rotateLeft函数:图1.6 7.parityCheck函数:图1.7 8.mul2OK函数:图1.8 9.mult3div2函数:图1.9 10.subOK函数:图1.10 11.absVal函数:图1.1112.float_abs函数:图1.1213.float_f2i函数:图1.131.5实验结果1.使用dlc检查函数实现代码是否符合实验要求的编码规则。
a)首先./dlc bits.c直接检测是否有错误。
如图1.14所示:图1.14由图知,输出Compilation Successful(1 warning),故bits.c文件编写无误符合要求。
b)然后用-e选项调用dlc,观察操作符数。
如图1.15所示:图1.152.使用 btest 检查函数实现代码的功能正确性。
a)首先使用make编译生成btest可执行程序,如图1.16所示:图1.16b)然后调用 btest 命令检查 bits.c中所有函数的功能正确性。
如图1.17所示:图1.17由图知,得分全拿到了,故bits.c文件中函数功能都实现了。
1.6实验小结这次实验让我更好地熟悉和掌握计算机中整数和浮点数的二进制编码表示。
尤其是加深对数据二进制编码表示的了解。
通过使用有限类型和数量的运算操作实现一组给定功能的函数来提高了我对数据表示方面的C语言编程能力。
总之这次实验的过程整体还是很愉快的,耗时不是很长但是收获很大!实验2:拆弹实验2.1 实验概述实验目的:增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。
实验目标:需要拆除尽可能多的炸弹。
实验要求:使用gdb调试器和objdump来反汇编炸弹的可执行文件,并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用,进而设法“推断”出拆除炸弹所需的目标字符串。
实验语言:c。
实验环境:linux2.2 实验内容一个“binary bombs”(二进制炸弹,下文将简称为炸弹)是一个Linux可执行C程序,包含了6个阶段(phase1~phase6)。
炸弹运行的每个阶段要求你输入一个特定的字符串,若你的输入符合程序预期的输入,该阶段的炸弹就被“拆除”,否则炸弹“爆炸”并打印输出 "BOOM"字样。
实验的目标是拆除尽可能多的炸弹层次。
每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增:* 阶段1:字符串比较* 阶段2:循环* 阶段3:条件/分支* 阶段4:递归调用和栈* 阶段5:指针* 阶段6:链表/指针/结构另外还有一个隐藏阶段,但只有当你在第4阶段的解之后附加一特定字符串后才会出现。
为了完成二进制炸弹拆除任务,你需要使用gdb调试器和objdump来反汇编炸弹的可执行文件,并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用,进而设法“推断”出拆除炸弹所需的目标字符串。
这可能需要你在每一阶段的开始代码前和引爆炸弹的函数前设置断点,以便于调试。
2.2.1 阶段1 字符串比较1.任务描述:通过phase_1的反汇编代码找出要输入的字符串。
2.实验设计:利用gdb结合断点来动态地分析。
3.实验过程:观察phase_1的反汇编代码,如图2.1.1所示:图2.1.1发现在调用strings_not_equal对比字符串之前,有一个地址送入了堆栈,大胆猜测该地址就是正确字符串的首址,于是在phase_1处下个断点,运行至此处后,用x命令查看字符串。
如图2.1.2所示:图2.1.2故猜测“Border relations with Canada have never been better.”就是所需字符串。
重新执行该程序,直接输入该字符串,观察结果。
如图2.1.3所示:图2.1.34.实验结果:如图2.1.3所示,阶段一拆弹成功!阶段一很简单,当初的找出字符串首地址就可以了,没有什么大的难点。
2.2.2 阶段2 循环1.任务描述:通过phase_2的反汇编代码推断第二阶段要输入的数据2.实验设计:利用gdb结合断点来动态地分析3.实验过程:观察phase_1的前一部分反汇编代码,如图2.2.1所示:图2.2.1发现输入的应该是六个数字,而且要求[esp+0x18]必须大于等于0才行,于是测试输入“0 1 2 3 4 5”,观察这些数字在调用read_six_numbers后是如何存放在栈中的,如图2.2.2所示:图2.2.2观察到执行read_six_numbers后,输入的数字依次存放在esp+0x18、esp+0x1c、esp+0x20、esp+0x24、esp+0x28、esp+0x2c中,故对输入的数字首先就要有第一个数不能小于0。
继续观察phase_2的后一部分反汇编代码,如图2.2.3所示:图2.2.3能容易发现这是一个循环,首先将ebx赋值为1,然后比较[esp+ebx*4+0x14]加上ebx与[esp+ebx*4+0x18]是否相等,相等就ebx加一继续执行,直到ebx 等于6后退出。
然后来分析应该输入的值。
第一个数只要大于等于0就可以。
不妨就输入0。
他将会被保存在esp+0x18处。
所以ebx等于1时,有[esp+ebx*4+0x18]=[esp+0x1c]=[esp+ebx*4+0x14]+ebx=[esp+0x18]+1。
故第二个输入的数字应该为0+1=1。
同理分析可得后面的数依次为3、6、10、15。
故这六个数依次为0、1、3、6、10、15。
重新执行该程序,直接输入“0 1 3 6 10 15”,观察结果。
如图2.2.4所示:图2.2.44.实验结果:如图2.2.4所示,阶段二拆弹成功!阶段二涉及到了小的循环,慢慢的依次执行很同意就能发现规律,也不是很难。
2.2.3 阶段3 条件/分支1.任务描述:通过phase_3的反汇编代码推断第三阶段要输入的数据2.实验设计:利用gdb结合断点来动态地分析3.实验过程:观察phase_3的前一部分反汇编代码,如图2.3.1所示:图2.3.1发现输入的应该要求__isoc99_sscanf@plt的返回值大于1,于是观察调用__isoc99_sscanf@plt时格式字符串的值,在0x8048c23处下断点然后进入函数单步调试,并测试输入“0 1 2 3 4”,如图2.3.2所示:图2.3.2观察到格式字符串为“%d %d”,故只需输入两个数字即可。
同phase_2操作可以发现输入的数字依次存放在esp+0x18、esp+0x1c中。
继续观察phase_3的后一部分反汇编代码,如图2.3.3所示:图2.3.3可以显然的发现一个数字要求不能比0x7大,然后就会将第一个数字送入eax中,然后跳转至[eax*4+0x804a1c0]处执行,显然是个分支程序。
重新调试程序输入“1 100”,观察执行到0x8048c86处eax的值,即第二个数应该的值。
如图2.3.4所示:图2.3.4故第二个数为61。
重新执行该程序,直接输入“1 61”,观察结果。
如图2.3.5所示:图2.3.54.实验结果:如图2.3.5所示,阶段三拆弹成功!阶段三用到了分支,由于没有必要弄懂整个分支的功能,只要选择其中的某一路就可以了,所以解决起来也不是很难,单步执行下去就能很快的找到第二个输入的正确值。
2.2.4 阶段4 递归调用和栈1.任务描述:通过phase_4以及func4的反汇编代码推断第四阶段要输入的数据2.实验设计:利用gdb结合断点来动态地分析3.实验过程:观察phase_4的前一部分反汇编代码,如图2.4.1所示:图2.4.1发现输入的应该要求__isoc99_sscanf@plt的返回值等于2,于是同阶段三一样测试观察调用__isoc99_sscanf@plt时格式字符串的值,发现为仍然为“%d %d”,而且[esp+0x18]要求小于等于0xe。
如图2.4.2所示:图2.4.2继续观察phase_4的后一部分反汇编代码,如图2.4.3所示:图2.4.3可以不难发现依次将输入的第一个数,以及0x0和0xe作为参数传给func4,要求返回值为0xf而且输入的第二个数与0xf相等才不会爆炸。