2016-12-29 70 views
1

比方說,我有以下功能:GDB - 查找密碼

void personalData() 
{ 
    char password[30]; 
    puts("Please enter your password"); 
    fgets(password, 6, stdin); 

    if(correctPassword(password) != 0) { 
     puts("Try again later !"); 
    } 
    else { 
     puts("Hello master"); 
    } 
} 

int correctPassword(char password[5]) 
{ 
    int i = 0; 
    char desiredPassword[5] = {0x12, 0x13, 0x14, 0x15, 0x16}; 
    char hash[5] = {0x22, 0x23, 0x24, 0x25, 0x26}; 

    for(i = 0; i < 5; ++i) { 
     password[i] ^= hash[i]; 
    } 
    return strncmp(password, desiredPassword, 5); 
} 

int main() { 
    personalData(); 
    return 0; 
} 

我的目標是使用GDB找我應該選擇什麼樣的密碼password爲了使功能personalData打印你好主人。我嘗試過使用斷點,每個部分都有許多錯誤,但我不知道在哪裏尋找實際結果。我也試圖看看strncmp,但沒有結果。 我不應該改變源代碼。

+0

您的代碼*不完整* - 散列來自哪裏? –

+0

@EmployedRussian對不起,我忘了複製那段代碼。現在完成了。 – ireallytried

回答

1

我的目標是使用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_64calling convention代替。從它可以看到,strncmp的3個參數在RDI,RSIRDX寄存器中傳遞。他們的價值是什麼?

(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轉化爲Cb轉化爲@。從這裏我們可以選擇以下兩種方式之一:我們可以嘗試更多的字符並猜測輸入 - >混淆密碼算法是什麼,或者我們可以更多地查看反彙編,並簡單地「讀取」它。

拆卸顯示:

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...,這是一個公平的猜測,通過0x4006390x4006322指令只是初始化目標字符串(注意: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。

0

由於散列數組可能不知道(但可以從GDB訪問),所以您需要將密碼設置爲hash[n]^desiredPassword[n]。由於xor的反函數是xor,結果應該是desiredPassword。

下面是演示代碼:

#include <stdio.h> 

char hash[] = {0x23, 0x45, 0x55, 0xbb, 0xdd}; /* Some unknown values */ 


void personalData() 
{ 
    char password[30]; 

    puts("Please enter your password"); 
    fgets(password, 6, stdin); 


    if(correctPassword(password) != 0) { 
     puts("Try again later !"); 
    } 
    else { 
     puts("Hello master"); 
    } 
} 

int correctPassword(char password[5]) 
{ 
    int i = 0; 
    char desiredPassword[5] = {0x12, 0x13, 0x14, 0x15, 0x16}; 
    for(i = 0; i < 5; ++i) { 
     password[i] ^= hash[i]; 
    } 
    return strncmp(password, desiredPassword, 5); 
} 


int main() 
{ 
    personalData(); 
} 

性病控制檯:

gcc -g find_passwd.c 
gdb .\a.exe -q 

一旦在gdb控制檯:

(gdb) b correctPassword 
Breakpoint 1 at 0x4006b9: file find_passwd.c, line 32. 
(gdb) r 
Starting program: /home/xxx/workspace/c/xx/a.out 
Please enter your password 
garbagePasswd 

Breakpoint 1, correctPassword 
32  int i = 0; 
(gdb) n 
33  char desiredPassword[5] = {0x12, 0x13, 0x14, 0x15, 0x16}; 
(gdb) 
34  for(i = 0; i < 5; ++i) { 
(gdb) set password[0] = hash[0]^desiredPassword[0] 
(gdb) set password[1] = hash[1]^desiredPassword[1] 
(gdb) set password[2] = hash[2]^desiredPassword[2] 
(gdb) set password[3] = hash[3]^desiredPassword[3] 
(gdb) set password[4] = hash[4]^desiredPassword[4] 
(gdb) c 
Continuing. 
Hello master 
[Inferior 1 (process 19557) exited normally] 
+0

謝謝,但我本來應該使用gdb來做這個...這種解決方法與gdb無關。 – ireallytried

+0

我不想重寫任何內容...我想使用_gdb_ – ireallytried

+0

找到密碼的**實際**值只需在'xor'後輸入密碼值 – GurstTavo