appendice: generazione del codice clandestino
ricordiamoci che il nostro scopo è chiamare LoadLibraryA passandogli l'indirizzo di una stringa situata nel codice stesso, e subito dopo fare un JMP all'entry point originale.
possiamo strutturare il codice come segue:
- PUSH
- CALL
- JMP
- nome del file della DLL
cominciamo dal PUSH, già abbiamo un problema: con una rapida consultatina al manuale Intel vediamo che la versione che dovremmo usare è
PUSH imm32, opcode 0x68 seguito da 4 bytes di valore immediato. calcolare il valore immediato è banale, basta sommare l'RVA della stringa al base address dell'eseguibile; il problema è che avremmo (in teoria) bisogno di un fixup in quel punto... possibili soluzioni?
1) ce ne freghiamo - tanto è un eseguibile, verrà sicuramente caricato al suo base address predefinito, a meno che il programmatore sadico non l'abbia definito come 0x7C800000 (il base address di kernel32.dll) o come >= 0x80000000 (base address in kernel space).
2) pur di essere sicuri di non doverci rilocare spostiamo tutto l'eseguibile al base address standard, 0x00400000

e a dire il vero non è neanche una soluzione tanto difficile: basta rilocare tutto il file utilizzando (0x00400000 - il suo base address) come delta
col PUSH siamo quindi (più o meno

) a posto: iniziamo a scrivere 0x68 e lasciamo 4 byte vuoti perché l'RVA della stringa ancora non lo sappiamo.
ora passiamo al CALL: stavolta, al contrario del caso precedente, se vogliamo usare un valore immediato nella chiamata non abbiamo a disposizione una versione absolute dell'istruzione, ma solo relative; peccato che adesso invece ci serviva proprio la absolute (eccheppalle

).
abbiamo due casi:
1) l'eseguibile importa LoadLibraryA da kernel32.dll
2) l'eseguibile non importa LoadLibraryA
nel primo caso siamo fortunati: dobbiamo usare
CALL r/m32 specificando l'indirizzo della entry relativa a LoadLibraryA nella Import Address Table. non entro in dettagli perché dal manuale non ho capito la codifica di quella versione di CALL ^__^''
nel secondo caso invece, considerando che nello spazio di indirizzamento di qualsiasi processo il base address di kernel32.dll non cambia mai (e quindi neanche l'indirizzo di LoadLibraryA), utilizzeremo
CALL rel32: scriviamo 0xE8 e subito dopo un delta così calcolato:
(indirizzo di LoadLibraryA ottenuto da una GetProcAddress chiamata in qualsiasi processo) - (VA a cui stiamo scrivendo il CALL) - (dimensione del CALL, cioè 5)
e la cosa bella è che qui non ci serve il fixup
andiamo avanti: il JMP. caso analogo: ciò che dobbiamo usare è
JMP rel32, opcode 0xE9 seguito dai 4 bytes di delta così calcolati:
(valore originale del membro AddressOfEntryPoint dell'header principale) - (VA del JMP) - (dimensione del JMP, cioè 5)
dopodiché scriviamo la stringa e a questo punto, conoscendo anche l'RVA della stringa stessa, possiamo ultimare il PUSH iniziale. occhio però: ai 4 bytes immediati del PUSH non dobbiamo scrivere l'RVA, ma il VA (l'RVA sommato al base address predefinito, sperando che sia sempre anche quello effettivo

).