APC注入和KernelCallbackTable注入的实现
字数 2689 2025-08-25 22:58:28
APC注入和KernelCallbackTable注入技术详解
一、APC注入技术
1. APC基础概念
APC(Asynchronous Procedure Call)是Windows系统中的异步过程调用机制,允许在特定线程上下文中执行代码。APC分为两种类型:
- 用户模式APC:在目标线程的进程上下文中的用户空间执行,要求目标线程处于可更改的等待状态
- 内核模式APC:在内核空间执行,又可分为常规APC和特殊APC
2. APC相关结构
每个线程都有_KTHREAD数据结构,其中包含_KAPC_STATE类型的成员:
struct _KAPC_STATE {
LIST_ENTRY ApcListHead[2]; // 内核或用户态APC的队列头
PKPROCESS Process;
UCHAR InProgressFlags;
UCHAR KernelApcPending;
UCHAR UserApcPendingAll;
};
3. APC注入实现步骤
- 确定目标进程:通过PID找到要注入的进程
- 分配内存:在目标进程内存空间中分配内存
- 写入Shellcode:将准备好的Shellcode写入分配的内存
- 枚举线程:查找目标进程中的所有线程
- 队列APC:将APC函数放入所有线程的队列
- 执行Shellcode:线程恢复时执行Shellcode
4. 关键API函数
实现APC注入需要以下关键函数:
CreateToolhelp32Snapshot,Process32First,Process32Next- 枚举进程Thread32First,Thread32Next- 枚举线程OpenProcess,OpenThread- 打开进程/线程句柄VirtualAllocEx,WriteProcessMemory- 分配和写入内存QueueUserAPC- 将APC对象添加到线程队列ResumeThread- 恢复线程执行
5. Early Bird APC注入技术
传统APC注入的缺陷是无法强制线程执行注入代码,Early Bird技术通过以下方式解决:
- 以挂起状态创建新进程(
CREATE_SUSPENDED标志) - 在进程初始化阶段进行APC注入
- 线程恢复时自动执行注入代码
关键代码示例:
CreateProcessA(NULL, cmdLine, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo);
VirtualAllocEx(processInfo.hProcess, NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
VirtualProtectEx(processInfo.hProcess, addr, size, PAGE_EXECUTE_READ, &oldProtect);
QueueUserAPC((PAPCFUNC)shellcode, processInfo.hThread, 0);
ResumeThread(processInfo.hThread);
二、KernelCallbackTable注入技术
1. 基本概念
KernelCallbackTable位于PEB中,被KeUserModeCallback使用,允许内核态调用用户态函数。许多提权漏洞(如CVE-2018-8453)都涉及Hook KernelCallbackTable。
2. KernelCallbackTable结构
KernelCallbackTable包含大量回调函数指针,其中__fnCOPYDATA是注入常用的入口点:
typedef struct _KERNELCALLBACKTABLE {
ULONG_PTR __fnCOPYDATA;
ULONG_PTR __fnCOPYGLOBALDATA;
// ... 其他回调函数指针
} KERNELCALLBACKTABLE;
3. 注入实现步骤
- 生成并存放Payload
- 获取窗口句柄:通过
FindWindow查找目标窗口 - 获取进程ID:使用
GetWindowThreadProcessId - 读取PEB和KernelCallbackTable地址
- 写入新表到远程进程
- 更新PEB并触发Payload
- 恢复原KernelCallbackTable
- 清理资源
4. 关键API函数
FindWindow- 查找目标窗口GetWindowThreadProcessId- 获取窗口所属进程IDReadProcessMemory- 读取远程进程内存VirtualAllocEx,WriteProcessMemory- 分配和写入内存SendMessage- 发送消息触发回调NtQueryInformationProcess- 查询进程信息
5. 注入问题与解决方案
问题1:注入explorer.exe导致崩溃
- 原因:更新PEB时进程崩溃并重启,导致句柄失效
- 解决方案:注入其他进程如notepad.exe
问题2:隐藏进程无法获取窗口句柄
- 解决方案:
- 使用
STARTUPINFO结构设置窗口属性 - 设置
dwFlags为STARTF_USESHOWWINDOW - 设置
wShowWindow为SW_HIDE - 使用
WaitForInputIdle等待进程初始化完成
- 使用
关键代码示例:
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
CreateProcess(L"notepad.exe", NULL, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
WaitForInputIdle(pi.hProcess, 1000);
三、技术对比与选择建议
| 特性 | APC注入 | KernelCallbackTable注入 |
|---|---|---|
| 适用场景 | 新创建进程或已有进程 | 主要是GUI进程 |
| 技术要求 | 需要枚举线程 | 需要理解回调机制 |
| 稳定性 | 较高 | 可能导致目标进程崩溃 |
| 隐蔽性 | 较好 | 依赖窗口消息,可能被检测 |
| 实现复杂度 | 中等 | 较高 |
选择建议:
- 对新进程注入优先考虑Early Bird APC注入
- 对已有GUI进程可尝试KernelCallbackTable注入
- 需要高稳定性时避免注入关键系统进程如explorer.exe
四、防御建议
- 监控关键API调用:如
QueueUserAPC、WriteProcessMemory等 - 限制进程权限:遵循最小权限原则
- 启用DEP:防止数据区域执行代码
- 检测异常窗口消息:防范KernelCallbackTable注入
- 监控PEB修改:检测KernelCallbackTable篡改
五、扩展思考
- 组合利用:可将两种技术与DLL注入、进程空心化等技术结合
- 绕过检测:通过间接系统调用或直接内核对象操作绕过用户层监控
- 跨架构注入:研究32位与64位进程间的注入兼容性问题
- 新型系统适配:关注Windows新版本中这些机制的变化
通过深入理解这些注入技术的原理和实现细节,可以更好地进行安全防护和渗透测试工作。