BOMLAB

实验题目:BOMBLAB

实验目的:理解汇编语言,学会使用gdb调试器。程序运行在linux环境中,程序中有6个关卡(6个phase),每个phase需要用户在终端上输入特定的字符或者数字才能通关,否则会引爆炸弹(即退出程序)。需要使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。然后分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。

实验环境:16.04 32位Ubuntu系统

实验内容及操作步骤:

先输入objdump -d bomb > lyz.txt将反汇编代码输出到一个自动生成的叫lyz.txt的文本中。然后查看反汇编代码,开始拆炸弹。

main

08048a1d <main>:

 8048a1d: 55                    push   %ebp

 8048a1e: 89 e5                 mov    %esp,%ebp

 8048a20: 53                    push   %ebx

 8048a21: 83 e4 f0              and    $0xfffffff0,%esp

 8048a24: 83 ec 10              sub    $0x10,%esp

 8048a27: 8b 45 08              mov    0x8(%ebp),%eax

 8048a2a: 8b 5d 0c              mov    0xc(%ebp),%ebx

 8048a2d: 83 f8 01              cmp    $0x1,%eax

 8048a30: 75 0c                 jne    8048a3e <main+0x21>

 8048a32: a1 a4 c3 04 08        mov    0x804c3a4,%eax

 8048a37: a3 cc c3 04 08        mov    %eax,0x804c3cc

 8048a3c: eb 74                 jmp    8048ab2 <main+0x95>

 8048a3e: 83 f8 02              cmp    $0x2,%eax

 8048a41: 75 49                 jne    8048a8c <main+0x6f>

 8048a43: c7 44 24 04 a8 a0 04 movl   $0x804a0a8,0x4(%esp)

 8048a4a: 08

 8048a4b: 8b 43 04              mov    0x4(%ebx),%eax

 8048a4e: 89 04 24              mov    %eax,(%esp)

 8048a51: e8 1a fe ff ff        call   8048870 <fopen@plt>

 8048a56: a3 cc c3 04 08        mov    %eax,0x804c3cc

 8048a5b: 85 c0                 test   %eax,%eax

 8048a5d: 75 53                 jne    8048ab2 <main+0x95>

 8048a5f: 8b 43 04              mov    0x4(%ebx),%eax

 8048a62: 89 44 24 0c           mov    %eax,0xc(%esp)

 8048a66: 8b 03                 mov    (%ebx),%eax

 8048a68: 89 44 24 08           mov    %eax,0x8(%esp)

 8048a6c: c7 44 24 04 aa a0 04 movl   $0x804a0aa,0x4(%esp)

 8048a73: 08

 8048a74: c7 04 24 01 00 00 00 movl   $0x1,(%esp)

 8048a7b: e8 10 fe ff ff        call   8048890 <__printf_chk@plt>

 8048a80: c7 04 24 08 00 00 00 movl   $0x8,(%esp)

 8048a87: e8 a4 fd ff ff        call   8048830 <exit@plt>

 8048a8c: 8b 03                 mov    (%ebx),%eax

 8048a8e: 89 44 24 08           mov    %eax,0x8(%esp)

 8048a92: c7 44 24 04 c7 a0 04 movl   $0x804a0c7,0x4(%esp)

 8048a99: 08

 8048a9a: c7 04 24 01 00 00 00 movl   $0x1,(%esp)

 8048aa1: e8 ea fd ff ff        call   8048890 <__printf_chk@plt>

 8048aa6: c7 04 24 08 00 00 00 movl   $0x8,(%esp)

 8048aad: e8 7e fd ff ff        call   8048830 <exit@plt>

 8048ab2: e8 5f 06 00 00        call   8049116 <initialize_bomb>

 8048ab7: c7 04 24 2c a1 04 08 movl   $0x804a12c,(%esp)

 8048abe: e8 2d fd ff ff        call   80487f0 <puts@plt>

 8048ac3: c7 04 24 68 a1 04 08 movl   $0x804a168,(%esp)

 8048aca: e8 21 fd ff ff        call   80487f0 <puts@plt>

 8048acf: e8 58 07 00 00        call   804922c <read_line>

 8048ad4: 89 04 24              mov    %eax,(%esp)

 8048ad7: e8 b4 00 00 00        call   8048b90 <phase_1>

 8048adc: e8 45 08 00 00        call   8049326 <phase_defused>

 8048ae1: c7 04 24 94 a1 04 08 movl   $0x804a194,(%esp)

 8048ae8: e8 03 fd ff ff        call   80487f0 <puts@plt>

 8048aed: e8 3a 07 00 00        call   804922c <read_line>

 8048af2: 89 04 24              mov    %eax,(%esp)

 8048af5: e8 ba 00 00 00        call   8048bb4 <phase_2>

 8048afa: e8 27 08 00 00        call   8049326 <phase_defused>

 8048aff: c7 04 24 e1 a0 04 08 movl   $0x804a0e1,(%esp)

 8048b06: e8 e5 fc ff ff        call   80487f0 <puts@plt>

 8048b0b: e8 1c 07 00 00        call   804922c <read_line>

 8048b10: 89 04 24              mov    %eax,(%esp)

 8048b13: e8 e9 00 00 00        call   8048c01 <phase_3>

 8048b18: e8 09 08 00 00        call   8049326 <phase_defused>

 8048b1d: c7 04 24 ff a0 04 08 movl   $0x804a0ff,(%esp)

 8048b24: e8 c7 fc ff ff        call   80487f0 <puts@plt>

 8048b29: e8 fe 06 00 00        call   804922c <read_line>

 8048b2e: 89 04 24              mov    %eax,(%esp)

 8048b31: e8 85 02 00 00        call   8048dbb <phase_4>

 8048b36: e8 eb 07 00 00        call   8049326 <phase_defused>

 8048b3b: c7 04 24 c0 a1 04 08 movl   $0x804a1c0,(%esp)

 8048b42: e8 a9 fc ff ff        call   80487f0 <puts@plt>

 8048b47: e8 e0 06 00 00        call   804922c <read_line>

 8048b4c: 89 04 24              mov    %eax,(%esp)

 8048b4f: e8 d0 02 00 00        call   8048e24 <phase_5>

 8048b54: e8 cd 07 00 00        call   8049326 <phase_defused>

 8048b59: c7 04 24 0e a1 04 08 movl   $0x804a10e,(%esp)

 8048b60: e8 8b fc ff ff        call   80487f0 <puts@plt>

 8048b65: e8 c2 06 00 00        call   804922c <read_line>

 8048b6a: 89 04 24              mov    %eax,(%esp)

 8048b6d: e8 fb 02 00 00        call   8048e6d <phase_6>

 8048b72: e8 af 07 00 00        call   8049326 <phase_defused>

 8048b77: b8 00 00 00 00        mov    $0x0,%eax

 8048b7c: 8b 5d fc              mov    -0x4(%ebp),%ebx

 8048b7f: c9                    leave  

 8048b80: c3                    ret    

 8048b81: 66 90                 xchg   %ax,%ax

 8048b83: 66 90                 xchg   %ax,%ax

 8048b85: 66 90                 xchg   %ax,%ax

 8048b87: 66 90                 xchg   %ax,%ax

 8048b89: 66 90                 xchg   %ax,%ax

 8048b8b: 66 90                 xchg   %ax,%ax

 8048b8d: 66 90                 xchg   %ax,%ax

 8048b8f: 90                    nop

