ReadProcessMemory for a 64 bit process takes hours. How do I reduce the amount of time taken

0

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
    }
}
}
c#
readprocessmemory
asked on Stack Overflow Apr 22, 2019 by JeremyDodson

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0