Created
December 19, 2017 22:58
-
-
Save ReubenBond/24a6ba0ca58b3af83fd78d109dc22058 to your computer and use it in GitHub Desktop.
INT3 Vectored Exception Handler hooking
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
veh_hook Vectored Exception Handler hooking library | |
Version: 24-March-2008 | |
**/ | |
#define WINVER 0x0501 | |
#define _WIN32_WINNT 0x0501 | |
#include <windows.h> | |
#include "veh_hook.h" | |
static veh_list_t* list = NULL; | |
char int3bp[] = "\xCC"; | |
bool add_veh_hook(void* origFunc, void* newFunc, int hook_type) | |
{ | |
//static veh_list_t* list = NULL; | |
DWORD oldProtect; | |
if (list == NULL) list = new_veh_list(); | |
if (list == NULL) return false; | |
void* handle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)veh_dispatch); | |
veh_node_t* newnode = insert_veh_node(list, origFunc, newFunc, handle); | |
// For memory hooks especially, we need to know the address of the start of the relevant page. | |
MEMORY_BASIC_INFORMATION mem_info; | |
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION)); | |
newnode->baseAddr = mem_info.BaseAddress; | |
VirtualProtect(origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &newnode->OldProtect); | |
memcpy((void*)(&newnode->origBaseByte), (const void*)origFunc, sizeof (BYTE)); | |
memcpy((void*)origFunc, (const void*)&int3bp, sizeof (BYTE)); | |
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect); | |
return true; | |
} | |
bool remove_veh_hook(void* origFunc) | |
{ | |
if (list == NULL) return false; | |
veh_node_t* node = get_veh_node(list, origFunc, true); | |
if (node == NULL) return false; | |
RemoveVectoredExceptionHandler(node->handle); | |
return remove_veh_node(list, origFunc); | |
} | |
bool remove_veh_node(veh_list_t* list, void* origFunc) | |
{ | |
veh_node_t* searchnode; | |
veh_node_t* lastsearchnode = NULL; | |
searchnode = list->head; | |
while (searchnode != NULL) | |
{ | |
if (searchnode->origFunc == origFunc) | |
{ | |
if (lastsearchnode == NULL) | |
{ | |
list->head = searchnode->next; | |
if (list->tail == searchnode) list->tail = searchnode->next; | |
} | |
else | |
{ | |
lastsearchnode->next = searchnode->next; | |
} | |
free(searchnode); | |
return true; | |
} | |
lastsearchnode = searchnode; | |
searchnode = searchnode->next; | |
} | |
return false; | |
} | |
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo) | |
{ | |
DWORD oldProtect; | |
void* Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress; | |
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode; | |
if (Code != STATUS_BREAKPOINT && Code != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH; | |
// Try to find the node associated with the address of the current exception, continue searching for handlers if not found; | |
veh_node_t* currnode = get_veh_node(list, Addr, false); | |
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH; | |
DWORD hooktype = currnode->hooktype; | |
// Pre-callback functions: | |
if (Code == STATUS_BREAKPOINT && hooktype == VEH_HK_INT3) | |
{ | |
//(Temporarily) remove the int3 breakpoint | |
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect); | |
memcpy((void*)Addr, (const void*)(&currnode->origBaseByte), sizeof (char)); | |
currnode->newFunc(); | |
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect); | |
} | |
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_INT3) | |
{ | |
// Restore the INT3 breakpoint | |
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect); | |
memcpy((void*)currnode->origFunc, (const void*)&int3bp, sizeof (BYTE)); | |
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect); | |
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS | |
return EXCEPTION_CONTINUE_EXECUTION; | |
} | |
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_HW) | |
{ | |
currnode->newFunc(); | |
} | |
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_MEM) | |
{ | |
currnode->newFunc(); | |
} | |
return EXCEPTION_CONTINUE_EXECUTION; | |
} | |
veh_list_t* new_veh_list() | |
{ | |
veh_list_t* newlist = (veh_list_t*)malloc(sizeof(veh_list_t)); | |
if (newlist == NULL) return NULL; | |
newlist->head = NULL; | |
newlist->tail = NULL; | |
return newlist; | |
} | |
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, void* newFunc, void* handle) | |
{ | |
if (list == NULL) return NULL; | |
/* create a new node and fill in the blanks */ | |
veh_node_t* newnode = (veh_node_t*)malloc(sizeof(veh_node_t)); | |
if (newnode == NULL) return NULL; | |
newnode->origFunc = origFunc; | |
newnode->newFunc = (pfvoid)newFunc; | |
newnode->handle = handle; | |
newnode->OldProtect = PAGE_EXECUTE_READWRITE; | |
newnode->next = NULL; | |
if (list->head == NULL) | |
{ | |
list->head = newnode; | |
list->tail = newnode; | |
} | |
else | |
{ | |
list->tail->next = newnode; | |
list->tail = newnode; | |
} | |
return newnode; | |
} | |
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, bool exactmatch) | |
{ | |
veh_node_t* newnode; | |
veh_node_t* closestnode = NULL; | |
if (list == NULL) return NULL; | |
newnode = list->head; | |
MEMORY_BASIC_INFORMATION mem_info; | |
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION)); | |
while (newnode != NULL) | |
{ | |
if (newnode->origFunc == origFunc) | |
{ | |
return newnode; | |
} | |
if (!exactmatch) if (newnode->baseAddr == mem_info.BaseAddress) closestnode = newnode; | |
newnode = newnode->next; | |
} | |
return closestnode; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
veh_hook Vectored Exception Handler hooking library | |
Version: 24-March-2008 | |
**/ | |
#ifndef LIST_T_H_INCLUDED | |
#define LIST_T_H_INCLUDED | |
#include <windows.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
// VEH Hooking types | |
#define VEH_HK_INT3 0 | |
#define VEH_HK_MEM 1 | |
#define VEH_HK_HW 2 | |
// - | |
#define OPCODE_INT3 "\xCC" | |
typedef void (*pfvoid)(); | |
typedef struct veh_node | |
{ | |
void* origFunc; | |
pfvoid newFunc; | |
void* handle; | |
DWORD hooktype; | |
void* baseAddr; // Address of the page in which origFunc resides. | |
BYTE origBaseByte; | |
DWORD OldProtect; | |
struct veh_node* next; | |
} veh_node_t; | |
typedef struct | |
{ | |
veh_node_t* head; | |
veh_node_t* tail; | |
} veh_list_t; | |
// VEH hook interface functions for creating and removing hooks. | |
bool add_veh_hook(void* origFunc, void* newFunc, int hook_type); | |
bool remove_veh_hook(void* origFunc); | |
// The VEH dispathing function is called by Windows every time an exception is encountered. | |
// the function dispatches calls to the correct inctercept function. | |
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo); | |
// Functions used internally by the library. | |
veh_list_t* new_veh_list(); | |
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, void* newFunc, void* handle); | |
bool remove_veh_node(veh_list_t* list, void* origFunc); | |
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, bool exactmatch); | |
#endif // LIST_T_H_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment