C++ 用户层下的用Push+Ret API HOOK

说道API HOOK ,这已经是老掉牙的技术了,但是它的实用性却是不能忽视的。虽然在网上这类的文章很多,但大多数的实现方法是将一个函数的前5字节直接改为 jmp XXXX 。这种方法虽然简单可行,但是不通用,因为一些特殊函数的前5字节不是完整的,如果直接修改,就会截断指令,导致出错。以前在一个论坛上看到过一个用反汇编引擎实现的通用例子,感觉想法很好,于是自己也写了一个。其中用到了一个头文件LDasm.h(里面实际就是一个轻量级的反汇编引擎,网上可以下载到)。

第一个函数用于对指定API进行HOOK,并返回一个进入原函数的代理函数地址。


代码
PVOID HookFunction(PCHAR ModuleName,PCHAR FunctionName,PVOID pNewFunction)
{

    UCHAR JumpCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3};     //push xxxxxxxx ret
     UCHAR JumpBackCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3}; //push xxxxxxxx ret
     
    PVOID pSourceFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName);
    if (!pSourceFunction)return NULL;

    *(ULONG *)((ULONG)JumpCode + 1) = (ULONG)pNewFunction;


    PVOID pProxyFunction = 0;
    PUCHAR pOpCode;
    ULONG BackupLength = 0;

    
    while (BackupLength < 6)
    {
        BackupLength += SizeOfCode((PVOID)((ULONG)pSourceFunction + BackupLength),&pOpCode);
    }


    pProxyFunction = VirtualAlloc(NULL,BackupLength + 6,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (!pProxyFunction)return NULL;

    *(ULONG *)((ULONG)JumpBackCode + 1) = (ULONG)pSourceFunction + BackupLength;
    
    RtlCopyMemory(pProxyFunction,pSourceFunction,BackupLength);
    RtlCopyMemory((PVOID)((ULONG)pProxyFunction + BackupLength),JumpBackCode,6);

    FlushInstructionCache((HANDLE)-1,pProxyFunction,BackupLength + 6);

    DWORD OldProtect = 0;
    VirtualProtect(pSourceFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect);

    RtlCopyMemory(pSourceFunction,JumpCode,6);

    VirtualProtect(pSourceFunction,6,OldProtect,&OldProtect);

    FlushInstructionCache((HANDLE)-1,pSourceFunction,6);

    return pProxyFunction;


}

注意,在JumpCode和JumpBackCode中,我使用的是push+ret的方式进行跳转(跟网上一牛人学的),其目的是不用计算相对偏移,也不容易被一些安全工具发现。其中还有一个重要的函数——SizeOfCode(),它就是反汇编引擎里的一个函数,用于计算一个完整指令的长度,防止指令被截断,它是实现通用性的关键。LDasm.h和LDasm.c可以去网上下载,如果你是用的vc6.0以后版本,可以把LDasm.c改名为LDasm.cpp,然后把文件加入到工程,直接编译可成功. 第二个函数用于恢复被HOOK的函数,它需要HookFunction函数返回的代理函数地址作为参数。
代码
PVOID HookFunction(PCHAR ModuleName,PCHAR FunctionName,PVOID pNewFunction)
{

    UCHAR JumpCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3};     //push xxxxxxxx ret
     UCHAR JumpBackCode[6] = {0x68,0x00,0x00,0x00,0x00,0xC3}; //push xxxxxxxx ret
     
    PVOID pSourceFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName);
    if (!pSourceFunction)return NULL;

    *(ULONG *)((ULONG)JumpCode + 1) = (ULONG)pNewFunction;


    PVOID pProxyFunction = 0;
    PUCHAR pOpCode;
    ULONG BackupLength = 0;

    
    while (BackupLength < 6)
    {
        BackupLength += SizeOfCode((PVOID)((ULONG)pSourceFunction + BackupLength),&pOpCode);
    }


    pProxyFunction = VirtualAlloc(NULL,BackupLength + 6,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (!pProxyFunction)return NULL;

    *(ULONG *)((ULONG)JumpBackCode + 1) = (ULONG)pSourceFunction + BackupLength;
    
    RtlCopyMemory(pProxyFunction,pSourceFunction,BackupLength);
    RtlCopyMemory((PVOID)((ULONG)pProxyFunction + BackupLength),JumpBackCode,6);

    FlushInstructionCache((HANDLE)-1,pProxyFunction,BackupLength + 6);

    DWORD OldProtect = 0;
    VirtualProtect(pSourceFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect);

    RtlCopyMemory(pSourceFunction,JumpCode,6);

    VirtualProtect(pSourceFunction,6,OldProtect,&OldProtect);

    FlushInstructionCache((HANDLE)-1,pSourceFunction,6);

    return pProxyFunction;


}


 

 

代码
BOOL UnHookFunction(PCHAR ModuleName,PCHAR FunctionName,PVOID pProxyFunction)
{

    PVOID pSourceFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName);
    if (!pSourceFunction)return FALSE;
    
    DWORD OldProtect = 0;
    VirtualProtect(pSourceFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect);

    RtlCopyMemory(pSourceFunction,pProxyFunction,6);

    VirtualProtect(pSourceFunction,6,OldProtect,&OldProtect);

    FlushInstructionCache((HANDLE)-1,pSourceFunction,6);

    BOOL res = VirtualFree(pProxyFunction,NULL,MEM_RELEASE);
    if (!res)return FALSE;

    return TRUE;

}


这个函数很简单,只是做一些清理工作。

最后,我还写了个函数用于检查某个函数是否被HOOK,但只能检查出两种形式的HOOK,一种jmp形式,一种push+ret形式,不过也够用了。

代码
BOOL IsFuncHooked(PCHAR ModuleName,PCHAR FunctionName)
{
    PVOID pFunction = GetProcAddress(GetModuleHandleA(ModuleName),FunctionName);
    
    if (!pFunction)return FALSE;

    DWORD OldProtect = 0;
    VirtualProtect(pFunction,6,PAGE_EXECUTE_READWRITE,&OldProtect);

    UCHAR chas = *(UCHAR *)((ULONG)pFunction + 5);

    if (((*(UCHAR *)pFunction == 0x68)&&(*(UCHAR *)((ULONG)pFunction + 5) == 0xC3))||(*(UCHAR *)pFunction == 0xEB)||(*(UCHAR *)pFunction == 0xEA))
    {
        VirtualProtect(pFunction,6,OldProtect,&OldProtect);
        return TRUE;
    }
    else
    {
        VirtualProtect(pFunction,6,OldProtect,&OldProtect);
        return FALSE;
    }
    
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值