POC IRP Hooking

avril 26th, 2007 at 12:44 admin

Vous l’attendiez, le voilà ! Le POC de mon précédent post, ou l’art de planquer des fichiers en utilisant un IRP Hook. Mais avant que vous fassiez des bêtises, on va mettre au clair quelques petites choses.

Pour récupérer le contenu d’un dossier, l’OS va utiliser un appel système sur l’API NtQueryDirectoryFile. Cette API va ensuite forger une requête, un IRP, et l’envoyé au driver Nfts qui se chargera de répondre. La routine du driver Nfts qui est utilisée s’appelle NtfsFsdDirectoryControl de prototype :

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

Les arguments sont passés à travers l’IRP. Par exemple, lorsque vous affichez le contenu de votre C:\, voici ce qui se passe.

Breakpoint 1 hit
Ntfs!NtfsFsdDirectoryControl:
fcb3f2c3 684c010000      push    14Ch
kd> kb
ChildEBP RetAddr  Args to Child
f9316cd0 804e3d77 80e7a408 ffacb430 80e8cf38 Ntfs!NtfsFsdDirectoryControl
f9316ce0 fcbbb459 f9316d0c 804e3d77 80e7add0 nt!IopfCallDriver+0x31
f9316ce8 804e3d77 80e7add0 ffacb430 806ed070 sr!SrPassThrough+0x31
f9316cf8 8056a9ab f9316d64 00c2de3c 80574dad nt!IopfCallDriver+0x31
f9316d0c 80574e0a 80e7add0 ffacb430 80e39118 nt!IopSynchronousServiceTail+0x60
f9316d30 804df06b 00000544 00000000 00000000 nt!NtQueryDirectoryFile+0x5d
f9316d30 7c91eb94 00000544 00000000 00000000 nt!KiFastCallEntry+0xf8
00c2de04 7c91df6a 7c80eec2 00000544 00000000 ntdll!KiFastSystemCallRet
00c2de08 7c80eec2 00000544 00000000 00000000 ntdll!ZwQueryDirectoryFile+0xc
00c2e114 7c9f8afd 00c2e3bc 00000000 001500ac kernel32!FindFirstFileExW+0x3a0
00c2e138 7c9f8a97 00c2e3bc 001500ac 0014fe9c SHELL32!SHFindFirstFile+0x2a
00c2e38c 7c9fa996 00100138 00000000 00c2e3bc SHELL32!SHFindFirstFileRetry+0x5b
00c2e5dc 7c9fa870 00101a88 00101a70 00c2e604 SHELL32!CFileSysEnum::Init+0x14b
00c2e5ec 7c9fab6d 0010c820 00100138 00000060 SHELL32!CFSFolder_CreateEnum+0x37
00c2e604 7c9ff03d 0010c830 00100138 00000060 SHELL32!CFSFolder::EnumObjects+0x30
00c2e638 7c9ffa3e 00100138 0014b7f4 0014b7d8 SHELL32!CDefviewEnumTask::FillObjectsToDPA+0x8b
00c2e68c 7774e201 00000001 00000000 0014b7d8 SHELL32!CDefView::CreateViewWindow2+0x2de
WARNING: Frame IP not in any known module. Following frames may be wrong.
00c2e738 777392ca 000dac20 0014b7d8 0014e210 0x7774e201
00c2e848 77f5a77f 00106900 777364e1 0013fac4 0x777392ca
00c2e77c 75f35fa2 000dac24 0014e210 00145798 SHLWAPI!EnumConnectionPointSinks+0xac

Dans la call stack on peut retrouver les arguments passé à la fonction NtQueryDirectoryFile :

kd> dd 00c2de08+8
00c2de10  00000544 00000000 00000000 00000000
00c2de20  00c2de78 00c2dea8 00000268 00000003
00c2de30  00000001 00c2de90 00000000

Ce qui correspond, pour être plus clair à l’appel suivant :

ZwQueryDirectoryFile(
IN HANDLE FileHandle, -> 0x544
IN HANDLE Event OPTIONAL, -> NULL
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, -> NULL
IN PVOID ApcContext OPTIONAL, -> NULL
OUT PIO_STATUS_BLOCK IoStatusBlock, -> 0xc2de78
OUT PVOID Buffer, -> 0xc2dea8
IN ULONG BufferLength,-> 0x268
IN FILE_INFORMATION_CLASS FileInformationClass, -> 0x3=FileBothDirectoryInformation
IN BOOLEAN ReturnSingleEntry, -> 1=TRUE
IN PUNICODE_STRING FileName, -> 0xc2de90
IN BOOLEAN RestartScan -> NULL
);

