In Windows it's possible to open devices and volumes via CreateFile(). I've used this successfully before to ReadFile() from devices, but now I want to switch to memory-mapping. In the following code, I receive INVALID_HANDLE_VALUE for the value of b, and c is set to 87, ERROR_INVALID_PARAMETER.
HANDLE a = ::CreateFileA("\\\\.\\h:", GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_NO_BUFFERING, NULL);
HANDLE b = ::CreateFileMappingA(a, NULL, PAGE_READONLY, 0, 0, NULL);
DWORD c = ::GetLastError();
How can I get this to work?
You can't. CreateFileMapping can only create a mapping to a file. Take a look at the difference in the documentation between the hFile parameter for ReadFile and for CreateFileMapping. For ReadFile it lists all the different types of handles it accepts (which includes devices), for CreateFileMapping it only lists files.
Related
What I would like to do is use MiniDumpWriteDump() write to a named pipe and then read/write it myself. I am able to perform the dump successfully if I write the contents to a file directly. However, while writing to the named pipe has been successful the subsequent read/write operation does not go so well. I can read all the data out of the pipe but then when it's written the DMP file appears to be corrupted.
Here is the ReadFile() logic:
while (ReadFile(hInboundPipe, &vecBuffer[dwOffset], vecBuffer.size() - dwOffset, &dwRead, NULL)) {
dwOffset += dwRead;
while (dwOffset >= vecBuffer.size()) {
vecBuffer.resize(vecBuffer.size() + iBuffer * sizeof(char));
}
}
Here is the WriteFile() logic:
HANDLE hDumpFile = CreateFileW(L"C:\\test.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hDumpFile , &vecBuffer[0], dwOffset, &dwOutBytes, NULL);
CloseHandle(hDumpFile);
I'm not certain if it's applicable to the root cause but here is the named pipe setup:
HANDLE hInboundPipe = CreateNamedPipe(
szPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_WAIT | PIPE_TYPE_BYTE,
PIPE_UNLIMITED_INSTANCES,
0,
0,
(DWORD)-1,
&SecAttrib);
There are not any errors being reported back from GetLastError(). Am I missing something obvious?
EDIT: Adding how the MiniDumpWriteDump() is being done in response to a comment.
HANDLE hDump = CreateFile(szPipeName, GENERIC_ALL, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
MiniDumpWriteDump(hProcess, pid, hDump, mdValue, NULL, NULL, NULL);
CloseHandle(hDump);
UPDATE:
I was under the impression that reading by chunks was somehow dropping data. To test this I increased the buffer of the named pipe to accommodate the entire dump without any resizing. I also increased the vecBuffer size to match. Now when performing the ReadFile() operation I receive the entire dump but it is still off. I'm still playing with various named pipe settings trying to figure out what needs to be done to get MiniDumpWriteDump() to provide valid output to a named pipe.
It appears this cannot be done. See the comments for more information. Writing directly to a named pipe from MiniDumpWriteDump() cannot be done because the handle that is passed in must have the ability to seek. Named pipes do not have that functionality, therefore you must use a legitimate file handle.
I know how to do this through an anonymous pipe, just create an anonymous pipe and before executing createprocess(), set the startupInfo as follow:
startupInfo.hStdInput = hstdinRead;//hstdinRead is the handle of the pipe
startupInfo.hStdOutput = hstdoutWrite;
But can I do the same when I use a named pipe?
I have tried to create a named pipe through CreateNamedPipeA function and do similar above, but things don't seem to work at all.
Should I do some pre-settings or is it just impossible to communicate between a process and it's child process through a named pipe?
And : My child process is an unchangable .exe, so I must do all these things before createprocess() function in the parent process.
20180804: thanks for your comments, I am still polishing my English, and my codes using named pipes are like these.
First I create two named pipes and I have confirmed they succeed:
inFileWrite = CreateNamedPipeA("\\\\.\\pipe\\cmder_in", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 10, 4096, 4096, 0, &saAttr);//for writting to the child process
outFileRead = CreateNamedPipeA("\\\\.\\pipe\\cmder_out", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 10, 4096, 4096, 0, &saAttr);//for reading from the child process
Then I try to connect to these pipes in the same process(I am a bit confused about this step)
inFileRead = CreateFileA("\\\\.\\pipe\\cmder_in", GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, &saAttr)
outFileWrite = CreateFileA("\\\\.\\pipe\\cmder_out", GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, &saAttr);
After some other init steps, I create a STARTUPINFO struct for childprocess, in which I try to redirect its std input/output:
startupInfo.hStdInput = inFileRead;
startupInfo.hStdOutput = outFileWrite;
Finally it's the createprocess:
char cmdLine[] = { "cmd" };
CreateProcess(NULL,
cmdLine,
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&startupInfo,
&procInfo);
These all codes seem to work well, but when I write an command like "cd .." and try to read the result from childprocess through the pipe, it reads nothing. I think the problem is I didn't redirect childprocess's stdin/out successfully.
I succeeded in doing similar things by using an anonymous pipe or named pipes in Linux. I am new to windows programming, and this problem has stuck me for a long time.
assuming there's the following code -
HANDLE h = CreateFile(L"some_dll.dll", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE map = CreateFileMapping(h, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
LPVOID res = MapViewOfFileEx(map, 0, 0, 0, 0, 0);
Is it possible to extract 'some_dll', given the address it's mapped to, using c++ ?
When trying to debug this executable using windbg, it seems that it doesn't extract the module well too
Yes, this is exactly what GetMappedFileName is for:
Checks whether the specified address is within a memory-mapped file in the address space of the specified process. If so, the function returns the name of the memory-mapped file.
PS: there's no reason for windbg to show the name of a memory mapped file that isn't a loaded module, even if the file happens to be a DLL.
I have admin rights and have no problem getting a valid handle and ultimately reading an entire hard drive via:
IntPtr handle = CreateFile(#"\\.\PHYSICALDRIVE1", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
I can also get a valid handle when I try to open a directory of that drive:
IntPtr handle = CreateFile(#"\\.\Z:\\", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
But I cannot get a valid handle when I try to simply open a partition of that drive:
IntPtr handle = CreateFile(#"\\.\Z:", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
GetLastWin32Error returns access denied (5).
Of course if I offline the drive, then I get "The system cannot find the file specified."
I've tried everything I could think of with different partitions, different options etc. to no available.
I found the answer myself. Let me correct myself in pointing out that CreateFile(#"\.\Z:" is opening a Volume, not necessarily a partition. However, I could not even open a volume.
Until I added FILE_SHARE_WRITE to the options as follows:
IntPtr handle = CreateFile(#"\.\Z:", GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
That was the key to getting a valid handle. This is certainly not intuitive!
Why this should be the case is only known by Microsoft I guess.
I would like to point out that the documentation of CreateFile says the following about FILE_SHARE_WRITE:
Enables subsequent open operations on a file or device to request write access.
Otherwise, other processes cannot open the file or device if they request write access.
If this flag is not specified, but the file or device has been opened for write access or has a file mapping with write access, the function fails.
I have a modem on COM44 and when I try to access it via C++ I end up receiving ERROR_SHARING_VIOLATION. The code I am using is and m_hFile ends up as -1:
void* m_hFile;
m_hFile = ::CreateFile( "\\\\.\\COM44",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL );
I have tested access to the modem via Putty and was able to open its comport and send AT commands to it without any problem so I know it works.
The problem ends up not being with the CreateFile code but with the registry code I have above it which determines the com port number to use which I hadn't added because I didn't think it was relevant.