---
# System prepended metadata

title: Sprint Pwndbg (10.08.2022)

---

# Sprint Pwndbg (10.08.2022)

Hi! Witaj na stronie sprintu Pwndbg. Poniżej możesz przeczytać opisy przykładowych rzeczy, które można by dodać lub usprawnić w Pwndbg :).

* Repo projektu: https://github.com/pwndbg/pwndbg/

Sprint zaczniemy od małego wstępu "co to jest Pwndbg" i "co mogę z tym zrobić", a następnie podzielimy się na zadania wylistowane poniżej (ofc można dodać również i swoje).

### Jak rozpocząć debugowanie programu w GDB?
```bash
$ echo 'int main() { puts("Hello world"); )}' > a.c
$ gcc a.c
$ gdb --quiet ./a.out

pwndbg> break main
pwndbg> continue
```

Przydatne komendy:
```
break <symbol albo adres>     - ustawia breakpoint na danym adresie
run [<argumenty>]             - uruchamia procesu z danymi argumentami (jeśli nie ustawiliśmy breakpointa, to proces może się skończyć)
starti [<argumenty>]          - uruchamia proces i zatrzymuje się na jego pierwszej instrukcji
continue                      - kontynuuje wykonywanie programu
si                            - skrót od "step instruction", czyli: wykonaj dokładnie jedną instrukcję (wchodząc również do funkcji które są wywoływane)
ni                            - skrót od "next instruction", czyli: wykonaj jedną instrukcję, ale jeśli jest ona wywołaniem funkcji (np. instrukcja "call") to wykonaj całe wnętrze i zatrzymaj się dopiero na następnej instrukcji w funkcji w której jesteśmy

info break                    - wyświetl ustawione breakpointy
delete <numer-breakpointa>    - usuwa dany breakpoint; jeśli nie podamy numeru, to usunie wszystkie


print <wyrazenie>             - oblicz i wypisz dane wyrażenie 

x/10i $rip                    - komenda GDB "examine", posiadająca różne formaty; tu: wyświetlająca 10 instrukcji rozpoczynając od adresu z rejestru RIP (IP == Instruction Pointer), który wskazuje na instrukcję którą program będzie właśnie wykonywać
```
Polecam również [GDB cheatsheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf).

#### Taski na sprincie

Zadania mają różną trudność i wymagają różnej wiedzy. Prostsze zadania mogą pomóc w rozeznaniu się w strukturze projektu lub różnych schematach, np. jak wygląda "komenda".

PS: Na samym dole dodałem kilka przykładów róznych API w Pwndbg, które mogą się przydać oraz informacji o samym GDB.

