Apex AntiCheat - Die kommunizierende Zwiebel
Kommunizieren kann Apex also auch noch! Nur leider noch nicht so ganz mit dem Reverser. Denn in diesem Post geht es um das Netzwerkprotokoll und natürlich wie Apex da mit drin hängt. Es werden aber auch die Apex-Module angeschnitten, die bereits in den letzen Posts Erwähnung fanden.
Ein direkter Mitschnitt von Netzwerktraffic ist schwer möglich, da auf jedes Packet auf eine ganz abscheuliche (und ziemlich schwer nachzuvollziehende) weiße von XOR und Bitshifting-Operationen gequält wird. Daher muss auf andere Wege zurückgegriffen werden, um das Netzwerkprotokoll zu durchschauen. In der CShell-Module finden sich eine Menge netter Strings, wie z.B:
CS_CH_GETUSERID_REQ
Die XRefs von IDA Pro führen auf eine Funktion, in der dieser String verwendet wird. Der interessante Teil beschränkt sich zunächst auf folgende Zeilen:
.text:0069D723 call memcpy .text:0069D728 mov ecx, someGlobalManager .text:0069D72E add [ebp+var_C], esi .text:0069D731 add dword_15BEF24, ebx .text:0069D737 mov eax, [ecx] .text:0069D739 mov eax, [eax+2D8h] .text:0069D73F add esp, 0Ch .text:0069D742 lea edx, [ebp+Dst] .text:0069D748 push edx .text:0069D749 call eax .text:0069D74B mov eax, GlobalILTClient .text:0069D750 add dword_15BEF24, ebx .text:0069D756 mov ecx, [eax] .text:0069D758 mov edx, [ecx+18h] .text:0069D75B push offset aCs_ch_getuseri ; "CS_CH_GETUSERID_REQ" .text:0069D760 push eax ; Args .text:0069D761 call edx
Wie unschwer zu erkennen ist, wird ein statischer Zeiger geladen und dessen Pointer in EAX gespeichert. Dort wird im Anschluss die Adresse einer virtuellen Funktion geladen (ECX + 2D8h) und diese mit einem Argument in EDX aufgerufen. Wie sich später herrausstellt ist in EDX das eigentliche Packet gespeichert. Im Anschluss wird nochmals eine virtuelle Funktion geladen und aufgerufen, dieses mal allerdings zu Logzwecken. Wie können wir uns das zu nutze machen? Wir hooken beide Funktionen und loggen so alle Packete die Packetnamen in ein Logfile. Und das alles, bevor irgendetwas verschlüsselt wird .
Ein solcher Packet-Dump ist leider auf den ersten Blick nicht sehr aufschlussreich:
12:49:21 Packet logged! PacketPtr: 0x18d4f0 PacketID: 0x4014 Packet Size: 0 1 Size2: 8 SIZE AND: 0 Addr Size 2: 0x18d4f0 12:49:21 Packet Data FIRST 16: 0x00000000 14 40 14 89 db 1a c0 80 .@...... 0x00000008 20 00 00 00 01 00 00 00 ........ 12:49:21 Packet Data: 12:49:22 Logged SendClientRequest: Caller: 0x1b432e38 Size: 6. Data: 0x00000000 01 63 10 ff 05 00 .c.... 12:49:21 LOG: CS_IN_ITEMPRICE_VERSION_REQ 2:49:21 Packet logged! PacketPtr: 0x1b38ca18 PacketID: 0xe12 Packet Size: 0 256 Size2: 40 SIZE AND: 32 Addr Size 2: 0x3449f364 12:49:21 Packet Data FIRST 16: 0x00000000 20 0e 12 20 20 20 20 20 ........ 0x00000008 01 1b 00 00 00 01 2e 08 ........ 12:49:21 Packet Data: 0x00000000 00 00 06 6d 61 69 6e 20 ...main. 0x00000008 73 6c 65 65 70 20 65 72 sleep.er 0x00000010 72 3a 31 35 37 38 00 00 r:1578.. 0x00000018 00 00 00 00 00 00 00 00 ........ 12:49:21 LOG: CS_CK_SENDAPEX_CLIENTINFO_REQ
Der Packet-Header setzt sich aus einem unkekanntem Byte, einer PacketID (WORD) und auch einer encodierten Packetgröße (DWORD) zusammen. Im Anschluss folgen die Daten. Zuordnen können wir also zunächst nur die PacketID. Diese ist bei einem “CS_CK_SENDAPEX_CLIENTINFO_REQ”-Packet 0x120E. Bei SENDAPEX_CLIENTINFO läuten bei uns alle Alarmglocken. Was hat Apex mit dem internen Netzwerkprotokoll von Wolfteam zu tun?
Ein Netzwerkdump von ausschließlich dieser Packete lässt zumindest zwei Arten von Packeten erkennen:
0x00000000 01 9e 08 ff 00 00 04 43 .......C 0x00000008 51 12 a8 26 f3 6c b5 b8 Q..&.l.. 0x00000010 ed 55 9a c9 fd 2e d1 4a .U.....J [.... ] 0x00000000 01 d8 10 ff 00 00 ...... 0x00000000 01 67 a1 ff 00 00 9d ea .g...... 0x00000008 7f 7e 43 3c 9b c4 fe 2a ~C<...* 0x00000010 b2 85 2d 53 c0 05 a9 92 ..-S.... [.......] 0x00000000 01 aa 10 ff 01 00 ...... 0x00000000 01 3c 10 ff 02 00 .
Alle Apex-Packete scheinen mit 01 zu beginnen, im Anschluss folgt ein Byte welches vermutlich für die Verschlüsselung verwendet wird. Die kleinen Packete werden nun alle von 0×10 0xff gefolgt und diese wiederrum von einem Packet-Zähler.
Wie sieht die Strategie eines Reversers aus, der keine Ahnung hat wie man nun weitermachen sollte? Parameter ändern! Wenn das Packet ein “großes” Datenpacket ist, so änderte ich ein einzelnen Byte mitten im Packet. Nunja, die Belohnung war ein Apex Kick. :/ Und was passiert, wenn man diese Packete einfach herrausfiltert und blockt? Der Server scheint sich daran zunächst nicht zu stören. Doch nach 3 Minuten folgt dann doch der Apex Kick, keine Packte zu senden fällt also auch raus.
Bleibt wohl nichts anderes übrig als des Pudels Kern zu suchen. Beim Server-Connect wird im Hintergrund zwei mal Speicher von stattlicher Größe reserviert. Hineingeschrieben wird Code, welcher irgendwie aus der ACDC.dat entschlüsselt wird. Genannt habe ich die beiden Module nach ihrem “Sinn”, einmal ein großes Scanner-Modul und einmal ein kleineres Modul “Starter”-Module welches 5 Threads startet (Wahrscheinlich wird auf 5 verschiedene Methoden überwacht). Von hier werden auch die Apex Packtete gesendet. Nur zurückverfolgen lassen die sich schwer. Die Scanner Module selbst scheinen mehr Daten zu sammeln, als richtige Checks durchzuführen. Und diese gesammelten Daten werden an den Server geschickt.
Fest steht: Wir können nicht eindeutig sagen, wann Apex kickt. Denn Apex sendet keine “Kick”-Request, sondern schickt fleißig Daten, die auf dem Server ausgewertet werden. Keine gute Nachricht für uns. Aber immerhin wissen wir jetzt, womit wir es zutun haben. Wir müssen uns also darauf fokusieren, wann der Server die gesendeten Daten nicht mag. Mehr zum umgehen dieser Sachen gibt es im nächsten Post.
Easy
Noch keine Kommentare vorhanden.