mirror of
https://github.com/tdeerenberg/InlineWhispers3.git
synced 2025-07-17 00:44:17 +00:00
253 lines
9.4 KiB
Markdown
253 lines
9.4 KiB
Markdown
# SysWhispers3
|
|
|
|
SysWhispers helps with evasion by generating header/ASM files implants can use to make direct system calls.
|
|
|
|
## Official Discord Channel
|
|
|
|
Come hang out on Discord!
|
|
|
|
[](https://discord.gg/f6w6dwZq)
|
|
|
|
### Why on earth didn't I create a PR to SysWhispers2?
|
|
|
|
The reason for SysWhispers3 to be a standalone version are many, but the most important are:
|
|
|
|
* SysWhispers3 is the de-facto "fork" used by [Inceptor][1], and implements some utils class which are not relevant to the
|
|
original version of the tool.
|
|
* SysWhispers2 is moving towards supporting NASM compilation (for gcc/mingw), while this version is specifically designed and
|
|
tested to support MSVC (because [Inceptor][1] will stay a Windows-only framework for the near future).
|
|
* SysWhispers3 contains partially implemented features (such as egg-hunting) which would not be sensible to include
|
|
in the original version of the tool.
|
|
|
|
## Differences with SysWhispers2
|
|
|
|
The usage is pretty similar to [SysWhispers2](https://github.com/jthuraisamy/SysWhispers2), with the following exceptions:
|
|
|
|
* It also supports x86/WoW64
|
|
* It supports syscalls instruction replacement with an EGG (to be dynamically replaced)
|
|
* It supports direct jumps to syscalls in x86/x64 mode (in WOW64 it's almost standard)
|
|
* It supports direct jumps to random syscalls (borrowing [@ElephantSeal's idea](https://twitter.com/ElephantSe4l/status/1488464546746540042))
|
|
|
|
A better explanation of these features are better outlined i the blog post [SysWhispers is dead, long live SysWhispers!][2]
|
|
|
|
## Introduction
|
|
|
|
Security products, such as AVs and EDRs, usually place hooks in user-mode API functions to analyse a program execution
|
|
flow, in order to detect potentially malicious activities.
|
|
|
|
SysWhispers2 is a tool designed to generate header/ASM pairs for any system call in the core kernel image
|
|
(`ntoskrnl.exe`), which can then be integrated and called directly from C/C++ code, evading user-lands hooks.
|
|
|
|
The tool, however, generates some patters which can be included in signatures, or behaviour which can be detected
|
|
at runtime.
|
|
|
|
SysWhispers3 is built on top of SysWhispers2, and integrates some helpful features to bypass these forms of detection.
|
|
|
|
## Installation
|
|
|
|
```
|
|
C:\> git clone https://github.com/klezVirus/SysWhispers3.git
|
|
C:\> cd SysWhispers3
|
|
C:\> python .\syswhispers.py --help
|
|
```
|
|
|
|
## Usage and Examples
|
|
|
|
The help shows all the available commands and features of the tool:
|
|
|
|
```
|
|
C:\>python syswhispers.py -h
|
|
|
|
usage: syswhispers.py [-h] [-p PRESET] [-a {x86,x64}] [-m {embedded,egg_hunter,jumper,jumper_randomized}] [-f FUNCTIONS] -o OUT_FILE [--int2eh] [--wow64] [-v] [-d]
|
|
|
|
SysWhispers3 - SysWhispers on steroids
|
|
|
|
optional arguments:
|
|
-h, --help show this help message and exit
|
|
-p PRESET, --preset PRESET
|
|
Preset ("all", "common")
|
|
-a {x86,x64}, --arch {x86,x64}
|
|
Architecture
|
|
-c {msvc,mingw,all}, --compiler {msvc,mingw,all}
|
|
Compiler
|
|
-m {embedded,egg_hunter,jumper,jumper_randomized}, --method {embedded,egg_hunter,jumper,jumper_randomized}
|
|
Syscall recovery method
|
|
-f FUNCTIONS, --functions FUNCTIONS
|
|
Comma-separated functions
|
|
-o OUT_FILE, --out-file OUT_FILE
|
|
Output basename (w/o extension)
|
|
--int2eh Use the old `int 2eh` instruction in place of `syscall`
|
|
--wow64 Use Wow64 to run x86 on x64 (only usable with x86 architecture)
|
|
-v, --verbose Enable debug output
|
|
-d, --debug Enable syscall debug (insert software breakpoint)
|
|
```
|
|
|
|
### Command Lines
|
|
|
|
#### Standard SysWhispers, embedded system calls (x64)
|
|
|
|
```powershell
|
|
# 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
|
|
```
|
|
|
|
#### SysWhispers3-only samples
|
|
|
|
```powershell
|
|
# Normal SysWhispers, 32-bits mode
|
|
py .\syswhispers.py --preset all -o syscalls_all -m jumper --arch x86
|
|
|
|
# Normal SysWhispers, using WOW64 in 32-bits mode (only specific functions)
|
|
py .\syswhispers.py --functions NtProtectVirtualMemory,NtWriteVirtualMemory -o syscalls_mem --arch x86 --wow64
|
|
|
|
# Egg-Hunting SysWhispers, to bypass the "mark of the sycall" (common function)
|
|
py .\syswhispers.py --preset common -o syscalls_common -m egg_hunter
|
|
|
|
# Jumping/Jumping Randomized SysWhispers, to bypass dynamic RIP validation (all functions) using MinGW as the compiler
|
|
py .\syswhispers.py --preset all -o syscalls_all -m jumper -c mingw
|
|
|
|
|
|
```
|
|
|
|
### Script Output
|
|
|
|
```
|
|
PS C:\Projects\SysWhispers2> py .\syswhispers.py --preset common --out-file temp\syscalls_common -v
|
|
|
|
. ,--.
|
|
,-. . . ,-. . , , |-. o ,-. ,-. ,-. ,-. ,-. __/
|
|
`-. | | `-. |/|/ | | | `-. | | |-' | `-. . \
|
|
`-' `-| `-' ' ' ' ' ' `-' |-' `-' ' `-' '''
|
|
/| | @Jackson_T
|
|
`-' ' @modexpblog, 2021
|
|
|
|
Edits by @klezVirus, 2022
|
|
SysWhispers3: Why call the kernel when you can whisper?
|
|
|
|
|
|
Common functions selected.
|
|
|
|
Complete! Files written to:
|
|
temp\syscalls_common.h
|
|
temp\syscalls_common.c
|
|
temp\syscalls_common_.asm
|
|
Press a key to continue...
|
|
|
|
```
|
|
|
|
## Importing into Visual Studio
|
|
|
|
1. Copy the generated H/C/ASM files into the project folder.
|
|
2. In Visual Studio, go to *Project* → *Build Customizations...* and enable MASM.
|
|
3. In the *Solution Explorer*, add the .h and .c/.asm files to the project as header and source files, respectively.
|
|
4. Go to the properties of the ASM file, and set the *Item Type* to *Microsoft Macro Assembler*.
|
|
|
|
## Compiling outside of Visual Studio
|
|
|
|
### Windows
|
|
|
|
Makefile for 64 bits:
|
|
|
|
`Makefile.msvc`
|
|
```
|
|
OPTIONS = -Zp8 -c -nologo -Gy -Os -O1 -GR- -EHa -Oi -GS-
|
|
LIBS = libvcruntime.lib libcmt.lib ucrt.lib kernel32.lib
|
|
|
|
program:
|
|
ML64 /c syscalls-asm.x64.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64
|
|
cl.exe $(OPTIONS) syscalls.c program.c
|
|
link.exe /OUT:program.x64.exe -nologo $(LIBS) /MACHINE:X64 -subsystem:console -nodefaultlib syscalls-asm.x64.obj syscalls.obj program.obj
|
|
```
|
|
|
|
Makefile for 32 bits:
|
|
|
|
`Makefile.msvc`
|
|
```
|
|
OPTIONS = -Zp8 -c -nologo -Gy -Os -O1 -GR- -EHa -Oi -GS-
|
|
LIBS = libvcruntime.lib libcmt.lib ucrt.lib kernel32.lib
|
|
|
|
program:
|
|
ML /c syscalls-asm.x86.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X86
|
|
cl.exe $(OPTIONS) syscalls.c program.c
|
|
link.exe /OUT:program.x86.exe -nologo $(LIBS) /MACHINE:X86 -subsystem:console -nodefaultlib syscalls-asm.x86.obj syscalls.obj program.obj
|
|
```
|
|
|
|
Compile with nmake:
|
|
```
|
|
nmake -f Makefile.msvc
|
|
```
|
|
|
|
### Linux
|
|
|
|
Makefile for both 64 and 32 bits:
|
|
|
|
`Makefile.mingw`
|
|
```
|
|
CC_x64 := x86_64-w64-mingw32-gcc
|
|
CC_x86 := i686-w64-mingw32-gcc
|
|
OPTIONS := -masm=intel -Wall
|
|
|
|
program:
|
|
$(CC_x64) syscalls.c program.c -o program.x64.exe $(OPTIONS)
|
|
$(CC_x86) syscalls.c program.c -o program.x86.exe $(OPTIONS)
|
|
```
|
|
|
|
Compile with make:
|
|
```
|
|
make -f Makefile.mingw
|
|
```
|
|
|
|
## Caveats and Limitations
|
|
|
|
- The Egg-Hunter functionality is not implemented within this tool, it is in [Inceptor][1].
|
|
- System calls from the graphical subsystem (`win32k.sys`) are not supported.
|
|
- Tested on Visual Studio 2019/2022 with Windows 10 SDK.
|
|
- Support for NASM is not guaranteed.
|
|
- Support for GCC and MinGW is not guaranteed.
|
|
|
|
## Troubleshooting
|
|
|
|
#### From SysWhispers2
|
|
- Type redefinitions errors: a project may not compile if typedefs in `syscalls.h` have already been defined.
|
|
- Ensure that only required functions are included (i.e. `--preset all` is rarely necessary).
|
|
- If a typedef is already defined in another used header, then it could be removed from `syscalls.h`.
|
|
|
|
#### New
|
|
- With `--verbose`, it is possible to enable troubleshooting output during code generation.
|
|
- With `--debug`, the tool will insert a software breakpoint in the syscall stub, to ease the debugging in WinDbg.
|
|
- If you get a `error A2084:constant value too large` during compilation, regenerates the stubs.
|
|
|
|
## Credits
|
|
|
|
#### SysWhispers2
|
|
|
|
Developed by [@Jackson_T](https://twitter.com/Jackson_T) and [@modexpblog](https://twitter.com/modexpblog),
|
|
but builds upon the work of many others:
|
|
|
|
- [@FoxHex0ne](https://twitter.com/FoxHex0ne) for cataloguing many function prototypes and typedefs in a machine-readable format.
|
|
- [@PetrBenes](https://twitter.com/PetrBenes), [NTInternals.net team](https://undocumented.ntinternals.net/), and [MSDN](https://docs.microsoft.com/en-us/windows/) for additional prototypes and typedefs.
|
|
- [@Cn33liz](https://twitter.com/Cneelis) for the initial [Dumpert](https://github.com/outflanknl/Dumpert) POC implementation.
|
|
|
|
#### SysWhispers2 (x86/WOW64)
|
|
|
|
- [@rooster](https://github.com/mai1zhi2) for creating a sample x86/WOW64 compatible fork.
|
|
|
|
#### Others
|
|
|
|
- [@ElephantSe4l](https://mobile.twitter.com/elephantse4l) for the idea about randomizing the jumps to the syscalls.
|
|
- [@S4ntiagoP](https://twitter.com/s4ntiago_p) for the incredible work on [nanodump](https://github.com/helpsystems/nanodump), which gave me tons of ideas.
|
|
|
|
## Licence
|
|
|
|
As the original, this project is also licensed under the Apache License 2.0.
|
|
|
|
|
|
[1]: https://github.com/klezVirus/inceptor
|
|
[2]: https://klezvirus.github.io/RedTeaming/AV_Evasion/NoSysWhisper/
|