“Hooks.h” es una cabecera escrita en lenguaje C, que recopila las funciones más importantes a la hora de realizar ganchos en modo kernel (en sistemas MS Windows), y que nos permite llevar cierto orden a la hora de saber cuántas y qué funciones, están enganchadas en la SSDT del kernel de Windows.
Básicamente, su comodidad reside en la relación existente entre las funciones, y tres variables declaradas que nos ayudan a llevar un control de los ganchos:
#define NHOOKS 1//Numero de ganchos
unsigned short SSDT_HOOKED=0;//Booleano
unsigned short HOOKS_SSDT[NHOOKS]={0};//El estado de cada gancho
Cada función está definida con un valor entero, el cual usaremos en nuestras funciones y con el que movernos en el array “HOOKS_SSDT” para saber el estado del gancho. Ejemplo:
#define ZwCPEx 1
Para usar más funciones, basta con modificar el código de “Hooks.h” para que trabaje con ellas de la misma manera que lo hace con “ZwCreateProcessEx”, y definirlas con un ID único para cada funcion. Aprovechando la declaración anterior de “ZwCPEx”, la siguiente funcion podria ser:
#define ZwQSI 2 //ZwQuerySystemInformation
A continuación, el código de “Hooks.h” usando como ejemplo la API “ZwCreateProcessEx”:
/** ESTRUCTURAS Y VARIABLES PARA REALIZAR LOS GANCHOS **/
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
#define SYSTEMSERVICE(_function) \
KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig ) _Orig = \
(PVOID) InterlockedExchange((PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig ) InterlockedExchange( \
(PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
/** Para llevar un control de los ganchos **/
#define NHOOKS 1//Numero de ganchos
unsigned short SSDT_HOOKED=0;//Booleano
unsigned short HOOKS_SSDT[NHOOKS]={0};//El estado de cada gancho
/*
* FUNCION PARA ENGANCHAR LA SSDT Y SOBRE ESTA, ENGANCHAR
* NUESTRAS FUNCIONES
*/
NTSTATUS HookSSDT()
{
NTSTATUS ret=STATUS_UNSUCCESSFUL;
g_pmdlSystemCall=MmCreateMdl(NULL,KeServiceDescriptorTable.ServiceTableBase,
KeServiceDescriptorTable.NumberOfServices*4);
if(g_pmdlSystemCall)
{
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
SSDT_HOOKED=1;
ret=STATUS_SUCCESS;
#ifdef DEBUG
DbgPrint("SSDT Enganchada");
#endif
}
#ifdef DEBUG
else
DbgPrint("Error al enganchar SSDT");
#endif
return ret;
}
/*
* ENGANCHA UNA FUNCION DETERMINADA POR EL PARAMETRO "ID"
* EN LA SSDT
* (Ver cabeceras)
*/
void Hook(unsigned int ID)
{
NTSTATUS ret;
if(ID>=NHOOKS)
{
#ifdef DEBUG
DbgPrint("ID de la funcion fuera de rango");
#endif
return;
}
if(!(SSDT_HOOKED || (!SSDT_HOOKED && (ret=HookSSDT())==STATUS_SUCCESS)))
{
#ifdef DEBUG
DbgPrint("SSDT NO enganchada, y no se pudo enganchar");
#endif
return;
}
/* Deshabilitamos las interrupciones y
* desactivamos la proteccion contra escritura
* mediante el registro CR0 del micro
*/
_asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
switch(ID)
{
#ifdef ZwCPEx
case ZwCPEx:
HOOK_SYSCALL(ZwCreateProcessEx,ZwCreateProcessExHACK,ZwCreateProcessExORIG);
HOOKS_SSDT[ID]=1;
#ifdef DEBUG
DbgPrint("%d Enganchada",ID);
#endif
break;
#endif
}
/* Habilitamos las interrupciones y
* activamos la proteccion contra escritura
* mediante el registro CR0 del micro
*/
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
return;
}
/*
* FUNCION PARA ENGANCHAR TODAS LAS FUNCIONES DEFINIDAS, EN LA SSDT
*/
void HookAll()
{
unsigned int i;
for(i=0;i<NHOOKS;i++)
Hook(i);
return;
}
/*
* FUNCION PARA DESENGANCHAR UNA FUNCION DETERMINADA POR EL
* PARAMETRO "ID" DE LA SSDT.
* (Ver cabeceras)
*/
void UnHook(unsigned int ID)
{
if(!SSDT_HOOKED)
return;
/* Deshabilitamos las interrupciones y
* desactivamos la proteccion contra escritura
* mediante el registro CR0 del micro
*/
_asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
switch(ID)
{
#ifdef ZwCPEx
case ZwCPEx:
if(HOOKS_SSDT[ID]==1)
{
UNHOOK_SYSCALL(ZwCreateProcessEx,ZwCreateProcessExORIG,ZwCreateProcessExHACK);
HOOKS_SSDT[ID]=0;
#ifdef DEBUG
DbgPrint("Desenganchada");
#endif
}
break;
#endif
}
/* Habilitamos las interrupciones y
* activamos la proteccion contra escritura
* mediante el registro CR0 del micro
*/
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
return;
}
/*
* FUNCION PARA DESENGANCHAR LA SSDT, ASEGURANDONOS PREVIAMENTE
* DE QUE NO HAY FUNCIONES ENGANCHADAS. EN CASO DE HABERLAS, LAS
* DESENGANCHA.
*/
void UnHookSSDT()
{
unsigned int i;
//Nos aseguramos de deshacer los ganchos
for(i=0;i<NHOOKS;i++)
if(HOOKS_SSDT[i])
UnHook(i);
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
SSDT_HOOKED=0;
#ifdef DEBUG
DbgPrint("SSDT liberada");
#endif
}
return;
}
sch3m4 C/C++, Kernel Mode, MS Windows, Programacion, Seguridad
Ultimos Comentarios