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

mercredi 24 décembre 2008

H-CL vous souhaite un joyeux noël !

Un revenant ? Et oui me revoilà back from h3ll après quelques semaines d'inactivités.
Je vais profiter de ce petit article, pour vous racontez mes péripéties. Mais celles-ci ne se déroulent non pas dans les contrées rocheuses avoisinant mon chère kernel, mais belle et bien In Real Life.

Il y a quelques semaines de cela, mon laptop a subit une terrible perte ; un petit texte pour vous contez ces aventures.
Ma maudite machine plutôt jeune et jusqu'à présent assez performante me laissa tomber : un beau matin en l'allumant, j'entends alors de vieux bips systèmes..après quelques recherches de faite il s'avère que c'est ma motherboard :(.

Me voilà face au gouffre, le ciel prêt à s'écraser sur ma tête : obliger de renvoyer la bestiole au sav.

Jusqu'à présent rien de bien grave..
L'unique problème c'est que bien sur je n'ai aucun backup..AUCUN .
Mes neurones en ébullition se rassemblent dans l'espoir de trouver une solution me permettant de sauvegarder mon disque dur..Mais rien ! Si je tente toutes bidouilles avec le disque dur interne du laptop, la garantie saute.

Après un petit coup de fil avec le réparateur, il me propose de sauvegarder un dossier

"Quel dossier je vous sauvegarde monsieur ?"
"Humm, le dossier C:\kernel s'il vous plait !"
"heu..il n'y a pas de dossier kernel"
"le dossier k3rn3l !"

Encore un technicien ignorant le 1337 sp34k1ng.

Mais aujourd'hui je reviens, avec des (merci hzv <3) laptops tout propre, ready, avec backup :] (merci ivan:p).

C'est donc en ce soir de nowel, que je vous propose le début d'un projet qui me tiens plutôt à cœur car à mon avis plus qu'utile.

L'idée n'a rien de transcendante, c'est en fait une espèce de librairie.
Un header contenant quelques fonctions useful quand on aime bien trifouiller son kernel.

L'originalité du projet, je pense, est le fait que tout est réunis dans UN unique fichier : personnellement je trouve que ça simplifie grandement les choses quant à l'utilisation.

Concernant l'avancement du projet ; c'est encore au stade embryonnaire à peine 5 fonctions pour le moment.

Disons que, ça intéressera surement quelques personnes : d'ailleurs si certains on des reports de bugs, ou autres n'hésitez pas à me laisser un commentaire ; j'aimerais bien faire un truc propre et pourquoi pas utilisé ?
Tant que j'y pense, si vous avez des idées de fonctions à implémenter n'hésitez pas encore une fois à laisser un petit mot ; merci :)).

Je vais donc bien sur continuer à poster régulièrement maintenant que tout est rentré dans l'ordre !
En attendant je vous laisse avec mon .h en espérant que ça servira à quelques mangeur de chips fan de black-métal ; ça serait un bon début :)).

-H-CL.h

En tous cas, joyeux noël à vous, passer de bonnes fêtes :).

jeudi 17 juillet 2008

Sudami KillMe PoC.

Je me permets d'écrire un petit post après la publication du dernier article par mon jedi ; il concerne l'analyse d'un driver tout droit venu de l'orient.
En effet, sudami et son blog avait déjà interpellé notre ami Ivan, il contenait les sources d'un rootkit kerneland assez puissant d'après ce que les sources inspiraient.

Cette fois-ci il s'agit d'un PoC concernant une technique de DKOM afin de rendre un processus interminable ; du jamais vu pour ma part.
C'est pour cela qu'en dévorant ce jolie article, je me suis empressé de coder un PoC.

J'ai donc remarquer que lorsque le PoC était "complet", autrement dit toutes les modifications au niveau des structures étaient effectuées le processus était "inerte".
Interminable certes, mais un processus qui ne peux plus rien faire c'est assez embêtant, voir presque inutile (apart pour embeter la victime avec une fenêtre en plein milieu de l'écran..un peu à la sudami :)).
Celui-ci est disponible en fin de page bien évidemment.

