inlinehookinline HOOK啥意思的?

inlinehook  时间:2021-07-14  阅读:()

什么是杀毒软件?

江民和金山根本没用.杀毒能力很差. 瑞星占用资源比较大. 个人还是推荐卡巴斯基7.0.占用资源小.更新快,现在还可以免费使用半年. 只要下载个360安全卫士.!就可以免费使用半年卡巴. 360安全卫士下载地址. /

如何调用 ntuserquerywindow

有窗口的程序还可以inline hook NtUserQueryWindow+NtUserFindWindowEx+NtUserWindowFromPoint+NtUserNotifyIMEStatus+NtDuplicateObject防止其它程序枚举和复制自身窗口句柄。

wsyscheck里面的FSD是什么

不是,如果要真正回答这个问题,估计不是三言两语就可以说明白,但可以概括为:SSDT,是一个路标,像5楼所说,就是一个把ring3的Win32 API和ring0的内核API联系起来的角色,那么,这里又涉及到两个概念,一个是ring,一个是API。

所谓的ring,实际按等级分为0-3,但通常只用两个:系统核心层(0)和用户程序层(3),显然,前者有着至高无上的权限,后者只有着普通应用权限,受系统限制。

而API,是应用编程接口,windows中的dll便是其API函数的重要组成部分之一,它是能用来操作组件、应用程序或者操作系统的一组函数。

API又分为两级:用户API和原生API。

话说,我们在执行程序操作时,首先会由用户API导出相关函数,在用户API和原生API交换之前,会先经过ntdll.dll这个动态数据链接来实行真正意义上的交换,因为真正处理这个执行请求还是原生API(native API),然后,系统会在SSDT里查找原生API的位置,最后由原生API执行完成请求并返回。

实际上,SSDT就是一个表,里面记录的是原生API的位置以及其他一些相关信息。

FSD:file system driver,就是文件系统驱动。

通常,在系统中,负责管理磁盘数据和文件读写的部分被称为“文件系统”,而在windows系统中,是叫做“输入输出管理程序”,简称为IOS(汗,全称有一个单词不记得怎么写的……),而在IOS下面,就是“可安装文件系统”,简称为IFS(继续有单词不记得如何拼写……),再下面,也就是最底层,就是这个FSD了(呵呵,全称已经在有了……),很明显,如果控制了这方面的权限,那么,你会出现删除其相关文件出错,或者是储如此类的情况。

这个也是Rookit在hook SSDT以及inline hook SSDT以后,用于反anti-Rookit工具的一种自我保护措施。

总结一下,SSDT是程序执行过程中的一组函数路标,而FSD是对文件读写操作控制相关。

前者被恶意HOOK后,典型表现为,你执行程序明明做A事,结果却做B事去了,而FSD如果对恶意HOOK的话,则表现为对其相关程序进行保护,拒绝一些文件操作请求。

最后回答一下楼主的问题:hal.dll是Windows硬件提取层模块,用于解决硬件的复杂性(这个是百度知道里的)。

因为FSD直通ISO,而再下面就是向硬件化发展了。

总觉得这问题真不好讲清楚,好难缠,说不明,也很难说的感觉,有时间将在下一篇的Wsyscheck的教程中加以概括说明,有兴趣的朋友到时候可以留意一下。

由于自己的认识有限,可能不甚准确,仅供参考。

[]

inline hook只能hook在函数头部吗

当执行完我们自定义的hook函数之后,又从被hook函数的首部开始执行,被hook函数一进入就被跳转了。

而本文,则要实现在某个函数体内部任意地方进行hook并跳转,执行完我们的函数之后,再回到原来的位置继续向下执行完未执行的逻辑。

那么,初看这种方式似乎与前面写的两篇hook没有什么差别,都是hook,都是跳转然后回到被hook的函数。

但仔细一想,你会发现本文要实现的方式要比前面两种hook复杂,因为hook的地方是函数体内任意地方,那么回来的时候就不是直接调用被hook的函数了,而是要回到之前hook的地方去。

