吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 825|回复: 19
上一主题 下一主题
收起左侧

[系统底层] 手搓Nt*或Zw*函数,避免被hook 支持x86_x64

  [复制链接]
跳转到指定楼层
楼主
wtujoxk 发表于 2024-11-6 12:09 回帖奖励
本帖最后由 wtujoxk 于 2024-11-6 13:39 编辑

仅学习,如有错误请指出…………

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

原理:

1、利用CreateFile创建文件

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) return functionAddress;

2、把系统目录里ntdll.dll读入内存

//把ntdll读入进内存
DWORD dwRead = 0;
DWORD dwSize = GetFileSize(hFile, &dwRead);
BYTE* pBuff = new BYTE[dwSize];
RtlZeroMemory(pBuff, sizeof(pBuff));
ReadFile(hFile, pBuff, dwSize, &dwRead, NULL);

3、用程序里的Nt函数地址找到读入内存的ntdll.dll的foa地址

PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
#ifdef _WIN64
PIMAGE_NT_HEADERS64 pNtHeader = (PIMAGE_NT_HEADERS64)(pDosHeader->e_lfanew + ((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader)) + sizeof(IMAGE_NT_HEADERS64));
#else
PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + ((ULONG_PTR)pDosHeader));
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader)) + sizeof(IMAGE_NT_HEADERS32));
#endif
ULONG_PTR foaAddress = 0;
//Nt函数地址 - ntdll基址 = rva
ULONG_PTR rva = apiAddress - (ULONG_PTR)dllHandle;
for (WORD i = 0; i < pNtHeader->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;
    }
}

4、使用foa地址去读取出opcode,32位程序opcode码,va地址和foa不一致,需要处理,64位无需处理

//opcode读取
int opcodeOffset = 0;
#ifdef _WIN64
while (true)
{
    //x64位opcode读取
    functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));
    if (*(BYTE*)(pBuff + foaAddress + opcodeOffset) == 0xC3) //遇到ret指令结束
    {
        //C3       ret
        //CD 2E    int 2E
        //C3       ret
        //遇到C3后还要追加int 2E ret指令
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //CD
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //2E
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //C3
        break;
    }
    ++opcodeOffset;
}
#else
while (true)
{
    //x86位opcode读取
    if (*(BYTE*)(pBuff + foaAddress + opcodeOffset) == 0xC2 && opcodeOffset > 10) //遇到ret指令结束
    {
        //C2 2000   ret 20
        //遇到C2后还要追加返回值opcode
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));  //C2
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //20
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //00
        break;
    }
    //x86 opcode在8、9位时foa值与va值不同,需要特殊处理
    else if (opcodeOffset == 8 || opcodeOffset == 9)
    {
        functionBytes.push_back(*(BYTE*)(apiAddress + opcodeOffset));
    }
    else
    {
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));
    }
    ++opcodeOffset;
}
#endif

5、申请内存把opcode码写入到新内存

//申请堆空间执行汇编代码
int sizeCustomFunction = functionBytes.size();
functionAddress = (BYTE*)VirtualAlloc(0, sizeCustomFunction, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
for (int j = 0; j < sizeCustomFunction; j++)
{
    //写入opcode到新内存,执行汇编代码
    *(functionAddress + j) = functionBytes[j];
}

6、使用演示

//NtGetContextThread
typedef BOOL(NTAPI* PNtGetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtGetContextThread pZwGetContextThread;
BOOL MyNtGetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
        pZwGetContextThread = (PNtGetContextThread)CustomNtFunction("NtGetContextThread");
        return pZwGetContextThread(hThread, lpContext);
}
//NtSetContextThread
typedef BOOL(CALLBACK* PNtSetContextThread)(HANDLE hThread, LPCONTEXT lpContext);
PNtSetContextThread pZwSetContextThread;
BOOL MyNtSetContextThread(HANDLE hThread, LPCONTEXT lpContext)
{
        pZwGetContextThread = (PNtSetContextThread)CustomNtFunction("NtSetContextThread");
        return pZwGetContextThread(hThread, lpContext);
}
//NtProtectVirtualMemory
typedef BOOL(NTAPI* PNtProtectVirtualMemory)(HANDLE hProcess, PVOID* lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
BOOL MyNtProtectVirtualMemory(HANDLE hProcess, PVOID* lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect)
{
        // 将函数名转换为地址并执行
        pNtProtectVirtualMemory = (PNtProtectVirtualMemory)CustomNtFunction("NtProtectVirtualMemory");
        return pNtProtectVirtualMemory(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}

完整代码如下:

BYTE* CustomNtFunction(const char* functionName)
{
    std::vector<BYTE> functionBytes;
    BYTE* functionAddress = 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) return functionAddress;
    HMODULE dllHandle = LoadLibraryA(dllPath);
    ULONG_PTR apiAddress = (ULONG_PTR)GetProcAddress(dllHandle, functionName);

    //把ntdll读入进内存
    DWORD dwRead = 0;
    DWORD dwSize = GetFileSize(hFile, &dwRead);
    BYTE* pBuff = new BYTE[dwSize];
    RtlZeroMemory(pBuff, sizeof(pBuff));
    ReadFile(hFile, pBuff, dwSize, &dwRead, NULL);

    //通过apiAddress地址获取函数的foa地址
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
#ifdef _WIN64
    PIMAGE_NT_HEADERS64 pNtHeader = (PIMAGE_NT_HEADERS64)(pDosHeader->e_lfanew + ((ULONG_PTR)pDosHeader));
    PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader)) + sizeof(IMAGE_NT_HEADERS64));
