仅学习,如有错误请指出…………
在加壳软件中,ntdll.dll里的有些API会被加壳软件hook,导致我们在做补丁无法正常执行
如:有的程序会hook NtGetContextThread和NtSetContextThread,导致无法下硬件断点,也有的会hook NtProtectVirtualMemory,无法修改内存属性,就不能修改汇编代码等……
Nt或Zw开头的函数执行的代码是一样的,他们所指向的函数地址都是同一个,具体有什么不同,请自行搜索查看,我这里使用Nt函数进行编写。
代码:
代码是这篇文章代码的优化版:DLL巧妙的绕过被VMP壳HOOK的ZwProtectVirtualMemory
#include <iostream>
#include <windows.h>
static void* lpNtdllBuffer = NULL;
ULONG_PTR CustomNtFunction(const char* functionName)
{
ULONG_PTR functionAddress = 0;
char dllPath[MAX_PATH];
GetSystemDirectoryA(dllPath, MAX_PATH);
strcat_s(dllPath, MAX_PATH, "\\ntdll.dll");//拼接系统目录ntdll.dll路径
HMODULE dllHandle = LoadLibraryA(dllPath);
ULONG_PTR apiAddress = (ULONG_PTR)GetProcAddress(dllHandle, functionName);
//读取ntdll.dll到内存,程序运行时只读一次
if (lpNtdllBuffer == NULL)
{
HANDLE hFile = CreateFileA(dllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dwBytesRead = 0;
DWORD dwSize = GetFileSize(hFile, NULL);
if (dwSize == INVALID_FILE_SIZE || dwSize == 0) return functionAddress;
lpNtdllBuffer = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ReadFile(hFile, lpNtdllBuffer, dwSize, &dwBytesRead, NULL);
CloseHandle(hFile);
}
}
//通过apiAddress地址获取函数的foa地址
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpNtdllBuffer;
//取出PE头结构
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + ((ULONG_PTR)pDosHeader));
//取出节头结构
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pNtHeaders + sizeof(IMAGE_NT_HEADERS));
ULONG_PTR foaAddress = 0;
//Nt函数地址 - ntdll基址 = rva
ULONG_PTR rva = apiAddress - (ULONG_PTR)dllHandle;
for (WORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; ++i)
{
if (rva >= pSectionHeader[i].VirtualAddress && rva <= pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)
{
//找到foa地址
foaAddress = rva - pSectionHeader[i].VirtualAddress + pSectionHeader[i].PointerToRawData;
break;
}
}
#ifndef _WIN64 // x86位8、9位foa值与va值不同,要特殊处理
memcpy((PVOID)((ULONG_PTR)lpNtdllBuffer + foaAddress + 6), (PVOID)(apiAddress + 6), 6);
#endif
functionAddress = (ULONG_PTR)lpNtdllBuffer + foaAddress;
printf("函数名称: %s, 地址:%Ix, 偏移:%Ix\n", functionName, functionAddress, foaAddress);
//VirtualFree(lpNtdllBuffer, 0, MEM_RELEASE); lpNtdllBuffer = NULL;
return functionAddress;
}
//NtGetContextThread
typedef BOOL(NTAPI* PNtGetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtGetContextThread pNtGetContextThread;
//NtSetContextThread
typedef BOOL(CALLBACK* PNtSetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtSetContextThread pNtSetContextThread;
//NtProtectVirtualMemory
typedef BOOL(NTAPI* PNtProtectVirtualMemory)(HANDLE hProcess, PVOID* lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
int main()
{
CustomNtFunction("ZwResumeThread");
CustomNtFunction("NtSuspendThread");
HANDLE hThread = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
//NtGetContextThread
pNtGetContextThread = (PNtGetContextThread)CustomNtFunction("NtGetContextThread");
pNtGetContextThread(hThread, &context);
//NtSetContextThread
pNtSetContextThread = (PNtSetContextThread)CustomNtFunction("ZwSetContextThread");
pNtSetContextThread(hThread, &context);
//NtProtectVirtualMemory
SIZE_T size = 1;
ULONG OldProtect = 0;
PVOID addr = (PVOID)GetModuleHandle(nullptr);
pNtProtectVirtualMemory = (PNtProtectVirtualMemory)CustomNtFunction("NtProtectVirtualMemory");
pNtProtectVirtualMemory((HANDLE)-1, &addr, &size, PAGE_EXECUTE_READWRITE, &OldProtect);
system("pause");
return 0;
}
最后,实战一个VMP加壳的程序,此程序正常情况下无法修改内存属性
程序下载地址:https://nns.lanzouu.com/iiMLu2ee6sxi
ntdll.h.zip
(45.8 KB, 下载次数: 6, 售价: 15 CB吾爱币)
效果演示