Русское сообщество по скриптингу

Реверс клиента игры [Пошаговый разбор. Не CS]

Флуд, который не касается других разделов форума.

Модератор: Модераторы

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

Реверс клиента игры [Пошаговый разбор. Не CS]

Сообщение Kaylon » 02 фев 2017, 13:10

Здравствуйте, пытаюсь найти в каком месте программа использует шифрование своих ресурсов, до этого мне удавалось распаковать парочку простых игр (не сетевых), но сейчас дошло дело до MMO клиента игры и хочу глянуть, где она использует шифрование, но в Си++ я не силён. Прошёлся Ассемблером и поправил стек поинты, вот что из этого вышло в декомпилированном виде.

Давайте сделаем вот что, я буду поочередно декомпилировать каждые части - тела функции и мы понемногу дойдем до момента, когда разгадаем полностью весь клиент. Разберёмся за одно, как там японцы строчат свои ммошки.

По возможности, я буду обновлять данную тему и код в ней, по мере понимания, а так же выложу что уже обновил новым комментарием! Шапка будет обновляться.

Важно: Если Вы понимаете Ассемблере или в С++, то не откажусь от вашей помощи декомпилированния .exe файла. Я в C++ не особо знаток и не знаю точно, как должен выглядеть код в читабельном виде.

Всего 14 тел в .exe и все они не были распознаны, а значит код написан программистом вручную
Вот что мне удалось декомпилировать разобрав и поправив стек
Код: Выделить всё
#include <windows.h>
#include <defs.h>


//-------------------------------------------------------------------------
// Function declarations

void Start();
void (*__stdcall sub_401020(int a1))(void);
_DWORD *__cdecl sub_401100(int a1);
_DWORD *__cdecl DOSorPE(int a1);
_DWORD *__cdecl sub_401170(int a1int a2);
signed int __cdecl sub_401390(_BYTE *a1);
signed int __cdecl sub_4013D0(int a1int a2);
signed int __cdecl sub_4014C0(int a1int a2);
signed int __cdecl sub_401600(int a1int a2);
unsigned __int32 sub_401640();
BOOL __cdecl sub_401660(int a1int a2int a3int a4);
BOOL __cdecl sub_401810(int a1_DWORD *a2);
signed int __cdecl sub_401870(int a1char *a2unsigned int a3int a4);
void start();

//-------------------------------------------------------------------------
// Data declarations

char byte_6A9939[3]; // weak
char byte_892969[3]; // weak
char byte_8929B9[3]; // weak


//----- (GameMain) Выполняется после Start, создает переменную в которую заносит данные из стека и кидает на обработку в sub_401020(int a1)
void GameMain()
{
  
int v0// [sp-260h] [bp-260h]@0
  
int v1// [sp-98h] [bp-98h]@0

  
sub_401020(v1);
  
JUMPOUT(__CS__v0);
}
//----- (00401020) Сюда прилетает значение из функции выше и происходит выполнение данного тела
void (*__stdcall sub_401020(int a1))(void)
{
  
int v1// edi@1
  
int v2// esi@1
  
int v3// ebx@1
  
void (*v5)(void); // ebx@5
  
int v6// edi@8
  
char v7// [sp+10h] [bp-4Ch]@3
  
int v8// [sp+1Ch] [bp-40h]@8
  
int v9// [sp+28h] [bp-34h]@5
  
int v10// [sp+2Ch] [bp-30h]@8
  
char v11// [sp+30h] [bp-2Ch]@1
  
void (__stdcall *v12)(_DWORD); // [sp+3Ch] [bp-20h]@10
  
int (__stdcall *v13)(intintsigned intint *); // [sp+40h] [bp-1Ch]@2

  
v1 = *(_BYTE *)(a1 7);
  
v2 = *(_DWORD *)(a1 + -v1 40) + a1 + -v1 1;
  
v3 sub_401100(v2);
  if ( !
sub_401170(v2, (int)&v11) || !v13(v2v364, &a1) || !sub_401660(v2, &v11, &v7v1) )
    return 
0;
  
v5 = (void (*)(void))(v9 v2);
  if ( 
v1 )
  {
    
v6 v8 v2;
    
sub_4013D0(v8 v2v8 v2);
    
sub_4014C0(v6, (int)&v11);
    if ( ((
int (__stdcall *)(intsigned int_DWORD))(v2 v10))(v610) )
      
v5();
    
v12(0);
  }
  else if ( 
v2 != (*(int (__stdcall **)(_DWORD))&v11)(0) )
  {
    
sub_401600(v2, (int)v5);
    return 
v5;
  }
  return 
v5;
}

