Tecniche per il reverse engineering del software - Elaborato finale in Sistemi operativi Scuola Politecnica e delle Scienze di Base Corso di ...
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Sistemi operativi Tecniche per il reverse engineering del software Anno Accademico 2018/2019 Candidato: Gennaro Testa matr. N46002038
Indice Introduzione 1 1 Casi applicativi 2 1.1 Sistema Legacy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Applicazioni in ambito software . . . . . . . . . . . . . . . . . . . . . . 4 2 Radare2 6 2.1 Caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Utilizzo base da linea di comando . . . . . . . . . . . . . . . . . . . . . 9 2.3 Cutter una gui per radare2 . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 Individuazione di codice malevolo con cutter 11 Conclusioni e sviluppi futuri 21 Bibliografia 22 ii
Elenco delle figure 2.3.1 Interfaccia di Cutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3.0.1 Codice Main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.0.2 Funzione ’fcn.00403b30’ . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.0.3 Codice assembly del branch . . . . . . . . . . . . . . . . . . . . . . . . 13 3.0.4 Blocco indirizzo ‘0x4041f9’ . . . . . . . . . . . . . . . . . . . . . . . . 13 3.0.5 Funzione ‘fcn.00403240’ . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.0.6 Resource widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.0.7 Contenuto risorsa ’110’ . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.0.8 Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.0.9 Blocco indirizzo ’0x00403317’ . . . . . . . . . . . . . . . . . . . . . . . 16 3.0.10 Funzione ‘fcn.00401560’ . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.0.11 Xref della funzione ‘fcn.00401c90’ . . . . . . . . . . . . . . . . . . . . 17 3.0.12 Apertura risorsa ’101’ con Hexdump widget . . . . . . . . . . . . . . . 18 3.0.13 Decrittazione della risorsa con ror 3 . . . . . . . . . . . . . . . . . . . . 19 3.0.14 Script per generazione file .bin . . . . . . . . . . . . . . . . . . . . . . 20 iii
Introduzione Il reverse engineering è il processo di analisi di un sistema al fine di individuare le com- ponenti e le loro relazioni interne e creare rappresentazioni di tale sistema in altra forma o ad un livello di astrazione più alto (Institute of Electrical and Electronics Engineers, 1990). Tale processo potrebbe essere paragonato alla ricerca scientifica, con la differenza dei campi di applicazione che, in tal caso, abbracciano l’ingegneria meccanica, elettronica, informatica, ecc. Il reverse engineering trova la sua origine nell’analisi dell’hardware per vantaggi commerciali o militari. Però, il processo di reverse engineering non è interessa- to alla creazione di una copia o, in qualche modo, alla modifica dell’artefatto; esso mira all’analisi con il fine di dedurre caratteristiche di design, ma andando ad escludere co- noscenze riguardanti le procedure utilizzate nella produzione originale. Un famoso caso di reverse engineering è quello della prima implementazione del BIOS non effettuata da IBM, con la conseguente nascita della storica industria degli IBM PC compatibili,i quali dominarono la scena hardware per diversi anni. 1
Capitolo 1 Casi applicativi Il processo di reverse engineering è applicabile per molteplici scopi, come ad esem- pio, la creazione di prodotti interoperabili o anche l’analisi di prodotti di competitor commerciali. 1.1 Sistema Legacy In alcuni casi, l’obiettivo del reverse engineering può anche essere la ridocumentazione di sistemi legacy, cioè sistemi basati su tecnologie non più in uso. Il primo utilizzo del termine “legacy” relativo ad un sistema di calcolo risale agli anni 70. Dagli anni 80 in poi è stato comunemente utilizzato per riferirsi a sistemi di calcolo già esistenti in modo da distinguerli da design e implementazione dei nuovi sistemi. Nonostante tale termine fac- cia percepire un sistema come datato, un sistema legacy può tranquillamente continuare ad essere utilizzato per molteplici ragioni; come ad esempio: La capacità di continuare a soddisfare i bisogni dell’utilizzatore, ragioni economiche come potrebbe essere un ritorno di investimento o per una varietà di altre ragioni legate alle funzionalità. 2
Tecniche di reverse engineering del software Ci sono infatti anche sistemi legacy che richiedono una costante disponibilità, basti pen- sare, ad esempio, a sistemi bancari o di controllo del traffico aereo; questi ultimi, non potendo essere sostituiti, data la necessità di rimanere sempre attivi e disponibili, devono necessariamente essere sottoposti ad un processo di reverse engineering per renderli com- patibili con nuovi sistemi o semplicemente per essere ridocumentati. Tuttavia i sistemi legacy sono considerati potenzialmente problematici da diversi ingegneri del software per svariate ragioni: • Se il software legacy gira su hardware antiquato, il costo di mantenimento potrebbe superare il costo di replica di software e hardware, a meno dell’utilizzo di emulatori, per permettere al software di girare su un nuovo hardware. • Questi sistemi potrebbero essere difficili da mantenere, migliorare ed espandere a causa della generale mancanza di conoscenze del sistema stesso. • Ci potrebbero essere vulnerabilità nei vecchi sistemi operativi o applicazioni a causa della mancanza di patch di sicurezza aggiornate. • Difficoltà di integrazione tra nuovo e vecchio sistema. 3
Tecniche di reverse engineering del software 1.2 Applicazioni in ambito software Ci sono due procedure fondamentali per il reverse engineering del software: 1. La ridocumentazione, che consiste nella creazione di nuove rappresentazioni del codice in modo tale da renderlo più comprensibile. 2. Ricostruzione del design, che consiste nell’utilizzo di deduzioni o ragionamen- ti basati su conoscenze generali o esperienze personali sul prodotto, in modo da comprendere appieno le funzionalità di quest’ultimo. Il reverse engineering del software può aiutare a migliorare la comprensione del codice sorgente per la manutenzione e il miglioramento del software. Grazie a tale processo possono essere estratte informazioni di rilievo che consentiranno di prendere decisioni in merito allo sviluppo del software. Inoltre, la rappresentazione grafica del codice può for- nire ulteriori punti di vista sul codice sorgente, i quali possono aiutare nell’individuazione e correzione di bug o vulnerabilità del software stesso. Frequentemente, come in molti sviluppi software, le informazioni di design e i miglioramenti vengono persi nel tempo, ma questi dati possono essere recuperati tramite proprio il reverse engineering. Tale pro- cesso può inoltre aiutare ad accorciare i tempi di comprensione di un codice sorgente, riducendo quindi i costi totali di sviluppo, e può essere utilizzato anche per l’individua- zione e l’eliminazione di codice malevolo. Il reversing del codice sorgente può inoltre essere utilizzato per trovare usi alternativi di quest’ultimo, come ad esempio l’individua- zione di repliche non autorizzate del codice laddove non si era intenzionati ad utilizzarlo. Tale processo è comunemente usato per “craccare” software andando a rimuovere la copy protection, o per creare “knockoff” (Counterfeit consumer goods); cioè dei beni, spesso di qualità inferiore, creati e venduti da un altro brand senza l’autorizzazione del brand proprietario. 4
Tecniche di reverse engineering del software Il reverse engineering del software può essere effettuato con vari metodi. I tre principali gruppi sono: 1. Analisi tramite l’osservazione del cambiamento di informazioni, diffusa soprattutto nel reverse engineering dei protocolli, la quale prevede l’utilizzo di analizzatori di bus e di pacchetti, ad esempio, per accedere alla connessione di rete di un computer e svelare il traffico di dati. 2. Lettura e comprensione del linguaggio macchina tramite un disassembler. 3. Decompilazione del codice, cioè un processo che prova, con risultati variabili, a ricreare il codice sorgente in un determinato linguaggio ad alto livello per un programma di cui è disponibile solo il codice macchina o il bytecode. 5
Capitolo 2 Radare2 Radare è stato creato nel Febbraio del 2006 da Sergi Àlvarez. Egli mirava a fornire una semplice interfaccia da linea di comando per un editor esadecimale, che supportasse l’off- set a 64 bit, per la ricerca e ripristino di dati dall’hard disk. Da allora, il progetto è cre- sciuto con l’obiettivo di fornire un framework completo per l’analisi del codice, facendo uso di concetti UNIX base. Nel 2009 fu presa la decisione di riscrivere totalmente il programma in modo da colmare le iniziali lacune di design, nacque quindi Radare2. Es- so aggiunse maggior flessibilità e feature dinamiche; spianando inoltre la strada ad una migliore integrazione grazie alla possibilità di essere utilizzato con differenti linguaggi di programmazione. Radare2 è un framework per il reverse engineering e analisi del codice. Esso è costruito attorno ad un disassembler che genera codice sorgente in assem- bly partendo da codice macchina; inoltre supporta diversi tipi di eseguibile per differenti processori e sistemi operativi. 6
Tecniche di reverse engineering del software 2.1 Caratteristiche R2 è composto da una serie di piccoli tool che possono essere usati singolarmente o combinati tra loro da linea di comando. Ad esempio abbiamo: • radare2 è il tool principale dell’intero framework. Tramite l’utilizzo dell’editor esadecimale e del debugger, permette di aprire svariate fonti di input/output a patto che siano semplici file (inclusi dischi, connessioni di rete, kernel driver e così via). Esso implementa un’avanzata interfaccia da linea di comando per spaziare attorno a file, analisi di dati, comparazione di dati, binary patching, disassemblaggio, ricerca, risposta e visualizzazione. Può essere scritto in vari linguaggi tra cui Python, Ruby e JavaScript. • rabin2 è un programma per estrarre informazioni dagli eseguibili come ELF, PE, Java CLASS ed ogni formato supportato da R2. • rasm2 è un assembler e disassembler da linea di comando che supporta molteplici architetture come ad esempio Intel x86 e ARM. • rahash2 è un’implementazione di un hash tool block-based. Esso supporta svariati algoritmi come ad esempio: MD4, MD5 e SHA256. Viene utilizzato per verificare l’integrità o tracciare i cambiamenti di grandi file, dischi o porzioni di memoria. • radiff2 è una binary diffing utility che implementa svariati algoritmi. Viene utiliz- zato per trovare cambiamenti nei blocchi di codice ottenuti dall’analisi effettuata con R2. • rafind2 è un programma per trovare i byte pattern nei file. • ragg2 viene utilizzato per compilare programmi scritti in un linguaggio ad alto livello in semplici binari per x86, x86-64, e ARM. 7
Tecniche di reverse engineering del software • rarun2 è un launcher per eseguire programmi fra differenti ambienti, con differenti parametri, permessi, directory, ed inoltre ignorare i descrittori di default dei file. Risulta utile per risolvere crackmes ( programmi creati appositamente per testare le skill di reverse engineering di un programmatore), per il fuzzing ( tecnica usata per individuare errori o falle di sicurezza del software) e per i test suite ( un insieme di test case utilizzati per testare un software e mostrare il suo comportamento). • rax2 è un valutatore di espressioni matematiche per la shell che viene utilizzato per effettuare conversioni base. Può inoltre essere utilizzato come una shell interattiva se non sono dati parametri. 8
Tecniche di reverse engineering del software 2.2 Utilizzo base da linea di comando Solitamente la curva di apprendimento è abbastanza ripida all’inizio. Superato però il pri- mo impatto, sarà possibile capire facilmente come funzionano la maggior parte delle cose e come combinare i vari tool che radare offre. Navigazione, ispezione e modifica di un file binario caricato sono effettuati utilizzando tre semplici azioni: ricerca ( posizionare), stampa ( buffer), alterna ( scrivi, aggiungi). Il comando ‘seek’ è abbreviato con ‘s’ ed accetta espressioni (ad esempio ‘10’, ‘+0x25’) come suoi parametri. Se si apre un file con radare2, di default verrà aperto in modalità Virtual Addressing ( VA) e le sezioni saran- no mappate sul loro indirizzo virtuale. In modalità VA la ricerca è basata sull’indirizzo virtuale e la posizione di partenza sarà settata al punto d’ingresso dell’eseguibile. Uti- lizzando l’opzione ‘-n’ è possibile far aprire un file non in modalità VA, in questo modo la ricerca sarà basata sull’offset dall’inizio del file. Il comando ‘print’ è abbreviato con ‘p’ ed ha un certo numero di sottomodalità che vengono specificate dalla seconda lettera (ad esempio con ‘px’ è possibile stampare in esadecimale). Per essere abilitati a scrivere sul file è necessario utilizzare l’opzione ‘-w’ in fase di apertura del file. Il comando ‘w’ permette di scrivere stringhe, esadecimali ( aggiungendo la ‘x’ dopo la ‘w’), o anche co- dice operativo assembly ( aggiungendo ‘a’ dopo la ‘w’). Aggiungendo invece ‘?’ ad un comando, sarà possibile visualizzare il suo messaggio di aiuto. Inoltre radare2 è anche dotato di una visual mode, cioè una modalità che fornisce un’interfaccia più user-friendly rispetto al prompt comandi. Tale modalità permette una navigazione più semplice, ha una modalità cursore per selezionare i byte ed offre numerose connessioni che semplificano l’utilizzo del debugger. Per entrare in visual mode basta digitare ‘V+INVIO’ e tramite la pressione del tasto ‘q’ sarà possibile uscire e ritornare al prompt. Per navigare andranno utilizzati i tasti ‘H’ ‘J’ ‘K’ ‘L’(rispettivamente sinistra, sotto, sopra, destra). Per selezio- nare un range di byte in cursor mode, sarà necessario premere il tasto ‘SHIFT’ seguito dai tasti di navigazione per marcare la selezione. 9
Tecniche di reverse engineering del software 2.3 Cutter una gui per radare2 Radare2 ha visto sviluppare svariate interfacce utente ( ragui, r2gui, gradare, r2net, bok- ken) nel corso degli anni, ma nessuna di loro ha avuto abbastanza manutenzione, e quindi si sono estinte. Dopo tre anni di sviluppo privato, Hugo Teso; l’autore di Bokken ( pre- cedente gui di r2 scritta in python) rilasciò al pubblico una nuova GUI per r2, stavolta scritta in C++ e Qt, che è stata ben accolta dalla community. Questa GUI fu chiamata inizialmente laito per poi essere ribattezzata Cutter ( nome votato dalla community) da Xarkes che divenne leader del progetto. Figura 2.3.1: Interfaccia di Cutter 10
Capitolo 3 Individuazione di codice malevolo con cutter In questo capitolo si analizzerà Dropshot, noto anche come StoneDrill. Esso non è altro che un virus utilizzato dal gruppo APT33 per bersagliare un numero elevato di organiz- zazioni dell’Arabia Saudita. Nello specifico l’obiettivo sarà quello di decriptare le risorse che contengono il payload del virus. Per prima cosa si procede con l’analisi del main utilizzando la Graph mode che ci permette di visualizzare il flusso del main per individuare i target. Figura 3.0.1: Codice Main 11
Tecniche di reverse engineering del software La prima cosa che risalta all’occhio è la chiamata della funzione ‘fcn.00403b30’. Con un doppio click sulla linea è possibile accedere al grafo della funzione, la quale si rivela essere piuttosto grande. Figura 3.0.2: Funzione ’fcn.00403b30’ Analizzando tale funzione è possibile notare svariate chiamate alle Windows API con parametri non validi. Questo è un chiaro esempio di anti-emulazione in dropshot. Le tec- niche di anti-emulazione sono utilizzate per ingannare gli emulatori degli antivirus i quali vengono utilizzati per analizzare il funzionamento dei virus. La tecnica più comune, che è anche quella utilizzata nella funzione di dropshot sopracitata, consiste nell’utilizzo di chiamate API non comuni o non documentate. Tale tecnica può inoltre essere migliorata con l’utilizzo di parametri non corretti per una determinata API che possono causare una Violation Exception. Successivamente alla chiamata della funzione ( che per semplicità è stata rinominata ‘AntiEmulation’) ci troviamo davanti ad un branch. 12
Tecniche di reverse engineering del software Figura 3.0.3: Codice assembly del branch Come si può osservare dal codice assembly, ricavato con il Disassembly widget di Cutter, il branch non verrà mai effettuato, in quanto la condizione che ’eax’ sia uguale a 0 non sarà mai verificata, dato che tale variabile è stata settata a 1 nella riga di codice precedente. Un altro blocco interessante è quello che inizia all’indirizzo ‘0x4041f9’. Figura 3.0.4: Blocco indirizzo ‘0x4041f9’ Qui possiamo notare l’invocazione della funzione ‘CreateDialogParamA’, che è ricono- sciuta da radare2 come ‘fcn.DialogFunc’, la quale contiene la logica principale del drop- per. Successivamente viene invocata la funzione ‘ShowWindow’, ovviamente si tratta di una finta finestra che non verrà mai visualizzata dato che l’autore del virus non vuole mostrare alcun artefatto alla vittima. Sarà proprio tramite questa funzione che si attive- rà l’esecuzione di ‘fcn.DialogFunc’. Tramite un doppio click sarà possibile visualizzare quest’ultima, la quale non fa altro che comparare i messaggi che riceve e richiamare la funzione ‘fcn.00403240’. 13
Tecniche di reverse engineering del software Figura 3.0.5: Funzione ‘fcn.00403240’ Dal primo blocco della funzione è possibile evincere che Dropshot si sta auto gestendo utilizzando ‘GetModuleHandleA’. In seguito, utilizzando ‘FindResourceA’, andrà a lo- calizzare un finto tipo 0x67( 111 in decimale) e un finto nome 0x6e( 110 in decimale). Infine, la risorsa localizzata verrà caricata utilizzando ‘LoadResource’. Figura 3.0.6: Resource widget 14
Tecniche di reverse engineering del software Utilizzando il Resources widget di cutter è anche possibile visualizzare il contenuto della risorsa con il nome ’110’. Figura 3.0.7: Contenuto risorsa ’110’ Nel blocco successivo al caricamento della risorsa è possibile notare l’inizio di un loop. Esso verifica se ‘local_2ch’ è uguale a 0x270f(9999 in decimale) e in caso di esito po- sitivo esce dal loop. All’interno del loop ce ne sarà un altro di 999 iterazioni. Questo è semplicemente un’altra tecnica di anti-emulazione che di fatto non produce alcun effetto. Figura 3.0.8: Loop 15
Tecniche di reverse engineering del software Un altro branch ci porta ad analizzare un nuovo blocco, che risulta essere uno dei più interessanti. Figura 3.0.9: Blocco indirizzo ’0x00403317’ Inizialmente viene invocata ‘VirtualAlloc’ della dimensione di 512 byte. Viene poi suc- cessivamente invocata la funzione ‘fcn.00401560’ con 3 parametri. Figura 3.0.10: Funzione ‘fcn.00401560’ 16
Tecniche di reverse engineering del software Andando ad analizzare quest’ultima nello specifico notiamo l’invocazione della funzio- ne ‘GetModuleFileNameW’ della quale viene fornito l’indirizzo da ‘GetProcAddress’ e successivamente viene spostata in ’[0x41dc04]’ (non è altro che un wrapper di ‘GetMo- duleFileNameW’ , cosa abbastanza comune nel codice di dropshot). Dopo la chiamata di ‘GetModuleFileNameW’ , dropshot utilizza ‘VirtualAlloc’ per allocare ’0x14’ byte (20 byte ), successivamente viene invocata ‘fcn.00401a40’ che dati 3 parametri(indirizzo, va- lore, e dimensione) si occupa di colmare il range tra indirizzo e indirizzo più dimensione con il valore dato. Subito dopo viene invocata la funzione ‘fcn.00401c90’ e vengono pas- sati 3 parametri: 0x14( 20), 0x66( 102) e 0x68( 104). Il valore 20 è proprio la dimensione del buffer precedentemente allocato mentre ‘102’ e ‘104’ ricordano il nome e il tipo vi- sti precedentemente (110 e 111). Analizzando il tutto con il Resource widget possiamo subito capire che ‘102’ è proprio il nome di una risorsa di tipo ‘104’ e con dimensione di 19 byte. Il valore di ritorno di ‘fcn.00401c90’ insieme ad altri due parametri (rispetti- vamente 20 e il buffer precedentemente allocato) verranno passati in ingresso ad un’altra funzione ‘fcn.00401a80’ che si occuperà di copiare un buffer dalla memoria allocata. Ciò aiuta anche a far comprendere la funzione ‘fcn.00401c90’ la quale quindi ha l’obiettivo di leggere una risorsa da un buffer e ritornare un puntatore ad essa. Figura 3.0.11: Xref della funzione ‘fcn.00401c90’ 17
Tecniche di reverse engineering del software Ora aprendo la finestra X-Refs è possibile notare come la funzione ‘fcn.00401c90’( per semplicità è stata rinominata get_resource) viene invocata due volte. La prima( ’0x0040336d’) ci è già familiare in quanto è stata utilizzata per ottenere ‘102’, mentre la seconda( ’0x00403439’ ) è utilizzata per ottenere ‘101’. Come si può evincere dal Resource widget (Figura 6), la risorsa ‘101’ è molto più grande delle altre, quindi sarà proprio il payload di Dropshot. Figura 3.0.12: Apertura risorsa ’101’ con Hexdump widget Facendo doppio click è possibile visualizzare l’offset della risorsa e tramite l’Hexdump widget è possibile vedere che il contenuto non ha senso e presenta un’alta entropia. Ta- li dati sono compressi e criptati quindi sarà necessario decriptarli. Per decriptare una risorsa è necessario analizzare il flusso del programma per vedere come e dove è sta- ta utilizzata. Appena dopo di get_resource con ’101’ e ‘103’, la risorsa è stata copiata in ’[local_20h]’ ( rinominato per semplicità in compressed_payload). Successivamen- te compressed_payload viene passato a ‘fcn.004072f0’ insieme ad un altro buffer [lo- cal_54h]. Lo scopo di tale funzione è di decomprimere un buffer utilizzando zlib ( rino- minato per semplicità in zlib_decompressed) e inserirlo successivamente in ’[local_54h]’ ( rinominato per semplicità in decompressed_payload). 18
Tecniche di reverse engineering del software Figura 3.0.13: Decrittazione della risorsa con ror 3 Infine il buffer decompresso viene passato alla funzione ‘fcn.00402620’ che effettuerà l’ultima decrittazione della risorsa (utilizzando ror 3 che effettua la rotazione a destra di ogni byte del buffer decompresso) e successivamente utilizzerà la nota tecnica del “Process Hollowing” col fine di eseguire il payload decriptato. Utilizzando infine il seguente script sarà possibile generare un file .bin di un modulo Dropshot contenente la parte del virus individuata e decriptata. 19
Tecniche di reverse engineering del software Figura 3.0.14: Script per generazione file .bin 20
Conclusioni e sviluppi futuri Come visto, le tecniche di reverse engineering sono molteplici ed abbracciano tutti i cam- pi dell’ingegneria. Se utilizzate a dovere permettono di analizzare un software in maniera dettagliata, permettendo di individuarne tutte le funzionalità ma contemporaneamente an- dando a mettere a nudo anche tutti i difetti. Proprio per questa sua estrema potenza, risulta un’arma a doppio taglio che, usata da persone poco raccomandabili, può portare alla crea- zione di software malevoli che vanno proprio a sfruttare le falle ed i difetti individuati, ma al contempo è fondamentale per la risoluzione di alcuni problemi, come può essere la modernizzazione di sistemi legacy. Ciò è stato appunto mostrato nel terzo capitolo, in cui si è effettuata un’analisi dettagliata di un software malevolo e si è provveduto ad individuare e decriptare il payload del codice. Inoltre grazie alla nascita di tool, come ad esempio radare, ed alla costante presenza di una community di esperti ed appassionati, il reverse engineering è destinato ad espandersi ed a perfezionare le tecniche. 21
Bibliografia Articolo consultato su internet: “Decrypting APT33’s Dropshot Malware with Radare2 and Cutter”, https://www.megabeets.net/decrypting-dropshot-with-radare2-and-cutter-part-2 Libro di Radare2: “Radare2 Book” , https://radare.gitbooks.io/radare2book/content/ Wikipedia: “Reverse engineering” , https://en.wikipedia.org/wiki/Reverse_engineering 22
Puoi anche leggere