本文所有代码回复2023-12-26获取。
简介
针对于各大安全厂商对私有内存的监控,就是我们之前使用VirtualAlloc/EX来申请的内存,最后执行shellcode如下图是RWX的内存区域,里面是我们的shellcode。
映射注入
由于各大安全厂商以及安全软件对分配私有内存有着高度监控,所以为了避免使用一些常见的API函数,比如VirtualAlloc/EX,VirtualProtect/Ex,映射注入使用Mapped内存类型,并使用不同的Win API函数,例如CreateFileMapping和MapViewOfFile。
需要注意的是VirtualProtect是无法更改更改映射内存的内存权限。
创建文件映射
这里需要用到如下函数:
CreateFileMapping
经微软介绍CreateFileMapping函数可以创建或打开命名或未命名的文件映射对象,该对象通过内存映射技术对文件内容的访问,它允许进程创建虚拟内存空间,映射到磁盘上文件的内容或另一个内存位置。该函数返回文件映射对象的句柄。
HANDLE CreateFileMappingA(
[in] HANDLE hFile,
[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
[in] DWORD flProtect,
[in] DWORD dwMaximumSizeHigh,
[in] DWORD dwMaximumSizeLow,
[in, optional] LPCSTR lpName
);
hFile 用于创建文件映射对象的文件的句柄,由于在实现中不需要从文件中创建文件映射因此可以使用INVALID_HANDLE_VALUE标志来代替,微软对INVALID_HANDLE_VALUE的解释是:
如果 hFile 为 INVALID_HANDLE_VALUE,则调⽤进程还必须在dwMaximumSizeHigh和dwMaximumSizeLow参数中指定映射对象的大小,在这种情况下CreateFileMappingA创建指定大小的文件映射对象。设置此标志允许函数在不使用磁盘中的文件的情况下执行任务,而是在内存中创建文件映射对象,大小由dwMaximumSizeHigh和dwMaximumSizeLow参数来决定的。
flProtect参数表示指定文件映射对象的权限,这里我们设置为PAGE_EXECUTE_READWRITE权限即可,这里并不会立即创建RWX的内存区域,而是稍后进行创建,我们如果设置PAGE_READWRITE的话,后续shellcode将无法执行。
MapViewOfFile
MapViewOfFile函数会将文件映射的视图映射到调用进程的地址空间中,它获取文件映射对象的句柄和所需的访问权限,并返回指向进程地址空间中映射开头的指针。
LPVOID MapViewOfFile(
[in] HANDLE hFileMappingObject,
[in] DWORD dwDesiredAccess,
[in] DWORD dwFileOffsetHigh,
[in] DWORD dwFileOffsetLow,
[in] SIZE_T dwNumberOfBytesToMap
);
hFileMappingObject参数表示文件映射对象的句柄,也就是上面我们通过CreateFileMapping创建的文件映射,dwDesiredAccess参数表示文件映射的访问类型,这里我们将其设置为FILE_MAP_EXECUTE和FILE_MAP_WRITE标志来返回有效的可执行和可写的内存。
代码编写
首先通过CreateFileMapping函数创建一个文件映射句柄。
这里的第一个参数我们上面说过了给他一个INVALID_HANDLE_VALUE标志,不需要从文件中创建文件映射,还有就是四个和第五个参数指定的就是映射对象的大小,这里我们第五个参数指定shellcode的大小即可,并且第三个参数我们需要指定PAGE_EXECUTE_READWRITE表示我们需要RWX的内存区域,但不是立即创建,而是稍后创建。
hFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, shellcodeSize, NULL);
创建完成文件映射之后,接下来需要来将文件映射的视图映射到进程的地址空间中。
这里第一个参数是我们上面通过CreateFileMapping函数拿到的文件映射的句柄,第二个参数就是我们上面说过的,需要将其设置为FILE_MAP_EXECUTE和FILE_MAP_WRITE标志,来返回有效的可执行和可写的内存,最后一个参数就是shellcode的大小。
pMapAddress = MapViewOfFile(hFile, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, shellcodeSize);
这前两步我们可以理解为VirtualAlloc这一类的函数。
创建完成之后,我们拿到了创建好内存的地址,然后通过memcpy将shellcode复制到创建好的内存地址中。
copy shellcode到内存。
最后我们通过回调函数去执行即可,当然你也可以使用创建线程的方式,或者指针的方式都可以。
EnumChildWindows(NULL, (WNDENUMPROC)Address, NULL);
但是我们提前得把这块内存的地址给他带出来。
*ppAddress = Address;
UnmapviewOfFile
UnmapviewOfFile函数用于取消映射先前映射的内存,这个一般我们在执行完shellcode之后再去调用,而不是正在运行中,UnmapviewOfFile函数只需要取消映射的文件映射视图的基地址,也就是Address。
我们来一步一步来跟一下:
首先将文件映射的视图映射到调用进程的地址空间,然后copy shellcode。
copy shellcode。
最后通过回调函数执行。