基于WinAPI实现进程终止后持久化共享内存的技术需求问询
Alright, let's break down how to build this persistent shared memory solution using CreateFileMapping() for your password storage needs—since you want to avoid easily accessible options like physical files or the registry, and need the data to live in memory until explicit deletion (or a system reboot).
Core Background
When you call CreateFileMapping() with INVALID_HANDLE_VALUE as the hFile parameter, you're creating shared memory backed by the system page file. This means the data gets automatically wiped when the system restarts, which fits your requirement perfectly. The key to making it persist after the creating process exits is using a named mapping object: named kernel objects stay alive as long as at least one process holds an open handle to them, or until you explicitly delete them.
Step 1: Create the Persistent Shared Memory
First, we'll create a named file mapping with read-write permissions, using a unique name to avoid conflicts. Use the Global\ prefix if you need cross-session access (like between a user app and a service); otherwise, Local\ works for the same user session.
#include <windows.h> #include <iostream> // Use a unique name—add a GUID or app-specific identifier to avoid collisions #define MAPPING_NAME L"Global\\SecurePassStore_7a9f2b" #define BUFFER_SIZE 256 // Adjust based on your max password length int main() { // Create the file mapping object backed by the system page file HANDLE hMapping = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, // Use default security (customize if you need strict access controls) PAGE_READWRITE, 0, // High-order size (0 for buffers under 4GB) BUFFER_SIZE, MAPPING_NAME ); if (hMapping == NULL) { std::cerr << "CreateFileMapping failed. Error code: " << GetLastError() << std::endl; return 1; } // Map the shared memory to our process's address space LPVOID pBuffer = MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, // Full access for writing the password 0, 0, BUFFER_SIZE ); if (pBuffer == NULL) { std::cerr << "MapViewOfFile failed. Error code: " << GetLastError() << std::endl; CloseHandle(hMapping); return 1; } // Write your encrypted password here (always encrypt plaintext passwords!) const wchar_t* encryptedPassword = L"[EncryptedPasswordHere]"; wcscpy_s((wchar_t*)pBuffer, BUFFER_SIZE / sizeof(wchar_t), encryptedPassword); std::cout << "Password stored in shared memory. Press enter to exit..." << std::endl; std::cin.get(); // Unmap the view but leave the mapping handle open—let the OS close it when the process exits // Important: If no other process has opened the mapping before this process exits, the kernel object will be destroyed automatically UnmapViewOfFile(pBuffer); return 0; }
Step 2: Read the Password from Another Process
To access the stored password in a separate process, you just need to open the existing named mapping and map a view to it (use read-only access for better security):
#include <windows.h> #include <iostream> #define MAPPING_NAME L"Global\\SecurePassStore_7a9f2b" #define BUFFER_SIZE 256 int main() { // Open the existing named mapping HANDLE hMapping = OpenFileMapping( FILE_MAP_READ, // Restrict to read-only access FALSE, // Don't inherit the handle MAPPING_NAME ); if (hMapping == NULL) { std::cerr << "OpenFileMapping failed. Error code: " << GetLastError() << std::endl; return 1; } // Map the view to read the data LPVOID pBuffer = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, BUFFER_SIZE ); if (pBuffer == NULL) { std::cerr << "MapViewOfFile failed. Error code: " << GetLastError() << std::endl; CloseHandle(hMapping); return 1; } // Read the encrypted password (decrypt it securely in your actual code!) std::wcout << "Retrieved encrypted password: " << (wchar_t*)pBuffer << std::endl; // Clean up UnmapViewOfFile(pBuffer); CloseHandle(hMapping); return 0; }
Step 3: Explicitly Delete the Shared Memory
To delete the shared memory so no other processes can access it, you need to ensure all open handles to the mapping object are closed. The safest way is to create a dedicated function/process that opens the mapping and closes the handle (this will destroy the kernel object if it's the last open handle):
#include <windows.h> #include <iostream> #define MAPPING_NAME L"Global\\SecurePassStore_7a9f2b" int main() { HANDLE hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, MAPPING_NAME ); if (hMapping == NULL) { std::cerr << "Mapping not found—may already be deleted. Error code: " << GetLastError() << std::endl; return 1; } // Closing this handle will destroy the mapping if it's the last open one CloseHandle(hMapping); std::cout << "Shared memory deleted successfully." << std::endl; return 0; }
Critical Security Best Practices
- Encrypt Everything: Never store plaintext passwords in shared memory. Use Windows CryptoAPI functions like
CryptProtectDatato encrypt the password with a user-specific key before storing it. - Restrict Access: Customize the
SECURITY_ATTRIBUTESinCreateFileMapping()to limit access to only your processes or specific users. This prevents unauthorized apps from reading the shared memory. - Minimize Exposure: Unmap the memory view as soon as you're done using it in each process, and avoid keeping the mapping handle open longer than necessary.
- Unique Names: Use a highly unique name (like a GUID) for the mapping to prevent collisions with other applications.
Key Limitation to Keep in Mind
If no processes hold an open handle to the mapping object, the OS will automatically destroy it (freeing the shared memory) even if you didn't explicitly delete it. If you need the memory to persist without any active processes using it, you'll need a lightweight background service that holds the mapping handle open until you trigger explicit deletion.
内容的提问来源于stack exchange,提问作者Shnor W.

