IRP Hooking

avril 21st, 2007 at 02:36 admin

Hiver nucléaire, le ciel s’est assombrit depuis longtemps, les températures ont chuté et le monde s’est retrouvé recouvert de neige. Planète dévastée, population décimée, les derniers survivants s’entassent dans des refuges, luttant chaque jour pour survivre contre le froid et la faim. La routine se résume aux actes les plus basiques, l’inertie environnementale est telle que l’espoir d’une tentative pour améliorer la situation est faible. Depuis le bombardement nucléaire les individus se sont retrouvés disloqués, éparpillés dans des zones de survies, au fur et à mesure se sont crée des nouvelles nations, se bâtissant sur les ruines des anciennes, certes moins puissantes que les originelles elles n’en sont pas moins restées autant autarciques. L’objectif de ces nouvelles patries est simple, le retour de lumière solaire mais uniquement au dessus de leurs territoires, les autres peuvent mourir. Ainsi est née une guerre après la guerre, tout les coups sont permis pour s’approprier les dernières découvertes du voisin.


Pourtant certains s’interrogent sur cette situation, ils envisagent une alliance mondiale visant à rassembler les nations. On leurs rétorque que des ennemis resteront toujours des ennemis et qu’après le retour du soleil ces derniers n’hésiteront pas à briser l’alliance. Au final, chacun travaille de son coté sur le même grand projet et on est en droit de se demander combien de temps l’humanité va t’elle encore souffrir de la vanité.

C’est durant ce contexte que se sont développés des réseaux parallèles d’informations, les idées sont échangées librement entre les membres, sans se partage les plus grandes découvertes n’auraient jamais eu lieu. Cette communauté active, travaille dans l’ombre, désintéressée du profit, son but est pourtant le même que tous mais pour eux un partage global des connaissances est la clé de la réussite.

Pour ceux qui n’auraient pas vu que cette petite histoire écrite sous trip chocapics est une analogie à la manière dont je perçois le monde de l’informatique. D’un coté les grandes sociétés, se croyant maître dans leurs domaine et gardant jalousement leurs découvertes. En face une communauté prônant un partage de l’information, sa puissance provenant de son enrichissement par des idées innovatrices venues de toutes parts. Force est de constater que de nombreuses idées de l’underground informatique on été reprises par les sociétés, surtout dans le domaine de la sécu-info, les hackers sont les inventeurs.

Ainsi en y pensant un peu, j’ai remarqué que c’est grâce à ces hackers que j’ai apprit, uniquement parce que quelques personnes ont jugé qu’il était plus judicieux de partager leurs idées et connaissances plutôt que de les vendre au plus offrant. C’est en fait le but de ce blog, je veux juste partager ce que je sais faire en espérant que grâce à cela d’autres découvrent et apprennent.

Ha je me rends compte que je vous casse les couilles avec mes conneries racontées en caleçon (vous voulez des photos ? envoyez la monnaie ! Et si vous êtes une fille envoyez votre photo d’abord :]). Je me souviens en fait que j’ai mit un titre et qu’il serait plus intéressant que j’essaye de le suivre plutôt que lassé par mes bêtises vous retourniez coder devant votre porno.

#include <pr0n.h>

Ca me revient, j’avais envie de faire un post sur l’IRP hooking, technique de détournement de fonctions qui va se nicher dans le trou du cul du système et qui permet de se passer (dans certains cas) de Hook SSDT et de DKOM. Pour commencer on va regarder un peu comment l’OS gère la communication avec ses drivers. Partons avec le code suivant :

#include <ntddk.h>

#define DeviceName L"\Device\IRPdev"
#define LnkDeviceName L"\Global??\IRPdev" // <=>  DosDevicesIRPdev

NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING usLnkName;
	RtlInitUnicodeString(&usLnkName,LnkDeviceName);
	IoDeleteSymbolicLink(&usLnkName);

	IoDeleteDevice(DriverObject->DeviceObject);
	DbgPrint("Bye Mofo !!n");
	return STATUS_SUCCESS;
}

NTSTATUS DriverDispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	DbgPrint("DriverDispatchCreate reachedn");

	__asm{int 3} //BP
	Irp->IoStatus.Status=STATUS_SUCCESS;
  	IoCompleteRequest(Irp,IO_NO_INCREMENT);
  	return Irp->IoStatus.Status;
}

