В Ruby, как я могу прочитать значения памяти из внешнего процесса? - PullRequest
3 голосов
/ 15 мая 2010

Итак, все, что я просто хочу сделать, - это создать Ruby-программу, которая считывает некоторые значения из известного адреса памяти в виртуальной памяти другого процесса. Благодаря моим исследованиям и базовым знаниям о шестнадцатеричном редактировании сборки x86 запущенного процесса в памяти, я нашел базовый адрес и смещения для значений в памяти, которые я хочу. Я не хочу их менять; Я просто хочу их прочитать. Я спросил разработчика редактора памяти, как подойти к этой абстрактной формулировке языка и использовать платформу Windows. Он сказал мне, что вызовы Win32API для OpenProcess, CreateProcess, ReadProcessMemory и WriteProcessMemory были способом использования C или C ++. Я думаю, что для этого нужно просто использовать класс Win32API и отобразить два его экземпляра; Один для OpenProcess или CreateProcess, в зависимости от того, запущен ли у пользователя процесс th или нет, а другой экземпляр будет сопоставлен с ReadProcessMemory. Возможно, мне все еще нужно найти функцию для получения списка запущенных процессов, чтобы я знал, какой запущенный процесс мне нужен, если он уже запущен.

Это заняло бы некоторую работу, чтобы собрать все воедино, но я полагаю, что не так уж и плохо писать код. Для меня это просто новая область программирования, так как я никогда не работал на этом низком уровне с языком высокого уровня (ну, в любом случае, с более высоким уровнем, чем C). Мне просто интересно, как подойти к этому. Я мог бы просто использовать несколько вызовов Win32API, но это означает необходимость иметь дело с кучей пакетов и массивов и распаковкой, которая зависит от системы. Я хочу в конечном итоге сделать эту работу кроссплатформенной, поскольку процесс, из которого я читаю, производится из исполняемый файл, имеющий несколько сборок платформы (я знаю, что адрес памяти меняется от системы к системе. Идея состоит в том, чтобы иметь плоский файл, содержащий все отображения памяти, чтобы программа Ruby могла просто сопоставить текущую среду платформы с соответствующим отображением памяти. ) но, судя по всему, мне просто нужно создать класс, который будет обернуть все вызовы функций, связанных с памятью общей системной библиотеки текущей платформы.

Насколько я знаю, уже мог существовать рубиновый самоцвет, который позаботится обо всем этом для меня, которого я просто не нахожу. Я также мог бы попытаться отредактировать исполняемые файлы для каждой сборки, чтобы каждый раз, когда значения памяти, из которых я хочу читать, записывались процессом, он также записывал копию нового значения в пространство в разделяемой памяти, которое у меня каким-то образом было Ruby создает экземпляр класса, который является указателем на этот адрес совместно используемой памяти и каким-то образом сигнализирует программе Ruby, что значение было обновлено и должно быть перезагружено. В принципе, система на основе прерываний была бы хороша, но поскольку целью чтения этих значений является просто отправка на табло, транслируемое с центрального сервера, я мог бы просто придерживаться системы на основе опросов, которая отправляет обновления через фиксированные интервалы времени. Я также мог бы просто полностью отказаться от Ruby и перейти на C или C ++, но я почти не знаю их. Я на самом деле знаю больше x86, чем C ++, и я знаю только C, насколько это зависит от системы ANSI C, и никогда раньше не имел дело с общими системными библиотеками.

Так есть ли в наличии гем или менее известный модуль, который уже сделал это? Если нет, то любая дополнительная информация о том, как этого добиться, была бы неплохой. Я думаю, вкратце, как мне все это сделать?

Заранее спасибо, Grg

PS: Также было бы неплохо подтвердить, что эти вызовы Win32API должны быть направлены на библиотеку kernel32.dll.

Ответы [ 2 ]

2 голосов
/ 20 января 2013

Использовать Ruby-FFI:

Если вы знаете C и Win32 API, то вам может быть проще использовать Ruby-FFI gem. Ruby-FFI прозрачно оборачивает функции C, позволяя вам использовать любую функцию Win32.

Для именованной совместно используемой памяти Win32 предоставляет CreateFileMapping( ) и MapViewOfFile( ).

У них есть заголовки

# WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCSTR);
# WINBASEAPI PVOID WINAPI MapViewOfFile(HANDLE,DWORD,DWORD,DWORD,DWORD);

Передавая неверный дескриптор файла 0xFFFFFFFF в CreateFileMapping, вы можете вообще избежать работы с файлами и просто определить свою общую память, используя массивы и указатели.

Ниже приведен упрощенный пример, который читает из общей памяти. (Версия производственного качества будет использовать семафоры в считывателе и записывающем устройстве и кольцевой буфер, чтобы позволить обоим процессам выполняться асинхронно, при этом гарантируя, что записывающее устройство не перезаписывает буфер до тех пор, пока считыватель не завершит его чтение.)

Упрощенный Ruby Пример:

require 'ffi'

module Win32
   extend FFI::Library
   ffi_lib 'kernel32'  # see winbase.h
   attach_function :CreateFileMapping, 
            :CreateFileMappingA,[ :uint, :pointer, :long, :long, :long, :pointer ], :pointer   
            # suffix A indicates the ASCII version
   attach_function :MapViewOfFile, 
            :MapViewOfFile,[ :pointer, :long, :long, :long, :long ], :pointer  
end

memoryName = "Share Memory Name"
sz_buf = 1000  # bytes  (250 ints, 4 bytes each)
num_ints = sz_buf / 4

# Windows constants
PAGE_READWRITE = 0x0004
FILE_MAP_WRITE = 2

# Get handle to shared memory
hMemory = Win32.CreateFileMapping(0xFFFFFFFF, nil, PAGE_READWRITE, 0, sz_buf, memoryName)

# Create pointer into shared memory in the reader's memory space 
pMemory = FFI::MemoryPointer.new(:int, num_ints )
pMemory = Win32.MapViewOfFile(hMemory, FILE_MAP_WRITE, 0, 0, sz_buf)

# Read from shared memory buffer
puts pMemory.read_array_of_int(sz_buf).join(" ")  

Некоторая полезная информация:

2 голосов
/ 15 мая 2010

Взгляните на win32utils . Я думаю, что это должно, по крайней мере, поставить вас на ноги и привести примеры того, как копаться в самом API, если сами камни не работают на вас. Возможно, вам придется прикусить пулю и написать модуль на языке C.

...