CreateFileMapping and OpenFileMapping not cooperating in different processes - c++

I'm trying to use CreateFileMapping and OpenFileMapping to share memory between processes. This isn't working as I want it to - OpenFileMapping returns null and GetLastError is 5 - access denied. Any ideas what I am doing wrong? Name is something like MemoryTest.
Edit:
using CreateFileMapping both times I can read the data written in the other process. The reason this is a problem is that I get Error 183 - memory area already exists. However, it still returns a handle to the existing memory.
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0)
*handle = 10;
UnMapViewOfFile(map_handle);
getchar();
Other process:
var map_handle = OpenFileMapping(PAGE_READWRITE, false, name.c_str())
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();
This works for the second process though:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();

Simple things to be aware of from the very start:
Error code 5: ERROR_ACCESS_DENIED "Access is denied."
Error code 183: ERROR_ALREADY_EXISTS "Cannot create a file when that file already exists."
ERROR_ALREADY_EXISTS is a documented behavior and is an indication of scenario that you do receive handle, but it is a handle to already existing object, not created.
The problem with not working OpenFileMapping is around its first argument: the API function expects values/flags from another enumeration, it takes FILE_MAP_* values and not PAGE_*. Incorrect argument results in failure to open you the mapping you want.

In case someone else needed, in my case the error has nothing to do with the access to the file, it's with the size provided to the CreateFileMapping, after spending hours with a similar error I'd to use a working sample posted somewhere else and line by line compare what was the difference.
If you don't know the size of the file when executing the CreateFileMapping you need to use 0, this will tell the API to use the file size of the mapped file. Most of the answers in SO around this are wrong and people is not bothering testing what is the problem about, I wasted hours reading other posts with similar suggestions.
To solve the problem the code should look like this:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0, name.c_str());
Hope this saves hours to other fellow developers.

Related

MapViewOfFile returns different addresses with same handle

I'm trying to implement IPC for a school assignment by sharing memory.
I made a class called SharedMemoryBuffer to deal with creating file mappings and views.
My Init() function looks like this:
BYTE * SharedMemoryBuffer::Init(const wchar_t * name, size_t bufferSize)
{
FileMapHandle = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
name); // name of mapping object
if (FileMapHandle == NULL)
{
FileMapHandle =
CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
bufferSize,
name);
pBuf = (BYTE*)MapViewOfFile(FileMapHandle, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
bufferSize);
}
else
{
pBuf = (BYTE*)MapViewOfFile(
FileMapHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize
);
}
return this->GetBuffer();
}
Essentially, I pass it a name and size and it tries to open a mapping with this name. If it fails, it creates it instead.
I call it like so
this->ringBuffer.Init(widestr.c_str(), buffSize);
After this is done (I call Init 4 times for 2 buffers, from the same process) I print out the addresses of the buffers (pBuf from Init()) but theyre all different addresses.
I cant for the love of my life figure out why the addresses would be different!
I have made sure that the second time i call Init() with the same name that it does indeed open the file mapping successfully.
source: https://github.com/RavioliFinoli/SharedMemory
You are mapping the same region twice in your process. You will get two distinct addresses, but they are backed by the same physical memory. Writing into the buffer pointed by the first address modifies the buffer pointed to by the second address, since they are really the same memory.

How can an independent DLL find out what Token file accesses will be made with?

If the parent process has used LogonUser so that the access token being used for file access is different than than the token the process was started with, how can the DLL find out the NT User name that the file accesses will be processed under?
If I had a specific file location then I could use GetFileSecurity, however I don't know any guaranteed accessible paths in the context of the DLL.
If I used the following:
PSID ownedSID(NULL);
SECURITY_INFORMATION siRequested = OWNER_SECURITY_INFORMATION;
wSecInfoOK = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT, siRequested, &ownedSID, NULL, NULL, NULL, NULL);
then the PSID returned references the Windows user of the logged on process rather than that under which any writes will be treated as!
New Question in light comment / answer from #arx
I am now using TokenUser with GetTokenInformation on the handle from OpenThreadToken, but again I am getting the launching user but not the impersonated user
HANDLE hThreadToken = NULL;
if (OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hThreadToken))
{
// success
CHeapPtr<TOKEN_USER, CGlobalAllocator> pToken;
DWORD length = 0U, dwError(0UL);
if (!GetTokenInformation(hThreadToken, TokenUser, NULL, 0, &length) && ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
pToken.AllocateBytes(length);
SetLastError(ERROR_SUCCESS);//Reset last error - we have now allocated the required memory so the buffer is now big enough i.e GetLastError() != ERROR_INSUFFICIENT_BUFFER
if (pToken && GetTokenInformation(hThreadToken, TokenUser, pToken, length, &length))
{
if (IsValidSid(pToken->User.Sid))
sFailedUser = WinSecurityInfo::GetAccountSID(pToken->User.Sid, dwError);
}
dwError = GetLastError();
if (dwError)
{
boost::system::error_code sidError = MakeSysError(dwError);
TRACE("Error text for GetLastError() = '%s'\n", sidError.message().c_str());
}
}
}
P.S WinSecurityInfo::GetAccountSID is just a wrapper around LookupAccountSid
P.P.S Tried both FALSE and TRUE in OpenThreadToken, no change
You are looking at the wrong information in the thread token retrieved with OpenThreadToken. To get the identity of the user being impersonated you need to look at the TokenUser, not the TokenOwner.
Use GetTokenInformation to retrieve the user.
However, rather than going to great lengths to work in the face of impersonation, it is more usual to specify as part of your API contract that you don't. And then ignore the problem.