这期间就涉及到hook函数的返回地址问题和被hook函数的返回地址问题。

说了这么多,可能还是有点晕,先不管为什么要这么做,也不管这种hook方式能有什么用途(在本文最后会说明用途),下面我们先写一些代码,在实践中来想一想这种方式有什么用途,并且与之前的两篇hook进行比较。

首先,我们需要一个自定义的hook函数,这个函数也就是被hook函数被hook后跳转到的地方,这个hook函数负责hook与unhook,还可以监视寄存器,监视内存,也可以管理hook的次数,以供我们灵活的hook需求。

直接贴代码吧: [cpp] view plaincopyprint? #include #include #pragma warning( disable : 4311 ) #pragma warning( disable : 4312 ) #define HOOK_BYTES 5 typedef unsigned int uint; uint hookAddr = 0; char old_code[ HOOK_BYTES ]; char new_code[ HOOK_BYTES ]; void printRegisters( void ); bool hook( void ) { DWORD dwFlag; if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) ) { memcpy( old_code, ( void* )hookAddr, HOOK_BYTES ); memcpy( ( void* )hookAddr, new_code, HOOK_BYTES ); VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag ); return true; } return false; } void unhook( void ) { DWORD dwFlag; if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) ) { memcpy( ( void* )hookAddr, old_code, HOOK_BYTES ); VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag ); } } namespace global { uint gEAX = 0; uint gEBX = 0; uint gECX = 0; uint gEDX = 0; uint gESP = 0; uint gEBP = 0; uint gESI = 0; uint gEDI = 0; uint gRet = 0; // 临时的返回地址 uint gTmp = 0; // 一些临时的值保存 uint gPar = 0; // 被hook函数的正常返回地址 uint gCnt = 1; // 当前hook的次数 uint gMax = 0; // 最大hook次数,为0表示一直hook bool bEnt = 0; // 是否为第一次进入hook函数 } void __declspec( naked ) hook_jmp( void ) { __asm { __entry: pushad { cmp global::bEnt, 0 // 如果没有进入则表示需要unhook je __first cmp global::gMax, 0 // 如果为0,则一直启用hook逻辑 je __second mov eax, global::gCnt cmp eax, global::gMax // 如果当前hook次数没有达到最大次数,则继续 jl __second mov global::gCnt, 1 // reset state mov global::bEnt, 0 // reset state mov global::gMax, 0 // reset state mov eax, global::gPar // 被hook函数的正常返回地址 mov global::gRet, eax // 准备跳转到被hook函数的上层调用,结束hook popad jmp __ret } __first: // 保存相关重要寄存器值 { popad mov global::gEAX, eax mov global::gEBX, ebx mov global::gECX, ecx mov global::gEDX, edx mov global::gESP, esp mov global::gEBP, ebp mov global::gESI, esi mov global::gEDI, edi } // 第一次进入,unhook并监视相关状态 pushad { mov global::bEnt, 1 // 记录状态 mov edi, global::gEBP // 被hook函数的ebp mov eax, [ edi + 4 ] // 被hook函数的返回地址(其上层调用地址) mov global::gPar, eax // 保存返回地址 mov esi, __entry // 将被hook函数的返回地址修改为 mov [ edi + 4 ], esi // 本函数的首地址,以便执行完被hook函数的 // 剩余逻辑之后能够返回到本函数,决定是否 // 还需要hook。

