Register for your free account! | Forgot your password?

Go Back   elitepvpers > Shooter > S4 League > S4 League Hacks, Bots, Cheats & Exploits
You last visited: Today at 16:04

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Tutorial] Reversing the Client (EP. 1)

Discussion on [Tutorial] Reversing the Client (EP. 1) within the S4 League Hacks, Bots, Cheats & Exploits forum part of the S4 League category.

Reply
 
Old   #1
 
elite*gold: 225
Join Date: Sep 2014
Posts: 334
Received Thanks: 460
[Tutorial] Reversing the Client (EP. 1)

[ Hey guys. I wanna start a new series of tutorials for reversing
the S4 League Game Client since it is very easy. ]

To get started we need a few things set-up:


[0. x86 (intel syntax) asm knowledge and the ability to think logically]
1. Disassembler (I prefer IDA Pro 6.9 with Hex-Rays plugin)
2. Struct Analyzing tool (ReClass 2015 or Cheat Engine)
3. Executable Dumper (Scylla)
4. Fundamental IDA Pro plugins (Class Informer and String Associate Plugin)
5. C++ knowledge for better understanding of the compiler



After that let's first get a fresh dump of the client. Start up the game with a bypass and dump it with scylla once you are in the lobby to make sure everything is initialized. In this episode we are only applying static analysis so we can close the client again and drag the dumped file into ida pro; it will start to analyze the binary which can take about 5-10 minutes with an average pc. You will notice that the IAT and EAT is broken. Of course it'd be better if it wasn't but we don't need it in this episode. Since I have no point to start reversing we will just use strings.

I found an interesting format string that could give us alot of information:

