Гайд Поиск указателя на ClientMode // на русском

Dreammmless.
Эксперт
Статус
Оффлайн
Регистрация
19 Мар 2019
Сообщения
2,956
Реакции[?]
962
Поинты[?]
1K
Эта тема - перевод данной статьи -
Пожалуйста, авторизуйтесь для просмотра ссылки.

Повествования будут вестись от лица автора оригинальной статьи.



Ну что ж, я просто начал реверсить некоторое время назад, и есть довольно популярный туториал по поиску 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 ) );
Итак, что это значит? Мы можем просто искать "(time_int)", а также" (time_float)", и это должен быть HudUpdate. Взгляните сами на декомпилированную функцию.



Видите совпадения? Вот как мы узнаем, что 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 );
}
Вы можете видеть, что единственная вещь внутри него - это буквально вызов ClientMode, это создает небольшую функцию, которая означает, что мы можем найти именно то, что хотим, без каких-либо проблем, поэтому мы знаем, что таблица CHLClient имеет HudProcessInput, расположенный непосредственно под HudUpdate, но как мы это узнаем?

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;
};
Взгляните на таблицу, вы сами все увидите. Я выделил его жирным шрифтом и для вас ( он не выделил ), на случай, если вы его пропустили, с помощью этой информации мы можем взять HudUpdate и вычесть из него индекс 1, который приведет нас к HudProcessInput, поэтому мы сделаем это, перейдя в HudUpdate в таблице CHLClient, а затем спустившись на одну, дважды щелкните по этой функции, а затем вы должны перейти к функции, которая выглядит примерно так.



У нас есть ссылка на ClientMode прямо там, в этом конкретном случае он называется "dword_105D4C98", точное положение которого таково

C++:
.text:1009A4F3                 mov     ecx, 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 - это функция, которую мы использовали для поиска указателя, так почему бы нам не использовать ее и в качестве начальной точки? Ну, вот что мы сделаем, вот как выглядит мой код, если вам нужен примерный вид.

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);
Теперь, иногда очень возможно, что индекс ClientMode CreateMove изменится, к счастью для вас (и для меня) есть урок, который объясняет, как это найти (гораздо лучше, чем объясняет мой урок)...) прямо здесь, на yougame, вы можете найти этот учебник здесь! Ревёрсинг в IDA, путь к нахождению ClientMode::CreateMove // на русском


Конец ?
 
Сверху Снизу