大致浏览main的反汇编代码,不难发现每个关卡会调用相应的phase函数,因此找出每个关卡的通关数字或者字符串需要分析对应的phase函数。

1.phase_1(字符串)

08048b90 <phase_1>:

 8048b90: 83 ec 1c              sub    $0x1c,%esp #栈上分配空间

 8048b93: c7 44 24 04 e4 a1 04 movl   $0x804a1e4,0x4(%esp) #传入第二个参数

 8048b9a: 08

 8048b9b: 8b 44 24 20           mov    0x20(%esp),%eax

 8048b9f: 89 04 24              mov    %eax,(%esp) #传入第一个参数

 8048ba2: e8 03 05 00 00        call   80490aa <strings_not_equal>

 8048ba7: 85 c0                 test   %eax,%eax

 8048ba9: 74 05                 je     8048bb0 <phase_1+0x20>

 8048bab: e8 05 06 00 00        call   80491b5 <explode_bomb>

 8048bb0: 83 c4 1c              add    $0x1c,%esp

 8048bb3: c3                    ret    

 查看phase_1反汇编代码可以得知,我们调用了一个strings_not_equal函数,并且传入了两个参数,一个是(%esp),一个是0x4(%esp),该函数的作用就是判断这两个参数(字符串)是否相同。这两个参数,前者是我们输入的字符串,后者是我们要比较的字符串。如果字符串相同,则strings_not_equal函数返回0。而test指令是将两个操作数作与运算,并根据结果设置标志寄存器,比如此处就是判断%eax是否为0,如果为0则ZF=1。如果strings_not_equal函数返回值是0,则跳转并输出成功破解第一关的提示,不然就调用bomb函数,输出失败并且结束程序。该关卡关键点在于我高亮标出的地方,由于我们要和此处的字符串做比较,因此该地址存储的值就是我们需要的答案。

输入x/s 0x804a1e4查看字符串。

第一关拆解成功。

补充:examine指令

语法格式x/ <n/f/u> <addr>

其中,n、f、u是可选的参数,addr表示待查看的内存地址。

n是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址(units)的内容。

f表示显示的格式(format),如果地址所指的是null-terminated string,那么格式可以是s,如果地址是machine instruction,那么格式可以是i,默认初始使用十六进制格式。

u表示(the unit size)从当前地址往后请求的位宽大小。如果不指定的话,GDB默认是4个bytes。

u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了位宽长度后,GDB会从指内存定的内存地址开始,读写指定位宽大小,并把其当作一个值取出来。

举例说明:x/7xw 0x80484c0

(x即examine命令,查看内存地址中的值,7代表需要显示的内存单元的个数,x表示以hex的格式来显示,w表示从当前地址往后请求查看四字节长度,当我们指定了字节长度后,GDB会从指定内存的内存地址开始,读写指定字节,并把其当作一个值取出来。)

2.phase_2(特定的数列)

08048bb4 <phase_2>:

 8048bb4: 53                    push   %ebx

 8048bb5: 83 ec 38              sub    $0x38,%esp

 8048bb8: 8d 44 24 18           lea    0x18(%esp),%eax

 8048bbc: 89 44 24 04           mov    %eax,0x4(%esp)

 8048bc0: 8b 44 24 40           mov    0x40(%esp),%eax

 8048bc4: 89 04 24              mov    %eax,(%esp)

 8048bc7: e8 10 06 00 00        call   80491dc <read_six_numbers>

 8048bcc: 83 7c 24 18 00        cmpl   $0x0,0x18(%esp)

 8048bd1: 79 22                 jns    8048bf5 <phase_2+0x41>

 8048bd3: e8 dd 05 00 00        call   80491b5 <explode_bomb>

 8048bd8: eb 1b                 jmp    8048bf5 <phase_2+0x41>

 8048bda: 89 d8                 mov    %ebx,%eax

 8048bdc: 03 44 9c 14           add    0x14(%esp,%ebx,4),%eax

 8048be0: 39 44 9c 18           cmp    %eax,0x18(%esp,%ebx,4)

 8048be4: 74 05                 je     8048beb <phase_2+0x37>

 8048be6: e8 ca 05 00 00        call   80491b5 <explode_bomb>

 8048beb: 83 c3 01              add    $0x1,%ebx

 8048bee: 83 fb 06              cmp    $0x6,%ebx

 8048bf1: 75 e7                 jne    8048bda <phase_2+0x26>

 8048bf3: eb 07                 jmp    8048bfc <phase_2+0x48>

 8048bf5: bb 01 00 00 00        mov    $0x1,%ebx

 8048bfa: eb de                 jmp    8048bda <phase_2+0x26> 

 8048bfc: 83 c4 38              add    $0x38,%esp

 8048bff: 5b                    pop    %ebx

 8048c00: c3                    ret    

查看phase_2反汇编代码,留意第一行高亮代码,可以发现phase_2调用了一个read_six_numbers函数,即本关卡需要输入6个符合要求的数字才能破解成功。

我们继续往下看,留意第二行高亮代码,发现输入的第一个数字存储在0x18(%esp),并且为非负数,如果输入的第一个数字不是非负数即触发bomb函数。跳转后会将%ebx置为0,并且继续向前跳转到mov  %ebx,%eax,由此可以看出,这是一个循环体,结合最下面一行高亮代码可知这是一个循环6次的循环体。

