In the current digital security ecosystem, where threats evolve rapidly and with complexity, companies developing Endpoint Detection and Response (EDR) solutions are in constant search for innovations that not only keep up but also anticipate emerging attack vectors. In this context, this article introduces the HookChain, a look from another perspective at widely known techniques, which when combined, provide an additional layer of sophisticated evasion against traditional EDR systems. Through a precise combination of IAT Hooking techniques, dynamic SSN resolution, and indirect system calls, HookChain redirects the execution flow of Windows subsystems in a way that remains invisible to the vigilant eyes of EDRs that only act on Ntdll.dIl, without requiring changes to the source code of the applications and malwares involved. This work not only challenges current conventions in cybersecurity but also sheds light on a promising path for future protection strategies, leveraging the understanding that continuous evolution is key to the effectiveness of digital security. By developing and exploring the HookChain technique, this study significantly contributes to the body of knowledge in endpoint security, stimulating the development of more robust and adaptive solutions that can effectively address the everchanging dynamics of digital threats. This work aspires to inspire deep reflection and advancement in the research and development of security technologies that are always several steps ahead of adversaries.
在当前的数字安全生态系统中，威胁发展迅速而复杂，开发端点检测和响应（EDR）解决方案的公司一直在寻求创新，不仅要跟上时代的步伐，还要预测新出现的攻击载体。在此背景下，本文将介绍 HookChain（钩链），从另一个角度审视广为人知的技术，将这些技术结合起来，就能为传统 EDR 系统提供额外一层复杂的规避手段。通过将 IAT 挂钩技术、动态 SSN 解析和间接系统调用精确结合，HookChain 可以重定向 Windows 子系统的执行流，使只对 Ntdll.dIl 采取行动的 EDR 无法察觉，而无需更改相关应用程序和恶意软件的源代码。这项工作不仅挑战了网络安全领域的现有惯例，还为未来的保护策略指明了一条大有可为的道路，因为人们认识到，持续演进是数字安全有效性的关键所在。通过开发和探索 HookChain 技术，本研究为端点安全领域的知识体系做出了重大贡献，促进了更稳健、适应性更强的解决方案的开发，从而有效应对瞬息万变的数字威胁。这项工作旨在激发人们深入思考，推动安全技术的研究和开发，使其始终领先对手数步。
0:002> u ntdll!NtReadFile
ntdll!NtReadFile:
00007ffe`b258d090 4c8bd1
mov r10,rcx
00007ffe`b258d093 b806000000
mov eax,6
00007ffe`b258d0a2 0f05
syscall
00007ffe`b258d0a4 c3
ret
lkd> uf nt!ZwReadFile
nt!ZwReadFile:
fffff806`0e7f9e00 488bc4 mov rax,rsp
fffff806`0e7f9e03 fa
fffff806`0e7f9e04 4883ec10
cli
sub rsp,10h
fffff806`0e7f9e08 50 push rax
fffff806`0e7f9e09 9c pushfq
fffff806`0e7f9e0a 6a10
push
lea
push
fffff806`0e7f9e13 50
mov
jmp
10h
rax,[nt!KiServiceLinkage (fffff806`0e802640)]
rax
eax,6
fffff806`0e7f9e14 b806000000
fffff806`0e7f9e19 e9e2710100
nt!KiServiceInternal (fffff806`0e811000)
0:002> lm
start end
00007ff7`3ddf0000 00007ff7`3de28000
module name
notepad
. . .
0:002> !dh 00007ff7`3ddf0000 f
File Type: EXECUTABLE IMAGE
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g10.jpg?height=455&width=1186&top_left_y=2297&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g11.jpg?height=546&width=1717&top_left_y=144&top_left_x=175)
In the output above, we can observe the IAT listing of the notepad.exe process, as well as in the output below it is observed that at the indicated address is indeed the code of the mapped function.
b1b8b1d0 KERNEL32!GetProcAddressStub: 00007ffe
b1b8b1d0 4c8b0424 mov r8,qword ptr [rsp]b1b8b1d0 KERNEL32!GetProcAddressStub：00007ffeb1b8b1d0 4c8b0424 mov r8,qword ptr [rsp].
b1b8b1d4 48ff25a5580600 jmp qword ptr [KERNEL32!_imp_GetProcAddressForCaller (00007ffe
b1bf0a80)]b1b8b1d4 48ff25a5580600 jmp qword ptr [KERNEL32!_imp_GetProcAddressForCaller (00007ffe
b1bf0a80)] 。b1b8b1db cc int 00007ffe
b1b8b1dc cc int 3
Figure 6 illustrates the entire import scheme that was detailed.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g11.jpg?height=675&width=1469&top_left_y=1484&top_left_x=296)
Figure 6: PE Import Schema
\subsection*{2.3. Function Hook}
Function interception (Hook) is not something new and has various applications such as application debugging (as implemented by the API Monitor software [7]) but also in the monitoring process by defense layers (EDR).
The general idea behind function interception is to insert into the control
flow of the application being monitored. The monitoring agent takes control of the monitored function before the original code is executed, after the desired analysis (which can be logging, telemetry, control among others) the flow of execution is transferred to the original function. [8, p. 687]
To carry out this process, there are several approaches available, in this article we will discuss the most used by EDRs: 1  Use of JMP or CALL ; 2 
Manipulation of the IAT (Import Address Table). In both strategies, the EDR performs the desired manipulations at runtime, that is, at the moment of the application's loading, the EDR receives the event and performs the injection of its Hook DLL, which in turn will alter the desired code of the application to be monitored.
Note: As previously described, the flows and diagrams refer to Windows 64 bits with the application also running in 64 bits.
\subsection*{2.3.1. JMP or CALL}
This strategy is generally used to alter the code of native function calls within ntdll.dII.
Below, we can see the original NtCreateProcess function, that is, without the presence of a hook.
b258e700 4c8bd1 mov r10,rcx 00007ffe
b258e703 b8ba000000b258e712 0f05 00007ffe
b258e714 c3b258e715 cd2e syscall ret int 2Eh 00007ffe
b258e717 c3
Now, when an EDR is present, it can be observed that the first instructions are replaced by a JMP (it could be a CALL, but it is less common to see), thus redirecting the application's execution flow to an arbitrary code injected by the EDR.
96bee700 e9f81b1600 00007fff
96bee705 cc96d502fd 00007fff
96bee706 cc96bee712 0f05 syscall 00007fff
96bee714 c3
And the destination address of the JMP is not linked to any known module (DLL), thus being a code injected at runtime.
96d502fd Usage: Base Address: End Address: Region Size: State: Protect: Type: Allocation Base: <unknown> 00007fff
96d5000096d502fd Usage：基址：结束地址：区域大小：状态：保护：类型分配基数：<unknown> 00007fff
96d5000096d53000 00000000
00003000(12.000 kB)
\subsection*{2.3.2. IAT Hook}
One of the first records of the function interception process through IAT manipulation was described by Matt Pietrek in 1995 in his book Windows 95 System Programming Secrets [8, p. 687]
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g13.jpg?height=638&width=1255&top_left_y=1286&top_left_x=412)
Figure 7: Original execution flow
Figure 7 demonstrates the original application execution flow, where when the application needs to make an external function call (referenced in another DLL) the application looks in the IAT for the desired function's address and subsequently makes the CALL to this address.
On the other hand, in Figure 8 it can be observed that the function's address in the IAT was replaced by an arbitrary address (interceptor function) that optionally can execute the original function.
In scenarios where this interception is carried out by the EDR, the address present in the IAT will be the address of the EDR function that will perform telemetry processes, checks, logs, and other tasks planned by the EDR.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g14.jpg?height=1106&width=1535&top_left_y=138&top_left_x=272)
Figure 8: Execution flow with interception
\subsection*{2.4. Known Bypasses}
Regarding the bypass of hooks performed by the EDR, there are several possible techniques that have been publicly disclosed, but commonly they are reduced to the following techniques:
 Remapping of Ntdll.dll to obtain the original code or overwrite the function code in the previously mapped memory area.
 Direct syscall calls (direct syscalls).
