I. Introduction
Processus creux ( Processus Hollowing ) est une technique utilisée par certains logiciels malveillants dans lequel un processus légitime est chargé sur le système uniquement pour servir comme un conteneur ou hôte pour le code hostile. Lors de son lancement, le code légitime du processus est purger de la mémoire et remplacée par un code malveillant. L'avantage est que l'on garde la peau du processus légitime. Si vous inspectez le processus et ses importations en utilisant des outils classiques, ils se ressemblent en tous point au processus légitime. Le PEB est intacte, mais le code actuel et les données du processus ont été changés.
Pour détecter efficacement les
logiciels malveillants qui utilise processus évidement, nous devons d'abord
comprendre comment cette technique fonctionne.
Nous allons prendre comme
exemple un malware utilisant cette technique parmi quelqu'un utilisant cette
technique "Kronos" ,
"EvilBunny" , "Cryak" , ... etc
Vous trouverez également la
cette technique sous le nom "RunPE", mais on peut distingué une
nuance le concepte de Processus Hollowing signe le fait de vider le processus
pour exécuter du code qui peut être un Schellcode ou autre. On gardera la
technique "RunPE" pour le code compléter d'un autre programme ce
logeant dans le processus creusé
Exemple un processus ayant été
creusé pour positionner un shellcode sera un processus Hollowing. Mais
n'utilise pas la technique de RunPE. Par contre un processus qui exécutera un
programme complété sera un processus Hollowing et utilisant la technique
"RunPE"
II. Description schématique du principe technique
Le malware crée d'abord un nouveau
un processus légitime (tel que explorer.exe, regsvr32.exe, svchost.exe,
calc.exe etc.) en mode suspendu pour cela il utilise souvent l'API
CreateProcess et en définissant l'indicateur de création du processus avec le
flag CREATE_SUSPENDED (0x00000004). Le thread
principal du nouveau processus est de ce fait créé en tant qu'état supendu
jusqu'à ce que la fonction ResumeThread(..) soit appelée lancent le démarrage
de l'exécution.
Mais avant cela, le malware
remplacer le contenu du fichier légitime en mémoire par celle de la charge malveillante qui peut être un simple
Shellcode ou un programme complét. Cela peut
être fait en appelant ZwUnmapViewOfSection ou NtUnmapViewOfSection pour
décharger la mémoire du processus cible ligitime.Les deux API libèrent la
mémoire d'une section donnée. Lorsque la mémoire est décharger (démapper), le
chargeur du malware peut soit remplacer directement le code à l'emplacement
initial ou allouer de la mémoire dans le processus légitime.
Ensuite le malware va utiliser une
API comme WriteProcessMemory pour écrire la partie correspondant de à la charge
utile dans l'espace du processus cible. Enfin le malware va ajuster le contexte du thread supendu via l'appeler d'une Api comme
SetThreadContext(..) pour que le pointer l'entrée vers le nouveau code soit
celui du processus supendu si cela est nécessaire fonction du mode d'insertion
choisi dans le cas RunPE cela est toujours nécessaire pas obligatoirement dans
le cas d'un shellcode. Maintenant tous est prêt le malware n'a plus qu'a
réveiller ou démarrer le thread principal via l'appel de ResumeThread(..).
Nous avons schématisé les
différentes étapes via une présentation symbolique
L'étape1, consiste à créé un
processus suppendu au travers du malware comme "calc.exe"
Lorsque le processus est crée
supendu, le loader de Windows à charger lancement du processus en mémoire et
initialisé le PEB et TEB du processus.
le Thread supendu via son contexte,
nous pouvons obtenir deux éléments
important,
le point d'entrée du thread qui ce
trouve dans RCX. et le pointeur vers le PEBX64
(Process Environment Block X64) se trouvant dans RDX.
Ce que nous pouvons voir dans le capture
suivante sur cas pratique.
Cela nous montre bien que le registre RDX contient
l'adresse du PEBX64
Etape 2 ,défini la manière dont on va insérer le
code malveillant
Elle peut être un démappage de la section contenant
le code dans le processus cible ou un écrasement des instructions directement .
Pour la dés allocation du bloc ont peut utiliser
NtMapViewOfSession ou ZwUnmapViewOfSection pour démapper l'image du processus
légitime.
A contrario,l'écrasement nécessite de changer les flags de mémoire de la section
ou ce trouve le code. Car il ne dispose pas du flag ("Writing" ) et
dispose en générale que de "Reading" et "Execute".
Un autre choix peut être l'allocation d'un bloc mémoire pour garder le code initial et cela ce fait via une api comme VirtualAllocEx
pour disposer d'un bloc avec les bons flag "Reading , "Writing" et "Execute".
Dans notre schéma nous avons effectué la libération du bloc avant allocation pour bien visualiser que le processus légitime est Creux ou Hollowing .
Si non on ce rapproche trop du concept de thead hijacking indirectement et aussi parce qu'il est plus simple d'avoir son bloc propre avec les
caractéristiques de la mémoire souhaité.
Etape 4, elle est simplement l'écriture dans le processus légitime de notre code malveillant
Dans le cas d'un shellcode, il y a pas grand chose à dire c'est simplement l'écriture du shellcode dans la mémoire.
Par contre dans le cas d'un programme complet, il y tous une partie de
raccordement à faire entre la structure d'import et les adresse à faire
correspondre dans le cas d'un RunPE.L'étape 5 consiste à faire correspondre le point de démarrage du processus légitime avec le début du shellcode ou du point d'entrer du PE dans le cas d'un programme complet.
L'étape 6 est uniquement le réveille du thread ou le démarrage de celui-ci, a ce moment le code malveillant est exécuté dans le processus cible.
Cela vous permet de visualiser
les différentes étapes pour la génération d'un processus creux.
III. Mise en pratique avec un shellcode X64
Dont voici le shellcode
correspondant dans un tableau de char en C
unsigned char ShellcodeX64_MessageBox_sc[] =
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00"
"\x48\x83\xEC\x28"
"\x48\x83\xE4\xF0"
"\xE8\xE9\x01\x00\x00"
"\xBA\x8E\x4E\x0E\xEC"
"\x48\x89\xC1"
"\xE8\x68\x00\x00\x00"
"\xEB\x27"
"\x59"
"\xFF\xD0"
"\xBA\xA8\xA2\x4D\xBC"
"\x48\x89\xC1"
"\xE8\x56\x00\x00\x00"
"\x48\x89\xC3"
"\x4D\x31\xC9"
"\xEB\x1F"
"\x41\x58"
"\xEB\x3A"
"\x5A"
"\x48\x31\xC9"
"\xFF\xD3"
"\x48\x83\xC4\x28"
"\xC3"
"\xE8\xD4\xFF\xFF\xFF"
"\x75\x73\x65\x72\x33\x32\x2E\x64\x6C\x6C\x00"
"\xE8\xDC\xFF\xFF\xFF"
"\x3E\x58\x36\x34\x20\x53\x61\x6D\x70\x6C\x65\x3A\x20\x4D\x65\x73"
"\x73\x61\x67\x65\x42\x6F\x78\x41\x3C\x00"
"\xE8\xC1\xFF\xFF\xFF"
"\x3C\x39\x42\x31\x31\x33\x44\x31\x41\x3E\x00"
"\x89\x54\x24\x10\x48\x89\x4C\x24\x08\x48\x83\xEC\x68\x48\xC7\x44"
"\x24\x18\x00\x00\x00\x00\x48\x8B\x44\x24\x70\x48\x89\x44\x24\x08"
"\x48\x8B\x44\x24\x08\x48\x63\x48\x3C\x48\x8B\x44\x24\x08\x48\x03"
"\xC1\x48\x89\x04\x24\x48\x8B\x04\x24\x48\x05\x88\x00\x00\x00\x48"
"\x89\x44\x24\x10\x48\x8B\x44\x24\x10\x83\x38\x00\x0F\x84\x18\x01"
"\x00\x00\x48\x8B\x44\x24\x10\x8B\x08\x48\x8B\x44\x24\x08\x48\x03"
"\xC1\x48\x89\x44\x24\x20\x48\x8B\x44\x24\x20\x8B\x48\x20\x48\x8B"
"\x44\x24\x08\x48\x03\xC1\x48\x89\x44\x24\x30\x48\x8B\x44\x24\x20"
"\x8B\x48\x24\x48\x8B\x44\x24\x08\x48\x03\xC1\x48\x89\x44\x24\x28"
"\x48\x8B\x44\x24\x20\x8B\x48\x1C\x48\x8B\x44\x24\x08\x48\x03\xC1"
"\x48\x89\x44\x24\x38\xC7\x44\x24\x40\x00\x00\x00\x00\xEB\x0B\x8B"
"\x44\x24\x40\x83\xC0\x01\x89\x44\x24\x40\x48\x8B\x44\x24\x20\x8B"
"\x40\x18\x39\x44\x24\x40\x0F\x83\x9E\x00\x00\x00\x8B\x4C\x24\x40"
"\x48\x8B\x44\x24\x30\x8B\x0C\x88\x48\x8B\x44\x24\x08\x48\x03\xC1"
"\x48\x89\x44\x24\x48\xC7\x44\x24\x50\x00\x00\x00\x00\x48\x8B\x44"
"\x24\x48\x0F\xBE\x00\x85\xC0\x74\x3E\x48\x8B\x44\x24\x48\x0F\xBE"
"\x00\x89\x44\x24\x54\x48\x8B\x44\x24\x48\x48\x83\xC0\x01\x48\x89"
"\x44\x24\x48\x8B\x44\x24\x50\xC1\xE8\x0D\x8B\x4C\x24\x50\xC1\xE1"
"\x13\x0B\xC1\x89\x44\x24\x50\x8B\x4C\x24\x54\x8B\x44\x24\x50\x03"
"\xC1\x89\x44\x24\x50\xEB\xB6\x8B\x44\x24\x78\x39\x44\x24\x50\x75"
"\x24\x8B\x4C\x24\x40\x48\x8B\x44\x24\x28\x0F\xB7\x0C\x48\x48\x8B"
"\x44\x24\x38\x8B\x0C\x88\x48\x8B\x44\x24\x08\x48\x03\xC1\x48\x89"
"\x44\x24\x18\xEB\x05\xE9\x45\xFF\xFF\xFF\x48\x8B\x44\x24\x18\x48"
"\x83\xC4\x68\xC3"
"\x56\x57\x53\x48\x33\xDB\x6A\x30\x58\x65\x48\x8B\x30\x48\x8B\x46"
"\x60\x48\x8B\x40\x18\x48\x8B\x70\x10\x48\x8B\x7E\x60\x48\x8B\x46"
"\x30\x48\x8B\x36\x38\x5F\x18\x75\xF0\x5B\x5F\x5E\xC3";
|
Nous vous mettons
également le code assembleur correspondant pour mieux appréhendé les actions
qu'il réalise en dessous:
00000000:
48 B8 00 00 00 00 00 00 00 00 MOV RAX,0x0000000000000000 ""
0000000A:
FF D0 CALL
RAX
0000000C: 48 83 EC 28 SUB RSP,0x28
00000010:
48 83 E4 F0 AND
RSP,FFFFFFFFFFFFFFF0h
00000014:
E8 E9 01 00 00 CALL
000001E9h (+1E9h ->:00000202)
00000019:
BA 8E 4E 0E EC MOV
EDX, EC0E4E8Eh "ŽN
ì" (EC0E4E8E=Hash[ROR13(Additive)]('LoadLibraryA'))
0000001E:
48 89 C1 MOV
RCX,RAX
00000021:
E8 68 00 00 00 CALL
00000068h (+68h ->:0000008E)
00000026:
EB 27 JMP(rel8)
27h (+27h ->:0000004F)
00000028:
59 POP
RCX
00000029:
FF D0 CALL
RAX
0000002B:
BA A8 A2 4D BC MOV
EDX, BC4DA2A8h "¨¢M¼"
(BC4DA2A8=Hash[ROR13(Additive)]('MessageBoxA'))
00000030:
48 89 C1 MOV
RCX,RAX
00000033:
E8 56 00 00 00 CALL
00000056h (+56h ->:0000008E)
00000038:
48 89 C3 MOV
RBX,RAX
0000003B:
4D 31 C9 XOR
R9,R9
0000003E:
EB 1F JMP(rel8)
1Fh (+1Fh ->:0000005F)
00000040:
41 58 POP
R8
00000042:
EB 3A JMP(rel8)
3Ah (+3Ah ->:0000007E)
00000044:
5A POP
RDX
00000045:
48 31 C9 XOR
RCX,RCX
00000048:
FF D3 CALL
RBX
0000004A:
48 83 C4 28 ADD
RSP,0x28
0000004E:
C3 RET
0000004F:
E8 D4 FF FF FF CALL
FFFFFFD4h (-2Ch ->:00000028)
db
"user32.dll"
00000054:
75 73 65 72 33 32 2E 64 6C 6C
0000005E:
00
0000005F:
E8 DC FF FF FF CALL
FFFFFFDCh (-24h ->:00000040)
db
">X64 Sample: MessageBoxA<"
00000064:
3E 58 36 34 20 53 61 6D 70 6C 65 3A 20 4D 65 73 73 61 67 65 42 6F 78
41 3C
0000007D:
00
0000007E:
E8 C1 FF FF FF CALL
FFFFFFC1h (-3Fh ->:00000044)
db
"<9B113D1A>"
00000083:
3C 39 42 31 31 33 44 31 41 3E
0000008D:
00
0000008E:
89 54 24 10 MOV
DWORD PTR [RSP+10h],EDX
00000092:
48 89 4C 24 08 MOV
QWORD PTR [RSP+08h],RCX
00000097: 48 83 EC 68 SUB RSP,0x68
0000009B:
48 C7 44 24 18 00 00 00 00 MOV QWORD PTR[RSP+0x18],0x00000000
000000A4:
48 8B 44 24 70 MOV
RAX,QWORD PTR[RSP+70h]
000000A9:
48 89 44 24 08 MOV
QWORD PTR [RSP+08h],RAX
000000AE:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
000000B3:
48 63 48 3C MOVSXD
RCX,DWORD PTR[RAX+0x3C]
000000B7:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
000000BC:
48 03 C1 ADD
RAX,RCX
000000BF:
48 89 04 24 MOV
QWORD PTR[RSP],RAX
000000C3:
48 8B 04 24 MOV
RAX,QWORD PTR[RSP]
000000C7:
48 05 88 00 00 00 ADD
RAX,00000088h
000000CD:
48 89 44 24 10 MOV
QWORD PTR [RSP+10h],RAX
000000D2:
48 8B 44 24 10 MOV
RAX,QWORD PTR[RSP+10h]
000000D7:
83 38 00 CMP
DWORD PTR[RAX],00h
000000DA: 0F 84 18 01 00 00 JE 00000118h (+118h ->:000001F8)
000000E0:
48 8B 44 24 10 MOV
RAX,QWORD PTR[RSP+10h]
000000E5:
8B 08 MOV ECX,DWORD PTR[RAX]
000000E7:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
000000EC:
48 03 C1 ADD
RAX,RCX
000000EF:
48 89 44 24 20 MOV
QWORD PTR [RSP+20h],RAX
000000F4:
48 8B 44 24 20 MOV
RAX,QWORD PTR[RSP+20h]
000000F9:
8B 48 20 MOV
ECX,DWORD PTR[RAX+20h]
000000FC:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
00000101:
48 03 C1 ADD
RAX,RCX
00000104:
48 89 44 24 30 MOV
QWORD PTR [RSP+30h],RAX
00000109:
48 8B 44 24 20 MOV
RAX,QWORD PTR[RSP+20h]
0000010E:
8B 48 24 MOV ECX,DWORD PTR[RAX+24h]
00000111:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
00000116:
48 03 C1 ADD
RAX,RCX
00000119:
48 89 44 24 28 MOV
QWORD PTR [RSP+28h],RAX
0000011E:
48 8B 44 24 20 MOV
RAX,QWORD PTR[RSP+20h]
00000123:
8B 48 1C MOV
ECX,DWORD PTR[RAX+1Ch]
00000126:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
0000012B:
48 03 C1 ADD
RAX,RCX
0000012E:
48 89 44 24 38 MOV
QWORD PTR [RSP+38h],RAX
00000133:
C7 44 24 40 00 00 00 00 MOV
DWORD PTR [RSP+40h], 00000000h ""
0000013B:
EB 0B JMP(rel8)
0Bh (+0Bh ->:00000148)
0000013D:
8B 44 24 40 MOV
EAX,DWORD PTR [RSP+40h]
00000141:
83 C0 01 ADD
EAX,01h
00000144:
89 44 24 40 MOV
DWORD PTR [ESP+40h],EAX
00000148:
48 8B 44 24 20 MOV
RAX,QWORD PTR[RSP+20h]
0000014D: 8B 40 18 MOV
EAX,DWORD PTR[RAX+18h]
00000150:
39 44 24 40 CMP
DWORD PTR[ESP+40h],EAX
00000154:
0F 83 9E 00 00 00 JAE
0000009Eh (+9Eh ->:000001F8)
0000015A:
8B 4C 24 40 MOV
ECX,DWORD PTR[RSP + 0x40]
0000015E:
48 8B 44 24 30 MOV
RAX,QWORD PTR[RSP+30h]
00000163:
8B 0C 88 MOV
ECX,DWORD PTR[RAX + RCX*4]
00000166:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
0000016B:
48 03 C1 ADD
RAX,RCX
0000016E:
48 89 44 24 48 MOV
QWORD PTR [RSP+48h],RAX
00000173:
C7 44 24 50 00 00 00 00 MOV DWORD
PTR [RSP+50h], 00000000h ""
0000017B:
48 8B 44 24 48 MOV
RAX,QWORD PTR[RSP+48h]
00000180:
0F BE 00 MOVSX
EAX, BYTE PTR[RAX]
00000183:
85 C0 TEST
EAX,EAX
00000185:
74 3E JZ(rel8)
3Eh ;if Zero(+3Eh ->:000001C5)
00000187:
48 8B 44 24 48 MOV
RAX,QWORD PTR[RSP+48h]
0000018C:
0F BE 00 MOVSX
EAX, BYTE PTR[RAX]
0000018F:
89 44 24 54 MOV
DWORD PTR [ESP+54h],EAX
00000193:
48 8B 44 24 48 MOV
RAX,QWORD PTR[RSP+48h]
00000198:
48 83 C0 01 ADD
RAX,01h
0000019C:
48 89 44 24 48 MOV
QWORD PTR [RSP+48h],RAX
000001A1:
8B 44 24 50 MOV
EAX,DWORD PTR [RSP+50h]
000001A5:
C1 E8 0D SHR
EAX,0x0D (13)
000001A8:
8B 4C 24 50 MOV
ECX,DWORD PTR[RSP + 0x50]
000001AC:
C1 E1 13 SHL
ECX,0x13 (19)
000001AF:
0B C1 OR
EAX,ECX
000001B1:
89 44 24 50 MOV
DWORD PTR [ESP+50h],EAX
000001B5:
8B 4C 24 54 MOV
ECX,DWORD PTR[RSP + 0x54]
000001B9:
8B 44 24 50 MOV
EAX,DWORD PTR [RSP+50h]
000001BD:
03 C1 ADD
EAX,ECX
000001BF:
89 44 24 50 MOV
DWORD PTR [ESP+50h],EAX
000001C3:
EB B6 JMP(rel8)
B6h (-4Ah ->:0000017B)
000001C5:
8B 44 24 78 MOV
EAX,DWORD PTR [RSP+78h]
000001C9:
39 44 24 50 CMP
DWORD PTR[ESP+50h],EAX
000001CD:
75 24 JNZ
24h (if No Zero (rel8)(+24h ->:000001F3))
000001CF:
8B 4C 24 40 MOV
ECX,DWORD PTR[RSP + 0x40]
000001D3:
48 8B 44 24 28 MOV
RAX,QWORD PTR[RSP+28h]
000001D8:
0F B7 0C 48 MOVZX
ECX, WORD PTR[RAX + RCX*2]
000001DC:
48 8B 44 24 38 MOV
RAX,QWORD PTR[RSP+38h]
000001E1:
8B 0C 88 MOV
ECX,DWORD PTR[RAX + RCX*4]
000001E4:
48 8B 44 24 08 MOV
RAX,QWORD PTR[RSP+08h]
000001E9:
48 03 C1 ADD
RAX,RCX
000001EC:
48 89 44 24 18 MOV
QWORD PTR [RSP+18h],RAX
000001F1:
EB 05 JMP(rel8)
05h (+05h ->:000001F8)
000001F3:
E9 45 FF FF FF JMP
FFFFFF45h (-FFFFFF45h ->:0000013D)
000001F8:
48 8B 44 24 18 MOV
RAX,QWORD PTR[RSP+18h]
000001FD:
48 83 C4 68 ADD
RSP,0x68
00000201:
C3 RET
00000202:
56 PUSH
RSI
00000203:
57 PUSH
RDI
00000204:
53 PUSH
RBX
00000205:
48 33 DB XOR
RBX,RBX
00000208:
6A 30 PUSH
30h (push imm8)
0000020A:
58 POP
RAX
0000020B:
65 48 8B 30 MOV
RSI,QWORD PTR gs:[RAX]
0000020F:
48 8B 46 60 MOV
RAX,QWORD PTR[RSI+0x60]
00000213:
48 8B 40 18 MOV
RAX,QWORD PTR[RAX+0x18]
00000217:
48 8B 70 10 MOV
RSI,qword ptr [RAX+10h]
0000021B:
48 8B 7E 60 MOV
RDI,QWORD PTR[RSI+60h]
0000021F:
48 8B 46 30 MOV
RAX,QWORD PTR[RSI+0x30]
00000223:
48 8B 36 MOV
RSI,[RSI]
00000226:
38 5F 18 CMP
BYTE PTR[RDI+18h], BL
00000229:
75 F0 JNZ
F0h (if No Zero(rel8)(-10h ->:0000021B))
0000022B:
5B POP
RBX
0000022C:
5F POP
RDI
0000022D: 5E POP
RSI
0000022E: C3 RET
|
Nous allons expliquer les grands blocs du code via le passage dans
l'analyseur de bloc d'un outils dédié au shellcode X64 de notre toolbox de
développeur "Easy ShellCode Analyzer X64 V1.4" dont vous avez la
capture en dessous:
Et dont nous vous mettons
le diagramme du shellcode
00000000: 48 B8 00 00 00 00 00 00 00 00 MOV
RAX,0x0000000000000000 ""
0000000A: FF D0 CALL
RAX
0000000C: 48 83
EC 28 SUB RSP,0x28
00000010: 48 83 E4 F0 AND RSP,FFFFFFFFFFFFFFF0h
00000014: E8 E9 01 00 00 CALL 000001E9h (+1E9h ->:00000202)
00000019: BA 8E 4E 0E EC MOV EDX, EC0E4E8Eh "ŽN
ì" (EC0E4E8E=Hash[ROR13(Additive)]('LoadLibraryA'))
0000001E: 48 89 C1 MOV
RCX,RAX
00000021: E8 68 00 00 00 CALL 00000068h (+68h ->:0000008E)
00000026: EB 27 JMP(rel8)
27h (+27h ->:0000004F)
00000028: 59 POP
RCX
00000029: FF D0 CALL
RAX
0000002B: BA A8 A2 4D BC MOV EDX, BC4DA2A8h "¨¢M¼"
(BC4DA2A8=Hash[ROR13(Additive)]('MessageBoxA'))
00000030: 48 89 C1 MOV
RCX,RAX
00000033: E8 56 00 00 00 CALL 00000056h (+56h ->:0000008E)
00000038: 48 89 C3 MOV
RBX,RAX
0000003B: 4D 31 C9 XOR
R9,R9
0000003E: EB 1F JMP(rel8)
1Fh (+1Fh ->:0000005F)
00000040: 41 58 POP
R8
00000042: EB 3A JMP(rel8)
3Ah (+3Ah ->:0000007E)
00000044: 5A POP
RDX
00000045: 48 31 C9 XOR
RCX,RCX
00000048: FF D3 CALL
RBX
0000004A: 48 83 C4 28 ADD RSP,0x28
0000004E: C3 RET
0000004F: E8 D4 FF FF FF CALL FFFFFFD4h (-2Ch ->:00000028)
db
"user32.dll"
00000054: 75 73 65 72 33 32 2E 64 6C 6C
0000005E: 00
0000005F: E8 DC FF FF FF CALL FFFFFFDCh (-24h ->:00000040)
db
">X64 Sample: MessageBoxA<"
00000064: 3E 58 36 34 20 53 61 6D 70 6C 65 3A 20 4D
65 73 73 61 67 65 42 6F 78 41 3C
0000007D: 00
0000007E: E8 C1 FF FF FF CALL FFFFFFC1h (-3Fh ->:00000044)
db
"<9B113D1A>"
00000083: 3C 39 42 31 31 33 44 31 41 3E
0000008D: 00
0000008E ->
00000201: =>DWORD64
GetProcAddressByHashROR13AdditiveInX64V1(HMODULE hMod,DWORD dwHash)
00000202 ->
0000022E: =>HMODULE
GetKernel32InX64V1(void)
|
Le codes est assez simple et
la visualisation des zones de data est aussi assez parlant
Nous avons crée un
programme permettant d'effectuer le process hollowing comme le ferait un
malware. Ce programme est nommé "SampleProcessHollowing.exe" qui met
en pratique cette technique
Dont voici le résultat
avec la visualisation que pour le système le processus et vu comme la
calculatrice windows. Car le PEB du processus légitime, l'enveloppe est
toujours la même. Par contre le code exécuté est notre shellcode.
En lancant un
"Process Hasker" ou un "Process Explorer", nous voyons bien
notre calculatrice avec tous les caractéristiques de celle-ci . De même au
niveau de la barre des taches windows, nous retrouvons l'icone de l'application
légitime.
IV. Méthode pour détecter des processus Hollowing
Du fait de ce que l'on vient de voir
avec notre exemple
L'avantage de cette technique est
que le chemin du processus évidé pointera toujours vers le chemin légitime et
en s'exécutant dans le contexte d'un processus légitime,
le logiciel malveillant peut
contourner les pare-feu et éviter les systèmes ce bassant sur le nom des
processus pour l'analyse.
Par exemple, si le processus
calc.exe est évidé comme dans notre exemple, le chemin pointe toujours vers
l'exécutable légitime (C: \ Windows \ system32 \ calc.exe),
mais seulement dans la mémoire, la
section exécutable de calc.exe est remplacée par de code malveillant notre
shellcode.
l'un des éléments simple au vu de
l'exemple est la relation entre parent et le processus creux. Comme c'est le
processus du malware qui crée le processus légitime
Le processus creux a donc comme
"Id Parent" , Id du malware ce que dans notre exemple notre processus
calc a comme Ipd Parent 3828 qui n'est autre que notre programme
On peut aussi contrôler l'image du
PE par rapport a celle du binaire est si celle-ci est différente, nous somme
devant un processus hollowing
Nous monterons un outils permettant
la détection des processus hollowing dans un prochain article.
V. Conclusions
Nous espérons que ces quelque ligne,
vous permet de mieux comprendre la mécanique utiliser et mis en oeuvre par des
malware
Les techniques d'injection
cross-process sont divers et continuerons à évoluer que ce soit les processus
hollowing , atomic bombing. Bien d'autre existe comme les Windows Title Attack.
Aucun commentaire:
Enregistrer un commentaire