NTSTATUS DriverDispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	DbgPrint("DriverDispatchClose reachedn");

	__asm{int 3} //BP
	Irp->IoStatus.Status=STATUS_SUCCESS;
  	IoCompleteRequest(Irp,IO_NO_INCREMENT);
  	return Irp->IoStatus.Status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath)
{
	ULONG i,NtStatus;
	PDEVICE_OBJECT pDeviceObject=NULL;
	UNICODE_STRING usDriverName,usLnkName;

	DbgPrint("Hello from KernelLand mastern");

	pDriverObject->MajorFunction[IRP_MJ_CREATE]=DriverDispatchCreate;
	pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DriverDispatchClose;

	RtlInitUnicodeString(&usDriverName,DeviceName);
	RtlInitUnicodeString(&usLnkName,LnkDeviceName);

	NtStatus=IoCreateDevice(pDriverObject,
							0,
	 						&usDriverName,
	 						FILE_DEVICE_UNKNOWN,
	 						FILE_DEVICE_SECURE_OPEN,
	 						FALSE,
	 						&pDeviceObject);
	if(NtStatus!=STATUS_SUCCESS)
	{
		DbgPrint("Error with IoCreateDevice : 0x%x", NtStatus);
		return STATUS_UNSUCCESSFUL;
	}	

	pDeviceObject->Flags|=DO_DIRECT_IO;	

	NtStatus=IoCreateSymbolicLink(&usLnkName,&usDriverName);
	if(NtStatus!=STATUS_SUCCESS)
	{
		DbgPrint("Error with IoCreateSymbolicLink : 0x%x", NtStatus);
		return STATUS_UNSUCCESSFUL;
	}

	pDriverObject->DriverUnload=DriverUnload;

	return STATUS_SUCCESS;
}

Ce code initialise un device crée par IoCreateDevice qui est en fait interface permettant au système de communiquer avec le driver. Les 2 routines DriverDispatch permettant de gérer les requètes. Afin que le process puissent eux aussi communiquer avec le driver on doit créer un Symbolic Link avec la fonction IoCreateSymbolicLink qui place un objet dans l’ObpRootDirectoryObject (\\Global?? ou \\Dosdevice) servant à retrouver le device objet.

Le driver est représenté par un objet DRIVER_OBJECT et le device par un objet (attention!) DEVICE_OBJECT nommé \\Device\\IRPdev.

Pour mieux comprendre le rôle des devices, le driver i8042prt gère à la fois le port souris et le clavier (ps2) ainsi en regardant sous le KD ses caractéristiques on peut voir :

kd> !drvobj driveri8042prt
Driver object (81dac788) is for:
 Driveri8042prt
Driver Extension List: (id , addr)

Device Object list:
81d9a7d0  81e0c628

Ce drivers possède 2 devices attachés. Celui ci représente l’interface pour la souris.

kd> !devobj 81d9a7d0
Device object (81d9a7d0) is for:
  Driveri8042prt DriverObject 81dac788
Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
DevExt 81d9a888 DevObjExt 81d9ab18
ExtensionFlags (0000000000)
AttachedDevice (Upper) 81d98040 DriverMouclass
AttachedTo (Lower) 81fe6950 DriverACPI
Device queue is not busy.

Et le dernier concerne l’interface pour le clavier.

kd> !devobj 81e0c628
Device object (81e0c628) is for:
  Driveri8042prt DriverObject 81dac788
Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
DevExt 81e0c6e0 DevObjExt 81e0c970
ExtensionFlags (0000000000)
AttachedDevice (Upper) 81d9d228 DriverKbdclass
AttachedTo (Lower) 81fe6a78 DriverACPI
Device queue is not busy.

Maintenant voici un petit programme qui va communiquer avec le driver vu plus haut :

#include <windows.h>
#include <stdio.h>
ULONG main()
{
	HANDLE hFile;
	hFile=CreateFile(TEXT("\.\IRPdev"), // file to open
                   GENERIC_READ,          // open for reading
                   FILE_SHARE_READ,       // share for reading
                   NULL,                  // default security
                   OPEN_EXISTING,         // existing file only
                   FILE_ATTRIBUTE_NORMAL, // normal file
                   NULL);                 // no attr. template

	if (hFile==INVALID_HANDLE_VALUE)
	{
    	printf("Error with CreateFile : %d n", GetLastError());
    	return 0;
	}

	CloseHandle(hFile);
	return 0;
}

