注入Dll 阻止任务管理器结束进程 -- Win 10/11

任务管理器通过 NtQuerySystemInformation 获取进程信息,通过 TerminateProcess 以及 EndTask 等函数终止进程,我们可以通过挂钩途径中的多个R3函数实现在任务管理器中保护进程。网上有很多通过挂钩 TerminalProcess 来拦截终止功能的教程。这里从查找进程信息阶段拦截实现保护/隐身目标进程。

2024.05.24:近期有读者指出该代码不能够做到拦截的效果,我将抽空核实是否能够拦截,并研究解决方法。

这里需要注意的是,通过挂钩 SHParseDisplayName 可以进一步阻止右键菜单中的打开文件路径操作。

NtQuerySystemInformation 的定义如下:

NTSTATUS WINAPI NtQuerySystemInformation(
    _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_ _Out_ PVOID SystemInformation,
    _In_       ULONG SystemInformationLength,
    _Out_opt_  PULONG ReturnLength
);

其中,第一个参数是一个结构体,包含进程的信息,结构体是根据 ProcessHacker 网站的资料获得的:

typedef struct _SYSTEM_PROCESS_INFORMATION
{
    ULONG            NextEntryOffset; // 指向下一个结构体的指针
    ULONG            ThreadCount; // 本进程的总线程数
    ULONG            Reserved1[6]; // 保留
    LARGE_INTEGER    CreateTime; // 进程的创建时间
    LARGE_INTEGER    UserTime; // 在用户层的使用时间
    LARGE_INTEGER    KernelTime; // 在内核层的使用时间
    UNICODE_STRING   ImageName; // 进程名
    KPRIORITY        BasePriority; // 
    ULONG            ProcessId; // 进程ID
    ULONG            InheritedFromProcessId;
    ULONG            HandleCount; // 进程的句柄总数
    ULONG            Reserved2[2]; // 保留
    VM_COUNTERS      VmCounters;
    IO_COUNTERS      IoCounters;
    SYSTEM_THREAD_INFORMATION Threads[5]; // 子线程信息数组
}SYSTEM_PROCESS_INFORMATION, * PMY_SYSTEM_PROCESS_INFORMATION;

可以看出该接口返回的结构体包含链表结构,我们可以通过断链方法隐藏进程,或者通过记录查找到的进程信息,在联合挂钩 NtOpenProcess 等函数来保护进程。

// 一下记录最近20条的模式其实可以用栈来实现
DWORD pid[20] = { 0 };// 只记录最近的20个目标进程
int cnt = 0;// 计数
NTSTATUS WINAPI HookedNtQuerySystemInformation(
    _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_ _Out_ PVOID SystemInformation,
    _In_       ULONG SystemInformationLength,
    _Out_opt_  PULONG ReturnLength
) {
    bool flag = false;
    // 先正常调用原函数,获取返回值
    NTSTATUS status = ((__NtQuerySystemInformation)fpNtQuerySystemInformation)(SystemInformationClass,
        SystemInformation,
        SystemInformationLength,
        ReturnLength);
    // 判断是否是进程信息和调用是否成功
    if (SystemInformationClass == SystemProcessInformation && NT_SUCCESS(status)) {
        //MY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
        PMY_SYSTEM_PROCESS_INFORMATION pNext = (PMY_SYSTEM_PROCESS_INFORMATION)SystemInformation;

        // 单链表循环
        do
        {
            pNext = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pNext + pNext->NextEntryOffset);

            if (!wcsncmp(pNext->ImageName.Buffer, L"Notepad.exe", pNext->ImageName.Length))
            {
                flag = false;
                for (int i = 1; i <= cnt; i++)
                {
                    if (pid[i] == (DWORD)pNext->InheritedFromProcessId)
                        flag = true;
                }

                if (flag == false && cnt < 19)
                {
                    pid[++cnt] = (DWORD)pNext->InheritedFromProcessId;
                    pid[0] = cnt;
                }
                else if (flag == false && cnt >= 19)// 记录满了就清零
                {
                    cnt = 0;
                    pid[++cnt] = (DWORD)pNext->InheritedFromProcessId;
                    pid[0] = cnt;
                }
            }
        } while (pNext->NextEntryOffset != 0);
    }
    // 正常返回
    return status;
}

