SPAGHETTI HACKER

  1. LAZY BINDING - bash
    log.019

    Tags
    re
    By AKIRA BASHO il 5 May 2023
     
    0 Comments   42 Views
    .
    Au8tLPx-17055745273392

    ;il lazy binding nei binari ELF di Linux è implementato con l'aiuto di due sezioni speciali, chiamate Procedure Linkage Table (.plt) e Global Offset Table (.got).

    ;i binari linkati staticamente sono indipendenti (autonomi), poiché portano in sé tutte le funzioni richieste. Per essere più precisi, quando un codice sorgente viene compilato, impacchetta al suo interno qualsiasi funzione di libreria richiesta dall'eseguibile, durante la fase di linking. Ciò significa anche che il binario è ben consapevole di dove sono memorizzate le funzioni (indirizzi e offset).

    ;un binario linkato dinamicamente è l'opposto, in quanto non impacchetta la libreria condivisa al suo interno; quando viene eseguito un binario linkato dinamicamente, nella memoria viene caricato anche un linker/loader dinamico, che aiuta a risolvere la funzione della libreria linkata; ciò è necessario in quanto l'indirizzo della libreria condivisa è sconosciuto e può variare a causa di vari fattori; uno dei fattori può essere che, se il codice della libreria viene aggiornato, ci sia una modifica dell'indirizzo; un altro esempio può essere un meccanismo di protezione come l'ASLR, che randomizza l'indirizzo delle librerie condivise, senza lasciare al binario alcun indizio sulla loro posizione; GOT e PLT entrano in gioco quando si esegue un binario linkato dinamicamente.

    ;Il lazy binding è abilitato/disabilitato dall'opzione -z del linker, ld.

    ;lazy
    ;dice al linker dinamico di posticipare la risoluzione dell'indirizzo della funzione al momento in cui la funzione viene chiamata (lazy binding), anziché al momento del loading.

    ;now
    ;dice al linker dinamico di risolvere tutti i simboli all'avvio del programma o quando la libreria condivisa è linkata all'utilizzo di dlopen(), invece di rimandare la risoluzione dell'indirizzo della funzione nel momento in cui la funzione viene chiamata la prima volta.

    ;il now binding è l'impostazione predefinita per ragioni di sicurezza; si usa l'opzione -W del gcc per passare l'opzione -z al linker ld.

    gcc -Wl,-zlazy -o plt1 plt1.c

    #include <stdio.h>
    #include <stdlib.h>

    int main(int argc, char **argv) {
    puts("Hello world");
    puts("Hello world");
    exit(0);
    }

    ;prima diamo un'occhiata alla sezione PLT, che sta per Procedural Liked Table; contiene il codice, responsabile di fornire l'indirizzo della funzione richiesta di una libreria condivisa durante il runtime o, nel caso non sia stato ancora risolto, chiama il linker dinamico, responsabile della ricerca dell'indirizzo.

    ;ogni volta che viene chiamata per la prima volta una funzione esterna, all'interno di un binario linkato dinamicamente, è la struttura PLT, il cui codice esegue una ricerca dell'indirizzo della funzione, utilizzando il linker/caricatore dinamico (ld.so) fino a valorizzare una voce all'interno della GOT table, dove si trovarà infine l'indirizzo della funzione originale; la seconda volta, la risoluzione non deve essere eseguita poiché l'indirizzo della funzione è stato già risolto durante la prima chiamata ed è stato memorizzato nel GOT; questo è chiamato lazy binding; aiuta a migliorare le prestazioni in quanto evita le risoluzioni non necessarie durante il runtime.

    ;come mostra l'output di readelf, .plt è una sezione di codice che contiene codice eseguibile, proprio come .text, mentre .got.plt è una sezione di dati.
    Z9EA08I
    ReoiDLi
    ;supponiamo che si voglia chiamare la funzione puts, che fa parte della ben nota libreria libc; invece di chiamarla direttamente (cosa non possibile per i motivi sopra menzionati), si effettua una chiamata allo stub PLT corrispondente, puts@plt (passaggio ➊ nella Figura 2-2).

    ;lo stub PLT inizia con un'istruzione di salto indiretto, che salta a un indirizzo memorizzato nella sezione .got.plt (passaggio ➋ nella Figura 2-2).

    ;inizialmente, prima che si verifichi il lazy binding, questo indirizzo è semplicemente l'indirizzo dell'istruzione successiva nello stub PLT della funzione, che è un'istruzione push; pertanto, il salto indiretto trasferisce semplicemente il controllo all'istruzione immediatamente successiva (passo ➌ nella Figura 2-2)!

    ;è un modo piuttosto indiretto per arrivare all'istruzione successiva; l'istruzione push spinge un numero intero (in questo caso, 0x0) nello stack; questo numero intero funge da identificatore per lo stub PLT in questione.

    ;l'istruzione successiva passa allo stub PLT di default predefinito comune condiviso tra tutti gli stub della funzione PLT (passaggio ➍ nella Figura 2-2).

    ;lo stub di default esegue il push di un altro identificatore (preso dal GOT), identificando l'eseguibile stesso, quindi passa (indirettamente, sempre attraverso il GOT) al linker dinamico (passaggio ➎ nella Figura 2-2).

    ;utilizzando i dati pushati dagli stub PLT, il linker dinamico si occupa di risolvere l'indirizzo della funzione puts e deve farlo per conto dell'eseguibile principale caricato nel processo; è importante sapere questo perché potrebbero esserci più librerie caricate anche nello stesso processo, ciascuna con il proprio PLT e GOT.

    ;il linker dinamico cerca quindi l'indirizzo in cui si trova la funzione puts e inserisce l'indirizzo di tale funzione nella voce GOT associata a puts@plt.

    ;pertanto, ora la voce GOT non punta più indietro nello stub PLT, come faceva inizialmente, ma all'effettivo indirizzo della funzione puts; a questo punto, il processo di lazy binding è completo; il linker dinamico soddisfa l'intenzione originaria di chiamare puts trasfesrendogli il controllo.

    ;per qualsiasi successiva chiamata a puts@plt, la GOT entry contiene già l'indirizzo appropriato (corretto) di puts in modo che il salto all'inizio dello stub PLT vada direttamente a puts senza coinvolgere il linker dinamico (passaggio ➏ nella figura).

    JQbl8uu
    ;l'indirizzo della funzione condivisa ancora non è stato risolto
    OOkj2oq
    ;all'indirizzo 0x555555558010 a cui si riferisce l'istruzione jmp abbiamo l'indirizzo della funzione _dl_runtime_resolve_xsavec del linker dinamico che risolverà l'indirizzo della funzione puts
    3G6LemS
    ;l'indirizzo della puts ora è stato risolto e non c'è più bisogno di coinvolgere il linker dinamico


    Edited by HCF - 27/4/2024, 20:25
      Share  
     
    .