#else
    PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + ((ULONG_PTR)pDosHeader));
    PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(((ULONG_PTR)(pNtHeader)) + sizeof(IMAGE_NT_HEADERS32));
#endif
    ULONG_PTR foaAddress = 0;
    //Nt函数地址 - ntdll基址 = rva
    ULONG_PTR rva = apiAddress - (ULONG_PTR)dllHandle;
    for (WORD i = 0; i < pNtHeader->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;
        }
    }

    //opcode读取
    int opcodeOffset = 0;
#ifdef _WIN64
    while (true)
    {
        //x64位opcode读取
        functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));
        if (*(BYTE*)(pBuff + foaAddress + opcodeOffset) == 0xC3) //遇到ret指令结束
        {
            //C3       ret
            //CD 2E    int 2E
            //C3       ret
            //遇到C3后还要追加int 2E ret指令
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //CD
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //2E
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //C3
            break;
        }
        ++opcodeOffset;
    }
#else
    while (true)
    {
        //x86位opcode读取
        if (*(BYTE*)(pBuff + foaAddress + opcodeOffset) == 0xC2 && opcodeOffset > 10) //遇到ret指令结束
        {
            //C2 2000   ret 20
            //遇到C2后还要追加返回值opcode
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));  //C2
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //20
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + ++opcodeOffset)); //00
            break;
        }
        //x86 opcode在8、9位时foa值与va值不同,需要特殊处理
        else if (opcodeOffset == 8 || opcodeOffset == 9)
        {
            functionBytes.push_back(*(BYTE*)(apiAddress + opcodeOffset));
        }
        else
        {
            functionBytes.push_back(*(BYTE*)(pBuff + foaAddress + opcodeOffset));
        }
        ++opcodeOffset;
    }
#endif

    //申请堆空间执行汇编代码
    int sizeCustomFunction = functionBytes.size();
    functionAddress = (BYTE*)VirtualAlloc(0, sizeCustomFunction, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    for (int j = 0; j < sizeCustomFunction; j++)
    {
        //写入opcode到新内存,执行汇编代码
        *(functionAddress + j) = functionBytes[j];
    }

    delete[] pBuff; pBuff = NULL;
    CloseHandle(hFile);
    return functionAddress;
}

//NtProtectVirtualMemory
typedef BOOL(NTAPI* PNtProtectVirtualMemory)(HANDLE hProcess, PVOID* lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect);
PNtProtectVirtualMemory pNtProtectVirtualMemory;
BOOL MyNtProtectVirtualMemory(HANDLE hProcess, PVOID* lpAddress, PSIZE_T dwSize, ULONG flNewProtect, PULONG lpflOldProtect)
{
    // 将函数名转换为地址并执行
    pNtProtectVirtualMemory = (PNtProtectVirtualMemory)CustomNtFunction("NtProtectVirtualMemory");
    return pNtProtectVirtualMemory(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}

最后,实战一个VMP加壳的程序,此程序正常情况下无法修改内存属性

程序下载地址:https://nns.lanzouu.com/iiMLu2ee6sxi

补丁工程文件: winmm补丁工程文件.zip (176.86 KB, 下载次数: 34, 售价: 15 CB吾爱币)

免费评分

参与人数 6吾爱币 +8 热心值 +6 收起 理由
156608225 + 2 + 1 用心讨论,共获提升!
Issacclark1 + 1 谢谢@Thanks!
hunfeifei + 1 + 1 我很赞同!
朱朱你堕落了 + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
SnowRen + 1 + 1 我很赞同!
海水很咸 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
hunfeifei 发表于 2024-11-6 15:51
感谢分享。之前也被VMP的保护坑过。做过这个。后来发现只要 openprocess 一下 ,句柄不用 -1 就可以了
沙发
lc2006 发表于 2024-11-6 12:59
3#
yaoguen 发表于 2024-11-6 13:07
4#
wshq 发表于 2024-11-6 13:51
感谢分享
5#
hbfp 发表于 2024-11-6 14:07
收藏学习,谢谢
7#
影风 发表于 2024-11-6 15:54
shadow api??
8#
wuai52001 发表于 2024-11-6 16:53

感谢分享。
9#
sherlock0209 发表于 2024-11-6 17:24
牛啊,牛啊
10#
910jqkAAAA 发表于 2024-11-6 17:37
还得是你啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-7 04:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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