VEH Hook 及 检测

SEH(Struct Exception Handler,结构化异常) VEH(Vector Exception Handler,向量异常处理)
SEH是OS提供给线程来感知和处理异常的一种回调机制。
在Intel Win32平台上,由于FS寄存器问题指向当前的TIB(线程信息块),因此FS:[0]处能找到最新的一个EXCEPTION_REGISTRATION_RECORD结构。
typedef struct _EXCEPTION_REGISTRATION_RECORD {
    struct _EXCEPTION_REGISTRATION_RECORD *Next;
    PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;
EXCEPTION_ROUTINE (
    _Inout_ struct _EXCEPTION_RECORD *ExceptionRecord,
    _In_ PVOID EstablisherFrame,
    _Inout_ struct _CONTEXT *ContextRecord,
    _In_ PVOID DispatcherContext
    );

typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE;
typedef struct _EXCEPTION_RECORD {
    DWORD    ExceptionCode;
    DWORD ExceptionFlags;
    struct _EXCEPTION_RECORD *ExceptionRecord;
    PVOID ExceptionAddress;
    DWORD NumberParameters;
    ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
    } EXCEPTION_RECORD;
   
XP之后,在基于线程的SEH基础增加了基于进程的VEH
比较:
1.SEH基于线程,VEH基于进程
2.优先级:调试器 > VEH > SEH 即KiUserExceptionDispatcher()函数先检查进程是否处理调试,然后VEH,最后SEH.
3.SEH单链表,VEH双链表,VEH节点可挂在头上或尾上。
注册VEH的回调API:
PVOID WINAPI AddVectoredExceptionHandler(
  __in  ULONG FirstHandler,
  __in  PVECTORED_EXCEPTION_HANDLER VectoredHandler
);

IA-32处理器定义了8个调试寄存器(DR0-DR7) DR0-DR3用于指点内存地址或I/O地址 DR4-DR5保留,DR6事件发生报告详细信息,DR7定义中断条件。
硬件断点HOOK是结合DR0-DR3调试寄存器和Winows SEH或VEH机制所引入的HOOK机制,因不涉及修改代码,不易检验检测到。

 

//测试EXE
#include <stdio.h>
#include <Windows.h>
#include <vector>

typedef LONG  (WINAPI *PVECTOREDEXCEPTIONHANDLER)(PEXCEPTION_POINTERS ExceptionInfo);

typedef PVOID (WINAPI *ADDVECTOREEXCEPTIONHANDLER)(
    ULONG FirstHandler,
    PVECTOREDEXCEPTIONHANDLER VectoredHandler
);

typedef struct _VECTORED_EXCEPTION_NODE {
LIST_ENTRY ListEntry;
PVECTORED_EXCEPTION_HANDLER pfnHandler; // 该指针出于安全目的已经被加密
} VECTORED_EXCEPTION_NODE, *PVECTORED_EXCEPTION_NODE;

LONG CALLBACK VectoredHandlerinit1(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    return EXCEPTION_CONTINUE_SEARCH;
}
LONG CALLBACK VectoredHandlerinit2(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    return EXCEPTION_CONTINUE_SEARCH;
}
LONG CALLBACK VectoredHandlerinit3(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    return EXCEPTION_CONTINUE_SEARCH;
}


LONG CALLBACK VectoredHandler(__in  PEXCEPTION_POINTERS ExceptionInfo)
{
	ExceptionInfo;
	return EXCEPTION_CONTINUE_EXECUTION;
}

int CheckVEHHook(std::vector<PVOID>& vecVEH, bool bcache, bool bdelete = false)
{
	PVOID pExceptionHandler = NULL;
	PVECTORED_EXCEPTION_NODE pCurrent = NULL;
	PVECTORED_EXCEPTION_NODE pNext = NULL, pDel = NULL;
	pCurrent = (PVECTORED_EXCEPTION_NODE)AddVectoredExceptionHandler(0,VectoredHandler);
	if( pCurrent == NULL )
	{
		printf("AddVectoredExceptionHandler111 failed.\n");
		return 0;
	}
	pNext = (PVECTORED_EXCEPTION_NODE)pCurrent->ListEntry.Blink;
	//pNext = (PVECTORED_EXCEPTION_NODE)pNext->ListEntry.Flink;
	printf("fake addr:0x%.8x pfnHandler:0x%.8x VEH function.\n",
		pCurrent, DecodePointer(pCurrent->pfnHandler));
	for( ; pNext != pCurrent; )
	{
		pExceptionHandler = DecodePointer(pNext->pfnHandler);
		if( pExceptionHandler )
		{
			if( bcache )
			{
				vecVEH.push_back(pNext);
			}
			printf("found addr:0x%.8x pfnHandler:0x%.8x VEH function.\n",pNext,pExceptionHandler);
			pNext = (PVECTORED_EXCEPTION_NODE)pNext->ListEntry.Blink;
			if( bdelete )
			{
				std::vector<PVOID>::iterator findit = find(vecVEH.begin(),vecVEH.end(),pNext);
				if( findit == vecVEH.end() )
				{
					pDel = pNext;
					pNext = (PVECTORED_EXCEPTION_NODE)pNext->ListEntry.Blink;
					printf("#### addr:0x%.8x pfnHandler:0x%.8x VEH function is illegal.\n",pDel,pExceptionHandler);
					if( RemoveVectoredExceptionHandler(pDel) )
					{
						printf("####the 0x%.8x is deleted.\n",pDel);
					}
					else
					{
						printf("####delete failed.\n");
					}
					break;
				}
			}
		}
	}
	if( RemoveVectoredExceptionHandler(pCurrent) )
	{
		printf("the fake node 0x%.8x is deleted.\n",pCurrent);
	}
	else
	{
		printf("delete failed.\n");
	}
	return 0;
}
DWORD func_addr = 0, func_addr_offset = 0;
void __declspec(naked) ReturnOriginalFunc(void) {  
    __asm {  
        mov edi,edi  
        //push ebp      way 222  
        jmp [func_addr_offset]  
    }  
}  

LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {  
    if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) { 
		func_addr = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
		func_addr_offset = func_addr + 0x2;
		printf("***catch some exception, don't know who hook that.\n");
        if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr) {  
        //if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr+2) {    way 222  
            PCONTEXT debug_context = ExceptionInfo->ContextRecord;  
            printf("only blind cat meet mouse !\n");  
 
            debug_context->Eip = (DWORD)&ReturnOriginalFunc;  
            return EXCEPTION_CONTINUE_EXECUTION;  
        }  
    }  
   return EXCEPTION_CONTINUE_SEARCH;  
}  


