Domanda:
Segmenti in IDA. Come superare il problema NONAME
ScumCoder
2014-08-13 19:20:53 UTC
view on stackexchange narkive permalink

Sto disassemblando un DOS MZ EXE a 16 bit compresso.

Per deoffuscarlo, ho impostato un punto di interruzione in DOSbox alla fine della routine di decompressione, l'ho lasciato funzionare e ho creato una memoria discarica. In questo modo ho essenzialmente ottenuto l'immagine EXE deoffuscata.

I problemi sono iniziati quando ho caricato l'immagine in IDA. Vedi, non capisco il concetto di segmenti dell'IDA. Sono simili ai segmenti x86, ma ci sono numerose differenze che non riesco a cogliere. Quando IDA mi ha chiesto di creare almeno un segmento, ho appena creato un singolo segmento enorme di 1 MB di lunghezza, perché il codice ei dati nello spazio degli indirizzi del programma sono misti e non ha senso introdurre segmenti separati come CODE , DATA ecc.

Dopo aver mostrato a IDA il punto di ingresso, tutto ha funzionato bene: funzioni determinate con successo da IDA, variabili locali, argomenti ecc. L'unico problema è che alcuni le chiamate sono contrassegnate come NONAME , anche se puntano alle subroutine corrette. La cosa più strana è che quelle subroutine hanno XREF corretti per le chiamate "illegali". Ecco un esempio:

  seg000: 188FF 004 call 1AD9h: 1; Procedura di chiamata  

Questa riga è rossa e presenta un problema NONAME associato nell'elenco dei problemi. Perché?

L'indirizzo 1AD9h: 1 seg: offset corrisponde all'indirizzo lineare 0x1ad91 , che ha questo:

  seg000: 1AD91; =============== SUBROUTINE ================================== ===== seg000: 1AD91seg000: 1AD91; Attributi: frameseg000: 1AD91seg000: 1AD91 sub_1AD91 proc far; CODICE XREF: sub_188F2 + DP  

Nota l'XREF. Quindi IDA elabora effettivamente la chiamata correttamente! Perché la chiamata è considerata non valida? Il file della guida IDA dice questo:

Problema: impossibile trovare il nome

Due motivi possono causare questo problema :

  1. Viene fatto riferimento a un indirizzo illegale nel programma in corso disassemblato;
  2. IDA non è riuscito a trovare un nome per l'indirizzo ma deve esistere.

Cosa fare

  1. Se questo problema è causato da un riferimento a un indirizzo illegale

    • Prova a inserire l'operando manualmente
    • Oppure rendi legale l'indirizzo illegale creando un nuovo segmento .
  2. Altrimenti, il database è danneggiato.

Quindi, immagino che il problema sia che ho un segmento gigantesco invece di diversi piccoli . Ma come divido correttamente lo spazio degli indirizzi in segmenti appropriati?

Conosco i valori di registro (inclusi DS , CS , SS , IP , ecc.) al punto di ingresso. Supponiamo che crei un segmento CODE a partire dal segmento corrispondente al valore del registro CS nel punto di ingresso. Ma che lunghezza dovrebbe avere questo segmento?

Qual è lo scopo dei segmenti in IDA? Se i segmenti di DATI possono contenere istruzioni e i segmenti di CODICE possono essere letti e scritti come dati?

Mi scusi per questa domanda per principianti, ma il manuale IDA ufficiale è notoriamente scarso ei forum di HexRays sono chiusi per me usa la versione freeware.