La fonction CreateFile va demander l’obtention d’un handle, cette action sera gérée par la routine du driver DriverDispatchCreate, ensuite le CloseHande demande la fermeture du handle et sera géré par DriverDispatchClose. Le mieux étant évidemment de tester et de voir par nous même. Après avoir charger le driver dans ma VM et lancer mon programme j’atteint le 1er breakpoint (int 3), en jetant un coup d’œil sur la call stack on observe ceci :

Hello from KernelLand master
DriverDispatchCreate reached
Break instruction exception - code 80000003 (first chance)
irp!DriverDispatchCreate+0x11:
fd2cd4cb cc              int     3
kd> kb
ChildEBP RetAddr  Args to Child
f95a6a4c 804e3d77 80df6998 80d856a0 80d856a0 irp!DriverDispatchCreate+0x11 [c:driversirpio.c @ 31]
f95a6a5c 80570f9c 80df6980 ffaed7ec f95a6c04 nt!IopfCallDriver+0x31
f95a6b3c 8056386c 80df6998 00000000 ffaed748 nt!IopParseDevice+0xa58
f95a6bc4 80567c63 00000000 f95a6c04 00000040 nt!ObpLookupObjectName+0x56a
f95a6c18 80571477 00000000 00000000 0fffff01 nt!ObOpenObjectByName+0xeb
f95a6c94 80571546 0012ff3c 80100080 0012fedc nt!IopCreateFile+0x407
f95a6cf0 8057167c 0012ff3c 80100080 0012fedc nt!IoCreateFile+0x8e
f95a6d30 804df06b 0012ff3c 80100080 0012fedc nt!NtCreateFile+0x30
f95a6d30 7c91eb94 0012ff3c 80100080 0012fedc nt!KiFastCallEntry+0xf8
0012fe98 7c91d68e 7c810b2c 0012ff3c 80100080 ntdll!KiFastSystemCallRet
0012fe9c 7c810b2c 0012ff3c 80100080 0012fedc ntdll!NtCreateFile+0xc
0012ff34 7c801a4f 00000000 80000000 00000001 kernel32!CreateFileW+0x35f
0012ff58 004006f1 004002e8 80000000 00000001 kernel32!CreateFileA+0x30
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ff80 00400807 00000001 00410b20 00410aa0 test+0x6f1
0012ffc0 7c816d4f 00370031 002d0031 7ffdc000 test+0x807
0012fff0 00000000 00400753 00000000 78746341 kernel32!BaseProcessStart+0x23

L’API CreateFile appel l’api native NtCreateFile. Arrivé dans le noyau le système vérifie avec la fonction ObpLookupObjectName que l’objet existe dans l’ObpRootDirectoryObject est plus précisément dans la partie contenant symbolic links, \\Global??. Après avoir récupéré le device object qui contient un pointeur sur le driver object l’I/O Manager forge un IRP qui sera envoyé au driver par l’appel IopfCallDriver. L’IRP (I/O Request Packet) en fait la structure servant de protocole de communication avec les drivers. Enfin notre driver traite la requête en disant quelle à réussi et renvoie le résultat avec IoCompleteRequest.

En relançant l’OS on atteint le second breakpoint et on retrouve le même schéma de fonctionnement.

