首页
论坛
课程
招聘
[原创][封装]简单易用的Api Hook函数 - MyApiHookFun
2015-6-7 22:48 7241

[原创][封装]简单易用的Api Hook函数 - MyApiHookFun

2015-6-7 22:48
7241
使用方法:
0.首先使用者请保证跑我的函数时已经注入到目标程序中
1.引用外部变量
extern DWORD *g_pApiAddr;
extern BYTE *g_pOldCode;
2.建立一个hook后工作函数

以下是hook后的测试函数
LPVOID _declspec(naked) WINAPI TestFun(LPVOID UnKnow1, LPVOID UnKnow2)
{
    ::MessageBox(NULL, TEXT("这是一个hook提示"), TEXT("提示"), NULL);

    //以下汇编不可动
    _asm
    {
        push g_pOldCode
        ret;
    }
}

3.调用
例子:
    MODULEAPI tagModuleAPI = {
        {TEXT("kernel32.dll"), "ExitProcess"},
    };
    MyApiHookFun(&tagModuleAPI,TestFun);
MyApiHookFun.h:
#pragma once
#include <windows.h>
//////////////////////////////////////////////////////////////////////////
//定义
typedef struct _MODULE_API
{
    TCHAR *pModuleName;
    char  *pApiName;
}MODULEAPI,*PMODULEAPI;
//////////////////////////////////////////////////////////////////////////
//函数声明
BOOL WINAPI MyApiHookFun(PMODULEAPI pModuleAPI, LPVOID pfnHookFun);

MyApiHookFun.cpp:
#include "MyApiHookFun.h"

DWORD g_dwApiAddr = NULL;
BYTE *g_pOldCode = NULL;
/************************************************************************
函数名字:BOOL WINAPI MyApiHookFun(PMODULEAPI pModuleAPI, LPVOID pfnHookFun)
功    能:API HOOK主函数
参  数 1:pModuleAPI  模块和api名字的数组
参  数 2:pfnHookFun  hook后执行的函数数组
返 回 值:TRUE - 成功/ FALSE - 失败
************************************************************************/
BOOL WINAPI MyApiHookFun(PMODULEAPI pModuleAPI, LPVOID pfnHookFun)
{
    char chE9 = (char)0xe9;
    TCHAR szTmp[MAX_PATH] = {0};
    DWORD dwPID = 0;
    BOOL bRet = FALSE;
    LPVOID pAllocAddr = NULL;
    DWORD dwOld = 0;
    HMODULE hModule = NULL;
    
    g_pOldCode = new BYTE[12];
    if (g_pOldCode == NULL)
    {
#ifdef _DEBUG
        ::OutputDebugString(TEXT("new g_pOldCode Error!"));
#endif
        return FALSE;
    }
    memset(g_pOldCode, 0, 12);

    //获得API地址
    hModule = ::GetModuleHandle(pModuleAPI->pModuleName);
    if (hModule == NULL)
    {
#ifdef _DEBUG
        ::OutputDebugString(TEXT("GetModuleHandle Error!"));
#endif
        return FALSE;
    }

    g_dwApiAddr = (DWORD)::GetProcAddress(hModule, pModuleAPI->pApiName);
    if (g_dwApiAddr == NULL)
    {
#ifdef _DEBUG
        ::OutputDebugString(TEXT("GetProcAddress Error!"));
#endif
        return NULL;
    }
    
    //改变内存属性 HOOK
    bRet = ::VirtualProtect((LPVOID)g_dwApiAddr,
                            5,
                            PAGE_EXECUTE_READWRITE,
                            &dwOld);
    if (bRet == FALSE)
    {
#ifdef _DEBUG
        wsprintf(szTmp, TEXT("VirtualProtect %08X Error!"), pApiAddr[i]);
        OutputDebugString(szTmp);
#endif
        return FALSE;
    }

    //shell code
    g_pOldCode[0] = (char)0xb8;
    *(DWORD *)(&g_pOldCode[1]) = g_dwApiAddr + 5;
    g_pOldCode[5] = *(BYTE *)g_dwApiAddr;
    *(DWORD *)(&g_pOldCode[6]) = *(DWORD *)(g_dwApiAddr + 1);
    g_pOldCode[10] = (char)0xff;
    g_pOldCode[11] = (char)0xe0;

    //写入
    *(BYTE *)g_dwApiAddr = 0xE9;
    *(DWORD *)(g_dwApiAddr + 1) = (DWORD)pfnHookFun - (g_dwApiAddr + 5);

    bRet = ::VirtualProtect((LPVOID)g_dwApiAddr,
                            5,
                            dwOld,
                            &dwOld);
    if (bRet == FALSE)
    {
#ifdef _DEBUG
        wsprintf(szTmp, TEXT("VirtualProtect2 %08X Error!"), pApiAddr[i]);
        OutputDebugString(szTmp);
#endif
        return FALSE;
    }
    return TRUE;
}


附件:

