_  _  _  _  _  _  _  _  _  _
                       / \/ \/ \/ \/ \/ \/ \/ \/ \/ \
                       \ AGGIUNGERE UNA DLL A UN PE /
                       /                            \
                       \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

                             - IL PREAMBOLO -
Autore:    NaGA
Tools:     Hiew, il vostro cervello (sono quasi obbligatori)
Optionals: Un compilatore C (se volete automatizzare la procedura)

                     
                                - L'INTRO -
In principio era il caos, poi arrivarono i cracker, e le cose peggiorarono...


                              - IL PROBLEMA -
Se fate cracking o reversing (perche' i programmi, cosi' come sono, proprio
non vi piacciono) o se siete dei virus coders (perche' siete bastardi dentro)
vi sarete trovati nella situazione di dover chiamare delle API che non erano
state previste al momento dell'assemblaggio del codice che state modificando.
A questo punto i casi sono due:
1)Avete culo e la funzione che vi serve fa cmq parte di un modulo gia' linkato
  a run time (es. kernel32).
2)Siete un po' sfortunati e la funzione che vi serve si trova in una DLL che
  il programma da modificare non usa affatto.

Se ricadete nella prima casistica e' tutto molto semplice: basta dare uno
sguardo al segmento di import o usare l'API GetProcAddress (se non sbaglio
viene mappata sempre, con kernel32) per ottenere l'indirizzo che vi serve.
N.B. Se non avete capito niente di quello che c'e' scritto, fatevi un giro fra
gli altri tutorial sui PE, per chiarire ogni vostro dubbio.

Se invece ricadete nella seconda casistica (quella degli sfigati) le cose si
complicano un po'. L'header del segmento di Import non si puo', infatti,
modificare.
O almeno e' quello che ci vuole far credere il caro zio Bill...


                 
                               - LA SOLUZIONE -
La soluzione e' quanto mai banale, e il fatto di non aver trovato nessun
tutorial in proposito, probabilmente e' dovuto alla mia incapacita' nell'usare
i motori di ricerca.

Il suddetto header e' indirizzato da una dword che si trova all'offset 0x80
dall'inizio dell'header PE (che dovrebbe corrispondere allo 0x100 dall'inizio
del file). Quello che dovremo fare e' spostare l'header da un altra parte,
aggiungere una entry relativa alla DLL che ci serve, e modificare la dword
a 0x100 per farla puntare al nostro nuovo header. A questo punto potremo
inserire delle nuove entry per le funzioni che ci servono (magari proprio al
posto del vecchio header) o usare GetProcAddress per avere tutti gli indirizzi
utili.

E' probabile che a questo punto sarete molto confusi, quindi rivediamo tutto
passo passo.

-In Teoria.
L'header del segmento di import e' formato da una serie di entries e termina
con una entry vuota.
Ogni Entry ha la seguente struttura:
   ________________________________
  |                                |
  | DD - Name LookUpTable    (+0)  |
  | DD - UNUSED              (+4)  |
  | DD - UNUSED              (+8)  |
  | DD - Import Name         (+12) |
  | DD - Address LookUpTable (+16) |
  |________________________________|

La dword a +12 punta ad una stringa (NULL terminated) che rappresenta il nome
               della DLL da importare.
La dword a +0  punta alla tabella dei nomi.
La dword a +16 punta alla tabella degli indirizzi.

La tabella dei nomi altro non e' che una serie di indirizzi a stringhe che
rappresentano le funzioni della DLL che ci interessa usare.
Ogni stringa comincia con una word (usata per distinguere fra selezione
per nome o per numero, ma questo e' un'altra storia) e termina con un NULL.
La tabella finisce con un indirizzo nullo.

La tabella degli indirizzi verra' riempita al momento dell'esecuzione con gli
offset delle corrispondenti funzioni richiamate.


Es: Prendiamo HyperTerminal (dovreste avercelo tutti). Apritelo con Hiew. 
    Premete F8 (per avere l'header) e poi F7 (per avere le informazioni di
    import/export). Selezionate Import. Dovreste vedere quanto segue...

    HYPERTRM.EXE  R     PE.00025000     --------     6144 ¦ Hiew 6.04 (c)SEN
.00025000:  7C 50 00 00-80 4F 50 2A-FF FF FF FF-66 51 00 00  |P  ÇOP*    fQ
.00025010:  C0 50 00 00-64 50 00 00-9E 4F 50 2A-FF FF FF FF  +P  dP  ×OP*    
.00025020:  A0 51 00 00-A8 50 00 00-70 50 00 00-A0 1C 0C 32  áQ  ¿P  pP  á2
.00025030:  FF FF FF FF-D4 51 00 00-B4 50 00 00-00 00 00 00      ÈQ  ¦P
.00025040:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

    Questo e' l'header. La prima dword puntera' alla Tabella dei 
    nomi. Riordinando i byte e aggiungendo ImageBase (in questo caso 
    0x00020000) avremo il suo indirizzo: 0x2507C
    Se andiamo a questo indirizzo potremo vedere le seguenti righe...

