# Lista 9 (06.05.2021), grupa pwit
###### tags: `ask21` `ćwiczenia` `pwit`
## Deklaracje
Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle.
**UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!**
Tabelka zawiera tylko osoby zapisane do grupy. Osoby oczekujące proszone są o wpisanie się do osobnej tabelki poniżej.
:::danger
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --------------------:| --- | --- | --- | --- |:---:|:---:| --- |
|Wojciech Adamiec | | X | | | X | | |
|Kacper Bajkiewicz | | X | X | X | X | | |
|Bartłomiej Hildebrandt| X | X | | | X | | |
|Dominik Komła | | | | | | | |
|Aleksandra Kosińska | | X | | | | | |
|Oleś Kulcewicz | | X | | | X | | |
|Damian Lukas | | X | | | X | | |
|Michał Mikołajczyk | | X | X | | X | | |
|Mateusz Opala | | X | | | X | | |
|Łukasz Orawiec | | X | X | X | X | | |
|Szymon Pielat | | X | X | | X | | |
|Łukasz Pluta | | X | | | X | | |
|Kamil Puchacz | | X | X | | X | | |
|Magdalena Rzepka | | X | | | | | |
|Cezary Stajszczyk | | X | X | | | | |
|Jakub Szajner | | X | X | X | X | | |
|Bartosz Troszka | | | | | | | |
|Miłosz Urbanik | | | | | | | |
Deklaracje zadań z listy 8:
| | 7 | 8 |
| --------------------:| --- |:---:|
| Bartłomiej Hildebrandt | X | X |
:::
## Zadanie 8.7 i 8.8
:::info
Autor: Bartłomiej Hildebrandt
(Rozwiązania proszę wpisać w formularzu dla poprzedniej listy)
:::
## Zadanie 1
:::info
Autor: Bartłomiej Hildebrandt
:::
> W trakcie tłumaczenia poniższego kodu na asembler kompilator umieścił tablicę skoków dla instrukcji wyboru switch w sekcji «.rodata». W sekcji «.text» i «.rodata» wskaż miejsca występowania referencji do symboli, a następnie podaj zawartość tablicy rekordów relokacji «.rela.text» i «.rela.rodata».
>
> 
>
> W wyniku konsolidacji pliku wykonywalnego zawierającego procedurę «relo3», została ona umieszczona pod adresem 0x1000, a tablica skoków pod 0x2000. Oblicz wartości, które należy wstawić w miejsca referencji, do których odnoszą się rekordy relokacji.
Kod w C:
```c=
int relo3(int val) {
switch (val) {
case 100:
return val;
case 101:
return val + 1;
case 103:
case 104:
return val + 3;
case 105:
return val + 5;
default:
return val + 6;
}
}
```
Kod w assemblerze:
```c=
0000000000000000 <relo3>:
0: 8d 47 9c lea -0x64(%rdi), %eax
3: 83 f8 05 cmp $0x5, %eax
6: 77 15 ja 1d <relo3+0x1d>
8: 89 c0 mov %eax, %eax
a: ff 24 c5 00 00 00 00 jmpq *0x0(,%rax,8)
11: 8d 47 01 lea 0x1(%rdi), %eax
14: c3 retq
15: 8d 47 03 lea 0x3(%rdi), %eax
18: c3 retq
19: 8d 47 05 lea 0x5(%rdi), %eax
1c: c3 retq
1d: 8d 47 06 lea 0x6(%rdi), %eax
20: c3 retq
21: 89 f8 mov %edi,%eax
23: c3 retq
```
Sekcje:
- `.text` - kod programu
- `.rodata` - dane do odczytu (tablica skoków, stałe stringowe itp.)
- `.rel.text` - informacje o relokacji dla sekcji `.text` (np. adresy instrukcji, które będą musiały być zmodyfikowane w pliku wykonywalnym)
- `.rel.rodata` - informacje o relokacji dla sekcji `.rodata`
Narzędzia:
- `objdump` - wyświetla ogólne informacje o dowolnym formacie pliku obiektowego
- `readelf` - również wyświetla informacje o pliku obiektowym, ale może wydrukować wszystkie możliwe informacje na jego temat i jest niezależny od architektury
### W sekcji `.text` i `.rodata` wskaż miejsca występowania referencji do symboli.
Aby wskazać miejsca występowania referencji do symboli, użyjemy polecenia, które wyświetli relokacje.
```bash=
objdump -D -r -j .text relo3.o
```
Flaga `-D` deassembluje cały dany obiekt, flaga `-r` drukuje wpisy relokacji pliku, a flaga `-j` pozwala nam wybrać sekcję.
#### Sekcja `.text`
```bash=
objdump -D -r -j .text relo3.o
relo3.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <relo3>:
0: f3 0f 1e fa endbr64
4: 8d 47 9c lea -0x64(%rdi),%eax
7: 83 f8 06 cmp $0x6,%eax
a: 77 23 ja 2f <relo3+0x2f> # referencja do symbolu
c: 89 c0 mov %eax,%eax
e: 48 8d 15 00 00 00 00 lea 0x0(%rip),%rdx # 15 <relo3+0x15>
11: R_X86_64_PC32 .rodata-0x4
15: 48 63 04 82 movslq (%rdx,%rax,4),%rax
19: 48 01 d0 add %rdx,%rax
1c: 3e ff e0 notrack jmpq *%rax
1f: 8d 47 01 lea 0x1(%rdi),%eax
22: c3 retq
23: 8d 47 03 lea 0x3(%rdi),%eax
26: c3 retq
27: 8d 47 05 lea 0x5(%rdi),%eax
2a: c3 retq
2b: 8d 47 0a lea 0xa(%rdi),%eax
2e: c3 retq
2f: 8d 47 06 lea 0x6(%rdi),%eax
32: c3 retq
33: 89 f8 mov %edi,%eax
35: c3 retq
```
#### Sekcja `.rodata`
```bash=
objdump -D -r -j .rodata relo3.o
relo3.o: file format elf64-x86-64
Disassembly of section .rodata:
0000000000000000 <.rodata>:
...
0: R_X86_64_PC32 .text+0x33
4: R_X86_64_PC32 .text+0x23
8: R_X86_64_PC32 .text+0x37
c: R_X86_64_PC32 .text+0x2f
10: R_X86_64_PC32 .text+0x33
14: R_X86_64_PC32 .text+0x3b
18: R_X86_64_PC32 .text+0x43
```
### Podaj zawartość tablicy rekordów relokacji `.rela.text` i `.rela.rodata`.
**rekordy relokacji (ang. relocation entries)** - struktury danych w relokowalnych modułach obiektowych, których zadaniem jest poinformowanie konsolidatora jak zmodyfikować referencję do obiektu, którego lokalizacji nie zna, kiedy łączy plik obiektowy w plik wykonywalny.
Ilekroć asembler napotka odniesienie do obiektu, którego ostateczne położenie jest nieznane, generuje pozycję relokacji, która mówi konsolidatorowi, jak zmodyfikować odniesienie, gdy łączy plik obiektowy w plik wykonywalny.
Relokacja typu `R_X86_64_PC32` relokuje referencje do adresów, które są obliczane na podstawie przesunięcia aktualnej wartości PC (Program Counter) o dany offset. Wartość PC to zawsze adres następnej instrukcji w pamięci.
Natomiast relokacja typu `R_X86_64_32` relokuje referencje do adresów, które są `absolute`, czyli bierzemy surowy adres zakodowany w instrukcji i przekształcamy na efektywny adres, bez modyfikowania go w żaden sposób.
```bash=
readelf -r relo3.o
Relocation section '.rela.text' at offset 0x4e0 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000011 000500000002 R_X86_64_PC32 0000000000000000 .rodata - 4
Relocation section '.rela.rodata' at offset 0x4f8 contains 7 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000000 000200000002 R_X86_64_PC32 0000000000000000 .text + 33
000000000004 000200000002 R_X86_64_PC32 0000000000000000 .text + 23
000000000008 000200000002 R_X86_64_PC32 0000000000000000 .text + 37
00000000000c 000200000002 R_X86_64_PC32 0000000000000000 .text + 2f
000000000010 000200000002 R_X86_64_PC32 0000000000000000 .text + 33
000000000014 000200000002 R_X86_64_PC32 0000000000000000 .text + 3b
000000000018 000200000002 R_X86_64_PC32 0000000000000000 .text + 43
```
### Oblicz wartości, które należy wstawić w miejsca referencji, do których odnoszą się rekordy relokacji.
Algorytm relokacji:
```c=
// s - sekcja (tablica bajtów)
// r - wpis tablicy relokacji (struktury typu Elf32_Rel)
foreach section s { // iteracja po sekcjach s
foreach relocation entry r { // iteracja po wpisach relokacji
refptr = s + r.offset; // oblicza adres w tablicy s 4-bajtowego odniesienia, które ma zostać przeniesione
/* realokuj referencję zależną od PC */
if (r.type == R_X86_64_PC32) { // jeżeli jest to adres typu relative to do adresu sekcji dodaj offset wpisu i realokuj
refaddr = ADDR(s) + r.offset; // adres referencji = adres sekcji + offset wpisu realokacji
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr);
}
// wpp. jest to adres typu absolute, więc po prostu realokujemy go
if (r.type == R_X86_64_32)
*refptr = (unsigned) (ADDR(r.symbol) + r.addend);
}
}
```
Obliczenia:
```c=
a) obliczenia dla relokacji z procedury relo3 dla sekcji .text
Sekcja .text ma tylko 1 wpis relokacji.
ADDR(r.symbol) = 0x2000
ADDR(.text) = 0x4e0
r.type = R_X86_64_PC32
// Informacje z tabeli rekordów aktywacji
r.offset = 0x11
r.addend = -0x4
refaddr = ADDR(.text) + r.offset = 0x4e0 + 0x11 = 0x4f1
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x2000 - 0x4 - 0x4f1 = 0x1b0b
b) obliczenia dla relokacji z procedury relo3 dla sekcji .rodata
Sekcja .rodata ma 7 wpisów relokacji.
ADDR(.text) = 0x4f8
ADDR(r.symbol) = 0x1000
r.type = R_X86_64_PC32
1)
r.offset = 0x0
r.addend = 0x33
refaddr = ADDR(.text) + r.offset = 0x4f8
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x33 - 0x4f8 = 0xb3b
2)
r.offset = 0x4
r.addend = 0x23
refaddr = ADDR(.text) + r.offset = 0x4fc
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x23 - 0x4fc = 0xb27
3)
r.offset = 0x8
r.addend = 0x37
refaddr = ADDR(.text) + r.offset = 0x500
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x37 - 0x500 = 0xb37
4)
r.offset = 0xc
r.addend = 0x2f
refaddr = ADDR(.text) + r.offset = 0x504
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x2f - 0x504 = 0xb2b
5)
r.offset = 0x10
r.addend = 0x33
refaddr = ADDR(.text) + r.offset = 0x508
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x33 - 0x508 = 0xb2b
6)
r.offset = 0x14
r.addend = 0x3b
refaddr = ADDR(.text) + r.offset = 0x50c
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x3b - 0x50c = 0xb2f
7)
r.offset = 0x18
r.addend = 0x43
refaddr = ADDR(.text) + r.offset = 0x510
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = 0x1000 + 0x43 - 0x510 = 0xb33
```
## Zadanie 2
:::info
Autor: Szymon Pielat
:::

