% ..%%%%%# %/.
/%%%%%,.%%%%%%%%%%%%%%%%%%%%%%%%%%%%.%%%%%%
. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%%*.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ,%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
#%%%%%%%%%%%%%%. %%%%%%%%%%%%%%%%
%%%%%%%( %%%%%%%%%
& %%# .%% ..
&&. . . #&
&&&&. . %&&&&&&&&. &&&&
&&&&&&&.. . . (&&&&&&&&&&&&&&&&&%. . .&&&&&&&
.%&&&&&&&&&&&&&&&&&&&&& ____ &&&&&&&&&&&&&&&&&&&&&
#&&&&&&&&&&&&&&&&&&& |___ \ &&&&&&&&&&&&&&&&&&&
,&&&&&&&&&&&&&&&&& __) | &&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&& |__ < &&&&&&&&&&&&&&
&&&&&&&&&& ___) | &&&&&&&&&&
%&& |____/ &&.
NimlineWhispers3
Editor: @klezVirus 2022
Original: @ajpc500 2021
As with the original NimlineWhispers2
, this project parses the SysWhispers
header file output to include function
return types and arguments in the outputted inline assembly. Everything is then output into a single Nim file including
an emit
block with the SysWhispers3 methods, plus the defined functions.
NOTE: NimlineWhispers 1 can be found here. NOTE: NimlineWhispers 2 can be found here.
- Clone this repository including the SysWhispers3 sub module.
git clone --recurse-submodules https://github.com/klezVirus/NimlineWhispers3.git
- Update which functions you required in
functions.txt
. - Run
python3 NimlineWhispers3.py
(additional flags listed below) to generate the inline assembly (syscalls.nim
) file - example in the repo. - Add
include syscalls
to your Nim project.
An example of integrating NimlineWhispers[2-3] output with your project can be seen in this repo.
To evade detection based on the presence of function names in our Nim executables (as outlined in @ShitSecure's blog here), NimlineWhispers2 can be run with a --randomise
flag, as follows:
python3 .\NimlineWhispers2.py --randomise --nobanner
[i] Function filter file "functions.txt" contains 6 functions.
[i] Using SysWhispers2 to generate asm stubs...
Complete! Files written to:
nimlinewhispers.h
nimlinewhispers.c
nimlinewhispersstubs.asm
[i] Found return types for 6 functions.
[i] Producing randomised function mapping...
NtResumeThread -> vWhUCQWffAEdMboE
NtAllocateVirtualMemory -> SIitcDuyPGMirHPr
NtClose -> uWZzTmdnlNmvteiL
NtCreateThreadEx -> PDoWbNOwYbDDAcmW
NtOpenProcess -> vWfwKlChxKZOutiX
NtWriteVirtualMemory -> wItyVDPJWcFUqTNK
[+] Success! Outputted to syscalls.nim
For ease of integration, the mapping shown in the command-line is added as a comment in the outputted syscalls.nim
file (just above the functions and below the SW2 methods). As below (including the first function to demonstrate the output):
...
# NtResumeThread -> vWhUCQWffAEdMboE
# NtAllocateVirtualMemory -> SIitcDuyPGMirHPr
# NtClose -> uWZzTmdnlNmvteiL
# NtCreateThreadEx -> PDoWbNOwYbDDAcmW
# NtOpenProcess -> vWfwKlChxKZOutiX
# NtWriteVirtualMemory -> wItyVDPJWcFUqTNK
proc vWhUCQWffAEdMboE*(ThreadHandle: HANDLE, PreviousSuspendCount: PULONG): NTSTATUS {.asmNoStackFrame.} =
asm """
mov [rsp +8], rcx
...
Notably your function definitions such as the below will need to be updated with the randomised names too.
EXTERN_C NTSTATUS NtOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId OPTIONAL);
Should become:
EXTERN_C NTSTATUS sjGfpzWwEqIMryMW(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId OPTIONAL);
syscalls_rand.nim
is included as an example output of this randomisation function.
To modify the behaviour of SysWhispers3, pass the arguments to the subparser sw
in NimlineWhispers3:
usage: NimlineWhispers3.py sw [-h] [-a {x86,x64,all}] [-c {msvc,mingw,all}] [-m {embedded,egg_hunter,jumper,jumper_randomized}] [--int2eh] [--wow64] [-v] [--sw-debug]
optional arguments:
-h, --help show this help message and exit
-a {x86,x64,all}, --arch {x86,x64,all}
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
--int2eh Use the old `int 2eh` instruction in place of `syscall`
--wow64 Add support for WoW64, to run x86 on x64
-v, --verbose Enable debug output
--sw-debug Enable syscall debug (insert software breakpoint)
So, to use the "jumper" method, as an example, just use the following command line:
python NimlineWhispers3.py sw -m jumper
- Egg insertion is not yet fully supported (issue with bytes definition)
- 32-bits is not yet tested, and may cause issues
- apjc500 for NimlineWhispers2 which practically already implemented all the logic of this tool.
- Cas van Cooten and yamakadi for posing and then answering how SW2 output could be used in Nim projects, which I've simply codified😁
- This tool uses SysWhispers3 to generate syscall stubs which are then processed for Nim.
- SysWhispers3 is based on SysWhispers2, so huge props to @Jackson_T for
SysWhispers2
. - FalconForce's SysWhispers2BOF from which I borrowed several helper functions.
- All people credited for SysWhispers and SysWhispers2
- @Outflank and @_DaWouw for InlineWhispers
- @byt3bl33d3r for his incredibly informative OffensiveNim repository
- S3cur3Th1sSh1t for giving me a reason to work on this project.