23-内存申请总结

从本篇到还有后面的两篇都是总结概况性的文章,旨在总结前面提及过的各种API的用法以及拓宽未介绍的思路和视野,这样就可以构造多条shellcode注入的执行链,帮助读者更好的绕过AV/EDR。

在shellcode的注入中,内存申请总是绕不过的话题,它是shellcode注入的三部曲的第一步,也是至关重要的一步。

⚠注意

  1. 在shellcode注入中一定要分清是注入本进程还是远程进程。

  2. 这里并不讨论使用Nt或Zw类型的API,也不讨论系统调用。

一、VirutallAlloc

官方文档:VirtualAlloc 函数 (memoryapi.h) - Win32 apps | Microsoft Learnarrow-up-right

VirtualAlloc 函数来是最常见的一个内存申请的API,它可以申请一块动态内存来存放我们的shellcode。

我们来回顾一下官方介绍的用法:保留提交更改调用进程的虚拟地址空间中页面区域的状态。 此函数分配的内存会自动初始化为零。

再看一下它的语法

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

我在这里再次说明,VirtualAlloc 的第三个参数 flAllocationType 才是这个函数的精髓所在,这使得 VirtualAlloc 可以申请一块RWX的内存区域。

二、VirtualAllocEx

官方文档:

VirtualAllocEx 是另一个可以申请一块RWX的内存区域的API,不过它申请的对象是远程进程

语法

三、HeapCreate+HeapAlloc

HeapCreate:创建可由调用进程使用的专用堆对象

语法

它的第一个参数 flOptions 可以设置为 HEAP_CREATE_ENABLE_EXECUTE,这是 HeapCreate+HeapAlloc 的关键所在,这意味着我们可以创建一块可以执行的堆对象。

HeapAlloc:从堆中分配内存块。 分配的内存不可移动。

语法

HeapAlloc 的第一个参数是要从中分配内存的堆的句柄,我们可以将 HeapCreate 创建的 HEAP_CREATE_ENABLE_EXECUTE 堆的句柄作为 HeapAlloc 的参数。

四、AllocADsMem

官方文档:AllocADsMem 函数 (adshlp.h) - Win32 apps | Microsoft Learnarrow-up-right

AllocADsMem :分配指定大小的内存块。很朴实无华的一个API,它分配的内存的保护属性为可读可写不可执行,常与 ReallocADsMem 搭配使用

语法

五、GlobalAlloc

官方文档:globalAlloc 函数 (winbase.h) - Win32 apps | Microsoft Learnarrow-up-right

GlobalAlloc:从堆中分配指定的字节数,该堆是全局堆,意味着各个进程都能访问到,值得关注是该全局堆为可读可写不可执行的。语法

六、LocalAlloc

官方文档:localAlloc 函数 (winbase.h) - Win32 apps | Microsoft Learnarrow-up-right

LocalAlloc:从堆中分配指定的字节数,该堆是本地堆,意味着只有调用进程可以使用,该本地堆是可读可写不可执行的。语法

七、CreateFileMapping+MapViewOfFile+MapViewOfFile2

官方文档:

CreateFileMapping:创建文件映射对象。语法:

它的第三个参数 flProtect 可以指定文件映射对象的页面保护属性,这个是关键所在,因为 MapViewOfFileMapViewOfFile2 返回的内存是不能用 VirtualProtect 修改内存的保护属性

MapViewOfFile:将文件映射的视图映射到调用进程的地址空间,返回值为映射视图的起始地址。语法:

MapViewOfFile2:将文件视图或页面文件支持的节映射到指定进程的地址空间中,返回值为映射视图的起始地址。语法

文件视图其实就是进程的某一块与文件映射对象建立映射关系的内存

八、本地缓冲数组

本地缓冲可能是栈上的某个内存也可能是堆中的某个内存,默认内存保护属性为可读可写不可执行。

九、VirtualProtect/VirtualProtectEx

VirutallAlloc 申请的内存是毋庸置疑可以修改的,且大多数网上的文章都会介绍 VirutallAlloc+VirtualProtect 的组合使用。在这里,介绍网上没有人介绍的,就是能不能尝试改变 GlobalAllocLocalAllocHeapAllocAllocADsMem本地缓冲数组 的内存保护属性

网上也有人用下面这条编译指令直接赋予数据段可执行权限,避免 VirtualAlloc 等敏感API调用。具体怎么用这些这些方法还是看情况而言的

9.1 测试能否修改GlobalAlloc

9.2 测试能否修改LocalAlloc

9.3 测试能否修改HeapAlloc

9.4 测试是否能修改AllocADsMem

9.5 测试是否能修改本地缓冲数组