Affichage des articles dont le libellé est hook. Afficher tous les articles
Affichage des articles dont le libellé est hook. Afficher tous les articles

mardi 19 mai 2009

Understand phook's internals.

Je me décide finalement à publier un petit quelque chose, malgré tous le taff que les études peuvent me demander en ce moment :).

Entrons dans le vif du sujet, "phook" est le nom donné à un PoC réalisé par Shearer and Dreg concernant une technique de hook peu commune, je dirais même nouvelle.
Un paper à d'ailleurs été publié dans la dernière issues de phrack (65).
Après sa lecture, la mise en place de la technique reste assez floue, je decide donc de partager mon PoC (même pas complet !) ; celui-ci m'a permis de me rendre compte qu'au final la technique est loin d'être parfaite et imprenable.

Pour situer le sujet, les auteurs nous propose de combiner de "l'iat patching", avec leur nouvel technique donc, pour nous assurer un total contrôle des apis.
La nouveauté dans tout cela, c'est qu'avec une simple modification de la table des importations d'un binaire, nous allons contrôler seulement les appels "statiques", ceux qui ne seront pas résolus dynamiquement.
En effet, si dans le cadre d'un hook d'iat nous retrouvons nos fonctions dynamiquement en utilisant GetModuleHandle et GetProcAddress et bien la technique devient inutile.

Nos deux compères nous proposent alors un périple dans le PEB, pour être plus précis, ils nous proposent de falsifier les champs DllBase, EntryPoint et SizeOfImage des structures LDR_DATA_TABLE_ENTRY pointé par chaque entrée de la liste doublement chainée PEB.Ldr.InLoadOrderModuleList.
Voici sa structure :

lkd> dt nt!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void

Pour rappel, cette liste stocke les modules chargés par un binaire dans l'ordre de chargement en mémoire, on est donc censé trouvé en premier lieu ntdll.dll bien sur suivit de kernel32.dll etc :

kd> !process 0 0 calc.exe
PROCESS 814ad740 SessionId: 0 Cid: 01a4 Peb: 7ffdb000 ParentCid: 05bc
DirBase: 0d88d000 ObjectTable: e15ccbc0 HandleCount: 37.
Image: calc.exe

kd> .process 814ad740
Implicit process is now 814ad740
WARNING: .cache forcedecodeuser is not enabled
kd> !peb
PEB at 7ffdb000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: No
ImageBaseAddress: 01000000
Ldr 001a1e90
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 001a1f28 . 001a2d18
Ldr.InLoadOrderModuleList: 001a1ec0 . 001a2d08
Ldr.InMemoryOrderModuleList: 001a1ec8 . 001a2d10
Base TimeStamp Module
1000000 3b7d8410 Aug 17 22:52:32 2001 C:\WINDOWS\system32\calc.exe
7c910000 4125331a Aug 20 01:09:14 2004 C:\WINDOWS\system32\ntdll.dll
7c800000 4623a01c Apr 16 18:11:08 2007 C:\WINDOWS\system32\kernel32.dll
7c9d0000 4125330f Aug 20 01:09:03 2004 C:\WINDOWS\system32\SHELL32.dll
77be0000 45d97cd4 Feb 19 11:32:52 2007 C:\WINDOWS\system32\msvcrt.dll
77ef0000 45f030c5 Mar 08 16:50:29 2007 C:\WINDOWS\system32\GDI32.dll
7e390000 45f030c6 Mar 08 16:50:30 2007 C:\WINDOWS\system32\USER32.dll
77da0000 412532e8 Aug 20 01:08:24 2004 C:\WINDOWS\system32\ADVAPI32.dll
[...]

Pour comprendre le principe même de la technique, il faut savoir que l'api GetModuleHandle par exemple, va parser cette liste afin de récupérer l'image base d'une dll par exemple.
Imaginer que l'on echange le champs DllBase de la dll kernel32.dll, avec une dll factice ; et bien un GetModuleHandle("kernel32.dll") nous renverrais l'image base de notre dll factice !
C'est en fait le coeur de la technique, car celle-ci nécessite quelques pré-requis pour sa mise en place.

Notre dll devra donc répondre à quelques exigences, en effet elle devra exporter le même nombre de fonctions que la dll original, avec les mêmes noms de fonctions, ainsi que les mêmes ordinaux.
Le premier problème auquel on est confronté, c'est alors de créer une dll qui exporte les mêmes noms de fonctions que kernel32.dll par exemple, en effet si l'on veut créer une exportation pour GetModuleHandle (par exemple), et bien, bien sur le compilateur nous crie dessus étant donné que cette fonction est déjà définie/déclarée dans les headers windows.

