Willkommen zum ersten “richtigen” Teil des MW2 Bots. Hier wird vorallem auf das CLR-Hosting eingegangen und am Ende die Basis-Funktionen und der Hook der zu injectenden DLL erklärt.
Widmen wir uns zu erst dem CLR-Hosting. Die in Teil 0 angesprochene Problematik, managed Code in einem unmanaged Programm auszuführen wird durch das sog. Hosting eines CLR-Interfaces umgangen. Auf Wikipedia gibt es zu dem Thema einen schönen Beitrag und eine noch schönere Grafik:
Doch was ist jetzt dieses ominöse CLR-Hosting? Im Grunde genommen lädt das Programm dazu ein paar .NET DLLs nach, welche uns das Ausführen von managed Code ermöglicht. Und dazu gibt es eine tolle Klasse, welche wir verwenden werden: ICLRRuntimeHost!
[spoiler]
Ich persönlich habe mir einen CLRHelper geschrieben, welcher die einzelnen Abläufe vereinfacht. Hier mal die Header-Datei des CLRHelpers. Denkt daran “MSCorEE.h” einzubinden und “MSCorEE.lib” mitzulinken.
class CLRHelper { public: static void InitCLR(); // Initialisiert das ganze CLRHosting static int ExecuteMethod(char* sName, char* sParam); // Ruft eine Methode aus einer (noch) hardcoded DLL auf static ICLRRuntimeHost* pCLR; // Unsere eigentliche Hostingklasse static DWORD LastResult; // Hier wird der letze Rückgabewert von dem managed Code gespeichert static LPCWSTR CharToWideChar(char* txt); // Da wir WideChar in der Funktion "ExecuteMethod" verwenden müssen, ist hier eine Converterfunktion };
Ich denke die einzelnen Objekte und Methoden brauchen keine weitere Erklärung, daher gleich weiter zur CPP Datei:
void CLRHelper::InitCLR() { CorBindToRuntimeEx(NULL, L"wks", NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pCLR); pCLR->Start(); }
Diese Funktion initialisiert unser Hostingobjekt. Im Grunde bindet diese Funktion die .NET Runtime an den aktuellen Prozess und läd die entspechenden DLLs, wenn nicht schon gesehen. Die genaue Paramter kann man in der Linkliste weiter unten in dem Post finden. Wichtig ist dass die Adresse unsereres Hostingobjekts übergeben wird und dieses somit initialisiert ist.
Im Anschluss wird dann pCLR->Start() aufgerufen, um das Hosting zu starten.
int CLRHelper::ExecuteMethod(char* sName, char* sParam) { pCLR->ExecuteInDefaultAppDomain(L"Z:\GAMEZ\Call Of Duty Modern Warfare 2\MW2_ModLoader_Bots\MW2BotDLLManaged.dll", L"MW2_Bot_DLL_Managed.Main", CLRHelper::CharToWideChar(sName), CLRHelper::CharToWideChar(sParam), &CLRHelper::LastResult); return CLRHelper::LastResult; }
Die Methode “ExecuteInDefaultAppDomain” ruft eine statische Funktion aus einer managed DLL auf, der Rückgabewert wird in LastResult gespeichert.
Die Parameter sehen wie folgt aus:
- Pfad und Dateiname zu der DLL aus der gelesen werden soll
- Der Namespace und die statische Klasse aus der eine Funktion aufgerufen werde. Es MUSS eine statische Klasse sein!
- Der Name der Funktion die aufgerufen werden soll. Diese muss ebenfalls statisch sein, ein Int32 zurückliefern und als einzigen Parameter einen String erwarten.
- Ein Parameter in Form eines Strings, welcher an die Funktion übergeben wird.
Wie ihr seht ist der Pfad z.Z. noch hardcoded, ist z.Z. zu Debugzwecken so eingerichtet.
LPCWSTR CLRHelper::CharToWideChar(char* txt) { size_t newsize = strlen(txt) + 1; wchar_t * wcstring = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wcstring, newsize, txt, _TRUNCATE); return wcstring; }
Hier noch schließlich die Funktion zum Umwandeln eines char-Pointers in ein WideCharString. Die Funktion ist aus dem Internet und u.a. hier zu finden.
Das war schon der ganze CLRHosting Teil. Jetzt möchte ich noch schnell den restlichen Source der zu injectenden DLL erklären. Ich gehe dabei davon aus, dass ihr wisst wie Detours funktionieren Wenn nicht -> Google.
BOOL APIENTRY DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { if(dwReason == DLL_PROCESS_ATTACH) { CreateThread(0, 0, HooK, 0, 0, 0); } return TRUE; }
Was ihr hier seht ist der EntryPoint der DLL. Sobald sie attached ist, wird ein neuer Thread mit unserer Hook-Funktion gestartet. Der Grund, warum dieses in einen Thread geschieht, ist folgender: Wenn kein Thread verwendet wird, so kann dieses in einem Deadlock enden.
Für die folgende Funktion fehlt uns noch die Typedefinierung der die EndScene Funktion. Diese erwartet, wie man sehen kann, keine Parameter.
typedef void ( _cdecl* tRenderShit )(); tRenderShit oRenderShit=0; // Dieses ist unsere originale EndScene Funktion DWORD WINAPI HooK( LPVOID ) { CLRHelper::InitCLR(); // Initialisiert unser CLRHosting CLRHelper::ExecuteMethod("Init","Init"); // Ruft die statische Init-Funktion mit dem Parameter "Init" auf. oRenderShit = (tRenderShit)DetourFunction( ( PBYTE )0x586E00, ( PBYTE )&hRenderShit ); //Diese Funktion hooked schließlich die EndFrame Funktion. Dabei wird die originale Funktion in oRenderShit gespeichert und zu hRenderShit detoured. return 0; }
0x586E00 ist die Adresse, an der die orginale EndFrame-Funktion zu finden ist. Ich verwende die AlterIWNet Version (1.3.3.7++), das entspricht der 1.0.184 der SteamVersion. Zu Detours einfach mal nach “Microsoft Detours” suchen. Ansonsten sollten die Kommentare soweit alles andere beschreiben, daher gleich weiter mit hRenderShit.
void hRenderShit( ) // Die gedetourte Funktion { _asm pushad; // wir sichern alle Register CLRHelper::ExecuteMethod("Run","Test"); // Der CLRHelper ruft die Run-Methode unseres Bots auf __asm popad; // wir stellen alle Register wieder auf den Orginalzustand zurück oRenderShit(); // und schließlich wird die originale EndFrame-Funktion aufgerufen }
Das wars auch schon von dieser relativ “kleinen” DLL. Natürlich wird diese später noch wachsen, aber das ist soweit das Grundgerüst. Damit ist es möglich, dass bei jedem Ende vom einem Spiel-Frame die Run-Methode, welche managed Code ist, aufgerufen wird!
Sollte es Fragen zu diesem Thema geben, so hinterlasst doch einfach ein Kommentar!
Linklist zu managed DLL Injection und Hosting:
- http://www.codingthewheel.com/archives/how-to-inject-a-managed-assembly-dll -> Sehr guter Blogartikel der genau den DLL Injection/Hosting Vorgang. Vorallem das Diagramm ist toll!
- http://www.blizzhackers.cc/viewtopic.php?t=430074 -> Ebenfalls ein tolles, allerdings nicht allzu ausführliches, Managed DLL Injection Tutorial. Lasst euch nicht von dem C# Teil weiter unten irritieren, das kommt nächtes mal dran =)
- MSDN Einleitungsartikel über CLRHosting und eine MSDN Referenz zum Thema CLRHosting
Greez Easysurfer
[/spoiler]