利用Detours STL MAP HOOK NT函数

Nt函数是在Ring3层最底层的函数了,选择此类函数进行Hook,是为了提高绕过门槛。我的Hook方案使用的是微软的Detours。(转载请指明出处)
        Detours的Hook和反Hook的写入如下:
DetourTransactionBegin();  
DetourUpdateThread(GetCurrentThread());  
DetourAttach(lpOriFuncAddr, lpNewFuncAddr);  
DetourTransactionCommit();  
[cpp] view plaincopy
DetourTransactionBegin();  
DetourUpdateThread(GetCurrentThread());  
DetourDetach(lpOriFuncAddr, lpNewFuncAddr);  
DetourTransactionCommit();  
        从以上可以见得,我们需要保存lpOriFuncAddr(原始函数入口地址)和lpNewFuncAddr(修改后函数入口地址),我们使用一个结构体来保存这两个信息。
// 记录(函数原始函数地址,修改后函数地址)的结构  
typedef struct _FuncPointer_{  
    VOID* lpOri;  
    VOID* lpNew;  
}FuncPointer, *pFuncPointer;  
        因为我们要Hook很多函数,我们定义一个Map来保存信息,以方便寻找到相关的函数入口,我们的Map是以函数名为Key,以保存原始函数入口和修改后函数入口结构体为值。

// 以函数名为Key,其(函数原始函数地址,修改后函数地址)为值的map  
typedef std::map<std::string,FuncPointer> MapFuncPointer;  
typedef MapFuncPointer::iterator MapFuncPointerIter;  
typedef MapFuncPointer::const_iterator MapFuncPointerCIter;  
        寻找原始函数的入口地址可以通过Detours提供的DetourFindFunction,而修改后的函数入口地址则需要我们自己定义。在我工程的NewNtRegFunc.h和NewNtRegFunc.cpp文件中,我分别定义了所有修改后函数声明和实现。新函数名的规则是“New_原函数名”,如
NTSTATUS __stdcall New_NtOpenKey(  
            __out       PHANDLE KeyHandle,  
            __in        ACCESS_MASK DesiredAccess,  
            __in        POBJECT_ATTRIBUTES ObjectAttributes );  
        我们第一步就是要生成这样Map
extern MapFuncPointer g_MapRegFuncPointer;  
  
VOID GetHookNtRegFuncInfo()  
{  
    HOOKNTDLLFUNC( CreateKey );  
    HOOKNTDLLFUNC( OpenKey );  
    HOOKNTDLLFUNC( DeleteKey );  
    HOOKNTDLLFUNC( DeleteValueKey );  
    HOOKNTDLLFUNC( QueryKey );  
    HOOKNTDLLFUNC( SetValueKey );  
    HOOKNTDLLFUNC( QueryValueKey );  
    HOOKNTDLLFUNC( EnumerateKey );  
    HOOKNTDLLFUNC( EnumerateValueKey );  
    HOOKNTDLLFUNC( FlushKey );  
    HOOKNTDLLFUNC( NotifyChangeKey );  
    HOOKNTDLLFUNC( Close );  
    HOOKNTDLLFUNC( SetSecurityObject );  
    HOOKNTDLLFUNC( QuerySecurityObject );  
  
    // vista及以上系统  
    HOOKNTDLLFUNC( OpenKeyEx );  
    HOOKNTDLLFUNC( CreateKeyTransacted );  
    HOOKNTDLLFUNC( OpenKeyTransacted );  
    HOOKNTDLLFUNC( OpenKeyTransactedEx );  
}  
        其中HOOKTNDLLFUNC是一个宏,其定义如下
#define HOOKNTDLLFUNC(x)\  
    HOOKNTITEM("NtDll.dll", x )  
      HOOKNTITEM也是个宏
