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

4 people like this post.
  1. Noch keine Kommentare vorhanden.

  1. Noch keine TrackBacks.