返回

Win11任务管理器进程描述自定义:SetProcessDescription详解

windows

Windows 11 任务管理器“”列:自定义你的进程

Windows 任务管理器的“详细信息”选项卡里,每个进程都有个“描述”列。以前,这列显示的是进程主程序文件里的描述信息。

但 Windows 11 好像不太一样了。比如 WebView2,它跟 Chromium 差不多,一个程序能跑多个子进程。怪的是,Windows 11 的任务管理器里,这些子进程的“描述”列五花八门:

Task Manager

这些进程明明用的都是同一个程序文件,可任务管理器却显示不同的描述。原来的文件描述还在,但好像有啥新方法能盖过它,用程序自己提供的描述。而且,好像只有任务管理器认这个新描述,Process Explorer 最新版都看不出来。

我搜了半天,愣是没找到相关文档(甚至都没人提过这事儿!),大多数讨论说的还是 Windows 11 之前的任务管理器。

这到底咋回事?普通 Win32 程序能用这个功能吗?(我有个程序也是多进程、单文件的架构,要是能给每个进程加个 ప్రత్యేక的描述,那可太方便了!)

问题根源:Windows 11 的新特性

经过一番挖掘和测试, 基本确定了是 Windows 11 引入了一套新的机制, 允许程序在运行时动态修改任务管理器中显示的进程描述。

以前, 任务管理器的"描述"列通常读取自可执行文件的 VERSIONINFO 资源中的 FileDescription 字段。 但现在,进程可以通过一些 API 来覆盖这个默认值。虽然目前缺乏官方文档, 但可以通过对 WebView2 进程行为的逆向工程, 大致了解其实现原理。

解决方案:多种途径自定义进程描述

针对这个问题,目前有以下几种方法,可以实现自定义进程

1. SetProcessDescription API (推荐)

这是最直接、最推荐的方法。Windows 11 新增了 SetProcessDescription API,可以直接设置当前进程的描述。

原理:

SetProcessDescription 函数直接修改了进程的某个内部结构,从而让任务管理器显示自定义的描述。这个修改是进程级别的,不会影响到可执行文件本身。

代码示例 (C++):

#include <Windows.h>
#include <iostream>

int main() {
    // 设置进程描述
    HRESULT hr = SetProcessDescription(GetCurrentProcess(), L"我的自定义进程描述");

    if (SUCCEEDED(hr)) {
        std::wcout << L"进程描述设置成功!" << std::endl;
    } else {
        std::wcerr << L"进程描述设置失败,错误码:" << hr << std::endl;
    }

    //  程序其余部分...
     std::cin.get(); //保持窗口
    return 0;
}

编译和运行:

  1. 将代码保存为 .cpp 文件 (例如 SetProcessDesc.cpp)。
  2. 使用 Visual Studio 或其他 C++ 编译器编译:
    cl.exe SetProcessDesc.cpp /link User32.lib
    
  3. 运行生成的可执行文件。
  4. 打开任务管理器,在“详细信息”选项卡中查看进程描述是否已更改。

安全建议:

  • 确保传入的描述字符串长度合理, 避免过长导致显示问题或潜在的缓冲区溢出。

进阶技巧:

  • 你可以在程序的任何地方调用 SetProcessDescription,动态更新进程描述。 比如, 可以根据进程当前的状态或任务来改变描述。

2. 修改 PEB (进程环境块) (不推荐, 仅供研究)

这种方法更底层, 直接操作进程的 PEB。 但不推荐 在生产环境中使用, 因为它依赖于未公开的 Windows 内部结构, 稳定性无法保证, 且可能在未来的 Windows 版本中失效。

原理:

任务管理器显示的进程描述,最终是从进程环境块 (PEB) 中的某个字段读取的。 理论上,可以通过直接修改 PEB 来改变描述。

代码示例 (C++):

// 警告:此代码仅用于研究目的,不建议在生产环境中使用!
#include <Windows.h>
#include <winternl.h>
#include <iostream>

