Se quello che avete letto in
http://www.sciax2.it/forum/c-c/c-sulle-dll-453824.html#post2873233
vi è chiaro, allora possiamo fare un passo avanti.
Supponiamo di conoscere la firma della funzione ma di non avere una Import Library (una .lib) da indicare al linker per potere individuare l'entry point della stessa all'interno della DLL. Oppure (ed è il motivo più importante) di voler lavorare dinamicamente, chiamando le funzioni che più ci interessano secondo particolari esigenze.
Dico che è il più importante perché ha risvolti pesanti nel campo di virus e malware particolarmente pericolosi (rootkit).
Infatti, per utilizzi standard, la "Import Library" è ottenibile a partire dalla DLL (tramite i comandi DUMPBIN e LIB che avrete a disposizione se avete installato Visual Studio), secondo procedure semplici e documentate.
Diverso il discorso se manca la firma della funzione (ricordo, nome, valore restituito, numero e tipo di parametri) perché in quel caso non c'è modo di ottenere tali informazioni dalla DLL e si deve ricorrere al reverse engineering.
Tornando all'utilizzo dinamico delle funzioni delle DLL, Windows mette a disposizione (da sempre) alcune API specifiche, ovvero
La prima e la seconda funzione sono utilizzate per ottenere un riferimento (sostanzialmente l'indirizzo virtuale a partire dal quale la DLL che ci interessa è caricata in memoria) con la differenza che la prima (LoadLibrary) legge dal disco e carica in memoria la DLL se questa non è già caricata (e altre cose minori) mentre la seconda (GetModuleHandle) si attende che la DLL sia già stata caricata in memoria e mappata nello spazio di indirizzamento del processo e ne ottiene l'indirizzo.
Se la DLL è di tipo custom (una vostra DLL) o non è tra quelle più utilizzate, allora si rende necessario usare la LoadLibrary.
Ma se la DLL è una tra quelle più comuni (e usate praticamente da tutti i processi), come ntdll.dll o kernel32.dll, allora basta la GetModuleHandle.
A questo punto, il programma dell'esempio precedente diventa
con le linee aggiunte/modificate in rosso che vediamo in dettaglio
1) con la typedef creiamo un nuovo tipo di dato (puntatore a funzione che restituisce un valore NTSTATUS e che non accetta parametri) che descrive la "firma" della funzione che intendiamo richiamare
2) dichiariamo una variabile di nome DynamicGetVersion (o quello che meglio ci pare) che sarà un puntatore a funzione del tipo appena dichiarato. In pratica, essendo un puntatore, conterrà l'indirizzo della nostra funzione (appena ce lo scriveremo ...)
3) otteniamo l'indirizzo in memoria della dll kernel32.dll nella variabile hDll tramite la GetModuleHandle
4) inseriamo l'indirizzo della GetVersion nel puntatore a funzione, a partire da quello della kernel32.dll, tramite la GetProcessAddress. A questo punto la variabile DynamicGetVersion contiene l'indirizzo della funzione GetVersion
5) utilizziamo il puntatore per richiamare la funzione esattamente come se l'indirizzo l'avessimo ottenuto staticamente.
Per capire meglio, modifichiamo il codice per visualizzare qualche dato e fare qualche prova, ovvero aggiungiamo le linee in rosso dopo quelle indicate
e otterremo a video delle linee simili (gli indirizzi possono variare da sistema a sistema)
kernel32 base: 0x7C800000
GetVersion address: 0x7C81127A
che indicano dove è posizionata la DLL in memoria e dove, al suo interno, inizia la API GetVersion (ricordate sempre che sono indirizzi virtuali).
Per capire ancora bene come l'indirizzo sia quello effettivamente utilizzato dal programma, commentiamo la linea
// DynamicGetVersion = (PF_DynamicGetVersion) GetProcAddress( hDll, "GetVersion" );
in modo che il valore in DynamicGetVersion sia 0. Avremo
kernel32 base: 0x7C800000
GetVersion address: 0x00000000
e ovviamente, essendo diventato un puntatore NULL, l'utilizzo di DynamicGetVersion nella chiamata causerà un errore di tipo
Unhandled exception at 0x00000000 in <vostro_eseguibile>: 0xC0000005: Access violation reading location 0x00000000.
e il programma si bloccherà (non sapendo dove sia la funzione da eseguire) confermando che è proprio la GetProcAddress che fornisce l'indirizzo della funzione al programma e non la Import Library.
Spero che quello che ho scritto vi sia chiaro (o almeno non troppo oscuro ... ). Anche questa volta, se avete dubbi esprimeteli e commentate ... la prossima volta, discuteremo di un esempio più concreto di chiamata dinamica di funzioni da DLL ...
http://www.sciax2.it/forum/c-c/c-sulle-dll-453824.html#post2873233
vi è chiaro, allora possiamo fare un passo avanti.
Supponiamo di conoscere la firma della funzione ma di non avere una Import Library (una .lib) da indicare al linker per potere individuare l'entry point della stessa all'interno della DLL. Oppure (ed è il motivo più importante) di voler lavorare dinamicamente, chiamando le funzioni che più ci interessano secondo particolari esigenze.
Dico che è il più importante perché ha risvolti pesanti nel campo di virus e malware particolarmente pericolosi (rootkit).
Infatti, per utilizzi standard, la "Import Library" è ottenibile a partire dalla DLL (tramite i comandi DUMPBIN e LIB che avrete a disposizione se avete installato Visual Studio), secondo procedure semplici e documentate.
Diverso il discorso se manca la firma della funzione (ricordo, nome, valore restituito, numero e tipo di parametri) perché in quel caso non c'è modo di ottenere tali informazioni dalla DLL e si deve ricorrere al reverse engineering.
Tornando all'utilizzo dinamico delle funzioni delle DLL, Windows mette a disposizione (da sempre) alcune API specifiche, ovvero
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
Perfavore,
Entra
oppure
Registrati
per vedere i Link!
La prima e la seconda funzione sono utilizzate per ottenere un riferimento (sostanzialmente l'indirizzo virtuale a partire dal quale la DLL che ci interessa è caricata in memoria) con la differenza che la prima (LoadLibrary) legge dal disco e carica in memoria la DLL se questa non è già caricata (e altre cose minori) mentre la seconda (GetModuleHandle) si attende che la DLL sia già stata caricata in memoria e mappata nello spazio di indirizzamento del processo e ne ottiene l'indirizzo.
Se la DLL è di tipo custom (una vostra DLL) o non è tra quelle più utilizzate, allora si rende necessario usare la LoadLibrary.
Ma se la DLL è una tra quelle più comuni (e usate praticamente da tutti i processi), come ntdll.dll o kernel32.dll, allora basta la GetModuleHandle.
A questo punto, il programma dell'esempio precedente diventa
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
con le linee aggiunte/modificate in rosso che vediamo in dettaglio
1) con la typedef creiamo un nuovo tipo di dato (puntatore a funzione che restituisce un valore NTSTATUS e che non accetta parametri) che descrive la "firma" della funzione che intendiamo richiamare
2) dichiariamo una variabile di nome DynamicGetVersion (o quello che meglio ci pare) che sarà un puntatore a funzione del tipo appena dichiarato. In pratica, essendo un puntatore, conterrà l'indirizzo della nostra funzione (appena ce lo scriveremo ...)
3) otteniamo l'indirizzo in memoria della dll kernel32.dll nella variabile hDll tramite la GetModuleHandle
4) inseriamo l'indirizzo della GetVersion nel puntatore a funzione, a partire da quello della kernel32.dll, tramite la GetProcessAddress. A questo punto la variabile DynamicGetVersion contiene l'indirizzo della funzione GetVersion
5) utilizziamo il puntatore per richiamare la funzione esattamente come se l'indirizzo l'avessimo ottenuto staticamente.
Per capire meglio, modifichiamo il codice per visualizzare qualche dato e fare qualche prova, ovvero aggiungiamo le linee in rosso dopo quelle indicate
Codice:
Perfavore,
Entra
oppure
Registrati
per vedere i codici!
e otterremo a video delle linee simili (gli indirizzi possono variare da sistema a sistema)
kernel32 base: 0x7C800000
GetVersion address: 0x7C81127A
che indicano dove è posizionata la DLL in memoria e dove, al suo interno, inizia la API GetVersion (ricordate sempre che sono indirizzi virtuali).
Per capire ancora bene come l'indirizzo sia quello effettivamente utilizzato dal programma, commentiamo la linea
// DynamicGetVersion = (PF_DynamicGetVersion) GetProcAddress( hDll, "GetVersion" );
in modo che il valore in DynamicGetVersion sia 0. Avremo
kernel32 base: 0x7C800000
GetVersion address: 0x00000000
e ovviamente, essendo diventato un puntatore NULL, l'utilizzo di DynamicGetVersion nella chiamata causerà un errore di tipo
Unhandled exception at 0x00000000 in <vostro_eseguibile>: 0xC0000005: Access violation reading location 0x00000000.
e il programma si bloccherà (non sapendo dove sia la funzione da eseguire) confermando che è proprio la GetProcAddress che fornisce l'indirizzo della funzione al programma e non la Import Library.
Spero che quello che ho scritto vi sia chiaro (o almeno non troppo oscuro ... ). Anche questa volta, se avete dubbi esprimeteli e commentate ... la prossima volta, discuteremo di un esempio più concreto di chiamata dinamica di funzioni da DLL ...