lunes, 28 de enero de 2013

ZwOpenProcess, provocar un acceso denegado

Llevo tiempo leyendo acerca de driver y me decidí a comenzar tocar código, es por ello que hice esta modificación al driver de Hendrix, que publica en su tema "Introducción a la programación de drivers en Windows", le agregue la parte de la comunicación, se que no es mucho pero bueno por algo se comienza.
Código de EXE
#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)
 
void Usage(char *name);
char *ExtractFileName(char *Name);
void SendPID(int PID, int bBlock);
 
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]), 1);
      break;
    }
     
    case 'u':{
      printf("Liberación de PID\n");
      SendPID(atoi(argv[2]), 0);
      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");
}
 
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, int bBlock){
  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, dwState, &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()); 
  }
}

Código del SYS
#include 
  
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase;
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
__declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
  
#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)
  
//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);
  
  
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";
UNICODE_STRING  Dev, lnk;
 
int ListPID;
 
NTSTATUS IOControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
  PIO_STACK_LOCATION Stack;
  int *oBuffer;
  int *iBuffer;
  NTSTATUS Status = STATUS_SUCCESS;
   
  Stack = IoGetCurrentIrpStackLocation(Irp);
   
  DbgPrint("Accesando a bloqueo de PID");
  DbgPrint("Asociando buffers...");
       
  iBuffer = oBuffer = Irp->AssociatedIrp.SystemBuffer;
  if (oBuffer && iBuffer){
    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){
              DbgPrint("Protegiendo PID %d.", *iBuffer);
              ListPID = *iBuffer;
              *oBuffer = 1;
            } else {
              *oBuffer = 0;
              DbgPrint("No hay espacio para proteger.");  
            }
            break;
          }
     
          case Unblock:
          {
            DbgPrint("Eliminando proteccion"); 
            if (ListPID != 0){
              DbgPrint("Liberando PID %d.", *iBuffer);
              ListPID = 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 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 (PID == (HANDLE)ListPID){
    DbgPrint("PID: 0x%x", 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 );
 
  //Eliminamos la MDL
  if(g_pmdlSystemCall)
  {
    MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
    IoFreeMdl(g_pmdlSystemCall);
  }
}
  
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING theRegistryPath)
{
  int i;
   NTSTATUS Status;
   DriverObject->DriverUnload  = OnUnload;
  for(i=0; iMajorFunction[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.");
   ZwOpenProcessIni =(TypZwOpenProc)(SYSTEMSERVICE(ZwOpenProcess));
  
   DbgPrint("Hookeando...");
   HOOK_SYSCALL( ZwOpenProcess, NewZwOpenProcess, ZwOpenProcessIni );
  
   return  Status;
}

En esta imagen se demuestra como se regresa un acceso denegado al intentar cerrar el proceso.


Saludos!

1 comentario:

  1. interesante!!!, igual estoy empezando con estos temas cuesta entender pero vamos haciendole la lucha :)

    ResponderEliminar