<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6861594251940891157</id><updated>2011-08-18T14:22:15.309+02:00</updated><category term='linux'/><category term='debuggeur'/><category term='CreateRemoteThread'/><category term='intellitamper 2.07'/><category term='techniques anti debug'/><category term='IAT'/><category term='NtGlobalFlags'/><category term='cacher DLL'/><category term='SEH'/><category term='UPX 3.03'/><category term='cave method'/><category term='non intrusif'/><category term='CheckRemoteDebuggerPresent'/><category term='ApLib'/><category term='IsDebuggerPresent'/><category term='stack overflow'/><category term='FSG 2.0'/><category term='TH32CS_SNAPMODULE'/><category term='GCC'/><category term='hide modules'/><category term='SetWindowsHookEx'/><category term='Process Explorer'/><category term='_IsNonwritableInCurrentImage'/><category term='Stack Smashing Protection'/><category term='free() overflow'/><category term='trick'/><category term='tool us3l3ss'/><category term='CreateToolhelp32Snapshot'/><category term='EnumProcessModules'/><category term='INT 0x2E'/><category term='injection DLL'/><category term='packer'/><category term='windows'/><category term='unpacker'/><category term='buffer overflow'/><category term='VirtualBox ca pue'/><category term='double-free() error'/><category term='Nt QueryInformationProcess'/><category term='DebugActiveProcess'/><category term='loader'/><category term='PE reader'/><category term='SSP'/><title type='text'>Pérégrination d'un wanabee-hacker</title><subtitle type='html'>Ici seront décrites toutes les expériences foireuses que j'entreprend dans le but de devenir maitre du mOnde.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-1875712133312216789</id><published>2009-10-22T17:01:00.033+02:00</published><updated>2009-10-24T12:02:44.954+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='INT 0x2E'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualBox ca pue'/><category scheme='http://www.blogger.com/atom/ns#' term='techniques anti debug'/><category scheme='http://www.blogger.com/atom/ns#' term='trick'/><title type='text'>INT 0x2E a la trick</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:arial;"&gt;&lt;span style="font-style: italic;"&gt;Je m'excuse de la présentation hasardeuse de ce post (notamment la page vide), blogger c'est de la bouse.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Afin de prouver au monde entier que je ne suis pas complètement mort, je me permet de mettre ici une petite analyse d'un trick anti-unpacker qui n'a pas reçu l'attention qu'il mérite à mon humble avis. Il n'est pas compliqué et pas très méchant mais il peut casser los boulos quand on le découvre.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;En effet, il n'est pas présent dans la &lt;/span&gt;&lt;a style="font-family: arial;" href="http://pferrie.tripod.com/papers/unpackers.pdf"&gt;Holy Bible&lt;/a&gt;&lt;span style="font-family:arial;"&gt; de l'unpacking de notre ami Peter et à ma connaissance la seule référence dans la littérature se trouve dans les slides d'une présentation faite récemment lors de la dernière conférence VB par &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.virusbtn.com/pdf/conference_slides/2009/Baumgartner-VB2009.pdf"&gt;Kurt Baumgartner&lt;/a&gt;&lt;span style="font-family:arial;"&gt;. Mais cette analyse, qui décrit le trick comme "Int 0x2e 0xc0000005 location generation trick" est un peu trop rapide, donc j'en profite pour réveiller mon blog.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Comme tu l'a déjà deviné cher lecteur, ce trick utilise l'interruption 0x2E qui&lt;/span&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt; permettait de lancer dans « l’ancien temps » les appels systèmes Windows : on plaçait le numéro de l’appel dans le registre EAX, ses arguments dans EDX et hop ! Depuis, l’instruction SYSENTER à remplacé ce bouzin, car plus rapide. Mais bien sur INT 0x2E traine toujours sa ganache dans le coin pour des questions de compatibilité. Finalement, l'instruction n'est pas documentée par Microsoft, ce qui impose une approche "black box" si, comme moi, on est faignant et peu porté dans l'architecture Windows.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:100%;"  &gt;&lt;span style="font-size:130%;"&gt;&lt;span&gt;I- Utilisation "basique"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;Le trick utilisé de la façon la plus simple possible donne :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;&lt;span style="font-size:85%;"&gt;B8 FFFFFFFF&lt;span style="color: rgb(0, 0, 0);"&gt;____&lt;/span&gt;MOV EAX,-1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;CD 2E&lt;span style="color: rgb(0, 0, 0);"&gt;__________&lt;/span&gt;&lt;/span&gt;INT 2E&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;&lt;span style="font-size:85%;"&gt;66:817A FE CD2&lt;span style="color: rgb(0, 0, 0);"&gt;_&lt;/span&gt;CMP WORD PTR DS:[EDX-2],&lt;span style="color: rgb(204, 0, 0);"&gt;2ECD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;On appelle donc l’interruption avec comme numéro de syscall "-1" (ce qui est invalide).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;Le comportement « normal » dans ce cas là est de faire échouer le syscall en plaçant &lt;span style="font-weight: bold;"&gt;un code d’erreur dans EAX&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;(0xC000001C) &lt;/span&gt;et en &lt;span style="font-weight: bold;"&gt;faisant pointer EDX vers l’instruction suivant l'interruption&lt;/span&gt;.  Donc dans notre exemple, EDX-2 pointe sur le début de l'instruction INT 2E dont les opcodes sont bien 2ECD en little-endian.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;Par contre sous contrôle d’OllyDbg (v1 ou v2), le registre EDX va être mis à 0xFFFFFFFF si on passe l’interruption en « single-step ». Dans ce cas là un accès mémoire invalide sera réalisé lors de la comparaison, ce qui fera planter le programme.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;Remarquons que ce trick devient aussi « anti-VM » dans le cas de &lt;span style="font-style: italic;"&gt;VirtualBox&lt;/span&gt; de Sun (&lt;span style="font-style: italic;"&gt;EDIT: Voir commentaires)&lt;/span&gt;, puisque même sans être sous le contrôle du débuggeur le registre EDX est mis à 0xFFFFFFFF à tous les coups, sûrement une mauvaise implémentation des interruptions... Une raison de plus (avec la non-implémentation des hardwares breakpoints lorsqu’on n’utilise pas les techniques de virtualization matérielle) pour rester sur VMWare pour l’analyse de malwares.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;Finalement, il est utile contre tout émulateur qui n'implémentent pas les interruption de façon rigoureuse.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;II- Utilisation "avancée"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:arial;"&gt;Ce qui n'est pas dit dans la littérature et qui est déjà connu des méchants (par exemple ceux qui font le packer de Waledac), c'est que :&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul  style="text-align: justify;font-family:arial;"&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;d'une part, en plaçant autre chose dans EAX que "-1" la valeur de retour va varier et donner divers code d'erreur, tout ceci de façon "stable" (on nike pas tout dude). Pour vérifier cela on se fait un petit programme qui appelle l'interruption sur divers paramètres, voici les premières valeurs qu'on obtient :&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:100%;"&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;caption&gt; INT 2E return values &lt;/caption&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; Parameter &lt;/th&gt;&lt;br /&gt;&lt;th&gt; Return value &lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0xFFFFFFFF &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC000001C &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x0-0x1 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000005 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x2 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC000005C &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x3 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000005 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x4-0x8 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC000000D &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x9 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000002 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0xA-0xC &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000005 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0xD &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000008 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0xE-0x10 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000005 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x11 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC00000F1 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; 0x12 &lt;/th&gt;&lt;br /&gt;&lt;td&gt; 0xC0000141 &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; ... &lt;/th&gt;&lt;br /&gt;&lt;td&gt; ... &lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:arial;"&gt;Il y a donc certaines valeurs particulières, ce qui fait un levier de plus pour détecter un émulateur|débuggeur|VM-pourrie-de-chez-Sun.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul  style="text-align: justify;font-family:arial;"&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;  d'autre part, ECX doit normalement toujours être positionné sur ESP après la levée de l'interruption.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:arial;"&gt;Tout ca peut donner lieu à des utilisations plus rigolote du trick, comme celle-ci vu récemment dans mon malware préféré :&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:arial;"&gt;Le code démarre sur ça :&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;span style="font-size:85%;"&gt;68 &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);font-size:85%;" &gt;CD2E&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);font-size:85%;" &gt;EB08&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;___&lt;/span&gt;PUSH 8EB2ECD&lt;span style="color: rgb(0, 0, 0);"&gt;________________&lt;/span&gt;; &lt;/span&gt;&lt;span style="color: rgb(204, 0, 0);font-size:85%;" &gt;INT 2E&lt;/span&gt;&lt;span style="font-size:85%;"&gt; camouflé&lt;br /&gt;58&lt;span style="color: rgb(0, 0, 0);"&gt;____________&lt;/span&gt;POP EAX&lt;br /&gt;2D C42EEB08&lt;span style="color: rgb(0, 0, 0);"&gt;___&lt;/span&gt;SUB EAX,8EB2EC4&lt;span style="color: rgb(0, 0, 0);"&gt;_____________&lt;/span&gt;; EAX = 9&lt;br /&gt;EB F4&lt;span style="color: rgb(0, 0, 0);"&gt;_________&lt;/span&gt;JMP SHORT Waledac_.00401153 ; JMP sur le &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);font-size:85%;" &gt;INT 2E&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div style="text-align: justify;"&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;&lt;span style="font-size:100%;"&gt;Donc on saute sur le INT 2E camouflé au milieu du premier PUSH, ce qui donne à ce moment là le code suivant (les commentaires donnent les valeurs "attendues") :&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:100%;"&gt;&lt;span style=";font-family:courier new;font-size:100%;"  &gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-size:85%;" &gt;CD 2E&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;_______&lt;/span&gt;INT 2E&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);font-size:85%;" &gt;EB 08&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;_______&lt;/span&gt;JMP SHORT &lt;span style="color: rgb(204, 51, 204);"&gt;Waledac_.0040115F&lt;/span&gt;&lt;br /&gt;58&lt;span style="color: rgb(0, 0, 0);"&gt;__________&lt;/span&gt;POP EAX&lt;br /&gt;2D C42EEB08&lt;span style="color: rgb(0, 0, 0);"&gt;_&lt;/span&gt;SUB EAX,8EB2EC4&lt;br /&gt;EB F4&lt;span style="color: rgb(0, 0, 0);"&gt;_______&lt;/span&gt;JMP SHORT Waledac_.00401153&lt;br /&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;52&lt;span style="color: rgb(0, 0, 0);"&gt;__________&lt;/span&gt;PUSH EDX&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;____________________&lt;/span&gt;; adresse qui suit INT2E (0x401155)&lt;br /&gt;91&lt;span style="color: rgb(0, 0, 0);"&gt;__________&lt;/span&gt;XCHG EAX,ECX&lt;span style="color: rgb(0, 0, 0);"&gt;________________&lt;/span&gt;; EAX=ESP, ECX=0xC0000002&lt;br /&gt;0FC9&lt;span style="color: rgb(0, 0, 0);"&gt;________&lt;/span&gt;BSWAP ECX&lt;span style="color: rgb(0, 0, 0);"&gt;___________________&lt;/span&gt;; ECX=0x020000C0&lt;br /&gt;C1E1 04&lt;span style="color: rgb(0, 0, 0);"&gt;_____&lt;/span&gt;SHL ECX,4&lt;span style="color: rgb(0, 0, 0);"&gt;___________________&lt;/span&gt;; ECX=0x20000C00&lt;br /&gt;8B00&lt;span style="color: rgb(0, 0, 0);"&gt;________&lt;/span&gt;MOV EAX,DWORD PTR DS:[EAX]&lt;span style="color: rgb(0, 0, 0);"&gt;__&lt;/span&gt;; adresse de retour initiale&lt;br /&gt;2B4424 04&lt;span style="color: rgb(0, 0, 0);"&gt;___&lt;/span&gt;SUB EAX,DWORD PTR SS:[ESP+4]; EAX = 0&lt;br /&gt;03C8&lt;span style="color: rgb(0, 0, 0);"&gt;________&lt;/span&gt;ADD ECX,EAX&lt;span style="color: rgb(0, 0, 0);"&gt;_________________&lt;/span&gt;; ECX=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;0x20000C00&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;81E9 FAE5FF&lt;span style="color: rgb(0, 0, 0);"&gt;_&lt;/span&gt;SUB ECX,1FFFE5FA&lt;span style="color: rgb(0, 0, 0);"&gt;____________&lt;/span&gt;; ECX=0x00002606&lt;br /&gt;03CA&lt;span style="color: rgb(0, 0, 0);"&gt;________&lt;/span&gt;ADD ECX,EDX&lt;span style="color: rgb(0, 0, 0);"&gt;_________________&lt;/span&gt;; ECX = &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;0x401155 + 0x00002606&lt;/span&gt; = 0x40375B&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;870C24&lt;span style="color: rgb(0, 0, 0);"&gt;______&lt;/span&gt;XCHG DWORD PTR SS:[ESP],ECX&lt;br /&gt;FF1424&lt;span style="color: rgb(0, 0, 0);"&gt;______&lt;/span&gt;CALL DWORD PTR SS:[ESP]&lt;span style="color: rgb(0, 0, 0);"&gt;_____&lt;/span&gt;; CALL &lt;/span&gt; 0x40375B -&gt; HERE WE GO 3v1L!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:arial;"&gt;On voit dans ce petit exemple comment sont utilisés les trois leviers possibles de ce trick :&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul style="font-family: arial; text-align: justify;"&gt;&lt;li&gt;la valeur de retour qui doit être le code d'erreur associé à l'appel système (comme on passe pas d'arguments dans EDX, y a peu de risque que l'appel système fonctionne).&lt;/li&gt;&lt;li&gt;l'adresse mise dans EDX qui doit normalement être celle de l'instruction qui suit la levée de l'interruption.&lt;/li&gt;&lt;li&gt;ECX doit être égal à ESP après la levée de l'interruption.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family:arial;"&gt;En jouant avec les valeurs de retours on peut faire beaucoup de tricks différents pour tester l'implémentation de cette interruption, that's not so bad.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Bon allez je retourne dans ma grotte!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-1875712133312216789?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/1875712133312216789/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=1875712133312216789' title='7 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/1875712133312216789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/1875712133312216789'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2009/10/int-0x2e-la-trick.html' title='INT 0x2E a la trick'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-2852884060077664022</id><published>2009-02-16T23:30:00.004+01:00</published><updated>2009-02-16T23:48:17.851+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='_IsNonwritableInCurrentImage'/><category scheme='http://www.blogger.com/atom/ns#' term='IAT'/><category scheme='http://www.blogger.com/atom/ns#' term='UPX 3.03'/><category scheme='http://www.blogger.com/atom/ns#' term='packer'/><title type='text'>Oupsx...</title><content type='html'>&lt;div style="text-align: justify;"&gt;Cette semaine j'ai mis le nez dans le code de UPX 3.03, un packer connu pour être très facile à unpacker (ce qui se comprend puisque ce n'est pas pour ça qu'il a été conçu). Mais comme pour FSG, mon but n'était pas de faire de l'unpacking mais plutôt de comprendre comment le loader (le "stub" dans la terminologie UPX) fonctionne et réalise son unpacking. Ces stubs sont programmés en ASM et les commentaires sont plutôt laconiques, donc ça vaut le coup de sortir son débuggeur préféré pour comprendre à la main :-)&lt;br /&gt;&lt;br /&gt;Ca ma permit de découvrir une "feature" assez marrante @Microsoft : quand on compile avec Visual Studio C++ un programme qui fait des opérations flottantes, le programme va vérifier dans le header PE que les sections de la mémoire qui ne doivent pas être "écrivables" (typiquement .text et .rdata) le sont bien. Sinon il déclenche un joli message "R6002: floating point not loaded error" et votre programme plante lamentablement. Le "side-effect" c'est que quand un packer lambda (comme FSG) décompresse son exécutable dans une zone mémoire (donc avec les droits d'écritures) il laisse les droits et donc le programme plante.&lt;br /&gt;UPX résoud le problème en changeant les droits juste avant de jumper sur l'OEP mais ça implique un appel à VirtualProtect() pour pouvoir modifier le PE header (+ 1 pour remettre les anciens droits) et d'écrire dans la mémoire, donc une perte de temps.&lt;br /&gt;Voir &lt;a href="http://nezumi-lab.org/blog/?p=73"&gt;le post&lt;/a&gt; de kpnc sur le sujet.&lt;br /&gt;&lt;br /&gt;Ayant une expérience très restreinte je ne sais pas comment les autres packers s'en sortent. Do you have any idea ?&lt;br /&gt;&lt;br /&gt;Sur ce, &lt;a href="http://kqkq12.ifrance.com/travail/UPX%203.03%20-%20keynote.pdf"&gt;voici le bouzin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-2852884060077664022?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/2852884060077664022/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=2852884060077664022' title='6 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/2852884060077664022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/2852884060077664022'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2009/02/oupsx.html' title='Oupsx...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-8566624335560367816</id><published>2009-02-09T03:50:00.004+01:00</published><updated>2009-02-09T04:03:56.668+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ApLib'/><category scheme='http://www.blogger.com/atom/ns#' term='FSG 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='loader'/><category scheme='http://www.blogger.com/atom/ns#' term='packer'/><category scheme='http://www.blogger.com/atom/ns#' term='unpacker'/><title type='text'>De retour...</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;Pour te jouer un mauvais tour&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Je suis toujours vivant, et j'espère avoir de nouveau le temps d'alimenter ce blog :-)&lt;br /&gt;&lt;br /&gt;Ces temps-ci je travaille sur les packers et j'essaye de décortiquer leur fonctionnement avec plus ou moins de succès... J'ai commencé petit, donc par les packers les plus simples qui ne font que de la compression. Tout ça pour dire que j'écris des petites keynotes me permettant de me rapeller facilement ce que j'ai compris, il ne s'agit pas du tout d'un travail pédagogique (en gros c'est incompréhensible) mais sait-on jamais, ça peut peut-être dépanner quelqu'un :-)&lt;br /&gt;&lt;br /&gt;La première est sur FSG 2.0, un packer très simple dont j'ai étudié le loader sans m'occuper de l'aspect compression qui a déjà été très bien expliqué par &lt;a href="http://beatrix2004.free.fr/FSG.pdf"&gt;Beatrix.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tu la trouvera &lt;a href="http://kqkq12.ifrance.com/travail/FSG%202.0%20-%20keynote.pdf"&gt;ici&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;J'ai aussi rajouté mon mail dans la colonne de droite, histoire que si tu est timide et que tu as vu des bourdes dans mon bouzin tu puisses m'insulter.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-8566624335560367816?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/8566624335560367816/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=8566624335560367816' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8566624335560367816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8566624335560367816'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2009/02/de-retour.html' title='De retour...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-8007794280079249068</id><published>2008-08-13T10:59:00.002+02:00</published><updated>2008-08-13T11:20:55.263+02:00</updated><title type='text'>Holidays, sometimes holidays...</title><content type='html'>&lt;span style="font-style: italic;"&gt;Genre tu laches ton PaiCai ?!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bon en fait pas vraiment, mais (pour une fois) je vais raconter ma vie : je pars au Canada dans 7 jours pour une année : ca va être hallluucccccinant ! Mais le temps que je m'installe, que je règle tous les problèmes qui vont très certainement arriver... Bref, avant que je puisse rebosser tranquillement sur mes petits projets, un bon mois va se passer. Donc l'activité de ce bl0g sera réduite.&lt;br /&gt;&lt;br /&gt;Pour pas te laisser sur ta faim cher lecteur, je te livre quand même un &lt;a href="http://calvet.joan.free.fr/travail/iat.c"&gt;petit source&lt;/a&gt;, il s'agit d'un dumper d'IAT, tu lui donnes le PID de ton process cible et il va t'afficher l'Import Address Table du module exécutable du process. Rien de c00l, mais ça peut facilement se modifier pour faire du hook d'IAT. Sinon, je commence à me lancer sur des outils un peu plus complexes, et j'essaye de me diversifier en étudiant quelques applis par ci par là, so see you soon ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-8007794280079249068?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/8007794280079249068/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=8007794280079249068' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8007794280079249068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8007794280079249068'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/08/holidays-sometimes-holidays.html' title='Holidays, sometimes holidays...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-5243440364002869839</id><published>2008-08-06T15:00:00.000+02:00</published><updated>2008-08-06T15:00:34.418+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EnumProcessModules'/><category scheme='http://www.blogger.com/atom/ns#' term='CreateToolhelp32Snapshot'/><category scheme='http://www.blogger.com/atom/ns#' term='TH32CS_SNAPMODULE'/><category scheme='http://www.blogger.com/atom/ns#' term='Process Explorer'/><category scheme='http://www.blogger.com/atom/ns#' term='cacher DLL'/><category scheme='http://www.blogger.com/atom/ns#' term='hide modules'/><title type='text'>Cachez ce module que je ne saurai voir...</title><content type='html'>&lt;span style="font-style: italic;"&gt;Putin qu'est ce qu'il fait chaud...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;L'affichage des modules chargés par un processus ( les DLLs kwa !) de façon fiable est un problème qui se pose rapidement quand on commence à foutre le dawa dans la mémoire.&lt;br /&gt;&lt;br /&gt;Il y a deux méthodes fort connues basées sur des fonctions documentées par Microsoft...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;1- Cheese !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La première façon c'est d'utiliser CreateToolhelp32Snapshot() avec TH32CS_SNAPMODULE en premier argument, ça nous retourne un HANDLE sur un snapshot ( une "image" à un instant t de la mémoire, dans notre cas des modules ) et il suffit de se promener à partir de ce HANDLE avec la fonction Module32Next() pour récupérer une structure MODULEENTRY32 qui donne le nom de chaque module, son adresse de base, son chemin...&lt;br /&gt;&lt;br /&gt;Le code source du bouzin est &lt;a href="http://calvet.joan.free.fr/travail/process_viewver_snapshot.c"&gt;ici&lt;/a&gt;, j'ai aussi utilisé cette API pour lister les threads d'un process ( même méthode sauf qu'on parcourt des THREADENTRY32 ce coup ci).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;2- EnumProcessModules()&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;La deuxième f0cking way de lister les modules c'est d'utiliser une fonction qui porte bien son nom : EnumProcessModules()... Ca nous remplit un tableau avec des HANDLEs sur tous les modules chargés en mémoire pour un processus donné, ensuite on récupère les infos intéressantes avec les fonctions GetModuleBaseName(), GetModuleFileNameEx() et GetModuleInformation().&lt;br /&gt;&lt;br /&gt;Le code source du bouzin est &lt;a href="http://calvet.joan.free.fr/travail/process_viewver_enum.c"&gt;là&lt;/a&gt;, rien de bien particulier à dire.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;3- Euh oué... et alors ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Là cher lecteur t'a envie de me dire "Chapi chapo jojo, t'a réussi à utiliser des fonctions documentés pour faire exactement la même chose de deux manières différentes, putin tu roxsamere". Oui mais c'est là que ça devient intéressant...&lt;br /&gt;&lt;br /&gt;Si on s'interesse à la structure du Process Executiv Block (celle qui "décrit" un processus en user-land), son troisième champ est :&lt;br /&gt;&lt;br /&gt;PEB_LDR_DATA                * LdrData;&lt;br /&gt;&lt;br /&gt;Et la structure PEB_LDR_DATA contient (entre autre) :&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;LIST_ENTRY          InLoadOrderModuleList;&lt;br /&gt;LIST_ENTRY          InMemoryOrderModuleList;&lt;br /&gt;LIST_ENTRY          InInitializationOrderModuleList;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;C'est à dire le point de départ vers trois listes doublement chainées ( la structure LIST_ENTRY n'est constituée que deux pointeurs, l'un vers "l'avant", l'autre vers "l'arrière" ) qui vont liées entre elles des structures LDR_DATA_ENTRY décrivant les modules chargées en mémoire dans trois ordres différents...&lt;br /&gt;&lt;br /&gt;Cette structure contient la suite du chainage dans ses trois premiers champs :&lt;br /&gt;&lt;br /&gt;LIST_ENTRY              InLoadOrderModuleList;&lt;br /&gt;LIST_ENTRY              InMemoryOrderModuleList;&lt;br /&gt;LIST_ENTRY              InInitializationOrderModuleList;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Tout ceci est décrit très brièvement, car même si ce n'est pas documenté officiellement tu trouvera facilement toutes les infos sur ces structures dans l'internet multimédia ( par exemple dans le post de lilxam sur &lt;a href="http://nibbles.tuxfamily.org/?p=66"&gt;nibbles&lt;/a&gt; ).&lt;br /&gt;&lt;br /&gt;Ce qui est intéressant c'est que tout ça c'est dans l'user-land, alors bien sûr la première idée qui up dans ton mind c'est de modifier ces listes chainées, pour "cacher" ton module favoris dans un processus cible.&lt;br /&gt;&lt;br /&gt;Et tu as raison, car c'est facile à faire :&lt;br /&gt;&lt;br /&gt;On trouve l'adresse du PEB du processus cible en créant un thread distant sur la routine RtlGetCurrentPeb() et on récupère sa valeur de retour (l'adresse du PEB) avec un GetExitCodeThread().&lt;br /&gt;&lt;br /&gt;On trouve ensuite l'adresse du premier module dans le champ LdrData, puis on démarre un parcours sur les LDR_DATA_ENTRY, quand on trouve le module qui nous intéresse, on l'enlève du chainage. Pour cela, c'est simplement de l'unlinkage dans une liste doublement chainée : on fait pointer le "pointeur avant" (Flink) du module précédent vers le module suivant, et le "pointeur arrière" (Blink) du module suivant vers le module précédent ( tu me suis ?). Par exemple, pour la InLoadOrderModuleList, ça donne :&lt;br /&gt;&lt;br /&gt;&lt;verbatim&gt;&lt;br /&gt;/* Modifie Flink du module précédent (=Blink du module courant) pour le faire pointer sur le module suivant (=Flink du module courant) */&lt;br /&gt;WriteProcessMemory(targetProcess, &lt;br /&gt;                                      module.InLoadOrderModuleList.Blink,&lt;br /&gt;                                      &amp;amp;module.InLoadOrderModuleList.Flink,&lt;br /&gt;                                      4,&lt;br /&gt;                                      NULL);&lt;br /&gt;&lt;br /&gt;/* Modifie Blink du module suivant (=Flink du module courant + 4) pour le faire pointer sur le module précédent (=Blink du module courant) */&lt;br /&gt;WriteProcessMemory(targetProcess,&lt;br /&gt;                                      module.InLoadOrderModuleList.Flink+4,&lt;br /&gt;                                      &amp;amp;module.InLoadOrderModuleList.Blink,&lt;br /&gt;                                      4,&lt;br /&gt;                                      NULL);&lt;br /&gt;    &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;Faut pas oublier qu'on est dans un process distant, donc un autre espace mémoire, d'où le WriteProcesMemory(). Et là où ca pwne, c'est que si après cet unlinkage je lance mon premier programme de listings ( celui avec &lt;/verbatim&gt;CreateToolhelp32Snapshot()&lt;verbatim&gt;), mon module n'apparait plus !!&lt;br /&gt;&lt;br /&gt;Par contre, le EnumProcessModules() fonctionne toujours.. si on était un peu naïf on pourrait se dire que cette API utilise une façon "sûre" de lister les modules avec des techniques de jedi inside the kernel, et là on commence à s'exciter sur une way de la bypasser...&lt;br /&gt;&lt;br /&gt;...Et puis on se rapelle qu'il y a deux autres listes doublement chainées sur les modules : InMemoryOrderModuleList et InInitializationOrderModuleList. Alors on fait le même unlinkage et on s'aperçoit que &lt;/verbatim&gt;EnumProcessModules()  utilise la InMemoryOrderModuleList, et qu'il est donc aussi facilement pwnable...&lt;br /&gt;&lt;br /&gt;Ca nous donne un "cacheur" de modules que vous trouverez &lt;a href="http://calvet.joan.free.fr/travail/hider_modules.c"&gt;ici&lt;/a&gt;, vous lui filez un PID et un nom de module ( du type ntdll.dll kwa ) et il n'apparaitra plus lorsqu'on utilise les APIs sus-nommées.&lt;br /&gt;&lt;br /&gt;C'est bien sûr pas la technique du siècle, il suffit de checker le dump mémoire pour voir les modules mais ce qui est rigolo c'est que par exemple &lt;span style="font-weight: bold;"&gt;ProcessExplorer&lt;/span&gt; utilise ces APIs pour lister les modules d'un process et donc on le &lt;span style="font-weight: bold;"&gt;pwn sans aucun souci&lt;/span&gt;, ça invite à être prudent sur les infos fournies par ce genre d'outils :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-5243440364002869839?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/5243440364002869839/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=5243440364002869839' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/5243440364002869839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/5243440364002869839'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/08/cachez-ce-module-que-je-ne-saurai-voir.html' title='Cachez ce module que je ne saurai voir...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-4913151757284380999</id><published>2008-08-04T14:00:00.005+02:00</published><updated>2008-08-04T14:53:21.435+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IsDebuggerPresent'/><category scheme='http://www.blogger.com/atom/ns#' term='DebugActiveProcess'/><category scheme='http://www.blogger.com/atom/ns#' term='Nt QueryInformationProcess'/><category scheme='http://www.blogger.com/atom/ns#' term='CheckRemoteDebuggerPresent'/><category scheme='http://www.blogger.com/atom/ns#' term='techniques anti debug'/><category scheme='http://www.blogger.com/atom/ns#' term='NtGlobalFlags'/><title type='text'>Je sais que tu m'observes.</title><content type='html'>&lt;span style="font-style: italic;"&gt;Et kéketufais toi ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Toujours dans mes histoires de debuggeur, j'ai tenté d'améliorer la "non-intrusivité" du code que j'avais présenté dans &lt;a href="http://joe-is-a-rocknroll-star.blogspot.com/2008/07/debug-me.html"&gt;ce post&lt;/a&gt;. Je me suis donc intéressé aux diverses techniques qui permettent à un processus de détecter qu'il est sous la surveillance d'un débuggeur, c'est classique mais ça mange pas de pain au nutella de le faire.&lt;br /&gt;&lt;br /&gt;Pour cela, j'ai fait un développement en parallèle : à ma gauche... venu tout droit de sa contrée lointaine de l'user-land... le programme &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; qui va faire appel à différentes techniques ninja pour checker la présence d'un débuggeur, et à ma droite... le JoE d3bugg3ur qui va tenter l'entourloupe de débugger son adversaire sans se faire repérer. La tension est à son comble, la foule est en délire... Avant de débuter ce qui sera sûrement un très grand match, rappelons que la principale contrainte est que je reste en user-land et que j'implémente les checks de la présence d'un débuggeur comme de simples appels de fonctions, c'est pas forcément très réaliste (pour certains d'entre eux) mais ça permet de se faire une bonne idée de leur fonctionnement.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1-PEB!IsDebugged et kernel32!IsDebuggerPresent&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La première vérification de la présence d'un débuggeur peut se faire dans la structure Process Executive Block ( accessible en user-land et décrivant le process ). Si on la dump on trouve au troisième octet un champ nommé "IsDebugged" et qui (sans surprise)  sera mis à 1 par le système si le process est débuggé ( y compris quand c'est par DebugActiveProcess() ). De plus, la fonction IsDebuggerPresent() va lire directement ce champ. Donc notre programme &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me &lt;/span&gt;va faire un appel à la fonction sus-nommée et aussi checker directement la valeur de ce champ en récupérant l'adresse du PEB avec l'API RtlGetCurrentPeb() (histoire d'éviter les hooks sur IsDebuggerPresent()).&lt;br /&gt;Ce double-check on the byte ne pose aucune problème a être éviter, il suffit bien entendu d'aller modifier en dur le champ avant que la cible n'ait pu le checker ( ce qui se fait sans souci, j'y reviens de suite ).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;2- PEB!NtGlobalFlags and Heap Flags&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;La deuxième protection se trouve également en partie dans le Process Executiv Block. Elle se site au niveau du champ NtGlobalFlags qui va contenir des valeurs indiquant au programme comment gérer son tas ( cette gestion étant différente suivant que le process est débuggé ou non ). Après quelques tests, on se convainc assez facilement que ce champ prend la valeur 0x70 si le process est sous le contrôle d'un débuggeur. Il suffit alors de checker la valeur de ce champ, mais encore une fois le débuggeur n'a qu'a modifier la valeur pour y mettre 0x0 ( valeur de base ) avant que sa cible n'ait pu vérifier le champ.&lt;br /&gt;&lt;br /&gt;Mais modifier en dur le PEB ne suffit pas en ce qui concerne le tas qui possède un comportement vraiment différent suivant que le process a été créé en mode debug ou non ( flags dans la structure de management du tas qui permettent aussi de checker le débuggage, taille des chunks différente..). Bref comme dirait l'ami zantrop "c'est le bowdel", et y a une solution qui permet de tout résoudre d'un coup : ne pas créer le process en mode debug et utiliser le mode non intrusif ( la boucle infinie à la place de l'EP et tout le bouzin, je te renvoie à &lt;a href="http://joe-is-a-rocknroll-star.blogspot.com/2008/07/debug-me.html"&gt;ce post&lt;/a&gt; ), ce qui nous permet de bypasser tous les checks sur le tas !&lt;br /&gt;&lt;br /&gt;Ca a aussi comme avantage qu'on maitrise le moment où notre cible commence à exécuter son code ( puisqu'on on le fait boucler sur son EP ) et donc on peut tranquillement modifier les champs du PEB avant de le laisser le process cible continuer et faire ses vérifications.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;3- ntdll!NtQueryInformationProcess et kernel32!CheckRemoteDebuggerPresent&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Plus profondément cachée, la fonction NtQueryInformationProcess()  permet de récupérer tout un tas d'infos sur un processus. C'est un simple wrapper vers ZwQueryInformationProcess() qui débouche sur un appel système. Son prototype est :&lt;br /&gt;&lt;pre class="libCScode" id="ctl00_rs1_mainContentContainer_ctl01" space="preserve"&gt;NTSTATUS WINAPI NtQueryInformationProcess(&lt;br /&gt;__in       HANDLE &lt;i&gt;ProcessHandle&lt;/i&gt;,&lt;br /&gt;__in       PROCESSINFOCLASS &lt;i&gt;ProcessInformationClass&lt;/i&gt;,&lt;br /&gt;__out      PVOID &lt;i&gt;ProcessInformation&lt;/i&gt;,&lt;br /&gt;__in       ULONG &lt;i&gt;ProcessInformationLength&lt;/i&gt;,&lt;br /&gt;__out_opt  PULONG &lt;i&gt;ReturnLength&lt;/i&gt;&lt;br /&gt;);&lt;/pre&gt;En fixant la valeur de l'argument&lt;span style="font-family:courier new;"&gt; ProcessInformationClass&lt;/span&gt;, on indique quels types d'info on veut regarder. Ces informations "résultantes" seront placés dans le buffer pointé par &lt;span style="font-family:courier new;"&gt;ProcessInformation&lt;/span&gt; (3eme argument). Ce qui nous intéresse c'est que en mettant 7 en &lt;span style="font-family:courier new;"&gt;ProcessInformationClass&lt;/span&gt;, la fonction nous retourne "a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process is being run under the control of a ring 3 debugger." C'est easy donc, il suffit pour &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; d'appeler cette fonction et de checker la nullité de ProcessInformation :-D&lt;br /&gt;Pour l'appel, la doc nous indique comment faire : "This function has no associated import library. You must use the LoadLibrary and  GetProcAddress functions to dynamically link to Ntdll.dll."&lt;br /&gt;&lt;br /&gt;Maintenant pour notre debuggeur user-land il faut réagir, la fonction étant appelé directement par son addresse, je ne vois qu'une seule manière de ne pas se faire repérer : il faut la hooker "in-line", c'est à dire modifier directement son code.&lt;br /&gt;&lt;br /&gt;Notre objectif est simple : dans le cas où cette fonction est appelé avec 7 en &lt;span style="font-family:courier new;"&gt;ProcessInformationClass&lt;/span&gt;, on doit mettre 0 dans le &lt;span style="font-family:courier new;"&gt;ProcessInformation&lt;/span&gt; pour ne pas être repéré. De plus, comme la fonction NtQueryInformationProcess() est souvent appelée pour tout un tas de trucs (c'est précis comme description, hein ?), on doit modifier son résultat seulement dans le cas qui nous intéresse et la laisser s'exécuter normalement dans les autres, sinon on va foutre un bon gros bordel.&lt;br /&gt;&lt;br /&gt;Donc pour le hook, je vais mettre en place à l'adresse de NtQueryInformationProcess() un jump vers un shellcode que j'aurai placé en mémoire qui me permettra de gérer tranquillement la fonction. Pour celà je regarde d'abord la geule du code au début de cette fameuse fonction (en fait ZwQueryInformationProcess(), mais on va les confondre :-)  :&lt;br /&gt;&lt;br /&gt;MOV EAX,9A&lt;br /&gt;MOV EDX,7FFE0300&lt;br /&gt;CALL DWORD PTR DS:[EDX]&lt;br /&gt;RETN 14&lt;br /&gt;&lt;br /&gt;Il s'agit d'un classique appel système, donc c'est là que je dois intervenir et mettre mon JMP vers un shellcode qui va tout pwned. Mon loader que je vais mettre à cet endroit aura la tête suivante :&lt;br /&gt;&lt;br /&gt;MOV EAX,0xFAFAFEFE&lt;br /&gt;JMP EAX&lt;br /&gt;&lt;br /&gt;Où 0xFAFAFEFE est l'adresse où se trouve le shellcode et qui sera patché au moment de l'exécution.&lt;br /&gt;Ce loader va ainsi écraser les deux premières instructions de NtQueryInformationProcess() en laissant trois opcodes inutilisés (rappelle toi en pour la suite cher lecteur), il me faudra donc les rétablir dans les cas où je veux laisser la fonction s'exécuter normalement.&lt;br /&gt;&lt;br /&gt;Maintenant intéressons nous au shellcode, gardons à l'esprit que viennent d'être mis en place dans la pile les arguments de NtQueryInformationProcess():&lt;br /&gt;&lt;br /&gt;//Est ce que ProcessInformationClass == 7 ?&lt;br /&gt;CMP DWORD PTR SS:[ESP+8],7&lt;br /&gt;&lt;br /&gt;// Si c'est pas le cas, on ne dois pas intervenir&lt;br /&gt;JNZ SHORT Normal&lt;br /&gt;&lt;br /&gt;// Time to hook !&lt;br /&gt;MOV EAX,0 // on met en place la valeur de retour&lt;br /&gt;MOV EDX,DWORD PTR SS:[ESP+C]&lt;br /&gt;MOV DWORD PTR SS:[EDX],0 // on met 0 dans la valeur résultat =&gt; &lt;span style="color: rgb(51, 51, 255);"&gt;check pwned !&lt;/span&gt;&lt;br /&gt;CMP DWORD PTR DS:[ESP+14],0 // on teste si ReturnLength est NULL&lt;br /&gt;JE SHORT FinDuHook // si c'est le cas, on n'a pas à la modifier&lt;br /&gt;MOV EDX,DWORD PTR SS:[ESP+14]&lt;br /&gt;MOV DWORD PTR SS:[EDX],4 // on met 4 dans ReturnLength&lt;br /&gt;&lt;br /&gt;FinDuHook:&lt;br /&gt;RETN 14&lt;br /&gt;&lt;br /&gt;Normal: // ici on doit rediriger vers le flux normal d'exécution&lt;br /&gt;MOV EAX,9A // rétablissement des deux premières instructions que le&lt;br /&gt;MOV EDX,7FFE0300 // loader a écrasé&lt;br /&gt;PUSH EBX // sauvegarde de EBX qui sera utilisé pour le JMP suivant&lt;br /&gt;MOV EBX,NTDLL.7C91D7E9&lt;br /&gt;JMP EBX // reprendre le cours normal de la fonction ( appel système )&lt;br /&gt;&lt;br /&gt;Quelques remarques :&lt;br /&gt;&lt;br /&gt;1- D'après la doc "The function returns  an NTSTATUS success or error code." et on se convainc assez facilement que 0 est le code de succès, donc à mettre dans EAX :-)&lt;br /&gt;&lt;br /&gt;2- Dans le cas du hook, il ne faut pas oublier de positionner ReturnLength (5ème argument c'est à dire ESP+14)  à 4 car d'après la doc, c'est "A pointer to a variable in which the function returns the size of the requested information." et donc, même si il est optionnel, on pourrait imaginer que &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me &lt;/span&gt;l'utilise et teste la valeur retournée pour voir qu'elle n'est pas nulle (dans le cas d'un test de debug on retourne un DWORD_PTR donc c'est 4 bytes ). D'ailleurs c'est ce qu'il fait le petit salopio.&lt;br /&gt;&lt;br /&gt;3- Dans le cas où on ne veut rediriger vers le flux normal d'exécution, y a pas de mystères, on exécute les deux instructions que le loader a écrasé et on saute sur l'adresse hardcodé qui était l'instruction suivante ( que j'apellerai instruction Y pour la suite de ce merdier ). En fait, comme pour ce JMP j'utilise EBX, je vais d'abord le sauvegarder sur la pile et je vais mettre juste avant l'instruction Y un POP EBX pour rétablir la valeur de ce registre et m'éviter de faire foirer le programme qui s'attend à trouver une "certaine" valeur dedans :-) Et tout ça tombe très bien puisque j'avais de la place à la fin de mon loader ( 3 opcodes précisément, rapelle toi ! ). Bon bien sûr c'est pas beau caca d'avoir hardcodé cette adresse, on pourrait tout à fait la patcher à l'éxecution puisqu'elle est située à distance fixe du début de NtQueryInformationProcess(). Mais j'avais la flemme, donc c'est l'adresse "kivabien" pour XP SP3.&lt;br /&gt;&lt;br /&gt;Là où c'est tout bon c'est que en hookant cette fonction, on pwne aussi CheckRemoteDebuggerPresent() qui l'utilise :-)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;4- La MSDN c'est plus fort que toi...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si on s'intéresse un peu à la doc sur les exceptions dans la MSDN, on trouve la fonction suivante :&lt;br /&gt;&lt;br /&gt;&lt;pre class="libCScode" id="ctl00_rs1_mainContentContainer_ctl04" space="preserve"&gt;BOOL CheckForDebugger()&lt;br /&gt;{&lt;br /&gt;__try&lt;br /&gt;{&lt;br /&gt;DebugBreak();&lt;br /&gt;}&lt;br /&gt;__except(GetExceptionCode() == EXCEPTION_BREAKPOINT ?&lt;br /&gt;     EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)&lt;br /&gt;{&lt;br /&gt;// No debugger is attached, so return FALSE&lt;br /&gt;// and continue.&lt;br /&gt;return FALSE;&lt;br /&gt;}&lt;br /&gt;return TRUE;&lt;br /&gt;}&lt;/pre&gt;Rien de bien folichon, on déclenche une breakpoint exception dans le process appelant ( donc &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; dans notre cas ), et on regarde si effectivement cette exception s'est produite ( par l'appel à GetExceptionCode() ), si ce n'est pas le cas ça veut dire qu'elle a été "catché" par un débuggeur. Pour bypasser ça, il suffit de faire en sorte que le débuggeur ne gère pas la breakpoint exception et la laisse arriver jusqu'au process debuggé, cela se règle dans la fonction ContinueDebugEvent() en mettant le troisième argument à DBG_EXCEPTION_NOT_HANDLED, ce qui laisse le programme responsable de l'exception la traiter ( et la détecter :-).&lt;br /&gt;En pratique ça veut dire que toutes les breakpoints exceptions doivent pouvoir être gérés par le programme cible, ce qui posera sans doute des problèmes quand il s'agit d'exceptions "non-naturelles" (mises en place par le débuggeur), mais dans mon cas, mon but étant plutôt de tracer le comportement du programme de façon furtive ça n'a pas de conséquences.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;5- debug me !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Pour l'instant le JoE d3bugg3r s'en sort bien, tous les checks d'avant sont assez facilement bypassables... C'est maintenant que les choses se compliquent :-)&lt;br /&gt;&lt;br /&gt;Un autre trick consiste à se débugger soit même : on créé un nouveau processus et on lui fait appeler DebugActiveProcess() sur son processus parent, dans le cas où il on a déjà un débuggeur sur le dos, l'appel de cette fonction va échouer et hop, débuggeur spooted !&lt;br /&gt;&lt;br /&gt;En pratique j'ai implémenté ça dans &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; par une création d'un process "classique" ( = notepad.exe, pour être le plus "portable" possible ) dans lequel je vais créer un thread distant. Mais on ne peut pas juste lui faire exécuter DebugActiveProcess() car on va prendre dans la geule le comportement par défaut de cette fonction qui est "Exiting the debugger also exits the process unless you use the &lt;a id="ctl00_rs1_mainContentContainer_ctl04" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl04',this);" href="http://msdn.microsoft.com/en-us/library/ms679307%28VS.85%29.aspx"&gt;&lt;b&gt;&lt;/b&gt;&lt;/a&gt;DebugSetProcessKillOnExit() function." c'est à dire que lorsque notre thread distant va terminer, il va tuer &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt;...&lt;br /&gt;Donc il faut travailler un peu plus et se faire un petit shellcode qui va nous faire l'appel à DebugSetProcessKillOnExit() pour changer le comportement par défaut lors de la fin du thread distant.&lt;br /&gt;En pratique, ca ressemble à ça :&lt;br /&gt;&lt;br /&gt;push 0xFAFAFEFE // the PID of the process to debug&lt;br /&gt;mov edx,kernel32.DebugActiveProcess&lt;br /&gt;call edx&lt;br /&gt;test eax,eax&lt;br /&gt;jz fin // if it works we dont jump&lt;br /&gt;mov edx,kernel32.DebugSetProcessKillOnEx&lt;br /&gt;push 0&lt;br /&gt;call edx&lt;br /&gt;&lt;br /&gt;fin:&lt;br /&gt;retn&lt;br /&gt;&lt;br /&gt;0xFAFAFEFE est le PID de &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; que je patche à l'exécution avant de copier le shellcode dans le process distant ( pas oublier de le faire en little-endian :). Il faut aussi éviter de faire l'appel à DebugSetProcessKillOnEx() dans le cas où DebugActiveProcess() à échoué car la valeur de retour de notre shellcode ( celle qui nous permet de dire si ça a marché ou pas )  sera celle du dernier appel, donc de DebugSetProcessKillOnEx() et cette fonction semble "marcher" même si DebugActiveProcess() a échoué.&lt;br /&gt;&lt;br /&gt;Une fois le shellcode patché, on l'écrit dans notre process notepad.exe, on le fait s'exécuter en créant un thread à son adresse avec CreateRemoteThread() et on récupère la valeur de retour avec GetExitCodeThread()... Si c'est 0 ça veut dire que ça a échoué donc qu'un débuggeur est là :-)&lt;br /&gt;&lt;br /&gt;Pour bypasser ça, c'est la galère... le débuggeur ne controlant pas la création du processus "fils" notepad.exe, il ne peut pas venir hooker à temps DebugActiveProcess() dans celui-ci. Et même si on y arrivait (= l'appel à DebugActiveProcess() "marcherait" tout le temps) &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; pourrait venir vérifier qu'on reçoit effectivement les exceptions ( par exemple celle de création du process qui est toujours reçue en premier ).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;6- Tic tac, tic tac...&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Une technique bien connue consiste à utiliser les différents compteurs que le système maintient à jour : l'idée consiste simplement à remarquer que certaines opérations prennent beaucoup plus de temps selon qu'un débuggeur est présent ou non. Quel genre d'opérations ? Sur le net on trouve pas mal d'exemples avec de simples boucles sur des printf(). Perso j'ai aucune différences, les printfs prennent autant de temps que le débuggeur soit là ou pas (ce qui semble assez logique, l'affichage d'une chaine par le biais d'un printf() n'est pas un évènement de débug, non?)... Il faut donc mieux utiliser une opération véritablement couteuse dans le cas d'un débuggage, par exemple OutputDebugString() :-)&lt;br /&gt;&lt;br /&gt;Le code qu'on met dans &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; est donc du genre :&lt;br /&gt;&lt;br /&gt;firstTick=GetTickCount();&lt;br /&gt;&lt;br /&gt;for(loop=0;loop&lt;10000;loop++)    &lt;br /&gt;{      &lt;br /&gt;OutputDebugString("MDR");    &lt;br /&gt;}     &lt;br /&gt;&lt;br /&gt;secondTick=GetTickCount();&lt;br /&gt;&lt;br /&gt; if(secondTick-firstTick &gt; NORMAL_TIME_COUNT)&lt;br /&gt; {&lt;br /&gt;// too long, debugger spooted xD&lt;br /&gt; }&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;// no debugger&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;NORMAL_TIME_COUNT est une constante définie à partir de mesures des exécutions sans débuggeur ! Dans mon cas j'ai utilisé GetTickCount() mais on peut aussi faire avec QueryPerformanceCounter()...&lt;br /&gt;&lt;br /&gt;Là encore pour le bypasser, c'est pas du gateau mon salop : on pourrait hooker GetTickCount() et lui faire retourner une valeur constante ( dans ce cas là le test secondTick-firstTick&gt;NORMAL_TIME_COUNT serait toujours faux..) mais il suffit de modifier le test de notre précédent code et de mettre : if((secondTick-firstTick&gt;NORMAL_TIME_COUNT)&lt;br /&gt;  ||&lt;span style="color: rgb(102, 0, 204);"&gt;(secondTick==firstTick)&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;et on détecte le hook :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;7- C'est cadeau !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Pour terminer ce tour non-exhaustif, une technique un peu plus aggressive...&lt;br /&gt;&lt;br /&gt;A force de m'attacher à des process pour essayer de leur démonter la tête, j'ai finis par m'apercevoir ( bien ouerj oeil de lynx ) que tous les débuggeurs ring3 ( que ça soit OllyDbg ou le JoE d3bugg3r ) créent un nouveau thread dès qu'ils s'attachent et que ce nouveau thread démarre toujours sur la fonction DbgUiRemoteBreakIn() dont le code est de la forme suivante :&lt;br /&gt;&lt;br /&gt;VOID&lt;br /&gt;NTAPI&lt;br /&gt;DbgUiRemoteBreakin(VOID)&lt;br /&gt;{&lt;br /&gt;/* Make sure a debugger is enabled; if so, breakpoint */&lt;br /&gt;if (NtCurrentPeb()-&gt;BeingDebugged) DbgBreakPoint();&lt;br /&gt;/* Exit the thread */&lt;br /&gt;RtlExitUserThread(STATUS_SUCCESS);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Mais le code n'est pas le plus important, ce qui rox, c'est que cette fonction soit toujours appelée au moment de l'attachement, pour empêcher un débuggeur de s'attacher, il nous suffit de remplacer le code de cette API par un code qui va l'emmerder ! Pour faire simple, &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; va écrire un appel à TerminateProcess() à l'emplacement de cette fonction, et ainsi quand le débuggeur s'attache au process, BAM il se termine.&lt;br /&gt;&lt;br /&gt;La parade est simple, il suffit au débuggeur de repatcher à chaud le code de cette API avant de s'y attacher. Bon, a noter que dans notre cas j'ai même pas eu besoin de le faire puisque le JoE d3bugg3r s'attache au moment où la cible est à son EP, donc elle n'a pas pu encore patché son DbgUiRemoteBreakin(). Disons que cette protection est utile pour empêcher l'attachement à un process en cours, ou alors il faudrait utiliser un version modifiée de la DLL qui contient cette fonction (ntdll) mais là j'imagine qu'on touche du doigt des domaines un peu plus compliqué ( packers ? ) et j'en suis pas encore là  :-)&lt;br /&gt;&lt;br /&gt;A noter un effet de bord intéressant : ce fameux DbgUiRemoteBreakin() explique l'exception qui est toujours levé lorsqu'on commence de débugger un process en mode non intrusif ( il y en a aussi une en mode intrusif mais cela ne nous regarde pas ;). J'avais pris en compte ce fait en laissant toujours de côté la première exception dans le code de mon débuggeur, mais là on s'aperçoit que si on modifie le byte IsDebugged du PEB, l'exception ne sera plus levée, donc la première exception qu'on cathera sera une "vraie", à prendre en compte donc :)&lt;br /&gt;&lt;br /&gt;Pour conclure, on peut remarquer que dans les conditions dans lesquelles je me suis plaçé ( c'est à dire en avantageant le débuggeur en lui laissant la main en premier ), il est facile de bypasser les APIs fournie par Microsoft ( IsDebuggerPresent(), CheckRemoteDebugger() ), mais d'un autre côté il y a d'autres checks très faciles à mettre en place ( le self-debug ou les timers ) qui semblent difficiles (impossibles?) à pwned... Donc le JoE d3bugg3r a perdu, mais il reviendra, plus fort, plus beau :D&lt;br /&gt;&lt;br /&gt;Je suis bien sûr loin d'avoir étudier tous les anti-debug ( j'en ai même laisser certains importants de côté ), je me suis cantonné à des techniques "non-agressive" (ormis la dernière, mais c'est du caca celle là), je continuerai ce travail d'ici peu de temps pour voir où ça mène ;-)&lt;br /&gt;&lt;br /&gt;Le code du debuggeur se trouve &lt;a href="http://calvet.joan.free.fr/travail/debugger.c"&gt;ici&lt;/a&gt;, le mode non-intrusif implémente tous les anti-anti-debug que j'ai décrit au dessus. Le code source de &lt;span style="color: rgb(255, 0, 0);"&gt;dont&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Try&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;To&lt;/span&gt;&lt;span style="color: rgb(255, 255, 0);"&gt;Debug&lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;Me&lt;/span&gt; est &lt;a href="http://calvet.joan.free.fr/travail/donttrytodebugme.c"&gt;là&lt;/a&gt; ainsi que le binaire compilé sous XP SP3 &lt;a href="http://calvet.joan.free.fr/travail/donttrytodebugme.exe"&gt;ici&lt;/a&gt; ( vous pouvez checker votre débuggeur maison, voir si il fait mieux que moi :p ).&lt;br /&gt;&lt;br /&gt;Coté bibliographie je me suis en grande partie basé sur l'article référence de N. Fallière que vous pouvez trouver &lt;a href="http://www.tuts4you.com/download.php?view.1919"&gt;ici&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-4913151757284380999?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/4913151757284380999/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=4913151757284380999' title='4 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/4913151757284380999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/4913151757284380999'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/07/je-sais-que-tu-mobserves.html' title='Je sais que tu m&apos;observes.'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-1800297056445770432</id><published>2008-07-22T17:21:00.001+02:00</published><updated>2008-07-23T10:56:17.043+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='loader'/><category scheme='http://www.blogger.com/atom/ns#' term='SetWindowsHookEx'/><category scheme='http://www.blogger.com/atom/ns#' term='cave method'/><category scheme='http://www.blogger.com/atom/ns#' term='injection DLL'/><category scheme='http://www.blogger.com/atom/ns#' term='CreateRemoteThread'/><title type='text'>Inject your DLL</title><content type='html'>Pour continuer mon apprentissage du fabuleux (aheum) monde de Windows, je me suis lancé dans l'implémentation d'un grand classique : l'injection de DLL.&lt;br /&gt;&lt;br /&gt;Mon but est donc simple :&lt;span style="font-weight: bold;"&gt; injecter une bibliothèque dynamique dans un/des process distant(s)&lt;/span&gt; ( sans m'occuper de l'utilisation qu'on pourrait en faire ). Pour celà j'ai implémenté différentes techniques "de base" dans un petit tool. J'ai également tripé en essayant de rendre le truc le plus furtif possible, c'est à dire en libérant au maximum la mémoire allouée pour l'injection quand il y en a. Let's start :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;1- "Classical method" :&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Archi-connue, cette technique consiste à utiliser l'API CreateRemoteThread() qui créé donc un thread dans un process distant (jsuis totally bilingual et oué) en lui donnant l'adresse de LoadLibrary() à laquelle on fournit le nom de la DLL à injecter, qui aura été précédemment écris dans la mémoire du process cible ( VirtualAllocEx() + WriteProcessMemory() ).&lt;br /&gt;&lt;br /&gt;La seule difficulté c'était de savoir quand je pouvais libérer cette mémoire allouée pour l'appel ( et gagner un petit peu de furtivité plutot que de laisser le nom de la DLL se balader dans la mémoire ) : il me fallait détecter que l'injection était terminée donc que LoadLibrary() à finie son boulot. Comme j'étais chaud bouillant j'ai commencé à dumper le EIP en boucle et à m'exciter sur les valeurs qu'il pouvait prendre une fois l'injection terminée... Puis j'ai découvert WaitForSingleObject(), qui dixit la doc "Waits until the specified object is in the signaled state or the time-out interval elapses." et pour un thread le "signaled state" c'est "when the thread terminates." c'est dans la poche :-)&lt;br /&gt;&lt;br /&gt;A noter qu'il ne faut pas oublier de s'allouer les droits de debug pour pouvoir ouvrir un HANDLE sur n'importe quels process et pouvoir ainsi s'injecter dans tout ce qui bouge.&lt;br /&gt;De plus, cette méthode ne fonctionne que sous Windows NT alors par acquis de conscience j'ai rajouté une fonction isWindowsNT() qui utilise l'API GetVersionEx() pour vérifier que la version de l'OS est ok...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;2- "Cave code method"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;La technique précédente c'est du tout bon, ca marche bien, mais ça fait appel à l'API surpuissante CreateRemoteThread() qui finalement sert "juste" à faire un appel à LoadLibrary(), et qui peut être facilement repéré par des outils anti-injection (enfin, j'imagine :p ).&lt;br /&gt;Donc une autre idée est de se coder un loader en assembleur qui remplacerait l'appel à CreateRemoteThread(), ce qui nous permettrait de nous injecter en chargeant ce loader dans la mémoire du process distant puis en redirigeant le flux d'exécution dessus.&lt;br /&gt;&lt;br /&gt;La principale difficulté en ce qui concerne le loader c'est qu'il contient plusieurs adresses qu'on ne connait pas au moment de la compilation : l'adresse de retour où on retournera après que notre loader ait été exécuté, l'adresse de l'argument de LoadLibrary() (= le nom de la dll qu'on veut mapper) et l'adresse de LoadLibrary() ( même si en pratique on a envie d'hardcodé celle là, il faut pas forget que même entre service pack 2 et 3 sous XP il y a des différences au niveau des adresses de mapping des DLLs, donc si on veut faire un truc un minimum portable c'est pas top).&lt;br /&gt;&lt;br /&gt;Cela nous donne :&lt;br /&gt;&lt;br /&gt;  push 0xFAFAFEFE   // return address&lt;br /&gt;&lt;br /&gt;  pushfd  // save the eflags register&lt;br /&gt;  pushad    // save the registers&lt;br /&gt;&lt;br /&gt;  push 0xFAFAFEFE // argument of LoadLibrary()&lt;br /&gt;  mov eax,0xFAFAFEFE // @ of LoadLibrary()&lt;br /&gt;  call eax&lt;br /&gt;&lt;br /&gt;  popad&lt;br /&gt;  popfd&lt;br /&gt;&lt;br /&gt;  ret&lt;br /&gt;&lt;br /&gt;Je fous des 0xFAFAFEFE à la place des trucs que je vais devoir patché et j'oublie pas de sauvegarder les registres avant et de les rétablir après histoire de pas avoir de souci :-)&lt;br /&gt;&lt;br /&gt;Le code du loader se trouve donc dans mon process "injecteur" et premier petit problème, comment localiser ce code pour pouvoir le patcher ? Sous GCC y a pas de souci, tu utilises la balise __asm__ et tu fous ton code ASM direct à l'intérieur d'une fonction, l'adresse de la fonction te donnera l'adresse de ton loader et en cadeau bonus, tu peux même déclarer une autre fonction "vide" derrière ce qui te permettra de connaitre la taille de ton loader avec la différence d'adresse. Sauf que voilà, dans le but de m'introduire plus profondément dans la communauté des t4pz je mange des chocapicz et je compile désormais avec VC++ 2008. Et sous ce magnifique compilateur que trouve t'on à l'adresse de la fonction dans laquelle on a mis le code ASM du loader ? Je te le donne en mille émile :&lt;br /&gt;&lt;br /&gt;00401005    JMP main.00401060&lt;br /&gt;&lt;br /&gt;Oui dude, un JMP vers le "vrai" code de la fonction, ce qui est emmerdant. Donc la seule solution  c'est de transformer mon loader en opcodes et de mettre tout ça dans une variable globale qui me donnera l'adresse dont j'ai besoin.&lt;br /&gt;&lt;br /&gt;Donc une fois que l'adresse du loader est connue, on commence par patcher l'adresse de l'argument de LoadLibrary() qu'on obtient en allouant de la mémoire dans le process cible avec VirtualAllocEx() puis celle de LoadLibrary() qu'on obtient avec GetProcAddress().&lt;br /&gt;&lt;br /&gt;Reste à mettre l'adresse de retour, pour celà on va d'abord suspendre le main thread du process distant, à cet effet je me suis codé une fonction qui récupère le TID de ce thread à partir du PID du process distant, rien de bien compliqué : on fait un snapshot de tous les threads du système avec CreateToolhelp32Snapshot(), on récupère ceux dont le PID owner est le même que le PID de notre process cible. Une fois le TID du main thread récupéré, on créer un HANDLE dessus avec OpenThread() et on suspend le thread avec SuspendThread().&lt;br /&gt;&lt;br /&gt;On récupère alors l'EIP avec GetThreadContext(), on l'écrit dans notre loader.. et hop ! notre loader est patché, il ne reste plus qu'à le copier dans la mémoire de notre cible. Une fois que c'est fait on modifie l'EIP pour qu'il pointe vers lui avec SetThreadContext(), on relance le thread et on attend ! Si tout va bien, le process cible va exécuter notre loader, charger la DLL puis revenir là où il était...&lt;br /&gt;&lt;br /&gt;Oui mais voilà, on attend un peu trop longtemps... Tout est en place, l'EIP pointe bien sur notre loader mais pourtant le code ne s'exécute pas ou du moins pas tout de suite.. à moins que je "passe la souris dessus" ( pour un process graphique j'entend, pour un process console c'est une autre histoire ) . Ce qui n'est pas très pratique, je voudrai pouvoir être sûr que mon code va être exécuté directement une fois que j'ai relancé le thread sans devoir intervenir sur la cible et ainsi pouvoir libérer la mémoire occupé par le loader histoire d'être caché inside the bosquet.&lt;br /&gt;&lt;br /&gt;Ma première idée c'était que le problème se situe au niveau de l'ordonnancement : le système ne donne pas de temps processeur à mon process cible tant qu'il n'y pas "quelque chose" qui lui laisse croire qu'il va se passer un truc important dans ce process ( d'où le coup de souris ) ou qu'il n'a rien de mieux à faire. Ce qui est confirmé par le fait que "de temps en temps" l'injection va avoir lieu au bout de 10s et dans d'autres cas, après une minute toujours rien...&lt;br /&gt;&lt;br /&gt;Donc j'ai commencé à faire le fou avec les fonctions SetPriorityClass() et SetThreadPriority() histoire de "forcer" le processeur à exécuter mon process cible. Mais j'ai eu beau foutre la priorité max, j'ai vu aucune différence notable... Et j'ai donc abandonné l'idée en me disant que de toute façon l'ordonnanceur Windows doit être un beau bordel et que faudrait être maso ( ou plus fort que moi :p ) pour jouer avec. J'ai quand même retenu cette phrase de la doc qui m'a bien fait rire "Threads are scheduled in a round-robin fashion at each priority level". On y croit.&lt;br /&gt;&lt;br /&gt;Finalement, ce que je veux c'est un moyen de simuler mon "coup de souris" sur la cible puisque apparament il n'y a que ça qui force le process à être exécuté ca$h par le processeur à coup sûr. "Me dis pas que dans ces API de malades que Windows possèdent en ce qui concerne les manipulations de processus en user-land, je trouverai pas mon bonheur." Et effectivement, je l'ai trouvé, il suffit d'envoyer un "message" au process qui, comme tout bon GUI process possède une "message queue" et va réagir au quart de tour pour traiter ce message. Pour cela j'utilise PostThreadMessage() qui, dixit la doc, "posts a message to the message queue of the specified thread" (sympa la doc non?). L'effet est immédiat : mon code est exécuté dans la seconde, et je peux enchainer en libérant la mémoire du loader, celle de l'argument de LoadLibrary() et ni vu ni connu jt'injecte :-)&lt;br /&gt;&lt;br /&gt;Reste que pour un process console "basique" y a pas de message queue et que donc mon message va tomber dans le vide inter-sidéral et ça ne va rien accélèrer, donc pour ces process là ( que je détecte suivant le code de retour de PostThreadMessage() ) je libère pas la mémoire allouée dans la cible et j'attend sagement que l'injection se fasse. Si quelqu'un connait une fucking way de forcer un process console à être exécuté ca$h par le processeur je lui serai gré de m'en faire part.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;3- "SetWindowsHookEx()" :&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Là encore, une méthode très connue : tout se joue avec l'API SetWindowsHookEx() qui permet de poser un hook (en gros, une fonction) pour un certain type d'event : si cet event se produit, notre fonction sera appelée. Pour que la fonction soit appelée dans un process distant (= la cible de l'injection) elle dois être définie dans une DLL, lorsque l'event se produit, le process va vouloir exécuter la fonction définie comme étant le hook et pour cela il va charger la DLL qui la contient :-) De plus, on peut définir si on veut poser le hook pour un thread particulier ou pour tous les threads qui sont dans le "same desktop" donc ça nous donne une possibilité d'injection massive ! Intéressons nous d'abord à une attaque "ciblé".&lt;br /&gt;&lt;br /&gt;La théorie ça rox, mais en bidouillant un peu on s'aperçoit que cette API est un peu plus fourbe que ça :&lt;br /&gt;&lt;br /&gt;1- Première remarque : cette technique ne marche que sur des process "graphiques" et pas pour des process consoles ( décidément... ), en trifouillant sur le net on trouve une explication "Hooks don't work on console processes. The process wich runs consoles (csrss) is considered to be too important to the system so it is designed this way." Pour rendre les choses plus propres on a un moyen de distinguer les process consoles/GUI et éviter ainsi des appels inutiles :&lt;br /&gt;&lt;br /&gt;if(WaitForInputIdle(targetHandle,0)==WAIT_FAILED)&lt;br /&gt;{&lt;br /&gt; // console process&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;// GUI process&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;2- Sur quel évènement poser ce hook ? Il nous en faut un qui nous garantisse une injection le plus rapidement possible une fois le hook mis en place. Je comprend pas vraiment pourquoi la majorité des exemples sur le net se borne à mettre WH_CBT en argument de SetWindowsHookEx() c'est à dire un évènement qui correspond à "activating, creating, destroying, minimizing, maximizing, moving, or sizing a window", en gros un truc qui nous pousse à devoir intervenir sur le process cible avec la souris. En mettant un WH_GETMESSAGE qui lui  "Installs a hook procedure that monitors messages posted to a message queue. ", il suffit ensuite de poster un message avec PostThreadMessage() et on est sûr que le hook va avoir lieu...&lt;br /&gt;&lt;br /&gt;3- Le hook n'existe que tant que le thread qui le pose est vivant, dès qu'il meurt non seulement le hook n'existe plus ( et donc l'injection ne peut plus avoir lieu ) mais de plus, il va y avoir un FreeLibrary() sur notre DLL dans le thread qui a utilisé ce hook. Là j'avoue ne pas vraiment comprendre pourquoi il y a cet appel, après une petite enquète il est déclenché par un GetMessageW(), j'aurai donc tendance à penser que c'est bien déclenché à distance mais il n'est pas à exclure que ça soit plutôt une erreur dans mon implémentation ;-)&lt;br /&gt;Ca pose en tout cas un léger problème : une fois que le thread qui a posé le hook est mort, le FreeLibrary() qui va avoir lieu dans la cible va décrémenter le compteur de référence de la DLL qui va arriver à 0 (=plus personne n'a besoin de cette bibliothèque) et elle va donc être déchargé de la cible... Un peu emmerdant c'était justement le but de la manoeuvre de la charger :-D&lt;br /&gt;Donc pour bypass ce ptit souci j'ai rajouté dans la fonction de hook dans la DLL un appel à LoadLibrary() sur elle-même, ce qui incrémente le compteur de référence et évite qu'elle soit déchargé lors de la mort du thread injecteur. "C'est moche mais ça marche !"&lt;br /&gt;Vous trouverez le code de la DLL en question&lt;a href="http://kqkq12.ifrance.com/travail/oneshoot.c"&gt; &lt;/a&gt;&lt;a href="http://kqkq12.ifrance.com/travail/oneshoot.c"&gt;ici&lt;/a&gt;. Remarquez le très subtil chemin de la DLL rentrer en dur pour l'appel à LoadLibrary()...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;4- "The IvanOv m4l4ri4"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Ainsi nommée d'après la personne bien intentionné qui m'en a donné l'idée.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Comme dis précédemment, SetWindowsHookEx() permet de poser un hook sur tous les threads du bureau, ce qui nous donne envie de s'en servir pour injecter tout le monde !&lt;br /&gt;Déjà, dans l'idée de l"IvanOv m4l4ri4", l'évènement qui va déclencher le hook ne sera pas "controlé" par l'injecteur : on va laisser le WH_CBT et dès qu'un process "bougera" il sera infecté (c'est plus rigolol, non ?).&lt;br /&gt;&lt;br /&gt;Rappelons nous que le hook n'existe que tant que le thread qui l'a posé est vivant. Or, on a pas envie de laisser tourner notre process injecteur en tache de fond le temps que tous les autres process soient infectés. Pour celà il serait plus judicieux de faire une première injection dans un process dont on est sûr qu'il sera "toujours là" et on laisse ce process poser le hook.&lt;br /&gt;&lt;br /&gt;En fait tout va se jouer dans la DLL, on va l'injecter dans notre process qui va servir de pivot à l'infection, puis on va poser le hook sur tout le système dans le DllMain(). Une fois le hook posé, tous les process qui vont recevoir un event graphique vont charger la DLL. Ca nous amène au principal problème de cette technique : les hooks qui concerne tous les threads du bureau sont extrèmement couteux en performance, donc si à chaque chargement de la DLL, le hook est de nouveau posé ça va rapidement faire ramer la machine, pas très discret. Il nous faut donc un moyen de savoir si le hook est déjà poser quand on charge la DLL, histoire de savoir si c'est à nous de le faire ou pas. Ce qu'on veut c'est donc une sorte de "variable globale" au système qui serait en gros mise à 1 si le hook est déjà en place et nous permettrait ainsi une communication inter-processus. Et ça porte un nom : le mutex. Pour faire simple un mutex est lié à un thread qui le "possède", et n'importe quel thread du système peut essayer de prendre possession du mutex en appelant WaitForSingleObject(), il réussira si personne ne l'a pris avant lui (ou si il l'a libéré). Pour le reconnaitre le mutex sera dans notre cas "nommé" c'est à dire qu'on lui donne un nom particulier. Donc tout ce qu'il y a faire lors du chargement de la DLL c'est de faire appel à CreateMutex() avec le nom de notre mutex, si c'est le premier appel le mutex va être créé, puis le thread va faire un WaitForSingleObject() pour en prendre possession, et ainsi poser le hook. Le prochain thread qui "bouge" va utiliser le hook et charger la DLL, ce coup-ci l'appel à CreateMutex() lui retournera juste un HANDLE sur le mutex ( qui existe déjà ) et l'appel à WaitForSingleObject() lui signalera que le mutex est déjà pris par un autre thread, donc que ce n'est pas à lui de poser le hook.&lt;br /&gt;Remarquons que pour faire la première injection, il ne faut pas utiliser la technique 1 qui consiste à créer un thread dans le process cible, car une fois que ce thread va se terminer, le hook va être enlevé et le mutex se retrouvera esseulé (= dans l'état WAIT_ABANDONED, qui est décrit à tord comme un "success state" dans la doc).. La "cave method" est bien plus adapté car elle utilise le main thread ( je savais bien que j'avais pas fait ça pour rien !).&lt;br /&gt;Donc pour cette technique il suffit de lancer l'injection de la DLL dont le code source est &lt;a href="http://kqkq12.ifrance.com/travail/malaria.c"&gt;ici&lt;/a&gt; en "cave method" puis de laisser faire la nature, le premier qui bouge, BAM dans sa geule.&lt;br /&gt;&lt;br /&gt;Il faut quand même remarquer que j'ai un souci au niveau de la libération du mutex, qui doit se faire lorsque le process "pivot" de l'injection meurt, donc quand il décharge la DLL. J'ai pas réussi à faire marcher un ReleaseMutex() dans la clause DLL_PROCESS_DETACH de ma DLL. C'est pas vraiment grave dans le sens où ça empeche juste la technique de fonctionner une deuxième fois de suite avec un mutex de même nom ( le mutex est en WAIT_ABANDONED : le thread qui le possèdait est mort et ne l'a pas libéré ). Mais si votre infection a bien fonctionné, y a normalement pas besoin de la relancer :-)&lt;br /&gt;&lt;br /&gt;Le code final est &lt;a href="http://kqkq12.ifrance.com/travail/injecteur.c"&gt;ici&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-1800297056445770432?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/1800297056445770432/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=1800297056445770432' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/1800297056445770432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/1800297056445770432'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/07/inject-your-dll.html' title='Inject your DLL'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-7649070027948535743</id><published>2008-07-14T17:00:00.001+02:00</published><updated>2008-07-23T11:03:05.349+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='debuggeur'/><category scheme='http://www.blogger.com/atom/ns#' term='non intrusif'/><title type='text'>Debug me !</title><content type='html'>&lt;span style="font-style: italic;"&gt;Dans la série des useless tools...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Après l'avoir vu utilisé dans différents articles (notamment le très bon post de YoLeJedi sur &lt;a href="http://nibbles.tuxfamily.org/?p=34"&gt;nibbles&lt;/a&gt; ou encore par Ivan &lt;a href="http://www.ivanlef0u.tuxfamily.org/"&gt;dans son implémentation de PaX&lt;/a&gt;) j'ai décidé de me coder un petit débuggeur tranquillou mon pépère.&lt;br /&gt;Mon idée est classique : c'est de permettre deux modes : l'un intrusif et l'autre pas. Késako ?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;I- Be bad&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le mode intrusif c'est du classique, on créé un processus en mode debug et on va donc recevoir tous les debugEvent qui vont se produire ( chargement des DLLs, exceptions...) ce qui peut être bien pratique pour fuzzer : on lance une application en boucle avec différentes entrées et on récupère les exceptions pour voir où ça merde. Côté réalisation y a rien de bien compliqué, surtout que la doc est &lt;a href="http://msdn.microsoft.com/en-us/library/ms681675%28VS.85%29.aspx"&gt;assez explicite sur ce point&lt;/a&gt;: après la création du process ( avec l'argument  DEBUG_PROCESS ) on rentre dans une debug loop qui va catcher tout les debugEvent et c'est du tout bon.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;II- Be bad ok, but without pain please&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le mode non-intrusif est plus fallacieux. Déjà, quel est son intéret ? Il est simple : un process peut avoir des comportements différents suivant qu'il est sous le contrôle d'un débuggeur ou non. Sans rentrer dans des techniques anti-debugging complexes on peut citer deux exemples "naturels" : le gestionnaire d'exception final ( aka UnhandledExceptionFilter ) qu'on peut mettre en place dans un programme avec SetUnhandledExceptionFilter() n'est pas appelé en mode debug, ce qui n'est pas très pratique quand on veut tester une exploitation qui consiste justement à réécrire son adresse. On peut aussi parler des chunks dans le tas qui sont différents en mode débug (16 bytes de plus), ce qui facilite pas les choses lors du test d'un heap overflow ;-)&lt;br /&gt;&lt;br /&gt;L'idée du mode non-intrusif consiste à s'attacher au process une fois qu'il est lancé avec l'API DebugActiveProcess(). J'ai alors crié "This is just so fuking easy !" :  je créé mon process avec un CreateProcess() en mode normal, j'apelle cette API pour m'attacher puis je lance ma debug loop et hop.&lt;br /&gt;&lt;br /&gt;Je me suis lancé, j'ai codé, j'ai compilé, j'ai executé et jme suis pris un comportement bien bizarre dans la gueule : pour la majorité des process auquels je m'attache ça plante complètement, pour d'autres ça marchent, mais pas à tous les coups et dans certains cas, chose bizarre, j'arrive à récupérer le nom des DLLs qui sont chargés (après l'avoir lancé une première fois) alors que &lt;a href="http://nibbles.tuxfamily.org/?p=34"&gt;ça ne devrait pas être le cas&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;Après avoir consulté l'oracle (aka YoLeJedi :p), j'ai compris ce qui se passait. Pour celà, intéressons nous au processus de création d'un process sous Windows (par l'appel à CreateProcess()) : il se divise en 6 étapes (extrait de Windows Internals) :&lt;br /&gt;&lt;br /&gt;&lt;ol class="docList" type="1"&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;Open the image file (.exe) to be executed inside the  process.&lt;/p&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;Create the Windows executive process object.&lt;/p&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;Create the initial thread (stack, context, and Windows  executive thread object).&lt;/p&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;Notify the Windows subsystem of the new process so that it can  set up for the new process and thread.&lt;/p&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;Start execution of the initial thread (unless the CREATE_  SUSPENDED flag was specified).&lt;/p&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt; &lt;div style="font-weight: normal;"&gt; &lt;p class="docList"&gt;In the context of the new process and thread, complete the  initialization of the address space (such as load required DLLs) and begin  execution of the program&lt;/p&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Comme on peut le voir c'est assez complexe, et c'est là que se situe le problème, si juste après l'appel à CreateProcess() j'apelle DebugActiveProcess(), je risque de m'attacher avant que la fin de l'initialisation réalisé à l'étape 6 ne soit terminée. Or DebugActiveProcess() est une API qui est faite pour s'attacher à des process "en cours" donc complètement initialisé. Ca explique aussi  pourquoi desfois je reçois les noms des DLLs : si je m'attache avant l'étape 6 alors je serai "notifié" du chargement des DLLs comme si le process avait été lancé en mode DEBUG ( m'enfin je m'avance peut être un peu là ).&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tout ce qu'il faut retenir c'est qu'il faut laisser le processus d'initialisation se terminer avant de s'attacher.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Une première idée pourrait être de caler un ptit Sleep(X) avant de faire appel à DebugActiveProcess() : ça fonctionne mais c'est moche : si la durée d'endormissement est trop longue le process qu'on débugge aura déjà attaquer d'exécuter son code et donc on risque de louper des debugEvents ( et c'est bien sûr pas portable du tout, si un process charge beaucoup de DLLs il mettra plus de temps à s'initialiser et hop il faudra changer la valeur ).&lt;br /&gt;&lt;br /&gt;Il existe une meilleure façon de faire, in 6 steps :&lt;br /&gt;&lt;br /&gt;1- On créé le process en mode SUSPENDED : il est suspendu (jure?)...&lt;br /&gt;2- On modifie l'Entry Point (EP) du programme pour y mettre une boucle infinie&lt;br /&gt;3- On relance le process et on attend que le main thread (créé à l'étape 5) du programme atteigne l'EP ( avant d'y arriver il réalise l'étape 6 de l'initialisation, c'est à dire le chargement des DLLs et tout le bordel) : le process est alors complétement initialisé et se met à boucler.&lt;br /&gt;4- On s'attache au process avec DebugActiveProcess() .&lt;br /&gt;5- On restaure l'EP initial, le main thread commence l'execution du code et on n'en perd pas une miette :-)&lt;br /&gt;&lt;br /&gt;Décrivons plus en détail les étapes les plus compliquées (pas trop non plus :p) :&lt;br /&gt;&lt;br /&gt;2- Il nous faut récupérer l'EP, pour celà jme fait un petit parcours du header PE. Les lecteurs assidus de ce blog (et ils sont nombreux, aheum), auront remarqué que mon premier useless tool était justement un PE reader, cool, je peux réutiliser mon code ?! En fait pas du tout, pour faire plaisir au ch3f je mappe le fichier en mémoire avec MapViewOfFile() et je le parcours directement en déréférençant des pointeurs.&lt;br /&gt;    2-1 Une fois l'adresse de l'EP récupérée, on utilise VirtualProtectEx() pour changer la protection de la mémoire où il se trouve et pour pouvoir y écrire.&lt;br /&gt;    2-2 On oublie pas de faire une sauvegarde des deux premiers octets se trouvant à l'EP&lt;br /&gt;    2-3 On écrit EB FE à la place de ces octets ce qui correspond aux opcodes d'un JMP à la même addresse, donc une boucle infinie :). On cale un ptit appel à FlushInstructionCache() derrière pour s'assure que nos modifs se propageront bien en mémoire centrale et ne resteront pas dans le cache du processeur.&lt;br /&gt;&lt;br /&gt;3- On relance le processus avec ResumeThread(), et on attend qu'il atteigne l'EP en dumpant la valeur de l'EIP avec GetThreadContext().&lt;br /&gt;&lt;br /&gt;4- Appel à DebugActiveProcess()..&lt;br /&gt;&lt;br /&gt;5- On réécrit les anciens opcodes à la place de notre boucle infinie, on oublie pas de flusher et de restaurer les anciens droits de la mémoire.&lt;br /&gt;&lt;br /&gt;Let's launch the debug loop, et c'est good :-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;III- Et comment tu t'apelles ?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Comme YoLeJedi l'explique dans son post, dans le monde non intrusif, on n'a pas accès aux noms des DLLs loadés en mémoire directement dans les structures de debug qu'on récupère. Pour trouver ces noms il faut se casser un peu le c..&lt;br /&gt;YoLeJedi donne 3 techniques pour le faire, perso j'ai implémenté la première qui, dixit le maitre, est la plus rapide :-)&lt;br /&gt;"Le principe consiste à mapper le premier octet du fichier en mémoire à partir de son Handle (&lt;strong&gt;CreateFileMapping + MapViewOfFile&lt;/strong&gt;). Ceci crée indirectement un objet section qui contient le chemin du fichier. Celui-ci est alors récupéré avec l’API &lt;strong&gt;GetMappedFileName&lt;/strong&gt;. La lettre du lecteur est retrouvée avec le couple &lt;strong&gt;GetLogicalDriveStrings + QueryDosDevice&lt;/strong&gt;."&lt;br /&gt;Et on trouve un code source qui nous fait tout ça &lt;a href="http://msdn.microsoft.com/en-us/library/aa366789%28VS.85%29.aspx"&gt;ici.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Mais comme ce code est un peu trop propre et que le copier/coller favorise pas l'apprentissage, je me suis retapé un codage "maison" que vous trouverez dans la fonction getTheNameOfTheFile(), c'est pas vraiment joli (voire carrément dégeulasse) et sûrement pas assez commenté mais ca reste du parcours de string, donc pas très complexe à refaire :)&lt;br /&gt;&lt;br /&gt;Vous trouverez donc la source du bouzin &lt;a href="http://kqkq12.ifrance.com/travail/debugger.c"&gt;ici&lt;/a&gt; ( pas oublié de linker avec Psapi.lib lors du build de l'executable pour &lt;strong style="font-weight: normal;"&gt;GetMappedFileName()&lt;/strong&gt; ) et le binaire compilé sous XP SP2 &lt;a href="http://kqkq12.ifrance.com/travail/debugger.exe"&gt;là&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Une prochaine amélioration pourrait être un mode interactif pour pouvoir afficher la mémoire du process avec des commandes à la gdb...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Thanks to YoLeJedi pour son aide et ses commentaires utiles ;-)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-7649070027948535743?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/7649070027948535743/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=7649070027948535743' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/7649070027948535743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/7649070027948535743'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/07/debug-me.html' title='Debug me !'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-6062594176816817418</id><published>2008-07-07T18:04:00.003+02:00</published><updated>2008-07-07T21:33:05.937+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tool us3l3ss'/><category scheme='http://www.blogger.com/atom/ns#' term='PE reader'/><title type='text'>Useless tool...</title><content type='html'>Inauguration d'une nouvelle section de ouf qui regroupera les tools inutiles que je code...&lt;br /&gt;&lt;br /&gt;First entry : un PE reader qui a rien de bien original si ce n'est que j'essaye de restreindre l'affichage aux champs intéressants. Il peut être facilement customizé pour n'afficher que le header qui vous intéresse.&lt;br /&gt;J'ai aussi rajouter ma section cop4ain, donc si t'es mon copin et que je t'ai oublié, query me on irc ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-6062594176816817418?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/6062594176816817418/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=6062594176816817418' title='3 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/6062594176816817418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/6062594176816817418'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/07/useless-tool.html' title='Useless tool...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-919490483242233215</id><published>2008-06-22T21:49:00.036+02:00</published><updated>2008-06-24T09:00:06.743+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='intellitamper 2.07'/><category scheme='http://www.blogger.com/atom/ns#' term='stack overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='SEH'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>First real exploitation on Windows</title><content type='html'>&lt;span style="font-style: italic;"&gt;Le titre en anglais ça pête...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Les stacks overflows de base sous Windows sont, comme sous Linux, bien documentés, mais les cas pratiques sont pas forcément toujours très réalistes. L'idée est donc ici de se frotter à un ptit tool conseillé par mon maitre jedi Heurs : IntelliTamper 2.07.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Ce qui suit a été réalisé sous Windows XP SP2 FR.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;I- Première approche de la cible&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;IntelliTamper est un "aspirateur web" : vous lui donnez un site, il vous en recrache l'arborescence. On a aussi la possibilité de sauvegarder l'architecture d'un site dans un fichier .map et bien sûr de charger un .map précédemment sauvé :-)&lt;br /&gt;&lt;br /&gt;On dl le bouzin, on le lance et on observe...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Uc9LKH3dBWc/SF9WRs5HjAI/AAAAAAAAAAg/8z3Qrb5TVvY/s1600-h/interface.bmp"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Uc9LKH3dBWc/SF9WRs5HjAI/AAAAAAAAAAg/8z3Qrb5TVvY/s320/interface.bmp" alt="" id="BLOGGER_PHOTO_ID_5214981755626818562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Nous sommes à la recherche d'un overflow, donc on regarde les différents moyens que l'utilisateur a à sa disposition pour passer des données au programme. A première vue, il y en a deux : l'url que le logiciel doit scanner (qui se rentre dans la barre du haut) et les fichiers .map qu'il peut charger (accessible par un classique "File/Load").&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;It's time to fuzzzzzzz this bullshit&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;L'idée est donc ici de balancer des masses de données dans les différentes entrées possibles et de croiser les doigts pour que ça plante, ce qui indiquerait un overflow que nous pourrions peut être exploiter :-)  Pour cela j'utilise un tool fournit avec le framework Metasploit : je lui donne la longueur de chaine que je veux et il me la génère en faisant en sorte que je n'ai jamais les 4 mêmes caractères côte à côte, ça permet de voir ( d'après le rapport d'erreur microsoft ) qu'elle est la longueur de données qu'il faut pour faire merder le bouzin.&lt;br /&gt;&lt;br /&gt;First test, on balance une grosse chaine de caractères (500) dans la barre URL et il se passe... rien du tout ! On se décourage pas, on rajoute une url correcte devant notre chaine et on re-teste et ...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Uc9LKH3dBWc/SF9Z38rT_hI/AAAAAAAAAAo/15GY2uMwGZM/s1600-h/first.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Uc9LKH3dBWc/SF9Z38rT_hI/AAAAAAAAAAo/15GY2uMwGZM/s320/first.JPG" alt="" id="BLOGGER_PHOTO_ID_5214985711233793554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Yeah, un premier overflow spooted !&lt;br /&gt;&lt;br /&gt;Deuxième test : on se fabrique un petit fichier .map en y mettant là encore une chaine très longue.&lt;br /&gt;Et... bingo ! Après avoir balancer des données de longueur diverse ( et avoir rajouter un saut de ligne derrière ),  un autre message d'erreur qui va bien apparaît aux alentours des 7500 caractères.&lt;br /&gt;Nous avons donc deux overflows ( à première vue ) dans ce programme, et comme dans la vie il faut faire des choix, nous allons nous intéresser ici à celui qui est provoqué par le chargement de fichiers .map foireux.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;II- This is not so easy&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Regardons le rapport d'erreur issue de notre BOF :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Uc9LKH3dBWc/SF9eIoX777I/AAAAAAAAAAw/SgwKLe-jx00/s1600-h/error_first.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Uc9LKH3dBWc/SF9eIoX777I/AAAAAAAAAAw/SgwKLe-jx00/s320/error_first.JPG" alt="" id="BLOGGER_PHOTO_ID_5214990395888103346" border="0" /&gt;&lt;/a&gt;Notre offset ne correspond à rien dans la chaine de caractère que nous avons mis dans notre fichier .map de la mort. Ce n'est donc pas directement un écrasement d'adresse de retour qui provoque l'overflow.&lt;br /&gt;Pour vérifier ça on lance OllyDbg sur notre tool et on charge notre fichier crafté pour voir qu'est ce qui provoque le plantage :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Uc9LKH3dBWc/SF9iMMz69yI/AAAAAAAAAA4/WdJ3AjW876g/s1600-h/first2.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Uc9LKH3dBWc/SF9iMMz69yI/AAAAAAAAAA4/WdJ3AjW876g/s320/first2.JPG" alt="" id="BLOGGER_PHOTO_ID_5214994855255275298" border="0" /&gt;&lt;/a&gt;La valeur chargée dans EBX est issue de la stack, où a surement été copié le contenu de notre fichier crafté, elle doit donc être foireuse et au moment d'accéder à EBX+73B0 on tombe sur une zone mémoire non allouée et ça déclenche un "Access violation". Simple, non ? Regardons exactement la gueule de la stack au moment du plantage pour s'en convaincre : la copie de notre fichier commence en 00123A64, et EBX a effectivement été réécris puisqu'il contient 6964652D qui est bien contenu dans notre .map. Voyons si nous ne pouvons pas nous servir de ce déclenchement d'erreur pour rediriger le flux d'exécution... :-)&lt;br /&gt;&lt;br /&gt;Un autre "détail" intéressant est le fait que, à partir d'un certains nombres de caractères, notre programme est "killé" et sans aucun message d'erreur, essayons d'identifier la source de ce comportement étrange ( jsuis trop en forme là ) :&lt;br /&gt;&lt;br /&gt;Je bourrine un bon gros fichier .map fabriqué avec amour ( plus de 12000 caractères ) et on observe avec Olly... Notre "Access violation" a bien lieu à la même ligne à cause de la valeur contenue dans EBX, le programme va alors chercher un gestionnaire d'exception pour traiter ce cas d'erreur...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Interlude - Gestion d'exception sous Windows&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Pour bien comprendre ce qui suit, il est bon d'avoir quelques notions de la gestion d'exception sous windows : &lt;span style="font-style: italic;"&gt;ce qui suit est lâchement pompé du très bon article de Carib publié dans theHackademyManuel #12&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Lorsqu'un évènement imprévu survient et qu'une exception est déclenchée le contrôle est passé à la procédure KiUserExceptionDispatcher() qui va dérouler un algorithme pour décider où doit se poursuivre l'exécution du programme. Il existe différents types de gestionnaire, regroupés sous l'acronyme SEH (Structured Exception Handling), mais dans notre cas il est bon de retenir que ceux qui nous intéressent (car mis dans la pile :)) sont les gestionnaires de threads qui sont mis en place à l'aide d'une structure SEH simple :&lt;br /&gt;&lt;br /&gt;DWORD Next SEH&lt;br /&gt;DWORD SEH Handler&lt;br /&gt;&lt;br /&gt;Le premier champ pointe sur la structure SEH suivante ( ou -1 si il y en a pas ) et le second désigne la procédure qui traitera l'exception.&lt;br /&gt;Les gestionnaires d'un thread sont donc chainés les uns aux autres : si un handler n'est pas capable de gérer une exception, il a la possibilité de renvoyer une valeur signifiant à KiUserExceptionDispatcher() de passer le contrôle au gestionnaire suivant, qui pourra éventuellement la traiter. Rajoutons à cela le fait que ces structures SEH sont placés dans la pile et que le dernier gestionnaire installé ( donc celui qui sera appelé en premier )  est pointé par fs:[0].&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ce qu'il faut retenir, c'est que lorsqu'une exception se déclenche le dernier gestionnaire d'exception installé est appelé et qu'il y a donc redirection du flux d'exécution sur le SEH Handler qu'il contient.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Un dernier détail, qui n'en est pas un, c'est que &lt;span style="font-weight: bold;"&gt;au moment du lancement du SEH Handler, le système lui passe 3 arguments dont le premier est un pointeur vers un code d'erreur associé à l'exception ( et qui se trouve placé dans la pile ) et le deuxième est un pointeur vers la structure SEH dont on lance justement le SEH Handler&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;!&lt;/span&gt; ( donc ce deuxième argument contient exactement l'adresse du champ Next SEH ).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Fin de l'interlude&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Donc on revient à notre programme qui cherche un gestionnaire d'exception après avoir eu un accès mémoire invalide : il regarde donc dans fs:[0] pour trouver le plus récemment enregistré et il y lit... 001265F4 qui est bien une adresse dans la pile et &lt;span style="font-weight: bold;"&gt;qui a été écrasé lors de la copie de notre .map&lt;/span&gt; fr0m the h3ll. Alors le programme JUMPe sur l'adresse du SEH Handler, qui est invalide car j'ai mis de la merde dans mon fichier, et donc ça redéclenche une exception qui ne peut être traitée car il n'y a plus de gestionnaires SEH et donc finalement le programme se kill ( c'est très schématique, toute information complémentaire est encouragée dans les commentaires ;))&lt;br /&gt;&lt;br /&gt;Donc l'idée est assez simple : on va réécrire le champ SEH Handler avec une valeur "qui va bien" pour rediriger le flux d'exécution à partir du déclenchement d'une exception.&lt;br /&gt;Le problème c'est que n'est plus aussi simple depuis l'introduction du flag de compilation /SafeSEH avec Visual Studio 2003 qui fait en sorte qu'on ne puisse donner comme adresse de SEH Handler que des valeurs qui ont été précédemment enregistrées, et donc on est un ptit peu niked. Vérifions donc si ce tag est présent ici, pour cela j'utilise le plugin pour Olly SafeSEH disponible &lt;a href="http://www.tuts4you.com/download.php?view.1676"&gt;ici&lt;/a&gt;.&lt;br /&gt;Il va nous indiquer ce qui a été compilé avec le flag :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_Uc9LKH3dBWc/SF90QeHp1rI/AAAAAAAAABA/4VfzzV3gqnw/s1600-h/safeSEH.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_Uc9LKH3dBWc/SF90QeHp1rI/AAAAAAAAABA/4VfzzV3gqnw/s320/safeSEH.JPG" alt="" id="BLOGGER_PHOTO_ID_5215014719830218418" border="0" /&gt;&lt;/a&gt;Alleluia ! L'exécutable n'a pas été compilé avec /SafeSEH, ce qui veut dire qu'on peut JUMPer où l'on veut dans son code... &lt;span style="font-weight: bold;"&gt;Le but étant de revenir dans la stack&lt;/span&gt; où l'on a copié notre .map ( et qui pourrait contenir un shellcode :)), c'est là qu'on se rapelle du fait que le gestionnaire d'exception prend en deuxième argument l'adresse de la structure SEH, qui se trouve donc être dans la stack à un endroit qu'on peut tout à fait écraser...&lt;br /&gt;&lt;br /&gt;Une technique classique lors de ce genre d'exploitation consiste à mettre l'adresse d'une suite d'instructions : POP | POP | RET comme SEH Handler, on va donc ainsi dépiler l'adresse de retour, puis le premier argument et retourner sur le deuxième argument du handler ( le pointeur vers notre structure SEH dans la pile, c'est à dire le champ Next SEH ).&lt;br /&gt;Une fois qu'on est revenu sur le Next SEH, on a à notre disposition les 4 octects de ce champ pour JUMPer sur un shellcode qu'on aura placé dans la pile...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;III- Now it's time to do the payload&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Essayons de tout mettre en place pour n'avoir plus que le shellcode à insérer dans notre fichier .map. Si on récapitule par un petit schéma de notre pile montrant les différentes étapes :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_Uc9LKH3dBWc/SF-ycYr_eNI/AAAAAAAAABI/2U4LPMSQYz8/s1600-h/stack.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_Uc9LKH3dBWc/SF-ycYr_eNI/AAAAAAAAABI/2U4LPMSQYz8/s320/stack.jpg" alt="" id="BLOGGER_PHOTO_ID_5215083094251370706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On met tout ça en place dans un fichier .map qui va bien en prenant comme adresse du POPPOPRET 00416CEB où l'on trouve :&lt;br /&gt;&lt;br /&gt;00416CEB  |. 59             POP ECX&lt;br /&gt;00416CEC  |. 59             POP ECX&lt;br /&gt;00416CED  \. C3             RETN&lt;br /&gt;&lt;br /&gt;Le fait que ça soit POPer dans ECX a son importance comme nous le verrons tout à l'heure.&lt;br /&gt;&lt;br /&gt;On lance le programme, l'exception se déroule et on regarde la tête de notre stack avant l'appel au gestionnaire d'exception (j'ai rempli tous les caractères inutiles par des 0x90 et mis des 0xCC dans le Next SEH) :&lt;br /&gt;&lt;br /&gt;001265E4   90909090&lt;br /&gt;001265E8   90909090&lt;br /&gt;001265EC   90909090&lt;br /&gt;001265F0   90909090&lt;br /&gt;001265F4   CCCCCCCC  Pointer to next SEH record&lt;br /&gt;001265F8   00416CEB  SE handler&lt;br /&gt;001265FC   00000000&lt;br /&gt;00126600   00000000&lt;br /&gt;00126604   00000000&lt;br /&gt;&lt;br /&gt;On laisse l'exception continuer... La main est donné au "gestionnaire" placé en 00416CEB qui double-POP et retourne à l'adresse 001265F4 pour s'interrompre ( instruction 0xCC). It's fun !&lt;br /&gt;&lt;br /&gt;Mais on remarque quelque chose : après avoir copié mon adresse 00416CEB dans la pile (donc en partant du 0xEB pour finir par copier le 0x00), toute la suite a été mis à 0x00... &lt;span style="font-weight: bold;"&gt;Donc dès qu'on 0x00 est copié, tout ce qui suit est aussi mis à zéro !&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Ca nous pose un problème : on ne peut pas utiliser l'espace mémoire situé après l'adresse du SE Handler pour mettre un shellcode ( on aurait pu atteindre ce shellcode en mettant un JMP 4 à la place du champ Next SEH et ainsi retomber après le champ SEH Handler ).&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Donc on doit obligatoirement placer le shellcode avant la structure SEH et trouver un moyen, avec les 4 octets du champ Next SEH de "remonter" dans la pile.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Placer le shellcode plus haut ne pose aucun problème si ce n'est qu'il ne faut pas qu'il y ait de 0x00 dedans. Il faut maintenant JUMPer pour "remonter" au dessus. Pour celà, nous avons donc 4 octets à notre disposition. Ma première idée était de faire un JMP SHORT en négatif : on utilise des entiers signés donc un JMP 0xYY avec le premier bit de YY à 1 remontera dans la pile ( en fait descendra puisqu'elle croit vers les adresses décroissantes, mais bref vous avez compris l'idée ). Le problème est bien sûr évident : on ne peut "remonter" que à 127 octets à partir du JMP, donc ça limite grandement la taille de notre shellcode. Je n'y connais pas grand chose dans ce domaine mais en voyant la geule des générateurs automatiques, les shellcodes Windows semblent dépasser alègrement les 160 octets.&lt;br /&gt;Donc il nous faut trouver un autre moyen pour remonter toujours plus haut (alllllerrrr plus hauuuut) in th3 st4ck.&lt;br /&gt;C'est là qu'on se souvient du premier argument du SEH Handler qui est une adresse d'un code d'erreur mis dans la stack que l'on POP dans ECX au moment de notre POP|POP|RET. Essayons de manipuler cette adresse pour qu'elle tombe dans notre buff3r de la mort.&lt;br /&gt;Pour cela, un petit rappel sur les registres :&lt;br /&gt;si ECX=00123456&lt;br /&gt;alors CX = 3456&lt;br /&gt;CH = 34&lt;br /&gt;CL = 56&lt;br /&gt;&lt;br /&gt;La valeur qu'on a mis dans ECX ( une adresse sur la stack ) est de la forme 0012XXYY et rappelons nous que le fichier copié dans la stack est décris par une plage d'adresse de la forme 0012ZZYY et est d'une très grosse taille ( plus de 11k octets ). Donc il serait intéressant de manipuler CH pour transformer XX en ZZ et caler un JMP ECX derrière qui nous amènerait en plein milieu de notre buffer. &lt;span style="font-weight: bold;"&gt;Ceci est tout à fait faisable sur 4 octets puisque MOV CH,ZZ est sur 2 octets et JMP ECX de même.&lt;/span&gt;&lt;br /&gt;Dans mon cas, le paramètre POPer dans ECX est &lt;span style="color: rgb(51, 204, 0);"&gt;00123314&lt;/span&gt; ( l'adresse où se trouve le code d'erreur de l'exception ) et mon fichier copié dans la stack commence à l'adresse &lt;span style="color: rgb(51, 51, 255);"&gt;00123A64&lt;/span&gt;, il me suffit par exemple de faire un MOV CH,3B ( B5 3B en ASM x86 ) et je me retrouve avec ECX qui contient l'adresse &lt;span style="color: rgb(255, 0, 0);"&gt;00123B14 &lt;/span&gt;qui pointe inside my buff3r. Je rajoute derrière un JMP ECX ( FF E1 ) et en 4 octets me voilà en position de force pour exécuter un shellcode :-)&lt;br /&gt;Pour récapituler, ma stack ressemble finalement à :&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;00123A64&lt;/span&gt;   90909090 &lt;- Début de la copie de mon file&lt;br /&gt;00123A68   90909090&lt;br /&gt;. . . &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;00123B14&lt;/span&gt;   90909090 &lt;- Pointé par ECX après MOV CH,3B &lt;br /&gt;. . .&lt;br /&gt;001265E8   &lt;span style="color: rgb(255, 255, 51);"&gt;shellcode&lt;/span&gt;&lt;br /&gt;001265EC   &lt;span style="color: rgb(255, 255, 0);"&gt;from&lt;/span&gt;&lt;br /&gt;001265F0   &lt;span style="color: rgb(255, 255, 0);"&gt;the h3ll&lt;/span&gt;&lt;br /&gt;001265F4   E1FF3BB5  Pointer to next SEH record&lt;br /&gt;001265F8   00416CEB  SE handler&lt;br /&gt;001265FC   00000000&lt;br /&gt;00126600   00000000&lt;br /&gt;&lt;br /&gt;J'ai transformé tous mes caractères caca par des NOPs (0x90) histoire de pas me prendre la tête avec les adresses, là je peux remonter très haut à partir de ECX et caler un shellcode de plus de 10k octets sans problème.&lt;br /&gt;&lt;br /&gt;Pour conclure, on voit que les SEH c'est de la boulette pour se faire un BOF qui pwne, mais il faut bien avoué que si le tag /SafeSEH avait été mis à la compilation du tool, cette technique ne marcherait pas ( impossible de mettre l'adresse d'un POP|POP|RET en SEH Handler ).&lt;br /&gt;Il doit aussi sûrement exister d'autres manières que le MOV CH,XX JMP ECX pour 'remonter' dans notre buffer.&lt;br /&gt;&lt;br /&gt;Et pour pas vous vendre du vent, voici un fichier crafté avec un shellcode bien foireux made in Metasploit : il vous lance un processus cmd.exe mais vous ne le verrez pas puisqu'il appelle WinExec avec un paramètre mis à 0 au lieu de 1, et comme le shellcode est polymorphique et que j'y connais (pour le moment ! :=D) pas grand chose dans ce domaine, je vois pas bien ce qu'il faut modifier. Donc vous pouvez checker que ça marche dans le sens où le processus est bien créé :-) ( ou remplacer le shellcode par un qui marche mieux ...)&lt;br /&gt;&lt;br /&gt;Je peux pas vous mettre directement le fichier .map ( la copie du 0x00 ne passe pas ;-X)  mais je vous donne le dump hexadécimal du file, vous permettant de le générer vous même avec les outils qui vont bien pour ça ( python? :p ) :&lt;br /&gt;&lt;br /&gt;&lt;a href="http://uuu.enseirb.fr/%7Ecalvet/map.txt"&gt;map.txt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Special thanks to 0vercl0k and Ivan x-D&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-919490483242233215?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/919490483242233215/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=919490483242233215' title='3 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/919490483242233215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/919490483242233215'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/06/first-real-exploitation-on-windows.html' title='First real exploitation on Windows'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_Uc9LKH3dBWc/SF9WRs5HjAI/AAAAAAAAAAg/8z3Qrb5TVvY/s72-c/interface.bmp' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-8084298394124693523</id><published>2008-06-16T18:34:00.013+02:00</published><updated>2008-06-24T23:54:48.848+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='double-free() error'/><category scheme='http://www.blogger.com/atom/ns#' term='free() overflow'/><title type='text'>Double-free attack V2.0</title><content type='html'>Suite aux nombreux messages d'encouragement qui ont suivis la première version de ce post (&lt;span style="font-style: italic;"&gt;traduction : après deux remarques du genre "Putin mais ton dernier post c'est de la merde t'as rien décris du tout&lt;/span&gt;") j'ai décidé de reprendre à zéro l'analyse du double-free() et de pousser un peu plus loin. Et j'ai bien fait... puisqu'il y avait plus de choses à dire que ce que je pensais :-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;I- Il y a fort longtemps...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Donc on reprend l'histoire depuis le début : toute personne ayant déjà suivie un cours de programmation en C s'est entendu dire "il ne faut pas oublier de free() tout pointeur alloué avec malloc(), et ne pas re-free() une zone déjà libéré". En effet, si on en croit la page de manuel qui va bien :  "if the space [qu'on essaye de free()] has been deallocated by a call to &lt;i&gt;free&lt;/i&gt;() [...] the behavior is undefined." Donc si on "double-free()" un pointeur, le comportement serait aléatoire ?&lt;br /&gt;&lt;br /&gt;Nous allons donc voir, à travers plusieurs versions de la libc ( puisque ce qui nous intéresse ici c'est les fonctions malloc() et free() ) quel est ce fameux comportement.&lt;br /&gt;&lt;br /&gt;Testons ça dans un premier temps sur une version Windows XP SP2 ...&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;void * first=malloc(20);&lt;br /&gt;void * second;&lt;br /&gt;void * third;&lt;br /&gt;&lt;br /&gt;free(first);&lt;br /&gt;free(first); // Oh My God, un double-free !&lt;br /&gt;&lt;br /&gt;second=malloc(20);&lt;br /&gt;*((int *)second)=2;&lt;br /&gt;third=malloc(20);&lt;br /&gt;*((int *)third)=3;&lt;br /&gt;&lt;br /&gt;printf("second : %d, third : %d\n",*((int*)second),*((int*)third));&lt;br /&gt;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Et là que se passe t'il dude ?&lt;br /&gt;&lt;br /&gt;&gt; second : 3, third : 3&lt;br /&gt;&lt;br /&gt;Là tu n'en crois pas tes yeux cher lecteur, mais pour finir de te convaincre de ce comportement intéressant, je rajoute un petit :&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;if(third==second)&lt;br /&gt;printf("third = second !!!\n");&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Et ça donne :&lt;br /&gt;&lt;br /&gt;&gt; second : 3, third : 3&lt;br /&gt;third = second !!!&lt;br /&gt;&lt;br /&gt;WTF ? Et bien oui les deux pointeurs désignent la même zone mémoire ! &lt;span style="font-weight: bold;"&gt;Donc quand on fait un double-free() avec cette version de la libc, les deux malloc() qui suivent vont désigner le même endroit&lt;/span&gt;, on comprend aisément que si dans un programme ce genre d'erreur se produit, ou du moins qu'on arrive à faire en sorte que ça soit le cas  ( genre un cas à la con que le programmeur a pas prévu qui va "double-free()" une variable globale) et que l'utilisateur à la main sur les données rentrées à partir du deuxième malloc(), il va écraser celles du premier et c'est le &lt;span style="font-weight: bold;"&gt;0v3RFl0W&lt;/span&gt; dude !&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;II- And now, what's up ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Il est temps de tester le double-free() avec la dernière version de la libc (2.7), je reprend donc mon superbe code, je lance l'exécution et là :&lt;br /&gt;&lt;br /&gt;*** glibc detected *** ./test: double free or corruption (fasttop): 0x0804a008 ***&lt;br /&gt;&lt;br /&gt;Pinaiz, ils ont implémenté une protection anti-"double free()". Shame on me, mon overflow de la mort ne fonctionne plus ?&lt;br /&gt;&lt;br /&gt;Intéressons nous donc réellement au fonctionnement de free()|malloc(), pour voir quelle est cette nouvelle protection qui ma pwned.&lt;br /&gt;Donc, direction la libc et plus particulièrement malloc.c qui contient le code des deux fonctions sus-nommées ( et oué ).&lt;br /&gt;&lt;br /&gt;Première étape, se renseigner sur la gestion des blocs (chunks) libres, puisque c'est celà qui nous intéresse ici.&lt;br /&gt;On trouve un passage intéressant dans les commentaires ligne 2049 :&lt;br /&gt;"Chunks of the same size are linked with the most recently freed at the front, and allocations are taken from the back."&lt;br /&gt;Donc les blocs libres sont mis dans des "free-list" qui contiennent des blocs de même taille et l'allocation fonctionne sur un modèle FIFO : quand on libère un bloc il est ajouté en tête de la liste qui le concerne et quand on a besoin d'un bloc on prend le plus "vieux" ( donc celui qui se trouve à la fin ).&lt;br /&gt;&lt;br /&gt;Regardons donc maintenant la protection "anti-double free()" : on cherche le code de free() et on voit à la ligne 4594 :&lt;br /&gt;&lt;br /&gt;if (__builtin_expect (*fb == p, 0))&lt;br /&gt;   {&lt;br /&gt; errstr = "double free or corruption (fasttop)";&lt;br /&gt; goto errout;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;où p est l'adresse du bloc qu'on veut libérer et fb un pointeur vers la free-list qui lui est associé (celle qui contient les blocs libres de même taille que lui).&lt;br /&gt;Tiens donc ? &lt;span style="font-weight: bold;"&gt;Ce test vérifie donc que le bloc qu'on veut libérer n'est pas celui qui se trouve en tête de la free-list associée, donc si il n'est pas le dernier qui a été free().&lt;/span&gt;&lt;br /&gt;Vérifions ce comportement :&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;void * first=malloc(12);&lt;br /&gt;void * second=malloc(12); // Ces deux pointeurs seront stockés dans la même  free-list lors de leurs libération&lt;br /&gt;&lt;br /&gt;free(first);&lt;br /&gt;free(second);&lt;br /&gt;free(first); // Oh my God, double-free() on first !&lt;br /&gt;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;On lance le bouzin et... aucun message d'erreur ! On a pu double-free() notre pointeur sans aucun souci. Le check qui est effectué par la libc est donc facilement bypassable... Mais en même temps on "comprend" qu'un check complet de la free-list ( donc un parcours linéaire ) serait très couteux en temps.&lt;br /&gt;&lt;br /&gt;Maintenant qu'on voit comment on peut pwned la protection, voyons si on pourrait exploiter celà pour faire un overflow. Réprésentons l'évolution de la free-list associée à mes deux pointeurs first et second :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Uc9LKH3dBWc/SFjfbiDOVII/AAAAAAAAAAY/-uELfivIgo4/s1600-h/freeList.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_Uc9LKH3dBWc/SFjfbiDOVII/AAAAAAAAAAY/-uELfivIgo4/s320/freeList.jpg" alt="" id="BLOGGER_PHOTO_ID_5213162232771138690" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;C'est là que dans ton cerveau malade la possibilité de l'overflow apparait (rappelons que lors de l'appel à malloc(), le bloc choisi est celui qui se trouve "en bas" de la free-list), si je rajoute dans mon code :&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void * third=malloc(12); // va prendre le premier bloc du bas (=first)&lt;br /&gt;void * fourth=malloc(12); // va prendre le deuxième bloc en partant du bas (=second)&lt;br /&gt;void * cinqth=malloc(12); // va prendre le troisième bloc en partant du bas (=first !)&lt;br /&gt;&lt;br /&gt;if(third==cinqth)&lt;br /&gt; printf("Double free inside the heap !\n");&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Et l'exécution donne :&lt;br /&gt;$ Double free inside the heap !&lt;br /&gt;&lt;br /&gt;Cinqth (et oué) et third pointe sur le même bloc ! Donc on en reviens au principe originel : ce qui sera écris à partir de cinqth écrasera ce qui a été écris à partir de third -&gt; game over.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;On peut donc voir que les double-free() sont encore possibles, il faut néanmoins, pour qu'ils soient exploitables, qu'il y ait eu au moins un autre free() d'un bloc de même taille entre temps. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;III- The ultimate protection...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La solution pour éviter de devoir checker dans des codes assez lourd à chaque free(ptr) ce qu'on a fait avant avec le pointeur, c'est de faire :&lt;br /&gt;&lt;br /&gt;free(ptr); ptr=NULL;&lt;br /&gt;&lt;br /&gt;puisque d'après le manuel "If ptr is NULL, no operation is performed.", donc un deuxième free() ne foutra pas la zone. Easy, no ? A noter que ce genre de "bug" est déjà arrivé sur des projets assez costaud (voir &lt;a href="http://www.cert.org/advisories/CA-2002-07.html"&gt;ici&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-8084298394124693523?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/8084298394124693523/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=8084298394124693523' title='5 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8084298394124693523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/8084298394124693523'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/06/double-free-attack.html' title='Double-free attack V2.0'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_Uc9LKH3dBWc/SFjfbiDOVII/AAAAAAAAAAY/-uELfivIgo4/s72-c/freeList.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6861594251940891157.post-5257601962010390531</id><published>2008-06-12T21:30:00.000+02:00</published><updated>2008-06-14T14:06:24.352+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSP'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='GCC'/><category scheme='http://www.blogger.com/atom/ns#' term='stack overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='Stack Smashing Protection'/><title type='text'>GCC is protecting you...</title><content type='html'>Pour un newbie qui veut devenir une pop-star du hack, les "buffers overflows" (BOF), techniques ancestrales, constituent une cible de choix car très documenté et assez facile à réaliser. Malheureusement pour lui, le jeune wanabee va très vite s'apercevoir que les buffers overflows ça marche plus comme dans les tutoriaux de grand-papa.&lt;br /&gt;&lt;br /&gt;Dans ce post je vais m'efforcer de décrire les protections de GCC 4 ( donc la version actuelle ) concernant les "stack-overflows", la variante la plus abordable des BOFs, histoire de mieux comprendre was passiert.&lt;br /&gt;&lt;br /&gt;Il est supposé que celui qui lit ça connait le principe d'un stack overflow, si ce n'est pas le cas, il peut se mettre un doigt dans le cul car je ne vais pas expliquer quelque chose que d'autres ont déjà décrit bien mieux que moi.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;I- GCC has a protector...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Et son nom est le Stack Smashing Protector (SSP) dont le but est simple : tout d'abord protèger la cible principale d'un stack overflow c'est à dire l'adresse de retour empilé au moment d'un appel de fonction. Mais aussi une deuxième cible potentielle : la sauvegarde du Base Pointer qui est effectué par le prologue de la fonction ( pour éviter les attaques du type "&lt;a href="http://www.ghostsinthestack.org/article-21-loff-by-one.html"&gt;Off by one&lt;/a&gt;"),  et la troisième cible possible : les variables locales de la fonction qui pourraient également être écrasées par un buffer. Finalement, il existe une quatrième et dernière cible : les arguments de la fonction ( qui pourrait être écrasés pour faire de multiple "&lt;a href="http://www.ghostsinthestack.org/article-6-les-ret-onto-ret.html"&gt;Ret-onto-ret&lt;/a&gt;" par exemple ).&lt;br /&gt;&lt;br /&gt;Pour réaliser ces 4 objectifs, le SSP va réaliser trois actions particulières en intervenant directement au niveau du code assembleur produit par GCC : l'ajout de canary, la réorganisation des variables locales et la sauvegarde des arguments des fonctions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Avant d'entrer plus dans les détails, remarquons que le SSP est activé par défaut dans GCC 4 et que vous pouvez le désactiver en compilant votre programme avec l'option -fno-stack-protector, ce qui permet de très vite comprendre les différences.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;II- Cui-cui&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;SSP, notre Superman, va, pour protéger le Saved EBP et le Saved EIP, rajouter un "canary". Le principe est simple : pour éviter que l'on puisse venir à partir d'un buffer ( situé plus bas dans la pile ) écraser ses deux sauvegardes, on va placer une constante aléatoire avant de placer les variables locales à la fonction :&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_Uc9LKH3dBWc/SFGCGi41cbI/AAAAAAAAAAM/USEtr-RUwig/s1600-h/stack1.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://bp2.blogger.com/_Uc9LKH3dBWc/SFGCGi41cbI/AAAAAAAAAAM/USEtr-RUwig/s320/stack1.jpg" alt="" id="BLOGGER_PHOTO_ID_5211089292800389554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Le principe théorique du canary est alors facile à comprendre : on suppose que le programme a la possibilité de connaitre de façon certaine la valeur du canary (en en plaçant une copie dans un endroit inaccessible en écriture) et que l'utilisateur lui ne peut pas la deviner (car elle est aléatoire). Il suffit alors au programme de vérifier à la fin de la fonction que c'est bien la même valeur.&lt;br /&gt;&lt;br /&gt;En pratique, le fonctionnement des canary est différent avec SSP, puisque d'après la documentation, il y a des cas où le programme n'est pas capable de générer une valeur aléatoire pour mettre dans son canary. Dans ce cas-là il se rabat sur une valeur fixe : 0xff0a0000 ( en big-endian).  Et c'est là que tout un tas de questions up dans ton mind !&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-weight: bold;"&gt;Pourquoi le programme ne pourrait pas générer une valeur aléatoire ?&lt;/span&gt; Alors là c'est mystère et boule de gommes, cette valeur est normalement générer avec /dev/urandom et je vois pas bien pourquoi il y aurait un problème d'accès. En tout cas ce qui est sûr c'est qu'après pas mal de test, &lt;span style="font-weight: bold;"&gt;cette valeur n'est jamais aléatoire&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;chez moi&lt;/span&gt;, et avec le manque de clarté des diverses docs là dessus je suis toujours à la recherche de la réponse.&lt;span style="font-weight: bold;"&gt; Donc notre canary contient toujours la valeur 0xff0a0000.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mais si le canary à toujours la même valeur, pourquoi qu'on le remplace pas par cette valeur au moment de l'overflow et ni vu ni connu jt'embrouille ?! &lt;/span&gt;&lt;br /&gt;Tu aura remarqué que la valeur du canary parait avoir été choisie : elle contient les caractères 0x00 ( terminaison d'une string ) et  0x0a c'est à dire "\n" en ASCII (terminaison pour la fonction gets() ) qui vont donc rendre impossible tout buffer overflow par les fonctions de manipulation de string : quand tu va vouloir copier ta chaine de caractère pour tout écraser tu ne pourra pas remplacer le canary par sa valeur car ces caractères particuliers constituent des fins de string et tu n'ira donc pas plus loin.&lt;br /&gt;Mais là, une boulette apparait : si le buffer overflow n'est pas déclenché par une fonction de manipulation de string "classique" mais par une fonction encore plus foireuse "faite maison" ou directement en manipulant la mémoire avec memcpy() ? Ben là tu pourra tout à fait réécrire le canary...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Et les performances dans tout ça ?&lt;/span&gt;&lt;br /&gt;Les canary ne sont rajoutés que dans les fonctions "où ça en vaut la peine", c'est à dire &lt;span style="font-weight: bold;"&gt;dès qu'un tableau de char de taille au moins égale à 8&lt;/span&gt; est déclaré dans une fonction, ce qui limite l'atteinte aux performances.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;En pratique ça ressemble à quoi ?&lt;/span&gt;&lt;br /&gt;Pour celà, codons nous un exemple bateau de fonction "vulnérable" à un stack overflow :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void function(char * src)&lt;br /&gt;{&lt;br /&gt;char buffer[10];&lt;br /&gt;strcpy(buff,src);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char * argv[])&lt;br /&gt;{&lt;br /&gt;function(argv[1]);&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Il est important de remarquer que nous ne occupons pas du cas où la faille apparait directement dans le main() car dans GCC 4 le prologue de cette fonction est différent de celui des autres ( j'y reviendrai dans un autre post, mais pour le moment j'ai pas tout compris ) et ça ne fait que compliquer les choses et ça n'a aucun intéret pour comprendre le fonctionnement des canarys.&lt;br /&gt;&lt;br /&gt;Donc on prend notre courage à deux mains, on lance gdb sur le programme et on désassemble notre function() pour voir si on voit quelque chose qui concerne ces fameux oiseaux. Je vous présente ces lignes de codes ASM suivies de commentaires quand il y a besoin :&lt;br /&gt;&lt;br /&gt;function+0 :    push   %ebp&lt;br /&gt;function+1 :    mov    %esp,%ebp&lt;br /&gt;function+3 :    sub    $0x18,%esp&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Ceci est le prologue classique d'une fonction avec réservation de la place nécessaire aux variables locales...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;function+6 :    mov    0x8(%ebp),%eax&lt;br /&gt;function+9 :    mov    %eax,-0x14(%ebp)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Ces deux lignes seront expliqués plus bas, elles ne concernent pas les canarys&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;function+12 :    mov    %gs:0x14,%eax&lt;br /&gt;function+18 :    mov    %eax,-0x4(%ebp)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Tiens donc, sauvegarde d'une "valeur" contenue dans le registre GS juste après EBP xD&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;... &lt;- &lt;span style="font-style: italic;"&gt;Ici du code sans importance : appel a strpcy()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;function+23 :    mov    -0x4(%ebp),%eax&lt;br /&gt;function+26 :    xor    %gs:0x14,%eax&lt;br /&gt;function+33 :    je     0x80483bc &lt;function+40&gt;&lt;br /&gt;function+35 :    call   0x80482fc &lt;__stack_chk_fail@plt&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;On récupère la valeur sauvegardée précédemment et on la compare à la valeur initiale contenue dans le registre GS. Si elle est égale, on se dirige vers l'épilogue de la fonction sinon on saute sur la routine __stack_chk_fail dont le nom est assez explicite :P&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;function+40 :    leave&lt;br /&gt;function+41 :    ret&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Epilogue classique d'une fonction.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le fonctionnement parait assez clair : la valeur du canary est stocké dans le registre GS et on le met comme prévue juste après le Saved EBP ( pointé par EBP ). Dans le cas où il est écrasé on saute sur une routine qui doit sûrement déclencher un message d'erreur pas piqué des ours ( oué ça se dit ).&lt;br /&gt;&lt;br /&gt;Confirmons ce fonctionnement en sautant à pied joint dans la mémoire lorsqu'on est dans function() :&lt;br /&gt;&lt;br /&gt;(gdb) break function&lt;br /&gt;(gdb) run aaaaaaaa&lt;br /&gt;&lt;br /&gt;Et là, que vois t'on dans la pile ?&lt;br /&gt;...&lt;br /&gt;0xbffdff90:    0x61616161    &lt;span style="color: rgb(51, 255, 51);"&gt;0xff0a0000&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;   0xbffdffb8&lt;/span&gt; &lt;span style="color: rgb(51, 102, 255);"&gt;   0x0804842f&lt;/span&gt;&lt;br /&gt;...          &lt;br /&gt;Notre buffer a donc été rempli par les 'a' (0x61) que nous avons donné en argument et tout de suite après vient... notre &lt;span style="color: rgb(51, 255, 51);"&gt;canary&lt;/span&gt; ! Tout de suite suivie par le &lt;span style="color: rgb(255, 0, 0);"&gt;Saved EBP&lt;/span&gt; et le &lt;span style="color: rgb(51, 51, 255);"&gt;Saved EIP&lt;/span&gt;.&lt;br /&gt;Tout semble au mieux dans le meilleur des mondes, notre canary est bien en place et va donc empêcher les écrasement classiques par des fonctions type strcpy(). Ce qu'on voit par un test :&lt;br /&gt;&lt;br /&gt;$ ./prog aaaaaaaaaaaaaaaaaaaaa&lt;br /&gt;*** stack smashing detected ***: ./prog terminated&lt;br /&gt;&lt;br /&gt;Donc, nos deux premiers objectifs sont atteints !&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;III- Réorganisation des variables locales d'une fonction&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Cette réorganisation pars d'un principe simple : &lt;span style="font-weight: bold;"&gt;un buffer ne peut écraser que les valeurs qui ont été empilées avant lui, &lt;/span&gt;SSP se charge donc de mettre les buffers le plus près possible de EBP ( c'est à dire en haut de la pile ) et de placer les autres variables locales en dessous. Si le buffer déborde ça sera vers le haut et il ne pourra donc pas les écraser.&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Pour s'en convaincre compilons le petit code ci-dessous :&lt;br /&gt;&lt;br /&gt;void function()&lt;br /&gt;{&lt;br /&gt;int c=3;&lt;br /&gt;int d=4;&lt;br /&gt;char buff[8];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char * argv[])&lt;br /&gt;{&lt;br /&gt;function();&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;On regarde la tête de la stack dans function() :&lt;br /&gt;&lt;br /&gt;(gdb)x/16x $esp&lt;br /&gt;...&lt;br /&gt;0xbfaf4010:    0xb7ef4b19    0x00000004    0x00000003    0x080482c8&lt;br /&gt;...&lt;br /&gt;(gdb) x/x buff&lt;br /&gt;0xbfaf401c:    0x080482c8&lt;br /&gt;&lt;br /&gt;Notre buffer se trouve bien plus haut dans la pile que nos deux variables locales, malgré le fait qu'il soit déclaré avant les deux constantes, il a été empilé en premier.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/function+40&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;IV- Recopie des arguments d'une fonction&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Dernière protection apportée par SSP : la recopie de certains arguments des fonctions, en fait &lt;span style="font-weight: bold;"&gt;tous les pointeurs passés en argument sont recopiés dans le contexte de la fonction pour éviter de faire référence aux arguments&lt;/span&gt;. Let's test :&lt;br /&gt;&lt;br /&gt;void function(char * src, char * src2, int * c)&lt;br /&gt;{&lt;br /&gt;char buff[8];&lt;br /&gt;strcpy(buff,src);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char * argv[])&lt;br /&gt;{&lt;br /&gt;int * d;&lt;br /&gt;function(argv[1],"bbbbb",d);&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;On saute avec gdb dans la stack de function() pour voir ce qui se passe :&lt;br /&gt;&lt;br /&gt;(gdb) b function&lt;br /&gt;(gdb) run &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;aaaaaaaa&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;function (src=0xbfcbd750 "aaaaaaaa", src2=0x8048510 "bbbbb", c=0xb7fe6dc0)&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;(gdb) x/16x $esp&lt;br /&gt;0xbfcbb9a0:    0xbfcbb9bc    0xbfcbd750    0x00000000    &lt;span style="color: rgb(255, 0, 0);"&gt;0xb7fe6dc0&lt;/span&gt;&lt;br /&gt;0xbfcbb9b0:   &lt;span style="color: rgb(255, 0, 0);"&gt; 0x08048510&lt;/span&gt;    &lt;span style="color: rgb(255, 0, 0);"&gt;0xbfcbd750&lt;/span&gt;    0x00000000    &lt;span style="color: rgb(0, 204, 204);"&gt;0x61616161&lt;/span&gt;&lt;br /&gt;0xbfcbb9c0:    &lt;span style="color: rgb(102, 204, 204);"&gt;0x61616161&lt;/span&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;0xff0a0000&lt;/span&gt;    0xbfcbb9f8    0x0804843c&lt;br /&gt;0xbfcbb9d0:    0xbfcbd750    0x08048510    0xb7fe6dc0    0x080482ec&lt;br /&gt;&lt;br /&gt;Voici donc que nos 3 adresses passées en arguments ont été recopiés dans le contexte de la fonction, avec bien sûr la réorganisation des variables locales elles se retrouvent plus haut que le &lt;span style="color: rgb(0, 204, 204);"&gt;buffer&lt;/span&gt;.&lt;br /&gt;Pour finir de s'en convaincre, on regarde le code :&lt;br /&gt;&lt;br /&gt;(gdb) disassemble function&lt;br /&gt;...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;prologue classique&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;function+6  :    mov    0x8(%ebp),%eax&lt;br /&gt;function+9  :    mov    %eax,-0x14(%ebp)&lt;br /&gt;function+12:    mov    0xc(%ebp),%eax&lt;br /&gt;function+15:    mov    %eax,-0x18(%ebp)&lt;br /&gt;function+18:    mov    0x10(%ebp),%eax&lt;br /&gt;function+21:    mov    %eax,-0x1c(%ebp)&lt;br /&gt;...&lt;br /&gt;&lt;span style="font-style: italic;"&gt;mise en place du canary et suite de la fonction&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Bref, rien de bien compliqué de ce côté là.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;Pour conclure, j'espère que ce post t'aura permis de comprendre le fonctionnement de SSP. Maintenant on peut réfléchir à des attaques possibles contre les diverses protections misent en place :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6861594251940891157-5257601962010390531?l=joe-is-a-rocknroll-star.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joe-is-a-rocknroll-star.blogspot.com/feeds/5257601962010390531/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6861594251940891157&amp;postID=5257601962010390531' title='9 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/5257601962010390531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6861594251940891157/posts/default/5257601962010390531'/><link rel='alternate' type='text/html' href='http://joe-is-a-rocknroll-star.blogspot.com/2008/06/gcc-is-protecting-you.html' title='GCC is protecting you...'/><author><name>JoE</name><uri>http://www.blogger.com/profile/05721724412770179649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_Uc9LKH3dBWc/SFGCGi41cbI/AAAAAAAAAAM/USEtr-RUwig/s72-c/stack1.jpg' height='72' width='72'/><thr:total>9</thr:total></entry></feed>