其他部分不在详细叙述,给出完整代码,需要注意的是,该挂钩只适用于 Taskmgr 不适用于procexp 等程序。

对于窗口程序,需要挂钩 SendMessageTimeout 函数,过滤其发出的 SC_CLOSE 消息,挂钩 NtOpenProcessNtOpenThread 可以阻止 ZwTerminateProcess 等函数,因为我们返回无效句柄。

完整代码:

#include "pch.h"
#include "detours.h"
#include <winternl.h>
#include <ShlObj.h>
#include <TlHelp32.h>

#pragma comment(lib, "detours.lib")


void StartHookingFunction();
void UnmappHookedFunction();


typedef struct _VM_COUNTERS
{
    SIZE_T        PeakVirtualSize;
    SIZE_T        VirtualSize;
    ULONG         PageFaultCount;
    SIZE_T        PeakWorkingSetSize;
    SIZE_T        WorkingSetSize;
    SIZE_T        QuotaPeakPagedPoolUsage;
    SIZE_T        QuotaPagedPoolUsage;
    SIZE_T        QuotaPeakNonPagedPoolUsage;
    SIZE_T        QuotaNonPagedPoolUsage;
    SIZE_T        PagefileUsage;
    SIZE_T        PeakPagefileUsage;
} VM_COUNTERS;

// 线程信息结构体
typedef struct _MY_SYSTEM_THREAD_INFORMATION
{
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG           WaitTime;
    PVOID           StartAddress;
    CLIENT_ID       ClientId;
    KPRIORITY       Priority;
    KPRIORITY       BasePriority;
    ULONG           ContextSwitchCount;
    LONG            State;// 状态,是THREAD_STATE枚举类型中的一个值
    LONG            WaitReason;//等待原因, KWAIT_REASON中的一个值
} MY_SYSTEM_THREAD_INFORMATION, * PMY_SYSTEM_THREAD_INFORMATION;


typedef struct _MY_UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} MY_UNICODE_STRING, * PMY_UNICODE_STRING;


typedef struct _MY_SYSTEM_PROCESS_INFORMATION
{
    ULONG            NextEntryOffset; // 指向下一个结构体的指针
    ULONG            ThreadCount; // 本进程的总线程数
    ULONG            Reserved1[6]; // 保留
    LARGE_INTEGER    CreateTime; // 进程的创建时间
    LARGE_INTEGER    UserTime; // 在用户层的使用时间
    LARGE_INTEGER    KernelTime; // 在内核层的使用时间
    MY_UNICODE_STRING   ImageName; // 进程名
    KPRIORITY        BasePriority; // 
    ULONG            ProcessId; // 进程ID
    ULONG            InheritedFromProcessId;
    ULONG            HandleCount; // 进程的句柄总数
    ULONG            Reserved2[2]; // 保留
    VM_COUNTERS      VmCounters;
    IO_COUNTERS      IoCounters;
    SYSTEM_THREAD_INFORMATION Threads[5]; // 子线程信息数组
}MY_SYSTEM_PROCESS_INFORMATION, * PMY_SYSTEM_PROCESS_INFORMATION;

#define STDAPICALLTYPE __stdcall

// 定义一个指针函数类型
typedef NTSTATUS(WINAPI* __NtQuerySystemInformation)(
    _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_ _Out_ PVOID SystemInformation,
    _In_       ULONG SystemInformationLength,
    _Out_opt_  PULONG ReturnLength
    );

typedef HANDLE (WINAPI* __OpenProcess)(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwProcessId
    );

typedef HANDLE (WINAPI* __OpenThread)(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwThreadId
);

typedef LRESULT (WINAPI* __SendMessageW)(
    _In_   HWND   hWnd,
    _In_   UINT   Msg,
    _In_   WPARAM wParam,
    _In_   LPARAM lParam
);

typedef LRESULT(WINAPI* __SendMessageTimeoutW)(
    _In_       HWND       hWnd,
    _In_       UINT       Msg,
    _In_       WPARAM     wParam,
    _In_       LPARAM     lParam,
    _In_       UINT       fuFlags,
    _In_       UINT       uTimeout,
    _Out_opt_  PDWORD_PTR lpdwResult
);

