• KdSystemDebugControl

 #370234  por cLn
 28 May 2012, 16:26
Hola...

Bueno..otro texto más de Ivan lefou..iré traduciendo textos de dicho usuario y otros en francés que me parezcan interesantes e iré colocandolos aqui para quien le interese...

Por fin estoy empezando a jugar con Windows 7. Hasta ahora he jugado con mi viejo XP, era necesario cambiar eso. Recién en Win7 quería manipular la API NtSystemDebugControl que puede hacer lo que quieras desde user-land sin cansarse o con un driver \ Device \ PhysicalMemory. Sólo que con Win7 gran parte de las características interesantes ya no están disponibles. Molesta cuando se quiere modificar el sistema operativo, sobre todo si estás en la versión de 64 bits o un driver firmado es obligatorio. Solo arrancando en modo de depuración, WinDbg es capaz de hacer cosas buenas en la depuración del kernel. El hecho de saber que trabaja en user-land, donde se va a recuperar información de la memoria del núcleo o en MSR? Antes pasó por NtSystemDebugControl pero en Win7?

En realidad, nada nuevo, Alex Ionescu ya había tratado este mecanismo en la Recon 2k6 en su charla "Subverting Windows 2003 SP1 Kernel Integrity Protection". Una versión simplificada de la API NtSystemDebugControl siempre es accesible desde el modo usuario sólo con el SeDebugPrivilege, pero las características más interesantes son accesibles sólo en el modo kernel a través de la API exportados por el núcleo: KdSystemDebugControl.

Aquí está su prototipo:
Código: [ Debe registrarse para ver este enlace ]
NTSTATUS
NTAPI
KdSystemDebugControl(
    SYSDBG_COMMAND Command,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength,
    PULONG ReturnLength,
    KPROCESSOR_MODE PreviousMode
);
Ahora hay que entender cómo WinDbg se comunica con la API en modo usuario. De hecho, es bastante simple, requiere un controlador! Esto es %systemroot%\system32\kldgbdrv.sys que actúa como un contenedor para KdSystemDebugControl. Hay un montón de información de este controlador mediante el Administrador de control de servicios en el LocalLiveKernelTargetInfo pública :: InitDriver (void) de dbgeng.dll

Parte de la información acerca de este controlador:
lkd> !devobj \device\kldbgdrv
Device object (87bca750) is for:
kldbgdrv \Driver\kldbgdrv DriverObject 898b59e0
Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000040
Dacl 8b250ca0 DevExt 87bca808 DevObjExt 87bca810
ExtensionFlags (0x00000800)
Unknown flags 0x00000800
Device queue is not busy.

lkd> !drvobj \Driver\kldbgdrv 3
Driver object (898b59e0) is for:
\Driver\kldbgdrv
Driver Extension List: (id , addr)

Device Object list:
87bca750

DriverEntry: 94191e00
DriverStartIo: 00000000
DriverUnload: 94191a10
AddDevice: 00000000

