lundi 29 mai 2017

Shellcode utilisant des Hash ROL3


Introduction


Nous avons trouvé plusieurs sources sur Internet de shellcode utilisant des hashs moins current basé sur ROL3
nous avons également trouver les deux variantes CallApi(...) et la fonction autonome de génération du hash en Rol3. Ainsi que la classique api GetProcAddrByRol3(...)

Nous avons prendre comme exemple la page  "http://bbs.pediy.com/thread-126839.htm"
qui fait l'équivalent de WinExec("E:\\2.EXE",SW_SHOW); pour notre analyse des HashRol3 et remonter à une fonction C.

Analyse par l'exemple


Exemple d'un bloc du shellcode qui nous intéresse plus particulièrement dans ce shellcode sera le suivant:

\x64\xA1\x30\x00\x00\x00\x8B\x40\x0C\x8B\x40\x1C\x8B\x00\x8B\x40
\x08\x68\x4B\xF7\x6E\x01\x50\xE8\x57\x00\x00\x00\x90\xE8\x0B\x00
\x00\x00\x45\x3A\x5c\x5c\x32\x2E\x65\x78\x65\x00\x00\x5D\x6A\x00
\x55\xFF\xD0

Nous l'avons transcrit en assembleur via un outil perso. Cela nous donne le code assembleur suivant:
 
00000000:   64 A1 30 00 00 00      MOV EAX,DWORD PTR FS:[00000030]
00000006:   8B 40 0C                  MOV EAX,[EAX+0Ch]
00000009:   8B 40 1C                  MOV EAX,[EAX+1Ch]
0000000C:   8B 00                      MOV EAX,DWORD PTR DS:[EAX]
0000000E:   8B 40 08                  MOV EAX,[EAX+08h]
00000011:   68 4B F7 6E 01          PUSH 016EF74Bh
00000016:   50                                PUSH EAX
00000017:   E8 57 00 00 00          CALL 00000057h
0000001C:   90                           NOP
0000001D:   E8 0B 00 00 00 CALL 0000000Bh
                                      db "E:\\2.exe"
00000022:  45 3A 5C 5C 32 2E 65 78 65 00
0000002C:   00                          
0000002D:   5D                          POP EBP
0000002E:   6A 00                      PUSH 0h
00000030:   55                           PUSH EBP
00000031:   FF D0                      CALL EAX

Mais vous pourrez voir que sur plusieurs autres site l'utilisation de hash Rol3 avec la même structure d'appel comme sur le blocs de code fournit par la page  "http://www.sgoldcn.com/simple/?t329.html" 

00408C58   . 55                  PUSH EBP
00408C59   . 8BEC              MOV EBP,ESP
00408C5B   . 83EC 20         SUB ESP,20
00408C5E   . 53                  PUSH EBX
00408C5F   . 56                  PUSH ESI
00408C60   . 57                  PUSH EDI
00408C61   . E8 22010000   CALL WRAR39~1.00408D88
00408C66   . 8BF0               MOV ESI,EAX
00408C68   . 68 89FD12A4   PUSH A412FD89
00408C6D   . 56                  PUSH ESI
00408C6E   . 8975 EC          MOV DWORD PTR SS:[EBP-14],ESI
00408C71   . E8 52010000   CALL WRAR39~1.00408DC8
00408C76   . 68 19D0D602   PUSH 2D6D019
00408C7B   . 56                   PUSH ESI
00408C7C   . 8BF8               MOV EDI,EAX
00408C7E   . E8 45010000   CALL WRAR39~1.00408DC8
00408C83   . BB 60A90010   MOV EBX,1000A960
00408C88   . 81EB 00A20010 SUB EBX,1000A200
00408C8E   . 53                   PUSH EBX
00408C8F   . 6A 40               PUSH 40
00408C91   . FFD0                CALL EAX
00408C93   . 8945 F8           MOV DWORD PTR SS:[EBP-8],EAX
00408C96   . E8 AD010000   CALL WRAR39~1.00408E48
00408C9B   . 8945 F0           MOV DWORD PTR SS:[EBP-10],EAX
00408C9E   . 90                   NOP
00408C9F   . 90                   NOP
00408CA0   . 90                   NOP
00408CA1   . B1 6C              MOV CL,6C
00408CA3   . 32C0               XOR AL,AL
00408CA5   . C645 E0 73      MOV BYTE PTR SS:[EBP-20],73
00408CA9   . C645 E1 68      MOV BYTE PTR SS:[EBP-1F],68
00408CAD   . 884D E2          MOV BYTE PTR SS:[EBP-1E],CL

 Nous avons mis en rouge les deux parties qui nous intéressent le plus avec le mode d'appel et les deux hashs 016EF74B  et  A412FD89

