登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 96|回复: 3

手搓Nt*或Zw*函数,避免被hook 支持x86_x64

[复制链接]

42

主题

3

回帖

66

积分

版主

积分
66
发表于 6 天前 | 显示全部楼层 |阅读模式

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

推荐使用方式二

方式一:

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

方式二:

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

0

主题

104

回帖

179

积分

注册会员

积分
179
发表于 6 天前 | 显示全部楼层
谢谢分享
回复

使用道具 举报

0

主题

104

回帖

179

积分

注册会员

积分
179
发表于 5 天前 | 显示全部楼层
谢谢分享
回复

使用道具 举报

0

主题

12

回帖

12

积分

新手上路

积分
12
发表于 3 天前 | 显示全部楼层
看帖看完了至少要顶一下,还可以加入到淘帖哦!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-5-31 07:30 , Processed in 0.126610 second(s), 22 queries , Yac On.

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

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