void main()
{
	SetUnhandledExceptionFilter(ExceptionFilter);
	//事先加3个进去
	AddVectoredExceptionHandler(1,VectoredHandlerinit1);
    AddVectoredExceptionHandler(0,VectoredHandlerinit2);
    AddVectoredExceptionHandler(1,VectoredHandlerinit3);

	MessageBox(NULL,"the fact infor111","test SEH hook",MB_OK);

	std::vector<PVOID> vecVEH;
	printf("-----------------before LoadLibraryA.----------------\n");
	CheckVEHHook(vecVEH,true,false);

	::LoadLibraryA("WaiGua.dll");
	printf("-----------------after LoadLibraryA.----------------\n");
	CheckVEHHook(vecVEH,false,false);
	MessageBox(NULL,"the fact infor222","test SEH hook",MB_OK);

	printf("-----------------delete LoadLibraryA added veh.-----\n");
	CheckVEHHook(vecVEH,false,true);

	MessageBox(NULL,"the fact infor333","test SEH hook",MB_OK);
	//如果用下面的,是字面值需要VirtualProtect,并且和第2个MessageBox指向同一地址,则弹出内容还是被改变的。
	//MessageBox(NULL,"the fact infor222","test SEH hook",MB_OK);
	getchar();
}


 

//VEH hook dll.
// VEHHook.cpp : Defines the entry point for the DLL application.
//
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <limits.h>
#include <Winbase.h>

typedef HANDLE (WINAPI *OPENTHREAD) (DWORD dwFlag, BOOL bUnknow, DWORD dwThreadId); 
 OPENTHREAD g_lpfnOpenThread = NULL; 

 typedef LONG  (WINAPI *PVECTOREDEXCEPTIONHANDLER)(PEXCEPTION_POINTERS ExceptionInfo);

typedef PVOID (WINAPI *ADDVECTOREEXCEPTIONHANDLER)(
    ULONG FirstHandler,
    PVECTOREDEXCEPTIONHANDLER VectoredHandler
);
ADDVECTOREEXCEPTIONHANDLER g_AddVectorExceptionHandler = NULL;

DWORD func_addr = 0x00401000;
DWORD func_addr_offset = func_addr + 0x2;

