Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
SysWhispers2 — 직접 시스템 호출을 통한 AV/EDR 회피 | Kitploit
도구/GitHubGitHub/jthuraisamy/syswhispers2
Defensive ToolsIDS/IPS EvasionShellcodeRed TeamingPayload DevelopmentBinary Exploitation
GitHubjthuraisamy/syswhispers2

SysWhispers2

직접 시스템 호출을 통한 AV/EDR 회피

저장소 보기
1.8k2653년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

SysWhispers2

SysWhispers는 직접 시스템 호출을 하기 위해 임플란트가 사용할 수 있는 헤더/ASM 파일을 생성하여 회피를 돕습니다.

모든 핵심 시스템 호출이 지원되며, 생성된 예제 파일은 example-output/ 폴더에서 확인할 수 있습니다.

SysWhispers 1과 2의 차이점

사용법은 SysWhispers1과 거의 동일하지만, 지원할 Windows 버전을 지정할 필요가 없습니다. 대부분의 변경 사항은 내부에 있습니다. 더 이상 @j00ru의 시스템 호출 테이블에 의존하지 않고, @modexpblog가 대중화한 "시스템 호출 주소로 정렬" 기술을 사용합니다. 이로 인해 시스템 호출 스텁의 크기가 크게 줄어듭니다.

SysWhispers2의 구체적인 구현은 @modexpblog 코드의 변형입니다. 한 가지 차이점은 함수 이름 해시가 생성할 때마다 무작위화된다는 점입니다. 이 기술을 먼저 발표한 @ElephantSe4l은 C++17 기반의 다른 구현도 가지고 있으며, 이것도 확인해볼 가치가 있습니다.

원본 SysWhispers 저장소는 여전히 유지되고 있지만 향후 폐기될 수 있습니다.

소개

다양한 보안 제품은 사용자 모드 API 함수에 후크를 설치하여 실행 흐름을 자체 엔진으로 리디렉션하고 의심스러운 동작을 탐지합니다. 시스템 호출을 수행하는 ntdll.dll의 함수는 몇 가지 어셈블리 명령어로만 구성되어 있으므로, 이를 자체 임플란트에서 다시 구현하면 해당 보안 제품 후크의 트리거를 우회할 수 있습니다. 이 기술은 @Cn33liz에 의해 대중화되었으며, 그의 블로그 게시글에는 더 많은 기술적 세부 사항이 있으니 읽어볼 가치가 있습니다.

SysWhispers는 레드 팀에게 핵심 커널 이미지(ntoskrnl.exe)의 모든 시스템 호출에 대한 헤더/ASM 쌍을 생성할 수 있는 기능을 제공합니다. 헤더에는 필요한 형식 정의도 포함됩니다.

설치

root@kitploit:~
> git clone https://github.com/jthuraisamy/SysWhispers2.git
> cd SysWhispers2
> py .\syswhispers.py --help

사용법 및 예제

명령줄

root@kitploit:~
# 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

스크립트 출력

root@kitploit:~
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?

모든 함수가 선택되었습니다.

완료! 파일이 다음 위치에 기록되었습니다:
        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 인젝션의 전후 예제

root@kitploit:~
py .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
root@kitploit:~
#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);
}
root@kitploit:~
#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);
}

일반 함수

--preset common 스위치를 사용하면 다음 함수들이 포함된 헤더/ASM 쌍이 생성됩니다:

함수 목록을 펼치려면 클릭.
  • NtCreateProcess (CreateProcess)
  • NtCreateThreadEx (CreateRemoteThread)
  • NtOpenProcess (OpenProcess)
  • NtOpenThread (OpenThread)
  • NtSuspendProcess
  • NtSuspendThread (SuspendThread)
  • NtResumeProcess
  • NtResumeThread (ResumeThread)
  • NtGetContextThread (GetThreadContext)
  • NtSetContextThread (SetThreadContext)
  • NtClose (CloseHandle)
  • NtReadVirtualMemory (ReadProcessMemory)
  • NtWriteVirtualMemory (WriteProcessMemory)
  • NtAllocateVirtualMemory (VirtualAllocEx)
  • NtProtectVirtualMemory (VirtualProtectEx)
  • NtFreeVirtualMemory (VirtualFreeEx)
  • NtQuerySystemInformation (GetSystemInfo)
  • NtQueryDirectoryFile
  • NtQueryInformationFile
  • NtQueryInformationProcess
  • NtQueryInformationThread
  • NtCreateSection (CreateFileMapping)
  • NtOpenSection
  • NtMapViewOfSection
  • NtUnmapViewOfSection
  • NtAdjustPrivilegesToken (AdjustTokenPrivileges)
  • NtDeviceIoControlFile (DeviceIoControl)
  • NtQueueApcThread (QueueUserAPC)
  • NtWaitForMultipleObjects (WaitForMultipleObjectsEx)

