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