[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;
}