Detect Hidden Processes – Handle Table List

Bonjour/Bonsoir,
je me vois obligé de laisser un petit post en réponse à celui d’Overclok, je cite : « How to pwn lilxam’s toolz :) « . Ce post faisant lui-même référence à mon article  » Listing all processes« . Bref revoyons un peu tout ça :
-Ivanlef0u puis Overclok s’amuse à cacher des processus à « unlinkant » les structure EPROCESS de ces processus de la table PsActiveProcessList.
-Me viens alors l’idée de trouver un moyen de retrouver ces processus cachés, je met alors en place un Brute Force sur les ID des processus en testant leur existence via OpenProcess(). Rien de bien élégant mais ceci à le mérite de fonctionner.
-Overclok viens alors à présenter 2 autres techniques pour cacher des processus. La première étant l’unlink de la PspCidTable, technique qui met en échec mon précédent tool puisque la fonction OpenProcess() se sert de la table PspCidTable. La seconde est l’unlink d’une structure dans csrss.exe. Ce processus étant un sorte de « sous-système », il a un handle ouvert sur tous les processus. On aurait donc pu lister les processus en récupérant tous les handles ouvert par csrss.exe.

Mon problème alors est d’arriver à lister tous les processus mêmes cachés avec les trois techniques précédentes.

The HandleTableList

Au cours de ma recherche je me suis beaucoup penché sur les handles et l’Object Manager jusqu’à apprendre l’existence d’une table appelé ObjectTable contenue dans chaque processus contenant les handles ouverts par celui-ci. Ces tables sont de type HANDLE_TABLE :


kd> dt nt!_HANDLE_TABLE
+0×000 TableCode : Uint4B
+0×004 QuotaProcess : Ptr32 _EPROCESS
+0×008 UniqueProcessId : Ptr32 Void
+0×00c HandleTableLock : [4] _EX_PUSH_LOCK
+0×01c HandleTableList : _LIST_ENTRY
+0×024 HandleContentionEvent : _EX_PUSH_LOCK
+0×028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0×02c ExtraInfoPages : Int4B
+0×030 FirstFree : Uint4B
+0×034 LastFree : Uint4B
+0×038 NextHandleNeedingPool : Uint4B
+0×03c HandleCount : Int4B
+0×040 Flags : Uint4B
+0×040 StrictFIFO : Pos 0, 1 Bit

A noter le pointeur sur la structure EPROCESS en +0×04 et le pointeur sur l’ID du processus en +0×08. Mieux encore, les HANDLE_TABLE des processus forment une liste double-chainée. On note en effet le membre de la structure HandleTableList qui est de type LIST_ENTRY :

kd> dt nt!_LIST_ENTRY
+0×000 Flink : Ptr32 _LIST_ENTRY
+0×004 Blink : Ptr32 _LIST_ENTRY

On peut accéder à l’ObjectTable d’un processus par le biais de la structure EPROCESS :

kd> dt nt!_EPROCESS
+0×000 Pcb : _KPROCESS
+0×06c ProcessLock : _EX_PUSH_LOCK
+0×070 CreateTime : _LARGE_INTEGER
+0×078 ExitTime : _LARGE_INTEGER
+0×080 RundownProtect : _EX_RUNDOWN_REF
+0×084 UniqueProcessId : Ptr32 Void
+0×088 ActiveProcessLinks : _LIST_ENTRY
+0×090 QuotaUsage : [3] Uint4B
+0×09c QuotaPeak : [3] Uint4B
+0×0a8 CommitCharge : Uint4B
+0×0ac PeakVirtualSize : Uint4B
+0×0b0 VirtualSize : Uint4B
+0×0b4 SessionProcessLinks : _LIST_ENTRY
+0×0bc DebugPort : Ptr32 Void
+0×0c0 ExceptionPort : Ptr32 Void
+0×0c4 ObjectTable : Ptr32 _HANDLE_TABLE

En +0×0C4 se trouve un pointeur sur notre ObjectTable.
Voici alors les étapes qu’il nous faudrait suivre :
1. Récupérer l’EPROCESS courante ou d’un processus connu.
2. Récupérer un pointeur sur l’ObjectTable.
3. Parcourir la liste chainée des ObjectTable de chaque processus.
4. A chaque ObjectTable récupérer l’ID du processus ainsi qu’un pointeur sur l’EPROCESS.
5. Récupérer le nom du processus grâce à cette dernière (+0×174 ImageFileName : [16] UChar).

