0815 GetProcAddress Hacks
« | 06 Jan 2021 | »Wenn ich mich nicht irre, habe ich etwas Ähnliches schon bei der Einführung von Windows Phone 8 gelesen:
Eigentlich gesperrte API Funktionen sind per
GetProcAddress()
erreichbar.
Es geht dabei um APIs die Microsoft in den SDKs für bestimmte Plattformen deaktiviert bzw ausgeschlossen hat. Früher war das beim Windows Phone so, heute sind das allgemein “Store Apps” oder andere UWP Konstellationen.
In Desktop Apps kann man per
LoadLibrary ()
und GetProcAddress()
quasi alles laden und danach ausführen. In Verbindung mit
CreateRemoteThread()
konnte also jeder Virus sich
selbst in bereits laufende Prozesse hineinladen und dort Daten ausspähen oder
Blödsinn anstellen.
Kein Wunder also, dass Microsoft dieses aus Kompatibilitätsgründen erhaltene Einbruchwerkzeug wo immer es möglich war deaktivieren wollte. Und die neuen Plattformen ab Windows 8 waren dabei ein guter Kandidat.
Windows Store Apps verfügen daher zwar noch über GetProcAddress()
, doch die
anderen APIs zur Lieferung des HMODULE
Pointers, der für GetProcAddress()
notwendig ist, sind diesen Prozessen nicht zugänglich.
Man findet sie nicht in den Headern und sie fehlen auch in den Lib-Bibliotheken.
Damit kann ein Prozess eigentlich nichts mehr dynamisch nachladen.
(Für Plugins und Ähnliches gibt es das abgespeckte
LoadPackagedLibrary
um DLLs innerhalb einer signierten App laden zu dürfen).
Der Punkt ist also: Hat man ein HMODULE
der implizit geladenen DLLs, könnte
man auch andere Funktionen der Bibliotheken nutzen, die uns das SDK
vorenthalten möchte.
Und dafür gibt es tatsächlich einen bekannten Hack, der so lange funktionieren wird, bis Microsoft die gesamte Windows API aufräumt. Und nachdem das bis Windows 10 nicht passiert wird, wird die Lösung vermutlich noch lange funktionieren:
VirtualQuery()
auf einen Funktionszeiger liefert inAllocationBase
die Adresse zurück, auf die auchHMODULE
normalerweise zeigt.
Das heißt also, nachdem LoadLibrary()
zumeist im gleichen Modul sitzt wie auch
GetProcAddress()
(nämlich kernel32.dll
), hilft uns folgender Hack:
1typedef HMODULE (WINAPI *loader_ptr)(LPCWSTR lpLibFileName); 2MEMORY_BASIC_INFORMATION info; 3 4VirtualQuery(&GetProcAddress, &info, sizeof(info)); 5HMODULE hkernel = (HMODULE)mbi.AllocationBase; 6 7loader_ptr my_loader = GetProcAddress(hkernel, "LoadLibraryW"); 8 9HMODULE injected = my_loader(L"unsupported.dll"); 10FARPROC backdoor = GetProcAddress(injected, "backdoor");
Natürlich kann Windows dann immer noch das Laden innerhalb der Funktionen blockieren bzw. nur nach bestimmten Regeln zulassen. Man kann also nie sicher sein, wann und wo der Hack wirklich funktioniert.
Es gibt aber eine ähnliche Anwendung, die mir recht nützlich erscheint:
Man kann so auch “Nachbarfunktionen” dynamisch Laden, die gar nicht gesperrt
sind und diese Technik versetzt dann ältere Compiler oder ältere SDKs in die
Lage Funktionen einzubinden, die sie offiziell gar nicht unterstützen.
Ein Beispiel: Mit dem Wissen, dass einige WinRT Funktionen in combase.dll
implementiert sind und dort nun auch alte OLE
Routinen liegen, kann man daher “klassisch” linken und dann z.B. per
HMODULE
von CoCreateInstance()
zu RoGetActivationFactory
wechseln.
Dann hätte man nämlich Code, der Windows 7 kompatibel ist und trotzdem unter
Windows 8 / Windows 10 innerhalb eines App-Pakets auf die Windows RunTime
zugreifen könnte.
Der Linker entscheidet dann, was verfügbar ist und der Code kann ohne
Änderungen beide Szenarien abbilden. Das wäre also in statischen Bibliotheken
ein gangbarer Weg, die keine unnötigen bzw. exklusive Abhängigkeiten eingehen
wollen.
Ob das dann sinnvoll ist, ist natürlich eine ganz andere Frage ;)
Aber hey … wir wollen hier schließlich keine “bösen” Pfade beschreiten.