habrahabr

Меня попросили взломать программу на собеседовании

  • суббота, 20 сентября 2014 г. в 03:11:01
http://habrahabr.ru/post/237469/

TL;DR Меня попросили взломать программу на собеседовании. И я получил работу.

Всем привет,

Я собеседовался на позицию инженера программной безопасности, они спрашивали в основном разные низкоуровневые вещи. Некоторые ответы я знал, некоторые нет.
Потом они прислали 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à!

Компания прислала мне вторую часть, так что вскоре я напишу ещё одну статью.