typedef NTSTATUS(NTAPI* _NtQueryInformationProcess)(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
    );

typedef struct _PROCESS_BASIC_INFORMATION2 {
    PVOID Reserved1[5]; // Changed ULONG_PTR to PVOID[5]
    PPEB PebBaseAddress;
    PVOID Reserved2[4];  // Changed ULONG_PTR to PVOID[4]
    ULONG_PTR UniqueProcessId;
    ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION2;

int main()
{

    //加载 ntdll.dll
    HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
    if (hNtdll == NULL)
    {
        std::cerr << "Failed to get ntdll.dll handle" << std::endl;
        return 1;
    }
    //获取 NtQueryInformationProcess 函数的地址
    _NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");

    if (NtQueryInformationProcess == NULL) {
      std::cerr << "获取 NtQueryInformationProcess 函数的地址失败" << std::endl;
       return 1;
    }

      // 获取当前进程的 PEB 地址
      PROCESS_BASIC_INFORMATION2 pbi;
    DWORD returnLength;
        //  获取当前进程的基本信息
        NTSTATUS status = NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), (PULONG)&returnLength);
    if (!NT_SUCCESS(status)) {
           std::wcerr << L"NtQueryInformationProcess失败. 状态码: "  <<  std::hex <<status << std::endl;
        return 1;
    }
    PPEB peb = pbi.PebBaseAddress;

    // 确保 PEB 指针有效
     if (!peb) {
         std::cerr << "无效的 PEB 地址" << std::endl;
          return 1;
    }
     if (IsBadReadPtr(peb, sizeof(PEB))) {
          std::cerr << "无法读取 PEB" << std::endl;
         return 1;
    }
     //设置进程描述
      wchar_t newDescription[] = L"My New Process Description";

      // 写入新的进程描述(注意:直接修改 PEB 很危险!)
      // 直接操作内存, 请务必小心!
     size_t descSize = sizeof(newDescription);
    if (IsBadWritePtr(peb->ProcessParameters->WindowTitle.Buffer, peb->ProcessParameters->WindowTitle.MaximumLength ))
    {
        std::cerr << "无法写入 ProcessParameters->WindowTitle" << std::endl;
        return 1;

    }

    RtlCopyMemory(peb->ProcessParameters->WindowTitle.Buffer, newDescription, descSize > peb->ProcessParameters->WindowTitle.MaximumLength ? peb->ProcessParameters->WindowTitle.MaximumLength: descSize);

    //触发重新显示描述 (非必要, 因为任务管理器会定期刷新)

    std::wcout << L"尝试修改 PEB... 在任务管理器中查看结果" << std::endl;

      //保持窗口.
    std::cin.get();
    return 0;
}

编译与运行 :

  1. 跟方法一类似,将上面代码保存为 .cpp 文件。
  2. 同样用 Visual Studio 或兼容的 C++ 编译器编译。 这次需要链接 ntdll.lib:
    cl.exe  SetPebDescription.cpp /link  ntdll.lib User32.lib
    
    可能需要设置编译器的 Additional Library Directories, 指向包含 ntdll.lib 的目录。
  3. 以管理员权限运行程序,否则没有权限修改 PEB。

严重警告:

  • 直接操作 PEB 风险极高! 可能导致程序崩溃,甚至系统不稳定。
  • 这段代码仅为演示, 说明有这种可能的修改途径。 实测有时有效, 有时无效. 不建议使用.
  • 上述代码还可能因为安全软件的保护, 导致无法工作.

3. 利用其他工具(如果存在)

将来可能有第三方工具提供更方便的设置界面。 目前还未发现有此类工具。

总结:

虽然官方文档缺失,但我们找到了修改 Windows 11 任务管理器进程描述的方法。 SetProcessDescription API 是首选方案,安全可靠。 修改 PEB 的方法仅用于研究,不建议实际使用。