Sending keyboard input via DeviceIoControl

For the past 3 hours or so I've been attempting to send keyboard input by writing to the keyboard device. I have successfully found and opened the keyboard device, but I'm stuck at the final step. I don't know exactly how to format the DeviceIoControl parameters and I don't really know where to start getting the values.
Currently I have the following taken partly from a library called Interception posted in another answer here. I left out all the device opening stuff to save space.
#define IOCTL_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x820, METHOD_BUFFERED, FILE_ANY_ACCESS)
if(device != INVALID_HANDLE_VALUE) {
DWORD dwReturned;
KEYBOARD_INPUT_DATA kbinput;
kbinput.UnitId = 0;
kbinput.MakeCode = 0x2D;
kbinput.Flags = KEY_MAKE;
kbinput.Reserved = 0;
kbinput.ExtraInformation = 0;
DeviceIoControl(device, IOCTL_WRITE, &kbinput, sizeof(KEYBOARD_INPUT_DATA), NULL, 0, &dwReturned, NULL);
kbinput.Flags = KEY_BREAK;
DeviceIoControl(device, IOCTL_WRITE, &kbinput, sizeof(KEYBOARD_INPUT_DATA), NULL, 0, &dwReturned, NULL);
}
If I call GetLastError after the DeviceIoControl calls I get a return value of ERROR_INVALID_FUNCTION(1). I assume that means IOCTL_WRITE isn't the correct value, but I haven't the faintest idea on how to find the correct value and no amount of searching has gotten me any further.

Directory relative ZwCreateFile

I have to implement cross view file integrity checker for my University project. For that how do I list the files of a Directory in Kernel Mode??
Your starting point would be ZwCreateFile - which has options such as "FILE_LIST_DIRECTORY".
You will then use ZwQueryDirectoryFile to get the information about the file(s) within that directory.
Make SURE that you are not forgetting to ZwClose after you open something - it's not so critical in a user-mode application that closes again after it's been used. But the kernel doesn't know when a driver stops using a file (or, for that matter, if some other driver has been given that filehandle, and will be using it at some point), so even if your driver is unloaded, files that it opened will remain open until the system restarts - I quite like to "not restart" my systems, and with a good set of drivers, running a machine for more than a year should be possible. If your driver so much as leaks one handle a day, that's 365 handles leaked.
So, the code would look something like this:
HANDLE h;
NTSTATUS status;
OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), NULL, L"mydir",
OPEN_CASE_INSENSITIVE, NULL, NULL };
IO_STATUS_BLOCK iosb = {};
status = ZwCreateFile(&h, FILE_LIST_DIRECTORY, &oa, &iosb, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_OPEN, FILE_DIRECTORY_FILE,
NULL, 0);
if (status != STATUS_SUCCESS)
{
... do something...
return errorcode;
}
else
{
FILE_DIRECTORY_INFORMATION info;
for(;;)
{
status = ZwQueryDirectoryFile(h, NULL, NULL, &iosb, &info, sizeof(info),
FileDirectoryInformation, TRUE, L"*.*",
FALSE);
if (status != STATUS_SUCCESS)
{
... check error code and perhaps print if unexpected error ...
break;
}
... do soemthing with `info` ...
}
}
ZwClose(h);
This is just a "rough sketch". I don't have a setup to compile this right now, and I may have missed something important. But it should give you some idea. There are LOTS of optional parameters and optional choices here, and some I've "guessed" what you'd want, but I think I've made reasonable choices. There may be details missing that make this not work, but as a rough starting point, it should give you an idea at least.

Struggling with debug asserts with mem alloc for SP_DEVICE_INTERFACE_DETAIL_DATA

I'm struggling with some debug asserts when my test program exits. The purpose is to get the device path to a disk drive through using the Setup API. This I'm doing. I'm following the rule described here for SetupDiGetDeviceInterfaceDetail i.e. calling SetupDiGetDeviceInterfaceDetail() to determine the size needed for the structure, and allocating memory for the structure and calling SetupDiGetDeviceInterfaceDetail() again.
This process works and I'm getting the data that I need. What is not working correctly is, when the program exits, or I delete the memory directly, I get a debug assertion. The assert window has the file where the problem was found, dbgdel.cpp, on line 52. The problem: "Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)".
I'm not sure what the problem is. If I remove all of the code I'm using and new up an SP_DEVICE_INTERFACE_DETAIL_DATA object without all of the Setup API calls, the call to delete works. Basically, here's what I'm doing:
HDEVINFO hDevs = SetupDiGetClassDevs(&DiskClassGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
SP_DEVICE_INTERFACE_DATA devInterfaceData = {sizeof(SP_DEVICE_INTERFACE_DATA)};
DWORD size(0);
SetupDiEnumDeviceInterfaces(hDevs, NULL, &DiskClassGuid, 0, &devInterfaceData);
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetails(NULL);
SetupDiGetDeviceInterfaceDetail(hDevs, &devInterfaceData, pDetails, 0, &size, NULL);
pDetails = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(new BYTE[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + size]);
// zero allocated memory
pDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(hDevs, &devInterfaceData, pDetails, size, NULL, NULL);
delete[] pDetails;
When the program exits, or the delete[] is called, the assert that mentioned earlier shows up. Please explain to me what I'm doing wrong.
Thanks,
Andy
UPDATE:
Forgot to add the definition of SP_DEVICE_INTERFACE_DETAIL_DATA. That can be found here. However, it looks like this:
typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
DWORD cbSize;
TCHAR DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;