owned this note
owned this note
Published
Linked with GitHub
# Architektury systemów komputerowych - rozbrajanie bomby
W tej notatce opiszę jak przebiegało rozbrajanie bomby w moim przypadku, na pewno nie jest to najskuteczniejsze (ani najmądrzejsze) podejście, ale udało mi się rozwiązać wszystkie fazy, włącznie z ukrytą, także może mi się uda kogoś naprowadzić na sensowne rozwiązanie.
Na samym początku przygotowałem sobie zbiór plików `txt` z wydrukami deasemblowanych funkcji kolejnych faz, który powiększał się w trakcie rozbrajania (np. gdy natrafiałem na funkcje używane w kolejnych fazach), posłużyło mi do tego polecenie:
```
objdump -d bomb | awk -F"\n" -v RS="\n\n" '$1 ~/nazwa_funkcji/' > nazwa_funkcji.txt
```
Dzięki temu przed rozpoczęciem zadania wiedziałem, jakich inputów oczekują kolejne fazy, co znacznie przyspieszyło moje działanie.
Do łatwiejszego debugowania użyłem [GDB Dashboard](https://github.com/cyrus-and/gdb-dashboard) wspomnianego na SKOSie, dzięki temu mamy podgląd rejestrów, flag, stosu, części kodu itp. bez wpisywania żadnych dodatkowych komend, dzięki czemu wszystko przebiega znacznie szybciej. Rozwiązania kolejnych faz warto zapisywać do jakiegoś pliku `txt`, a następnie po uruchomieniu `gdb` z bombą wpisujemy `set args nazwapliku.txt`, aby niepotrzebnie nie wpisywać wcześniejszych rozwiązań przy każdym uruchomieniu programu.
## Faza pierwsza
Wydruk objdump:
```
0000000000001405 <phase_1>:
1405: 48 83 ec 08 sub $0x8,%rsp
1409: 48 8d 35 3c 1d 00 00 lea 0x1d3c(%rip),%rsi
# 314c <_IO_stdin_used+0x14c>
1410: e8 54 04 00 00 callq 1869 <strings_not_equal>
1415: 85 c0 test %eax,%eax
1417: 75 05 jne 141e <phase_1+0x19>
1419: 48 83 c4 08 add $0x8,%rsp
141d: c3 retq
141e: e8 52 05 00 00 callq 1975 <explode_bomb>
1423: eb f4 jmp 1419 <phase_1+0x14>
```
Widzimy, że porównywane są dwa stringi (`<strings_not_equal>`), w razie gdy są różne od siebie, następuje skok do instrukcji `<explode_bomb>`, a więc musimy tego uniknąć. String ten musi znajdować się w pamięci programu, więc poniższym poleceniem możemy podejrzeć, jakie znajdują się w bombie, a następnie poszukamy najbardziej wyróżniającego się.
```
strings bomb
```
Jest ich dosyć dużo, ale nas interesują te "sensowne", część z nich znajduje się tutaj:
```
That's number 2. Keep going!
Halfway there!
Good work! On to the next...
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
So you got that one. Try this one.
Public speaking is very easy.
oilers
maduiersnfotvbylWow! You've defused the secret stage!
So you think you can stop the bomb with ctrl-c, do you?
Curses, you've found the secret phase!
But finding it and solving it are quite different...
Congratulations! You've defused the bomb!
Well...
OK. :-)
```
Moją uwagę najbardziej przykuły te trzy:
```
Public speaking is very easy.
oilers
maduiersnfotvbyl
```
A więc próbujemy po kolei je wpisywać, okazuje się, że pierwszy string jest poprawny, a więc przechodzimy do następnej fazy!
## Faza druga
Wydruk objdump:
```
0000000000001425 <phase_2>:
1425: 55 push %rbp
1426: 53 push %rbx
1427: 48 83 ec 28 sub $0x28,%rsp
142b: 48 89 e6 mov %rsp,%rsi
142e: e8 68 05 00 00 callq 199b <read_six_numbers>
1433: 83 3c 24 01 cmpl $0x1,(%rsp)
1437: 75 09 jne 1442 <phase_2+0x1d>
1439: 48 89 e3 mov %rsp,%rbx
143c: 48 8d 6b 14 lea 0x14(%rbx),%rbp
1440: eb 15 jmp 1457 <phase_2+0x32>
1442: e8 2e 05 00 00 callq 1975 <explode_bomb>
1447: eb f0 jmp 1439 <phase_2+0x14>
1449: e8 27 05 00 00 callq 1975 <explode_bomb>
144e: 48 83 c3 04 add $0x4,%rbx
1452: 48 39 eb cmp %rbp,%rbx
1455: 74 0b je 1462 <phase_2+0x3d>
1457: 8b 03 mov (%rbx),%eax
1459: 01 c0 add %eax,%eax
145b: 39 43 04 cmp %eax,0x4(%rbx)
145e: 74 ee je 144e <phase_2+0x29>
1460: eb e7 jmp 1449 <phase_2+0x24>
1462: 48 83 c4 28 add $0x28,%rsp
1466: 5b pop %rbx
1467: 5d pop %rbp
1468: c3 retq
```
Pierwszą rzeczą, jaka rzuca się w oczy, jest wywołanie funkcji `<read_six_numbers>` - jej nazwa mówi sama za siebie. Po wczytaniu sześciu liczb (całkowitych) `a b c d e f` przechodzimy do kolejnych instrukcji: trafiamy na `cmpl $0x1,(%rsp)` - porównujemy naszą pierwszą liczbę `a` z wartością `0x1`, gdy nie są one równe, bomba wybucha. Wiemy więc, że nasz ciąg musi zaczynać się od wartości `0x1`, aby ominąć pierwszy warunek. Przechodzimy więc dalej, do instrukcji o adresie `0x1457`, a więc do `mov (%rbx), %eax`, a następnie do `add %eax, %eax`. Pierwsza z nich przypisuje wartość z rejestru `%rbx` do `%eax`, a druga dodaje do siebie `%eax` (a więc mnoży wartość `%eax` przez 2). Następnie porównywana jest uzyskana wartość po pomnożeniu z `0x4(%rbx)` i w razie równości idziemy na początek pętli do adresu `0x144e`. Można łatwo wywnioskować, że skoro przy każdym wywołaniu mnożymy wartość przez 2, a pierwszą z nich jest 1, to będziemy mieli do czynienia z ciągiem geometrycznym `1 2 4 8 16 32`, który przeniesie nas do fazy trzeciej!
## Faza trzecia
Wydruk objdump:
```
0000000000001469 <phase_3>:
1469: 48 83 ec 18 sub $0x18,%rsp
146d: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx
1472: 48 8d 54 24 0c lea 0xc(%rsp),%rdx
1477: 48 8d 35 69 1e 00 00 lea 0x1e69(%rip),%rsi
# 32e7 <array.3195+0x147>
147e: b8 00 00 00 00 mov $0x0,%eax
1483: e8 a8 fc ff ff callq 1130 <__isoc99_sscanf@plt>
1488: 83 f8 01 cmp $0x1,%eax
148b: 7e 1f jle 14ac <phase_3+0x43>
148d: 83 7c 24 0c 07 cmpl $0x7,0xc(%rsp)
1492: 0f 87 8b 00 00 00 ja 1523 <phase_3+0xba>
1498: 8b 44 24 0c mov 0xc(%rsp),%eax
149c: 48 8d 15 dd 1c 00 00 lea 0x1cdd(%rip),%rdx
# 3180 <_IO_stdin_used+0x180>
14a3: 48 63 04 82 movslq (%rdx,%rax,4),%rax
14a7: 48 01 d0 add %rdx,%rax
14aa: ff e0 jmpq *%rax
14ac: e8 c4 04 00 00 callq 1975 <explode_bomb>
14b1: eb da jmp 148d <phase_3+0x24>
14b3: b8 ce 02 00 00 mov $0x2ce,%eax
14b8: eb 05 jmp 14bf <phase_3+0x56>
14ba: b8 00 00 00 00 mov $0x0,%eax
14bf: 2d e2 03 00 00 sub $0x3e2,%eax
14c4: 05 bf 03 00 00 add $0x3bf,%eax
14c9: 2d 24 03 00 00 sub $0x324,%eax
14ce: 05 24 03 00 00 add $0x324,%eax
14d3: 2d 24 03 00 00 sub $0x324,%eax
14d8: 05 24 03 00 00 add $0x324,%eax
14dd: 2d 24 03 00 00 sub $0x324,%eax
14e2: 83 7c 24 0c 05 cmpl $0x5,0xc(%rsp)
14e7: 7f 06 jg 14ef <phase_3+0x86>
14e9: 39 44 24 08 cmp %eax,0x8(%rsp)
14ed: 74 05 je 14f4 <phase_3+0x8b>
14ef: e8 81 04 00 00 callq 1975 <explode_bomb>
14f4: 48 83 c4 18 add $0x18,%rsp
14f8: c3 retq
14f9: b8 00 00 00 00 mov $0x0,%eax
14fe: eb c4 jmp 14c4 <phase_3+0x5b>
1500: b8 00 00 00 00 mov $0x0,%eax
1505: eb c2 jmp 14c9 <phase_3+0x60>
1507: b8 00 00 00 00 mov $0x0,%eax
150c: eb c0 jmp 14ce <phase_3+0x65>
150e: b8 00 00 00 00 mov $0x0,%eax
1513: eb be jmp 14d3 <phase_3+0x6a>
1515: b8 00 00 00 00 mov $0x0,%eax
151a: eb bc jmp 14d8 <phase_3+0x6f>
151c: b8 00 00 00 00 mov $0x0,%eax
1521: eb ba jmp 14dd <phase_3+0x74>
1523: e8 4d 04 00 00 callq 1975 <explode_bomb>
1528: b8 00 00 00 00 mov $0x0,%eax
152d: eb b3 jmp 14e2 <phase_3+0x79>
```
Tutaj dzieje się już troszkę więcej niż w dwóch poprzednich fazach. W komentarzu widnieje adres pamięci w tablicy (`32e7 <array.3195+0x147>`), jednak sam wydruk z objdump'a nic nam tutaj nie da. Musimy odpalić GDB i ustawiając breakpoint na `phase_3` wpisać cokolwiek (aby dostać się do fazy trzeciej). W miejscu tego komentarza pojawia się adres `0x5555555572e7`, warto więc sprawdzić co się tam znajduje, gdyż dwie instrukcje dalej wywoływana jest funkcja `sscanf`, która jako jeden z argumentów przyjmuje "styl" wejścia. Wiemy, że jest to string, a więc w GDB używamy polecenia:
```
>>> x/s 0x5555555572e7
0x5555555572e7: "%d %d"
```
Zwrócona wartość `"%d %d"` mówi o tym, że na wejściu przyjmowane są dwie liczby całkowite, więc możemy zacząć debugowanie od nowa (bo kto by się spodziewał, że akurat należy wpisać dwie liczby). Znów mamy porównanie wartości `$0x1`, więc nasz input będzie postaci `1 x`. Gdy drugi argument (ten `x`) jest zbyt duży, to nie przejdziemy późniejszych testów. Dość szybko rzucają się w oczy instrukcje:
```
14ba: b8 00 00 00 00 mov $0x0,%eax
14bf: 2d e2 03 00 00 sub $0x3e2,%eax
14c4: 05 bf 03 00 00 add $0x3bf,%eax
14c9: 2d 24 03 00 00 sub $0x324,%eax
14ce: 05 24 03 00 00 add $0x324,%eax
14d3: 2d 24 03 00 00 sub $0x324,%eax
14d8: 05 24 03 00 00 add $0x324,%eax
14dd: 2d 24 03 00 00 sub $0x324,%eax
```
Postanowiłem obliczyć wartość `%eax` po wykonaniu ich, a więc szukamy rozwiązania następującego równania: `0 - a + b - c`, gdzie `a = 0x3e2 = 994`, `b = 0x3bf = 959`, `c = 0x324 = 804`. Wynikiem jest `-839`, wpisujemy to jako drugi argument i jesteśmy w kolejnej fazie!
## Faza czwarta
Wydruk objdump:
```
0000000000001567 <phase_4>:
1567: 48 83 ec 18 sub $0x18,%rsp
156b: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
1570: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
1575: 48 8d 35 6b 1d 00 00 lea 0x1d6b(%rip),%rsi
# 32e7 <array.3195+0x147>
157c: b8 00 00 00 00 mov $0x0,%eax
1581: e8 aa fb ff ff callq 1130 <__isoc99_sscanf@plt>
1586: 83 f8 02 cmp $0x2,%eax
1589: 75 0c jne 1597 <phase_4+0x30>
158b: 8b 44 24 0c mov 0xc(%rsp),%eax
158f: 83 e8 02 sub $0x2,%eax
1592: 83 f8 02 cmp $0x2,%eax
1595: 76 05 jbe 159c <phase_4+0x35>
1597: e8 d9 03 00 00 callq 1975 <explode_bomb>
159c: 8b 74 24 0c mov 0xc(%rsp),%esi
15a0: bf 06 00 00 00 mov $0x6,%edi
15a5: e8 85 ff ff ff callq 152f <func4>
15aa: 39 44 24 08 cmp %eax,0x8(%rsp)
15ae: 75 05 jne 15b5 <phase_4+0x4e>
15b0: 48 83 c4 18 add $0x18,%rsp
15b4: c3 retq
15b5: e8 bb 03 00 00 callq 1975 <explode_bomb>
15ba: eb f4 jmp 15b0 <phase_4+0x49>
```
```
000000000000152f <func4>:
152f: b8 00 00 00 00 mov $0x0,%eax
1534: 85 ff test %edi,%edi
1536: 7e 2e jle 1566 <func4+0x37>
1538: 89 f0 mov %esi,%eax
153a: 83 ff 01 cmp $0x1,%edi
153d: 74 27 je 1566 <func4+0x37>
153f: 41 54 push %r12
1541: 55 push %rbp
1542: 53 push %rbx
1543: 41 89 f4 mov %esi,%r12d
1546: 89 fb mov %edi,%ebx
1548: 8d 7f ff lea -0x1(%rdi),%edi
154b: e8 df ff ff ff callq 152f <func4>
1550: 42 8d 2c 20 lea (%rax,%r12,1),%ebp
1554: 8d 7b fe lea -0x2(%rbx),%edi
1557: 44 89 e6 mov %r12d,%esi
155a: e8 d0 ff ff ff callq 152f <func4>
155f: 01 e8 add %ebp,%eax
1561: 5b pop %rbx
1562: 5d pop %rbp
1563: 41 5c pop %r12
1565: c3 retq
1566: c3 retq
```
Tutaj znów sprawdzamy co powinno znajdować się argumentach (tak samo jak w fazie trzeciej). Nie będę ukrywał, że tej fazy nie chciało mi się robić manualnie, ze względu na rekurencyjne wywołania w `func4`, dlatego napisałem skrypt sprawdzający wszystkie kombinacje dla dwóch liczb z przedziału od 1 do 1000:
```bash=
#!/bin/bash
> brute.txt # stworzenie lub wyczyszczenie zawartości pliku
test() {
out=$(./bomb psol.txt <<< "$1 $2") # uruchomienie bomby z argumentem i, j
echo $out # wypisanie wszystkiego ze stdout
}
for ((i=0; i<1000;i++))
do
for ((j=0; j<1000;j++))
do
echo "i: $i j: $j $(test $i $j)" >> brute.txt
# wypisujemy dane w postaci i: val_i j: val_j test_output
# i zapisujemy je w nowej linijce brute.txt
done
done
```
Ostrzegam, że skrypt troszkę się wykonuje (u mnie było to około 40 minut) i plik wyjściowy zajmuje 223MB, ale spełnia swoją rolę. Mając już cały plik wyszukałem zapytaniem regex'owym wyrażenia `.*BOMB.*\n`, a więc każdej linijki, w której występuje słowo `BOMB` (pojawia się tylko przy nieudanym rozbrojeniu) i skasowałem otrzymane wyniki. Pozostałe otrzymane wartości to `40 2`, `60 3` oraz `80 3`.
Z ciekawości odpaliłem breakpoint na tej fazie, aby zobaczyć czy na pewno wszystko dobrze przebiega, w pewnym momencie (po zakończeniu fazy) pokazał mi się kod źródłowy, a że nie przeglądałem go wcześniej, postanowiłem zdeasemblować funkcję `phase_defused`.
```c=94
input = read_line();
phase_4(input);
phase_defused();
```
```
0000000000001b20 <phase_defused>:
1b20: 83 3d 59 38 00 00 06 cmpl $0x6,0x3859(%rip)
# 5380 <num_input_strings>
1b27: 74 01 je 1b2a <phase_defused+0xa>
1b29: c3 retq
1b2a: 48 83 ec 68 sub $0x68,%rsp
1b2e: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx
1b33: 48 8d 54 24 0c lea 0xc(%rsp),%rdx
1b38: 4c 8d 44 24 10 lea 0x10(%rsp),%r8
1b3d: 48 8d 35 ed 17 00 00 lea 0x17ed(%rip),%rsi
# 3331 <array.3195+0x191>
1b44: 48 8d 3d 65 3d 00 00 lea 0x3d65(%rip),%rdi
# 58b0 <input_strings+0xf0>
1b4b: b8 00 00 00 00 mov $0x0,%eax
1b50: e8 db f5 ff ff callq 1130 <__isoc99_sscanf@plt>
1b55: 83 f8 03 cmp $0x3,%eax
1b58: 74 11 je 1b6b <phase_defused+0x4b>
1b5a: 48 8d 3d 0f 17 00 00 lea 0x170f(%rip),%rdi
# 3270 <array.3195+0xd0>
1b61: e8 fa f4 ff ff callq 1060 <puts@plt>
1b66: 48 83 c4 68 add $0x68,%rsp
1b6a: c3 retq
1b6b: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
1b70: 48 8d 35 c3 17 00 00 lea 0x17c3(%rip),%rsi
# 333a <array.3195+0x19a>
1b77: e8 ed fc ff ff callq 1869 <strings_not_equal>
1b7c: 85 c0 test %eax,%eax
1b7e: 75 da jne 1b5a <phase_defused+0x3a>
1b80: 48 8d 3d 89 16 00 00 lea 0x1689(%rip),%rdi
# 3210 <array.3195+0x70>
1b87: e8 d4 f4 ff ff callq 1060 <puts@plt>
1b8c: 48 8d 3d a5 16 00 00 lea 0x16a5(%rip),%rdi
# 3238 <array.3195+0x98>
1b93: e8 c8 f4 ff ff callq 1060 <puts@plt>
1b98: b8 00 00 00 00 mov $0x0,%eax
1b9d: e8 d8 fb ff ff callq 177a <secret_phase>
1ba2: eb b6 jmp 1b5a <phase_defused+0x3a>
```
Okazało się, że to właśnie w tej funkcji zawarta jest funkcja `secret_phase`, do której rozwiązania przejdę później. Póki co interesuje nas to, że w jakiś sposób możemy do niej się dostać. Przeczytajmy więc kod źródłowy dołączony do zadania, będą nas interesować (o dziwo najbardziej) komentarze:
```c=
/***************************************************************************
* Dr. Evil's Insidious Bomb, Version 1.1
* Copyright 2011, Dr. Evil Incorporated. All rights reserved.
*
* LICENSE:
*
* Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
* VICTIM) explicit permission to use this bomb (the BOMB). This is a
* time limited license, which expires on the death of the VICTIM.
* The PERPETRATOR takes no responsibility for damage, frustration,
* insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
* harm to the VICTIM. Unless the PERPETRATOR wants to take credit,
* that is. The VICTIM may not distribute this bomb source code to
* any enemies of the PERPETRATOR. No VICTIM may debug,
* reverse-engineer, run "strings" on, decompile, decrypt, or use any
* other technique to gain knowledge of and defuse the BOMB. BOMB
* proof clothing may not be worn when handling this program. The
* PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
* humor. This license is null and void where the BOMB is prohibited
* by law.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "support.h"
#include "phases.h"
/*
* Note to self: Remember to erase this file so my victims will have no
* idea what is going on, and so they will all blow up in a
* spectaculary fiendish explosion. -- Dr. Evil
*/
```
Wiele razy jest wspominana fraza `Dr. Evil`, którą mogliśmy zauważyć już w wydruku `strings bomb` (nie ująłem tego w fazie pierwszej), jednak w postaci `DrEvil`. Skoro pojawia się ona w symbolach, to musi być gdzieś użyta w kodzie. Aktywować ukrytą fazę możemy dopisując `DrEvil` na końcu wejścia, np. `40 2 DrEvil`. Teraz spokojnie, po wyczerpującym bruteforce możemy przejść do kolejnej fazy.
## Faza piąta
Wydruk objdump:
```
00000000000015bc <phase_5>:
15bc: 53 push %rbx
15bd: 48 83 ec 10 sub $0x10,%rsp
15c1: 48 89 fb mov %rdi,%rbx
15c4: e8 83 02 00 00 callq 184c <string_length>
15c9: 83 f8 06 cmp $0x6,%eax
15cc: 75 45 jne 1613 <phase_5+0x57>
15ce: b8 00 00 00 00 mov $0x0,%eax
15d3: 48 8d 0d c6 1b 00 00 lea 0x1bc6(%rip),%rcx
# 31a0 <array.3195>
15da: 0f b6 14 03 movzbl (%rbx,%rax,1),%edx
15de: 83 e2 0f and $0xf,%edx
15e1: 0f b6 14 11 movzbl (%rcx,%rdx,1),%edx
15e5: 88 54 04 09 mov %dl,0x9(%rsp,%rax,1)
15e9: 48 83 c0 01 add $0x1,%rax
15ed: 48 83 f8 06 cmp $0x6,%rax
15f1: 75 e7 jne 15da <phase_5+0x1e>
15f3: c6 44 24 0f 00 movb $0x0,0xf(%rsp)
15f8: 48 8d 7c 24 09 lea 0x9(%rsp),%rdi
15fd: 48 8d 35 66 1b 00 00 lea 0x1b66(%rip),%rsi
# 316a <_IO_stdin_used+0x16a>
1604: e8 60 02 00 00 callq 1869 <strings_not_equal>
1609: 85 c0 test %eax,%eax
160b: 75 0d jne 161a <phase_5+0x5e>
160d: 48 83 c4 10 add $0x10,%rsp
1611: 5b pop %rbx
1612: c3 retq
1613: e8 5d 03 00 00 callq 1975 <explode_bomb>
1618: eb b4 jmp 15ce <phase_5+0x12>
161a: e8 56 03 00 00 callq 1975 <explode_bomb>
161f: eb ec jmp 160d <phase_5+0x51>
```
Bardzo mocno rzuca się w oczy kolejna funkcja, jeszcze nie użyta - `<string_length>`. Zwracana przez nią wartość jest porównywana z 6, a więc nasz string musi mieć 6 znaków.
Odwołujemy się w całej funkcji do dwóch stringów (adresy z komentarzy), sprawdzając je poleceniem `x/s` otrzymujemy `"maduiersnfotvbylWow! You've defused the secret stage"` oraz `"oilers"`. Skoro nasz string może mieć 6 znaków, to prawdopodobnie `"oilers"` będzie rozwiązaniem lub czymś, co nas na nie naprowadzi. Wiemy też, że wiadomość `"Wow! You've defused the secret stage"` nie pasuje do naszej fazy, stąd pozostaje nam ciąg `"maduiersnfotvbyl"`.
Po przejściu `phase_5` w GDB zobaczyć możemy, że wykonujemy 6 razy pętlę i w każdym przejściu wykonywana jest instrukcja `and $0xf, %edx`. W każdej iteracji pętli w `%edx` przechowywane są kolejne litery naszego ciągu, a więc ich wartość (z ASCII) andujemy z `0xf`, dzięki czemu uzyskamy indeksy od 0 do 15 - pokryją się idealnie z pozostałym ciągiem. Możemy sobie zrobić prostą tabelkę, którą wypełnimy w następujący sposób: litery `a-z` zapiszemy jako liczby całkowite, w kolejnym wierszu będą przechowywane wartości `(int)ch AND 0xf`, a w ostatnim wierszu odszukamy litery o odpowiednich indeksach z ciągu `"maduiersnfotvbyl"`.
| char | a | b | c | ... | x | y | z |
|:------------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| **ASCII** | 97 | 98 | 99 | ... | 120 | 121 | 122 |
| `AND 0xf` | 1 | 2 | 3 | ... | 8 | 9 | 10 |
| zaszyfrowane | a | d | u | ... | n | f | o |
Z tak utworzonej tabelki szukamy liter "zaszyfrowanych" odpowiadających tym z wyrazu `"oilers"`, znajdujemy w ten sposób jeden z kilku ciągów będących odpowiedzią: `"jdoefg"` i idziemy do ostatniej znanej fazy.
## Faza szósta
Wydruk objdump:
```
0000000000001621 <phase_6>:
1621: 41 57 push %r15
1623: 41 56 push %r14
1625: 41 55 push %r13
1627: 41 54 push %r12
1629: 55 push %rbp
162a: 53 push %rbx
162b: 48 83 ec 58 sub $0x58,%rsp
162f: 4c 8d 74 24 30 lea 0x30(%rsp),%r14
1634: 4c 89 f6 mov %r14,%rsi
1637: e8 5f 03 00 00 callq 199b <read_six_numbers>
163c: 4d 89 f4 mov %r14,%r12
163f: 41 bf 01 00 00 00 mov $0x1,%r15d
1645: 4c 8d 6c 24 30 lea 0x30(%rsp),%r13
164a: e9 a4 00 00 00 jmpq 16f3 <phase_6+0xd2>
164f: e8 21 03 00 00 callq 1975 <explode_bomb>
1654: e9 ac 00 00 00 jmpq 1705 <phase_6+0xe4>
1659: 48 89 e6 mov %rsp,%rsi
165c: 49 8d 7c 24 18 lea 0x18(%r12),%rdi
1661: 41 8b 0c 24 mov (%r12),%ecx
1665: b8 01 00 00 00 mov $0x1,%eax
166a: 48 8d 15 7f 3c 00 00 lea 0x3c7f(%rip),%rdx
# 52f0 <node1>
1671: 83 f9 01 cmp $0x1,%ecx
1674: 7e 0b jle 1681 <phase_6+0x60>
1676: 48 8b 52 08 mov 0x8(%rdx),%rdx
167a: 83 c0 01 add $0x1,%eax
167d: 39 c8 cmp %ecx,%eax
167f: 75 f5 jne 1676 <phase_6+0x55>
1681: 48 89 16 mov %rdx,(%rsi)
1684: 49 83 c4 04 add $0x4,%r12
1688: 48 83 c6 08 add $0x8,%rsi
168c: 4c 39 e7 cmp %r12,%rdi
168f: 75 d0 jne 1661 <phase_6+0x40>
1691: 48 8b 1c 24 mov (%rsp),%rbx
1695: 48 8b 44 24 08 mov 0x8(%rsp),%rax
169a: 48 89 43 08 mov %rax,0x8(%rbx)
169e: 48 8b 54 24 10 mov 0x10(%rsp),%rdx
16a3: 48 89 50 08 mov %rdx,0x8(%rax)
16a7: 48 8b 44 24 18 mov 0x18(%rsp),%rax
16ac: 48 89 42 08 mov %rax,0x8(%rdx)
16b0: 48 8b 54 24 20 mov 0x20(%rsp),%rdx
16b5: 48 89 50 08 mov %rdx,0x8(%rax)
16b9: 48 8b 44 24 28 mov 0x28(%rsp),%rax
16be: 48 89 42 08 mov %rax,0x8(%rdx)
16c2: 48 c7 40 08 00 00 00 movq $0x0,0x8(%rax)
16c9: 00
16ca: bd 05 00 00 00 mov $0x5,%ebp
16cf: eb 4c jmp 171d <phase_6+0xfc>
16d1: e8 9f 02 00 00 callq 1975 <explode_bomb>
16d6: 48 83 c3 01 add $0x1,%rbx
16da: 83 fb 05 cmp $0x5,%ebx
16dd: 7f 0c jg 16eb <phase_6+0xca>
16df: 41 8b 44 9d 00 mov 0x0(%r13,%rbx,4),%eax
16e4: 39 45 00 cmp %eax,0x0(%rbp)
16e7: 75 ed jne 16d6 <phase_6+0xb5>
16e9: eb e6 jmp 16d1 <phase_6+0xb0>
16eb: 49 83 c7 01 add $0x1,%r15
16ef: 49 83 c6 04 add $0x4,%r14
16f3: 4c 89 f5 mov %r14,%rbp
16f6: 41 8b 06 mov (%r14),%eax
16f9: 83 e8 01 sub $0x1,%eax
16fc: 83 f8 05 cmp $0x5,%eax
16ff: 0f 87 4a ff ff ff ja 164f <phase_6+0x2e>
1705: 49 83 ff 06 cmp $0x6,%r15
1709: 0f 84 4a ff ff ff je 1659 <phase_6+0x38>
170f: 4c 89 fb mov %r15,%rbx
1712: eb cb jmp 16df <phase_6+0xbe>
1714: 48 8b 5b 08 mov 0x8(%rbx),%rbx
1718: 83 ed 01 sub $0x1,%ebp
171b: 74 11 je 172e <phase_6+0x10d>
171d: 48 8b 43 08 mov 0x8(%rbx),%rax
1721: 8b 00 mov (%rax),%eax
1723: 39 03 cmp %eax,(%rbx)
1725: 7e ed jle 1714 <phase_6+0xf3>
1727: e8 49 02 00 00 callq 1975 <explode_bomb>
172c: eb e6 jmp 1714 <phase_6+0xf3>
172e: 48 83 c4 58 add $0x58,%rsp
1732: 5b pop %rbx
1733: 5d pop %rbp
1734: 41 5c pop %r12
1736: 41 5d pop %r13
1738: 41 5e pop %r14
173a: 41 5f pop %r15
173c: c3 retq
```
Jest to najdłuższa faza z rozpatrywanych, po przeanalizowaniu instrukcji możemy dojrzeć komentarz z odnośnikiem `52f0 <node1>` - prawdopodobnie będziemy pracować z jakąś strukturą danych z węzłami. Powyżej widzimy znaną już nam funkcję `<read_six_numbers>`, możemy się spodziewać, że będziemy operować na sześciu węzłach. Podejrzyjmy poleceniem `x/3x` wspomniany adres (jednak nie z objdumpa, a GDB), otrzymamy wtedy:
```
0x5555555592f0 <node1>: 0x0000038c 0x00000001 0x55559300
```
Kolejne wartości odpowiadają: wartości węzła, indeksowi węzła, adresowi kolejnego węzła (uciętego do 8 ostatnich cyfr). Sporządźmy sobie tabelkę, w której zapiszemy wszystkie wartości, od razu obliczmy wartość dziesiętną węzłów:
| wartość HEX | wartość DEC | indeks | adres (kolejny węzeł) |
|:-----------:|:-----------:|:------:|:---------------------:|
| `0x38c` | `908` | 1 | `0x555555559300` |
| `0x36d` | `877` | 2 | `0x555555559310` |
| `0x10d` | `269` | 3 | `0x555555559320` |
| `0x2af` | `687` | 4 | `0x555555559330` |
| `0x06c` | `108` | 5 | `0x5555555591f0` |
| `0x0d9` | `217` | 6 | `0x0` |
Mając tak przygotowaną tabelkę, możemy przejść do kolejnej części tej fazy. Po dość długiej i żmudnej analizie instrukcji można dojść do wniosku, że program oczekuje na wejściu posortowanych rosnąco po wartościach indeksów węzłów, a więc dużo łatwiej jest znów puścić bruteforce, żeby znaleźć poprawne rozwiązanie (zaoszczędzimy dużo czasu, bo jest tylko $6!=720$ możliwości). W moim przypadku rozwiązaniem tej fazy jest ciąg `5 6 3 4 2 1`.
## Faza siódma (ukryta)
Wydruk objdump:
```
000000000000177a <secret_phase>:
177a: 53 push %rbx
177b: e8 5c 02 00 00 callq 19dc <read_line>
1780: ba 0a 00 00 00 mov $0xa,%edx
1785: be 00 00 00 00 mov $0x0,%esi
178a: 48 89 c7 mov %rax,%rdi
178d: e8 7e f9 ff ff callq 1110 <strtol@plt>
1792: 48 89 c3 mov %rax,%rbx
1795: 8d 40 ff lea -0x1(%rax),%eax
1798: 3d e8 03 00 00 cmp $0x3e8,%eax
179d: 77 26 ja 17c5 <secret_phase+0x4b>
179f: 89 de mov %ebx,%esi
17a1: 48 8d 3d 68 3a 00 00 lea 0x3a68(%rip),%rdi
# 5210 <n1>
17a8: e8 90 ff ff ff callq 173d <fun7>
17ad: 83 f8 04 cmp $0x4,%eax
17b0: 75 1a jne 17cc <secret_phase+0x52>
17b2: 48 8d 3d f7 19 00 00 lea 0x19f7(%rip),%rdi
# 31b0 <array.3195+0x10>
17b9: e8 a2 f8 ff ff callq 1060 <puts@plt>
17be: e8 5d 03 00 00 callq 1b20 <phase_defused>
17c3: 5b pop %rbx
17c4: c3 retq
17c5: e8 ab 01 00 00 callq 1975 <explode_bomb>
17ca: eb d3 jmp 179f <secret_phase+0x25>
17cc: e8 a4 01 00 00 callq 1975 <explode_bomb>
17d1: eb df jmp 17b2 <secret_phase+0x38>
```
```
000000000000173d <fun7>:
173d: 48 85 ff test %rdi,%rdi
1740: 74 32 je 1774 <fun7+0x37>
1742: 48 83 ec 08 sub $0x8,%rsp
1746: 8b 17 mov (%rdi),%edx
1748: 39 f2 cmp %esi,%edx
174a: 7f 0c jg 1758 <fun7+0x1b>
174c: b8 00 00 00 00 mov $0x0,%eax
1751: 75 12 jne 1765 <fun7+0x28>
1753: 48 83 c4 08 add $0x8,%rsp
1757: c3 retq
1758: 48 8b 7f 08 mov 0x8(%rdi),%rdi
175c: e8 dc ff ff ff callq 173d <fun7>
1761: 01 c0 add %eax,%eax
1763: eb ee jmp 1753 <fun7+0x16>
1765: 48 8b 7f 10 mov 0x10(%rdi),%rdi
1769: e8 cf ff ff ff callq 173d <fun7>
176e: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
1772: eb df jmp 1753 <fun7+0x16>
1774: b8 ff ff ff ff mov $0xffffffff,%eax
1779: c3 retq
```
Znów będę szczery, nie chciało mi się za bardzo siedzieć i nad tym myśleć, dlatego po jednym prześledzeniu działania przy wejściu `6` (co okazało się być dosyć trafne, gdyż oczekiwany input to jedna liczba całkowita), postanowiłem zrobić kolejny bruteforce na wartościach od 0 do 1000, dosyć szybko okazało się, że szukaną wartością jest 7, co sprawiło że cała bomba została pomyślnie rozbrojona.
## Easter egg
Po próbie zakończenia programu skrótem `Ctrl + C` zostaniemy zapytani, czy myślimy, że zatrzymamy bombę właśnie tym skrótem. Jeżeli wpiszemy `yes`, to wypisane zostanie `Well...`, a następnie w nieskończonej pętli będzie wypisywało się `y` od nowej linii. Gdy wpiszemy coś innego (np. `no`), wypisane zostanie tylko `Well...OK. :-)` i program zakończy swoje działanie.