mardi 28 octobre 2008

Integer Overflow

Hello :),
je me suis souvent posé la question du pourquoi du comment j'obtenais parfois des résultats ambigus avec mes entiers. Par exemple une somme de deux entiers positifs qui donnait un résultat négatif...
Ceci est en fait du à ce qu'on appelle "Integer Overflow" ou débordement d'entier.
Tout d'abord essayons de comprendre comment tout ceci fonctionne.

Les Entiers



Tout d'abord nous savons tous qu'il existe différents types de données (BYTE, WORD, DWORD, ...). Prenons quelques exemples de type de données :

-Le type BYTE/SBYTE (en C c'est notre cher unsigned/signed char) : il est codé sur 1 octet donc 8 bits. Sa plage de valeur est donc comprise entre 0x00 et 0xFF.

-Le type WORD/SWORD (en C unsigned/signed short) : il est codé sur 2 octets donc 16 bits. Sa plage de valeur est comprise entre entre 0x0000 et 0xFFFF.

-De même le type DWORD/SDWORD (notre fameux unsigned/signed int) : codé sur 4 octets soit 32bits. Sa plage va de 0x00000000 à 0xFFFFFFFF;

De plus nous savons qu'un entier est soit positif, non-signé(unsigned), soit relatif, signé(signed). Pour les entiers positifs, il n'y a pas de complication. Pour un BYTE par exemple la plage de valeur est de 0 à 255.
Cependant voyons maintenant les entiers signés ou relatifs. Et oui ils peuvent être soit positifs soit négatifs d'où notre (petit) problème. Ce n'est en fait pas très compliqué. Prenons l'exemple d'un SBYTE (codé sur 1 octet et donc 8 bits). Il va en fait être partagé en deux parties, la première constituant le bit de poids fort et la seconde les 7 autres bits. Ce qui donne :



Si on parle binaire, les nombres compris entre 00000000 et 011111111 sont positifs et les nombres compris entre 10000000 et 11111111 sont négatifs. En hexa cela nous donne positif de 0x00 à 0x7F et négatif de 0x80 à 0xFF avec 0x80 = -128 < 0xff =" -1.">Débordement d'entier
Pour commencer qu'est-ce qu'un débordement d'entier ? Et bien c'est tout simplement lorsque un entier prend une valeur qui n'est pas comprise dans sa plage. Par exemple un BYTE ne peut contenir la valeur 395 puisque supérieure à 255. Tout de même si vous tentez l'expérience vous verrez que votre variable prend une valeur (139 pour être précis). Tiens c'est bizarre tout ça.
En fait, lorsqu'on va tenter de mettre 395 dans notre variable c'est le résultat de 395 % 255 = 139 qui va être placé dans la variable.
Il se fera de même pour les autres types de données et les entiers relatifs.
Voici un code qui illustre tout ça :



Maintenant vous allez me dire, mais que se passe-t-il d'autre lors d'un débordement d'entier, une exception n'est pas levée ? Et bien à part dans le cas d'une division non. On verras plus tard pour ce cas particulier. Il y a parcontre des changements au niveau des flags notament le Carry Flag et le Overflow Flag. Le CF lui est armé à chaque fois qu'une opération déborde de la plage de valeur du type de donnée. Pour le OF c'est un peu plus compliqué. Il est mis à un lorsque le résultat d'une opération est de signe logiquement contraire à celui qu'il aurait du être, ceci étant du à un int overflow. Quelques exemples pour illustrer ceci :

-L'addition de deux nombres positifs qui donne un nombre négatif ou inversement. Ce qui est intéressant c'est si l'entier est signé ou non-signé le flag OF prend les mêmes valeurs. Voyez le code si dessous vous comprendrez peutêtre mieux:




Pour le premier résultat il n'y a pas de problème, on constate bien qu'il est négatif à cause de l'int overflow.
Pour le second c'est un peu plus surprenant. Le résultat 254 est positif cependant si on le converti en hexa 0xFE ou en binaire 11111110 on voit bien que si c'était un entier signé il serait négatif. Et bien c'est ce qui est pris en compte pour notre OF.

-La soustraction d'un nombre positif avec un nombre négatif qui donne un résultat négatif ou inversement.

-La multiplication de deux nombres positifs qui donne un résultat négatif, de même pour la division.

Tout à l'heure je parlais de l'instruction DIV mais aussi IDIV qui génèrent une exception lorsque le résultat ou quotient est trop grand. Voici un morceau de code qui génère l'exception :

MOV AX, 1000h
MOV BL, 10h
DIV BL

Et on obtient un joli message d'erreur:




A noter que l'exception générée est Integer Overflow, on s'en serait douté. Cette exception correspond à l'interruption 04h et comme nous le dis le manuel intel le handler de cette interruption ne va pas modifier grand chose au programme et celui-ci va planter. On nous dis aussi que l'instruction INTO (INTerruption on Overflow) génère l'exception Integer Overflow lorsque le OF est à 1. On va donc pouvoir « catcher » ou détecter une partie des Int Overflow là où on pense qu'ils peuvent avoir lieu. Je dis une partie en effet car l'OF n'est pas set à chaque fois comme dis précédemment. Il suffit de mettre un INTO après notre calcul puis de poser un handler et le tour est joué. Voici ce que ça donne :




Et voilà on arrive à détecter un Int overflow qui agit sur l'OF avant qu'il ne puisse faire mal.
Pour ce qui est des débordements d'entiers qui agissent seulement sur le CF il faut soit vérifier son état soit utiliser une instruction comme ADC (ADd with Carry)par exemple qui ajoute à l'opérande destination l'oprérande source et le contenu de CF.

C'est à peu près tout ce que je voulais expliquer. Je vous laisse donc avec un petit divertissement qui a fais peur à Overclok :p : MiniCrackme :)

Les codes et binaires sont disponibles ici.

Voilà à bientôt.

dimanche 28 septembre 2008

L'Union Fait la Force.

Voici une archive contenant deux articles qui sont le résultats d'un travail en commun avec Overclok, le fruit d'une entraide conséquente à renouveler puisque plutôt efficace :). En effet depuis quelques temps nous travaillons sur deux sujets : les buffer overflows sous php et les TLS Callbacks.
0vercl0k nous a mijoté une jolie classe toute propre pour gérer l'implémentation de TLS Callbacks le tout en expliquant le fonctionnement de ceux-ci.
Il met en pratique le tout en montrant comment détecter un debugger avant même que celui-ci n'est eu le temps de breaker l'entry point.
Il continue avec un exemple d'HotPatching reprennant le principe de l'inline hooking. Encore un sujet que mon camarade mène avec brio en montrant comment rendre très discret un anti-debugger qui ne l'est pas.
Tout ceci étant bien évidemment accompagné de codes, screenshots, schémas, dumps et explications.
Je ne vous en dis pas plus, à vous de découvrir la suite :).
Pour ma part j'aborde les buffers overflows sous php. Je débute en créant un fuzzer me permettant de trouver des fonctions faillibles. Au total 8 sont détectées. J'entame alors une analyse de PHP.exe pour essayer de localise les failles ainsi que de comprendre pourquoi celles-ci ont lieu d'être. L'exploitation est basée sur la réécriture de SEH et aboutie à deux exploits, l'un pour PHP 5.x et l'autre pour Apache 2.x.

Je vous souhaite donc une bonne lecture.
A bientôt.

L'archive est disponible ici.

Les codes/exploits/binaires de mon paper sont également dispo ici.

Un petit coucou à Freespirit qui revient parmi nous :).

samedi 6 septembre 2008

List Hidden Pocesses suite... (KiWaitListHead method)

Mon précédent article finissait sur un échec mais grâce à Ivanlef0u je peux continuer :). Heureusement puisque la première technique que je présentais dans cet article, technique qui m'avais pris plusieurs heures à mettre en place, n'a pas résisté plus de 10 minutes à Overclok :(.
Nous nous étions arrêté à la récupération d'un pointeur sur la table KiWaitListHead après avoir scanné la fonction KeWaitForSingleObject() exportée par ntoskrnl.exe.
Mon problème était de savoir par quelles structures était composée cette table. Je n'est pas la réponse exacte mais j'ai pu recueillir les infos nécessaire ici
On peut imaginer cette structure de cette façon :


...
offset : x-0x60 PETHREAD Thread
...
offset : x LIST_ENTRY KiWaitListHead
...

Pour certaines version de windows autres que XP l'offset de Thread sera x-0x70 d'après le liens ci-dessus.
La table KiWaitListHead est donc une liste double-chainée de structures décrivant les threads et contenant un pointeur vers la structure ETHREAD du thread courant. On va donc pouvoir lister nos threads en parcourant cette table, ce qui confirme ce que je supposais dans mon article précédent :)

Une fois la structure ETHREAD récupérée il nous est facile de remonter au processus par le biais de l'EPROCESS. Voici à quoi ressemble l'ETHREAD :


