我的目標是使用gdb來找到我應該爲密碼選擇什麼密碼才能使personalData功能啓動nt你好主人。
您沒有說明您使用的平臺。我們假設Linux/x86_64。該平臺非常重要,因爲調用約定取決於平臺。這裏的答案可以很容易地針對不同的平臺進行調整。
讓我們考慮優化二進制(通常比較困難)的情況。的personalData
顯示拆卸:
0x000000000040074d <+45>: callq 0x400560 <[email protected]>
0x0000000000400752 <+50>: xor %eax,%eax
0x0000000000400754 <+52>: mov %rsp,%rdi
0x0000000000400757 <+55>: callq 0x400680 <correctPassword>
0x000000000040075c <+60>: test %eax,%eax
0x000000000040075e <+62>: jne 0x400780 <personalData+96>
這就告訴我們,從stdin
讀取密碼後,我們稱之爲correctPassword
並根據correctPassword
是否返回0或非零變更控制。接下來的兩條指令:
0x0000000000400760 <+64>: mov $0x400851,%edi
0x0000000000400765 <+69>: callq 0x400530 <[email protected]>
正在打印一些輸出。如果correctPassword
返回0
並且未採取跳轉,正在打印什麼?
(gdb) x/s 0x400851
0x400851: "Hello master"
因此,我們的目標是使correctPassword
返回0。讓我們看看它的拆解:
(gdb) disas correctPassword
....
0x0000000000400673 <+99>: callq 0x4004c0 <[email protected]>
0x0000000000400678 <+104>: add $0x28,%rsp
0x000000000040067c <+108>: retq
這告訴我們,correctPassword
返回任何strncmp
返回,即返回我們所期望的0 IFF我們密碼匹配第一個N
字符,不管它是否與strncmp
一致。時間設定在strncmp
斷點:
(gdb) break strncmp
Breakpoint 1 at 0x4004c0
(gdb) run
Starting program: /tmp/a.out
Please enter your password
aaaaaaaaa
在上面,我進入了9個字符的密碼,只是作爲一個初始猜測。
Breakpoint 1, __strncmp_ssse3() at ../sysdeps/x86_64/multiarch/../strcmp.S:174
174 ../sysdeps/x86_64/multiarch/../strcmp.S: No such file or directory.
我碰巧有glibc安裝調試符號,居然可以檢查glibc源碼和源代碼級的參數,但是您可能沒有這種奢侈,所以我會用Linux/x86_64
calling convention代替。從它可以看到,strncmp
的3個參數在RDI
,RSI
和RDX
寄存器中傳遞。他們的價值是什麼?
(gdb) p/x $rdi
$1 = 0x7fffffffdd50
(gdb) p/x $rsi
$2 = 0x7fffffffdd20
(gdb) p/x $rdx
$3 = 0x5
好的,所以只有密碼的前5個字符被比較,並且之後的任何字符都被忽略。
比較哪些字符串?
(gdb) x/s $rdi
0x7fffffffdd50: "CBEDG"
(gdb) x/s $rsi
0x7fffffffdd20: "\022\023\024\025\026"
嗯,這兩個字符串都不像我們的「aaa ...」密碼。讓我們嘗試不同的密碼:
(gdb) run
Starting program: /tmp/a.out
Please enter your password
bbbbb
Breakpoint 1, __strncmp_ssse3() at ../sysdeps/x86_64/multiarch/../strcmp.S:174
174 ../sysdeps/x86_64/multiarch/../strcmp.S: No such file or directory.
(gdb) x/s $rdi
0x7fffffffdd50: "@AFGD"
(gdb) x/s $rsi
0x7fffffffdd20: "\022\023\024\025\026"
現在,我們可以立即看到$rsi
順序沒有改變,並且可以假設"\022\023\024\025\026"
是預期的密碼。
我們也看到第一個a
轉化爲C
和b
轉化爲@
。從這裏我們可以選擇以下兩種方式之一:我們可以嘗試更多的字符並猜測輸入 - >混淆密碼算法是什麼,或者我們可以更多地查看反彙編,並簡單地「讀取」它。
拆卸顯示:
0x0000000000400622 <+18>: movb $0x12,(%rsp)
...
0x000000000040062a <+26>: movb $0x13,0x1(%rsp)
0x000000000040062f <+31>: movb $0x14,0x2(%rsp)
0x0000000000400634 <+36>: movb $0x15,0x3(%rsp)
0x0000000000400639 <+41>: movb $0x16,0x4(%rsp)
0x000000000040063e <+46>: movb $0x22,0x10(%rsp)
0x0000000000400643 <+51>: movb $0x23,0x11(%rsp)
0x0000000000400648 <+56>: movb $0x24,0x12(%rsp)
0x000000000040064d <+61>: movb $0x25,0x13(%rsp)
0x0000000000400652 <+66>: movb $0x26,0x14(%rsp)
因爲我們知道,「目標」字符串是\022\023...
,這是一個公平的猜測,通過0x400639
從0x4006322
指令只是初始化目標字符串(注意:0x12
== \022
) 。也許從0x40063e
開始的指令與混淆有關?在拆卸進一步看,我們可以看到:
0x0000000000400626 <+22>: cmp $0x5,%rax
...
0x0000000000400657 <+71>: je 0x40066b <correctPassword+91>
0x0000000000400659 <+73>: movzbl 0x10(%rsp,%rax,1),%edx
0x000000000040065e <+78>: xor %dl,(%rdi,%rax,1)
0x0000000000400661 <+81>: add $0x1,%rax
0x0000000000400665 <+85>: cmp $0x5,%rax
0x0000000000400669 <+89>: jne 0x400659 <correctPassword+73>
這與5固定的行程計數一個循環,並且在循環中,我們從一個緩衝器和XOR
與來自另一緩衝區中的字符值加載單個字符。密碼的第一個字符是XOR
編號0x22
有什麼可能?
(gdb) p/c 'a'^0x22
$5 = 67 'C'
(gdb) p/o 0x12
$6 = 022
(gdb) p/c 'b'^0x22
$7 = 64 '@'
這看起來很有前途! (當然可以通過在適當的指令中設置斷點來確認混淆過程前後的各種緩衝區的內容)。
作爲我們猜測的最終確認,最後一個字符是XOR
編輯0x26
。
(gdb) p/c 'a'^0x26
$8 = 71 'G' # matches last char of 'aaa...' guess
(gdb) p/c 'b'^0x26
$9 = 68 'D' # matches last char of 'bbb...' guess
最後,構建了正確的密碼,我們需要採取的「目標」字符串,並做的XOR
S也是一樣的順序就可以了:
(gdb) p/c 022^0x22
$10 = 48 '0'
(gdb) p/c 023^0x23
$11 = 48 '0'
... etc.
因此,正確的密碼爲00000
。讓我們看看是否有效:
(gdb) disable
(gdb) run
Starting program: /tmp/a.out
Please enter your password
00000
Hello master
[Inferior 1 (process 45643) exited normally]
QED。
您的代碼*不完整* - 散列來自哪裏? –
@EmployedRussian對不起,我忘了複製那段代碼。現在完成了。 – ireallytried