Méthodes de détection de protectors et de logiciels - Big
Transcription
Méthodes de détection de protectors et de logiciels - Big
Méthodes de détection de protectors et de logiciels malveillants Emeau Juillet 2007 Sous licence Creative Commons Table des matières 1 Introduction 1.1 Rappel sur les protectors . . . . . . . 1.2 But de la détection de protectors . . 1.3 Rappel sur les malwares . . . . . . . 1.4 Interêt de la détection des malwares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 2 3 3 2 Détection et identification de protectors 2.1 Les Signatures . . . . . . . . . . . . . . 2.1.1 Les Tags . . . . . . . . . . . . . . 2.1.2 Les séquences d’octets . . . . . . 2.2 Détection par analyse heuristique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5 6 malware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 7 8 9 9 4 Conclusions sur les méthodes utilisées 4.1 Malwares . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Resumé de méthodes non-abordées . . . . . . . . 4.2 Protectors . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Comparaison des deux méthodes expliquées . . . 4.2.2 Possibilité de contrer ces méthodes de détection . . . . . . . . . . . . . . . . . . . . . . . . . . 11 11 11 12 12 12 . . . . 3 Méthodes de détection et d’identification 3.1 Identification par Hash . . . . . . . . . . . 3.1.1 MD5 . . . . . . . . . . . . . . . . . 3.1.2 SHA . . . . . . . . . . . . . . . . . 3.1.3 Exemples concrets . . . . . . . . . 3.2 Détection par analyse heuristique . . . . . 3.3 Identification de fonctions . . . . . . . . . 5 Outroduction de . . . . . . . . . . . . 13 1 1 Introduction Ce document est séparé en deux parties, une explicant les différentes méthodes utilisées pour la détection de protectors et la seconde concernant celles utilisées pour l’identification ou la détection de malwares. Y seront abordés l’analyse par signature, l’analyse par heuristique puis la reconnaissance par hash pour enfin comparer ces méthodes et en tirer des conclusions. Je vous invite à prendre en compte la ressemblance des méthodes utilisés pour la détection de protector(logiciels permettant la protections d’executable et leurs compression) et celle de malwares (logiciels malveillants), les méthodes qui seront détaillés ici sont, en majorité, appliquables à la fois à la détection et identification de protectors et à la recherche et détection des malwares. 1.1 Rappel sur les protectors En résumé, un protector est un programme mit à disposition des dévellopeurs pour protéger un programme tierce, hélas ces protections sont rapidement cassées due à une trop forte simplicitée ou une mauvaise implémentation. Un protector de "base" inclu généralement un chiffrement de l’executable, redirection et/ou destruction de la Table des Imports ainsi que des Anti-Debug (Opérations servant à stopper, ou du moins ralentir, la rétro-ingéniérie de la protection). Les chiffrements étant plus ou moins compliqués ainsi que les antidebug plus ou moins fréquents et subptiles, la difficulté de l’analyse d’un packer est variable. Cependant avec de l’expèrience on peut remarquer une certaine similitude entre tout ces packers et l’analyse devient régulierement rébarbative. 1.2 But de la détection de protectors Une des premières questions si l’on est néophyte dans le domaine est le but d’une telle démarche. La détection de packer est une tache essentielle pour les Reverse-Engineers, la protection d’un programme "cible" est souvent l’interêt de l’étude. Or outre-passer régulierement la même protection à la main est une chose inutile et très souvent répété. C’est pourquoi la détection de la version du protector permet ensuite de chercher l’unpacker travaillant avec cette version (ou encore de fouiller son disque dur à la recherche de celui que l’analyste à lui-même codé). 2 1.3 Rappel sur les malwares Si vous connaissez un peu le domaine de la recherche de Malwares vous êtes au courant concernant les conditions d’études nécessaires et surtout l’environnement propice à ce type d’étude. Cependant un petit rappel concernant ceux-ci ne fait jamais de mal. Pour étudier des logiciels malveillants il est nécessaire de posséder une Machine Virtuel (VM), il en existe plusieurs comme VMWare , Quemu, VirtualPC etc... Le but d’une telle manoeuvre est de protéger votre ordinateur et vos données personnelles de toutes actions que pourrait entreprendre un malware. Il est nécessaire de posséder une VM pour l’étude d’un quelquonque logiciel malveillant. 1.4 Interêt de la détection des malwares Comme vous le savez, chaque "menace" a son propre fonctionnement et réalise certaines actions spécifique. Dans le cas de virus, la méthode d’infection et de propagation est unique à chaque virus ce qui rends l’anti-virus associé à un virus particulier inutilisable pour une variante ou encore un autre virus. C’est pourquoi la détection de malware est essentielle pour la sécurité de l’utilisateur alpha cependant l’éradication de cette menace ne se feras pas sans l’identification de celui-ci. 3 2 2.1 Détection et identification de protectors Les Signatures Ce que l’on appelle communement signatures sont en faite des suites d’octets permettant de détecter le logiciel utilisé pour protéger un logiciel tierce, cela permet, dans la majorité des cas, de chercher par la suite un unpacker (programme automatisant la suppression de la protection) spécifique à la protection et à sa version utilisée pour proteger le programme. Le protector insère une signature bien à lui dans le programme pour ne pas re-protéger un fichier, cela pouvant causer des erreurs. La signature inséré par un protector est souvent commune à plusieurs versions ce qui rends la précision concernant l’identification de la version du logiciel utilisé très faible voir nulle. C’est pourquoi il a fallu trouver un autre moyen pour identifier plus précisement une version d’un protector. En partant du principe que chaque nouvelle version entraine ses changements, une solution qui se présente d’elle même serait la recherche d’une suite d’instructions qu’execute le programme. Or les instructions étant stockés sous formes d’opcodes (OPeration Code, code numérique représentant les instructions à effectuer) et les opcodes étant en réalité un ou plusieurs octets l’un à la suite de l’autre, nous appellerons ce type de détection "identification par séquences d’octets". Il est à noter que la méthode la plus répandue pour l’identification de protector est la suite d’octets car cette méthode est plus fiable et plus précise. 2.1.1 Les Tags Revenons au concret, imaginons que nous analysions un programme packé par UPX, un petit scan de chaine de caractères grace à Snoopy nous montrerait quelquechose ressemblant à ceci : ======================================== Snoopy 1.1 - FRETool codé par BeatriX (dans la joie et la bonne humeur) ======================================== Recherche de chaines ANSI en cours... __________________________________________ name : offset ( VA ) | string __________________________________________ ... header : 000003e0 ( 004003e0 ) | UPX ! ... ===================== > EOF... "UPX !"... si vous regardez sur d’autres programme packés de la sorte vous pourrez vous appercevoir que la chaine de caractères "UPX !" est toujours présents, c’est le Tag du packer. Vous pouvez essayer avec plusieurs version d’UPX, vous 4 obtiendrez le même Tag. Le fait que plusieurs version du packer utilisent le même Tag est un désaventage énorme concernant l’identification de la version du protectorr utilisé, c’est pourquoi nous allons expliquer la méthode de détection par séquences d’octets. 2.1.2 Les séquences d’octets Ce type de détection utilise le principe de la séquence d’octets est la présences des mêmes opérations dans les programmes une fois packés par la même version d’UPX (reprenons notre exemple ;-) ). Une séquence d’octet est simplement une suite de nombres à chercher dans le fichier. En théorie sa recherche parait simple cependant l’appliquer est plus difficile. Regardons la signature d’UPX v1.2 de Marcus et Lazlo (tirée d’une base de signature) : Signature = 60 BE ? ? ? ? ? ? ? ? 8D BE ? ? ? ? ? ? ? ? 57 83 CD FF EB 05 A4 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 F2 31 C0 40 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 75 07 8B 1E 83 EE FC 11 DB 73 E6 31 C9 83 EntrypointOnly = True Première explication, pour le membre Signature, vous avez sûrement remarqué les ? ? ce sont des octets qui peuvent être différents de programmes en programmes. Ensuite vous aurez remarqué le membre EntrypointOnly, c’est un booléen(il est True ou False, Oui ou Non dans notre cas), il informe le programme détectant le packer si il doit chercher cette séquence d’octets à l’Entrypoint (si True) ou dans tout le programme (si False). Si vous packez un programme avec UPX 1.2 vous pourrez voir en désassemblant votre programme sous ollydbg quelquechose ressemblant à ceci : 004332D0 . 60 PUSHAD 004332D1 . BE 00E04100 MOV ESI,cible.0041E000 004332D6 . 8DBE 0030FEFF LEA EDI,DWORD PTR DS :[ESI+FFFE3000] 004332DC . 57 PUSH EDI 004332DD . 83CD FF OR EBP,FFFFFFFF 004332E0 . EB 10 JMP SHORT upx.004332F2 Je n’ai pas cité tout le code par manque de place, cependant si vous regardez ce bout de code vous devinerez aisément que le programme a été packé avec UPX 1.20 d’après la signature. De plus, je vous invite à regarder par vous même si vous avez quelques doutes. 5 2.2 Détection par analyse heuristique Imaginez que vous ayez un yahourt dans votre frigo, il est 4h du matin, vous mourrez de faim, hélàs la date de pérenption du yahourt a disparu. Vous allez devoir analyser basiquement l’aspect et la consistance de celui-ci pour savoir si vous pouvez le manger. Premièrement, est-ce que le yahourt est ouvert ? Ensuite l’aspect de la surface du yahourt est-il naturel ? Le yahourt dégage-t-il une odeur habituelle ? Si tout est bon jusque-là on peut toujours essayé d’en gouter une cuillérée, le gout du yahourt et sa consistance vous parait-elle normale ? Si pour l’instant rien n’est à signaler on peut supposer que l’on peut manger notre yahourt en toute tranquilité cependant nous ne pouvons pas en être sûr à cent pour cent. Vous avez compris l’analogie ? non, c’est normal. Le principe d’une analyse heuristique est de vérifier un tas d’hypothèse pour avoir une approximation concernant, ici, la présence d’une protection dans un programme. Si vous avez étudié plusieurs packers ou protectors, vous vous êtes certainement rendu compte de plusieurs similitudes, essayons de les énumérer sommairement : – Entrypoint en dehors de la première section ; – Présence de plusieurs sections exécutables ; – Position de l’Import Table non-communne ; – Préssence des APIs LoadLibrary et GetProcAddress dans l’IAT ; – Présence de TLS ; – Présence de beaucoup d’instructions inconnus(chiffrement ?) ; – et j’en passe... ; Ceci n’est qu’un bref descriptif des méthodes que l’on peut employer pour détecter la présence d’une protection. De plus si une seule des conditions est remplis la probabilité d’un possible chiffrement ou d’une compression est très faible, c’est pourquoi rien n’est mieux que d’étudier sois même le logiciel pour avoir un avis sûr. 6 3 Méthodes de détection et d’identification de malware Les méthodes de détections de packer sont utilisées dans la recherche de malware ainsi que dans leurs préventions. En effet pour protéger son programme, les programmeurs de virus utilisent parfois des protections logiciels publiques ou commerciales, reconnues par signatures. Cependant ils utilisent aussi des protections "maisons", fabriquées pour l’occasion et non-détectées par signature. En effet, nous parlerons ici de la façon dont les malwares en général sont identifiés, la méthode étant applicable aussi bien au virus qu’au trojan ou mail-bomber (au coup de légères modifications). Chaque versions de malware possède son propre nom et est identifié à l’aide d’un hash. Nous établirons dans cette partie la façon dont sont générées ces signatures. 3.1 Identification par Hash La méthode utilisée pour la détection de malware est simple. A sa découverte, un hash de l’executable est fait et des informations à propos de ce malware sont envoyées aux éditeurs d’anti-virus accompagné de son/ses hash, l’éditeur lui donne ensuite un nom ,associé au hash de l’executable, qui est ajouté à une base de données. L’identification par hash des anti-virus est majoritairement fiable 3.1.1 MD5 L’algorithme de hash MD5 fut proposé par Rivest en 1991, il est intéressant par la compression utilisée. En effet MD5 utilise des blocs de 512 bits pour créer une signature de 128 bits. Elle est unique cependant il existe aujourd’hui des algorithme permettant la recherche de collisions en seulement 230 opérations. Ce qui nous amène à admettre que MD5 est devenu un algorithme peu sûr. 3.1.2 SHA SHA est un algorithme de hash, tout comme MD5, c’est enfaite son successeurs. SHA est le "papa" de SHA-1 et le "grands-pere" de SHA-256 qui sont au final basés sur le même système.L’algorithme de hash utilisé pour l’identification de malware est SHA-1. Cependant, un algorithme pour la recherche de collisions par brute-force existe et ne nécessite que 263 opération, SHA-1 est donc cassé, bien qu’il reste largement utilisé. 7 3.1.3 Exemples concrets Voici quelques couples hash/nom de malwares pour illustrer ces propos : Win32.Email-Worm.Zhelatin.EL – hash MD5 : FEB9BC1A86DB4C3A0D48D7950BC39CFA – hash SHA-1 : 4713765D3A5C21EC1EA8D53545AFDBBE37E582EE Win32.Virus.Cheburgen.A – hash MD5 : 1D1C897BCCBf4178DEAF617B4C35B12A – hash SHA-1 : 4070094B8EF2F9C46E0F608E280E61F7838249E6 Win32.Packed.PolyCrypt.B – hash MD5 : ECC7C3C7B6B956B2455D5C40A0E94B51 – hash SHA-1 : 5E2653BB6D5265FE698C4607484471D06A2D07D7 Et voici deux variantes du même malware pour vous montrer l’efficacitée d’une telle méthode. Win32.Trojan.Pakes.AN – hash MD5 : 19055926DEB48A43A595463A8A8542E9 – hash SHA-1 : B6EB09D4DD42427213A08C8993E6FB00FF797317 Win32.Trojan.Pakes.AO – hash MD5 : EC577EB7636F7123ED756E25A8B804F3 – hash SHA-1 : 8BD8E5fDA40D34F5CC2B07826486EEDD67B2BFF 8 3.2 Détection par analyse heuristique L’analyse heuristique utilisée dans la détection de malwares utilise le même principe que celle pour la détection de protectors cependant les élements vérifiés sont différents. En effet, une fois un logiciel unpacké, les APIs utilisées par le programme sont visibles ainsi que son code, cela permet de comprendre le fonctionnement de ce programme ou encore d’en avoir un appercu par détection heuristique à la recherche de charactéristiques souvent présentes dans les malwares : – EntryPoint du programme en dehors de la première section – EntryPoint avant la première section – Dernière section "Executable" – Présence d’un deuxieme PE Header dans le fichier – Données non mises à jour dans le PE – Redirection du code à l’EntryPoint du programme – Présence d’une routine de type Delta (recherche de l’adresse de Kernel32.dll) – Utilisation de LoadLibrary et GetProcAddress – Présences d’adresses systèmes hardcodés – Utilisation du PEB pour récupérer des adresses systèmes – Utilisation de chaines de caractères de types "*.exe" – Présence de chaines de caractères comportant le nom d’APIs – Connection à un serveur et télechargement de fichiers – Prise d’informations et envoie de celles-ci à un server – Capture des lettres tapées par l’utilisateur – Connexion à un server IRC – Création/Modification/Suppresion de fichiers – Etc... Merci à Nicolas Brulez pour une partie de ces informations Comme dit précédemment, la détection heuristique, ici de malware n’est pas complétement sûre, c’est pourquoi si un fichier parait suspect, il est bon de vérifier à la main avant de le cataloguer comme malware. En effet, des erreurs surviennent, ce sont des faux-positifs. Un fichier étant suspect pour le moteur heuristiques n’est enfaite qu’un logiciel possédant des tricks anti-debug ou une protections logiciel. Il est importants de savoir vérifier sois-même si un fichier suspect est un malware à l’aide du reverse-engineering car un programme n’est pas infaillible et certaines tâches ne sont que très difficilement automatisables, même pour de très bon programmeurs. 9 3.3 Identification de fonctions Vous aurez peut-être remarqué la présence de cette ligne "Présence d’une routine de type Delta (recherche de l’adresse de Kernel32.dll)" dans la précédente liste mais, "Comment reconnaitre une fonction précise ?". La réponse est finalement assez simple, imaginons une guitare classique, on la vois formée d’un long manche et d’une grosse cavitée. Si, en prenant le train, vous appercevez une housse noir large en bas et possédant un long manche, si l’on vous pose a question de savoir ce qu’il y a dedans, vous proposerez surement que la housse contient une guitare. Pourquoi avez-vous pensé à ça ? Tout simplement car votre cerveau à enregistrer la forme de la guitare et que dès qu’il appercois cette forme, le mot guitare vous vient à l’esprit. Le même principe est utilisé, plus ou moins, pour l’identification de fonctions. On peut décomposer cette pratique en deux méthodes : La première concernant l’identification d’une fonction par son hash, la deuxième par certains aspect de la fonction (nombre d’arguments, opérations effectués, type de valeure retournée, etc...), c’est à dire sa structure. Ces méthodes ne sont que très peu fiable, cependant leurs résultats sont parfois très pratique. 10 4 4.1 Conclusions sur les méthodes utilisées Malwares Comme vous avez pu le constater, la détection automatique de malware est évolué mais pas infaillible alors qu’au contraire l’identification de ceux-ci parait sans failles. D’un côté nous avons l’analyse heuristique, la prévention par analyse du code du malware qui, en vérifiant plusieurs hypothèse nous emets un avis sur le caractère potentiellement dangereux d’un executable. Et de l’autre nous avons une comparaison de signatures d’executables pour affirmer ou réfuter l’identité probable du malware choisi. Il faut toute fois prendre en compte le fait que le but de ces deux méthodes n’étant pas les même, la comparaison de celles-ci est difficile et non-rigoureuse. De plus, l’identification de malwares connus étant plus facile que la détection de nouveux malware, le fait que l’un d’entre eux soit plus fiable que l’autre parait tout à fait logique. Finalement, on peut facilement concevoir l’importance de Malware-Researchers pour détecter, identifier et supprimer des logiciels malveillants. 4.1.1 Resumé de méthodes non-abordées En effet il existe d’autres méthodes tel que l’émulation de code, ou encore l’analyse comportementale qui sont à regrouper avec l’analyse heuristique, non-sûr mais prévenant de nouveaux virus encore inconnus à l’heure actuelle. L’analyse comportemantale consiste à constater les actions qu’un programme effectue pour, s’il est nécessaire, en déduire qu’il a un comportement douteux et qu’il vaut mieux prévenir l’utilisateur d’un potentiel risque encourue par l’utilisation de ce fichier. On peut, par exemple, surveiller les actions, potentiellement dangereuses, suivantes : – Accès en lecture et/ou écriture à un fichier executable – Ecriture dans un secteur disque réservé – Intrusion dans la mémoire d’un processus tierce – Suppresion et/ou modification de fichiers sensibles Un des problème résultants de cette méthode est le fait que les actions potentiellement dangereuses sont executées avant qu’un quelquonque avertissement n’ai pu être transmis à l’utilisateur. L’émulation de code ressemble foncierement à l’analyse comportementale à l’inverse que celle-ci émule les actions réalisées par un fichier dans un environnement clos pour en déduire si l’executable émulé est potentiellement dangereux, ou non, avant un quelquonque impacte sur le système hôte. Cependant une telle analyse consomme énormément de ressources et ralentit les actions entrepris par l’utilisateur, c’est pourquoi cette option est trop souvent désactivée, à tords. 11 4.2 Protectors Bien que l’identification ou même leur détection semble moins importante que celle des malwares, il faut savoir que tout malware seras plus long à être analysé s’il est protégé correctement.et donc l’irradication de ce malware seras plus tardive. C’est pourquoi l’identification précise du protector utilisé est un gain de temps non-négligeable en ce qui concerne l’étude d’un malware ou d’un logiciel quelconque. 4.2.1 Comparaison des deux méthodes expliquées La détection et l’identification de protectors reprennent le même schémas que celles des malwares, c’est pourquoi on peut affirmer que la détection de protector automatisée est moins sûr que leurs identifications. Cependant, le plus intéressant serait de se pencher sur des moyens de retarder ou d’empêcher cette identification, qui parait l’élément le plus regrettable pour un protector, afin d’en déduire de possibles évolutions concernant les techniques utilisées actuellement. 4.2.2 Possibilité de contrer ces méthodes de détection Les méthodes utilisés pour l’identification d’un protector sont basés sur le même principe : reconaissance d’une suite d’octets propre à la version du protector utilisé. Ces Octets correspondants à des instructions, la première idée venant en tête est le remplacement de ces instructions par d’autres ayant le même effet, on peut par exemple trouver équivalence entre : MOV EAX, 0 == XOR EAX, EAX == SUB EAX, EAX ou encore MOV EBX, 0 MOV EAX, EBX etc... Ce qui a pour but de modifier les octets du programme et donc de rendre la signature erronée. Or our empêcher réellement l’identification de son protector, il faudrait changer chaques opcodes pour toutes les versions distribuées : Tâche rébarbatives, perte de temps, crampes aux doigts et cerveau qui fume. C’est là qu’entre en scène le polymorphisme, ou le fait de modifier son code automatiquement selon certaines règles (règles du même nom) grâce à un moteur polymorphique. Pour plus d’informations vous pouvez consulter les tutoriaux de Dark-Avenger sur ces type de moteurs. Cependant, le polymorphisme est devenu, bien qu’encore aujourd’hui très utilisé et redoutable, obsolète. En effet il existe un nouveau moyen de modifier son propre code de manière plus poussées, le metamorphisme. Je vous invite à consulter votre moteur de recherche préféré pour avoir plus de renseignement. Il est toute fois à noter qu’il n’existe qu’un seul moteur metamorphique public à ce jour, celui de 29A, réalisé en mars 2002. 12 5 Outroduction Comme vous avez pu le constater, la détection de protector se fait majoritairement à l’aide d’une comparaison d’octets, cela permet de la même manière de l’identifier. Il existe des programmes tels que StudPE ou encore PE !D basés sur des bases de signatures. La détection de malware est quant à elle beaucoup plus ancrée dans la pratique humaine, ou du moins l’automatisation d’une partie du reverse-engineering de ce type de logiciel. Leurs identifcations, au contraire, se base sur un hash du fichier. Toutefois pour chaque nouvelle variante d’un virus, sa détection se fait dans les plus bref délais par les logiciels anti-virus commerciaux. Il faut aussi savoir que la détection et la création de malware deviens de plus en plus évolué, chaque partie de cette chasse à la souris perpetuelle innovent, de nouveaux type de malwares apparaissent et de nouveaux moyen de les éradiquer les suivent, ou les précèdent. 13