PHP Code:
.text:01A2A3B8 0000006E C %[%s Actor %pTeamID: %I64dActorID: %I64uP2PID:{%d,%d,%d}, StateID0x%X0x%xHP: %d(%d), MP: %d(%d
This string will get us to know the following points:
  • Live status (dead or alive)
  • Spectator or Player
  • Class ptr
  • TeamID
  • ActorID
  • P2PID
  • StateID
  • HP
  • MP

The most useful thing in here is the class ptr. If you got the instance you can reverse it at runtime(ingame) and find really much stuff out.

Let's now reverse some code by going to the cross-reference of the string.
PHP Code:
.text:00AF7B77                 mov     eax, [ebp+var_10]
.
text:00AF7B7A                 push    eax
.text:00AF7B7B                 mov     ecx, [ebp+var_64]
.
text:00AF7B7E                 push    ecx
.text:00AF7B7F                 mov     edx, [ebp+var_60]
.
text:00AF7B82                 push    edx
.text:00AF7B83                 push    offset aSSActorPTeamid "%s [%s Actor %p] TeamID: %I64d, ActorID"...
.
text:00AF7B88                 lea     eax, [ebp+var_A0]
.
text:00AF7B8E                 push    eax
.text:00AF7B8F                 call    sub_168B4C0
.text:00AF7B94                 add     esp48h 
We can immediately identify the calling convention by looking after the call instruction. The stack is cleaned by the caller. Thus it's __cdecl.
(https://en.wikipedia.org/wiki/X86_calling_conventions)


We can also count the arguments that were passed to this function by dividing 48h with 4 and then convert it to decimal. [ATTENTION: for optimization some compilers only use one add instruction and you cant really see if its only cleaning up one call or few)

Now let's continue with finding out what actually is passed to our function.
The first argument is eax which is &var_A0. Sooo find out what var_A0 is:
Scroll up and lookup an instruction that involves var_A0 as operand.
Nothing is being moved(copied) in var_A0 so it's just used as a reference or pointer to fill some value in it(buffer). Second argument is the format string...
Third argument seems to be a string which is passed in edx, whereas edx is var_60. Let's dig deeper.


PHP Code:
.text:00AF7A40 loc_AF7A40:                             ; CODE XREFsub_AF78A0+197j
.text:00AF7A40                 mov     edx, [ebp+var_10]
.
text:00AF7A43                 mov     eax, [edx]
.
text:00AF7A45                 mov     ecx, [ebp+var_10]
.
text:00AF7A48                 mov     edx, [eax+0D4h]
.
text:00AF7A4E                 call    edx
.text:00AF7A50                 movzx   eaxal
.text:00AF7A53                 test    eaxeax
.text:00AF7A55                 jz      short loc_AF7A60
.text:00AF7A57                 mov     [ebp+var_60], offset aLive "Live"
.text:00AF7A5E                 jmp     short loc_AF7A67
.text:00AF7A60 ; ---------------------------------------------------------------------------
.
text:00AF7A60
.text:00AF7A60 loc_AF7A60:                             ; CODE XREFsub_AF78A0+1B5j
.text:00AF7A60                 mov     [ebp+var_60], offset aDeath "Death" 
here's where var_60 is being set. var_10 is probably some player class or actor class. then the address of the virtual table get's copied into eax and it's calling the 53th virtual function of this class (0D4h / 4 to decimal)[basic index calculating]. This function can be compared to
PHP Code:
virtual bool IsAlive() = 0
. The result of this function gets tested and if it returned true the string which gets copied into var_60 is "Alive" and otherwise "Death".

Wow this took longer to explain than I expected. We will continue this shxt in the next episode. cya.
Cyrex' is offline  
Thanks
25 Users
Old 02/28/2016, 15:41   #2
 
elite*gold: 1
Join Date: Apr 2012
Posts: 3,001
Received Thanks: 6,198
Added to my Overview.
Keep it up! Looks nice.
Shinzuya is offline  
Thanks
1 User
Old 02/28/2016, 15:57   #3
 
elite*gold: 225
Join Date: Sep 2014
Posts: 334
Received Thanks: 460
PS: I have noticed that the function we were in is also a virtual function and additionally the main loop (it loops thru CTeam* vector and thru CActor* vector). Here's a nice static ptr to CTeamManager: (DWORD)GetModuleBase("S4Client.exe") + 0x2098574

And this is how it loops thru the teams:

PHP Code:
CTeam__thiscall GetTeam(CTeamManagerpThissize_t idx)
{
  
int result// eax@4
  
int v3// [sp+10h] [bp-4h]@2

  
if ( (*(_DWORD *)(*(_DWORD *)(this 4) + 4) - **(_DWORD **)(this 4)) >> <= a2 )
  {
    
result 0;
  }
  else
  {
    
v3 = *(_DWORD *)(this 4);
    if ( (*(
_DWORD *)(v3 4) - *(_DWORD *)v3) >> <= a2 )
      
v57AD3A0C("invalid vector<T> subscript");
    
result = *(_DWORD *)(*(_DWORD *)v3 a2);
  }
  return 
result;

Therefore CTeamManager + 0x4 is CTeams vector. (CTeamManager + 0x0 is vftable).
And this is how it loops thru actors/players:


PHP Code:
CActor__thiscall GetPlayer(CTeampThissize_t idx)
{
  
int result// eax@4
  
int v3// [sp+10h] [bp-4h]@2

  
if ( (*(_DWORD *)(*(_DWORD *)(this 0x24) + 4) - **(_DWORD **)(this 0x24)) >> <= a2 )
  {
    
result 0;
  }
  else
  {
    
v3 = *(_DWORD *)(this 0x24);
    if ( (*(
_DWORD *)(v3 4) - *(_DWORD *)v3) >> <= a2 )
      
v57AD3A0C("invalid vector<T> subscript");
    
result = *(_DWORD *)(*(_DWORD *)v3 a2);
  }
  return 
result;

Therefore CTeam + 0x24 is the players vector.

With this information you can either call the engine functions to get ptrs to specific players, teams
or you can rebuild this function in cpp what i've done for you:


PHP Code:
class CTeamManager;
class 
CTeam;
class 
CActor;

class 
CTeamManager
{
public:
    
voidpVTable//0x0000
    
std::vector<CTeam*>* ppTeams//0x0004
    
    
static CTeamGetTeamById(size_t idx)
    {
        return *(
CTeam**)(*ppTeams idx 4);
    }
}

class 
CTeam
{
public:
    
voidpVTable//0x0000
    
char pad[0x20]; //0x0004
    
std::vector<CActor*>* ppPlayers//0x0024
    
    
static CActorGetPlayerById(size_t idx)
    {
        return *(
CActor**)(*ppPlayers idx 4);
    }


Have fun guys playing with this stuff :P



EDIT:
new stuff:

PHP Code:
.text:00AF7B6F                 mov     ecxdword ptr [ebp+var_78+4]
.
text:00AF7B72                 push    ecx // ActorID
.text:00AF7B73                 mov     edxdword ptr [ebp+var_78]
.
text:00AF7B76                 push    edx //TeamID 
PHP Code:
.text:00AF79F6                 mov     ecx, [ebp+var_48]
.
text:00AF79F9                 add     ecx8
.text:00AF79FC                 call    sub_AFA390
.text:00AF7A01                 movzx   eaxal
.text:00AF7A04                 cdq
.text:00AF7A05                 mov     dword ptr [ebp+var_78], eax
.text:00AF7A08                 mov     dword ptr [ebp+var_78+4], edx 
PHP Code:
TeamID sub_AFA390(var_48+8); 
how it gets calculated in the function itself: (this is var_48+8)
PHP Code:
v3 = *(_BYTE *)(this 2) ^ *(_BYTE *)this
[means values are encrypted :^)]

EDIT2:

that's how you decrypt the teamID:

the first byte at selection is *(BYTE*)this which is 'E1' and +2 bytes is 'E1' too. XOR'ing 'E1' with 'E1' results to 0. So the team I'm in has ID 0. (for the ones who does not know, " ^ " <- this character means bitwise exclusive or aka. XOR which is mostly used in games to encrypt things like strings or other values)
Cyrex' is offline  
Thanks
16 Users
Old 03/01/2016, 15:56   #4
 
elite*gold: 225
Join Date: Sep 2014
Posts: 334
Received Thanks: 460
more info:

how to get game rules (again s4 provides us a static ptr..)
PHP Code:
.text:00AF8761                 mov     ecxds:dword_20968B4
.text:00AF8767                 mov     [ebp+var_114], ecx
.text:00AF876D                 mov     edx, [ebp+var_114]
.
text:00AF8773                 mov     eax, [edx+12Ch]
.
text:00AF8779                 mov     [ebp+var_16C], eax
.text:00AF877F                 mov     ecx, [ebp+var_16C]
.
text:00AF8785                 add     ecx1Ch
.text:00AF8788                 call    sub_AFA400
.text:00AF878D                 mov     [ebp+var_11C], eax
.text:00AF8793                 mov     ecx, [ebp+var_11C]
.
text:00AF8799                 push    ecx
.text:00AF879A                 push    offset aLimitscoreD "LimitScore = %d"
.text:00AF879F                 lea     edx, [ebp+var_244]
.
text:00AF87A5                 push    edx
.text:00AF87A6                 call    sub_168B4C0 
c++
PHP Code:
typedef int (__thiscall *tGetScoreLimit)(voidpThis);
tGetScoreLimit GetScoreLimit 0xAFA400 + (DWORD)GetModuleBase("S4Client.exe");

uintptr_t pECX = *(uintptr_t*)(0x20968B4);
uintptr_t pEAX = *(uintptr_t*)(pECX 0x12C);
pEAX += 0x1C;

^
minimizes to:

voidpObject = *(uintptr_t*)(*(uintptr_t*)(0x20968B4) + 0x12C) + 0x1C;
int LimitScore GetScoreLimit(pObject); 
you can find other game rules around there :P
(more will come, when im back home)
Cyrex' is offline  
Thanks
11 Users
Old 03/01/2016, 17:44   #5


 
onahoe's Avatar
 
elite*gold: 10
Join Date: May 2013
Posts: 814
Received Thanks: 1,265
well, finally something useful in this section. not bad. keep it up!
onahoe is offline  
Thanks
3 Users
Old 03/01/2016, 19:33   #6
 
elite*gold: 225
Join Date: Sep 2014
Posts: 334
Received Thanks: 460
PHP Code:
ecx = *(DWORD*)(*(DWORD*)(*(DWORD*)(0x28C68CC) + 0x12C) + 0xC);
call    eax [11
Get current round time

virtual call -> 11th index of ecx's(instance ptr) virtual table(vftable)
after the call the result or the current round time gets set in eax
which means the return value of *(DWORD**)(ecx)[11]() is the current round time.

for calling virtuals you just need the correct calling convention which is always __thiscall
parameters get passed normally - pushed onto the stack in x86 before ecx is getting set.
PHP Code:
typedef int (__thiscalltGetRoundTime)(void); 
then just call it like that:
PHP Code:
tGetRoundTime ( * ( uintptr_t** )( ecx )[ 11 ] ) ) ( ) 
hf.
Cyrex' is offline  
Thanks
8 Users
Old 03/02/2016, 14:57   #7
Trade Restricted
 
elite*gold: 74
Join Date: Mar 2015
Posts: 632
Received Thanks: 109
Really nice. Keep that **** going ^^
H ~ is offline  
Thanks
1 User
Old 03/03/2016, 00:54   #8
 
▒ Ant.'s Avatar
 
elite*gold: 0
Join Date: Dec 2008
Posts: 423
Received Thanks: 1,378
Wow! Really nice to see someone actually reversing the game for once and not just doing small ****.

P.S.: I released the source of my , and it contains some S4 information like this; maybe it will be of assistance.~
▒ Ant. is offline  
Thanks
5 Users
Old 03/03/2016, 02:14   #9


 
onahoe's Avatar
 
elite*gold: 10
Join Date: May 2013
Posts: 814
Received Thanks: 1,265
Quote:
Originally Posted by ▒ Ant. View Post
Wow! Really nice to see someone actually reversing the game for once and not just doing small ****.

P.S.: I released the source of my , and it contains some S4 information like this; maybe it will be of assistance.~
lel just noticed your release now. it's very nice! thanks for that!
onahoe is offline  
Thanks
1 User
Old 03/03/2016, 15:28   #10
 
xDarkMan's Avatar
 
elite*gold: 20
Join Date: Oct 2012
Posts: 346
Received Thanks: 361
as a member(me ) who is intersted in reversing games. happy to see someone reversing S4 and and posting tips/tuts. helped me alot.
was looking for smthin like that. keep it up.
xDarkMan is offline  
Old 03/04/2016, 00:05   #11
 
elite*gold: 0
Join Date: Jul 2015
Posts: 6
Received Thanks: 1
Quote:
Originally Posted by Shinzuya View Post
Added to my Overview.
Keep it up! Looks nice.
Since you understood !!
So what exactly is this :! so confuse ?
JulietLover is offline  
Old 03/04/2016, 17:37   #12
 
elite*gold: 36
Join Date: Jan 2014
Posts: 73
Received Thanks: 13
and this is what?
SquishHD is offline  
Reply


Similar Threads Similar Threads
[TUTORIAL] Reversing the graphics pipeline
10/19/2015 - S4 League Hacks, Bots, Cheats & Exploits - 4 Replies
Hey guys, this tutorial will show you basic static reverse engineering or analysis of a dump. In this case I will show you something of S4's graphics pipeline. The practical example will be the D3D Font. This tutorial aims at a bit advanced members and requires asm knowledge. At the end of the tutorial, I will also give you a tip on how to aquire a static pointer. D3D Font http://i.imgur.com/yzxNCmF.png Here, we found an interesting string that will help us to get a starting point....
[Tutorial-Collection] Metin2 Reversing/Hacking
07/03/2015 - Metin2 Guides & Templates - 149 Replies
Hey Epvp'ler. Ich habe mich dazu entschieden die ungebildete Metin2-Community mal ein bisschen auf Vordermann zu bringen und release hier meine private Playlist mit Reversing-Tutorials für Metin2. Die Tutorials sind so vom Niveau her für Anfänger, jedoch nicht für welche, die keine Ahnung von Memory, Assembler und Cheat Engine und sowas haben. Also WriteProcessMemory() solltet ihr schonmal gehört haben. Wenn ihr Ideen für weitere Videos oder Fragen habt, fragt einfach hier, wenn sie mir...
Reversing Tutorial 1 (Kickvote)
04/18/2015 - S4 League Hacks, Bots, Cheats & Exploits - 26 Replies
http://i.epvpimg.com/GWnxd.png http://i.epvpimg.com/wPtlf.png http://i.epvpimg.com/YTLnb.png Das folgende Tutorial ist von mir geschreiben und ist nur für Elitepvpers, ich erlaube es nicht es in andere Foren zu kopieren! -Zu erst downloadet ihr euch Cheat Engine falls ihr das noch nicht habt. -Danach öffnet ihr S4 mit einen Bypass. -Startet nun Cheat engine und geht in die Settings siehe Bild.
[Tutorial] Basic Reversing in S4L (KickVote Function)
04/13/2015 - S4 League Hacks, Bots, Cheats & Exploits - 13 Replies
Hello. :) Wanna show you how to reverse functions in S4 League. So let's get started; First you need the address of the pre-kickvote processing function, which is located in some class(__thiscall). I found out that it's not a vtable entry, so that's not so good because with vftables you can always grab your functions easier. http://i.imgur.com/8x9rO2q.png .text:00E5FB12 push eax
[Tutorial] Reversing Spell Encryption
06/15/2014 - CO2 Programming - 1 Replies
It has been quite a while since I last wrote a tutorial related to Conquer. This is mostly useless because as far as I know the spell encryption has already been reversed long time ago. The purpose of this post / tutorials is to help people understand how it's possible to find functions and implement them in desired language by reverse engineering. This will also be kind of log for me on how I approach reversing. This reverse engineering was performed on a unnamed private server so I'm not...



All times are GMT +1. The time now is 16:07.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.