kd> g
DriverDispatchClose reached
Break instruction exception - code 80000003 (first chance)
irp!DriverDispatchClose+0x11:
fd2cd519 cc              int     3
kd> kb
ChildEBP RetAddr  Args to Child
f95a6c5c 804e3d77 80df6998 80d856a0 80d856a0 irp!DriverDispatchClose+0x11 [c:driversirpio.c @ 42]
f95a6c6c 8056afec 80cefac8 00000000 00000000 nt!IopfCallDriver+0x31
f95a6ca4 80563ff6 00cefae0 80cefac8 00000000 nt!IopDeleteFile+0x132
f95a6cc0 804e3c55 80cefae0 00000000 0000001c nt!ObpRemoveObjectRoutine+0xdf
f95a6ce4 80567543 80cd2da0 e15da928 80cd7440 nt!ObfDereferenceObject+0x5f
f95a6cfc 805675ac e15da928 80cefae0 0000001c nt!ObpCloseHandleTableEntry+0x155
f95a6d44 805675f6 0000001c 00000001 00000000 nt!ObpCloseHandle+0x87
f95a6d58 804df06b 0000001c 0012ff70 7c91eb94 nt!NtClose+0x1d
f95a6d58 7c91eb94 0000001c 0012ff70 7c91eb94 nt!KiFastCallEntry+0xf8
0012ff60 7c91d592 7c809bbb 0000001c 0012ff80 ntdll!KiFastSystemCallRet
0012ff64 7c809bbb 0000001c 0012ff80 0040071c ntdll!ZwClose+0xc
0012ff70 0040071c 0000001c 0000001c 0012ffc0 kernel32!CloseHandle+0x51
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ff80 00400807 00000001 00410b20 00410aa0 test+0x71c
0012ffc0 7c816d4f 00370031 002d0031 7ffdc000 test+0x807
0012fff0 00000000 00400753 00000000 78746341 kernel32!BaseProcessStart+0x23

La fonction !devobj du KD permet de retrouver diverses info sur notre device.

kd> !devobj deviceIRPdev
Device object (80df6998) is for:
 IRPdev Driverirp DriverObject 80d884e0
Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000050
Dacl e1259364 DevExt 00000000 DevObjExt 80df6a50
ExtensionFlags (0000000000)
Device queue is not busy.

Cette fonction agit tout simplement en récupérant les infos de la structure DEVICE_OBJECT.

kd> dt nt!_DEVICE_OBJECT 80df6998
   +0x000 Type             : 3
   +0x002 Size             : 0xb8
   +0x004 ReferenceCount   : 1
   +0x008 DriverObject     : 0x80d884e0 _DRIVER_OBJECT
   +0x00c NextDevice       : (null)
   +0x010 AttachedDevice   : (null)
   +0x014 CurrentIrp       : (null)
   +0x018 Timer            : (null)
   +0x01c Flags            : 0x50
   +0x020 Characteristics  : 0x100
   +0x024 Vpb              : (null)
   +0x028 DeviceExtension  : (null)
   +0x02c DeviceType       : 0x22
   +0x030 StackSize        : 1 ''
   +0x034 Queue            : __unnamed
   +0x05c AlignmentRequirement : 0
   +0x060 DeviceQueue      : _KDEVICE_QUEUE
   +0x074 Dpc              : _KDPC
   +0x094 ActiveThreadCount : 0
   +0x098 SecurityDescriptor : 0xe1259350
   +0x09c DeviceLock       : _KEVENT
   +0x0ac SectorSize       : 0
   +0x0ae Spare1           : 0
   +0x0b0 DeviceObjectExtension : 0x80df6a50 _DEVOBJ_EXTENSION
   +0x0b4 Reserved         : (null)

Pareil, la fonction !drvobj permet de voir ce qui notre driver à dans le ventre.

kd> !drvobj Driverirp 3
Driver object (80d884e0) is for:
 Driverirp
Driver Extension List: (id , addr)

Device Object list:
80df6998  

DriverEntry:   fd3145c2	irp!DriverEntry
DriverStartIo: 00000000
DriverUnload:  fd31443a	irp!DriverUnload

Dispatch routines:
[00] IRP_MJ_CREATE                      fd31449c	irp!DriverDispatchCreate
[01] IRP_MJ_CREATE_NAMED_PIPE           805025e4	nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fd3144ea	irp!DriverDispatchClose
[03] IRP_MJ_READ                        805025e4	nt!IopInvalidDeviceRequest
[04] IRP_MJ_WRITE                       805025e4	nt!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION           805025e4	nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION             805025e4	nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA                    805025e4	nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      805025e4	nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               805025e4	nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    805025e4	nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      805025e4	nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           805025e4	nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         805025e4	nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              805025e4	nt!IopInvalidDeviceRequest
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     805025e4	nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN                    805025e4	nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                805025e4	nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     805025e4	nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT             805025e4	nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              805025e4	nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                805025e4	nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       805025e4	nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL              805025e4	nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE               805025e4	nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 805025e4	nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   805025e4	nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         805025e4	nt!IopInvalidDeviceRequest