Cependant j’ai pensé affirmer un peu vite que les ObjectTable forment une liste chainée. J’ai alors voulu vérifier ceci avant de me mettre à coder ce driver (/me redoute encore le r0), c’est possible avec windbg :

Etape 1 :

kd> !process csrss.exe
PROCESS 80558e80 SessionId: none Cid: 0000 Peb: 00000000 ParentCid: 0000
DirBase: 00039000 ObjectTable: e1001cd8 HandleCount: 173.
Image: Idle
VadRoot 00000000 Vads 0 Clone 0 Private 0. Modified 0. Locked 0.

Avec cette commande on peut obtenir un pointeur sur l’EPROCESS à l’adresse 0×80558e80 (et même sur l’ObjectTable mais on va faire comme ci on avait pas vu, pour suivre nos étapes).

Voyons ensuite à quoi ressemble l’EPROCESS de csrss.exe :

kd> dt nt!_EPROCESS 80558e80
+0×000 Pcb : _KPROCESS
+0×06c ProcessLock : _EX_PUSH_LOCK
+0×070 CreateTime : _LARGE_INTEGER 0×0
+0×078 ExitTime : _LARGE_INTEGER 0×0
+0×080 RundownProtect : _EX_RUNDOWN_REF
+0×084 UniqueProcessId : (null)
+0×088 ActiveProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0×090 QuotaUsage : [3] 0
+0×09c QuotaPeak : [3] 0
+0×0a8 CommitCharge : 0
+0×0ac PeakVirtualSize : 0
+0×0b0 VirtualSize : 0
+0×0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0×0bc DebugPort : (null)
+0×0c0 ExceptionPort : (null)
+0×0c4 ObjectTable : 0xe1001cd8 _HANDLE_TABLE

Etape 2:
On peut alors récupérer un pointeur sur l’objectTable comme prévu à l’adesse 0xe1001cd8.

Voyons à quoi celli-ci ressemble :

kd> dt nt!_HANDLE_TABLE e1001cd8
+0×000 TableCode : 0xe1002000
+0×004 QuotaProcess : (null)
+0×008 UniqueProcessId : 0×00000004
+0×00c HandleTableLock : [4] _EX_PUSH_LOCK
+0×01c HandleTableList : _LIST_ENTRY [ 0xe10065d4 - 0x805617c8 ]
+0×024 HandleContentionEvent : _EX_PUSH_LOCK
+0×028 DebugInfo : (null)
+0×02c ExtraInfoPages : 0
+0×030 FirstFree : 0×520
+0×034 LastFree : 0
+0×038 NextHandleNeedingPool : 0×800
+0×03c HandleCount : 173
+0×040 Flags : 0
+0×040 StrictFIFO : 0y0

Etape 3 :
On se penche ensuite sur l’HanldeTableList :


kd> dt nt!_LIST_ENTRY e1001cd8+0×01c
[ 0xe10065d4 - 0x805617c8 ]
+0×000 Flink : 0xe10065d4 _LIST_ENTRY [ 0xe13d66fc - 0xe1001cf4 ]
+0×004 Blink : 0×805617c8 _LIST_ENTRY [ 0xe1001cf4 - 0xe1661d9c ]


On a en théorie un pointeur sur l’HandleTableList précédente et suivante.
Récupérons la suivante :

kd> dt nt!_LIST_ENTRY 0xe10065d4
[ 0xe13d66fc - 0xe1001cf4 ]
+0×000 Flink : 0xe13d66fc _LIST_ENTRY [ 0xe13c7fd4 - 0xe10065d4 ]
+0×004 Blink : 0xe1001cf4 _LIST_ENTRY [ 0xe10065d4 - 0x805617c8 ]

Etape 4:
Tout semble correct pour l’instant, tentons alors de récupérer l’ObjectTable :

