Archive for juillet 25th, 2007

New Registry Hiding Method

Toujours, à suivre les dernières recherches dans le domaine, je m’aperçois souvent que les chinois nous mettent une grosse raclée dans la gueule. Dernièrement je suis tombé sur post décrivant une nouvelle technique permettant de caché une clé dans le registre. Après avoir passé quelques heures à reverser et étudier le POC, je vais vous décrire (pour votre plus grand plaisir) le fonctionnement de cette nouvelle technique.

D’abord je tiens à préciser que j’utiliserais les termes anglais pour désigner les divers composants du registre, tout simplement pour qu’il soit plus simple de reconnaître le rôle des API (et puis fu le français).

Il faut savoir que le registre est composé d’un ensemble de hives, ceux ci sont définit dans la clé HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist :

C:\\Drivers\\HideKey>reg query  HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\hivelist 
! REG.EXE VERSION 3.0

HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\hivelist
    \\REGISTRY\\MACHINE\\HARDWARE	REG_SZ	
    \\REGISTRY\\MACHINE\\SECURITY	REG_SZ	\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\SECURITY
    \\REGISTRY\\MACHINE\\SOFTWARE	REG_SZ	\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\software
    \\REGISTRY\\MACHINE\\SYSTEM	REG_SZ	\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\system
    \\REGISTRY\\USER\\.DEFAULT	REG_SZ	\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\default
    \\REGISTRY\\MACHINE\\SAM	REG_SZ	\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\SAM
    \\REGISTRY\\USER\\S-1-5-20	REG_SZ	\\Device\\HarddiskVolume1\\Documents and Settings\\NetworkService\\NTUSER.DAT
    \\REGISTRY\\USER\\S-1-5-20_Classes	REG_SZ	\\Device\\HarddiskVolume1\\Documents and Settings\\NetworkService\\Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat
    \\REGISTRY\\USER\\S-1-5-21-448539723-2025429265-839522115-1003	REG_SZ	\\Device\\HarddiskVolume1\\Documents and Settings\\Moi\\NTUSER.DAT
    \\REGISTRY\\USER\\S-1-5-21-448539723-2025429265-839522115-1003_Classes	REG_SZ	\\Device\\HarddiskVolume1\\Documents and Settings\\Moi\\Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat

Ces hives sont situées sur le disque dans le dossier C:\WINDOWS\system32\config\ comme l’indique le dump au dessus. En fait le registre sous Windows n’est en fait qu’un ensemble de fichiers qui contiennent des structures définies de manière non documentées et dont le noyau manipule les valeurs en mappant ces derniers en mémoire. Une hive est composée de Keys de Subkeys puis de Data qui contiennent les Values.

Bon, je vais aller vite pour la suite. On veut étudier le fonctionnement de ZwEnumerateKey, cette fonction permet d’énumérer toutes les Subkeys d’une Key, son prototype est le suivant :

NTSTATUS
  ZwEnumerateKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_INFORMATION_CLASS  KeyInformationClass,
    OUT PVOID  KeyInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

Le KeyHandle peut être obtenu avec un ZwCreateKey ou ZwOpenKey, en incrémentant le paramètre Index on énumère les différentes SubKeys jusqu’à que la fonction nous renvoie un STATUS_NO_MORE_ENTRIES. Pour la suite je me baserais sur la call stack suivante :