A large part of the EDRs currently on the market centralize their monitoring point, in user mode, through the interception of calls in Ntdll.dll using the JMP technique, thus the publicly reported user mode hook bypass techniques to date act around Ntdll.dll.
\subsection*{2.4.1. Remapping of NtdII.dII}
The technique of remapping ntdll, as well as other techniques, can have various variants. Generally, remapping consists of reading a complete copy of ntdll.dll (without the hooks), usually directly from the disk, and subsequently overwriting the memory area related to the intercepted functions.
Another common way to obtain a copy of ntdll.dll without the interceptions is by creating a process in suspended mode, and later reading
the ntdll.dll from this process, because as we have seen previously, ntdll.dll is essential and crucial for the loading and execution of a new process. Thus, even in suspended mode, the process already holds a copy of ntdll.dll in its memory area, and as the process loading has not yet been completed, the EDR has not yet received the callback to inject its Hook DLL, thus the copy of ntdll.dll in this process is still intact (without the hooks).
\subsection*{2.4.2. Direct Syscalls}
By far, the methodology for evading hooks inserted into the functions of Ntdll.dll is the execution of direct Syscall calls. [1, p. 25]
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g15.jpg?height=509&width=1334&top_left_y=768&top_left_x=361)
Figure 9: Normal Execution Flow of NtAllocateVirtualMemory
Figure 9 demonstrates the normal and expected flow for an application to make the call to the NtAllocateVirtualMemory function in Ntdll.dll.
This process involves reconstructing the code of the desired function from NtdII.dII as in the example below:
Subsequently in the C++ application create the function definition:
In this way, the application executes the SYSCALL instruction [9] directly without going through any of the Windows subsystem DLLs (User32.dll, kernel32.dIl among others) nor through Ntdll.dll, as illustrated in Figure 10.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g16.jpg?height=527&width=1338&top_left_y=131&top_left_x=359)
Figure 10: Direct execution flow of NtAllocateVirtualMemory
This methodology has the advantage of evading all usermode hooks since all execution control is within the application itself. However, there is a high probability of identification by the EDR due to some telemetry such as:
 Total execution time of the process.
 Execution chain, where the EDR expects the function call to have come from the application, then passed through Kernel32.dII, then through NtdII.dII.
Besides the possibility of identification, there are other downsides to this methodology:
 The need for manual mapping of each SSN (System Service Number) and its related function, as we have seen before, Windows changes these numbers at any time without any prior notice.
 A significant programming effort to port the desired codes that use Windows subsystem DLLs to use only native functions through direct Syscall calling.
 Low portability of preexisting codes. Because there is a need to adjust the source code of the application to use only native calls such as Nt... and Zw...
