博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习记录--HooKSystemCall
阅读量:4311 次
发布时间:2019-06-06

本文共 4252 字,大约阅读时间需要 14 分钟。

前言:

这两天看了一个github上的项目,记录一下学习的心得。

Win32 API大多数都要从Ring3层进入Ring0层,在内核中完成主要操作。这中间肯定要经过KiFastSystemCall这个过程,这个调用是Ring3层的。这些知识在《Windows内核安全与驱动开发》21章中。

项目:

HookSystemCall大致原理就是自己构建一个类似SSDT的东西,当有函数通过KiFastSystemCall进入内核时,就进入自己构建的SSDT中的函数。代码如下,dwHookSystemCall中保存的是自己的函数地址,dwOrigSystemCall中保存的是SSDT中原始的函数地址。Zw函数都是通过索引在SSDT中找相应的Nt函数,索引即在函数的第二个字节。

//HOOK后跳入的函数地址DWORD dwHookSystemCall[0x4C8*10] = {
0};//保存原始函数调用地址DWORD *dwOrigSystemCall[0x4C8*10] = {
0};//调用函数GetDllFuncAddr以便获得服务号int HookSystemCall::GetSysCallIndex( PCHAR FuncName ){ DWORD FuncAddr; //函数地址 int SysCallIndex;//服务号 FuncAddr = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"),FuncName); SysCallIndex = *( (WORD*)(FuncAddr + 1) ); return SysCallIndex;}

 

接下来要Hook KiFastSystemCall,这个调用代码如下:

77866190 >  8BD4             MOV EDX,ESP77866192    0F34             SYSENTER77866194 >  C3               RETN

可以看到只有短短5个字节,所以要 Hook就要先进行短跳转,再来一发长跳转,如下:

//    Hook KiFastSystemCall    *(PWORD)ULongToPtr(dwKiFastSystemCall) = 0xF9EB; //即 EB F9 --> 向前跳5个字节    *(PBYTE)ULongToPtr(dwKiFastSystemCall - 0x5) = 0xE9;    *(PDWORD)ULongToPtr(dwKiFastSystemCall - 0x4) = PtrToUlong(KiFastSystemCall) - (dwKiFastSystemCall - 0x5) - 5;//跳到自己的KiFastSystemCall中

自己的KiFastSystemCall如下:

DWORD HookFunctionAdress;__declspec(naked) void KiFastSystemCall(){        __asm{        pushad            pushfd            cmp         dword ptr [eax*4+dwHookSystemCall],0;比较是否已经有Hook过的函数            jz          Label            popfd            popad            add         esp,4            jmp         dword ptr [dwHookSystemCall+eax*4]Label:        push eax        call HookFunctionAdress        popfd        popad        jmp         KiFastSystemCallEx    }}

对于KiFastSystemCall需要补充一点,Ring3层的堆栈空间如何被传入Ring0层代码中,这里用的方法是MOV EDX,ESP。在内核代码中直接MOV ESP,EDX就可以得到Ring3层的堆栈空间,完全不用拷贝就能直接得到所有的参数。而上面代码 add esp,4 是因为当调用Zw函数时进入Zw再进入KiFastSystemCall中已经发生一次call,esp向上抬了4个字节,需要加回来才能调用正确的参数。

 

下面就是安装钩子的代码了:

// 安装钩子BOOL HookSystemCall::InstallHook(PCHAR FunName,        //NTAPI                                 DWORD pHookFunc,    //HOOK的函数                                 DWORD * pOrigFunc)    //返回的函数{    DWORD dwOldProtect;    DWORD dwIndex = GetSysCallIndex(FunName);    DWORD    dwFunadd =PtrToUlong(GetProcAddress(GetModuleHandleA("NTDLL.dll"), FunName));        //保存各种信息    dwHookSystemCall[dwIndex] = pHookFunc;    dwOrigSystemCall[dwIndex] = (PDWORD)malloc(0x10);        //将原本的ZW函数保存进去    memcpy(dwOrigSystemCall[dwIndex],(PVOID)dwFunadd,0x10);        //野猪改造开始    VirtualProtect(ULongToPtr(dwOrigSystemCall[dwIndex]), 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect);    *(PBYTE)((DWORD)dwOrigSystemCall[dwIndex]    + 5)    =     0xE8;    *(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 6)        =     (DWORD)KiFastSystemCallEx - (DWORD)dwOrigSystemCall[dwIndex] -0xA;//修改系统的KiFastSystemCall为自己的    *(PWORD)((DWORD)dwOrigSystemCall[dwIndex]    + 10)    =     0x9090;    * pOrigFunc = (DWORD)dwOrigSystemCall[dwIndex];        return 0;}// Ex安装钩子BOOL HookSystemCall::InstallHookEx(DWORD dwIndex,        //NTAPI                                   WORD dwRetIndex,    //返回堆栈平衡                                   DWORD pHookFunc,        //HOOK的函数                                   DWORD * pOrigFunc)    //返回的函数{    DWORD dwOldProtect;    //保存各种信息    dwHookSystemCall[dwIndex] = pHookFunc;    dwOrigSystemCall[dwIndex] = (PDWORD)malloc(0x10);    //将原本的ZW函数保存进去    memcpy(dwOrigSystemCall[dwIndex],(PVOID)SystemCall,0x10);    //野猪改造开始    VirtualProtect(ULongToPtr(dwOrigSystemCall[dwIndex]), 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect);    *(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 2)        =     (DWORD)dwIndex;    *(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 7)        =     (DWORD)KiFastSystemCallEx - (DWORD)dwOrigSystemCall[dwIndex] - 0xB;    *(PWORD)((DWORD)dwOrigSystemCall[dwIndex]    + 12)    =     dwRetIndex;    * pOrigFunc = (DWORD)dwOrigSystemCall[dwIndex];    return 0;}

EX这个主要是为了HOOK 一些不是NTDLL 导出的函数,比如NtUserFindWindowEx之类的函数,因为Shadow SSDT也是经由KiFastSystemCall进入内核,原理大概一致.

不过因为没办法直接获取函数INDEX所以必须根据系统版本自己确定,而且也无法获取函数地址,所以使用我们之前构造的函数原形来处理.ret的平衡也只能手动了!

 

最后附上源代码的地址:https://github.com/xiaomagexiao/GameDll/blob/master/HookSystemCall.cpp

转载于:https://www.cnblogs.com/Anony-WhiteLearner/p/8590637.html

你可能感兴趣的文章
消息队列2
查看>>
C++ 线程同步之临界区CRITICAL_SECTION
查看>>
测试—自定义消息处理
查看>>
MFC中关于虚函数的一些问题
查看>>
根据图层名获取图层和图层序号
查看>>
规范性附录 属性值代码
查看>>
提取面狭长角
查看>>
Arcsde表空间自动增长
查看>>
Arcsde报ora-29861: 域索引标记为loading/failed/unusable错误
查看>>
记一次断电恢复ORA-01033错误
查看>>
C#修改JPG图片EXIF信息中的GPS信息
查看>>
从零开始的Docker ELK+Filebeat 6.4.0日志管理
查看>>
How it works(1) winston3源码阅读(A)
查看>>
How it works(2) autocannon源码阅读(A)
查看>>
How it works(3) Tilestrata源码阅读(A)
查看>>
JDK下载(百度网盘)
查看>>
一篇掌握python魔法方法详解
查看>>
JNDI+springmvc使用
查看>>
XSL 开发总结
查看>>
【NOI 2018】归程(Kruskal重构树)
查看>>