第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (16)
雪    币: 100
活跃值: 活跃值 (49)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dico 活跃值 2015-6-8 08:08
2
0
通用性如何?支持X64么?
雪    币: 325
活跃值: 活跃值 (34)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
地狱怪客 活跃值 2 2015-6-8 09:43
3
0
喜欢这个。。。直接用上试试
雪    币: 452
活跃值: 活跃值 (38)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
木瓜枫叶 活跃值 2 2015-6-8 10:08
4
0
肯定不支持64位
雪    币: 22
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
慢吞吞 活跃值 2015-6-8 23:19
5
0
i下载收一份
雪    币: 381
活跃值: 活跃值 (22)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
BinGzL 活跃值 1 2015-6-9 16:44
6
0
不支持x64,指针长度不一样 shellcode没办法写,有需要我改个x64的
雪    币: 4773
活跃值: 活跃值 (469)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
menglv 活跃值 2015-6-27 13:11
7
0
留个脚印,收藏一个。
雪    币: 2
活跃值: 活跃值 (597)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yaoguen 活跃值 2015-6-28 17:27
8
0
需要支持x64的
雪    币: 222
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Dvsz 活跃值 2015-6-29 09:24
9
0
谢谢分享!
雪    币: 49
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
化魔 活跃值 2015-6-30 19:27
10
0
留下脚印。谢谢分享
雪    币: 69
活跃值: 活跃值 (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hulucc 活跃值 2015-7-1 16:17
11
0
多线程环境下 不把所有线程暂停hook的话会有概率崩溃
雪    币: 154
活跃值: 活跃值 (455)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sunbinjin 活跃值 1 2015-7-2 11:56
12
0

真正稳定的代码是更复杂的
我后来才理解detours为啥那么多代码
雪    币: 267
活跃值: 活跃值 (39)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
wswm 活跃值 2015-12-29 18:21
13
0
恕小生愚昧,LPVOID _declspec(naked) WINAPI TestFun(LPVOID UnKnow1, LPVOID UnKnow2)这个函数是两个参数的,  而ExitProcess是一个参数的,这样InlineHook  栈会平衡吗?
雪    币: 381
活跃值: 活跃值 (22)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
BinGzL 活跃值 1 2015-12-29 22:21
14
0
我当初是简单测试过的,而且这个也不是很完美,比如没有写一个取指令长度的引擎。
不过在裸函数中,也就随意了。

可以使用任意引擎改进下代码,比如我的。
标 题: 【原创】国庆时完工的反汇编引擎源码
作 者: BinGzL
时 间: 2015-11-26,10:22:12
链 接: http://bbs.pediy.com/showthread.php?t=206071

或者可以使用下面这个我朋友封装好的
通用hook代码模板
http://www.jmpoep.com/thread-34-1-1.html
雪    币: 333
活跃值: 活跃值 (16)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 活跃值 2 2015-12-30 01:07
15
0
楼主,我直接指出你的错误吧!第一,这个不支持X64位,从你的回答中也看到你知道这个问题了。

第二有一个问题,就是,这个HOOK没有注意多线程安全,HOOK是要强调多线程安全的,你的HOOK函数在执行时,你没有保证HOOK不会被别的线程打断,在单线程程序,也就是只有一个主线程的程序里,你的HOOK函数在执行时是可以保证不会被打断的,因为,只有一个主线程,没有别的线程打断你的HOOK了,但是,如果是在一个多线程程序中,并且是频繁调用被HOOK的函数的程序中,问题就出来了,首先,你的HOOK函数,并没有暂停别的线程,这样就有可能导致,别的线程在执行原来的指令时,有几率会被你写入的新的指令覆盖,这会导致不可预估的错误!

不注意多线程安全,是大多数HOOK的通病啊!毕竟,我们在写程序的时候,一直是在单线程中的main函数中编写的,可是要是到了,多线程环境,或者是内核的APC回调函数中,那可就惨了,因为你不知道这些不属于main函数调用的东西是什么时候去调用你正在HOOK的函数,要是在这些函数被别的线程或者内核回调APC中调用你正在HOOK的函数的话,你惨了,HOOK这时候还没完成,指令早就不知道被你写飞到哪里去了!
雪    币: 381
活跃值: 活跃值 (22)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
BinGzL 活跃值 1 2015-12-30 09:42
16
0
感谢指出,我写hook还真是没注意过这个问题,也没有触发过。tks
雪    币: 333
活跃值: 活跃值 (16)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
czcqq 活跃值 2 2015-12-30 10:21
17
0
你编程的时候,或者说,你自己开发的时候是在main函数下的,一般情况下这个函数是单线程的,就不会遇到我说的打断hook的问题,但是一旦在别的机器上运行或者是用别的库函数,或者是需要多线程处理的函数,还有内核回调函数的情况下,就有一定的几率遇到这个问题!这个几率是很低的,所以你很可能不会遇到过,但是代表你不会遇到!只是遇到的几率很低而已!
游客
登录 | 注册 方可回帖
返回