.00025070:  C2 51 00 00-AE 51 00 00-00 00 00 00-52 51 00 00  -Q  «Q      RQ
.00025080:  44 51 00 00-24 51 00 00-34 51 00 00-0A 51 00 00  DQ  $Q  4Q   Q
.00025090:  02 51 00 00-F4 50 00 00-18 51 00 00-74 51 00 00  Q  ¶P  Q  tQ

    Questo e' l'inizio della tabella dei nomi. Il primo elemento ad esempio 
    (a 0x2507C) punta a 0x25152. Andando a questo indirizzo troveremo...

.00025150:  00 00 25 02-5F 65 78 63-65 70 74 5F-68 61 6E 64    %_except_hand
.00025160:  6C 65 72 33-00 00 4D 53-56 43 52 54-32 30 2E 64  ler3  MSVCRT20.d

    Il nome della funzione!

    Se riguardate l'header dovreste anche vedere dove inizia la tabella degli 
    indirizzi (0x250C0). A RunTime l'indirizzo di _except_handler3 vi verra'
    caricato proprio a 0x250C0. Cioe' l'indirizzo della prima funzione nel 
    primo elemento, quello della seconda nel secondo elemento e cosi' via.

N.B. Tutti gli indirizzi sono RVA e ad essi va sommato ImageBase.
Questo porta a qualche calcolo in piu', ma ci garantisce una perfetta 
rilocabilita' dell'header.

-In Pratica
Facciamo finta di voler usare ShellExecuteA in un prog che non linka shell32
(es. HyperTerminal)

1) Leggete la dword a 0x100. Questo e' l'inizio dell'header di import.
Portatevi a tale indirizzo: 0x25000 (ricordatevi di sommare ImageBase). 
Cominciate a copiare tutto quello che c'e', a blocchi di 20 byte, 
in una zona vuota del file (o, se vi piace di piu', in un nuovo segmento
che vi sarete creati). Quando incontrate una entry che ha l'ImportName 
nullo fermatevi, perche' l'header e' finito (in questo caso ci sono solo 3 
entries).

In C sarebbe:
---------------------------------------------------------------------------

//Trasforma l'RVA in indirizzo fisico
DWORD Where=ImportOffS-ImRVA+ImAdd; 
fseek (ffileS,Where, SEEK_SET);
fseek (ffileD,BlankSpace, SEEK_SET); 
for(;;)
{
	fread(buff,1,20,ffileS);
	// Se trova una entry nulla finisce
	if ( *((DWORD *)&buff[12])==0) break;
	fwrite(buff,1,20,ffileD);		
}

dove
ImportOffS e' l'indirizzo a 0x100.

ImRVA e' l'RVA del segmento di import (lo trovate nell'header dei segmenti,
        o con lo HIEW premendo F8 e poi F6); in questo caso vale 0x5000

ImAdd e' l'indirizzo fisico del segmento di import; in questo caso vale 0xA00.

BlankSpace e' una zona vuota del file.

ffileS e ffileD rappresentano il file originale e il file modificato.
----------------------------------------------------------------------------




2) Rimpiazzate l'header con le informazioni che vi servono.
Es:
----------------------------------------------------------------------------
   DWORD Where=ImportOffS-ImRVA+ImAdd;                 // Sovrascriviamo 
   fseek (ffileD,Where, SEEK_SET); 		       // il vecchio header

   fprintf(ffileD,"SHELL32.DLL"); fputc(0x00,ffileD);  // Nome del modulo 
                                                       // da caricare
   fputc(0x72,ffileD);                                 // Id per la funzione
   fputc(0x00,ffileD);                                 //  "  "   "  "
   fprintf(ffileD,"ShellExecuteA");fputc(0x00,ffileD); // Nome della funzione

   DWORD Stuff=ImportOffS+12;   // Puntatore alla stringa
   fwrite(&Stuff,4,1,ffileD);   // "ShellExecuteA" con l'Id

   fputc(0x00,ffileD); // Per marcare la fine della NameTable
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);

   fputc(0x00,ffileD); // AddressTable
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);

   fputc(0x00,ffileD);
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);
   fputc(0x00,ffileD);
-----------------------------------------------------------------------------