//----- (00401100) --------------------------------------------------------
// Сюда передается вычисления из v2 = *(_DWORD *)(a1 - 5 + -8 * v1 + 40) + a1 - 5 + -8 * v1 + 1; 
// а переменная a1 равняется int v1; // [sp+0h] [bp+0h]@1 // увы, но что такое sp+0 и bp+0 я не знаю, ибо что заносится в эти регистры процессора - хрен знает
// всё что могу вам сказать, так это то что sp - это стековый указатель, а bp - базовый указатель
int __cdecl 401100(int a1)
{
  
int result// eax@1

  
result DOSorPE(a1); // Либо 0, либо result = (_DWORD *)(a1 + *(_DWORD *)(a1 + 60))  | 17744+(17744+60)
  
if ( result )  // Если не 0, то 
    
result = *(_DWORD *)(result 80); // Получается 
  
return result;
}

//----- (00401120) --------------------------------------------------------
_DWORD *__cdecl DOSorPE(int a1)
{
  
// Что известно a1 может быть либо MZ (23117) либо PE (17744)
  
signed int v1// ecx@2   // Целочисленная переменная, может быть как отрицательным, так и положительным значением
  
_DWORD *result// eax@7  // Целочисленная переменная, может быть только от 0 до 4294967295 

  // Операции
  
if ( !a1 // Если a1 отрицательно, то возвращает reuslt = 0, это выполнится если вы запускаете клиент с табуретки 0_о
    
goto LABEL_12

  
v1 = -1// тут всё понятно, в переменную v1 заносится -1
  
if ( *(_WORD *)a1 == 23117 // Проверка, если a1 = MZ формату
    
v1 0// Если a1 равно MZ и проверка a1 = MZ верна, то v1 = 0
 
  
if ( *(_WORD *)a1 // Проверка a1 положительное
  
{
    if ( 
v1 
      goto 
LABEL_12;
  }
  else
  {
    
v1 1;
  }
  
result = (_DWORD *)(a1 + *(_DWORD *)(a1 60)); // Не пойму что тут конкретно вычисляется, но это ключ к следующему телу. Если из под DOS - вернет 0, если нет, то вернет это
  //
  
if ( !v1 )
  {
    if ( *
result != 17744 // Если 
      
result 0;
    return 
result;
  }
  if ( 
v1 == && *result // Если v1 == 1 и result положительное, то result равен 0 или же return result?
LABEL_12:
    
result 0;
  return 
result;

  
// Вывод следующий
  // Если запускаем из под DOS, то result = 0
  // Если запускаем из под Windows, то result = (_DWORD *)(a1 + *(_DWORD *)(a1 + 60)); увы, но если подставить сюда 17744, то получается бред вроде 17744+(17744+60), оставим пока так
  // Оставим пока так, суть тела ясна

}

//----- (00401170) --------------------------------------------------------
signed int __cdecl sub_401170(int a1int a2)
{
  
signed int result// eax@1
  
int v3// eax@2
  
int v4// eax@2
  
int v5// eax@2
  
int v6// ecx@2
  
int v7// edx@2
  
int v8// edi@2
  
int v9// [sp+34h] [bp-14h]@2
  
int v10// [sp+38h] [bp-10h]@2
  
char *v11// [sp+3Ch] [bp-Ch]@2
  
char *v12// [sp+40h] [bp-8h]@2
  
int v13// [sp+44h] [bp-4h]@2

  
result DOSorPE(a1);
  if ( 
result )
  {
    
v3 = *(_DWORD *)(result 128);
    
v9 = -390555319;
    
v10 = -1398003287;
    
v4 = *(_DWORD *)(v3 a1 16);
    
v11 = (char *)152676637;
    
v5 a1 v4;
    
v12 0;
    
v6 = *(_DWORD *)v5;
    
v5 += 4;
    *(
_DWORD *)(a2 4) = v6;
    
v7 = *(_DWORD *)v5;
    
v5 += 4;
    *(
_DWORD *)(a2 8) = v7;
    *(
_DWORD *)a2 = *(_DWORD *)v5;
    *(
_DWORD *)(a2 12) = *(_DWORD *)(v5 4);
    
sub_401390(&v9);
    
v8 = (*(int (__stdcall **)(int *))a2)(&v9);
    
v9 = -2001184358;
    
v10 = -904275544;
    
v11 = (char *)2040068312;
    
v12 = (char *)43209;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 16) = (*(int (__stdcall **)(intint *))(a2 8))(v8, &v9);
    
v9 = -90662517;
    
v10 159951113;
    
v11 = (char *)155814825;
    
v12 = (char *)-121042007;
    
v13 31401;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 20) = (*(int (__stdcall **)(intint *))(a2 8))(v8, &v9);
    
v9 = -1182152501;
    
v10 964401592;
    
v11 byte_6A9939;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 24) = (*(int (__stdcall **)(intint *))(a2 8))(v8, &v9);
    
v9 = -1182152501;
    
v10 964401592;
    
v11 = (char *)-1190422215;
    
v12 = (char *)-397809416;
    
v13 56201;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 28) = (*(int (__stdcall **)(intint *))(a2 8))(v8, &v9);
    
v9 1792596267;
    
v10 = -630679191;
    
v11 = (char *)155814809;
    
v12 = (char *)169;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 32) = (*(int (__stdcall **)(intint *))(a2 8))(v8, &v9);
    
v9 = -1190590038;
    
v10 2034862840;
    
v11 = (char *)1803156104;
    
v12 byte_892969;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 36) = (*(int (__stdcall **)(_DWORD_DWORD))(a2 8))(v8, &v9);
    
v9 = -1729615413;
    
v10 = -389452887;
    
v11 byte_8929B9;
    
sub_401390(&v9);
    *(
_DWORD *)(a2 40) = (*(int (__stdcall **)(_DWORD_DWORD))(a2 8))(v8, &v9);
    
result 1;
  }
  return 
result;
}

//----- (00401390) --------------------------------------------------------
signed int __cdecl sub_401390(_BYTE *a1)
{
  
_BYTE *v1// ecx@1
  
int v2// edx@1
  
unsigned __int8 v3// al@1
  
signed int result// eax@3

  
v1 a1;
  
v2 0;
  
v3 = *a1;
  if ( *
a1 )
  {
    do
    {
      *
v1 = ~(16 v3 | (v3 >> 4)) - (v2 3);
      
v3 = (v1++)[1];
      ++
v2;
    }
    while ( 
v3 );
    
result 1;
  }
  else
  {
    
result 1;
  }
  return 
result;
}

//----- (004013D0) --------------------------------------------------------
signed int __cdecl sub_4013D0(int a1int a2)
{
  
int v2// edi@1
  
_DWORD *v3// eax@1
  
_DWORD *v4// esi@1
  
int v5// ecx@2
  
int v6// eax@2
  
signed int result// eax@3
  
int v8// ecx@5
  
int v9// edx@5
  
unsigned int v10// ebx@7
  
unsigned int v11// edx@7
  
int v12// ecx@10
  
int v13// esi@11
  
_WORD *v14// edi@11
  
int v15// edx@12
  
_DWORD *v16// [sp+8h] [bp-8h]@1
  
unsigned int v17// [sp+Ch] [bp-4h]@7

  
v2 a1;
  
v3 DOSorPE(a1);
  
v4 v3;
  
v16 v3;
  if ( !
v3 )
    goto 
LABEL_26;
  
v5 v3[13];
  
v6 a2 v5;
  if ( 
a2 == v5 )
    return 
1;
  if ( 
v4[29] > 5u && (v8 v4[40], v9 v4[41], v8) && v9 )
  {
    
v10 v8 a1;
    
v11 v8 a1 v9;
    
v17 v11;
    if ( 
v8 a1 v11 )
    {
      while ( 
)
      {
        
v12 = *(_DWORD *)(v10 4);
        if ( !
v12 )
          break;
        
v13 v2 + *(_DWORD *)v10;
        
v14 = (_WORD *)(v10 8);
        if ( 
v10 v12 v10 )
        {
          do
          {
            
v15 = *v14 0xFFF;
            switch ( (
unsigned int)*v14 >> 12 )
            {
              case 
1u:
                *(
_WORD *)(v15 v13) += HIWORD(v6);
                break;
              case 
2u:
                *(
_WORD *)(v15 v13) += v6;
                break;
              case 
3u:
                *(
_DWORD *)(v15 v13) += v6;
                break;
            }
            ++
v14;
          }
          while ( (
unsigned int)v14 v12 v10 );
          
v11 v17;
        }
        
v10 += *(_DWORD *)(v10 4);
        if ( 
v10 >= v11 )
        {
          
v4 v16;
          break;
        }
        
v2 a1;
        
v4 v16;
      }
    }
    
v4[13] = a2;
    
result 1;
  }
  else
  {
LABEL_26:
    
result 0;
  }
  return 
result;
}