typedef HRESULT (STDAPICALLTYPE* __SHParseDisplayName)(
    _In_            PCWSTR           pszName,
    _In_opt_        IBindCtx* pbc,
    _Out_           PIDLIST_ABSOLUTE* ppidl,
    _In_            SFGAOF           sfgaoIn,
    _Out_opt_       SFGAOF* psfgaoOut
);

typedef BOOL (WINAPI* __EndTask)(
    _In_ HWND hWnd,
    _In_ BOOL fShutDown,
    _In_ BOOL fForce
);

// 定义一个存放原函数的指针
PVOID fpNtQuerySystemInformation = NULL;
PVOID fpOpenProcess = NULL;
PVOID fpOpenThread = NULL;
PVOID fpSendMessageTimeout = NULL;
PVOID fpSendMessage = NULL;
PVOID fpSHParseDisplayName = NULL;
PVOID fpEndTask = NULL;

// 全局变量
DWORD pid[20]{};
int cnt = 0;

NTSTATUS WINAPI HookedNtQuerySystemInformation(
    _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_ _Out_ PVOID SystemInformation,
    _In_       ULONG SystemInformationLength,
    _Out_opt_  PULONG ReturnLength
);

HANDLE WINAPI HookedOpenProcess(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwProcessId
);

HANDLE WINAPI HookedOpenThread(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwThreadId
);

LRESULT WINAPI HookedSendMessageW(
    _In_   HWND   hWnd,
    _In_   UINT   Msg,
    _In_   WPARAM wParam,
    _In_   LPARAM lParam
    );

LRESULT WINAPI HookedSendMessageTimeout(
    _In_       HWND       hWnd,
    _In_       UINT       Msg,
    _In_       WPARAM     wParam,
    _In_       LPARAM     lParam,
    _In_       UINT       fuFlags,
    _In_       UINT       uTimeout,
    _Out_opt_  PDWORD_PTR lpdwResult
);

HRESULT STDAPICALLTYPE HookedSHParseDisplayName(
    _In_            PCWSTR           pszName,
    _In_opt_        IBindCtx* pbc,
    _Out_           PIDLIST_ABSOLUTE* ppidl,
    _In_            SFGAOF           sfgaoIn,
    _Out_opt_       SFGAOF* psfgaoOut
);

BOOL WINAPI HookedEndTask(
    _In_ HWND hWnd,
    _In_ BOOL fShutDown,
    _In_ BOOL fForce
);

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    DisableThreadLibraryCalls(hModule);
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        StartHookingFunction();
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        UnmappHookedFunction();
        break;
    }
    return TRUE;
}

void StartHookingFunction()
{
    //开始事务
    DetourTransactionBegin();
    //更新线程信息  
    DetourUpdateThread(GetCurrentThread());

    fpNtQuerySystemInformation =
        DetourFindFunction(
            "ntdll.dll",
            "NtQuerySystemInformation");
    fpOpenProcess =
        DetourFindFunction(
            "kernel32.dll",
            "OpenProcess");
    fpOpenThread =
        DetourFindFunction(
            "kernel32.dll",
            "OpenThread");
    fpSendMessage =
        DetourFindFunction(
            "user32.dll",
            "SendMessageW");
    fpSendMessageTimeout =
        DetourFindFunction(
            "user32.dll",
            "SendMessageTimeoutW");
    fpSHParseDisplayName =
        DetourFindFunction(
            "shell32.dll",
            "SHParseDisplayName");
    fpEndTask =
        DetourFindFunction(
            "user32.dll",
            "EndTask");
    //将拦截的函数附加到原函数的地址上,这里可以拦截多个函数。
    DetourAttach(&(PVOID&)fpNtQuerySystemInformation,
        HookedNtQuerySystemInformation);
    DetourAttach(&(PVOID&)fpOpenProcess,
        HookedOpenProcess);
    DetourAttach(&(PVOID&)fpOpenThread,
        HookedOpenThread);
    DetourAttach(&(PVOID&)fpSendMessage,
        HookedSendMessageW);
    DetourAttach(&(PVOID&)fpSendMessageTimeout,
        HookedSendMessageTimeout);
    DetourAttach(&(PVOID&)fpSHParseDisplayName,
        HookedSHParseDisplayName);
    DetourAttach(&(PVOID&)fpSHParseDisplayName,
        HookedSHParseDisplayName);
    DetourAttach(&(PVOID&)fpEndTask,
        HookedEndTask);
    //结束事务
    DetourTransactionCommit();
}

