如何在hotpatch之后调用原始函数

时间:2013-12-21 07:01:01

标签: c++ hook hotpatching

我编写了代码来修补“睡眠”功能,例如来自Kernel32.dll。修补工作非常好。删除补丁工作完全正常。但是,调用原始函数根本不起作用。它严重崩溃。

#include <windows.h>
#include <iostream>

std::uint8_t* Patch(std::uint8_t* OrigFunc, std::uint8_t* HookFunc)
{
    DWORD dwProtect = 0;
    const static std::uint8_t jmp[] = {0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
    const static std::int8_t jmp_size = sizeof(jmp) / sizeof(std::uint8_t);
    static std::uint8_t HookJump[jmp_size + 1] = {jmp_size};
    VirtualProtect(OrigFunc, jmp_size, PAGE_EXECUTE_READWRITE, &dwProtect);
    memcpy(&HookJump[1], OrigFunc, jmp_size);
    memcpy(OrigFunc, jmp, jmp_size);
    memcpy(OrigFunc + 1, &HookFunc, sizeof(void*));
    VirtualProtect(OrigFunc, jmp_size, dwProtect, &dwProtect);
    return HookJump;
}

void RemovePatch(std::uint8_t* OrigFunc, std::uint8_t* HookJump)
{
    DWORD dwProtect = 0;
    VirtualProtect(OrigFunc, HookJump[0], PAGE_EXECUTE_READWRITE, &dwProtect);
    memcpy(OrigFunc, &HookJump[1], HookJump[0]);
    VirtualProtect(OrigFunc, HookJump[0], dwProtect, &dwProtect);
}

typedef void (__stdcall *pSleep)(DWORD);
pSleep oSleep;

void __stdcall hSleep(DWORD MS)
{
    std::cout<<"HERE";
    oSleep(MS); //Crashes Here.
}

int main()
{
    std::uint8_t* OrigFunc = (std::uint8_t*)GetProcAddress(GetModuleHandle("kernel32.dll"), "Sleep");
    std::uint8_t* HookFunc = (std::uint8_t*)hSleep;
    std::uint8_t* HookJump = Patch(OrigFunc, HookFunc); //Works fine.

    oSleep = (pSleep)&HookJump[1];
    Sleep(1000);  //Prints Here then crashes immediately.

    RemovePatch(OrigFunc, HookJump); //Works fine.
    Sleep(1000); //Works fine.
}

我的代码遗失了什么想法?

1 个答案:

答案 0 :(得分:0)

在给定的代码中,您似乎将原始字节存储在名为HookJump的静态数组中,返回指向该数组的指针,然后跳转到它的开头,就好像它是有效的机器代码一样。它没有跟随原始功能的其余部分。


在Windows中挂钩函数的更好方法是使用Microsoft Detours。

这是我的(a) Hook 课程的工作草图,使用Detours:

  

[Hook.h]

#pragma once
// Copyright (c) 2013 Alf P. Steinbach

#include <rfc/cppx/core/Non_copyable.h>     // cppx::Non_copyable
#include <rfc/cppx/core/macros/ASSERT.h>    // CPPX_ASSERT
#include <rfc/detours/Transaction.h>        // detours::Transaction

namespace detours {
    using cppx::Non_copyable;

    template< class Func >
    class Hook_
        : public Non_copyable
    {
    private:
        Func*   original_;
        Func*   replacement_;

    public:
        auto original_func() const
            -> Func*
        { return original_; }

        ~Hook_()
        { 
            if( original_ != nullptr )
            {
                Transaction().detach( original_, replacement_ ).commit();
            }
        }

        Hook_( Func* const original, Func* const replacement )
            : original_( original )
            , replacement_( replacement )
        {
            CPPX_ASSERT( original_ != nullptr );
            CPPX_ASSERT( replacement_ != nullptr );
            Transaction().attach( original_, replacement_ ).commit();
        }

        Hook_( Hook_&& other )
            : original_( other.original_ )
            , replacement_( other.replacement_ )
        { other.original_ = nullptr; other.replacement_ = nullptr; }
    };

    template< class Func >
    inline auto hook( Func* const original, Func* const replacement )
        -> Hook_<Func>
    { return Hook_<Func>( original, replacement ); }

}  // namespace detours

这里是它使用的 Transaction 类,后者又调用了Detours API:

  

[Transaction.h]

#pragma once
// Copyright (c) 2013 Alf P. Steinbach

#include <rfc/cppx/core/utility/If_.h>      // cppx::If
#include <rfc/cppx/core/Non_copyable.h>     // cppx::Non_copyable
#include <rfc/cppx/core/Type_.h>            // cppx::Type_

#include <thread>           // std::thread
#include <type_traits>      // std::is_function, std::enable_if

namespace detours {
    using cppx::If_;
    using cppx::Non_copyable;
    using cppx::Type_;
    using std::is_function;
    using std::thread;

    typedef thread::native_handle_type Thread_handle;

    class Basic_transaction
        : public Non_copyable
    {
    private:
        typedef Type_<void(*)()> Proc;

        bool    is_committed_;

        void raw_attach( Proc& original, Proc const replacement );
        void raw_detach( Proc& original, Proc const replacement );

    public:
        auto is_committed() const
            -> bool;
        void commit();

        auto update_thread( Thread_handle const h )
            -> Basic_transaction&;

        auto update_this_thread()
            -> Basic_transaction&;

        template< class Func, class Enabled = If_<is_function<Func>> >
        auto attach( Func*& original, Func* const replacement )
            -> Basic_transaction&
        {
            raw_attach(
                reinterpret_cast<Proc&>( original ),
                reinterpret_cast<Proc>( replacement )
                );
            return *this;
        }

        template< class Func, class Enabled = If_<is_function<Func>> >
        auto detach( Func*& original, Func* const replacement )
            -> Basic_transaction&
        {
            raw_detach(
                reinterpret_cast<Proc&>( original ),
                reinterpret_cast<Proc>( replacement )
                );
            return *this;
        }

        ~Basic_transaction();
        Basic_transaction();
    };

    class Transaction
        : public Basic_transaction
    {
    public:
        Transaction()
        { update_this_thread(); }
    };

}  // namespace detours
  

[Transaction.cpp]

#include "Transaction.h"

#include <rfc/cppx/core/throwing.h>
#include <rfc/cppx/core/macros/ASSERT.h>                    // CPPX_ASSERT
#include <rfc/detours_wrappers/detours_h.h>

using cppx::hopefully;
using cppx::fail;

typedef long Error_code;

namespace detours{

    auto Basic_transaction::is_committed() const
        -> bool
    { return is_committed_; }

    void Basic_transaction::commit()
    {
        CPPX_ASSERT( !is_committed_ );
        Error_code const code = ::DetourTransactionCommit();
        hopefully( code == 0 )
            || fail( "Basic_transaction::commit: DetourTransactionCommit failed", code );
        is_committed_ = true;
    }

    auto Basic_transaction::update_thread( Thread_handle const h )
        -> Basic_transaction&
    {
        Error_code const code = ::DetourUpdateThread( reinterpret_cast<HANDLE>( h ) );
        hopefully(code == 0)
            || fail("Transaction::update_thread: DetourUpdateThread failed", code);
        return *this;
    }

    auto Basic_transaction::update_this_thread()
        -> Basic_transaction&
    {
        return update_thread( Thread_handle( ::GetCurrentThread() ) );
    }

    void Basic_transaction::raw_attach( Proc& original, Proc const replacement )
    {
        Error_code const code = ::DetourAttach(
            reinterpret_cast<void**>( &original ),
            reinterpret_cast<void*>( replacement )
            );
        hopefully(code == 0)
            || fail("Transaction::attach: DetourAttach failed", code);
    }

    void Basic_transaction::raw_detach( Proc& original, Proc const replacement )
    {
        Error_code const code = ::DetourDetach(
            reinterpret_cast<void**>( &original ),
            reinterpret_cast<void*>( replacement )
            );
        hopefully(code == 0)
            || fail("Transaction::attach: DetourAttach failed", code);
    }

    Basic_transaction::~Basic_transaction()
    {
        if (!is_committed_)
        {
            Error_code const code = ::DetourTransactionAbort();
            hopefully( code == 0 )
                || fail( "Basic_transaction::<destroy>: DetourTransactionAbort failed", code );
        }
    }

    Basic_transaction::Basic_transaction()
        : is_committed_( false )
    {
        Error_code const code = ::DetourTransactionBegin();
        hopefully( code == 0 )
            || fail( "Basic_transaction::<init>: DetourTransactionBegin failed", code );
    }

}  // namespace detours

Detours包装器标题:

  

[detours.h]

#pragma once
#include <rfc/winapi_wrappers/windows_h.h>
#include <microsoft_detours/detours.h>

然后我使用cpp文件引入特定的Detours实现,例如对于x86:

  

[detours_cpp.x86-32.cpp]

// Copyright (c) 2013 Alf P. Steinbach

#define DETOURS_INTERNAL                    // Necessary for DETOUR_TRACE
#include <rfc/detours_wrappers/detours_h.h>
#define DETOURS_X86
#define DETOURS_32BIT
#include <microsoft_detours/detours.cpp>    // Source
#include <microsoft_detours/disasm.cpp>     // More source, e.g. DetourCopyInstruction