//----- (004014C0) --------------------------------------------------------
signed int __cdecl sub_4014C0(int a1int a2)
{
  
int v2// ebp@1
  
_DWORD *v3// eax@1
  
int v4// ebx@3
  
int v5// eax@3
  
unsigned int v6// ebx@5
  
int v7// esi@8
  
_BYTE *v8// esi@9
  
int v9// edi@9
  
char v10// al@12
  
int v11// eax@13
  
int *v12// ebx@13
  
int i// eax@15
  
int v14// eax@17
  
_BYTE *v15// esi@18
  
char v16// cl@19
  
int *v17// eax@21
  
signed int result// eax@23
  
unsigned int v19// [sp+10h] [bp-8h]@5
  
unsigned int v20// [sp+14h] [bp-4h]@5
  
int *v21// [sp+1Ch] [bp+4h]@13

  
v2 a1;
  
v3 DOSorPE(a1);
  if ( 
v3 && v3[29] > 1u && (v4 v3[32], v5 v3[33], v4) && v5 )
  {
    
v6 a1 v4;
    
v19 v6;
    
v20 v6 v5;
    if ( 
v6 v6 v5 )
    {
      while ( 
)
      {
        
v7 = *(_DWORD *)(v6 12);
        if ( !
v7 )
          break;
        
v8 = (_BYTE *)(v2 v7);
        
v9 = (*(int (__stdcall **)(_BYTE *))a2)(v8);
        if ( !
v9 )
        {
          
v9 = (*(int (__stdcall **)(_BYTE *))(a2 4))(v8);
          if ( !
v9 )
            goto 
LABEL_24;
        }
        if ( *
v8 )
        {
          do
          {
            *
v8 0;
            
v10 = (v8++)[1];
          }
          while ( 
v10 );
        }
        
v11 = *(_DWORD *)v6;
        
v12 = (int *)(v2 + *(_DWORD *)(v6 16));
        
v21 = (int *)(v11 v2);
        if ( !
v11 )
          
v21 v12;
        for ( 
= *v21i= *v17 )
        {
          if ( 
0x80000000 )
          {
            
v14 = (*(int (__stdcall **)(int_DWORD))(a2 8))(v9, (unsigned __int16)i);
          }
          else
          {
            
v15 = (_BYTE *)(v2 2);
            *(
_WORD *)(v2) = 0;
            
v14 = (*(int (__stdcall **)(int_BYTE *))(a2 8))(v9v15);
            if ( *
v15 )
            {
              do
              {
                *
v15 0;
                
v16 = (v15++)[1];
              }
              while ( 
v16 );
            }
          }
          if ( !
v14 )
            goto 
LABEL_24;
          *
v12 v14;
          
v17 v21 1;
          ++
v12;
          
v21 v17;
        }
        
v19 += 20;
        if ( 
v19 >= v20 )
          break;
        
v6 v19;
      }
    }
    
result 1;
  }
  else
  {
LABEL_24:
    
result 0;
  }
  return 
result;
}

//----- (00401600) --------------------------------------------------------
signed int __cdecl sub_401600(int a1int a2)
{
  
int v2// eax@1
  
int v3// ecx@1
  
int v4// eax@1
  
signed int result// eax@4

  
v2 = *(_DWORD *)(sub_401640() + 12);
  
v3 v2 12;
  
v4 = *(_DWORD *)(v2 12);
  if ( 
v4 == v3 )
  {
LABEL_4:
    
result 0;
  }
  else
  {
    while ( *(
_DWORD *)(v4 24) != a1 )
    {
      
v4 = *(_DWORD *)v4;
      if ( 
v4 == v3 )
        goto 
LABEL_4;
    }
    *(
_DWORD *)(v4 28) = a2;
    
result 1;
  }
  return 
result;
}

//----- (00401640) --------------------------------------------------------
unsigned __int32 sub_401640()
{
  return 
__readfsdword(48);
}