Visual Studio로 가져오기

  1. 생성된 H/C/ASM 파일을 프로젝트 폴더로 복사합니다.
  2. Visual Studio에서 프로젝트 → *빌드 사용자 지정...*으로 이동하여 MASM을 활성화합니다.
  3. 솔루션 탐색기에서 .h 및 .c/.asm 파일을 각각 헤더 및 소스 파일로 프로젝트에 추가합니다.
  4. x86 ASM 파일의 속성으로 이동합니다.
  5. 구성 드롭다운에서 모든 구성을 선택합니다.
  6. 플랫폼 드롭다운에서 Win32를 선택합니다.
  7. 다음 옵션을 설정합니다:
    • 빌드에서 제외 = 아니요
    • 콘텐츠 = 예
    • 항목 형식 = Microsoft 매크로 어셈블러
  8. 적용을 클릭합니다.
  9. 플랫폼 드롭다운에서 x64를 선택합니다.
  10. 다음 옵션을 설정합니다:
    • 빌드에서 제외 = 예
    • 콘텐츠 = 예
    • 항목 형식 = Microsoft 매크로 어셈블러
  11. 적용을 클릭한 후 확인을 클릭합니다.
  12. x64 ASM 파일의 속성으로 이동합니다.
  13. 구성 드롭다운에서 모든 구성을 선택합니다.
  14. 플랫폼 드롭다운에서 Win32를 선택합니다.
  15. 다음 옵션을 설정합니다:
    • 빌드에서 제외 = 예
    • 콘텐츠 = 예
    • 항목 형식 = Microsoft 매크로 어셈블러
  16. 적용을 클릭합니다.
  17. 플랫폼 드롭다운에서 x64를 선택합니다.
  18. 다음 옵션을 설정합니다:
    • 빌드에서 제외 = 아니요
    • 콘텐츠 = 예
    • 항목 형식 = Microsoft 매크로 어셈블러
  19. 적용을 클릭한 후 확인을 클릭합니다.

MinGW 및 NASM으로 컴파일하기

다음 예제는 위 예제 프로그램을 MinGW 및 NASM 어셈블러를 사용하여 EXE 및 DLL로 컴파일하는 방법을 보여줍니다:

x86 예제 EXE

root@kitploit:~
i686-w64-mingw32-gcc -c main.c syscalls.c -Wall -shared
nasm -f win32 -o syscallsstubs.std.x86.o syscallsstubs.std.x86.nasm
i686-w64-mingw32-gcc *.o -o temp.exe
i686-w64-mingw32-strip -s temp.exe -o example.exe
rm -rf *.o temp.exe

x86 예제 DLL (내보내기 포함)

root@kitploit:~
i686-w64-mingw32-gcc -c dllmain.c syscalls.c -Wall -shared
nasm -f win32 -o syscallsstubs.std.x86.o syscallsstubs.std.x86.nasm
i686-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
i686-w64-mingw32-strip -s temp.dll -o example.dll
rm -rf *.o temp.dll

x64 예제 EXE

root@kitploit:~
x86_64-w64-mingw32-gcc -m64 -c main.c syscalls.c -Wall -shared
nasm -f win64 -o syscallsstubs.std.x64.o syscallsstubs.std.x64.nasm
x86_64-w64-mingw32-gcc *.o -o temp.exe
x86_64-w64-mingw32-strip -s temp.exe -o example.exe
rm -rf *.o temp.exe

x64 예제 DLL (내보내기 포함)

root@kitploit:~
x86_64-w64-mingw32-gcc -m64 -c dllmain.c syscalls.c -Wall -shared
nasm -f win64 -o syscallsstubs.std.x64.o syscallsstubs.std.x64.nasm
x86_64-w64-mingw32-gcc-dllwrap --def dllmain.def *.o -o temp.dll
x86_64-w64-mingw32-strip -s temp.dll -o example.dll
rm -rf *.o temp.dll

MinGW 및 GNU 어셈블러(GAS)로 컴파일하기

x86 예제 EXE

root@kitploit:~
i686-w64-mingw32-gcc -m32 -Wall -c main.c syscalls.c syscallsstubs.std.x86.s -o temp.exe
i686-w64-mingw32-strip -s temp.exe -o example.exe

x86 예제 DLL (내보내기 포함)

root@kitploit:~
i686-w64-mingw32-gcc -m32 -Wall -c dllmain.c syscalls.c syscallsstubs.std.x86.s -o temp.dll
i686-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
i686-w64-mingw32-strip -s temp.dll -o example.dll

x64 예제 EXE

root@kitploit:~
x86_64-w64-mingw32-gcc -m64 -Wall -c main.c syscalls.c syscallsstubs.std.x64.s -o temp.exe
x86_64-w64-mingw32-strip -s temp.exe -o example.exe

x64 예제 DLL (내보내기 포함)