kd> kv
ChildEBP RetAddr  Args to Child              
f944cc70 8056f016 e1338008 007f5a50 e1091fb8 nt!HvpGetCellMapped (FPO: [Non-Fpo])
f944ccb4 8056f17d e159c1e8 00000001 00000000 nt!CmEnumerateKey+0x65 (FPO: [Non-Fpo])
f944cd44 804de7ec 00000070 00000001 00000000 nt!NtEnumerateKey+0x1ea (FPO: [Non-Fpo])
f944cd44 7c91eb94 00000070 00000001 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f944cd64)
0007f454 7c91d958 77dada0c 00000070 00000001 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0007f458 77dada0c 00000070 00000001 00000000 ntdll!NtEnumerateKey+0xc (FPO: [6,0,0])
WARNING: Stack unwind information not available. Following frames may be wrong.
0007f5c0 77dad6c1 00000070 00000001 0007f5ec ADVAPI32!RegNotifyChangeKeyValue+0xa6
0007f5f8 010088ce 00000070 00000001 0007f628 ADVAPI32!RegEnumKeyW+0x78
0007f82c 0100896b 0007011e 000add90 0000004e regedit!KeyTree_ExpandBranch+0xe3 (FPO: [Non-Fpo])
0007fa78 01005221 00070106 0007fc48 0007faa0 regedit!RegEdit_OnKeyTreeItemExpanding+0x62 (FPO: [Non-Fpo])
0007fa88 0100674c 00070106 00000001 0007fc48 regedit!RegEdit_OnNotify+0xa7 (FPO: [Non-Fpo])
0007faa0 7e398734 00070106 0000004e 00000001 regedit!RegEditWndProc+0x9c (FPO: [Non-Fpo])
0007facc 7e398816 010066b0 00070106 0000004e USER32!InternalCallWinProc+0x28
0007fb34 7e39b89b 00000000 010066b0 00070106 USER32!UserCallWinProcCheckWow+0x150 (FPO: [Non-Fpo])
0007fb70 7e39b903 0054bf18 0054be20 00000001 USER32!SendMessageWorker+0x4a5 (FPO: [Non-Fpo])
0007fb90 773aaff1 00070106 0000004e 00000001 USER32!SendMessageW+0x7f (FPO: [Non-Fpo])
0007fc28 773c87e9 000a8c70 fffffe3a 0007fc48 COMCTL32!CCSendNotify+0xc20 (FPO: [Non-Fpo])
0007fcb8 773c9833 000a8c70 fffffe3a 000add90 COMCTL32!TV_SendItemExpand+0x83 (FPO: [Non-Fpo])
0007fd0c 773ca527 000a8c70 00000002 00000002 COMCTL32!TV_Expand+0x90 (FPO: [Non-Fpo])
0007fd80 773cab7f 000a8c70 00000201 00000001 COMCTL32!TV_ButtonDown+0x240 (FPO: [Non-Fpo])

Commençons par regarder la valeur du Handle passé à NtEnumerateKey :

kd> !handle 70
processor number 0, process 80d6d850
PROCESS 80d6d850  SessionId: 0  Cid: 00e0    Peb: 7ffdf000  ParentCid: 0490
    DirBase: 01492000  ObjectTable: e16508e0  HandleCount:  33.
    Image: regedit.exe

Handle table at e105f000 with 33 Entries in use
0070: Object: e1091fb8  GrantedAccess: 00000008 Entry: e105f0e0
Object: e1091fb8  Type: (80e96040) Key
    ObjectHeader: e1091fa0 (old version)
        HandleCount: 1  PointerCount: 2
        Directory Object: 00000000  Name:
\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS

La Key reférencé ici est donc HKEY_LOCAL_MACHINE\SYSTEM\SOFTWARE\MICROSOFT\WINDOWS, on souhaite obtenir des infos sur la SubKey à l’indice 1. Pour cela NtEnumerateKey va faire appel aux API du Configuration Manager (CM), plus précisément à CmEnumerateKey dont le prototype est le suivant :

NTSTATUS
CmEnumerateKey(
    IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
    IN ULONG Index,
    IN KEY_INFORMATION_CLASS KeyInformationClass,
    IN PVOID KeyInformation,
    IN ULONG Length,
    IN PULONG ResultLength
    )

L’argument intéressant est le KeyControlBlock :

