csapp:bomb-lab 解题笔记

这是一个非常有趣的lab。

  你可以用gdb,和反编译破解作者设置的密码。当然,作者提供了不带实现的c源码和(估计使用0g优化级别)。降低难度。

phase1


code:

0000000000400ee0 :
  400ee0:    48 83 ec 08              sub    $0x8,%rsp
  400ee4:    be 00 24 40 00           mov    $0x402400,%esi # 关键代码
  400ee9:    e8 4a 04 00 00           callq  401338 
  400eee:    85 c0                    test   %eax,%eax
  400ef0:    74 05                    je     400ef7 
  400ef2:    e8 43 05 00 00           callq  40143a 
  400ef7:    48 83 c4 08              add    $0x8,%rsp
  400efb:    c3                       retq   

做了挺多无用功,比如靠函数名就能才猜到的功能没必要去反推c源码。也了解了elf文件,知道如何定义程序入口。最后使用gdb查看地址找到密码:

0x402400: "Border relations with Canada have never been better."

phase2


000000000040145c : #   (%rsp) in %rsi  offse comp to 400efe
  40145c:    48 83 ec 18              sub    $0x18,%rsp #  400efe-64
  401460:    48 89 f2                 mov    %rsi,%rdx #  rdx=rsp-40 save arg2
  401463:    48 8d 4e 04              lea    0x4(%rsi),%rcx 
  401467:    48 8d 46 14              lea    0x14(%rsi),%rax
  40146b:    48 89 44 24 08           mov    %rax,0x8(%rsp) 
  401470:    48 8d 46 10              lea    0x10(%rsi),%rax
  401474:    48 89 04 24              mov    %rax,(%rsp) #
  401478:    4c 8d 4e 0c              lea    0xc(%rsi),%r9 #
  40147c:    4c 8d 46 08              lea    0x8(%rsi),%r8 #
  401480:    be c3 25 40 00           mov    $0x4025c3,%esi
  401485:    b8 00 00 00 00           mov    $0x0,%eax 
  40148a:    e8 61 f7 ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  40148f:    83 f8 05                 cmp    $0x5,%eax  
  401492:    7f 05                    jg     401499 
  401494:    e8 a1 ff ff ff           callq  40143a 
  401499:    48 83 c4 18              add    $0x18,%rsp
  40149d:    c3                       retq   

    read_six_number,根据传入的是栈指针,以及汇编一直在基于栈做赋值之类的运算,可以推测出arg2是数组。再用内存查看对0x4025c3,可以看到是"%d %d ..." 六个d。结合sscanf函数的意义,可以理解为把input,即参数0,以指定格式给到六个参数中,这六个参数应该是数组。

这里可以gdb然后画个图方便理解。

    再看phase2就比较简单了。

0000000000400efc :
  400efc:    55                       push   %rbp
  400efd:    53                       push   %rbx
  400efe:    48 83 ec 28              sub    $0x28,%rsp # -40
  400f02:    48 89 e6                 mov    %rsp,%rsi
  400f05:    e8 52 05 00 00           callq  40145c 
  400f0a:    83 3c 24 01              cmpl   $0x1,(%rsp)
  400f0e:    74 20                    je     400f30 
  400f10:    e8 25 05 00 00           callq  40143a 
  400f15:    eb 19                    jmp    400f30 
  400f17:    8b 43 fc                 mov    -0x4(%rbx),%eax
  400f1a:    01 c0                    add    %eax,%eax 
  400f1c:    39 03                    cmp    %eax,(%rbx)
  400f1e:    74 05                    je     400f25 
  400f20:    e8 15 05 00 00           callq  40143a 
  400f25:    48 83 c3 04              add    $0x4,%rbx
  400f29:    48 39 eb                 cmp    %rbp,%rbx
  400f2c:    75 e9                    jne    400f17  # jump to loop
  400f2e:    eb 0c                    jmp    400f3c  # jump to exit
  400f30:    48 8d 5c 24 04           lea    0x4(%rsp),%rbx
  400f35:    48 8d 6c 24 18           lea    0x18(%rsp),%rbp
  400f3a:    eb db                    jmp    400f17 
  400f3c:    48 83 c4 28              add    $0x28,%rsp
  400f40:    5b                       pop    %rbx
  400f41:    5d                       pop    %rbp
  400f42:    c3                       retq  

    就是数组开头必须是1,然后依次*2.我们也可以根据-4,+4,+0x18猜到这是一个int 数组。

    结果:1 2 4 8 16 32

