lundi 31 août 2009

New Bl0g - I Moved !

Voilà bien longtemps que je n'avais pas fait acte de présence, je vous annonce que j'ai déménagé chez tuxfamily pour héberger un nouveau blog. J'en avais un peu marre de Blogspot et j'ai préféré opter pour Wordpress.
Sans plus attendre : Lilxam
Vous aurez droit à un tout nouvel article :).

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.