+0x000 Tcb : _KTHREAD
+0x1c0 CreateTime : _LARGE_INTEGER
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
+0x1c0 ApcNeeded : Pos 2, 1 Bit
+0x1c8 ExitTime : _LARGE_INTEGER
+0x1c8 LpcReplyChain : _LIST_ENTRY
+0x1c8 KeyedWaitChain : _LIST_ENTRY
+0x1d0 ExitStatus : Int4B
+0x1d0 OfsChain : Ptr32 Void
+0x1d4 PostBlockList : _LIST_ENTRY
+0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
+0x1dc ReaperLink : Ptr32 _ETHREAD
+0x1dc KeyedWaitValue : Ptr32 Void
+0x1e0 ActiveTimerListLock : Uint4B
+0x1e4 ActiveTimerListHead : _LIST_ENTRY
+0x1ec Cid : _CLIENT_ID
+0x1f4 LpcReplySemaphore : _KSEMAPHORE
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
+0x208 LpcReplyMessage : Ptr32 Void
+0x208 LpcWaitingOnPort : Ptr32 Void
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
+0x210 IrpList : _LIST_ENTRY
+0x218 TopLevelIrp : Uint4B
+0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
+0x220 ThreadsProcess : Ptr32 _EPROCESS
+0x224 StartAddress : Ptr32 Void
+0x228 Win32StartAddress : Ptr32 Void
+0x228 LpcReceivedMessageId : Uint4B
+0x22c ThreadListEntry : _LIST_ENTRY
+0x234 RundownProtect : _EX_RUNDOWN_REF
+0x238 ThreadLock : _EX_PUSH_LOCK
+0x23c LpcReplyMessageId : Uint4B
+0x240 ReadClusterSize : Uint4B
+0x244 GrantedAccess : Uint4B
+0x248 CrossThreadFlags : Uint4B
+0x248 Terminated : Pos 0, 1 Bit
+0x248 DeadThread : Pos 1, 1 Bit
+0x248 HideFromDebugger : Pos 2, 1 Bit
+0x248 ActiveImpersonationInfo : Pos 3, 1 Bit
+0x248 SystemThread : Pos 4, 1 Bit
+0x248 HardErrorsAreDisabled : Pos 5, 1 Bit
+0x248 BreakOnTermination : Pos 6, 1 Bit
+0x248 SkipCreationMsg : Pos 7, 1 Bit
+0x248 SkipTerminationMsg : Pos 8, 1 Bit
+0x24c SameThreadPassiveFlags : Uint4B
+0x24c ActiveExWorker : Pos 0, 1 Bit
+0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
+0x24c MemoryMaker : Pos 2, 1 Bit
+0x250 SameThreadApcFlags : Uint4B
+0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
+0x250 LpcExitThreadCalled : Pos 1, 1 Bit
+0x250 AddressSpaceOwner : Pos 2, 1 Bit
+0x254 ForwardClusterOnly : UChar
+0x255 DisablePageFaultClustering : UChar



Et le membre qui nous intéresse :
+0x220 ThreadsProcess : Ptr32 _EPROCESS


Maintenant je pense que l'unlink de la table KiWaitListHead est possible, j'attends que Overclok s'en charge.
Cependant le paper sur lequel je me suis appuyé parle d'une autre table, la KiDispatcherReadListHead que je tenterais d'explorer dans un prochain article. Donc je vous laisse sur le mot de la fin :
A suivre...


Le code + binaire ici

Remerciements à Overclok et Ivanlef0u qui nous surveille :)

Lilxam.

Overclok owned :p - List Hidden Processes

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

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

The HandleTableList



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


kd> dt nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit



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

kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY


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

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
+0x088 ActiveProcessLinks : _LIST_ENTRY
+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
...


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

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

Etape 1 :

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


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

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

kd> dt nt!_EPROCESS 80558e80
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER 0x0
+0x078 ExitTime : _LARGE_INTEGER 0x0
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : (null)
+0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x090 QuotaUsage : [3] 0
+0x09c QuotaPeak : [3] 0
+0x0a8 CommitCharge : 0
+0x0ac PeakVirtualSize : 0
+0x0b0 VirtualSize : 0
+0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x0bc DebugPort : (null)
+0x0c0 ExceptionPort : (null)
+0x0c4 ObjectTable : 0xe1001cd8 _HANDLE_TABLE
...


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

Voyons à quoi celli-ci ressemble :

kd> dt nt!_HANDLE_TABLE e1001cd8
+0x000 TableCode : 0xe1002000
+0x004 QuotaProcess : (null)
+0x008 UniqueProcessId : 0x00000004
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0xe10065d4 - 0x805617c8 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0
+0x030 FirstFree : 0x520
+0x034 LastFree : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount : 173
+0x040 Flags : 0
+0x040 StrictFIFO : 0y0


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


kd> dt nt!_LIST_ENTRY e1001cd8+0x01c
[ 0xe10065d4 - 0x805617c8 ]
+0x000 Flink : 0xe10065d4 _LIST_ENTRY [ 0xe13d66fc - 0xe1001cf4 ]
+0x004 Blink : 0x805617c8 _LIST_ENTRY [ 0xe1001cf4 - 0xe1661d9c ]


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

kd> dt nt!_LIST_ENTRY 0xe10065d4
[ 0xe13d66fc - 0xe1001cf4 ]
+0x000 Flink : 0xe13d66fc _LIST_ENTRY [ 0xe13c7fd4 - 0xe10065d4 ]
+0x004 Blink : 0xe1001cf4 _LIST_ENTRY [ 0xe10065d4 - 0x805617c8 ]


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

kd> dt nt!_HANDLE_TABLE e10065d4-0x01c
+0x000 TableCode : 0xe128e000
+0x004 QuotaProcess : 0x8163d1a0 _EPROCESS
+0x008 UniqueProcessId : 0x000001ac
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0xe13d66fc - 0xe1001cf4 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0
+0x030 FirstFree : 0x54
+0x034 LastFree : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount : 19
+0x040 Flags : 0
+0x040 StrictFIFO : 0y0


Tout à l'air bon, le PID de ce processus est 0x1ac.

Etape 5 :

Voyons à qui il appartient :

kd> dt nt!_EPROCESS 0x8163d1a0
...
+0x084 UniqueProcessId : 0x000001ac
...
+0x174 ImageFileName : [16] "smss.exe"


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


Lilxam driver OK

Process : System

Process : smss.exe

Object Table : 0xe145e178

--- PID : 0x370

--- PPEPROCESS : 0xe145e17c

--- PEPROCESS : 0x86071980

--- Name : csrss.exe

Object Table : 0xe1014bb0

--- PID : 0x33c

--- PPEPROCESS : 0xe1014bb4

--- PEPROCESS : 0x860754b8

--- Name : smss.exe

Object Table : 0xe1003ec8

--- PID : 0x4

--- PPEPROCESS : 0xe1003ecc

--- PEPROCESS : 0x0

Object Table : 0x80564b8c

--- PID : 0x0

--- PPEPROCESS : 0x80564b90

--- PEPROCESS : 0x0

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

--- PID : 0x260

--- PPEPROCESS : 0xe134ed14

--- PEPROCESS : 0x85706a78

--- Name : calc.exe

...

End



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


Getting list of threads ???




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

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

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

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


+0x8CB8 mov dword ptr [eax], offset _KiWaitListHead



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

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

Les codes sont dispo ici


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

Lilxam.

mercredi 26 mars 2008

Anti-Debugging Part I

Bonjour/Bonsoir,
j'ai décidé récemment de me pencher un peu sur les techniques d'anti-debugging. Je vais donc vous en présenter quelques unes dans cet article, et d'autres je l'espère dans un prochain.
Au programme :
-CheckRemoteDebuggerPresent() ainsi qu'une petit analyse de son fonctionnement que je trouve plutôt intéressant.
-SetUnhandledExceptionFilter() avec une petite introduction aux exceptions SEH.
-Vérification du bit BeingDebugged du PEB et IsDebuggerPresent().
-Un petit anti-Olly connu de tous, l'exploit OutputDebugString().
-Une petite connerie pour le fun que j'ai rencontré sur le crackme #5 de Kaine, l'utilisation de CreateFile() pour empêcher le reload du programme.

A noter dans le titre de cet article le "Part I" qui promet d'autres points en espérant qu'ils soit un peu plus pertinants que certains que je vais présenter ici.

I.Make your own debugger

Avant de commencer je vais juste vous montrer un petit peu à quoi ressemble un debugger. C'est tout simple :
1.On crée le process (CreateProcess()) avec le flag DEBUG_ONLY_THIS_PROCESS
2.Et on récupère les DebugEvents avec WaitForDebugEvent() dans la structure DEBUG_EVENT.

Notre debugger ressemble alors à ça :


#include <windows.h>