往下看第三行高亮代码,可以观察出输入的六个数字依次存储于

0x18(%esp)、0x1c(%esp)、0x20(%esp)、0x24(%esp)、0x28(%esp)、0x2c(%esp)

再结合第四第五行高亮代码,可以发现这构建了一个a[i]+i=a[i+1]的数列,其中a[1]为首项,且大于等于0,i[1,6]。只有输入满足这个条件的数列的前六项,才能破解该关卡。

我们进行尝试。

第二关拆解成功。

3.phase_3(switch)

08048c01 <phase_3>:

 8048c01: 83 ec 3c              sub    $0x3c,%esp

 8048c04: 8d 44 24 2c           lea    0x2c(%esp),%eax

 8048c08: 89 44 24 10           mov    %eax,0x10(%esp)

 8048c0c: 8d 44 24 27           lea    0x27(%esp),%eax

 8048c10: 89 44 24 0c           mov    %eax,0xc(%esp)

 8048c14: 8d 44 24 28           lea    0x28(%esp),%eax

 8048c18: 89 44 24 08           mov    %eax,0x8(%esp)

 8048c1c: c7 44 24 04 32 a2 04 movl   $0x804a232,0x4(%esp) #传入四个参数

 8048c23: 08

 8048c24: 8b 44 24 40           mov    0x40(%esp),%eax

 8048c28: 89 04 24              mov    %eax,(%esp)

 8048c2b: e8 30 fc ff ff        call   8048860 <__isoc99_sscanf@plt>

 8048c30: 83 f8 02              cmp    $0x2,%eax

 8048c33: 7f 05                 jg     8048c3a <phase_3+0x39>

 8048c35: e8 7b 05 00 00        call   80491b5 <explode_bomb>

 8048c3a: 83 7c 24 28 07        cmpl   $0x7,0x28(%esp)

 8048c3f: 0f 87 fc 00 00 00     ja     8048d41 <phase_3+0x140>

 8048c45: 8b 44 24 28           mov    0x28(%esp),%eax

 8048c49: ff 24 85 40 a2 04 08 jmp    *0x804a240(,%eax,4)

 8048c50: b8 63 00 00 00        mov    $0x63,%eax

 8048c55: 81 7c 24 2c 70 02 00 cmpl   $0x270,0x2c(%esp)

 8048c5c: 00

 8048c5d: 0f 84 e8 00 00 00     je     8048d4b <phase_3+0x14a>

 8048c63: e8 4d 05 00 00        call   80491b5 <explode_bomb>

 8048c68: b8 63 00 00 00        mov    $0x63,%eax

 8048c6d: e9 d9 00 00 00        jmp    8048d4b <phase_3+0x14a>

 8048c72: b8 74 00 00 00        mov    $0x74,%eax

 8048c77: 81 7c 24 2c 1b 03 00 cmpl   $0x31b,0x2c(%esp)

 8048c7e: 00

 8048c7f: 0f 84 c6 00 00 00     je     8048d4b <phase_3+0x14a>

 8048c85: e8 2b 05 00 00        call   80491b5 <explode_bomb>

 8048c8a: b8 74 00 00 00        mov    $0x74,%eax

 8048c8f: e9 b7 00 00 00        jmp    8048d4b <phase_3+0x14a>

 8048c94: b8 75 00 00 00        mov    $0x75,%eax

 8048c99: 81 7c 24 2c 9c 02 00 cmpl   $0x29c,0x2c(%esp)

 8048ca0: 00

 8048ca1: 0f 84 a4 00 00 00     je     8048d4b <phase_3+0x14a>

 8048ca7: e8 09 05 00 00        call   80491b5 <explode_bomb>

 8048cac: b8 75 00 00 00        mov    $0x75,%eax

 8048cb1: e9 95 00 00 00        jmp    8048d4b <phase_3+0x14a>

 8048cb6: b8 78 00 00 00        mov    $0x78,%eax

 8048cbb: 81 7c 24 2c af 01 00 cmpl   $0x1af,0x2c(%esp)

 8048cc2: 00

 8048cc3: 0f 84 82 00 00 00     je     8048d4b <phase_3+0x14a>

 8048cc9: e8 e7 04 00 00        call   80491b5 <explode_bomb>

 8048cce: b8 78 00 00 00        mov    $0x78,%eax

 8048cd3: eb 76                 jmp    8048d4b <phase_3+0x14a>

 8048cd5: b8 6f 00 00 00        mov    $0x6f,%eax

 8048cda: 81 7c 24 2c 03 02 00 cmpl   $0x203,0x2c(%esp)

 8048ce1: 00

 8048ce2: 74 67                 je     8048d4b <phase_3+0x14a>

 8048ce4: e8 cc 04 00 00        call   80491b5 <explode_bomb>

 8048ce9: b8 6f 00 00 00        mov    $0x6f,%eax

 8048cee: eb 5b                 jmp    8048d4b <phase_3+0x14a>

 8048cf0: b8 71 00 00 00        mov    $0x71,%eax

 8048cf5: 81 7c 24 2c 9e 00 00 cmpl   $0x9e,0x2c(%esp)

 8048cfc: 00

 8048cfd: 74 4c                 je     8048d4b <phase_3+0x14a>

 8048cff: e8 b1 04 00 00        call   80491b5 <explode_bomb>

 8048d04: b8 71 00 00 00        mov    $0x71,%eax

 8048d09: eb 40                 jmp    8048d4b <phase_3+0x14a>

 8048d0b: b8 6a 00 00 00        mov    $0x6a,%eax

 8048d10: 81 7c 24 2c 09 02 00 cmpl   $0x209,0x2c(%esp)

 8048d17: 00

 8048d18: 74 31                 je     8048d4b <phase_3+0x14a>

 8048d1a: e8 96 04 00 00        call   80491b5 <explode_bomb>

 8048d1f: b8 6a 00 00 00        mov    $0x6a,%eax

 8048d24: eb 25                 jmp    8048d4b <phase_3+0x14a>

 8048d26: b8 71 00 00 00        mov    $0x71,%eax

 8048d2b: 81 7c 24 2c bd 01 00 cmpl   $0x1bd,0x2c(%esp)

 8048d32: 00

 8048d33: 74 16                 je     8048d4b <phase_3+0x14a>

 8048d35: e8 7b 04 00 00        call   80491b5 <explode_bomb>

 8048d3a: b8 71 00 00 00        mov    $0x71,%eax

 8048d3f: eb 0a                 jmp    8048d4b <phase_3+0x14a>

 8048d41: e8 6f 04 00 00        call   80491b5 <explode_bomb>

 8048d46: b8 74 00 00 00        mov    $0x74,%eax

 8048d4b: 3a 44 24 27           cmp    0x27(%esp),%al

 8048d4f: 74 05                 je     8048d56 <phase_3+0x155>

 8048d51: e8 5f 04 00 00        call   80491b5 <explode_bomb>

 8048d56: 83 c4 3c              add    $0x3c,%esp

 8048d59: c3                    ret   