void UnmappHookedFunction()
{
    //开始事务
    DetourTransactionBegin();
    //更新线程信息 
    DetourUpdateThread(GetCurrentThread());

    //将拦截的函数从原函数的地址上解除,这里可以解除多个函数。
    DetourDetach(&(PVOID&)fpNtQuerySystemInformation,
        HookedNtQuerySystemInformation);
    DetourDetach(&(PVOID&)fpOpenProcess,
        HookedOpenProcess);
    DetourDetach(&(PVOID&)fpOpenThread,
        HookedOpenThread);
    DetourDetach(&(PVOID&)fpSendMessage,
        HookedSendMessageW);
    DetourDetach(&(PVOID&)fpSendMessageTimeout,
        HookedSendMessageTimeout);
    DetourDetach(&(PVOID&)fpSHParseDisplayName,
        HookedSHParseDisplayName);
    DetourDetach(&(PVOID&)fpEndTask,
        HookedEndTask);
    //结束事务
    DetourTransactionCommit();
}


// 定义一个Hook函数,隐藏指定进程名程序
NTSTATUS WINAPI HookedNtQuerySystemInformation(
    _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_ _Out_ PVOID SystemInformation,
    _In_       ULONG SystemInformationLength,
    _Out_opt_  PULONG ReturnLength
) {
    bool flag = false;
    // 先正常调用原函数,获取返回值
    NTSTATUS status = ((__NtQuerySystemInformation)fpNtQuerySystemInformation)(SystemInformationClass,
        SystemInformation,
        SystemInformationLength,
        ReturnLength);
    // 判断是否是进程信息和调用是否成功
    if (SystemInformationClass == SystemProcessInformation && NT_SUCCESS(status)) {
        //MY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
        PMY_SYSTEM_PROCESS_INFORMATION pNext = (PMY_SYSTEM_PROCESS_INFORMATION)SystemInformation;

        // 单链表循环
        do
        {
            //pCurrent = pNext;
            pNext = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pNext + pNext->NextEntryOffset);

            if (!wcsncmp(pNext->ImageName.Buffer, L"Notepad.exe", pNext->ImageName.Length))
            {
                flag = false;
                for (int i = 1; i <= cnt; i++)
                {
                    if (pid[i] == (DWORD)pNext->InheritedFromProcessId)
                        flag = true;
                    //pid = (DWORD)pNext->UniqueProcessId;
                }

                if (flag == false && cnt < 19)
                {
                    pid[++cnt] = (DWORD)pNext->InheritedFromProcessId;
                    pid[0] = cnt;
                    //ListProcessThreads((DWORD)pNext->UniqueProcessId);
                }
                else if (flag == false && cnt >= 19)
                {
                    cnt = 0;
                    pid[++cnt] = (DWORD)pNext->InheritedFromProcessId;
                    pid[0] = cnt;
                    //ListProcessThreads((DWORD)pNext->UniqueProcessId);
                }
            }
        } while (pNext->NextEntryOffset != 0);
    }
    // 正常返回
    return status;
}

HANDLE WINAPI HookedOpenProcess(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwProcessId
)
{
    if ((int)pid[0] > 1) {
        for (int i = (int)pid[0]; i >= 1; i--) {
            if (dwProcessId == pid[i])
            {
                SetLastError(5);
                return NULL;
            } 
        }
        return ((__OpenProcess)fpOpenProcess)(dwDesiredAccess, bInheritHandle, dwProcessId);
    }
    else if ((int)pid[0] == 1) {
        if (dwProcessId == pid[1])
        {
            SetLastError(5);
            return NULL;
        }
        else
        {
            return ((__OpenProcess)fpOpenProcess)(dwDesiredAccess, bInheritHandle, dwProcessId);
        }
    }
    else
    {
        return ((__OpenProcess)fpOpenProcess)(dwDesiredAccess, bInheritHandle, dwProcessId);
    }
}

