/***************************************************************************
* Dr. Evil's Insidious Bomb, Version 1.1
* Copyright 2011, Dr. Evil Incorporated. All rights reserved.
*
* LICENSE:
*
* Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
* VICTIM) explicit permission to use this bomb (the BOMB). This is a
* time limited license, which expires on the death of the VICTIM.
* The PERPETRATOR takes no responsibility for damage, frustration,
* insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
* harm to the VICTIM. Unless the PERPETRATOR wants to take credit,
* that is. The VICTIM may not distribute this bomb source code to
* any enemies of the PERPETRATOR. No VICTIM may debug,
* reverse-engineer, run "strings" on, decompile, decrypt, or use any
* other technique to gain knowledge of and defuse the BOMB. BOMB
* proof clothing may not be worn when handling this program. The
* PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
* humor. This license is null and void where the BOMB is prohibited
* by law.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"
/*
* Note to self: Remember to erase this file so my victims will have no
* idea what is going on, and so they will all blow up in a
* spectaculary fiendish explosion. -- Dr. Evil
*/
FILE *infile;
int main(int argc, char *argv[])
{
char *input;
/* Note to self: remember to port this bomb to Windows and put a
* fantastic GUI on it. */
/* When run with no arguments, the bomb reads its input lines
* from standard input. */
if (argc == 1) {
infile = stdin;
}
/* When run with one argument <file>, the bomb reads from <file>
* until EOF, and then switches to standard input. Thus, as you
* defuse each phase, you can add its defusing string to <file> and
* avoid having to retype it. */
else if (argc == 2) {
if (!(infile = fopen(argv[1], "r"))) {
printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
exit(8);
}
}
/* You can't call the bomb with more than 1 command line argument. */
else {
printf("Usage: %s [<input_file>]\n", argv[0]);
exit(8);
}
/* Do all sorts of secret stuff that makes the bomb harder to defuse. */
initialize_bomb();
printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
printf("which to blow yourself up. Have a nice day!\n");
/* Hmm... Six phases must be more secure than one phase! */
input = read_line(); /* Get input */
phase_1(input); /* Run the phase */
phase_defused(); /* Drat! They figured it out!
* Let me know how they did it. */
printf("Phase 1 defused. How about the next one?\n");
/* The second phase is harder. No one will ever figure out
* how to defuse this... */
input = read_line();
phase_2(input);
phase_defused();
printf("That's number 2. Keep going!\n");
/* I guess this is too easy so far. Some more complex code will
* confuse people. */
input = read_line();
phase_3(input);
phase_defused();
printf("Halfway there!\n");
/* Oh yeah? Well, how good is your math? Try on this saucy problem! */
input = read_line();
phase_4(input);
phase_defused();
printf("So you got that one. Try this one.\n");
/* Round and 'round in memory we go, where we stop, the bomb blows! */
input = read_line();
phase_5(input);
phase_defused();
printf("Good work! On to the next...\n");
/* This phase will never be used, since no one will get past the
* earlier ones. But just in case, make this one extra hard. */
input = read_line();
phase_6(input);
phase_defused();
/* Wow, they got it! But isn't something... missing? Perhaps
* something they overlooked? Mua ha ha ha ha! */
return 0;
}
phase_1: Border relations with Canada have never been better.
0x400e32 <main+146> callq 0x40149e <read_line>
#在此隨意輸入“asdfghjkl".
#換用stepi命令進入phase_1函數:(后面的phase相同)
0x400e3a <main+154> callq 0x400ee0 <phase_1>
#-----------------------------------------------------------------------------------
#phase_1函數內部:
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 sub $0x8,%rsp
400ee4: be 00 24 40 00 mov $0x402400,%esi
#這里出現了一個內存地址,進行查看:
#(gdb) x/20bc $esi
#0x402400: 66 'B' 111 'o' 114 'r' 100 'd' 101 'e' 114 'r' 32 ' ' 114 'r'
#0x402408: 101 'e' 108 'l' 97 'a' 116 't' 105 'i' 111 'o' 110 'n' 115 's'
#0x402410: 32 ' ' 119 'w' 105 'i' 116 't'
#貌似是一串字符,繼續查看完整得到:Border relations with Canada have never been better.
#猜想該字符串可能是用來比較的
400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>
400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17>
#如果strings_not_equal的返回后eax是0,則不進入explode_bomb,所以我們要進入strings_not_equal看看
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
#注意這里的explode_bomb函數,要避免進入
400ef7: 48 83 c4 08 add $0x8,%rsp
400efb: c3 retq
#-----------------------------------------------------------------------------------
#0000000000401338 <strings_not_equal>:
#401338: 41 54 push %r12
#40133a: 55 push %rbp
#40133b: 53 push %rbx
#40133c: 48 89 fb mov %rdi,%rbx
#40133f: 48 89 f5 mov %rsi,%rbp
#401342: e8 d4 ff ff ff callq 40131b <string_length>
##該處換用nexti,不進入string_length,完成后發現rax變為9,即我們輸入字符串的長度
#401347: 41 89 c4 mov %eax,%r12d
#40134a: 48 89 ef mov %rbp,%rdi
#40134d: e8 c9 ff ff ff callq 40131b <string_length>
##該處rax變為52,即Border relations with Canada have never been better.的長度,隨后比較兩處長度
#401352: ba 01 00 00 00 mov $0x1,%edx
#401357: 41 39 c4 cmp %eax,%r12d
#40135a: 75 3f jne 40139b <strings_not_equal+0x63>
##.........
#到此我們已經可以大致猜想該處答案可能就是Border relations with Canada have never been better.經嘗試,果然如此。
phase_2: 1 2 4 8 16 32
#輸入”asdfghjkl“
0000000000400efc <phase_2>:
400efc: 55 push %rbp
400efd: 53 push %rbx
400efe: 48 83 ec 28 sub $0x28,%rsp
400f02: 48 89 e6 mov %rsp,%rsi
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>
#進入read_six_numbers,看這個名字好像就是讀入六個數字
#-------------------------------------------------------------------
#000000000040145c <read_six_numbers>:
#40145c: 48 83 ec 18 sub $0x18,%rsp
#401460: 48 89 f2 mov %rsi,%rdx
#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
##注意這里的一個內存地址,經查看為字符串:
##0x4025c3: 37 '%' 100 'd' 32 ' ' 37 '%' 100 'd' 32 ' ' 37 '%' 100 'd'
##0x4025cb: 32 ' ' 37 '%' 100 'd' 32 ' ' 37 '%' 100 'd' 32 ' ' 37 '%'
##0x4025d3: 100 'd' 0 '\000'
##明顯為sscanf讀入六個數字的format部分
#401485: b8 00 00 00 00 mov $0x0,%eax
#40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt>
##這里是一個sscanf,nexti跳過即可
#40148f: 83 f8 05 cmp $0x5,%eax
##注意這里在比較了eax是否大於5(即是否讀入了6個數字),當我們第一次的輸入沒有數字時,eax為0,從而引發explode_bomb
#401492: 7f 05 jg 401499 <read_six_numbers+0x3d>
#401494: e8 a1 ff ff ff callq 40143a <explode_bomb>
#401499: 48 83 c4 18 add $0x18,%rsp
#40149d: c3 retq
##由此,我們輸入字符串”1 2 3 4 5 6 7 8 9 0",在該函數內未引爆炸彈,且eax為6.
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
#查看rsp:
#(gdb) x/28bc $rsp
#0x7fffffffdba0: 1 '\001' 0 '\000' 0 '\000' 0 '\000' 2 '\002' 0 '\000' 0 '\000' 0 '\000'
#0x7fffffffdba8: 3 '\003' 0 '\000' 0 '\000' 0 '\000' 4 '\004' 0 '\000' 0 '\000' 0 '\000'
#0x7fffffffdbb0: 5 '\005' 0 '\000' 0 '\000' 0 '\000' 6 '\006' 0 '\000' 0 '\000' 0 '\000'
#0x7fffffffdbb8: 49 '1' 20 '\024' 64 '@' 0 '\000'
#可以發現rsp指向的就是剛剛讀入的6個數字(多余數字並未讀入)
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 callq 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
#首先是比較了第一個讀入的數字是不是1,否則爆炸
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 <phase_2+0x29>
400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
#第三步跳轉到這里,首先將rbx指向的前一個數賦值給eax,並將eax*2,比較rbx指向的數和前一個數的兩倍,如果不相等,就爆炸。
400f25: 48 83 c3 04 add $0x4,%rbx
400f29: 48 39 eb cmp %rbp,%rbx
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
#第四部跳轉到這里,將rbx指向后一個數,並比較rbp rbx的值(是否所有的數都被指向比較了一遍),如果不相等就從剛剛的第三部進行新的比較,否則退出函數。
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
#第二步跳轉到這里,將第二個數的地址給rbx,第六個數后一位的地址給rbp
400f3a: eb db jmp 400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 add $0x28,%rsp
400f40: 5b pop %rbx
400f41: 5d pop %rbp
400f42: c3 retq
#由以上分析可知,該函數就是檢查讀入的前6個數是否是按照*2依次遞增的,並且第一個數還必須是1,所以輸入1 2 4 8 16 32拆除炸彈。
phase_3: 1 311
0000000000400f43 <phase_3>:
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 <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
#這個地方和phase_3很相似,都是讀入兩個數字,否則爆炸,於是輸入“1 2”
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
#查看rsp知,0x8(%rsp)表示讀取的第一個數,0xc(%rsp)表示讀取的第二個數
400f6f: 77 3c ja 400fad <phase_3+0x6a>
#比較第一個是否大於7,如果大於,則發生爆炸。
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
#用第一個數作為switch的條件,判斷該跳轉到jump table的哪個位置,這里rax為1.
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
#第一步跳轉到這里,發現其在比較第二個數是不是0x137,如果是的話就退出函數,於是我們輸入“1 311”即可。
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 retq
phase_4: [0, 1, 3, 7] 0
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>
#跟phase_3一樣,讀入兩個數字,否則爆炸,於是輸入“1 2"
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 callq 40143a <explode_bomb>
#如果第一個數字大於14,就爆炸
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>
#edx=14 esi=0 edi=第一個讀入的數字
#--------------------------------------------------------------------------------
#0000000000400fce <func4>:
#400fce: 48 83 ec 08 sub $0x8,%rsp
#400fd2: 89 d0 mov %edx,%eax
#400fd4: 29 f0 sub %esi,%eax
##eax=14
#400fd6: 89 c1 mov %eax,%ecx
#400fd8: c1 e9 1f shr $0x1f,%ecx
##ecx中是14邏輯右移31位,ecx=0
#400fdb: 01 c8 add %ecx,%eax
##eax=14
#400fdd: d1 f8 sar %eax
##這個地方我犯了一個錯誤,書上說位移操作需要imm8或者%cl來指示位移的個數,這兩個都是要顯示寫出來的,如果單單寫一個位移操作符,默認是位移一位。
##eax=eax>>1=14/2=7
#400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx
##ecx=7+0*1=7
#400fe2: 39 f9 cmp %edi,%ecx
#400fe4: 7e 0c jle 400ff2 <func4+0x24>
##比較7和第一個讀入的數字,如果第一個數字大於等於7,跳至400ff2
#400fe6: 8d 51 ff lea -0x1(%rcx),%edx
##edx=7-1=6
#400fe9: e8 e0 ff ff ff callq 400fce <func4>
##遞歸調用
#400fee: 01 c0 add %eax,%eax
#400ff0: eb 15 jmp 401007 <func4+0x39>
##eax=eax*2 退出函數
#400ff2: b8 00 00 00 00 mov $0x0,%eax
#400ff7: 39 f9 cmp %edi,%ecx
#400ff9: 7d 0c jge 401007 <func4+0x39>
##如果7>=第一個讀入的數,就退出函數,且eax=0
#400ffb: 8d 71 01 lea 0x1(%rcx),%esi
##esi=7+1=8
#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
##首先來看第一個數字小於7的情況,不斷遞歸調用直到第一個數字大於等於ecx(((7-1)/2)-1.....)(7->3->1- >0),跳至400ff2,此時如果ecx大於等於第一個數,則退出函數。所以要想拆除炸彈,可以在小於7的數中間找一 個(並且要能夠等於之后的ecx),所以0 1 3都可以,此時返回的eax為0。
##當數字大於等於7時,直接跳轉到400ff2,可以使第一個數就是7,從而退出函數。
40104d: 85 c0 test %eax,%eax
40104f: 75 07 jne 401058 <phase_4+0x4c>
#如果返回的eax不為0,則爆炸。
401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp)
#比較第二個數是否為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
phase_5: [ionefg]
0000000000401062 <phase_5>:
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
#這個地方是在設置“Stack Canaries”,后面會查看這只“金絲雀”是否被改變了,防止棧溢出攻擊。
401071: 00 00
401073: 48 89 44 24 18 mov %rax,0x18(%rsp)
401078: 31 c0 xor %eax,%eax
40107a: e8 9c 02 00 00 callq 40131b <string_length>
40107f: 83 f8 06 cmp $0x6,%eax
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 callq 40143a <explode_bomb>
#判斷讀入字符串長度是否為6,否則爆炸,於是輸入字符串”abcdef“測試。
401089: eb 47 jmp 4010d2 <phase_5+0x70>
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
#測試rbx是剛剛輸入的字符串的地址:
#(gdb) x/20bc $rbx
#0x6038c0 <input_strings+320>: 97 'a' 98 'b' 99 'c' 100 'd' 101 'e' 102 'f' 0 '\000' 0 '\000'
#所以此時ecx內部為第一個字符
40108f: 88 0c 24 mov %cl,(%rsp)
401092: 48 8b 14 24 mov (%rsp),%rdx
401096: 83 e2 0f and $0xf,%edx
#此時edx內為字符ascii碼十六進制的低位。
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx
#測試0x4024b0這個地址:
#(gdb) x/s 0x4024b0
#0x4024b0 <array.3449>: "maduiersnfotvbylSo you think you can stop the bomb with ctrl- #c, do you?"
#注意到”maduiersnfotvbyl“剛好是16個,代表字母十六進制低位的16種可能。所以說,這里就是將字母的十六進制低位加上0x4024b0這個基地址選出的字母放到edx中。
4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)
#驗證rsp對應內容:為雜亂序列,這里就是將剛剛生成的分別6個字母分別放到以rsp+0x10為基地址的內存中。
4010a4: 48 83 c0 01 add $0x1,%rax
4010a8: 48 83 f8 06 cmp $0x6,%rax
4010ac: 75 dd jne 40108b <phase_5+0x29>
#此處為一個6次的循環
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp)
#0x16=0x10+6將剛剛生成的6個字母形成一個字符串。
4010b3: be 5e 24 40 00 mov $0x40245e,%esi
#(gdb) x/s 0x40245e
#0x40245e: "flyers" 這可能就是等會要比較的字符串了
4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
#rdi指向剛剛生成的新字符串
4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>
4010c2: 85 c0 test %eax,%eax
#測試兩個字符串是否相等
4010c4: 74 13 je 4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov $0x0,%eax
4010d7: eb b2 jmp 40108b <phase_5+0x29>
#第一步跳到這里,就是把eax置了個0 。。。
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 <phase_5+0x8c>
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
#由以上分析,maduiersnfotvbyl分別對應低位為0123456789ABCDEF的字符,所以為了生成”flyers“字符串,低位必須為”9FE567“,例如”ionefg“就可以。(查ascii碼表)
phase_6: 4 3 2 1 6 5
00000000004010f4 <phase_6>:
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 <read_six_numbers>
#以rsp為基地址(棧)讀取六個數字。
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 <phase_6+0x34>
401123: e8 12 03 00 00 callq 40143a <explode_bomb>
401128: 41 83 c4 01 add $0x1,%r12d
40112c: 41 83 fc 06 cmp $0x6,%r12d
401130: 74 21 je 401153 <phase_6+0x5f>
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 <phase_6+0x51>
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>
401145: 83 c3 01 add $0x1,%ebx
401148: 83 fb 05 cmp $0x5,%ebx
40114b: 7e e8 jle 401135 <phase_6+0x41>
#這個上面是一個嵌套循環,外側循環6次,分別測試讀入的數字是否小於等於6(實際是無符號數減1后是否小於等 #於5,所以0是不行的),內部的循環比較當前的數字和剩下的數字是否相同。總結起來就是要求這六個數字各不相 #同,且大於0小於7,所以這六個數字可以是123456的組合。
40114d: 49 83 c5 04 add $0x4,%r13
401151: eb c1 jmp 401114 <phase_6+0x20>
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi
401158: 4c 89 f0 mov %r14,%rax
40115b: b9 07 00 00 00 mov $0x7,%ecx
401160: 89 ca mov %ecx,%edx
401162: 2b 10 sub (%rax),%edx
401164: 89 10 mov %edx,(%rax)
401166: 48 83 c0 04 add $0x4,%rax
40116a: 48 39 f0 cmp %rsi,%rax
40116d: 75 f1 jne 401160 <phase_6+0x6c>
#上面這個循環是依次將剛剛讀入的六個數字將7作為被減數得到的結果。如輸入654321將得到123456.
40116f: be 00 00 00 00 mov $0x0,%esi
401174: eb 21 jmp 401197 <phase_6+0xa3>
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx
40117a: 83 c0 01 add $0x1,%eax
40117d: 39 c8 cmp %ecx,%eax
40117f: 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov $0x6032d0,%edx
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
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
40119a: 83 f9 01 cmp $0x1,%ecx
40119d: 7e e4 jle 401183 <phase_6+0x8f>
40119f: b8 01 00 00 00 mov $0x1,%eax
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx
4011a9: eb cb jmp 401176 <phase_6+0x82>
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
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
4011cb: 74 05 je 4011d2 <phase_6+0xde>
4011cd: 48 89 d1 mov %rdx,%rcx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
4011d9: 00
#上面這一段是本實驗最難理解的部分,循環的大致意思是設置0x6032d0為基地址的內存模塊和以rsp為基地址的內存模塊保存剛剛輸入的數字和0x6032d0/e0/f0 0x603300/10/20,其實並不用完全弄懂該部分,結合下面的”爆炸導火索“更好理解一些。
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 <phase_6+0xfa>
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011f2: 83 ed 01 sub $0x1,%ebp
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
#當輸入123456
#(gdb) x/20wx $rsp
#0x7fffffffdb60: 0x00000006 0x00000005 0x00000004 0x00000003
#0x7fffffffdb70: 0x00000002 0x00000001 0x00000000 0x00000000
#0x7fffffffdb80: 0x00603320 0x00000000 0x00603310 0x00000000
#0x7fffffffdb90: 0x00603300 0x00000000 0x006032f0 0x00000000
#0x7fffffffdba0: 0x006032e0 0x00000000 0x006032d0 0x00000000
# (gdb) x/20wx $rdx
#0x6032d0 <node1>: 0x0000014c 0x00000001 0x00000000 0x00000000
#0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032d0 0x00000000
#0x6032f0 <node3>: 0x0000039c 0x00000003 0x006032e0 0x00000000
#0x603300 <node4>: 0x000002b3 0x00000004 0x006032f0 0x00000000
#0x603310 <node5>: 0x000001dd 0x00000005 0x00603300 0x00000000
#0x603320 <node6>: 0x000001bb 0x00000006 0x00603310 0x00000000
#該測試循環是這樣工作的,從棧中后部的第一個地址開始(這里地址1是0x00603320)判讀(地址1)>=((地址1+0x8)),注意有兩層括號,是否成立,不成立即爆炸,若成立,則令地址1=(地址1+0x8),進行下一次循環。在這個例子中,由於1bb<1dd,發生爆炸。於是乎我們的任務就變成了尋找地址1是哪一個的規律以及地址+0x8保存的是哪些地址的規律。
#輸入654321后,得到:
#(gdb) x/24wx $rsp
#0x7fffffffdb60: 0x00000001 0x00000002 0x00000003 0x00000004
#0x7fffffffdb70: 0x00000005 0x00000006 0x00000000 0x00000000
#0x7fffffffdb80: 0x006032d0 0x00000000 0x006032e0 0x00000000
#0x7fffffffdb90: 0x006032f0 0x00000000 0x00603300 0x00000000
#0x7fffffffdba0: 0x00603310 0x00000000 0x00603320 0x00000000
#0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
#0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032f0 0x00000000
#0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
#0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
#0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
#0x603320 <node6>: 0x000001bb 0x00000006 0x00000000 0x00000000
#結合動態運行可知,地址1為rsp后面保存的第一個地址,並且將依次將隨后的5個地址存入0x60...+0x8的地方。結合之前123456的測試,這里可以觀察到,7-x操作后數字與地址對應關系:
# 1 - > 0x6032d0
# 2 - > 0x6032e0
# 3 - > 0x6032f0
# 4 - > 0x603300
# 5 - > 0x603310
# 6 - > 0x603320
#現在結合上面循環測試的規則,我們對(0x603...)的六個常數進行排列:0x0000039c > 0x000002b3 > 0x000001dd > 0x000001bb > 0x0000014c > 0x000000a8,用地址表示就是(0x6032f0) > (0x603300) > (0x603310) > (0x603320) > (0x6032d0) > (0x6032e0)
#所以我們應該得到這樣一個內存:
#0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
#0x6032e0 <node2>: 0x000000a8 0x00000002 0x00000000 0x00000000
#0x6032e0+0x8應該是0,因為0x0a8它是最小的了,且只比較5次。
#0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
#0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
#0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
#0x603320 <node6>: 0x000001bb 0x00000006 0x006032d0 0x00000000
#即得到這樣一個棧空間:
#0x7fffffffdb60: xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx
#0x7fffffffdb70: xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx
#0x7fffffffdb80: 0x006032f0 0x00000000 0x00603300 0x00000000
#0x7fffffffdb90: 0x00603310 0x00000000 0x00603320 0x00000000
#0x7fffffffdba0: 0x006032d0 0x00000000 0x006032e0 0x00000000
#由於:
# 1 - > 0x6032d0
# 2 - > 0x6032e0
# 3 - > 0x6032f0
# 4 - > 0x603300
# 5 - > 0x603310
# 6 - > 0x603320
#所以7-x操作后應該是345612,即應該輸入432165。
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
綜上,輸入文件應該如下:
psol.txt
Border relations with Canada have never been better.
1 2 4 8 16 32
1 311
0 0
ionefg
4 3 2 1 6 5
運行輸出:(也可以手動輸入)
frank@under:~/Desktop/cs:app/lab/bomblab$ ./bomb psol.txt
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!
\[2017.10.27]更新:學校重新安排了一次相似的實驗,只是把一些常量改變了,然后添加了一個“secret_phase”。這次把最后一個階段將輸入逐個7減后的算法詳細分析下,上次是利用結果推測過程,沒有具體研究算法。
注:下面分析的第六階段我們學校改過的,密碼每個人都不一樣(這個的bomb_id為0x28),但算法是和cmu的那個炸彈一樣的。secret階段原CMU炸彈並沒有
..........(參見前文)
#后部分的代碼主要分兩個算法
#“混淆算法開始”
#混淆階段1
40116e: be 00 00 00 00 mov $0x0,%esi
401173: eb 1a jmp 40118f <phase_6+0xad>
401175: 48 8b 52 08 mov 0x8(%rdx),%rdx
401179: 83 c0 01 add $0x1,%eax
40117c: 39 c8 cmp %ecx,%eax
40117e: 75 f5 jne 401175 <phase_6+0x93>
401180: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
401185: 48 83 c6 04 add $0x4,%rsi
401189: 48 83 fe 18 cmp $0x18,%rsi
40118d: 74 14 je 4011a3 <phase_6+0xc1>
40118f: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
401192: b8 01 00 00 00 mov $0x1,%eax
401197: ba f0 32 60 00 mov $0x6032f0,%edx
40119c: 83 f9 01 cmp $0x1,%ecx
40119f: 7f d4 jg 401175 <phase_6+0x93>
4011a1: eb dd jmp 401180 <phase_6+0x9e>
#混淆階段2
4011a3: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
4011a8: 48 8d 44 24 20 lea 0x20(%rsp),%rax
4011ad: 48 8d 74 24 48 lea 0x48(%rsp),%rsi
4011b2: 48 89 d9 mov %rbx,%rcx
4011b5: 48 8b 50 08 mov 0x8(%rax),%rdx
4011b9: 48 89 51 08 mov %rdx,0x8(%rcx)
4011bd: 48 83 c0 08 add $0x8,%rax
4011c1: 48 89 d1 mov %rdx,%rcx
4011c4: 48 39 c6 cmp %rax,%rsi
4011c7: 75 ec jne 4011b5 <phase_6+0xd3>
4011c9: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
#驗證算法開始
4011d0: 00
4011d1: bd 05 00 00 00 mov $0x5,%ebp
4011d6: 48 8b 43 08 mov 0x8(%rbx),%rax
4011da: 8b 00 mov (%rax),%eax
4011dc: 39 03 cmp %eax,(%rbx)
4011de: 7d 05 jge 4011e5 <phase_6+0x103>
4011e0: e8 52 02 00 00 callq 401437 <explode_bomb>
4011e5: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011e9: 83 ed 01 sub $0x1,%ebp
4011ec: 75 e8 jne 4011d6 <phase_6+0xf4>
.......(見前文)
經過前面的7減算法后,我們如果輸入1 6 2 5 3 4, 7減后為6 1 5 2 4 3,查看rsp為:
另外注意到這一句話有一個常量地址
401197: ba f0 32 60 00 mov $0x6032f0,%edx
查看該地址內容:
可以觀察到每一行(16個字節)是由 4字節xxx常數 + 4字節1~6 + 下一個16字節的地址(除了最后一個16字節除外)
分析混淆算法的第一階段
40116e: be 00 00 00 00 mov $0x0,%esi
401173: eb 1a jmp 40118f <phase_6+0xad>
#小循環(根據取到的數在0x6032f0起始的內存塊中尋找第幾個地址,例如為5的話就是0x6032f0 + (5-1)*16 + 8代表的0x603330
401175: 48 8b 52 08 mov 0x8(%rdx),%rdx
401179: 83 c0 01 add $0x1,%eax
40117c: 39 c8 cmp %ecx,%eax
40117e: 75 f5 jne 401175 <phase_6+0x93>
#大循環,取出六個數,如果是1的話直接在棧中append 0x6032f0這個地址(最小的那個),否則進入上面的小循環取得一個地址然后append到棧中。
401180: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
401185: 48 83 c6 04 add $0x4,%rsi
401189: 48 83 fe 18 cmp $0x18,%rsi
40118d: 74 14 je 4011a3 <phase_6+0xc1>
40118f: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
401192: b8 01 00 00 00 mov $0x1,%eax
401197: ba f0 32 60 00 mov $0x6032f0,%edx
40119c: 83 f9 01 cmp $0x1,%ecx
40119f: 7f d4 jg 401175 <phase_6+0x93>
4011a1: eb dd jmp 401180 <phase_6+0x9e>
所以,我們如果輸入的是1 6 2 5 3 4,7減操作后為 6 1 5 2 4 3,棧中就應該被依次append
3340
32f0
3330
3300
3320
3310
如圖:
接着分析混淆算法的第二階段
4011a3: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx #棧中第一個append進的地址
4011a8: 48 8d 44 24 20 lea 0x20(%rsp),%rax #棧中第一個append進的地址的地址
4011ad: 48 8d 74 24 48 lea 0x48(%rsp),%rsi #棧中最后一個append進的地址的地址
4011b2: 48 89 d9 mov %rbx,%rcx #第一個append進的地址
#開始循環直到最后一個append進的地址也存入0x6032f0起始的內存塊中
4011b5: 48 8b 50 08 mov 0x8(%rax),%rdx
4011b9: 48 89 51 08 mov %rdx,0x8(%rcx) #將rax指向的下一個地址存入0x6032f0起始的內存塊中
4011bd: 48 83 c0 08 add $0x8,%rax #更新使rax指向棧中下一個之前存入的地址
4011c1: 48 89 d1 mov %rdx,%rcx #這次存入的地址變為下次要存入的基地址
4011c4: 48 39 c6 cmp %rax,%rsi
4011c7: 75 ec jne 4011b5 <phase_6+0xd3>
4011c9: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
由上面的棧圖,我們的操作就是(用<-代表寫入):603340+8<-6032f0 6032f0+8<-603330 603330+8<-603300 603300+8<-603320 603320+8<-603310 而603310+8原本存儲的603320沒改變為0,驗證:
開始分析導火索(驗證算法)
4011d0: 00
4011d1: bd 05 00 00 00 mov $0x5,%ebp #設計循環量為5次
#開始循環
4011d6: 48 8b 43 08 mov 0x8(%rbx),%rax #第一次rbx保存的是第一個存入棧中的地址,rax將變為rbx+8中保存的地址
4011da: 8b 00 mov (%rax),%eax
4011dc: 39 03 cmp %eax,(%rbx)
4011de: 7d 05 jge 4011e5 <phase_6+0x103> #rbx指向的常數必須大於等於rbx+8指向的常數,否則爆炸
4011e0: e8 52 02 00 00 callq 401437 <explode_bomb>
4011e5: 48 8b 5b 08 mov 0x8(%rbx),%rbx #將rbx替換為rbx+8保存的地址
4011e9: 83 ed 01 sub $0x1,%ebp
4011ec: 75 e8 jne 4011d6 <phase_6+0xf4>
逆推構建輸入
由導火索算法的分析,又因為常量如下:
2e4(0x603310) > 257(0x6032f0) > 235(0x603330) > 169(0x603300) > 098(0x603340) > 05b(0x603320)
所以我們應該將0x6032f0起始的內存塊構建為這個樣子:
0x6032f0 <node1>: 0x0000000100000257 0x0000000000603330
0x603300 <node2>: 0x0000000200000169 0x0000000000603340
0x603310 <node3>: 0x00000003000002e4 0x00000000006032f0
0x603320 <node4>: 0x000000040000005b 0x0000000000000000
0x603330 <node5>: 0x0000000500000235 0x0000000000603300
0x603340 <node6>: 0x0000000600000098 0x0000000000603320
即我們的存入操作為:603310+8<-6032f0 6032f0+8<-603330 603330+8<-603300 603300+8<-603340 603340+8<-603320
由混淆算法的第二階段分析,我們的存入我們的棧append的地址應該是這個順序:
603310 6032f0 603330 603300 603340 603320
由混淆算法的第一階段分析,我們我們輸入的數字7減操作后應該為:
3 1 5 2 6 4
所以減7前的密碼為:4 6 2 5 1 3
secret_phase
默認情況下並不能激發隱藏關卡:
在bomb的反匯編代碼內找到調用secret_phase
的函數,居然是phase_defused
...
phase_defused
內關鍵的代碼:
4015fe: be c2 25 40 00 mov $0x4025c2,%esi
401603: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
401608: e8 2b fd ff ff callq 401338 <strings_not_equal>
40160d: 85 c0 test %eax,%eax
40160f: 75 1e jne 40162f <phase_defused+0x71>
401611: bf 98 24 40 00 mov $0x402498,%edi
401616: e8 c5 f4 ff ff callq 400ae0 <puts@plt>
40161b: bf c0 24 40 00 mov $0x4024c0,%edi
401620: e8 bb f4 ff ff callq 400ae0 <puts@plt>
401625: b8 00 00 00 00 mov $0x0,%eax
40162a: e8 1f fc ff ff callq 40124e <secret_phase>
注意到常數地址0x4025c2。
所以phase_defused應該是讀入了字符,判斷是否等於DrEvil,相等的話就進入隱藏關卡。
於是我們在phase_defused
中尋找是否有讀入的命令,發現就在上面相鄰處有:
4015ea: be b9 25 40 00 mov $0x4025b9,%esi
4015ef: bf 90 38 60 00 mov $0x603890,%edi
4015f4: e8 b7 f5 ff ff callq 400bb0 <__isoc99_sscanf@plt>
4015f9: 83 f8 03 cmp $0x3,%eax
4015fc: 75 31 jne 40162f <phase_defused+0x71>
查看0x4025b9
可見是讀入兩個整數和一個字符串
查看0x603890
就是我在第四階段輸入的密碼——兩個整數,所以我們在第四階段輸入10 5 DrEvil即可進入隱藏關卡:
分析隱藏關卡的算法
000000000040124e <secret_phase>:
40124e: 53 push %rbx
40124f: e8 44 02 00 00 callq 401498 <read_line> #讀入一行數據
401254: ba 0a 00 00 00 mov $0xa,%edx
401259: be 00 00 00 00 mov $0x0,%esi
40125e: 48 89 c7 mov %rax,%rdi
401261: e8 2a f9 ff ff callq 400b90 <strtol@plt> #將讀入的數據轉化為整數
401266: 48 89 c3 mov %rax,%rbx
401269: 8d 40 ff lea -0x1(%rax),%eax
40126c: 3d e8 03 00 00 cmp $0x3e8,%eax #不能讀入0x3e8+1 = 1001
401271: 76 05 jbe 401278 <secret_phase+0x2a>
401273: e8 bf 01 00 00 callq 401437 <explode_bomb>
401278: 89 de mov %ebx,%esi #參數二為剛剛讀入的數
40127a: bf 10 31 60 00 mov $0x603110,%edi #參數一為
40127f: e8 8c ff ff ff callq 401210 <fun7>
401284: 83 f8 03 cmp $0x3,%eax #必須返回3
401287: 74 05 je 40128e <secret_phase+0x40>
401289: e8 a9 01 00 00 callq 401437 <explode_bomb>
.......
檢查調用fun7
傳入的第一個參數0x603110
進入fun7
(必須返回3)
0000000000401210 <fun7>:
401210: 48 83 ec 08 sub $0x8,%rsp
401214: 48 85 ff test %rdi,%rdi
401217: 74 2b je 401244 <fun7+0x34> #第一次由secret_phase調用的話,不可能為0
401219: 8b 17 mov (%rdi),%edx #0x24
40121b: 39 f2 cmp %esi,%edx #比較讀入的數和0x24
40121d: 7e 0d jle 40122c <fun7+0x1c>
40121f: 48 8b 7f 08 mov 0x8(%rdi),%rdi
401223: e8 e8 ff ff ff callq 401210 <fun7> #又是TMD的遞歸。。史老師您就這么熱愛遞歸嘛。。。(我們學校把第4階段也改成了遞歸)
401228: 01 c0 add %eax,%eax
40122a: eb 1d jmp 401249 <fun7+0x39>
40122c: b8 00 00 00 00 mov $0x0,%eax
401231: 39 f2 cmp %esi,%edx
401233: 74 14 je 401249 <fun7+0x39>
401235: 48 8b 7f 10 mov 0x10(%rdi),%rdi
401239: e8 d2 ff ff ff callq 401210 <fun7>
40123e: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401242: eb 05 jmp 401249 <fun7+0x39>
401244: b8 ff ff ff ff mov $0xffffffff,%eax
401249: 48 83 c4 08 add $0x8,%rsp
40124d: c3 retq
為了方便分析算法,抽象成偽代碼:
需要返回3,初始rdi=0x603110,esi = input_number, eax=input_number-1
若rdi=0,返回eax = -1
edx = (rdi)
若rdi指向的常數小於等於input_number,跳L1
rdi += 8;
遞歸
eax = eax*2
return
L1: eax = 0
如果esi=edx,return
rdi = (%rdi+0x10)
遞歸
eax = 2*eax+1
return
eax = -1
return
可以觀察到,返回值只有eax = eax*2(偶數)eax = 2*eax+1(奇數)和-1與0這四種情況,所以為了獲得3的返回值,我們的遞歸順序應該如下:
返回3: 2*1 + 1 -> 返回1: 2*0 + 1 -> 返回0 : 0*2 -> eax=0, esi=edx,return
觀察0x603110起始的內存塊:
0x603110 <n1>: 0x0000000000000024 0x0000000000603130
0x603120 <n1+16>: 0x0000000000603150 0x0000000000000000
0x603130 <n21>: 0x0000000000000008 0x00000000006031b0
0x603140 <n21+16>: 0x0000000000603170 0x0000000000000000
0x603150 <n22>: 0x0000000000000032 0x0000000000603190
0x603160 <n22+16>: 0x00000000006031d0 0x0000000000000000
0x603170 <n32>: 0x0000000000000016 0x0000000000603290
0x603180 <n32+16>: 0x0000000000603250 0x0000000000000000
0x603190 <n33>: 0x000000000000002d 0x00000000006031f0
0x6031a0 <n33+16>: 0x00000000006032b0 0x0000000000000000
0x6031b0 <n31>: 0x0000000000000006 0x0000000000603210
0x6031c0 <n31+16>: 0x0000000000603270 0x0000000000000000
0x6031d0 <n34>: 0x000000000000006b 0x0000000000603230
0x6031e0 <n34+16>: 0x00000000006032d0 0x0000000000000000
0x6031f0 <n45>: 0x0000000000000028 0x0000000000000000
0x603200 <n45+16>: 0x0000000000000000 0x0000000000000000
0x603210 <n41>: 0x0000000000000001 0x0000000000000000
0x603220 <n41+16>: 0x0000000000000000 0x0000000000000000
0x603230 <n47>: 0x0000000000000063 0x0000000000000000
0x603240 <n47+16>: 0x0000000000000000 0x0000000000000000
0x603250 <n44>: 0x0000000000000023 0x0000000000000000
.......
按照遞歸分析逐步寫出rdi的變化和對input_number的限制條件的縮小:
%rdi : 0x603110 -> 0x603150 -> 0x6031d0 -> 603230
input_number的范圍:input_number >= 0x24 (要跳L1)input_number != 0x24-> input_number >= 0x32 (要跳L1)input_number != 0x32 -> input_number < 0x6b(不能跳L1)-> input_number >= 0x63(要跳L1)input_number = edx = 0x63
所以,密碼應該為0x63即99。