#define USAGE "debugger.exe <process path>"
int main(int args, char *argv[])
{
if(args < 2)
{
printf("Usage : %s\n\n",USAGE);
system("pause");
exit(0x0);
}

STARTUPINFO si = {0x0};
PROCESS_INFORMATION pi = {0x0};
DEBUG_EVENT DebugEvent;

printf("Starting Process...");

if(!CreateProcess(argv[1], NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi))
{
printf("FAILED : 0x%x\n\n", GetLastError());
system("pause");
exit(0x0);
}

printf("OK");

printf("\nDebugging Process (ID : 0x%x)...\n\n", pi.dwProcessId);

while(1)
{

WaitForDebugEvent(&DebugEvent, INFINITE);

if(DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
printf("\n\nProcess exited\n\n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
break;
}

ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
}

system("pause");
return 0x0;
}



Voilà vous pouvez maintenant faire des tests avec votre propre pseudo-debugger.


II.CheckRemoteDebuggerPresent()

Voyons un peu comment fonctionne cette fonction.
On commence par un petit disass :


7C859902 8BFF MOV EDI,EDI
...
7C859915 6A 00 PUSH 0
7C859917 6A 04 PUSH 4
7C859919 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8]
7C85991C 50 PUSH EAX
7C85991D 6A 07 PUSH 7
7C85991F FF75 08 PUSH DWORD PTR SS:[EBP+8]
7C859922 FF15 AC10807C CALL DWORD PTR DS:[<&ntdll.NtQueryInformationProcess>]
...


Oh mais que voit-on ? un appel à la fonction NtQueryInformationProcess(). Tiens ça devient intéressant tout ça. En effet NtQueryInformationProcess() est une fonction du kernel land, elle est référencée dans la SSDT. On regarde de plus près (pour faire style de se servir de WinDbg :p):


kd> dd nt!KeServiceDescriptorTable
80552180 80501030 00000000 0000011c 805014a4
80552190 00000000 00000000 00000000 00000000
805521a0 00000000 00000000 00000000 00000000
805521b0 00000000 00000000 00000000 00000000
805521c0 00002710 bf80db87 00000000 00000000
805521d0 f94559e0 81692050 816720f0 806dff40
805521e0 00000000 00000000 00000000 00000000
805521f0 67b093c0 01c88fe4 00000000 00000000
kd> dps 80501030
80501030 8059847e nt!NtAcceptConnectPort
80501034 805e5664 nt!NtAccessCheck
80501038 805e8eaa nt!NtAccessCheckAndAuditAlarm
....
80501294 80599232 nt!NtQueryInformationPort
80501298 805c14bc nt!NtQueryInformationProcess <----- La voici :)
8050129c 805c0088 nt!NtQueryInformationThread
...


Au passage je met à dispo un dump de ma SSDT, si ça peut servir on sait jamais : DumpSSDT.txt

Plus sérieusement si on va chercher le prototype de la fonction dans la msdn on retrouve ceci :


NTSTATUS WINAPI NtQueryInformationProcess(
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);


On remarque alors la structure PROCESSINFOCLASS :


typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation, 0
ProcessQuotaLimits, 1
ProcessIoCounters, 2
ProcessVmCounters, 3
ProcessTimes, 4
ProcessBasePriority, 5
ProcessRaisePriority, 6
ProcessDebugPort, 7 <------ Ce qui nous interresse :)
ProcessExceptionPort 8
ProcessAccessToken, 9
ProcessLdtInformation, 10
ProcessLdtSize, 11
ProcessDefaultHardErrorMode, 12
ProcessIoPortHandlers, 13
ProcessPooledUsageAndLimits, 14
ProcessWorkingSetWatch, 15
ProcessUserModeIOPL, 16
ProcessEnableAlignmentFaultFixup, 17
ProcessPriorityClass, 18
ProcessWx86Information, 19
ProcessHandleCount, 20
ProcessAffinityMask, 21
ProcessPriorityBoost, 22
ProcessDeviceMap, 23
}


C'est le paramètre ProcessDebugPort qui va nous intéresser. En effet si le processus est débuggé, ce paramètre aura une valeur non-égale à zéro, super :). Seulement ceci ne marche que pour les debuggers ring3 :( :


ProcessDebugPort NtQueryInformationProcess fills in a DWORD with the port number of the
debugger for the process being queried. The ProcessInformationLength parameter to
NtQueryInformationProcess should be set to sizeof(DWORD). The debug port is a value that's
useles eans that the process
s to ring 3 code. However, you can infer that a nonzero debug port m
is bein run under the control of a ring 3 debugger such as the Visual C++ IDE or Turbo Debugger.


Bon on a a donc finis avec CheckRemoteDebuggerPresent(), et j'espère que vous avez maintenant compris comment elle fonctionne. Un petit code :


#define _WIN32_WINNT 0x0501

#include

int main()
{
BOOL dwIsDebugged;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &dwIsDebugged);
if(!dwIsDebugged)
MessageBox(NULL, "Okay :)", "Okay :)", MB_OK);
else
MessageBox(NULL, "I'm Debugged !!!", "I'm Debugged !!!", MB_OK);

return 0x0;
}


III.SetUnhandledExceptionFilter()

Voilà une fonction intéressante également. Cette fonction va se baser sur la gestion des exceptions. En effet vous devez tous avoir déjà eu à faire à une méchante msgBox qui vous dit que votre programme à planté pour telle ou telle raison comme le fameux "Memory access violation". Bref je vais pas m'attarder sur ce sujet, je m'y pencherais certainement dans un prochain article. En fait, SetUnhandledExceptionFilter() permet de poser un handler de haut niveau. C'est alors le système qui va, lorsqu'une exception est générée, vérifier dans une table si un handler a été définit par la fonction SetUnhandledExceptionFilter(). Si c'est le cas, la fonction UnhandledExceptionFilter() va, de la même façon que le fait CheckRemoteDebuggerPresent(), regarder si le process est débuggé ou pas. Si la fonction a détecté un debugger, alors elle n'execute pas le handler, sinon elle saute dessus. Du coup il nous est facile de connaitre la présence d'un debugger, si le handler est executé alors le process n'est pas débuggé, sinon il l'est.
Voici le code :


#include

DWORD NotDebugged()
{
MessageBox(NULL, "Okay :)", "Okay :)", MB_OK);
}
int main()
{
SetUnhandledExceptionFilter(&NotDebugged);
RaiseException(EXCEPTION_FLT_DIVIDE_BY_ZERO, 0, 0, NULL); //Génère l'exception
MessageBox(NULL, "I'm Debugged !!!", "I'm Debugged !!!", MB_OK);

return 0x0;
}


Le principe est simple, je filtre les exceptions avec SetUnhandledExceptionFilter() avec ma fonction NotDebugged() comme handler. Ensuite je génère l'exception avec RaiseException(). Si le programme est débuggé et que le debugger "ignore" l'exception on va arriver sur la MsgBox() "I'm Debugged" sinon la fonction NotDebugged() va être exécutée.
Voilà un petit apperçu de cette fonction.

IV.Process Evironment Block : BeingDebugged

Cette fois je vais m'intéresser à la structure PEB :

kd> dt nt!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
...


On remarque le champ BeingDebugged :). En fait lorsqu'un programme est debuggé, le système va positionner cet octet à 1. Il suffit donc de le vérifier pour s'appercevoir de la présence d'un debugger.
Voilà ce que ça donne en C :

#include

typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
/*
...
*/
} PEB, *PPEB;

int main()
{
PVOID (*GetCurrentPEB)();
PPEB ProcessPEB;

GetCurrentPEB = (PVOID *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetCurrentPeb");
ProcessPEB = (PPEB)(*GetCurrentPEB)();

if(!ProcessPEB->BeingDebugged)
MessageBox(NULL, "Okay :)", "Okay :)", MB_OK);
else
MessageBox(NULL, "I'm Debugged !!!", "I'm Debugged !!!", MB_OK);

return 0x0;
}

C'est en fait ce que fait la fonction IsDebuggerPresent() que vous connaissez tous !
En effet si on désassemble cette fonction on trouve :


7C812E03 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
7C812E09 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30] //Se Positionne sur le PEB
7C812E0C 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2] //Récupère le 3e octet
7C812E10 C3 RETN


Voilà, vous savez maintenant comment marche cette fonction.

V.Exploit OutputDebugString()

Voilà un petit trick anti-OllyDBG bien connu des reversers. Il s'agit en fait de passer une chaine mal-formaté à la fonction OutputDebugString() que Olly va mal gérer. Celui-ci va alors crasher. Je m'attarderais pas sur ça, un petit code :


#include

int main()
{
OutputDebugString("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%
s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%
s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
return 0x0;
}


VI.Anti reloading

Et pour finir une petite connerie :)
On va empêcher Olly de recharger le programme qu'il veut débugger. Pour celà on va utiliser CreateFilA(). Notre programme va ressembler à ceici :


#include

int main()
{
HANDLE hFile = CreateFileA("main.exe", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
MessageBox(NULL, "Reload me :p", "Reload me :p", MB_OK);
CloseHandle(hFile);
return 0x0;
}


Voilà juste pour emmerder notre amis reverser.

C'est finis pour cette petite intro aux anti-debugs, tout ça pour dire qu'il y a beaucoup de façons de détecter la présence d'un debugger mais elles resteront toujours bypassables. Je pense présenter d'autres techniques dans un prochain article et notamment parler un peu plus des SEHs.

Bon debugging ;)