En analysant un peu les arguments, le FileHandle correspond à :

kd> !handle 544
processor number 0, process ffb5f798
PROCESS ffb5f798  SessionId: 0  Cid: 0524    Peb: 7ffd9000  ParentCid: 0504
    DirBase: 009a5000  ObjectTable: e1793b28  HandleCount: 340.
    Image: explorer.exe

Handle table at e1536000 with 340 Entries in use
0544: Object: 80e39118  GrantedAccess: 00100001 Entry: e1536a88
Object: 80e39118  Type: (80e95e70) File
    ObjectHeader: 80e39100
        HandleCount: 1  PointerCount: 3
        Directory Object: 00000000  Name: \\ {HarddiskVolume1}

Un handle du process explorer.exe de type File, portant le nom de ‘\’ attaché au HarddiskVolume1. En fait c’est tout simplement le handle sur C:\

Le FileName quant à lui contient :

kd> !ustr 00c2de90
String(2,6) at 00c2de90: *

Le fichier demandé est donc C:\*

Enfin le FileInformationClass est mit à FileBothDirectoryInformation (3). Ce qui veut dire que la fonction va renvoyer dans la Buffer en 0xc2dea8 une liste chaînée de structures FILE_BOTH_DIRECTORY_INFORMATION contenant les descriptions des fichiers contenu dans C:\

Vous voyez que c’est pas compliqué Windows :}

Maitenant qu’on sait ce que NtQueryDirectoryFile doit faire, regardons la forme de l’IRP.

kd> !irp ffacb430
Irp is active with 9 stacks 9 is current (= 0xffacb5c0)
 No Mdl: No System Buffer: Thread 80d4e020:  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
>[  c, 1]   2  0 80e7a408 80e39118 00000000-00000000
	       FileSystemNtfs
			Args: 00000268 ffb03038 00000003 00000000

[ c, 1] Veut dire qu’on à fait appel à une routines IRP_MJ_DIRECTORY_CONTROL(0xc) avec le code IRP_MN_QUERY_DIRECTORY(1). Dans les arguments de l’IRP on peut retrouver la taille du Buffer (0×268) et le FileInformationClass (3). Le Buffer lui est placé dans le champ UserBuffer de l’IRP.

Maintenant qu’on sait tout ca, on peut définir le fonctionnement du hook. Il s’agit de modifier la table des Dispatch routines du driver Nfts afin d’y mettre notre fonction à la place de NtfsFsdDirectoryControl. Notre fonction va vérifier si les arguments passés à la routine vérifient certaines propriétés, sachant qu’on désire modifier le résultat de la requête afin de supprimer dans la liste chainée un ou plusieurs fichiers, il nous faut donc s’intéresser aux requêtes qui vérifient :
- Le champ MinorFunction de l’IRP vaut IRP_MN_QUERY_DIRECTORY
- Le champ Irp->Parameters.QueryDirectory.FileInformationClass vaut une de ces valeurs :
FileDirectoryInformation
FileFullDirectoryInformation
FileBothDirectoryInformation
FileNamesInformation

Si ces conditions ne sont pas vérifiées alors on return en appelant la fonction originale NtfsFsdDirectoryControl pour compléter la requête.

Dans la cas ou les conditions sont OK, on appel toujours la fonction NtfsFsdDirectoryControl puis on parcourt la liste chainée en modifiant au besoins les résultats.

Enfin, il reste aussi la routine NtfsFsdCreate, qui permet à partir d’un nom de fichier de d’obtenir un handle. Ainsi il est possible d’ouvrir un fichier en même si on ne voit pas « directement ». Il faut donc tenir compte de ce problème en posant un hook sur cette routine et en vérifiant le nom du fichier. Si jamais il correspond à ceux qu’on veut cacher alors on renvoie un STATUS_OBJECT_NAME_INVALID.

Dans mon code, tout les fichiers et dossiers commençant par un ‘_’ sont cachés. De plus si l’utiliser essaye d’ouvrir un handle sur le fichier C:\_bouh.txt la routine NtfsFsdCreate renverra STATUS_OBJECT_NAME_INVALID.

Voici de quoi vous amusez

http://ivanlef0u.fr/repo/IRP.rar

Enjoy !

En cas de soucis n’hesitez pas à me poser des questions.

Références :

