Bonjour à tous, cette semaine j’ai décidé de me pencher sur les objects types initializer.

Je surfais sur le blog de mon maître jedi quand je suis tombé face à face sur un article concernant ces « Object Type Initializer », il aborde alors le sujet en énumérant quelques applications possibles.

Rendre un processus inkillable fut mon premier objectif, je pris donc mon courage a deux mains et me mit à bosser le sujet.

Il existe sous windows un "sous-système" qui a pour rôle de gerer les objects. L'object manager souvent abrégé "ObjMgr", est un système qui va gérer les ressources de windows. Ce que je désigne par le nom de “resource” peut être : un processus, un device, un driver..



Tout ces objects sont constitués de la même façon. Ils commencent d’abord par un header (OBJECT_HEADER) et sont suivit d'un body qui change en function du type d’object, EPROCESS pour un process, FILE_OBJECT pour un fichier ainsi de suite.

L'object manager à donc pour rôle de fournir à l’utilisateur une interface pour manipuler les différentes resources du noyau, cette interface étant principalement basée sur les handles.



Chaque object posséde une structure de type OBECT_TYPE_INITIALIZER qui est identique pour tout les objects de même type .Je décide donc de sortir le kd pour me renseigner un peu plus sur cette structure.

D’abord j’utilise la commande !process du kd. Je cite :


Syntax in Windows XP and later:
!process [/s Session] [/m Module] [Process [Flags]]
!process [/s Session] [/m Module] 0 Flags ImageName

[..]
Process
Specifies the hexadecimal address or the process ID of the process on the target computer.
The value of Process determines whether the !process extension displays a process address or a process ID . If Process is -1 in Windows NT 4.0 or is omitted in any version of Windows, the debugger displays data only about the current system process. If Process is 0 and ImageName is omitted, the debugger displays information about all active processes.

Flags
Specifies the level of detail to display. Flags can be any combination of the following bits. If Flags is 0, only a minimal amount of information is displayed. The default varies according to the version of Windows and the value of Process. In Windows NT 4.0, the default is 0x3 if Process is omitted or if Process is 0; otherwise, the default is 0xF. In Windows 2000, the default is 0x3 if Process is omitted or if Process is 0 and ImageFile is omitted; otherwise, the default is 0xF. In Windows XP and later, the default is 0x3 if Process is omitted or if Process is either 0 or -1; otherwise, the default is 0xF.

Bit 0 (0x1)
Displays time and priority statistics.

Bit 1 (0x2)
Displays a list of threads and events associated with the process, and their wait states.

Bit 2 (0x4)
Displays a list of threads associated with the process. If this is included without Bit 1 (0x2), each thread is displayed on a single line. If this is included along with Bit 1, each thread is displayed with a stack trace.

Bit 3 (0x8)
(Windows XP and later) Displays the return address, the stack pointer, and (on Itanium-based systems) the bsp register value for each function. The display of function arguments is suppressed.

Bit 4 (0x10)
(Windows XP and later) Sets the process context equal to the specified process for the duration of this command. This results in a more accurate display of thread stacks. Because this flag is equivalent to using .process /p /r for the specified process, any existing user-mode module list will be discarded. If Process is zero, the debugger displays all processes, and the process context is changed for each one. If you are only displaying a single process and its user-mode state has already been refreshed (for example, with .process /p /r), it is not necessary to use this flag. This flag is only effective when used with Bit 0 (0x1).

Me voilà partis.

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 817cc7c0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00039000 ObjectTable: e1001cb0 HandleCount: 204.
Image: System

PROCESS 8160b698 SessionId: none Cid: 0228 Peb: 7ffdc000 ParentCid: 0004
DirBase: 0335b000 ObjectTable: e12feac0 HandleCount: 21.
Image: smss.exe

PROCESS 817e98f0 SessionId: 0 Cid: 0264 Peb: 7ffdf000 ParentCid: 0228
DirBase: 0440b000 ObjectTable: e13f8c08 HandleCount: 267.
Image: csrss.exe

PROCESS 815de5e0 SessionId: 0 Cid: 027c Peb: 7ffdb000 ParentCid: 0228
DirBase: 04511000 ObjectTable: e1440eb8 HandleCount: 251.
Image: winlogon.exe

PROCESS 815b8020 SessionId: 0 Cid: 02a8 Peb: 7ffde000 ParentCid: 027c
DirBase: 04e53000 ObjectTable: e14da758 HandleCount: 240.
Image: services.exe

PROCESS 815b4020 SessionId: 0 Cid: 02b4 Peb: 7ffd5000 ParentCid: 027c
DirBase: 04ef0000 ObjectTable: e1512ee0 HandleCount: 273.
Image: lsass.exe

PROCESS 8159c020 SessionId: 0 Cid: 0350 Peb: 7ffd4000 ParentCid: 02a8
DirBase: 0586d000 ObjectTable: e15371a8 HandleCount: 209.
Image: svchost.exe

