В Ruby, как мне прочитать значения памяти из внешнего процесса?

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

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

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

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

Заранее спасибо, гр.

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


person grg-n-sox    schedule 15.05.2010    source источник


Ответы (2)


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

person x1a4    schedule 15.05.2010
comment
Да, я смотрел на это раньше. С учетом того, как они организуют модуль win32utils, то, что я бы искал, было бы в подмодуле win32-process, и он содержит функции, которые находятся в том же наборе, что и функции процесса, которые мне нужны в win32-api, но разработчик (s) win32utils еще не реализовал функции ReadProcessMemory и/или WriteProcessMemory. - person grg-n-sox; 15.05.2010
comment
Извините за двойной комментарий, но мне было интересно, почему я должен делать модуль C, а не просто создавать несколько экземпляров класса Win32API, связанных с разными вызовами функций, и оборачивать их в класс Ruby, который я мог бы сделать, называемый ExternalProcessMemory? - person grg-n-sox; 15.05.2010

Используйте 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(" ")  

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

person Assad Ebrahim    schedule 20.01.2013