Zoom Icon

Lezione 5 IDA Tutorial

From UIC Archive

IDA Tutorial

Contents


Lezione 5 IDA Tutorial
Author: UICommunity
Email: Email
Website: No Site
Date: 14/12/2008 (dd/mm/yyyy)
Level: Some skills are required
Language: Italian Flag Italian.gif
Comments:



Introduzione

In questa guida non mostrerò tutte le voci del menu o l’utilizzo di tutti i componenti di IDA, sarebbe una cosa mostruosa, ma vi mostrerò solo le tecniche più funzionali per analizzare un applicazione.
Se volete vedere tutte le altre funzioni di IDA, vi conviene leggervi help file e poi iniziare a perder un po' di tempo su IDA.


Tools e Riferimenti

IDA Demo
Msdn


Essay

Installiamo la demo di IDA, e poi lanciamo l'eseguibile. Cliccando su "New" vi dovrebbe apparire una finestra con tanti tab, selezionate il tab "Windows" e poi cliccate su "PE executable".
Aprendo il notepad, è contenuto in C:\Windows\, vi dovrebbe apparire una finestra per il wizard, selezionate "Analisis option" ed andate avanti fino ad arrivare alla schermata di "Kernel Option": ecco la descrizione delle varie opzioni

Analisis option

  • Kernel Option
    • Analisis
      • Trace execution flow: IDA segue il flusso di esecuzione e tenta di convertire tutte le referenze a dei byte già disassemblati in istruzioni ed evita di lasciarne solo l'opcode.
      • Analyse and create all xrefs: questa è l'opzione che fa la differenza tra IDA ed altri disassemblatori, senza di essa il nostro programma non analizzerebbe il file più volte e non creerebbe tutte le xreferences e le altre chicche caratteristiche di IDA, avremmo quindi codice disassemblato puro e non vedremmo tutte le "semplificazioni" che potremmo invece ottenere attivando questa opzione.
    • Functions
      • Create functions if call is present: fa si che IDA crei una funzione se nel codice è presente una chiamata, se nel codice troviamo una chiamata di questo genere:
        call routineallora
        IDA creerà una funzione all'etichetta "routine" che conterrà tutto il codice che si trova nella chiamata, questa opzione cerca di "staccare" le chiamate dal resto del codice per permetterci un approccio visuale, ma anche tecnico, più semplice.
      • Create function tails: Questa opzione consente a IDA di trovare e appendere alla definizione della funzione parti finali di funzione che sono separati
      • Create function if data xref data->code32 exists: se IDA incontra un riferimento ad un dato da un SEGMENTO DATI ad un SEGMENTO CODICE a 32bit allora controlla la presenza di istruzioni disassemblabili utili, se trova un'istruzione la marca (manco a dirlo ;) come un'istruzione e crea lì una funzione. È molto più semplice di quanto appaia con questa spiegazione :)
      • Rename jump functions as j_...: funzione di utilità elevatissima, questa opzione permette ADDIRITTURA di cambiare una istruzione come: jmp indirizzo in: j_indirizzo vi rendete conto...Ma dico ve ne rendete conto di quanto la presenza di questa opzione possa permettere anche a mio cugino di 10 anni di diventare un reverser :P....In realtà la presenza di un'opzione tanto "poco" importante non fa altro che confermare la professionalità di questo programma.
      • Rename empty functions as nullsub_...: permette a IDA di rinominare le funzioni vuote, cioè quelle contenenti solo l'istruzione "ret" come nullsub_1...nullsub_2 ecc...
    • Library Functions
      • Use FLIRT signatures: permette l'uso della tecnologia FLIRT, non preoccupatevi non vedrete IDA e IDO fare gli sporcaccioni sul monitor ;)))))), questa tecnologia consente di riconoscere il tipo di compilatore usato e di identificare le chiamate standard, in questo modo invece di vedere questo: call 00469187, vedremo: call MessageboxA, nel caso che questa tecnologia fallisca nel riconoscere i compilatori (leggi: Delphi) la si può sempre forzare ad usare le istruzioni del compilatore che riteniamo sia stato usato per fare quel determinato programma semplicemente aprendo il menu "View | Signatures" e premendo "ins" per far apparire la lista dei compilatori disponibili.
      • Automatically hide library functions: questa funzione aggiunge un coGrassettommento a funzioni anonime delle librerie.
      • Multiple copy library function recognition:: consente a FLIRT di riconoscere diverse copie della stessa funzione nel programma
    • Stack:
      • Create stack variables: fa si che IDA crei automaticamente le variabili dello stack ed i parametri delle funzioni
      • Trace stack pointer: con questa opzione attivata IDA traccerà il lo Stack Pointer, attivatela perchè come funzione è davvero davvero utile, può permettervi di identificare alcuni trick che altrimenti sarebbero impossibili da notare guardando soltato il disassemblato.
    • Argumenten information propagation
      • Propagate stack argument information: quest’opzione propaga i parametri passati allo stack (nomi e tipi) allo stack del chiamante
      • Propagate stack argument information: quest’opzione propaga le informazione dei registri (nomi e tipi) al chiamante.
    • Strings
      • Check unicode Strings: riconosce le stringe in formato unicode.
      • Create ASCII string if data xref exists: se IDA incontra un data reference ad un blocco indefinito, questo controlla la presenza di stringe ASCII.
    • Final Analisis
      • Make final analysis pass: questa opzione permette a IDA di coagulare tutti i byte non esplorati convertendoli in dati o, se possibile in istruzioni.
      • Mark typical code sequences as code: IDA riconosce alcune sequenze tipiche di codice (esempio: push bp e mov bp, sp) e durante il caricamento converte questi byte in istruzioni anche se non ci sono referenze ad essi.
      • Delete instructions with no xrefs: permette a IDA di non definire le istruzioni non referenziate, in pratica se noi eseguiamo il comando "undefine" (che vi spiegherò in seguito) all'inizio di una funzione il programma cancellerà tutte le istruzioni che hanno perso contatto con l'istruzione appena "undefinita"...supponiamo di avere ad una determinata riga l'istruzione "jmp 401000", se facciamo "undefine" IDA trasformerà quell'istruzione in soli byte (come se non l'avesse disassemblata) se esisteva una qualche referenza nel codice a quell'istruzione allora IDA la cancellerà, se non selezioniamo questa opzioni allora IDA lascierà intatta la referenza.
      • Convert 32bit instruction operand to offset: funziona solo su segmenti a 32bit, se un'istruzione ha un operando che può essere convertito in un'utile espressione allora la converte in offset, il valore dell'operando deve però essere più grande di 0x10000
      • Create offset if data xref to seg32 exists: se nel programma IDA incontra un riferimento ad un segmento a 32bit ed il file contiene un valore che può essere rappresentato come un offset allora IDA lo converte.....ad un offset
      • Coagulate data segments in the final pass: questa opzione torna utile solo se è attivata anche l'opzione "Make final analysis pass" e permette a IDA di convertire i byte inesplorati ad array di dati nel segmento dati. Se disabilitiamo questa opzione IDA coagulerà solo il segmento codice. Non ci nuocerà se la lasceremo disabilitata.
      • Create offsets and segments using fixup info: IDA per rendere più piacevole il disassemblato, fa uso delle informazioni di rilocazione e converte tutti gli oggetti con le info di rilocazione in word o doubleword e se un'istruzione ha assegnate delle informazioni di rilocazione IDA converte i dati ad un offset oppure ad un segmento, facciamo un esempio per rendere più chiara questa spiegazione, poniamo di avere nel nostro codice sorgente qualcosa di questo tipo:

.386


snip snip-----

.data valore dd 000F3785h

.code start:

  mov eax, offset valore 

end start Se disassembliamo il file con W32Dasm otteniamo questo:
mov eax, 0040200
Se invece lo disassemblassimo con IDA e con l'opzione attivata allora otterremo questo:
mov eax, offset valore
Può essere una funzione davvero utile al fine della comprensione del disassemblato.

      • Automatically convert data to offsets: quest’opzione consente ad IDA di convertire i più nuovi elementi dati creati in offset se le seguenti opzioni sono verificate
        • se l’offset è un indirizzo nel programma
        • l’indirizzo è maggiore di 0x20
        • l’indirizzo non punto nel mezzo di un elemento
        • se è un pezzo di codice, l’esecuzione non scorre ad un istruzione precedente
        • il dato è un dword (in ambiente x86) o un qword (ambiente x64)
        • il tipo del segmento non è specificato
    • Misc
      • Locate and create jump tables: questa opzione permette a IDA di ipotizzare la dimensione e l'indirizzo di una "jump table"

Dopo Kernel Option c'è la schermata PC PROCESS OPTION

  • PC PROCESS OPTION
    • Conversion of immediate operands
      • Convert immediate operand of "push" to offset: se IDA vede una sequenza tipo questa: push seg, push gino, proverà a convertire gino in un offset
      • Convert immediate operand of "mov reg,..." to offset: anche qui se IDA trova qualcosa come: mov ax, 258h, mov sp, es allora convertirà 258h in un offset
      • Convert immediate operand of "mov memory,..." to offset: ancora se IDA trova istruzioni come: mov ax, 895h mov X, seg (X è un riferimento ad una memoria) allora converte 895h in offset
    • Padding istructions
      • Convert db 90h after "jmp" to "nop": se dopo un jump troviamo "db 90h" invece di lasciarlo com'è lo trasforma in nop (No operation)
      • Disassemble zero opcode instructions: se nel codice trova degli opcode del tipo "0000" cerca di disassemblarli e trasformarli in codice.
    • Advanced istructions
      • Don’t display redundant istructions prefixes
      • Enable FPU emulation instructions
      • Explicit RIP-addressing
    • High-level language
      • Advanced analysis of Borland's RTTI: cerca di attuare un'analisi avanzata del Borland RTTI, questa opzione è utile se il programma è stato scritto con un compilatore Borland
      • Check 'unknown_libname' for Borland's RTTI: ricerca dei nomi di librerie sconosciuto per il Borland RTTI
      • Advanced analysis of catch/finally block after function: e istruzioni catch/finally sono istruzioni usate solamente per la gestione delle exception nel linguaggio C/C++ (vi rimando al mio tute sulle Exception) che occupano una parte considerevole dell'eseguibile, il problema delle exception è che sono davvero difficili da vedere sia da disassemblato che da debugger, attivando questa opzione IDA cerca di mostrarci più informazioni possibile su tutti gli exception handler installati dal programma.

Andate avanti ed attendete che IDA finisca di analizzare l'eseguibile, alla fine vi dovrebbe apparire una cosa del genere

L'interfaccia

Idatute1.png



Tralascio il menu, e le scrollbar, poi capirete il perchè (oltre alla pigrizia ;); spiego direttamente i tab presenti.

IDA imposta all'inizio otto tab:

  • Ida View: vi mostra il codice disassemblato in modo grafico o in modo standard. (per attivarlo fate tasto destro e poi Text View)
  • Hex View: vi mostra il codice hex
  • Exports : vi mostra le export del PE che state analizzando: l’unico export di un .exe è l’entrypoint
  • Imports: vi mostra tutte le api che importa il PE
  • Names: vi mostra tutti i nomi trovati durante l'analisi nel PE
  • Functions: mostra tutte le funzioni individuate in durante il disasm, come potreste notare se scorrette la lista delle funzioni, non tutte iniziano con sub_xxx, infatti molte funzioni vengono riconosciute esempio

loc_1002F2A:  ; dwInitParam push esi push offset DialogFunc ; lpDialogFunc <-- la dialog function viene riconosciuta, e gli viene assegnato un nome standard push dword_1009830  ; hWndParent push 0Eh  ; lpTemplateName push hInstance  ; hInstance call ds:DialogBoxParamW

  • Enums e Structs: sono tutte quelle strutture e le enum usate nell’exe, più avanti vi mostrerò come aggiungerne di nuove

La lista completa delle view è reperibile attraverso il menu’: "View" -> "Open Subviews", ora ne mostro subito alcune molto utili:

  • Signatures: tramite questa window è possibile applicare varie signature al disasm, cioè vengono riconosciute le funzioni stardard di un compilatore o di una libreria. Per applicare una signature basta fare tasto destro, "apply new signature..." e selezionare la signature desiderata.
  • Cross references: cliccando col mouse sull’inizio di una funzione, o su una variabile, e poi aprendo questa view, vengono mostrati tutti gli indirizzi che ne fanno riferimento.
  • Function calls: In alto ostra mostra tutte le cross references; in basso tutte call chiamate dalla funzione che si sta analizzando.

Il Disasm

Ecco il disasm dell’entrypoint mostrato da IDA

Attributes
bp-based frame

public start start proc near

StartupInfo= _STARTUPINFOA ptr -80h var_3C= dword ptr -3Ch var_38= dword ptr -38h var_34= byte ptr -34h var_30= byte ptr -30h var_2C= byte ptr -2Ch Code= dword ptr -28h var_24= dword ptr -24h var_20= dword ptr -20h var_1C= dword ptr -1Ch ms_exc= CPPEH_RECORD ptr -18h

push 70h push offset stru_1001898 call __SEH_prolog xor ebx, ebx push ebx  ; lpModuleName mov edi, ds:GetModuleHandleA call edi ; GetModuleHandleA cmp word ptr [eax], 5A4Dh jnz short loc_10073DA Come avete notato IDA riconosce tutte le variabili allocate nello stack e tutti gli argomenti passati, ogni variabile può essere rinominata così da facilitarci l’analisi, basta cliccare su una di essa e premere N, o tasto destro -> "rename".
Iniziamo a giocherellare un po': tenete premuto il pulsante sinistro in "graph overview" e spostate il mouse verso il basso, fino ad arrivare alla fine della funzione: loc_1007557: or [ebp+ms_exc.disabled], 0FFFFFFFFh mov eax, esi call __SEH_epilog retn start endp ; sp-analysis failed Cliccate due volte col mouse su __SEH_epilog, per andare al disasm di questa funzione.
Al top del riquadro potete vedere tre pulsanti:

  • Set node color: imposta il colore del background del nodo
  • Rename: permette di rinominare la funzione, per far ciò potete anche cliccare col mouse su un nome, poi pulsante destro e "rename"
  • Jmp to xref: mostra tutti gli indirizzi che fanno riferimento alla funzione che state analizzando


Esercizio 1: inserite un commento alla prima riga del disasm. Vi do un piccolo aiuto: usate il tasto destro.

Ora passiamo alla visualizzazione testo standard del disasm: destro -> "text view" (per tornare al graph view fate destro -> "graph view").

Strutture ed Enum

Ritorniamo all’entrypoint in questo modo, andate nel menu "jump", cercate "jump to entrypoint" (per tornare indietro, basta cliccare sulla freccia indietro collocata al di sotto del menu).
Sotto l’entry trovate una chiamate a GetModuleHandleRitorna l'ImageBase del Modulo: .text:010073A9 xor ebx, ebx ; ebx = 0 .text:010073AB push ebx  ; lpModuleName .text:010073B2 call edi ; GetModuleHandleA .text:010073B4 cmp word ptr [eax], 5A4Dh Cliccate il pulsante destro col puntatore del mouse su "5A4Dh", e noterete che potete convertire quella costante in decimale, ottale, binario o in testo: selezioniamo ‘MZ'; a questo punto, chi ha un po' di conoscenza nel PE (se non l’avete vi rimando al tute di Ntoskrnl), avrà già capito che questo codice farà qualche controllo sull’immagine in memoria del programma, infatti andando avanti vengono fatti dei controlli: .text:010073BB mov ecx, [eax+3Ch] ;<-- eax è usato come puntatore di una struttura .text:010073BE add ecx, eax .text:010073C0 cmp dword ptr [ecx], 4550h .text:010073C6 jnz short loc_10073DA Come avete letto dal commento che ho aggiunto a canto al mov, [eax+3Ch] rappresenta un membro di una struttura, ma quale? Per sapere la struttura che viene utilizzata avete due possibilità: sapete già qual è, o avete intuito quale possa essere, poiché vengono usate costanti o API particolari.
In questo caso la struttura usata è Dos Header, aggiungiamola nella view "structures": premete INS e poi cliccate su Add standard structures, e cercate _IMAGE_DOS_HEADER.
Ora andate su eax+3Ch, premete il pulsante destro, selezionate structure offset e poi IMAGE_DOS_HEADER.
Continuiamo l’analisi fino ad arrivare in questo punto: .text:010073C0 cmp dword ptr [ecx], 'EP' ;<-- ho visualizzato la costante come testo .text:010073C6 jnz short loc_10073DA .text:010073C8 movzx eax, word ptr [ecx+18h] ;<-- ecco a voi un altra struttura .text:010073CC cmp eax, 10Bh .text:010073D1 jz short loc_10073F2 .text:010073D3 cmp eax, 20Bh .text:010073D8 jz short loc_10073DF Questa volta la struttura usata e _IMAGE_NT_HEADERS, aggiungetela ed applicatela a quell’istruzione, che verrà mostrata in questo modo .text:010073C8 movzx eax, [ecx+_IMAGE_NT_HEADERS.OptionalHeader.Magic] Il Magic può avere i seguenti valori

  1. define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b // normale eseguibile 32bit
  2. define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b // 64bit
  3. define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 // ROM

Quindi non ci resta che dichiarare un nuovo enum:
aprite la view "enum", premete INS e poi N per inserire le varie costanti. (potete anche semplicemente fare il parsing di un file .h: menu File -> Load file -> Parse C header file).

A questo punto cliccate col destro su "10Bh", selezionate "symbolic costant" e poi "IMAGE_NT_OPTIONAL_HDR32_MAGIC".

Ecco a voi il disasm così come lo abbiamo definito fino a questo punto: .text:0100739D push 70h .text:0100739F push offset stru_1001898 .text:010073A4 call __SEH_prolog .text:010073A9 xor ebx, ebx .text:010073AB push ebx  ; lpModuleName .text:010073AC mov edi, ds:GetModuleHandleA .text:010073B2 call edi ; GetModuleHandleA .text:010073B4 cmp word ptr [eax], 'ZM' .text:010073B9 jnz short loc_10073DA .text:010073BB mov ecx, [eax+IMAGE_DOS_HEADER.e_lfanew] .text:010073BE add ecx, eax .text:010073C0 cmp dword ptr [ecx], 'EP' .text:010073C6 jnz short loc_10073DA .text:010073C8 movzx eax, [ecx+_IMAGE_NT_HEADERS.OptionalHeader.Magic] .text:010073CC cmp eax, IMAGE_NT_OPTIONAL_HDR32_MAGIC .text:010073D1 jz short loc_10073F2 .text:010073D3 cmp eax, IMAGE_NT_OPTIONAL_HDR64_MAGIC .text:010073D8 jz short loc_10073DF Figo, non è vero? ;)

