Raised This Month: $128 Target: $400
 32% 

DHooks (Dynamic Hooks - Dev Preview)


Post New Thread Reply   
 
Thread Tools Display Modes
ayrton09_arg
Senior Member
Join Date: Nov 2017
Old 04-24-2019 , 09:14   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #661

Quote:
Originally Posted by Xutax_Kamay View Post
Okay I'm pretty dumb
https://github.com/XutaxKamay/dhooks...es/tag/v2.2.1b

That should fix the issue, the issue was because I was getting a wrong idea of using that ke::Vector thing (the amtl didn't prove push_back so i just replaced by append, but that turned out to be a mistake), I use std::vector now, hopefully you shouldn't have link errors during load, but definitly needs a change later, I just did it for a hotpatch
with latest dev sm 1.10 i got this error : <FAILED> file "dhooks.ext.dll": Could not find interface: IBinTools
ayrton09_arg is offline
xkonsole
AlliedModders Donor
Join Date: Mar 2018
Old 04-26-2019 , 09:44   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #662

Quote:
Originally Posted by ayrton09_arg View Post
with latest dev sm 1.10 i got this error : <FAILED> file "dhooks.ext.dll": Could not find interface: IBinTools
Same.

Though this
Quote:
Originally Posted by TheByKotik View Post
Can someone test it?
It's Rayan's dhooks-detours7-for-sourcemod-1.10 from https://forums.alliedmods.net/showthread.php?p=2628691
Build SM-10 + MM-10 + clang-8 + Debian 9.
Works on latest available dev build.
output
xkonsole is offline
Xutax_Kamay
Member
Join Date: Feb 2016
Old 04-26-2019 , 16:34   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #663

https://github.com/XutaxKamay/dhooks...es/tag/v2.2.1c
Should work for SM 1.10 now
Xutax_Kamay is offline
Spirit_12
Veteran Member
Join Date: Dec 2012
Location: Toronto, CA
Old 04-28-2019 , 23:14   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #664

This might be an odd question but how much speed difference is there between coding a function in extension or hooking it via DHooks Detour? I'm aware its not really noticeable in game, but what are the benefits of going extension over Dhooks?
__________________
Spirit_12 is offline
Xutax_Kamay
Member
Join Date: Feb 2016
Old 04-29-2019 , 14:17   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #665

Quote:
Originally Posted by ayrton09_arg View Post
with latest dev sm 1.10 i got this error : <FAILED> file "dhooks.ext.dll": Could not find interface: IBinTools
Quote:
Originally Posted by xkonsole View Post
Same.

Though this


Works on latest available dev build.
output
Quote:
Originally Posted by Spirit_12 View Post
This might be an odd question but how much speed difference is there between coding a function in extension or hooking it via DHooks Detour? I'm aware its not really noticeable in game, but what are the benefits of going extension over Dhooks?
In short, DHooks works only for virtual functions and detouring is a more general approach where you can hook any type of function

It's not really noticeable as you guess (depending on what you're doing), I'm not an expert at detouring functions but the idea behind it is to copy instructions of the original function somewhere else in case you want to callback it and you place a jmp inside the original function so it calls your new function.
The main difference with virtual table hooking and detour hooking is that you actually replace the virtual function inside the virtual table by your own "new virtual function" and since the address to call in assembly is computed "dynamically", you don't need to do it like detours in case you want to callback the original function. Hope it helps to understand how it works.

Another method that can work greatly for detours is to search for all the callers for the function and replace the original call by your own. But it can varies depending on compiler options (like relative jump, call instructions, or even ret instruction and so on)

Here an older approach I've tried of how it would work:
Code:
class CHookCall
{
public:

    CHookCall( Pointer pFunction , Pointer pNewFunction )
        : m_FoundFunctionsRVACall( 0 ) , m_pFunction( nullptr ) , m_pNewFunction( nullptr ) , m_pOldRelativeRVA( nullptr )
    {
        m_pFunction = pFunction;
        m_pNewFunction = pNewFunction;
    }

    ~CHookCall()
    {
        UnHook();
        m_FoundFunctionsRVACall.clear();
        m_pFunction = nullptr;
        m_pNewFunction = nullptr;
        m_pOldRelativeRVA = nullptr;
    }