That's number 2. Keep going!

phase3


    应该是lab里面最简单的一个了。方法本地分配两个变量,假设0x8(%rsp)=a,0xc(%rsp)=b,那么只需要满足公式:8a+0x400f7c=b即可,那么设置a=0,指令会跳转到0x400f7c处,可以看到直接赋值%rax 0xcf,那么我们只需要另b=207就行了。400fbe地址处

 400f43:    48 83 ec 18              sub    $0x18,%rsp
  400f47:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx 
  400f4c:    48 8d 54 24 08           lea    0x8(%rsp),%rdx
  400f51:    be cf 25 40 00           mov    $0x4025cf,%esi
  400f56:    b8 00 00 00 00           mov    $0x0,%eax
  400f5b:    e8 90 fc ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  400f60:    83 f8 01                 cmp    $0x1,%eax
  400f63:    7f 05                    jg     400f6a 
  400f65:    e8 d0 04 00 00           callq  40143a 
  400f6a:    83 7c 24 08 07           cmpl   $0x7,0x8(%rsp) # arg1<=7
  400f6f:    77 3c                    ja     400fad 
  400f71:    8b 44 24 08              mov    0x8(%rsp),%eax
  400f75:    ff 24 c5 70 24 40 00     jmpq   *0x402470(,%rax,8)
  400f7c:    b8 cf 00 00 00           mov    $0xcf,%eax
  400f81:    eb 3b                    jmp    400fbe 
  400f83:    b8 c3 02 00 00           mov    $0x2c3,%eax
  400f88:    eb 34                    jmp    400fbe 
  400f8a:    b8 00 01 00 00           mov    $0x100,%eax
  400f8f:    eb 2d                    jmp    400fbe 
  400f91:    b8 85 01 00 00           mov    $0x185,%eax
  400f96:    eb 26                    jmp    400fbe 
  400f98:    b8 ce 00 00 00           mov    $0xce,%eax
  400f9d:    eb 1f                    jmp    400fbe 
  400f9f:    b8 aa 02 00 00           mov    $0x2aa,%eax
  400fa4:    eb 18                    jmp    400fbe 
  400fa6:    b8 47 01 00 00           mov    $0x147,%eax
  400fab:    eb 11                    jmp    400fbe 
  400fad:    e8 88 04 00 00           callq  40143a 
  400fb2:    b8 00 00 00 00           mov    $0x0,%eax
  400fb7:    eb 05                    jmp    400fbe 
  400fb9:    b8 37 01 00 00           mov    $0x137,%eax
  400fbe:    3b 44 24 0c              cmp    0xc(%rsp),%eax
  400fc2:    74 05                    je     400fc9 
  400fc4:    e8 71 04 00 00           callq  40143a 
  400fc9:    48 83 c4 18              add    $0x18,%rsp
  400fcd:    c3                       retq   

     答案:0 207

Halfway there!

phase4