Remerciements à Baboon pour les erreurs qu'il m'a fait remarquer.

Les codes d'anti-dbg dispo ici : Path

Le code du debugger : Source+binaire

Une excellente doc sur les anti-debugs : Windows anti-debug reference

vendredi 14 mars 2008

API hooking by IAT Patching : hook global de TerminateProcess()

Bonjour/Bonsoir,
voilà un bon bout de temps que j'étais sur ce projet que je viens juste de "finir", le hook d'API. Il s'agit en fait de détourner une API afin de la contrôler.
Le projet s'organise en 2 parties majeures, tout d'abord on injecte une dll dans un processus, j'ai déjà fais un article expliquant comment faire ça (article) cependant j'ai quand même apporté quelques modifications au code que j'avais fais, je l'ai mis à jour, et ensuite, une fois la dll chargée en mémoire dans le processus, on va modifier l'IAT de celui-ci afin de faire pointer la fonction que l'on veut hooker sur un fonction déclarée dans notre dll.Pour les explications de la 2e partie je vous renvoie à cet article : article .

Afin d'illustrer ce code, je vous propose d'hooker la fonction TerminateProcess() sur tous les processus.
Je prends par exemple un code que j'avais fait qui permet de terminer un processus et je vais essayer de lui appliquer mon code :


>loader C:\killprocess.dll KillProcess.exe

Injecting dll C:\killprocess.dll into process KillProcess.exe ...


Adresse de LoadLibrary() : 7c801d77
Process ID : 244

[+]Processus ouvert : 7d0
[+]Mémoire allouee : 510000
[+]Ecriture dans le processus reussie
----Avec 19 bits ecrits
[+]Donnees executees



Donc en premier lieu on injecte la dll (Si ça ne marche pas c'est peutêtre à cause d'un AV ou firewall).
Ensuite la dll va faire son travail et on va voir si ça marche :



(Ne faites pas attention au fautes d'anglais, c'était mes debuts ^^)
Super, on nous demande confirmation de l'arrêt du processus.
Maintenant on peut faire la même chose en hook global, c'est à dire sur tous les processus sauf les systèmes pour éviter de se prendre un BSOD.


>loader C:\killprocess.dll all

Injecting dll C:\killprocess.dll into process MDM.EXE ...


Adresse de LoadLibrary() : 7c801d77
Process ID : 2812

[+]Processus ouvert : 6ac
[+]Mémoire allouee : a00000
[+]Ecriture dans le processus reussie
----Avec 19 bits ecrits
[+]Donnees executees
Injecting dll C:\killprocess.dll into process devcpp.exe ...


Adresse de LoadLibrary() : 7c801d77
Process ID : 316

[+]Processus ouvert : 6a0
[+]Mémoire allouee : 15f0000
[+]Ecriture dans le processus reussie
----Avec 19 bits ecrits
[+]Donnees executees
Injecting dll C:\killprocess.dll into process codeblocks.exe ...


Adresse de LoadLibrary() : 7c801d77
Process ID : 3252

[+]Processus ouvert : 694
[+]Mémoire allouee : 1090000
[+]Ecriture dans le processus reussie
----Avec 19 bits ecrits
[+]Donnees executees
Injecting dll C:\killprocess.dll into process explorer.exe ...

...



On tente de terminer un processus avec taskmgr.exe et on vois apparaitre notre jolie messagebox qui demande une confirmation :). Juste un petit cafouilla sur le nom du processus victime, je me suis pas embêté pour ce qui est de récupérer le nom des processus.

Bien évidemment TerminateProcess() n'est pas la seule API qu'on peut hooker, à présent tout dépend de votre imagination ;).

Maintenant ce que vous voulez, les codes :

Le loader :

projet
loader.c
code+binaire en zip



La dll :

projet
main.c
code + binaire en zip


Le programme qui sert d'exemple, KillProcess.exe :

projet
main.cpp
code + binaire en zip

Je tiens également à remercier Overclok et Ivanlef0u qui m'ont aidé pour ce projet. Un article sur l'API hooking est également présent sur le blog d'Overclok.

Have Fun ;)
lilxam.

mercredi 20 février 2008

Listing all processes

Plop :)
Alors que je lisais un article de monsieur Ivanlef0u (article), un article très intéressant où ivan nous projette en ring0 avec l'API NtSystemDebugControl() et notamment deux contrôles qui sont DebugSysReadVirtual et DebugSysWriteVirtual (ce ne sont pas les seuls permettant de faire ça :]), je vois monsieur s'amuse à cacher des processus et nous laisse un petit message "Il existe tout de même une façon de le retrouver mais shuuuuut !". Je prends ça comme un petit défis et me dis qu'on va faire réapparaître sont processus ! Nan mais! Je prends mes petits doigts et je réfléchis... Je fais quelques petits tests et arrive par me demander s'il n'est pas possible de retrouver le nom d'un processus à partir de son ID. Je fais un saut chez la msdn et je vois la fonction GetModuleBaseName() :). Juste ce qu'il me fallait, il ne me reste plus qu'à faire un petit BF sur les ID des processus et récupérer les noms correspondant.
On prends le prog d'Ivan, on cache notre bien aimée calculatrice et on va essayer de la retrouver.


>tasklist

Nom de l'image PIDÿ Nom de la sessio Num‚ro d Utilisation
========================= ====== ================ ======== ============
System Idle Process 0 Console 0 28 Ko
System 4 Console 0 240 Ko
smss.exe 796 Console 0 408 Ko
csrss.exe 852 Console 0 3ÿ092 Ko
winlogon.exe 876 Console 0 3ÿ980 Ko
services.exe 920 Console 0 5ÿ436 Ko
lsass.exe 940 Console 0 1ÿ464 Ko
svchost.exe 1108 Console 0 5ÿ100 Ko
svchost.exe 1176 Console 0 4ÿ756 Ko
svchost.exe 1284 Console 0 23ÿ552 Ko
svchost.exe 1416 Console 0 3ÿ872 Ko
spoolsv.exe 1740 Console 0 4ÿ516 Ko
explorer.exe 1952 Console 0 11ÿ316 Ko
nod32kui.exe 2028 Console 0 2ÿ568 Ko
jusched.exe 2036 Console 0 5ÿ060 Ko
igfxtray.exe 188 Console 0 3ÿ412 Ko
hkcmd.exe 184 Console 0 3ÿ400 Ko
igfxpers.exe 200 Console 0 3ÿ044 Ko
SearchSettings.exe 212 Console 0 6ÿ000 Ko
FileZilla Server Interfac 244 Console 0 1ÿ708 Ko
msnmsgr.exe 328 Console 0 28ÿ980 Ko
igfxsrvc.exe 344 Console 0 2ÿ948 Ko
LightScribeControlPanel.e 348 Console 0 7ÿ360 Ko
RocketDock.exe 356 Console 0 9ÿ916 Ko
UberIcon Manager.exe 520 Console 0 3ÿ384 Ko
YzShadow.exe 532 Console 0 4ÿ768 Ko
msdtc.exe 596 Console 0 5ÿ044 Ko
aawservice.exe 704 Console 0 29ÿ644 Ko
FileZilla server.exe 728 Console 0 3ÿ072 Ko
LSSrvc.exe 772 Console 0 2ÿ660 Ko
nod32krn.exe 1580 Console 0 25ÿ504 Ko
kpf4ss.exe 1612 Console 0 14ÿ804 Ko
StarWindServiceAE.exe 1704 Console 0 4ÿ068 Ko
mqsvc.exe 1844 Console 0 6ÿ516 Ko
mqtgsvc.exe 1248 Console 0 4ÿ036 Ko
kpf4gui.exe 2128 Console 0 7ÿ168 Ko
svchost.exe 2144 Console 0 4ÿ180 Ko
alg.exe 2448 Console 0 4ÿ048 Ko
WgaTray.exe 3232 Console 0 188 Ko
kpf4gui.exe 3320 Console 0 9ÿ528 Ko
usnsvc.exe 3648 Console 0 2ÿ584 Ko
MDM.EXE 4008 Console 0 3ÿ136 Ko
firefox.exe 2484 Console 0 94ÿ372 Ko
mirc.exe 3564 Console 0 2ÿ344 Ko
devcpp.exe 2176 Console 0 1ÿ072 Ko
calc.exe 1012 Console 0 3ÿ116 Ko <-----
cmd.exe 2244 Console 0 3ÿ588 Ko
tasklist.exe 488 Console 0 4ÿ640 Ko
wmiprvse.exe 3904 Console 0 5ÿ692 Ko


Avant d'aplliquer le prog d'ivan on vois bien la présence de calc.exe avec l'id 1012.
On applique son code :