Cependant, le fait que le processus était larvaire après avoir appliqué les manipulations de structures kernel, ivan me proposa de jouer en désactivant quelques "protections" afin d'obtenir un processus assez difficile à tuer mais un processus actif, une technique bien utile vous pouvez me croire dans le cadre d'un quelconque malware.
Pour moi l'implentation plus ou moins idéal reste de modifier le champ KernelApcDisable à l'offset 0x0d4 de la structure ETHREAD.
Concernant de plus amples explications concernant ces APCs kernel je vous suggère une petite lecture de l'analyse d'ivan.

Concernant l'activité que je peux avoir sur mon blog ces temps-ci, autrement dit, une activité assez limitée dirons nous, celle-ci est due à mon engagement dans divers projets qui verront leurs concrétisations dans quelques temps (avant la rentré j'esepère) wait and see .

Sinan en attendant je vous conseil quelques liens :

- #carib0u@irc.worldnet.net déjà :p.
- http://joe-is-a-rocknroll-star.blogspot.com/ -> une personne que j'apprécie beaucoup, des écrits clair toussa, continue :).
- http://md5.sh4ka.fr/ -> un service de très grande qualité codé par un très bon ami concernant la recherche de plaintext MD5 ; celui-ci possède en plus d'opérer à des recherches sur de multiples sites du même genre une base de donnée plutôt bien garnis et qui ne cesse de s'aggrandir !
- http://www.rootkit.com/ -> Faut peut-être pas l'oublier :).


Les PoCs :

- SudamiKillMe.c.
- SudamiKillMe Idéal (?).c.


Voilà pour les nouvelles, si vous trouvez mieux concernant cette technique je suis tout à fait preneur sur ce bonne soirée.

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.

jeudi 21 février 2008

First steps into ring0.

Bonjour à tous,
Je profite de mes petites vacances pour attaquer la programmation de driver.
Cela me trottait dans la tête depuis pas mal de temps enfaite, je vous dévoile alors aujourd'hui mes premier pas dans ce nouveau monde.

Conseils préliminaires :

- Je vous recommande encore une fois, l'utilisation massive de machines virtuels, et de snapshots.
Tout simplement, parce que les Blues Screen Of Death (abrégé BSOD) arrivent très rapidement.

- Ensuite, tout comme dans l'userland (ring3), des outils de debugs sont les bienvenus, je vous conseille donc d'installer les "Debugging Tools for Windows".

- Pour pouvoir mener vos test sur les drivers, je vous recommande "Driver Loader" qui va permettre d'enregistrer votre driver au sein du système.
Vous pouvez ensuite le lancer avec aisance par le biais de la commande "net" :

net start votredriver

Le programme "WinObj" peut aussi vous être utile.

- Et bien sur, le WDK (Windows Driver Kit)!
Cette iso va contenir de la documentation très bien faite, les librairies nécessaires au développement de vos drivers, ..tous ce que vous aurez besoins pour coder vos drivers en tout cas :).
Je cite :

"The Windows Driver Kit (WDK) is a fully integrated driver development system for the Microsoft Windows family of operating systems. It contains the Windows DDK and tests that Microsoft uses to test the stability and reliability of the Windows operating system."
source : http://www.microsoft.com/whdc/devtools/WDK/AboutWDK.mspx.

Voilà tout pour le moment.
Je vous propose à présent, quelques lignes sur la configuration du debuggeur de kernel (kd).


Debug your fucking vm.



Pour pouvoir debugguer vos futurs driver, ou votre kernel, vous avez besoin d'un serveur prêt à être debugguer, ou une machine virtuel.
En ce qui me concerne j'ai choisis la solution machine virtuel, cela est bien plus simple.
Afin de connecter le kd à votre machine virtuel il va falloir tout d'abord ajouter un Port série à votre vm.



On choisit ensuite de faire transiter les données par un named pipe.




On configure la connection de la named pipe avec le port série.




N'oublions pas de cliquer sur le bouton "Advanced" et de cochez "Yield CPU on poll".
Une fois configurer notre port série, on va modifier un petit peu le boot.ini pour que la machine supporte le remote debugging.
Vous ouvrez donc le boot.ini avec notepad++ par exemple, vous copiez collez la ligne dans le [Operating systems] qui existe déjà, vous vous retrouvez avec deux lignes identiques.
Vous rajoutez sur l'une des deux cela :