kd> dt nt!_CM_KEY_CONTROL_BLOCK  e159c1e8
   +0x000 RefCount         : 4
   +0x004 ExtFlags         : 0y00000000 (0)
   +0x004 PrivateAlloc     : 0y1
   +0x004 Delete           : 0y0
   +0x004 DelayedCloseIndex : 0y100000000000 (0x800)
   +0x004 TotalLevels      : 0y0000000101 (0x5)
   +0x008 KeyHash          : _CM_KEY_HASH
   +0x008 ConvKey          : 0x63e9570a
   +0x00c NextHash         : (null)
   +0x010 KeyHive          : 0xe1338008 _HHIVE
   +0x014 KeyCell          : 0x7590f8
   +0x018 ParentKcb        : 0xe101a648 _CM_KEY_CONTROL_BLOCK
   +0x01c NameBlock        : 0xe1680aa0 _CM_NAME_CONTROL_BLOCK
   +0x020 CachedSecurity   : 0xe13583e8 _CM_KEY_SECURITY_CACHE
   +0x024 ValueCache       : _CACHED_CHILD_LIST
   +0x02c IndexHint        : 0x00000003 _CM_INDEX_HINT_BLOCK
   +0x02c HashKey          : 3
   +0x02c SubKeyCount      : 3
   +0x030 KeyBodyListHead  : _LIST_ENTRY [ 0xe1091ff4 - 0xe1091ff4 ]
   +0x030 FreeListEntry    : _LIST_ENTRY [ 0xe1091ff4 - 0xe1091ff4 ]
   +0x038 KcbLastWriteTime : _LARGE_INTEGER 0x1c7674a`5d986830
   +0x040 KcbMaxNameLen    : 0x1c
   +0x042 KcbMaxValueNameLen : 0
   +0x044 KcbMaxValueDataLen : 0
   +0x048 KcbUserFlags     : 0y0000
   +0x048 KcbVirtControlFlags : 0y0000
   +0x048 KcbDebug         : 0y00000000 (0)
   +0x048 Flags            : 0y0000000000100000 (0x20)

Allay hop, sous l’influence de chocapics on fait un peu n’importe quoi, alors dumpons quelques structures :

   
kd> dt nt!_CM_NAME_CONTROL_BLOCK 0xe1680aa0
   +0x000 Compressed       : 0x1 ''
   +0x002 RefCount         : 5
   +0x004 NameHash         : _CM_NAME_HASH
   +0x004 ConvKey          : 0x2f7de68b
   +0x008 NextHash         : (null)
   +0x00c NameLength       : 7
   +0x00e Name             : [1] 0x4957

kd> db 0xe1680aa0+E l 7
e1680aae  57 49 4e 44 4f 57 53    WINDOWS

Juste par curiosité, faisons pareil avec le champ ParentKcb :

kd> dt nt!_CM_KEY_CONTROL_BLOCK 0xe101a648
   +0x000 RefCount         : 0x60
   +0x004 ExtFlags         : 0y00000000 (0)
   +0x004 PrivateAlloc     : 0y1
   +0x004 Delete           : 0y0
   +0x004 DelayedCloseIndex : 0y100000000000 (0x800)
   +0x004 TotalLevels      : 0y0000000100 (0x4)
   +0x008 KeyHash          : _CM_KEY_HASH
   +0x008 ConvKey          : 0xdf3378bb
   +0x00c NextHash         : (null) 
   +0x010 KeyHive          : 0xe1338008 _HHIVE
   +0x014 KeyCell          : 0x6771c0
   +0x018 ParentKcb        : 0xe101aa08 _CM_KEY_CONTROL_BLOCK
   +0x01c NameBlock        : 0xe147c988 _CM_NAME_CONTROL_BLOCK
   +0x020 CachedSecurity   : 0xe13583e8 _CM_KEY_SECURITY_CACHE
   +0x024 ValueCache       : _CACHED_CHILD_LIST
   +0x02c IndexHint        : 0x0000005f _CM_INDEX_HINT_BLOCK
   +0x02c HashKey          : 0x5f
   +0x02c SubKeyCount      : 0x5f
   +0x030 KeyBodyListHead  : _LIST_ENTRY [ 0xe101a678 - 0xe101a678 ]
   +0x030 FreeListEntry    : _LIST_ENTRY [ 0xe101a678 - 0xe101a678 ]
   +0x038 KcbLastWriteTime : _LARGE_INTEGER 0x1c7cd6d`b11231e0
   +0x040 KcbMaxNameLen    : 0x38
   +0x042 KcbMaxValueNameLen : 0
   +0x044 KcbMaxValueDataLen : 0
   +0x048 KcbUserFlags     : 0y0000
   +0x048 KcbVirtControlFlags : 0y0000
   +0x048 KcbDebug         : 0y00000000 (0)
   +0x048 Flags            : 0y0000000000100000 (0x20)
   