000000000040100c :
  40100c:    48 83 ec 18              sub    $0x18,%rsp  # arg1=0 arg0<=e
  401010:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx # 参数1
  401015:    48 8d 54 24 08           lea    0x8(%rsp),%rdx # 参数0
  40101a:    be cf 25 40 00           mov    $0x4025cf,%esi
  40101f:    b8 00 00 00 00           mov    $0x0,%eax
  401024:    e8 c7 fb ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  401029:    83 f8 02                 cmp    $0x2,%eax
  40102c:    75 07                    jne    401035 
  40102e:    83 7c 24 08 0e           cmpl   $0xe,0x8(%rsp)
  401033:    76 05                    jbe    40103a 
  401035:    e8 00 04 00 00           callq  40143a 
  40103a:    ba 0e 00 00 00           mov    $0xe,%edx
  40103f:    be 00 00 00 00           mov    $0x0,%esi
  401044:    8b 7c 24 08              mov    0x8(%rsp),%edi
  401048:    e8 81 ff ff ff           callq  c  # arg0, 0, e
  40104d:    85 c0                    test   %eax,%eax
  40104f:    75 07                    jne    401058 
  401051:    83 7c 24 0c 00           cmpl   $0x0,0xc(%rsp)
  401056:    74 05                    je     40105d 
  401058:    e8 dd 03 00 00           callq  40143a 
  40105d:    48 83 c4 18              add    $0x18,%rsp
  401061:    c3                       retq   

func4

0000000000400fce : # x in %rdi , y in %rsi z in %rdx
  400fce:    48 83 ec 08              sub    $0x8,%rsp
  400fd2:    89 d0                    mov    %edx,%eax
  400fd4:    29 f0                    sub    %esi,%eax
  400fd6:    89 c1                    mov    %eax,%ecx
  400fd8:    c1 e9 1f                 shr    $0x1f,%ecx
  400fdb:    01 c8                    add    %ecx,%eax
  400fdd:    d1 f8                    sar    %eax
  400fdf:    8d 0c 30                 lea    (%rax,%rsi,1),%ecx
  400fe2:    39 f9                    cmp    %edi,%ecx
  400fe4:    7e 0c                    jle    400ff2 
  400fe6:    8d 51 ff                 lea    -0x1(%rcx),%edx
  400fe9:    e8 e0 ff ff ff           callq  400fce 
  400fee:    01 c0                    add    %eax,%eax
  400ff0:    eb 15                    jmp    401007 
  400ff2:    b8 00 00 00 00           mov    $0x0,%eax
  400ff7:    39 f9                    cmp    %edi,%ecx
  400ff9:    7d 0c                    jge    401007 
  400ffb:    8d 71 01                 lea    0x1(%rcx),%esi
  400ffe:    e8 cb ff ff ff           callq  400fce 
  401003:    8d 44 00 01              lea    0x1(%rax,%rax,1),%eax
  401007:    48 83 c4 08              add    $0x8,%rsp
  40100b:    c3                       retq   

这一题要结合phase4 和fun4来看。

  首先看sscanf的参数,%rsi0x4025cf处,gdb查看是要求两个整数,根据40102c行也能得出此结论。40102e行说明参数需要0小于等于14,然后0,和e被当作参数1,2传递给fun4.再根据fun4的汇编反汇编一下,经过几版优化,基本可以得出它的功能如上,一直用z模2,直到z==x,否则返回2*fun(x,y,--z),其实else不用管它,因为如果你x传递0,那么0*任何数都会返回0。而且结合401051 行。发现第二个输入的数,也要是0,那么就更不会走第二个情况了。

感觉这题需要的debug会比较多一点。

答案:0 0

鄙人可能错误的反汇编

int fun4(int x, int y, int z) //arg0,0,e ,should return 0
{  
    z %=2;//offset%2
    if(z == x){
        return 0;
    }
    else{
        return 2*fun(x,y,--z);
    }
}

So you got that one. Try this one.

  成功的喜悦~

phase5


0000000000401062 :
  401062:    53                       push   %rbx
  401063:    48 83 ec 20              sub    $0x20,%rsp
  401067:    48 89 fb                 mov    %rdi,%rbx
  40106a:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax #40
  401071:    00 00 
  401073:    48 89 44 24 18           mov    %rax,0x18(%rsp) # 24 金丝雀值
  401078:    31 c0                    xor    %eax,%eax # eax=0;
  40107a:    e8 9c 02 00 00           callq  40131b 
  40107f:    83 f8 06                 cmp    $0x6,%eax
  401082:    74 4e                    je     4010d2 
  401084:    e8 b1 03 00 00           callq  40143a 
  401089:    eb 47                    jmp    4010d2 
