飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 842|回复: 4

[C/C++] 手搓Nt*或Zw*函数,避免被hook 支持x86_x64

[复制链接]
  • TA的每日心情
    奋斗
    2024-10-21 16:09
  • 签到天数: 93 天

    [LV.6]常住居民II

    发表于 2024-11-12 09:15:11 | 显示全部楼层 |阅读模式
    本帖最后由 wtujoxk 于 2024-11-14 13:57 编辑

    仅学习,如有错误请指出…………
    在加壳软件中,ntdll.dll里的有些API会被加壳软件hook,导致我们在做补丁无法正常执行
    如:有的程序会hook NtGetContextThread和NtSetContextThread,导致无法下硬件断点,也有的会hook NtProtectVirtualMemory,无法修改内存属性,就不能修改汇编代码等……
    Nt或Zw开头的函数执行的代码是一样的,他们所指向的函数地址都是同一个,具体有什么不同,请自行搜索查看,我这里使用Nt函数进行编写。

    代码:
    [C++] 纯文本查看 复制代码
    #include <iostream>
    #include <windows.h>
     
    static void* lpNtdllBuffer = NULL;
    ULONG_PTR GetFunctionAddressByName(const char* functionName)
    {
    	ULONG_PTR functionAddress = 0;
    	
    	//读取ntdll.dll到内存,程序运行时只读一次
    	if (lpNtdllBuffer == NULL)
    	{
            char dllPath[MAX_PATH];
    	    GetSystemDirectoryA(dllPath, MAX_PATH);
    	    strcat_s(dllPath, MAX_PATH, "\\ntdll.dll");//拼接系统目录ntdll.dll路径
    		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);
            }
    	}
     
    	//取出导出表
    	//DLL内存数据转成DOS头结构
    	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpNtdllBuffer;
    	//取出PE头结构
    	PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)lpNtdllBuffer + pDosHeader->e_lfanew);
    	//判断PE头导出表表是否为空
    	if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) return functionAddress;
     
    	//取出导出表偏移
    	ULONG_PTR FileOffset = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
     
    	//取出节头结构
    	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pNtHeaders + sizeof(IMAGE_NT_HEADERS));
    	PIMAGE_SECTION_HEADER pOldSectionHeader = pSectionHeader;
    	//遍历节结构进行地址运算
    	for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    	{
    		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    		{
    			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    			break;
    		}
    	}
     
    	//导出表地址
    	PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)lpNtdllBuffer + FileOffset);
    	//取出导出表函数地址
    	FileOffset = pExportDirectory->AddressOfFunctions;
    	//遍历节结构进行地址运算
    	pSectionHeader = pOldSectionHeader;
    	for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    	{
    		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    		{
    			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    			break;
    		}
    	}
    	PLONG AddressOfFunctions = (PLONG)((ULONG_PTR)lpNtdllBuffer + FileOffset);//这里注意一下foa和rva
     
    	//取出导出表函数名字
    	FileOffset = pExportDirectory->AddressOfNameOrdinals;
     
    	//遍历节结构进行地址运算
    	pSectionHeader = pOldSectionHeader;
    	for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    	{
    		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    		{
    			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    			break;
    		}
    	}
    	PUSHORT AddressOfNameOrdinals = (PUSHORT)((ULONG_PTR)lpNtdllBuffer + FileOffset);//注意一下foa和rva
     
    	//取出导出表函数序号
    	FileOffset = pExportDirectory->AddressOfNames;
     
    	//遍历节结构进行地址运算
    	pSectionHeader = pOldSectionHeader;
    	for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    	{
    		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    		{
    			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    			break;
    		}
    	}
    	PULONG AddressOfNames = (PULONG)((ULONG_PTR)lpNtdllBuffer + FileOffset);//注意一下foa和rva
     
    	//分析导出表
    	ULONG uNameOffset;
    	ULONG uOffset;
    	LPSTR FunName;
    	ULONG uAddressOfNames;
    	//获取所有导出函数名
    	for (DWORD uIndex = 0; uIndex < pExportDirectory->NumberOfNames; uIndex++, AddressOfNames++, AddressOfNameOrdinals++)
    	{
    		uAddressOfNames = *AddressOfNames;
    		pSectionHeader = pOldSectionHeader;
    		for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    		{
    			if (pSectionHeader->VirtualAddress <= uAddressOfNames && uAddressOfNames <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    			{
    				uOffset = uAddressOfNames - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    				break;
    			}
    		}
    		FunName = (LPSTR)((ULONG_PTR)lpNtdllBuffer + uOffset);
     
    		//得到指定的函数地址
    		if (!_stricmp(FunName, functionName))
    		{
    			pSectionHeader = pOldSectionHeader;
    			uOffset = (ULONG)AddressOfFunctions[*AddressOfNameOrdinals];
    			for (WORD Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
    			{
    				//计算函数偏移地址
    				if (pSectionHeader->VirtualAddress <= uOffset && uOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    				{
    					uNameOffset = uOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    					break;
    				}
    			}
    			functionAddress = (ULONG_PTR)lpNtdllBuffer + uNameOffset;
    			printf("函数名称: %s, 地址:%Ix, 偏移:%Ix\n", functionName, functionAddress, uNameOffset);
     
    			//VirtualFree(lpNtdllBuffer, 0, MEM_RELEASE); lpNtdllBuffer = NULL;
    			return functionAddress;
    		}
    	}
    	//VirtualFree(lpNtdllBuffer, 0, MEM_RELEASE); lpNtdllBuffer = NULL;
    	return functionAddress;
    }
    static BYTE* lpJmpWow64TransitionBuffer = NULL;
    ULONG_PTR CustomNtFunction2(const char* functionName)
    {
    #ifdef _WIN64
    	return GetFunctionAddressByName(functionName);
    #else
    	if (lpJmpWow64TransitionBuffer == NULL)
    	{
    		// 只处理一次Wow64Transition的va地址
    		char dllPath[MAX_PATH];
    		GetSystemDirectoryA(dllPath, MAX_PATH);
    		strcat_s(dllPath, MAX_PATH, "\\ntdll.dll");//拼接系统目录ntdll.dll路径
    		//jmp ntdll.Wow64Transition 写到内存
    		lpJmpWow64TransitionBuffer = (BYTE*)VirtualAlloc(NULL, sizeof(ULONG_PTR) + 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    		lpJmpWow64TransitionBuffer[0] = 0xFF;  // jmp ntdll.Wow64Transition地址
    		lpJmpWow64TransitionBuffer[1] = 0x25;
    		ULONG_PTR Wow64TransitionAddress = (ULONG_PTR)GetProcAddress(LoadLibraryA(dllPath), "Wow64Transition");
    		memcpy(lpJmpWow64TransitionBuffer + 2, &Wow64TransitionAddress, sizeof(ULONG_PTR));
    	}
    	//写jmpWow64Transition地址的内存到functionNameAddress+6的位置
    	ULONG_PTR functionNameAddress = GetFunctionAddressByName(functionName);
    	memcpy((void*)(functionNameAddress + 6), &lpJmpWow64TransitionBuffer, sizeof(ULONG_PTR));
     
    	//printf("函数名称: %s, 地址:%Ix,地址2:%Ix\n", functionName, functionNameAddress, lpJmpWow64TransitionBuffer);
    	return functionNameAddress;
    #endif
    }
    //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;
     
    //extern "C" NTSTATUS NTAPI NtGetContextThread(HANDLE hThread, LPCONTEXT lpContext);
    int main()
    {
    	CustomNtFunction2("ZwResumeThread");
    	CustomNtFunction2("NtSuspendThread");
     
    	HANDLE hThread = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    	CONTEXT context;
    	memset(&context, 0, sizeof(CONTEXT));
    	context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    	//NtGetContextThread
    	pNtGetContextThread = (PNtGetContextThread)CustomNtFunction2("NtGetContextThread");
    	pNtGetContextThread(hThread, &context);
     
    	//NtSetContextThread
    	pNtSetContextThread = (PNtSetContextThread)CustomNtFunction2("ZwSetContextThread");
    	pNtSetContextThread(hThread, &context);
     
    	NtProtectVirtualMemory
    	SIZE_T size = 1;
    	ULONG OldProtect = 0;
    	PVOID addr = (PVOID)GetModuleHandle(nullptr);
    	pNtProtectVirtualMemory = (PNtProtectVirtualMemory)CustomNtFunction2("NtProtectVirtualMemory");
    	pNtProtectVirtualMemory((HANDLE)-1, &addr, &size, PAGE_EXECUTE_READWRITE, &OldProtect);
     
    	system("pause");
    	return 0;
    }

    评分

    参与人数 1威望 +1 飘云币 +1 收起 理由
    mfkusrai + 1 + 1 感谢发布原创作品,PYG有你更精彩!

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    开心
    昨天 07:47
  • 签到天数: 1855 天

    [LV.Master]伴坛终老

    发表于 2024-11-13 09:09:17 | 显示全部楼层
    感谢分享,学习了!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 05:12
  • 签到天数: 106 天

    [LV.6]常住居民II

    发表于 2024-11-16 23:08:20 | 显示全部楼层
    拥抱大大大大大佬!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 10:16
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    发表于 前天 08:54 | 显示全部楼层
                               
    感谢分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表