Invalid handle when calling IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER - c++

Anyone out there have experience of c/c++ IOCTL calls?
Basically I'm trying to identify what port a USB memory stick is plugged into.
I have all the USB info and have volume info. Apparantly to link these 2 blocks of info I need either the driver-key or serial-number.
However when calling DeviceIoControl I'm getting invalid handle as the "last error code"
My drive USB drive mounted to a directory in c:\ (not a drive letter) See below
//get a handle on the volume
HANDLE hVolume;
DWORD dwAccessFlags;
dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
hVolume = CreateFile(L"C:\_USB\MP1",
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
if (hVolume == INVALID_HANDLE_VALUE) {
printf("Invalid Handle");
}
//use the handle
MEDIA_SERIAL_NUMBER_DATA* pserialNumberData = new MEDIA_SERIAL_NUMBER_DATA;
wstring result;
//HANDLE hVolume = OpenVolume(vname.substr(0, vname.length() - 1).c_str());
DWORD bytesReturned = 0;
LPDWORD lpBytesReturned = &bytesReturned;
OVERLAPPED over;
LPOVERLAPPED lpOver = &over;
BOOL success = 1;
success = DeviceIoControl(
(HANDLE) hVolume, // handle to device
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID) pserialNumberData, // output buffer
(DWORD) sizeof(MEDIA_SERIAL_NUMBER_DATA), // size of output buffer
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOver // OVERLAPPED structure
);
wcout << L"--> GetSn() DeviceIoControl success " << success << endl;
wcout << L"--> GetSn() DeviceIoControl Last error number " << GetLastError() << endl;
wcout << L"--> GetSn() DeviceIoControl Bytes Returned " << bytesReturned << endl;
wcout << L"--> GetSn() DeviceIoControl struct size " << sizeof(MEDIA_SERIAL_NUMBER_DATA) << endl;

If you look at the Remarks section for the DeviceIoControl function, it says:
To retrieve a handle to the device, you must call the CreateFile function with either the name of a device or the name of the driver associated with a device. To specify a device name, use the following format:
\\.\DeviceName
DeviceIoControl can accept a handle to a specific device. For example, to open a handle to the logical drive A: with CreateFile, specify \\.\a:. Alternatively, you can use the names \\.\PhysicalDrive0, \\.\PhysicalDrive1, and so on, to open handles to the physical drives on a system.
You are not opening a device handle, and thus DeviceIoControl is not going to work for that case.

The first big problem I see is that the CreateFile function must be called with the FILE_FLAG_BACKUP_SEMANTICS flag in order to get a valid handle to a directory. So, for starters, try:
hVolume = CreateFile( L"C:\_USB\MP1",
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL );

Hmmm... I think the handle you get from CreateFile is the handle to the directory you mounted your drive to, rather than the drive itself. To be sure you get the handle to device you want, you should use a device path, e.g. \\.\Device\HarddiskVolume1. WinObj or DeviceTree can probably help you find the path to your usb drive.

Related

How to create a virtual file in memory and use it as a normal FILE pointer? [duplicate]