kd> dt nt!_CM_NAME_CONTROL_BLOCK 0xe147c988
   +0x000 Compressed       : 0x1 ''
   +0x002 RefCount         : 6
   +0x004 NameHash         : _CM_NAME_HASH
   +0x004 ConvKey          : 0x7f00cd26
   +0x008 NextHash         : (null) 
   +0x00c NameLength       : 9
   +0x00e Name             : [1] 0x494d
   
kd> db 0xe147c988+e l 9
e147c996  4d 49 43 52 4f 53 4f 46-54 MICROSOFT

Par la suite CmEnumerateKey appelle HvpGetCellMapped, son prototype est :

struct _CELL_DATA *
HvpGetCellMapped(
    PHHIVE      Hive,
    HCELL_INDEX Cell
    )

Le premier paramètre est donné par CmEnumerateKey en lisant le membre KeyHive à l’offset 0×10 de la structure CM_KEY_CONTROL_BLOCK. Le second paramètre est passé par CmEnumerateKey en prennant le champ KeyCell.

kd> dt nt!_HHIVE 0xe1338008
   +0x000 Signature        : 0xbee0bee0
   +0x004 GetCellRoutine   : 0x8056e48b     _CELL_DATA*  nt!HvpGetCellMapped+0
   +0x008 ReleaseCellRoutine : 0x8056e5c3     void  nt!HvpReleaseCellMapped+0
   +0x00c Allocate         : 0x8058c2f0     void*  nt!CmpAllocate+0
   +0x010 Free             : 0x8058c337     void  nt!CmpFree+0
   +0x014 FileSetSize      : 0x8058ce45     unsigned char  nt!CmpFileSetSize+0
   +0x018 FileWrite        : 0x80594fac     unsigned char  nt!CmpFileWrite+0
   +0x01c FileRead         : 0x805acd92     unsigned char  nt!CmpFileRead+0
   +0x020 FileFlush        : 0x80594e9e     unsigned char  nt!CmpFileFlush+0
   +0x024 BaseBlock        : 0xe1339000 _HBASE_BLOCK
   +0x028 DirtyVector      : _RTL_BITMAP
   +0x030 DirtyCount       : 0
   +0x034 DirtyAlloc       : 0x94c
   +0x038 RealWrites       : 0x1 ''
   +0x03c Cluster          : 1
   +0x040 Flat             : 0 ''
   +0x041 ReadOnly         : 0 ''
   +0x042 Log              : 0x1 ''
   +0x044 HiveFlags        : 0
   +0x048 LogSize          : 0x400
   +0x04c RefreshCount     : 0
   +0x050 StorageTypeCount : 2
   +0x054 Version          : 5
   +0x058 Storage          : [2] _DUAL

La fonction HvpGetCellMapped renvoie une des structures faisant partie de l’union suivante :

typedef struct _CELL_DATA {
    union _u {
        CM_KEY_NODE      KeyNode;
        CM_KEY_VALUE     KeyValue;
        CM_KEY_SECURITY  KeySecurity;    // Variable security descriptor length
        CM_KEY_INDEX     KeyIndex;       // Variable sized structure
        CM_BIG_DATA      ValueData;      // This is only for big cells; a list of cells
                                         // all of the length CM_KEY_VALUE_BIG
        HCELL_INDEX      KeyList[1];     // Variable sized array
        WCHAR            KeyString[1];   // Variable sized array
    } u;
} CELL_DATA, *PCELL_DATA;

Dans mon cas, HvpGetCellMapped me renvoie une structure CM_KEY_NODE, indiquant que nous avons une SubKey :

