Playing With Windows Handles

janvier 11th, 2007 at 11:56 admin

Hello, voici encore un tool sortit de mon esprit torturé. Il permet d’énumerer les handles ouverts pas un process, pratique par exemple pour connaîtres les fichiers ouvert par un process.


Le programme utilise principalement l’API native de Win, il fonctionne de la manière suivante :

- On récupère le nombre total de handles ouvert (NtQuerySystemInformation), puis on alloue la mémoire sur HandleCount*sizeof(SYSTEM_HANDLE_INFORMATION), SYSTEM_HANDLE_INFORMATION est une structure qui contient :

typedef struct _SYSTEM_HANDLE_INFORMATION { // Information Class 16
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;  // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;

On peut ainsi trouver les handles ouvert par notre process en conaissant son PID.

- On duplique le handle (NtDuplicateHandle) pour que notre process puisse récupérer des informations desssus, la fonction NtQueryObject :

extern "C" NTSTATUS __stdcall NtQueryObject(
IN HANDLE ObjectHandle,
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
OUT PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT PULONG ReturnLength OPTIONAL
);

est utilisée avec les ObjectInformationClass ObjectTypeInformation et ObjectNameInformation, avec le premier on trouve (je pense que vous l’avez deviné) le type de l’objet qui peut être :

(phrack 59-0x10 by crazylord)
* Adapter       * File             * Semaphore
* Callback      * IoCompletion     * SymbolicLink
* Controler     * Job              * Thread
* Desktop       * Key              * Timer
* Device        * Mutant           * Token
* Directory     * Port             * Type
* Driver        * Process          * WaitablePort
* Event         * Profile          * WindowStation
* EventPair     * Section          * WmiGuid

Puis on récup le nom de l’object et on affiche tout ca.

Bon jusqu’ici c’est simple, le problème c’est que je suis tomber sur un bug lorsqu’on esssaye d’obtenir le nom sur un NamedPipe ouvert en mode synchrone (gnifulol?) la fonction NtQueryObject devient blocante oO. J’ai donc implémenté un thread qui effectue cette opération pour ce type (de type File en fait), au moins il peut bloqué puisqu’on le kill si il fait le malin ;).

D’après ce que j’ai vu sur d’autres programme qui font la même, soit ceux ci utilisent directement un driver pour récup des infos sur les objets, soit ils sont codé par des autruches, sisi aller voir la et dites moi ce que vous pensez du code http://www.codeguru.com/Cpp/W-P/system/processesmodules/article.php/c2827.

Le but de ce tool est surtout de montrer la puissance de l’API native qui permet de faire plein plein de choses qu’on ne peut faire avec les API documentées par le SDK.
Allay un petit exemple :

C:\\ProgHack\\c\\Handles>handle explorer.exe
Process Handle Enumeration By IvanlefOu
Be MAD!
Process : explorer.exe
Total Handles : 5368

KeyedEvent : \\KernelObjects\\CritSecOutOfMemoryEvent
Directory : \\KnownDlls
File : \\Documents and Settings\\Moi
Section :
Directory : \\Windows
[...]

Le binaire et le code dispo dans le pack !
http://ivanlef0u.fr/repo/Handle.rar

Pour aller plus loin sachez que chaque process à sa propre table de handles, celle ci se trouve pointé dans la structure _EPROCESS (on est ds le noyau la pour ceux qui se touchent le pipi au fond) :

lkd> dt nt!_EPROCESS
[...]
+0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE
[...]

ObjectTable pointe sur une structure _HANDLE_TABLE

lkd> dt nt!_HANDLE_TABLE
+0x000 TableCode        : Uint4B
+0x004 QuotaProcess     : Ptr32 _EPROCESS
+0x008 UniqueProcessId  : Ptr32 Void
+0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
+0x01c HandleTableList  : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo        : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages   : Int4B
+0x030 FirstFree        : Uint4B
+0x034 LastFree         : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount      : Int4B
+0x040 Flags            : Uint4B
+0x040 StrictFIFO       : Pos 0, 1 Bit

