Моя цель состоит в том, чтобы использовать 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_64
calling 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.
Ваш код * неполный * - откуда берется 'hash'? –
@EmployedRussian sorry, я забыл скопировать этот фрагмент кода. Теперь все готово. – ireallytried