Dreammmless.
-
Автор темы
- #1
Эта тема - перевод данной статьи -
Повествования будут вестись от лица автора оригинальной статьи.
Ну что ж, я просто начал реверсить некоторое время назад, и есть довольно популярный туториал по поиску ClientMode в разделе CS:GO, но он работает только для игр, которые являются > L4D2, что означает, что если вы хотите читерить в игре, такой как Double Action Boogaloo, CS:S, TF2 или любой другой игре, которая не сделана после L4D2, вы не сможете использовать эту строковую ссылку для поиска указателя на ClientMode.
Я тоже был затронут этой проблемой, поэтому вместо того, чтобы тратить свое время на перестройку WriteUsercmdDeltatoBuffer или подключение GetUserCmd (что даст вам все типы ошибок предикта), я просто нашел свой собственный способ найти ClientMode.
Без лишних слов давайте перейдем к этому, чтобы следовать этому уроку, было бы лучше, если бы у вас был такой инструмент, как IDA, и если у вас есть доступ к ним, двоичные файлы mac очень помогут в этом.
Во-первых, мы собираемся открыть IDA и загрузить client.dll, мы откроем окно strings и поищем "VEngineClient", который приведет нас к CHLClient::Init,
он выглядит примерно так.
Наведите курсор на ту часть, где написано ".text:XXXXXX" и нажмите клавишу F5, это приведет к декомпиляции функции, это должно выглядеть примерно так.
Во-первых, дайте ему имя, щелкнув правой кнопкой мыши на функцию (первая строка, обычно называется sub_XXXXXXXX) и нажав кнопку "Rename global item", давайте дадим ему имя "CHLClient::Init", затем мы щелкнем правой кнопкой мыши на функцию и нажмем кнопку "Jump to xref".
Теперь дважды щелкните, это приведет вас к CHLClient vtable, вот где происходит волшебство. Нам нужно будет знать, где находится HudUpdate, в большинстве игр это 11, но узнаем ли мы, находимся ли мы в HudUpdate? Ну, поскольку мне не повезло, мы не можем подсчитать аргументы, потому что функция имеет соглашение о вызове "userpurge", а это означает, что IDA на самом деле не уверена, каковы аргументы функции, однако внутри HudUpdate есть также строковые ссылки. Функция выглядит следующим образом.
Мы видим в этой функции следующее
Итак, что это значит? Мы можем просто искать "(time_int)", а также" (time_float)", и это должен быть HudUpdate. Взгляните сами на декомпилированную функцию.
Видите совпадения? Вот как мы узнаем, что HudUpdate - это функция, в которой мы сейчас находимся. Давайте дадим ей имя "CHLClient::HudUpdate", а затем мы вернемся к vtable тем же способом, что и здесь, щелкнув правой кнопкой мыши на функции и нажав кнопку "Jump to xref", а затем вернемся к таблице. Теперь у нас должно быть 2 функции в нашей таблице с именем "CHLClient__Init" и "CHLClient__HudUpdate", примерно так.
Теперь я знаю, что HudProcessInput имеет вызов ClientMode где-то в нем, я знаю это из-за Source SDK, который находится на GitHub. HudProcessInput выглядит так.
Вы можете видеть, что единственная вещь внутри него - это буквально вызов ClientMode, это создает небольшую функцию, которая означает, что мы можем найти именно то, что хотим, без каких-либо проблем, поэтому мы знаем, что таблица CHLClient имеет HudProcessInput, расположенный непосредственно под HudUpdate, но как мы это узнаем?
Взгляните на таблицу, вы сами все увидите. Я выделил его жирным шрифтом и для вас ( он не выделил ), на случай, если вы его пропустили, с помощью этой информации мы можем взять HudUpdate и вычесть из него индекс 1, который приведет нас к HudProcessInput, поэтому мы сделаем это, перейдя в HudUpdate в таблице CHLClient, а затем спустившись на одну, дважды щелкните по этой функции, а затем вы должны перейти к функции, которая выглядит примерно так.
У нас есть ссылка на ClientMode прямо там, в этом конкретном случае он называется "dword_105D4C98", точное положение которого таково
Теперь мы знаем, что ClientMode находится в client.dll + 0x05D4C98, но это бесполезно для нас, так как он будет сломан в следующем обновлении в любом случае! Мы собираемся "sig-нуть" эту функцию, таким образом, она сломается позже, мы собираемся нажать кнопку "Edit", затем выделить "Plugins" с помощью курсора, нажмите кнопку "SigMaker" и выберите Code Style, потому что это используют большинство pattern find функций (но вы выбираете именно ту опцию, которая подходит под вашу pattern find функцию) . Теперь в окне вывода появится подпись, она должна выглядеть примерно так.
Sigmaker для IDA 7.0 -
Но подождите, у нас проблема! Подпись не уникальна, как говорит IDA
Biggest possible signature is not unique, not going to bother searching any further.
Это означает, что если мы "sig-нем" с самого начала client.dll, мы заденем что-то другое! Это нехорошо, но решение есть! Мы можем взять CHLClient vtable и использовать функцию из него в качестве отправной точки, мы знаем, что HudProcessInput - это функция, которую мы использовали для поиска указателя, так почему бы нам не использовать ее и в качестве начальной точки? Ну, вот что мы сделаем, вот как выглядит мой код, если вам нужен примерный вид.
Теперь, иногда очень возможно, что индекс ClientMode CreateMove изменится, к счастью для вас (и для меня) есть урок, который объясняет, как это найти (гораздо лучше, чем объясняет мой урок)...) прямо здесь, на yougame, вы можете найти этот учебник здесь! Ревёрсинг в IDA, путь к нахождению ClientMode::CreateMove // на русском
Конец ?
Пожалуйста, авторизуйтесь для просмотра ссылки.
Повествования будут вестись от лица автора оригинальной статьи.
Ну что ж, я просто начал реверсить некоторое время назад, и есть довольно популярный туториал по поиску ClientMode в разделе CS:GO, но он работает только для игр, которые являются > L4D2, что означает, что если вы хотите читерить в игре, такой как Double Action Boogaloo, CS:S, TF2 или любой другой игре, которая не сделана после L4D2, вы не сможете использовать эту строковую ссылку для поиска указателя на ClientMode.
Я тоже был затронут этой проблемой, поэтому вместо того, чтобы тратить свое время на перестройку WriteUsercmdDeltatoBuffer или подключение GetUserCmd (что даст вам все типы ошибок предикта), я просто нашел свой собственный способ найти ClientMode.
Без лишних слов давайте перейдем к этому, чтобы следовать этому уроку, было бы лучше, если бы у вас был такой инструмент, как IDA, и если у вас есть доступ к ним, двоичные файлы mac очень помогут в этом.
Во-первых, мы собираемся открыть IDA и загрузить client.dll, мы откроем окно strings и поищем "VEngineClient", который приведет нас к CHLClient::Init,
он выглядит примерно так.
Наведите курсор на ту часть, где написано ".text:XXXXXX" и нажмите клавишу F5, это приведет к декомпиляции функции, это должно выглядеть примерно так.
Во-первых, дайте ему имя, щелкнув правой кнопкой мыши на функцию (первая строка, обычно называется sub_XXXXXXXX) и нажав кнопку "Rename global item", давайте дадим ему имя "CHLClient::Init", затем мы щелкнем правой кнопкой мыши на функцию и нажмем кнопку "Jump to xref".
Теперь дважды щелкните, это приведет вас к CHLClient vtable, вот где происходит волшебство. Нам нужно будет знать, где находится HudUpdate, в большинстве игр это 11, но узнаем ли мы, находимся ли мы в HudUpdate? Ну, поскольку мне не повезло, мы не можем подсчитать аргументы, потому что функция имеет соглашение о вызове "userpurge", а это означает, что IDA на самом деле не уверена, каковы аргументы функции, однако внутри HudUpdate есть также строковые ссылки. Функция выглядит следующим образом.
C++:
void CHLClient::HudUpdate( bool bActive )
{
float frametime = gpGlobals->frametime;
#if defined( TF_CLIENT_DLL )
CRTime::UpdateRealTime();
#endif
GetClientVoiceMgr()->Frame( frametime );
gHUD.UpdateHud( bActive );
{
C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false );
IGameSystem::UpdateAllSystems( frametime );
}
// run vgui animations
vgui::GetAnimationController()->UpdateAnimations( engine->Time() );
hudlcd->SetGlobalStat( "(time_int)", VarArgs( "%d", (int)gpGlobals->curtime ) );
hudlcd->SetGlobalStat( "(time_float)", VarArgs( "%.2f", gpGlobals->curtime ) );
// I don't think this is necessary any longer, but I will leave it until
// I can check into this further.
C_BaseTempEntity::CheckDynamicTempEnts();
#ifdef SIXENSE
// If we're not connected, update sixense so we can move the mouse cursor when in the menus
if( !engine->IsConnected() || engine->IsPaused() )
{
g_pSixenseInput->SixenseFrame( 0, NULL );
}
#endif
}
C++:
hudlcd->SetGlobalStat( "(time_int)", VarArgs( "%d", (int)gpGlobals->curtime ) );
hudlcd->SetGlobalStat( "(time_float)", VarArgs( "%.2f", gpGlobals->curtime ) );
Видите совпадения? Вот как мы узнаем, что HudUpdate - это функция, в которой мы сейчас находимся. Давайте дадим ей имя "CHLClient::HudUpdate", а затем мы вернемся к vtable тем же способом, что и здесь, щелкнув правой кнопкой мыши на функции и нажав кнопку "Jump to xref", а затем вернемся к таблице. Теперь у нас должно быть 2 функции в нашей таблице с именем "CHLClient__Init" и "CHLClient__HudUpdate", примерно так.
Теперь я знаю, что HudProcessInput имеет вызов ClientMode где-то в нем, я знаю это из-за Source SDK, который находится на GitHub. HudProcessInput выглядит так.
C++:
void CHLClient::HudProcessInput( bool bActive )
{
g_pClientMode->ProcessInput( bActive );
}
C++:
class CHLClient : public IBaseClientDLL
{
public:
CHLClient();
virtual int Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals );
virtual void PostInit();
virtual void Shutdown( void );
virtual bool ReplayInit( CreateInterfaceFn fnReplayFactory );
virtual bool ReplayPostInit();
virtual void LevelInitPreEntity( const char *pMapName );
virtual void LevelInitPostEntity();
virtual void LevelShutdown( void );
virtual ClientClass *GetAllClasses( void );
virtual int HudVidInit( void );
virtual void HudProcessInput( bool bActive );
virtual void HudUpdate( bool bActive );
virtual void HudReset( void );
virtual void HudText( const char * message );
// Mouse Input Interfaces
virtual void IN_ActivateMouse( void );
virtual void IN_DeactivateMouse( void );
virtual void IN_Accumulate( void );
virtual void IN_ClearStates( void );
virtual bool IN_IsKeyDown( const char *name, bool& isdown );
virtual void IN_OnMouseWheeled( int nDelta );
// Raw signal
virtual int IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding );
virtual void IN_SetSampleTime( float frametime );
// Create movement command
virtual void CreateMove ( int sequence_number, float input_sample_frametime, bool active );
virtual void ExtraMouseSample( float frametime, bool active );
virtual bool WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand );
virtual void EncodeUserCmdToBuffer( bf_write& buf, int slot );
virtual void DecodeUserCmdFromBuffer( bf_read& buf, int slot );
virtual void View_Render( vrect_t *rect );
virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw );
virtual void View_Fade( ScreenFade_t *pSF );
virtual void SetCrosshairAngle( const QAngle& angle );
virtual void InitSprite( CEngineSprite *pSprite, const char *loadname );
virtual void ShutdownSprite( CEngineSprite *pSprite );
virtual int GetSpriteSize( void ) const;
virtual void VoiceStatus( int entindex, qboolean bTalking );
virtual void InstallStringTableCallback( const char *tableName );
virtual void FrameStageNotify( ClientFrameStage_t curStage );
virtual bool DispatchUserMessage( int msg_type, bf_read &msg_data );
// Save/restore system hooks
virtual CSaveRestoreData *SaveInit( int size );
virtual void SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int );
virtual void SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int );
virtual void PreSave( CSaveRestoreData * );
virtual void Save( CSaveRestoreData * );
virtual void WriteSaveHeaders( CSaveRestoreData * );
virtual void ReadRestoreHeaders( CSaveRestoreData * );
virtual void Restore( CSaveRestoreData *, bool );
virtual void DispatchOnRestore();
virtual void WriteSaveGameScreenshot( const char *pFilename );
// Given a list of "S(wavname) S(wavname2)" tokens, look up the localized text and emit
// the appropriate close caption if running with closecaption = 1
virtual void EmitSentenceCloseCaption( char const *tokenstream );
virtual void EmitCloseCaption( char const *captionname, float duration );
virtual CStandardRecvProxies* GetStandardRecvProxies();
virtual bool CanRecordDemo( char *errorMsg, int length ) const;
virtual void OnDemoRecordStart( char const* pDemoBaseName );
virtual void OnDemoRecordStop();
virtual void OnDemoPlaybackStart( char const* pDemoBaseName );
virtual void OnDemoPlaybackStop();
virtual bool ShouldDrawDropdownConsole();
// Get client screen dimensions
virtual int GetScreenWidth();
virtual int GetScreenHeight();
// save game screenshot writing
virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/, bool bWriteVTF/*=false*/ );
// Gets the location of the player viewpoint
virtual bool GetPlayerView( CViewSetup &playerView );
// Matchmaking
virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties );
virtual uint GetPresenceID( const char *pIDName );
virtual const char *GetPropertyIdString( const uint id );
virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes );
virtual void StartStatsReporting( HANDLE handle, bool bArbitrated );
virtual void InvalidateMdlCache();
virtual void ReloadFilesInList( IFileList *pFilesToReload );
// Let the client handle UI toggle - if this function returns false, the UI will toggle, otherwise it will not.
virtual bool HandleUiToggle();
// Allow the console to be shown?
virtual bool ShouldAllowConsole();
// Get renamed recv tables
virtual CRenamedRecvTableInfo *GetRenamedRecvTableInfos();
// Get the mouthinfo for the sound being played inside UI panels
virtual CMouthInfo *GetClientUIMouthInfo();
// Notify the client that a file has been received from the game server
virtual void FileReceived( const char * fileName, unsigned int transferID );
virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName );
virtual void ClientAdjustStartSoundParams( struct StartSoundParams_t& params );
// Returns true if the disconnect command has been handled by the client
virtual bool DisconnectAttempt( void );
public:
void PrecacheMaterial( const char *pMaterialName );
virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar );
private:
void UncacheAllMaterials( );
void ResetStringTablePointers();
CUtlVector< IMaterial * > m_CachedMaterials;
};
У нас есть ссылка на ClientMode прямо там, в этом конкретном случае он называется "dword_105D4C98", точное положение которого таково
C++:
.text:1009A4F3 mov ecx, dword_105D4C98
Sigmaker для IDA 7.0 -
Пожалуйста, авторизуйтесь для просмотра ссылки.
, если вы сами не смогли найти.Но подождите, у нас проблема! Подпись не уникальна, как говорит IDA
Biggest possible signature is not unique, not going to bother searching any further.
Это означает, что если мы "sig-нем" с самого начала client.dll, мы заденем что-то другое! Это нехорошо, но решение есть! Мы можем взять CHLClient vtable и использовать функцию из него в качестве отправной точки, мы знаем, что HudProcessInput - это функция, которую мы использовали для поиска указателя, так почему бы нам не использовать ее и в качестве начальной точки? Ну, вот что мы сделаем, вот как выглядит мой код, если вам нужен примерный вид.
C++:
client = createinterface<cclient*>("client.dll", "VClient017");
DWORD* clienttable = (DWORD*) *(DWORD*) client;
clientmode = **(clientmodeshared***) (util::findpattern(clienttable[10], 0x100, "\x8B\x0D\x00\x00\x00\x00\x8B", "xx????x") + 0x02);
VMT *vmt_client = new VMT(clientmode);
vmt_client->hook(24, hookmngr::createmove, 0);
Конец ?