Archive for janvier 11th, 2007

Playing With Windows Handles

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

15 comments janvier 11th, 2007


Calendar

janvier 2007
L Ma Me J V S D
« déc   fév »
1234567
891011121314
15161718192021
22232425262728
293031  

Posts by Month

Posts by Category