CSAPP3e - x86-64 assembly code analysis - Bomb Lab: phase 4

来源:互联网 发布:阿里云搭建http代理 编辑:程序博客网 时间:2024/05/02 04:26

先看看phase_4做了什么:

000000000040100c <phase_4>:  40100c:    48 83 ec 18              sub    $0x18,%rsp  401010:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx  401015:    48 8d 54 24 08           lea    0x8(%rsp),%rdx  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 <phase_4+0x29>  40102e:    83 7c 24 08 0e           cmpl   $0xe,0x8(%rsp)  401033:    76 05                    jbe    40103a <phase_4+0x2e> # 0<=num1<=14  401035:    e8 00 04 00 00           callq  40143a <explode_bomb>  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  400fce <func4>  40104d:    85 c0                    test   %eax,%eax  40104f:    75 07                    jne    401058 <phase_4+0x4c> # %rax must be 0  401051:    83 7c 24 0c 00           cmpl   $0x0,0xc(%rsp) # the second num must be 0  401056:    74 05                    je     40105d <phase_4+0x51>  401058:    e8 dd 03 00 00           callq  40143a <explode_bomb>  40105d:    48 83 c4 18              add    $0x18,%rsp  401061:    c3                       retq   
同样将rcx和rdx这两个参数设置好后调用sscanf扫入两个整型数(通过查看0x4025cf也可以验证这一点),并且从401029可以看出必为2个,否则触雷

第一个数字存在rsp+8的位置上,在401033可以看出,jbe将其作为无符号数比较,满足条件才能跳过炸弹,这使得第一个数不能小于0,也不能大于14

其后edx被设为14,esi为0,edi为我们输入的第一个数,然后调用func4:

0000000000400fce <func4>:  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 <func4+0x24>  400fe6:8d 51 ff             lea    -0x1(%rcx),%edx  400fe9:e8 e0 ff ff ff       callq  400fce <func4>  400fee:01 c0                add    %eax,%eax  400ff0:eb 15                jmp    401007 <func4+0x39>  400ff2:b8 00 00 00 00       mov    $0x0,%eax  400ff7:39 f9                cmp    %edi,%ecx  400ff9:7d 0c                jge    401007 <func4+0x39>  400ffb:8d 71 01             lea    0x1(%rcx),%esi  400ffe:e8 cb ff ff ff       callq  400fce <func4>  401003:8d 44 00 01          lea    0x1(%rax,%rax,1),%eax  401007:48 83 c4 08          add    $0x8,%rsp  40100b:c3                   retq   
这个函数做的事情,从400fd2到400fdf是将edx赋值给eax,eax减去esi,然后将eax赋值给ecx,ecx逻辑右移31位(也就是说,它在eax小于0时变为1,否则为0)

接着将eax加上ecx,然后eax除以2,将eax+esi的值赋给ecx

关键的地方400fe2,将此时的ecx与我们输入的第一个数(存在edi那里)作比较,不妨先假设我们输入的数较小会发生什么:

400fe4的jump不会被采用,下一步时将ecx-1赋值给edx后,再调用func4

总结一下,进行到这一步时,rax、rdx和rcx这三个变量,在phase_4中分别为0 14 rsp+12 已经分别变成了7 6 7

也就是,如果要让ecx比第一个数大,我们的数要小于7才行

那接下来会发生什么?调用func4,同样的套路,rax rdx rcx会变成3 2 3

如果我们输入的数比3还要小,又调用func4: rax rdx rcx就成了1 0 1

如果我们输入的数干脆是0:rax rdx rcx成了0 -1 0

这样肯定可以满足ecx<=edi,看看接下来又发生什么

jbe满足,跳到400ff2,eax被赋值为0,

关键又来了,400ff7处比较ecx和edi:

如果ecx大于等于edi(假设我们输入的数是0,显然这时ecx也是0能满足),直接跳到401007结束了,这时eax是0

回到之前存有另外几个func4的栈,类似逐一跳出,400fee处eax乘以2不改变它是0

回到phase_4的40104d,类似我们在phase_1中看到的,需要ZF为0才能避免满足jne的条件触雷,也就是说eax必须为0,这个条件满足

其后401051可见,第二个数必须为0,否则会在401058无法跳过触雷

这样我们就确定了一个解:0 0

如果我们仔细看400fe2和400ff7两处cmp命令及紧跟的jle和jge,不难发现如果edi和ecx两个参数相等,就能直接跳过两次结束func4了,并且400ff2处eax也被赋予了0

可以看出,每次递归调用func4后如果经过处理的ecx能与我们输入的第一个数相等,就能返回正确结果

这样另外几个正确解就是:

1 0

3 0

7 0

有没有其他的解呢?如果我们输入的第一个数大于7,在[8,14]上,那么代入计算可知,ecx会不断变大。

eax edx ecx esi的变化规律是(以输入14为例)(每次在第一个cmp后跳到400ff2前)

7 14 7 8

3 14 11 12

1 14 13 14

0 14 14(这时第二个cmp后jge也满足,故将eax乘以2加1跳出)

但不管在哪一组参数时跳出,在401003处eax都要被赋予2*eax+1的值,这决定了eax最后都不会等于0。

如果第一个数在[0,7]上而有别于之前的正确解呢? 根据之前总结过的,我们知道func4会递归调用到某一层使得ecx小于第一个数,然后满足了第一个jle的条件使得跳到400ff2,进入第二个cmp,这回到了我们上面讲过的类似情况,同样的,由于一定会在第二个cmp后调用过func4后,将eax乘以2加上1,

因此eax不可能返回为0,因此回到第一层func4,400fee处将eax乘以2,eax也不可能为0

所以正确的结果只有:

0 0

1 0

3 0

7 0




0 0
原创粉丝点击