PROCESS 8158ebd8 SessionId: 0 Cid: 03a4 Peb: 7ffd9000 ParentCid: 02a8
DirBase: 05be1000 ObjectTable: e1567690 HandleCount: 218.
Image: svchost.exe

PROCESS 8157d1b0 SessionId: 0 Cid: 0408 Peb: 7ffdc000 ParentCid: 02a8
DirBase: 06467000 ObjectTable: e14277b8 HandleCount: 774.
Image: svchost.exe

PROCESS 81571968 SessionId: 0 Cid: 0458 Peb: 7ffd7000 ParentCid: 02a8
DirBase: 06ac0000 ObjectTable: e14d7ba8 HandleCount: 55.
Image: svchost.exe

PROCESS 81562a08 SessionId: 0 Cid: 04b4 Peb: 7ffde000 ParentCid: 02a8
DirBase: 06aa5000 ObjectTable: e15ab910 HandleCount: 108.
Image: spoolsv.exe

PROCESS 8152eda0 SessionId: 0 Cid: 05b4 Peb: 7ffde000 ParentCid: 058c
DirBase: 097c9000 ObjectTable: e1abb258 HandleCount: 380.
Image: explorer.exe

PROCESS 81525928 SessionId: 0 Cid: 0638 Peb: 7ffd6000 ParentCid: 05b4
DirBase: 0ad0c000 ObjectTable: e1b763f0 HandleCount: 36.
Image: VMwareTray.exe

PROCESS 81512300 SessionId: 0 Cid: 0648 Peb: 7ffd4000 ParentCid: 05b4
DirBase: 0b018000 ObjectTable: e15ed1a0 HandleCount: 73.
Image: VMwareUser.exe

PROCESS 8150b3e8 SessionId: 0 Cid: 0650 Peb: 7ffd7000 ParentCid: 05b4
DirBase: 0b232000 ObjectTable: e15eb6a8 HandleCount: 69.
Image: ctfmon.exe

PROCESS 81509ad0 SessionId: 0 Cid: 0660 Peb: 7ffdc000 ParentCid: 05b4
DirBase: 0b3b8000 ObjectTable: e15f3830 HandleCount: 30.
Image: LClock.exe

PROCESS 814f3540 SessionId: 0 Cid: 06b4 Peb: 7ffde000 ParentCid: 02a8
DirBase: 0bc5f000 ObjectTable: e1ba3648 HandleCount: 42.
Image: VMwareService.exe

PROCESS 814ab8d8 SessionId: 0 Cid: 00b4 Peb: 7ffde000 ParentCid: 02a8
DirBase: 0cfb3000 ObjectTable: e1b74bb0 HandleCount: 106.
Image: alg.exe

PROCESS 8149b668 SessionId: 0 Cid: 06a8 Peb: 7ffdc000 ParentCid: 05b4
DirBase: 0906c000 ObjectTable: e1528008 HandleCount: 88.
Image: OSRLOADER.exe

PROCESS 8156f740 SessionId: 0 Cid: 031c Peb: 7ffdd000 ParentCid: 05b4
DirBase: 072b0000 ObjectTable: e10d49d0 HandleCount: 64.
Image: Dbgview.exe

PROCESS 8149b020 SessionId: 0 Cid: 0400 Peb: 7ffdb000 ParentCid: 05b4
DirBase: 08b93000 ObjectTable: e1618448 HandleCount: 75.
Image: taskmgr.exe


Ensuite j’utilise la commande !object.


The !object extension displays information about a system object.

!object Address
[...]
Address
If the first argument is a nonzero hexadecimal number, it specifies the hexadecimal address of the system object for which to display information.

On prend donc n'importe quel processus, car tous ces objects sont du même type, de plus la structure OBJECT_TYPE_INITIALIZER est globale à chaque type d'object.


kd> !object 817cc7c0
Object: 817cc7c0 Type: (817cce38) Process
ObjectHeader: 817cc7a8 (old version)
HandleCount: 2 PointerCount: 51

Nous avons donc l'adresse de ses headers.


kd> dt nt!_OBJECT_HEADER 817cc7a8
+0x000 PointerCount : 51
+0x004 HandleCount : 2
+0x004 NextToFree : 0x00000002
+0x008 Type : 0x817cce38 _OBJECT_TYPE
+0x00c NameInfoOffset : 0 ''
+0x00d HandleInfoOffset : 0 ''
+0x00e QuotaInfoOffset : 0 ''
+0x00f Flags : 0x22 '"'
+0x010 ObjectCreateInfo : 0x80560c80 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x80560c80
+0x014 SecurityDescriptor : 0xe10017d5
+0x018 Body : _QUAD

A partir de cette structure nous pouvons 'jongler' dans les headers de l'object.