>KFist.exe calc.exe
KFist : UserLand DKOM Process Hider (xp only)
By Ivanlef0u
BE MAD!
Current ETHREAD : 0x84165020
Current EPROCESS : 0x85388aa8
Process Name : KFist.exe
EPROCESS : 0x80562730
Process Name : ÿÿÿÿ
EPROCESS : 0x85fac830
Process Name : System
EPROCESS : 0x85dcf5e8
Process Name : smss.exe
EPROCESS : 0x85e85020
Process Name : csrss.exe
EPROCESS : 0x85be84d0
Process Name : winlogon.exe
EPROCESS : 0x85bd19d0
Process Name : services.exe
EPROCESS : 0x85ccd128
Process Name : lsass.exe
EPROCESS : 0x85cb8a48
Process Name : svchost.exe
EPROCESS : 0x85492318
Process Name : svchost.exe
EPROCESS : 0x85ca7c60
Process Name : svchost.exe
EPROCESS : 0x856fcda0
Process Name : svchost.exe
EPROCESS : 0x8540eda0
Process Name : spoolsv.exe
EPROCESS : 0x853ac7e0
Process Name : explorer.exe
EPROCESS : 0x853f2400
Process Name : nod32kui.exe
EPROCESS : 0x853e7888
Process Name : jusched.exe
EPROCESS : 0x85db5a78
Process Name : igfxtray.exe
EPROCESS : 0x85b903c8
Process Name : hkcmd.exe
EPROCESS : 0x85d52c10
Process Name : igfxpers.exe
EPROCESS : 0x85d5a560
Process Name : SearchSettings.
EPROCESS : 0x85428c10
Process Name : FileZilla Serve
EPROCESS : 0x85bfeda0
Process Name : msnmsgr.exe
EPROCESS : 0x853dec10
Process Name : igfxsrvc.exe
EPROCESS : 0x853dad78
Process Name : LightScribeCont
EPROCESS : 0x85db33c0
Process Name : RocketDock.exe
EPROCESS : 0x85be7da0
Process Name : UberIcon Manage
EPROCESS : 0x85bb9da0
Process Name : YzShadow.exe
EPROCESS : 0x853e02c8
Process Name : msdtc.exe
EPROCESS : 0x853d82a0
Process Name : aawservice.exe
EPROCESS : 0x853e1650
Process Name : FileZilla serve
EPROCESS : 0x853fdda0
Process Name : LSSrvc.exe
EPROCESS : 0x853eb8b0
Process Name : nod32krn.exe
EPROCESS : 0x85c0eab0
Process Name : kpf4ss.exe
EPROCESS : 0x85d6e998
Process Name : StarWindService
EPROCESS : 0x85be0850
Process Name : mqsvc.exe
EPROCESS : 0x83c11020
Process Name : mqtgsvc.exe
EPROCESS : 0x846ceda0
Process Name : kpf4gui.exe
EPROCESS : 0x85b77a20
Process Name : svchost.exe
EPROCESS : 0x846cb5b0
Process Name : alg.exe
EPROCESS : 0x846d5a38
Process Name : regedt32.exe
EPROCESS : 0x846b6da0
Process Name : WgaTray.exe
EPROCESS : 0x83baf728
Process Name : kpf4gui.exe
EPROCESS : 0x84680da0
Process Name : usnsvc.exe
EPROCESS : 0x8467a8e8
Process Name : MDM.EXE
EPROCESS : 0x85369020
Process Name : firefox.exe
EPROCESS : 0x85da3890
Process Name : regedt32.exe
EPROCESS : 0x85bfe248
Process Name : AcroRd32.exe
EPROCESS : 0x85c12c10
Process Name : mirc.exe
EPROCESS : 0x8475b9a8
Process Name : devcpp.exe
EPROCESS : 0x853436d0
Process Name : regedt32.exe
EPROCESS : 0x82b60318
Process Name : calc.exe
Process Found ! Now hiding it... <-----
Prev EPROCESS : 0x853436d0
Next EPROCESS : 0x83c08020
Hiding done, have fun!
EPROCESS : 0x83c08020
Process Name : cmd.exe
EPROCESS : 0x8465caf8
Process Name : wmiprvse.exe
EPROCESS : 0x853452e0
Process Name : notepad.exe
EPROCESS : 0x85388aa8

>tasklist

Nom de l'image PIDÿ Nom de la sessio Num‚ro d Utilisation
========================= ====== ================ ======== ============
System Idle Process 0 Console 0 28 Ko
System 4 Console 0 240 Ko
smss.exe 796 Console 0 408 Ko
csrss.exe 852 Console 0 3ÿ148 Ko
winlogon.exe 876 Console 0 3ÿ988 Ko
services.exe 920 Console 0 5ÿ436 Ko
lsass.exe 940 Console 0 1ÿ140 Ko
svchost.exe 1108 Console 0 5ÿ100 Ko
svchost.exe 1176 Console 0 4ÿ756 Ko
svchost.exe 1284 Console 0 23ÿ364 Ko
svchost.exe 1416 Console 0 3ÿ872 Ko
spoolsv.exe 1740 Console 0 4ÿ516 Ko
explorer.exe 1952 Console 0 11ÿ396 Ko
nod32kui.exe 2028 Console 0 2ÿ568 Ko
jusched.exe 2036 Console 0 5ÿ060 Ko
igfxtray.exe 188 Console 0 3ÿ412 Ko
hkcmd.exe 184 Console 0 3ÿ400 Ko
igfxpers.exe 200 Console 0 3ÿ044 Ko
SearchSettings.exe 212 Console 0 6ÿ000 Ko
FileZilla Server Interfac 244 Console 0 1ÿ708 Ko
msnmsgr.exe 328 Console 0 28ÿ980 Ko
igfxsrvc.exe 344 Console 0 2ÿ948 Ko
LightScribeControlPanel.e 348 Console 0 7ÿ360 Ko
RocketDock.exe 356 Console 0 9ÿ916 Ko
UberIcon Manager.exe 520 Console 0 3ÿ392 Ko
YzShadow.exe 532 Console 0 4ÿ956 Ko
msdtc.exe 596 Console 0 5ÿ044 Ko
aawservice.exe 704 Console 0 29ÿ644 Ko
FileZilla server.exe 728 Console 0 3ÿ072 Ko
LSSrvc.exe 772 Console 0 2ÿ660 Ko
nod32krn.exe 1580 Console 0 25ÿ504 Ko
kpf4ss.exe 1612 Console 0 14ÿ804 Ko
StarWindServiceAE.exe 1704 Console 0 4ÿ068 Ko
mqsvc.exe 1844 Console 0 6ÿ516 Ko
mqtgsvc.exe 1248 Console 0 4ÿ036 Ko
kpf4gui.exe 2128 Console 0 7ÿ168 Ko
svchost.exe 2144 Console 0 4ÿ180 Ko
alg.exe 2448 Console 0 4ÿ048 Ko
WgaTray.exe 3232 Console 0 188 Ko
kpf4gui.exe 3320 Console 0 9ÿ528 Ko
usnsvc.exe 3648 Console 0 2ÿ584 Ko
MDM.EXE 4008 Console 0 3ÿ136 Ko
firefox.exe 2484 Console 0 94ÿ784 Ko
mirc.exe 3564 Console 0 2ÿ344 Ko
devcpp.exe 2176 Console 0 1ÿ088 Ko
cmd.exe 2244 Console 0 3ÿ620 Ko
wmiprvse.exe 3904 Console 0 6ÿ028 Ko
notepad.exe 3744 Console 0 936 Ko
notepad.exe 3312 Console 0 3ÿ336 Ko
tasklist.exe 2748 Console 0 4ÿ636 Ko


calc.exe n'apparait plus dans la liste, le code d'ivan marche donc bien :).
A nous maintenant :


>ListAllProcess.exe

Enumerating processes...