查看phase_3反汇编代码,我们可以发现一开始传入了四个参数,分别是

0x2c(%esp),0x27(%esp),0x28(%esp),0x804a232,第一行黄色高亮代码,0x4(%esp)直接传入了一个地址值0x804a232,我们通过x/s 0x804a232进行查看。

结合前面我们需要传入的参数,我们可知该关卡应输入两个int,一个char,第四个参数程序已经帮我们传入,就是该提示信息。

继续往下看,第二第三行黄色高亮代码说明,0x28(%esp)应该是一个小于等于7的数字,由于是ja跳转,则0x28(%esp)必须大于等于0,因此我们输入的0x28(%esp)[0,7]。

第四行黄色高亮代码明显是一个switch的跳转表,由%eax控制着跳转到对应的分支条件代码块,p/x *0x804a240查看跳转表首地址存储的内容

该地址即第一行绿色高亮代码,第一第二行绿色高亮代码块即第一种分支条件代码块,

case 0(0x28(%esp)=0)的情况下需满足%eax=0x63,0x2c(%esp)=0x270。假设我们满足该条件继续跳转,跳转到最后一行黄色高亮代码,需要满足0x27(%esp)=%al才能拆解成功,即0x27(%esp)=%eax的低八位。

我们整理一下第一种分支条件下拆解成功需要满足的条件,0x28(%esp)=0,0x27(%esp)=0x63,0x2c(%esp)=0x270。转换成十进制整数和字符即0x28(%esp)=0,0x27(%esp)=c,0x2c(%esp)=624。

由于0x28(%esp)∈[0,7],因此总共有八种答案,根据对应的分支条件代码块可以得出。

0x28(%esp)=0,0x27(%esp)=c,0x2c(%esp)=624

0x28(%esp)=1,0x27(%esp)=t,0x2c(%esp)=795

0x28(%esp)=2,0x27(%esp)=u,0x2c(%esp)=668

0x28(%esp)=3,0x27(%esp)=x,0x2c(%esp)=431

0x28(%esp)=4,0x27(%esp)=o,0x2c(%esp)=158

0x28(%esp)=5,0x27(%esp)=q,0x2c(%esp)=515

0x28(%esp)=6,0x27(%esp)=j,0x2c(%esp)=521

0x28(%esp)=7,0x27(%esp)=q,0x2c(%esp)=445

我们尝试其中一种。

第三关拆解成功。

4.phase_4(递归函数)

08048d5a <func4>:

 8048d5a: 56                    push   %esi

 8048d5b: 53                    push   %ebx

 8048d5c: 83 ec 14              sub    $0x14,%esp

 8048d5f: 8b 54 24 20           mov    0x20(%esp),%edx

 8048d63: 8b 44 24 24           mov    0x24(%esp),%eax

 8048d67: 8b 5c 24 28           mov    0x28(%esp),%ebx

 8048d6b: 89 d9                 mov    %ebx,%ecx

 8048d6d: 29 c1                 sub    %eax,%ecx

 8048d6f: 89 ce                 mov    %ecx,%esi

 8048d71: c1 ee 1f              shr    $0x1f,%esi

 8048d74: 01 f1                 add    %esi,%ecx

 8048d76: d1 f9                 sar    %ecx

 8048d78: 01 c1                 add    %eax,%ecx

 8048d7a: 39 d1                 cmp    %edx,%ecx

 8048d7c: 7e 17                 jle    8048d95 <func4+0x3b>

 8048d7e: 83 e9 01              sub    $0x1,%ecx

 8048d81: 89 4c 24 08           mov    %ecx,0x8(%esp)

 8048d85: 89 44 24 04           mov    %eax,0x4(%esp)

 8048d89: 89 14 24              mov    %edx,(%esp)

 8048d8c: e8 c9 ff ff ff        call   8048d5a <func4>

 8048d91: 01 c0                 add    %eax,%eax

 8048d93: eb 20                 jmp    8048db5 <func4+0x5b>

 8048d95: b8 00 00 00 00        mov    $0x0,%eax

 8048d9a: 39 d1                 cmp    %edx,%ecx

 8048d9c: 7d 17                 jge    8048db5 <func4+0x5b>

 8048d9e: 89 5c 24 08           mov    %ebx,0x8(%esp)

 8048da2: 83 c1 01              add    $0x1,%ecx

 8048da5: 89 4c 24 04           mov    %ecx,0x4(%esp)

 8048da9: 89 14 24              mov    %edx,(%esp)

 8048dac: e8 a9 ff ff ff        call   8048d5a <func4>

 8048db1: 8d 44 00 01           lea    0x1(%eax,%eax,1),%eax

 8048db5: 83 c4 14              add    $0x14,%esp

 8048db8: 5b                    pop    %ebx

 8048db9: 5e                    pop    %esi

 8048dba: c3                    ret    

