Dans ce second épisode nous allons nous pencher sur le rôle de la fonction antifuck
du malware. Cette fonction est l’avant-dernière fonction appelée dans le WinMain
, juste avant la fonction dont l’adresse était obfusquée.
D’entrée de jeux, la fonction répète un schéma qui nous est maintenant classique : deux GetTickCount
, séparés par un Sleep()
de 6 secondes (6001ms pour être exact).
Le délai entre ces deux instructions est calculé par soustraction entre les deux prises de temps et est comparé à différentes possibilités (inférieur à 5s ? supérieur à 18s ? inférieur à 1s ?)
En fonction des résultats de ces tests, une valeur différente est définie pour une variable locale : 17, 5, 47 ou 1. La valeur obtenue normalement étant 5.
Passé ce test, on entre dans une fonction ne prenant aucun argument. Cette fonction commence par effectuer différentes modifications sur une zone mémoire de 9 octets située dans la section .data
.
Cette modification n’a rien de régulier : aucune boucle n’est présente, tout se fait au cas par cas.
Ainsi on part de la suite d’octets suivante : 0E 02 0D 00 03 00 00 C2 00
À laquelle on applique différentes modifications (dans l’ordre) :
- ajouter 1 au premier octet
- retirer 1 au second octet
- mettre à zéro le 5ème octet
- ajouter 1 au 8ème octet
- écraser les octets du 4ème au 7ème inclus par la valeur
0x0042004C
(qui correspond à une adresse mémoire située dans.data
)
On obtient finalement 9 nouveaux octets :
1
0F 01 0D 4C 00 42 00 C3 00
On entre ensuite dans une fonction particulière que voici :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
40129b ! push ebp
40129c ! mov ebp, esp
40129e ! push ecx
40129f ! push ebx
4012a0 ! push esi
4012a1 ! push edi
4012a2 ! push ecx
4012a3 ! pop ecx
4012a4 ! nop
4012a5 ! nop
4012a6 ! call sub_401284
4012ab ! mov [ebp-4], eax
4012ae ! push ecx
4012af ! push ebx
4012b0 ! push edx
4012b1 ! mov edx, ecx
4012b3 ! nop
4012b4 ! nop
4012b5 ! inc ecx
4012b6 ! pop edx
4012b7 ! pop ebx
4012b8 ! pop ecx
4012b9 ! nop
4012ba ! mov eax, [ebp-4]
4012bd ! pop edi
4012be ! pop esi
4012bf ! pop ebx
4012c0 ! mov esp, ebp
4012c2 ! pop ebp
4012c3 ! ret
Ce qui la rend si particulière, c’est la présence d’instructions inutiles (nop et modifications de registres qui sont restaurés juste après).
On note à l’adresse 4012a6
l’appel à la fonction suivante :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
401284 ! push ebp
401285 ! mov ebp, esp
401287 ! push ecx
401288 ! push ebx
401289 ! push esi
40128a ! push edi
40128b ! mov eax, [ebp+4]
40128e ! mov [ebp-4], eax
401291 ! mov eax, [ebp-4]
401294 ! pop edi
401295 ! pop esi
401296 ! pop ebx
401297 ! mov esp, ebp
401299 ! pop ebp
40129a ! ret
Cette fonction retourne comme valeur le contenu du [ebp+4]
. Or les habitués du langage assembleur savent que les arguments placés sur la pile ne commence qu’à [ebp+8]
. À quoi correspond [ebp+4]
? Tout simplement à l’adresse de retour (l’adresse où sauter en sortant de la fonction) qui est 4012ab
.
Une fois que l’on a “remonté” ces deux fonctions et que l’on se retrouve à nouveau dans la fonction antifuck
, cette adresse est sauvegardée dans une variable globale.
Finalement le malware appelle la fonction VirtualProtect
avec les arguments suivants :
- l’adresse
0x004012ab
récupérée précédemment. - la valeur 9
- la valeur
0x40
- l’adresse d’une variable locale.
Ce qui peut se traduire en “modifier les paramètres d’accès des 9 octets se trouvant à l’adresse 0x004012ab
pour qu’ils soient readable, writable et executable (flag 0x40
)”.
On saute ensuite à l’adresse 0x00402d40
que je ne prendrais pas la peine de détailler mais qui est pourrie de junk-code et de sauts sur des adresses relatives (du genre jmp dword ptr [edx*4+mem]
) destinés à abuser le désassembleur.
Cette fonction volontairement obscurcie se charge de recopier les neuf octets modifiés tout à l’heure à l’adresse 0x004012ab
qui a été déprotégée par VirtualProtect
.
En fin de compte, la suite de push et de nop que l’on a croisé plus haut prend tout son sens : ils servaient à “garder” de la place pour placer des instructions cachées.
Et à quoi correspond la suite d’octets 0F 01 0D 4C 00 42 00 C3 00
en assembleur ? Voici la réponse :
1
2
sidt fword ptr ds:[0042004C]
retn
Alors que ces instructions ont été placées en mémoire, on saute dessus puis on retourne aux instructions suivantes avant de revenir à antifuck
:
1
2
3
4
5
6
7
40136b ! xor ecx, ecx
40136d ! mov cl, [data_420051]
401373 ! xor eax, eax
401375 ! cmp ecx, 0d0h
40137b ! setg al
...
401384 ! ret
À quoi tout ça rime ? Et bien le malware récupère l’adresse de la table de description des interruptions (IDT) par le biais de l’instruction sidt
. Il stocke le résultat obtenu (un fword
, soit 6 octets, à l’adresse mémoire 0x0042004C
)
Les 6 octets retournés par sidt
correspondant à la taille de la table de description des interruptions (sur deux octets) et son adresse (sur 4 octets).
Le dernier octet correspondant à l’octet de poids fort de l’adresse de l’IDT est placé dans ecx
et est ensuite comparé à la valeur hexadécimale 0xD0
. Si c’est supérieur on retourne 1, sinon on retourne 0.
Afin de mettre les choses au point, j’ai écrit le programme suivant (à compiler avec FASM) qui affiche l’adresse de l’IDT :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
format PE console
entry start
include 'macro\import32.inc'
section '.text' code readable executable
start:
sidt fword [val]
lea eax, [val+2]
mov eax, [eax]
push eax
push fmt_str
call [printf]
add esp, 8
push 0
call [ExitProcess]
section '.data' data readable writeable
val df ?
fmt_str db "%p", 10, 0
section '.idata' import data readable writeable
library kernel, 'KERNEL32.DLL',\
msvcrt, 'MSVCRT.DLL'
import kernel,\
ExitProcess,'ExitProcess'
import msvcrt, \
printf, 'printf'
Quand je l’exécute directement depuis mon Win7 j’obtiens par exemple 807CC020
ou 80B95400
. En revanche depuis le Windows XP virtualisé dans VirtualBox, l’adresse obtenue est F8C06BD0
.
Si on recherche sur Google, on trouve quelques références sur des forums chinois à cette comparaison destinée à détecter la présence d’un environnement virtualisé (VMWare, VirtualBox…)
Si le malware détecte l’entourloupe, il quitte rapidement le programme. Sinon il tente d’allouer avec VirtualAlloc
une quarantaine de Mo (48 000 320 octets pour être précis). S’il échoue, le programme quitte sinon il libère cette mémoire, ajoute 1 à la variable locale vue au tout début de l’article (qui passe donc à 6) et le programme suit son cours (on quitte proprement antifuck
avec la valeur de retour 6 pour retourner au WinMain
).
Je n’ai pas encore déterminé à quoi correspondait ce test mémoire… peut-être le programme va-t-il faire une utilisation importante de la mémoire à venir et préfère vérifier tout de suite les capacités du système sur lequel il se trouve…
Pour conclure cette fonction antifuck
a pour unique but de détecter la présence d’une machine virtuelle mais le créateur du malware a pris soin de dissimuler cet objectif par différents moyens (réécriture de code, junk-code etc).
Dans le prochain article, nous verrons comment le malware déchiffre des chaines de caractères et importe des fonctions qui ne sont pas présentes dans la table des imports.
Published January 11 2011 at 15:45