Ways to pass large amounts of data to child processes

How to pass large data to child processes

In an article yesterday, we said that if we want to transfer more than 32767 characters of data to a child process, we need to find other methods (rather than command line parameters) to achieve.

The first method we can think of is: WM_COPYDATA. When the child process is created and enters the message loop, we use FindWindow to find the window of the process and send the WM_COPYDATA message. However, this method has several problems:

> You need to find a way to make sure that the child process has indeed created the target window and enters the message loop, so that the window can be searched. (Hint: You can use the method WaitForInputIdle)

> You need to make sure that the window we use FindWindow to find is indeed the one you want, because if the windows of other processes happen to have the same title or window class, you may not get the target window. Or, if there are multiple instances of the same child process, the same window instance will be created. Therefore, you need to make sure to find the correct target window. (Hint: You can use the GetWindowThreadProcessId method)

> You need to make sure that other people will not find your window and send WM_COPYDATA before you. If they do, then they will have control of your child process.

> The child process needs to design a mechanism to prevent some malicious processes from sending forged WM_COPYDATA messages, and handle them as correctly as possible (discard such requests).

The method I recommend is: anonymous shared memory

The basic idea is to create a shared memory and fill it with the data you need to transfer. Then set its handle to be inheritable, then create a child process, and transmit the number of the handle to the command line of the child process.
The child process will get this handle from the command line and map this shared memory to its process space, so that it can access the data you pass to it.

A few notes about this method:

> The child process needs to judge the validity of the handle to prevent some people from passing invalid or forged data.

> If malicious processes want to mess up your child process command line, they must have PROCESS_VM_WRITE permission. If they want to access the process handle table, they also need PROCESS_DUP_HANDLE permission. These are safe access masks, and all ACLs that are properly configured can play a very good protective role. (The default ACL can be used for protection, so just use the default ACL)

> In this method, no names and numbers can be monitored or forged by malicious processes. The premise is that you have implemented PROCESS_VM_WRITE and PROCESS_DUP_HANDLE protection for the child process.

> Because we are using shared memory, the shared data will not really be copied between the two processes, they are just remapped by the operating system. For transferring large data, this method is very efficient.

In the following example code, we demonstrate how to use shared memory technology to transfer data.

 

In an actual project, the members of the STARTUPPARAMS structure above may be very complicated, but for demonstration purposes, I only define an integer member here.

 

CreateStartupParams creates a structure of STARTUPPARAMS in the shared memory area. First, we fill the SECURITY_ATTRIBUTES structure and set its inheritable property to TRUE, so that the child process can access this shared memory. Setting lpSecurityDescriptor to NULL indicates that we want to use the default security descriptor, and it is enough for us to use this default value. Then, we created a shared memory object of a specified size, and then mapped it to memory, and finally, we returned a shared memory handle and mapped memory address.

 

The GetStartupParams function is a function corresponding to CreateStartupParams. It parses the value of the handle from the command line and tries to perform memory mapping. If the handle is not a valid file mapping handle, the MapViewOfFile call will fail, and we can check the validity of the parameters in this way. Then, we used VirtualQuery to query the size of the memory mapped area. (Here, we did not use a more rigorous test method, because its return value may be rounded to the nearest page boundary)

 

We also need to release shared memory to prevent possible memory leaks, so we define the FreeStartupParams function above to achieve this.

 

In the above function, we mainly construct the command line parameters of the child process. We use GetModuleFileName(NULL) to get the full path of the execution program, and then transmit the digital representation of the handle, and set the parameter TRUE when calling CreateProcess to indicate that we want the handle of the child process to be inherited.
There is one small thing to note: we have used quotation marks to deal with spaces in the program path.

 

Finally, we put all the above program fragments together.
If there is already a parameter on the command line, it means that the subprocess is running this time, so we convert this parameter to STARTUPPARAMS and get the data in it and display it.
If no parameters are passed on the command line, it means that we are running the parent process. In this case, we create a STARTUPPARAMS and set the data we need to transmit (here 42 is used as an example), and then transmitted to the child process .

to sum up

Today we demonstrated how to transfer a large amount of data to the child process. Although in the above example, the amount of data we passed is small, if we make a little improvement, we can completely transfer large data.
So, brothers, you can put this method steadily into your skill toolbox.

Guess you like

Origin blog.csdn.net/mmxida/article/details/108180914