异常处理机制流程分析
字数 1311 2025-08-05 08:20:14
异常处理机制流程分析与反调试技术
前言
异常处理机制在二进制安全领域常用于动态反调试技术。当正常运行的进程发生异常时,在SEH(Structured Exception Handling)机制作用下,操作系统会接收异常并调用进程中注册的SEH处理程序。但如果进程正在被调试器调试,调试器会先于SEH接收处理异常。利用这一特性可以判断进程是正常运行还是调试运行,从而实现反调试。
异常处理流程分析
32位异常处理完整流程
-
KiUserDispatcher阶段
- 首先判断是64位异常还是32位异常
-
VEH(Vectored Exception Handling)链处理
- 遍历所有注册的VEH处理程序
-
SEH(Structured Exception Handling)链处理
- 遍历SEH处理程序
- 倒数第二个SEH会调用
UnHandledExceptionFilter- 内部调用
NtQueryInformationProcess查询DebugPort - 然后调用
TopLevelExceptionFilter处理
- 内部调用
-
返回阶段
- 通过
zwcontinue进行返回
- 通过
异常分发详细机制
-
首次分发
KiDispatchException尝试将异常分发给用户态调试器- 如果DebugPort不为空,将异常发送给调试子系统
- 调试子系统将异常发送给调试器
- 如果调试器处理了异常,分发结束
-
调试器未处理的情况
KiDispatchException修改用户态栈- 返回用户层后执行
KiUserExceptionDispatcher- 调用
RtlDispatchException寻找异常处理器- 首先遍历VEH
- 然后遍历SEH
- 调用
- 如果
RtlDispatchException返回FALSE且进程在被调试:- 调用
ZwRaiseException并将FirstChance设置为FALSE(第二轮分发)
- 调用
- 如果没有被调试,结束进程
-
第二轮分发
ZwRaiseException通过内核服务NtRaiseException把异常传递给KiDispatchException- 第二次将异常传递给调试器
- 如果仍未处理,将异常分配给ExceptionPort异常端口监听者处理
- 如果返回FALSE,结束进程
实例分析
程序主逻辑
v7 = 0;
memset(&v8, 0, 0x4Fu);
v10 = dword_401360;
sub_401060("input your flag : ", v6);
v5 = (int **)80;
sub_4010D0("%s", (unsigned int)&v7);
v13 = &v7;
v12 = &v8;
v13 += strlen(v13);
v11 = ++v13 - &v8;
if (v13 - &v8 == 16) // 判断输入长度是否为16
{
v9 = &v4;
v5 = &v10;
wsprintfA(&v4, "%s", &v10);
if ((unsigned __int8)sub_401860(&v7))
sub_401060("Good ,u success! \n", v6);
else
sub_401060("Wrong,u lose! \n", v6);
j___fgetchar();
result = j___fgetchar();
}
else
{
sub_401060("wrong u lose \n", v6);
result = 0;
}
return result;
关键函数分析
sub_401860函数
bool __cdecl sub_401860(_BYTE *a1)
{
signed int i; // [esp+0h] [ebp-4h]
*a1 *= 2;
a1[1] >>= 3;
a1[2] >>= 4;
a1[3] >>= 88;
a1[4];
a1[4] = 0;
a1[7] ^= 0xAu;
a1[8] += 61;
a1[9] /= 8;
a1[10] %= 4;
a1[11] ^= 0xCu;
for (i = 0; i < 10; ++i)
a1[i] = sub_4017E0(a1[i], a1[i+1]);
a1[12] ^= a1[11];
a1[13] ^= a1[12];
a1[14] ^= a1[13];
a1[15] ^= a1[14];
return sub_401390(i) != 0;
}
sub_401390函数
int __usercall sub_401390@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4@<ebx>,
int a5@<ebp>, int a6@<edi>, int a7@<esi>, int a8,
const char **a9, const char **a10)
{
*(_DWORD *)(a5 - 4) = a1;
*(_DWORD *)(a5 - 8) = a4;
*(_DWORD *)(a5 - 12) = a3;
*(_DWORD *)(a5 - 16) = a2;
*(_DWORD *)(a5 - 20) = a6;
*(_DWORD *)(a5 - 24) = a7;
if (*(_DWORD *)(a5 - 4) == 1466715468 &&
*(_DWORD *)(a5 - 8) == 794374773 &&
*(_DWORD *)(a5 - 12) == 1664641876 &&
*(_DWORD *)(a5 - 16) == 727266099 &&
*(_DWORD *)(a5 - 20) == 1984706644)
{
*(_DWORD *)(a5 - 24);
}
return main(a8, a9, a10);
}
异常处理关键点
- 程序在0x401360处触发异常
- 自定义VEH处理程序
LONG __stdcall Handler(struct _EXCEPTION_POINTERS *ExceptionInfo) { // 处理逻辑... return 0; } - TopLevelExceptionFilter处理
LONG __stdcall TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) { ExceptionInfo->ContextRecord->Eax = ExceptionInfo->ExceptionRecord->ExceptionInformation[0]; ExceptionInfo->ContextRecord->Ebx = ExceptionInfo->ExceptionRecord->ExceptionInformation[1]; ExceptionInfo->ContextRecord->Ecx = ExceptionInfo->ExceptionRecord->ExceptionInformation[2]; ExceptionInfo->ContextRecord->Edx = ExceptionInfo->ExceptionRecord->ExceptionInformation[3]; ExceptionInfo->ContextRecord->Edi = ExceptionInfo->ExceptionRecord->ExceptionInformation[4]; ExceptionInfo->ContextRecord->Esi = ExceptionInfo->ExceptionRecord->ExceptionInformation[5]; ExceptionInfo->ContextRecord->Eip = (DWORD)sub_401390; SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); RemoveVectoredExceptionHandler(Handler); return -1; }
加密流程分析
- 4轮异或操作
- 自定义Base64加密
- 字母表被修改为:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/
- 字母表被修改为:
- 解密脚本示例
import binascii
base64_table = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/'
base_encode = str(raw_input(u"请输入解密字符"))
counter = base_encode.count("=")
length = len(base_encode)
encode = ""
encode_re = ""
if (counter == 2):
a = base64_table.find(base_encode[length-4:length-3]) # 取前六位
a = a << 2
b = base64_table.find(base_encode[length-3:length-2]) # 取2位
b = b >> 4
encode_re = chr(a + b)
if (counter == 1):
a = base64_table.find(base_encode[length-4:length-3]) # 第一个字符前6位
a = a << 2
b = base64_table.find(base_encode[length-3:length-2]) # 第二个字符前2位
b = b >> 4
encode_re1 = chr(a + b)
a = base64_table.find(base_encode[length-3:length-2]) # 第二个字符后4位
a = (a & 0xf) << 4
b = base64_table.find(base_encode[length-2:length-1]) # 第三个字符前4位
b = b >> 2
encode_re2 = chr(a + b)
encode_re = encode_re1 + encode_re2
length = length - 4
if (counter == 0):
length = length + 4
for i in range(0, length, 4): # 以4个字符为一组
a = base64_table.find(base_encode[i:i+1]) # 第一个字符6位
a = a << 2
b = base64_table.find(base_encode[i+1:i+2]) # 第二个字符前2位
b = b >> 4
encode = encode + chr(a + b)
a = base64_table.find(base_encode[i+1:i+2]) # 第二个字符后4位
a = ((a & 0xf) << 4)
b = base64_table.find(base_encode[i+2:i+3]) # 第三个字符前4位
b = b >> 2
encode = encode + chr(a + b)
a = base64_table.find(base_encode[i+2:i+3]) # 取第三个字符后2位
a = (a & 3) << 6
b = base64_table.find(base_encode[i+3:i+4]) # 取第四个字符6位
encode = encode + chr(a + b)
encode = encode + encode_re
print(binascii.b2a_hex(encode))
print('\n')
总结
通过分析异常处理机制,我们可以:
- 理解Windows平台下异常处理的完整流程
- 掌握利用异常处理机制实现反调试的技术原理
- 学习如何分析复杂的加密和异常处理结合的二进制程序
- 掌握自定义Base64等加密算法的逆向分析方法
最终通过逆向分析得到的flag为:flag{Ex<ept10n~}