    auto Hook() -> bool
    {
        auto pDosHeader = ( PIMAGE_DOS_HEADER ) FindModule();

        if ( !IsPointer( pDosHeader ) )
            return false;

        auto pNtHeaders = reinterpret_cast< pNTHeaders >( ( reinterpret_cast< uintptr_t >( pDosHeader ) + pDosHeader->e_lfanew ) );

        auto FunctionRVA = reinterpret_cast< uintptr_t >( m_pFunction ) - reinterpret_cast< uintptr_t >( pDosHeader );

        auto ImageSize = pNtHeaders->OptionalHeader.SizeOfImage;

        auto TempModule = Alloc<uintptr_t>( ImageSize );

        // We copy the module so we don't need to change all the protections on it.

        memcpy( ( Pointer ) TempModule , pDosHeader , ImageSize );

        for ( uintptr_t Slot = 0; Slot != ImageSize; Slot++ )
        {
            auto Address = TempModule + Slot;

            BYTE ByteRead = Read<BYTE>( Address );

            if ( ByteRead == 0xE8
                 || ByteRead == 0xE9 )
            {
                // Let's check if it's what we wanted.

                // call 0x...
                // call RelativeAddress ( FunctionToCall - ( FunctionFromBeingCalled + sizeof( Pointer ) ) )
                // or
                // jmp 0x...
                // jmp RelativeAddress ( FunctionToCall - ( FunctionFromBeingCalled + sizeof( Pointer ) ) )

                auto RelativeAddress = Read<uintptr_t>( Address + 1 );

                // + 1 byte for call opcode, and add a size of a pointer
                // because the CPU call our function once it has finished to read the address.

                auto CalledFrom = Address + 1 + sizeof( Pointer );

                auto CalledFromRVA = CalledFrom - TempModule;

                auto CalledFunctionRVA = RelativeAddress + CalledFromRVA;

                // Is That our function ?

                if ( CalledFunctionRVA == FunctionRVA )
                {
                    // Yup.
                    m_FoundFunctionsRVACall.push_back( CalledFromRVA - sizeof( Pointer ) );
                }
            }
        }

        for ( auto && FunctionRVACall : m_FoundFunctionsRVACall )
        {
            auto CallerAddress = reinterpret_cast< uintptr_t >( pDosHeader ) + FunctionRVACall;

            // We want to access it.

            DWORD dwOldFlag;
            if ( VirtualProtect( reinterpret_cast< Pointer >( CallerAddress ) , sizeof( CallerAddress ) , PAGE_EXECUTE_READWRITE , &dwOldFlag ) )
            {
                uintptr_t *pWriteAddress = Write<uintptr_t>( CallerAddress );

                m_pOldRelativeRVA = reinterpret_cast< Pointer >( *pWriteAddress );

                // Add a size of a pointer because the CPU call our function once it has finished to read the address.
                *pWriteAddress = reinterpret_cast< uintptr_t >( m_pNewFunction ) - ( CallerAddress + sizeof( Pointer ) );

                if ( !VirtualProtect( reinterpret_cast< Pointer >( CallerAddress ) , sizeof( CallerAddress ) , dwOldFlag , &dwOldFlag ) )
                {
                    return false;
                }
            }
        }

        FreeS( TempModule );

        PrintConsole( FOREGROUND_GREEN , TEXT( "Found %i references for 0x%p\n" ) , m_FoundFunctionsRVACall.size() , m_pFunction );

        return m_FoundFunctionsRVACall.size() != 0;
    }

    auto FindModule() -> Pointer
    {
        Pointer pProcess = GetCurrentProcess();

        auto SnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE , GetProcessId( pProcess ) );

        MODULEENTRY32 ModuleEntry;
        auto FirstModule = Module32First( SnapShot , &ModuleEntry );

        if ( IsPointer( FirstModule ) )
        {
            do
            {
                auto ModuleBase = reinterpret_cast< uintptr_t >( ModuleEntry.hModule );
                auto Function = reinterpret_cast< uintptr_t >( m_pFunction );

                if ( ( Function >= ModuleBase )
                     && ( Function < ( ModuleBase + ModuleEntry.modBaseSize ) ) )
                {
                    CloseHandle( SnapShot );

                    return ModuleEntry.hModule;
                }
            } while ( Module32Next( SnapShot , &ModuleEntry ) );
        }

        CloseHandle( SnapShot );