/debug /debugport=COM1:

Je me retrouve avec un boot.ini qui ressemble à cela :

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe /debug /debugport=COM1:

A présent, on redemare notre vm..et là au boot, nous avons le choix entre un démarrage classsique, et un démarrage avec le debug activé!



Il est temps de sortir WinDbg.
Vous allez dans le menu "File"->"Kernel Debug" et on va le configurer pour que les données entre la vm et le debug transite par le named pipe.




On valide, et Break (CTR+Break), et vous devriez vous retrouvez avec le prompt du kd.




Je vous conseil aussi de télécharger les symbols : http://msdl.microsoft.com/download/symbols.
Ensuite vous vous creez une variable d'environnement qui porte le nom :

_NT_SYMBOL_PATH

et comme valeur :

SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols

Vous êtes donc prêt à debugguer vos drivers !
Ceci dit je vous donne un peu de documentations :

- Si vous voulez connecter virtualpc a windbg -> http://therecyclebin.wordpress.com/2007/06/11/kernel-debugging-windbg-and-virtual-pc/.
- Windbg -> http://software.rkuster.com/.
- WDK -> http://connect.microsoft.com/.

Introduction

"One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them." The Fellowhip of the Ring, J. R. R. TOLKIEN.


Je vais consacrer ces quelques lignes à présenter un peu le ring0.
Comme vous le savez peut être déjà tous, les processeurs mettent à disposition 4 niveaux de privilèges appelés rings (ring0 , .. , ring3).
Le système windows en utilise que deux d'entre eux à savoir :

- L'userland ou le ring3 (abrégé r3).
- Et le kerneland ou le ring0 (abrégé r0).

Le ring0 va permettre la gestion de la mémoire virtuelle par exemple, ou encore la gestion d'un matériel connecté à votre ordinateur ; c'est enfaite le coeur du système.
Comme la citation le laisse entrevoir, dans le ring0 c'est nous le maître :).
En revanche le ring3 est ce qui est le plus classique, les exécutables classiques, notre bon vieux client irc, ou notre player de musique préférée ; ceci dit cette espace est restreint à des règles.




On retrouve souvent le fonctionnement suivant : une application est exécutée depuis l'userland, celle-ci va envoyer des informations à un driver qui lui va pouvoir agir en conséquence, en lui renvoyant si nécessaire des informations de retours.

If faut savoir aussi que la taille des registres de nos processeurs s'élève à 32bits (architecture x86), nous avons donc accès a 2^32 adresses mémoire, soit 4go : 2 pour l'userland (de 0x00000000 à 0xBFFFFFFF) et 2 pour le kerneland (de 0xC0000000 à 0xFFFFFFFF).

A présent notre but va être de coder des programmes capables de survivre dans ce monde où il n'est question que de BSOD (mais nan :)).
On appellera ces programmes des drivers.

Et pourquoi pas arriver vers un rootkit de base commandé de l'userland ? :).
Place au coding à présent.


Message venu du nouveau monde.


Après cette brève introduction au ring0, nous allons pouvoir aborder la programmation de driver.
Le point d'entré d'un driver est celui-ci :

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
}

Avec pDriverObject qui est un pointeur sur une structure du type DRIVER_OBJECT.
Celle-ci représente le driver chargé, et le second argument pRegistryPath est une chaine de caractères UNICODE de la forme suivante :

\Registry\Machine\System\CurrentControlSet\Services\NomDuDriver

Ensuite si vous voulez déchargez un driver, il faut spécifier une fonction d'unload par le biais du membre DriverUnload de la structure DRIVER_OBJECT.

pDriverObject->DriverUnload = VotreFonction;

Et enfin, on utilise l'équivalent de printf() mais au niveau kerneland à savoir : DbgPrint().
Les messages seront bien sur visible grâce à un outil utilisé dans des articles précédents : DebugView.
Ceci nous amène donc à la compilation!

Euh..On compile cela comment?

J'y viens.:)
Tout d'abord j'utiliserais le compilateur disponible avec le wdk, cela évitera de se casser la tête.
Deux fichiers sont nécéssaires à la compilation :