http://www.rootkit.com/newsread_print.php?newsid=690
http://www.rootkit.com/newsread.php?newsid=647
http://msdn2.microsoft.com/en-us/library/ms795825.aspx
http://msdn2.microsoft.com/en-us/library/ms795806.aspx
http://www.antirootkit.com/articles/Nailuj-Rootkit-Analysis/index.htm
http://ivanlef0u.fr/repo/windoz/hidingfr.txt

Entry Filed under: Non classé

11 Comments

  • 1. Anonyme  |  avril 26th, 2007 at 14:45

    Super, j’adore ! continue ;)
    Ps: J’ai testé le drv et j’ai eu un bsod. Peut être a cause du driver de Outpost Firewall. J’ai pas eu le temps de voir…


  • 2. fRoGGz  |  avril 27th, 2007 at 18:28

    Tests concluants, excellent travail..
    Un « dir _* » révèle le fichier mais c’est logique.
    Informations très clairement détaillées, c’est agréable.

    Bonne continuation.


  • 3. admin  |  avril 27th, 2007 at 20:12

    Ha oui effectivement mon code gérait mal le cas oû la fonction renvoyait une unique structure. J’ai corrigé le code et mit a jour l’archive

    Merci de m’avoir montrer le « bug » :}


  • 4. Anonyme  |  mai 2nd, 2007 at 04:42

    Hors sujet.. je trouvais pas ton email alors je te le dis ici. Sa te dit pas de créer un beau forum « fr » sur ton site :) (rookit, stealth, coding…) Franchement il y a beaucoup de forum avec reverse, tutos, truc bidule, mais pas un forum fr sur les techniques de rootkits, les injections, la discrétion et tout, un forum bien technique…


  • 5. admin  |  mai 2nd, 2007 at 10:22

    ivanlef0u119@yahoo.fr

    Autrement je ne pense pas qu’un forum soit intéressant, en tout cas je n’en vois pas l’intéret d’en avoir un en parallèle avec mon blog.


  • 6. Anonyme  |  mai 3rd, 2007 at 15:43

    Sinon t’aurais pu trouver son mail tout seul : http://ivanlef0u.free.fr/ = ivanlef0u(Arobase)free.fr ..
    Sinon, excellents articles que tu nous ponds Ivan, continue comme ça :p.


  • 7. Marsu  |  mai 5th, 2007 at 11:40

    Joli taf…. Ca a lair plus efficace que de hooker ZwQueryDirectoryFile. J’essaierai ca quand jaurai un peu de temps


  • 8. Qwa?  |  mai 5th, 2007 at 20:31

    Salut,

    J’ai un petit point a souligner. C’est connu que après avoir appeler IoCompleteRequest sur un IRP, il ne faut plus accéder aux valeurs de ce IRP. Donc, toi tu appeles la version original de NtfsFsdDirectoryControl mais es-tu certain que cette fonction la ne va pas appeler IoCompleteRequest ? Car après dans ton code tu joue avec l’IRP donc tu vas avoir un BSOD…. Just some food for thoughts !!

    IWTDASWYS.


  • 9. Pim's  |  novembre 27th, 2008 at 17:24

    Voilà, ça fait longtemps que je remarque que la souris ou le stylet de ma tablette graphique ne restitue pas un trait fidèle à ce que je ferais sur papier, ça tremblote un peu.
    Un logiciel, Inkscape, a un bon outil : L’inertie de son outil plume. Il est paramétrable de 0 à 20 : 0 pas d’inertie – 20 inertie maximum.

    Mais voilà, il faut dessiner dans Inkscape pour en bénéficier :
    QUESTION au champion du hook :
    Peut-on faire un hook qui, une fois lancé, ne s’occupe que de l’inertie de la souris ou du stylet quand on trace (clic ou appuie sur stylet) pour TOUS les logiciels en route sur le système et avec la possibilité de le paramétrer de 0 à 20 façon inkscape, pour windows XP.

    Quelle formidable avancée ! Quel défis ! J’en pleurerai de joie… si si


  • 10. Null  |  janvier 17th, 2012 at 14:43

    Iop, super utile cet article, même après 5 ans (waw !) !!!

    Par contre, pour éviter quelques bugs un peu gonflants (dans mon cas ça m’empêchait de virer le driver proprement), il faut rajouter :

    ObDereferenceObject(DrvNtfsObj);

    Encore merci pour cet article !!!


  • 11. API hooking sous Windows &hellip  |  mai 30th, 2012 at 08:32

    [...] 3- Hook IRP : http://www.ivanlef0u.tuxfamily.org/?p=45 [...]


Trackback this post


Calendar

avril 2025
L Ma Me J V S D
« fév    
 123456
78910111213
14151617181920
21222324252627
282930  

Most Recent Posts