我正在为特定的应用程序开发一个小内存扫描程序。当我选择要扫描的进程时,我要做的第一件事就是验证进程是特定应用程序的实例......为此,我必须找到一个可以在其内存中的任何位置的签名。
这是我的代码:
[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
...这可能是原因吗?
然后我也有一些问题:
1)我应该在继续扫描循环之前调用OpenProcess
吗?我不这么认为,对吧?
2)我想使我的应用程序兼容x32和x64。我应该在我的代码中更改什么以确保它能够正确地使用两个系统(address
限制,address
的值类型,RegionSize
演员......)?
3)在扫描进程内存以找到我的目标字节数组时,我应该检查当前MEMORY_BASIC_INFORMATION
的属性(AllocationProtect
,State
,Protect
和/或lType
),看看我是否可以跳过当前区域的ReadProcessMemory
,因为它没有必要或它无法读取?
4)我还能做些什么来优化这种方法的速度,这非常重要吗?
Oooooooook我解决了它。问题是我在不使用VirtualQueryEx并检查内存区域保护的情况下尝试读取它的方式!