kd> dt nt!_HANDLE_TABLE e10065d4-0×01c
+0×000 TableCode : 0xe128e000
+0×004 QuotaProcess : 0×8163d1a0 _EPROCESS
+0×008 UniqueProcessId : 0×000001ac
+0×00c HandleTableLock : [4] _EX_PUSH_LOCK
+0×01c HandleTableList : _LIST_ENTRY [ 0xe13d66fc - 0xe1001cf4 ]
+0×024 HandleContentionEvent : _EX_PUSH_LOCK
+0×028 DebugInfo : (null)
+0×02c ExtraInfoPages : 0
+0×030 FirstFree : 0×54
+0×034 LastFree : 0
+0×038 NextHandleNeedingPool : 0×800
+0×03c HandleCount : 19
+0×040 Flags : 0
+0×040 StrictFIFO : 0y0

Tout à l’air bon, le PID de ce processus est 0×1ac.

Etape 5 :

Voyons à qui il appartient :

kd> dt nt!_EPROCESS 0×8163d1a0

+0×084 UniqueProcessId : 0×000001ac

+0×174 ImageFileName : [16] « smss.exe »

Oh mais que voyons ? Il s’agit bien d’un processus :) )). Notre hypothèse était donc bonne :) .
Et bien voilà pour cette technique, pour le code je vous envoi à la fin de l’article.
Voici un petit exemple de ce que ça donne, ayant caché au préalable calc.exe avec le driver d’Overclok :

Lilxam driver OK

Process : System

Process : smss.exe

Object Table : 0xe145e178

— PID : 0×370

— PPEPROCESS : 0xe145e17c

— PEPROCESS : 0×86071980

— Name : csrss.exe

Object Table : 0xe1014bb0

— PID : 0×33c

— PPEPROCESS : 0xe1014bb4

— PEPROCESS : 0×860754b8

— Name : smss.exe

Object Table : 0xe1003ec8

— PID : 0×4

— PPEPROCESS : 0xe1003ecc

— PEPROCESS : 0×0

Object Table : 0×80564b8c

— PID : 0×0

— PPEPROCESS : 0×80564b90

— PEPROCESS : 0×0

Object Table : 0xe134ed10 <---- :) )))

--- PID : 0x260

--- PPEPROCESS : 0xe134ed14

--- PEPROCESS : 0x85706a78

--- Name : calc.exe

...

End

Malheureusement cette technique est facilement bypassable et Overclok me l’a déjà prouvé :( . En revanche rkUnhooker arrive encore à trouver le processus d’Overclok…
J’ai alors encore un petite hypothèse que je n’est pas réussi à mettre en place.

Getting list of threads ???

Dans son article, Overclok se pose plusieurs question après avec tenté l’unlink de la structure ETHREAD, je cite :

 »
- Comment RkUnhooker remet la main sur mon processus ?
- Quel(s) technique(s) utilise t-il pour cela ?
- Existe t-il un autre endroit où une liste des processus lancées sur le système est disponible ?
 »

Mes recherches et mes tentatives mon alors amené sur une table, appelé KiWaitListHead sous XP qui, à ce qui ce dirait, permettrait d’obtenir une liste des threads.
Alors voyons comment trouver cette liste. Après quelques recherches j’apprends que cette table est utilisée par la fonction KeWaitForSingleObject. Un petit disass avec IDA, j’ai préféré l’utilisé à windbg pour pouvoir voir tous les jumps facilement car celui-ci m’a trompé pendant un moment, et on trouve :

loc_40DE4F:
mov ecx, ds:dword_48226C
lea eax, [esi+60h]
mov dword ptr [eax], offset _KiWaitListHead
mov [eax+4], ecx
mov [ecx], eax
mov ds:dword_48226C, eax
jmp loc_40513E

+0×8CB8 mov dword ptr [eax], offset _KiWaitListHead

On va donc scanner cette fonction et on pourra récupérer un pointeur sur la table :) .
Mais voilà, une fois la table récupérée je ne sais plus quoi en faire, je n’arrive pas à reconstituer les structures :( .
Donc voilà j’en appelle à vous, peut-être avez-vous une idée ?
A suivre…

Je vous propose donc seulement le code pour récupérer un pointeur sur KiWaitListHead.

Les codes sont dispo ici

Merci à Overclok pour cette petite aventure bien sympatique, peut-être n’est-elle pas finie ;) .

Lilxam.

  1. Aucun commentaire pour l'instant

  1. 17 août 2009
Les commentaires sont fermés