网上的都不能用啊…全是未完成代码或者兼容性极差的代码。自己写呗。
任务管理器实际上是用了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;
}
}
}
}
去年写的放寒假才发出来,原因是作业太多,学习好累啊…