前言
在开始讲解本文章技术之前,我们需要先了解什么是内存属性以及VEH。
内存属性(Memory Protection Attributes)用于控制进程对内存页的访问权限,防止非法访问和保护数据安全。就像是给每块内存加上不同的“门禁”,它的作用是防止程序随意读取、修改或执行不该访问的内存,从而提高安全性,避免程序崩溃或被恶意攻击。
VEH全称(Vectored Exception Handling),中文名向量异常处理,简单来说就是程序执行的时候报错了如果设置了异常处理那就会走到里面。
本文将演示如何去通过修改内存属性来加载shellcode,让杀软无法读取shellcode执行的那片内存空间,但我们能通过VEH来接管这篇内存空间让我们的shellcode执行。
内存属性
基本属性
属性 |
描述 |
PAGE_NOACCESS |
不能读取、写入或执行该页内容,访问会导致访问冲突(Access Violation)。 |
PAGE_READONLY |
只能读取该页内容,尝试写入会导致访问冲突。 |
PAGE_READWRITE |
可以读取和写入该页内容。 |
PAGE_WRITECOPY |
允许读,写入时会触发写时复制(Copy-on-Write)机制,分配新页。 |
PAGE_EXECUTE |
只能执行该页内容,不能读取或写入。 |
PAGE_EXECUTE_READ |
可以执行和读取该页内容,但不能写入。 |
PAGE_EXECUTE_READWRITE |
可以执行、读取和写入该页内容。 |
PAGE_EXECUTE_WRITECOPY |
允许执行和读取,写入时触发写时复制机制。 |
特殊属性(可与基本属性组合)
属性 |
描述 |
PAGE_GUARD |
使页面成为“保护页”,首次访问时会触发异常,之后 PAGE_GUARD 标志被移除。 |
PAGE_NOCACHE |
禁用 CPU 缓存,直接访问物理内存,通常用于硬件交互。 |
PAGE_WRITECOMBINE |
允许写入合并,提高写入性能,常用于 GPU 显存映射。 |
我们主要关注的是PAGE_GUARD属性。PAGE_GUARD是内存属性里面的一种,他的作用是,当你访问一个没有被分配的内存时候,会触发一个异常,这个异常可以被我们捕获,然后我们可以在异常处理函数中,对这个内存进行分配,然后返回到原来的地方继续执行。
原理
在读取shellcode的时候,我们将shellcode的那片内存空间设置为不可访问,当访问这块内存的时候就会报错,因为设置了VEH就会走到VEH里面,VEH将这块内存的属性取消不可访问,然后shellcode在继续去执行就不会报错了,执行完之后继续修改内存属性为不可访问,循环往复。
代码实现
我们需要先定义一个全局变量,这个全局变量会在异常处理函数中使用,用于知道是哪些需要保护的区域触发了异常
PageGuardMemory(): 这个函数将一个地址空间页面标记为guarded,以便当程序尝试读写该页面时触发硬件异常。它首先使用VirtualQuery()函数查询给定地址所在的页面信息、设置PAGE_GUARD标志并调用VirtualProtect()函数将该页面标记为guarded。
UnPageGuardMemory(): 这个函数将一个页面标记为非guarded,调用和‘PageGuardMemory()`类似,但是它将PAGE_GUARD标志从保护权限中移除。
VectoredExceptionHandler(): 此功能作为VEH的入口点,其目的是监听发生在用户代码内的异常。如果错误代码为EXCEPTION_GUARD_PAGE,则此函数将将执行点标记为单步操作标志;如果错误代码为EXCEPTION_SINGLE_STEP,则在发生单步异常后回到用户程序中,而VEH会检查当前异常是否与某些已被标记为guarded的页面有关。如果是,它将解除页面保护,使得进程继续执行。
注册异常处理。通过AddVectoredExceptionHandler函数设置异常走向我们的VEH函数。
我们可以看一下这个函数的定义。这个函数的作用就是添加VEH,简单说就是指定报错后处理的函数。
First 这个参数是确定调用优先级的,将我们的函数优先级设为1,优先调用我们的VEH函数。
Handler 异常处理的函数指针,这里将其指向我们的VEH函数
然后修改shellcode加载函数,在加载shellcode之前将其地址设置成受保护状态。
这样我们就实现了
思考
这里有一个问题,如果过杀软将PAGE_GUARD标记了,当我们去修改内存属性为PAGE_GUARD的时候,会不会将该行为探测到,从而将我们的进程结束并移除。
那我们是否可以将内存修改成其他属性从而达到和PAGE_GUARD类似的效果呢,答案是有的。
从内存属性那里看以看到,有一个叫PAGE_NOACCESS的内存属性,对其的描述是“不能读取、写入或执行该页内容,访问会导致访问冲突(Access Violation)。”。根据描述我们可以想到使用PAGE_NOACCESS来代替PAGE_GUARD实现类似的效果。
这里我们就不使用上面写的修改方式,我们通过使用NtProtectVirtualMemory来修改属性。
同样的我们的VEH函数也要修改一下
通过这样的方式我们可以代替PAGE_GUARD实现一个类似的功能,做到一定的规避,不容易被察觉。
总结
传统的PAGE_GUARD 直接触发 EXCEPTION_GUARD_PAGE,容易被检测。但通过使用PAGE_NOACCESS 触发 EXCEPTION_ACCESS_VIOLATION,并通过VEH 去接管这块内存,可以实现一个PAGE_GUARD 的替代方案,无 PAGE_GUARD 相关特征,AV/EDR 很难检测。
原文始发于微信公众号(泾弦安全):免杀对抗从0开始(八)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论