LOA Hacklab - Corso di ASM/reversing/secure C by Lidl&&Mala - 0010/1010 ----------------------------------------------------------------------- All'interno di questa dispensa troverete (in versione riveduta e corretta) i concetti che abbiamo spiegato durante la seconda lezione del corso. Visto che mentre spiegavamo abbiamo notato, di tanto in tanto, occhi sgranati e quella tipica espressione tipo: "Ma che @a770 stanno dicendo", abbiamo cercato di approfondire quei concetti che davamo per scontati e che invece forse era il caso di ribadire. Quindi, se certe cose vi sembrano troppo banali non dovete prendervela con noi, ma con quelli che sgranavano gli occhi. Detto questo, cominciamo con un piccolo sommario: IL REGISTRO EFLAGS guardare per credere LE ISTRUZIONI i tipi principali di istruzioni e il loro effetto SIMPATICI ESEMPIETTI vediamo se riuscite a capire cosa fanno questi snippet BIBLIOGRAFIA ============================================================================= IL REGISTRO EFLAGS ============================================================================= Giusto per rinfrescarvi la memoria (e in caso non abbiate scaricato anche i lucidi), visto che parliamo di registri, eccovi un elenco dei registri con cui avremo a che fare: Nome Descrizione ----------------------------------------------------------------------------- EAX Accumulator register: usato x la maggior parte delle operazioni e per contenere i valori di ritorno delle funzioni chiamate (CALL). ----------------------------------------------------------------------------- EBX Base address register: usato comunemente x l'indirizzamento indiretto. ----------------------------------------------------------------------------- ECX Count register: usato come contatore. ----------------------------------------------------------------------------- EDX Data register: overflow, indirizzi I/O. ----------------------------------------------------------------------------- ESI Source index: usato insieme ad EDI come puntatore per accedere in modo indiretto alla memoria, molto spesso per la gestione delle stringhe. ----------------------------------------------------------------------------- EDI Destination index: vedi sopra. ----------------------------------------------------------------------------- EBP Base pointer: simile a EBX, viene spesso utilizzato per gestire parametri passati a funzioni e variabili locali. ----------------------------------------------------------------------------- ESP Stack pointer: punta alla locazione di memoria attualmente in cima allo stack. ----------------------------------------------------------------------------- EIP Instruction pointer: punta alla locazione di memoria contenente la prossima istruzione da eseguire. ----------------------------------------------------------------------------- FLAGS Flags register: contiene diversi valori, come vedrete fra poco :) ----------------------------------------------------------------------------- ?S Segment registers: CS (code), DS (data), ES (extra), SS (stack), FS e GS ----------------------------------------------------------------------------- Ricordatevi anche che la "E" davanti a ogni registro (fatta eccezione per le flags e i segment) sta a identificare la versione a 32 bit (4 byte) dello stesso: se la togliete avete ancora un registro valido, pero' grande solo 16 bit (2 byte). Inoltre, per i primi 4 registri (EAX, EBX, ECX ed EDX) potete effettuare ancora una distinzione fra parte alta (AH, BH, CH, DX) e parte bassa (AL, BL, CL, DL). Ad esempio: 8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| | | | | | +-------AH------+-------AL------+ | | | | +---------------AX--------------| | | +------------------------------EAX------------------------------+ Naturalmente, se lavorate solo su una parte del registro EAX la modifica verra' effettuata solo sui bit relativi ad essa: se, ad esempio, inserite un valore in AL con una MOV i 24 bit fuori da esso resteranno invariati. Ma veniamo ora al registro FLAGS (anzi, EFLAGS anche se i bit alti non sono utilizzati): la sua struttura e' la seguente 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |__|__|__|__|_O|_D|_I|_T|_S|_Z|__|AC|__|_P|__|_C| | | | | | | | | | | | | | | | | | | Overflow------+ | | | | | | | | Direction--------+ | | | | | | | Interrupt-----------+ | | | | | | Trace------------------+ | | | | | Sign----------------------+ | | | | Zero-------------------------+ | | | Auxiliary Carry--------------------+ | | Parity-----------------------------------+ | Carry------------------------------------------+ Cosa significa 'sta roba? In pratica, immaginate il registro FLAGS (ignoriamo i bit sopra al sedicesimo) non tanto come un numero ma come un insieme di bit, ognuno dei quali e' uno se si verifica una particolare condizione, zero in caso contrario: delle "bandierine" (flags) di segnalazione, se proprio volete dare un significato al nome del registro :) A questo punto la domanda sorge spontanea: "allora che significato hanno i vari flag di segnalazione?" Quelli che a noi interessano maggiormente sono i seguenti: - Overflow: viene impostato a 1 se, dopo un'operazione aritmetica, il risultato e' troppo grosso per essere contenuto nell'operando di destinazione. Si noti che in questo caso l'operando e' DOTATO DI SEGNO. - Sign: viene impostato a 1 se il risultato di qualche calcolo e' un valore negativo. Un numero e' considerato negativo se il bit di ordine massimo (quello piu' a sinistra, per intenderci) e' uguale a 1: la conseguenza e' che la sign flag viene impostata a 1 anche quando si lavora con valori senza segno, ma che hanno il bit di ordine massimo uguale a 1. - Zero: la zero flag viene impostata a 1 se il risultato di un'operazione e' 0. Questa flag e' particolarmente importante, in particolare quando verificherete se due valori sono uguali (cioe' se la loro differenza e' zero). - Carry: la carry flag ha diversi utilizzi: innanzitutto, ha valore 1 se si verifica un overflow su numeri senza segno (analogamente a Overflow nel caso di numeri dotati di segno); inoltre viene usata da diverse operazioni e, poichè è possibile modificarla in modo molto semplice, potete utilizzarla per effettuare calcoli booleani. Come avrete gia' avuto modo di vedere dall'elenco mostrato in precedenza, le flag descritte non sono le uniche presenti nel registro FLAGS: se volete sapere cosa fanno anche le altre, vi rimandiamo alla "bibbia" dell'ASM... The Art of the Assembly Language (anch'essa presente online). Ah... se vi andate a vedere pure il manuale dell'Intel (v. Bibliografia) troverete addirittura delle ALTRE flag... ma quante ne so! ============================================================================= LE ISTRUZIONI ============================================================================= Le istruzioni dell'ASM 80x86 possono essere divise, in prima approssimazione, in otto categorie principali: 1) Istruzioni di spostamento dati mov, lea, les, push, pop, pushf, popf 2) Conversioni cbw, cwd, xlat 3) Istruzioni aritmetiche add, inc, sub, dec, cmp, neg, mul, imul, div, idiv 4) Istruzioni logiche e che lavorano sui bit and, or, not, xor, shr, shl, rcr, rcl 5) Istuzioni di I/O in, out 6) Istruzioni che lavorano sulle stringhe movs, stos, lods 7) Istuzioni per il controllo di flusso jmp, call, ret, salti condizionali 8) Varie ed eventuali clc, stc, cmc 1) ISTRUZIONI DI SPOSTAMENTO DEI DATI All'interno di questa categoria, l'istruzione principale (e quella che, di sicuro, incontrerete piu' spesso) è MOV. Essa compare in diverse forme, ma il suo significato universale e': MOV destinazione, sorgente cioe' COPIA (NON sposta, copia!) in destinazione il valore che si trova in sorgente. Quest'ultimo parametro può essere un valore numerico (in base 16, naturalmente), un registro (in questo caso verrà copiato il contenuto di tale registro), un indirizzo di memoria eventualmente preceduto dalla dimensione del dato che si desidera copiare o un segment register. Il parametro di destinazione puo' essere un indirizzo di memoria, un segment register o un registro (sia esso a 32, 16 o 8 bit). Le eccezioni a questo comando stanno nel fatto che non e' possibile avere un indirizzo come valore di sorgente e di destinazione allo stesso tempo, ne' e' possibile inserire un valore numerico all'interno di un segment register: se volete eseguire operazioni di questo tipo dovete elaborare voi dei metodi alternativi (come ad esempio MOV EAX, memoria1 - mov memoria2, EAX per copiare un dato da una parte all'altra della memoria). Ultima nota riguardo al comando MOV: esso non modifica il registro EFLAGS, quindi anche se, ad esempio, fate una MOV di un valore nullo, la Zero Flag non verra' modificata. Un'altra istruzione che troverete, anche se con una frequenza decisamente inferiore a MOV, all'interno dei vostri disassemblati è LEA: tale comando, con sintassi LEA registro, memoria vi consente di caricare l'indirizzo effettivo (Load Effective Address) che avete specificato in all'interno di . Notate, infatti, che quando viene specificato il parametro "memoria" potete avere anche dei valori diversi da semplici numeri: questo solleva il problema del cosiddetto indirizzamento indiretto, che ora descriveremo in breve... ============================================================================= SIMPATICI ESEMPIETTI ============================================================================= Questi sono gli snippet citati a lezione... vediamo un po' se riuscite a capire cosa fanno! Non preoccupatevi troppo, comunque: a lato del codice, trovate alcune brevi spiegazioni sul loro funzionamento. ;Summary: Calculates absolute value of a signed integer in eax. ;Compatibility: 386+ ;Notes: 9 bytes, 4 clocks (P5), destroys ecx mov ecx, eax ; Duplicate value shr ecx, 31 ; Fill ecx with its sign xor eax, ecx ; Do 'not eax' if negative sub eax, ecx ; Do 'inc eax' if negative ; For comparison, the standard way (2-8 clocks on P5 and 1-17 on P6): ; or eax, eax ; js @@1 ; neg eax ;@@1: ;Summary: eax = min (eax, ecx) (both eax and ecx unsigned) ;Compatibility: 386+ ;Notes: 8 bytes, 4 clocks (P5), destroys ecx and edx sub ecx, eax ; ecx = n2 - n1 sbb edx, edx ; edx = (n1 > n2) ? -1 : 0 and ecx, edx ; ecx = (n1 > n2) ? (n2 - n1) : 0 add eax, ecx ; eax += (n1 > n2) ? (n2 - n1) : 0 ; Standard cmp/jbe/mov takes 2-8 clocks on P5 and 1-17 on P6 ;Summary: eax = max (eax, ecx) (both eax and ecx unsigned) ;Compatibility: 386+ ;Notes: 9 bytes, 5 clocks (P5), destroys ecx and edx sub ecx, eax ; ecx = n2 - n1 cmc ; cf = n1 <= n2 sbb edx, edx ; edx = (n1 > n2) ? 0 : -1 and ecx, edx ; ecx = (n1 > n2) ? 0 : (n2 - n1) add eax, ecx ; eax += (n1 > n2) ? 0 : (n2 - n1) ; Standard cmp/jae/mov takes 2-8 clocks on P5 and 1-17 on P6 ============================================================================= BIBLIOGRAFIA ============================================================================= Naturalmente, "The Art of the Assembly Language" e' un testo che non potete ignorare, in particolare relativamente a questa lezione. Tra l'altro, avrete anche modo di notare che alcune immagini che ho utilizzato per i lucidi le ho fregate da li' O:-)... Il capitolo 6 e' quello da cui sono state prese la maggior parte delle informazioni presenti in queste dispense, ma anche i primi 5 hanno il loro bel perche' :) Un altro documento davvero prezioso per chi programma in ASM e' il mitico file 386intel.txt, ovvero "INTEL 80386 PROGRAMMER'S REFERENCE MANUAL", che nonostante la sua veneranda eta' (e' del 1986) contiene tutto quello che vi serve sapere (e pobabilmente anche qualcosa di piu') per programmare in ASM. Crackpc e' un'ottima quick reference per quando programmate e - partendo dal programma chiamato helppc - e' stato modificato per contenere anche il manuale di softice (quello che molto probabilmente diventera' il vostro debugger preferito sotto win). Infine, un elenco degli opcode velocemente consultabile puo' sempre tornarvi comodo: nella cartella dedicata alla documentazione c'e' un file in formato help di windows, ma se preferite nessuno vi impedisce di usare 386intel.txt e le opzioni di ricerca di un editor di testo veloce.