~  40108b:    0f b6 0c 03              movzbl (%rbx,%rax,1),%ecx
~  40108f:    88 0c 24                 mov    %cl,(%rsp)
~  401092:    48 8b 14 24              mov    (%rsp),%rdx
~  401096:    83 e2 0f                 and    $0xf,%edx
~  401099:    0f b6 92 b0 24 40 00     movzbl 0x4024b0(%rdx),%edx
~  4010a0:    88 54 04 10              mov    %dl,0x10(%rsp,%rax,1)
~  4010a4:    48 83 c0 01              add    $0x1,%rax
~  4010a8:    48 83 f8 06              cmp    $0x6,%rax
~  4010ac:    75 dd                    jne    40108b 
~  4010ae:    c6 44 24 16 00           movb   $0x0,0x16(%rsp)
~  4010b3:    be 5e 24 40 00           mov    $0x40245e,%esi
~  4010b8:    48 8d 7c 24 10           lea    0x10(%rsp),%rdi
~  4010bd:    e8 76 02 00 00           callq  401338 
  4010c2:    85 c0                    test   %eax,%eax
  4010c4:    74 13                    je     4010d9 
  4010c6:    e8 6f 03 00 00           callq  40143a 
  4010cb:    0f 1f 44 00 00           nopl   0x0(%rax,%rax,1)
  4010d0:    eb 07                    jmp    4010d9 
  4010d2:    b8 00 00 00 00           mov    $0x0,%eax
  4010d7:    eb b2                    jmp    40108b 
  4010d9:    48 8b 44 24 18           mov    0x18(%rsp),%rax
  4010de:    64 48 33 04 25 28 00     xor    %fs:0x28,%rax
  4010e5:    00 00 
  4010e7:    74 05                    je     4010ee 
  4010e9:    e8 42 fa ff ff           callq  400b30 <__stack_chk_fail@plt>
  4010ee:    48 83 c4 20              add    $0x20,%rsp
  4010f2:    5b                       pop    %rbx
  4010f3:    c3                       retq  

比较核心的代码就是我用‘~’号标记出来的。大致的意思是取你输入字符的最后一个字节,保留低4位,在加上基地址0x4024b0 取到一个字符,凑6个成字符串,再和0x40245e处的字符比较,一样退出,否则引爆。

比较难懂的是40106amov %fs:0x28,%rax。搜索得知这是利用段寄存器获得随机值。还有4010a4: add $0x1,%rax的目的。弄明白这两个基本没有问题。

这题没有固定答案,只要你输入的字符串每个字节低四位依次等于9fe567的二进制表示就行。我的答案:9/.567

Good work! On to the next...

phase6

这是六个语句中最长的一句。总共有三个部分。