Tre risposte:
Igor Skochinsky
2014-08-13 23:32:04 UTC
view on stackexchange narkive permalink
  1. Il tuo programma sta usando un segmento con base 1AD9h (la parte del segmento della chiamata remota). Devi creare un nuovo segmento che lo corrisponda.

      Start = 0x1AD90 (0x1AD9<<4) End = 0x2AD90 [ad esempio] (start + 64KB - dimensione massima) Base = 0x1AD9 (o) 16 bit  
  2. Ora passa attraverso il nuovo segmento e assicurati che tutto abbia un senso. Taglia il segmento (riduci l'indirizzo finale) se necessario.

  3. Trova un altro salto lontano / chiamata con un valore di segmento diverso. Ripeti il ​​passaggio 1 per la nuova base.

  4. Fai lo stesso con i segmenti di dati (cerca i valori caricati in ds / es / ss ).

Quindi stai insinuando che per ogni chiamata lontana, IDA dovrebbe avere un segmento la cui base è uguale alla parte del segmento della chiamata? Ma i segmenti x86 possono sovrapporsi e i segmenti IDA no. Cosa succede se dopo aver creato un segmento che inizia a 0x1AD90 mi imbatto in una chiamata remota al segmento 1ADAh? Devo ridurre il primo segmento a 16 byte per poter creare un nuovo segmento a partire da 0x1ADA0? Sembra che finirò con un sacco di piccoli segmenti. Dubito che sia questa la strada da percorrere.
I programmi reali usano raramente segmenti sovrapposti.
Rolf Rolles
2014-08-14 00:48:17 UTC
view on stackexchange narkive permalink

Mi sono occupato di un'immagine ROM una volta e ho riscontrato questo problema. Ero anche confuso su cosa fare fino a quando Igor non ha offerto il suo consiglio.

Quello che sembrava accadere era che il linker stava inserendo ogni file oggetto nel proprio segmento, quindi ogni invocazione di funzione inter-oggetto veniva resa in il binario come chiamata lontana, dove la base del segmento era la base data a tutte le funzioni all'interno del modulo. Cioè, il caso che hai menzionato nella tua risposta al commento di Igor non si è materializzato per me.

Per risolvere il problema, ho cercato nel binario tutte le istruzioni di chiamata remota e quindi ho creato un nuovo segmento IDA (il più grande possibile ) all'indirizzo lineare di ogni segmento x86 di riferimento. Cioè, sono davvero finito con un sacco di piccoli segmenti. Questo non è davvero un problema; in realtà, il problema è che non facendo ciò i riferimenti non verranno smontati correttamente. È stato un lavoro piuttosto veloce e probabilmente poteva essere automatizzato con uno script.

Giusto. Ma può esserci un programma che richiama la stessa funzione con due diversi valori di segmento. Ad esempio, la funzione inizia all'indirizzo `0x12345`, ed è chiamata da un posto come` call far 1233h: 0015h` e da un altro come `call far 1234h: 0005h`. Può essere "usato raramente in programmi reali", ma è fisicamente possibile, e in quel caso non sarà possibile impostare il segmento della func in modo tale che entrambe le chiamate non abbiano problemi con NONAME. È solo strano che uno strumento così potente come IDA possa avere problemi in una situazione del genere, non importa quanto sia puramente teorica.
Sì, certamente * potrebbe * accadere: per offuscamento, o solo per un programmatore di assembly intelligente. Per quanto riguarda IDA e le sue limitazioni, è il mio software preferito di tutti i tempi, insieme a SoftICE, ma durante il suo lungo sviluppo sono state prese molte decisioni architettoniche che possono farti inciampare nei tuoi tentativi di inversione. Cose del genere mi frustravano e mi infastidivano, finché non trovavo un lavoro come sviluppatore di software, e ora capisco. Hex-Rays realizza prodotti straordinari considerando le loro risorse limitate. Puoi fare quasi tutto quello che vuoi, il supporto è ottimo e l'SDK / IDAPython è buono. Prepara la limonata.
Guntram Blohm supports Monica
2014-08-13 20:47:53 UTC
view on stackexchange narkive permalink

Il problema alla base di questo è che ogni segmento indirizza un massimo di 64 KB e, per generare un assembly significativo, IDA deve sapere quali dovrebbero essere i registri del segmento quando viene eseguito il codice.

avere il seguente codice all'indirizzo lineare 0x23456:

  mov bx, 6789call [bx]  

Quale funzione chiama questa funzione? Bene, se il tuo registro CS ha 0x2000 e il tuo IP è 0x3456 , allora questo chiama 2000: 6789 o (lineare) 0x26789 . Ma, altrettanto bene, potresti avere 0x2345 in CS e 0x0006 in IP. In tal caso viene chiamato 2345: 6789 o ( 0x23450 + 0x6789 =) 0x29BD9 .

Ci sono casi in cui i target jump / call non sono così ambigui, ad esempio con chiamate lontane assolute, come la tua call 1AD9: 1 , o con salti relativi (questo è il motivo per cui ho usato l'indiretto [bx] call; call 6789 userebbe un'istruzione assembly relativa all'IP, quindi indipendente dal segmento).

Tuttavia, gli offset non hanno senso se non sai a quale segmento appartengono. Se hai un codice come questo

  mov ax, 1234push axpop esmov bx, es: [abcd] mov ax, 5678push axpop esmov dx, es: [cdef]  

vuoi una definizione di variabile (per bx) in 1234: abcd e un'altra (per dx) in 5678: cdef . Ciò significa che IDA deve sapere che un segmento inizia da 1234 per inserire la prima variabile e un altro inizia da 5678 per la seconda variabile. (Ho usato il push / pop perché, per quanto ricordo, non c'era alcun codice operativo del processore per caricare direttamente un registro di segmento, e penso che ci fossero alcune restrizioni anche con lo spostamento, quindi il push / pop è stato usato pesantemente per caricare loro).

Ovviamente, il punto dei segmenti è che sono una cattiva idea e hanno causato molti problemi, ma Intel voleva essere in grado di indirizzare più di 64K con un processore a 16 bit, quindi li ha inventati. Il che significa che esistono e dobbiamo adattarli correttamente quando si smontano programmi a 16 bit. Se ci piacciono o meno non è il problema.

Il meglio che puoi fare è trovare il maggior numero di riferimenti ai segmenti che puoi: valori CS / DS / ES / SS iniziali, chiamate lontane ad alcuni cs: ip posizione e valori che vengono caricati nei registri di segmento. Quindi, annota i valori del segmento, presumi che ognuno di essi sia abbastanza grande da contenere tutto lo spazio per quello successivo e invia questo elenco a IDA.

Grazie, ma conosco il sistema di segmentazione x86. Sembra che non abbia nulla a che fare con i segmenti IDA. (1) il codice che sto smontando non ha virtualmente salti vicini, solo brevi e lontani che non necessitano di segmenti adeguati. (2) l'istruzione `call 1AD9h: 1` che ho menzionato è un salto in avanti (codice operativo` 9a 01 00 d9 1a`), ed è ancora contrassegnata come non valida. (3) Ancora non capisco perché IDA sia riuscita a generare XREF appropriato per questa chiamata "non valida". (4) Per quanto ne so tu controlli i valori dei registri di segmento non dalla vista "Segmentazione del programma" ma dalla vista "Registri di segmento", che sembra essere una cosa diversa.


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...