- le makefile.
- et un fichier "sources" (c'est enfaite le nom des fichiers de projets sous le wdk).

Le fichier makefile est composé d'une seule ligne :

!INCLUDE $(NTMAKEENV)\makefile.def

Ensuite le fichier sources est décomposé de la façon suivante :

TARGETNAME = LeNomDuDriver
TARGETPATH = obj
TARGETTYPE = DRIVER

INCLUDES = %BUILD%\inc
LIBS = %BUILD%\lib

SOURCES = VotreSource.c

Nous sommes donc prêt à compiler notre premier driver, émotion au rendez vous !
Nous ouvrons le build environment xp.
On se déplace dans notre dossier contenant les trois fichiers, et on lance la commande build.
Oh..un .sys :), il s'agit de notre driver.

Mais comment le lance t-on?

Patience, nous y voilà.
Dans les premières lignes de ce modeste article, je vous proposais plusieurs outils, dont DriverLoader.
DriverLoader va nous permettre d'enregistrer notre driver, et de pouvoir le lancer.
Nous demarrons DebugView, on lance DriverLoader, et on lance notre driver.



Et voilà, notre helloWorld fonctionne :).
A présent, just for phun, nous allons provoquer un BSOD, histoire d'en réver pendant une semaine.
On va aller écrire n'importe quoi à n'importe qu'elle adresse enfaite :).
Resultat en image :



Enfin bon, a présent passons aux choses sérieuses.


E.T téléphone kernel.


Maintenant notre but va être de faire communiquer une application lancée en ring3 et un driver en ring0.
Nous commencerons par le driver.
Pour mener à bien notre quête, nous allons utiliser les IOCTLs codes et les IRPs.
Mais nous en parlerons un peu plus bas.
Afin de pouvoir communiquer avec l'exterieur, nous avons besoin de creer un "device" une sorte d'interface.

NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);

N'oublions pas que les chaines mis en jeux sont des chaines unicodes.
Ensuite il est nécéssaire de creer un symlink entre le nom de notre interface, et le nom visible de l'userland.
Ce symlink permettra d'avoir accès à notre device depuis le r3.

NTSTATUS
IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName
);

Après ces étapes, nous allons "handler" des fonctions à déclencher selon la réception des différentes IRP.
Je m'explique, une IRP est enfaite un paquet d'information envoyé à un driver, il existe plusieurs type d'IRP (voir documentation).

A l'intérieur de la structure DRIVER_OBJECT il existe un membre nommé MajorFunction qui est tableau de pointeur.

kd> dt nt!_DRIVER_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00c DriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32 Void
+0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
+0x02c DriverInit : Ptr32 long
+0x030 DriverStartIo : Ptr32 void
+0x034 DriverUnload : Ptr32 void
+0x038 MajorFunction : [28] Ptr32 long

Ce tableau nous permet alors d'handler des fonctions qui vont réagir selon les différentes IRPs reçus.

Par exemple, lorsque l'on va ouvrir un handle sur notre device (dans notre application ring3) par le biais de la fonction CreateFile(), le driver va recevoir
une IRP_MJ_CREATE, et quand on va fermer le handle, il va recevoir une IRP_MJ_CLOSE.

C'est ici que les IOCTLs rentrent en jeux.
En effet pour pouvoir déclencher tel ou tel action, nous avons besoin d'une sorte de "code" qui serait recuperé par le driver, et qui agirait en conséquence.
Nous allons donc forger des IOCTLs, par le biais de la macro CTL_CODE().
On va donc creer notre propre "code" qui sera reconnus par le driver.

#define IOCTL_LOL\
CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)

par exemple.
Il faut savoir qu'il existe plusieurs type de transfert pour nos données, en ce qui nous concerne nous utiliserons la METHOD_BUFFERED.

Bon à présent lors de l'envoi de l'IOCTL par notre appli r3, le driver va alors recevoir une IRP_MJ_DEVICE_CONTROL.
La fonction qui sera "handler" à cette irp va alors s'occuper de récuperer des informations sur le type d'IOCTL reçus.
Pour cela nous utiliserons la fonction suivante :

PIO_STACK_LOCATION
IoGetCurrentIrpStackLocation(
IN PIRP Irp
);

