Sharing memory between two processes (C, Windows)
Asked Answered
R

8

35

Since I haven't found an answer to the question asked previously here I'm trying a different approach.

Is there any way to share memory between two processes?

The second process gets the information from an injection since it's a legacy program that it's not being supported anymore.

My idea is to inject some code there, in the struct that I am passing to the injected program pass the address (or whatever) to the share memory where the data I need to run is located. Once I get the data I will populate my own variables inside the injected thread.

Is this possible? How?

Code is appreciated.

EDIT:

I think it's not clear so I'll clarify. I do know how to inject. I am doing it already. The issue here is to pass dynamic data to the injection.

Rackety answered 29/7, 2009 at 15:10 Comment(3)
What sort of program? Windows, GUI, console?Holna
all of them. I can run from a service, or a GUI or a consoleRackety
There's a nice easy to use C++ wrapper for memory mapped files in the POCO project. pocoproject.org/download/index.html I found it after repeatedly painfully trying to use the Boost stuff, which other people might find easy to use, but I found brutally difficult to use properly.Ayers
M
16

You can try a memory-mapped file.

This gives a bit more step-by-step detail.

Mandatory answered 29/7, 2009 at 15:13 Comment(2)
If you don't want to go all the way down to Raw Win32 calls, I suggest the POCO project's pre-built tested wrapper classes. pocoproject.org/download/index.html Far more lightweight and readable than Boost.Ayers
Can you do a memory-mapped file but the file never touches the filesystem and instead is a memory-backed-only file?Haig
C
32

Although windows supports shared memory through its file mapping API, you can't easily inject a shared memory mapping into another process directly, as MapViewOfFileEx does not take a process argument.

However, you can inject some data by allocating memory in another process using VirtualAllocEx and WriteProcessMemory. If you were to copy in a handle using DuplicateHandle, then inject a stub which calls MapViewOfFileEx, you could establish a shared memory mapping in another process. Since it sounds like you'll be injecting code anyway, this ought to work well for you.

To summarize, you'll need to:

  • Create an anonymous shared memory segment handle by calling CreateFileMapping with INVALID_HANDLE_VALUE for hFile and NULL for lpName.
  • Copy this handle into the target process with DuplicateHandle
  • Allocate some memory for code using VirtualAllocEx, with flAllocationType = MEM_COMMIT | MEM_RESERVE and flProtect = PAGE_EXECUTE_READWRITE
  • Write your stub code into this memory, using WriteProcessMemory. This stub will likely need to be written in assembler. Pass the HANDLE from DuplicateHandle by writing it in here somewhere.
  • Execute your stub using CreateRemoteThread. The stub must then use the HANDLE it obtained to call MapViewOfFileEx. The processes will then have a common shared memory segment.

You may find it a bit easier if your stub loads an external library - that is, have it simply call LoadLibrary (finding the address of LoadLibrary is left as an exercise to the reader) and do your work from the library's dllmain entry point. In this case using named shared memory is likely to be simpler than futzing around with DuplicateHandle. See the MSDN article on CreateFileMapping for more details, but, essentially, pass INVALID_HANDLE_VALUE for hFile and a name for lpName.

Edit: Since your problem is passing data and not actual code injection, here are a few options.

  1. Use variable-sized shared memory. Your stub gets the size and either the name of or a handle to the shared memory. This is appropriate if you need only exchange data once. Note that the size of a shared memory segment cannot be easily changed after creation.
  2. Use a named pipe. Your stub gets the name of or a handle to the pipe. You can then use an appropriate protocol to exchange variable-sized blocks - for example, write a size_t for length, followed by the actual message. Or use PIPE_TYPE_MESSAGE and PIPE_READMODE_MESSAGE, and watch for ERROR_MORE_DATA to determine where messages end. This is appropriate if you need to exchange data multiple times.

Edit 2: Here's a sketch of how you might implement handle or pointer storage for your stub:

.db B8            ;; mov eax, imm32
.dl handle_value  ;; fill this in (located at the start of the image + one byte)
;; handle value is now in eax, do with it as you will
;; more code follows...

You could also just use a fixed name, which is probably simpler.

Clarinda answered 29/7, 2009 at 15:14 Comment(8)
As a non-windows person who has only a notional idea of what's going on here, should I be a little freaked out that this possible? Is there a comparable unix process for doing this?Commixture
Yes, this can be done in unix. Use PTRACE_POKEUSER to frob registers for an anonymous mmap call. Once the call completes, use PTRACE_POKEDATA or mmapping /proc/pid/mem to write code in. Then have the code do whatever.Clarinda
To clarify, the above was for Linux. Other unixes will likely have something similar. If you want your own thread, call out to libpthread from your injected stub.Clarinda
This sounds like a good solution. I know how to inject and I have working code already. Could you post a sample how on how to use the entire thing (what you just described). Thanks!Rackety
Not right now, I'm afraid. I'm sure you can figure it out, though - the hardest part of all of this is writing the stub for the code injection. :)Clarinda
that is already done. i'm just having trouble passing the handle to the remote threadRackety
as a response to the EDIT: The whole problem started with the fact that one of the components of the stub i am passing to the remote thread might sometimes need to be bigger in size to accommodate extra information. Now, since i can't pass a pointer I am using static variables (such as a char[256]) and I can't chance that at runtime. Which was my previous question (see the link)Rackety
then use a fixed name instead of passing in handlesClarinda
M
16