void PrintParameters(PCONTEXT debug_context) 
{
    printf("EAX: %X EBX: %X ECX: %X EDX: %X\n",
        debug_context->Eax, debug_context->Ebx, debug_context->Ecx, debug_context->Edx);

    printf("ESP: %X EBP: %X\n",
        debug_context->Esp, debug_context->Ebp);

    printf("ESI: %X EDI: %X\n",
        debug_context->Esi, debug_context->Edi);

    printf("Parameters\n"
        "HWND: %X\n"
        "text: %s\n"
        "caption: %s\n",
        (HWND)(*(DWORD*)(debug_context->Esp + 0x4)),
        (char*)(*(DWORD*)(debug_context->Esp + 0x8)),
        (char*)(*(DWORD*)(debug_context->Esp + 0xC)));
    
}

void ChangeText(PCONTEXT debug_context) {
    char* text = (char*)(*(DWORD*)(debug_context->Esp + 0x8));
    int length = strlen(text);
	DWORD oldprotect = 0;
	VirtualProtect(text,length,PAGE_EXECUTE_READWRITE,&oldprotect);
    _snprintf(text, length, "Be Hooked!");
	VirtualProtect(text,length,oldprotect,&oldprotect);
}

void __declspec(naked) ReturnOriginalFunc(void) {
    __asm {
        mov edi,edi
        jmp [func_addr_offset]
    }
}

LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
    if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
        if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr) {
            PCONTEXT debug_context = ExceptionInfo->ContextRecord;
            printf("Breakpoint hit!\n");
            PrintParameters(debug_context);
            ChangeText(debug_context);
            debug_context->Eip = (DWORD)&ReturnOriginalFunc;
            return EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

void VEHHook(void) 
{
    HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if(hTool32 != INVALID_HANDLE_VALUE) 
	{
        THREADENTRY32 thread_entry32;
        thread_entry32.dwSize = sizeof(THREADENTRY32);
        FILETIME exit_time, kernel_time, user_time;
        FILETIME creation_time;
        FILETIME prev_creation_time;
        prev_creation_time.dwLowDateTime = 0xFFFFFFFF;
        prev_creation_time.dwHighDateTime = INT_MAX;
        HANDLE hMainThread = NULL;
        if(Thread32First(hTool32, &thread_entry32)) 
		{
	
            do { //取最早启动的线程作为hook对象
               
				if(thread_entry32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(thread_entry32.th32OwnerProcessID)
                    && thread_entry32.th32OwnerProcessID == GetCurrentProcessId()
                    /*&& thread_entry32.th32ThreadID != GetCurrentThreadId()*/)
				{
					HANDLE hThread = g_lpfnOpenThread(THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
														FALSE, thread_entry32.th32ThreadID); 
					GetThreadTimes(hThread, &creation_time, &exit_time, &kernel_time, &user_time);
					
					if(CompareFileTime(&creation_time, &prev_creation_time) == -1) 
					{
							//creation_time 小于 prev_creation_time时候为-1
                            memcpy(&prev_creation_time, &creation_time, sizeof(FILETIME));
                            if(hMainThread != NULL)
                                CloseHandle(hMainThread);
                            hMainThread = hThread;
                    }
                    else
                           CloseHandle(hThread);


                }
                thread_entry32.dwSize = sizeof(THREADENTRY32);
            } while(Thread32Next(hTool32, &thread_entry32));

            //(void)SetUnhandledExceptionFilter(ExceptionFilter);
			g_AddVectorExceptionHandler(1, ExceptionFilter);
            CONTEXT thread_context = {CONTEXT_DEBUG_REGISTERS};
            thread_context.Dr0 = func_addr;
            thread_context.Dr7 = (1 << 0);

            SetThreadContext(hMainThread, &thread_context);
            CloseHandle(hMainThread);
        }
        CloseHandle(hTool32);
    }
}

int APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) 
{
    if(reason == DLL_PROCESS_ATTACH) 
	{
        DisableThreadLibraryCalls(hModule);
        if(AllocConsole()) 
		{
            freopen("CONOUT$", "w", stdout);
            SetConsoleTitle("Console");
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
            printf("DLL loaded.\n");
        }

		HMODULE hDll = ::LoadLibrary("kernel32.dll");
		g_lpfnOpenThread =  (OPENTHREAD)::GetProcAddress(hDll, "OpenThread"); 
		func_addr = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
		func_addr_offset = func_addr+2;
		printf("MessageBoxA Addr: 0x%x\n",func_addr);
		g_AddVectorExceptionHandler = (ADDVECTOREEXCEPTIONHANDLER)GetProcAddress(GetModuleHandle("kernel32.dll"), "AddVectoredExceptionHandler");
        VEHHook();
    }
    return TRUE;
}


  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值