Reloaded.Memory.SigScan icon indicating copy to clipboard operation
Reloaded.Memory.SigScan copied to clipboard

Scanner Needs Options To Scan Through Range of Virtual Memory Address Space

Open tojo423 opened this issue 4 years ago • 6 comments

The Scanner class needs functionality to scan between memory regions starting at address A, and ending at address B. This is easy to implement by oneself, by simply walking all the memory regions of the process, reading bytes from the region, and using the scanner as is. BUT, it would be much more convenient to have this functionality built-in.

tojo423 avatar Sep 24 '21 15:09 tojo423

@Sewer56

Any plans on adding this? There is no option to specify a custom range for an external process at all, which is VERY limiting.

slxdy avatar Aug 01 '24 08:08 slxdy

@slxdy It's more likely going to happen in the Rust port a few months from now.

The scanner can already do address ranges, technically speaking.

What's really being asked here is to scan through the virtual address space through all memory between a specific minimum and maximum address.

So we're talking:

  • VirtualQueryEx on Windows
  • Parsing /proc/{id}/maps on Linux
  • mach_vm_region on macOS

etc.

Then walk through the pages returned to find all used pages, and scan the memory within them.

I'm actually already doing this sort of thing in reloaded-memory-buffers [both C# and Rust versions]; albeit doing the opposite to find free pages.

The library itself should really only contain the scanning code; but functionality like this would be very useful in an extension library. Some design/research would be handy there, as you may for example want to only scan for pages with specific permissions (e.g. executable for game code). Some OSes might also have specific page types other might not. Mapped memory for example is common in emulators, because it helps with taking quick savestates.

If I were to do it myself, I'd do it in the Rust port a few months from now; after the Reloaded-III spec is done, and I finish work on Reloaded.Hooks-rs

Sewer56 avatar Aug 01 '24 12:08 Sewer56

May I at least suggest a new constructor that would allow us to iterate through the memory pages manually?

public Scanner(Process proc, nuint startAddress, nuint length) { }

slxdy avatar Aug 01 '24 12:08 slxdy


Forgot to add this.

There are also some edge cases you'd need to consider here.

For example if you're scanning through the address space of a process, it's possible another thread could unmap a part of memory that is currently being scanned.

If that happened you'd get an Access Violation (SIGSEGV on Linux); and your process would die. While the probability of that is very unlikely, it could happen. Imagine you just happened to be scanning through a thread's stack, and that thread has exit at just the right time.

Some mechanism for suspending threads, like the one in Cheat Engine would probably be needed, and it would need to be cross platform. Some research into edge cases would be needed.

Sewer56 avatar Aug 01 '24 12:08 Sewer56

Reading the memory of another process should not cause any exceptions, other than the read function failing as far as I know.

Even then, same can be said for reading module memory. What if a module is suddenly freed? Would result in the same issue

slxdy avatar Aug 01 '24 12:08 slxdy

Of an external process, it might be ok, as the OS itself would just return an error and not kill the whole process. Though it would be much, much slower, because you perform a memory copy to get the data out in the first place.

What if a module is suddenly freed? Would result in the same issue

Yeah, it would. Though modules are very rarely unloaded in any software in practice. I originally built this library with the main purpose of scanning the main executable's code in-process; i.e. searching for code across game versions. So usage with external processes is not as ideal as it could be.

In any case, check these constructors

https://github.com/Reloaded-Project/Reloaded.Memory.SigScan/blob/9760d49f6b9c4c98eb1987f8e18206eb19d5c71f/Reloaded.Memory.Sigscan/Scanner.cs#L32-L41

https://github.com/Reloaded-Project/Reloaded.Memory.SigScan/blob/9760d49f6b9c4c98eb1987f8e18206eb19d5c71f/Reloaded.Memory.Sigscan/Scanner.cs#L50-L77

If you see the else branch, it pretty much shows how you could do a custom range from an external process today. It's just a memory read, and then use of the first constructor.

Sewer56 avatar Aug 01 '24 12:08 Sewer56