call printRegisters // 打印寄存器值[测试],或者其他 call unhook // unhook mov eax, hookAddr // 获得被hook的内存地址 mov global::gRet, eax } popad pop global::gTmp // 移除本函数的返回地址,并将hook的地址设置 jmp __ret // 为本函数的返回地址,从而实现跳转 __second: // 第二次进入, 继续hook, 这次进入是被hook函数ret返回的,没有新的ret地址被压栈 { mov global::bEnt, 0 // 设置状态 add global::gCnt, 1 // 增加hook计数 call hook // hook mov eax, global::gPar // 将被hook函数的返回地址设置为本函数的 mov global::gRet, eax // 返回地址,从而实现正常的函数流程 } popad __ret: push global::gRet // 修改本函数的返回地址 ret } } void setHookBytes( uint addr ) { hookAddr = addr; new_code[ 0 ] = ( char )0xe8; // call 指令机器码 ( uint& )new_code[ 1 ] = ( uint )hook_jmp - addr - 5; // 计算跳转偏移 } void printRegisters( void ) { printf( "EAX = 0x%08x/n", global::gEAX ); printf( "EBX = 0x%08x/n", global::gEBX ); printf( "ECX = 0x%08x/n", global::gECX ); printf( "EDX = 0x%08x/n", global::gEDX ); printf( "ESP = 0x%08x/n", global::gESP ); printf( "EBP = 0x%08x/n", global::gEBP ); printf( "ESI = 0x%08x/n", global::gESI ); printf( "EDI = 0x%08x/n", global::gEDI ); } 如上,hook_jmp函数即为我们自定义的hook函数,当被hook函数被hook之后,就会跳转到这个函数里,执行相关逻辑,上面我加了很详细的注释。

应该很容易看懂。

还是先看怎么使用这套方法,再来细说,代码如下: [cpp] view plaincopyprint? void testHook( void ) { printf( "This is a hook test 1./n" ); printf( "This is a hook test 2./n" ); printf( "This is a hook test 3./n" ); printf( "This is a hook test 4./n" ); printf( "______________________/n" ); } int main( void ) { uint hook_addr = 0x0042ec7b; setHookBytes( hook_addr ); global::gMax = 2; if ( hook() ) { testHook(); testHook(); testHook(); } system( "pause" ); return 0; } 如上,testHook函数即为被hook的函数,在main函数中,0x0042ec7b则为testHook函数里的第二个printf调用的地址,在你的机器上可能不一样。

这里只是测试之用。

testHook函数具体反汇编代码如下: [cpp] view plaincopyprint? void testHook( void ) { 0042EC50 push ebp 0042EC51 mov ebp,esp 0042EC53 sub esp,0C0h 0042EC59 push ebx 0042EC5A push esi 0042EC5B push edi 0042EC5C lea edi,[ebp-0C0h] 0042EC62 mov ecx,30h 0042EC67 mov eax,0CCCCCCCCh 0042EC6C rep stos dword ptr es:[edi] printf( "This is a hook test 1./n" ); 0042EC6E push offset string "This is a hook test 1./n" (487E24h) 0042EC73 call @ILT+4550(_printf) (42D1CBh) 0042EC78 add esp,4 printf( "This is a hook test 2./n" ); 0042EC7B push offset string "This is a hook test 2./n" (487E08h) 0042EC80 call @ILT+4550(_printf) (42D1CBh) 0042EC85 add esp,4 printf( "This is a hook test 3./n" ); 0042EC88 push offset string "This is a hook test 3./n" (487DECh) 0042EC8D call @ILT+4550(_printf) (42D1CBh) 0042EC92 add esp,4 printf( "This is a hook test 4./n" ); 0042EC95 push offset string "This is a hook test 4./n" (487DD0h) 0042EC9A call @ILT+4550(_printf) (42D1CBh) 0042EC9F add esp,4 printf( "______________________/n" ); 0042ECA2 push offset string "_____________________./n" (487DB4h) 0042ECA7 call @ILT+4550(_printf) (42D1CBh) 0042ECAC add esp,4 } 0042ECAF pop edi 0042ECB0 pop esi 0042ECB1 pop ebx 0042ECB2 add esp,0C0h 0042ECB8 cmp ebp,esp 0042ECBA call @ILT+3570(__RTC_CheckEsp) (42CDF7h) 0042ECBF mov esp,ebp 0042ECC1 pop ebp 0042ECC2 ret 我们hook的就是第18行(0042EC7B)那句代码,setHookBytes构建了一个5字节的call语句,0xe8为CALL指令的机器码,后面4个字节是CALL的偏移量(目标地址 - 当前地址 - CALL指令占用的5个字节)。