//----- (00401660) --------------------------------------------------------
BOOL __cdecl sub_401660(int a1int a2int a3int a4)
{
  
int v4// esi@1
  
int v5// edi@1
  
BOOL v6// ebp@1
  
int v7// ebx@4
  
_DWORD *v8// eax@5
  
unsigned int v9// edi@5
  
int v10// ecx@5
  
int v11// edx@5
  
int v12// eax@6
  
int v13// ebp@8
  
int v14// ecx@10
  
int v15// eax@10
  
char *v16// esi@10
  
unsigned int v17// edi@11
  
int v19// [sp+58h] [bp-214h]@1
  
int v20// [sp+5Ch] [bp-210h]@1
  
int v21// [sp+60h] [bp-20Ch]@10
  
char v22// [sp+64h] [bp-208h]@1

  
v4 a2;
  (*(
void (__stdcall **)(intchar *, signed int))(a2 20))(a1, &v22260);
  
v5 = (*(int (__stdcall **)(char *, unsigned intsigned int_DWORDsigned intsigned int_DWORD))(a2 24))(
         &
v22,
         
2147483648,
         
1,
         
0,
         
3,
         
128,
         
0);
  
v20 v5;
  
v6 v5 != -1;
  
v19 0;
  if ( 
v5 != -)
  {
    
v19 = (*(int (__stdcall **)(int_DWORDsigned int_DWORD_DWORD_DWORD))(a2 28))(v502000);
    
v6 v19 != 0;
  }
  if ( 
v6 )
  {
    
v7 = (*(int (__stdcall **)(intsigned int_DWORD_DWORD_DWORD))(a2 32))(v194000);
    
v6 v7 != 0;
    if ( 
v7 != )
    {
      
v8 DOSorPE(a1);
      
v9 v8[21];
      
v10 = *((_WORD *)v8 3);
      
v11 0;
      if ( (
signed int)(unsigned __int16)v10 )
      {
        
v12 = (int)v8 + *((_WORD *)v8 10) + 40;
        do
        {
          if ( *(
_DWORD *)(v12 4) > v9 )
            break;
          
v13 = *(_DWORD *)v12;
          
v12 += 40;
          
v9 += v13;
          ++
v11;
        }
        while ( 
v11 v10 );
      }
      
v6 sub_401810(a3, (_DWORD *)(v7 v9 32 a4));
      if ( 
v6 )
      {
        
v14 = *(_DWORD *)(a3 12);
        
v15 v14 a1;
        
v16 = (char *)(v7 v9 + *(_DWORD *)(a3 16));
        
v21 v14 a1;
        if ( 
a4 )
        {
          
sub_401870(v15v16, *(_DWORD *)(a3 20), *(_DWORD *)a3);
        }
        else
        {
          
v17 = *(_DWORD *)(a3 24) - v14 0x2000;
          
sub_401870(v15v16v17, *(_DWORD *)a3);
          
qmemcpy((void *)(v21 v17), &v16[v17], *(_DWORD *)(a3 20) - v17);
        }
        
v4 a2;
      }
      
v5 v20;
    }
    if ( 
v7 )
      (*(
void (__stdcall **)(int))(v4 36))(v7);
  }
  if ( 
v19 )
    (*(
void (__stdcall **)(int))(v4 40))(v19);
  if ( 
v5 != -)
    (*(
void (__stdcall **)(int))(v4 40))(v5);
  return 
v6;
}

//----- (00401810) --------------------------------------------------------
BOOL __cdecl sub_401810(int a1_DWORD *a2)
{
  
char *v2// esi@1
  
int v3// edi@1
  
signed int v4// ecx@1
  
int v5// eax@2
  
int v6// eax@2

  
*(_DWORD *)a1 = *a2;
  
v2 = (char *)(a2 1);
  
v3 = *a2;
  
v4 0;
  do
  {
    
v5 = *(_DWORD *)v2;
    
v2 += 4;
    *(
_DWORD *)&v2[a1 - (_DWORD)(a2 1) - 4] = v3 v5;
    
v6 v4 v4 ^ (v3 v5 v4);
    ++
v4;
    
v3 v6;
  }
  while ( 
v4 );
  return *(
_DWORD *)(a1 4) == 1313754955;
}

//----- (00401870) --------------------------------------------------------
signed int __cdecl sub_401870(int a1char *a2unsigned int a3int a4)
{
  
int v4// edx@1
  
signed int result// eax@1
  
char *i// esi@1
  
int v7// edi@2

  
v4 = ~a3 a4;
  
result 0;
  for ( 
a2result < (signed int)(a3 >> 2); ++result )
  {
    
v7 = *(_DWORD *)i;
    
+= 4;
    *(
_DWORD *)&i[a1 - (_DWORD)a2 4] = v4 v7;
    
v4 = (v4 result v7) ^ result result;
  }
  return 
result;
}

//----- (004018C0) --------------------------------------------------------
void start() // Точка входа в программу
{
  
GameMain();
}


Тема будет обновляться и код по возможности будет переходить в более читабельный вид, благодаря вашей помощи, а так же моих предположений и реверсинга

