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

Ваш код * неполный * - откуда берется 'hash'? –

+0

@EmployedRussian sorry, я забыл скопировать этот фрагмент кода. Теперь все готово. – ireallytried

ответ

1

Моя цель состоит в том, чтобы использовать GDB, чтобы найти какой пароль я должен выбрать для пароля для функции personalData для pri Привет, мастер.

Вы не указали платформу, которую используете. Предположим, 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 вместо этого. Из этого вы можете видеть, что 3 параметра до strncmp переданы в 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..., это справедливо предположить, что инструкции из 0x4006322 через 0x400639 просто инициализировать целевую строку (обратите внимание, что 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 ed с 0x22?

(gdb) p/c 'a'^0x22 
$5 = 67 'C' 
(gdb) p/o 0x12 
$6 = 022 
(gdb) p/c 'b'^0x22 
$7 = 64 '@' 

Это выглядит многообещающе! (Конечно, вы можете, конечно, подтвердить содержимое различных буферов до и во время процесса обфускации, установив точки останова на соответствующие инструкции).

В качестве окончательного подтверждения нашей догадки последним символом является XOR ed с 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 с на нем:

(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, результатом должно быть искомоеPassword.

Вот демонстрационный код:

#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

Смежные вопросы