08048dbb <phase_4>:

 8048dbb: 83 ec 2c              sub    $0x2c,%esp

 8048dbe: 8d 44 24 1c           lea    0x1c(%esp),%eax

 8048dc2: 89 44 24 0c           mov    %eax,0xc(%esp)

 8048dc6: 8d 44 24 18           lea    0x18(%esp),%eax

 8048dca: 89 44 24 08           mov    %eax,0x8(%esp)

 8048dce: c7 44 24 04 af a3 04 movl   $0x804a3af,0x4(%esp)

 8048dd5: 08

 8048dd6: 8b 44 24 30           mov    0x30(%esp),%eax

 8048dda: 89 04 24              mov    %eax,(%esp)

 8048ddd: e8 7e fa ff ff        call   8048860 <__isoc99_sscanf@plt>

 8048de2: 83 f8 02              cmp    $0x2,%eax

 8048de5: 75 07                 jne    8048dee <phase_4+0x33>

 8048de7: 83 7c 24 18 0e        cmpl   $0xe,0x18(%esp)

 8048dec: 76 05                 jbe    8048df3 <phase_4+0x38>

 8048dee: e8 c2 03 00 00        call   80491b5 <explode_bomb>

 8048df3: c7 44 24 08 0e 00 00 movl   $0xe,0x8(%esp)

 8048dfa: 00

 8048dfb: c7 44 24 04 00 00 00 movl   $0x0,0x4(%esp)

 8048e02: 00

 8048e03: 8b 44 24 18           mov    0x18(%esp),%eax

 8048e07: 89 04 24              mov    %eax,(%esp)

 8048e0a: e8 4b ff ff ff        call   8048d5a <func4>

 8048e0f: 83 f8 06              cmp    $0x6,%eax

 8048e12: 75 07                 jne    8048e1b <phase_4+0x60>

 8048e14: 83 7c 24 1c 06        cmpl   $0x6,0x1c(%esp)

 8048e19: 74 05                 je     8048e20 <phase_4+0x65>

 8048e1b: e8 95 03 00 00        call   80491b5 <explode_bomb>

 8048e20: 83 c4 2c              add    $0x2c,%esp

 8048e23: c3                    ret    

查看phase_4反汇编代码,先是传入了三个参数,分别是

0x1c(%esp),0x18(%esp),0x804a3af,第一行高亮代码0x4(%esp)直接传入了一个地址值0x804a3af,我们通过x/s 0x804a3af进行查看。

结合前面我们需要传入的参数,我们可知该关卡应输入两个int,第三个参数程序已经帮我们传入,就是该提示信息。

第二行高亮代码,我们输入的0x18(%esp)要小于等于14,由于是jbe跳转因此0x18(%esp)要大于等于0。

第三行高亮代码,调用func4函数,往func4中传入了三个参数,0xe,0x0,0x0x18(%esp)。

我们查看func4代码,并且将其转换成c++程序。

#include<iostream>

using namespace std;

int func4(int edx,int eax,int ebx){

int flag=(ebx-eax)>>31; //获取符号位

int ecx=(flag+ebx-eax)/2+eax;

if(edx>=ecx){

eax=0;

if(ecx==edx) return 0;

else return 2*func4(edx,ecx+1,ebx)+1;

}

else return 2*func4(edx,eax,ecx-1);

}

分析完func4函数,我们继续分析phase_4函数,第四行高亮代码,说明func4函数的返回值必须是6,即我们往func4中输入0x18(%esp)要使得func4的返回值是6。因此我们再设计一个main函数尝试出0x18(%esp)应该是多少。

int main(){

for(int i=0;i<=14;i++){

if(func4(i,0,14)==6) cout<<i<<endl;

}

}

因此0x18(%esp)应该是8。

第五行高亮代码,0x1c(%esp)应该等于6,才能跳转到结束代码。

至此我们已经知道输入的两个参数,0x1c(%esp)=6,0x18(%esp)=6。

第四关拆解成功。

5.phase_5(数组+字符串)

08048e24 <phase_5>:

 8048e24: 53                    push   %ebx

 8048e25: 83 ec 18              sub    $0x18,%esp

 8048e28: 8b 5c 24 20           mov    0x20(%esp),%ebx

 8048e2c: 89 1c 24              mov    %ebx,(%esp)

 8048e2f: e8 57 02 00 00        call   804908b <string_length>

 8048e34: 83 f8 06              cmp    $0x6,%eax

 8048e37: 74 05                 je     8048e3e <phase_5+0x1a>

 8048e39: e8 77 03 00 00        call   80491b5 <explode_bomb>

 8048e3e: ba 00 00 00 00        mov    $0x0,%edx

 8048e43: b8 00 00 00 00        mov    $0x0,%eax

 8048e48: 0f b6 0c 03           movzbl (%ebx,%eax,1),%ecx

 8048e4c: 83 e1 0f              and    $0xf,%ecx

 8048e4f: 03 14 8d 60 a2 04 08 add    0x804a260(,%ecx,4),%edx

 8048e56: 83 c0 01              add    $0x1,%eax

 8048e59: 83 f8 06              cmp    $0x6,%eax

 8048e5c: 75 ea                 jne    8048e48 <phase_5+0x24>

 8048e5e: 83 fa 3a              cmp    $0x3a,%edx

 8048e61: 74 05                 je     8048e68 <phase_5+0x44>

 8048e63: e8 4d 03 00 00        call   80491b5 <explode_bomb>

 8048e68: 83 c4 18              add    $0x18,%esp

 8048e6b: 5b                    pop    %ebx

 8048e6c: c3                    ret  

查看phase_5反汇编代码,先是传入了一个参数0x20(%esp),然后调用了string_length函数,如果我们输入的字符串0x20(%esp)长度不为6那就调用bomb函数结束程序,由此可知我们需要输入的是一个长度为6的字符串。

第一行高亮代码,%ecx=%eax+%ebx。

第二行高亮代码,%ecx与上0xf,即保留%ecx的末四位。

第四行高亮代码,%eax是存储的是一个从0递增到6的变量,因此从8048e48到8048e5c是一个循环体,由于%ebx存储着我们输入的字符串,而%eax相当于一个递增的偏移量,因此每次循环时,%ecx都存储着输入的字符串每一个字符二进制下的末四位。

第三行高亮代码,明显0x804a260是一段存储信息的首地址,而%ecx的值则是其偏移量。我们通过x/48bx 0x804a260来查看其中存储的信息。

第五行高亮代码,由于要满足%edx=0x3a,而第三行高亮代码是add指令,意味着在一个循环6次的循环体里面,%edx要不断累加,等到循环体结束时%edx要等于0x3a。因此我们查看这段信息中哪6个数字加起来有0x3a,a+c+10+9+4+7=3a,这些数字对于的偏移量是1、4、5、6、8、9,而这些%ecx正是等于偏移量,结合上面我们所说,这些偏移量是输入的字符串每一个字符二进制下的末四位。因此我们输入的字符串的末4位在十六进制下要对应这些偏移量,查询ASCII表,我们可以得到其中一组答案。ADEFHI

第五关拆解成功。

6.phase_6(链表)