This question already has answers here:
in-memory FILE* (without disk access)
(3 answers)
Closed 1 year ago.
I need to load a file from the hard drive to a virtual file in RAM. I then need to access this virtual file using the fopen function (I need to get the FILE pointer from it). Is this possible?
For now, I only loaded the file to stringstream:
std::ifstream file("File.zip", ios::in | ios::binary);
if (file.is_open())
{
//clear:
ProtectedZipBuffer.str(std::string());
ProtectedZipBuffer << file.rdbuf();
file.close();
}
What I'm trying to do is to mod an old game. I would need to load an encrypted file (that's for later, at the moment I'm just trying to see if the virtual file works), decrypt it to a virtual file and return the read-only FILE pointer to game (from my DLL file to the main game process). This is needed, because I would like to use the purchased / licensed sound files, but the End User License forces me to encrypt files in order to disallow users from accessing copyrighted audio files by exploring game files.
Could somebody please give me some ideas how to do this?
EDIT:
I've tried the FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE method, unfortunately no matter what, it's always writing data (around 100MB) to disk (even though I have over 8GB RAM free).
Here's the code I am using:
string SourceFileStr = "TEST_FILE_SOURCE.bin";
string DestinationFileStr = "DESTINATION_FILE.bin";
wstring DestinationFileWstr = L"DESTINATION_FILE.bin";
if (FileExistsW(DestinationFileWstr.c_str())) {
DeleteFileW(DestinationFileWstr.c_str());
}
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to initialize security descriptor. GetLastError=" << dwLastError);
//return dwLastError;
return 0;
}
if (!SetSecurityDescriptorDacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the DACL
TRUE, // presence of a DACL in the security descriptor
NULL, // allows all access to the object
FALSE // DACL has been explicitly specified by a user
))
{
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor DACL. GetLastError=" << dwLastError);
//return dwLastError;
return 0;
}
if (!SetSecurityDescriptorGroup(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose primary group is set by this function
NULL, // no primary group
FALSE // Indicates whether the primary group information was derived from a default mechanism
))
{
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor primary group. GetLastError=" << dwLastError);
//return dwLastError;
return 0;
}
if (!SetSecurityDescriptorOwner(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose owner is set by this function.
NULL, // If this parameter is NULL, the function clears the security descriptor's owner information. This marks the security descriptor as having no owner.
FALSE // Indicates whether the owner information is derived from a default mechanism.
))
{
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor owner information. GetLastError=" << dwLastError);
//return dwLastError;
return 0;
}
if (!SetSecurityDescriptorSacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the SACL
FALSE, // the security descriptor does not contain a SACL
NULL, // security descriptor has a NULL SACL
FALSE // A pointer to a flag that is set to the value of the SE_SACL_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure if a SACL exists for the security descriptor
))
{
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor SACL. GetLastError=" << dwLastError);
//return dwLastError;
return 0;
}
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE;
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
//DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
// DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
//DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY;
hFileDecryptedWrite = ::CreateFile(DestinationFileWstr.c_str(), GENERIC_WRITE, dwShareMode, &sa, CREATE_NEW, dwFlagsAndAttributes, NULL);
//verify we created the file.
if (hFileDecryptedWrite == INVALID_HANDLE_VALUE) {
DWORD dwLastError = ::GetLastError();
//return dwLastError;
return 0;
}
std::streamsize const buffer_size = 64 * 1024;
std::ifstream file(SourceFileStr.c_str(), ios::in | ios::binary);
if (file.is_open()) {
if (file)
{
do
{
char buffer[buffer_size];
file.read(buffer, buffer_size);
size_t extracted = file.gcount();
//std::streamsize bytes_read = file.gcount();
//size_t nBytesRead = file.readsome(buffer, buffer_size);
//MessageBoxA(NULL, to_string(extracted).c_str(), "bytes read now:", MB_OK);
//result.process_bytes(buffer, ifs.gcount());
DWORD numBytesWritten;
if (!::WriteFile(hFileDecryptedWrite, buffer, extracted, &numBytesWritten, (LPOVERLAPPED)NULL)) {
DWORD dwLastError = ::GetLastError();
//LOG4CPLUS_ERROR(m_Logger, "Failed to write file to %TEMP% folder. GetLastError=" << dwLastError);
//return dwLastError;
MessageBoxA(NULL,"FAILED TO WRITE TO FILE", "ERROR", MB_OK);
return 0;
}
} while (file);
}
}
file.close();
//CloseHandle(hFileDecryptedWrite);
I am also using the CreateFileMapping / MapViewOfFile method for some other things. Unfortunately, there's no way to get a FILE * pointer which I could pass to the game process.
The fmem library: https://github.com/Snaipe/fmem
Seems to do exactly the same thing on Windows as creating the file with FILE_ATTRIBUTE_TEMPORARY
Is there anything else I could try?
Some C++ runtimes allow FILE* to be opened from memory:
fmemopen on Linux
fopencookie on Linux
funopen on FreeBSD
On Windows, however, Windows API does not include C++ runtime. You would usually deal with Visual Studio implementation of FILE*.
Visual Studio FILE* does not have a documented way to be backed by memory without file handle. Windows API does not provide a way to create a file out of memory (FILE_ATTRIBUTE_TEMPORARY and FILE_FLAG_DELETE_ON_CLOSE does not guarantee that the file is not actually written; and a pipe does not support fseek so may be not an option)
When posed with similar task I ended up in intercepting (hooking) Windows APIs. IAT patching is likely to do, without advanced hooking, such as trampolines.

How to append in file in Windows in UnBuffered mode using CreateFile

Every time my function is getting called it is overwriting to the file. Kindly note I am opening file in unbuffered mode using below flags.
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
If I am using simple buffered mode it is working fine.
FILE_ATTRIBUTE_NORMAL
I am getting following error in unbuffered mode.
** ERROR ** CreateFile failed: The parameter is incorrect.
Kindly find the code snippets below. This piece of code getting called many times.
HANDLE hFile;
LPCWSTR file_path = convertCharArrayToLPCWSTR(UNBUFFERED_FILE);
hFile = CreateFile(file_path,
FILE_APPEND_DATA,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "Unable to open/create file for writing" << std::endl;
PrintError(TEXT("CreateFile failed"));
}
Data *data = new Data();
DWORD dwBytesToWrite = sizeof(Data);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
bErrorFlag = WriteFile(
hFile, // open file handle
data, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL);
if (bErrorFlag == FALSE)
{
std::cout << "Unable to write to file" << std::endl;
PrintError(TEXT("Unable to write to file"));
}
if (dwBytesToWrite != dwBytesWritten)
{
std::cout << "Error in writing: Whole data not written" << std::endl;
PrintError(TEXT("Error in writing: Whole data not written"));
}
CloseHandle(hFile);
.
Kindly suggest if any alternative idea is available.
from NtCreateFile
FILE_NO_INTERMEDIATE_BUFFERING
The file cannot be cached or buffered in a driver's internal
buffers. This flag is incompatible with the DesiredAccess
parameter's FILE_APPEND_DATA flag.
so when you call
CreateFile(file_path,
FILE_APPEND_DATA, // !!
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING /*!!*/| FILE_FLAG_WRITE_THROUGH,
NULL
);
you use FILE_FLAG_NO_BUFFERING (mapped to FILE_NO_INTERMEDIATE_BUFFERING) with FILE_APPEND_DATA - you and must got ERROR_INVALID_PARAMETER. you need remove one flag. i suggest remove FILE_FLAG_NO_BUFFERING flag, because with it you can write only integral of the sector size.

Why does WriteFile not run more than once?