\subsection*{2.4.3. Indirect Syscall}
A widely used variant of the technique above is the Indirect Syscall, which consists of modifying the function to, instead of executing the SYSCALL instruction directly, perform a JMP to a memory address within the NtdII.dII that contains the Syscall instruction.
Considering the code below (extracted from a certain function) from NtdII.dII```
0:002> u ntdll!NtCreateProcess
ntdll!NtCreateProcess:
00007ffe`b258e700 4c8bd1
mov r10,rcx
00007ffe`b258e703 b8ba000000
mov eax,0BAh
00007ffe`b258e712 0f05
00007ffe`b258e714 c3
syscall
ret
00007ffe`b258e715 cd2e
int 2Eh
00007ffe`b258e717 c3
NtAllocateVirtualMemory PROC
mov r10, rcx
mov eax, <SSN>
JMP 00007ffe`b258e712
ret
NtAllocateVirtualMemory ENDP
// check neighboring syscall down
if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
&& *((PBYTE) pFunctionAddress + 1 + idx * DOWN) == 0x8b
&& *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xdl
&& *((PBYTE) pFunctionAddress + 3 + idx * DOWN) == 0xb8
&& *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
&& *((PBYTE) pFunctionAddress + 7 + idx * DOWN) == 0x00) {
BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN);
BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN);
pVxTableEntry>wSystemCall = (high << 8)  low  idx;
return TRUE;
}
[+] Listing ntdll Nt/Zw functions
Mapped 478 functions
[+] Listing loaded modules
C:\Users\M4v3r1ck\Desktop\hookchain_finder64.exe is loaded at 0x00007ff77bc30000.
C:\WINDOWS\SYSTEM32 tdll.dll is loaded at 0x00007ff8ee910000.
C:\WINDOWS\System32\KERNEL32.DLL is loaded at 0x00007ff8eca90000.
C:\WINDOWS\System32\KERNELBASE.dll is loaded at 0x00007ff8ec590000.
C:\WINDOWS\SYSTEM32\apphelp.dll is loaded at 0x00007ff8e9720000.
C:\WINDOWS\System32\msvcrt.dll is loaded at 0x00007ff8ee290000.
[+] Listing hooked modules
Checking ntdll.dll at KERNEL32.DLL IAT
+ 0 hooked functions.
Checking ntdll.dll at KERNELBASE.dll IAT
+ 0 hooked functions.
Checking ntdll.dll at msvcrt.dll IAT
+ 0 hooked functions.
[+] Listing ntdll Nt/Zw functions
NtCreateThreadEx is hooked
NtCreateUserProcess is hooked
NtDuplicateObject is hooked
NtFreeVirtualMemory is hooked
NtLoadDriver is hooked
NtMapUserPhysicalPages is hooked
NtMapViewOfSection is hooked
NtOpenProcess is hooked
NtQuerySystemInformation is hooked
NtQuerySystemInformationEx is hooked
NtQuerySystemTime is hooked
NtQueueApcThread is hooked
NtQueueApcThreadEx is hooked
NtQueueApcThreadEx2 is hooked
BitDefender 比特梵德 

P  
CarbonBlack 碳黑色 

P  
Checkpoint 检查点 

O  
Cortex 皮质  P  P  
CrowdStrike Falcon 

P  
Windows Defender  O  O  
Windows Defender + ATP  O  O  
Elastic 弹性  O  O  
ESET  P  P  
Kaspersky 卡巴斯基  O  P  
MalwareBytes  P  P  
SentinelOne 



Sophos 

O  
Symantec 赛门铁克  O  O  
Trellix 

P  
Trend 趋势 

O  
结果 1：94% 的受分析电子数据记录仪解决方案（16 个中的 15 个）不支持电子数据记录仪 只有一个 EDR 解决方案在 IAT 中显示了挂钩。