Extraction des APIs correspondant au Hash

Nous avons passer ces Hash dans notre outil ApiHashPredator.exe























Nous avons fait de même avec le hash A412FD89 qui nous a donné la Api correspondante  "LoadLibraryA"

Nous avons passer quelques fonctions qui sont souvent appeler dans des shellcodes pour crée un petit tableau de référence
Hash Value
Dll
Api Function
016EF74B
Kernel32.dll
WinExec
A412FD89
Kernel32.dll
LoadLibraryA
16118A5D
Urlmon.dll
URLDownloadToFileA
14D14C51
User32.dll
MessageBoxA

Maintenant regardons la façon dont est utilisé ses hashs dans ses deux shellcodes

68 4B F7 6E 01         PUSH 016EF74Bh
50                               PUSH EAX
E8 57 00 00 00         CALL 00000057h

Lorsque ces instruction sont exécutées, il en résulte que la pile lorsqu'elle arrive sur le code de la subroutine à l'adresse 0x00000057  ce compose comme suit



 Vu les deux shellcodes EAX contient le hModule de Kernel32.dll

Nous pouvons déduire de la que les deux calls sont sur  le même type de fonction qui est

DWORD GetProcAddressByHashRol3(HMODULE hMod,DWORD dwHashRol3 );

dans le bloc de la subroutine un call est également effectué vers une sur subroutine  que nous avons extrait du deuxième shellcode qui semble assez intéressante

\x55\x8B\xEC\x8B\x45\x08\x52\x33\xD2\xC1\xC2\x03\x32\x10\x40\x80
\x38\x00\x75\xF5\x8B\xC2\x5A\xC9\xC3

Nous l'avons transcrit en assembleur via un outil perso. Cela nous donne le code assembleur suivant:

00000000:   55                       PUSH EBP
00000001:   8B EC                MOV EBP,ESP
00000003:   8B 45 08                        MOV EAX,DWORD PTR [EBP+08h]
00000006:   52                       PUSH EDX
00000007:   33 D2                  XOR EDX,EDX
00000009:   C1 C2 03           ROL EDX,03h (3 en décimale)
0000000C:   32 10                  XOR DL,BYTE PTR[EAX]
0000000E:   40                       INC EAX
0000000F:   80 38 00             CMP BYTE PTR [EAX],00h
00000012:   75 F5                  JNZ F5h (rel8)(-0Bh ->:00000009)
00000014:   8B C2                 MOV EAX,EDX
00000016:   5A                      POP EDX
00000017:   C9                      LEAVE ( equivaut MOV ESP,EBP / POP EBP) en X86
00000018:   C3                       RET

Nous avons mis en bleu le prologue et épilogue de la fonction comme le bloc utilise le registre EDX pour travailler. Nous voyons la sauvegarde et restauration de sa valeur en début et fin de traitement de la fonction en orange.

La fonction n'a qu'un paramètre passé et renvoi un DWORD. Vu que le traitement étant sur des bytes on peut dire que le paramétres passer est un pointeur vers un char

donc la fonction est de la forme DWORD fonctionX(char* pC )

Test de la fonction en environnement C++

Nous avons porté ce code dans Visual Studio pour tester la fonction

DWORD __declspec(naked)GetHash_MalwareRef1_Asm_V2(const char* pFunction)
{
            __asm
            {
                        PUSH EBP
                        MOV EBP,ESP
                        MOV EAX,DWORD PTR[EBP+0x08]
                        PUSH EDX
                        XOR EDX, EDX
                        NextCharString:
                        ROL EDX,3  
                        XOR DL,[EAX]
                        INC EAX
                        CMP BYTE PTR[EAX],0x0
                        JNZ SHORT NextCharString
                        MOV EAX,EDX
                        POP EDX
                        LEAVE
                        RETN
            }
}

 voici le résultat du programme de test, après execution


 la transcription du code Assembleur en code C est assez simple dont voici la transposition

DWORD GetHash_MalwareRef1_C_V2(const char* pFunction)
{
      DWORD dwHashRol3 = 0x0;

         do
        {
            dwHashRol3 = ((dwHashRol3 << 3) & (DWORD)(-1))|(dwHashRol3 >> (32-3));
            dwHashRol3 = dwHashRol3 ^ (*pFunction);  // ^ est l'opérateur "ou exclusif binaire"
            pFunction++;
         }while(*pFunction);

      return dwHashRol3;
}