08048e6d <phase_6>:

 8048e6d: 56                    push   %esi

 8048e6e: 53                    push   %ebx

 8048e6f: 83 ec 44              sub    $0x44,%esp

 8048e72: 8d 44 24 10           lea    0x10(%esp),%eax

 8048e76: 89 44 24 04           mov    %eax,0x4(%esp)

 8048e7a: 8b 44 24 50           mov    0x50(%esp),%eax

 8048e7e: 89 04 24              mov    %eax,(%esp)

 8048e81: e8 56 03 00 00        call   80491dc <read_six_numbers>

 8048e86: be 00 00 00 00        mov    $0x0,%esi

 8048e8b: 8b 44 b4 10           mov    0x10(%esp,%esi,4),%eax

 8048e8f: 83 e8 01              sub    $0x1,%eax

 8048e92: 83 f8 05              cmp    $0x5,%eax

 8048e95: 76 05                 jbe    8048e9c <phase_6+0x2f>

 8048e97: e8 19 03 00 00        call   80491b5 <explode_bomb>

 8048e9c: 83 c6 01              add    $0x1,%esi

 8048e9f: 83 fe 06              cmp    $0x6,%esi

 8048ea2: 75 07                 jne    8048eab <phase_6+0x3e>

 8048ea4: bb 00 00 00 00        mov    $0x0,%ebx

 8048ea9: eb 38                 jmp    8048ee3 <phase_6+0x76>

 8048eab: 89 f3                 mov    %esi,%ebx

 8048ead: 8b 44 9c 10           mov    0x10(%esp,%ebx,4),%eax

 8048eb1: 39 44 b4 0c           cmp    %eax,0xc(%esp,%esi,4)

 8048eb5: 75 05                 jne    8048ebc <phase_6+0x4f>

 8048eb7: e8 f9 02 00 00        call   80491b5 <explode_bomb>

 8048ebc: 83 c3 01              add    $0x1,%ebx

 8048ebf: 83 fb 05              cmp    $0x5,%ebx

 8048ec2: 7e e9                 jle    8048ead <phase_6+0x40>

 8048ec4: eb c5                 jmp    8048e8b <phase_6+0x1e>

 8048ec6: 8b 52 08              mov    0x8(%edx),%edx

 8048ec9: 83 c0 01              add    $0x1,%eax

 8048ecc: 39 c8                 cmp    %ecx,%eax

 8048ece: 75 f6                 jne    8048ec6 <phase_6+0x59>

 8048ed0: eb 05                 jmp    8048ed7 <phase_6+0x6a>

 8048ed2: ba 3c c1 04 08        mov    $0x804c13c,%edx

 8048ed7: 89 54 b4 28           mov    %edx,0x28(%esp,%esi,4)

 8048edb: 83 c3 01              add    $0x1,%ebx

 8048ede: 83 fb 06              cmp    $0x6,%ebx

 8048ee1: 74 17                 je     8048efa <phase_6+0x8d>

 8048ee3: 89 de                 mov    %ebx,%esi

 8048ee5: 8b 4c 9c 10           mov    0x10(%esp,%ebx,4),%ecx

 8048ee9: 83 f9 01              cmp    $0x1,%ecx

 8048eec: 7e e4                 jle    8048ed2 <phase_6+0x65>

 8048eee: b8 01 00 00 00        mov    $0x1,%eax

 8048ef3: ba 3c c1 04 08        mov    $0x804c13c,%edx

 8048ef8: eb cc                 jmp    8048ec6 <phase_6+0x59>

 8048efa: 8b 5c 24 28           mov    0x28(%esp),%ebx #a[0]

 8048efe: 8d 44 24 2c           lea    0x2c(%esp),%eax #a[1]

 8048f02: 8d 74 24 40           lea    0x40(%esp),%esi #a[6]

 8048f06: 89 d9                 mov    %ebx,%ecx

 8048f08: 8b 10                 mov    (%eax),%edx

 8048f0a: 89 51 08              mov    %edx,0x8(%ecx)

 8048f0d: 83 c0 04              add    $0x4,%eax

 8048f10: 39 f0                 cmp    %esi,%eax

 8048f12: 74 04                 je     8048f18 <phase_6+0xab>

 8048f14: 89 d1                 mov    %edx,%ecx

 8048f16: eb f0                 jmp    8048f08 <phase_6+0x9b>

 8048f18: c7 42 08 00 00 00 00 movl   $0x0,0x8(%edx)

 8048f1f: be 05 00 00 00        mov    $0x5,%esi

 8048f24: 8b 43 08              mov    0x8(%ebx),%eax #%eax=下一个结点的首地址

 8048f27: 8b 00                 mov    (%eax),%eax #%eax=下一个结点的权值

 8048f29: 39 03                 cmp    %eax,(%ebx) #比较这两个结点的权值

 8048f2b: 7d 05                 jge    8048f32 <phase_6+0xc5>

 8048f2d: e8 83 02 00 00        call   80491b5 <explode_bomb>

 8048f32: 8b 5b 08              mov    0x8(%ebx),%ebx #更新地址,移到下一个结点

 8048f35: 83 ee 01              sub    $0x1,%esi

 8048f38: 75 ea                 jne    8048f24 <phase_6+0xb7>

 8048f3a: 83 c4 44              add    $0x44,%esp

 8048f3d: 5b                    pop    %ebx

 8048f3e: 5e                    pop    %esi

 8048f3f: c3                    ret    

查看phase_6反汇编代码,将代码分为五大模块。

第一模块

第一行高亮代码,调用了read_six_numbers函数,不难猜测该关卡需要输入6个数字。

第二模块

第三行高亮代码,%eax-1后要小于等于5,因此%eax只能小于等于6。

第四行高亮代码,%esi小于6则向前跳转。

第二行高亮代码,结合第三第四行高亮代码,不难分析出,这是一个双重循环,只有当%esi=6时跳出双重循环,而0x10(%esp)是存储着的6个数字的首地址,由%esi控制其偏移量,这6个数字都是小于等于6。

第五行高亮代码,将6个数字看成数组,相当于%eax=a[%ebx]。

第六行高亮代码,将a[%ebx]与a[%esi-1]相比,如果相等则boom,即数组中的6个数字都没有重复值。

第七行高亮代码,%ebx小于等于5继续内层循环比较。

至此我们得知这个双重循环是告诉我们,数组中的6个数字均小于等于6,且不存在重复的情况。

当跳出双重循环后,我们根据跳转指令跳转到8048ee3(第一处下划线)。

第三模块

第九行高亮代码,%ecx取得数组中的a[%ebx],由于初始时%ebx为0,因此第八行第十行高亮代码