Qui est au final un parsing des infos contenues dans la structure DRIVER_OBJECT.

kd> dt nt!_DRIVER_OBJECT 0x80d884e0
   +0x000 Type             : 4
   +0x002 Size             : 168
   +0x004 DeviceObject     : 0x80df6998 _DEVICE_OBJECT
   +0x008 Flags            : 0x12
   +0x00c DriverStart      : 0xfd314000
   +0x010 DriverSize       : 0x880
   +0x014 DriverSection    : 0x80d18928
   +0x018 DriverExtension  : 0x80d88588 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING "Driverirp"
   +0x024 HardwareDatabase : 0x8068de90 _UNICODE_STRING "REGISTRYMACHINEHARDWAREDESCRIPTIONSYSTEM"
   +0x028 FastIoDispatch   : (null)
   +0x02c DriverInit       : 0xfd3145c2     irp!DriverEntry+0
   +0x030 DriverStartIo    : (null)
   +0x034 DriverUnload     : 0xfd31443a     irp!DriverUnload+0
   +0x038 MajorFunction    : [28] 0xfd31449c     irp!DriverDispatchCreate+0

Dans les Drivers Routines on retrouve mes 2 fonctions DriverDispatchCreate et DriverDispatchClose correspondant à des requêtes de type IRP_MJ_CREATE et IRP_MJ_CLOSE. Les autres IRP_MJ_XX sont renvoyés vers une routine de l’I/O Manager, IopInvalidDeviceRequest, servant juste à dire qu’elles n’ont pas abouti.

C’est sur ces routines que repose l’art de l’IRP Hooking, en effet on retrouve une table contenant des pointeurs sur des fonctions chargées de gérer des demandes. Ainsi en modifiant ces pointeurs on peut remplacer ces fonctions par les nôtres et modifier le comportement du driver. Maintenant que le driver de test nous à permit de voir comment cela fonctionnait, on va tenter d’appliquer cette méhtode au driver du système de fichier, ntfs, dans le but, bien évidemment, de faire disparaître des fichiers ! (HAN le méchant !!)

Voici ce que la fonction !drvobj nous sort à propos du driver ntfs

kd> !drvobj Filesystemntfs 3
Driver object (80e8c578) is for:
 FileSystemNtfs
Driver Extension List: (id , addr)

Device Object list:
80e7a408  80e8c460  

DriverEntry:   fcb9c204	Ntfs!GsDriverEntry
DriverStartIo: 00000000
DriverUnload:  00000000	

Dispatch routines:
[00] IRP_MJ_CREATE                      fcb3ce37	Ntfs!NtfsFsdCreate
[01] IRP_MJ_CREATE_NAMED_PIPE           805025e4	nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fcb3c320	Ntfs!NtfsFsdClose
[03] IRP_MJ_READ                        fcb19ee4	Ntfs!NtfsFsdRead
[04] IRP_MJ_WRITE                       fcb18bca	Ntfs!NtfsFsdWrite
[05] IRP_MJ_QUERY_INFORMATION           fcb3d4d1	Ntfs!NtfsFsdDispatchWait
[06] IRP_MJ_SET_INFORMATION             fcb1aa58	Ntfs!NtfsFsdSetInformation
[07] IRP_MJ_QUERY_EA                    fcb3d4d1	Ntfs!NtfsFsdDispatchWait
[08] IRP_MJ_SET_EA                      fcb3d4d1	Ntfs!NtfsFsdDispatchWait
[09] IRP_MJ_FLUSH_BUFFERS               fcb42a68	Ntfs!NtfsFsdFlushBuffers
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fcb3d61c	Ntfs!NtfsFsdDispatch
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fcb3d61c	Ntfs!NtfsFsdDispatch
[0c] IRP_MJ_DIRECTORY_CONTROL           fcb3f2c3	Ntfs!NtfsFsdDirectoryControl
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fcb446d5	Ntfs!NtfsFsdFileSystemControl
[0e] IRP_MJ_DEVICE_CONTROL              fcb3d61c	Ntfs!NtfsFsdDispatch
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     805025e4	nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN                    fcb2b621	Ntfs!NtfsFsdShutdown
[11] IRP_MJ_LOCK_CONTROL                fcb90b11	Ntfs!NtfsFsdLockControl
[12] IRP_MJ_CLEANUP                     fcb3ccee	Ntfs!NtfsFsdCleanup
[13] IRP_MJ_CREATE_MAILSLOT             805025e4	nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              fcb3d61c	Ntfs!NtfsFsdDispatch
[15] IRP_MJ_SET_SECURITY                fcb3d61c	Ntfs!NtfsFsdDispatch
[16] IRP_MJ_POWER                       805025e4	nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL              805025e4	nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE               805025e4	nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 fcb3d4d1	Ntfs!NtfsFsdDispatchWait
[1a] IRP_MJ_SET_QUOTA                   fcb3d4d1	Ntfs!NtfsFsdDispatchWait
[1b] IRP_MJ_PNP                         fcb5bf3f	Ntfs!NtfsFsdPnp