Il faut voir que l'utilisation du registre EDX correspond à l'utilisation d'une variable local à la fonction EDX correspond à notre dwHashRol3

que la boucle do / while est notre JNZ en assembleur

Revenons maintenant au premier shellcode initial  analyse, nous avons la fin du shellcode qui est proche de la fonction décoder du second. Comme vous pouvez le voir dans la capture écran.


Nous avons transcrit cette fonction dans Visual Studio pour évalué sont résultat

DWORD __declspec(naked)GetHash_MalwareRef1_Asm_V3(const char* pFunction)
{
        __asm
       {
            POP ECX
            POP EAX
            PUSH EAX     //> Rajouter pour éviter les soucis de Pile en sortie de fonction
            PUSH ECX
            PUSH ESI
            XOR EDX,EDX
            XCHG EAX,ESI
            CLD
NextCharString:
            LODSB
            TEST AL,AL
            JZ finish
            ROL EDX,03h
            XOR DL,AL
            JMP NextCharString
finish:
            XCHG EAX,EDX
            POP ESI
            RET
       }
}

Nous avons intégré au testeur des fonctions hash Rol3

Tableau de hash Rol3 détecté dans des shellcodes

Voilà cela nous a permit de faire un tour sur ce type de hash Rol3. Delà il vous sera facile de trouver différente source utilisant ce type de hash Rol3

Dont par exemple si vous regardé la page "http://www.52pojie.cn/thread-59301-1-1.html"

Vous aurez un panel de ce type de hash utilisé complétant notre tableaux initial

Hash Value
Dll
Api Function
016EF74B
Kernel32.dll
WinExec
A412FD89
Kernel32.dll
LoadLibraryA
16118A5D
Urlmon.dll
URLDownloadToFileA
14D14C51
User32.dll
MessageBoxA
C5FF2F46
Kernel32.dll
VirtualProtect
38C62A7A
Kernel32.dll
CreateFileA
9554EFE7
Kernel32.dll
GetFileSize
A9D1FD70
Kernel32.dll
SetFilePointer
0BE25545
Kernel32.dll
ReadFile
02D6D019
Kernel32.dll
LocalAlloc
C0D6D616
Kernel32.dll
CloseHandle
405AD3CD
Kernel32.dll
LocalFree

dimanche 14 mai 2017

Shellcode en X64 "MessageBoxA"

Nous allons utiliser les mêmes techniques que sous X32 en portant les fonctions en X64

Disposer d'une fonction pour obtenir le HMODULE sur Kernel32.dll
cela grâce à une GetKernel32(..) en X64 que l'on nommera GetKernel32InX64
pour la partie API obtention des APIs qui nous serons utile
nous utiliserons des HASH et la fonction GetProcAddressByHashROR13Additive(..) en X64
Que l'on nommera  GetProcAddressByHashROR13AdditiveInX64V1

le pseudo code du shellcode sera

// Obtention du HMODULE de kernel32.dll
RAX = GetKernel32InX64(void)
// Obtention de la fonction "LoadLibraryA"
RAX = GetProcAddressByHashROR13AdditiveX64(RAX,0xEC0E4E8E )
// Appeler la fonction charger "user32.dll" et obtenir son HMODULE
RAX = LoadLibraryA("user32.dll")
// Obtenir la fonction "MessageBoxA"
RAX = GetProcAddressByHashROR13AdditiveInX64V1(RAX,0xBC4DA2A8 )
// Enfin appeler la fonction
// MessageBoxA(NULL,">X64 Sample: MessageBoxA<","<9B113D1A>",MB_OK);

Pour cela nous avons besoin d'une fonction HMODULE GetKernel32InX64(void) en X64

Dont voici le code assemble en X64 ( Intel )

PUSH RSI
PUSH RDI
PUSH RBX
XOR RBX,RBX
PUSH 30h
POP RAX
MOV RSI,QWORD PTR gs:[RAX]
MOV RAX,QWORD PTR[RSI+60h]
MOV RAX,QWORD PTR[RAX+18h]
MOV RSI,qword ptr [RAX+10h]
NextModule:
MOV RDI,QWORD PTR[RSI+60h]
MOV RAX,QWORD PTR[RSI+30h]
MOV RSI,[RSI]
CMP BYTE PTR[RDI+18h], BL
JNZ NextModule
POP RBX
POP RDI
POP RSI
RET

Pour la fonction

DWORD64 GetProcAddressByHashROR13AdditiveInX64V1(HMODULE hMod,
                                                                                                              DWORD dwHash);

