I. Introduction
Vous trouverez plusieurs sites ou ce hash est utilisé dans
différents shellcode ou Malware comme Zeus.
Rentrons dans le vif du sujet, il représente la chaîne
unicode de "KERNEL.DLL".
Pour bien représenté celle-ci est pour nos explications,
vous trouvez en en dessous une représentation en mémoire de la chaîne unicode.
L'algorithme utilisé est un Ror13 Additive Uppercase pour le
calcule du hash. De plus l'algorithme à une particularité, il ce base pas sur
un arrêt du calcule sur la fin de chaîne.
Mais reçoit le nombre d'octet à prendre en compte pour le
calcule du hash.
Ce qui fait que l'on peut avoir différente valeur de hash
fonction du nombre d'octet choisit
au lieu de prendre toute la chaîne on peut prendre X caractéres.II. Utilisation dans la pratique
Pour notre description de ce hash, nous somme partie d'un
fichier assembleur effectuant un simple WinExec("calc.exe"), mais
utilisant ce hash pour effectuer la recherche de HMODULE de kernel32.dll qui
est assez répandu comme utilisation de ce hash dans beaucoups de lien.
Nous mettons le listing de notre fichier
"WinExecCalcV1.asm" utilisé pour notre étude.
[SECTION
.text]
BITS 32
global
_start
_start:
jmp start_asm
GetKernel32Base:
cld ; // clear the direction
flag for the loop
xor edx, edx ; // zero edx
mov edx, [fs:edx+0x30 ] ; // get a pointer to the PEB
mov edx, [ edx+0x0C ] ; // get PEB->Ldr
mov edx, [ edx+0x14 ] ; // get the first module from the
InMemoryOrder module list
next_mod:
mov esi, [ edx+0x28 ] ; // get pointer to modules name
(unicode string)
mov ecx, 24 ; // set ecx to this
length for the loop
xor edi, edi ; // clear edi
which will store the hash of the module name
loop_modname:
xor eax, eax ; // clear eax
lodsb ; // read in the next byte of
the name
cmp al, 'a' ; // some versions of Windows use lower
case module names
jl not_lowercase
sub al, 0x20 ; // if so normalise
to uppercase
not_lowercase:
ror edi, 13 ; // rotate left
our hash value
add edi, eax ; // add the next
byte of the name
loop loop_modname ; // loop untill we have read
enough
cmp edi, 0x6A4ABC5B ; // compare the hash with that of
KERNEL32.DLL
mov ebx, [ edx+0x10 ] ; // get this modules base address
mov edx, [ edx ] ; // get the next module
jne next_mod
ret
find_function:
pushad
mov ebp, [esp + 0x24]
mov eax, [ebp + 0x3c]
mov edx, [ebp + eax + 0x78]
add edx, ebp
mov ecx, [edx + 0x18]
mov ebx, [edx + 0x20]
add ebx, ebp
find_function_loop:
jecxz find_function_finished
dec ecx
mov esi, [ebx + ecx * 4]
add esi, ebp ; esi now points to current
function string
; start of compute hash function
compute_hash:
; put this into a function
xor edi, edi ; edi will hold our hash
result
xor eax, eax ; eax holds our current
char
cld
compute_hash_again:
lodsb ; puts current char into eax
(except first time)
test al, al ; checks for null - end of function string
jz compute_hash_finished
ror edi, 0xd ; rotate the current hash
add edi, eax ; adds current char to
current hash
jmp compute_hash_again
compute_hash_finished:
; end of compute hash function
find_function_compare:
;this is where it compares the
calculated hash to our hash
cmp edi, [esp + 0x28]
jnz find_function_loop
mov ebx, [edx + 0x24]
add ebx, ebp
mov cx, [ebx + 2 * ecx]
mov ebx, [edx + 0x1c]
add ebx, ebp
mov eax, [ebx + 4 * ecx]
add eax, ebp
;this is the VMA of the function
mov [esp + 0x1c], eax
find_function_finished:
popad
ret
resolve_symbols_for_dll:
;about to load current hash into eax
(pointed to by esi)
lodsd
push eax
push edx
call find_function
mov [edi], eax
add esp, 0x08
add edi, 0x04
cmp esi, ecx
jne resolve_symbols_for_dll
resolve_symbols_for_dll_finished:
ret
start_asm:
; start our main program
sub esp, 0x08 ; allocate space on stack
for function addresses
mov ebp, esp ; set ebp as frame ptr for
relative offset on stack
call GetKernel32Base ;find address of
Kernel32.dll
mov edx, ebx
;resolve kernel32 symbols
jmp short locate_hashes ;locate address
of our hashes
locate_hashes_return:
;define return label to return to this code
pop esi ;get constants address from
stack
lea edi, [ebp + 0x04] ;this is where we
store our function addresses
mov ecx, esi
add ecx, 0x08 ;length of dns shellcode
hash list
call resolve_symbols_for_dll
jmp short GetCommand
CommandReturn:
pop ebx ;ebx now holds the handle to the
string
xor eax,eax ;empties out eax
push eax ;push null onto stack as empty
parameter value
push ebx ;push the command onto the
stack
call [ebp+4] ;call
WinExec(path,showcode)
xor eax,eax ;zero the register again,
clears winexec retval
push eax ;push null onto stack as empty
parameter value
call [ebp+8] ;call ExitProcess(0);
locate_hashes:
call locate_hashes_return
;WinExec ;result hash = 0x98FE8A0E
db 0x98
db 0xFE
db 0x8A
db 0x0E
;ExitProcess ;result hash = 0x7ED8E273
db 0x7E
db 0xD8
db 0xE2
db 0x73
GetCommand:
call CommandReturn
db "calc.exe"
db 0x00
|
Pour le compiler, vous pouvez utiliser "NASM", vous trouvez
cette assembleur à l'url suivant: https://www.nasm.us/
En suite vous avez plus qu'a compiler le fichier .asm avec
une ligne de commande suivant:
C:\NASM\nasm.exe -f bin C:\Asm\WinExecCalcV1.asm -o
C:\Asm\WinExecCalcV1.bin
|
Dans notre cas, nous allons utilisé un de nos anciens
programme de notre tools permettant de faire cela via un interface graphique
windows et il nous suffit de cliquer sur "Compile(bin)" pour obtenir
la compilation. Cela est assez pratique quand on veut modifier rapidement
quelques ligne du fichier et pas avoir à taper n commande pour générer des
exécutables
Suite à cela nous n'avons plus qu'a cliquer sur le button
"Obj/Bin", pour avoir les opcodes générés
Nous remontons en dessous le listing obtenu
\xE9\x98\x00\x00\x00\xFC\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B
\x52\x14\x8B\x72\x28\xB9\x18\x00\x00\x00\x31\xFF\x31\xC0\xAC\x3C
\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x81\xFF\x5B\xBC
\x4A\x6A\x8B\x5A\x10\x8B\x12\x75\xD9\xC3\x60\x8B\x6C\x24\x24\x8B
\x45\x3C\x8B\x54\x05\x78\x01\xEA\x8B\x4A\x18\x8B\x5A\x20\x01\xEB
\xE3\x34\x49\x8B\x34\x8B\x01\xEE\x31\xFF\x31\xC0\xFC\xAC\x84\xC0
\x74\x07\xC1\xCF\x0D\x01\xC7\xEB\xF4\x3B\x7C\x24\x28\x75\xE1\x8B
\x5A\x24\x01\xEB\x66\x8B\x0C\x4B\x8B\x5A\x1C\x01\xEB\x8B\x04\x8B
\x01\xE8\x89\x44\x24\x1C\x61\xC3\xAD\x50\x52\xE8\xAA\xFF\xFF\xFF
\x89\x07\x83\xC4\x08\x83\xC7\x04\x39\xCE\x75\xEC\xC3\x83\xEC\x08
\x89\xE5\xE8\x5E\xFF\xFF\xFF\x89\xDA\xEB\x1E\x5E\x8D\x7D\x04\x89
\xF1\x83\xC1\x08\xE8\xCF\xFF\xFF\xFF\xEB\x1B\x5B\x31\xC0\x50\x53
\xFF\x55\x04\x31\xC0\x50\xFF\x55\x08\xE8\xDD\xFF\xFF\xFF\x98\xFE
\x8A\x0E\x7E\xD8\xE2\x73\xE8\xE0\xFF\xFF\xFF\x63\x61\x6C\x63\x2E
\x65\x78\x65\x00
|
Nous gardons cela de côté pour la suite, revenons à la
partie qui nous intéresse le calcul du hash. Nous avons mis en rouge la
fonction GetKernel32Base qui exploite ce hash.
Regardons la partie qui correspond au calcule du hash en
dessous extrait de la fonction GetKernel32Base
mov ecx, 24 ; // set ecx to this length for the loop
xor edi, edi ; // clear edi
which will store the hash of the module name
loop_modname:
xor eax, eax ; // clear eax
lodsb ; // read in the next byte of the name
cmp al, 'a' ; // some
versions of Windows use lower case module names
jl not_lowercase
sub al, 0x20 ; // if so normalise
to uppercase
not_lowercase:
ror edi, 13 ; // rotate left
our hash value
add edi, eax ; // add the next
byte of the name
loop loop_modname ; // loop untill we have read
enough
cmp edi, 0x6A4ABC5B ; // compare the hash with that of
KERNEL32.DLL
|
Il y a utilisation du registre ECX pour fixer le nombre
d'octet à prendre pour le calcule du hash.
On peut à partir de la écrire une fonction C , effectuant le
même traitement
DWORD
CalculatehashRor13AdditiveUppercaseAndFixedLength(char*pData,DWORD dwLength)
{
DWORD dwHash =0x0;
for(int i=0;i<dwLength;i++)
{
dwHash = (dwHash >> 13) |
(dwHash << (32 - 13)); // ROR
dwHash , 13
dwHash += *pData >= 'a' ? *pData
- 32 : *pData; // Convert the
character to uppercase
pData++;
}
return dwHash;
}
|
On avait implémenté cela dans un petit programme pour
valider notre calculateur de se hash
Il y a quelque années
Nous avons bien le mode Uppercase, comme vous pouvez le
constater, nous avons écrit "KeRnel32.dLL" et fixer la taille à 24
octets pour le calcule du hash de la chaîne Unicode.
Revenons à notre exemple au dessus, nous avons référencé
cette fonction "GetKernel32Base" dans notre outils "
GetProcessTEBorPEB.exe", listant les références de la fonction GetKernel32
par PEB, trouvez lors de nos différentes étude de shellcode
Cette Fonction est référencé sous le numéro 38
Ce qui correspond en assembleur à cela avec les opcodes
00000000:
53 PUSH
EBX
00000001:
56 PUSH
ESI
00000002:
57 PUSH
EDI
00000003:
FC CLD
// Clear Direction Flag
00000004:
31 D2 XOR
EDX,EDX
00000006:
64 8B 52 30 MOV
EDX,DWORD PTR FS:[EDX+0x30]
0000000A:
8B 52 0C MOV
EDX,DWORD PTR[EDX+0x0C]
0000000D:
8B 52 14 MOV
EDX,DWORD PTR[EDX+0x14]
00000010:
8B 72 28 MOV ESI,DWORD PTR[EDX+0x28]
00000013:
B9 18 00 00 00 MOV
ECX, 00000018h ""
00000018:
31 FF XOR
EDI,EDI
0000001A:
31 C0 XOR
EAX,EAX
0000001C:
AC LODS
BYTE PTR DS:[ESI]
0000001D:
3C 61 CMP
AL,0x61 ('a')
0000001F:
7C 02 JL
02h (rel8)(+02h ->:00000023)
00000021:
2C 20 SUB
AL,20h
00000023:
C1 CF 0D ROR
EDI,0Dh (13)
00000026:
01 C7 ADD
EDI,EAX
00000028:
E2 F0 LOOP
F0h (-FFFFFFF0h=>:0000001A) Dec ECX or CX jump if !=0
0000002A:
81 FF 5B BC 4A 6A CMP
EDI,6A4ABC5Bh
(6A4ABC5B=Hash[ROR13(Additive)/FixedLenght](Unicode
>'KERNEL32.DLL',24))
00000030:
8B 5A 10 MOV EBX,DWORD PTR
[EDX+10h]
00000033:
8B 12 MOV
EDX,DWORD PTR [EDX]
00000035:
75 D9 JNZ
D9h (rel8)(-27h ->:00000010)
00000037:
8B C3 MOV
EAX,EBX
00000039:
5F POP
EDI
0000003A:
5E POP
ESI
0000003B:
5B POP
EBX
0000003C: C3 RET
|
Il ne nous reste plus qu' à vérifier si notre shellcode
générer via NASM est bien transcrit pas notre outil d'analyse de shellcode X32.
Pour cela nous avons juste à positionner le shellcode et basculer en mode
"Diagram".
Nous mettons le listing correspondant en dessous:
00000000: E9 98 00 00 00 JMP 00000098h (+98h ->:0000009D)
00000005 ->
00000038:
=>{BLOC}[AsmGetKernel32_V38 -> EBX]
00000039: C3 RET
0000003A ->
00000087: => DWORD
__declspec(naked) GetProcAddressByHashRor13AdditiveV3(HMODULE hMod,DWORD
dwHash)
00000088: AD LODSD
(Loads DS:[SI](ESI for LODSD) val into AL,AX,EAX and inc SI)
00000089: 50 PUSH
EAX
0000008A: 52 PUSH
EDX
0000008B: E8 AA FF FF FF CALL FFFFFFAAh (-56h ->:0000003A)
00000090: 89 07 MOV
DWORD PTR[EDI],EAX
00000092: 83 C4 08 ADD
ESP,08h
00000095: 83 C7 04 ADD
EDI,04h
00000098: 39 CE CMP ESI,ECX
0000009A: 75 EC JNZ
ECh (rel8)(-14h ->:00000088)
0000009C: C3 RET
0000009D: 83 EC
08 SUB ESP,08h (On
alloue l'espace de 8 octets sur la stack)
000000A0: 89 E5 MOV
EBP,ESP
000000A2: E8 5E FF FF FF CALL FFFFFF5Eh (-A2h ->:00000005)
000000A7: 89 DA MOV
EDX,EBX
000000A9: EB 1E JMP
1Eh +1Eh ->:000000C9)
000000AB: 5E POP
ESI
000000AC: 8D 7D 04 LEA
EDI,[EBP+04h]
000000AF: 89 F1 MOV
ECX,ESI
000000B1: 83 C1 08 ADD
ECX,08h
000000B4: E8 CF FF FF FF CALL FFFFFFCFh (-31h ->:00000088)
000000B9: EB 1B JMP
1Bh +1Bh ->:000000D6)
000000BB: 5B POP
EBX
000000BC: 31 C0 XOR
EAX,EAX
000000BE: 50 PUSH
EAX
000000BF: 53 PUSH
EBX
000000C0: FF 55 04 CALL
DWORD PTR [EBP+04h]
000000C3: 31 C0 XOR
EAX,EAX
000000C5: 50 PUSH
EAX
000000C6: FF 55 08 CALL
DWORD PTR [EBP+08h]
000000C9: E8 DD FF FF FF CALL FFFFFFDDh (-23h ->:000000AB)
db
(0E8AFE98=Hash[ROR13(Additive)]('WinExec'))
000000CE: 98 FE 8A
0E
db (73E2D87E=Hash[ROR13(Additive)]('ExitProcess'))
000000D2: 7E D8 E2
73
000000D6: E8 E0 FF FF FF CALL FFFFFFE0h (-20h ->:000000BB)
000000DB ->
000000E3: db 'calc.exe',00h
|
Maintenant, nous allons chercher quelques autres exemples via
internet au travers de la séquence suivant
"\x81\xFF\x5B\xBC\x4A\x6A\x"
Nous arrivons sur plusieurs référence de shellcode, dont
celui-ci:
http://ddecode.com/hexdecoder/?results=b22a5424479b1d0bf59c5cc59a056e61
Nous vous remettons en dessous le shellcode correspondant
"\xFC\x33\xD2\xB2\x30\x64\xFF\x32\x5A\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x33\xC9"
"\xB1\x18\x33\xFF\x33\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x03\xF8\xE2\xF0"
"\x81\xFF\x5B\xBC\x4A\x6A\x8B\x5A\x10\x8B\x12\x75\xDA\x8B\x53\x3C\x03\xD3\xFF\x72"
"\x34\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\x49\x8B\x72\x24\x03\xF3\x66\x8B\x0C\x4E\x8B\x72\x1C\x03\xF3\x8B\x14"
"\x8E\x03\xD3\x52\x68\x78\x65\x63\x01\xFE\x4C\x24\x03\x68\x57\x69\x6E\x45\x54\x53"
"\xFF\xD2\x68\x63\x6D\x64\x01\xFE\x4C\x24\x03\x6A\x05\x33\xC9\x8D\x4C\x24\x04\x51"
"\xFF\xD0\x68\x65\x73\x73\x01\x8B\xDF\xFE\x4C\x24\x03\x68\x50\x72\x6F\x63\x68\x45"
"\x78\x69\x74\x54\xFF\x74\x24\x20\xFF\x54\x24\x20\x57\xFF\xD0"
|
Si nous passons ce shellcode dans notre outils, nous
obtiendrons le code assembleur.
Comme vous pouvez le voir dans la capture en dessous:
Nous retrouvons bien le partie de recherche du hModule de
Kernel32.dll. Mais il y a plus intéressant, nous avons mis en rouge une partie
correspondant à une fonction que vous trouverez dans plusieurs shellcode lors
de vos recherche sur le hash 0x6A4ABC5B
Nous remettons le listing obtenu avec notre outils.
00000000: FC CLD
// Clear Direction Flag
00000001: 33 D2 XOR
EDX,EDX
00000003: B2 30 MOV
DL,30h
00000005: 64 FF 32 PUSH
DWORD PTR FS:[EDX]
00000008: 5A POP
EDX
00000009: 8B 52 0C MOV
EDX,DWORD PTR[EDX+0x0C]
0000000C: 8B 52 14 MOV
EDX,DWORD PTR[EDX+0x14]
0000000F: 8B 72 28 MOV
ESI,DWORD PTR[EDX+0x28]
00000012: 33 C9 XOR
ECX,ECX
00000014: B1 18 MOV
CL,0x18
00000016: 33 FF XOR
EDI,EDI
00000018: 33 C0 XOR
EAX,EAX
0000001A: AC LODS
BYTE PTR DS:[ESI]
0000001B: 3C 61 CMP
AL,0x61 ('a')
0000001D: 7C 02 JL
02h (rel8)(+02h ->:00000021)
0000001F: 2C 20 SUB
AL,20h
00000021: C1 CF 0D ROR
EDI,0Dh (13)
00000024: 03 F8 ADD
EDI,EAX
00000026: E2 F0 LOOP
F0h (-FFFFFFF0h=>:00000018) Dec ECX or CX jump if !=0
00000028: 81 FF 5B BC 4A 6A CMP EDI,6A4ABC5Bh
(6A4ABC5B=Hash[ROR13(Additive)/FixedLenght](Unicode >'KERNEL32.DLL',24))
0000002E: 8B 5A 10 MOV
EBX,DWORD PTR [EDX+10h]
00000031: 8B 12 MOV
EDX,DWORD PTR [EDX]
00000033: 75 DA JNZ
DAh (rel8)(-26h ->:0000000F)
00000035: 8B 53 3C MOV
EDX,DWORD PTR[EBX+0x3C]
00000038: 03 D3 ADD
EDX,EBX
0000003A: FF 72 34 PUSH
DWORD PTR[EDX+0x34]
0000003D: 8B 52 78 MOV
EDX,DWORD PTR[EDX+0x78]
00000040: 03 D3 ADD
EDX,EBX
00000042: 8B 72 20 MOV
ESI,DWORD PTR[EDX+0x20]
00000045:
03 F3 ADD
ESI,EBX
00000047: 33 C9 XOR
ECX,ECX
00000049: 41 INC
ECX
0000004A: AD LODSD
(Loads DS:[SI](ESI for LODSD) val into AL,AX,EAX and inc SI)
0000004B: 03 C3 ADD
EAX,EBX
0000004D: 81 38 47 65 74 50 CMP DWORD PTR[EAX],50746547h ('PteG' => GetP)
00000053: 75 F4 JNZ
F4h (rel8)(-0Ch ->:00000049)
00000055: 81 78 04 72 6F 63 41 CMP DWORD PTR[EAX+0x04],0x41636F72
"rocA"
0000005C: 75 EB JNZ
EBh (rel8)(-15h ->:00000049)
0000005E: 81 78 08 64 64 72 65 CMP DWORD PTR[EAX+0x08],0x65726464
"ddre"
00000065: 75 E2 JNZ
E2h (rel8)(-1Eh ->:00000049)
00000067: 49 DEC
ECX
00000068: 8B 72 24 MOV
ESI,DWORD PTR[EDX+0x24]
0000006B: 03 F3 ADD
ESI,EBX
0000006D: 66 8B 0C 4E MOV CX,WORD PTR[ESI+ECX*2]
00000071: 8B 72 1C MOV
ESI,DWORD PTR[EDX+0x1C]
00000074:
03 F3 ADD
ESI,EBX
00000076: 8B 14 8E MOV
EDX,DWORD PTR [ESI+ECX*4]
00000079: 03 D3 ADD
EDX,EBX
0000007B: 52 PUSH
EDX
0000007C: 68 78 65 63 01 PUSH 01636578h "xec" dw:23291256 / {120 101
99 1} / < w:25345 | w:30821 >
00000081: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
00000085: 68 57 69 6E 45 PUSH 456E6957h "WinE" dw:1164863831 / {87 105
110 69} / < w:28229 | w:22377 >
0000008A: 54 PUSH
ESP
0000008B: 53 PUSH
EBX
0000008C: FF D2 CALL
EDX
0000008E: 68 63 6D 64 01 PUSH 01646D63h "cmd" dw:23358819 / {99 109
100 1} / < w:25601 | w:25453 >
00000093: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
00000097: 6A 05 PUSH
05h (5) ''
00000099: 33 C9 XOR
ECX,ECX
0000009B: 8D 4C 24 04 LEA ECX,[ESP+0x04]
0000009F: 51 PUSH
ECX
000000A0: FF D0 CALL
EAX
000000A2: 68 65 73 73 01 PUSH 01737365h "ess" dw:24343397 / {101 115
115 1} / < w:29441 | w:25971 >
000000A7: 8B DF MOV
EBX,EDI
000000A9: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
000000AD: 68 50 72 6F 63 PUSH 636F7250h "Proc" ( 636F7250 = ('corP')
=> PILE:Proc )
000000B2: 68 45 78 69 74 PUSH 74697845h "Exit" ( 74697845 = ('tixE')
=> PILE:Exit )
000000B7: 54 PUSH
ESP
000000B8: FF 74 24 20 PUSH DWORD PTR [ESP+20h]
000000BC: FF 54 24 20 CALL DWORD [ESP+20h]
000000C0: 57 PUSH
EDI
000000C1: FF D0 CALL
EAX
|
Ce bloc représente une fonction qui permet d'avoir deux
adresses lors de son appel qui sont l'adresse du module kernel32 et l'adresse
de l'api GetProcAddress.
Nous avions écrit une fonction C pour tester cela il y a un
certain temps. Nous remettons en dessous la fonction.
void
GetAddressOfKernel32AndApiGetProcAddressV1(DWORD* pKernel32,DWORD*
pApiGetProcAddress)
{
__asm
{
CLD
XOR EDX,EDX
MOV DL,0x30
PUSH DWORD PTR FS:[EDX]
POP EDX
MOV EDX,DWORD PTR[EDX+0x0C]
MOV EDX,DWORD PTR[EDX+0x14]
saut3:
MOV ESI,DWORD PTR[EDX+0x28]
XOR ECX,ECX
MOV CL,0x18
XOR EDI,EDI
saut2:
XOR EAX,EAX
LODS BYTE PTR DS:[ESI]
CMP AL,0x61
JL saut1
SUB
AL,0x20
saut1:
ROR EDI,0x0D
ADD EDI,EAX
LOOP saut2
CMP EDI,0x6A4ABC5B
MOV EBX,DWORD PTR [EDX+0x10]
MOV EDX,DWORD PTR [EDX]
JNZ saut3
MOV EDX,DWORD PTR[EBX+0x3C]
ADD EDX,EBX
PUSH DWORD
PTR[EDX+0x34]
MOV EDX,DWORD PTR[EDX+0x78]
ADD EDX,EBX
MOV ESI,DWORD PTR[EDX+0x20]
ADD ESI,EBX
XOR ECX,ECX
saut4:
INC
ECX
LODSD
ADD EAX,EBX
CMP DWORD PTR[EAX],0x50746547
JNZ saut4
CMP
DWORD PTR[EAX+0x04],0x41636F72
JNZ
saut4
CMP
DWORD PTR[EAX+0x08],0x65726464
JNZ
saut4
DEC ECX
MOV ESI,DWORD PTR[EDX+0x24]
ADD ESI,EBX
MOV CX,WORD PTR[ESI+ECX*2]
MOV ESI,DWORD PTR[EDX+0x1C]
ADD ESI,EBX
MOV EDX,DWORD PTR [ESI+ECX*4]
ADD EDX,EBX
POP
EAX // équilibrage de la pile lié
MOV
EAX,DWORD PTR[pKernel32]
MOV DWORD PTR[EAX],EBX
MOV EAX,DWORD PTR[pApiGetProcAddress]
MOV DWORD PTR[EAX],EDX
}
}
|
Nous avons un testeur de cette fonction , nous mettons une
capture écran associer
Comme cette signature de bloc est incluse dans notre outil
d'analyse de shellcode X32
Nous mettons en dessous le listing obtenu
00000000 ->
0000007A:
=>{BLOC}[GetAddressOfKernel32AndApiGetProcAddressV1->
EBX:Kernel32 / EDX:Addr Api GetProcAddress]
0000007B: 52 PUSH
EDX
0000007C: 68 78 65 63 01 PUSH 01636578h "xec"
00000081: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
00000085: 68 57 69 6E 45 PUSH 456E6957h "WinE"
0000008A: 54 PUSH
ESP
0000008B: 53 PUSH
EBX
0000008C: FF D2 CALL
EDX
0000008E: 68 63 6D 64 01 PUSH 01646D63h "cmd
00000093: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
00000097: 6A 05 PUSH
05h (5) ''
00000099: 33 C9 XOR
ECX,ECX
0000009B: 8D 4C 24 04 LEA ECX,[ESP+0x04]
0000009F: 51 PUSH
ECX
000000A0: FF D0 CALL
EAX
000000A2: 68 65 73 73 01 PUSH 01737365h "ess"
000000A7: 8B DF MOV
EBX,EDI
000000A9: FE 4C 24 03 DEC BYTE PTR [ESP+0x03h]
000000AD: 68 50 72 6F 63 PUSH 636F7250h "Proc" ( 636F7250 = ('corP')
=> PILE:Proc )
000000B2: 68 45 78 69 74 PUSH 74697845h "Exit" ( 74697845 = ('tixE')
=> PILE:Exit )
000000B7: 54 PUSH
ESP
000000B8: FF 74 24 20 PUSH DWORD PTR [ESP+20h]
000000BC: FF 54 24 20 CALL DWORD [ESP+20h]
000000C0: 57 PUSH
EDI
000000C1: FF D0 CALL
EAX
|
Rien que à la lecture, il est simple de voir que ce
shellcode ne fait que un WinExec('cmd')
III. Test du shellcode WinExec("cmd")
Nous avons testé cela au travers d'un générateur de
shellcode perso dédier à la création de shellcode de type WinExec
Après avoir mis le shellcode dans la zone de saisi, nous
avons lancé le shellcode via le bouton "Run".
Et suite à cela nous
avons eu bien le lancement d'un "cmd" et la fermeture de notre
programme exécutant le shellcode lié à l'appel ExistProcess en fin du shellcode.
IV.Conclusions
L'intérêt de connaître les hash current permet de identifier plus rapidement des shellcode nouveau. Et il permet également de pas perdre son temps sur des copie de shellcode.
Comprendre lle processus de
reconnaissance par signature est importante. Car la technique étant lié à une
identification d'un bloc d'opcode , elle permet de rapidement connaitre les appels et la typologie du shellcode.
L'intérêt ici était de mettre en avant un type de calcule de hash basé sur la fixation de la taille.Il est est problabe que d'autre changerons le calcule ROR 13 par des ROL 7 , ROR 3 ... etc
Mais démarche pour retrouver les fonctions sera toujours identique.
Publication
RépondreSupprimer