Fast I/O routines:
FastIoCheckIfPossible                   fcb535ac	Ntfs!NtfsFastIoCheckIfPossible
FastIoRead                              fcb37b85	Ntfs!NtfsCopyReadA
FastIoWrite                             fcb43097	Ntfs!NtfsCopyWriteA
FastIoQueryBasicInfo                    fcb3c21a	Ntfs!NtfsFastQueryBasicInfo
FastIoQueryStandardInfo                 fcb3c0ae	Ntfs!NtfsFastQueryStdInfo
FastIoLock                              fcb43a4d	Ntfs!NtfsFastLock
FastIoUnlockSingle                      fcb43b53	Ntfs!NtfsFastUnlockSingle
FastIoUnlockAll                         fcb9071c	Ntfs!NtfsFastUnlockAll
FastIoUnlockAllByKey                    fcb90861	Ntfs!NtfsFastUnlockAllByKey
AcquireFileForNtCreateSection           fcb378ba	Ntfs!NtfsAcquireForCreateSection
ReleaseFileForNtCreateSection           fcb37901	Ntfs!NtfsReleaseForCreateSection
FastIoQueryNetworkOpenInfo              fcb7ee89	Ntfs!NtfsFastQueryNetworkOpenInfo
AcquireForModWrite                      fcb43855	Ntfs!NtfsAcquireFileForModWrite
MdlRead                                 fcb7ef9d	Ntfs!NtfsMdlReadA
MdlReadComplete                         8052bb18	nt!FsRtlMdlReadCompleteDev
PrepareMdlWrite                         fcb7f317	Ntfs!NtfsPrepareMdlWriteA
MdlWriteComplete                        80611143	nt!FsRtlMdlWriteCompleteDev
FastIoQueryOpen                         fcb3bee8	Ntfs!NtfsNetworkOpenCreate
AcquireForCcFlush                       fcb37762	Ntfs!NtfsAcquireFileForCcFlush
ReleaseForCcFlush                       fcb37788	Ntfs!NtfsReleaseFileForCcFlush

Nous on s’intéresse à la fonction NtfsFsdCreate chargée de renvoyé un handle sur un fichier. Hop rien de valant une jolie call stack pour comprendre comment sa marche (sachant un bol de chocapics n’ayant qu’un effet limité sur l’augmentation du QI), on se pose un petit BP sur la fonction. Après lancer le notepad je tombe sur ceci :

