shellcode loader
13、C++SEH实现shellcode loader
1、课程目标
- 理解SEH(结构化异常处理)机制
- 掌握__try/__except的使用
- 实现SEH方式执行ShellCode
- 了解SEH链的操作
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| SEH | Structured Exception Handling | 结构化异常处理 |
| __try/__except | - | MSVC SEH关键字 |
| EXCEPTION_RECORD | - | 异常信息结构 |
| FS:[0] | - | x86 SEH链头指针 |
3、代码实现
// seh_loader.cpp
// SEH方式执行ShellCode
#include <windows.h>
#include <stdio.h>
unsigned char shellcode[] = {
0x90, 0x90, 0x90, 0x90,
0x31, 0xC0, 0x40, 0xC3
};
LPVOID g_ShellcodeAddr = NULL;
// 方法1: 异常过滤器执行
LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ep) {
printf("[SEH] Exception filter called\n");
printf("[SEH] Exception code: 0x%08X\n",
ep->ExceptionRecord->ExceptionCode);
if (g_ShellcodeAddr) {
// 执行ShellCode
typedef int (*SC_FUNC)();
SC_FUNC func = (SC_FUNC)g_ShellcodeAddr;
int result = func();
printf("[SEH] Shellcode returned: %d\n", result);
}
return EXCEPTION_EXECUTE_HANDLER;
}
void Method1_FilterExecution() {
printf("[*] Method 1: Exception Filter Execution\n");
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
__try {
// 触发异常
*(int*)NULL = 0;
}
__except(ExceptionFilter(GetExceptionInformation())) {
printf("[SEH] Exception handled\n");
}
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
}
// 方法2: 在异常处理块中执行
void Method2_HandlerExecution() {
printf("[*] Method 2: Handler Block Execution\n");
LPVOID mem = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!mem) return;
memcpy(mem, shellcode, sizeof(shellcode));
__try {
// 故意除以零
int x = 1;
int y = 0;
int z = x / y; // 触发异常
printf("z = %d\n", z);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
printf("[SEH] In exception handler\n");
// 在处理块中执行ShellCode
typedef int (*SC_FUNC)();
SC_FUNC func = (SC_FUNC)mem;
int result = func();
printf("[SEH] Shellcode returned: %d\n", result);
}
VirtualFree(mem, 0, MEM_RELEASE);
}
// 方法3: 修改SEH链 (x86)
#ifndef _WIN64
typedef struct _EXCEPTION_REGISTRATION {
struct _EXCEPTION_REGISTRATION* Next;
PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
EXCEPTION_DISPOSITION __cdecl CustomHandler(
PEXCEPTION_RECORD ExceptionRecord,
PVOID EstablisherFrame,
PCONTEXT ContextRecord,
PVOID DispatcherContext)
{
printf("[SEH] Custom handler called\n");
if (g_ShellcodeAddr) {
// 修改EIP到ShellCode
ContextRecord->Eip = (DWORD)g_ShellcodeAddr;
return ExceptionContinueExecution;
}
return ExceptionContinueSearch;
}
void Method3_ManualSEH() {
printf("[*] Method 3: Manual SEH Chain (x86)\n");
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
// 手动注册SEH
__asm {
push CustomHandler // Handler
push fs:[0] // Next
mov fs:[0], esp // 注册
}
// 触发异常
__try {
*(int*)NULL = 0;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
// 不应该到这里
}
// 恢复SEH链
__asm {
pop fs:[0]
add esp, 4
}
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
}
#endif
// 方法4: 使用SetUnhandledExceptionFilter
LONG WINAPI TopLevelHandler(PEXCEPTION_POINTERS ep) {
printf("[TopLevel] Unhandled exception caught\n");
if (g_ShellcodeAddr) {
typedef int (*SC_FUNC)();
((SC_FUNC)g_ShellcodeAddr)();
}
return EXCEPTION_EXECUTE_HANDLER;
}
void Method4_TopLevelFilter() {
printf("[*] Method 4: Top Level Exception Filter\n");
g_ShellcodeAddr = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!g_ShellcodeAddr) return;
memcpy(g_ShellcodeAddr, shellcode, sizeof(shellcode));
// 设置顶层异常过滤器
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter =
SetUnhandledExceptionFilter(TopLevelHandler);
// 在新线程中触发未处理异常
// (主线程的__try会捕获,所以用新线程)
printf("[+] Top level filter set\n");
// 恢复
SetUnhandledExceptionFilter(oldFilter);
VirtualFree(g_ShellcodeAddr, 0, MEM_RELEASE);
}
int main() {
printf("========================================\n");
printf(" SEH ShellCode Loader \n");
printf("========================================\n\n");
Method1_FilterExecution();
printf("\n");
Method2_HandlerExecution();
printf("\n");
#ifndef _WIN64
Method3_ManualSEH();
printf("\n");
#endif
Method4_TopLevelFilter();
return 0;
}
4、课后作业
4.1、作业1:SEH链遍历
实现遍历当前线程的SEH链。
4.2、作业2:SafeSEH绑过
研究SafeSEH保护机制及其绕过方法。