**Dekorowanie nazw** służy do tego, aby odróżnić implementację różnych funkcji (o różnych sygnaturach) mających taką samą nazwę. Jest to oczywiście potrzebne w C++, ponieważ możemy przeciążać funkcje. Funkcja dekorująca jest różnowartościowa.
Udekorowane symbole zaczynają się od `_Z`.
Następnie mamy literę `N` mówiąca czy następuje`namespace`
1. Jeśli nie ma `N` to od razu po `Z` kodujemy nazwę podając najpierw liczbę liter wchodzących w skład nazwy, a następnie pełną nazwę.
2. Jeśli jest `N` to podajemy kolejne `namespace`'y na tej samej zasadzie co powyżej a po podaniu nazwy funkcji mamy literę `E`.
Następnie przechodzimy do argumentów funkcji. Tutaj mamy:
1. `P` oznacza `*`
2. `K` oznacza `const`
3. `R` oznacza `&`
4. `i` oznacza `int`, `d` oznacza `double` ....
Przykłady z zadania:
- `_Z4funcPKcRi` = `func(char const*, int&)`
- `_ZN3Bar3bazEPc` = `Bar::baz(char*)`
- `_ZN3BarC1ERKS_` =`Bar::Bar(Bar const&)`
- `_ZN3foo6strlenER6string` =`foo::strlen(string&)`
## Zadanie 3
:::info
Autor: Michał Mikołajczyk
:::
:::info
Przeprowadź na swoim komputerze atak na program «ropex» wykorzystując podatność **przepełnienia bufora** w procedurze «echo». Posłuż się techniką **ROP** (ang. return oriented programming). Wyznacz adresy procedury `«gadget»` oraz dowolnej instrukcji `«syscall»` w pliku `«ropex»`. Wpisz je, w porządku little-endian, do pliku `«ropex.in.txt»` na pozycji **0x38** i **0x40**, po czym przetłumacz go do postaci binarnej. Następnie uruchom polecenie `«ropex ropex.in»`, aby zobaczyć rezultat wykonania programu `«nyancat»` w terminalu. Przy pomocy debuggera gdb zaprezentuj zawartość stosu przed i po wykonaniu procedury `«gets»`. Pokaż jak procesor wykonując instrukcje `«ret»` skacze pod przygotowane przez Ciebie adresy.
:::
#### Definicje:
- **Przepełnienie bufora** -- funkcja może alokować bufor na stosie, a następnie przy wczytywaniu danych z wejścia/pliku może nie sprawdzać czy wczytała za dużo danych. W takim przypadku wypełnimy cały bufor na stosie, a następnie nadpiszemy część stosu poniżej tej części, która należy do wywoływanej funkcji. W ten sposób możemy nadpisać np. adres powrotu z funkcji.
- **ROP** -- technika polegająca na wykorzystywaniu istniejących części kodu atakowanej aplikacji. Polega na wczytaniu na stos i skoku do adresów instrukcji, które wykonują pożądane przez nas operacje i kończą się instrukcją *0xc3* (`ret`).
#### Przydatne polecenia:
```
sh:
objdump -d ropex
gdb --args ropex ropex.in
gdb:
x/32x $rsp[+0x??] (wyświetlanie bajtów ze stosu)
x/16c $rsp[+0x??] (wyświetlanie ascii ze stosu)
```
#### Procedura echo:
```
000000000040187b <echo>:
40187b: 48 83 ec 38 sub $0x38,%rsp
40187f: 48 89 e6 mov %rsp,%rsi
401882: e8 be ff ff ff call 401845 <readline>
401887: 48 89 e7 mov %rsp,%rdi
40188a: e8 d1 90 00 00 call 40a960 <_IO_puts>
40188f: 48 83 c4 38 add $0x38,%rsp
401893: c3 ret
```
#### Procedura gadget:
```
00000000004018cb <gadget>:
4018cb: 48 ff c8 dec %rax
4018ce: 48 89 d6 mov %rdx,%rsi
4018d1: 48 89 fa mov %rdi,%rdx
4018d4: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
4018d9: c3 ret
4018da: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
```
#### Jedna z instrukcji syscall:
```
4011ed: be 81 00 00 00 mov $0x81,%esi
4011f2: b8 ca 00 00 00 mov $0xca,%eax
4011f7: 48 8d 3d 42 0b 0b 00 lea 0xb0b42(%rip),%rdi # 4b1d40 <lock>
4011fe: 0f 05 syscall # <==============================
401200: bf 06 00 00 00 mov $0x6,%edi
401205: e8 e6 76 00 00 call 4088f0 <raise>
40120a: 64 48 8b 1c 25 10 00 mov %fs:0x10,%rbx
```
## Zadanie 4
:::info
Autor: Łukasz Orawiec
:::
**Kanarek** *(ang. canary)* -- losowa liczba umieszczana na stosie na początku wykonywania procedury, tuż przed adresem powrotu. Na końcu procedury jest sprawdzane, czy wartość się nie zmieniła, co mogłoby oznaczać przepełnienie bufora.
<br/>
**Uszkodzenie stosu** *(ang. stack smashing)* -- sytuacja, w której przepełnienie bufora prowadzi do nadpisania sąsiadującego obszaru pamięci na stosie (np. adres powrotu).
<br/>
**Randomizacja rozkładu przestrzeni adresowej** -- zabezpieczenie sprawiające, że różne sekcje programu są umieszczane pod losowymi adresami. Utrudnia atak przez wstrzyknięcie kodu na stos, bo trudno ustalić adres bufora.
<br/>
**Gadżet** -- fragment kodu istniejącego w programie wykorzystywany do ataku ROP.
## Zadanie 5
:::info
Autor: Wojciech Adamiec
:::
:::info