Breakpoint 0 hit
Ntfs!NtfsFsdCreate:
fcb3ce37 68ac000000      push    0ACh
kd> kb
ChildEBP RetAddr  Args to Child
f9a18a04 804e3d77 80e7a408 80d362b8 ffbc69b0 Ntfs!NtfsFsdCreate
f9a18a14 fcbc0876 80d362c8 80e8cf38 ffbc69b0 nt!IopfCallDriver+0x31
f9a18a60 804e3d77 80e7ae88 00000001 80d362b8 sr!SrCreate+0x150
f9a18a70 80570f9c 80e47890 ffaed7ec f9a18c18 nt!IopfCallDriver+0x31
f9a18b50 8056386c 80e478a8 00000000 ffaed748 nt!IopParseDevice+0xa58
f9a18bd8 80567c63 00000000 f9a18c18 00000040 nt!ObpLookupObjectName+0x56a
f9a18c2c 80571477 00000000 00000000 00000101 nt!ObOpenObjectByName+0xeb
f9a18ca8 80571546 0007d938 001000a1 0007d7e4 nt!IopCreateFile+0x407
f9a18d04 8057160e 0007d938 001000a1 0007d7e4 nt!IoCreateFile+0x8e
f9a18d44 804df06b 0007d938 001000a1 0007d7e4 nt!NtOpenFile+0x27
f9a18d44 7c91eb94 0007d938 001000a1 0007d7e4 nt!KiFastCallEntry+0xf8
0007d568 7c91dd09 7c818c14 0007d938 001000a1 ntdll!KiFastSystemCallRet
0007d56c 7c818c14 0007d938 001000a1 0007d7e4 ntdll!NtOpenFile+0xc
0007dfb0 7c80235e 00000000 0014329c 00141004 kernel32!CreateProcessInternalW+0x892
0007dfe8 7ca1def4 0014329c 00141004 00000000 kernel32!CreateProcessW+0x2c
0007ea6c 7ca1dd5e 00010080 00000000 001436ac SHELL32!_SHCreateProcess+0x387
0007eac0 7ca1dc95 0013fdb0 0007eae0 7ca1d797 SHELL32!CShellExecute::_DoExecCommand+0xb4
0007eacc 7ca1d797 00000000 000f8560 0013fdb0 SHELL32!CShellExecute::_TryInvokeApplication+0x49
0007eae0 7ca1d6c9 000f8560 000f8560 0007eb20 SHELL32!CShellExecute::ExecuteNormal+0xb1
0007eaf4 7ca1d665 0007eb20 00105520 000f8560 SHELL32!ShellExecuteNormal+0x30

La fonction CreateProcess afin de lire le binaire à besoin d’un handle. Pour cela l’API NtOpenFile réalise l’appel système qui va faire la demande au driver du chier ntfs. A noter que le module portant le nom « sr » correspond au driver de restauration du système dont le device va se mettre avant le device associé au système de fichier afin de pourvoir lire les requêtes et créer le point de restauration. On peut le voir sous le KD :

kd> !drvobj filesystemntfs
Driver object (80e8c578) is for:
 FileSystemNtfs
Driver Extension List: (id , addr)

Device Object list:
80e7a408  80e8c460
kd> !devobj 80e7a408
Device object (80e7a408) is for:
  FileSystemNtfs DriverObject 80e8c578
Current Irp 00000000 RefCount 0 Type 00000008 Flags 00000000
DevExt 80e7a4c0 DevObjExt 80e7ac68
ExtensionFlags (0000000000)
AttachedDevice (Upper) 80e7add0 FileSystemsr <----device associé au driver de restauration
Device queue is not busy.

L’architecture du noyau correspond à ce schéma, un série des drivers ayant au dessus d’eux un ou plusieurs devices, provenant soit de leur propre driver, soit associé à d’autres. On a donc une device stack au dessus de chaque driver et l’IRP va devoir traverser cette pile pour arrivé au driver final. On peut le voir avec la commande !devstack

kd> !devstack  80e7a408
  !DevObj   !DrvObj            !DevExt   ObjectName
  80e7add0  FileSystemsr     80e7ae88
> 80e7a408  FileSystemNtfs   80e7a4c0

Justement en parlant d’IRP, sachant que les XxxDispatchCreate routines sont toujours de la forme suivante :

NTSTATUS
  XxxDispatchCreate(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp
    );

On peut retrouve notre IRP qui correspond au second argument de la fonction NtfsFsdCreate, regardons cela avec notre KD :

kd> dt nt!_IRP 80d362b8
   +0x000 Type             : 6
   +0x002 Size             : 0x1b4
   +0x004 MdlAddress       : (null)
   +0x008 Flags            : 0x884
   +0x00c AssociatedIrp    : __unnamed
   +0x010 ThreadListEntry  : _LIST_ENTRY [ 0xffb68230 - 0xffb68230 ]
   +0x018 IoStatus         : _IO_STATUS_BLOCK
   +0x020 RequestorMode    : 1 ''
   +0x021 PendingReturned  : 0 ''
   +0x022 StackCount       : 9 ''
   +0x023 CurrentLocation  : 9 ''
   +0x024 Cancel           : 0 ''
   +0x025 CancelIrql       : 0 ''
   +0x026 ApcEnvironment   : 0 ''
   +0x027 AllocationFlags  : 0xc ''
   +0x028 UserIosb         : 0xf9a18b08 _IO_STATUS_BLOCK
   +0x02c UserEvent        : (null)
   +0x030 Overlay          : __unnamed
   +0x038 CancelRoutine    : (null)
   +0x03c UserBuffer       : (null)
   +0x040 Tail             : __unnamed