Добавлено спустя 19 минут 40 секунд:
Обновлено:
* Поправлено тело функции sub_401120 и переименовано в надлежащее ей DOSorPE
* Выяснено что такое sub_401120

Что делает тело функции sub_401120:
Данное тело проверяет, является ли запущенная программа MZ или PE форматом
Для тех кто не в танках:
MZ — стандартный формат 16-битных исполняемых файлов с расширением .EXE для DOS
PE - формат исполняемых файлов
Иначе говоря, тело проверяет, программа выполняет простую проверку.
Исходя из этого дадим имя этому телу, чтобы понимать сути её работы
Аватара пользователя
Kaylon
 
Сообщения: 36
Зарегистрирован: 22 янв 2015, 20:22
Забанен
Благодарил (а): 2 раз.
Поблагодарили: 8 раз.
Опыт программирования: Больше трех лет

Re: Реверс клиента игры [Пошаговый разбор. Не CS]

Сообщение RevCrew » 02 фев 2017, 14:58

По идеи, там еще где то должно быть автоматическое обновление клиента?
Аватара пользователя
RevCrew
Скриптер
 
Сообщения: 1648
Зарегистрирован: 15 июл 2013, 20:45
Благодарил (а): 273 раз.
Поблагодарили: 357 раз.
Языки программирования: Unkown

Re: Реверс клиента игры [Пошаговый разбор. Не CS]

Сообщение Kaylon » 02 фев 2017, 15:13

RevCrew писал(а):По идеи, там еще где то должно быть автоматическое обновление клиента?

Да, но для этого всегда есть второй исполняемый файл под названием Launcher.
Почти все игры имеют 2 исполняемых файла, один для обработки игровой механики и графики, а второй для закачки как раз таки обновлений.

Добавлено спустя 6 минут 36 секунд:
Ещё хочу добавить для тех, кто любит делать эмуляторы серверов.
Если хотите заменить IP адрес к которому коннектится игра, то можно пойти 2мя способами:
1) Распотрошить игровые ресурсы, создав распаковщик и упаковщик
2) Более гуманный способ, использовать ассемблер и софт отслеживающий пинг от клиента до сервера.
Пусть наш IP адрес сервера будет 102.22.22.45, открываем калькулятор в режиме "Программист" и пишем в режиме Dec число 102 и после выбираем Hex, получим 66. Делаем тоже самое с оставшимися числами.
У меня получилось 6616162D в шестнадцатеричной системе счисления, перевернем эти числа задом наперед и получаем 2D161666 - ищем этот адрес и получаем IP адрес нашей комнаты в которой находимся. Патчим эту область своим IP и получаем пропатченный клиент, но опять же, этот способ лишь насилие над клиентом, лучше использовать 1 способ, но для него понадобится больше мозгов и умений ибо надо разбирать точки входа, rva и многое другое и зачастую они запакованы.
Аватара пользователя
Kaylon
 
Сообщения: 36
Зарегистрирован: 22 янв 2015, 20:22
Забанен
Благодарил (а): 2 раз.
Поблагодарили: 8 раз.
Опыт программирования: Больше трех лет

Re: Реверс клиента игры [Пошаговый разбор. Не CS]

Сообщение Kaylon » 04 фев 2017, 03:24

В общем, случайно наткнулся после декомпиляции памяти игры вот на такую вкусняшку
Пока разобрать не получилось, у кого есть догадки - отпишитесь.
Я предполагаю что здесь может быть алгоритм какого нибудь шифрования, судя по кол-ву while в sub_4013C0
Код: Выделить всё
_DWORD *__thiscall sub_401350(int this, _DWORD *a2, int a3, int a4)
{
  int v4; // edi@1
  int *v5; // ebx@1
  int v6; // eax@2
  int v7; // esi@5
  int v8; // eax@7
  _DWORD *result; // eax@10

  v4 = this;
  v5 = (int *)(this + 4);
  if ( *(_DWORD *)(this + 24) < 8u )
    v6 = this + 4;
  else
    v6 
= *v5;
  if ( a3 )
    v7 = (a3 - v6) >> 1;
  else
    v7 
= 0;
  v8 = a4;
  if ( a4 )
    v8 = (a4 - a3) >> 1;
  sub_4012D0(this, v7, v8);
  if ( *(_DWORD *)(v4 + 24) < 8u )
  {
    result = a2;
    *a2 = (char *)v5 + 2 * v7;
  }
  else
  
{
    result = a2;
    *a2 = *v5 + 2 * v7;
  }
  return result;
}