// Hook函数,同时将{函数名,(函数原始函数地址,修改后函数地址)}保存到map中  
#define HOOKNTITEM(x,y)\  
    FuncPointer FP_##y; FP_##y.lpOri = DetourFindFunction( x , "Nt"#y );FP_##y.lpNew = static_cast<VOID*>(New_Nt##y); g_MapRegFuncPointer["Nt"#y]= FP_##y;  
        现在来说说这个宏,这个也是这篇文章中的一个重点。宏其实可以认为是一个模板,对于使用宏的地方,编译器会将其原封不动的替换到使用该宏处,这个特点和内联函数(inline)很像(但是VC的内联却不是人能控制的,编译器会根据它的判断来决定是否将你定义为inline的函数内容替换到调用处)。首先,我们要定义一个FuncPointer结构体对象,如果你在宏定义这个对象如下:FuncPointer FP;则在编译时报很多错,错误的原因就是一个变量名被定义多次,想想为什么?就是因为我们多次调用HOOKNTITEM,编译器也多次将FuncPointer FP插入到调用处。结果展开后如下

{  
    FuncPointer FP;  
    ……  
    FuncPointer FP;  
    ……  
    FuncPointer FP;  
    ……  
}  
        为了让每次定义的变量名不一样,我们使用了结合传入参数的方法,故定义为:

FuncPointer FP_##y  
        该宏之后的内容很浅显易懂了。
        现在开始我们的HOOK操作

BOOL HookRegApi()  
{  
    BOOL bSuc = FALSE;  
  
    do {  
        GetHookNtRegFuncInfo();  
          
        DetourTransactionBegin();  
        DetourUpdateThread(GetCurrentThread());  
         
        for ( MapFuncPointerIter it = g_MapRegFuncPointer.begin(); it != g_MapRegFuncPointer.end(); it++ ) {  
            // 必须要加以判断,否则之后不应该是失败的也失败了  
            if ( NULL != it->second.lpOri && NULL != it->second.lpNew ) {  
                LONG lRes = DetourAttach(&(it->second.lpOri), it->second.lpNew );  
            }  
        }  
        DetourTransactionCommit();  
  
        bSuc = TRUE;  
    } while (0);  
    return bSuc;  
}  
        该函数也很简单,但是其中有个细节一定要注意,那就是要判断原函数地址和修改后函数地址是否为空。使用Detours进行Hook特别要注意这点,否则会出现你也想不到的问题。当时我写这块时,伪代码可以如下表示

HOOK(CreateKey)  
HOOK(OpenKeyEx)  
HOOK(OpenKey)  
        结果我发现NtCreateKey函数被Hook了,而OpenKey却没有被Hook,出错的原因是:NtOpenKeyEx这个函数在vista及其以上系统才有,而我的开发环境是Xp,于是DetourFindFunction寻找到NtOpenKeyEx函数的入口地址为NULL,调用DetourAttach(NULL,lpNewFuncAddr)失败后,所有理论上应该成功的Hook(如Hook(OpenKey),NtOpenKey在xp上是存在的)也都会失败。当然最好还可以判断之前一步DetourAttach的返回值是否成功来决定是否继续Hook。
        反Hook的代码如下

BOOL UnHookRegApi()  
{  
    BOOL bSuc = FALSE;  
  
    do   
    {  
        DetourTransactionBegin();  
        DetourUpdateThread(GetCurrentThread());  
        for ( MapFuncPointerIter it = g_MapRegFuncPointer.begin(); it != g_MapRegFuncPointer.end(); it++ ) {  
            // 必须要加以判断,否则之后不应该是失败的也失败了  
            if ( NULL != it->second.lpOri && NULL != it->second.lpNew ) {  
                LONG lRes = DetourDetach(&(PVOID&)it->second.lpOri, it->second.lpNew );  
            }  
        }  
        DetourTransactionCommit();  
  
        bSuc = TRUE;  
    } while (0);  
  
    return bSuc;  
}  
        为了之后方便调用真实函数,我定义了一个宏

// 获取原始函数入口  
#define GETORIFUNC(x)\  
    ( (pfn_Nt##x)g_MapRegFuncPointer["Nt"#x].lpOri )  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值