Je vous laisse lire la doc du DDK pour avoir une description de ces différents champs. Par contre au lieu de se faire chier à dumper la structure on va utiliser la commande !irp.

kd> !irp 80d362b8
Irp is active with 9 stacks 9 is current (= 0x80d36448)
 No Mdl: No System Buffer: Thread ffb68020:  Irp stack trace.
     cmd  flg cl Device   File     Completion-Context
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
>[  0, 0]   0  0 80e7a408 ffbc69b0 00000000-00000000
	       FileSystemNtfs
			Args: f9a18a9c 01000060 00050000 00000000

Ici notre IRP possède 9 stacks, d’ailleurs j’avoue de ne pas savoir pourquoi, normalement on a une stack par driver accédé, ici on devrait donc en avoir 2 … Bref c’est pas vraiment important pour ce qu’on veut faire, les arguments de l’IRP sont passé par la pile et contenu dans une structure IO_STACK_LOCATION.

kd> dt nt!_IO_STACK_LOCATION 0x80d36448
   +0x000 MajorFunction    : 0 ''
   +0x001 MinorFunction    : 0 ''
   +0x002 Flags            : 0 ''
   +0x003 Control          : 0 ''
   +0x004 Parameters       : __unnamed
   +0x014 DeviceObject     : 0x80e7a408 _DEVICE_OBJECT
   +0x018 FileObject       : 0x80e402a8 _FILE_OBJECT
   +0x01c CompletionRoutine : (null)
   +0x020 Context          : (null)

Et dans cette magnifique structure se situant au fin fond du système on a un FILE_OBJECT contenant :

kd> !fileobj ffbc69b0

WINDOWSsystem32NOTEPAD.EXE

Device Object: 0x80e478a8   DriverFtdisk
Vpb is NULL

Flags:  0x2
	Synchronous IO

CurrentByteOffset: 0

On retrouve notre demande d’ouverture du handle sur le fichier notepad.exe. Vous l’avez compris en hookant les IRP_MJ_xxx du driver ntfs il est possible de renvoyé des valeurs modifiées à l’OS et ainsi par exemple ne plus faire apparaître des fichiers. Je réaliserais un POC prochainement et je vous filerais le code. En attendant vous pouvez retourner devant votre porno :]

PS : Cet articlé ayant été écrit entièrement en caleçon l’auteur s’excuse pour les odeurs.

Références :

Windows DDK -> Handling IRPs

Microsoft Windows Internals, Fourth Edition -> Chapter 9. I/O System

Rootkits: Subverting the Windows Kernel -> Kernel Hooks -> Hooking the Major I/O Request Packet Function Table in the Device Driver Object

Entry Filed under: Non classé

2 Comments

  • 1. Howl  |  avril 22nd, 2007 at 14:52

    Bon comme d’hab ça à l’air de claquer ton truc mais je pige pas tout….
    Juste pour apporter mon soutien et mon approbation à tes premiers paragraphes (parmi les euls que je comprenne ^^)
    Continue comme ça t’es pour moi une référence de la scène fr .

    Ciao


  • 2. erskuv  |  avril 22nd, 2007 at 15:21

    Ahah! How arrêtes de dire de la merde avec ta scène. De plus ivan’ c’est juste a geek qui se fait du plaisir sur Windows (c) de Micosesoft ™, c’est pas une « reference de la scene fr ». Et au lieu de baver devant des demonstrations de RCE bouge ton cul et va lire de la doc. Ce que sait ivan’ à présent n’était déjà pas préinstallé dans son cerveau à la naissance ;p.
    Mais en tout cas c’est vrai Ivan que tu commences à bien maîtriser le sujet, et partager des petites trouvailles du jour c’est sympa, pas tout le monde le fait.

    Keep on rewerzing !

    erskuv


Trackback this post


Calendar

octobre 2021
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts