Как получить все адресное пространство памяти, используемое процессом?

Мне нужно знать все адресное пространство памяти, используемое процессом. Позже пространство памяти будет просканировано, чтобы найти значения в процессе и определить их расположение / адреса. Мой текущий процесс для этого состоит в том, чтобы взять базовый адрес каждого модуля через его (базовый адрес + размер памяти).

Я тестирую это на процессе с известным значением по известному адресу. Когда я ищу этот конкретный адрес, я получаю ожидаемое значение. Однако, когда я сканирую (как мне кажется) все адресное пространство, используемое процессом, я нигде не могу найти это значение.

Я знаю, что по адресам 0x0CF8DC38 и 0x0CF8DDDC существует числовое значение "4143000". Когда я вызываю ReadMemoryBytes(module, module.BaseAddress, 4, (IntPtr)(0x0CF8DC38)), я возвращаю байты (152, 55, 63, 0). Когда я вызываю BitConverter.GetBytes(4143000), я получаю тот же набор байтов. Когда я использую другой сканер памяти для этого процесса, я нахожу это значение по этим адресам.

Однако, когда я сканирую «известные адреса», я нигде не нахожу этого значения. Не похоже, что мой код даже находит эти адреса, используемые процессом.

Таким образом, мой вопрос двоякий:

  • Как я могу найти эти адреса в этом процессе?
  • Я обеспокоен тем, что могу иметь дело с абсолютными адресами в системной памяти, а не с относительными адресами внутри процесса. Я делаю это правильно?

.

// (in the calling method)
foreach (ProcessModule module in process.Modules) {
    ParameterizedThreadStart pst = new ParameterizedThreadStart(p => SearchModule(module, value));
    Thread t = new Thread(pst);
    t.Start(); }

private unsafe void SearchModule(ProcessModule module, string value)
{
Process process = getProcess;
int iVal;
double dVal;
int.TryParse(value, out iVal);
double.TryParse(value, out dVal);
for (Int64 addr = (Int64)module.BaseAddress; addr + value.Length < (Int64)module.BaseAddress + module.ModuleMemorySize; addr++)
{
    // Compare ints
    if (iVal > 0)
    {
        byte[] ExpectedBytes = BitConverter.GetBytes(iVal);
        byte[] ActualBytes = ReadMemoryBytes(module, (IntPtr)addr, (uint)ExpectedBytes.Length, (IntPtr)addr);

        bool isMatch = true;
        for (int i = 0; i < ExpectedBytes.Length; i++)
            if (ExpectedBytes[i] != ActualBytes[i])
                isMatch = false;
        if (isMatch)
            PossibleAddresses.Add((IntPtr)addr);
    }
}

private byte[] ReadMemoryBytes(ProcessModule mod, IntPtr memAddress, uint size, IntPtr BaseAddress)
{
    byte[] buffer = new byte[size];
    IntPtr bytesRead;
    unsafe
    {
        ReadProcessMemory(processPointer, BaseAddress, buffer, size, out bytesRead);
        return buffer;
    }
}

[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);

person tsilb    schedule 05.06.2011    source источник
comment
Ваше ошибочное предположение состоит в том, что (из MSDN): ModuleMemorySize не включает никаких дополнительных выделений памяти, которые модуль делает после его запуска; он включает только размер статического кода и данных в файле модуля. Так что ваша петля не везде ищет. Что вам нужно, так это общая карта памяти процесса, но я не уверен, как вы можете сделать это на С#. Инструмент sysinternals VMMap может это сделать, но его исходный код недоступен... (technet .microsoft.com/en-us/sysinternals/dd535533)   -  person Joe    schedule 10.08.2011


Ответы (1)


Получаемые вами адреса являются указателями на управляемую (CLR) кучу. Обычно они не сопоставляются с абсолютными адресами памяти и могут перемещаться от вызова к вызову, когда GC решает запуститься.

Если вы используете «небезопасный» код, вы можете получить относительные указатели, а также управлять своим собственным пространством памяти. Он все еще находится в куче, но, по крайней мере, вы можете быть уверены, что сборщик мусора не изменит ваше адресное пространство.

Не ожидайте, что сможете получить доступ к вещам в куче из кода, отличного от CLR, без обширной упаковки. Есть способы сделать IPC между процессами, управляемыми CLR, но вам придется написать прокси-серверы доступа к «внешнему миру», если вы хотите, чтобы процесс, не являющийся CLR, попал в вашу память.

person ssamuel    schedule 26.08.2011