TL;DR Меня попросили взломать программу на собеседовании. И я получил работу.
Всем привет,
Я собеседовался на позицию инженера программной безопасности, они спрашивали в основном разные низкоуровневые вещи. Некоторые ответы я знал, некоторые нет.
Потом они прислали email с защищённым и зашифрованным бинарником, который нужно было взломать.
Когда я добрался до дома, я скачал его и увидел, что он спрашивает пароль. Они хотели, чтобы я нашёл этот пароль.
Вот что я увидел при первом запуске:
Я напечатал три раза какие-то глупые слова, и программа закрылась.
У меня ещё есть инструменты в запасе для анализа. Давайте соберём побольше информации о файле.
Окей, теперь мы знаем немного больше о бинарнике.
Ничего необычного. Объясню немного. linux-gate.so вы можете не найти в своей файловой системе. Но ldd показывает его как общую библиотеку. Это Virtual DSO.
Итак, вы знаете о linux-gate.so.1.
Возможно вы также знаете, что libc.so.6 это основная C библиотека для GNU систем.
ld-linux.so это загрузчик динамических библиотек в linux.
Запустим программу в отладчике и посмотрим что произойдёт.
Программа упала. Это значит, что в ней должны быть какие-то антиотладочные трюки. Окей…
Запустим её снова и посмотрим точку входа программы.
Поставим breakpoint на точку входа и начнём отладку:
Затем нажмём «r» для запуска. Окажемся на первой строке точки входа программы:
Должно выглядеть как-то так. Можно выбрать синтаксис между AT&T и Intel версиями. Мне больше нравится Intel.
По адресу 0x8047654, мы присваиваем 0x55 al регистру, а затем XOR'им его с 0x99 получая 0xCC.
0xCC это очень важно, так как это означает остановку процесса. Когда отладчик хочет прервать выполнение программы, он заменяет байты на 0xCC в том месте, где хочет её остановить.
По адресу 0x8047666, мы видим repnz scas; это означает поиск участка памяти, ограниченного es и edi, на предмет значения в al(0xCC).
Итак, эти строчки просто сканируют память, и если там есть 0xCC, программа прекращает выполнение.
Не хочу тратить слишком много времени тут. Запустим strace:
Судя по последним двум строчкам, программа упала опять. Из-за системного вызова ptrace.
Ptrace — это аббревиатура для «Process Trace». При помощи ptrace вы можете контролировать другой процесс меняя его состояние, как это делают отладчики.
Отладчики очень интенсивно используют ptrace. Это их работа.
Код для такого участка может выглядеть примерно так:
Кстати, вы можете сделать ptrace[PTRACE_TRACEMe] только один раз, так что если отладчик вызвал ptrace на нашей программе до этого, то наш вызов вернёт false и мы поймём, что кто-то контролирует программу извне.
Нам нужно обойти защиту на ptrace чтобы программа не думала, что мы пытаемся её отлаживать.
Мы заменим результат системного вызова.
Мы будем определять когда программа вызывает ptrace и возвращать ноль.
В домашней папке я создал новый .gdbinit файл. Следовательно, каждый раз когда я запускаю gdb, конфигурация будет загружаться автоматически.
В eax будет результат системного вызова. И он всегда будет 0, что означает истину в нашем случае.
Таким образом мы обошли защиту от отладки и можем вернуться к gdb.
Я поставил breakpoint на PJeGPC4TIVaKFmmy53DJ
Эта часть интересна. Я вижу манипулирование константами и то, что к подающимся данным на вход применяется XOR констант. Продолжим…
Ещё константы…
И оставшаяся часть функции:
Видите ли вы те же закономерности, что вижу я? Если нет — не беда.
Здесь в программе проверяется мой ввод поксоренный с константами.
Теперь ещё раз посмотрим на ввод, первые байты ксорятся с некоторыми константами, и затем вывод сравнивается с другими костантами.
Последние две функции должны выглядеть как-то так:
Я набросал скрипт на Python чтобы применить XOR к этим константам и нашёл ключ:
Voilà!
Компания прислала мне вторую часть, так что вскоре я напишу ещё одну статью.
Всем привет,
Я собеседовался на позицию инженера программной безопасности, они спрашивали в основном разные низкоуровневые вещи. Некоторые ответы я знал, некоторые нет.
Потом они прислали email с защищённым и зашифрованным бинарником, который нужно было взломать.
Когда я добрался до дома, я скачал его и увидел, что он спрашивает пароль. Они хотели, чтобы я нашёл этот пароль.
Вот что я увидел при первом запуске:
root@lisa:~# ./CrackTheDoor
*** DOOR CONTROL SYSTEM ***
PASSWORD:
Я напечатал три раза какие-то глупые слова, и программа закрылась.
У меня ещё есть инструменты в запасе для анализа. Давайте соберём побольше информации о файле.
root@lisa:~# file CrackTheDoor
CrackTheDoor: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x9927be2fe310bea01d412164103b9c8b2d7567ea, not stripped
root@lisa:~#
Окей, теперь мы знаем немного больше о бинарнике.
root@lisa:~# ldd CrackTheDoor
linux-gate.so.1 => (0xf777b000)
libc.so.6 => /lib32/libc.so.6 (0xf760c000)
/lib/ld-linux.so.2 (0xf777c000)
root@lisa:~#
Ничего необычного. Объясню немного. linux-gate.so вы можете не найти в своей файловой системе. Но ldd показывает его как общую библиотеку. Это Virtual DSO.
Итак, вы знаете о linux-gate.so.1.
Возможно вы также знаете, что libc.so.6 это основная C библиотека для GNU систем.
ld-linux.so это загрузчик динамических библиотек в linux.
Запустим программу в отладчике и посмотрим что произойдёт.
root@lisa:~# gdb CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Reading symbols from /root/CrackTheDoor...(no debugging symbols found)...done.
(gdb) r
Starting program: /root/CrackTheDoor
Program received signal SIGSEGV, Segmentation fault.
0x080484fb in __do_global_dtors_aux ()
(gdb)
Программа упала. Это значит, что в ней должны быть какие-то антиотладочные трюки. Окей…
Запустим её снова и посмотрим точку входа программы.
root@lisa:~# gdb CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Reading symbols from /root/CrackTheDoor...(no debugging symbols found)...done.
(gdb) info file
Symbols from "/root/CrackTheDoor".
Local exec file:
`/root/CrackTheDoor', file type elf32-i386.
Entry point: 0x804762c
…
...
Поставим breakpoint на точку входа и начнём отладку:
b * 0x804762c
Затем нажмём «r» для запуска. Окажемся на первой строке точки входа программы:
gdb) x/30i $pc
=> 0x804762c: pusha
0x804762d: mov $0xaa,%dl
0x804762f: mov $0x8048480,%edi
0x8047634: mov $0x8048cbc,%ecx
0x8047639: mov %edi,0x80476f3
0x804763f: mov %ecx,0x80476f7
0x8047645: sub %edi,%ecx
0x8047647: mov $0x804762f,%esi
0x804764c: push $0x80476c1
0x8047651: pusha
0x8047652: mov $0x55,%al
0x8047654: xor $0x99,%al
0x8047656: mov $0x8047656,%edi
0x804765b: mov $0x80476e5,%ecx
0x8047660: sub $0x8047656,%ecx
0x8047666: repnz scas %es:(%edi),%al
0x8047668: je 0x804770a
0x804766e: mov %edi,0x80476eb
0x8047674: popa
0x8047675: add 0x80476eb,%edx
0x804767b: ret
Должно выглядеть как-то так. Можно выбрать синтаксис между AT&T и Intel версиями. Мне больше нравится Intel.
По адресу 0x8047654, мы присваиваем 0x55 al регистру, а затем XOR'им его с 0x99 получая 0xCC.
0xCC это очень важно, так как это означает остановку процесса. Когда отладчик хочет прервать выполнение программы, он заменяет байты на 0xCC в том месте, где хочет её остановить.
По адресу 0x8047666, мы видим repnz scas; это означает поиск участка памяти, ограниченного es и edi, на предмет значения в al(0xCC).
Итак, эти строчки просто сканируют память, и если там есть 0xCC, программа прекращает выполнение.
Не хочу тратить слишком много времени тут. Запустим strace:
root@lisa:~# strace ./CrackTheDoor
execve("./CrackTheDoor", ["./CrackTheDoor"], [/* 17 vars */]) = 0
[ Process PID=31085 runs in 32 bit mode. ]
brk(0) = 0x9972000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7715000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=35597, ...}) = 0
mmap2(NULL, 35597, PROT_READ, MAP_PRIVATE, 3, 0) = 0xfffffffff770c000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib32/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300o\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1441884, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff770b000
mmap2(NULL, 1456504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xfffffffff75a7000
mprotect(0xf7704000, 4096, PROT_NONE) = 0
mmap2(0xf7705000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15d) = 0xfffffffff7705000
mmap2(0xf7708000, 10616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7708000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff75a6000
set_thread_area(0xffe4d864) = 0
mprotect(0xf7705000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xf7733000, 4096, PROT_READ) = 0
munmap(0xf770c000, 35597) = 0
ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted)
ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted)
Судя по последним двум строчкам, программа упала опять. Из-за системного вызова ptrace.
Ptrace — это аббревиатура для «Process Trace». При помощи ptrace вы можете контролировать другой процесс меняя его состояние, как это делают отладчики.
Отладчики очень интенсивно используют ptrace. Это их работа.
Код для такого участка может выглядеть примерно так:
int main() { if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { printf("DEBUGGING... Bye\n"); return 1; } printf("Hello\n"); return 0; }
Кстати, вы можете сделать ptrace[PTRACE_TRACEMe] только один раз, так что если отладчик вызвал ptrace на нашей программе до этого, то наш вызов вернёт false и мы поймём, что кто-то контролирует программу извне.
Нам нужно обойти защиту на ptrace чтобы программа не думала, что мы пытаемся её отлаживать.
Мы заменим результат системного вызова.
Мы будем определять когда программа вызывает ptrace и возвращать ноль.
В домашней папке я создал новый .gdbinit файл. Следовательно, каждый раз когда я запускаю gdb, конфигурация будет загружаться автоматически.
~/.gdbinit
set disassembly-flavor intel # Intel syntax is better
set disassemble-next-line on
catch syscall ptrace #Catch the syscall.
commands 1
set ($eax) = 0
continue
end
В eax будет результат системного вызова. И он всегда будет 0, что означает истину в нашем случае.
Таким образом мы обошли защиту от отладки и можем вернуться к gdb.
eren@lisa:~$ gdb ./CrackTheDoor
GNU gdb (GDB) 7.4.1-debian
Copyright © 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type «show copying»
and «show warranty» for details.
This GDB was configured as «x86_64-linux-gnu».
For bug reporting instructions, please see:
<www.gnu.org/software/gdb/bugs>…
Catchpoint 1 (syscall 'ptrace' [26])
Reading symbols from /home/eren/CrackTheDoor...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/eren/CrackTheDoor
Catchpoint 1 (call to syscall ptrace), 0x08047698 in ?? ()
=> 0x08047698: 3d 00 f0 ff ff cmp eax,0xfffff000
Catchpoint 1 (returned from syscall ptrace), 0x08047698 in ?? ()
=> 0x08047698: 3d 00 f0 ff ff cmp eax,0xfffff000
*** DOOR CONTROL SYSTEM ***
PASSWORD:
Я поставил breakpoint на PJeGPC4TIVaKFmmy53DJ
<code>Breakpoint 2, 0x08048534 in PJeGPC4TIVaKFmmy53DJ () => 0x08048534 <PJeGPC4TIVaKFmmy53DJ+0>: 1e push ds (gdb) x/40i $pc => 0x8048534 <PJeGPC4TIVaKFmmy53DJ>: push ds 0x8048535 <PJeGPC4TIVaKFmmy53DJ+1>: mov ebp,esp 0x8048537 <PJeGPC4TIVaKFmmy53DJ+3>: sub esp,0x20 0x804853a <PJeGPC4TIVaKFmmy53DJ+6>: mov BYTE PTR [ebp-0x1],0xe4 0x804853e <PJeGPC4TIVaKFmmy53DJ+10>: mov BYTE PTR [ebp-0x2],0x87 0x8048542 <PJeGPC4TIVaKFmmy53DJ+14>: mov BYTE PTR [ebp-0x3],0xfb 0x8048546 <PJeGPC4TIVaKFmmy53DJ+18>: mov BYTE PTR [ebp-0x4],0xbe 0x804854a <PJeGPC4TIVaKFmmy53DJ+22>: mov BYTE PTR [ebp-0x5],0xc9 0x804854e <PJeGPC4TIVaKFmmy53DJ+26>: mov BYTE PTR [ebp-0x6],0x93 0x8048552 <PJeGPC4TIVaKFmmy53DJ+30>: mov BYTE PTR [ebp-0x7],0x84 0x8048556 <PJeGPC4TIVaKFmmy53DJ+34>: mov BYTE PTR [ebp-0x8],0xfc 0x804855a <PJeGPC4TIVaKFmmy53DJ+38>: mov BYTE PTR [ebp-0x9],0x8d 0x804855e <PJeGPC4TIVaKFmmy53DJ+42>: mov BYTE PTR [ebp-0xa],0xe5 0x8048562 <PJeGPC4TIVaKFmmy53DJ+46>: mov BYTE PTR [ebp-0xb],0xbf 0x8048566 <PJeGPC4TIVaKFmmy53DJ+50>: mov BYTE PTR [ebp-0xc],0x5c 0x804856a <PJeGPC4TIVaKFmmy53DJ+54>: mov BYTE PTR [ebp-0xd],0xe2 0x804856e <PJeGPC4TIVaKFmmy53DJ+58>: mov BYTE PTR [ebp-0xe],0x76 0x8048572 <PJeGPC4TIVaKFmmy53DJ+62>: mov BYTE PTR [ebp-0xf],0x21 0x8048576 <PJeGPC4TIVaKFmmy53DJ+66>: mov BYTE PTR [ebp-0x10],0xb8 0x804857a <PJeGPC4TIVaKFmmy53DJ+70>: mov DWORD PTR [ebp-0x14],0x0 0x8048581 <PJeGPC4TIVaKFmmy53DJ+77>: mov eax,DWORD PTR [ebp-0x14] 0x8048584 <PJeGPC4TIVaKFmmy53DJ+80>: add eax,DWORD PTR [ebp+0x8] 0x8048587 <PJeGPC4TIVaKFmmy53DJ+83>: movzx eax,BYTE PTR [eax] 0x804858a <PJeGPC4TIVaKFmmy53DJ+86>: test al,al 0x804858c <PJeGPC4TIVaKFmmy53DJ+88>: je 0x8048808 <PJeGPC4TIVaKFmmy53DJ+724> 0x8048592 <PJeGPC4TIVaKFmmy53DJ+94>: mov eax,DWORD PTR [ebp-0x14] 0x8048595 <PJeGPC4TIVaKFmmy53DJ+97>: add eax,DWORD PTR [ebp+0x8] 0x8048598 <PJeGPC4TIVaKFmmy53DJ+100>: mov edx,DWORD PTR [ebp-0x14] 0x804859b <PJeGPC4TIVaKFmmy53DJ+103>: add edx,DWORD PTR [ebp+0x8] 0x804859e <PJeGPC4TIVaKFmmy53DJ+106>: movzx edx,BYTE PTR [edx] 0x80485a1 <PJeGPC4TIVaKFmmy53DJ+109>: xor dl,BYTE PTR [ebp-0x1] 0x80485a4 <PJeGPC4TIVaKFmmy53DJ+112>: mov BYTE PTR [eax],dl 0x80485a6 <PJeGPC4TIVaKFmmy53DJ+114>: add DWORD PTR [ebp-0x14],0x1 0x80485aa <PJeGPC4TIVaKFmmy53DJ+118>: mov eax,DWORD PTR [ebp-0x14] 0x80485ad <PJeGPC4TIVaKFmmy53DJ+121>: add eax,DWORD PTR [ebp+0x8] 0x80485b0 <PJeGPC4TIVaKFmmy53DJ+124>: movzx eax,BYTE PTR [eax] 0x80485b3 <PJeGPC4TIVaKFmmy53DJ+127>: test al,al 0x80485b5 <PJeGPC4TIVaKFmmy53DJ+129>: je 0x804880b <PJeGPC4TIVaKFmmy53DJ+727> 0x80485bb <PJeGPC4TIVaKFmmy53DJ+135>: mov eax,DWORD PTR [ebp-0x14] 0x80485be <PJeGPC4TIVaKFmmy53DJ+138>: add eax,DWORD PTR [ebp+0x8] 0x80485c1 <PJeGPC4TIVaKFmmy53DJ+141>: mov edx,DWORD PTR [ebp-0x14] 0x80485c4 <PJeGPC4TIVaKFmmy53DJ+144>: add edx,DWORD PTR [ebp+0x8] 0x80485c7 <PJeGPC4TIVaKFmmy53DJ+147>: movzx edx,BYTE PTR [edx] 0x80485ca <PJeGPC4TIVaKFmmy53DJ+150>: xor dl,BYTE PTR [ebp-0x2]</code>
Эта часть интересна. Я вижу манипулирование константами и то, что к подающимся данным на вход применяется XOR констант. Продолжим…
(gdb) x/30i X1bdrhN8Yk9NZ59Vb7P2 0x8048838 <X1bdrhN8Yk9NZ59Vb7P2>: sbb ecx,DWORD PTR [ecx+0x20ec83e5] 0x804883e <X1bdrhN8Yk9NZ59Vb7P2+6>: mov DWORD PTR [ebp-0x18],0x0 0x8048845 <X1bdrhN8Yk9NZ59Vb7P2+13>: mov BYTE PTR [ebp-0x1],0xd9 0x8048849 <X1bdrhN8Yk9NZ59Vb7P2+17>: mov BYTE PTR [ebp-0x2],0xcd 0x804884d <X1bdrhN8Yk9NZ59Vb7P2+21>: mov BYTE PTR [ebp-0x3],0xc9 0x8048851 <X1bdrhN8Yk9NZ59Vb7P2+25>: mov BYTE PTR [ebp-0x4],0xe5 0x8048855 <X1bdrhN8Yk9NZ59Vb7P2+29>: mov BYTE PTR [ebp-0x5],0x9e 0x8048859 <X1bdrhN8Yk9NZ59Vb7P2+33>: mov BYTE PTR [ebp-0x6],0xd0 0x804885d <X1bdrhN8Yk9NZ59Vb7P2+37>: mov BYTE PTR [ebp-0x7],0xe8 0x8048861 <X1bdrhN8Yk9NZ59Vb7P2+41>: mov BYTE PTR [ebp-0x8],0xa5 0x8048865 <X1bdrhN8Yk9NZ59Vb7P2+45>: mov BYTE PTR [ebp-0x9],0xaf 0x8048869 <X1bdrhN8Yk9NZ59Vb7P2+49>: mov BYTE PTR [ebp-0xa],0x87 0x804886d <X1bdrhN8Yk9NZ59Vb7P2+53>: mov BYTE PTR [ebp-0xb],0xd2 0x8048871 <X1bdrhN8Yk9NZ59Vb7P2+57>: mov BYTE PTR [ebp-0xc],0x79 0x8048875 <X1bdrhN8Yk9NZ59Vb7P2+61>: mov BYTE PTR [ebp-0xd],0xa9 0x8048879 <X1bdrhN8Yk9NZ59Vb7P2+65>: mov BYTE PTR [ebp-0xe],0x5d 0x804887d <X1bdrhN8Yk9NZ59Vb7P2+69>: mov BYTE PTR [ebp-0xf],0x7 0x8048881 <X1bdrhN8Yk9NZ59Vb7P2+73>: mov BYTE PTR [ebp-0x10],0x81 0x8048885 <X1bdrhN8Yk9NZ59Vb7P2+77>: mov DWORD PTR [ebp-0x14],0x0 0x804888c <X1bdrhN8Yk9NZ59Vb7P2+84>: mov eax,DWORD PTR [ebp-0x14] 0x804888f <X1bdrhN8Yk9NZ59Vb7P2+87>: add eax,DWORD PTR [ebp+0x8] 0x8048892 <X1bdrhN8Yk9NZ59Vb7P2+90>: movzx eax,BYTE PTR [eax] 0x8048895 <X1bdrhN8Yk9NZ59Vb7P2+93>: cmp al,BYTE PTR [ebp-0x1] 0x8048898 <X1bdrhN8Yk9NZ59Vb7P2+96>: je 0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106> 0x804889a <X1bdrhN8Yk9NZ59Vb7P2+98>: mov eax,DWORD PTR [ebp-0x18]
Ещё константы…
И оставшаяся часть функции:
0x804889d <X1bdrhN8Yk9NZ59Vb7P2+101>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488> 0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106>: add DWORD PTR [ebp-0x14],0x1 0x80488a6 <X1bdrhN8Yk9NZ59Vb7P2+110>: mov eax,DWORD PTR [ebp-0x14] 0x80488a9 <X1bdrhN8Yk9NZ59Vb7P2+113>: add eax,DWORD PTR [ebp+0x8] 0x80488ac <X1bdrhN8Yk9NZ59Vb7P2+116>: movzx eax,BYTE PTR [eax] 0x80488af <X1bdrhN8Yk9NZ59Vb7P2+119>: cmp al,BYTE PTR [ebp-0x2] 0x80488b2 <X1bdrhN8Yk9NZ59Vb7P2+122>: je 0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132> 0x80488b4 <X1bdrhN8Yk9NZ59Vb7P2+124>: mov eax,DWORD PTR [ebp-0x18] 0x80488b7 <X1bdrhN8Yk9NZ59Vb7P2+127>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488> 0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132>: add DWORD PTR [ebp-0x14],0x1 0x80488c0 <X1bdrhN8Yk9NZ59Vb7P2+136>: mov eax,DWORD PTR [ebp-0x14] 0x80488c3 <X1bdrhN8Yk9NZ59Vb7P2+139>: add eax,DWORD PTR [ebp+0x8] 0x80488c6 <X1bdrhN8Yk9NZ59Vb7P2+142>: movzx eax,BYTE PTR [eax] 0x80488c9 <X1bdrhN8Yk9NZ59Vb7P2+145>: cmp al,BYTE PTR [ebp-0x3] 0x80488cc <X1bdrhN8Yk9NZ59Vb7P2+148>: je 0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158> 0x80488ce <X1bdrhN8Yk9NZ59Vb7P2+150>: mov eax,DWORD PTR [ebp-0x18] 0x80488d1 <X1bdrhN8Yk9NZ59Vb7P2+153>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488> 0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158>: add DWORD PTR [ebp-0x14],0x1 0x80488da <X1bdrhN8Yk9NZ59Vb7P2+162>: mov eax,DWORD PTR [ebp-0x14] 0x80488dd <X1bdrhN8Yk9NZ59Vb7P2+165>: add eax,DWORD PTR [ebp+0x8] ---Type <return> to continue, or q <return> to quit--- 0x80488e0 <X1bdrhN8Yk9NZ59Vb7P2+168>: movzx eax,BYTE PTR [eax] 0x80488e3 <X1bdrhN8Yk9NZ59Vb7P2+171>: cmp al,BYTE PTR [ebp-0x4] 0x80488e6 <X1bdrhN8Yk9NZ59Vb7P2+174>: je 0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184> 0x80488e8 <X1bdrhN8Yk9NZ59Vb7P2+176>: mov eax,DWORD PTR [ebp-0x18] 0x80488eb <X1bdrhN8Yk9NZ59Vb7P2+179>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488> 0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184>: add DWORD PTR [ebp-0x14],0x1 0x80488f4 <X1bdrhN8Yk9NZ59Vb7P2+188>: mov eax,DWORD PTR [ebp-0x14] 0x80488f7 <X1bdrhN8Yk9NZ59Vb7P2+191>: add eax,DWORD PTR [ebp+0x8] 0x80488fa <X1bdrhN8Yk9NZ59Vb7P2+194>: movzx eax,BYTE PTR [eax] 0x80488fd <X1bdrhN8Yk9NZ59Vb7P2+197>: cmp al,BYTE PTR [ebp-0x5] 0x8048900 <X1bdrhN8Yk9NZ59Vb7P2+200>: je 0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210> 0x8048902 <X1bdrhN8Yk9NZ59Vb7P2+202>: mov eax,DWORD PTR [ebp-0x18] 0x8048905 <X1bdrhN8Yk9NZ59Vb7P2+205>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488> 0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210>: add DWORD PTR [ebp-0x14],0x1 0x804890e <X1bdrhN8Yk9NZ59Vb7P2+214>: mov eax,DWORD PTR [ebp-0x14]
Видите ли вы те же закономерности, что вижу я? Если нет — не беда.
Здесь в программе проверяется мой ввод поксоренный с константами.
Теперь ещё раз посмотрим на ввод, первые байты ксорятся с некоторыми константами, и затем вывод сравнивается с другими костантами.
Последние две функции должны выглядеть как-то так:
void PJeGPC4TIVaKFmmy53DJ (int * p) { int array[] = {0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8} for(i=0;i<16;i++) { p[i] = p[i] ^ array[i] } } int X1bdrhN8Yk9NZ59Vb7P2(int * p) { int array = {0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81} for(i=0;i<16;i++) { if(p[i] != array[i]) return false; // fail.. } return true }
Я набросал скрипт на Python чтобы применить XOR к этим константам и нашёл ключ:
#!/usr/bin/python firstConst = [0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8] secondConst = [0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81] ret ="" for x in range(16): ret+=chr(firstConst[x] ^ secondConst[x]) print ret
eren@lisa:~$ ./CrackTheDoor
*** DOOR CONTROL SYSTEM ***
PASSWORD: =J2[WClY«bm%K+&9
*** ACCESS GRANTED ***
*** THE DOOR OPENED ***
Voilà!
Компания прислала мне вторую часть, так что вскоре я напишу ещё одну статью.