kd> gu
nt!CmEnumerateKey+0x65:
8056f016 85c0            test    eax,eax
kd> dt nt!_CM_KEY_NODE @eax
   +0x000 Signature        : 0x6b6e
   +0x002 Flags            : 0x20
   +0x004 LastWriteTime    : _LARGE_INTEGER 0x1c7674e`b60b8700
   +0x00c Spare            : 0
   +0x010 Parent           : 0x6771c0
   +0x014 SubKeyCounts     : [2] 1
   +0x01c SubKeyLists      : [2] 0x6aba18
   +0x024 ValueList        : _CHILD_LIST
   +0x01c ChildHiveReference : _CM_KEY_REFERENCE
   +0x02c Security         : 0x210
   +0x030 Class            : 0xffffffff
   +0x034 MaxNameLen       : 0y0000000000000110 (0x6)
   +0x034 UserFlags        : 0y0000
   +0x034 VirtControlFlags : 0y0000
   +0x034 Debug            : 0y00000000 (0)
   +0x038 MaxClassLen      : 0
   +0x03c MaxValueNameLen  : 0
   +0x040 MaxValueDataLen  : 0
   +0x044 WorkVar          : 0
   +0x048 NameLength       : 8
   +0x04a ClassLength      : 0
   +0x04c Name             : [1] 0x5448
kd> db @eax+4C l 8
c5e6cd38  48 54 4d 4c 48 65 6c 70                          HTMLHelp

Si on regarde le disass de CmEnumerateKey on s’aperçoit quelle appel HvpGetCellMapped en lisant le champ GetCellRoutine de la structure HHIVE passée en argument. Alors pensons un peu, connaissant le prototype de HvpGetCellMapped, si on trouve une méthode nous permettant de récupèrer une structure HHIVE et modifier le pointeur de fonction GetCellRoutine par une fonction filtrant le retour de HvpGetCellMapped, il devrait être possible de renvoyé une valeur disant qu’une SubKey précise n’a pas été trouvé.

Alors, le hook va se dérouler de cette manière :
On ouvre un handle avec ZwOpenKey sur la Key qu’on veut cachée, puis un ObRefenceObjectByHandle pour retrouver l’objet référé par le handle qui est de type CM_KEY_BODY.

kd> dt nt!_CM_KEY_BODY
   +0x000 Type             : Uint4B
   +0x004 KeyControlBlock  : Ptr32 _CM_KEY_CONTROL_BLOCK
   +0x008 NotifyBlock      : Ptr32 _CM_NOTIFY_BLOCK
   +0x00c ProcessID        : Ptr32 Void
   +0x010 Callers          : Uint4B
   +0x014 CallerAddress    : [10] Ptr32 Void
   +0x03c KeyBodyList      : _LIST_ENTRY

A partir de la structure CM_KEY_BODY on peut retrouver le CM_KEY_CONTROL_BLOCK qui contient un pointeur sur la structure _HHIVE. De là on sauvegarde l’adresse et la valeur de la fonction HvpGetCellMapped et on l’a remplace par la notre qui va toujours faire appel à HvpGetCellMapped mais dont on pourra modifier le retour.

Ensuite sachant que l’on veut caché une Key, la valeur renvoyé par HvpGetCellMapped sera un pointeur sur une structure CM_KEY_NODE, ce pointeur aura été obtenu précédemment par un appel avec HvpReleaseCellMapped sur le HHIVE et le KeyCell qu’on vise. Lorsque notre fonction qui Hook HvpGetCellMapped, on va donc comparer le pointeur retourné à celui de notre Key, si ils ont égaux alors on va chialer :)

En effet, si jamais notre fonction qui hook HvpGetCellMapped renvoie NULL, CmEnumerateKey considère que la liste des SubKey est finie, l’idée consiste à renvoyé à la place de notre Subkey la dernière SubKey de la liste, le truc cool c’est qu’au départ je croyais que celait allait briser l’affichage par ordre alphabétique des Subkey mais il n’en n’est rien !

Pour récupérer la dernière SubKey, on va lire le champ Parent de notre KeyNode actuel :

kd> dt nt!_CM_KEY_NODE 0xca7c86d4
   +0x000 Signature        : 0x6b6e
   +0x002 Flags            : 0x20
   +0x004 LastWriteTime    : _LARGE_INTEGER 0x1c7cef7`f0e79ff0
   +0x00c Spare            : 0
   +0x010 Parent           : 0x1b8
   +0x014 SubKeyCounts     : [2] 0x112
   +0x01c SubKeyLists      : [2] 0xdc020
   +0x024 ValueList        : _CHILD_LIST
   +0x01c ChildHiveReference : _CM_KEY_REFERENCE
   +0x02c Security         : 0x218
   +0x030 Class            : 0xffffffff
   +0x034 MaxNameLen       : 0y0000000001001100 (0x4c)
   +0x034 UserFlags        : 0y0000
   +0x034 VirtControlFlags : 0y0000
   +0x034 Debug            : 0y00000000 (0)
   +0x038 MaxClassLen      : 0xa
   +0x03c MaxValueNameLen  : 0
   +0x040 MaxValueDataLen  : 0
   +0x044 WorkVar          : 3
   +0x048 NameLength       : 8
   +0x04a ClassLength      : 0
   +0x04c Name             : [1] 0x6553