root@kitploit:~
x86_64-w64-mingw32-gcc -m64 -Wall -c dllmain.c syscalls.c syscallsstubs.std.x64.s -o temp.dll
x86_64-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
x86_64-w64-mingw32-strip -s temp.dll -o example.dll

LLVM/Clang 사용하기

SysWhispers2는 ASM 스텁을 포함하는 clang 호환 .s 파일을 출력합니다. 이를 LLVM과 함께 사용하여 코드를 컴파일할 수 있습니다. 예를 들어, 위의 CreateRemoteThread DLL 인젝션 예제를 사용하면:

root@kitploit:~
clang -D nullptr=NULL main.c syscall.c syscallstubs.std.x64.s -o test.exe

인라인 헤더 전용

inlinegas 출력 옵션은 SysWhispers2의 헤더 전용 버전을 생성하며, BOF 컴파일과 함께 사용할 수 있습니다. 프로젝트에 헤더를 포함시키기만 하면 됩니다.

랜덤 시스템 호출 점프

랜덤 시스템 호출 점프 루틴을 사용하면 "시스템 호출 표식"을 피할 수 있습니다. 어셈블리 스텁은 새로운 함수 SW__GetRandomSyscallAddress를 호출하며, 이 함수는 ntdll.dll에서 깨끗한 시스템 호출 명령어를 검색하고 선택합니다. 이렇게 하면 사용자랜드 시스템 호출 명령어의 트리거를 피할 수 있습니다.

랜덤 시스템 호출 점프를 사용하려면 프로그램을 컴파일할 때 RANDSYSCALL을 정의하고 SysWhispers2 출력의 rnd 버전을 사용해야 합니다. 다음 예제는 GNU 어셈블러 스텁을 사용하는 방법을 보여줍니다.

x86 예제 EXE - 랜덤 시스템 호출 점프 사용

root@kitploit:~
i686-w64-mingw32-gcc main.c syscalls.c syscallsstubs.rnd.x86.s -DRANDSYSCALL -Wall -o example.exe

x64 예제 EXE - 랜덤 시스템 호출 점프 사용

root@kitploit:~
x86_64-w64-mingw32-gcc main.c syscalls.c syscallsstubs.rnd.x64.s -DRANDSYSCALL -Wall -o example.exe

주의사항 및 제한사항

  • 그래픽 하위 시스템(win32k.sys)의 시스템 호출은 지원되지 않습니다.
  • Visual Studio 2019 (v142) 및 Windows 10 SDK에서 테스트되었습니다.

문제 해결

  • 형식 재정의 오류: syscalls.h의 typedef가 이미 정의된 경우 프로젝트가 컴파일되지 않을 수 있습니다.
    • 필요한 함수만 포함되도록 하십시오(즉, --preset all은 거의 필요하지 않습니다).
    • 다른 사용된 헤더에 typedef가 이미 정의된 경우 syscalls.h에서 제거할 수 있습니다.

크레딧

@Jackson_T와 @modexpblog가 개발했지만, 다른 많은 사람들의 작업을 기반으로 합니다:

  • @FoxHex0ne: 기계가 읽을 수 있는 형식으로 많은 함수 프로토타입과 typedef를 카탈로그화했습니다.
  • @PetrBenes, NTInternals.net 팀 및 MSDN: 추가 프로토타입 및 typedef 제공.
  • @Cn33liz: 초기 Dumpert POC 구현.

관련 기사 및 프로젝트

  • @modexpblog: Bypassing User-Mode Hooks and Direct Invocation of System Calls for Red Teams
  • @hodg87: Malware Mitigation when Direct System Calls are Used
  • @Cn33liz: Combining Direct System Calls and sRDI to bypass AV/EDR (Code)
  • @0x00dtm: Userland API Monitoring and Code Injection Detection
  • @0x00dtm: Defeating Userland Hooks (ft. Bitdefender) (Code)
  • @mrgretzky: Defeating Antivirus Real-time Protection From The Inside
  • @SpecialHoang: Bypass EDR’s memory protection, introduction to hooking (Code)
  • @xpn and @domchell: Silencing Cylance: A Case Study in Modern EDRs
  • @mrjefftang: Universal Unhooking: Blinding Security Software ()

SysWhispers 참조

  • @JFaust_: Process Injection Part 1, Part 2, and Alaris loader project (Code)
  • @0xPat: Malware Development Part 2
  • @brsn76945860: Implementing Syscalls In The CobaltStrike Artifact Kit
  • @Cn33liz and @_DaWouw: Direct Syscalls in Beacon Object Files (Code)

라이선스

이 프로젝트는 Apache License 2.0에 따라 라이선스가 부여됩니다.

도구 다운로드
Code
  • @spotheplanet: Full DLL Unhooking with C++
  • @hasherezade: Floki Bot and the stealthy dropper
  • @hodg87: Latest Trickbot Variant has New Tricks Up Its Sleeve