HandleTableList est une double liste chainée sur les _HANDLE_TABLE des autres processus, on peut la parcouri en utilisant la commande suivante sous le kernel debugger :

!list -x "dt nt!_HANDLE_TABLE @$extret-1C" 0x(addresse de départ)

Chez moi ca donne :

lkd> !list -x "dt nt!_HANDLE_TABLE @$extret-1C" 0xe1a4f384
+0x000 TableCode        : 0xe1103001
+0x004 QuotaProcess     : 0x8173a750 _EPROCESS
+0x008 UniqueProcessId  : 0x000000b4
+0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
+0x01c HandleTableList  : _LIST_ENTRY [ 0xe1ab18b4 - 0xe17eb4fc ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo        : (null)
+0x02c ExtraInfoPages   : 0
+0x030 FirstFree        : 0x19c
+0x034 LastFree         : 0x774
+0x038 NextHandleNeedingPool : 0x1000
+0x03c HandleCount      : 469
+0x040 Flags            : 0
+0x040 StrictFIFO       : 0y0

+0x000 TableCode        : 0xe1165001
+0x004 QuotaProcess     : 0x815db758 _EPROCESS
+0x008 UniqueProcessId  : 0x0000069c
+0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
+0x01c HandleTableList  : _LIST_ENTRY [ 0xe151a88c - 0xe1a4f384 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo        : (null)
+0x02c ExtraInfoPages   : 0
+0x030 FirstFree        : 0x874
+0x034 LastFree         : 0
+0x038 NextHandleNeedingPool : 0x1000
+0x03c HandleCount      : 553
+0x040 Flags            : 0
+0x040 StrictFIFO       : 0y0

+0x000 TableCode        : 0xe1182000
+0x004 QuotaProcess     : 0x813f29c0 _EPROCESS
+0x008 UniqueProcessId  : 0x000005a0
+0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
+0x01c HandleTableList  : _LIST_ENTRY [ 0xe1f806bc - 0xe1ab18b4 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo        : (null)
+0x02c ExtraInfoPages   : 0
+0x030 FirstFree        : 0x190
+0x034 LastFree         : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount      : 129
+0x040 Flags            : 0
+0x040 StrictFIFO       : 0y0

Merci à fuzen_op de rootkit.com
http://www.rootkit.com/newsread.php?newsid=307

Alors ou qu’ils sont nos handles ! He bien ils sont dans un tableaux pointé par TableCode qui contient des structures _HANDLE_TABLE_ENTRY !

lkd> dt nt!_HANDLE_TABLE_ENTRY
+0x000 Object           : Ptr32 Void
+0x000 ObAttributes     : Uint4B
+0x000 InfoTable        : Ptr32 _HANDLE_TABLE_ENTRY_INFO
+0x000 Value            : Uint4B
+0x004 GrantedAccess    : Uint4B
+0x004 GrantedAccessIndex : Uint2B
+0x006 CreatorBackTraceIndex : Uint2B
+0x004 NextFreeTableEntry : Int4B

Qui plus précisement ressemble à:

/* From the free version of ntifs.h */
typedef struct _HANDLE_TABLE_ENTRY {
union {
PVOID Object;
ULONG ObAttributes;
PHANDLE_TABLE_ENTRY_INFO InfoTable;
ULONG Value;
};
union {
ULONG GrantedAccess;
struct {
USHORT GrantedAccessIndex;
USHORT CreatorBackTraceIndex;
};
LONG NextFreeTableEntry;
};
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

La struture ne contient pas directement l’addr de l’objet en fait comme on peut le voir :

Pour plus d’infos allez voir le chapitre Object Manager de Windows Internals. Pour récup le pointeur sur l’object header il faut donc use le chtit code suivant

#include 

int main(int argc, char * argv[])
{
ULONG handle=0;

handle=strtoul(argv[1], NULL, 0);

handle|=0x80000000; handle&=0xfffffff8;

printf("Object header is at : 0x%x\n", handle);

return 0;
}

Le pointeur sur object hearder pointe sur une structure (_OBJECT_HEADER)

lkd> dt nt!_OBJECT_HEADER
+0x000 PointerCount     : Int4B
+0x004 HandleCount      : Int4B
+0x004 NextToFree       : Ptr32 Void
+0x008 Type             : Ptr32 _OBJECT_TYPE
+0x00c NameInfoOffset   : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset  : UChar
+0x00f Flags            : UChar
+0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : Ptr32 Void
+0x014 SecurityDescriptor : Ptr32 Void
+0x018 Body             : _QUAD

Ce qui nous intéresse est la structure _OBJECT_TYPE :

lkd> dt nt!_OBJECT_TYPE
+0x000 Mutex            : _ERESOURCE
+0x038 TypeList         : _LIST_ENTRY
+0x040 Name             : _UNICODE_STRING
+0x048 DefaultObject    : Ptr32 Void
+0x04c Index            : Uint4B
+0x050 TotalNumberOfObjects : Uint4B
+0x054 TotalNumberOfHandles : Uint4B
+0x058 HighWaterNumberOfObjects : Uint4B
+0x05c HighWaterNumberOfHandles : Uint4B
+0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
+0x0ac Key              : Uint4B
+0x0b0 ObjectLocks      : [4] _ERESOURCE

On a le type de l’objet ainsi que son nom.
Donc si on voudrais virer l’acces à un handle il faudrait scanner cette table pour trouver lequel puis suprimer l’entrée.
Après je ne sais pas comment va réagir le système mais l’idée est la.
Je testerais cela prochainement je pense.

Ivanlef0u

Entry Filed under: RE

15 Comments

  • 1. admin  |  janvier 13th, 2007 at 17:53

    Mea culpa, une petite erreur c’était glissée, j’en est profité pour rajouter qques trucs


  • 2. Nelio  |  janvier 13th, 2007 at 23:47

    Elle se situait à quel niveau ?


  • 3. admin  |  janvier 14th, 2007 at 13:54

    En fait j’avais dit précédemment que le membre HandleTableList pointé sur la liste des handes du process, en fait c’est une double liste chainée sur les _HANDLE_TABLE des autres process. La table des handes, si je ne me trompe pas et pointé par TableCode… à confirmer mais ca semble être ca :’

    Ivanlef0u


  • 4. Ivanlef0u’s Blog &r&hellip  |  novembre 24th, 2007 at 16:22

    [...] le handle. On ne va pas s’amuser à énumérer tous les handles du process, cela est trop compliqué et prendrait trop de temps. On va ruser comme des renards, sachant qu’un handle n’est [...]


  • 5. Régis  |  février 29th, 2008 at 17:08

    Salut,

    Tu sembles bien t’y connaitre en process et handle.

    Bien que je cherche activement, je trouve pas trop d’infos, de fil en aiguile, je suis tombé sur ton blog fort intéressant !

    Je souhaite réaliser une petite application qui saurait copier un fichier alors que celui-ci est en cours d’utilisation et avec des droits bloquants sur ce fichier.

    D’autant plus, ce fichier est un fichier temporaire et l’application qui l’utilise l’efface régulièrement et le supprime avant de se fermer.

    Donc il est toujours locker.

    Avec un application comme unlocker (http://ccollomb.free.fr/unlocker/) on peut copier ce fichier et sans que l’application qui l’utilise ne se coupe.

    Unlocker est une application dont le code source n’est pas libre, j’ai donc pas trouvé comment il faisait.

    Aurais tu les compétences pour me conseiller dans la réalisation de cette fonction de copie de fichier ?

    Merci
    @+


  • 6. dora  |  février 29th, 2008 at 19:45

    Et après on dit que l’opensource c’est à chier :)


  • 7. Ivanlef0u’s Blog &r&hellip  |  mars 2nd, 2008 at 15:30

    [...] comment laissé sur mon blog récemment a attiré mon attention, j’ai donc décidé de répondre par mail à son auteur. Après [...]


  • 8. Régis  |  mars 3rd, 2008 at 09:59

    Re,

    J’attends avec impatience ton prochain article et merci pour tes réponses instructives.

    Surtout que la plupart des codes trouvés sur le net pour par exemple avoir la liste des handles demandent d’utiliser une bibliothèque externe si on veut aussi les hadles de fichier.
    Bibliothèque écrite en C du nom de kernelmemory.sys

    Je te donne les liens :
    http://www.cppfrance.com/codes/LSOF-LISTE-HANDLES-OUVERTS-PROCESSUS-COMME-SOUS-UNIX_39050.aspx
    http://www.csharpfr.com/codes/LISTER-HANDLES-FICHIERS-CLE-REGISTRES-OUVERTS-PROGRAMME-NT_40231.aspx

    @+


  • 9. Art60  |  mars 18th, 2008 at 08:11

    Bjr à tous !
    Régis, c’est étrange, je souhaite faire exactement la même chose !
    Copier un fichier (bloqué exclusif) du temp vers ailleurs pour ensuite le filtrer et enfin l’enregistrer dans un format compatible avec mon pendentif à écouteurs.
    Pour l’instant, unlocker me permet de le faire, à la main, merci encore à Cedrick, mais la programmation système comme vous la décrivez ici m’effraie un peu.
    En plus, y’a pas la lumière dans les pages, fait bien sombre…
    auriez vous l’amabilité d’héberger ou d’inclure des liens vers des kits complets avec les point-hash et/ou les point-déhellhell pour que les sources publiés ici puissent être aménagés et recompilés ?
    Au fait ? Compilateur préféré pour faire cela ?Visual Studio : ya goude ou pagoude ?
    Merci !


  • 10. admin  |  mars 18th, 2008 at 23:36

    Yo, pour compiler il faut avoir Visual Studio, soit le 2005 soit le 8, en version express ca suffit. Il faut aussi le Windows Plaform SDK que vous pourrez trouver içi .


  • 11. newsoft  |  mars 26th, 2008 at 23:18

    Je me suis laissé dire que Visual Studio 6 avait été le meilleur compilateur de tous les temps :)


  • 12. newsoft  |  avril 5th, 2008 at 15:02

    @Regis
    Petite astuce pour copier un fichier ouvert en mode exclusif : utiliser la fonction Volume Shadow Copy de Windows.

    Tous les détails ici :
    http://blogs.msdn.com/adioltean/archive/2005/01/05/346793.aspx


  • 13. curieux  |  novembre 23rd, 2008 at 23:53

    A la lecture de Windows Internals 4th ed (page 139), j’ai cru comprendre que la figure 3-21 que tu as reprise plus haut n’était valable que pour Windows 2000, il semblerait que pour Windows XP le bit #31 ne serve plus au lock, donc ton code
    handle|=0×80000000; handle&=0xfffffff8;
    serait à revoir pour XP..
    Qu’en penses-tu?


  • 14. admin  |  novembre 25th, 2008 at 10:57

    Yo,
    En fait c’est l’architecture de la table de handles qui change de Win2K à XP. La structure HANDLE_TABLE_ENTRY elle ne change pas.


  • 15. curieux  |  novembre 25th, 2008 at 18:05

    C’est vrai que la structure de HANDLE_TABLE a changé, mais il me semble que les flags dans HANDLE_TABLE_ENTRY ont également subi quelques modifs:

    Dans une Entry effective de la Table
    W2K: (1er double word- object header pointer)
    Bit#31: lock bit
    BIt#2 : flag audit
    Bit#1: flag inherit
    Bit#0: flag protect on close

    XP: (1er double word- object header pointer)
    BIt#2 = flag audit
    Bit#1: flag inherit
    Bit#0: lock bit
    (2ième double word- access mask)
    Bit#25: flag protect on close


Trackback this post


Calendar

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

Most Recent Posts