IRP Hooking
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
2 comments avril 21st, 2007