
libtalloc è uno script Python per l'uso con GDB che può essere utilizzato per analizzare l'"allocatore banale" (talloc)
libtalloc è uno script python per l'uso con GDB che può essere utilizzato per analizzare l'"allocatore banale" (talloc). Un'introduzione su talloc si può trovare qui:
https://talloc.samba.org/talloc/doc/html/index.html
libtalloc è stato ispirato da altri script python per GDB per l'analisi di heap come unmask_jemalloc e libheap. Alcune funzionalità di base sono identiche a questi progetti.
https://github.com/cloudburst/libheap
https://github.com/argp/unmask_jemalloc
Tieni presente che non sono un guru di python e la qualità del codice lo rispecchia. Se vedi qualcosa che ti disgusta, sentiti libero di inviare una patch o darmi qualche suggerimento. Tutti i feedback sono benvenuti.
libtalloc è stato testato su diverse release 2.x di talloc e supporta il rilevamento dinamico della versione per cercare di superare le varie differenze strutturali tra le versioni. È stato testato su 32-bit e 64-bit, ma non in modo esaustivo, quindi non sorprenderti se ogni tanto si rompe.
È stato testato in una certa misura su x86 e x64:
Se lo provi su un'altra versione, per favore fammi sapere se ha funzionato o cosa si è rotto e cercherò di aggiornarlo e/o la documentazione di conseguenza.
Lo script richiede semplicemente una versione relativamente moderna di GDB con supporto python.
Alcune distro LTS, come Ubuntu 12.04, usano ancora GDB con python 2.7, mentre versioni più recenti come 14.04 usano python 3.0. Ho cercato di far funzionare questo script con entrambi, quindi dovresti solo dover:
(gdb) source libtalloc.py
La maggior parte delle funzionalità è modellata sull'approccio di unmask_jemalloc, dove viene fornito un comando GDB separato piuttosto che un complesso insieme di opzioni.
Sono disponibili diversi metodi progettati specificamente per imitare le funzioni C della libreria talloc, per aiutare le persone che cercano di estendere libtalloc se sono già familiari con la libreria.
Per vedere un elenco completo dei comandi puoi eseguire il comando tchelp:
(gdb) tchelp
[libtalloc] talloc commands for gdb
[libtalloc] tcchunk -v -x <addr> : show chunk contents (-v for verbose, -x for data dump)
[libtalloc] tcvalidate -a <addr> : validate chunk (-a for whole heap)
[libtalloc] tcsearch <addr> : search heap for hex value or address
[libtalloc] tcwalk <func> : walk whole heap calling func on every chunk
[libtalloc] tcreport <addr> : give talloc_report_full() info on memory context
[libtalloc] tcdump -s <addr> : dump chunks linked to memory context (-s for sorted by addr)
[libtalloc] tcparents <addr> : show all parents of chunk
[libtalloc] tcchildren <addr> : show all children of chunk
[libtalloc] tcinfo : show information known about heap
[libtalloc] tcprobe : try to collect information about talloc version
[libtalloc] tchelp : this help message
Uno dei comandi più importanti è tcprobe. Deve essere eseguito per capire quale versione di talloc è effettivamente installata. I layout delle strutture per le diverse versioni possono variare notevolmente, quindi per far funzionare la maggior parte delle funzioni la versione deve essere nota.
Se il comando funziona, dovrebbe comunicarti la versione rilevata:
(gdb) tcprobe
Version: 2.1.1
File: /usr/lib/libtalloc.so.2.1.1
Il comando tcinfo è pensato per mostrare quante più informazioni raccolte sull'heap possibile, come le informazioni di tcprobe, la struttura null_context se è stata trovata, e altro. Al momento mostra solo la versione e se null_context è impostato. null_context è richiesto per la maggior parte delle funzioni che attraversano la gerarchia reale, e per trovarlo la maggior parte delle altre funzionalità, come tchunk, ecc., proveranno a trovarlo automaticamente.
Dopo che tcprobe è stato eseguito ma prima che tchunk venga effettivamente usato:
(gdb) tcinfo [libtalloc] null_context not yet found yet [libtalloc] Version: 2.0.7 [libtalloc] File: /usr/lib/i386-linux-gnu/libtalloc.so.2.0.7
Poi dopo aver analizzato un chunk, in questo modo:
(gdb) tcchunk 0xb94a52b0 WARNING: 0xb94a52b0 not a talloc_chunk. Assuming ptr to chunk data 0xb94a5280 sz:0x0000003c, flags:...., name:struct tevent_context
Puoi confermare che è stato trovato dopo il fatto usando tcinfo.
(gdb) tcinfo [libtalloc] null_context: 0xb94a5028 [libtalloc] Version: 2.0.7 [libtalloc] File: /usr/lib/i386-linux-gnu/libtalloc.so.2.0.7
Ora che null_context è impostato potresti eseguire altri comandi che normalmente si lamenterebbero che non è impostato, come il comando tcsearch.
tcchunk può fornirti un riepilogo del chunk, un output più dettagliato di ogni campo, o informazioni estremamente dettagliate su ogni chunk circostante.
NOTA: Una cosa importante da notare su tcchunk è che internamente usa il metodo tc_chunk(), che tenta di correggere errori commessi passando l'indirizzo del chunk. In particolare, se passi l'indirizzo dei dati del chunk stesso, se non trova la magic di talloc attesa, cercherà un header di chunk legittimo leggermente prima in memoria. Questo può confonderti in scenari corrotti, quindi assicurati sempre di passare l'indirizzo esplicito a meno che tu non stia facendo un'analisi sommaria.
Output di riepilogo:
(gdb) tcchunk 0x80a13c88
0x80a13c88 sz:0x00000020, flags:..p., name:struct netr_ServerPasswordSet
La seguente è una legenda per i chunk nell'output di riepilogo:
p - Membro di un pool (flag POOLMEM)
P - Il chunk è un pool (flag POOL)
F - Il chunk è libero (flag FREE)
L - Il chunk è in loop (flag LOOP)
Output dettagliato:
(gdb) tcchunk -v 0x80a13c88
struct talloc_chunk @ 0x80a13c88 {
next = 0x0
prev = 0x80a140c8
parent = 0x0
child = 0x80a14088
refs = 0x0
destructor = 0x0
name = 0x807d9f2f (struct netr_ServerPasswordSet)
size = 0x20
flags = 0xe8150c78 (POOLMEM)
limit = 0x0
pool = 0x80a13248
I chunk di talloc contengono alcuni valori magici che possono essere usati per validare se sono sani. Il comando tcvalidate analizzerà un chunk per assicurarsi che la magic del chunk sia come previsto. Inoltre, analizza tutti gli altri membri puntatore per assicurarsi che ricadano effettivamente in intervalli di memoria (come noto a gdb), se la dimensione è valida, ecc.
(gdb) tcvalidate 0x80a13c88
Chunk header is valid
Useremo un metodo integrato per modificare un valore per mostrare come potrebbe fallire:
(gdb) python set_destructor(tc_chunk(0x80a13c88), 0x41414141)
(gdb) tcchunk -v 0x80a13c88
struct talloc_chunk @ 0x80a13c88 {
next = 0x0
prev = 0x80a140c8
parent = 0x0
child = 0x80a14088
refs = 0x0
destructor = 0x41414141
name = 0x807d9f2f (struct netr_ServerPasswordSet)
size = 0x20
flags = 0xe8150c78 (POOLMEM)
limit = 0x0
pool = 0x80a13248
(gdb) tcvalidate 0x80a13c88
Chunk header is invalid:
0x80a13c88: Chunk has bad destructor pointer 0x41414141
tcparents può essere usato per visualizzare tutti i genitori del chunk fornito:
(gdb) tcparents 0x80a13c88
0x809f8300: null_context
0x80a08660: TALLOC_CTX *
0x809f8370: talloc_new: ../lib/util/talloc_stack.c:147
0x809fb680: talloc_new: ../lib/util/talloc_stack.c:147
0x80a13258: UNNAMED
0x80a13c58: talloc_new: ../lib/util/talloc_stack.c:147
0x80a13c88: struct netr_ServerPasswordSet
tchildren può essere usato per visualizzare tutti i figli (e nipoti, ecc.) del chunk fornito: