ディレクトリ
爆弾を解体CS APP実験2、
ここでgdbデバッガによるLinux環境が行われます
GDBデバッグモードを入力してください
入力端子$ gdb bomb
主な機能を見ます
エントリー(gdb) list main
初期化関数が見つかりinitialize_bomb()
、2つのprint
、出力プロンプト、および続くinput = read_line()
、我々は、パラメータ入力として呼び出しますphase_1
機能。
これはphase_1
、関数のコンパイルを参照して、入力チェックの関数であること。
phase_1機能
- エントリー
(gdb) disassemble phase_1
出力は以下の
Dump of assembler code for function phase_1:
0x08048b80 <+0>: push %ebp
0x08048b81 <+1>: mov %esp,%ebp
0x08048b83 <+3>: sub $0x8,%esp
0x08048b86 <+6>: movl $0x8049928,0x4(%esp)
0x08048b8e <+14>: mov 0x8(%ebp),%eax
0x08048b91 <+17>: mov %eax,(%esp)
0x08048b94 <+20>: call 0x8049067 <strings_not_equal>
0x08048b99 <+25>: test %eax,%eax
0x08048b9b <+27>: je 0x8048ba2 <phase_1+34>
0x08048b9d <+29>: call 0x804962e <explode_bomb>
0x08048ba2 <+34>: leave
0x08048ba3 <+35>: ret
End of assembler dump.
- 二つのレジスタの現在の内容は、EBPをプッシュする前に、前記ESPポインタレジスタとベースレジスタおよび修飾現在のスタックアドレスEBPスタック。
現在の状態
栈底方向^
...
main
...
参数
旧ebp <- ebp, esp寄存器
- スタックポインタ移動の3行目8つのバイト
栈底方向^
...
旧ebp <- ebp
空
空 <- esp寄存器
- mov命令と、2つの2つの値がある一つが、位置にスタックから空気ある
0x08049928
他は、積層方向の底に8バイトEBPスタックコンテンツのオフセット、つまり、私たちの引数であるに基づいていますinput
栈底方向^
...
旧ebp <- ebp
0x8049928
0x8(%ebp) <- esp寄存器
- そして、関数を呼び出す
<strings_not_equal>
ので、私たちはメモリ内にある0x08049928
コンテンツを表示するため、私たちは爆弾を解体する必要がある文字列です。
(gdb) x/s 0x8049928
答案是:私たちは...十億を作ることができるのに、なぜ兆を作りますか?
phase_2機能
- エントリー
(gdb) disassemble phase_1
0x08048ba4 <+0>: push %ebp
0x08048ba5 <+1>: mov %esp,%ebp
0x08048ba7 <+3>: sub $0x28,%esp
0x08048baa <+6>: movl $0x0,-0x4(%ebp)
0x08048bb1 <+13>: lea -0x20(%ebp),%eax
0x08048bb4 <+16>: mov %eax,0x4(%esp)
0x08048bb8 <+20>: mov 0x8(%ebp),%eax
0x08048bbb <+23>: mov %eax,(%esp)
0x08048bbe <+26>: call 0x8048fd4 <read_six_numbers>
0x08048bc3 <+31>: movl $0x0,-0x8(%ebp)
0x08048bca <+38>: jmp 0x8048bf3 <phase_2+79>
0x08048bcc <+40>: mov -0x8(%ebp),%eax
0x08048bcf <+43>: mov -0x20(%ebp,%eax,4),%edx
0x08048bd3 <+47>: mov -0x8(%ebp),%eax
0x08048bd6 <+50>: add $0x3,%eax
0x08048bd9 <+53>: mov -0x20(%ebp,%eax,4),%eax
0x08048bdd <+57>: cmp %eax,%edx
0x08048bdf <+59>: je 0x8048be6 <phase_2+66>
0x08048be1 <+61>: call 0x804962e <explode_bomb>
0x08048be6 <+66>: mov -0x8(%ebp),%eax
0x08048be9 <+69>: mov -0x20(%ebp,%eax,4),%eax
0x08048bed <+73>: add %eax,-0x4(%ebp)
0x08048bf0 <+76>: incl -0x8(%ebp)
0x08048bf3 <+79>: cmpl $0x2,-0x8(%ebp)
0x08048bf7 <+83>: jle 0x8048bcc <phase_2+40>
0x08048bf9 <+85>: cmpl $0x0,-0x4(%ebp)
0x08048bfd <+89>: jne 0x8048c04 <phase_2+96>
0x08048bff <+91>: call 0x804962e <explode_bomb>
0x08048c04 <+96>: leave
0x08048c05 <+97>: ret
sub $0x28,%esp
まず、下向きポインタSP空いた空間40bはM0〜M9と呼ばれる便宜上の0x28、32ビットシステム、10単位の合計であります
movl $0x0,-0x4(%ebp)
番号0Hユニットは、ゼロに設定され、すなわち
M0=0
lea -0x20(%ebp),%eax; mov %eax,0x4(%esp)
7番アドレスユニットは、8番のセルに割り当てられています。すなわち、
M8=&M7
M8は、配列へのポインタであってもよく、それは推論することができ、M7は、配列の最初のアドレスです。mov 0x8(%ebp),%eax;mov %eax,(%esp);call 0x8048fd4 <read_six_numbers>
最後のユニットM9で引数、およびその関数を呼び出すには、6桁の数字をお読みください。正確に10 6個の素子のアレイからなる6つのユニットを、残り、それは我々がA0〜A5になるM6〜M2に入れなければなりません。
$movl 0x0,-0x8(%ebp)
番号1、M1 = 0をゼロ
$cmpl 0x2,-0x8(%ebp);jle 0x8048bcc <phase_2+40>
M1及び第2比較器、ループ条件は以下であります
mov -0x8(%ebp),%eax; mov -0x20(%ebp,%eax,4),%edx
値EBP-20 + 4 * M1 EDXに、実際には、EDX = A [M1]
-0x8(%ebp),%eax; add $0x3,%eax; mov -0x20(%ebp,%eax,4),%eax
EAX = A [M1 + 3]
cmp %eax,%edx; je 0x8048be6 <phase_2+66>; call 0x804962e <explode_bomb>
このコールexploed_bombと等しくない場合は、EAXとEDXの比較
mov -0x8(%ebp),%eax; mov -0x20(%ebp,%eax,4),%eax; add %eax,-0x4(%ebp); incl -0x8(%ebp)
A [M1]はM0、M1書き込まれる++
推論によって、など本来の機能は、以下の
void phase_2(char* input){
int result = 0;
int a[6];
input >> a;
for(int i=0;i<=2;i++){
if (a[i]!=a[i+3])
bomb();
result += a[i];
}
if(reuslt == 0)
bomb()
}
そう答えは、6つの要素の配列、[I]、およびである[I + 3]と同じ、及び和([0]、 [1]、[2])!= 0 とすることができます。
1 2 3 1 2 3
または1 1 1 1 1 1
phase_3機能
Dump of assembler code for function phase_3:
0x08048c06 <+0>: push %ebp
0x08048c07 <+1>: mov %esp,%ebp
0x08048c09 <+3>: sub $0x28,%esp
0x08048c0c <+6>: movl $0x0,-0x8(%ebp)
0x08048c13 <+13>: movl $0x0,-0x4(%ebp)
0x08048c1a <+20>: lea -0x10(%ebp),%eax
0x08048c1d <+23>: mov %eax,0xc(%esp)
0x08048c21 <+27>: lea -0xc(%ebp),%eax
0x08048c24 <+30>: mov %eax,0x8(%esp)
0x08048c28 <+34>: movl $0x804995b,0x4(%esp)
0x08048c30 <+42>: mov 0x8(%ebp),%eax
0x08048c33 <+45>: mov %eax,(%esp)
0x08048c36 <+48>: call 0x8048868 <sscanf@plt>
0x08048c3b <+53>: mov %eax,-0x4(%ebp)
0x08048c3e <+56>: cmpl $0x1,-0x4(%ebp)
0x08048c42 <+60>: jg 0x8048c49 <phase_3+67>
0x08048c44 <+62>: call 0x804962e <explode_bomb>
0x08048c49 <+67>: mov -0xc(%ebp),%eax
0x08048c4c <+70>: mov %eax,-0x14(%ebp)
0x08048c4f <+73>: cmpl $0x7,-0x14(%ebp)
0x08048c53 <+77>: ja 0x8048c98 <phase_3+146>
0x08048c55 <+79>: mov -0x14(%ebp),%edx
0x08048c58 <+82>: mov 0x8049964(,%edx,4),%eax
0x08048c5f <+89>: jmp *%eax
0x08048c61 <+91>: addl $0x2cc,-0x8(%ebp)
0x08048c68 <+98>: subl $0x3a9,-0x8(%ebp)
0x08048c6f <+105>: addl $0x12f,-0x8(%ebp)
0x08048c76 <+112>: subl $0xcb,-0x8(%ebp)
0x08048c7d <+119>: addl $0x5d,-0x8(%ebp)
0x08048c81 <+123>: subl $0x2f4,-0x8(%ebp)
0x08048c88 <+130>: addl $0x2f4,-0x8(%ebp)
0x08048c8f <+137>: subl $0x207,-0x8(%ebp)
0x08048c96 <+144>: jmp 0x8048c9d <phase_3+151>
0x08048c98 <+146>: call 0x804962e <explode_bomb>
0x08048c9d <+151>: mov -0xc(%ebp),%eax
0x08048ca0 <+154>: cmp $0x5,%eax
0x08048ca3 <+157>: jg 0x8048cad <phase_3+167>
0x08048ca5 <+159>: mov -0x10(%ebp),%eax
0x08048ca8 <+162>: cmp %eax,-0x8(%ebp)
0x08048cab <+165>: je 0x8048cb2 <phase_3+172>
0x08048cad <+167>: call 0x804962e <explode_bomb>
0x08048cb2 <+172>: leave
0x08048cb3 <+173>: ret
End of assembler dump.
0x08048c06 ~ 0x08048c36
次のように、アプリケーション10ワード(4B /ワード)空間であった
M0=0, M1=0, M6=&M3, M7=&M2,M8=0x804995b, M9=%ebp+8
(依然としてEBP-を0x4からEBP-の0x28に、部4Bとしてそれぞれ)、およびその関数を呼び出しますsscanf
。パラメータとしてM9が入力された我々の規則、未知M8、M7、M2は、逆の順序でスタックのパラメータので、M2、M3にポインタ値を渡します。
私たちは、内容M8(0x804995b)のを確認してください
文字列「%D%D」が格納されている、見つけることができます
これは正確に二つのポインタによって達成される私たちの2つのデジタル入力と2つのデジタル転送を伝えます。
0x08048c3b~0x08048c44
上の
sscanf
1より大きいかどうかを確認するためのチェックの結果、そうでない場合は、コール爆弾()0x08048c49~0x08048c53
チェックするNUM1は7以上ではないが必要です。
0x08048c55~0x08048c5f
無条件ジャンプステートメントは、(NUM1が4 + 0x8049964 *)、注意が外にジャンプし
*
、分岐先がないnum1*4+0x8049964
電流範囲がより7 num1を、少しではないので、しかし、メモリ内のアドレスの値すばらしいです0x08048c61~0x08048c96
この部分は位置、すなわちM1のプラスまたはマイナスの一定数をジャンプするジャンプ文でなければなりません。
0x08048c9d~0x08048ca3
次いでNUM1と必要ない5つ以上のチェック、再びスコープ本明細書NUM1を低減
0x08048ca5~0x08048cab
そして、NUM2はM1、同等の要件と比較します
したがって、値NUM1が5以下であるが、我々は、NUM2算出された位置-519 5を取ることができ、M1のNUM2演算結果でなければなりません
phase_4機能
Dump of assembler code for function phase_4:
0x08048ce3 <+0>: push %ebp
0x08048ce4 <+1>: mov %esp,%ebp
0x08048ce6 <+3>: sub $0x28,%esp
0x08048ce9 <+6>: lea -0xc(%ebp),%eax
0x08048cec <+9>: mov %eax,0x8(%esp)
0x08048cf0 <+13>: movl $0x8049984,0x4(%esp)
0x08048cf8 <+21>: mov 0x8(%ebp),%eax
0x08048cfb <+24>: mov %eax,(%esp)
0x08048cfe <+27>: call 0x8048868 <sscanf@plt>
0x08048d03 <+32>: mov %eax,-0x4(%ebp)
0x08048d06 <+35>: cmpl $0x1,-0x4(%ebp)
0x08048d0a <+39>: jne 0x8048d13 <phase_4+48>
0x08048d0c <+41>: mov -0xc(%ebp),%eax
0x08048d0f <+44>: test %eax,%eax
0x08048d11 <+46>: jg 0x8048d18 <phase_4+53>
0x08048d13 <+48>: call 0x804962e <explode_bomb>
0x08048d18 <+53>: mov -0xc(%ebp),%eax
0x08048d1b <+56>: mov %eax,(%esp)
0x08048d1e <+59>: call 0x8048cb4 <func4>
0x08048d23 <+64>: mov %eax,-0x8(%ebp)
0x08048d26 <+67>: cmpl $0x78,-0x8(%ebp)
0x08048d2a <+71>: je 0x8048d31 <phase_4+78>
0x08048d2c <+73>: call 0x804962e <explode_bomb>
0x08048d31 <+78>: leave
0x08048d32 <+79>: ret
End of assembler dump.
0x08048ce3~0x08048cfe
アプリケーション・スタック空間4B * 10、及びM2を(次のように行わ
ebp-0xc
)アドレスM7(書き込みesp+0x8
)、0x8049984
その後呼び出し、書き込みM8は、上部M9に入ってくるパラメータを渡します<sscanf@plt>
我々は
0x8049984
文字列であり、チェック%d
、可視リードライトポインタM2 M7と整数0x08048d03~0x08048d06
sscanf
戻り値、それが唯一の数値入力が必要ですチェック0x08048d0c~0x08048d11
入力要求の数をチェックすると、0より大きい
0x08048d18~0x08048d1e
入力パラメータとして、呼び出しFUNC4
FUNC4チェック
見つけることができ、FUNC4は、再帰的な階乗関数です。
0x08048d23~0x08048d2a
FUNC4 M1、M1、および0x78とに戻り値が必要と等しい、すなわちクレームにおけるM1の== 120と比較されます
5:私たちはちょうどその答えの120ビットの結果の数値の階乗を見つける必要があります
phase_5
(gdb) disassemble phase_5
Dump of assembler code for function phase_5:
0x08048d33 <+0>: push %ebp
0x08048d34 <+1>: mov %esp,%ebp
0x08048d36 <+3>: sub $0x18,%esp
0x08048d39 <+6>: mov 0x8(%ebp),%eax
0x08048d3c <+9>: mov %eax,(%esp)
0x08048d3f <+12>: call 0x804903d <string_length>
0x08048d44 <+17>: mov %eax,-0x4(%ebp)
0x08048d47 <+20>: cmpl $0x6,-0x4(%ebp)
0x08048d4b <+24>: je 0x8048d52 <phase_5+31>
0x08048d4d <+26>: call 0x804962e <explode_bomb>
0x08048d52 <+31>: movl $0x0,-0x8(%ebp)
0x08048d59 <+38>: movl $0x0,-0xc(%ebp)
0x08048d60 <+45>: jmp 0x8048d7e <phase_5+75>
0x08048d62 <+47>: mov -0xc(%ebp),%eax
0x08048d65 <+50>: add 0x8(%ebp),%eax
0x08048d68 <+53>: movzbl (%eax),%eax
0x08048d6b <+56>: movsbl %al,%eax
0x08048d6e <+59>: and $0xf,%eax
0x08048d71 <+62>: mov 0x804a5c0(,%eax,4),%eax
0x08048d78 <+69>: add %eax,-0x8(%ebp)
0x08048d7b <+72>: incl -0xc(%ebp)
0x08048d7e <+75>: cmpl $0x5,-0xc(%ebp)
0x08048d82 <+79>: jle 0x8048d62 <phase_5+47>
0x08048d84 <+81>: cmpl $0x49,-0x8(%ebp)
0x08048d88 <+85>: je 0x8048d8f <phase_5+92>
0x08048d8a <+87>: call 0x804962e <explode_bomb>
0x08048d8f <+92>: leave
0x08048d90 <+93>: ret
End of assembler dump.
0x08048d33~0x08048d44
アプリケーション・スタック空間4B * 6、関数は入力と呼ばれ
<string_length>
、その結果M0、すなわちを書き込み、M0=length(input)
0x08048d47~0x08048d4d
請求項6に入力長、長さをチェックします。
0x08048d52~0x08048d60
0に割り当てられたM1、M2、ジャンプ
0x08048d62~0x08048d6e
(入力+ M2)0は、入力文字列と等価である、という事実であるため、対応するアドレス値で除去EAX、EAXに拡張
eax=input[M2]
、8つのEAX後に採取し、符号拡張をライトバックし、最後に撮影しました最後の4桁の数字。ここで入力としてASCIIコードであるので、0〜127の符号拡張の範囲を拡張しなければなりません。4つの入力に相当する操作の最終的な一連の各文字のASCIIコード値を取ります。0x08048d71~0x08048d78
基づいて撮影
0x804a5c0
シフトメモリの内容、M1に蓄積0x08048d7b~0x08048d82
M2増分は、サイクルを続け、5以下が決定されています
0x08048d84
請求項中の0x49ビット累算結果
チェック
0x804a5c0
内容を対応する値:2、10、6、1、12、16、9、3、4、7、14、5、11、8、15、
我々は6を取る、と等しい0x49を加えた場合
文字列を取ることができるようにここで、私は、限り、4つの条件を満足することができるよう、2,5,5,5,5,7 6の標準番号を削除します
255557
phase_6
(gdb) disassemble phase_6
Dump of assembler code for function phase_6:
0x08048e25 <+0>: push %ebp
0x08048e26 <+1>: mov %esp,%ebp
0x08048e28 <+3>: sub $0x18,%esp
0x08048e2b <+6>: movl $0x804a660,-0x8(%ebp)
0x08048e32 <+13>: mov 0x8(%ebp),%eax
0x08048e35 <+16>: mov %eax,(%esp)
0x08048e38 <+19>: call 0x8048858 <atoi@plt>
0x08048e3d <+24>: mov %eax,-0xc(%ebp)
0x08048e40 <+27>: mov -0x8(%ebp),%eax
0x08048e43 <+30>: mov %eax,(%esp)
0x08048e46 <+33>: call 0x8048d91 <fun6>
0x08048e4b <+38>: mov %eax,-0x8(%ebp)
0x08048e4e <+41>: mov -0x8(%ebp),%eax
0x08048e51 <+44>: mov %eax,-0x4(%ebp)
0x08048e54 <+47>: movl $0x1,-0x10(%ebp)
0x08048e5b <+54>: jmp 0x8048e69 <phase_6+68>
0x08048e5d <+56>: mov -0x4(%ebp),%eax
0x08048e60 <+59>: mov 0x8(%eax),%eax
0x08048e63 <+62>: mov %eax,-0x4(%ebp)
0x08048e66 <+65>: incl -0x10(%ebp)
0x08048e69 <+68>: cmpl $0x4,-0x10(%ebp)
0x08048e6d <+72>: jne 0x8048e5d <phase_6+56>
0x08048e6f <+74>: mov -0x4(%ebp),%eax
0x08048e72 <+77>: mov (%eax),%eax
0x08048e74 <+79>: cmp -0xc(%ebp),%eax
0x08048e77 <+82>: je 0x8048e7e <phase_6+89>
0x08048e79 <+84>: call 0x804962e <explode_bomb>
0x08048e7e <+89>: leave
0x08048e7f <+90>: ret
End of assembler dump.
0x08048e25~0x08048e3d
アプリケーションスタック空間4B * 6になる
0x804a660
M1を入れ、入力引数として呼び出され<atoi@plt>
、その結果を返しますがM2書かれています0x08048e40~0x08048e4b
引数としてM1、fun6を呼び出すには、M1の結果を書き戻す戻ります
emmm、fun6は見ていません
ハッハッハ、継続するには