Undefine - Data - Code

Vi può capitare di trovarvi avanti a dati Undefined come questi: .text:010075F4 unk_10075F4 db 33h ; 3  ; CODE XREF: start+AB#p .text:010075F4  ; DATA XREF: start+B8#o .text:010075F5 db 0C0h ; + .text:010075F6 db 0C3h ; + .text:010075F7 db 5 dup(0CCh) Possiamo modificare il tipo usato su quell’indirizzo, cioè passare da byta a word a dword, semplicemente selezionando la riga desiderata e premendo "D": .text:010075F4 byte_10075F4 db 33h

.text:010075F4 word_10075F4 dw 0C033h

.text:010075F4 dword_10075F4 dd 0CCC3C033h

Possiamo mostrare il disasm come un sequenza di byte, selezionando tutte le righe desiderate, e poi facendo destro -> "undefine", oppure convertire i byte in codice asm con pulsante destro -> "code" e poi definire una funzione tramite la voce "create function", accessibile sempre tramite il pulsante destro .text:010075F4 sub_10075F4 proc near  ; CODE XREF: start+AB#p .text:010075F4  ; DATA XREF: start+B8#o .text:010075F4 xor eax, eax .text:010075F6 retn .text:010075F6 sub_10075F4 endp

IDC Script

L'IDC è in tutto simile al C; le reference del linguaggio IDC le trovate nell'help di ida ed anche online sul sito della datarescue. Ecco un esempio di decrypt di un exe usando ida e idc: static decrypt() {

 auto i, temppp, blocco;   // definizione variabili
 blocco = 0x00401036;               // address di partenza
 for(i=0; i<519; i++)               // ciclo per tutte le dwords (519 dec)
 {
   temppp = Dword(blocco);          // prende la dword dall'address
   temppp = temppp^(0x4FC9FD9B);    // la xora
   PatchDword(blocco, temppp);      // e la rimette a posto decriptata
   blocco = blocco + 4;             // aggiorna l'address
 }

} Adesso salvate questo file di testo, andiamo in ida, menu, File->Idc File... e caricate il vostro IDC. Vi apparirà la floating bar con i due pulsanti, uno per aprire ed editare lo script e uno per compilarlo. Se lo compilate e non vi dà nessun errore allora lo potete eseguire perchè la sintassi è corretta (per la semantica sta a voi controllare :-P). Ok ora il nostro script è pronto, prima di usarlo però facciamo l'undefine (tasto u oppure usate il trackpopup menu) di tutto il codice criptato.
Ora la funzione del nostro script è "decrypt()", per cui per usarla andiamo nel menu File->Idc Command... e ci scriviamo un bel "decrypt();" per farla eseguire.

Per vedere all'opera IDC vi consiglio la seguente lettura: Soluzione Tarantula by AndreaGeddon


Approfondimenti

Ecco alcuni link utili:

Mega tutorial su IDA per windows (Tutorial v1.2)
Soluzione al 11° corso newbies - Addio WinDasm, è tempo di IDA
This tutorial introduces the main functionalities of the new IDA Windows PE Debugger plugin
IDA Pro 5.0 Preview
This tutorial is now available in PDF: remote debugging with IDA Pro
The IDA Pro Book


Compiti per casa

Completate questo wikitutorial!!!!
Chi vuole può aggiungere descrizioni di altre funzioni (tipo come si debugga con IDA), di menu o altre finestre non spiegate (come "Chart of xref ...")


Note Finali

Bello vero? Ecco perchè costa 700euro la versione pro ahaha (mica bruscolini), per fortuna che c'è la versione sq3free: consiglio vivamente di installarla =)
Ringrazio Que, Nt, Quake, Evilcry, Epokh, jnz_, Pn e tutti gli altri di #crack-it



Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.