C#隐藏任务管理器中进程 支持win10 win8.1 win7

时间:2022-08-10 14:57:58

网上的都不能用啊…全是未完成代码或者兼容性极差的代码。自己写呗。
任务管理器实际上是用了SysListView32控件,所以发点消息就可以解决(但是发点消息也没那么容易)
ListView_GetItemText宏只是对当前进程有效,对远程进程是无效的,但是label之类的控件gettext对远程进程是有效的,具体的可以看《Windows via C/C++》中文第5版第579面(只是记得有这个特性,但不记得书中多少面提到了。特地翻书找到了这一面,不容易)。

成品:http://download.csdn.net/download/wwh1004/10244689

比较关键的代码在下面

/// <summary>
/// 读取字符串,如果读取到非托管进程中,并且读取为LPSTR LPWSTTR BSTR等字符串类型,请自行转换为byte[]并使用<see cref="ReadBytes(uint, Pointer, byte[])"/><see cref="ReadBytes(uint, IntPtr, byte[])"/>
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="addr">地址</param>
/// <param name="value"></param>
/// <param name="bufferSize">缓存大小</param>
/// <param name="doubleZero">是否以2个\0结尾(比如LPWSTR以2个字节\0结尾,而LPSTR以1个字节\0结尾)</param>
/// <param name="encoding">编码</param>
/// <returns></returns>
internal static unsafe bool ReadStringInternal(IntPtr processHandle, IntPtr addr, out string value, int bufferSize, bool doubleZero, Encoding encoding)
{
    if (encoding == null)
        throw new ArgumentNullException(nameof(encoding) + "不能为null");
    if (bufferSize <= 0)
        throw new ArgumentOutOfRangeException(nameof(bufferSize) + "小于等于0");

    byte[] buffer;
    uint numberOfBytesRead;
    List<byte> bufferList;
    bool lastByteIsZero;

    buffer = null;
    numberOfBytesRead = 0;
    bufferList = new List<byte>(bufferSize);
    lastByteIsZero = false;
    for (int i = 0; i < int.MaxValue; i++)
    {
        buffer = new byte[bufferSize];
        ReadProcessMemory(processHandle, addr + bufferSize * i, buffer, (uint)bufferSize, &numberOfBytesRead);
        //读取到缓存
        if ((int)numberOfBytesRead == bufferSize)
        {
            //读取完整
            for (int j = 0; j < bufferSize; j++)
            {
                if (buffer[j] == 0)
                {
                    //出现\0
                    if (doubleZero)
                    {
                        //如果双\0结尾
                        if (lastByteIsZero)
                            //上一个字节为\0
                            goto addLastRange;
                        if (j + 1 != bufferSize)
                        {
                            //不是缓存区最后一个字节
                            if (buffer[j + 1] == 0)
                                //下一个字节也为\0
                                goto addLastRange;
                        }
                        else
                            //缓存读完,标记上一个字节为\0
                            lastByteIsZero = true;
                    }
                    else
                        //不是2个\0结尾,直接跳出
                        goto addLastRange;
                }
                else
                {
                    if (lastByteIsZero)
                        //上一个字节为\0,但当前字节不是
                        lastByteIsZero = false;
                }
            }
        }
        else if (numberOfBytesRead == 0)
        {
            //读取失败
            value = null;
            return false;
        }
        else
        {
            //读取不完整
            for (int j = 0; j < (int)numberOfBytesRead; j++)
            {
                if (buffer[j] == 0)
                {
                    //出现\0
                    if (doubleZero)
                    {
                        //如果双\0结尾
                        if (lastByteIsZero)
                            //上一个字节为\0
                            goto addLastRange;
                        if (j + 1 != (int)numberOfBytesRead && buffer[j + 1] == 0)
                            //不是缓存区最后一个字节且下一个字节也为\0
                            goto addLastRange;
                    }
                    else
                        //不是2个\0结尾,直接跳出
                        goto addLastRange;
                }
                else
                {
                    if (lastByteIsZero)
                        //上一个字节为\0,但当前字节不是
                        lastByteIsZero = false;
                }
            }
        }
        bufferList.AddRange(buffer);
    };
    addLastRange:
    numberOfBytesRead -= doubleZero ? 2u : 1u;
    for (int i = 0; i < (int)numberOfBytesRead; i++)
        bufferList.Add(buffer[i]);
    if (encoding.CodePage == Encoding.Unicode.CodePage)
        buffer = bufferList.ToArray();
    else
        buffer = Encoding.Convert(encoding, Encoding.Unicode, bufferList.ToArray());
    fixed (void* p = &buffer[0])
        value = new string((char*)p);
    return true;
}

