eWorld ReSearch - Assembler Tutorial eWorld Network ReSearch Last update: 12/1999 by Alessandro Polo Assembler Tutorial Descrizione Questo documente spiega brevemente e sommariamente la basi dell'Assembler x86. Puo essere un primo approccio alla programmazione di primo livello. Sistemi binario, decimale, esadecimale Noi siamo abituati a lavorare con il sistema decimale, ma i computer a livello hardware utilizzano il sistema binario (combinazioni di 0 e 1), il pc usa ovviamente anche il sistema esadecimale. Un cracker o un programmatore di Assembler deve conoscere tutti i sistemi elencati e sapere come convertire cifre. Il sistema più vicino a noi è quello decimale, quindi useremo quello per rendere gli altri sistemi più "amichevoli", il sistema binario utilizza infatti le cifre 0 e 1, quello il base 8 riciclerà le cifre da 0 a 7. Per il sistema esadecimale ci sono 16 cifre e quindi siamo costretti a ricorrere alle letter dell'alfabeto: Esadecimale:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 . Convertito: 0 1 2 3 4 5 6 7 8 9 A B C D E F . Quindi mentre il sistema decimale è "matematicamente incompatibile" col sistema esadecimale, il sistema binario è molto vicino ad entrambi, esso infatti lavora in base due e 2*2*2*2=16 (base esadecimale). ● Conversione Binaria a Decimale Prendiamo ad esempio 11011b in complemento a due, a che numero decimale corrisponde? numero binario: 1 1 2^4 2^3 potenze di 2: +8 formato decimale:16 sommando.. risultato: = 27 ● 0 2^2 +0 Conversione Binaria a Esadecimale 1 2^1 +2 1 2^0 +1 eWorld ReSearch - Assembler Tutorial Utilizzando lo stesso esempio calcoliamo il corrispondente esadecimale. (dividiamo in gruppi di quattro da dx verso sx) numero binario: 1 2^4 potenze di 2: formato decimale:16 1 2^3 +8 in Hex 8+2 +1=11 = B 1 risultato: ● 0 2^2 +0 1 2^1 +2 1 2^0 +1 = 1B Conversione Decimale a Binaria Come avrete tutti studiato parecchi anni fa per convertire un valore decimale in uno binario si gioca sulle divisioni e sul rimanente. DIV è il risultato della divisione mentre MOD è il resto. Così se scriverò 15 MOD 2 il risultato sarà DIV=7, MOD=1 (il simbolo che identifica MOD è %). Praticamente per trasformare un numero decimale in uno binario è sufficiente continuare a dividere per due componendo la cifra binaria da destra verso sinistra: 15/2 =7 +1 BIN -> 1 7 /2 =3 +1 BIN -> 11 3 /2 =1 +1 BIN -> 111 1 /2 =0 +1 BIN -> 1111 Hex 0 1 2 3 4 5 6 7 8 9 A B C D Bin 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 eWorld ReSearch - Assembler Tutorial E F 1110 1111 Quindi ad esempio 1101 1011 0111 0101 0011 corrisponde a D B 7 5 3. ● Operazioni & Logica Per distinguere la base di ogni cifra l'Assembler aggiunge l'iniziale del sistema al termine del numero Suffisso Sistema b Binario o d h Ottale Decimale Esadecimale Per scrivere il numero 7 in base due in 8 bit di memoria: 00000111. Se vogliamo rappresentare il numero -7 la cosa è più complessa: 00000111 invertiamo i bit: 11111000 aggiungiamo 1 al numero 11111000 + 1 = 11111001 --> -7 Infatti: (111 + 11111001 = 0 <-> 7 - 7 = 0) Il valore 1 corrisponde a vero mentre 0 corrisponde a falso, entriamo nell'affascinante mondo della logica (sezione della matematica che studia i predicati). Le operazioni fondamentali (porte logiche) sono AND, OR, NOT, XOR. Ecco una tabella riassuntiva dei risutati: c = a AND b a 0 0 1 1 b 0 1 0 1 c 0 0 0 1 c = a OR b a 0 0 1 1 b 0 1 0 1 c 0 1 1 1 eWorld ReSearch - Assembler Tutorial c = NOT a c = a XOR b a 0 1 c 1 0 (NOT funziona con una sola variabile) Unità di misura della memoria ab c 00 0 01 1 10 1 11 0 E' necessario introdurre ancora altri concetti prima di passare alla vera e propria programmazione, un concetto che non sarà senz'altro nuovo è quello de Bit, Byte, Word.. Un Bit è una cifra binaria: 0 oppure 1. Un Byte è una concatenazione di 8 Bit quindi 10010010, un byte può rappresentare un qualsiasi numero tra 0 e 2^8-1 (=255) o un qualsiasi esadecimale da 0 a FF. Una Word è l'unione di 2 byte, quindi sono in totale 16bit di memoria, i numeri arrivano a 65535, in Esadecimale fino a FFFF. Una Double Word è 2 Word ossia 4 byte, da 0 a 4294967295 e in esa da 0 a FFFFFFFF. Poi: un Kilobyte è 1024 Byte, un Mega 1024 Kilobyte, Un Gigabyte 1024 Megabyte. I Registri I registri sono delle locazioni di memoria dove il nostro programma può salvare dati, puntatori.. I Registri in questione sono AX, BX, CX, DX. ● ● ● ● AX - Registro a 16bit (divisibile in AH e AL da 8bit ciascuno), è detto "accumulatore" poichè è spesso usato per memorizzare calcoli matematici. BX - Registro a 16bit (divisibile in BH e BL da 8bit ciascuno), usato spesso per memorizzare OFFSET. CX - Registro a 16bit (divisibile in CH e CL da 8bit ciascuno), impiegato nella maggior parte dei casi come contatore di cicli. DX - Registro a 16bit (divisibile in DH e DL da 8bit ciascuno), usato per memorizzare grosse cifre matematiche e come puntatore nell'I/O. eWorld ReSearch - Assembler Tutorial ● ● ● ● ● BP - Registro a 16bit (Base Pointer), Puntatore di base dello stack. CS - (Code Segment), Contiene l'istruzione di programma da eseguire. DS - (Data Segment), Contiene dati dell'applicazione. ES - (Extra Segment), Registro aggiuntivo. SS - (Stack Segment), Contiene lo Stack. Dalle architetture del 386 sono stati aggiunti i registri 32bit: EAX, EBX, ECX, EDX, ESI, EDI, EBP. Ci sono altri due registri (spesso utili nel cracking) creati appositamente per la manipolazione delle stringhe: ● ● Il Registro FLAG DI - Registro di Destinazione SI - Registro di Partenza Questo registro viene utilizzato come memoria per l'esecuzione delle istruzioni, ad esempio se si esegue una sottrazzione che da come risultato zero, il FLAG verrà impostato a zero, quindi il 6° bit sarà 1. Bit 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 Descrizione CF Carry Flag 1 PF Parity Flag 0 AF Auxiliary Flag 0 ZF Zero Flag SF Sign Flag TF Trap Flag (Single Step) IF Interrupt Flag DF Direction Flag OF Overflow flag 0 IOPL I/O Privil. Level(286+ only) NT Nested Task Flag (286+ only) 0 RF Resume Flag (386+ only) VM Virtual Mode Flag (386+ only) eWorld ReSearch - Assembler Tutorial Segmenti e OffSets Le vecchie CPU dovevano gestire solo 1 mega di memoria, ma per indirizzare 1Mb di memoria sono necessari 20bit (2^20=1Mb) e noi abbiamo a disposizione solo 16bit; quindi i progettisti Intel hanno introdotto un nuovo tipo di indirizzo costituito da due parti: un SEGMENTO e un OFFSET (16bit ciascuno). Un indirizzo valido è nella forma SEGMENT:OFFSET, gli indirizzi sono in base esadecimale del tipo: 35B2:C02E. Il problema è che questo non è un indirizzo a 20 bit, ma a 32bit; per trovare il vero indirizzo è necessare effettuare due operazioni: moltiplicare il segmento per 10h (16) e sommarlo all'OFFSET. I registri relativi al segmento sono : CS, DS, ES, SS, quindi un segmento è 64K. Il primo programma "Hello World! Come da tradizione partiremo con il programma "Hello World!", tanto per famigliarizzare con l'ambiente di sviluppo e con i primi elementari comandi ASM. Non preoccupatevi se non capite, non è ancora questo lo scopo. ;ASM01.ASM .MODEL small .STACK 100h .DATA MyString DB "Ciauz WoRld",13,10,'$' .CODE mov ax,SEG MyString mov ds,ax mov dx,OFFSET MyString mov ah,09h int 21h mov ah,4Ch int 21h END [bY_ Alessandro Polo 1999] [modello di memoria] [dimensione dello Stack] [inizio del segmento dati] [dichiarazione del Stringa] [inizio del segmento di codice] [ax = indirizzo del Segmento Dati] [ds = ax] [ds = offset del Segmento Dati] [ ah = 09h ] [call all'interrupt DOS] [ ah = 4Ch ] [call all'interrupt DOS] [fine del programma] Questo programmino scriverà sullo schermo il messaggio "Ciauz WoRld", ora analizzaremo più in dettaglio i comandi usati e la struttura del codice: .Model eWorld ReSearch - Assembler Tutorial E' il modello di memoria da utilizzare nel programma, può essere: Large (codice e dati superano i 64Kb), Compact (a differenza dello Small, i puntatori Far possono superare i 64Kb), Medium (il codice può superare i 64Kb), Small (non oltre i 64kb), Tiny (non oltre i 64kb, file .COM). .Stack Spazio riservato per lo Stack (predefinito = 200h =1kb). .Data Sezione dei dati del programma, qui sono assegnati i valori alle costanti. MyString DB "Ciauz WoRld",13,10,'$' Viene assegnato il testo "Ciauz World" alla variabile Message, DB assegna il numero di byte necessari, in tutto 14: 11 per la stringa, 1 per l'invio (#13), 1 per #10 e uno per "$" che deve essere al termine di ogni stringa dichiarata. Nota: Mentre DB assegna un numero di byte, esistono altre direttive come: DW (Define Word), DD (Define Double Word), DQ (Define Quadword), DF (Define 48bit), DT (Define TenByte). .Code Questa sezione è il cuore del programma: il codice sorgente. Gli Interrupt Analizziamo il codice del programma proposto: Istruzione MOV ds,ax Istruzione MOV dx,OFFSET MyString Istruzione MOV ah,09h Istruzione INT 21h Quest'istruzione sposta il contenuto di ax nel data segment. Con quest'istruzione si copia l'offset della variabile (MyString) in dx. (N.B. OFFSET e SEG sono parole riservate.) Modifichiamo il registro ah inserendo il valore esadecimale 09. Chiama l'interrupt 21h per stampare sullo schermo il messaggio. eWorld ReSearch - Assembler Tutorial Istruzione MOV ah,4Ch Istruzione INT 21h Copiamo il valore 4C in ah, spiegherò il motivo di quest'istruzione nella sezione Interrupt. Chiama l'interrupt 21h per terminare il programma. (l'alternativa è resettare il pc) Gli interrupt sono delle funzioni paragonabili alle API di Windows (anche se meno avanzate e comode) del DOS o del BIOS. L'interrupt usato precedentemente è il 21h (fa parte del DOS), per capire il funzionamento è necessario sapere il valore di AH quando l'interrupt viene chiamato (AH è paragonabile alle variabili date alle API). Consultando il manuale in relazione all'interrupt 21h si cerca il valore 09h e si scopre che la funzione è: stampa una stringa nell'output del monitor, la stringa stampata è in DS: DX (infatti c'è il nostro messaggio). Le funzioni Interrupt sono salvate nel primo Kbyte di RAM, cioè dall'indirizzo 000h a 3FFh, ogni funzione è di 4 byte, quindi è possibile calcolare dove si trovi ogni interrupt in memoria: 4(byte) * 21h (interrupt) = 84h (indirizzo in memoria). Secondo Esempio Questo programma è molto simile a quello precedente nel senso che ha lo stesso fine: stampare qualcosa sullo schermo. ;ASM02.ASM SEG_A SEGMENT ASSUME CS:SEG_A, DS:SEG_A ORG 100H Ciauz PROC FAR PARTENZA: JMP START MyString DB "Ciauz WoRld",13,10,'$' START: mov dx,OFFSET MyString mov ah,09h [bY_ Alessandro Polo 1999] [salta a START] [dichiarazione del Stringa] [ds = offset del Segmento Dati] [ah = 09h] eWorld ReSearch - Assembler Tutorial int 21h RETN Ciauz ENDP SEG_A ENDS END PARTENZA [chiamata l'interrupt] Rispetto all'esempio precedente qui manca il Data Segment e lo Stack Segment. D'altra parte questo non è un EXE ma un COM ed infatti è necessario specificarlo al momento del"linking". Le Funzioni La call: message db 'Ciauz WoRld','$' mov dx, offset message call DisplayString La Routine: DisplayString: mov ax,cs mov ds,ax mov ah,9 ; DOS FUNCTION: display message int 21h ; Call the DOS interruptmov ah, ret eWorld ReSearch - Assembler Tutorial Linker, OBJ e file EXE Una volta terminato di scrivere il programma ASM e salvato il file xxx.ASM, è necessario prima compilare il programma e poi linkarlo; compilando il programma verrà creato un file oggetto (. OBJ) che deve essere linkato per creare il vero e proprio eseguibile. Il file risultante è apparentemente un ammasso di caratteri ASCII senza senso, ma in realtà esiste una relazione tra il file EXE e il codice ASM, infatti è anche possibile tornare dall'eseguibile al sorgente tramite un Disassemblatore oppure un Debugger (questo permette anche di modificare le istruzioni in Runtime cioè mentre il programma stà funzionando). Ad esempio l'istruzione JNE X8(Jump if Not Equal) ha come valore 75cb, quando si vuole patchare un programma, cioè modificare l'eseguibile per aggirare uan protezione (ad esempio) è necessario aprire il file e cambiare alcuni valori di questi caratteri ASCII (potremmo semplicemente modificare 75 a 74 per esempio). Comunque tratterò questi argomenti in altra sede. All trademarks are property of their respective owners. Any tools listed and available in zip package is free and was downloaded from the Internet. You are authorized to copy, redistribute and print this paper, keeping Author's credits visible and without changing the document's content. Author is not responsible for any consequences or damages related in any way to this material. Last update: 12/1999 ReSearch Home open source 1999 | by Alessandro Polo eWorld Network