#define DISPOSITION_DISMISS				0
#define DISPOSITION_CONTINUE_SEARCH 	1
#define DISPOSITION_NESTED_EXCEPTION	2
#define DISPOSITION_COLLIDED_UNWIND		3
 
#define EH_NONCONTINUABLE   0x01
#define EH_UNWINDING        0x02
#define EH_EXIT_UNWIND      0x04
#define EH_STACK_INVALID    0x08
#define EH_NESTED_CALL      0x10

#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025
#define STATUS_INVALID_DISPOSITION		0xC0000026

#define EXCEPTION_CONTINUE_EXECUTION 	-1

#define PAGE_EXEC_MASK (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)

typedef struct _EXCEPTION_RECORD {
	DWORD ExceptionCode;
	DWORD ExceptionFlags;
	struct _EXCEPTION_RECORD *ExceptionRecord;	// var_CW
	PVOID ExceptionAddress;
	DWORD NumberParameters;
	ULONG_PTR ExceptionInformation[15];
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;

typedef struct _EXCEPTION_REGISTRATION
{
	struct _EXCEPTION_REGISTRATION*	pNext;
	PEXCEPTION_HANDLER		handler;
} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;

typedef struct _VECTORED_EXCEPTION_NODE {
    LIST_ENTRY ListEntry;
    PVECTORED_EXCEPTION_HANDLER handler;
} VECTORED_EXCEPTION_NODE, *PVECTORED_EXCEPTION_NODE;

typedef enum _EXCEPTION_DISPOSITION 
{
  ExceptionContinueExecution,
  ExceptionContinueSearch,
  ExceptionNestedException,
  ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;

/* 7C97E3FA */
UCHAR LogExceptions = 0;

/* 7C97E3C0 */
LIST_ENTRY RtlpCalloutEntryList;

/* 7C9805E0 */
RTL_CRITICAL_SECTION RtlpCalloutEntryLock;
RTL_CRITICAL_SECTION LdrpLoaderLock;

/* 7C90E47C */
/*
 * 用户层的异常派发源头
 */
VOID KiUserExceptionDispatcher(__in PCONTEXT ContextRecord, 
                     __in PEXCEPTION_RECORD ExceptionRecord) 
{
	
	NTSTATUS Status;
	// 调用RtlDispatchException函数去派发异常.
	if (RtlDispatchException(ContextRecord, ExceptionRecord)) {
		/* 7C90E48E modify the execution context of the current thread to whatever the chosen exception handler gives us */
		// 结束异常分发
		Status = ZwContinue(ContextRecord, 0);
	} 
	else {
		/* 7C90E49A no exception handler found so re-raise the exception for a debugger or the NT exception handler */
		// 在此触发一个异常, 并触发时最后一个参数传FALSE,表明这是一个第二次触发的异常.
		Status = ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
	}
	
	/* 7C90E4A5 build an exception record with 20 bytes on the stack, second chance exception? */
	PEXCEPTION_RECORD exception = (PEXCEPTION_RECORD) alloca(0x14);
	exception->ExceptionCode = Status;
	exception->ExceptionFlags = 1;
	exception->ExceptionRecord = ContextRecord;
	exception->NumberParameters = 1;

	return RtlRaiseException(exception);
}

LPVOID RtlpGetRegistrationHead()
{
	_asm mov eax , fs:[0]
	_asm ret
}

/* 7C92A970 如果异常被处理返回TRUE */
BOOLEAN RtlDispatchException(PCONTEXT ContextRecord, PEXCEPTION_RECORD ExceptionRecord) {
	BOOLEAN ret = 0;
	LPVOID StackBase, StackLimit;
	PEXCEPTION_REGISTRATION head;
	DWORD kProcess_Flags;
	DWORD dispatch, highest;
	EXCEPTION_RECORD exRec;

	
	// 先将异常交给VEH处理. 如果能够处理,则结束异常分发
	if (RtlCallVectoredExceptionHandlers(ExceptionRecord, ContextRecord)) {
		/* 7C95010A */
		ret = 1;
	}
	else { /* 否则交给SEH处理 */
		
		/* 7C92A991 */
		RtlpGetStackLimits(&StackLimit, &StackBase);

		// 获取SEH链表头节点
		/* 7C92A99F */
		head = (PEXCEPTION_REGISTRATION)RtlpGetRegistrationHead();
		
		highest = 0;
		
		while (head != (PEXCEPTION_REGISTRATION) -1) {
			
			// 判断获取出来的节点的地址是否正确
			if (head < StackLimit || head + sizeof(EXCEPTION_REGISTRATION) > StackBase || head & 3) {
	
				ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID;
				goto exit;
			}
			
			// 判断异常处理函数的地址是否正确
			if (head->handler >= StackLimit && head->handler < StackBase) {
				
				ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID;
				goto exit;
			}
			
			// 判断异常处理函数是否为有效处理函数
			if (!RtlIsValidHandler(head->handler)) {
				/* 7C92A336 */
				ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID;
				goto exit;
			}
			else if (LogExceptions) {
				/* 7C950113 */
				RtlpLogExceptionHandler(ContextRecord, ExceptionRecord, 0, head, 0x10);
			}
			
			// 执行SEH的 _except_handler4()
			hret = RtlpExecuteHandlerForException(ContextRecord, 
			                                      head, 
												  ExceptionRecord,
												  &dispatch, 
												  head->handler);
			
			if (LogExceptions) {
				/* 7C950129 there is a second parameter to this function that I don't understand yet */
				RtlpLogLastExceptionDisposition(highest, hret);
			}
			
			/* 7C92AA1E */
			if (head == NULL) {
				ExceptionRecord->ExceptionFlags &= ~EH_NESTED_CALL;
			}
			
			/* 7C92AA27 */
			if (hret == DISPOSITION_DISMISS) {
				if (ExceptionRecord->ExceptionFlags & EH_NONCONTINUABLE) {
					/* 7C950181 */
					exRec.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
					exRec.ExceptionFlags = EH_NONCONTINUABLE;
					exRec.ExceptionRecord = ExceptionRecord;
					exRec.NumberParameters = 0;
					RtlRaiseException(&exRec);
					
					/* 7C92A31C a little fudging with this block */
					if (ExceptionRecord->ExceptionFlags & EH_STACK_INVALID) {
						goto exit;
					}
				}
				else {
					/* 77EDBD64 */
					ret = 1;
					break;
				}
			}
			// 如果SEH过滤函数返回的是搜索其它过滤函数处理
			else if (hret == DISPOSITION_CONTINUE_SEARCH) {
				/* 7C92A31C a little fudging with this block */
				if (ExceptionRecord->ExceptionFlags & EH_STACK_INVALID) {
					goto exit;
				}
			}
			else if (hret == DISPOSITION_NESTED_EXCEPTION) {
				/* 7C950169 */
				ExceptionRecord->ExceptionFlags |= EH_NESTED_CALL;
				
				if (dispatch > highest) {
					highest = dispatch;
				}
			}
			else { 
				/* 7C950147 */
					exRec.ExceptionCode = STATUS_INVALID_DISPOSITION;
					exRec.ExceptionFlags = EH_NONCONTINUABLE;
					exRec.ExceptionRecord = ExceptionRecord;
					exRec.NumberParameters = 0;
					RtlRaiseException(&exRec);
			}
			
			/* 7C92A326 */
			head = head->pNext;
		}
	}

exit:
	/* 7C92AA43 */
	return ret;
}

/* 7C92A934 */
// 调用VEH函数
BOOLEAN RtlCallVectoredExceptionHandlers(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord) {
	BOOLEAN ret = FALSE;
	struct {
		PEXCEPTION_RECORD eRec;
		PCONTEXT cRec;
	} Rec;
	PVECTORED_EXCEPTION_NODE veh;
	PVECTORED_EXCEPTION_HANDLER handler;
	DWORD disposition

	if (RtlpCalloutEntryList.Flink == &RtlpCalloutEntryList) {
		return FALSE;
	}
	
	eRec = ExceptionRecord;
	cRec = ExceptionRecord;
	
	// 进入临界区
	RtlEnterCriticalSection(&RtlpCalloutEntryLock);

	// 开始遍历VEH的双向链表
	for (veh = (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList.Flink); 
				veh != (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList; 
				veh =  (PVECTORED_EXCEPTION_NODE) veh->ListEntry.Flink) {
					
			// 解密处理函数地址
			handler = RtlDecodePointer(veh->handler);

			// 调用处理函数
			disposition = handler(&Rec);
			
			// 判断处理函数是否处理了异常.如果是则结束循环.
			// 如果没有,则继续找到下一个处理函数.
			if (disposition == EXCEPTION_CONTINUE_EXECUTION) {
				// 将返回值设置为TRUE.
				ret = 1;
				break;
			}
	}
	
	// 离开临界区
	RtlLeaveCriticalSection(&RtlpCalloutEntryLock);
	
	return ret;
}	

/* 7C9033DC */
VOID RtlpGetStackLimits(LPVOID **StackLimit, LPVOID **StackBase) {
	PTEB teb = _TEB;							// fs:18h
	
	*StackLimit = teb->NtTib->StackLimit;
	*StackBase = teb->NtTib->StackBase;
		
	return;
}

/* 7C92AA50 */
BOOLEAN RtlIsValidHandler(PEXCEPTION_HANDLER handler) {
	DWORD table_sz;
	LPVOID safeseh_table, base_addr;
	DWORD ret, result_len, exec_flags, high, low;
	MEMORY_BASIC_INFORMATION mbi;
	
	safeseh_table = RtlLookupFunctionTable(handler, &base_addr, &table_sz);

	if (safeseh_table == NULL || table_sz == 0) {
		/* 7C9500D1 ProcessExecuteFlags*/
		if (ZwQueryInformationProcess(INVALID_HANDLE_VALUE, 22, &exec_flags, 4, NULL) >= 0) {
			/* 7C92CF94 0x10 = ExecuteDispatchEnable */
			if (!(exec_flags & 0x10)) {
				return 1;
			}
		}
		
		/* 7C935E8E */
		if (NtQueryVirtualMemory(INVALID_HANDLE_VALUE, handler, NULL, &mbi, sizeof(MEMORY_BASIC_INFORMATION), &result_len) < 0) {
			return 1;
		}
		
		/* 7C935EA9 */
		if (!(mbi.Protect & PAGE_EXEC_MASK)) {
			RtlInvalidHandlerDetected(handler, -1, -1);
			return 0;
		}
		else if (mbi.Type != SEC_IMAGE) {
			return 1;
		}
		
		RtlCaptureImageExceptionValues(mbi.AllocationBase, &safeseh_table, &table_sz);
		
		/* 7C935ED0 */
		if (var_10 == NULL || table_sz == 0) {
			return 1;
		}
		
		return 0;
	}
	else if (safeseh_table == (LPVOID) -1 && table_sz == -1) {
		return 0;
	}
	
	/* 7C9500A6 */
	if (table_sz < 0) {
		RtlInvalidHandlerDetected(handler, safeseh_table, table_sz);
		return 0;
	}
	
	rel_addr = handler - base_addr;
	high = table_sz;
	low = 0;
	
	/* 7C9500B1 binary search through SafeSEH table */
	do {
		idx = (high + low) / 2;
		
		if (rel_addr < safeseh_table[idx]) {
			if (idx == 0) {
				RtlInvalidHandlerDetected(handler, safeseh_table, table_sz);
				return 0;
			}
			
			high = idx - 1;
			
			if (high < low) {
				RtlInvalidHandlerDetected(handler, safeseh_table, table_sz);
				return 0;
			}
		}
		else if (rel_addr > safeseh_table[idx]) {
			low = idx + 1;
			
			if (high < low) {
				RtlInvalidHandlerDetected(handler, safeseh_table, table_sz);
				return 0;
			}
		}
		else {
			break;
		}
	} while(1);
	
	return 1;
}

/* 7C92AAA4 */
LPVOID RtlLookupFunctionTable(PEXCEPTION_HANDLER handler, DWORD *base_addr, DWORD *table_sz) {
	MEMORY_BASIC_INFORMATION mbi;
	LPVOID safeseh_table, base;

	if (LdrpInLdrInit && RtlTryEnterCriticalSection(&LdrpLoaderLock) == 0) {
		/* 7C92DD29 3 = MemoryBasicVlmInformation */
		if (NtQueryVirtualMemory((HANDLE) -1, handler, 3, &mbi, sizeof(MEMORY_BASIC_INFORMATION), NULL) < 0) {
			return NULL;
		}
		else if (mbi.Type != SEC_IMAGE) {
			return NULL;
		}
			
		base = mbi.BaseAddress;
			
		/* 7C92DD51 */
		RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz);
	}
	else {
		if (_TEB != NULL) {
			/* 7C92AAD9 */
			PLDR_MODULE node = _PEB->Ldr->InLoadOrderModuleList.Flink
			
			if (_PEB->Ldr != 0 && node != NULL) {
				while (node != &_PEB->Ldr->InLoadOrderModuleList) {
					/* 7C92AB00 */
					if (handler < node->BaseAddr) {
						node = node->InLoadOrderModuleList.Flink;
						continue;
					}
					
					if (handler >= node->BaseAddr + node->SizeOfImage) {
						node = node->InLoadOrderModuleList.Flink;
						continue;
					}
					
					/* 7C92AB14 */
					base = node->BaseAddr;
					RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz);
					
					if (safeseh_table == NULL && NtDllBase != NULL && (base = RtlNtImageHeader(NtDllBase)) != NULL) {
						if (header > base && header < base + ((PIMAGE_NT_HEADER) base)->OptionalHeaders.SizeOfImage) {
							/* 7C950D7D */
							RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz);
						}
					}
					
					break;
				}
			}
		}
		
		/* 7C92AB2C */
		if (LdrpInLdrInit) {
			RtlLeaveCriticalSection(&LdrpLoaderLock);
		}
	}
	
	*base_addr = base;
	return safeseh_table;
}