typedef struct _SYSCALL_INFO {
DWORD64 dwSsn;
PVOID pAddress;
PVOID pSyscallRet;
PVOID pStubFunction;
DWORD64 dwHash;
SYSCALL_INFO, * PSYSCALL_INFO;
#define MAX_ENTRIES 512
typedef struct _SYSCALL_LIST
DWORD64 Count;
SYSCALL_INFO Entries[MAX_ENTRIES];
} SYSCALL_LIST, * PSYSCALL_LIST;
.data
qTableAddr QWORD Oh
qListEntrySize QWORD 28h
qStubEntrySize QWORD 14h
```qIdx0 QWORD OhqIdx1 QWORD OhqIdx2 QWORD OhqIdx3 QWORD OhqIdx 4 QWORD \(0 h\)qIdx5 QWORD Oh
Where:
 qTableAddr : Variable where the virtual address of the SYSCALL_LIST table/struct instance is stored .
 qListEntrySize : Variable that contains the size (in bytes) of each entry in the SYSCALL_LIST> Entries.
 qStubEntrySize: Variable that contains the size (in bytes) of each interception function used by HookChain. Further details on these functions and their usage methodology will be provided later in this article.
 qIdx0  qIdx5: Variables where the positions in the array of the necessary native function information for the initial processes and manipulations will be stored. These variables, whose names end with the values from 0 to 5, store the index of the following functions 0 ZwOpenProcess, 1  ZwProtectVirtualMemory, 2 ZwReadVirtualMemory, 3  ZwWriteVirtualMemory, 4 ZwAllocateVirtualMemory, 5  ZwDelayExecution.
\subsection*{4.3. Filling the Data Tables}
The SYSCALL_LIST data structure, in our code, was defined in a static variable named SyscallList as follows:
The filling of the array in the field SyscallList.Entries is carried out following the steps below:
1. Locates the base address of Ntdll.dll using the TEB (Thread
Environment Block) and PEB (Process Environment Block) tables.
2. Enumerates all functions with names starting with " Zw " or " \(\mathrm{Nt}^{2}\) ".
3. Checks if the function in question is one of the functions that will be used unconditionally through the Indirect Syscall. If so, adds a new entry in the array SyscallList.Entries and saves in which position of the array this function is present in the variables qIdx0  qIdx5. Here is the list of functions:
a. NtAllocateReserveObject
b. NtAllocateVirtualMemory
c. NtQueryInformationProcess
d. NtProtectVirtualMemory
e. NtReadVirtualMemory
f. NtWriteVirtualMemory
4. Checks if the function in question has a JMP present in its code, indicating the presence of a hook applied by the EDR. If so, adds a new entry in the array SyscallList.Entries.
Thus, at the end of this process, the array is filled with all \(\mathrm{Nt} / \mathrm{Zw}\) functions that present an EDR hook, as well as the 6 functions added unconditionally for future use as can be observed inFigure 15.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g30.jpg?height=618&width=1306&top_left_y=1484&top_left_x=381)
Figure 15: Values of the SyscallList.Entries array
b258e8e0 4c8bd1 mov r10,rcx 00007ffe
b258e8e3 b8c9000000 mov eax,0C9hb258e8e8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000
7ffe0308)],1b258e8f0 7503 jne ntdll!NtCreateUserProcess+0x15 (00007ffe
b258e8f5)b258e8f2 0f05 00007ffe
b258e8f4 c3
As can be seen in the image and the command result in Windbg above, the HookChain algorithm was able to obtain the SSN of the NtCreateUserProcess function (decimal 201, hexadecimal 0x00C9), as well as calculate the address of the next SYSCALL instruction (00007ffe`b258e8f2).
In steps 3 and 4, the SSN is obtained through the checking algorithm used in the Halo's Gate technique. It is implemented as shown in the code snippet below:
The address of the next SYSCALL instruction is obtained with the following code:
Where the function's address in Ntdll is passed as a parameter, which for the example below would be 0x00007ffeb258d0d0, and the GetNextSyscallInstruction function will start the search at this address until it locates the sequence 0x0f05 that represents the SYSCALL instruction.
b258d0d0 4c8bd1 mov r10,rcx 00007ffe
b258d0d3 b808000000 mov eax,8b258d0d8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000
7ffe0308) ],1b258d0e0 7503 00007ffe
b258d0e2 0f05b258d0e4 c3 00007ffe
b258d0e5 cd2eb258d0e7 c3 ntdll!NtWriteFile+0x15 (00007ffe
b258d0e5)
\subsection*{4.4. IAT Hook}
Once the previous step is completed, and having the array filled with the data of the native \(\mathrm{Nt} / \mathrm{Zw}\) functions, it is possible to move on to the next phase, which is the phase of modifying the IAT of all loaded DLLs.
However, if we carry out the procedure at this moment and subsequently another dynamic library is loaded and this new library contains in its IAT a reference to Ntdll, we would have to execute the process of manipulating the IAT of this DLL again. To avoid this reprocessing, it is recommended to load the necessary libraries before executing the IAT hook.
\subsection*{4.4.1. Preloading of DLLs}
For example, if we are creating an artifact using HookChain and after the implantation of HookChain we perform the injection and execution of a Portable Executable (PE) according to the technique created byStephen Fewer , ReflectiveDLLInjection [14], we need to perform the IAT Hook for these new DLLs that may have been loaded by ReflectiveDLLInjection. To avoid this process, it is recommended to map which DLLs the PE uses as a reference,
and which of these make a direct call to Ntdll and to load and IAT Hook these DLLs beforehand.
Below is the code snippet responsible for filling the array and IAT Hook of the kernel32 and kernelbase DLLs.
In this scenario of preloading that we are elucidating here, it would suffice to add the desired DLLs as shown in the example below:
\subsection*{4.4.2. IAT Hook}
The IAT hook procedure follows the same way as detailed in section 2.3.2 of this article. In general, HookChain will perform the following procedure for the requested DLLs through the UnhookAll function (demonstrated above).
1. Listing (in the IAT) of all DLL dependencies.
2. Checking the references to Ntdll.
3. Verification if the referenced function is in the array SyscallList.Entries, if so, change the IAT address to the address of an interception function created by HookChain, whose name is directly related to the item index in the array SyscallList.Entries.
\subsection*{4.4.3. Execution Flow}
After completing the previous steps, all the necessary procedures for the HookChain implantation are finalized, so that from this moment on all calls made to the Windows subsystems will be free from interceptions and monitoring by the EDR at the level of Ntdll.dII.
In this way, let's understand more deeply the execution flow of the application after the completion of the HookChain implants.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g34.jpg?height=906&width=1711&top_left_y=655&top_left_x=184)
Figure 16: Execution Flow After HookChain Implant
Figure 16 demonstrates in detail the execution flow of a function call after the HookChain implant, as follows the description below:
1. As an example, the application wants to create a new process through the CreateProcessW function available in the Kernel32.dll API/subsystem.
2. Since this specific function is implemented in Kernelbase.dll, kernel32.dll just redirects the execution flow to kernelbase.
3. Within the CreateProcessW code in the kernelbase DLL, after some parameter checks, it will reach the point of executing the ZwCreateUserProcess function belonging to Ntdll.dII.
4. Thus, the CreateProcessW code will search in the kernelbase IAT, where originally it would have the address of the ZwCreateUserProcess function in Ntdll.dII, but after the HookChain implant, this position in the IAT will contain the address of the function implanted by HookChain.
5. After obtaining the address of the deployed function, the CreateProcessW code will make a CALL to this address instead of the address of ZwCreateUserProcess in NtdII.dII, thus going to the function deployed by HookChain.
6. Each HookChain interception function was created with a specific name/index, in our example scenario the function name is Fnc0002, so the corresponding index in the SyscallList.Entries array will be 0x0002, in this way the HookChain code will search in the table (array SyscallList.Entries[0x0002]) for the information previously stored such as the SSN and the address of the syscall instruction in NtdII.
7. With all the necessary information in hand, the HookChain code reproduces what would be performed by the function in Ntdll (mov r10, rcx; mov eax, SSN) and subsequently forwards the execution flow to the Ntdll address that contains the syscall instruction.
8. At this point in our flow at the top of the stack, the return address will be contained, which will be the address of the next instruction inserted into the stack at the moment the CreateProcessW from kernelbase performed the CALL. Then, the Ntdll executes the syscall instruction. And when there is a return from the kernel, the flow will be directed to the respective return address within the CreateProcessW.
ATTENTION: HookChain does not require the use of the CreateProcessW function, or any similar forking mechanism, to operate. The diagram provided simply illustrates the function call process after HookChain implants.
\subsection*{4.5. Call Stack Telemetry}
One of the advantages of using HookChain is the fact that it does not alter the call stack (in point of EDR view) of the calls, even though this is not its main purpose. In this way, this test aims at the visualization and understanding of the call stack of functions before and after the HookChain implants. Therefore, the test code performs 3 actions:
1. Starts the Notepad.exe process using the CreateProcessW API. This procedure is carried out before the HookChain implants.
2. All HookChain implants are performed.
3. Starts a new Notepad.exe process using the CreateProcessW API. As at this point the HookChain has already performed all its implants and bypasses, the original ZwCreateUserProcess function from Ntdll.dll will not be executed.
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g36.jpg?height=1483&width=1174&top_left_y=149&top_left_x=184)
Figure 17: Code used for this test
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g37.jpg?height=1086&width=1757&top_left_y=151&top_left_x=184)
Figure 18: Monitoring the execution
\begin{tabular}{ccccccc}
\hline \multicolumn{5}{l}{3 Event Properties } & \multirow[t]{2}{*}{\(\square\)} & \multirow[t]{2}{*}{\(\times\)} \\
\hline 3 E & ent \{ \(\{\) 岛 \(P\) & rocess \(\quad \&\) Stack & & & & \\
\hline Frame & Module & Location & Address & Path & & \\
\hline K 0 & ntoskml.exe & PspCallProcess NotityRoutines + Ox213 & Oxffff8060ea6455t & C:IWINDOWS syystem32 intoskml.exe & & \\
\hline K 1 & ntoskml.exe & Psplnsert Thread \(+0 \times 68\) e & Oxffff 8060ea8c9ea & C:\WINDOWS syystem 32 vitoskml.exe & & \\
\hline K 2 & ntoskml.exe & NtCreate UserProcess + OxdeO & Oxffff8060e9edda0 & C:IWINDOWS syystem32vitoskml.exe & & \\
\hline K 3 & ntoskml.exe & KSystemServiceCopyEnd + Ox25 & Oxfffff8060e811575 & C:\WINDOWS \ system32 vitoskml.exe & & \\
\hline U 4 & ntdll.dll & ZwCreate UserProcess + Q*14 & Oxifeb258e8f4 & C:\Windows \System 32 vitdill.dll & & \\
\hline U 5 & KemelBase.dll & Create ProcessintemalW \(+0 \times 22 e 2\) & 0x 7 feafc2c5f2 & C:\Windows\System32\KemelBase.dll & & \\
\hline U6 & KemelBase.dll & CreatePPocess \(W+0 \times 66\) & 0x7feafc29666 & C:\Windows\System32\KemelBase.dll & & \\
\hline U 7 & kemel32.dll & CreateProcessWStub + Ox54 & \(0 \times 7\) feb 168 cec 4 & C:Windows\System32kemel32.dll & & \\
\hline U8 & HookChain.exe & CreatePProc + Oxi0. E:\Projects\Personal\HookChain\HookChain\main.c(21) & \(0 \times 7\) if7be5d620 & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 9 & HookChain.exe & wmain + Ox78. E:\Projects\Personal\HookChain\HookChain\main.c(67) & \(0 \times\) iff7be 5 d 6438 & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 10 & HookChain.exe & ![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g37.jpg?height=30\&width=661\&top_left_y=1753\&top_left_x=406) & \(0 \times 7776 e 5 \mathrm{db} 709\) & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 11 & HookChain.exe & _scit_common_main_seh + Ox 12e, D: \(: a \backslash\) _work\1/s\srch\ctools \crt\vcstartup \sre \statup & \(0 \times 7\) fibe 5 db 65 e & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 12 & HookChain.exe & ![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g37.jpg?height=30\&width=724\&top_left_y=1801\&top_left_x=406) & \(0 \times\) \仿7be5db51e & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 13 & HookChain.exe & ![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g37.jpg?height=26\&width=688\&top_left_y=1826\&top_left_x=406) & \(0 \times\) \ifbe5db84e & E:\Projects\Personal\HookChain \(\times 64\) \Debug \HookChain.exe & & \\
\hline U 14 & kemel32.dll & Base Threadlinithunk \(+0 \times 14\) & 0xतfeb 1687344 & C:\Windows \System32kemel 32.dll & & \\
\hline U 15 & ntdll.dIll & RitUserThreadStart \(+0 \times 21\) & 0xZfeb25426b1 & C.\Windows\System32vivalll.dll & & \\
\hline
\end{tabular}
Figure 19: Stack trace of the CreateProcessW call before the implants
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g37.jpg?height=498&width=1395&top_left_y=2058&top_left_x=339)
Figure 20: SyscallList.Entries array populated and implants performed
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g38.jpg?height=1047&width=1743&top_left_y=139&top_left_x=179)
Figure 21: Execution of the CreateProcessW call after the implants
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g38.jpg?height=584&width=1746&top_left_y=1287&top_left_x=178)
Figure 22: Stack trace of the CreateProcessW call after the implants
It can be observed in Figure 21 that the application (due to the presence of debug code) displayed on screen the moment when the interception function was executed as well as the index in the array, SSN, etc.
When comparing Figure 19 and Figure 22, it can be observed that one of our objectives was \(100 \%\) achieved, in such a way that the diversion of the application flow and the consequent presence of the hook created by HookChain did not alter the Stack Trace, thus being able to go unnoticed by the EDR telemetry.
Result 3 : Stack trace telemetry unchanged to the point where the flow diversion (Hook) can go unnoticed by an EDR check in kernelland.
\footnotetext{
0x00007FF7BE63DD30 = \&SyscallList
Index, Name, Ssn, Ntdll.dll Address
e[0] ZwAllocateVirtualMemory 24 0x00007FFEB258D2DO
e[1] ZwCreateSection 74 0x00007FFEB258D910
e[2] ZwCreateUserProcess 201 0x00007FFEB258E8EO
e[3] ZwDelayExecution 52 0x00007FFEB258D650
e[4] ZwMapViewOfSection 40 0x00007FFEB258D4D0
e[5] ZwOpenProcess 38 0x00007FFEB258D490
e[6] ZwProtectVirtualMemory 80 0x00007FFEB258D9D0
e[7] ZwQueryInformationProcess 25 0x00007FFEB258D2F0
e[8] ZwQuerySystemTime 90 0x00007FFEB258DB10
e[9] ZwReadVirtualMemory 63 0x00007FFEB258D7B0
e[10] ZwSetInformationThread 13 0x00007FFEB258D170
e[11] ZwWriteVirtualMemory 58 0x00007FFEB258D710
}
In the text above, extracted from the application console at the time of execution, one can see the information of the ZwCreateUserProcess function.
be5c0000 00007ff7
be64e00048080000 00007ffe
482a10009da80000 00007ffe
9daae000afba0000 00007ffe
afbc7000afbd0000 00007ffe
afec6000b1680000 00007ffe
b1720000b1b70000 00007ffe
b1c2d000
\begin{abstract}
In the passage above, we can observe the listing of the application modules in windbg, as well as the address of the Kernelbase subsystem and its respective IAT.
\end{abstract}
\footnotetext{
0:004> dps 00007ffe`afbd0000 + 1E48B8 00007ffe`afbd0000 + 1E48B8 + 1688 \(00007 f f e ` a f d b 48 b 8 \quad 00007 f f e ` b 2566\) e70 ntdll!ApiSetQueryApiSetPresence
・.
\(00007 f f e ` a f d b 4 e 2000007 f f e ` b 258 d 910\) ntdll!NtCreateSection
}```
00007ffe`afdb4e28
00007ffe`afdb4e30
00007ffe`afdb4e38
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=35&width=318&top_left_y=271&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=33&width=318&top_left_y=309&top_left_x=184)
00007ffe`afdb55b8
00007ffe`afdb5760
00007ffe`afdb5788
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=30&width=318&top_left_y=476&top_left_x=184)
00007ffe`afdb5798
00007ffe`afdb57a0
00007ffe`afdb59b0
00007ffe`afdb5a08
00007ffe`afdb5cc0
b258de80 ntdll!NtAllocateVirtualMemoryEx \(00007 f f e
b 258 d 650) ntdll!NtDelayExecution
b258de80 ntdll!NtAllocateVirtualMemoryEx （00007 f f e
b 258 d 650） ntdll!NtDelayExecution
0:004> dps 00007ffe`afbd0000 + 1E48B8 00007ffe`afbd0000 + 1E48B8 + 1688
00007ffe`afdb48b8 00007ffe`b2566e70 ntdll!ApiSetQueryApiSetPresence
...
00007ffe`afdb4e20 00007ff7`be5d7c30 HookChain!Fnc0001
00007ffe`afdb4e28 00007ffe`b2506790 ntdll!RtlOpenCurrentUser
00007ffe`afdb4e30 00007ff7`be5d7c6c HookChain!Fnc0004
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=35&width=318&top_left_y=1233&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=29&width=318&top_left_y=1276&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=33&width=318&top_left_y=1314&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=38&width=318&top_left_y=1352&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=38&width=318&top_left_y=1392&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=29&width=315&top_left_y=1439&top_left_x=185)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=29&width=318&top_left_y=1479&top_left_x=184)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=35&width=312&top_left_y=1513&top_left_x=187)
00007ffe`afdb59b0
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=38&width=315&top_left_y=1597&top_left_x=185)
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g40.jpg?height=30&width=318&top_left_y=1641&top_left_x=184)
00007ffe`b258d270 ntdll!NtQueryDefaultLocale
00007ff7`be5d7ca8 HookChain!Fnc0007
00007ffe`b2591130 ntdll!RtlCaptureContext
00007ff7`be5d7ce4 HookChain!Fnc000A
00007ff7`be5d7cd0 HookChain! Fnc0009
00007ff7`be5d7c94 HookChain!Fnc0006
00007ffe`b258d710 ntdll!NtWriteVirtualMemory
00007ff7`be5d7c1c HookChain!Fnc0000
00007ff7`be5d7c58 HookChain!Fnc0003
00007ff7`be5d7c80 HookChain!Fnc0005
00007ff7`be5d7c44 HookChain!Fnc0002
Fnc0000 PROC
mov rax, SyscallExec
push rax
mov rax, 0000h
ret
nop
Fnc0000 ENDP
Fnc0001 PROC
mov rax, SyscallExec
push rax
Below is the assembly code of the SyscallExec function, which is responsible for using the indexer of the functions that will receive the flow of the intercepted execution, searching in the SyscallList. Entries array for the respective information, and directing the application flow to the address of the Syscall instruction within Ntdll.dII.
\section*{5. HOOKCHAIN  TESTES}
\subsection*{5.1. Metodologia de testes}
Unlike the previous enumeration described in item 3 of this article, this testing phase was entirely conducted by me in a controlled environment.
For the tests, 14 EDR products were selected, 9 of which are included in Gartner's Magic Quadrant as of December 31, 2023 [15].
![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g42.jpg?height=1055&width=1032&top_left_y=643&top_left_x=518)
Figure 23: Gartner Magic Quadrant for Endpoint Protection Platforms as of December 31, 2023 [15].
The products present in Gartner's Magic Quadrant that were tested are highlighted in green in the image above, while the products marked in gray could not be tested.
Additionally, 4 other products that are not included in Gartner's Quadrant were tested, namely: Acronis, Cylance, Elastic, and MalwareBytes.
For these tests, two versions of HookChain were prepared as described below:
\subsection*{5.1.1. Remote Process Injection}
This first version aims to perform the injection of a simple shellcode into a remote process using a widely known technique of creating a thread in a remote process. The injected shellcode is created at runtime to execute the MessageBox API call from User32.dII.
This executable follows the following flow:
1. Implementation of the HookChain implants
2. Creation at runtime of a code (in Assembly) to execute the MessageBox
3. Opening a handle to the process where the code will be injected
4. Creation of a memory area in the remote process
5. Injection of the assembly code into the remote process
6. Creation and execution of a remote thread pointing to the loaded assembly
\subsection*{5.1.2. Loading and executing a PE}
For the second version of HookChain, a variant was prepared to download a shellcode via HTTP and execute it within the same process. This strategy allowed us to use a single HookChain executable for various payloads, as simply replacing the shellcode on the HTTP server would result in it being injected and executed in our process.
This executable follows the following flow:
1. Implementation of the HookChain implants
2. HTTP download of an obfuscated PE
3. Decoding and injecting the PE into the local process
4. Execution of the loaded PE in memory, in other words, reflectively.
Due to the flexibility provided by this strategy, various payloads with different levels of access could be tested, as shown in the table below:
\begin{tabular}{ccc}
\hline PAYLOAD & NÍVEL DE ACESSO & OBJETIVO \\
\hline Metasploit Meterpreter & Nonprivileged user & \begin{tabular}{l}
Check the ability to analyze and identify a highly \\
known payload that is typically blocked by EDRs.
\end{tabular} \\
\hline Havoc & Nonprivileged user & \begin{tabular}{l}
Check the ability to analyze and identify a payload \\
and C2 (Command \& Control) beacon.
\end{tabular} \\
\hline \begin{tabular}{l}
Metasploit Meterpreter \\
+ Módulo Kiwi
\end{tabular} & Administrative user & \begin{tabular}{l}
Check the ability to analyze and identify a highly \\
known payload that is typically blocked by EDRs \\
for credential dumping.
\end{tabular} \\
\hline Mimikatz & Administrative user & \begin{tabular}{l}
Check the ability to analyze and identify a highly \\
known payload that is typically blocked by EDRs \\
for credential dumping.
\end{tabular} \\
\hline
\end{tabular}
Procdump
Custom LSASS Dump ( \(100 \%\) assembly) Check the ability to identify credential dumping. Check the ability to identify credential dumping.
As can be observed in the table above, this strategy allows for an almost infinite variety of possibilities.
Note: It is important to emphasize that the goal of the HookChain technique is purely and simply to bypass the monitoring points of the defense layers at the user level (ring 3). As such, it can be used at any access level the user has (nonadministrative, administrative, or even as SYSTEM).
The tests focused on obtaining credentials (credential dump) from the LSASS memory were conducted to illustrate the potential of the HookChain technique when combined with other new and/or known techniques. This reinforces the fact that HookChain is a foundational technique, enabling the execution of other codes and/or techniques following its bypass implants.
\subsection*{5.2. Result}
The table below presents the results.
\begin{tabular}{cccccccc}
\hline \multirow{3}{*}{ PRODUCT } & \multicolumn{7}{l}{ EXECUTED CODE } \\
\hline & \multirow{2}{*}{\begin{tabular}{l}
Remote Process \\
Injection
\end{tabular}} & \multicolumn{6}{l}{ Download, local PE injection and executing } \\
\hline & & Meterpreter & Havoc & \begin{tabular}{l}
Meterpreter + \\
Kiwi
\end{tabular} & Mimikatz & Procdump & LSASS Dump \\
\hline Acronis & 4 & \(\nabla\) & v & v & v & v & v \\
\hline BitDefender & v & e & \(\nabla\) &  & 4 &  & 4 \\
\hline Cortex & \(\theta\) & \(\theta\) & v & \(\theta\) & \(\ominus\) & \(\ominus\) & \(\nabla\) \\
\hline CrowdStrike Falcon & \(\nabla\) & v & v &  & 4 & 4 & v \\
\hline Cylance & Ө & 4 & Ө & e & v &  & Ө \\
\hline Windows Defender & \(\nabla\) & 4 & \(\nabla\) &  &  &  & v \\
\hline Windows Defender XDR & v & v & v &  & ![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g45.jpg?height=47\&width=41\&top_left_y=1014\&top_left_x=2013) & ![](https://cdn.mathpix.com/cropped/2024_08_21_2bc849000e60b71ab241g45.jpg?height=47\&width=42\&top_left_y=1014\&top_left_x=2305) & \(\nabla\) \\
\hline Elastic & v &  & Ө & e &  &  & Ө \\
\hline ESET & v & 4 & v & \(\nabla\) & \(\nabla\) & Ө & \(\nabla\) \\
\hline MalwareBytes & v & v & v & v & v & v & v \\
\hline SentinelOne & 4 & v & 4 & \(\nabla\) & v & 4 & 1 \\
\hline Sophos & \(v\) & v & v & 4 & 4 &  & 4 \\
\hline Trellix & \(v\) & v & \(\nabla\) & \(\nabla\) & \(v\) &  & \(v\) \\
\hline Trend & \(\nabla\) & \(\nabla\) & v & \(\nabla\) & 0 &  & \(\nabla\) \\
\hline
\end{tabular}
Where:
\(\checkmark\) Executed without alerts and blocks.
4 Partially execution (no success) without alerts or Executed (successfully) with alerts.
Execution fail with block and alert
\subsection*{5.2.1. Nonprivileged user}
In the general tests with lowprivilege users (Remote Process Injection, Meterpreter and Havoc), the technique has \(71.43 \%\) effectiveness in bypassing monitoring and alerts. In additional 5 out of the 42 items tested has some type of failure during execution and/or an alert after execution, and 7 items had a total execution failure with complete process blocking.
Isolating these numbers by the effectiveness of the products, \(57.14 \%\) of products were effective in identifying and/or blocking the attempted attack.
During the tests with the Metasploit Open Source [16], some commands were blocked or triggered alerts after establishing a Metasploit session. This identification and blocking behavior is expected, as many of these commands execute other Windows processes, and since the new processes (even if they are child processes of HookChain) do not have the HookChain's bypass implants, the EDR will be able to monitor these behaviors and take appropriate mitigation actions.
However, when using the Havoc Framework [17], fewer blocks were observed, demonstrating that the identification and possible blocking are directly related to the actions performed and the framework used.
It is possible that using other products with more stealthy behavior, such as Metasploit Pro, Cobalt Strike, among others, would allow most of the actions to go unnoticed.
Result 4: Considering the isolated test points conducted with lowprivilege users, \(71.43 \%\) of the tests performed ( 30 out of 42 ) were successful without any identification or blocking. In other words, the HookChain were able to bypass security layer successfully.
Result 5: \(57.14 \%\) of the EDR solutions analyzed (8 out of 14) were able to identify or block the action performed.
\subsection*{5.2.2. Administrative user}
Unlike the tests with lowprivilege users, in the tests with administrative permissions, where the goal was to obtain credentials stored in the LSASS process memory, the products demonstrated better effectiveness, managing to contain or alert in \(57.14 \%\) of the tested scenarios.
This procedure (LSASS Dump) was chosen precisely because it involves an extremely critical process within the operating system's architecture, and the extraction techniques are based on wellknown procedures widely used by various malware and artifacts in penetration testing.
It was also observed during this test that when a new strategy was used, such as in the test where we used an LSASS dumper \(100 \%\) written in Assembly by me, the effectiveness of the products in defense and identification dropped to \(35.7 \%\).
Result 6: Considering the isolated test points conducted with administrative users, \(57.14 \%\) of the tests performed ( 32 out of 56 ) were mitigated, with or without an alert. Therefore, 24 out of the 56 tests were successful without any identification or blocking.
Result 7: Even when working with behavioral analysis, the EDR/XDR products were still unable to identify and mitigate custom and more sophisticated attacks, with the HookChain technique achieving a 64.29\% effectiveness in bypassing security in this scenario.
\section*{6. FINAL WORDS}
The HookChain technique proved to be effective in bypassing the security layers applied by EDR products, achieving up to \(71 \%\) effectiveness in bypassing during the tests, and even successfully bypassing 100\% of the detections in some evaluated products.
Since the topic of "defense bypass" is highly dynamic, with constant changes in both attack chains and techniques as well as in defense processes, the results presented here represent a snapshot of the time when the tests were conducted. Therefore, it is not possible to guarantee or predict the behavior of the solutions after the application of necessary patches by the vendors, nor can it account for improvements or failures in the specific configurations of each implemented environment.
Note: Some EDR/XDR vendors, such as SentineIOne and Trend, contact me after the completion of this study, requesting support for understanding and subsequently improving the detections and telemetry of their respective products.
\section*{7. ACKNOWLEDGMENTS}
I could not conclude this work without first thanking God for always being at the forefront of all my battles. I also want to thank my wife, my source of inspiration, a warrior woman who always walks beside me, supporting and encouraging me to be \(1 \%\) better every day.
To my children, I also extend my heartfelt thanks, for with every hug, with every gesture of affection, I feel like the most important man in the world, and I know how much hours dedicated to this work have been missed by all of us.
I cannot forget to mention my parents, who always went above and beyond to provide me the best education, love, and support to reach for my dreams, even if it meant moving far away.
Finally, I want to extend my gratitude to the entire Cyber Security community in Brazil and especially to those who entrusted their environments, licenses, and virtual machines for the tests to be conducted without you, this work would certainly be incomplete.
In a very special way, I would like to mention some names that have made and continue to make a difference in my life through their friendship, scoldings, support when I falter, and most importantly, their prayers. Thank you so much, Eder Luis, Marcus Prestes, Paulo Trindade, Aroldo Chociai, and Rafael Salema  you are all part of this story.
\section*{8. BIBLIOGRAPHY}
[1] M. Hand, Evading EDR: The Definitive Guide to Defeating Endpoint Detection Systems, San Francisco: No Stach Press, Inc, 2024.
[2] M. Russinovich, D. A. Solomon and A. Lonescu, Windows Internals, Sixth Edition, Part 1, Redmond, Washington: Microsoft Press, 2012.
[3] P. Yosifovich, A. Lonescu, E. M. Russinovich and A. D. Solomon, Windows Internals Seventh Edition  Part 1, Redmond: Microsoft Press, 2017.
[4] Microsoft, "Microsoft Learn," [Online]. Available:
https://learn.microsoft.com/enus/cpp/build/x64callingconvention?view=msvc170. [Accessed 2103 2024].
[5] Microsoft, "PE Format," [Online]. Available: https://docs.microsoft.com/windows/win32/debug/peformat. [Accessed 2103 2024].
[6] NtCore, "Explorer Suite," [Online]. Available:
https://ntcore.com/?page_id=388. [Accessed 2103 2024].
[7] R. Batra, "API Monitor," [Online]. Available:
http://www.rohitab.com/apimonitor. [Accessed 2103 2024].
[8] M. Pietrek, Windows 95 System Programming Secrets, Foster City: IDG Books Worldwide, Inc, 1995.
[9] @modexpblog, "Bypassing UserMode Hooks and Direct Invocation of System Calls for Red Teams," [Online]. Available:
https://www.mdsec.co.uk/2020/12/bypassingusermodehooksanddirectinvocationofsystemcallsforredteams/. [Accessed 2203 2024].
[10] amOnsec; smelly__vx;, [Online]. Available:
https://vxug.fakedoma.in/papers/VXUG/Exclusive/HellsGate.pdf. [Accessed 22 03 2024].
[11] ReenzOh from Sektor7, 2304 2021. [Online]. Available: https://blog.sektor7.net/\#!res/2021/halosgate.md. [Accessed 2203 2024].
[12] C. Joca, "NtGate, An implementation of Halo's Gate and indirect syscalls," [Online]. Available: https://github.com/hiatus/NtGate. [Accessed 2203 2024].
[13] H. C. J. M4v3r1ck, "HookChain Research  Step 1," [Online]. Available: https://github.com/helviojunior/hookchain/tree/0b4a953c10a18f53aa68f7588 db9818730dd7a52. [Accessed 2203 2024].
[14] S. Fewer, "ReflectiveDLLInjection," [Online]. Available: https://github.com/stephenfewer/ReflectiveDLLInjection/. [Accessed 2203 2024].
[15] Gartner, "Magic Quadrant for Endpoint Protection Platforms," 31122023. [Online]. Available: https://www.gartner.com/doc/reprints?id=12G7RNK65\&ct=240112\&st=sb.
[16] Rapid7, [Online]. Available: https://www.metasploit.com/. [Accessed 0304 2024].
[17] C5pider, [Online]. Available: https://havocframework.com/. [Accessed 0304 2024].