部分1

  4010f4:    41 56                    push   %r14
  4010f6:    41 55                    push   %r13
  4010f8:    41 54                    push   %r12
  4010fa:    55                       push   %rbp
  4010fb:    53                       push   %rbx
  4010fc:    48 83 ec 50              sub    $0x50,%rsp
  401100:    49 89 e5                 mov    %rsp,%r13
  401103:    48 89 e6                 mov    %rsp,%rsi
  401106:    e8 51 03 00 00           callq  40145c 
  40110b:    49 89 e6                 mov    %rsp,%r14
  40110e:    41 bc 00 00 00 00        mov    $0x0,%r12d
  401114:    4c 89 ed                 mov    %r13,%rbp # --------------
  401117:    41 8b 45 00              mov    0x0(%r13),%eax
  40111b:    83 e8 01                 sub    $0x1,%eax
  40111e:    83 f8 05                 cmp    $0x5,%eax
  401121:    76 05                    jbe    401128   # 
  401123:    e8 12 03 00 00           callq  40143a 
  401128:    41 83 c4 01              add    $0x1,%r12d
  40112c:    41 83 fc 06              cmp    $0x6,%r12d
  401130:    74 21                    je     401153 
  401132:    44 89 e3                 mov    %r12d,%ebx
  401135:    48 63 c3                 movslq %ebx,%rax
  401138:    8b 04 84                 mov    (%rsp,%rax,4),%eax
  40113b:    39 45 00                 cmp    %eax,0x0(%rbp)
  40113e:    75 05                    jne    401145   # 2 
  401140:    e8 f5 02 00 00           callq  40143a 
  401145:    83 c3 01                 add    $0x1,%ebx
  401148:    83 fb 05                 cmp    $0x5,%ebx
  40114b:    7e e8                    jle    401135 
  40114d:    49 83 c5 04              add    $0x4,%r13
  401151:    eb c1                    jmp    401114   # (%r13+4)-1<=5
  401153:    48 8d 74 24 18           lea    0x18(%rsp),%rsi # [5]
  401158:    4c 89 f0                 mov    %r14,%rax # [0]
  40115b:    b9 07 00 00 00           mov    $0x7,%ecx
  401160:    89 ca                    mov    %ecx,%edx
  401162:    2b 10                    sub    (%rax),%edx # [i]= 7- [i] i start with 0
  401164:    89 10                    mov    %edx,(%rax)  
  401166:    48 83 c0 04              add    $0x4,%rax # i++
  40116a:    48 39 f0                 cmp    %rsi,%rax # while (i!=5) loop.
  40116d:    75 f1                    jne    401160 

检测你输入的数是否大于7,或者是否有重复的。这里有for循环嵌套比较难看懂。接着把每个数-=7。

部分2


  40116f:    be 00 00 00 00           mov    $0x0,%esi # rsi = i
  401174:    eb 21                    jmp    401197 
  # -------------------------------- 
  401176:    48 8b 52 08              mov    0x8(%rdx),%rdx # amazing code!
  40117a:    83 c0 01                 add    $0x1,%eax
  40117d:    39 c8                    cmp    %ecx,%eax
  40117f:    75 f5                    jne    401176 
  # --------------------------------
  401181:    eb 05                    jmp    401188 
  # -----------------------------------------------
  401183:    ba d0 32 60 00           mov    $0x6032d0,%edx
  # ------------------------------------内循环 i 找到a[i]>1的,同时对i++
  401188:    48 89 54 74 20           mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:    48 83 c6 04              add    $0x4,%rsi
  401191:    48 83 fe 18              cmp    $0x18,%rsi # i < 6
  401195:    74 14                    je     4011ab  # jump out from loop
  401197:    8b 0c 34                 mov    (%rsp,%rsi,1),%ecx
  40119a:    83 f9 01                 cmp    $0x1,%ecx
  40119d:    7e e4                    jle    401183 
  # -----------------------------------------------
  # ------------------------------------else
  40119f:    b8 01 00 00 00           mov    $0x1,%eax
  4011a4:    ba d0 32 60 00           mov    $0x6032d0,%edx
  4011a9:    eb cb                    jmp    401176 

将栈上分配6个变量存放链表指针。这里功能最少确是最复杂的。因为引入了复杂数据结构(即使是最简单的),所以让反汇编起来难以理解,特别是双重循环的关系。到底谁是外循环,谁又是内循环,哪个寄存器控制着跳出条件?然后就是慢慢完善c语言,最后让c和汇编的逻辑一一对应。

从gdb看得出来是链表

