inline hook原理和例子

简介:inline hook写在DLL中。在 DLL_PROCESS_ATTACH(DLL加载时) 时hook(在汇编代码层面修改原函数跳转位置),在 DLL_PROCESS_DETACH(DLL卸载时) 时UnloadHook(在汇编代码层面还原原本的跳转位置)。

个人理解:Inline Hook 其实简单来说是 DLL 内函数劫持,因为是将原函数的跳转改变,没有用到消息钩子 SetWindowsHookEx 函数。

原理:将原DLL模块中导出的函数 extern "C++"__declspec(dllexport) 的起始字节改为跳转jmp,跳转自己的一模一样的函数(从原文件中复制,在自己的cpp中构建相同的函数,记得改函数名)。

流程:

  1. 原进程执行到目标函数时,遇到跳转指令 jmp 
  2. 执行自建相同函数中的自己的代码
  3. 不放行,return;结束
  4. 放行,UnloadHook(),卸载hook,防止死循环
  5. 使用原目标函数,记得将参数原封不动加入
  6. 若要继续hook,则hook()

相关函数:

  • CreateProcess:创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件,返回BOOL。
  • memset:填充的内存块,无返回值。
  • GetProcAddress:获取DLL导出的函数地址,返回值是DLL中的输出函数地址。
  • GetModuleHandle:获取模块句柄(可能需要打开进程OpenProcess)返回值是模块句柄。
  • ReadProcessMemory:读取进程内存,返回成功或失败。
  • WriteProcessMemory:写入进程内存,返回成功或失败。
  • GetCurrentProcess:返回当前进程的句柄

代码:

dllmain.cpp

#include<Windows.h>

//hook的目标函数
PROC hook_Function = NULL;
//hook的目标函数前五个字节
BYTE m_oldBytes[5];
//替代hook的目标函数的五个字节
BYTE m_newBytes[5];

BOOL Hook(LPCSTR hookModelName, LPCSTR hookFuncName, PROC myFunc);
void UnloadHook();
BOOL ReHook();

// NO2 从官方文档中复制来,在其中实现自己的代码。
//运行原理: 未劫持:程序1-> 正常的函数 -> 程序2
//          劫持后:程序1-> NO2函数 -> 程序2
BOOL WINAPI MyCreateProcessW(
    _In_opt_ LPCWSTR lpApplicationName,
    _Inout_opt_ LPWSTR lpCommandLine,
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCWSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOW lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
{
    BOOL flag = true;//true 不允许原程序继续执行,false 允许原程序继续执行
    if (flag)
    {
        //不允许原程序继续执行
        MessageBox(NULL, "lq", "lq", MB_OK);
        //在此写入自己的代码

    }
    else
    {
        //允许原程序继续执行
        UnloadHook();
        MyCreateProcessW(lpApplicationName,
            lpCommandLine,
            lpProcessAttributes,
            lpThreadAttributes,
            bInheritHandles,
            dwCreationFlags,
            lpEnvironment,
            lpCurrentDirectory,
            lpStartupInfo,
            lpProcessInformation);
        //在此写入自己的代码
        ReHook();
    }
    return true;
}

// NO1 程序从此进入,主要作用是找到需要劫持的函数,调用NO3将跳转到正常函数的汇编代码修改成NO2函数的汇编地址
BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        //当DLL首次加载时
        //这里hook的是 CreateProcessW 函数
        Hook("kernel32.dll", "CreateProcessW", (PROC)MyCreateProcessW);
        break;
    }
    case DLL_PROCESS_DETACH:
    {
        UnloadHook();
    }
        break;
    }
    return TRUE;
}

//NO3
BOOL Hook(LPCSTR hookModelName, LPCSTR hookFuncName,PROC myFunc)
{
    //防止这两个地址内存保留原来的东西
    memset(m_oldBytes,0,5);
    memset(m_newBytes,0,5);

    //获取模块中的目标函数地址。由于DLL加载进入了进程内部,所以不需要 OpenProcess 
    hook_Function = (PROC)GetProcAddress(GetModuleHandle(hookFuncName), hookFuncName);
    if (hook_Function == 0)return false;
        
    //保存 ReadProcessMemory 返回的 读取的大小
    DWORD Ret = 0;
    //保存目标函数的前五个字符
    ReadProcessMemory(GetCurrentProcess(), hook_Function, m_oldBytes, 5, &Ret);

    //构造jmp指令
    // '\xE9' 为二进制码,对应jmp
    m_newBytes[0] = '\xE9';
    //将我们函数的地址写入后四位,注意是偏移量,用 目标函数地址-我们函数地址-指令大小。为什么要减指令大小?因为汇编语言执行完我们的指令,寄存器地址是在当前指令下方。
    *(DWORD*)(m_newBytes + 1) = (DWORD)hook_Function - (DWORD)hook_Function - 5;

    //将构建的指令替换原指令,执行到目标函数时跳转
    WriteProcessMemory(GetCurrentProcess(), hook_Function, m_newBytes, 5, &Ret);
    return true;
}

void UnloadHook()
{
    //若 hook_Function == 0 则表示连目标函数都没有获取到,则没有hook住
    if (hook_Function != NULL)
    {
        DWORD Ret = 0;
        //还原目标函数,即不跳转了
        WriteProcessMemory(GetCurrentProcess(), hook_Function, m_oldBytes, 5, &Ret);
    }
}

BOOL ReHook()
{
    //若 hook_Function == 0 则表示连目标函数都没有获取到,则没有hook住
    if (hook_Function != NULL)
    {
        DWORD Ret = 0;
        //此时已经保存了所有参数
        WriteProcessMemory(GetCurrentProcess(), hook_Function, m_newBytes, 5, &Ret);
    }
    return true;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值