:::
**Dyrektywa asemblera** (assembler directive) to fraza w języku asemblera, która określa działanie asemblera i nie tłumaczy się bezpośrednio na kod maszynowy. Wszystkie dyrektywy asemblera zaczynają się od kropki (`.`).
Kod napisany w C. Potem przetłumaczony do `.s`:
`gcc -S -Og 1.c`
`gcc -S 2.c`
`gcc -S -O0 3.c`
Teraz, żeby sprawdzić `.symtab` to trzeba przetłumaczyć do `.o`. Po czym robimy `readelf -s nazwa.o`
Foo:

Struct:

Array:

[Link do dokumentacji](https://docs.oracle.com/cd/E26502_01/html/E28388/eoiyg.html)
Legenda:
`.align` integer, pad
The .align directive causes the next data generated to be aligned modulo integer bytes. Integer must be a positive integer expression and must be a power of 2. If specified, pad is an integer byte value used for padding. The default value of pad for the text section is 0x90 (nop); for other sections, the default value of pad is zero (0).
`.comm` name, size,alignment
The .comm directive allocates storage in the data section. The storage is referenced by the identifier name. Size is measured in bytes and must be a positive integer. Name cannot be predefined. Alignment is optional. If alignment is specified, the address of name is aligned to a multiple of alignment.
`.size` symbol, expr
Declares the symbol size to be expr. expr must be an absolute expression.
`.zero` expression
While filling a data section, the .zero directive fills the number of bytes specified by expression with zero (0).
Sprawdzamy `.symtab`:
1.

2.

3.

## Zadanie 6
:::info
Autor:
:::
## Zadanie 7
:::info
Autor:
:::