我最近学习了内联挂钩x32和x64,它基于用jmp将函数的第一个字节覆盖到挂钩函数,或者通过将64地址推到rax然后将jmp rax推入以在x64体系结构上执行远jmp 我还学习了iat挂钩和延迟导入挂钩,这需要在导入表中编辑最不重要的保持函数地址以指向我的挂钩函数 同样,通过异常进行挂钩还需要至少将第一个字节编辑为一个未知字节,这样就会引发异常,您将使用已安装的处理程序捕获该异常并重定向到蹦床
所有这些类型的挂钩都需要编辑内存,并且该内存通常对于函数来说是PAGE_EXECUTEREAD,对于导入表来说是只读的
因此,攻击者将使用VirtualProtect或NtVirtualProtect来编辑字节
另一种挂钩方法是通过保护异常,该保护异常几乎不需要对字节进行任何编辑,而是需要对内存保护进行任何编辑,因此在访问函数时会引发异常,您将处理它们并执行所需的任何操作
因此,这些方法都需要更改内存保护,因此我想钩住VirtualProtect和NtVirtualProtect来防止对特定地址进行任何编辑,但是该钩子可以取消钩子的功能并绕过它
我听说过一些新的缓解措施,例如防止动态代码生成,但是我需要分配一些可执行代码,所以我不能使用它,并且也无法防止iat挂钩和保护异常挂钩
真的有一种方法可以完全防御钩子,或者至少使钩子变得很难吗?
答案 0 :(得分:1)
我认为您无法完全避免钩子。黑客仍然可以以不安装挂钩的方式修改磁盘上的可执行文件。或者他只是可以自己在可执行文件中安装钩子。
为防止这种情况,实际上有很多技术。例如,您可以对程序的修改进行大量检查。您可以对程序中的特定代码部分进行隐藏检查,也可以对代码进行混淆。还有许多其他技术,通常将它们组合在一起即可构成一个有效的软件保护系统。但是,没有任何一种方法可以使您的代码得到完全保护,免受黑客的修改。如果有这样的保护措施,则不会盗版任何软件/游戏。现在,分发给客户的盗版软件仅是一个难题。保护系统越复杂,破解它所花费的时间就越多。但这绝非不可能。
答案 1 :(得分:-1)
为防止内存编辑进而可能导致钩挂,必须对该过程进行适当的配置。当指定的内存传递给调用时,攻击者将通过对WriteProcessMemory/NtWriteVirtualMemory的调用来修改代码。攻击者将使用这些例程,而不管它们是否在要修改的进程的上下文中执行。攻击者还可以使用其他各种方式来写内存,攻击者可能会使用这些方式,我将介绍如何保护自己。
请注意,如果没有为包含要修改的地址的页面配置适当的属性,则不能阻止WriteProcessMemory / NtWriteVirtualMemory调用从用户模式修改代码。当NtWriteVirtualMemory发起系统服务请求时,内核将处理其余的请求。
从内核模式的角度来看,为Windows驱动程序提供的API确实提供了一个例程,该例程为某些类型的句柄(例如进程和线程句柄)上的操作注册回调。该例程称为ObRegisterCallbacks。某些软件使用此例程来防止其句柄上的某些操作完成。
ObRegisterCallbacks可以为以下类型的句柄操作注册回调
防止在指定的进程句柄上执行特定操作可能会导致系统服务请求(例如NtWriteVirtualMemory(WriteProcessMemory)和NtProtectVirtualMemory(VirtualProtect/Ex)无法完成。这样做可以防止攻击者通过服务请求将内存写入进程,也可以防止攻击者更改进程中虚拟页的保护。
从用户模式的角度来看,您在能够读取诸如进程和线程之类的对象的内核数据结构方面受到更多限制,并且在可以调用的例程类型方面也受到更多限制。如果攻击者只是决定调用VirtualProtectEx并将页面从只读/执行更改为读取/写入/执行,则无法阻止WriteProcessMemory。
对流程的代码和数据部分的强大配置仍然会走很长一段路。实际上,确保正确配置过程中的所有安全描述符,DACL等非常重要。首先,请确保您的代码页是只读/执行的。每个进程都包含一个VAD (virtual address descriptor) tree (implemented as an AVL tree)到内核。 VAD包含过程中一系列虚拟地址的属性和标志。这些属性和标志包括各种类型的保护,例如读/写/执行,写时复制,是否提交/保留内存等等。
在VAD标志中使用了一个名为SecNoChange的标志。如果使用NtCreateSection重新映射过程中的代码部分,然后在AllocationAttributes中传递SecNoChange,然后调用NtMapViewOfSection将存储器映射回过程,则它将使诸如NtProtectVirtualMemory之类的调用失败。这将防止攻击者修改代码的页面属性,以使攻击者无法引起任意异常并处理它们以重定向代码,并且如果它们是只读的或执行写入该内存的操作,则它们也不能更改保护。当然,写入只读存储器将失败。在这里,将代码页标记为只读/执行而不是读/写/执行很重要,这样攻击者就无法更改保护或写入地址范围。
即使为您的部分配置了SecNoChange,使用诸如内存完整性检查之类的其他缓解技术也不会造成损害。在基本级别上,内存完整性检查通常通过对一组页面的内存内容进行哈希处理,并使用生成的第一个哈希值来验证下一个周期的完整性,如果哈希不同,则说明内存已被修改,程序可能终止其当前活动。
Windows提供了许多类型的缓解技术和策略。我还将研究Windows提供的process mitigation policies。
答案 2 :(得分:-2)
我有一个很好的解决方案 如果我不想受到钩子的影响,请不要直接从蹦床上使用钩子函数,因此攻击者必须知道您的蹦床的地址