Nos amis utilisent alors des fichiers de définitions (.def) à lier au binaire lors de l'édition des liens (avec mingw c'est l'option --def, et avec vc c'est /DEF:).
Par exemple, pour exporter GetModuleHandleA, nous définirons/déclarerons la fonction comme suit :

DLLEXPORT void GetModuleHandleA_()
{
//do the stuff
}


Et notre fichier de définitions sera comme cela :

LIBRARY kernel32
EXPORTS

GetModuleHandleA=GetModuleHandleA_ @ 29


Ou 29 est l'ordinal d'exportation !

Vous devez commencer à comprendre que notre dll, va être ni plus ni moins qu'une espèce de proxy entre le binaire, et la véritable dll ; cependant si l'appel nous intéresse nous le ré-définirons à notre guise, et nous appellerons l'api originel, à la manière d'un hook donc.

Le second problème, est alors de retrouver l'adresse de cette api originel, pour cela nous utiliserons une macro qui grosso-modo réalisera :

GetProcAddress(GetModuleHandleA("kernel32_.dll"), "NotreApi")

Ou kernel32_.dll est le nom de NOTRE dll, car si vous reflechissez 30 secondes, une fois que le PEB hook aura été réalisé, et bien les images bases auront été echangées ; or il nous faut récupérer l'image base de la véritable dll, ce qui sera donc obtenu avec GetModuleHandleA("Kernel32_.dll") .
La macro proposée par les auteurs est la suivante :

unsigned long tmp;

#define JMP( lib, func ) \
__asm \
( "pushad \n" \
" push edx \n" \
" push %1 \n" \
" call eax \n" \
" pop edx \n" \
" push %2 \n" \
" push eax \n" \
" call edx \n" \
" mov %4, eax \n" \
" popad \n" \
\
: : \
"a" (GetModuleHandle) , \
"g" (lib) , \
"g" (func) , \
"d" (GetProcAddress) , \
"g" (tmp) \
); \
asm ( "jmp %0" : : "g" (tmp) );


Je vous l'accorde ça pique les yeux, c'est très moche, mais ça compile avec mingw (avec l'option de compilation -masm=intel) c'est pour cela que je n'ai pas transposé cette macro à coup de _asm compilable seulement avec vcpp.
La macro réalise donc une sauvegarde des registres avec un pushad/popad afin de préserver l'environnement dont nécessite l'api, nous stockons l'adresse de la véritable api dans une variable, et enfin nous sautons sur l'api.

Cette dernière étape soulève un problème un peu plus important, celui-ci se situe au niveau de la pile et donc des arguments.
Il faut être, dans ce code, capable de fournir une pile propre, et utilisable par l'api et cela sans passer par un prototype spécifique ; en effet toutes les fonctions qui nous intéresserons pas, leurs prototypes seront :

void MaFonction_();

En tant normal, une tel fonction n'est pas censé recevoir de paramètre, cependant une option nous permet de réaliser cela, et donc de trouver une solution à notre problème : il faut compiler avec l'option -fomit-frame-pointer.
C'est en fait, le problème le plus délicat à résoudre dans ce projet, je ne sais pas si il est d'ailleurs possible de procéder autrement, j'ai simplement suivie la technique proposé par nos hookeurs de peb.
J'ai d'ailleurs tenté de compiler le code sans spécifiée l'option, et il semblerait que le tout fonctionne toujours..si quelqu'un peut m'éclairer à ce niveau là :].

Bon, une fois réalisé tout cela, nous obtenons un contrôle sur la résolution dynamique des apis ; si nous voulons obtenir un contrôle total, il faut mettre en place une reconstruction de la table d'importation du binaire, afin de faire pointer les importations de kernel32.dll vers NOTRE dll.

Et enfin, il faut aussi reconstruire les tables des importations des autres modules que notre binaire utilisent, à condition que ceux ci importent des fonctions de kernel32.dll ; tous cela dans le but de les rediriger vers NOTRE dll ! Et dans ce cas là, nous avons le contrôle sur tous les appels fait sur les apis de kernel32.dll.

Maintenant, il reste deux/trois détails à résoudre, en effet si l'on veut pouvoir intercepter tous les appels de fonctions en destination de kernel32.dll, nous devons créer le processus dans un état suspendu, à ce moment là on peut enfiler notre casquette "trappeur de PEB" et corrompre les différents champs.
C'est pour moi le point faible de la technique, en effet il faut pouvoir créer le processus pour pouvoir mettre en place correctement l'attaque.

A présent parlons implémentation, dreg & shearer ont choisis d'injecter un code qui va charger la dll (celle qui va mettre en place le peb hook et la reconstructions des imports), leurs code est plutôt original, il injecte en mémoire une structure formé des opcodes nécessaire au chargement de la dll ; les opcodes sont forgés à la volée : funny :)).

Pour ma part, j'ai tout simplement choisis de créer un thread distant sur la fonction LoadLibraryA afin de chargé ma dll.
Celle-ci se chargera de mettre en place le peb hook, et la reconstructions des importations du binaire, par manque d'envie je n'ai pas codé la reconstructions successive des IATs des différents modules chargés par le binaire.

Concernant leurs PoC, après l'avoir testé il semble défectueux chez moi.
En effet, au lieu d'injecter une dll réalisant le peb hook et le patch des imports, ils ont décidés d'interfacer la mise en place de l'attaque par le biais d'une espece de console.
Vous êtes alors contraint de vous connectez à une socket, on vous propose alors un menu (n'utilisez pas putty :p) ..enfin bon je trouve que le poc est entouré de fonction qui n'apporte pas de réel plus value au projet !

Dans la suite d'outil qu'ils nous proposent on trouve, bien sur,un générateur de code, celui-ci est capable de nous générer le code d'une dll avec les mêmes exportations etc ; celui-ci étant codé en C, j'ai décidé de me coder un petit script python (mon premier !:]]) avec le module pefile.
Cela m'a permis d'appréhender python pour finalement lacher le perl !
Je pense en effet qu'il est plus judicieux d'utilisé un language de script pour réaliser une tache de ce genre !