Dispatch routines:
[00] IRP_MJ_CREATE 94191a50 +0x94191a50
[01] IRP_MJ_CREATE_NAMED_PIPE 828f4537 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE 94191a50 +0x94191a50
[03] IRP_MJ_READ 828f4537 nt!IopInvalidDeviceRequest
[04] IRP_MJ_WRITE 828f4537 nt!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION 828f4537 nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION 828f4537 nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA 828f4537 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA 828f4537 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS 828f4537 nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION 828f4537 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION 828f4537 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL 828f4537 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL 828f4537 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL 94191a80 +0x94191a80
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL 828f4537 nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN 828f4537 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL 828f4537 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP 828f4537 nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT 828f4537 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY 828f4537 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY 828f4537 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER 828f4537 nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL 828f4537 nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE 828f4537 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA 828f4537 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA 828f4537 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP 828f4537 nt!IopInvalidDeviceRequest
Gracias a la forma de los IRP_MJ_ * WinDbg se comunica con el driver a través de los IOCTL (Classic). Éstas son todas las funciones de la clase de LocalLiveKernelTargetInfo en dbgeng.dll
LocalLiveKernelTargetInfo::CheckLowMemory(void)
LocalLiveKernelTargetInfo::DebugControl(_SYSDBG_COMMAND,void *,ulong,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::GetDescription(ushort *,ulong,ulong *)
LocalLiveKernelTargetInfo::GetTargetContext(ThreadInfo *,unsigned __int64,void *)
LocalLiveKernelTargetInfo::GetTargetKdVersion(_DBGKD_GET_VERSION64 *)
LocalLiveKernelTargetInfo::InitDriver(void)
LocalLiveKernelTargetInfo::Initialize(void)
LocalLiveKernelTargetInfo::LocalLiveKernelTargetInfo(void)
LocalLiveKernelTargetInfo::ReadBusData(ulong,ulong,ulong,ulong,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::ReadControl(ulong,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::ReadIo(ulong,ulong,ulong,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::ReadMsr(ulong,unsigned __int64 *)
LocalLiveKernelTargetInfo::ReadPhysical(unsigned __int64,void *,ulong,ulong,ulong *)
LocalLiveKernelTargetInfo::ReadVirtual(ProcessInfo *,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::WaitForEvent(ulong,ulong,ulong,ulong *)
LocalLiveKernelTargetInfo::WriteBusData(ulong,ulong,ulong,ulong,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::WriteControl(ulong,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::WriteIo(ulong,ulong,ulong,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::WriteMsr(ulong,unsigned __int64)
LocalLiveKernelTargetInfo::WritePhysical(unsigned __int64,void *,ulong,ulong,ulong *)
LocalLiveKernelTargetInfo::WriteVirtual(ProcessInfo *,unsigned __int64,void *,ulong,ulong *)
LocalLiveKernelTargetInfo::`scalar deleting destructor'(uint)
LocalLiveKernelTargetInfo::~LocalLiveKernelTargetInfo(void)
Cool! Si WinDbg es capaz de acceder a todo esto nosotros nos podemos aprovechar de ello también. Queda por determinar la forma de los IOCTL enviados al driver. Para esto vamos a volver a los tiempos dbgeng.dll y kldbgdrv.sys .
Después de pasar algún tiempo en él se obtiene la siguiente información::

1) KdSystemDebugControl no funciona si KdDebuggerEnabled está a 1. Esta variable se establece a 1 por KdInitSystem() unicámente si se inicia en DEBUG.

2)El código IOCTL es 0x22C007 por lo que es METHOD_NEITHER. Les puedo asegurar que todo está bien probado, tanto en el driver como en KdSystemDebugControl.

3)El driver comprobará que nuestro proceso tiene el uso de SeDebugPrivilege con la ayuda de SeSinglePrivilegeCheck.

4)El formato del parámetro lpInBuffer de DeviceIoControl es siempre el mismo, sobre 32 bits donde :
Código: [ Debe registrarse para ver este enlace ]
typedef struct _KLDBG
    {
    	SYSDBG_COMMAND DbgCommandClass;
    	PVOID DbgCommand;
    	DWORD DbgCommandLen;
    }KLDBG, * PKLDBG;
nInBufferSize vale entonces 0xC. Cuando los parámetrosa lpOutBuffer y nOutBufferSize toman los mismos valores que los campos DbgCommand y DbgCommandLen.

Se pueden obtener las definiciones de SYSDBG_COMMAND en el fichero kdtypes.h del NDK.

Sería posible activar el debugger en modo kernel llamando a KdEnableDebugger pero habría que cargar un driver sin firmar para ello. En 32 bits esto se hace bien tanto que no hay que cargar al arrancar, pero en 64 bits es más complicado.

Ahora es el momento de codificar un POC. Así que vamos a interactuar con el driver y enviarle los IOCTL. Pero primero vamos a comprobar varias cosas :

1)Se activa el SeDebugPrivilege.

2)Verificamos que hemos arrancado en modo DEBUG con la clave HKLM\System\CurrentControlSet\Control\SystemStartOptions.

3)Se carga el driver con ayuda del Service Control Manager. Por contra es Windbg quién los instala la primera vez que se efectua un Live Kernel Debugging, por tanto el POC no efectua un simple StartService.

4)A continuación podemos abrir el dispositivo "\\.\kldbgdrv" y enviarle los IOCTLs.

5)Le pediremos 2 cosas al driver, la primera que nos reenvíe el valor del MSR IA32_SYSENTER_EIP (0×176) utilizado por SYSENTER y que apunta sobre nt!KiFastCallEntry después dumpeamos 256 bytes de la memoria del kernel.

Lo he comprobado con éxito en Win7 de 32 bits. Por supuesto,debemos ejecutar el binario como administrador debido al UAC. Le sugiero que vea el kdtypes.h de NDK para jugar con otras características de esta API. Tenga en cuenta que no debe cambiar mucho para el funcionamiento de 64 bits: p Más PatchGuard DEBUG no está habilitada.

El código y el binario del POC puede descargarlo aqui :

[ Debe registrarse para ver este enlace ]

Espero que les sirva..

Saludos !
 #370925  por FroZenFeW
 30 May 2012, 19:03
esto si me gusta

un saludo charles tiempo si vernos por msn