WEBVTT 00:00:05.007 --> 00:00:10.009 Quel processeur bizarre - faire des misères au x86... et un peu de PE [Portable Executable] 00:00:10.009 --> 00:00:19.004 Bienvenue... et surtout, dites-moi si je vais trop vite 00:00:19.004 --> 00:00:28.002 Je vais parler des opcodes, et un peu du format PE et de leurs bizarreries 00:00:28.002 --> 00:00:35.000 Je fais du reverse depuis quelque temps. J'ai créé un projet appelé Corkami. 00:00:35.000 --> 00:00:42.003 Dans le passé, j'ai participé à Mame, l'émulateur Arcade, et professionnellement, analyste de virus, 00:00:42.003 --> 00:00:48.001 mais je suis ici à titre personnel, ce sont mes propres expériences à la maison. 00:00:48.001 --> 00:00:57.000 Donc, je viens de mentionner Corkami. C'est le nom du projet de mon projet de reverse [rétro-ingénierie] 00:00:57.000 --> 00:01:03.007 Je n'y parle que de choses techniques, pas de pubs, pas de login requis 00:01:03.007 --> 00:01:06.005 Directement le pur jus. 00:01:06.005 --> 00:01:12.004 J'essaie de le maintenir à jour, et util. J'ai créé des fiches pense-bêtes et d'autre documents 00:01:12.004 --> 00:01:15.008 que j'utilise moi-même au boulot, au quotidien 00:01:15.008 --> 00:01:18.006 mais c'est juste un loisir. je commence quand les enfants sont couchés 00:01:18.006 --> 00:01:23.001 tard dans la nuit, donc ça n'a probablement pas le polish professionnel 00:01:23.001 --> 00:01:25.002 que j'aimerais qu'il ait. 00:01:25.002 --> 00:01:30.005 Actuellement, Corkami est un wiki et des pense-bêtes 00:01:30.005 --> 00:01:37.005 et je me focalise sur la création de preuves de concepts [démonstration d'hypothèse, "proof of concept] [Tiens, salut Bob!] 00:01:37.005 --> 00:01:42.008 donc les binaires sont fait-main, d'habitude je n'utilise pas de compilateurs, je créé la structure du PE à la main 00:01:42.008 --> 00:01:46.004 pour que ce soit focalisé sur le point pertinent 00:01:46.004 --> 00:01:49.000 et qu'on est pas de parasites. on n'a probablement pas besoin d'IDA 00:01:49.000 --> 00:01:51.004 pour comprendre ce qui se passe 00:01:51.004 --> 00:01:54.009 car je me concentre uniquement sur ce qui est important. 00:01:54.009 --> 00:01:58.002 Les binaires sont directement téléchargeables pour que vous puissiez 00:01:58.002 --> 00:02:01.003 tester avec votre débogueur, vos outils, vos connaissances, 00:02:01.003 --> 00:02:03.008 directement. 00:02:03.008 --> 00:02:07.006 pour l'instant, je me suis concentré sur le PDF, l'assembleur et le format PE 00:02:07.006 --> 00:02:11.002 quelques autres trucs, mais ce sont les sujets les plus approfondis 00:02:11.002 --> 00:02:15.000 du site, et je partage tout ça avec une licence 00:02:15.000 --> 00:02:19.008 très permissive, BSD, donc vous pouvez réutiliser commercialement 00:02:19.008 --> 00:02:24.006 Même les images sont en format ouvert. 00:02:24.006 --> 00:02:29.003 Donc, la raison de cette présentation... il y a quelque temps, 00:02:29.003 --> 00:02:32.003 J'étais jeune et innocent, et je pensais que les CPUs, fait de transistors, 00:02:32.003 --> 00:02:38.004 était parfaitement logique 00:02:38.004 --> 00:02:41.006 et ensuite, un virus m'a piégé... simplement, 00:02:41.006 --> 00:02:46.005 IDA était rendu inutile. Donc j'ai décidé de repartir à zéro 00:02:46.005 --> 00:02:49.007 et d'étudier l'assembleur et le PE du début. 00:02:49.007 --> 00:02:52.009 j'ai écrit en chemin des documents, partagés sur Corkami 00:02:52.009 --> 00:02:57.006 et maintenant je vous présente le résultat plus ou moins final, 00:02:57.006 --> 00:03:01.006 ou du moins quelques buts atteints. Si j'étais juste un gars qui a étudié l'assembleur 00:03:01.006 --> 00:03:05.004 je ne serais probablement pas en train de présenter ici, 00:03:05.004 --> 00:03:10.005 à moins d'avoir eu quelques résultats avec certains outils. 00:03:10.005 --> 00:03:13.008 Donc, pour résumer, j'ai trouvés des bogues dans tous les désassembleurs que j'ai essayé 00:03:13.008 --> 00:03:22.000 et j'ai aussi obtenus quelques plantages. J'insiste que tous les auteurs ont été contactés 00:03:22.000 --> 00:03:26.000 et que la plupart des problèmes ont déjà été corrigé, 00:03:26.000 --> 00:03:30.009 mais en tout cas, en version 6.1, il plante directement, mais dans la version 6.2 00:03:30.009 --> 00:03:33.003 c'est corrigé. 00:03:33.003 --> 00:03:37.004 et la dernière version de Hiew [Hacker's view] (enfin, pas la dernière publique) 00:03:37.004 --> 00:03:41.004 corrige ça aussi. 00:03:41.004 --> 00:03:44.008 Donc, pour cette présentation, je commencerais facile, 00:03:44.008 --> 00:03:50.008 je pars du principe que vous êtes tous habitués à l'assembleur ? 00:03:50.008 --> 00:03:57.003 Oui. et vous êtes tous habitués, ou 00:03:57.003 --> 00:04:02.009 vous avez déjà rencontré des cas d'opcodes non documentés? 00:04:02.009 --> 00:04:06.001 Genre vous faites confiance à IDA, point barre. 00:04:06.001 --> 00:04:10.005 Est-ce habituel de voir quelque chose non géré par IDA ? 00:04:10.005 --> 00:04:14.003 Levez les bras... ok, pas tant que ça. 00:04:14.003 --> 00:04:19.005 Bon, après l'introduction en accéléré, 00:04:19.005 --> 00:04:25.003 Je parlerais de quelques techniques, puis présenterai CoST, mon programme 00:04:25.003 --> 00:04:28.009 et je parlerais aussi un peu du format PE 00:04:28.009 --> 00:04:34.000 Bon, vous connaissez tous l'assembleur, on va survoler ... 00:04:34.000 --> 00:04:37.009 Donc, on compile un binaire, il y a de l'assembleur, il y a 00:04:37.009 --> 00:04:44.002 un rapport, des points communs entre le code source et l'assembleur généré... 00:04:44.002 --> 00:04:48.007 et bien sûr, une relation entre langage machine et les opcodes 00:04:48.007 --> 00:04:53.006 ce qui est important est que l'assembleur est généré par le compilateur, mais ce qui reste 00:04:56.006 --> 00:04:59.007 dans le binaire, sont uniquement les opcodes, qui sont interprétés 00:04:59.007 --> 00:05:03.003 directement par le processeur, ce qui implique qu'il sache quoi faire avec, 00:05:03.003 --> 00:05:07.003 il s'en fiche si vous ou vos outils 00:05:07.003 --> 00:05:10.008 ne savent pas ce qui va arriver. il le fait, tout simplement. 00:05:10.008 --> 00:05:16.001 Et le problème, c'est que d'habitude, on ne lit pas les opcodes directement, mais le désassemblage 00:05:16.001 --> 00:05:20.006 donc si le désassemblage échoue, on est bloqué 00:05:20.006 --> 00:05:25.004 on est aveugle, on ne sait pas ce qui va s'exécuter 00:05:25.004 --> 00:05:28.000 l'autre problème est comme les instructions sont de longueurs variables 00:05:28.000 --> 00:05:30.003 on ne sait pas ou la suivante commence 00:05:30.003 --> 00:05:32.003 donc même la suite est inconnue. 00:05:32.003 --> 00:05:40.001 Donc, on créé une seule instruction non documentée dans un programme simple 00:05:40.001 --> 00:05:48.006 on utilise le mot-clef 'emit' -- c'est Visual Studio 2010 ultimate -- 00:05:48.006 --> 00:05:52.002 et on obtient un octet non identifié au désassemblage 00:05:52.002 --> 00:05:58.004 on a des juste points d'interrogations. 00:05:58.004 --> 00:06:01.007 et donc, même si Visual Studio coûte plusieurs milliers d'euros 00:06:01.007 --> 00:06:05.000 il ne sait pas ce qui va se produire.... 00:06:05.000 --> 00:06:09.000 et si on regarde les documentations Intel 00:06:09.000 --> 00:06:14.002 circulez, il y a rien a voir... l'opcode D6... inconnu au bataillon 00:06:14.002 --> 00:06:17.009 Microsoft n'a rien à dire, Intel non plus, 00:06:17.009 --> 00:06:21.001 donc d'habitude, si vous essayez des choses comme ça, attendez-vous au pire. 00:06:21.001 --> 00:06:26.005 Donc, aucune information... en général, ça annonce un plantage... 00:06:26.005 --> 00:06:29.007 mais dans ce cas particulier, aucun problème... 00:06:29.007 --> 00:06:35.002 nous ne savons pas ce qui se passe, si on regarde les docs Intel et Microsoft, on n'en sait pas plus. 00:06:35.002 --> 00:06:41.002 Mais le CPU a juste fait son boulot dans son coin. Ce qui s'est passé est qu'en fait 00:06:41.002 --> 00:06:49.001 D6 est un opcode très simple, qui ne fait pas grand chose, mais pas documenté par Intel, 00:06:49.001 --> 00:06:53.009 par contre, il l'est par AMD, et la plupart le sont aussi également, par AMD mais pas Intel 00:06:53.009 --> 00:06:58.001 aucune idée pourquoi. si quelqu'un le sait... 00:06:58.001 --> 00:07:04.001 c'est un opcode pourtant trivial, pourtant... 'y a rien à voir, continuez votre chemin' 00:07:04.001 --> 00:07:08.003 Il est utilisé souvent... l'utilisation habituelle de tels opcodes sont les virus et les packeurs 00:07:08.003 --> 00:07:13.003 pour éviter les analyses automatisées où trop facile. 00:07:13.003 --> 00:07:22.002 Ce qui est ironique, c'est que si vous regardez la doc, elle est pleine de trous. mais le désassembleur d'Intel, 00:07:22.002 --> 00:07:25.002 Xed, qui est gratuit mais pas ouvert, gère tous ces opcodes sans problème... 00:07:25.002 --> 00:07:35.005 Alors que Microsoft, Visual Studio, et WinDBG, suivent la documentation aveuglément 00:07:35.005 --> 00:07:43.000 Donc vous obtiendrez des points d'interrogation alors qu'Intel sait très bien ce qui se passe 00:07:43.000 --> 00:07:52.003 'faites ce que je fais, pas ce que je dit' 00:07:52.003 --> 00:08:01.001 donc, bien sûr, vous me direz que WinDbg est fait uniquement ce qui est généré 00:08:01.001 --> 00:08:08.000 par les compilateurs Microsoft, mais ça exclut WinDBG comme outil d'analyse de virus: 00:08:08.000 --> 00:08:17.006 vous rajoutez D6, trivial, et WinDbg est muet. 00:08:17.006 --> 00:08:25.005 pas génial 00:08:25.005 --> 00:08:32.007 un autre problème est que toutes ses choses non documentées 00:08:32.007 --> 00:08:37.006 sont peut-être présentes, l'une dans un virus, 00:08:37.006 --> 00:08:42.003 l'autre dans un packeur, etc... donc il n'est pas facile 00:08:42.003 --> 00:08:46.005 de trouver un bon regroupement de tels fichiers pour rassembler toutes ces informations 00:08:46.005 --> 00:08:50.002 donc par exemple, 00:08:50.002 --> 00:08:53.004 quelqu'un vous parle d'une astuce 00:08:53.004 --> 00:08:55.008 et vous dit qu'elle est enfouit dans MebRoot (un virus costaud) 00:08:55.008 --> 00:08:58.007 donc vous êtes obligé de creuser pour voir juste la partie qui vous intéresse 00:08:58.007 --> 00:09:03.009 et en plus, on sait que c'est un virus, donc ca ne circule pas facilement, 00:09:03.009 --> 00:09:08.006 et il y a plein de trucs dedans qui n'ont rien à voir dedans, 00:09:08.006 --> 00:09:15.001 avant ou après ce qui vous intéresse. Donc c'est le fossé que je veux remplir en fournissant 00:09:15.001 --> 00:09:21.001 un groupe de fichier à la fois simple et complet, et focalisé. 00:09:21.001 --> 00:09:27.007 Donc, on commence. enfin, du vrai, quelques opcodes non documentés. 00:09:27.007 --> 00:09:37.000 Mais avant d'avoir commencé à étudier, je me suis demandé quelles étaient les vrais capacités 00:09:37.000 --> 00:09:44.005 des processeurs, quelles instructions existent vraiment. 00:09:44.005 --> 00:09:52.002 C'est un peu comme l'anglais: la plupart de la population mondiale comprend ces mots, et 00:09:52.002 --> 00:09:57.007 si vous avez déjà désassemblé quelque chose, vous êtes habitués à ces instructions 00:09:57.007 --> 00:10:04.003 tous les compilateurs les utilisent. elles sont tellement répandues que si elles sont absentes, 00:10:04.003 --> 00:10:08.006 on se sent pris au dépourvu. 00:10:08.006 --> 00:10:19.007 mais les processeurs Intels datent des années 70. Donc, 00:10:19.007 --> 00:10:27.007 comme l'anglais de Shakespeare, vous voyez que c'est de l'anglais... mais, ça veut dire quoi en fait ? 00:10:27.007 --> 00:10:30.005 d'ailleurs, j'ai déjà oublié 00:10:30.005 --> 00:10:36.003 ces instructions sont toutes gérées par tous nos processeurs, pourtant, on n'a plus l'habitude de les lire 00:10:36.003 --> 00:10:41.009 c'est plus que génant 00:10:41.009 --> 00:10:46.008 En fait, j'ai écrit un exemple qui n'utilisent que ces vieilles instructions, qui font vraiment quelque chose 00:10:46.008 --> 00:10:53.001 donc si vous vous sentez ici comme chez vous, je voudrais vous demander 'quel âge avez-vous ?' 00:10:53.001 --> 00:10:59.007 parce que même moi, j'ai l'habitude de PUSH/JUMP/CALLs, mais ça, euhh... 00:10:59.007 --> 00:11:05.008 pourtant, ça marche même sur un i7, et c'est utilisable par les virus, 00:11:05.008 --> 00:11:13.009 les packeurs, etc... pourtant, la plupart est complètement inutilisée de nos jours, bien que parfaitement 00:11:13.009 --> 00:11:15.009 gérées par nos processeurs modernes. 00:11:15.009 --> 00:11:21.004 Et, tel l'anglais, c'est une langue qui évolue, et les générations précédentes 00:11:21.004 --> 00:11:27.007 n'ont pas l'habitude des derniers mots à la mode. 00:11:27.007 --> 00:11:35.001 Ces instructions sont parfois présentes sur les processeurs les plus récent. en une seule instruction, on fait 00:11:35.001 --> 00:11:41.003 un CRC32, on décrypte l'AES, on compare des chaînes, ou d'autres opérations complexes. 00:11:41.003 --> 00:11:47.006 Donc, c'est possible sur un processeur moderne. pas tous, bien sûr. 00:11:47.006 --> 00:11:54.006 une que j'aime bien est MOVBE -- move big endian -- parce que c'est le vilain petit canard du lot... 00:11:54.006 --> 00:12:01.008 uniquement implémentée sur les processeurs Atom, donc comme ce netbook, qui la gère... 00:12:01.008 --> 00:12:09.003 alors qu'un i7 64-bits ne l'a pas, même si lui aura CRC32, peut-être AES, etc... 00:12:09.003 --> 00:12:12.005 donc, tant pis pour la retro-compatibilité 00:12:12.005 --> 00:12:20.002 à ma connaissance, il n'y existe aucun processeur qui gère à la fois CRC32 et MOVBE. 00:12:20.002 --> 00:12:24.008 De plus, MOVBE est un peu inutile car il fait la même chose que MOV et BSWAP réunit... 00:12:24.008 --> 00:12:32.000 donc, bizarre. en tout cas, ce mini-PC a une instruction que la plupart des PC n'ont pas 00:12:32.000 --> 00:12:35.002 Pourquoi ? quelqu'un sait? 00:12:35.002 --> 00:12:37.008 [Auditeur:] "cette instruction est documentée ?" 00:12:37.008 --> 00:12:38.007 oui 00:12:38.007 --> 00:12:42.008 totalement documentée officiellement 00:12:42.008 --> 00:12:46.008 [Auditeur:] "Mais, c'est un drapeau du processeur juste pour cette instruction, ou implicitement lié au 00:12:46.008 --> 00:12:51.003 processeurs Atom ? 00:12:51.003 --> 00:12:58.003 mmm, je ne sais pas. je vérifie la valeur par CPUID, mais j'ai oublié la définition exacte. 00:12:58.003 --> 00:13:07.005 il y a tant d'informations données par CPUID que j'ai vite oublié. 00:13:07.005 --> 00:13:13.006 Autre chose, spécifique à Windows, car je m'intéresse aux virus... 00:13:13.006 --> 00:13:22.005 avant d'exécuter quoi que ce soit, je me demandais quelle était la valeur initiale de chaque registre 00:13:22.005 --> 00:13:28.007 quand le programme démarre. 00:13:28.007 --> 00:13:33.006 et ça vous donne en fait de l'information fiable, qu'on retrouve utilisée par les virus 00:13:33.006 --> 00:13:40.005 donc par exemple, au démarrage, EAX vous dit si vous êtes sur un OS ancien (XP ou avant) 00:13:40.005 --> 00:13:42.008 ou plus récent, Vista ou 7. 00:13:42.008 --> 00:13:50.007 de même, ce n'est pas utilisé par les virus à mon souvenir, mais si GS est nul, on est dans un OS 32 bits 00:13:50.007 --> 00:13:54.002 sinon, sur un 64b. 00:13:54.002 --> 00:13:56.009 J'utilise ça régulièrement, on le verra plus tard. 00:13:56.009 --> 00:14:04.003 De même, la relation entre les registres n'est pas forcément évidente. il y en a beaucoup, 00:14:04.003 --> 00:14:10.007 et j'ai été surpris qu'une instruction à virgule flottante (FPU) change le statut (FST), les registres 00:14:10.007 --> 00:14:18.005 eux-mêmes (STx), les registres MMx aussi, mais en plus, toutes les documentations en ligne associent 00:14:18.005 --> 00:14:24.009 ST0 et MM0, ce qui semble logique, alors qu'en fait, une seule instruction modifie 00:14:24.009 --> 00:14:31.003 non pas MM0, mais MM7, dans l'autre sens. 00:14:31.003 --> 00:14:36.007 donc après une instruction comme "load PI" [FLDPI] on regarde la valeur de MM7, 00:14:36.007 --> 00:14:39.004 ça peut-être utilisé comme astuce simple. 00:14:39.004 --> 00:14:45.009 alors que toutes les documentations, Wikipedia ou autre, se trompent. 00:14:45.009 --> 00:14:53.003 quelque chose d'autre qui peut être utilisé comme anti-débogueur sous XP: le FPU modifie aussi CR0 00:14:53.003 --> 00:14:59.007 donc ça fait une astuce anti-émulateur plutôt inattendue rien qu'avec le FPU. 00:14:59.007 --> 00:15:09.000 'store machine status word' [SMSW] est une instruction qui date du 286, quand le mode protégé était 00:15:09.000 --> 00:15:18.004 récent et incomplet, qui permet de lire les valeurs de CR0, même depuis le mode utilisateur. 00:15:18.004 --> 00:15:26.009 alors que 'MOV CR0' est privilégiée 00:15:26.009 --> 00:15:34.001 pour une raison inconnue, le mot de poid fort est officiellement non défini. 00:15:34.001 --> 00:15:40.004 donc à priori, on ne sait pas ce qu'il va contenir, 00:15:40.004 --> 00:15:45.007 mais en fait il s'agit bien du même mot de poid fort que CR0. 00:15:45.007 --> 00:15:52.009 et, sous XP, après une instruction FPU, la valeur de CR0 est modifiée, mais reprend sa valeur initiale 00:15:52.009 --> 00:16:00.003 toute seule par la suite. donc juste avec SMSW, verifier le résultat, puis faire une opération FPU, 00:16:00.003 --> 00:16:05.009 alors SMSW donnera un résultat différent, mais ensuite, le résultat redeviendra comme à l'origine. 00:16:05.009 --> 00:16:11.000 un moyen élégant de faire des boucles en apparence infinies. une astuce complexe anti-émulateurs. 00:16:11.000 --> 00:16:18.008 Une astuce similaire sous Windows 32b, où GS n'est pas stocké dans le CONTEXT, donc quand l'OS passe d'un 00:16:18.008 --> 00:16:25.006 fil d'exécution à l'autre (thread-switch), GS est remis à zero. Donc, si on attend, quoi qu'on fasse, 00:16:25.006 --> 00:16:33.003 GS change comme par enchantement. Mais si vous faites du pas à pas, c'est lent, donc l'OS change de fil, 00:16:33.003 --> 00:16:40.005 et GS est perdu dès l'instruction suivante. 00:16:40.005 --> 00:16:45.006 De même, si on attend que GS devienne nul, on finira par sortir de la boucle. 00:16:45.006 --> 00:16:53.001 En tout cas, la première fois, ça défiait mon entendement... sans autres process ou autre, je ne comprenais 00:16:53.001 --> 00:16:58.007 pas d'où ça venait. Au moins, mon exemple commence dès le début avec ça 00:16:58.007 --> 00:17:02.009 c'est plus pratique 00:17:02.009 --> 00:17:11.000 une autre particularité, c'est que ça met du temps pour être remis à zéro. en faisant 2 boucles d'attentes, 00:17:11.000 --> 00:17:17.005 et mesurant le temps entre les 2 (changement de fil), ça prend somme toute assez longtemps, comparé à une 00:17:17.005 --> 00:17:25.005 exécution standard. ça fait un anti-émulation solide. 00:17:25.005 --> 00:17:33.001 Je pensais tout naturellement que NOP était parfait! NOP, c'est NOP, ça ne fait rien, donc, aucun problème ! 00:17:33.001 --> 00:17:44.001 Mais à l'origine, NOP est 'échange ?AX avec lui-même' (xchg ?ax, ?ax) mais c'est le cas pour le NOP encodé 0x90 00:17:44.001 --> 00:17:51.001 mais il y a un autre encodage de XCHG EAX, EAX, qui ne fait rien non plus en 32b 00:17:51.001 --> 00:17:54.006 mais, à l'instar de toutes les instructions sur 32b en mode 64b 00:17:54.006 --> 00:17:58.007 cette instruction remet à zéro le double mot de poid fort 00:17:58.007 --> 00:18:02.007 donc on a un XCHG EAX [,EAX] qui fait quelque chose. 00:18:02.007 --> 00:18:05.007 bien qu'initialement il semblerait ne rien faire, de sa relation avec NOP 00:18:05.007 --> 00:18:10.001 mais heureusement, le NOP 0x90, lui, ne fait toujours rien, un vrai fainéant ;) 00:18:10.001 --> 00:18:14.001 Celui-ci est maintenant bien répandu, 00:18:14.001 --> 00:18:18.004 le HINT NOP est un NOP sur plusieurs octets 00:18:18.004 --> 00:18:23.004 qui indique au processeur ce qui va être exécuté ou accédé ensuite 00:18:23.004 --> 00:18:24.005 quelque soit l'adresse dans un HINT NOP en mémoire, 00:18:24.005 --> 00:18:26.002 aucune exception n'est déclenchée 00:18:26.002 --> 00:18:32.003 mais ... 00:18:32.003 --> 00:18:37.002 autre chose, il est partiellement non documenté par Intel 00:18:37.002 --> 00:18:44.005 (comme d'habitude, ce n'est pas le cas avec AMD) 00:18:44.005 --> 00:18:48.003 en outre, comme c'est une instruction sur plusieurs octets, avec des opérandes immédiates 00:18:48.003 --> 00:18:51.007 si on met ces octets à la fin d'une page mémoire 00:18:51.007 --> 00:18:55.000 alors le processeur va vouloir lire l'encodage des opérandes, 00:18:55.000 --> 00:18:56.006 et ça va déclencher une exception 00:18:56.006 --> 00:19:01.003 donc c'est un NOP qui peut déclencher une exception en bas de page 00:19:01.003 --> 00:19:04.005 Merci, Intel 00:19:04.005 --> 00:19:07.000 MOV également, je croyais... 00:19:07.000 --> 00:19:11.003 qu'il devrait être parfaitement logique 00:19:11.003 --> 00:19:16.000 mais, même s'il est documenté, il y a des cas compliqués, 00:19:16.000 --> 00:19:19.007 qui n'étaient pas parfaitement gérés dans tous les assembleurs que j'ai essayé 00:19:19.007 --> 00:19:22.009 sauf peut-être Xed 00:19:22.009 --> 00:19:29.005 on ne peut pas faire un MOV de ou vers CR0 en mémoire, 00:19:29.005 --> 00:19:33.000 la documentation dit que le Mod/RM est ignoré 00:19:33.000 --> 00:19:34.001 ce qui ne veut pas dire que l'instruction est invalide 00:19:34.001 --> 00:19:35.000 simplement, considéré comme n'utilisant pas la mémoire 00:19:35.000 --> 00:19:36.007 sinon, ça ferait un plantage 00:19:36.007 --> 00:19:39.005 donc, voici l'équivalent 00:19:39.005 --> 00:19:42.003 ce qui mettait en tord tous les désassembleurs 00:19:42.003 --> 00:19:44.004 jusque récemment 00:19:44.004 --> 00:19:50.000 MOVSXD est une instruction 64b, qui étend un registre 00:19:50.000 --> 00:19:55.003 donc, d'un registre vers un plus gros 00:19:55.003 --> 00:19:58.002 mais sans préfixe REX - ce qui n'est pas encouragé, 00:19:58.002 --> 00:20:02.000 on peut l'utiliser comme un MOV standard, de 32b vers 32b 00:20:02.000 --> 00:20:04.003 et dans l'autre sens, 00:20:04.003 --> 00:20:09.009 MOV d'un selecteur à un registre 32b marche sans problème, 00:20:09.009 --> 00:20:13.002 alors que beaucoup de désassembleurs afficheraient MOV AX, CS, ce qui semble logique 00:20:13.002 --> 00:20:16.000 niveau taille 00:20:16.000 --> 00:20:19.007 mais en fait le mot de poid fort du registre cible est 'non défini' 00:20:19.007 --> 00:20:21.008 mais ici, pas de surprise amusante, 00:20:21.008 --> 00:20:25.002 ce sont juste des zéros 00:20:25.002 --> 00:20:30.003 donc c'est équivalent à MOV EAX, CS 00:20:30.003 --> 00:20:32.005 BSWAP est un de mes favoris 00:20:32.005 --> 00:20:35.001 parce que je le compare à une administration: 00:20:35.001 --> 00:20:38.002 il est supposé passer d'un endianisme [endianness] à l' autre 00:20:38.002 --> 00:20:42.008 mais pour diverses raisons, 00:20:42.008 --> 00:20:45.001 il ne peut jamais faire son travail correctement 00:20:45.001 --> 00:20:50.004 donc, c'est juste en 64b que tout se passe 00:20:50.004 --> 00:20:51.009 comme prévu 00:20:51.009 --> 00:20:55.009 en 32b, comme toutes les autres instruction 32b 00:20:55.009 --> 00:20:59.003 le double mot de poid fort est mis à zéro... 00:20:59.003 --> 00:21:02.007 et sur un mot, il est non défini officiellement, 00:21:02.007 --> 00:21:04.001 mais il est pourtant utilisé couramment dans les virus et les packeurs 00:21:04.007 --> 00:21:07.000 car il remet simplement à zéro le registre, 00:21:07.000 --> 00:21:09.005 comme un simple XOR AX, AX 00:21:09.005 --> 00:21:14.005 donc, devant un résultat si inexplicable, je comprends 00:21:14.005 --> 00:21:18.007 qu'Intel ne veuille pas en parler 00:21:18.007 --> 00:21:20.009 ça serait sûrement gênant de devoir expliquer 00:21:20.009 --> 00:21:24.007 ce résultat plutôt comique. 00:21:24.007 --> 00:21:33.004 BSWAP AX est aussi mal géré par WinDbg et les autres 00:21:33.004 --> 00:21:35.006 on lira BSWAP EAX 00:21:35.006 --> 00:21:42.000 alors que le registre est remis à zéro... génant 00:21:42.000 --> 00:21:47.003 tout le monde comprend ce code? 00:21:47.003 --> 00:21:53.000 quelqu'un voit un piège possible? 00:21:53.000 --> 00:21:56.006 l'adresse de est empilée 00:21:56.006 --> 00:22:00.003 puis dépilée par RETN 00:22:00.003 --> 00:22:05.006 donc, on saute vers une adresse immédiates 00:22:05.006 --> 00:22:11.003 l'ordre d'exécution ? 00:22:11.003 --> 00:22:18.000 oui, l'exécution démarre ici 00:22:18.000 --> 00:22:20.009 non, rien à voir ici 00:22:20.009 --> 00:22:26.000 voilà OllyDbg 1 - c'est corrigé dans le 2 00:22:26.000 --> 00:22:28.002 Olly essaie même d'être sympa et de vous dire 00:22:28.002 --> 00:22:30.005 via un commentaire automatique, 00:22:30.005 --> 00:22:33.005 que RET sera utilisé comme saut vers 00:22:33.005 --> 00:22:36.003 et, voyez le résultat, plutôt différent 00:22:36.003 --> 00:22:37.004 donc, que c'est-il passé ? 00:22:37.004 --> 00:22:40.002 quelqu'un voit ? 00:22:40.002 --> 00:22:43.002 donc, RETN a un prefix 66 00:22:43.002 --> 00:22:47.003 donc, il retourne vers IP (16b), pas EIP 00:22:47.003 --> 00:22:56.001 donc on ne saute pas vers 401008, mais 00001008 00:22:56.001 --> 00:22:58.007 et dans mon exemple, la page nulle a été allouée 00:22:58.007 --> 00:23:01.000 et du code a été placé à 1008 00:23:01.000 --> 00:23:06.000 donc, ça ne retourne pas vers [] 00:23:06.000 --> 00:23:10.008 mais l'autre problème est que c'est aussi appelé un RETN 00:23:10.008 --> 00:23:15.007 bien que ce soit différent. les désassembleurs ont leur propre façon de l'afficher 00:23:15.007 --> 00:23:19.005 tel que 'small retn', 'ret.16', ou autre 00:23:19.005 --> 00:23:22.007 mais officiellement, c'est la même instruction qu'un RETN standard. 00:23:22.007 --> 00:23:28.006 donc, le dernier Hiew, et OllyDbg 1 00:23:28.006 --> 00:23:31.001 peut-être pas le 2 00:23:31.001 --> 00:23:33.001 mais on peut se faire avoir 00:23:33.001 --> 00:23:41.002 et le préfixe 66 a le même role avec CALLs, RETs, LOOPs, JMPs 00:23:41.002 --> 00:23:45.008 toutes les instructions contrôlant le flux d'exécution 00:23:45.008 --> 00:23:48.002 je ne vais pas tout énumérer 00:23:48.002 --> 00:23:51.007 car sinon vous allez mourir d'ennui 00:23:51.007 --> 00:23:55.004 pour en savoir plus, j'ai créé une page sur Corkami [x86.corkami.com], 00:23:55.004 --> 00:24:00.007 avec quelques graphiques et penses-bêtes 00:24:00.007 --> 00:24:04.007 pour faciliter le boulot 00:24:04.007 --> 00:24:06.009 bon, trop de théorie 00:24:06.009 --> 00:24:11.008 je n'aime pas lire sans avoir quelque chose à me mettre sous le débogueur, 00:24:11.008 --> 00:24:13.006 donc j'ai créé CoST 00:24:13.006 --> 00:24:16.000 ce qui signifie Corkami Standard Test 00:24:16.000 --> 00:24:20.000 CoST est un unique binaire, sans option de ligne de commande 00:24:20.000 --> 00:24:25.004 on l'exécute, il fait plein de tests 00:24:25.004 --> 00:24:28.006 le tout dans un PE compliqué 00:24:28.006 --> 00:24:35.001 pour aussi tester vos outils PE 00:24:35.001 --> 00:24:36.004 ou vos connaissances 00:24:36.004 --> 00:24:40.001 mais, dans ce PE compliqué, il est casse-pied à déboguer 00:24:40.001 --> 00:24:42.007 donc j'ai fait aussi une version 'PE standard' 00:24:42.007 --> 00:24:47.004 si on ne veut étudier que l'assembleur 00:24:47.004 --> 00:24:49.004 sans difficultés 00:24:49.004 --> 00:24:57.008 donc, CoST contient de nombreux tests 00:24:57.008 --> 00:24:59.007 les classiques, triviaux, 00:24:59.007 --> 00:25:03.009 un peu plus compliqués, JMP to IP, IRET... 00:25:03.009 --> 00:25:05.003 les non documentés 00:25:05.003 --> 00:25:10.004 les spécifiques aux processeurs, comme MOVBE, POPCNT, CRC32 00:25:10.004 --> 00:25:17.008 les détections d'OS et VM 00:25:17.008 --> 00:25:25.004 comme le fameux 'red pill'... juste une instruction SLDT, on compare le résultat, 00:25:25.004 --> 00:25:29.001 et on baptise ça 'red pill'... sans commentaire... 00:25:29.001 --> 00:25:32.009 et aussi, des bogues des SE, parce que Windows XP 00:25:32.009 --> 00:25:35.005 se trompe en essayant de vous dire 00:25:35.005 --> 00:25:38.006 quelle exception vient de se produire, 00:25:38.006 --> 00:25:44.007 ce qui permettrait de différencier un SE réel d'un émulateur. 00:25:44.007 --> 00:25:50.002 CoST est écrit en assembleur, donc rien de superflu 00:25:50.002 --> 00:25:52.007 pas compilé, ni généré 00:25:52.007 --> 00:25:56.007 mais pour le documenter un peu plus, j'ai ajouté des exports internes 00:25:56.007 --> 00:26:00.000 donc on peut aller facilement d'une section à l'autre 00:26:00.000 --> 00:26:05.008 donc on se retrouve facilement à la partie qui nous intéresse 00:26:05.008 --> 00:26:08.003 via les exports, 00:26:08.003 --> 00:26:13.007 et je voulais pouvoir afficher un message de manière pratique 00:26:13.007 --> 00:26:18.005 sans que ça allonge trop le listing 00:26:18.005 --> 00:26:21.009 je veux dire, devoir faire défiler l'écran parce qu'il est couvert d'appel à printf 00:26:21.009 --> 00:26:25.007 donc j'au utilisé un Vectored Exception Handler, et une instruction-marqueur 00:26:25.007 --> 00:26:28.005 donc plein de commentaires sont affichés, 00:26:28.005 --> 00:26:30.003 directement dans le code 00:26:30.003 --> 00:26:34.008 donc ça fait un code binaire documenté sans fichier de symboles de débogage 00:26:34.008 --> 00:26:38.009 et vous avez vu, il n'y a pas beaucoup d'affichage 00:26:38.009 --> 00:26:41.009 mais en fait, il y a beaucoup plus d'affichage de déboguage 00:26:41.009 --> 00:26:46.008 une centaine au moins, qui indiquent même ce qui va se produire, etc 00:26:46.008 --> 00:26:49.006 donc on est pas pris au dépourvu 00:26:49.006 --> 00:26:57.007 on est guidé lors de l'analyse 00:26:57.007 --> 00:27:00.002 quelqu'un comprend de quoi il s'agit? 00:27:00.002 --> 00:27:02.008 c'est un de mes préférés 00:27:02.008 --> 00:27:06.001 on ne peut pas voir les opcodes 00:27:06.001 --> 00:27:17.006 ah, il n'y a pas d'astuce à ce niveau là cette fois-ci ;) 00:27:17.006 --> 00:27:19.006 donc, on empile des valeurs 00:27:19.006 --> 00:27:21.000 on saute ici 00:27:21.000 --> 00:27:26.001 et avec le RETF, j'ai empilé l'adresse de 'push_eip' 00:27:26.001 --> 00:27:28.005 et un mot, 0x33 00:27:28.005 --> 00:27:31.000 donc on va revenir de loin ici 00:27:31.000 --> 00:27:35.006 donc on retourne à cette adresse avec un sélecteur 33 00:27:35.006 --> 00:27:39.001 qui est réservé au mode 64b, même pour un programme en 32b 00:27:39.001 --> 00:27:42.007 donc on va revenir ici, en mode 64b 00:27:42.007 --> 00:27:47.007 car 33 est le sélecteur pour le mode 64b 00:27:47.007 --> 00:27:49.008 qu'on peut atteindre depuis un programme 32b 00:27:49.008 --> 00:27:56.003 donc le code sera d'abord exécuté en mode 32b, avec le sélecteur standard, 00:27:56.003 --> 00:28:01.009 puis à nouveau, avec le sélecteur 33 00:28:01.009 --> 00:28:04.003 en mode 64b 00:28:04.003 --> 00:28:08.003 donc on a la même adresse, les mêmes opcodes, 00:28:08.003 --> 00:28:10.001 mais le désassemblage sera différent 00:28:10.001 --> 00:28:14.002 et j'ai choisi des opcodes qui génèrent des instructions 00:28:14.002 --> 00:28:18.001 spécifique à chaque mode 00:28:18.001 --> 00:28:22.009 donc, c'est déjà une belle s*loperie à désassembler, 00:28:22.009 --> 00:28:27.009 car avec la même EIP, si on ne fait pas attention au sélecteur, 00:28:27.009 --> 00:28:29.001 on est bloqué 00:28:29.001 --> 00:28:46.006 On peut déboguer un tel code - voir ma présentation à BerlinSides, transparent de démonstration 58 00:28:46.006 --> 00:28:50.006 Si on l'exécute en passant par dessus, on retourne au sélecteur d'origine 00:28:50.006 --> 00:28:52.005 qui était sauvé par le PUSH CS 00:28:52.005 --> 00:28:56.002 donc on retourne à avec le sélecteur initial 00:28:56.002 --> 00:28:58.007 l'exécution est rapide, 00:28:58.007 --> 00:29:00.007 mais difficile à déboguer (uniquement avec WinDbg+wow64exts) 00:29:00.007 --> 00:29:03.007 ça rend inutile les désassembleurs, et la plupart des débogueurs 00:29:03.007 --> 00:29:04.009 pourtant, c'est si simple. 00:29:04.009 --> 00:29:07.003 Voilà ce que donne CoST 00:29:07.003 --> 00:29:10.006 sous la dernière version de Hiew 00:29:10.006 --> 00:29:13.003 je pense que ce sera bientôt corrigé 00:29:13.003 --> 00:29:16.007 c'est un HINT NOP non documenté par Intel 00:29:16.007 --> 00:29:21.000 et oublié par la plupart des désassembleurs 00:29:21.000 --> 00:29:24.005 donc WinDbg et Hiew 00:29:24.005 --> 00:29:29.007 vous donnent des points d'interrogations 00:29:29.007 --> 00:29:34.006 au début, je pensais m'arrêter là pour Hashdays 00:29:34.006 --> 00:29:39.006 mais j'ai décidé de rajouter quelques astuces PE à CoST 00:29:39.006 --> 00:29:43.002 donc, en voici l'en-tête... MZ, puis du texte 00:29:43.002 --> 00:29:44.004 donc on peut taper 'type cost.exe', comme ce bon vieux Budokan... 00:29:44.004 --> 00:29:46.008 et ensuite, 00:29:46.008 --> 00:29:51.007 l'en-tête 'NT headers' - appelé 'PE' car il commence par ces lettres-là, 00:29:51.007 --> 00:29:54.007 et en fait à la fin du fichier 00:29:54.007 --> 00:29:56.000 le 'pied-de-page PE' 00:29:56.000 --> 00:29:59.003 et les valeurs de l'en-tête sont un peu extrême 00:29:59.003 --> 00:30:01.003 donc, pour le moins inattendu 00:30:01.003 --> 00:30:03.004 donc voici ce qu'IDA 6.1 en pensait 00:30:03.004 --> 00:30:07.001 ...plantage directe... 00:30:07.001 --> 00:30:11.002 ça lui apprendra à se fier aux valeurs 00:30:11.002 --> 00:30:15.009 mais, aussi bien dans CoST, on peut changer un registre, faire une comparaison, tester, 00:30:15.009 --> 00:30:17.000 et enchaîner ainsi plein de tests, 00:30:17.000 --> 00:30:19.006 aussi bien, côté PE, on n'a qu'un seul binaire, donc 00:30:19.006 --> 00:30:21.006 un seul essai 00:30:21.006 --> 00:30:25.007 donc même si CoST n'a pas de section, des TLS bizarres,.... 00:30:25.007 --> 00:30:27.007 il ne peut pas tout tester 00:30:27.007 --> 00:30:31.001 donc, j'ai créé pour ça une autre page sur Corkami 00:30:31.001 --> 00:30:37.002 avec comme d'habitudes, des exemples, des graphiques, 00:30:37.002 --> 00:30:40.007 elle n'est pas finie, mais déjà largement suffisante pour tester ou faire planter 00:30:40.007 --> 00:30:42.009 n'importe quel outil 00:30:42.009 --> 00:30:46.003 j'ai déjà une centaine d'exemples, 00:30:46.003 --> 00:30:51.006 qui mettent l'accent sur de nombreux aspects, avec parfois des résultats inattendus 00:30:51.006 --> 00:30:55.001 donc, voici une table de section virtuelle, et Hiew 00:30:55.001 --> 00:31:00.000 quand les alignements sont bas, on n'a pas besoin de section 00:31:00.000 --> 00:31:03.002 ou la table peut être vide 00:31:03.002 --> 00:31:08.003 donc, j'ai modifié SizeOfOptionalHeader pour qu'il pointe en espace mémoire virtuel 00:31:08.003 --> 00:31:11.009 donc la table des sections est en dehors du PE, pleines de zéros 00:31:11.009 --> 00:31:16.002 et Hiew n'aime pas ça. En conséquence, il ne pense même pas que c'est un PE 00:31:16.002 --> 00:31:18.008 alors que ça marche parfaitement, du moins sous XP 00:31:18.008 --> 00:31:27.002 car Windows 7 est plus capricieux concernant les valeurs de la table des section 00:31:27.002 --> 00:31:29.005 ensuite... 00:31:29.005 --> 00:31:34.002 si on fait de l'art dans les Data Directories 00:31:34.002 --> 00:31:37.001 vous pouvez commencer à vous inquiéter 00:31:37.001 --> 00:31:40.000 si vous avez un dessin plus joli, je suis preneur 00:31:40.000 --> 00:31:43.003 donc, il s'agit du 'Dual PE header', présenté 00:31:43.003 --> 00:31:46.001 par Reversing Labs à la BlackHat 00:31:46.001 --> 00:31:50.003 quelqu'un connaît ? 00:31:50.003 --> 00:31:52.005 donc, on augmente SizeOfHeader pour que 00:31:52.005 --> 00:31:59.006 les en-têtes NT soient en fait assez loin, 00:31:59.006 --> 00:32:04.000 pour qu'il soit aligné avec les sections 00:32:04.000 --> 00:32:05.005 quand il se charge en mémoire 00:32:05.005 --> 00:32:08.000 la première section sera chargée par dessus 00:32:08.000 --> 00:32:13.005 la première partie du OPTIONAL_HEADER est lue dans le fichier 00:32:13.005 --> 00:32:16.005 donc, prise en compte pour charger le fichier 00:32:16.005 --> 00:32:20.009 mais les Data Directories sont lus en mémoire 00:32:20.009 --> 00:32:25.000 donc, d'abord l'OPTIONAL_HEADER est analysé, chargé en mémoire, 00:32:25.000 --> 00:32:29.003 puis la section est dépliée sur la partie basse de l'en-tête 00:32:29.003 --> 00:32:31.008 et les vrais Data directories qui étaient initialement au début de la section 00:32:31.008 --> 00:32:34.002 vont être pris en compte, 00:32:34.002 --> 00:32:39.006 donc tout ceci est du pipeau présent dans le fichier, à la suite de SizeOfOptionalHeader 00:32:39.006 --> 00:32:45.000 mais en mémoire, ce sera écrasé et ignoré 00:32:45.000 --> 00:32:47.003 une autre bizarrerie est que les noms d'exports peuvent avoir n'importe quelle valeur, 00:32:47.003 --> 00:32:51.000 jusqu'au caractère zéro 00:32:51.000 --> 00:32:53.007 donc, absolument n'importe quoi, 00:32:53.007 --> 00:32:56.001 et de plus, 00:32:56.001 --> 00:32:57.005 Hiew les affichent directement 00:32:57.005 --> 00:32:59.003 donc on peut insérer ses propres messages 00:32:59.003 --> 00:33:02.005 ce sont juste des noms d'exports, d'ailleurs 00:33:02.005 --> 00:33:05.008 l'un d'entre eux est excessivement long, 00:33:05.008 --> 00:33:08.002 idéal pour tester les dépassement de tampon [buffer overflow] 00:33:08.002 --> 00:33:10.005 dans votre outil favori 00:33:10.005 --> 00:33:14.002 et il est également possible d'avoir un export avec un nom nul, 00:33:14.002 --> 00:33:16.003 on peut donc importer l'api nulle 00:33:16.003 --> 00:33:19.002 sans problème 00:33:19.002 --> 00:33:23.000 j'ai aussi essayé les différentes possibilités, 00:33:23.000 --> 00:33:26.004 avec des fichiers contenant un maximum de section, 00:33:26.004 --> 00:33:31.006 la limite est 96 sous XP, et 64K sous Vista et Windows 7 00:33:31.006 --> 00:33:33.000 ce qui donne 00:33:33.000 --> 00:33:36.007 avec le dernier OllyDbg 2 ce message surprenant 00:33:36.007 --> 00:33:38.002 mais le fichier charge quand même 00:33:38.002 --> 00:33:41.003 OllyDbg 1, lui, plante directement 00:33:41.003 --> 00:33:45.002 il reste du temps ? 00:33:45.002 --> 00:33:48.005 un dernier... pas très visuel 00:33:48.005 --> 00:33:52.006 l'adresse AddressOfIndex du TLS est mise à zéro au chargement 00:33:52.006 --> 00:33:59.002 et le terminus [terminator] des imports n'a pas besoin d'être composé de 5 doubles mots nuls 00:33:59.002 --> 00:34:03.000 mais juste d'un seul, pour son AddressOfName 00:34:03.000 --> 00:34:05.009 pour être considéré comme le terminus 00:34:05.009 --> 00:34:10.002 donc, si on fait pointer AddressOfIndex vers l'AddressOfName d'un descripteur d'imports 00:34:10.002 --> 00:34:15.002 s'il est mis à zéro, 00:34:15.002 --> 00:34:16.006 les imports seront tronqués 00:34:16.006 --> 00:34:20.005 et en fait, le comportement est différent sous XP ou 7 00:34:20.005 --> 00:34:25.008 donc, sous XP, il est écrasé après que les imports soient chargés, 00:34:25.008 --> 00:34:28.002 donc la table n'est pas tronquée 00:34:28.002 --> 00:34:32.003 alors que sous 7, il est écrasé avant les imports 00:34:32.003 --> 00:34:35.003 donc, pour le même PE, on a 2 comportements différents 00:34:35.003 --> 00:34:37.001 sous deux versions de Windows différentes, 00:34:37.001 --> 00:34:43.004 alors que le fichier marche sous les 2 versions. 00:34:43.004 --> 00:34:55.004 ah, attendez, on a encore le temps? 00:34:55.004 --> 00:34:56.005 15 minutes ? ok 00:34:56.005 --> 00:35:01.000 je vais commencer la démonstration 00:35:01.000 --> 00:35:23.008 pour vous montrer... 00:35:23.008 --> 00:35:26.000 le style de PE que je créé d'habitude 00:35:26.000 --> 00:35:29.001 avec le minimum d'éléments définis 00:35:29.001 --> 00:35:31.001 c'est en fait un pilotes [driver] 00:35:31.001 --> 00:35:36.008 même si j'ai utilisé des opcodes non documentés, 00:35:36.008 --> 00:35:40.008 ce pilote marche, sans le vrac 00:35:40.008 --> 00:35:43.002 habituel rajouté par le compilateurs 00:35:43.002 --> 00:35:47.009 donc, un exemple clair, simple 00:35:47.009 --> 00:35:51.004 sans rien pour vous géner la vue 00:35:51.004 --> 00:35:52.008 ou votre débogueur 00:35:52.008 --> 00:36:02.006 donc, cet exemple regarde les valeurs de CR0 00:36:02.006 --> 00:36:07.005 via SMSW, officiellement non défini sur un double mot 00:36:07.005 --> 00:36:10.000 mais en fait donne la même valeur 00:36:10.000 --> 00:36:11.007 que le MOV EAX, CR0 standard 00:36:11.007 --> 00:36:16.005 ensuite, MOV EAX, CR0 avec un 'mauvais' Mod/RM 00:36:16.005 --> 00:36:39.002 sous le dernier Hiew, ce n'est en fait même pas désassemblé 00:36:39.002 --> 00:36:43.007 on espère que ça ne plante pas... 00:36:43.007 --> 00:36:47.003 donc, vous voyez, on obtient les mêmes valeurs 00:36:47.003 --> 00:36:55.006 via le CR0 standard, l'invalide, et le non défini 00:36:55.006 --> 00:36:57.005 dont la partie de poids fort est non définie 00:36:57.005 --> 00:37:00.007 d'habitude, en langage Intel, non défini signifie 'mis à zéro', 00:37:00.007 --> 00:37:02.002 mais ici, on a bien CR0 entier 00:37:02.002 --> 00:37:03.006 et ma machine n'a même pas plantée 00:37:03.006 --> 00:37:05.009 ce qui signifie que le pilote fonctionne correctement 00:37:05.009 --> 00:37:08.004 donc vous pouvez étudier des petits pilotes 00:37:08.004 --> 00:37:12.004 le premier exemple présenté aujourd'hui 00:37:12.004 --> 00:37:15.007 était celui avec l'assembleur ancien 00:37:15.007 --> 00:37:20.002 quelqu'un connaît le résultat final ? 00:37:20.002 --> 00:37:23.007 certaines instructions sont inutiles, 00:37:23.007 --> 00:37:28.002 juste pour vérifier que le processeur les gère 00:37:28.002 --> 00:37:30.008 mais d'autres modifient les registres 00:37:30.008 --> 00:37:37.007 et ces instructions des années 70-80 00:37:37.007 --> 00:37:43.008 sont toujours gérées par les processeurs modernes 00:37:43.008 --> 00:37:47.007 un des exemples que j'ai crée teste 00:37:47.007 --> 00:37:50.004 les valeurs initiales de chaque registre 00:37:50.004 --> 00:37:56.001 donc on peut voir les valeurs possibles sous XP ou W7 00:37:56.001 --> 00:38:01.008 à chaque fois [TLS, EntryPoint, DllMain], je sauve tous les registres 00:38:01.008 --> 00:38:04.000 et je compare à diverses valeurs possibles 00:38:04.000 --> 00:38:06.002 successivement 00:38:06.002 --> 00:38:10.007 en fait, au TLS, on a beaucoup de contrôles de ces valeurs, 00:38:10.007 --> 00:38:16.007 car ces valeurs proviennent du Data Directory 00:38:16.007 --> 00:38:20.002 en particulier, son adresse relative, sa taille, les callbacks... 00:38:20.002 --> 00:38:26.007 pour plus de détail, voir le source... 00:38:26.007 --> 00:38:33.006 ça vous permet d'imiter mieux un SE dans votre émulateur, 00:38:33.006 --> 00:38:35.005 si ça vous intéresse 00:38:35.005 --> 00:38:41.006 on utilise SMSW, on compare la valeur 00:38:41.006 --> 00:38:46.004 ensuite, après une opération FPU, on regarde si la valeur a changé 00:38:46.004 --> 00:38:48.007 et si elle revient à sa valeur initiale. 00:38:48.007 --> 00:38:52.005 une autre bizarrerie, si quelqu'un a l'explication 00:38:52.005 --> 00:38:54.007 est qu'en fait 00:38:54.007 --> 00:39:01.001 ça se comporte différemment si on exécute le fichier normalement 00:39:01.001 --> 00:39:04.006 ou avec une redirection 00:39:04.006 --> 00:39:08.004 si on redirige, 'échec' 00:39:08.004 --> 00:39:11.005 sinon, ça marche normalement. 00:39:11.005 --> 00:39:22.002 pour vous montrer... on exécute, et on lance TYPE 00:39:22.002 --> 00:39:24.007 normal : OK 00:39:24.007 --> 00:39:26.005 redirection: ECHEC 00:39:26.005 --> 00:39:30.006 si vous avez une explication, je suis preneur 00:39:30.006 --> 00:39:37.008 tu as essayé de rediriger vers autre chose ? 00:39:37.008 --> 00:39:42.000 non, je n'ai pas essayé 00:39:42.000 --> 00:39:45.002 donc, rediriger vers un autre périphérique? 00:39:45.002 --> 00:39:46.007 mais, comment on récupère le résultat ? 00:39:46.007 --> 00:39:48.001 imprimante ? 00:39:48.001 --> 00:39:54.002 je n'ai pas de périphérique COM 00:39:54.002 --> 00:39:56.007 non, je ne sais pas 00:39:56.007 --> 00:39:59.009 mais c'était surprenant, car je lançais tous mes tests... 00:39:59.009 --> 00:40:02.003 et d'un coup, 'ECHEC'... 00:40:02.003 --> 00:40:07.002 alors qu'à la main, aucun problème. 00:40:07.002 --> 00:40:09.007 l'astuce avec GS 00:40:09.007 --> 00:40:11.002 très simple 00:40:11.002 --> 00:40:19.006 et quelques affichages 00:40:19.006 --> 00:40:21.008 je modifie GS, qui se remet à zéro 00:40:21.008 --> 00:40:23.006 puis j'attends le résultat, 00:40:23.006 --> 00:40:26.005 ensuite je fais 2 tests et je compare le temps entre 00:40:26.005 --> 00:40:30.000 car ça ne doit pas arriver trop vite 00:40:30.000 --> 00:40:37.002 NOPs 00:40:37.002 --> 00:40:39.005 je teste les NOPs non documentés 00:40:39.005 --> 00:40:45.006 celui sur une page invalide 00:40:45.006 --> 00:41:01.000 NOP standard 00:41:01.000 --> 00:41:07.005 32 bits 00:41:07.005 --> 00:41:15.007 tous mes tests 64b sont fait dans des programmes 32b, car on peut les exécuter sur un OS normal 00:41:15.007 --> 00:41:19.003 et ensuite je regarde GS pour voir si le mode 64b est disponible 00:41:19.003 --> 00:41:21.006 dans ce cas, on obtiendrait un résultat différent 00:41:21.006 --> 00:41:26.005 donc, en 64b, que je n'ai aps ici, on obtiendrait 00:41:26.005 --> 00:41:28.006 les tests en 64b 00:41:28.006 --> 00:41:31.000 et ces results. 00:41:31.000 --> 00:41:35.001 mais, pas si facile à déboguer 00:41:35.001 --> 00:41:39.004 mais ici, pas de piège, donc on peut revenir facilement en 32b 00:41:39.004 --> 00:41:45.000 on saute le code 64b et revient en 32b 00:41:45.000 --> 00:41:48.004 PUSH/RET 00:41:48.004 --> 00:41:52.002 on affiche le message et ensuite... 00:41:52.002 --> 00:41:58.000 Olly vous dit qu'on va sauter vers [4010]08 00:41:58.000 --> 00:42:03.007 mais en fait - ici, c'est correct 00:42:03.007 --> 00:42:05.009 et le TLS a alloué la page NULLE 00:42:05.009 --> 00:42:09.005 qui affiche 'ECHEC' 00:42:09.005 --> 00:42:15.003 donc, comme mentionné auparavant, pas de façon standard de désassembler ça correctement 00:42:15.003 --> 00:42:23.006 je ne peux pas exécuter les 64K sections 00:42:23.006 --> 00:42:27.007 et en fait, cet exemple exécute tout le code (l'espace virtuel complet des 65535 sections) 00:42:27.007 --> 00:42:29.002 elles sont grosses, 00:42:29.002 --> 00:42:33.002 et je modifie EAX pour que tous les 00 00 soient exécutés 00:42:33.002 --> 00:42:35.007 juste pour faire un printf à la fin 00:42:35.007 --> 00:42:39.000 ça prend plusieurs secondes sur un i7 00:42:39.000 --> 00:42:43.000 c'est assez amusant: on le lance, et même avec le cache, 00:42:43.000 --> 00:42:50.009 et que le SE n'est pas occupé, ça prend un temps visible, juste pour un tas de 00 00:42:50.009 --> 00:43:00.005 les sections virtuelles... celui que le dernier Hiew ne voit pas comme un PE 00:43:00.005 --> 00:43:02.003 enfin, bientôt corrigé 00:43:02.003 --> 00:43:08.006 ah, je ne peux pas l'analyser car il ne pense même pas que c'est un PE 00:43:08.006 --> 00:43:13.001 mais, pour simplifier, OPTIONAL_HEADER pointe au delà 00:43:13.001 --> 00:43:14.004 du fichier 00:43:14.004 --> 00:43:17.000 l'en-tête plié... 00:43:17.000 --> 00:43:18.006 quelques messages d'erreurs, 00:43:18.006 --> 00:43:21.000 à cause des faux Data Directories 00:43:21.000 --> 00:43:30.002 et les DD réels sont au début 00:43:30.002 --> 00:43:33.001 de la première section 00:43:33.001 --> 00:43:42.004 ceci deviendra les imports, et le vrai Data Directory 00:43:42.004 --> 00:43:49.002 et pour finir, celui avec TLS AddressOfIndex qui pointe... 00:43:49.002 --> 00:44:02.003 ...dans les descripteurs d'imports, sur AddressOfName 00:44:02.003 --> 00:44:04.003 donc, il sera écrasé au chargement 00:44:04.003 --> 00:44:11.009 et quand on le charge, il reconnait XP 00:44:11.009 --> 00:44:14.007 à la façon dont les imports ont été chargés 00:44:14.007 --> 00:44:17.001 et sous 7, on obtiendra un autre résultat. 00:44:17.001 --> 00:44:19.005 pour finir, les exports 00:44:19.005 --> 00:44:24.005 certains ont des noms très longs 00:44:24.005 --> 00:44:30.005 en fait, on remarque que j'écrase le désassemblage même 00:44:30.005 --> 00:44:33.009 donc je répète les faux opcodes et adresses 00:44:33.009 --> 00:44:37.005 donc le désassembleur est perturbé 00:44:37.005 --> 00:44:40.005 mais c'est juste visuel, pas vraiment grave 00:44:40.005 --> 00:44:43.001 bien que ce soit un problème récent dans IDA 00:44:43.001 --> 00:44:47.000 ou si on met un export au milieu d'une instruction 00:44:47.000 --> 00:44:49.007 l'export aura priorité sur le désassemblage, 00:44:49.007 --> 00:44:52.001 et casse l'instruction en deux 00:44:52.001 --> 00:44:58.005 il y a bien sûr un exemple pour ça sur Corkami 00:44:58.005 --> 00:45:05.001 donc, voilà pour les démonstrations 00:45:05.001 --> 00:45:10.001 Je voulais donc en savoir plus sur le x86 et le PE 00:45:10.001 --> 00:45:12.006 qui sont loin d'être correctement documentés 00:45:12.006 --> 00:45:14.007 et qui ne le sont toujours pas, 00:45:14.007 --> 00:45:18.004 mais j'en ai couvert un peu 00:45:18.004 --> 00:45:20.004 il y a encore des flous 00:45:20.004 --> 00:45:24.000 mais de moins en moins, j'y travaille 00:45:24.000 --> 00:45:27.005 en publiant mes recherches librement 00:45:27.005 --> 00:45:31.007 tel WinDbg, si vous suivez les documentations officielles à la lettre, 00:45:31.007 --> 00:45:36.001 vous êtes voués à l'échec, surtout avec tous les virus et packeurs existants 00:45:36.001 --> 00:45:40.006 si vous êtes intéressés, ou que vous programmez un outil, un émulateur, un moteur... 00:45:40.006 --> 00:45:44.005 vous savez que vous pouvez aller sur Corkami, lire les pages 00:45:44.005 --> 00:45:48.002 télécharger les exemples, qui sont disponibles librement, à tout point de vue 00:45:48.002 --> 00:45:50.007 et si vous trouvez des bugs, ce qui pourrait arriver 00:45:50.007 --> 00:45:57.000 envoyez-moi une carte postale, ou un t-shirt croix rouge ;) 00:45:57.000 --> 00:46:01.007 Merci à Peter Ferrie, et tous mes relecteurs et contributeurs 00:46:01.007 --> 00:46:03.006 vous avez des questions ? 00:46:03.006 --> 00:46:10.008 tu les as testés sur des anti-virus ? tu devrais trouver une ch*ée de 0days 00:46:10.008 --> 00:46:23.009 mouai, non, je ne saurais pas en faire des exploits... 00:46:23.009 --> 00:46:29.000 tenir en échec les désassembleurs me suffit 00:46:29.000 --> 00:46:40.002 j'ai trouvé un crash dans Xed d'Intel, ça me suffit 00:46:40.002 --> 00:46:45.000 une autre question ? tout le monde a survécu ? 00:46:45.000 --> 00:46:46.005 c'était une super présentation, mec 00:46:46.005 --> 00:46:48.002 merci! 00:46:48.002 --> 00:46:50.007 MERCI!