[+] Process Name : hkcmd.exe --- ID : 0xb8
[+] Process Name : hkcmd.exe --- ID : 0xb9
[+] Process Name : hkcmd.exe --- ID : 0xba
[+] Process Name : hkcmd.exe --- ID : 0xbb
[+] Process Name : igfxtray.exe --- ID : 0xbc
[+] Process Name : igfxtray.exe --- ID : 0xbd
[+] Process Name : igfxtray.exe --- ID : 0xbe
[+] Process Name : igfxtray.exe --- ID : 0xbf
[+] Process Name : igfxpers.exe --- ID : 0xc8
[+] Process Name : igfxpers.exe --- ID : 0xc9
[+] Process Name : igfxpers.exe --- ID : 0xca
[+] Process Name : igfxpers.exe --- ID : 0xcb
[+] Process Name : SearchSettings.exe --- ID : 0xd4
[+] Process Name : SearchSettings.exe --- ID : 0xd5
[+] Process Name : SearchSettings.exe --- ID : 0xd6
[+] Process Name : SearchSettings.exe --- ID : 0xd7
[+] Process Name : FileZilla Server Interface.exe --- ID : 0xf4
[+] Process Name : FileZilla Server Interface.exe --- ID : 0xf5
[+] Process Name : FileZilla Server Interface.exe --- ID : 0xf6
[+] Process Name : FileZilla Server Interface.exe --- ID : 0xf7
[+] Process Name : MsnMsgr.Exe --- ID : 0x148
[+] Process Name : MsnMsgr.Exe --- ID : 0x149
[+] Process Name : MsnMsgr.Exe --- ID : 0x14a
[+] Process Name : MsnMsgr.Exe --- ID : 0x14b
[+] Process Name : igfxsrvc.exe --- ID : 0x158
[+] Process Name : igfxsrvc.exe --- ID : 0x159
[+] Process Name : igfxsrvc.exe --- ID : 0x15a
[+] Process Name : igfxsrvc.exe --- ID : 0x15b
[+] Process Name : LightScribeControlPanel.exe --- ID : 0x15c
[+] Process Name : LightScribeControlPanel.exe --- ID : 0x15d
[+] Process Name : LightScribeControlPanel.exe --- ID : 0x15e
[+] Process Name : LightScribeControlPanel.exe --- ID : 0x15f
[+] Process Name : RocketDock.exe --- ID : 0x164
[+] Process Name : RocketDock.exe --- ID : 0x165
[+] Process Name : RocketDock.exe --- ID : 0x166
[+] Process Name : RocketDock.exe --- ID : 0x167
[+] Process Name : UberIcon Manager.exe --- ID : 0x208
[+] Process Name : UberIcon Manager.exe --- ID : 0x209
[+] Process Name : UberIcon Manager.exe --- ID : 0x20a
[+] Process Name : UberIcon Manager.exe --- ID : 0x20b
[+] Process Name : YzShadow.exe --- ID : 0x214
[+] Process Name : YzShadow.exe --- ID : 0x215
[+] Process Name : YzShadow.exe --- ID : 0x216
[+] Process Name : YzShadow.exe --- ID : 0x217
[+] Process Name : msdtc.exe --- ID : 0x254
[+] Process Name : msdtc.exe --- ID : 0x255
[+] Process Name : msdtc.exe --- ID : 0x256
[+] Process Name : msdtc.exe --- ID : 0x257
[+] Process Name : aawservice.exe --- ID : 0x2c0
[+] Process Name : aawservice.exe --- ID : 0x2c1
[+] Process Name : aawservice.exe --- ID : 0x2c2
[+] Process Name : aawservice.exe --- ID : 0x2c3
[+] Process Name : FileZilla Server.exe --- ID : 0x2d8
[+] Process Name : FileZilla Server.exe --- ID : 0x2d9
[+] Process Name : FileZilla Server.exe --- ID : 0x2da
[+] Process Name : FileZilla Server.exe --- ID : 0x2db
[+] Process Name : LSSrvc.exe --- ID : 0x304
[+] Process Name : LSSrvc.exe --- ID : 0x305
[+] Process Name : LSSrvc.exe --- ID : 0x306
[+] Process Name : LSSrvc.exe --- ID : 0x307
[+] Process Name : smss.exe --- ID : 0x31c
[+] Process Name : smss.exe --- ID : 0x31d
[+] Process Name : smss.exe --- ID : 0x31e
[+] Process Name : smss.exe --- ID : 0x31f
[+] Process Name : csrss.exe --- ID : 0x354
[+] Process Name : csrss.exe --- ID : 0x355
[+] Process Name : csrss.exe --- ID : 0x356
[+] Process Name : csrss.exe --- ID : 0x357
[+] Process Name : winlogon.exe --- ID : 0x36c
[+] Process Name : winlogon.exe --- ID : 0x36d
[+] Process Name : winlogon.exe --- ID : 0x36e
[+] Process Name : winlogon.exe --- ID : 0x36f
[+] Process Name : services.exe --- ID : 0x398
[+] Process Name : services.exe --- ID : 0x399
[+] Process Name : services.exe --- ID : 0x39a
[+] Process Name : services.exe --- ID : 0x39b
[+] Process Name : lsass.exe --- ID : 0x3ac
[+] Process Name : lsass.exe --- ID : 0x3ad
[+] Process Name : lsass.exe --- ID : 0x3ae
[+] Process Name : lsass.exe --- ID : 0x3af
[+] Process Name : calc.exe --- ID : 0x3f4 <----- Mais que voilà ?? :)
[+] Process Name : calc.exe --- ID : 0x3f5
[+] Process Name : calc.exe --- ID : 0x3f6
[+] Process Name : calc.exe --- ID : 0x3f7
[+] Process Name : svchost.exe --- ID : 0x454
[+] Process Name : svchost.exe --- ID : 0x455
[+] Process Name : svchost.exe --- ID : 0x456
[+] Process Name : svchost.exe --- ID : 0x457
[+] Process Name : svchost.exe --- ID : 0x498
[+] Process Name : svchost.exe --- ID : 0x499
[+] Process Name : svchost.exe --- ID : 0x49a
[+] Process Name : svchost.exe --- ID : 0x49b
[+] Process Name : mqtgsvc.exe --- ID : 0x4e0
[+] Process Name : mqtgsvc.exe --- ID : 0x4e1
[+] Process Name : mqtgsvc.exe --- ID : 0x4e2
[+] Process Name : mqtgsvc.exe --- ID : 0x4e3
[+] Process Name : svchost.exe --- ID : 0x504
[+] Process Name : svchost.exe --- ID : 0x505
[+] Process Name : svchost.exe --- ID : 0x506
[+] Process Name : svchost.exe --- ID : 0x507
[+] Process Name : svchost.exe --- ID : 0x588
[+] Process Name : svchost.exe --- ID : 0x589
[+] Process Name : svchost.exe --- ID : 0x58a
[+] Process Name : svchost.exe --- ID : 0x58b
[+] Process Name : nod32krn.exe --- ID : 0x62c
[+] Process Name : nod32krn.exe --- ID : 0x62d
[+] Process Name : nod32krn.exe --- ID : 0x62e
[+] Process Name : nod32krn.exe --- ID : 0x62f
[+] Process Name : kpf4ss.exe --- ID : 0x64c
[+] Process Name : kpf4ss.exe --- ID : 0x64d
[+] Process Name : kpf4ss.exe --- ID : 0x64e
[+] Process Name : kpf4ss.exe --- ID : 0x64f
[+] Process Name : StarWindServiceAE.exe --- ID : 0x6a8
[+] Process Name : StarWindServiceAE.exe --- ID : 0x6a9
[+] Process Name : StarWindServiceAE.exe --- ID : 0x6aa
[+] Process Name : StarWindServiceAE.exe --- ID : 0x6ab
[+] Process Name : spoolsv.exe --- ID : 0x6cc
[+] Process Name : spoolsv.exe --- ID : 0x6cd
[+] Process Name : spoolsv.exe --- ID : 0x6ce
[+] Process Name : spoolsv.exe --- ID : 0x6cf
[+] Process Name : mqsvc.exe --- ID : 0x734
[+] Process Name : mqsvc.exe --- ID : 0x735
[+] Process Name : mqsvc.exe --- ID : 0x736
[+] Process Name : mqsvc.exe --- ID : 0x737
[+] Process Name : Explorer.EXE --- ID : 0x7a0
[+] Process Name : Explorer.EXE --- ID : 0x7a1
[+] Process Name : Explorer.EXE --- ID : 0x7a2
[+] Process Name : Explorer.EXE --- ID : 0x7a3
[+] Process Name : nod32kui.exe --- ID : 0x7ec
[+] Process Name : nod32kui.exe --- ID : 0x7ed
[+] Process Name : nod32kui.exe --- ID : 0x7ee
[+] Process Name : nod32kui.exe --- ID : 0x7ef
[+] Process Name : jusched.exe --- ID : 0x7f4
[+] Process Name : jusched.exe --- ID : 0x7f5
[+] Process Name : jusched.exe --- ID : 0x7f6
[+] Process Name : jusched.exe --- ID : 0x7f7
[+] Process Name : kpf4gui.exe --- ID : 0x850
[+] Process Name : kpf4gui.exe --- ID : 0x851
[+] Process Name : kpf4gui.exe --- ID : 0x852
[+] Process Name : kpf4gui.exe --- ID : 0x853
[+] Process Name : svchost.exe --- ID : 0x860
[+] Process Name : svchost.exe --- ID : 0x861
[+] Process Name : svchost.exe --- ID : 0x862
[+] Process Name : svchost.exe --- ID : 0x863
[+] Process Name : devcpp.exe --- ID : 0x880
[+] Process Name : devcpp.exe --- ID : 0x881
[+] Process Name : devcpp.exe --- ID : 0x882
[+] Process Name : devcpp.exe --- ID : 0x883
[+] Process Name : cmd.exe --- ID : 0x8c4
[+] Process Name : cmd.exe --- ID : 0x8c5
[+] Process Name : cmd.exe --- ID : 0x8c6
[+] Process Name : cmd.exe --- ID : 0x8c7
[+] Process Name : alg.exe --- ID : 0x990
[+] Process Name : alg.exe --- ID : 0x991
[+] Process Name : alg.exe --- ID : 0x992
[+] Process Name : alg.exe --- ID : 0x993
[+] Process Name : firefox.exe --- ID : 0x9b4
[+] Process Name : firefox.exe --- ID : 0x9b5
[+] Process Name : firefox.exe --- ID : 0x9b6
[+] Process Name : firefox.exe --- ID : 0x9b7
[+] Process Name : ListAllProcesses.exe --- ID : 0xc64
[+] Process Name : ListAllProcesses.exe --- ID : 0xc65
[+] Process Name : ListAllProcesses.exe --- ID : 0xc66
[+] Process Name : ListAllProcesses.exe --- ID : 0xc67
[+] Process Name : WgaTray.exe --- ID : 0xca0
[+] Process Name : WgaTray.exe --- ID : 0xca1
[+] Process Name : WgaTray.exe --- ID : 0xca2
[+] Process Name : WgaTray.exe --- ID : 0xca3
[+] Process Name : NOTEPAD.EXE --- ID : 0xcf0
[+] Process Name : NOTEPAD.EXE --- ID : 0xcf1
[+] Process Name : NOTEPAD.EXE --- ID : 0xcf2
[+] Process Name : NOTEPAD.EXE --- ID : 0xcf3
[+] Process Name : kpf4gui.exe --- ID : 0xcf8
[+] Process Name : kpf4gui.exe --- ID : 0xcf9
[+] Process Name : kpf4gui.exe --- ID : 0xcfa
[+] Process Name : kpf4gui.exe --- ID : 0xcfb
[+] Process Name : mirc.exe --- ID : 0xdec
[+] Process Name : mirc.exe --- ID : 0xded
[+] Process Name : mirc.exe --- ID : 0xdee
[+] Process Name : mirc.exe --- ID : 0xdef
[+] Process Name : usnsvc.exe --- ID : 0xe40
[+] Process Name : usnsvc.exe --- ID : 0xe41
[+] Process Name : usnsvc.exe --- ID : 0xe42
[+] Process Name : usnsvc.exe --- ID : 0xe43
[+] Process Name : NOTEPAD.EXE --- ID : 0xea0
[+] Process Name : NOTEPAD.EXE --- ID : 0xea1
[+] Process Name : NOTEPAD.EXE --- ID : 0xea2
[+] Process Name : NOTEPAD.EXE --- ID : 0xea3
[+] Process Name : wmiprvse.exe --- ID : 0xf40
[+] Process Name : wmiprvse.exe --- ID : 0xf41
[+] Process Name : wmiprvse.exe --- ID : 0xf42
[+] Process Name : wmiprvse.exe --- ID : 0xf43
[+] Process Name : mdm.exe --- ID : 0xfa8
[+] Process Name : mdm.exe --- ID : 0xfa9
[+] Process Name : mdm.exe --- ID : 0xfaa
[+] Process Name : mdm.exe --- ID : 0xfab


