我正在为特定应用程序开发一个小内存扫描仪。当我选择要扫描的进程时,我要做的第一件事是验证该进程是否是特定应用程序的实例……为此,我必须找到一个可以在其内存中任何位置的签名。
这是我的代码:
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean ReadProcessMemory([In] IntPtr processHandle, [In] IntPtr processAddress, [Out] Byte[] buffer, [In] UInt32 bytesToRead, [Out] out IntPtr bytesRead);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern UInt32 VirtualQueryEx([In] IntPtr processHandle, [In, Optional] IntPtr processAddress, [Out] out MEMORY_BASIC_INFORMATION buffer, [In] UInt32 bufferSize);
internal struct MEMORY_BASIC_INFORMATION
{
public static UInt32 Size = (UInt32)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION));
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public AllocationProtect AllocationProtect;
public IntPtr RegionSize;
public StateEnum State;
public AllocationProtect Protect;
public TypeEnum lType;
}
public void Open()
{
Byte[] toFind = new Byte[] { 31, 55, 78, 33, 00, 00, 00, 37 };
UInt32 address = 0;
do
{
MEMORY_BASIC_INFORMATION info = new MEMORY_BASIC_INFORMATION();
if (NativeMethods.VirtualQueryEx(m_Process.Handle, (IntPtr)address, out info, NativeMethods.MemoryBasicInformation.Size) == 0)
break;
Byte[] buffer = new Byte[(UInt32)info.RegionSize];
IntPtr bytesRead;
if (NativeMethods.ReadProcessMemory(m_Process.Handle, info.BaseAddress, buffer, (UInt32)buffer.Length, out bytesRead))
{
if (buffer.Contains(toFind)) // Extension Method
{
m_IsValid = true;
break;
}
}
if (address == (UInt32)info.BaseAddress + (UInt32)info.RegionSize)
break;
address = (UInt32)info.BaseAddress + (UInt32)info.RegionSize;
}
while (address <= 0x7fffffff);
}
第一个问题是这个方法永远不会完成,它看起来像是在无限循环(昨天我让它运行了一个多小时以进行调试而没有到达终点)。在我的循环中检查 Marshal.GetLastWin32Error() 我注意到有时我ERROR_PARTIAL_COPY (0x0000012B)
在调用后得到一个ReadProcessMemory
得到一个......这是可能的原因吗?
然后我也有一些问题:
OpenProcess
1)在继续扫描循环之前我应该打电话吗?我不这么认为,对吧?
2) 我想让我的应用程序同时兼容 x32 和 x64。我应该在我的代码中进行哪些更改以确保它可以在两个系统中正常工作(address
限制、值类型address
、强制转换RegionSize
……)?
3)在扫描进程内存以找到我的目标字节数组时,我是否应该检查 currentMEMORY_BASIC_INFORMATION
的属性(AllocationProtect
、State
和Protect
/或lType
)以查看我是否可以跳过ReadProcessMemory
当前区域,因为它不是必需的或者它不能被阅读?
4)我还能做些什么来优化这个方法的速度,这很重要吗?