Nous expliquerons dans un autre article comment la crée, mais étant un peut longue l'intérêt assez limité. Pour le principe, elle a été généré à partir d'un code C via Microsoft Visual Studio qui est une technique très utilisé pour générer des bloques de Shellcode dans le monde Windows.

Nous avons mis le shellcode résultant globale dans un tableau en C avec des couleurs pour vous permettre de bien distinguer les différents blocs du Shellcode X64

unsigned char MessageBox64bitV1_sc[] =
"\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 avons passer dans un outil pour vous faire sortir les blocs de couleur

Pour le test du shellcode X64


Créer à partir de visual studio un projet "StarterShellcodeX64_MessageBoxA"

New Project\Win32 - Projet Win32 ( Projet Vide )

Puis ajouter un fichier code .cpp nommé "StarterShellcodeX64_MessageBoxA.cpp"

et copier le code dans le fichier

 

#define WIN32_LEAN_AND_MEAN             // Exclure les en-têtes Windows rarement utilisés
// Fichiers d'en-tête Windows :
#include <windows.h>

// Fichiers d'en-tête C RunTime
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
                unsigned char MessageBox64bitV1_sc[] =
                "\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";

                int len = sizeof(MessageBox64bitV1_sc);

                void *pvBuffer;
                pvBuffer = malloc(len);

                memcpy(pvBuffer,(void*)&(MessageBox64bitV1_sc[0]),len);

                DWORD oldProtect;
                if (VirtualProtect(pvBuffer, len, PAGE_EXECUTE_READWRITE, &oldProtect))
                {
                               (*((int (__stdcall *)(void))pvBuffer))();
                }       

                return 0;
}

 Vous devriez avoir une vue comme celle en dessous , configurer la compilation en X64


Suite à la compilation, vous aurez un executable X64 avec votre shellcode MessageBoxA


 

 


dimanche 2 avril 2017

Antivrus - Analyse Statique par signature


Les types d'analyse qu'effectue un Antivirus


on peut définit 3 types d'analyse effectué par les antivirus qui sont les suivant:

- l'analyse statique par signature
- l'analyse statique heuristiques
- l'analyse dynamique

L'analyse statique par signature

Cette analyse est basée sur une liste de séquence de byte ou l'on considérer qu'elle représente un marqueur du malware.

Quand un nouveau malware est détecté une analyse est effectué par des analystes de société d'antivirus. De là ils définissent une signature du malware qui va être rajouter à la liste. Lors de l'upgrade de la base donnée des signatures chaque antivirus va à ce moment là disposer de cette mise à jour. Cette signature peut être basée sur un code particulier ou d'autre critère comme hash du binaire lui-même.

Un malware possède des éléments de code fixe qui ne mutent pas, un peu comme les cellules souches d’une maladie. les analystes utilisent ces éléments fixes pour créer une signature qu’on peut ensuite identifier, de la même manière que l’on détermine un virus en fonction de son ARN/ADN.
Souvent la signature sur une suite d'octets d'un malware. Les antivirus ont une base de données contenant des millions de signatures et comparent le code du binaire scanné avec la base de données des signature.

Le gros problème de cette méthode d’analyse basée sur les signatures, c’est qu’elle ne peut pas être utilisée pour détecter un nouveau logiciel Malware sauf si celui-ci utilise une souche d'un code déjà référencé. Donc pour contourner cette analyse, il suffit à développeur de malware de faire une modification mineure du code pour fausser la signature de l'antivirus.

De plus les malwares polymorphes ont la capacité de modifier automatiquement leur code, ce qui ne permet pas de générer du hachage binaire unique identifiant celui-ci ou une signature spécifique sur une suite d'octet.

Démonstration sur l'analyse d'une signature spécifique


Nous allons prendre une signature dans notre exemple qui aujourd'hui n'est plus significative qui est connu.

Nous avons parlé dans un précédent article des deux éléments permettant de contruire un shellcode GetKernel32 et GetProcAddressByHash. Il existe d'autre technique pour obtenir l'addresse de la fonction GetProcAddress(..) via une fonction dans un shellcode.

Nous avons nommé GetAddressOfFnGetProcAddressInKernel32dll qui est présent dans plusieurs shellcode du net.

Son prototype est le suivant :


DWORD GetAddressOfFnGetProcAddressInKernel32dll( VOID )

 L'un des shellcodes de cette fonction est le suivant:
 
