22 August 2025

in this blog we will explores the concept of indirect system calls in windows,a technique used to bypass security measures and potentially evade detection by security software. It delves into the mechanisms behind system calls, the motivations for using indirect approaches, common methods employed, and the implications for system security.
system call or syscall is mechanism that allows user-mode applications to request services from the kernel-mode of the operating system. that because user-mode can not directly access privileged memory or hardware, so they invoke syscall to do the following
SN (System Service Number) is a unique ID that Windows assigns to each system call (Nt* function).
When a syscall is executed, the CPU doesn’t know which kernel function to run just from the syscall instruction, it reads the SSN from the EAX register.
The Windows kernel then uses this SSN as an index into the System Service Dispatch Table (SSDT) to find and run the correct function.
These numbers are not fixed they can and do change between different Windows versions and builds.
A syscall stub is a small function, usually located inside ntdll.dll, that prepares CPU registers and executes the syscall instruction. It acts as a wrapper for the transition from user mode to kernel mode in other words, it handles the setup needed before the CPU can perform the system call.

Typically, an application begins by calling a high‑level Win32 API, such as VirtualAlloc, which is provided by libraries like kernel32.dll. These high‑level APIs are designed to be developer‑friendly and handle common tasks, but under the hood, they delegate work to lower‑level native APIs in ntdll.dll.
For example, VirtualAlloc calls the native function NtAllocateVirtualMemory inside ntdll.dll. This native API contains a syscall stub.a very small piece of assembly code that prepares the required registers for the call, loads the System Service Number (SSN) into EAX, and executes the syscall instruction.
The syscall instruction is the critical point where execution transitions from user mode (ring 3) to kernel mode (ring 0). Once in kernel mode, the Windows kernel uses the SSN to look up the correct function in the System Service Dispatch Table (SSDT) and executes the corresponding kernel routine. When the kernel finishes its work, it returns execution back to user mode, and the result is passed back through ntdll.dll to the original high‑level API, which then returns it to the application.
Indirect Syscalls are a technique used to execute Windows system calls without calling them directly through the usual API functions. Normally, when a program calls a function like NtAllocateVirtualMemory, it goes through ntdll.dll’s syscall stub. Security tools such as EDRs often hook these functions in ntdll.dll to monitor or block suspicious behavior. With indirect syscalls, instead of calling the stub directly, the program finds its location in memory and jumps into it after the hook, or uses a copied version of the stub elsewhere. This way, the syscall instruction is still executed, but in a way that bypasses the API hooks, making it harder for security tools to detect or intercept the call.

simply it work like this in code:
let's do example when we use indirect system call to execute shell-code in memory, we will have two files one for assembly instructions, and the second for c++, let's see each file.
we will need to define the gables variables to be able to use them in assembly file. and the functions signatures
Now we need to extract information from memory, such as the SSN and the syscall address. The goal is to make it appear as though the call is coming from ntdll.dll, while actually bypassing any hooks. This way, if an EDR inspects the request, it will appear to have originated from ntdll.dll, and the returned address will also point back to ntdll.dll. Trust me everything will become clear as we go, just follow along.
now we need to get our shellcode to execute we can hardcode the shellcode, but to avide detetion more we will send HTTPS request to download the shellcode using this function, just read the comments.
now let's put all that together in the main function.
At the top of the assembly file, these EXTERN declarations tell the assembler that the listed variables are defined elsewhere in the program (in the C++ code) and will be linked in later.
remember the syscall stub? we are doing the exact same here:
do the same for the other functions
First, we need to generate the shellcode. We’ll use msfvenom for this. Run the following command, replacing the IP address with your own:
This will create a raw 64‑bit reverse TCP Meterpreter payload and save it to reverse64-192168242128-443.bin.Keep in mind that this payload will be detected by most firewalls and EDR solutions because its signature is well known. It’s possible to modify and obfuscate it to avoid detection, but that’s a separate topic.
the second step is to run the listener using the following commands
After that, we need to start an HTTPS server. This step is optional — you could simply hardcode the shellcode directly into the C++ code. However, for better obfuscation and to make the process less obvious, we’ll serve the shellcode from an HTTPS server instead. this’s a simple Python script to run an HTTPS server. You’ll need to replace the certificate and key files with your own:
after setting all this, Get the code from github, and this run it like this

let's see the attacker box

Simply because EDRs check for two key indicators:
Indirect syscalls solve both issues. They ensure both the syscall instruction and the return path stay within ntdll.dll memory. This mimics legitimate Windows behavior and avoids raising alarms with most EDRs.
In simple terms, we can make this technique even stealthier by:
By combining these, our calls look like normal ntdll.dll calls, with no suspicious imports, no hardcoded IDs, and no return addresses outside ntdll.dll, making it much harder for EDRs to detect.