vendredi 11 mai 2018

Technique Process Hollowing


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"

Le terme vient "Run PE" faire tourné un PE qui sont le diminutif ( Portable Executable ) et la structure PE d'un programme.


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


Pour cela nous utilisons un exemple assez simple comme processus légitime on prendra "calc.exe" et comme charge malveillante un shellcode affichant une simple MessageBox.





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)

Nous retrouvons une architecture classique avec 2 fonctions classique. L'une dédier à récupérer l'addresse de kernel32(X64).dll et la fonction pour trouver les addresses des APIs via leurs hash ROR13 que l'on nomme GetProcAddressByHashROR13Additive
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