Давайте сделаем вот что, я буду поочередно декомпилировать каждые части - тела функции и мы понемногу дойдем до момента, когда разгадаем полностью весь клиент. Разберёмся за одно, как там японцы строчат свои ммошки.
По возможности, я буду обновлять данную тему и код в ней, по мере понимания, а так же выложу что уже обновил новым комментарием! Шапка будет обновляться.
Важно: Если Вы понимаете Ассемблере или в С++, то не откажусь от вашей помощи декомпилированния .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 a1, int a2);
signed int __cdecl sub_401390(_BYTE *a1);
signed int __cdecl sub_4013D0(int a1, int a2);
signed int __cdecl sub_4014C0(int a1, int a2);
signed int __cdecl sub_401600(int a1, int a2);
unsigned __int32 sub_401640();
BOOL __cdecl sub_401660(int a1, int a2, int a3, int a4);
BOOL __cdecl sub_401810(int a1, _DWORD *a2);
signed int __cdecl sub_401870(int a1, char *a2, unsigned int a3, int 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)(int, int, signed int, int *); // [sp+40h] [bp-1Ch]@2
v1 = *(_BYTE *)(a1 - 5 + 7);
v2 = *(_DWORD *)(a1 - 5 + -8 * v1 + 40) + a1 - 5 + -8 * v1 + 1;
v3 = sub_401100(v2);
if ( !sub_401170(v2, (int)&v11) || !v13(v2, v3, 64, &a1) || !sub_401660(v2, &v11, &v7, v1) )
return 0;
v5 = (void (*)(void))(v9 + v2);
if ( v1 )
{
v6 = v8 + v2;
sub_4013D0(v8 + v2, v8 + v2);
sub_4014C0(v6, (int)&v11);
if ( ((int (__stdcall *)(int, signed int, _DWORD))(v2 + v10))(v6, 1, 0) )
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 < 0 )
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 == 1 && *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 a1, int 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 **)(int, int *))(a2 + 8))(v8, &v9);
v9 = -90662517;
v10 = 159951113;
v11 = (char *)155814825;
v12 = (char *)-121042007;
v13 = 31401;
sub_401390(&v9);
*(_DWORD *)(a2 + 20) = (*(int (__stdcall **)(int, int *))(a2 + 8))(v8, &v9);
v9 = -1182152501;
v10 = 964401592;
v11 = byte_6A9939;
sub_401390(&v9);
*(_DWORD *)(a2 + 24) = (*(int (__stdcall **)(int, int *))(a2 + 8))(v8, &v9);
v9 = -1182152501;
v10 = 964401592;
v11 = (char *)-1190422215;
v12 = (char *)-397809416;
v13 = 56201;
sub_401390(&v9);
*(_DWORD *)(a2 + 28) = (*(int (__stdcall **)(int, int *))(a2 + 8))(v8, &v9);
v9 = 1792596267;
v10 = -630679191;
v11 = (char *)155814809;
v12 = (char *)169;
sub_401390(&v9);
*(_DWORD *)(a2 + 32) = (*(int (__stdcall **)(int, int *))(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 a1, int 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 ( 1 )
{
v12 = *(_DWORD *)(v10 + 4);
if ( !v12 )
break;
v13 = v2 + *(_DWORD *)v10;
v14 = (_WORD *)(v10 + 8);
if ( v10 + 8 < 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 a1, int 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 ( 1 )
{
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 ( i = *v21; i; i = *v17 )
{
if ( i & 0x80000000 )
{
v14 = (*(int (__stdcall **)(int, _DWORD))(a2 + 8))(v9, (unsigned __int16)i);
}
else
{
v15 = (_BYTE *)(i + v2 + 2);
*(_WORD *)(i + v2) = 0;
v14 = (*(int (__stdcall **)(int, _BYTE *))(a2 + 8))(v9, v15);
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 a1, int 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 a1, int a2, int a3, int 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 **)(int, char *, signed int))(a2 + 20))(a1, &v22, 260);
v5 = (*(int (__stdcall **)(char *, unsigned int, signed int, _DWORD, signed int, signed int, _DWORD))(a2 + 24))(
&v22,
2147483648,
1,
0,
3,
128,
0);
v20 = v5;
v6 = v5 != -1;
v19 = 0;
if ( v5 != -1 )
{
v19 = (*(int (__stdcall **)(int, _DWORD, signed int, _DWORD, _DWORD, _DWORD))(a2 + 28))(v5, 0, 2, 0, 0, 0);
v6 = v19 != 0;
}
if ( v6 )
{
v7 = (*(int (__stdcall **)(int, signed int, _DWORD, _DWORD, _DWORD))(a2 + 32))(v19, 4, 0, 0, 0);
v6 = v7 != 0;
if ( v7 != 0 )
{
v8 = DOSorPE(a1);
v9 = v8[21];
v10 = *((_WORD *)v8 + 3);
v11 = 0;
if ( (signed int)(unsigned __int16)v10 > 0 )
{
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(v15, v16, *(_DWORD *)(a3 + 20), *(_DWORD *)a3);
}
else
{
v17 = *(_DWORD *)(a3 + 24) - v14 + 0x2000;
sub_401870(v15, v16, v17, *(_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 != -1 )
(*(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 + 4 - (_DWORD)(a2 + 1) - 4] = v3 ^ v5;
v6 = v4 * v4 ^ (v3 + v5 - v4);
++v4;
v3 = v6;
}
while ( v4 < 7 );
return *(_DWORD *)(a1 + 4) == 1313754955;
}
//----- (00401870) --------------------------------------------------------
signed int __cdecl sub_401870(int a1, char *a2, unsigned int a3, int a4)
{
int v4; // edx@1
signed int result; // eax@1
char *i; // esi@1
int v7; // edi@2
v4 = ~a3 + a4;
result = 0;
for ( i = a2; result < (signed int)(a3 >> 2); ++result )
{
v7 = *(_DWORD *)i;
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 - формат исполняемых файлов
Иначе говоря, тело проверяет, программа выполняет простую проверку.
Исходя из этого дадим имя этому телу, чтобы понимать сути её работы