中的地址就是链表的首地址。

查看可知这是一个三个元素为一个结点的链表,结合前面的信息进行推测,每一组第一个元素是权重,第二个元素是所存储的值,此处按123456顺序存储下来,第三个元素是下一个结点的首地址。

简单总结第三模块的代码,即将内存单元中存储的链表存储到该函数开辟的栈帧中。

第四模块

没有研究明白,应该是对链表进行处理,由第五模块反推,可能是将链表的结点按照权重大小从大到小排序。

第五模块

一个循环体,通过循环体判断,链表中的结点是否按照权重大小从大到小排序,如果不是就boom。因此我们从大到小输入6个数字即可通关。

0x327 3

0x29a 2

0x1b5 6

0x13a 1

0x10a 4

0x8c  5

第六关拆解成功。

7.secret_phase(二叉树)

过完六关之后,我们发现还有一个secret_phase函数,因此我们猜测还有一个隐藏关卡我们可以破解,但是一般而言破解六关之后程序就直接退出了,所以我们需要找到隐藏关卡的入口。

通过查看secret_phase的反汇编代码,我们发现最后调用了一个phase_defused函数,大胆猜测隐藏关卡的入口和这个函数有关。

08049326 <phase_defused>:

 8049326: 81 ec 8c 00 00 00     sub    $0x8c,%esp

 804932c: 65 a1 14 00 00 00     mov    %gs:0x14,%eax

 8049332: 89 44 24 7c           mov    %eax,0x7c(%esp)

 8049336: 31 c0                 xor    %eax,%eax

 8049338: 83 3d c8 c3 04 08 06 cmpl   $0x6,0x804c3c8 #如果没有解开6个关卡则不能进入隐藏phase中

 804933f: 75 72                 jne    80493b3 <phase_defused+0x8d>

 8049341: 8d 44 24 2c           lea    0x2c(%esp),%eax

 8049345: 89 44 24 10           mov    %eax,0x10(%esp)

 8049349: 8d 44 24 28           lea    0x28(%esp),%eax

 804934d: 89 44 24 0c           mov    %eax,0xc(%esp)

 8049351: 8d 44 24 24           lea    0x24(%esp),%eax

 8049355: 89 44 24 08           mov    %eax,0x8(%esp)

 8049359: c7 44 24 04 09 a4 04 movl   $0x804a409,0x4(%esp)

#x/s查看可得”%d,%d,%s”

#由于只有第四关,前面是两个int,因此需要在第四关输入两个int之后输入一个字符串才能进入隐藏关卡

 8049360: 08

 8049361: c7 04 24 d0 c4 04 08 movl   $0x804c4d0,(%esp)

#x/s查看可得””

 8049368: e8 f3 f4 ff ff        call   8048860 <__isoc99_sscanf@plt>

 804936d: 83 f8 03              cmp    $0x3,%eax

 8049370: 75 35                 jne    80493a7 <phase_defused+0x81>

 8049372: c7 44 24 04 12 a4 04 movl   $0x804a412,0x4(%esp)

#x/s查看可得”DrEvil” 

 8049379: 08

 804937a: 8d 44 24 2c           lea    0x2c(%esp),%eax

 804937e: 89 04 24              mov    %eax,(%esp)

 8049381: e8 24 fd ff ff        call   80490aa <strings_not_equal>

 8049386: 85 c0                 test   %eax,%eax

 8049388: 75 1d                 jne    80493a7 <phase_defused+0x81>

 804938a: c7 04 24 d8 a2 04 08 movl   $0x804a2d8,(%esp)

 8049391: e8 5a f4 ff ff        call   80487f0 <puts@plt>

 8049396: c7 04 24 00 a3 04 08 movl   $0x804a300,(%esp)

 804939d: e8 4e f4 ff ff        call   80487f0 <puts@plt>

 80493a2: e8 ea fb ff ff        call   8048f91 <secret_phase>

 80493a7: c7 04 24 38 a3 04 08 movl   $0x804a338,(%esp)

 80493ae: e8 3d f4 ff ff        call   80487f0 <puts@plt>

 80493b3: 8b 44 24 7c           mov    0x7c(%esp),%eax

 80493b7: 65 33 05 14 00 00 00 xor    %gs:0x14,%eax

 80493be: 74 05                 je     80493c5 <phase_defused+0x9f>

 80493c0: e8 fb f3 ff ff        call   80487c0 <__stack_chk_fail@plt>

 80493c5: 81 c4 8c 00 00 00     add    $0x8c,%esp

 80493cb: c3                    ret    

 80493cc: 66 90                 xchg   %ax,%ax

 80493ce: 66 90                 xchg   %ax,%ax

查看phase_defused函数的反汇编代码,发现某一个关卡实际上可以输入三个参数,%d,%d,%s,结合前面各关卡输入的参数,我们推导出只有第四关符合这个条件。再继续寻找,发现需要输入的字符串即为DrEvil。输入后成功进入隐藏关卡。

 

08048f40 <fun7>:

 8048f40: 53                    push   %ebx

 8048f41: 83 ec 18              sub    $0x18,%esp

 8048f44: 8b 54 24 20           mov    0x20(%esp),%edx

 8048f48: 8b 4c 24 24           mov    0x24(%esp),%ecx #传入两个参数

 8048f4c: 85 d2                 test   %edx,%edx #测试%edx是否为0

 8048f4e: 74 37                 je     8048f87 <fun7+0x47> #%edx为0跳转

 8048f50: 8b 1a                 mov    (%edx),%ebx 

 8048f52: 39 cb                 cmp    %ecx,%ebx #比较%ecx和%edx

 8048f54: 7e 13                 jle    8048f69 <fun7+0x29>

 8048f56: 89 4c 24 04           mov    %ecx,0x4(%esp)

 8048f5a: 8b 42 04              mov    0x4(%edx),%eax

 8048f5d: 89 04 24              mov    %eax,(%esp)

 8048f60: e8 db ff ff ff        call   8048f40 <fun7>

 8048f65: 01 c0                 add    %eax,%eax

 8048f67: eb 23                 jmp    8048f8c <fun7+0x4c>

 8048f69: b8 00 00 00 00        mov    $0x0,%eax

 8048f6e: 39 cb                 cmp    %ecx,%ebx

 8048f70: 74 1a                 je     8048f8c <fun7+0x4c>

 8048f72: 89 4c 24 04           mov    %ecx,0x4(%esp)

 8048f76: 8b 42 08              mov    0x8(%edx),%eax

 8048f79: 89 04 24              mov    %eax,(%esp)

 8048f7c: e8 bf ff ff ff        call   8048f40 <fun7>

 8048f81: 8d 44 00 01           lea    0x1(%eax,%eax,1),%eax

 8048f85: eb 05                 jmp    8048f8c <fun7+0x4c>

 8048f87: b8 ff ff ff ff        mov    $0xffffffff,%eax

 8048f8c: 83 c4 18              add    $0x18,%esp

 8048f8f: 5b                    pop    %ebx

 8048f90: c3                    ret    

