Archive

Archive for the ‘Kernel Mode’ Category

Localizando la EPROCESS

October 31st, 2008 No comments

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;
}
Categories: C/C++, Kernel Mode, MS Windows, Programacion Tags:

Hooks.h

October 31st, 2008 2 comments

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;
}