Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2023 Offsets #12

Open
ClaudiuHKS opened this issue Dec 6, 2023 · 1 comment
Open

2023 Offsets #12

ClaudiuHKS opened this issue Dec 6, 2023 · 1 comment

Comments

@ClaudiuHKS
Copy link

ClaudiuHKS commented Dec 6, 2023

#define CS_BOTS 0xE8, '*', '*', '*', '*'

#ifdef WIN32

#define CS_BOTS_W CS_BOTS, 0x83, 0xC4, 0x04, 0x84, 0xC0, '*', '*', '*', '*', '*', '*'

unsigned char CS_BOTS_RADIO[]{ CS_BOTS_W, '*', '*', 0xE8, '*', '*', '*', '*', 0x83, }; // phraseMan

unsigned char CS_BOTS_PROFILES[]{ CS_BOTS_W, 0x57, 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xE9, };
unsigned char CS_BOTS_CON_VARS[]{ CS_BOTS_W, 0x68, '*', '*', '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xFF, };
unsigned char CS_BOTS_CON_CMDS_REG[]{ CS_BOTS_W, 0x8B, '*', 0x8B, '*', 0x68, '*', '*', '*', '*', 0xFF, '*', '*', 0x8B, '*', 0x8B, '*', 0x68, };
unsigned char CS_BOTS_CON_CMDS_EXEC[]{ CS_BOTS_W, 0x56, 0x8B, '*', '*', 0xB9, '*', '*', '*', '*', 0x8B, '*', 0x0F, };
unsigned char CS_BOTS_MAP_NAV[]{ CS_BOTS_W, 0xC6, '*', '*', '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x85, '*', 0x74, '*', 0x68, };
unsigned char CS_BOTS_MANAGER[]{ CS_BOTS_W, '*', '*', 0x83, '*', '*', 0x75, '*', 0x8B, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xFF, }; // addBot

unsigned char CS_BOTS_DISPLAY[]{ CS_BOTS, 0x83, '*', '*', 0x80, '*', '*', '*', 0x74, '*', 0x8B, '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x6A, '*', 0x6A, '*', 0x6A, '*', 0xFF, '*', '*', '*', '*', '*', 0x6A, '*', 0xFF, }; // clientPrint #Game_radio_loc...

#else

#define CS_BOTS_L CS_BOTS, 0x83, 0xC4, 0x10, 0x84, 0xC0, '*', '*', '*', '*', '*', '*'

unsigned char CS_BOTS_RADIO[]{ CS_BOTS_L, 0x83, '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x83, '*', '*', 0x31, '*', 0xE9, }; // phraseMan

unsigned char CS_BOTS_PROFILES[]{ CS_BOTS, 0x84, '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', 0xC7, '*', '*', '*', '*', '*', '*', 0x89, '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xE9, };
unsigned char CS_BOTS_CON_VARS[]{ CS_BOTS_L, 0x83, '*', '*', 0x68, '*', '*', '*', '*', 0xFF, '*', '*', '*', '*', '*', 0xC7, '*', '*', '*', '*', '*', '*', 0xFF, };
unsigned char CS_BOTS_CON_CMDS_REG[]{ CS_BOTS_L, '*', 0x68, '*', '*', '*', '*', 0x53, 0xFF, '*', '*', 0x58, 0x8B, '*', 0x5A, 0x68, '*', '*', '*', '*', 0x53, 0xFF, '*', '*', 0x59, 0x58, 0x8B, };
unsigned char CS_BOTS_CON_CMDS_EXEC[]{ CS_BOTS_L, '*', '*', 0xBF, '*', '*', '*', '*', 0xB9, '*', '*', '*', '*', 0xF3, '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0xBF, };
unsigned char CS_BOTS_MAP_NAV[]{ CS_BOTS_L, '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x85, '*', 0x0F, '*', '*', '*', '*', '*', 0x83, '*', '*', 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xA1, };
unsigned char CS_BOTS_MANAGER[]{ CS_BOTS_L, 0x83, '*', '*', 0x89, '*', 0x8B, '*', '*', '*', '*', '*', 0x0F, '*', '*', '*', '*', '*', 0x85, '*', 0x0F, '*', '*', '*', '*', '*', 0x83, '*', '*', 0x0F, }; // addBot

unsigned char CS_BOTS_DISPLAY[]{ CS_BOTS, 0x80, '*', '*', '*', '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', 0x31, '*', 0xBB, '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0x89, '*', '*', '*', 0x89, }; // clientPrint #Game_radio_loc...

#endif

Use Orpheu to patch void CHostage::IdleThink(void).

The \steamapps\common\Half-Life\cstrike\addons\amxmodx\configs\orpheu\functions\CHostage\IdleThink file.

{
    "name"          : "IdleThink",
    "class"         : "CHostage",
    "library"       : "mod",
    "identifiers"   :
    [
        {
            "os"    : "windows",
            "mod"   : "cstrike",
            "value" : "?IdleThink@CHostage@@QAEXXZ"
        },
        {
            "os"    : "linux",
            "mod"   : "cstrike",
            "value" : "_ZN8CHostage9IdleThinkEv"
        }
    ]
}
#pragma tabsize 0
#pragma semicolon 0
#pragma ctrlchar '\'
#pragma dynamic 4194304

#include <amxmodx>

#tryinclude <amxmisc>

/// #include <fun>
/// #include <csx>
/// #include <json>
/// #include <sqlx>
/// #include <geoip>
/// #include <regex>
/// #include <engine>
/// #include <nvault>
/// #include <cstrike>
/// #include <sockets>
/// #include <fakemeta>
/// #include <hamsandwich>

#include <orpheu>

#tryinclude <orpheu_memory>

public plugin_init()
{
    register_plugin("CS Block Hostage Think", __DATE__, "Hattrick HKS (Caramel)");

    return PLUGIN_CONTINUE;
}

public plugin_precache()
{
    new OrpheuFunction: eOnHostageIdleThink = OrpheuGetFunction("IdleThink", "CHostage");

    if (OrpheuInvalidFunction != eOnHostageIdleThink)
    {
        OrpheuRegisterHook(eOnHostageIdleThink, "OnHostageIdleThink_PRE", OrpheuHookPre);
    }

    return PLUGIN_CONTINUE;
}

public OrpheuHookReturn: OnHostageIdleThink_PRE(nHostage)
{
    return OrpheuSupercede;
}

Wasn't able to test the Linux signatures. EDIT: Tested, working.

void CHostage::IdleThink(void) L/ W Signatures (To Block This Function)

L/ 57 56 53 83 ?? ?? 81 ?? ?? ?? ?? ?? ?? ?? ?? ?? 8B ?? ?? ?? 0F ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 85 ?? 0F
W/ 55 8B ?? 6A ?? 68 ?? ?? ?? ?? 64 ?? ?? ?? ?? ?? 50 83 ?? ?? 53 56 57 A1 ?? ?? ?? ?? 33 ?? 50 8D ?? ?? 64 ?? ?? ?? ?? ?? 8B ?? 83 ?? ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 75 ?? 85 ?? 74 ?? 8B ?? 6A ?? FF

[Update on Dec. 17, 2013] Patching void CHostage::IdleThink(void)/ blocking its execution will cause hostages to not work anymore. So:

#define CS_BOTS 0xE8, '*', '*', '*', '*'

#ifdef WIN32

#define CS_BOTS_W CS_BOTS, 0x83, 0xC4, 0x04, 0x84, 0xC0, '*', '*', '*', '*', '*', '*'

unsigned char CS_BOTS_RADIO[]{ CS_BOTS_W, '*', '*', 0xE8, '*', '*', '*', '*', 0x83, };                                                                                                                                          /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `int __cdecl BotPhraseManager::Initialize (BotPhraseManager * this, char * a2, int a3)` ( LINUX )

unsigned char CS_BOTS_PROFILES[]{ CS_BOTS_W, 0x57, 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xE9, };                                                                                                                 /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl BotProfileManager::Init (BotProfileManager * const this, char * filename, unsigned int * checksum)` ( LINUX )
unsigned char CS_BOTS_CON_VARS[]{ CS_BOTS_W, 0x68, '*', '*', '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xFF, };                                                                                        /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void Bot_RegisterCvars (void)` ( LINUX )
unsigned char CS_BOTS_CON_CMDS_REG[]{ CS_BOTS_W, 0x8B, '*', 0x8B, '*', 0x68, '*', '*', '*', '*', 0xFF, '*', '*', 0x8B, '*', 0x8B, '*', 0x68, };                                                                                 /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl CCSBotManager::AddServerCommands (CCSBotManager * this)` ( LINUX )
unsigned char CS_BOTS_CON_CMDS_EXEC[]{ CS_BOTS_W, 0x56, 0x8B, '*', '*', 0xB9, '*', '*', '*', '*', 0x8B, '*', 0x0F, };                                                                                                           /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `unsigned int __cdecl CCSBotManager::ServerCommand (CCSBotManager * this, const char * a2)` ( LINUX )
unsigned char CS_BOTS_MAP_NAV[]{ CS_BOTS_W, 0xC6, '*', '*', '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x85, '*', 0x74, '*', 0x68, };                                                                                        /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl CCSBotManager::ValidateMapData (CCSBotManager * this)` ( LINUX )
unsigned char CS_BOTS_MANAGER[]{ CS_BOTS_W, '*', '*', 0x83, '*', '*', 0x75, '*', 0x8B, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xFF, };                                                                              /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `int __usercall CCSBotManager::AddBot @ <eax> (int a1 @ <edi>, BotProfile * this, const BotProfile * a3)` ( LINUX )

unsigned char CS_BOTS_DISPLAY[]{ CS_BOTS, 0x83, '*', '*', 0x80, '*', '*', '*', 0x74, '*', 0x8B, '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x6A, '*', 0x6A, '*', 0x6A, '*', 0xFF, '*', '*', '*', '*', '*', 0x6A, '*', 0xFF, };    /// `void __cdecl ClientPrint (entvars_t * client, int msg_dest, const char * msg_name, const char * param1, const char * param2, const char * param3, const char * param4)` CALL WITH "#Game_radio_location" PARAMETER INSIDE FUNCTION `void __cdecl CBasePlayer::Radio (CBasePlayer * const this, const char * msg_id, const char * msg_verbose, __int16 pitch, bool showIcon)` ( LINUX )

unsigned char CS_BOTS_HOSTAGE[]{ 0x55, 0x8B, '*', 0x6A, '*', 0x68, '*', '*', '*', '*', 0x64, '*', '*', '*', '*', '*', 0x50, 0x83, '*', '*', 0x53, 0x56, 0x57, 0xA1, '*', '*', '*', '*', 0x33, '*', 0x50, 0x8D, '*', '*',        /// `void __thiscall CHostage::IdleThink (CHostage * this)` FUNCTION ( WINDOWS )
0x64, '*', '*', '*', '*', '*', 0x8B, '*', 0x83, '*', '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0x75, '*', 0x85, '*', 0x74, '*', 0x8B, '*', 0x6A, '*', 0xFF, };                                                    /// `void __cdecl CHostage::IdleThink (CHostage * const this)` FUNCTION ( LINUX )

unsigned char CS_BOTS_IMPROV[]{ 0x53, 0x8B, '*', 0x83, '*', '*', 0x83, '*', '*', 0x83, '*', '*', 0x55, 0x8B, '*', '*', 0x89, '*', '*', '*', 0x8B, '*', 0x6A, '*', 0x68, '*', '*', '*', '*', 0x64, '*', '*', '*', '*', '*',      /// `int * __userpurge sub_1004DBB0 @ <eax> (int * a1 @ <ecx>, int a2 @ <edi>, int a3 @ <esi>, int a4)` FUNCTION ( WINDOWS )
0x50, 0x53, 0x83, '*', '*', 0x56, 0x57, 0xA1, '*', '*', '*', '*', 0x33, '*', 0x50, 0x8D, '*', '*', 0x64, '*', '*', '*', '*', '*', 0x8B, '*', 0x89, '*', '*', 0xC7, };                                                           /// `void __cdecl CHostageImprov::CHostageImprov (CHostageImprov * const this, CHostage * entity)` FUNCTION ( LINUX )

unsigned char CS_BOTS_NEW[]{ CS_BOTS, 0x83, '*', '*', 0x89, '*', '*', 0xC7, '*', '*', '*', '*', '*', '*', 0x85, '*', 0x74, '*', 0x57, 0x8B, '*', 0xE8, '*', '*', '*', '*', 0xEB, };                                             /// `void * __cdecl operator new (unsigned size)` CALL INSIDE FUNCTION `void __cdecl CHostage::IdleThink (CHostage * const this)` ( LINUX )

#else

#define CS_BOTS_L CS_BOTS, 0x83, 0xC4, 0x10, 0x84, 0xC0, '*', '*', '*', '*', '*', '*'

unsigned char CS_BOTS_RADIO[]{ CS_BOTS_L, 0x83, '*', '*', 0xFF, '*', '*', '*', '*', '*', 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x83, '*', '*', 0x31, '*', 0xE9, };                                                /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `int __cdecl BotPhraseManager::Initialize (BotPhraseManager * this, char * a2, int a3)` ( LINUX )

unsigned char CS_BOTS_PROFILES[]{ CS_BOTS, 0x84, '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', 0xC7, '*', '*', '*', '*', '*', '*', 0x89, '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xE9, };                           /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl BotProfileManager::Init (BotProfileManager * const this, char * filename, unsigned int * checksum)` ( LINUX )
unsigned char CS_BOTS_CON_VARS[]{ CS_BOTS_L, 0x83, '*', '*', 0x68, '*', '*', '*', '*', 0xFF, '*', '*', '*', '*', '*', 0xC7, '*', '*', '*', '*', '*', '*', 0xFF, };                                                              /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void Bot_RegisterCvars (void)` ( LINUX )
unsigned char CS_BOTS_CON_CMDS_REG[]{ CS_BOTS_L, '*', 0x68, '*', '*', '*', '*', 0x53, 0xFF, '*', '*', 0x58, 0x8B, '*', 0x5A, 0x68, '*', '*', '*', '*', 0x53, 0xFF, '*', '*', 0x59, 0x58, 0x8B, };                               /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl CCSBotManager::AddServerCommands (CCSBotManager * this)` ( LINUX )
unsigned char CS_BOTS_CON_CMDS_EXEC[]{ CS_BOTS_L, '*', '*', 0xBF, '*', '*', '*', '*', 0xB9, '*', '*', '*', '*', 0xF3, '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0xBF, };                               /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `unsigned int __cdecl CCSBotManager::ServerCommand (CCSBotManager * this, const char * a2)` ( LINUX )
unsigned char CS_BOTS_MAP_NAV[]{ CS_BOTS_L, '*', '*', '*', 0xE8, '*', '*', '*', '*', 0x85, '*', 0x0F, '*', '*', '*', '*', '*', 0x83, '*', '*', 0x68, '*', '*', '*', '*', 0xE8, '*', '*', '*', '*', 0xA1, };                     /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `void __cdecl CCSBotManager::ValidateMapData (CCSBotManager * this)` ( LINUX )
unsigned char CS_BOTS_MANAGER[]{ CS_BOTS_L, 0x83, '*', '*', 0x89, '*', 0x8B, '*', '*', '*', '*', '*', 0x0F, '*', '*', '*', '*', '*', 0x85, '*', 0x0F, '*', '*', '*', '*', '*', 0x83, '*', '*', 0x0F, };                         /// `int __cdecl UTIL_IsGame (const char * gameName)` CALL INSIDE FUNCTION `int __usercall CCSBotManager::AddBot @ <eax> (int a1 @ <edi>, BotProfile * this, const BotProfile * a3)` ( LINUX )

unsigned char CS_BOTS_DISPLAY[]{ CS_BOTS, 0x80, '*', '*', '*', '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', 0x31, '*', 0xBB, '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0x89, '*', '*', '*', 0x89, };            /// `void __cdecl ClientPrint (entvars_t * client, int msg_dest, const char * msg_name, const char * param1, const char * param2, const char * param3, const char * param4)` CALL WITH "#Game_radio_location" PARAMETER INSIDE FUNCTION `void __cdecl CBasePlayer::Radio (CBasePlayer * const this, const char * msg_id, const char * msg_verbose, __int16 pitch, bool showIcon)` ( LINUX )

unsigned char CS_BOTS_HOSTAGE[]{ 0x57, 0x56, 0x53, 0x83, '*', '*', 0x81, '*', '*', '*', '*', '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', 0x0F, '*', '*', '*', '*', '*', 0x8B, '*', '*', '*', '*', '*', 0x85, '*', 0x0F, };    /// `void __cdecl CHostage::IdleThink (CHostage * const this)` FUNCTION ( LINUX )

unsigned char CS_BOTS_IMPROV[]{ 0x57, 0x31, '*', 0x66, '*', '*', '*', 0x56, 0xBA, '*', '*', '*', '*', 0x53, 0xB9, '*', '*', '*', '*', 0x83, '*', '*', 0xBF, '*', '*', '*', '*', 0x8B, '*', '*', '*', 0x0F, '*', '*', '*', '*',  /// `int * __userpurge sub_1004DBB0 @ <eax> (int * a1 @ <ecx>, int a2 @ <edi>, int a3 @ <esi>, int a4)` FUNCTION ( WINDOWS )
'*', '*', 0x8B, '*', '*', '*', 0x0F, '*', '*', '*', 0x0F, '*', '*', '*', 0xF3, '*', '*', '*', '*', '*', '*', '*', 0x89, '*', '*', '*', '*', '*', 0xB8, };                                                                       /// `void __cdecl CHostageImprov::CHostageImprov (CHostageImprov * const this, CHostage * entity)` FUNCTION ( LINUX )

unsigned char CS_BOTS_NEW[]{ CS_BOTS, 0x89, '*', '*', '*', 0x89, '*', '*', 0x89, '*', 0xE8, '*', '*', '*', '*', 0x89, '*', '*', '*', '*', '*', 0xE9, };                                                                         /// `void * __cdecl operator new (unsigned size)` CALL INSIDE FUNCTION `void __cdecl CHostage::IdleThink (CHostage * const this)` ( LINUX )

#endif
  1. Should block void __cdecl CHostageImprov::CHostageImprov (CHostageImprov * const this, CHostage * entity) function.
    On Windows, it's a int * function. Not void. So in Windows, return nullptr; is needed.

  2. Should block void * __cdecl operator new (unsigned size) call inside function void __cdecl CHostage::IdleThink (CHostage * const this).
    On Windows and Linux, return nullptr; is needed. The void * __cdecl operator new (unsigned size) function is a void * function.

  3. Warning, void __cdecl CHostageImprov::CHostageImprov (CHostageImprov * const this, CHostage * entity) is a main function, not a sub-function which resides inside a main function (like the others are). Perhaps this needs a different hook method.

  4. No need to hook/ block void __cdecl CHostage::IdleThink (CHostage * const this) anymore. Can still be hooked but call the original function into the hook.

unsigned char* Hook_LoadFileForMe(const char* pcszFileName, int* pnLength) noexcept
{
    static bool bShouldBlock{ };

    if (!::g_strGameDir.empty())
    {
        if (!::g_strGameDir.compare("cstrike"))
        {
            if (pcszFileName)
            {
                if (*pcszFileName)
                {
                    if (::std::strcmp("tutordata.txt", pcszFileName))
                    {
                        if (::std::strcmp("BotChatter.db", pcszFileName))
                        {
                            if (!::std::strstr(pcszFileName, "sound\\radio\\bot\\"))
                            {
                                if (!::std::strstr(pcszFileName, "sound/radio/bot/"))
                                {
                                    bShouldBlock = { };
                                }

                                else
                                {
                                    bShouldBlock = true;
                                }
                            }

                            else
                            {
                                bShouldBlock = true;
                            }
                        }

                        else
                        {
                            bShouldBlock = true;
                        }
                    }

                    else
                    {
                        bShouldBlock = true;
                    }
                }

                else
                {
                    bShouldBlock = { };
                }
            }

            else
            {
                bShouldBlock = { };
            }
        }

        else
        {
            bShouldBlock = { };
        }
    }

    else
    {
        bShouldBlock = { };
    }

    if (!::g_bNoReturn)
    {
        do
        {
            ::gpMetaGlobals->mres = ((bShouldBlock) ? (::MRES_SUPERCEDE) : (::MRES_IGNORED));

            if (((::gpMetaGlobals)->orig_ret))
            {
                if (bShouldBlock)
                {
                    return { };
                }

                return (*(unsigned char**) ::gpMetaGlobals->orig_ret);
            }

            else
            {
                return { };
            }

            return { };
        }

        while (false);
    }

    else
    {
        return { };
    }

    return { };
}

I use bot_chatter off setting and I don't need talkable bots. I use this Meta Mod hook above as is. And return false; into the custom hook for: int __cdecl UTIL_IsGame(const char * gameName) call inside function int __cdecl BotPhraseManager::Initialize (BotPhraseManager * this, char * a2, int a3).

To hook functions (not sub-functions) on Windows/ Linux you can use https://github.com/Zeex/subhook
To hook functions (not sub-functions) on Windows you can use https://github.com/microsoft/Detours

@Hedwig7s
Copy link

This should really be a pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants