在 Ruby 中,如何从外部进程读取内存值?

发布于 2024-09-01 11:10:48 字数 1269 浏览 1 评论 0原文

所以我只想制作一个 Ruby 程序,从另一个进程的虚拟内存中的已知内存地址读取一些值。通过我对内存中正在运行的进程的 x86 程序集进行十六进制编辑的研究和基本知识,我找到了内存中所需值的基址和偏移量。我不想改变它们;我只是想读一下它们。我询问内存编辑器的开发人员如何处理这种语言抽象并假设 Windows 平台。他告诉我,对 OpenProcess、CreateProcess、ReadProcessMemory 和 WriteProcessMemory 的 Win32API 调用是使用 C 或 C++ 的方法。我认为正确的方法就是使用 Win32API 类并映射它的两个实例;一个用于 OpenProcess 或 CreateProcess,具体取决于用户是否已经运行进程,另一个实例将映射到 ReadProcessMemory。我可能仍然需要找到用于获取正在运行的进程列表的函数,以便我知道哪个正在运行的进程是我想要的(如果它已经在运行)。

这需要一些工作才能将所有内容放在一起,但我认为编写代码也不会太糟糕。这对我来说只是一个新的编程领域,因为我从未使用过高级语言(嗯,无论如何比 C 更高级别)工作过这么低的级别。我只是想知道解决这个问题的方法。我可以只使用一堆或 Win32API 调用,但这意味着必须处理一堆与系统相关的字符串和数组包和解包我希望最终使这项工作跨平台,因为我正在读取的进程是从生成的具有多个平台构建的可执行文件,(我知道内存地址会因系统而异。其想法是拥有一个包含所有内存映射的平面文件,以便 Ruby 程序可以将当前平台环境与匹配的内存映射相匹配。 )但从表面上看,我只需要创建一个类来包装当前平台的系统共享库内存相关的函数调用。

据我所知,可能已经存在一个 Ruby gem 可以为我处理所有这一切,但我只是没有找到。我也可以尝试编辑每个构建的可执行文件,以便每当进程写入我想要读取的内存值时,它还会将新值的副本写入我以某种方式拥有的共享内存中的空间Ruby 创建一个类的实例,它是一个指向该共享内存地址的指针,并以某种方式向 Ruby 程序发出信号,表明该值已更新并且应该重新加载。基本上,基于中断的系统会很好,但由于读取这些值的目的只是发送到从中央服务器广播的记分板,因此我可以坚持使用基于轮询的系统,该系统以固定的时间间隔发送更新。我也可以完全放弃 Ruby,转而使用 C 或 C++,但我对这些也不太了解。事实上,我对 x86 的了解比对 C++ 的了解还要多,而且我只了解 C 以及与系统无关的 ANSI C,并且以前从未处理过共享系统库。

那么是否有一个 gem 或鲜为人知的模块可以做到这一点?如果没有,那么有关如何完成此操作的任何其他信息都会很好。我想,长话短说,我该怎么做这一切?

提前致谢, Grg

PS:另外确认那些 Win32API 调用应该针对 kernel32.dll 库会很好。

So all I simply want to do is make a Ruby program that reads some values from known memory address in another process's virtual memory. Through my research and basic knowledge of hex editing a running process's x86 assembly in memory, I have found the base address and offsets for the values in memory I want. I do not want to change them; I just want to read them. I asked a developer of a memory editor how to approach this abstract of language and assuming a Windows platform. He told me the Win32API calls for OpenProcess, CreateProcess, ReadProcessMemory, and WriteProcessMemory were the way to go using either C or C++. I think that the way to go would be just using the Win32API class and mapping two instances of it; One for either OpenProcess or CreateProcess, depending on if the user already has th process running or not, and another instance will be mapped to ReadProcessMemory. I probably still need to find the function for getting the list of running processes so I know which running process is the one I want if it is running already.

This would take some work to put all together, but I am figuring it wouldn't be too bad to code up. It is just a new area of programming for me since I have never worked this low level from a high level language (well, higher level than C anyways). I am just wondering of the ways to approach this. I could just use a bunch or Win32API calls, but that means having to deal with a bunch of string and array pack and unpacking that is system dependant I want to eventually make this work cross-platform since the process I am reading from is produced from an executable that has multiple platform builds, (I know the memory address changes from system to system. The idea is to have a flat file that contains all memory mappings so the Ruby program can just match the current platform environment to the matching memory mapping.) but from the looks of things I'll just have to make a class that wraps whatever is the current platform's system shared library memory related function calls.

For all I know, there could already exist a Ruby gem that takes care of all of this for me that I am just not finding. I could also possibly try editing the executables for each build to make it so whenever the memory values I want to read from are written to by the process, it also writes a copy of the new value to a space in shared memory that I somehow have Ruby make an instance of a class that is a pointer under the hood to that shared memory address and somehow signal to the Ruby program that the value was updated and should be reloaded. Basically a interrupt based system would be nice, but since the purpose of reading these values is just to send to a scoreboard broadcasted from a central server, I could just stick to a polling based system that sends updates at fixed time intervals. I also could just abandon Ruby altogether and go for C or C++ but I do not know those nearly as well. I actually know more x86 than C++ and I only know C as far as system independent ANSI C and have never dealt with shared system libraries before.

So is there a gem or lesser known module available that has already done this? If not, then any additional information as to how to accomplish this would be nice. I guess, long story short, how do I do all this?

Thanks in advance,
Grg

PS: Also a confirmation that those Win32API calls should be aimed at the kernel32.dll library would be nice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猥琐帝 2024-09-08 11:10:48

看一下 win32utils。我认为这至少应该让您站起来,并为您提供示例,说明如果 gem 本身不适合您,如何深入了解 api 本身。您可能需要硬着头皮用 C 语言编写一个模块。

Take a look at win32utils. I'm thinking that should at least get you on your feet, and give you examples of how to dig into the api itself if the gems themselves don't work for you. You might need to bite the bullet and write a module in C.

隱形的亼 2024-09-08 11:10:48

使用 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(" ")  

一些有用的信息:

Use Ruby-FFI:

If you know C and the Win32 API, then it you might find it easier to use Ruby-FFI gem. Ruby-FFI wraps C functions transparently, allowing you to use any Win32 function.

For named shared memory, Win32 provides CreateFileMapping( ) and MapViewOfFile( ).

These have the headers

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

By passing in an invalid file handle 0xFFFFFFFF into CreateFileMapping, you can avoid dealing with files at all, and simply define your shared memory using arrays and pointers.

Below is a simplified example that reads from shared memory. (A production quality version would use semaphores in the reader and writer, and a circular buffer, to allow both processes to proceed asynchronously while still ensuring that the writer does not overwrite a buffer until the reader has finished reading it.)

Simplified Ruby Example:

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(" ")  

Some useful information:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文