        return nullptr;
    }

    auto UnHook() -> bool
    {
        auto pDosHeader = ( PIMAGE_DOS_HEADER ) FindModule();

        if ( !IsPointer( pDosHeader ) )
            return false;

        for ( auto && FunctionRVACall : m_FoundFunctionsRVACall )
        {
            auto CallerAddress = reinterpret_cast< uintptr_t >( pDosHeader ) + FunctionRVACall;

            DWORD dwOldFlag;
            if ( VirtualProtect( reinterpret_cast< Pointer >( CallerAddress ) , sizeof( CallerAddress ) , PAGE_EXECUTE_READWRITE , &dwOldFlag ) )
            {
                uintptr_t *pWriteAddress = Write<uintptr_t>( CallerAddress );

                // Push back the old function.
                *pWriteAddress = reinterpret_cast< uintptr_t >( m_pOldRelativeRVA );

                if ( !VirtualProtect( reinterpret_cast< Pointer >( CallerAddress ) , sizeof( CallerAddress ) , dwOldFlag , &dwOldFlag ) )
                {
                    return false;
                }
            }
        }

        m_FoundFunctionsRVACall.clear();

        return true;
    }

    FORCEINLINE auto GetFunction() -> Pointer
    {
        return m_pFunction;
    }

    FORCEINLINE auto GetNewFunction() -> Pointer
    {
        return m_pNewFunction;
    }

    template< typename RetType = void , typename ... vArgs >
    constexpr FORCEINLINE auto CallFunction( vArgs ... pArgs )->RetType
    {
        return ( ( RetType( __cdecl* )( vArgs ... ) ) m_pFunction )( pArgs ... );
    }

private:
    std::vector<uintptr_t> m_FoundFunctionsRVACall;
    Pointer m_pOldRelativeRVA , m_pNewFunction , m_pFunction;
};
But basically you would need a decompiler/disass to do the work properly

Last edited by Xutax_Kamay; 04-29-2019 at 14:28.
Xutax_Kamay is offline
Spirit_12
Veteran Member
Join Date: Dec 2012
Location: Toronto, CA
Old 04-30-2019 , 00:03   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #666

I think what I was going for was that if I'm to detour a lot of functions then should I stick to Dhooks or should I go extension approach.
__________________
Spirit_12 is offline
Dr!fter
The Salt Boss
Join Date: Mar 2007
Old 04-30-2019 , 05:53   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #667

The only real overhead compared to just using an extension is the decoding of the parameters really. The concept of detours won’t change. I never actually compared the two but I doubt it’s noticeable. Same goes for hooks. It becomes what’s easier to use and update. This doesn’t rely on any sdk, so game updates don’t break it (unless one of my sdkhacks change, they probably won’t). If your function changes you just change the gamedata/plugin vs changing the extension/forward/plugin.
Dr!fter is offline
hmmmmm
Great Tester of Whatever
Join Date: Mar 2017
Location: ...
Old 04-30-2019 , 07:11   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #668

If possible, I'd recommend going with a plugin using DHooks detours. The gamedata management is much easier (no re-compiling necessary + easier to get a general overview) and also you get easy cross-compatibility as well as a simpler building/compiling process. It'll be a lot more accessible to everyone via plugin.

Obviously there will always be cases where doing something through DHooks detours won't be possible due to the limitations of plugins, and also sometimes memory-hacking-heavy setups can be a pain to do via SP, in which case you should go with an extension.
hmmmmm is offline
Spirit_12
Veteran Member
Join Date: Dec 2012
Location: Toronto, CA
Old 04-30-2019 , 10:09   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #669

Thanks for your explanations. I think Iíll stick to plugins and port most of my stuff from L4Downtown.

I find Dhooks much easier to work with, but Iíll be hooking 20+ functions and just wanted to know if Iíll be losing performance.
__________________
Spirit_12 is offline
Powerlord
AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
Old 04-30-2019 , 14:07   Re: DHooks (Dynamic Hooks - Dev Preview)
Reply With Quote #670

Quote:
Originally Posted by Dr!fter View Post
The only real overhead compared to just using an extension is the decoding of the parameters really. The concept of detours wonít change. I never actually compared the two but I doubt itís noticeable. Same goes for hooks. It becomes whatís easier to use and update. This doesnít rely on any sdk, so game updates donít break it (unless one of my sdkhacks change, they probably wonít). If your function changes you just change the gamedata/plugin vs changing the extension/forward/plugin.
You forgot to mention that you only need one extension recompiled (DHooks itself) when you change to newer versions of SourceMod rather than recompiling all of them.
__________________
Not currently working on SourceMod plugin development.
Powerlord is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 16:26.


Powered by vBulletin®
Copyright ©2000 - 2021, vBulletin Solutions, Inc.
Theme made by Freecode