unsigned char szShellCode_Fn_GetAddressOfFnGetProcAddressInKernel32dllV1[] =
         "\x60\x33\xC9\x64\x8B\x41\x30\x8B\x40\x0C\x8B"
         "\x70\x14\xAD\x96\xAD\x8B\x58\x10\x8B\x53"
         "\x3C\x03\xD3\x8B\x52\x78\x03\xD3\x8B\x72"
         "\x20\x03\xF3\x33\xC9\x41\xAD\x03\xC3\x81"
         "\x38\x47\x65\x74\x50\x75\xF4\x81\x78\x04"
         "\x72\x6F\x63\x41\x75\xEB\x81\x78\x08\x64"
         "\x64\x72\x65\x75\xE2\x8B\x72\x24\x03\xF3"
         "\x66\x8B\x0C\x4E\x49\x8B\x72\x1C\x03\xF3"
         "\x8B\x14\x8E\x03\xD3\x8B\xC2\x89\x44\x24\x1C\x61\xC3";

Via un outil, nous vous montrons le résultat de l'appel de la fonction GetAddressOfFnGetProcAddressInKernel32V1

Appel de la fonction GetAddressOfFnGetProcAddressInKernel32




























Vous pouvez tester vous même via le code similaire suivant :

void DlgShellCodeFnGetAddressOfFnGetProcAddress::OnBnClickedBtGetAddrfnGetprocaddress()
{
            unsigned char szShellCode_Fn_GetAddressOfFnGetProcAddressInKernel32dllV1[] =
            "\x60\x33\xC9\x64\x8B\x41\x30\x8B\x40\x0C\x8B"
            "\x70\x14\xAD\x96\xAD\x8B\x58\x10\x8B\x53"
            "\x3C\x03\xD3\x8B\x52\x78\x03\xD3\x8B\x72"
            "\x20\x03\xF3\x33\xC9\x41\xAD\x03\xC3\x81"
            "\x38\x47\x65\x74\x50\x75\xF4\x81\x78\x04"
            "\x72\x6F\x63\x41\x75\xEB\x81\x78\x08\x64"
            "\x64\x72\x65\x75\xE2\x8B\x72\x24\x03\xF3"
            "\x66\x8B\x0C\x4E\x49\x8B\x72\x1C\x03\xF3"
            "\x8B\x14\x8E\x03\xD3\x8B\xC2\x89\x44\x24\x1C\x61\xC3";

       int (*FnShellcode)() = (int(*)())(&szShellCode_Fn_GetAddressOfFnGetProcAddressInKernel32dllV1[0]);

            DWORD dwAddressOfFnGetProcAddressInKernel32Dll= FnShellcode();

            char szAddrFnGetProcAddress[255];
            sprintf(szAddrFnGetProcAddress,"%08X",dwAddressOfFnGetProcAddressInKernel32Dll);

            SetDlgItemText(IDC_ED_GETPROCADDRESS_RESU,szAddrFnGetProcAddress);
}

Maintenant revenu à notre sujet, nous allons crée un projet nommé "sampleSignatureViral" et intégrer le shellcode de notre fonction  GetAddressOfFnGetProcAddressInKernel32V1 et cela sans même appeler


























Nous lançons la compilation sur le poste et là l'anti-virus Avast détecte notre simple programme comme dangeureux avec comme signature "Win32:ShellCode-AK[Expl]"































Il nous reste plus qu'a chercher la séquence ou la suite d'octet que l'antivirus est pour lui le déclancheur de l'alerte et de l'action de suppression du binaire.

En fait c'est assez simple, il suffit d'enlever des octets et relancer la compilation jusqu'a avoir le plus petit suite d'octet de inclus dans notre shellcode et la suppression de l'un de plus n'engendre plus l'alerte

Nous vous donnons le resultat obtenu, si on enleve encore un octet au shellcode en dessous, il y aura plus alerte





























En conclusion la signature de l'infection Win32:ShellCode-AK[Expl] correspond à la séquence ou suite d' octet suivant:

"\x33\xC9\x64\x8B\x41\x30\x8B\x40\x0C\x8B\x70\x14\xAD\x96\xAD\x8B\x58\x10\x8B\x53  
  \x3C\x03\xD3\x8B\x52" 

Nous gardons à l'exprit pour la suite que l'octet qui suit le dernier octet de la signature est  "\x78".
Nous expliquerons pourquoi nous devons pas oublier ce point. même si pour la signature cela n'a aucune importante l'octet qui suite

Si nous passons notre binaire "sampleSignatureVirtal.exe" au scanne de VirusTotal qui est un site web permettant l'analyse de fichier suspects et facilite la détection rapide des virus, vers, chevaux de Troie et toutes sortes de malwares détectés par les moteurs antivirus.l'url du site est :  https://www.virustotal.com/

Nous obtenons le même résultat pour notre binaire