首页
社区
课程
招聘
Windows内核-异常(十)
2022-8-27 14:59 7075

Windows内核-异常(十)

2022-8-27 14:59
7075

10.1.cpu异常

中断和异常(都是IDT里面的函数)

中断源:

  • 硬件产生

  • 软件产生

异常源:

  • 处理器检测到的程序错误异常

  • 软件产生的异常

  • 机器检测异常

异常分三类

  • 错误:是一种通常能够被修正的异常

  • 陷进:当引起陷进的指令发生时,马上产生异常

  • 终止:严重错误

10.2.内核态异常派发

    如果这是第一次机会处理该异常,即 FirstChance 参数为TRUE,那么,交给内核调试器处理该异常,若内核调试器处理了该异常,则返回,发生异常的指令流继续执行;
    若不存在内核调试器或内核调试器没处理该异常,则调用RtlDispatchException 函数,试图将该异常分发到一个基于调用帧的异常处理器(call frame based handler)。只要能找到一个异常处理器能处理此异常,就返回。若第一次机会该异常未被处理,则再给内核调试器一次机会。若这次仍未被处理,则进入错误检查(bugcheck)。
    因此,内核模式的异常必须被处理,一旦未被处理,则系统崩溃。

_EXCEPTION_RECORD异常记录

typedef struct _EXCEPTION_RECORD { 
	 NTSTATUS ExceptionCode;   // 异常码
	 ULONG ExceptionFlags;    // 异常标志
 	 struct _EXCEPTION_RECORD *ExceptionRecord;   //相关的另一个异常
	 PVOID ExceptionAddress;   // 异常发生地址
	 ULONG NumberParameters;   // 参数数组中的元素个数
 	ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];   // 参数数组
 } EXCEPTION_RECORD;

KiDispatchException

KiDispatchException (
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN PKEXCEPTION_FRAME ExceptionFrame,   //一般为NULL
    IN PKTRAP_FRAME TrapFrame,		  //KTRAP_FRAME结构
    IN KPROCESSOR_MODE PreviousMode,     //0:内核 1:用户
    IN BOOLEAN FirstChance              //TRUE:第一轮   FALSE:第二轮
)

内核态派发流程逆向分析

10.3.用户态异常派发

    首先判断是否这是第一次机会处理该异常。如果这是第一次机会,若发生异常的进程(即当前进程)的调试端口为空并且有内核调试器,则交给内核调试器。
    若调试端口不为空,则发送一个消息至调试端口,然后等待应答。如果调试器处理了异常,则返回,继续执行。否则,把异常信息填充到用户栈中,并且设置好用户模式的 Eip为 KeUserExceptionDispatcher 函数指针(指向ntdll.dll 中的KiUserExceptionDispatcher 函数,在进程管理子系统初始化时设置),准备好该函数所需要的参数,然后KiDispatchException函数返回。
    因此,当从内核模式的异常处理例程返回以后,ntdll.dll 的 KiUserException.Dispatcher 函数获得控制,它会试图将该异常分发给一个基于调用帧的异常处理器。如果存在一个基于调用帧的异常处理器处理了该异常,则程序继续执行。如果该异常仍然未被处理,则通过 NtRaiseException 函数再次进入到内核中处理该异常。这一次KiDispatchException 函数被调用时,FirstChance 参数为 FALSE。
    如果是第二次机会处理一个异常,并且当前进程有一个调试端口,则发送一个消息至调试端口,然后等待应答。如果进程的调试器处理了该异常,则返回,并继续执行。否则,如果当前进程有一个异常端口,则发送一个消息至异常端口,然后等待应答。如果连接异常端口的环境子系统(Win32 子系统)处理了该异常,则返回,并继续执行。如果该异常仍未被处理,则进程被终止。


如果是用户态,从这里会跳转

10.4.VEH逆向分析

vector exception handler,一个进程的全局异常捕获,是一个链表

main.cpp

#include <stdio.h>
#include <Windows.h>

LONG NTAPI VectoredExceptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
{
	printf("ExceptionAddress = %x \n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
	printf("ExceptionCode = %x \n", ExceptionInfo->ExceptionRecord->ExceptionCode);
	printf("ExceptionFlags = %x \n", ExceptionInfo->ExceptionRecord->ExceptionFlags);
	printf("NumberParameters = %x \n", ExceptionInfo->ExceptionRecord->NumberParameters);
	
    //跳过两个字节,也就是跳过这个int i = x / 0; 
	ExceptionInfo->ContextRecord->Eip += 2;   

	MessageBoxA(NULL, NULL, NULL, NULL);

	return EXCEPTION_CONTINUE_EXECUTION;
}


int main()
{
    //第一个参数为TRUE:插在链表头部,为FALSE:插在链表尾部; 第二个参数为异常处理函数
	PVOID mem = AddVectoredExceptionHandler(TRUE, VectoredExceptionHandler);

	int x = 0;
	int i = x / 0;

	printf("测试\r\n");

	system("pause");

	return 0;
}

结果

ntdll.dll--->RtlAddVectoredExceptionHandler逆向分析

进入_RtlAddVectoredExceptionHandler@12


KiUserExceptionDispatcher逆向分析

进入_RtlDispatchException@8

进入_RtlCallVectoredExceptionHandlers@8

跳转

如果引用计数位0,则跳转到

10.5.SEH异常

seh:结构化异常,每一个线程一个,TEB和KPCR都保存一个异常链表



10.6.SEH编译器扩展

1.异常捕获

// Defined values for the exception filter expression
#define EXCEPTION_EXECUTE_HANDLER      1      //无论什么异常都会捕获
#define EXCEPTION_CONTINUE_SEARCH      0	 //不处理,等下一个去处理
#define EXCEPTION_CONTINUE_EXECUTION (-1)    //发生异常的地方去处理

2.try  except

#include <stdio.h>
#include <Windows.h>

void test()
{
	__try
	{
		int x = 0;
		int y = x / 0;
		printf("-------1------\r\n");

	}
	__except (EXCEPTION_CONTINUE_SEARCH)
	{

		printf("------__except---2----\r\n");
	}
}


DWORD FilterException(PEXCEPTION_POINTERS info)
{
	if (info->ExceptionRecord->ExceptionCode == 0xC0000094)
	{
		printf("------除0错误----\r\n");
		info->ContextRecord->Eip += 2;
		return EXCEPTION_CONTINUE_EXECUTION;
	}

	return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
	__try
	{
		test();
	}
	__except (FilterException(GetExceptionInformation()))
	{
		printf("------__except---3----\r\n");
	}


	system("pause");
	return 0;
}

结果


10.7.UEH

顶层异常处理器,是整个异常处理的最后一环

#include <stdio.h>
#include <Windows.h>

LPTOP_LEVEL_EXCEPTION_FILTER oldFun = NULL;

LONG WINAPI filterFunc(
	_In_ struct _EXCEPTION_POINTERS* ExceptionInfo
)
{
	MessageBoxA(NULL,NULL,NULL,NULL);
	return oldFun(ExceptionInfo);
}

int main()
{
	oldFun = SetUnhandledExceptionFilter(filterFunc);
	int x = 0;
	int y = x / 0;

	return 0;
}



[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2022-8-27 15:01 被zhang_derek编辑 ,原因:
收藏
点赞5
打赏
分享
最新回复 (1)
雪    币: 229
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
heye123 2022-8-27 20:24
2
0
学习
游客
登录 | 注册 方可回帖
返回