HANDLE WINAPI HookedOpenThread(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL  bInheritHandle,
    _In_ DWORD dwThreadId
)
{
    DWORD dwProtectedTid = 0;
    HWND hTargetWnd = FindWindowW(L"Notepad", NULL);
    if (hTargetWnd != NULL)
    {
        dwProtectedTid = GetWindowThreadProcessId(hTargetWnd, NULL);
    }

    if (dwProtectedTid != 0 && dwThreadId == dwProtectedTid)
    {
        SetLastError(5);
        return NULL;
    }
    return ((__OpenThread)fpOpenThread)(dwDesiredAccess, bInheritHandle, dwThreadId);
}

LRESULT WINAPI HookedSendMessageW(
    _In_   HWND   hWnd,
    _In_   UINT   Msg,
    _In_   WPARAM wParam,
    _In_   LPARAM lParam
)
{
    //DWORD curprocid = 0;
    
    if (hWnd == 0)
        return E_FAIL;

    if ((hWnd == HWND_BROADCAST ) && (Msg == WM_DESTROY || Msg == WM_QUIT || Msg == WM_CLOSE))
    {
        SetLastError(5);
        return E_FAIL;
    }

    if (hWnd != NULL)
    {
        int Target = NULL;
        WCHAR ClassName[500]{};
        Target = GetClassNameW(hWnd, ClassName, sizeof(ClassName) / sizeof(WCHAR));
        if (!wcscmp(ClassName, L"Notepad"))
        {
            SetLastError(5);
            return E_FAIL;
        }
        else return ((__SendMessageW)fpSendMessage)(hWnd, Msg, wParam, lParam);
    }
    return ((__SendMessageW)fpSendMessage)(hWnd, Msg, wParam, lParam);
}

LRESULT WINAPI HookedSendMessageTimeout(
    _In_       HWND       hWnd,
    _In_       UINT       Msg,
    _In_       WPARAM     wParam,
    _In_       LPARAM     lParam,
    _In_       UINT       fuFlags,
    _In_       UINT       uTimeout,
    _Out_opt_  PDWORD_PTR lpdwResult
)
{
    if (hWnd != NULL)
    {
        int Target = NULL;
        WCHAR ClassName[500]{};
        Target = GetClassNameW(hWnd, ClassName, sizeof(ClassName) / sizeof(WCHAR));
        if (!wcscmp(ClassName, L"Notepad") && Msg == WM_SYSCOMMAND && wParam == SC_CLOSE)
        {
            return S_FALSE;
        }
    }
    return ((__SendMessageTimeoutW)fpSendMessageTimeout)
        (hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
}

HRESULT STDAPICALLTYPE HookedSHParseDisplayName(
    _In_            PCWSTR               pszName,
    _In_opt_        IBindCtx*            pbc,
    _Out_           PIDLIST_ABSOLUTE*    ppidl,
    _In_            SFGAOF               sfgaoIn,
    _Out_opt_       SFGAOF*              psfgaoOut
)
{
    if (wcsstr(pszName, L"Notepad.exe"))
        return ((__SHParseDisplayName)fpSHParseDisplayName)
        (L"C:\\Windows\\explorer.exe", pbc, ppidl, sfgaoIn, psfgaoOut);
    else 
        return ((__SHParseDisplayName)fpSHParseDisplayName)
        (pszName, pbc, ppidl, sfgaoIn, psfgaoOut);
}


BOOL WINAPI HookedEndTask(
    _In_ HWND hWnd,
    _In_ BOOL fShutDown,
    _In_ BOOL fForce
)
{
    int Target = NULL;
    WCHAR ClassName[500]{};
    Target = GetClassNameW(hWnd, ClassName, sizeof(ClassName) / sizeof(WCHAR));

    if (Target != NULL && !wcscmp(ClassName, L"Notepad"))
    {
        SetLastError(5);
        return FALSE;
    }
    else return ((__EndTask)fpEndTask)(hWnd, fShutDown, fForce);
}

程序运行效果如下图所示:


转载请注明出处:Detours挂钩实现进程保护(任务管理器) 

发布于:2023.10.05,更新于:2023.10.14, 2024.05.24.

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涟幽516

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值