Localizando la EPROCESS
En ciertas ocasiones, cuando estamos programando en modo kernel en sistemas Windows, nos es necesario localizar la EPROCESS de algún proceso para conocer alguno/s de sus datos. Las siguientes funciones, devuelven la dirección de memoria de la EPROCESS del proceso indicado, o bien por el PID del proceso, o por el nombre de la imagen.
Localizar según el PID
unsigned long BuscaEPROCESSPidDKOM(unsigned int Pid)
{
unsigned long eproc,aux,proceso,ret;
PLIST_ENTRY lista;
unsigned int idProceso=0;
eproc=(unsigned long)PsGetCurrentProcess();//estamos en "System"
//tenemos los punteros al siguiente y al anterior
lista=(LIST_ENTRY*)(eproc+0×88);
aux=(unsigned long)lista->Blink;
proceso=(unsigned long)lista;
idProceso=*((int *)(proceso+0×84));
while(proceso!=0 && aux!=proceso && Pid!=idProceso)//recorremos la lista
{
proceso-=0×88;
ret=proceso;
idProceso=*((int *)(proceso+0×84));
//avanzamos
lista=lista->Flink;
proceso=(unsigned long)lista;
}
if(Pid!=idProceso)
{
ret=0;
#ifdef DEBUG
DbgPrint("DKOM: Coincidencia no encontrada");
}else{
DbgPrint("DKOM: Coincidencia PID=%d",Pid);
#endif
}
return ret;
}
Localizar según el nombre de la imagen
unsigned long BuscaEPROCESSNombreDKOM(unsigned char *Nombre)
{
unsigned long eproc,aux,proceso,ret=0;
PLIST_ENTRY lista;
unsigned char *p;
eproc=(unsigned long)PsGetCurrentProcess();//estamos en "System"
//tenemos los punteros al siguiente y al anterior
lista=(LIST_ENTRY*)(eproc+0×88);
aux=(unsigned long)lista->Blink;
proceso=(unsigned long)lista;
p=(unsigned char *)(proceso+0×174);
/* Recorremos la lista (comparando con la longitud del proceso
que nos dice el sistema, y no con el de el usuario */
while(proceso!=0 && aux!=proceso && p!=0 &&
strncmp(Nombre,p,strlen(Nombre))!=0)
{
proceso-=0×88;
ret=proceso;
p=(unsigned char *)(proceso+0×174);
//avanzamos
lista=lista->Flink;
proceso=(unsigned long)lista;
}
if(strncmp(Nombre,p,strlen(Nombre))!=0)
{
ret=0;
#ifdef DEBUG
DbgPrint("DKOM: Coincidencia no encontrada");
}else{
DbgPrint("DKOM: Coincidencia: %s",Nombre);
#endif
}
return ret;
}
Hooks.h
“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;
}




