I am trying to search the memory of a process looking for a specific string. The below code works when working with 32 bit processes (with some slight alterations to the structures to be the ones required for a 32 bit process) however when searching through a 64 bit process it takes hours and eventually fails with a system out of memory error.
Is there a way of searching the memory of a 64 bit process for a string in a more efficient way than the below method?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApp2
{
class Program
{
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr Handle, IntPtr Address, [Out] byte[] Arr, int Size, out int BytesRead);
[DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx", SetLastError=true)]
public static extern int VirtualQueryEx64(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION64 lpBuffer, uint dwLength);
static void Main(string[] args)
{
List<MEMORY_BASIC_INFORMATION64> Process_Memory_Basic_Info64 = new List<MEMORY_BASIC_INFORMATION64>();
Process[] processes = Process.GetProcesses();
Process process = null;
foreach (Process process1 in processes)
{
if (process1.ProcessName.Contains("notepad"))
{
process = process1;
}
}
long MaxAddress = 0x000007FFFFFEFFFF;
long address = 0;
const int PROCESS_VM_READ = 0x0010;
IntPtr processHandle = OpenProcess(PROCESS_VM_READ, false, process.Id);
do
{
int result = VirtualQueryEx64(process.Handle, (IntPtr)address,
out MEMORY_BASIC_INFORMATION64 m, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION64)));
if (address == (long)m.BaseAddress + (long)m.RegionSize)
{
break;
}
address = (long)m.BaseAddress + (long)m.RegionSize;
Process_Memory_Basic_Info64.Add(m);
} while (address <= MaxAddress);
byte[] buffer = new byte[int.MaxValue / 10];
int bytesRead = 0;
string test = "";
for (int i = 0; i < Process_Memory_Basic_Info64.Count; i++)
{
Console.WriteLine("{0}-{1} : {2} bytes",
Process_Memory_Basic_Info64[i].BaseAddress, (uint)Process_Memory_Basic_Info64[i].BaseAddress +
Process_Memory_Basic_Info64[i].RegionSize - 1, Process_Memory_Basic_Info64[i].RegionSize);
if (Process_Memory_Basic_Info64[i].RegionSize > int.MaxValue)
{
ulong start_address = Process_Memory_Basic_Info64[i].BaseAddress;
ulong end_address = Process_Memory_Basic_Info64[i].BaseAddress + (Process_Memory_Basic_Info64[i].RegionSize - 1);
ulong region = Process_Memory_Basic_Info64[i].RegionSize;
for (ulong j = start_address; j < end_address; j += int.MaxValue / 10)
{
ReadProcessMemory(process.Handle, (IntPtr)j, buffer, buffer.Length, out bytesRead);
test = Encoding.Unicode.GetString(buffer);
if (test.Contains("HelloWorld"))
{
Console.WriteLine("It is working!!!!");
}
}
}
else
{
long buffer_size = (long)Process_Memory_Basic_Info64[i].RegionSize;
bytesRead = 0;
IntPtr base_address = (IntPtr)Process_Memory_Basic_Info64[i].BaseAddress;
byte[] buffer1 = new byte[buffer_size];
ReadProcessMemory(process.Handle, base_address, buffer1, buffer1.Length, out bytesRead);
test = Encoding.Unicode.GetString(buffer);
if (test.Contains("HelloWorld"))
{
Console.WriteLine("It is working!!!!");
}
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION64
{
public ulong BaseAddress;
public ulong AllocationBase;
public int AllocationProtect;
public int __alignment1;
public ulong RegionSize;
public int State;
public int Protect;
public int Type;
public int __alignment2;
}
public enum AllocationProtect : uint
{
PAGE_EXECUTE = 0x00000010,
PAGE_EXECUTE_READ = 0x00000020,
PAGE_EXECUTE_READWRITE = 0x00000040,
PAGE_EXECUTE_WRITECOPY = 0x00000080,
PAGE_NOACCESS = 0x00000001,
PAGE_READONLY = 0x00000002,
PAGE_READWRITE = 0x00000004,
PAGE_WRITECOPY = 0x00000008,
PAGE_GUARD = 0x00000100,
PAGE_NOCACHE = 0x00000200,
PAGE_WRITECOMBINE = 0x00000400
}
}
}
User contributions licensed under CC BY-SA 3.0