En lançant mon implémentation, si tout ce passe correctement, vous devriez obtenir un dump du genre :

[3876] [ PebPwnDll implémentation par 0vercl0k, idée original de Shearer & Dreg ].
[3876] [DBG] RtlGetCurrentPeb : 0x7c970e89.
[3876] [DBG] PEB en : 0x7ffdf000.
[3876] [DBG] PEB_LDR_DATA en : 0x361e90.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 361ec0.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 361f18.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 361fc0.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 362060.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 362100.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 3622d0.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 362328.
[3876] [DBG] LDR_DATA_TABLE_ENTRY : 3623c8.
[3876]
[3876] [DBG] LDR_DATA_ENTRY_TABLE de la dll hook : 0x3622d0.
[3876] ImageBase : 0x623c0000
[3876] EntryPoint : 0x623c1000
[3876] SizeOfImage : 0x9f000
[3876]
[3876] [DBG] LDR_DATA_ENTRY_TABLE de la dll hooké : 0x361fc0.
[3876] ImageBase : 0x7c800000
[3876] EntryPoint : 0x7c80b5be
[3876] SizeOfImage : 0x105000
[3876]
[3876] [DBG] Kernel32.dll en 0x623c0000.
[3876] [DBG] Eat dumped !
[3876] [DBG] Patch de l'iat du binaire..
[3876] [DBG] Patch de l'iat du binaire, concernant la dll 'kernel32.dll'.
[3876] [DBG] Patch du binaire terminé.
[3876] [DBG] Attaque complète.


Pour tester la mise en place de la technique, j'ai tout simplement rajouter une MessageBox lors d'un appel à l'api Beep().
Si vous voulez tracer le binaire pour constater le fonctionnement, j'ai glissé une int 3, il vous suffit donc de définir OllyDbg comme JIT debugger.


Maintenant, on peut s'interroger si la technique est utilisable dans le cadre d'un malware..j'aurais tendance à dire oui bien sur, seulement un peb hook reste très simple à détecter : il suffit de constater les champs DllBase/EntryPoint/SizeOfImage en mémoire, et ceux du binaire en dur. On se rend vite compte que sa mise en place est aussi contraignante, car beaucoup d'actions sont réalisées, et que plus il y a d'actions à réalisées, plus il y a de chances pour que l'attaque tombe à l'eau (si l'une d'entres elles echoue, c'est la technique entière qui se voit tomber en miettes).

Cependant, une technique de ce type peut-être intéressante pour virtualiser certaines apis (les auteurs en parlent en fin de leur article) ou encore pour réaliser un traceur d'api ; c'est peut-être un peu lourd je vous l'accorde.
Enfin bref, c'est vraiment un article que j'ai A.D.O.R.E, jouer comme cela avec des structures accessible en userland c'est vraiment des techniques que je kiffe :).

Il est temps de lacher les sources, pour cette fois je vous fait une archive contenant source et binaire :

UnderstandPhooksInternals.zip

Sinan voici quelques liens en vrac :
Voilà, j'en ai finis pour aujourd'hui, en espérant que ça vous aura plu ;).


dimanche 28 septembre 2008

L'union fait la force.

