Otázka:
Jak mohu zkontrolovat, že jsem se přestěhoval mimo zásobník, aniž bych spustil poruchu ochrany?
ŹV -
2013-04-05 19:55:53 UTC
view on stackexchange narkive permalink

Přidávám do svého linuxového debuggeru funkci (používám Ptrace k manipulaci s vysledovaným procesem i libbfd / libopcodes), abych odvinul zásobník a určil, zda existují nesrovnalosti mezi přiděleným prostorem zásobníku pro každý CALL a staticky odvozeným místní proměnná velikost, tisk adresy a velikosti lokálního zásobníku každého rámce po cestě.

Moje obecná metodika je převzít adresu v základním ukazateli (EBP / RBP), přírůstek ukazatele by měl obsahovat ukazatel uloženého rámce, dereference této adresy, prozkoumejte ji pomocí PTRACE_PEEKDATA a opakujte, dokud neodradím adresu zabírající oblast mimo zásobník.

Vím, jak zkontrolovat registry segmentů kódu / dat, ale ideálně bych jako metoda ke kontrole, zda jsem stále uvnitř callstacku, i když byla segmentace změněna stránkami paměti W ^ X nebo jinak neproveditelným zásobníkem.

Stručně řečeno, jak mohu zkontrolovat (obecně případ), když jsem se přestěhoval mimo zásobník, aniž bych spustil poruchu obecné ochrany?

(Kromě toho si uvědomuji, že pracuji na předpokladu, že kontrola segmentu stránky adresy je zde ideální metodikou - možná existuje další jednodušší metoda k určení, zda je adresa v prostoru zásobníku aktuálního procesu)

Myslím, že pracujete pod Linuxem. Specifikace OS je zde zjevně nutná, protože nastavuje základní adresu zásobníku (s offsetem ASLR nebo ne) před zahájením procesu.
Děkuji, výše jsem upravil odpověď - je to opravdu linux.
Důrazně doporučujeme číst při odvíjení: [část 1] (http://www.mikeash.com/pyblog/friday-qa-2012-04-27-plcrashreporter-and-unwinding-the-stack-with-dwarf.html), [část 2] (http://www.mikeash.com/pyblog/friday-qa-2012-05-04-plcrashreporter-and-unwinding-the-stack-with-dwarf-part-2.html) (OS X orientované, ale stále platí mnoho věcí).
Vzhledem k tomu, že znáte využití zásobníku v prostředích intel / amd, víte, že hodnota odlivu by nutně zvýšila hodnotu pro každé následné vrácení (tj. Přístup k dalšímu rodiči). Vzhledem k tomu, že se díváte na prostředí Linuxu, můžete (poněkud bezpečně) předpokládat omezení velikosti zásobníku 8 MB (na vlákno). Kromě toho, vzhledem k tomu, že se (s největší pravděpodobností) používají stránky 4KB, můžete bezpečně číst hodnoty EBP, které jsou na vyšší adrese než ta aktuální, dokud nedosáhne jiné (a samozřejmě vyšší) položky stránky. V tomto okamžiku můžete pomocí mmap () zjistit, zda stránka existuje nebo není ...
Můžete také zjistit některé formy „poškozených“ hodnot EBP / RBP zkoumáním dolních 2 bitů (32 bitů) nebo dolních 3 bitů (64 bitů), protože hodnoty ESP / RSP a EBP / RSP jsou 4 bajty nebo Zarovnáno 8 bajtů.
Jeden odpovědět:
perror
2013-04-05 21:16:49 UTC
view on stackexchange narkive permalink

Takže je to úplně nevyzkoušené, ale tady je výsledek několika procházení Internetu.

Nejprve je základní adresa zásobníku v / proc / <pid> / maps , pak v určitém okamžiku musí být přístupný z uživatelského prostoru.

Podíval jsem se na kód příkazu pstack, který tiskne obsah zásobníku běžícího procesu. Tento kód získává základní adresu ze struktury link_map a ukládá ji do pole l_addr . Toto pole je nastaveno uvnitř funkce readLinkMap():

  static void readLinkMap (int pid, ElfN_Addr base, struct link_map * lm, char * name, unsigned int namelen ) {/ * base address * / lm->l_addr = (ElfN_Addr) ptrace (PTRACE_PEEKDATA, pid, base + offsetof (struct link_map, l_addr), 0); / * další prvek řetězce odkazových map * / if (-1! = (long) lm->l_addr ||! errno) lm->l_next = (struct link_map *) ptrace (PTRACE_PEEKDATA, pid, base + offsetof (struct link_map, l_next) ), 0); if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) {perror ("ptrace"); quit ("nelze přečíst cíl."); } loadString (pid, base + offsetof (struct link_map, l_name), name, namelen);}  

Myslím, že toto je správná cesta. Doporučil bych vám tedy podívat se na kód příkazu pstack (soubor není příliš dlouhý) a získat z něj inspiraci, protože dělá něco velmi podobného tomu, co chcete (na alespoň pokud chápu, co jste řekli správně).

Doufám, že vám tato krátká poznámka trochu pomůže.

V kontextu otázky uživatelů se to jeví jako adekvátní. Pokud však chcete implementovat funkci zpětného sledování, budete pravděpodobně muset použít trpasličí CFI, pokud chcete, aby byla spolehlivá.
@broadway: Ale trpaslík není vždy přítomen ve všech spustitelných souborech. Při pohledu na to můžete pomoci, ale podle mého skromného názoru by bylo chybou spoléhat se na to úplně a nic jiného.
jo, v tom případě prostě musíte akceptovat rozbití. Rámečky tam často prostě nebudou. Možná se však můžete pokusit heuristicky odvodit registry v některých běžných případech.


Tyto otázky a odpovědi byly automaticky přeloženy z anglického jazyka.Původní obsah je k dispozici na webu stackexchange, za který děkujeme za licenci cc by-sa 3.0, pod kterou je distribuován.
Loading...