Nous avons son Body en +0x18, ici il s'agit d'un pointeur sur une structure de type EPROCESS.

Nous avons un pointeur sur une structure de type OBJECT_TYPE, celle qui nous intéresse s'y trouve.


kd> dt nt!_OBJECT_TYPE 0x817cce38
+0x000 Mutex : _ERESOURCE
+0x038 TypeList : _LIST_ENTRY [ 0x817cce70 - 0x817cce70 ]
+0x040 Name : _UNICODE_STRING "Process"
+0x048 DefaultObject : (null)
+0x04c Index : 5
+0x050 TotalNumberOfObjects : 0x15
+0x054 TotalNumberOfHandles : 0x4c
+0x058 HighWaterNumberOfObjects : 0x16
+0x05c HighWaterNumberOfHandles : 0x52
+0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0ac Key : 0x636f7250
+0x0b0 ObjectLocks : [4] _ERESOURCE

Nous voilà dans cette fameuse structure 'globale'.

On y reconnaît bien le nom du type d'object à savoir Process dans ce cas là.

Ne perdons pas de vue notre structure OBJECT_TYPE_INITIALIZER en +0x60, go !


kd> dt nt!_OBJECT_TYPE_INITIALIZER 0x817cce38+0x60
+0x000 Length : 0x4c
+0x002 UseDefaultObject : 0 ''
+0x003 CaseInsensitive : 0 ''
+0x004 InvalidAttributes : 0xb0
+0x008 GenericMapping : _GENERIC_MAPPING
+0x018 ValidAccessMask : 0x1f0fff
+0x01c SecurityRequired : 0x1 ''
+0x01d MaintainHandleCount : 0 ''
+0x01e MaintainTypeList : 0 ''
+0x020 PoolType : 0 ( NonPagedPool )
+0x024 DefaultPagedPoolCharge : 0x1000
+0x028 DefaultNonPagedPoolCharge : 0x290
+0x02c DumpProcedure : (null)
+0x030 OpenProcedure : (null)
+0x034 CloseProcedure : (null)
+0x038 DeleteProcedure : 0x8058a87d void nt!PspProcessDelete+0
+0x03c ParseProcedure : (null)
+0x040 SecurityProcedure : 0x8056a71e long nt!SeDefaultObjectMethod+0
+0x044 QueryNameProcedure : (null)
+0x048 OkayToCloseProcedure : (null)

Je me vois donc hooker la callback DeleteProcedure, en effectuant une sorte de trie des processus victimes de la fonction PspProcessDelete.

Le prototype cette fonction est le suivant :


VOID
PspProcessDelete( IN PVOID Object )


Il me suffisait donc de récupérer le nom du processus, de le comparer a celui que j'etais censé protégé du kill et donc de lancer, ou au contraire de ne pas lancer la fonction PspProcessDelete.

J'installe donc mon hook, ma condition mais....

Le processus se fait quand même killer..

Frustré je vais tenter de vous montrer pourquoi il m'est impossible de protégé d'un kill du processus en controlant la DeleteProcedure.


« Merci à windows pour avoir foutu mon post en l'air :) »


Pour les personnes qui voudraient tout de même rendre un processus inkillable, vous pouvez toujours allez hooker la SSDT par exemple. La raison pour laquelle mon hook n'a pas fonctionné est la suivante : Cette callback est _apparemment_ pas utilisé pour détruire l'object mais pour déférencer le processus des tables ( EPROCESS par exemple ). Je n'intervenais donc en aucun cas sur la suppression ou non du processus cible.


On pourrait, je pense, faire des petits trucs sympathiques en allant s'amuser à hooker les procedures dans d'autre type d'object.

Si on hookait la OpenProcedure d'un type File, on pourrait par exemple mettre en place une espèce de routine de traitement, histoire de « monitorer » à chaque ouverture de handle sur l'object.

En tous cas, je ne voudrais pas m'avancer en ce qui concerne ces exemples d'exploitations car comme la mienne elles pourraient être vouées à l'echec ... :(


Bref continuons un peu plus sur les objects.

Au sein de la structure de type OBJECT_TYPE_INITIALIZER on peut croiser plusieurs type de callback :



Ces « méthodes » sont celles que j'ai pu rencontrer dans ma petite excursion.

Voilà les informations que j'ai pu récoltés sur l'object manager, si quelques personnes auraient menés des recherches en rapport avec celui-ci merci de me le faire savoir :).


A présent je vous propose mon code ( foireux certes ) de hook de la DeleteProcedure :



Et un petit lien venut tout droit du uninformed v8 :



Voilà c'est finis pour aujourd'hui, en espérant que le post plaira a certains malgrès l'echec de mon hook :/.

Cya!

PS : Un échange de liens vient d'être mise en place avec les noxistes ainsi qu'avec Ghosts In The Stack, je les ajoute donc à la blogrollz, bonne continuation à eux et merci à eux deux.