首页
社区
课程
招聘
[原创]# 内核异常拦截
发表于: 2025-8-14 09:28 1792

[原创]# 内核异常拦截

2025-8-14 09:28
1792

新人新帖 菜鸟一个

前言


某个游戏的反调试检测问题


在测试某款游戏时即使将异常直接交给游戏自身的异常处理逻辑,也不会导致崩溃;

然而,最近再帮好友另一款游戏在遇到类似异常时,如果未进行拦截、而直接崩溃。



来简单的实现针对性异常过滤与处理机制,以避免游戏因反调试检测而异常退出



处理拦截 KiDispatchException 是用户态异常处理链的核心分发函数,


对特定异常进行有条件拦截


只作用于被标记为调试对象的目标进程。


在反作弊场景(如 EAC、BE)中,当然还有魔兽 游戏往往会主动制造异常,经过Xdbg测试


基本都会抛出 :


EXCEPTION_ILLEGAL_INSTRUCTION (0xC000001D) CPU 遇到无法识别的指令(非法指令)。


EXCEPTION_POSSIBLE_DEADLOCK(0x10000002) 系列中的“伪异常码”,实际上是 MS 的调试特例码


EXCEPTION_ACCESS_VIOLATION 0xC0000005 


和 DEP  

OK 让AI 写一个 指令长度解析 的函数  



static ULONG FastGetInstructionLength64(PVOID Address)
{
	UCHAR* code = (UCHAR*)Address;
	ULONG len = 0;

	// 跳过常用前缀
	BOOLEAN prefix = TRUE;
	while (prefix)
	{
		switch (code[len])
		{
		case 0xF0: case 0xF2: case 0xF3:
		case 0x2E: case 0x36: case 0x3E: case 0x26:
		case 0x64: case 0x65: case 0x66: case 0x67:
			len++;
			break;
		default:
			prefix = FALSE;
			break;
		}
	}

	UCHAR opcode = code[len++];
	if (opcode == 0x0F) opcode = (UCHAR)(opcode << 8 | code[len++]); // 两字节 opcode

	// 常用简单指令直接返回长度
	if (opcode == 0xCC || opcode == 0xF4 || opcode == 0x0F0B) return len;
	if (opcode == 0xCD) return len + 1; // int imm8

	// 快速跳过 ModR/M + SIB + disp + imm(粗略估计)
	if ((opcode & 0xC0) == 0x00) len += 1;

	return len;
}


#define MAX_DEBUG_EXC 64
static PVOID g_LastExcAddr[MAX_DEBUG_EXC] = { 0 };
static ULONG g_LastExcIndex = 0;

__forceinline BOOLEAN IsRepeatedException(PVOID addr)
{
	for (ULONG i = 0; i < MAX_DEBUG_EXC; i++)
	{
		if (g_LastExcAddr[i] == addr)
			return TRUE;
	}
	g_LastExcAddr[g_LastExcIndex++ % MAX_DEBUG_EXC] = addr;
	return FALSE;
}

去 hook 接管 KiDispatchException 大致函数实现流程就是:


__forceinline BOOLEAN IsDebugTarget()
{
	return (PsGetCurrentProcessId() == g_DebugProcess.TargetPID);
}


LONG KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, void* ExceptionFrame, PKTRAP_FRAME TrapFrame, KPROCESSOR_MODE PreviousMode,
	BOOLEAN FirstChance)
{

	if (PreviousMode != KernelMode && IsDebugTarget())
	{
		// 吃掉游戏异常
		if (FirstChance &&
			(ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION ||
				ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
				ExceptionRecord->ExceptionCode == 0x10000002)) // 自定义异常
		{
			if (!IsRepeatedException((PVOID)TrapFrame->Rip))
			{
				ULONG instLen = FastGetInstructionLength64((PVOID)TrapFrame->Rip);
				if (instLen == 0) instLen = 1;
				TrapFrame->Rip += instLen;
			}
			return EXCEPTION_CONTINUE_EXECUTION;
		}

	
		if (FirstChance &&
			ExceptionRecord->ExceptionCode == 0x10000004 &&
			ExceptionRecord->NumberParameters == 2 &&
			ExceptionRecord->ExceptionInformation[0] == 8)
		{
			return EXCEPTION_CONTINUE_SEARCH;
		}

		// 转换用户态 SegCs 异常码
		USHORT segCs = 0;
		__try { segCs = TrapFrame->SegCs; }
		__except (EXCEPTION_EXECUTE_HANDLER) { segCs = 0; }
		if ((segCs & 0xfff8) == KGDT64_R3_CMCODE)
		{
			switch (ExceptionRecord->ExceptionCode)
			{
			case STATUS_BREAKPOINT:
				ExceptionRecord->ExceptionCode = STATUS_WX86_BREAKPOINT;
				break;
			case STATUS_SINGLE_STEP:
				ExceptionRecord->ExceptionCode = STATUS_WX86_SINGLE_STEP;
				break;
			}
		}


		if (DbgkForwardException(ExceptionRecord, TRUE, FALSE))
		{
			BOOLEAN isInt2d = FALSE;
			__try
			{
				if (*(PUSHORT)((ULONG64)(TrapFrame->Rip) - 3) == 0x2DCD)
					isInt2d = TRUE;
			}
			__except (EXCEPTION_EXECUTE_HANDLER) { isInt2d = FALSE; }

			if (!isInt2d)
				return FALSE;
		}


		__try { segCs = TrapFrame->SegCs; }
		__except (EXCEPTION_EXECUTE_HANDLER) { segCs = 0; }
		if ((segCs & 0xfff8) == KGDT64_R3_CMCODE)
		{
			switch (ExceptionRecord->ExceptionCode)
			{
			case STATUS_WX86_BREAKPOINT:
				ExceptionRecord->ExceptionCode = STATUS_BREAKPOINT;
				break;
			case STATUS_WX86_SINGLE_STEP:
				ExceptionRecord->ExceptionCode = STATUS_SINGLE_STEP;
				break;
			}
		}
	}

	// 调用原始 KiDispatchException
	return fnKernel::old_KiDispatchException(
		ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);

}

  • 通过拦截 KiDispatchException 并判断是否为调试目标进程,可以有选择性地过滤异常。

  • 对非法指令、DEP 违规等异常进行跳过处理,避免游戏因反调试检测而崩溃。

经过测试 对ms 或者jd  正常下段 不再出现游戏崩溃问题  如代码出现问题 请大佬指教 





传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 104
活跃值: (7406)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
tql
2025-8-14 14:11
0
雪    币: 127
活跃值: (1245)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
牛逼,值得学习
2025-8-16 07:19
0
雪    币: 390
活跃值: (1762)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
给大佬点赞
2025-8-22 11:09
0
雪    币: 127
活跃值: (1245)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
给大佬点赞,谢谢分享好的技术观点,希望以后继续发扬。
2025-12-30 19:47
0
游客
登录 | 注册 方可回帖
返回