Hop et voilà on a retrouvé notre calculatrice avec 0x3f4 comme ID et elle nous dis elle même que ça vaut 1012 en décimal :)).
Bref voilà je pourrais me coucher l'esprit tranquille maintenant :).

Je vous file le code, pas besoin de détailler c'est pas bien compliquer : ListAllProcesses.cpp

Le binaire est dispo ici : http://lilxam.free.fr/index.php?path=/repo/coding/windows/ListAllProcesses

mardi 19 février 2008

Gestionnaire des services windows

Hi all :)
Bon en ce moment je sais pas trop quoi faire alors me suis codé un petit prog pour gérer les services win. Ce prog se décompose en 5 fonctions à savoir :

-Enumération des service. Il suffit d'utiliser l'API EnumServicesStatusEx :


BOOL WINAPI EnumServicesStatusEx(
__in SC_HANDLE hSCManager,
__in SC_ENUM_TYPE InfoLevel,
__in DWORD dwServiceType,
__in DWORD dwServiceState,
__out_opt LPBYTE lpServices,
__in DWORD cbBufSize,
__out LPDWORD pcbBytesNeeded,
__out LPDWORD lpServicesReturned,
__inout_opt LPDWORD lpResumeHandle,
__in_opt LPCTSTR pszGroupName
);


Référence : http://msdn2.microsoft.com/en-us/library/ms682640(VS.85).aspx

On remplie ensuite la structure ENUM_SERVICE_STATUS_PROCESS dont voici la définition :


typedef struct _ENUM_SERVICE_STATUS_PROCESS {
LPTSTR lpServiceName;
LPTSTR lpDisplayName;
SERVICE_STATUS_PROCESS ServiceStatusProcess;
} ENUM_SERVICE_STATUS_PROCESS,
*LPENUM_SERVICE_STATUS_PROCESS;


Référence : http://msdn2.microsoft.com/en-us/library/ms682648(VS.85).aspx
On s'aperçoit de la présence de la structure SERVICE_STATUS_PROCESS :


typedef struct _SERVICE_STATUS_PROCESS {
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
DWORD dwProcessId;
DWORD dwServiceFlags;
} SERVICE_STATUS_PROCESS,
*LPSERVICE_STATUS_PROCESS;


Référence : http://msdn2.microsoft.com/en-us/library/ms685992(VS.85).aspx

A l'aide de ces deux structures on peut déjà en connaitre pas mal sur les services.



-Démarrage d'un service. Ici on a besoin de récupérer un handle sur le service avec la fonction OpenService() puis d'utiliser la fonction StartService() pour le démarrer. Quelque fois certains services refusent d'être démarrer par n'importe quel processus. Vous risquez donc d'avoir des erreurs avec la fonction. Les prototypes des fonctions :


SC_HANDLE WINAPI OpenService(
__in SC_HANDLE hSCManager,
__in LPCTSTR lpServiceName,
__in DWORD dwDesiredAccess
);


Référence : http://msdn2.microsoft.com/en-us/library/ms684330(VS.85).aspx


BOOL WINAPI StartService(
__in SC_HANDLE hService,
__in DWORD dwNumServiceArgs,
__in_opt LPCTSTR* lpServiceArgVectors
);


Référence : http://msdn2.microsoft.com/en-us/library/ms686321(VS.85).aspx

-Arrêt d'un service. Pour celà on récupère un handle sur le service et on l'arrête avec ControlService() :


BOOL WINAPI ControlService(
__in SC_HANDLE hService,
__in DWORD dwControl,
__out LPSERVICE_STATUS lpServiceStatus
);


Référence : http://msdn2.microsoft.com/en-us/library/ms682108(VS.85).aspx

-Création d'un service. On a juste besoin de l'API CreateService() et le tour est joué :


SC_HANDLE WINAPI CreateService(
__in SC_HANDLE hSCManager,
__in LPCTSTR lpServiceName,
__in_opt LPCTSTR lpDisplayName,
__in DWORD dwDesiredAccess,
__in DWORD dwServiceType,
__in DWORD dwStartType,
__in DWORD dwErrorControl,
__in_opt LPCTSTR lpBinaryPathName,
__in_opt LPCTSTR lpLoadOrderGroup,
__out_opt LPDWORD lpdwTagId,
__in_opt LPCTSTR lpDependencies,
__in_opt LPCTSTR lpServiceStartName,
__in_opt LPCTSTR lpPassword
);


Référence : http://msdn2.microsoft.com/en-us/library/ms682450(VS.85).aspx

-Effacer un service. On récupère un handle sur le service, on l'arrête et on l'efface avec DeleteService().

Voilà, rien de bien compliqué.



Le code : gerstionnaire_services.cpp

Le code + binaire : gestionnaire_services.zip

PS: Ceci peut par exemple servir à installer un driver :)

PS2: Au passage j'en profite pour vous faire remarquer mon nouveau repo à l'adresse http://lilxam.free.fr/

Have Fun :)
lilxam.

dimanche 3 février 2008

Stack Watcher/Registers Viewer

Plop all :)
Voilà quelque temps que ce sujet m'intriguais, j'ai décidé de faire un petit programme pour voir l'état des registres d'un thread en temps réel.
Voici comme on va se dépatouiller :

1.La rien de bien compliqué, on récupère l'id du processus voulu.

Les APIs nécessaires :
-CreateToolhelp32Snapshot() -> http://msdn2.microsoft.com/en-us/library/ms682489(VS.85).aspx
-Process32First() -> http://msdn2.microsoft.com/en-us/library/ms684834(VS.85).aspx
-Process32Next() -> http://msdn2.microsoft.com/en-us/library/ms684836(VS.85).aspx
Sans oublier notre structure PROCESSENTRY32. -> http://msdn2.microsoft.com/en-us/library/ms684839(VS.85).aspx

typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];
} PROCESSENTRY32,
*PPROCESSENTRY32;

2.On établit la liste de tous les threads en cour d'execution. Comme pour créer une liste des processus CreateToolhelp32Snapshot() mais avec TH32CS_SNAPTHREAD en premier argument.