在main函数中,构建了hook的5个字节之后,设置了hook次数,如main函数那段代码的第15行:global::gMax = 2,则会hook两次。

然后是main函数那段代码的第16行,调用hook函数,将5个字节的call指令写入0042EC7B中,并保存了0042EC7B中原来的代码到old_code中。

之后,我们便可以调用testHook函数进行测试hook的流程了。

最终输出结果为: This is a hook test 1. EAX = 0x00000017 EBX = 0x7ffdc000 ECX = 0x8df97741 EDX = 0x00499148 ESP = 0x0012fd84 EBP = 0x0012fe54 ESI = 0x00000000 EDI = 0x0012fe54 This is a hook test 2. This is a hook test 3. This is a hook test 4. ______________________ This is a hook test 1. EAX = 0x00000017 EBX = 0x7ffdc000 ECX = 0x8df97741 EDX = 0x00499148 ESP = 0x0012fd84 EBP = 0x0012fe54 ESI = 0x00000000 EDI = 0x0012fe54 This is a hook test 2. This is a hook test 3. This is a hook test 4. ______________________ This is a hook test 1. This is a hook test 2. This is a hook test 3. This is a hook test 4. ______________________ 可以看出,前面两次调用testHook函数时,都执行了hook_jmp函数,并调用了printRegisters函数将寄存器打印了出来,之后又回到testHook中,继续输出后面的3句字符串。

当两次hook之后,第三次调用testHook时,就不会再输出寄存器了,也没有被hook了。

我们来看几个比较hook_jmp中比较关键的几个地方: 第104到110行:这段汇编代码,主要用于保存testHook函数(被hook函数)的正常的返回地址(main函数里调用testHook的下一句指令的地址)到global::gPar变量中,并将hook_jmp的首地址(也就是__entry标签指示的地址)写入testHook函数的返回地址所在的内存里。

这样当unhook并执行完testHook之后又能回到hook_jmp中,进一步判断是否需要下一次hook。

如果不需要再hook(已经达到最大hook次数)时,则会执行第79到80行的两句汇编代码,这两句汇编代码的作用是将hook_jmp函数的返回地址设置为testHook函数正常的返回地址,也就是main函数里调用testHook函数的下一句汇编代码的地址(ret指令的原理如果不清楚,请看前两篇hook文章或查阅相关资料)。

这样一来,当不再需要hook时,就能顺利的从hook_jmp函数返回后直接跳转到main函数的作用域里。

这样整个调用流程就符合原本的调用流程了。

第113行:这句代码是在调用了printRegister函数之后进行unhook操作,将原本的5个字节的代码重新拷贝到testHook函数的相应代码地址的内存里,本例中为testHook函数中第二句printf函数调用的地址。

unhook之后,第115到116行的两句代码与第79到80行的两句汇编代码类似,只不过这时是将被hook的内存地址设置为hook_jmp的返回地址,这样就能在第一次进入testHook函数并执行完毕返回时,能够跳转到被hook的地址(hookTest函数里第2句printf调用的地址)继续向下执行剩余的逻辑。

第131到132行:这两句汇编代码与第79到80行的两句汇编代码一致,都是将main函数里相应的代码地址设置为hook_jmp函数的ret返回地址,这样就能直接从hook_jmp跳转到main函数里继续向下执行,这样也就代表testHook被顺利的调用完成。

所以,总结下来,hook_jmp函数会进入两次,第一次用于监视一些数据,本例只监视了相关寄存器,还可以增加监视指定内存地址等等。

第一次进入时,会保存被hook函数(testHook函数)的返回地址,并将其修改为hook_jmp函数的首地址,这样做是为了执行完testHook函数之后能够第二次进入hook_jmp函数。

那么,第二次进入后,首先是判断是否还需要hook,不需要则直接返回到main函数里,如果还要继续hook,则再次调用hook函数,然后跳转到main函数里。

这样就构成了一个严密的调用流程,一切都看起来很和谐的调用,有点类似缓冲区溢出攻击的原理。

