Rob-- / memoryjs

Read and write process memory in Node.js (Windows API functions exposed via Node bindings)
MIT License
632 stars 86 forks source link

How to read shared memory channel? (Windows) #101

Open hmpmarketing opened 2 years ago

hmpmarketing commented 2 years ago

Hi,

I have an app running in windows that I need to read a MemoryMappedFile as per post below in C

Can anyone help how I can do this using memoryjs?

Thank you in advance!

hmpmarketing commented 2 years ago

This is how we would do in c

using System;
using System.IO.MemoryMappedFiles;

class HelloWorld
{
    static void Main()
    {
        double Ask = -1;
        while (true){
            MemoryMappedFile RateFile = MemoryMappedFile.OpenExisting("Global\\KEY");
            if (RateFile != null)
            {
                var accessor = RateFile.CreateViewAccessor();
                Ask = accessor.ReadDouble(sizeof(double));
                accessor.Dispose();
                Console.WriteLine("ASK: " + Ask);
            }
            RateFile.Dispose();
        }
        //return true;
    }
}
Rob-- commented 1 year ago

Just pushed a commit (3be70b051025327db5d5f54cd5a1f777dea75943) that I think should enable this now (not on NPM yet). I wasn't familiar with memory mapped files before working on this change, but from my little testing it seems like you should be able to replicate this C# logic with memoryjs now. Updated the README with an example (documentation).

To achieve what you want, this should work:

const processObject = memoryjs.openProcess("example.exe");
const fileHandle = memoryjs.openFileMapping("MappedFooFile");

const baseAddress = memoryjs.mapViewOfFile(processObject.handle, fileHandle.handle, 0, 8, memoryjs.PAGE_READONLY);
const ask = memoryjs.readMemory(processObject.handle, baseAddress, memoryjs.DOUBLE);

This will map the first 8 bytes (size of double) of the memory mapped file to your target process memory and return the address. You just need to read the double at this address now to get the ASK value.

Rob-- commented 1 year ago

Main limitation it seems right now is that to read the memory mapped file you need to provide a target process to map the file to. If you don't have one, you can just use the current Node process:

const processObject = memoryjs.openProcess(process.pid);

I might add another overload to this function at some point to do this by default, so we can just call memoryjs.mapViewOfFile without having to provide a process handle.

staceywhitmore-inl commented 1 year ago

@Rob-- I was able to get this to work using by mapping to the current Node process and and shared handle to get a baseAddress as you mentioned.

const processObject = memoryjs.openProcess(process.pid);
const fileHandle = memoryjs.openFileMapping("MyMappedFileName");

const baseAddress = memoryjs.mapViewOfFile(processObject.handle, fileHandle, 0, 8, memoryjs.PAGE_READONLY);
const ask = memoryjs.readMemory(processObject.handle, baseAddress, memoryjs.DOUBLE);

From the example cited above, how would one retrieve a new address to map (and later read) a double located in the next 8 bytes? By keeping the viewSize at 8 an incrementing the offset parameter by 1? I "Error mapping file to process!" when I try changing the offset parameter to anything other than 0 (while at a viewSize of 8[DOUBLE]).

In short, how would one go about iterating through and then reading (/mapping) several variables from a mapped memory file?

Rob-- commented 1 year ago

@staceywhitmore-inl the documentation for MapViewOfFile2 states that the offset parameter "must be 64k aligned". I think this would mean that the offset needs to be a multiple of 64KB.

Therefore, to read the next 8 bytes just increase viewSize and apply the offset when reading memory:

const baseAddress = memoryjs.mapViewOfFile(processObject.handle, fileHandle, 0, 16, memoryjs.PAGE_READONLY);
const value = memoryjs.readMemory(processObject.handle, baseAddress + 8, memoryjs.DOUBLE);