//----- (004013C0) --------------------------------------------------------
_BYTE *__thiscall sub_4013C0(char *this)
{
  char *v1; // esi@1
  int v2; // ecx@1
  unsigned int v3; // edx@1
  int *v4; // eax@1
  int v5; // edi@2
  int v6; // edi@4
  unsigned int v7; // eax@6
  int *v8; // edx@6
  int v9; // edi@7
  int v10; // edi@9
  _BYTE *v11; // eax@11
  signed int v12; // ecx@11
  _BYTE *result; // eax@13
  _DWORD *v14; // ecx@13
  signed int v15; // edx@13
  char v16; // [sp+Ch] [bp-4h]@6

  v1 = this;
  v2 = (int)(this + 4);
  *(_DWORD *)v1 = 0;
  v3 = *(_DWORD *)(v2 + 24);
  v4 = (int *)(v2 + 4);
  if ( v3 < 8 )
    v5 = v2 + 4;
  else
    v5 
= *v4;
  v6 = v5 + 2 * *(_DWORD *)(v2 + 20);
  if ( v3 >= 8 )
    v4 = (int *)*v4;
  sub_401350(v2, &v16, (int)v4, v6);
  v7 = *((_DWORD *)v1 + 14);
  v8 = (int *)(v1 + 36);
  if ( v7 < 8 )
    v9 = (int)(v1 + 36);
  else
    v9 
= *v8;
  v10 = v9 + 2 * *((_DWORD *)v1 + 13);
  if ( v7 >= 8 )
    v8 = (int *)*v8;
  sub_401350((int)(v1 + 32), &v16, (int)v8, v10);
  *((_WORD *)v1 + 30) = 0;
  *((_WORD *)v1 + 31) = 0;
  v1[64] = 0;
  *((_WORD *)v1 + 33) = 0;
  *((_WORD *)v1 + 34) = 0;
  v1[70] = 0;
  *((_WORD *)v1 + 36) = 0;
  *((_WORD *)v1 + 37) = 0;
  v1[76] = 0;
  v1[77] = 0;
  *((_DWORD *)v1 + 20) = 0;
  *((_DWORD *)v1 + 21) = 0;
  v1[88] = 0;
  *((_DWORD *)v1 + 23) = 0;
  *((_DWORD *)v1 + 24) = 0;
  v1[100] = 0;
  *((_WORD *)v1 + 51) = 0;
  v1[104] = 0;
  v1[112] = 0;
  *((_DWORD *)v1 + 31) = 0;
  *((_DWORD *)v1 + 32) = 0;
  *((_DWORD *)v1 + 33) = 0;
  v1[136] = 0;
  v1[143] = 0;
  v1[192] = 0;
  *((_DWORD *)v1 + 49) = 0;
  *((_DWORD *)v1 + 50) = 0;
  *((_DWORD *)v1 + 51) = 0;
  *((_DWORD *)v1 + 52) = 0;
  *((_DWORD *)v1 + 29) = 0;
  *((_DWORD *)v1 + 30) = 0;
  v11 = v1 + 139;
  v12 = 2;
  do
  
{
    *(v11 - 2) = 0;
    *v11 = 0;
    (v11++)[2] = 0;
    --v12;
  }
  while ( v12 );
  result = v1 + 184;
  v14 = v1 + 144;
  v15 = 8;
  do
  
{
    *v14 = 1065353216;
    ++v14;
    *(result - 8) = 0;
    *result++ = 0;
    --v15;
  }
  while ( v15 );
  return result;


Добавлено спустя 59 минут 15 секунд:
В общем, ребята, выяснил что это за звёздочки такие волшебные - это же обычные массивы :)
Переведу первую часть в более порядочный вид

Код: Выделить всё

public sub_401350
(int this, _DWORD *a2, int a3, int a4) // написал public короче, чтоб понятней было
{
  int v4[256]        // 
  int *v5[256]; // ebx@1 // Скорее всего массив
  int v6; // eax@2
  int v7; // esi@5  
  int v8; // eax@7
  _dword *result; // eax@10

  v4 = this
  v5 
= this[4];
  if (this[24] < 8u )
    v6 = this[4];
  else
    v6 
= v5;
  if ( a3 )
    v7 = (a3 - v6) >> 1;
  else
    v7 
= 0;
  v8 = a4;
  if ( a4 )
    v8 = (a4 - a3) >> 1; // Это что внатуре побитовые операции? 
  unknow_function(this, v7, v8); // ещё 1 паблик, добавлю как расшифрую его значение
  if (v4[24] < 8u )
  {
    result = a2;
    *a2 = v5[2] * v7;
  }
  else
  
{
    result = a2;
    *a2 = v5[2] * v7;
  }
  return result;
}