You can try a memory-mapped file.

This gives a bit more step-by-step detail.

Mandatory answered 29/7, 2009 at 15:13 Comment(2)
If you don't want to go all the way down to Raw Win32 calls, I suggest the POCO project's pre-built tested wrapper classes. pocoproject.org/download/index.html Far more lightweight and readable than Boost.Ayers
Can you do a memory-mapped file but the file never touches the filesystem and instead is a memory-backed-only file?Haig
G
5

You can use Shared Memory

Gerdy answered 29/7, 2009 at 15:16 Comment(2)
Shared memory is memory mapped files. What are you trying to do?Clarinda
Sorry I meant pipes. Let me delete that commentRackety
C
1

Did you try to use pipes (for memory) or even serialization (for your objects)? You can use files to manage memory between processes. Sockets are also good to get communication between processes.

Cheryl answered 1/9, 2010 at 15:40 Comment(0)
D
1

Memory mapping is the way to go, you don't even need to create a permanent memory space, the memory sector goes out of scope when all the processes sharing it are shutdown. There are other ways too. A quick and dirty way of passing data from one C app to another is just to use the OS. At command line type app1 | app2. This causes app2 to be the output destination of app1 or iow a printf command from app1 would send it to app2 (this is called piping).

Deflation answered 12/9, 2011 at 13:11 Comment(0)
L
0

You can try using Boost.Interprocess to communicate between two processes. But to inject code into a previously existing, not supported software, you'll probably have to use @bdonlan's way using WriteProcessMemory.

Luisaluise answered 29/7, 2009 at 15:10 Comment(2)
Thanks. Can you elaborate? I know how to inject, that's not the issue.Rackety
i am using writeprocessmemory. i just need to pass information that changes sizes sometimesRackety
M
0

If you're talking about Windows, the main roadblock is that processes each live in their own virtual address space. You unfortunately can't pass normal memory addresses around from process to process and get the results you'd expect. (Threads, on the other hand, all live in the same address space, which is why threads can see memory in the same way.)

Windows does, however, have a shared memory space that you have to be very careful to manage correctly. Any process that allocates space in the shared memory space is responsible for freeing that memory explicitly. This is in contrast to local memory, which more or less vanishes when the process dies.

See this MSDN sample article for some ideas on how you might use the shared memory space to take over the world. Er, interface with legacy software. Or whatever :) Good luck whatever you end up doing!

Mitrewort answered 29/7, 2009 at 15:21 Comment(7)
Thanks for the comments. They clarify the situation a bit more. That article doesn't really tell what kind of APIs or methodologies to use though.Rackety
The global heap is process-local in win32. Using it for shared memory won't work on anything NT based (XP and friends), at least.Clarinda
@Clarinda - ?? maybe we're not talking about the same thing here. The global heap lives in global memory, which is shared amongst all processes. all allocations are handle based, not pointer based, etc. I think you might be right if we were talking .NET - I don't recall if the managed CLR terminology has "global" meaning something else. bdonlan, can you please expand your comment? I'd like to make sure I understand what I'm talking about :)Mitrewort
"Windows memory management does not provide a separate local heap and global heap. Therefore, the GlobalAlloc and LocalAlloc functions are essentially the same." msdn.microsoft.com/en-us/library/aa366574%28VS.85%29.aspxGehrke
Ah! Now I understand my confusion. I was saying 'heap' completely incorrectly. I was thinking of the shared memory space. That's not a heap. :) thx bdonlan!Mitrewort
I've edited the answer accordingly (replacing heap with shared memory space).Omsk
@AKE: No, this answer is discussing that "global heap" which Win16 provided. It doesn't work any longer in Win32.Coir
P
0

As of Windows 10 version 1703, there is a new API MapViewOfFile2 which lets you inject a file mapping into a process (which is usable for shared memory sections). Version 1803 adds MapViewOfFile3, which is usable for this purpose as well.

Here's the interface definition (as found on the MSDN page).

PVOID MapViewOfFile2(
  [in]           HANDLE  FileMappingHandle,
  [in]           HANDLE  ProcessHandle,
  [in]           ULONG64 Offset,
  [in, optional] PVOID   BaseAddress,
  [in]           SIZE_T  ViewSize,
  [in]           ULONG   AllocationType,
  [in]           ULONG   PageProtection
);

First, create a file mapping using CreateFileMapping, use an obtained process handle as the ProcessHandle parameter to MapViewOfFile2 and then use some method of giving the returned pointer to the other process (if you want to do that).

Paddock answered 27/3 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.