hook_jmp函数中需要注意寄存器的保存,否则输出的寄存器值并不是testHook函数执行到hook位置时的寄存器状态,这样就丧失了监视的意义。

原理上其实比较简单,构建稍微细致了一些,与前两篇hook最大的不同就是需要手动修改ret的返回地址,从而达到hook的目的,不像之前的两篇hook,在进入hook函数之后,要回到被hook的函数时,只需要直接call就可以了,并不需要维护ret指令的返回地址。

另外,由于本文的hook方式与第一篇的hook方式类似,所以本文的方式并没有支持多线程环境。

好了,本文到此结束,由于水平有限,可能存在bug,还望指教,衷心感谢!

inline HOOK啥意思的?

hook 计算机里面一般是指 挂钩某函数, 就是替换掉原来的函数。

inline hook , 是直接在以前的函数替里面修改指令,用一个跳转或者其他指令来达到挂钩的目的。

这是相对普通的hook来说,因为普通的hook只是修改函数的调用地址,而不是在原来的函数体里面做修改。

一般来说 普通的hook比较稳定使用。

inline hook 更加高级一点,一般也跟难以被发现。

所以很多人比如病毒制作者都比较推崇inline hook。

Linode十八周年及未来展望

这两天Linode发布了十八周年的博文和邮件,回顾了过去取得的成绩和对未来的展望。作为一家运营18年的VPS主机商,Linode无疑是有一些可取之处的,商家提供基于KVM架构的VPS主机,支持随时删除(按小时计费),可选包括美国、英国、新加坡、日本、印度、加拿大、德国等全球十多个数据中心,所有机器提供高出入网带宽,最低仅$5/月($0.0075/小时)。This month marks Linod...

SugarHosts糖果主机六折 云服务器五折

也有在上个月介绍到糖果主机商12周年的促销活动,我有看到不少的朋友还是选择他们家的香港虚拟主机和美国虚拟主机比较多,同时有一个网友有联系到推荐入门的个人网站主机,最后建议他选择糖果主机的迷你主机方案,适合单个站点的。这次商家又推出所谓的秋季活动促销,这里一并整理看看这个服务商在秋季活动中有哪些值得选择的主机方案,比如虚拟主机最低可以享受六折,云服务器可以享受五折优惠。 官网地址:糖果主机秋季活动促...

杭州王小玉网-美国CERA 2核8G内存19.9元/月,香港,日本E3/16G/20M CN2带宽150元/月,美国宿主机1500元,国内宿主机1200元

官方网站:点击访问王小玉网络官网活动方案:买美国云服务器就选MF.0220.CN 实力 强 强 强!!!杭州王小玉网络 旗下 魔方资源池 “我亏本你引流活动 ” mf.0220.CNCPU型号内存硬盘美国CERA机房 E5 2696v2 2核心8G30G总硬盘1个独立IP19.9元/月 续费同价mf.0220.CN 购买湖北100G防御 E5 2690v2 4核心4G...

inlinehook为你推荐
微信收款语音播报怎么设置微信收付款如何设置声音提示oncontextmenu鼠标右键很好用,但是左键一点反应也没有,请问是什么原因呢?webcrack我用WebCrack4 在破解路由器密码的时候为什么在破解密码的中途自动关闭掉rownumbersql server 2005中row_number怎么用smartupload为什么使用smartupload执行上传保存操作时用这句smart.save("upload")失败用smart.save("/upload")成功清除电脑垃圾怎样清除电脑垃圾jsindexofjavascript 中indexof 的用法qq业务中心QQ业务办理pci数据捕获和信号处理控制器华硕pci数据捕获和信号处理控制器出现黄色叹号该下载什么驱动菜霸为什么现在都在说生意难做?
mysql虚拟主机 域名系统 到期域名查询 Dedicated 韩国加速器 轻博客 lamp配置 国外网站代理服务器 卡巴斯基官方免费版 129邮箱 腾讯实名认证中心 卡巴斯基是免费的吗 石家庄服务器托管 东莞主机托管 googlevoice globalsign 2016黑色星期五 挂马检测工具 9929 主机配置 更多