08048f91 <secret_phase>:

 8048f91: 53                    push   %ebx

 8048f92: 83 ec 18              sub    $0x18,%esp

 8048f95: e8 92 02 00 00        call   804922c <read_line>

 8048f9a: c7 44 24 08 0a 00 00 movl   $0xa,0x8(%esp)

#传入三个参数,第三个是10

 8048fa1: 00

 8048fa2: c7 44 24 04 00 00 00 movl   $0x0,0x4(%esp) #第二个是0

 8048fa9: 00

 8048faa: 89 04 24              mov    %eax,(%esp) 

#第一个是我们输入的字符串

 8048fad: e8 1e f9 ff ff        call   80488d0 <strtol@plt>

#调用c库函数,long int strtol(const char *str,char** endptr,int base),将我们输入的str转换成base型的整数,根据上面的三个参数不难看出此处该函数是将我们输入的字符串转换成十进制的整数

 8048fb2: 89 c3                 mov    %eax,%ebx #将函数的返回值传给%ebx

 8048fb4: 8d 40 ff              lea    -0x1(%eax),%eax #%eax=%eax-1

 8048fb7: 3d e8 03 00 00        cmp    $0x3e8,%eax

 8048fbc: 76 05                 jbe    8048fc3 <secret_phase+0x32>

#%eax-0x3e8<=0则不会boom

 8048fbe: e8 f2 01 00 00        call   80491b5 <explode_bomb>

 8048fc3: 89 5c 24 04           mov    %ebx,0x4(%esp) #传入的第二个参数,strtol的返回值是fun7的一个参数

 8048fc7: c7 04 24 88 c0 04 08 movl   $0x804c088,(%esp) #传入的第一个参数

 8048fce: e8 6d ff ff ff        call   8048f40 <fun7> #调用fun7函数

 8048fd3: 83 f8 04              cmp    $0x4,%eax 

 8048fd6: 74 05                 je     8048fdd <secret_phase+0x4c>

#将fun7函数的返回值和4比较,不相等则boom

 8048fd8: e8 d8 01 00 00        call   80491b5 <explode_bomb>

 8048fdd: c7 04 24 0c a2 04 08 movl   $0x804a20c,(%esp)

#如果fun7的返回值是4,输出Wow! You've defused the secret stage!

 8048fe4: e8 07 f8 ff ff        call   80487f0 <puts@plt>

 8048fe9: e8 38 03 00 00        call   8049326 <phase_defused>

 8048fee: 83 c4 18              add    $0x18,%esp

 8048ff1: 5b                    pop    %ebx

 8048ff2: c3                    ret    

 8048ff3: 66 90                 xchg   %ax,%ax

 8048ff5: 66 90                 xchg   %ax,%ax

 8048ff7: 66 90                 xchg   %ax,%ax

 8048ff9: 66 90                 xchg   %ax,%ax

 8048ffb: 66 90                 xchg   %ax,%ax

 8048ffd: 66 90                 xchg   %ax,%ax

 8048fff: 90                    nop

查看secret_phase函数的反汇编代码,先是调用了strtol函数,往其中传入了三个参数,分别是我们输入的string,0,10,这个函数的作用是将我们输入的字符串转换成十进制的整数。

然后调用了fun7函数,并且传入了两个参数,分别是*0x804c088=0x24和strtol函数的返回值。fun7函数运行结束后,要求其返回值为4才能成功破解该关卡。因此我们来看一下fun7函数的反汇编代码,此处为了省下分析篇幅,将其转换成较好理解的c++语言。

int fun7(Node* root,int val){

if(root->value==val) return 0;

else if(root->value>val) return 2*fun7(root->left,val);

else if(root->value<val) return 2*fun7(root->right,val)+1;

else return -1;

}

不难发现,我们一开始传入的0x804c088是树的根结点的地址。而树的一个结点包含三个信息,一个树结点本身的值,一个是树的左子结点的地址,一个是树的右子结点的地址。

并且分析以上代码可知,当我们传入一个参数val,edx会指向一个树的结点,令该结点的值与我们读入的值进行比较。

如果两者相等则返回0。

如果前者大于后者:edx移至左子树,返回2*eax。

如果后者大于前者:edx移至右子树,返回2*eax+1。

现在我们的fun7需要返回的是4,4的上一次返回应该是2,从左子树返回,而2的上一次返回为1,也从左子树返回,而1的上一次调用为0。即在二叉树中按照左左右查找。

                      

因此我们可以从给定的根节点0x804c088出发,向下查询,其过程如下:

                   

即0x7即为所求。

综上,构建的二叉树如下,同时满足BTS的特性。

             

至此我们成功破解了所有关卡。

实验结果及分析:

收获与体会:

①通过此实验更加熟练掌握了gdb调试方法。比如对于x命令有更深的了解,x/ <n/f/u> <addr>,其中,n、f、u是可选的参数,addr表示待查看的内存地址。

n是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址(units)的内容。

f表示显示的格式(format),如果地址所指的是null-terminated string,那么格式可以是s,如果地址是machine instruction,那么格式可以是i,默认初始使用十六进制格式。

u表示(the unit size)从当前地址往后请求的位宽大小。如果不指定的话,GDB默认是4个bytes。

u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了位宽长度后,GDB会从指内存定的内存地址开始,读写指定位宽大小,并把其当作一个值取出来。

②通过此实验更加了解了各种数据结构的反汇编代码,比如数组是存放在连续的内存单元,通过改变偏移量来控制数组中不同的元素,链表是结点中会存储下一个结点的地址,二叉树则是结点中会存储左右结点的地址,跳转表则是保存分支条件代码块的地址,也是通过偏移量选择分支条件代码块。通过查询内存单元可以分析出数据结构的种类。

验成绩

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值