(gdb) x/6xg 0x7fffffffde40
0x7fffffffde40:    0x00000000006032d0    0x0000000000603320
0x7fffffffde50:    0x0000000000603310    0x0000000000603300
0x7fffffffde60:    0x00000000006032f0    0x00000000006032e0
x/12xg 0x6032d0
0x6032d0 :    0x000000010000014c    0x00000000006032e0
0x6032e0 :    0x00000002000000a8    0x00000000006032f0
0x6032f0 :    0x000000030000039c    0x0000000000603300
0x603300 :    0x00000004000002b3    0x0000000000603310
0x603310 :    0x00000005000001dd    0x0000000000603320
0x603320 :    0x00000006000001bb    0x0000000000000000

部分3

4011ab:    48 8b 5c 24 20           mov    0x20(%rsp),%rbx # b=node1
  4011b0:    48 8d 44 24 28           lea    0x28(%rsp),%rax # 
  4011b5:    48 8d 74 24 50           lea    0x50(%rsp),%rsi #
  4011ba:    48 89 d9                 mov    %rbx,%rcx
  4011bd:    48 8b 10                 mov    (%rax),%rdx #  
  4011c0:    48 89 51 08              mov    %rdx,0x8(%rcx) # 
  4011c4:    48 83 c0 08              add    $0x8,%rax # 
  4011c8:    48 39 f0                 cmp    %rsi,%rax # not 
  4011cb:    74 05                    je     4011d2 
  4011cd:    48 89 d1                 mov    %rdx,%rcx # rcx 
  4011d0:    eb eb                    jmp    4011bd   #  0x6032d0 332
  4011d2:    48 c7 42 08 00 00 00     movq   $0x0,0x8(%rdx) # *(d->next)=0
  4011d9:    00 
  4011da:    bd 05 00 00 00           mov    $0x5,%ebp
  4011df:    48 8b 43 08              mov    0x8(%rbx),%rax
  4011e3:    8b 00                    mov    (%rax),%eax
  4011e5:    39 03                    cmp    %eax,(%rbx)
  4011e7:    7d 05                    jge    4011ee 
  4011e9:    e8 4c 02 00 00           callq  40143a 
  4011ee:    48 8b 5b 08              mov    0x8(%rbx),%rbx
  4011f2:    83 ed 01                 sub    $0x1,%ebp
  4011f5:    75 e8                    jne    4011df 
  4011f7:    48 83 c4 50              add    $0x50,%rsp
  4011fb:    5b                       pop    %rbx
  4011fc:    5d                       pop    %rbp
  4011fd:    41 5c                    pop    %r12
  4011ff:    41 5d                    pop    %r13
  401201:    41 5e                    pop    %r14
  401203:    c3                       retq   

其实这一部分还是可以根据4011d9: 00 分成2部分。第一部分把0x6032d0处的链表连接起来。具体是node6->node1;其余从小到大依次连接。

    mov    0x8(%rbx),%rax
    mov    (%rax),%eax
    cmp    %eax,(%rbx)
    jge    4011ee 
    callq  40143a 

第二部分(上面代码)就是要求前面后四位的要大于后面的。要求node1~node6 数据后4位从大到小排列。即对

(gdb) x/12xg 0x6032d0
0x6032d0 :    0x000000010000014c    0x0000000000603320
0x6032e0 :    0x00000002000000a8    0x00000000006032f0
0x6032f0 :    0x000000030000039c    0x0000000000603300
0x603300 :    0x00000004000002b3    0x0000000000603310
0x603310 :    0x00000005000001dd    0x0000000000603320
0x603320 :    0x00000006000001bb    0x0000000000603310

排列。而这个数据是在第二部放置的。
应该的顺序:3 4 5 6 1 2。然而在部分1会对所有输入-=7。
所以答案:4 3 2 1 6 5
Congratulations! You've defused the bomb!

至此,bomblab主线完成,据说还有一个secret phase .弃。

Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2. Keep going!
Halfway there!
So you got that one. Try this one.
Good work! On to the next...
Congratulations! You've defused the bomb!

你可能感兴趣的:(csapp,asm,反编译)