Ici le nom du KeyNode est celui de : HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services 
kd> db 0xca7c86d4+4C l 8
ca7c8720  53 65 72 76 69 63 65 73                          Services

Le parent KeyNode contient un HCELL_INDEX indiquant une structure appelé CM_KEY_INDEX. Cette structure est définie par :

typedef struct _CM_KEY_INDEX {
    USHORT      Signature;              // also type selector
    USHORT      Count;
    HCELL_INDEX List[1];                // Variable sized array
} CM_KEY_INDEX, *PCM_KEY_INDEX;

Elle contient une liste de HCELL_INDEX de taille Count, qui est tout simplement un tableau permettant de retrouver les SubKeys.

kd> !reg cellindex 0xe101b008 0xdc020

Map = e101e000 Type = 0 Table = 0 Block = dc Offset = 20
MapTable     = e101f000 
BlockAddress = ca81d000 

pcell:  ca81d024
kd> dt nt!_CM_KEY_INDEX ca81d024
   +0x000 Signature        : 0x686c ;=CM_KEY_FAST_LEAF 
   +0x002 Count            : 0x112
   +0x004 List             : [1] 0x20d560

kd> dd ca81d024+4 l 20
ca81d028  0020d560 1c17bbb0 0019a3e0 5aca60b7
ca81d038  00087728 56e32bd0 00087858 70b87c26
ca81d048  00087a98 0033af41 00087ce0 14643cd5
ca81d058  00087e08 a63ea796 00088080 000165fb
ca81d068  00088468 056776b8 000886e0 09c77b47
ca81d078  00088948 09c77bdc 00088b80 167c6f83
ca81d088  00089378 000166dc 00089810 15603420
ca81d098  00088828 15848934 00089bb8 283b4b86

Si je dump, la première entrée :

   
kd> !reg cellindex 0xe101b008 0x20d560

Map = e101e000 Type = 0 Table = 1 Block = d Offset = 560
MapTable     = e1021000 
BlockAddress = ca94e000 

pcell:  ca94e564

