2016-12-29 71 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