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

课程实验报告

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

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

报告日期: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

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

int parityCheck(int x) {

//每次将数的低半数位与高半数位比较,再把y右移31位,最后把y转化为逻辑的0和1 int y; y = x<<16; y = y^x; y = y^(y<<8); y = y^(y<<4); y = y^(y<<2); y = y^(y<<1); y = y>>31; return !(!y); } /*

* mul2OK - Determine if can compute 2*x without overflow * Examples: mul2OK(0x30000000) = 1 * mul2OK(0x40000000) = 0 *

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

int mul2OK(int x) {

//把x第31位和30位分别和1做按位与,再异或,再和1异或 int m;

m = ((x>>31)&0x1)^((x>>30)&0x1); return m^0x1; } /*

* mult3div2 - multiplies by 3/2 rounding toward 0,

* Should exactly duplicate effect of C expression (x*3/2),

4

* including overflow behavior. * Examples: mult3div2(11) = 16 * mult3div2(-9) = -13

* mult3div2(1073741824) = -536870912(overflow) * Legal ops: ! ~ & ^ | + <<>> * Max ops: 12 * Rating: 2 */

int mult3div2(int x) {

//左移一位再+x即x*3,右移一位的时候,当y的最高位和最低位都为0时还要+1

int y = (x<<1)+x;

y = (y>>1)+(((y>>31)&1)&(((y<<31)>>31)&1)); return y; } /*

* subOK - Determine if can compute x-y without overflow * Example: subOK(0x80000000,0x80000000) = 1, * subOK(0x80000000,0x70000000) = 0, * Legal ops: ! ~ & ^ | + <<>> * Max ops: 20 * Rating: 3 */

int subOK(int x, int y) {

//x的最高有效位和y的最高有效位不同且x和(x-y)的最高位不同才能判断溢出

int m = (x>>31)&1; int n = (y>>31)&1;

x = (m^n)&(m^(((x+(~y+1))>>31)&1)); return (!x); } /*

* absVal - absolute value of x * Example: absVal(-1) = 1.

* You may assume -TMax <= x <= TMax

5

* Legal ops: ! ~ & ^ | + <<>> * Max ops: 10 * Rating: 4 */

int absVal(int x) {

//x最高位为0时就是x,最高位为1时是~x+1 int y = x>>31;

x = (y&(~x+1))+((~y)&x); return x; } /*

* float_abs - Return bit-level equivalent of absolute value of f for * floating point argument f.

* Both the argument and result are passed as unsigned int's, but * they are to be interpreted as the bit-level representations of * single-precision floating point values. * When argument is NaN, return argument..

* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while

* Max ops: 10 * Rating: 2 */

unsigned float_abs(unsigned uf) { int x=uf&(~(1<<31)); if(x>0x7f800000) {

return uf; }

else return x; } /*

* float_f2i - Return bit-level equivalent of expression (int) f * for floating point argument f.

* Argument is passed as unsigned int, but

* it is to be interpreted as the bit-level representation of a

6

* single-precision floating point value.

* Anything out of range (including NaN and infinity) should return * 0x80000000u.

* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while

* Max ops: 30 * Rating: 4 */

int float_f2i(unsigned uf) { unsigned num=0x80000000;

int x=(uf&0x007fffff)^0x00800000; int order=0;

order=(uf&0x7f800000)>>23; if(order>158){ return num; }

if(order<127) return 0; else if(((uf>>31)&1)==1){ if(order>150){

return ~(x<<(order-150))+1; }

else return ~(x>>(150-order))+1; } else{

if(order>150) return x<<(order-150); else return x>>(150-order); } }

1.4 实验过程

编写源码,运行btest,得出实验结果。

1.5实验结果

7

可见13个函数全部正确。

1.6实验小结

此次实验主要考查的是对数据的处理,对此需要掌握数据在机器中的表示,运用合理的位运算来实现相应的功能。

8

实验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

可见输入的第一个数一定小于7

8048c4e: 8048c52:

8b 44 24 28 mov 0x28(%esp),êx ff 24 85 60 a2 04 08

jmp *0x804a260(,êx,4)

假设输入的第一个数为0,即(êx)=0,所以:

8048c59: 8048c5e:

b8 76 00 00 00 mov $0x76,êx 81 7c 24 2c 04 01 00 cmpl $0x104,0x2c(%esp)

所以第二个字符ascll码为0x76,即字符'v' 而第三个数为0x104,即260

4.实验结果:

从实验结果来看结果正确,拆弹成功。

2.2.4 阶段4 递归调用和栈 1.任务描述:拆除炸弹4

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

用x/sb 0x804a3cf 来查询有几个输入以及输入的类型,如下所示:

14

由此可见输入是两个整数。 再由phase_4中:

知道func4第二个参数值为1f,即37

再仔细研究func4函数,发现其实现了递归调用:

08048d5c : 8048d5c: 8048d5d: 8048d5e: 8048d61: 8048d65: 8048d69: 8048d6d: 8048d6f: 8048d71: 8048d73: 8048d76: 8048d78: 8048d7a: 8048d7d: 8048d7f: 8048d81: 8048d84:

56 53

push %esi push ?x

83 ec 14 sub $0x14,%esp

8b 54 24 20 mov 0x20(%esp),íx /ebx是传递的参数/ 8b 44 24 24 mov 0x24(%esp),êx 8b 74 24 28 mov 0x28(%esp),%esi 89 f1 29 c1 89 cb

mov %esi,ìx sub êx,ìx mov ìx,?x

c1 eb 1f shr $0x1f,?x / ebx 右移31位 / 01 d9 d1 f9

add ?x,ìx sar ìx

8d 1c 01 lea (ìx,êx,1),?x 39 d3 7e 17

cmp íx,?x

jle 8048d98

8d 4b ff lea -0x1(?x),ìx 89 4c 24 08 mov ìx,0x8(%esp)

15

8048d88: 8048d8c: 8048d8f: 8048d94: 8048d96: 8048d98: 8048d9a: 8048d9c: 8048d9e: 8048da2: 8048da5: 8048da9: 8048dac: 8048db1: 8048db3: 8048db6: 8048db7: 8048db8:

89 44 24 04 mov êx,0x4(%esp) 89 14 24 e8 c8 ff ff ff

mov íx,(%esp)

call 8048d5c

add ?x,êx

jmp 8048db3 mov ?x,êx cmp íx,?x

jge 8048db3

01 d8 eb 1b 89 d8 39 d3 7d 15

89 74 24 08 mov %esi,0x8(%esp) 8d 43 01

lea 0x1(?x),êx

89 44 24 04 mov êx,0x4(%esp) 89 14 24 e8 ab ff ff ff

mov íx,(%esp)

call 8048d5c

add ?x,êx

01 d8

83 c4 14 add $0x14,%esp 5b 5e c3

pop ?x pop %esi ret

下面就来剖析func4,这个函数在确定栈之后,首先取出来传递给它的参数,依次放在eax,edx,esi.中,从一个jle和一个jge可以看出,这个递归函数跳出的条件根据func4的第二个参数和第二个参数进过种种运算的结果等于第一个参数即可。注意在递归过程中第一个参数是不变的,最后返回值是经过运算后的ebx加上第一个参数。当时做实验时推出了具体的表达式,未记录下来,只记录了最后得出fun(11)=31。 运行结果如下:

16

由此可见,phase_4拆除成功!

4.实验结果:给出阶段x的实验结果和必要的结果分析

2.2.5 阶段5 phase_5

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

此阶段实验与指针相关,又根据静态调试跟踪可知,需借助gdb的动态调试跟踪来查找相关地址中存放的数据的值,进而分析出最终的拆弹密码。 3.实验过程:

首先观察代码,分析代码时发现有多个跳转指令,具体为x>15时,bomb;x>=1时,取x低4位;

17

使用gdb调试发现,要输入的是两个%d数。由后面的步骤知输入第一个数为初始数组下标,第二个数为循环15次累加求的和。

再接着:8048e70: 8b 04 85 80 a2 04 08 mov 0x804a280(,êx,4),êx,这句就是从(0x804a280+eax*4)里面拿数据出来,加到eax上。

因为eax只能是0~F的数,所以0x804a260 这个地址里面存的应该是一个数据大小为16的数组,用gdb看,得到:

观察到果然是一个数组,然后下面就是把5个输入对应ascll码的低4位转换的十进制数对应的数值一个一个的转化为这个数组,得到累加值ecx。

18

观察循环部分:

由此知当退出循环的条件是取出的数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

可见lea把buf的指针地址-0x28(?p)传给了Gets(),所以buf离返回地址有0x28+4=44个字节的距离,因此只要在buf处开始填44个字节的非'\\n'数,接下来填写要返回的地址,因为要返回至smoke,查看smoke函数的代码:

可见smoke函数起始地址为0x08048c90,所以最后四个字节应该填入90 8c 04 08,所以输入的48个字节为:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 8c 04 08

4.实验结果:

24

可见getbuf成功返回至smoke。

3.2.1 阶段1 fizz

1.任务描述:将getbuf函数执行return后执行test函数改为执行fizz函数。 2.实验设计:跟阶段0类似,多了一个比较cookie环节,所以要把cookie填入相应地址。

3.实验过程:只是将执行的函数从smoke改为fizz,查看fizz的汇编代码:

可知val变量存储地址为fizz函数中的0x8(?p),而fizz函数开始的地址为08048cba,所以输入的前44个字节为非'\\n'任意值,第45-48个字节存放fizz函数起始地址,即ba 8c 04 08,接下来4字节也是非'\\n'值,最后为cookie

25

值,即07 ab 99 67,所以输入的56个字节为

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ba 8c 04 08 00 00 00 00 07 ab 99 67 4.实验结果:

可见成功返回至fizz。 3.2.2 阶段2 bang

1.任务描述: 将getbuf函数执行return后执行test函数改为执行bang函数 。 2.实验设计:找到cookie的地址和global_value的地址,将global_value的值改为cookie值,再使函数成功跳至bang执行。 3.实验过程: 先观察bang的代码:

bang函数的首地址0x08048d05,在bang函数中,会将全局变量global_value

和cookie进行比较,global_value的地址是0x804c218,cookie的地址是

26

0x804c220,global_value在c代码中显示为0,所以需要修改global_value

的值使其与cookie一致。汇编代码为:

mov mov ret

0x804c220,êx êx,0x804c218

将这4行代码保存至example.s文件,进行汇编和反汇编,查看example.d文件

得到指令序列:a1 20 c2 04 08 a3 18 c2 04 08 c3 设置断点查看cookie为0x6799ab07时buf的首地址:

为0x55683148,综合之前的指令序列,45-48字节放buf首址,49-52放bang函数首址,得到:

a1 20 c2 04 08 a3 18 c2 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 31 68 55 05 8d 04 08

27

4.实验结果:

可见结果正确。

3.2.3 阶段3 bomb

1.任务描述:getbuf照常返回至test,但是返回值改为cookie值。 2.实验设计:返回test函数时的eax要赋值为cookie值,还要恢复被覆盖的ebp值。

3.实验过程:查看test汇编代码:

28

要返回至test,应该返回至调用getbuf之后的一步,地址为0x08048e81,返回的值要为cookie的值,写出汇编代码:

mov 0x804c220,êx push $0x08048e81 ret

保存至cookie.s文件中,经过汇编、反汇编后的代码为:

29

得到指令序列a1 20 c2 04 08 68 81 8e 04 08 c3

覆盖getbuf返回地址的时候会覆盖保存的寄存器ebp的值,所以通过设置断点来查看ebp的地址:

得到的地址为0x556831a0

所以得到的序列指令放在前11个字节,41-44位存储ebp地址的,最后四位存储buf首址:

a1 20 c2 04 08 68 81 8e 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a0 31 68 55 48 31 68 55

4.实验结果:

可见结果正确。

3.2.4 阶段4

1.任务描述:基本与阶段3相似,但要加上-n参数运行bufbomb。 2.实验设计:给出解题思路分析和拟采用的技术和方法等 3.实验过程:详细描述实验的具体过程

4.实验结果:给出阶段x的实验结果和必要的结果分析

3.3实验小结

30

本次实验主要是切身实践了缓冲区溢出带来的种种有趣的现象,更加理解了数在机器内部的存储结构。

31

实验总结

这学期的计算机系统基础的上机实验相较其它学科的实验更加有趣味性,让人乐于去探索,在实验过程中,收获了很多,同时也发现了自己的不足之处。

第一次实验让我明白数据在机器中的表示方法,以及溢出、进位等现象产生的本质是什么,这都是在课上听到过,但未曾实践的,通过第一次上机就基本上将课上所学的融会贯通,说到底,程序在机器中都是01序列,不管是指令还是数据,因此才有了各种按位的运算,以及各种对01序列的操作。

在第二次实验中,也是一步一步,由易到难,逐渐提升难度,从一开始的简单的找寻字符串地址,到后来的在指针数组结构中去获得一系列满足条件的数字、字符序列,在这次实验中,是第一次使用gcc、gdb作为辅助工具,一开始使用起来很难记它们的命令,但做完几个实验下来,基本的指令都记得差不多了,会用它们进行小程序的调试、汇编等等。

第三个实验总体围绕一个主题展开:缓冲区溢出攻击,就是要我们实践,当程序不检查时,利用输入的漏洞去篡改函数的返回地址,达到实验所要求的目的,这在现在我们看来是很有趣的一件事,但当我们以后遇到却又没有发现这种问题,可能就会造成不必要的很大的麻烦,所以作为一个计算机专业的学生,必须要知道数据在底层机器中的各种存储方式、表示方式、结构方式等等。这也是这门课、这门实验带给我们的最大的益处,这样我们在今后的编程实践中才能写出更加高效的代码。

总而言之,这门实验课上受益匪浅,但任重道远,还需要在今后的编程道路上多多学习,不断提高自身能力。

32