Cette fonction va permettre de récupérer tous ce dont on aura besoin sur l'action demandée.
Ensuite nous allons lire le membre Parameters.DeviceIoControl.IoControlCode de la structure IO_STACK_LOCATION.
Ce membre nous indique le "code" envoyé : celui forgé ; notre IOCTLs.
Il nous reste plus qu'a mettre en place un switch sur ce membre, et agir en conséquence :).
Il est aussi possible de passer des arguments, il suffit de lire le membre AssociatedIrp.SystemBuffer de la structure IRP et d'y écrire dedans.
Ce buffer fait office de buffer d'entré et de sortie, mais ceci est propre à la METHOD_BUFFERED.


Screenshot pour la route :



On peut aussi à ce moment là, utiliser l'outil WinObj pour constater l'existence de notre device avec un symlink.



Ouf, vous pouvez soufler un peu, nous arrivons à la fin.
Comme vous vous en doutez surrement, ces IOCTLs vont donc être massivement employer dans les rootkits par exemple, afin de faire communiquer le driver et l'application userland.

Pas d'exemple concret?:(

Mais si!


How to hide a fucking process with DKOM (Direct Kernel Object Manipulation).


Dans cette partie nous allons nous amusez à cacher un processus au système :).
Je vous explique un peu notre plan :

- Notre application userland, va recuperer le nom du processus que l'on veut cacher.
- L'appli va envoyer une IOCTL au driver, avec un argument : le nom du processus.

- Le driver va donc recuperer le nom du processus. (c'est là que ça devient intéréssant)
- Nous allons récupérer un pointeur sur une structure EPROCESS grâce à la fonction IoGetCurrentProcess().
- Une fois récupérer notre pointeur, nous allons parcourir les structures grâce au membre ActiveProcessLinks qui est enfaite une double liste chainée.
- Nous allons comparer le nom du processus récupéré avec le membre ImageFileName.
- Si il n'y a aucune différence nous nous trouvons dans la structure EPROCESS concernant le processus à cacher.
- A présent il nous reste juste à modifier la structure précédente et suivante afin que les membres Flink et Blink des listes chainées ne pointent plus sur la structure du processus à caché.
On va en quelques sortes "sauter" la structure à caché.

Voilà à présent je vous file 2 structures qui vont être utile dans la compréhension du code :

kd> dt nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void //PID du processus, à l'offset 0x084.
+0x088 ActiveProcessLinks : _LIST_ENTRY //ce qui nous interesse :)) à l'offset 0x088.
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar //Nom du process
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B

kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY //Pointe sur la struct suivante.
+0x004 Blink : Ptr32 _LIST_ENTRY //Pointe sur la struct precedente.

Je pense que vous êtes apte à comprendre le code fournis :).

Un petit screenshot pour la route :



A présent il nous reste à aborder l'application ring3.
Celle-ci est extremement simple à comprendre/coder.
En effet, on ouvre un handle sur notre device avec CreateFile(), nous envoyons nos IOCTLs grâce à la fonction DeviceIoControl().
Voilà tout!

Et je compile ça comment?

J'ai utilisé le compilateur disponible dans le wdk.
Seul le fichier "sources" diffère, je vous propose le mien :


TARGETNAME=votreAppli
TARGETTYPE=PROGRAM

INCLUDES=

SOURCES=VotreAppli.c

UMTYPE=console
UMBASE=0x04000000

USE_MSVCRT=1


Vous pouvez dorénavant compiler l'application utilisé pour communiquer avec notre driver !

Mais..cette technique n'a pas de "point" faible?

Hum, à mon grand regret après avoir lus un article disponible sur le blog d'un amis (lilxam), celui-ci nous montre comment "bypasser" ce hide de process :).
Enfin bon, je ne m'avous pas vaincus, je reviendrais avec une meilleure technique :))).

Il est venus le temps de filer les codes :

- HelloWorld.c
- BSOD.c

- HideFuckingProcessR3.c
- HideFuckingProcessR0.c

Et voilà c'est finit pour aujourd'hui !
Encore merci aux personnes qui m'auraient filer un coup de main et toussa :).
cya.

PS : Achetez vous "Subverting kernel windows" écrit par le créateur rootkit.com, un superbe livre de chevet :).