3.On parcourt et recherche les threads appartenant à notre processus. On parcourt la liste des threads avec :
-Thread32First() -> http://msdn2.microsoft.com/en-us/library/ms686728(VS.85).aspx
-Thread32Next() -> http://msdn2.microsoft.com/en-us/library/ms686731(VS.85).aspx
Et on remplit la structure THREADENTRY32 -> http://msdn2.microsoft.com/en-us/library/ms686735(VS.85).aspx

typedef struct tagTHREADENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ThreadID;
DWORD th32OwnerProcessID;
LONG tpBasePri;
LONG tpDeltaPri;
DWORD dwFlags;
} THREADENTRY32,
*PTHREADENTRY32;

Ceci reste très similaire à la façon de traiter les processus.

4.On récupère les informations sur la pile. Ce qui nous interresse.
Pour celà on doit stopper l'execution du thread avec SuspendThread() et reprendre son execution avec ResumeThread. Entre temps on aura utilisé la fonction
GetThreadContext() :

BOOL WINAPI GetThreadContext(
__in HANDLE hThread,
__inout LPCONTEXT lpContext
);

qui nous permet de récupérer les inforamtions sur la pile au travers de la structure CONTEXT (à voir dans winnt.h) :

typedef struct _CONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;


Voilà on a donc maintenant un dump des registres de notre processus.
Un petit rappel sur les registres :

Les registres principaux :

EAX : Registre 32 bits. 16 bits : Ax formé par Ah : 8 bits et Al : 8bits. Fonction : Accumulateur

EBX : Registre 32 bits. 16 bits : Bx formé par Bh : 8 bits et Bl : 8bits. Fonction : Base, utilisé lors de l'accès à une zone mémoire.

ECX : Registre 32 bits. 16 bits : Cx formé par Ch : 8 bits et Cl : 8bits. Fonction : Compteur.

EDX : Registre 32 bits. 16 bits : Dx formé par Dh : 8 bits et Dl : 8bits. Fonction : Stockage de données.

EIP (Instruction Pointer) : Registre 32 bits. Pointe sur la prochaine instruction a executer.

ESI (Source Index) : Registre 32 bits. Pointer sur la variable source.

EDI (Destination Pointer) : Registre 32 bits. Pointer sur la variable destinataire.

EBP (Base Pointer) : Registre 32 bits. Pointe sur le premier élémente de la pile.

ESP (Stack Pointer) : Registre 32 bits. Pointe sur le dernier élément de la pile.


Les registres debug :

Une bonne doc ici : http://en.wikipedia.org/wiki/Debug_register

Les registres de Segments :

CS (Code Segment) : Mémorise le segment où se trouve le code en cours d'execution

DS (Data Segment) : Mémorise le segment où se trouvent les données du programme

ES (Extra Segment) : Il peut être utilisé à faire ce que l'on veut.

SS (Stack Segment) : Mémorise le segment où se trouve la pile de données du programme.

Le code : Stack.cpp
Le projet + binaire : StackWatcher.zip

Voilà ce sera tout pour cet article.
Have Fun ;)
lilxam.

vendredi 25 janvier 2008

Sniffer TCP with Raw Sockets

Plop all :)
aujourd'hui je me penche un peu sur les raw sockets et je vous propose ce petit code qui permet de sniffer les trames TCP entrentent. Bon ici je montre que les bases mais le code ne demande qu'à être renchérit.

Le principe est simple, on créé un socket qui va écouter et intercepter toutes les données qui passent notre réseau. La création du socket se fait presque normalement, si ce n'est qu'il ne faut pas oublier d'activer le mode promiscuous de la carte réseau, à savoir grace à la fonction WSAIoctl().

Référence de la fonction : http://msdn2.microsoft.com/en-us/library/ms741621(VS.85).aspx

Prototype de la fonction WASIoctl() :

int WSAIoctl(
__in SOCKET s,
__in DWORD dwIoControlCode,
__in LPVOID lpvInBuffer,
__in DWORD cbInBuffer,
__out LPVOID lpvOutBuffer,
__in DWORD cbOutBuffer,
__out LPDWORD lpcbBytesReturned,
__in LPWSAOVERLAPPED lpOverlapped,
__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine


Ensuite on fait un simple recv() et le tour est joué, on peux récupérer la trame TCP.
Viens ensuite le traitement, il faut récupérer les données dont nous avons besoin.
Voyons ces deux schémas issuent de www.frameip.com


Entête IP:





Entête TCP:





De là on peut en déduire deux structures, une qui contiendra l'entete IP et l'autre l'entete TCP. Toutefois ceci reste minimaliste.
typedef struct iphdr //Entete IP
{
unsigned char IHL:4;
unsigned char Version :4;
unsigned char TypeOfService;
unsigned short TotalLength;
unsigned short ID;
unsigned char FlagOffset :5;
unsigned char MoreFragment :1;
unsigned char DontFragment :1;
unsigned char ReservedZero :1;
unsigned char FragOffset;
unsigned char Ttl;
unsigned char Protocol;
unsigned short Checksum;
unsigned int Source;
unsigned int Destination;
}IP_HDR;

typedef struct tcphdr // Entente TCP
{
unsigned short PortSource;
unsigned short PortDest;
unsigned int seqnum;
unsigned int acknum;
unsigned char unused:4, tcp_hl:4;
unsigned char flags;
unsigned short window;
unsigned short checksum;
unsigned short urgPointer;
} TCP_HDR;

Et voilà il ne nous reste plus qu'à remplir les structures et le tour est joué!

De la doc sur : http://www.frameip.com/
http://msdn2.microsoft.com/en-us/library/ms741394%28VS.85%29.aspx

Le code : main.cpp

Le projet + binaire : SnifferTCP.zip

Have Fun ;)
lilxam.

dimanche 13 janvier 2008

PE Analyser

Bonjour,
aujourd'hui je me penche sur le format PE. J'ai donc fais ce petit programme qui permet de récupérer quelques informations sur les entetes, sections et la table des imports. J'ai essayé de faire un code clair ainsi que d'accompagner toutes les structures que j'ai utilisé de leur définition, elles se situent toutes dans winnt.h.

Voici le code : PEAnalyser.cpp
De la doc : Format PE

Have Fun ;)
lilxam

samedi 12 janvier 2008

Injection de dll dans un processus

Aujourd'hui je vais vous présenter une méthode plutot connue pour injecter une dll dans un processus. Pour celà on va d'abord faire un loader qui s'ocuppera de charger notre dll dans un processus puis on construira ensuite celle-ci.
Pour le loaders on distingue 5 étapes :

1.Récupérer l'adresse de LoadLibraryA()
Pour récupérer l'adresse de LoadLibraryA() il suffit d'utiliser la fonction GetModuleHandleA(). Le prototype de la fonction :

HMODULE WINAPI GetModuleHandle(
__in_opt LPCTSTR lpModuleName
);


2.Ouvrir le processus voulu
Pour celà on créera une liste de tous les processus actifs et on récupèrera l'id de celui voulu. On ouvrira simplement le processus avec OpenProcess(). Le prototype de la fonction :
HANDLE WINAPI OpenProcess(
__in DWORD dwDesiredAccess,
__in BOOL bInheritHandle,
__in DWORD dwProcessId
);


3.Allouer un espace de mémoire dans le processus
Pour allouer un espace de mémoire on utilisera VirtualAllocEx(). Le prototype de la fonction :
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess,
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);


4.Ecrire les donnes necessaires au chargement de la dll
Pour ceci on va utiliser WriteProcessMemory(). On pourrait écrire quelque chose du genre LoadLibraryA("dll.dll") dans le processus, ce qui donne en assembleur :
PUSH offset_nom_dll
CALL LoadLibraryA
RET
Mais pour faire simple on se contentera d'écrire seulement le nom de la dll dans l'espace de mémoire et on éxecutera LoadLibraryA() grace à notre thread.
Le prototype de la fonction WriteProcessMemory est :
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess,
__in LPVOID lpBaseAddress,
__in LPCVOID lpBuffer,
__in SIZE_T nSize,

__out SIZE_T* lpNumberOfBytesWritten
);

5.Créer un thread dans le processus afin d'excuter le code écris dans l'espace de mémoire alloué
C'est l'étape la plus importante, ici on utilisera CreateRemoteThread() pour créer un thread dans le processus qui executera LoadLibraryA() avec en parametre le nom de notre dll. Le prototype de la fonction :
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);

Viens ensuite notre dll. Je vais faire simple pour bien montrer le concept.
Lorsqu'on va charger notre dll avec LoadLibaryA(), la fonction va ensuite appeler la fonction main de la Dll avec DLL_PROCESS_ATTACH comme second parametre. On vérifiera donc que le seconde parametre est bien à cette valeur et le tour est joué.
Vous trouverez plus d'info ici : http://msdn2.microsoft.com/en-us/library/ms684175(VS.85).aspx
et ici :
http://msdn2.microsoft.com/en-us/library/ms682583(VS.85).aspx

Le code de la dll : Injectme.cpp
Le code du loader : DllInjector.cpp

Voilà ce sera tout pour aujourd'hui.
Have Fun :)
lilxam.