A questo punto, al posto del vecchio header, avremo il nome della DLL 
(a ImportOffs+0), il nome della funzione che ci serve (a ImportOffs+12) 
e il puntatore (a ImportOffs+28) alla stringa a ImportOffs+12. Quest'ultimo, 
in realta', rappresenta la tabella dei nomi con un unico elemento 
(cioe' il puntatore alla stringa ShellExecute) e che termina con
una entry nulla:

.00025000:  53 48 45 4C-4C 33 32 2E-44 4C 4C 00-72 00 53 68  SHELL32.DLL r Sh
.00025010:  65 6C 6C 45-78 65 63 75-74 65 41 00-0C 50 00 00  ellExecuteA P
.00025020:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

N.B. Per sapere qual'e' l'Id della funzione vi conviene cercarlo in un altro 
prog che la usi (di ShellExecuteA e' 0x7200)!



3) Aggiungete una entry all'header spostato. 
Riposizionatevi alla fine dell'header copiato e partite!

Es:
--------------------------------------------------------------
        Stuff=ImportOffS+28;
        fwrite(&Stuff,4,1,ffileD);      // Puntatore alla NameTable

        Stuff=0x00000000;               
        fwrite(&Stuff,4,1,ffileD);      // Vuoti
        fwrite(&Stuff,4,1,ffileD);

        fwrite(&ImportOffS,4,1,ffileD); // Puntatore al nome della libreria

        Stuff=ImportOffS+36;            // Puntatore alla AddressTable
        fwrite(&Stuff,4,1,ffileD);
---------------------------------------------------------------

Quindi, il nostro header adesso contiene una nuova entry composta cosi'

DD - Puntatore alla NameTable (che ha un unico elemento che punta alla stringa
                               Id+"ShellExecuteA")
DD - Vuoto
DD - Vuoto

DD - Puntatore alla stringa "shell32.dll" (cioe' il nome della libreria)

DD - Puntatore alla AddressTable (cioe' l'offset che a RunTime conterra'
                                  l'indirizzo di ShellExecuteA)

N.B. Ricordatevi di aggiungere una entry (20 byte) nulla per chiudere 
l'header.

Avrete (supponendo che il nosto BlankSpace inizi a 0x257A0) :

-vecchio header spostato
.000257A0:  7C 50 00 00-80 4F 50 2A-FF FF FF FF-66 51 00 00  |P  ÇOP*    fQ
.000257B0:  C0 50 00 00-64 50 00 00-9E 4F 50 2A-FF FF FF FF  +P  dP  ×OP*    
.000257C0:  A0 51 00 00-A8 50 00 00-70 50 00 00-A0 1C 0C 32  áQ  ¿P  pP  á2
.000257D0:  FF FF FF FF-D4 51 00 00-B4 50 00 00-00 00 00 00      ÈQ  ¦P
.000257E0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

-nuova entry
.000270F0:  1C 50 00 00-00 00 00 00-00 00 00 00-00 50 00 00  P           P
.00027100:  24 50 00 00-00 00 00 00-00 00 00 00-00 00 00 00  $P
.00027110:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00027120:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00


4) Modificate il puntatore all'header e la sua dimensione.

Andate all'offset 0x100 e fatelo puntare al vostro nuovo header 
L'indirizzo deve essere RVA (senza pero' ImageBase). Per ottenere l'RVA
prendete l'offset fisico del vostro header (BlankSpace), sottraeteci l'offset
fisico del segmento dove si trova, e sommateci l'RVA (sempre del segmento
dove si trova).

Poi spostatevi all'offset 0x104 e sommate 0x14 al valore che trovate.
In realta' state ingrandeno l'header di 20 byte (cioe' la dimensione
dell'entry che avete aggiunto).
Questa operazione sembra non servire a niente, ma non si sa mai.


5) Richiamate ShellExecuteA.
A RunTime la dword a ImportOffS+36 (cioe' a 0x25024) verra' riempita con 
l'indirizzo di ShellExecuteA, quindi vi bastera' fare una call reindirizzata 
a ImportOffS+36. Infatti ora shell32 sara' mappata nel vostro spazio di 
indirizzamento!!!!

Per callare basta inserire, dove vi serve, il codice

  FF 15     24 50 02 00
^^call^^   ^^indirizzo^^
 
per richiamare ShellExecuteA =)

Visto che non era tanto difficile?

N.B. FF15 fa una call all'indirizzo contenuto nell'offset che riceve come 
parametro.


                            - I RINGRAZIAMENTI -
Ho fatto praticamente tutto da solo, quindi l'unico che mi sento di 
ringraziare veramente e' il mio vecchio compagno di coding-hacking-cracking 
R@Nc0r.


                               - I SALUTI -
Saluto tutti i miei amici ed in particolar modo |LnZ| e ALoR (RingZer0), 
10t80r (NeuroZone2) e PeSy (Casa mia). Inoltre saluto tutti i membri di 
RingZer0, che spero di conoscere al prossimo HackIt.
Non saluto i bastardi che fanno i tutorials sbagliati, i miei professori
dell'uni, le tipe che se la tirano.


                              - LA MASSIMA -
Non so se, quando cambieranno, le cose saranno migliori....ma so che, se
voglio che siano migliori, devono cambiare.


                               - LA MINIMA -
Durante la notte 12 gradi centigradi nella zona di MilanoLambrate.


(la signature la dovete guardare con l'Edit di MS-DOS, altrimenti si vede
 la seguente schifezza...)

                     ° ± ² ± °              ° ± ² ± °
                     °±±±²±±±°              °±±±²±±±°
                     \°°°±°°°/              \°°°±°°°/ 
                      °±±²±±°                °±±²±±°
                      °±±²±±° |   |     /    °±±²±±°
                      °±±²±±° | \ |    / _\  °±±²±±°
                      °±±²±±° |_ \_ aG/_  /_ °±±²±±°
                     _°±±²±±°_             __°±±²±±°_