Добавлено спустя 44 минуты 45 секунд:
А теперь, забудьте всё что было выше, будем делать по другому.
Пойду по порядку и попробую декомпилировать все регулярные функции прямо из памяти.
Аватара пользователя
Kaylon
 
Сообщения: 36
Зарегистрирован: 22 янв 2015, 20:22
Забанен
Благодарил (а): 2 раз.
Поблагодарили: 8 раз.
Опыт программирования: Больше трех лет

Re: Реверс клиента игры [Пошаговый разбор. Не CS]

Сообщение Kaylon » 04 фев 2017, 17:47

Вот что вчера ночью удалось декомпилировать, пока не понятно что тут происходит

Код: Выделить всё



int sub_4010C0
(int this)
{
   
int result;
   
result this;

   
this 0;
   
this[4] = 0;
   
this[8] = 0;
   
this[12] = 0;
   
this[16] = 0;
   
this[20] = 0;
   
   return 
result;
}
 

int sub_4010E0(void *this)
{
  
ntdll_RtlInitializeCriticalSection(this);
  return 
0;
}

int sub_401160(_DWORD *this)
{
  return 
oleaut32_SysFreeString(*this[]);
}



int sub_401170(int aint bint cint d[]) // d скорее всего массив
{
  
int result
  
int local_5;
  
int local_6;

  
result 1;

  if ( 
>= )
  {
    
v5 a1;
    
v6 a3;
    do
    {
      
result d[local_5]);
      
local_5 += b;
      --
local_6;
    }
    while ( 
local_6 );
  }
  return 
result;
}

signed int sub_4011A0(int param_oneint param_two)
{
  
int local_2// edi@1
  
int local_4// [sp-8h] [bp-10h]@0
  
int local_5// [sp-4h] [bp-Ch]@0
  
int local_6// [sp+0h] [bp-8h]@0
  
int local_7// [sp+4h] [bp-4h]@0

  
local_2 0;
  if ( !
param_one )
    return -
2147024809;
  if ( 
param_one[] )
  {
    if ( 
param_one[] != 44 
      return -
2147024809;  // при переводе в hex получается 0x80070057, странно 80 07 00 57 оставлю в таком ввиде, возможно long значение
    
if (param_one[36] > )
    {
      do
      {
        if ( 
local_2 || local_2 >= param_one[36] )
        {
          
// Адрес 0x0C000008C был числом -1073741684. Возможно нужно перевернуть 0x8C 00 00 0C хотя больше похоже на какие то оп коды, пример выше
          
kernel32_RaiseException(-1073741684100local_4local_5local_6local_7);
          
__debugbreak();
          
JUMPOUT(sub_401230[]);
        }
        
void user32_UnregisterClassW(param_one[32][2] * local_2++), param_two);
      }
      while ( 
local_2 param_one[36] );
    }
    if ( 
param_one[36] )
    {
      
sub_85C611(param_one[32]);
      
param_one[32] = 0;
    }
    
param_one[36] = 0;
    
param_one[40] = 0;
    
void ntdll_RtlDeleteCriticalSection(param_one[4]);
    *(
_DWORD *)a1 0;
  }
  return 
0;
}


// с этой я разобрался за пару минут 
char sub_401230(char *this[]) 
{
  
char *local_1[256]; // esi@1
  
int local_2[256]; // ecx@1
  
bool local_3// sf@1
  
char *result// eax@1

  
local_1 this;
  
local_2 this[4]; // тут непонятица, сначала присваивается одно, а ниже обнуляется что-ли
  
local_2 0// скорее всего это массив local_2 и возможно он не обнуляется, а обнуляется лишь local_2[0] = 0, хмм
  
local_2[4] = 0;
  
local_2[8] = 0;
  
local_2[12] = 0;
  
local_2[16] = 0;
  
local_2[20] = 0;

  
local_1[8] = 0;
  
local_1[9] = 0;
  
local_1[10] = 0;
  
local_1 44;
  
local_1[7] = 0;
  
local_3 sub_4010E0(local_2) < 0;
  
result v1;
  if ( 
local_3 )
    
byte_981900 1;
  return 
result;
}
 
Аватара пользователя
Kaylon
 
Сообщения: 36
Зарегистрирован: 22 янв 2015, 20:22
Забанен
Благодарил (а): 2 раз.
Поблагодарили: 8 раз.
Опыт программирования: Больше трех лет


Вернуться в Болтовня

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 6