Skip to content

06: Chapter 3 | Concept of Direct Syscalls

VirtualAllocEx edited this page Aug 4, 2023 · 11 revisions

What is a Direct System Call?

This is a technique that allows an attacker (red team) to execute malicious code, e.g. shell code, in such a way that the system call or syscall stub is not obtained via ntdll.dll, but is implemented directly as an assembly instruction, e.g. in the .text region of the malware or shellcode loader. Hence the name direct system calls. There are now several tools and POCs such as SysWhispers, SysWhispers2, SysWhispers3, Hell's Gate, Halo's Gate etc. that can be used to implement or exploit the capabilities of direct system calls in your own malware.

But in this course we will deliberately not use them, because we want to do as much as possible ourselves, keep all the C and assembler code used as simple as possible, and I will concentrate on teaching you the concept of direct and indirect syscalls in a proper way. The code examples provided definitely do not use the most stealthy code, but I found it the best way to teach the concept of direct and indirect sycalls in the best and most practical way. All the POCs needed for this course can be found on the main page of this repository as a Visual Studio project.

Compared to the previous illustration in the system calls chapter, the following illustration shows the principle of direct system calls on Windows in a simplified way. You can see that the user mode process malware.exe does not get the system call, or more precisely the instructions from the sycall stub, from the native API NtCreateFile via ntdll.dll, as would normally be the case, but instead has implemented the necessary instructions for the system call itself.

01

Why Direct System Calls?

Both Antivirus (AV) and Endpoint Detection and Response (EDR) products rely on different defence mechanisms to protect against malware. To dynamically inspect potentially malicious code in the context of Windows APIs at runtime, most EDRs today implement the principle of user-mode API hooking. Put simply, this is a technique whereby code executed in the context of a Windows API, such as VirtualAlloc or its native API NtAllocateVirtualMemory, is deliberately redirected by the EDR into the EDR's own hooking.dll. Under Windows, the following types of hooking can be distinguished, among others:

  • Inline API Hooking
  • Import Address Table (IAT) Hooking
  • SSDT Hooking (Windows Kernel)

Before the introduction of Kernel Patch Protection (KPP) aka Patch Guard, it was possible for Antivirus products to implement their hooks in the Windows kernel, e.g. using SSDT hooking. With Patch Guard, this was prevented by Microsoft for reasons of operating system stability. Most of the EDRs I have analysed rely primarily on inline API hooking. Technically, an inline hook is a 5-byte assembly instruction (also called a jump or trampoline) that causes a redirection to the EDR's hooking.dll before the system call is executed in the context of the respective native API. The return from the memory of the EDR's hooking.dll back to the memory of the respective native function in ntdll.dll for the final execution of the syscall instruction only occurs if the code executed in the context of the function was determined by the EDR to be harmless, otherwise the execution of the corresponding system call is prevented by the Endpoint Protection (EPP) component of an EPP/EDR combination. The following diagram provides a simplified illustration of how user-mode API hooking works with EDR.

image

02

Important note! Because ntdll.dll is a common denominator in user space before the transition to kernel mode, many EDRs set their user mode hooks in ntdll.dll, especially in the early days of EDRs. But depending on the EDR, they also set their hooks in other important DLLs in user space. Based on my research by analysing different EDRs, here are some examples where they set their user mode hooks in different DLLs in user space.

DLL Name Examples of hooked APIs
ntdll.dll NtAllocateVirtualMemory
user32.dll SetWinEventHook
win32u.dll NtUserShowWindow
kernel32.dll CreateRemoteThread
kernelbase.dll CreateRemoteThreadEx
combase.dll CoGetInstanceFromIStorage
crypt32.dll CryptUnprotectData
ole32.dll CoGetObject
samcli.dll NetUserAdd
shell32.dll Shell_NotifyIconW
advapi32.dll ClearEventLogA
sechost.dll StartServiceW
wevtapi.dll EvtOpenSession
wininet.dll InternetConnectA

The total number of hooks varies from vendor to vendor or from EDR to EDR. There are EDRs that have around 20 hooks and their other EDRs that have around 90 hooks. It is also important to note that an EDR will never be able to hook all APIs, otherwise the performance impact would be dramatic. Never forget that a good EDR will try to protect as much as possible, but also stay in the background as much as possible and not slow down a system too much.

Consequences for the Red Team

From the Red Team's perspective, the user-mode hooking technique results in EDR making it more difficult for malware to execute code, such as shellcode. For this reason, Red Teamer as well as malicious attackers use various techniques to bypass EDR usermode hooks. Among others, the following techniques are used individually, but also in combination, e.g. API Unhooking and Direct System Calls.

  • Use no hooked APIs
  • User mode unhooking
  • Indirect syscalls
  • Direct syscalls

In this workshop we will focus on the direct syscall and indirect syscall technique, i.e. we will create a direct syscall and an indirect syscall shellcode loader step by step. The basics of direct syscalls and user mode hooks should now be clear, and the journey towards developing our own indirect syscall loader can begin.

Summary: Direct Syscalls

  • Direct syscalls were a logical consequence of the EPPs/EDRs starting to implement various forms of user mode API hooking.
  • Hooking simply means that the EDR injects its own DLL into the user space address space of each process.
  • Hooking allows EDRs to analyse executed code in the context of APIs at runtime.
  • Most EDRs use the technique of inline API hooking by replacing mov eax, SSN with an unconditional jump instruction jmp.
  • Which DLLs are hooked and how many functions in those DLLs are hooked depends heavily on the EDR.
  • There are also EDRs like Windows Defender ATP that do not use any user mode hooks.
  • To execute system calls directly, we need to implement the necessary code (syscall stub) directly into the shellcode loader or malware.
  • The structure of the syscall stub implemented directly into our malware is always the same, only the SSN is unique and differs from function to function.