Was macht das?
Es findet die Adresse der Funktion GetProcAddress. Diese kann dann dazu verwendet werden weitere Funktionen (LoadLibrary, ...) zu laden.
Wie funktioniert das?
Windows speichert eine Liste aller geladenen Module (das Programm selber, benötigte DLLs, ...), deren Startelement von der PEB_LDR_DATA Struktur referenziert wird. Die Adresse dieser Struktur befindet sich im Process Enviroment Block (PEB). Ein Zeiger zum PEB befindet sich in fs:[30h].
Danke dieser Vorraussetzungen ist es möglich, die Position von kernel32.dll im Speicher (welche bei verschiedenen Versionen/Servicepacks/Windows Versionen und Relocations variiert und somit nicht hardcoded werden sollte) zu lokalisieren.
Von dort an kann man ganz normal kernel32.dll parsen (--> PE Format) und den ExportTable "durchlaufen".
Dort findet man schlussendlich die RVA (Adresse die relativ zur momentanen Position von kernel32.dll ["ImageBase"] ist).
Zu dieser addiert man dann noch die über den PEB gefundene Adresse von kernel32.dll und schon hat man die Adresse von GetProcAddress, welche man anschließend über Funktionszeiger (ich liebe C :D) aufrufen kann.
Wozu ist das gut?
Import verstecken, Heuristiken austricksen und natürlich einfach zum Spaß :P
Wieso ist das entstanden?
Das ich das implementiert habe ist ursprünglich schon etwas länger her (die originale Version ist in MASM), doch jetzt habe ich das ganze auf Anfrage auch nach C portiert.
int main(void)
{
int i;
int offset;
int ordinal;
int SymbolRVA;
short *ExportOrdinalTable;
int *ExportAddressTable;
int index;
PEB *peb;
PEB_LDR_DATA *pld;
LDR_MODULE *ldrm;
IMAGE_DOS_HEADER *idh;
IMAGE_NT_HEADERS *inh;
IMAGE_EXPORT_DIRECTORY *ied;
GPA _GetProcAddress;
// _GetProcAddress := address of GetProcAddress in kernel32.dll
return 0;
}
Quellen für die Strukturdefinitionen:
Microsoft's MSDN und undocumented.ntinternals.net.
Anmerkung:
In gpa.h finden sich auskommentierte Strukturen. Diese sind da, weil sie für die anderen Strukturen, oder sogar im Programm selber wichtig sind, jedoch bereits definiert wurden.
MSDN sagt z.B., dass die Struktur _PEB bzw. das dazugehörige Typedef in "Winternl.h" definiert sein sollten.
Da MinGW diesen Header jedoch nicht besitzt habe ich mir das Zeug zusammengeschustert und die überflüssigen Strukturen da gelassen, für den Fall, dass jemand diese nicht hat.
MfG. BlackBerry
13.04.2010, 01:21
br00_pwn
Gute Arbeit, Black :)
13.04.2010, 06:10
Bozok
Sehr schön, jedoch würde ich gleich Uppercase('kernel32.dll') nehmen, das war bei mir in Windows 7 der Fall wodurch sowas nicht geklappt hat :/
13.04.2010, 15:04
blackberry
Ich nutze auch Windows 7 und es hat bei mir sehr gut funktioniert.
Dennoch habe ich noch einen kleinen Fehler gefunden und dabei gleich noch ein tolower() bei dem Vergleich der Zeichen eingefügt.
17.05.2010, 22:24
jojoomgasd
dafür muss aber GetProcAddress aber in der ImportTable sein oder?
wenn nicht dann ist das hammer :P
man kann ja auch noch 'GetModuleHandleA' laden und somit alle api's zur laufzeit laden :P
17.05.2010, 23:53
l0dsb
Zur Erwähnen wäre noch, dass diese Vorgehensweise auch sehr oft in Malware (siehe 29A) und Softwareschutzsystemen (ASProtect, EXECryptor, Themida und ähnliche) verwendet wird.
Dort werden aber nicht komplette Funktionsnamen verglichen, sondern lediglich deren Hashes (üblicherweise in dword-Größe). Das mag schneller sein, einleuchtend ist jedoch, dass die Funktionsnamen der gesuchten Funktionen nicht sofort ersichtlich sind. ;)
Zum Vorposter: Nein, GetProcAddress muss nicht in der IT sein, aber kernel32.dll im Speicher. LoadLibrary wäre da auch noch eine Idee, um auch APIs nachladen zu können, deren DLL noch nicht geladen ist.
Ach ja: Ich warte auf ein neues UnpackUs, BlackBerry! :) Hoffentlich mit regerer Beteiligung. :/