Here's my code in which I've got on an infinite loop (to my knowledge)
while(true) {
DWORD TitleID = XamGetCurrentTitleId();
std::ostringstream titleMessageSS;
titleMessageSS << "Here's the current title we're on : " << TitleID << "\n\n";
std::string titleMessage = titleMessageSS.str(); // get the string from the stream
DWORD dwBytesToWrite = (DWORD)titleMessage.size();
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
HANDLE logFile = CreateFile( "Hdd:\\LOGFile.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
bErrorFlag = WriteFile(logFile, titleMessage.c_str(), dwBytesToWrite, &dwBytesWritten, NULL);
CloseHandle(logFile);
Sleep(30000);
}
return NULL;
Does anyone see a reason as to why this only writes just once? I've waited over 5 minutes to see if it does anything in the end to no avail.
The Flag CREATE_NEW in CreateFile prevents the update of the file because CreateFile fail with ERROR_FILE_EXISTS. Use OPEN_ALWAYS instead.
Also it will always truncate. Replace GENERIC_WRITE with FILE_APPEND_DATA if you want to add a new line at the end of your logfile.
The whole CreateFile line should be:
HANDLE logFile = CreateFile( "Hdd:\\LOGFile.txt", FILE_APPEND_DATA , 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
Read CreateFile documentation carefully, it worth it, because it has a central role in the windows IO universe:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
look also add:
https://stackoverflow.com/a/9891875/1922748
As Martin James mentioned, from MSDN:
CREATE_NEW
Creates a new file, only if it does not already exist.
If the specified file exists, the function fails and the last-error
code is set to ERROR_FILE_EXISTS (80).
If the specified file does not exist and is a valid path to a writable
location, a new file is created.
So it seems that the handle is invalid after the first call, and hence WriteFile() fails.

CreateFile path error in Visual C++

for (int i = 0; i < 1000; i++)
{
sprintf_s(text, "Text from process %d\r\n", GetCurrentProcessId());
HANDLE hFile = CreateFile(_T("\\\\.\\Device\\HarddiskVolume2\\dev\\test\\test.txt"), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
cout << "Error opening file " << GetLastError() << " at index " << i << endl;
break;
}
SetFilePointer(hFile, GetFileSize(hFile, NULL), NULL, FILE_BEGIN);
DWORD bytes;
WriteFile(hFile, text, strlen(text), &bytes, NULL);
CloseHandle(hFile);
}
i'm trying to open write using the actual device name
\Device\HarddiskVolume2 is mapped to c:\
the folder already exist in c drive
i'm getting error opening file
Error code 3 is ERROR_PATH_NOT_FOUND. The reason you see that is because \\.\Device\HarddiskVolume2 is the path of the raw device. If you use that path, you no longer have access to the file system. What that path gives you is access to the raw disk sectors.
If you must use \\.\Device\HarddiskVolume2 to identify the drive then you need to first convert, by some means or other, to a mapped drive letter, or a DOS device path for the volume. The latter would be, in your case, \\.\HarddiskVolume2
Please refer
ERROR_PATH_NOT_FOUND
3 (0x3)
The system cannot find the path specified.
So please try to check the path is available or not ..\\Device\\HarddiskVolume2\\dev\\test\\test.txt.
this is because program unable to find the path
or try this:
..\\Device\\HarddiskVolume2\\dev\\test\\test.txt
if the path is in same directory as your exe.
Reason
While creating the file the compiler look into the path which is in the directory where the exe file is. If it is not found then Program will check into the Drive where the Program is running.
Also try to get some information from CreateFile.
hope this will help you.

Writing raw data to a disk in windows fails with error code 83 (invalid parameter)

I have a little snippet of code that I am trying to use to write a string that is roughly 100 bytes long to a disk at the address 0x600.
UCHAR szStr[0x4C] = {0};
memcpy(szStr, "Example string", 8);
DWORD bytes, cb;
HANDLE hDisk = CreateFile("\\\\.\\I:", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDisk == INVALID_HANDLE_VALUE)
{
cout << "CreateFile error"<< endl << GetLastError();
}
if (!DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &cb, NULL))
{
cout << "IO Error"<< endl << GetLastError();
}
if (SetFilePointer(hDisk, 0x600, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
cout << "Pointer error"<< endl << GetLastError();
}
if (!WriteFile(hDisk, szStr, 0x4C, &bytes, 0))
{
cout << "Write error" << endl << GetLastError(); //Only one that triggers (err code 87)
}
CloseHandle(hDisk);
For some reason everything is OK until I call WriteFile() which fails. GetLastError() returns a code of 83 which means INVALID_PARAMETER. I have tried debugging it by specifing a normal file on the desktop instead of the drive I:\ and the operation fires off successfully so my best guess would be the problem lies with the disk handle to the drive I:\.
I read an article by MSDN located here that explains that raw disk I/O gets blocked if you don't lock/dismount the drive first. I am confused as to why that would be a problem as in my code I call DeviceIoControl with FSCTL_LOCK_VOLUME to lock the device before I perform anything else. The disk has an active file system (FAT32/FAT16) and the 0x600 region likely lies within the filesystem, but according to the article if I lock the drive I should be able to write to it. Any idea what is going on here? Thanks!
Are you checking DeviceIoControl and SetFilePointer for an error indication?
Do you have the rights to do the operations you're attempting? Administrator account is required for raw disk writes IIRC.
Is the disk you're trying to open a system disk? (Does it contain the OS files?) If so the Lock IOCTL will fail.
If there's a page file on the disk you're trying to lock the Lock IOCTL will fail.