kd> dt nt!_CM_KEY_NODE ca94e564
   +0x000 Signature        : 0x6b6e 
   +0x002 Flags            : 0x20
   +0x004 LastWriteTime    : _LARGE_INTEGER 0x1c7cef5`53bac860
   +0x00c Spare            : 0
   +0x010 Parent           : 0x876d0
   +0x014 SubKeyCounts     : [2] 1
   +0x01c SubKeyLists      : [2] 0x20d5c0
   +0x024 ValueList        : _CHILD_LIST
   +0x01c ChildHiveReference : _CM_KEY_REFERENCE
   +0x02c Security         : 0x218
   +0x030 Class            : 0xffffffff
   +0x034 MaxNameLen       : 0y0000000000010000 (0x10)
   +0x034 UserFlags        : 0y0000
   +0x034 VirtControlFlags : 0y0000
   +0x034 Debug            : 0y00000000 (0)
   +0x038 MaxClassLen      : 0
   +0x03c MaxValueNameLen  : 0x18
   +0x040 MaxValueDataLen  : 0x54
   +0x044 WorkVar          : 0
   +0x048 NameLength       : 0xf
   +0x04a ClassLength      : 0
   +0x04c Name             : [1] 0x2d31
kd> db ca94e564+4C l f
ca94e5b0  31 2d 64 72 69 76 65 72-2d 76 6d 73 72 76 63     1-driver-vmsrvc

Je tombe bien sur la première SubKey de HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services. Il faut savoir qu’on peut tomber sur 2 types de listes d’index. Soit sur un tableau de CM_INDEX (le CM_KEY_INDEX est alors un structure CM_KEY_FAST_INDEX) dont chaque élément fait 8 bytes, ou un tableau de HCELL_INDEX de 4 bytes chacun (CM_KEY_INDEX est une structure « normale »). Pour être plus clair :

typedef ULONG HCELL_INDEX;
typedef HCELL_INDEX *PHCELL_INDEX;

typedef struct _CM_INDEX {
    HCELL_INDEX Cell;
    union {
        UCHAR       NameHint[4];    // upcased first four chars of name 
        ULONG       HashKey;        // hash key of name
    };
} CM_INDEX, *PCM_INDEX;

typedef struct _CM_KEY_FAST_INDEX {
    USHORT      Signature;              // also type selector
    USHORT      Count;
    CM_INDEX    List[1];                // Variable sized array
} CM_KEY_FAST_INDEX, *PCM_KEY_FAST_INDEX;

typedef struct _CM_KEY_INDEX {
    USHORT      Signature;              // also type selector
    USHORT      Count;
    HCELL_INDEX List[1];                // Variable sized array
} CM_KEY_INDEX, *PCM_KEY_INDEX;

Dans le dump de la CM_KEY_INDEX je suis tombé sur une structure CM_KEY_FAST_INDEX, donc ma liste contient un HCELL_INDEX suivit d’un Hash. Pour déterminer le type de liste qu’on trouve, il suffit de regarder le champ signature qui peut prendre les valeurs :

Listes de 4 bytes 
#define CM_KEY_INDEX_ROOT       0x6972      // ir
#define CM_KEY_INDEX_LEAF       0x696c      // il

Listes de 8 bytes 
#define CM_KEY_FAST_LEAF        0x666c      // fl
#define CM_KEY_HASH_LEAF        0x686c      // hl

Bref, quand HvpGetCellMapped va renvoyé le pointeur sur la CM_KEY_NODE qu’on veut hider, on va aller lire le ParentNode pour obtenir la dernière SubKey de la liste et la renvoyé à la place. Plus tard lorsque la fonction HvpGetCellMapped nous renvoie le LastKeyNode alors on renvoie NULL à la place (pour retomber sur nos pattes).

Finalement ce qu’il faut retenir c’est qu’il est possible de modifier la fonction énumérant les SubKeys d’un Key. L’avantage c’est qu’on n’effectue aucun hookind d’image de binaire mappé mais du KOH (Kernel Object Hooking) sur la structure HHIVE. Grâce à cela, on a une technique permettant de cacher une Key plus difficile à detecter car celles d’avant consistaient à hooker les différentes API natives.

Voici un POC qui cache la clé HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDIS

http://ivanlef0u.fr/repo/HideKey.rar

FEARZ DAZ CH1NEZZE L33STZ SCKIL2Z :(

Ref:
http://en.wikipedia.org/wiki/Windows_Registry
http://book.itzero.com/read/microsoft/0507/Microsoft.Press.Microsoft.Windows.Internals.Fourth.Edition.Dec.2004.internal.eBook-DDU_html/0735619174/ch04lev1sec1.html

4 comments juillet 25th, 2007


Calendar

juillet 2007
L Ma Me J V S D
« juin   août »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Posts by Month

Posts by Category