Archive for avril 26th, 2007

POC IRP Hooking

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

11 comments avril 26th, 2007


Calendar

avril 2007
L Ma Me J V S D
« mar   mai »
 1
2345678
9101112131415
16171819202122
23242526272829
30  

Posts by Month

Posts by Category