/// <summary>
/// 在远程进程中读取结构
/// </summary>
/// <typeparam name="TStruct"></typeparam>
/// <param name="hWnd">控件句柄</param>
/// <param name="structure">读取出的结构体</param>
/// <param name="callbackBeforeRead">读取前回调方法</param>
/// <param name="callbackAfterRead">读取后回调方法</param>
/// <returns></returns>
public static unsafe bool ReadStructRemote<TStruct>(IntPtr hWnd, out TStruct structure, Func<IntPtr, IntPtr, bool> callbackBeforeRead, Func<IntPtr, IntPtr, bool> callbackAfterRead) where TStruct : IWin32ControlStruct
{
    uint processId;
    IntPtr hProcess;
    bool is64;
    IntPtr remoteAddr;

    structure = default(TStruct);
    processId = Process.GetProcessIdByHWnd(hWnd);
    //获取控件所在进程ID
    hProcess = OpenProcessRWQuery(processId);
    //打开进程
    if (hProcess == IntPtr.Zero)
        return false;
    if (!Process.Is64ProcessInternal(hProcess, out is64))
        return false;
    if (is64 && !Environment.Is64BitProcess)
        throw new NotSupportedException("目标进程为64位但当前进程为32位");
    try
    {
        remoteAddr = VirtualAllocEx(hProcess, IntPtr.Zero, structure.Size, MEM_COMMIT, PAGE_READWRITE);
        //在控件所在进程分配内存,用于储存structure
        try
        {
            if (callbackBeforeRead != null)
                if (!callbackBeforeRead(hProcess, remoteAddr))
                    return false;
            if (!ReadProcessMemory(hProcess, remoteAddr, structure.ToPointer(), structure.Size, null))
                //从远程进程取回到当前进程失败
                return false;
            if (callbackAfterRead != null)
                if (!callbackAfterRead(hProcess, remoteAddr))
                    return false;
            return true;
        }
        finally
        {
            VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
            //释放之前分配的内存
        }
    }
    finally
    {
        CloseHandle(hProcess);
        //关闭句柄
    }
}

/// <summary>
/// 获取列表视图控件中Item的文本
/// </summary>
/// <param name="i">The index of the list-view item.</param>
/// <param name="iSubItem">The index of the subitem. To retrieve the item text, set iSubItem to zero.</param>
/// <returns></returns>
public unsafe string GetItemText(int i, int iSubItem)
{
    LVITEM item;
    IntPtr pStr;
    string text;

    text = null;
    pStr = IntPtr.Zero;
    item = new LVITEM
    {
        iSubItem = iSubItem,
        cchTextMax = 0x1000
    };
    Util.WriteStructRemote(Handle, ref item, (IntPtr hProcess, IntPtr addr) =>
    {
        pStr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, MEM_COMMIT, PAGE_READWRITE);
        //分配内存用于写入字符串
        if (pStr == IntPtr.Zero)
            return false;
        item.pszText = (char*)pStr;
        //设置缓存区地址
        return true;
    }, (IntPtr hProcess, IntPtr addr) =>
    {
        try
        {
            if (ListView_GetItemText(Handle, i, addr, 0x1000) == 0)
                return false;
            return MemoryIO.ReadStringInternal(hProcess, (IntPtr)item.pszText, out text, 0x1000, true);
        }
        finally
        {
            VirtualFreeEx(hProcess, pStr, 0, MEM_RELEASE);
        }
    });
    return text;
}

别的实现起来就挺简单了

using System;
using System.Threading;
using FastWin32.Control;
using FastWin32.Diagnostics;

namespace 隐藏进程Demo
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            RemoveItemLoop("chrome.exe", "conhost.exe", "RuntimeBroker.exe", "svchost.exe", "隐藏进程Demo.exe");
        }

        /// <summary>
        /// 移除循环
        /// </summary>
        /// <param name="name">进程名</param>
        private static void RemoveItemLoop(params string[] names)
        {
            if (names == null || names.Length == 0)
                throw new ArgumentNullException();

            while (true)
            {
                foreach (string name in names)
                    RemoveItem(name);
                Thread.Sleep(100);
            }
        }

        /// <summary>
        /// 从任务管理器中移除进程
        /// </summary>
        /// <param name="name">进程名</param>
        /// <returns></returns>
        private static bool RemoveItem(string name)
        {
            IntPtr hWnd;
            SysListView32 listView;
            int count;
            string text;

            hWnd = GetListViewHandle();
            if (hWnd == IntPtr.Zero)
                return false;
            listView = new SysListView32(hWnd);
            count = listView.GetItemCount();
            if (count == 0)
                return false;
            name = name.ToUpperInvariant();
            for (int i = count - 1; i >= 0; i--)
            {
                text = listView.GetItemText(i, 0);
                if (text == null)
                    continue;
                if (text.ToUpperInvariant() == name)
                    listView.DeleteItem(i);
            }
            return true;
        }

        /// <summary>
        /// 获取任务管理器列表控件句柄
        /// </summary>
        /// <returns></returns>
        private static IntPtr GetListViewHandle()
        {
            IntPtr hWnd;

            if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1)
            {
                //Win7
                hWnd = Window.FindWindow(null, "Windows 任务管理器");
                if (hWnd == IntPtr.Zero)
                    return IntPtr.Zero;
                hWnd = Window.FindWindow(hWnd, IntPtr.Zero, null, "Processes");
                if (hWnd == IntPtr.Zero)
                    return IntPtr.Zero;
                return Window.FindWindow(hWnd, IntPtr.Zero, "SysListView32", "进程");
            }
            else
            {
                //Win8.1 Win10 别的系统未适配
                hWnd = Window.FindWindow(null, "任务管理器");
                if (hWnd == IntPtr.Zero)
                    return IntPtr.Zero;
                hWnd = Window.FindWindow(hWnd, IntPtr.Zero, null, "TaskManagerMain");
                if (hWnd == IntPtr.Zero)
                    return IntPtr.Zero;
                hWnd = Window.FindWindow(hWnd, IntPtr.Zero, "DirectUIHWND", null);
                if (hWnd == IntPtr.Zero)
                    return IntPtr.Zero;
                Window.EnumChildWindows(hWnd, (IntPtr hChildWnd) =>
                {
                    hWnd = Window.FindWindow(hChildWnd, IntPtr.Zero, "SysListView32", null);
                    if (hWnd == IntPtr.Zero)
                        return true;
                    else
                        return false;
                });
                return hWnd;
            }
        }
    }
}

去年写的放寒假才发出来,原因是作业太多,学习好累啊…