I'm developing a little memory scanner for a specific application. When I select a process to scan, the first thing I want to do is to verify that the process is an instance that specific application... and to do this I must find a signature that can be anywhere inside its memory.
Here is my code:
[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);
}
The first problem that this method is never reaching completion and it looks like it's endlessly looping (yesterday I let it running for debug purposes for more than one hour without reaching the end). Checking for Marshal.GetLastWin32Error() inside my loop I noticed that sometimes I get an ERROR_PARTIAL_COPY (0x0000012B)
after calling ReadProcessMemory
... is it the possible cause?
Then I also have some questions:
1) Should I call OpenProcess
before proceeding with the scan loop? I don't think so, right?
2) I would like to make my application both x32 and x64 compatible. What should I change inside my code to be sure it will properly work with both systems (address
limit, value type of address
, RegionSize
cast, ...)?
3) While scanning the process memory in order to find my target byte array, should I check the current MEMORY_BASIC_INFORMATION
's properties (AllocationProtect
, State
, Protect
and/or lType
) to see if I can skip ReadProcessMemory
for the current region because it's not necessary or it can't be read?
4) Is there anything else I can do to optimize the speed of this methos, which is very important?
Oooooooook I solved it. The problem was the way I was trying to read it without using VirtualQueryEx and checking for the memory region protection!
User contributions licensed under CC BY-SA 3.0