
Plugin e script IDA per l'analisi del frame di utilizzo dei registri

"""
A cosa serve questo registro?
Hmm.. Lo rinominerò semplicemente in veryuniquename, farò una ricerca testuale e troverò tutti i riferimenti!
Ok.. Aspettando che la ricerca finisca.. da un momento all'altro.. Fatto!
Ora devo solo capire quale dei risultati della ricerca sia rilevante per il frame di utilizzo corrente del registro.
Non dovrebbe essere troppo difficile, giusto?
"""
Se ti è mai successo (forse più di una volta), ti aspetta una sorpresa!
Basta Shift-X e i tuoi problemi spariranno!
Puoi anche rinominare il registro nel frame di utilizzo. Basta Shift-N e segui le istruzioni!
Inoltre, invece di cambiare i tipi di tutti gli utilizzi in un certo tipo, basta Shift-T una volta.
E ultimo ma non meno importante - se vuoi impostare un offset (come fare Ctrl-R) per tutti gli utilizzi di questo registro, basta premere Shift-R.
Nota: A volte esiste già un altro plugin che usa Shift-T. Rimuovi quel plugin - tanto non l'hai mai usato prima :-).
Questo plugin utilizza sark per interagire con gli script IDA in modo confortevole, e cachetools per mettere in cache la scansione del frame, il che lo rende molto più veloce.
Oregami supporta sia IDA 7.x/8.x che IDA 9.0+.
Se stai usando IDA 9, assicurati di avere una versione aggiornata di sark che supporti IDA 9.
Nota: IDA 9 ha introdotto la propria funzionalità Shift-X. Se hai bisogno di usare lo Shift-X integrato di IDA invece di quello di oregami, dovresti cambiare la scorciatoia di oregami nel file del plugin.
[Per python3]
pip3 install sark
[Per python2]
Se stai usando la variante python2 di IDA, dovresti invece eseguire:
pip2 install -U git+https://github.com/tmr232/[email protected]#egg=Sark
Nota che python2 non è supportato attivamente (poiché IDA si è spostato per lo più su python3, e così ho fatto io), quindi potrebbe non funzionare.
git clone https://github.com/shemesh999/oregami
La base di codice di sark offre molti plugin. Uno di questi è: https://github.com/tmr232/Sark/blob/master/plugins/plugin_loader.py
Consigliamo di copiarlo nella tua directory dei plugin e poi eseguire IDA una volta con privilegi di amministratore (in modo che possa creare i file plugins.list).
Dopo averlo fatto, puoi aggiungere nuovi plugin aggiungendo il percorso a uno dei file plugins.list creati (ad esempio, uno viene creato nella cartella cfg di IDA)
Ora, aggiungi a uno dei file plugins.list:
FULLPATH\oregami\oregami_plugin.py
FULLPATH\oregami\regname_plugin.py
FULLPATH\oregami\typeregter_plugin.py
FULLPATH\oregami\offreg_plugin.py
Riavvia IDA e i plugin dovrebbero funzionare.
In alternativa:
Copia tutti i file (inclusa la cartella interna oregami, escluso setup.py) nella directory dei plugin di IDA.
Oltre ad essere utilizzato come plugin, oregami può essere usato anche per scrivere i tuoi script!
Per questo, dovresti prima installarlo usando il file setup.py incluso. Cioè dovresti eseguire:
'python setup.py develop', e da allora in poi potrai usare le classi e le funzioni interne.
Nota che consigliamo di usare 'develop' e non 'install', in modo che se scarichi una nuova versione di oregami, funzioni immediatamente.
Per esempio:
-- script.py --
def find_func_usage(func_ea, reg='r0'):
"""
Find and print all usages of a register, including the information of the specific operands
it is in, and what operation it does in the operand.
"""
import oregami
rf = oregami.RegFrame(func_ea, reg)
for insn in rf.get_instructions():
print('Addr:{:x}'.format(insn.ea))
for opnd in insn.operands:
if opnd.uf_is_external:
continue
print('--opnd_idx:{} - {}'.format(opnd.n, oregami.UsageBits(opnd.op_flags)))
Supponiamo la seguente sequenza di opcode:
ROM:01000010 e_lis r10, 0x4004 # 0x40040000 # Load Immediate Shifted
ROM:01000014 e_add16i r10, r10, 0x1337 # 0x40041337 # Add Immediate
ROM:01000020 se_mr r30, r31 # Move Register
ROM:01000022 cmplw r11, r10 # Compare Logical Word
ROM:01000026 se_bge loc_1000036 # Branch if greater than or equal
ROM:01000028
ROM:01000028 loc_1000028: # CODE XREF: sub_0100000+144↓j
ROM:01000028 e_stmw r30, 0(r11) # Store Multiple Word
ROM:0100002C e_add16i r11, r11, 8 # Add Immediate
ROM:01000030 cmplw r11, r10 # Compare Logical Word
ROM:01000034 se_blt loc_1000028 # Branch if less than
ROM:01000036
ROM:01000036 loc_1000036: # CODE XREF: sub_0100000+136↑j
ROM:01000036 e_add16i r10, r10, 8 # Add Immediate
ROM:0100003A e_li r11, 0 # Load Immediate
Se scansioniamo il frame di utilizzo del registro r10, a partire dall'indirizzo 01000022, troveremo tre tipi di utilizzi inclusi nel frame di utilizzo.
Questo includerà le istruzioni che inizializzano il valore del registro.
Potremmo voler includere solo l'ultima istruzione che ha cambiato il valore del registro (indirizzo 01000014 nell'esempio), o una sequenza di operazioni usate per impostare il valore iniziale del registro (indirizzi 01000010 e 01000014 nell'esempio).
La sequenza di operazioni usata nell'inizializzazione del registro può essere chiamata "fase di init".
Puoi scegliere di supportare una fase di init o meno, a seconda del parametro init_stage_bool nell'inizializzazione di RegFrame.
Questo includerà le istruzioni che usano il valore del registro e non lo modificano in alcun modo. Queste corrispondono alle righe 01000022 e 01000030 nell'esempio.
Questo includerà le istruzioni che usano il valore del registro, ma poi ne cambiano il valore. Queste istruzioni possono essere viste come incluse in due frame di utilizzo distinti - quello che porta a loro e quello che ha origine da loro.
Ciò corrisponde alla riga 01000036.
Quando si esegue la scansione del registro di utilizzo, arrivare a un'operazione di init o a un'operazione di break ci farà fermare la scansione in una certa direzione.
Ma potremmo anche fermare la scansione a causa di istruzioni al di fuori del frame di utilizzo.
Ad esempio, scansionando il frame di utilizzo del registro r11 a partire dall'indirizzo 01000030 ci si fermerà alla riga 0100003A.
Questa è la classe base usata in oregami. Inizializzandola su un indirizzo e un registro specifico, eseguirà la scansione del frame di utilizzo del registro e creerà un UFIntruction per tutte le istruzioni rilevanti.
get_instruction - ottiene l'istruzione dall'indirizzo dato
get_instructions - un generatore che restituisce le istruzioni nel frame di utilizzo.
Puoi anche richiedere sottoinsiemi specifici delle istruzioni utilizzate:
get_init_instructions - ottieni solo istruzioni del tipo init
get_pure_instructions - ottieni solo istruzioni del tipo pure
get_break_instructions - ottieni solo istruzioni del tipo break
get_nobreak_instructions - ottieni solo istruzioni che non sono del tipo break (cioè init + pure)
get_noinit_instructions - ottieni solo istruzioni che non sono del tipo init (cioè pure + break)
get_outbreak_instructions - ottieni solo istruzioni del tipo out break
Di default questa classe metterà in cache i risultati della scansione e si preverrà dal riesaminare lo stesso frame di utilizzo. Ciò significa che richiedere il RegFrame di qualsiasi istruzione che faceva parte del frame di utilizzo (specificamente dei tipi init + pure. Non break, perché iniziare una scansione su di esse dovrebbe restituire il frame di utilizzo che ha origine da esse) restituirà la stessa istanza RegFrame pre-calcolata. Per forzare una nuova scansione, usa il flag force quando inizializzi la classe.
Questa è la classe restituita da RegFrame, che rappresenta un'istruzione nel frame di utilizzo.
Questa classe eredita dalla classe Instruction di sark e, come tale, supporta gli stessi metodi.
Una differenza principale è che invece di contenere un array di operandi della classe Operand di sark, conterrà un array della classe UFOperand.
Questa classe contiene anche metodi per comprendere il tipo di istruzione (init, pure, break, outbreak) e i bit delle operazioni (read, write, explicit e diversi tipi di implicit).
Questa è la classe nell'array degli operandi all'interno di uno specifico UFInstruction.
Questa classe eredita dalla classe Instruction di sark e, come tale, supporta gli stessi metodi.
In aggiunta alle operazioni di sark, contiene metodi per ottenere i bit delle operazioni (read, write, explicit e diversi tipi di implicit), e per sapere se l'operando fa effettivamente parte del frame di utilizzo (utile per sapere quale operando in un'istruzione di tipo break fa parte del frame di utilizzo).
Questa è una classe usata per analizzare un'istruzione specifica, per conoscere il suo utilizzo riguardo ai registri.
Lo fa usando la conoscenza da IDA, l'analisi testuale e dettagli specifici del processore.
La ragione di questa classe è che l'analisi di base di IDA tende a mentire sull'insieme dei registri utilizzati e su come vengono utilizzati in molti opcode.
Questa classe eredita dalla classe Instruction di sark e, come tale, supporta gli stessi metodi.
Una differenza principale è che invece di contenere un array di operandi della classe Operand di sark, conterrà un array della classe RegOperand.
Questa è una classe usata per analizzare un operando specifico, per conoscere il suo utilizzo riguardo ai registri.
Lo fa usando la conoscenza da IDA, l'analisi testuale e dettagli specifici del processore.
La ragione di questa classe è che l'analisi di base di IDA tende a mentire sull'insieme dei registri utilizzati e su come vengono utilizzati in molti opcode.
Questa classe eredita dalla classe Operand di sark e, come tale, supporta gli stessi metodi.