Taski / kto co robi (poniżej jest dłuższy opis tasków):
* [x] [Poprawienie opisu oraz testy komendy `memfrob`](#Poprawienie-opisu-komendy-memfrob) -- artcz
* [x] [Sprzątanie po Pythonie 2](#Sprzątanie-po-Pythonie-2) -- Ivellios
* [x] [Rejestr X30 na architekturze aarch64](#Rejestr-X30-na-architekturze-aarch64) -- arcz
* [ ] [Dodanie możliwości `telescope --reversed`](#Dodanie-możliwości-telescope---reversed)
* [x] [Poprawienie parsowania adresów](#Poprawienie-parsowania-adresów) -- Nika
* [ ] [Dodanie komendy `patch <adres> <dane lub instrukcje>`](#Dodanie-komendy-patch-ltadresgt-ltdane-lub-instrukcjegt)
* [ ] [Dodanie testów do wybranych funkcjonalności](#Dodanie-testów-do-wybranych-funkcjonalności)
* [ ] [Dodanie funkcjonalności/komendy "dump memory as code"](#Dodanie-funkcjonalnościkomendy-“dump-memory-as-code”) -- vesim
* [x] [Dziwny bug #1008](https://github.com/pwndbg/pwndbg/issues/1008) - arcz
* [x] [Dziwny bug 2 #1042](https://github.com/pwndbg/pwndbg/issues/1042) - disconnect3d
* [ ] [Renderowanie argumentów printf-podobnych funkcji](#Renderowanie-argumentów-printf-podobnych-funkcji)
* [ ] Bundlowanie Pwndbg w jeden skrypt - Hubert
* [ ] Telemetria (eh :D)


---


## Poprawienie opisu komendy `memfrob`
Komenda `memfrob` robi XORa danej pamięci z kluczem `'*'`.

Powinniśmy to ująć w jej opisie, tak, żeby `memfrob --help` lub `help memfrob` jasno opisywało co to robi.

* Komendę memfrob możemy znaleźć szukając w projekcie funkcji `memfrob` naturalnie :)

## Sprzątanie po Pythonie 2
Stare wersje Pwndbg wspierały Pythona 2, ale od pewnej wersji usunęliśmy support dla Pythona 2, gdyż obecnie żadne nowe distro nie buduje GDB z Pythonem 2.

W kodzie Pwndbg pozostały jednak rzeczy, które potrzebne były jedynie w Pythonie 2, a teraz możemy się ich pozbyć.

Na przykład:
- komentarze odnośnie kodowania plików (`-*- coding: utf-8 -*-` itp.)
- w sumie to nie związane z Py2, ale niektóre pliki mają też shebang (`#!/usr/bin/env python`), który jest zbędny, gdyż nigdy nie są uruchamiane bezpośrednio

Być może coś jeszcze?


## Rejestr X30 na architekturze aarch64

Aarch64 to 64-bitowa architektura ARM (czyli to, co mamy m.in. w telefonach czy Macbookach M1/M2).
Na tej architekturze jest dość dużo rejestrów - X0-X30 - i obecnie chyba źle wyświetlamy jeden z nich.

Tu więcej info: https://github.com/pwndbg/pwndbg/issues/1039

To wszystko można przetestować lokalnie na architekturze x64 używając QEMU user emulation. Aby to zrobić musimy:
- zainstalować paczkę z QEMU user (`sudo apt install qemu-user`)
- zainstalować kompilator gcc na aarch64, aby cross-kompilować przykładowy program napisany w C do AARCH64 (`sudo apt install gcc-11-aarch64-linux-gnu`)
- stworzyć przykładowy program (`echo 'int main() {}' > main.c`)
- skompilować go
- wtedy możemy uruchomić ten program pod qemu: `qemu-aarch64 -L <sciezka-do-/lib-aarch64> ./a.out`
- dodając flagę `-g 1234` QEMU wystawi gdbserver na danym porcie (tu: 1234)
- wtedy możemy w GDB zrobić `target remote :1234` aby podłączyć się do tego gdbservera i debugować emulowany proces

## Dodanie możliwości `telescope --reversed`

* TL;DR: Trzeba wysłać PR z patchem, który jest w https://github.com/pwndbg/pwndbg/issues/1047
* Oraz pomyśleć, czy nie nazwać tego argumentu inaczej
* Warto zbadać co się stanie jeśli będziemy klikać <enter> dalej - czy pokażą się kolejne adresy? Czy powinniśmy renderować poprzednie czy kolejne wartości? Do przedyskutowania

## Poprawienie parsowania adresów

TL;DR: https://github.com/pwndbg/pwndbg/issues/1050

## Dodanie komendy `patch <adres> <dane lub instrukcje>`

Przydałaby się komenda do "patchowania" kodu, tak, żeby można było w łatwy sposób zmienić kod programu na inny - na przykład usunąć "ifa" z programu, albo zrobić tak, żeby dana funkcja zawsze zwracała zero (lub inną wartość).

Przykładowo, `patch 0x1234 nop; nop; nop` (na x86/x64) powinno wpisać pod adres `0x1234` zasemblowane instrukcje `nop; nop; nop`, czyli wartość `0x90` trzy razy, bo instrukcja `nop`, która jest tak zwanym "no operation", tzn. nic nie robi, odpowiada właśnie bajtowi 0x90 na architekturach x86/x64.

Przydatne rzeczy:
- musimy stworzyć nową komendę w pliku `pwndbg/commands/patch.py` - możemy
Do tego zadania przyda się biblioteka [`pwntools`](http://docs.pwntools.com/en/latest/) (którą trzeba dodać jako zależność)


Kod plus minus:
```py
# prawdopodobnie trzeba string arch jakoś zmapować z nazw Pwndbg na nazwy architektur używane przez Pwntools
import pwnlib

arch = pwndbg.arch.current
data = pwnlib.asm.asm(assembly_code, arch=arch)
pwndbg.memory.write(address, data)
```

Potencjalne rozszerzenia:
1. Zamiast pobierać architekturę za każdym razem podczas wykonywania komendy, moglibyśmy ustawiać `pwnlib.context.context.arch = ...` gdy ustawiane jest `pwndbg.arch.current`
2. Można rozszerzyć interfejs tak, aby pozwolić wprowadzać bajty instrukcji heksadecymalnie, zamiast tylko poprzez instrukcje asemblera; na przykład:
  - `patch 0x1234 0x90` - powinno wpisać pod `0x1234` bajt `0x90` (czyli instrukcję `nop` na x86/x64)
  - `patch 0x1234 9090` - powinno wpisać dwie instrukcje `nop`
    - Do zastanowienia się: czy powinniśmy supportować hexy bez prefixu `0x`?
3. Można zapisywać listę wszystkich dodanych patchy i wtedy:
  - `patch --list` - listowałoby zaaplikowane patche
  - `patch --disable <id...>` - wyłączałoby dane patche
  - `patch --enable <id...>` - włączałoby dane patche
  - `patch --revert <id...>` - pozwołiłoby zrevertować dany patch
  - `patch --revert-all` - cofałoby wszystkie patche
4. Powinniśmy pozwalać na export patchy do pliku
5. Dodanie testów :)

Potencjalne problemy:
- Co z rebase'owaniem binarki (ASLR/PIE)?

## Dodanie testów do wybranych funkcjonalności
- obecnie Pwndbg ma dość mało testów
- testy na CI są uruchamiane przez `PWNDBG_GITHUB_ACTIONS_TEST_RUN=1 sudo --preserve-env ./tests.sh` i są zaimplementowane w `./tests/`

Potrzebujemy testów m.in. dla wielu komend:
- `hexdump ...`
- nawigacja po programie - `nextret`, `nextsyscall`, `stepsyscall`, etc.
- wyszukanie wartości w programie: `search ...`
- zmieniania uprawnień do pamięci - `mprotect`
- listowanie layoutu pamięci - `vmmap`
  - również dla targetów z QEMU user emulation
  - również dla targetów z QEMU kernel
- komend wyświetlających pamięć w ciekawy sposób - `probeleak`, `leakfind`
- (bardzo trudne) funkcjonalności związane ze stertą (heap) z Pull Requesta, dla różnych wersji glibc i architektur

## Dodanie funkcjonalności/komendy "dump memory as code"

W skrócie, można by dodać, żeby niektóre komendy, jak na przykład `dq`, `dw`, `dd`, `db` pozwalały na zdumpowanie danych w formie kodu, tak, żeby można było łatwo wkleić je np. jako tablicę w C?
* TL;DR: https://github.com/pwndbg/pwndbg/issues/1018
* Przy okazji być może dałoby się zrefaktoryzować te parsery komend dq itd., żeby nie było tyle powtórzen tego samego kodu?

## Dziwny bug #1008

Ktoś zgłosił bug, w którym jak ustawimy rejestr RIP (Instruction Pointer) na niezmapoawny adres, to Pwndbg się crashuje. Trzeba by to sprawdzić, zdebugować i naprawić: https://github.com/pwndbg/pwndbg/issues/1008 (lub zamknąć jeśli to nieaktualne).

## Renderowanie argumentów printf-podobnych funkcji

Chodzi o to, żeby gdy jesteśmy na instrukcji `call printf` wyświetlać ładnie argumenty tego printfa.

* Issue na to jest stworzone w https://github.com/pwndbg/pwndbg/issues/939
* Mamy też PR z poprzedniego sprintu z EuroPython 2022, który zaczął to dodawać: https://github.com/pwndbg/pwndbg/issues/939
* Trzeba sprawdzić, czy obsługuje to wszystkie przypadki, czy nie jest zbugowane, czy się nie crashuje gdy coś się nie zgadza
* No i dodać testy

# Co nieco informacji o GDB
  
GDB (GNU Debugger) to konsolowy debugger na Linuxa, który obsługuje debugowanie programów napisanych w przeróżnych językach, na wiele różnych targetów - architektur czy ABI. Można tu np. zobaczyć wewnątrz GDB wykonanie komend:
* `show arch`
* `show osabi`
* `show language` - warto wiedzieć, że "wybrany" język wpływa na to jakie wyrażenia możemy używać w GDB debugując dany program
  
GDB pod spodem korzysta pod spodem z wywołania systemowego [`ptrace`](https://man7.org/linux/man-pages/man2/ptrace.2.html), które pozwala na śledzenie procesów na Linuxie oraz na czytanie i modyfikację ich stanu (pamięci i rejestrów procesora).

Wcześniej wymienione `arch`, `osabi` czy `language`, to właściwie "parametry" GDB. Takich parametrów jest **sporo** i można je wszystkie wyświetlić komendą `show`, a co niektórych zmieniać wartość poprzez komendę `set <parametr> <wartosc>`.
  



# Useful Pwndbg APIs

```py
# Reading memory
# NOTE: may raise gdb.error(...) if `addr` is not readable or mapped in the target

pwndbg.memory.write(addr, data)             # write `data` bytes into memory, e.g. b'asdf'
data = pwndbg.memory.read(addr, count)      # read `count` bytes from memory, returns e.g. b'asdf'

# Useful constants
pwndbg.arch.endian                  # endianess used by the architecture
pwndbg.arch.ptrsize                 # size of a pointer on a given architecture
pwndbg.arch.ptrmask                 #

# Getting useful info about process
pwndbg.arch.current                 # name of target architecture (string)
pwndbg.regs.current                 # list of target registers
pwndbg.heap.current                 # currently used heap

pwndbg.vmmap.get()                  # get list of memory maps mapped into the process
pwndbg.auxv.get()                   # get ELF Auxiliary Vectors info
pwndbg.file.get(filepath)           # download a file from the target's filesystem
pwndbg.symbol.get(address)          # fetch text name for a symbol at given address
pwndbg.disasm.get(address, n)       # disassebmle N instructions at address
pwndbg.chain.get(addr, limit, offset, ...)  # recursively dereference address
pwndbg.string.get(addr, ...)        # returns a printable C-string from address
```