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
|
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
Nous avons intégré au testeur des fonctions hash Rol3
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
}
}
|
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
|
Aucun commentaire:
Enregistrer un commentaire