Me revoilà pour un nouveau post, (un peu tardif me direz vous, mais bon pas toujours facile avec les cours) mais cette fois-ci c'est un peu spécial.
En effet, lilxam et moi même vous proposons aujourd'hui une archive liant deux papers écrit en "collaboration".
Un gros travail d'entraide à été mis en place sur cette série de papers, une expérience à renouveler je pense car très efficace.
Tout cela pour dire que l'on sera surement amené à renouvelé ce type d'opération, hein lilxam :)?

Entrons dans le vif du sujet.

L'archive est composé d'un premier paper signé lilxam traitant des débordements de tampons appliqué et exploité sur php 5.x.
L'approche est vraiment intéréssante car mon chère collègue à due mener de nombreuses recherches sur l'organisation, l'appel des fonctions au seins de php.exe.
Une fois cette étape de franchis, il entamme la recherche de fonctions faillibles en codant un fuzzer like maison qui m'a foi à porté ces fruits :).
Non loin d'une dizaine de fonction faillible sur la version 5.2.6, l'exploitation rentre donc maintenant en jeux.
La technique utilisé est une réécriture de SEH (Structured Exception Handling), afin de rediriger le flot d'éxecution de php sur un vilain shellcode :).
Voilà en gros le fil rouge du paper, le tout est bien sûr agrementé de schéma/screenshots/codes et d'explications :).

Avec le second paper on change complétement de sujet ; je présente en premier temps les TLS CallBacks, puis l'HotPatching, et enfin une à deux petites applications liant les deux "outils" vu precedemment.Rien de bien méchant en tout cas, un contenus très soft :).
J'ai mis à disposition dans l'archive l'éboche, la tentative de rédaction d'une classe cpp (et oui, je m'y mets!) permettant l'implémentation d'une tls callback..la classe est vraiment très simple et peu fiable je pense cependant elle m'aura permis d'allonger du code pour me faire la main avec ce language.

Je vous laisse en compagnie de nos écris :
-L'Union Fait la Force.zip.

En espérant que ça plaira bonne après midi :).

samedi 29 mars 2008

ph03nix et l'object manager.

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 :


  • Open qui est appelé lors de la création/ouverture/copie d'un handle.

  • Close qui est appelé lors de la fermeture d'un handle.

  • Delete qui est appelé lors de la suppression d'un object pour le déréférencer.


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.

samedi 17 novembre 2007

API Hooking - IAT patching

Bonjour à tous ,
Aujourd'hui je vais essayer de vous présenter l'api hooking via l'iat patching.
En effet notre but lors de ce petit billet sera de détourner l'appel d'apis.
J'illustrerais avec un petit exemple de hooking sur le notepad.exe , cependant vous pourriez , après avoir compris le principe , laisser cours à votre imagination afin de creer de multiples attaques.
Cette démonstration de hook sera réalisé dans l'userland (ring3).

Tout d'abord je vais vous exposer ma façon d'opérer :
- Nous allons coder un programme chargé d'injecter notre dll dans le processus cible ( voir billet sur l'injection ).
- Ensuite nous allons coder une dll qui ira modifier directement l'iat du processus cible ( voir billet sur le dump de l'iat ).

Voilà donc les grandes étapes :
- On retrouve le pid de notre processus.
- Nous ouvrons notre processus afin d'avoir un handle sur celui-ci , avec l'api OpenProcess.
- On alloue de la mémoire dans le processus cible , on y écrira le full path de notre dll.
- Nous créons un thread dans le processus sur l'adresse de LoadLibraryA ( exporté par kernel32.dll ) avec comme arguement le path de la dll donc .
- A présent notre dll est loadé par l'application cible.
- Notre dll dès son chargement va aller modifier l'adresse de la fonction à hooker par l'adresse de notre fonction dans l'iat.

L'application à chaque appel de l'api hooké appelera enfaite notre fonction , c'est pour cela qu'elle doit posséder le même prototype que la fonction hooké.
Je tiens aussi à préciser , que la modification de l'iat ne peut se faire qu'après un appel à l'api VirtualProtect.Et ce pour changer l'acces à la zone mémoire , après la modification
nous rétablissons l'accès originel de la zone mémoire.

Voici donc les illustrations :
Tout d'abord l'injecteur : InjecteurDll.
La dll pour hooker le ShellAbout de notepad.exe : HookShellAboutW.dll.
Un petit screenshot pour les plus fainéants :




Puis pour terminé j'ai voulu faire un exemple un peu plus concret mais qui reste très simple.
Imaginons le code d'une petite application permettant de lister les fichiers et dossiers dans le current directory.
Notre but serait de cacher un fichier .
Voici les codes : - HookFindNextFirstFile.dll.
- cible.exe.

Et un petit screnshot :



J'essairais plus tard de coder un petit rootkit userland prenant le contrôle de l'userland par le biais de hook justement.
Sur ce bonne fin de journée , cya.