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