MW2 Bot Singleplayer - TakeDamage Hook
Scrollt man in IDA Pro durch die Strings von Modern Warefare 2, so findet man einige nette (und manchmal auch verwirrende) Sachen. So fiel folgender String ins Auge:
.rdata:006CD724 00000021 C ERROR: kill failed for entity %d
Daraus folgt, dass der Befehl zum Töten einer Einheit ein paar Befehle vorher folgte. Und genau da begegnen wir der Funktion, die ich sinniger Weise “TakeDamage” getauft habe. Der Aufbau setzt sich wie folgt zusammen:
char __cdecl TakeDamage(Entity* target, Entity* shooter1, Entity* shooter2, void* unknown1, void* unknown2, int Damage, int nullData, int Flag1, int Flag2, int Flag3, int Flag3) |
Nunja, die ersten Versuche mit der Funktion irgendetwas zu erreichen waren ernüchternd. Scheinbar kann die Funktion nicht aus dem EndScene-Hook gecalled werden (falscher Thread?) und auch die Parameter scheinen ziemlich willkürlich zu sein. Die Funktion selbst ist riesig und daher ungeeignet zum Analysieren. Aber hey, wieso nicht mal Hooken? So bekommt man schön alle Parameter ohne diese sich aus dem Stack zu kramen und kann auch gescheites Logging betreiben. Gesagt getan, der Funktionsprototyp wurde geschrieben und gleich eine kleine Umleitung (Detour) eingebaut:
oTakeDamage = (char (__cdecl*)(int, int, int , int , int , int , int , int , int , int , __int64))DetourFunction((PBYTE)0x00492260,(PBYTE)hTakeDamage); |
Der Detour funktionierte auf Anhieb! Doch was fängt man mit einem solchen Detour nun an? Das leichteste und naheliegenste ist natürlich folgender Code:
if (target == (int)EntityManager::GetPlayer()->entityOld) { return oTakeDamage(target, Normally_two, use_NULL, USE_NULL3, Use_NULL2, 0, a7, USE_ELEVEN, USE_NULL, NOT_19, a11); } return oTakeDamage(target, Normally_two, use_NULL, USE_NULL3, Use_NULL2, 13337, a7, USE_ELEVEN, USE_NULL, NOT_19, a11); |
Hier wurde einfach geprüft ob die “TargetEntity” der eigene Spieler ist. Wenn ja, so wurde die Funktion mit allen originalen Argumenten aufgerufen, bis auf den Schaden. Dieser wird auf 0 gesetzt wenn ich getroffen werde, 13337 bekommen aber Gegner wenn sie Schaden von mir erhalten. So waren alle Schüsse ab jetzt “OneShotKills” und der Spieler befand sich im Godmode. Der Schaden dieser Funktion bestimmt wohl auch welche Sterbeanimation die Gegner abspielen. Bei diesem hohen Schaden denkt die Engine wohl, die Schüsse seien von einem Sniper abgegeben worden und die Gegner fliegen dementsprechend weg. Das betrifft übrigens nicht nur Gegner, sondern auch explodierende Autos und sogar Helikopter
Lustig ist auch den Schaden einfach umzubiegen. Wir prüfen wieder ob der Spieler den Schaden erhält und setzen als neues Target den Schadensurheber. Sobald Gegner auf mich schießen fallen sie angeschossen zu Boden. Wenn Gegner auf den Spieler zustürmen um eine Nahkampfattack auszuführen und dann zu Boden fallen sieht das in der Tat lustig aus Und die so verhassten Hunde sterben selbst, nachdem sie dem Spieler eigentlich die Kehle durchgebissen haben. Was für ein Genuss!
Mit dieser Funktion ist es auch ein leichtes einfach alle Gegner auf einmal zu töten. Da hört der (Spiel)Spass aber spätestens auf.
Greez Easy