문제

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.

도움이 되었습니까?

해결책

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.

다른 팁

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:

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top