Pisanie cheatów pod CS 1.6 pliki *.ASI w kliencie

Od razu zaznaczam w wpisie nie znajdziecie wpełni działającego kodu cheat’a do CS 1.6. Cały wpis powstał podczas pisania własnego cheata zawierającego

  • WH
  • ESP
  • Anty SS

Jednak już po napisaniu projekt zdecydowałem się na nie udostępnianie go dalej czy pokazywanie kodu. Spowodowane jest to przemyśleniem czy warto psuć dalej grę.

Wiele nauczyłem się podczas pisania tego jednak nie chce aby w jakiś zły sposób wpłynęło na społeczność graczy.

Pliki ASI są plikami pozwalającymi na załadowanie dowolnej dynamicznej biblioteki ( DLL ) do procesu gry. Popularną modyfikacją wykorzystującą ten plik jest CSX Guard

CSX Guard jest modyfikacją napisaną w delphi ja skupie się na pisaniu w C++.

Pliki ASI działają we wszystkich grach opartych na silniku GoldSrc ( Half-Life , CS 1.6 itp. itd. ).

Silnik GoldSrc wykorzystuje dll’ke mss32.dll która ładuje wszystkie pliki asi z głównego katalogu gry jako normalna dll’ka ( ale z innym rozszerzeniem ).

Dla starszych wersji engine np. 4554 Dllka jest ładowanie normalnie poprzez DllMain ale od nowszych wersji np. 6027 musimy już ładować nasz kod poprzez Rib_Main.

Do naszego projektu potrzebujemy niektórych plików z HLSDK można je ściągnąć stąd lub z mojej strony darkHack.zip Download

Cały projekt składa się z dwóch plików AsiMain.cpp oraz AsiMain.h

Zawartość AsiMain.cpp

#include "HLSDK/stdafx.h"
#include "AsiMain.h"

extern "C" DLLEXPORT S32 AILCALL RIB_Main(HPROVIDER provider_handle,
										U32 up_down,
										RIB_alloc_provider_handle_ptr RIB_alloc_provider_handle,
										RIB_register_interface_ptr RIB_register_interface,
										RIB_unregister_interface_ptr RIB_unregister_interface
										)
{
    if(up_down)
    {
		//code loaded
	}
	else
	{
		//code on unload
	}
	return 1;
}

Zawartość AsiMain.h

#ifdef _WIN32
#define AILCALL        __stdcall
#else
#define AILCALL
#endif

#ifndef C8
#define C8 char
#endif

#ifndef U32
#define U32 unsigned int
#endif

#ifndef S32
#define S32 signed int
#endif

#ifndef UINTa
#define UINTa unsigned int
#endif

#define FAR

typedef U32 HPROVIDER;
typedef S32 RIBRESULT;

typedef enum
{
   RIB_NONE = 0, // No type
   RIB_CUSTOM,   // Used for pointers to application-specific structures
   RIB_DEC,      // Used for 32-bit integer values to be reported in decimal
   RIB_HEX,      // Used for 32-bit integer values to be reported in hex
   RIB_FLOAT,    // Used for 32-bit single-precision FP values
   RIB_PERCENT,  // Used for 32-bit single-precision FP values to be reported as percentages
   RIB_BOOL,     // Used for Boolean-constrained integer values to be reported as TRUE or FALSE
   RIB_STRING,   // Used for pointers to null-terminated ASCII strings
   RIB_READONLY = 0x80000000  // Property is read-only
}
RIB_DATA_SUBTYPE;

typedef enum
{
   RIB_FUNCTION = 0,
   RIB_PROPERTY       // Property: read-only or read-write data type
}
RIB_ENTRY_TYPE;

typedef struct
{
   RIB_ENTRY_TYPE   type;
   C8 FAR *entry_name;
   UINTa            token;
   RIB_DATA_SUBTYPE subtype;     // Property subtype
}
RIB_INTERFACE_ENTRY;


typedef HPROVIDER	(*RIB_alloc_provider_handle_ptr) (long module);
typedef RIBRESULT	(*RIB_register_interface_ptr) (HPROVIDER  provider, C8 const FAR *interface_name, S32 entry_count, RIB_INTERFACE_ENTRY const FAR *rlist);
typedef RIBRESULT	(*RIB_unregister_interface_ptr)  (HPROVIDER  provider, C8 const FAR *interface_name, S32 entry_count, RIB_INTERFACE_ENTRY const FAR *rlist);

extern "C" DLLEXPORT S32 AILCALL RIB_Main(HPROVIDER provider_handle,
										U32 up_down,
										RIB_alloc_provider_handle_ptr RIB_alloc_provider_handle,
										RIB_register_interface_ptr RIB_register_interface,
										RIB_unregister_interface_ptr RIB_unregister_interface
										);

Kod powyżej tak naprawdę nie robi nić możemy do niego dodać ładowanie naszej biblioteki poprzez np.

HINSTANCE LoadME;
LoadMe = LoadLibrary("..\\enter a Path To Your Dll here\\LoadMe.dll");

if (LoadMe != 0)
    printf("LoadMe library loaded!\n");
else
    printf("LoadMe library failed to load!\n");

Spróbujmy dodać teraz kod będzie reagował na komendę w konsoli i wypisywał coś do niej.

Na początku potrzebujemy IDA PRO lub programu podobnego do niego.

Otwieramy plik hw.so i zaczynamy jego analizę następnie Edit-> Segments-> Rebase Program i ustawiamy ImageBase na on 0x40000000.

Szukamy ScreenShake.
acec8b202f2a4d5a6085f3d398a89efc
e3fd890fbac2f16a30511196c94a8704

Znajdujemy adres cl_enginefuncs w hw.so. Według IDE PRO jest to 0x40134260. Jako że ImageBase to 0x40000000, offset dla tej struktury jest równy 0x134260.

W AsiMain.cpp deklarujemy

cl_enginefunc_t *cl_enginefuncs;

Przed RibMain deklarujemy funkcje

void Hello()
{
	cl_enginefuncs->Con_Printf("Hello You!\n");
}

W RibMain dodajemy

HANDLE hw=LoadLibraryA("hw.dll");
cl_enginefuncs=(cl_enginefunc_t*)((unsigned long)hw+0x134260);
cl_enginefuncs->pfnAddCommand("SayHello",Hello);

Po wpisaniu w konsole SayHello dostaniemy wiadomość Hello You!

Paczka projektu:
darkHack.zip Download

Dodaj komentarz