Bypassing Windows API hooking with syscalls
by Marcelo Benesciutti
Recently I started to do some researches on AV/EDR bypass and Windows internals (shoutout to my friend Thiago Peixoto on this part, who have helped me alot). On my studies I have stumbled on a very common detection method employed by most AV/EDR solutions, Windows API hooking. Basically, the solutions hook common functions used on malicious code, such as OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread, among others, and if an unknown PE makes use of these functions, it will be potentially flagged as malicious. A downside to this detection method is that these hooks are set at the user level of the OS, so if we manage to not use any functions or libraries at the user level, using only kernel level instructions, or system calls, we should be able to evade this detection method, such as described by Cn33liz on this blogpost.
In my study case, Windows Defender was flagging my PE as malicious because I went through the list of processes running, copied the PID of notepad.exe and used it to open the process, in order to inject shellcode on it by loading a malicious dll. In order to evade detection, I implemented a function to make a direct syscall targeting the ZwOpenProcess function on the kernel (syscall 26 on Windows 10). In the video, the API monitor will flag the usage of OpenProcess and NtOpenProcess on 1st execution of the PE, since I was using the kernel32.dll OpenProcess function. This was the PE version being flagged by Windows Defender. At the 2nd run, the ZwOpenProcess function I am calling is passing the arguments directly to the syscall, not making use of kernel32 OpenProcess or ntdll NtOpenProcess, effectively escaping the userland API hooking in progress and evading Windows Defender.