CreateFile: direct write operation to raw disk "Access is denied" - Vista, Win7 - c++

The relevant Microsoft doc is:
Blocking Direct Write Operations to Volumes and Disks
CreateFile, remarks on Physical Disks and Volumes
The executable is written in C++ and it calls CreateFile() to open an SD card that has no filesystem. The CreateFile() and consecutive ReadFile() calls are successful for GENERIC_READ without Administrator privileges.
CreateFile fails for GENERIC_WRITE even with Administrator privileges. In the explorer, I set Run as Administrator under Properties > Compatibility > Privilege Level. I also tried to run the executable from an Administrator cmd (started with Ctrl+Shift+Enter, "Administrator:" is in the window title, properly elevated). Still, I get ERROR_ACCESS_DENIED (0x5).
Do I have to pass something else to CreateFile? I have no idea what security attributes are, I just pass NULL, relevant code is here at line 92, and here at line 48.
Or is there anything else that should be set to run the process with Administrator privileges?
A related questions:
Can I get write access to raw disk sectors under Vista and Windows 7 in user mode?
Raw partition access in Windows Vista
How to obtain direct access to raw HD data in C?
Is there a clean way to obtain exclusive access to a physical partition under Windows?

While the answer of #MSalters makes sense, it is not how my code works. In fact it is so counter-intuitive, I spent several days making sure the code does in fact work.
These code snippets are in a proven, mass consumer market software product. When it needs to modify an on-disk structure, it dismounts the win32 volume so it can modify NTFS or FAT filesystem structures. Interestingly, the volume access handle is read-only:
char fn [30];
snprintf (fn, sizeof fn, "\\\\.\\%s:", vol -> GetVolName ());
vol_handle = CreateFile (fn, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS,
NULL);
if (vol_handle == INVALID_HANDLE_VALUE)
{
// show error message and exit
}
If unable to get write access to a volume or partition, this code forces a dismount if the user authorizes such after a stern warning:
if (!DeviceIoControl (vol_handle, FSCTL_DISMOUNT_VOLUME,
NULL, 0, NULL, 0, &status, NULL))
{
DWORD err = GetLastError ();
errormsg ("Error %d attempting to dismount volume: %s",
err, w32errtxt (err));
}
// lock volume
if (!DeviceIoControl (vol_handle, FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0, &status, NULL))
{
// error handling; not sure if retrying is useful
}
Writing is then fairly straightforward, except for positioning the file pointer by 512-byte sector:
long hipart = sect >> (32-9);
long lopart = sect << 9;
long err;
SetLastError (0); // needed before SetFilePointer post err detection
lopart = SetFilePointer (vol_handle, lopart, &hipart, FILE_BEGIN);
if (lopart == -1 && NO_ERROR != (err = GetLastError ()))
{
errormsg ("HWWrite: error %d seeking drive %x sector %ld: %s",
err, drive, sect, w32errtxt (err));
return false;
}
DWORD n;
if (!WriteFile (vol_handle, buf, num_sects*512, &n, NULL))
{
err = GetLastError ();
errormsg ("WriteFile: error %d writing drive %x sectors %lu..%lu: %s",
err, drv, sect, sect + num_sects - 1,
w32errtxt (err));
return false;
}

It's quite rare to want only GENERIC_WRITE. You most likely want GENERIC_READ|GENERIC_WRITE.

There is note in MSDN in documentation of CreateFile:
Direct access to the disk or to a volume is restricted. For more information, see "Changes to the file system and to the storage stack to restrict direct disk access and direct volume access in Windows Vista and in Windows Server 2008" in the Help and Support Knowledge Base at http://support.microsoft.com/kb/942448.
It refers to Vista/2008, but maybe apply to Win7 also.

I had a similar issue when porting from x86 to x64 code. You mention that you are passing null for your SECURITY_ATTRIBUTES parameter; I was getting access-denied errors myself using this approach until I actually began creating/passing this parameter.

Related

Windows Resource Monitors "Network Activity" c++

I'm trying to figure out how to get all network activity for a given process. In the Windows "Resource Monitor" application in the "Network Activity" box, you are able to see all tcp / udp connections, and the data being sent etc. I first tried using the cmd netstat, and was going to parse this but quickly realized it "misses" a whole bunch of udp connections. So that was out. Now I've been looking into using iphlpapi.h in c++ along with its GetExtendedUdpTable function. But even this doesn't seem to be showing all the data that Resource Monitor shows. Can anyone direct me to the proper windows API that can get the same information as seen in the Network Activity tab under Resource Monitor. I've been searching for a while now and everything I've found is extremely old, I'm hoping to use whatever is the current/modern approach. This doesn't have to be backwards compatible, windows 10 only is fine.
Basically my end-goal is to build an app that can geo-locate ip's using a database automatically for a target application (including UDP connections). Now I'm sure there are many libraries/apps out there that can already do this. I'm just wanting to do it as a learning process so I'd like to avoid any libraries/API other than windows provided ones.
This is currently what I've been working with, please forgive the use of poor practices such as using printf and not using static_cast etc. I'll be rewriting everything properly once I've found a way of obtaining the information I'm after.
MIB_UDPTABLE_OWNER_PID* pUdpTable;
MIB_UDPROW_OWNER_PID* owner;
DWORD dwSize;
DWORD dwResult;
dwResult = GetExtendedUdpTable(NULL, &dwSize, false, AF_INET, UDP_TABLE_OWNER_PID, 0);
pUdpTable = (MIB_UDPTABLE_OWNER_PID*)MALLOC(dwSize);
dwResult = GetExtendedUdpTable(pUdpTable, &dwSize, false, AF_INET, UDP_TABLE_OWNER_PID, 0);
for (DWORD dwLoop = 0; dwLoop < pUdpTable->dwNumEntries; dwLoop++) {
owner = &pUdpTable->table[dwLoop];
printf("%ld ", owner->dwOwningPid);
HANDLE Handle = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
owner->dwOwningPid
);
if (Handle) {
TCHAR Buffer[MAX_PATH];
if (GetModuleFileNameEx(Handle, 0, Buffer, MAX_PATH)) {
printf(Buffer);
printf("\n");
} else {
printf("Error GetModuleFileNameEx : %lu\n", GetLastError());
}
CloseHandle(Handle);
} else {
printf("Error OpenProcess : %lu\n", GetLastError());
}
}
FREE(pUdpTable);

WriteFile fails for > 4700 blocks (SD card raw write / Window)

I am writing / reading raw data on a SD card. The code for writing is working up to approx. 4700 blocks and fails after this limit. Here is the code:
//Data to be written
uint8_t* sessions;
sessions = (uint8_t *) malloc(2048*sizeof(uint8_t));
unsigned int i;
for(i=0;i<(2048*sizeof(uint8_t));i++) sessions[i]=8;
DWORD dwWrite;
HANDLE hDisk=CreateFileA("\\\\.\\K:", // drive to open = SD CARD
GENERIC_WRITE, // access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_FLAG_NO_BUFFERING, // file attributes
NULL); // do not copy file attributes
if(hDisk==INVALID_HANDLE_VALUE)
{
CloseHandle(hDisk);
printf("ERROR opening the file !!! ");
}
DWORD dwPtr = SetFilePointer(hDisk,10000*512,0,FILE_BEGIN); //4700 OK
if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
{
printf("CANNOT move the file pointer !!! ");
}
//Try using this structure but same results: CAN BE IGNORED
OVERLAPPED osWrite = {0,0,0};
memset(&osWrite, 0, sizeof(osWrite));
osWrite.Offset = 10000*512; //4700 OK
osWrite.hEvent = CreateEvent(FALSE, FALSE, FALSE, FALSE);
if( FALSE == WriteFile(hDisk,sessions,2048,&dwWrite,&osWrite) ){
printf("CANNOT write data to the SD card!!! %lu",dwWrite);
}else{
printf("Written %lu on SD card",dwWrite);
}
CloseHandle(hDisk);
The issue is with the function "Writefile" (windows.h). If the number of block is less than 4700. everything is fine (data are written on the SD card) but if the block number is let's say 5000 or 10000, the function fails "Written 0".
Notice that without FILE_FLAG_NO_BUFFERING, no way to open the drive (SD card). The "OVERLAPPED" is a failed attempt to make it works, not using it (WriteFile(hDisk,sessions,2048,&dwWrite,NULL) )leads to the same behaviour. "SetFilePointer" works also for blocks higher than 4700. Have tested as well 2 different SD cards. I am on Windows 10.
Any hint as to what is happening?
Thank you for your input
From the documentation for WriteFile:
A write on a volume handle will succeed if the volume does not have a mounted file system, or if one of the following conditions is true:
The sectors to be written to are boot sectors.
The sectors to be written to reside outside of file system space.
You have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.
The volume has no actual file system. (In other words, it has a RAW file system mounted.)
You are able to write to the first couple of megabytes because (for historical reasons) the file system doesn't use that space. In order to write to the rest of the volume, you'll first have to lock the volume using the FSCTL_LOCK_VOLUME control code.
You should pass Null as the 3rd parameter of SetFilePointer, lpDistanceToMoveHigh, unless you are using the higher order 32 bits of a 64-bit address. Also, if you are not using the OVERLAPPED structure, make sure to pass Null to WriteFile for that parameter.
Also, be sure that you are not having any overflows for the data types you are using. And, be mindful of the addressing limitations of the system you are working on.
MSDN WriteFile
MSDN SetFilePointer

CreateFile error trying to open pipe

I am trying to create a demonstration client/server application using named pipes on two Windows 7 machines, but cannot get this to work. The two machines, let's call them server and laptop, are both connected to an ethernet switch which is in turn connected to a cable modem. Both machines can see the internet, and both machines show up in the Windows network map. So I think they are correctly networked.
I am writing in Visual C++ and am basically copying the sample code on MSDN for a named pipe server and client. On my server, I call CreateNamedPipe() using the pipe name:
\\.\pipe\MyServerName
On the client, I call CreateFile with the pipe name of:
\\<machine>\pipe\MyServerName
where "machine" is configurable. If I run the server and client on the same machine, and for machine use either "." or "POWEREDGE" (the name of my server machine according to Windows), the two programs communicate fine.
Now I go to my laptop and run the client software. I use "POWEREDGE" as the machine name. CreateFile fails with GetLastError=1 ("Incorrect Function" apparently).
Any ideas about what could be going wrong here?
In response to requests, here is the actual code:
// CLIENT SIDE
// note: value of gLKServer is "POWEREDGE"
char PipeName[256]="";
wsprintf(PipeName,"\\\\%s\\pipe\\LKServer", gLKServerName);
while (TRUE) {
hPipe = CreateFile(
PipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (hPipe != INVALID_HANDLE_VALUE) {
break;
}
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (err=GetLastError() != ERROR_PIPE_BUSY)
{
printf("CreateFile error %lu\n", err);
}
...
// SERVER SIDE
char PipeName[256]="\\\\.\\pipe\\LKServer";
hPipe = CreateNamedPipe(
PipeName, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute

C++ USB communication

I have a problem regarding communication with a USB device on Windows. I can't use libusb or WinUSB as I have a specific driver for that (Silabs USB to UART, which is a USB-to-serial bridge). This is how I initialize a device file, send&read data and close the handle.
HANDLE hDevFile = CreateFile(L"\\??\\USB#VID_10C4&PID_EA60#0001#{a5dcbf10-6530-11d2-901f-00c04fb951ed}",
GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
PurgeComm(hDevFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
DCB dcbInitState;
GetCommState(hDevFile, &dcbInitState);
DCB dcbNewState = dcbInitState;
dcbNewState.BaudRate = 57600;
dcbNewState.Parity = NOPARITY;
dcbNewState.ByteSize = 8;
dcbNewState.StopBits = ONESTOPBIT;
if (SetCommState(hDevFile, &dcbNewState) == 0)
{
printf("Could not set COM state. Error: %i", GetLastError());
return -1;
}
Sleep(60);
BYTE outData[8];
outData[0] = 0x53;
outData[1] = 0x10;
outData[2] = 0x04;
outData[3] = 0x10;
outData[4] = 0x40;
outData[5] = outData[3] ^ outData[4];
outData[6] = 0xAA;
outData[7] = 0x00;
DWORD dwWritten;
if (!WriteData(hDevFile, outData, 8, &dwWritten))
{
printf("Could not write data. Error: %i", GetLastError());
return -1;
}
BYTE inData[8];
DWORD dwRead;
if (!ReadData(hDevFile, inData, 8, &dwRead, 2000))
{
printf("Could not read data. Error: %i", GetLastError());
return -1;
}
SetCommState(hDevFile, &dcbInitState);
Sleep(60);
CloseHandle(hDevFile);
hDevFile = INVALID_HANDLE_VALUE;
(I get the device symbolic name from the registry but I've skipped that part to make my question concise. WriteData() and ReadData() are custom functions that write and read accordingly.)
The problem is that SetCommState() returns a zero-value. GetLastError() returns 122, which is ERROR_INSUFFICIENT_BUFFER.
The problem now is that PurgeComm() generates ERROR_INSUFFICIENT_BUFFER, too. CreateFile() gives ERROR_SUCCESS, so it must be opened properly.
What's wrong? Did I miss something?
Edit: I tried enumerating COM ports and found an interesting thing - there are no COM ports on my computer. Even though the device is connected and enabled, with the driver present and all that stuff. I also tried forcefully putting \\.\COM1, \\.\COM2, and so on as the file name for CreateFile, but with no luck. Everytime got an ERROR_FILE_NOT_FOUND.
Please, help. This is very important to me.
Because this is a CP210x device, it's a virtual COM port, so you should be opening it as such in CreateFile. You had it right when you said that you tried using \.\COMx, you just need to find out which COM port your CP210x device has been assigned and you will not get the ERROR_FILE_NOT_FOUND error. You can find this by looking in device manager:
Take a look a the Serial Communications Guide for the CP210x, this explains how to make these types of calls to your device, there's even a COM port discovery function that will help you find the COMxx name dynamically. It also has accompanying software, AN197SW.zip.
You can use the Win32 Communication Functions just fine with a handle gotten from passing the device interface path to CreateFile. I do this all the time. Ignore the people telling you that you must use COMx.
However, it is important that you use the device interface path corresponding to the (virtual) serial port device (GUID_DEVINTERFACE_COMPORT). Many drivers are implemented as a pair of (USB device, serial port device), where the serial port is a child of the USB device. Opening the USB device (GUID_DEVINTERFACE_USB_DEVICE) will not give you working communication functions, such as PurgeCommState. (And this is exactly what you're trying now, note that the tail end of your device interface path exactly matches the GUID documented on MSDN)
If you don't have anything listed under the Ports section in Device Manager, you either don't have the driver correctly installed, or the device is not connected.
Once you get a port device found, you can use CM_Get_Parent to pair up the GUID_DEVINTERFACE_COMPORT instance with the GUID_DEVINTERFACE_USB_DEVICE, solving your question of "What serial port is attached to USB in this particular way?"

OpenProcessToken fails with ERROR_ACCESS_DENIED from a local system service

Let me explain my situation first. The issue I describe below comes from an end-user's machine, and all I have to work with is just a copy of the Windows Event Log. I cannot access the machine itself to run any debugging tests.
Now the issue. I have a service application that I create as such:
SC_HANDLE hScService = CreateService(hScManager,
L"MyServiceID",
L"My Service Name",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
SrvcPath,
NULL, NULL, NULL, NULL, _T(""));
The service process later has its SE_DEBUG_NAME privilege set using the AdjustTokenPrivileges API.
Later on I have a method that enumerates running processes and later gets processes LUIDs, using a code as such:
//'pProcIDs' = list of process IDs obtained from EnumProcesses()
for(UINT i = 0; i < nNumProc; i++)
{
DWORD dwProcID = pProcIDs[i];
//Skip obvious system processes
if(dwProcID != 0 &&
dwProcID != 4)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcID);
if(hProcess)
{
HANDLE hTokenHandle;
if(::OpenProcessToken(hProcess, TOKEN_QUERY, &hTokenHandle))
{
TOKEN_STATISTICS ts;
DWORD dwcbSz = 0;
if(::GetTokenInformation(hTokenHandle, TokenStatistics, &ts, sizeof(ts), &dwcbSz))
{
//And so on...
}
else
{
//Handle error here
}
::CloseHandle(hTokenHandle);
}
else
{
//***Here's where I get my error in question***
}
::CloseHandle(hProcess);
}
else
{
//Handle error here
}
}
}
When I run the code above on my own development computers, it runs just fine. Note that those computers run "stock" copies of the OS without any AVP or other third-party software installed.
The event log copy I received from a customer running Windows 7 Professional machine (that is a member of an Active Directory domain) has 3 processes that return ERROR_ACCESS_DENIED when I call OpenProcessToken on them from the code above. Their PIDs are just regular values, such as 1824, 2760, 5024 (that obviously change after a reboot.)
Does anyone have any idea why it happens? Do I need to set additional privileges for my service?
PS. From the event log I can tell that the workstation in question has some Symantec Antivirus product installed, judging by this line:
New virus definition file loaded. Version: 140217066.
Symantec antivirus software (as well as that of many other security software vendors) may attempt to prevent tampering with their processes by un-authorized actors. Acquiring the process token for one of their processes just might qualify.
That said, you can quickly verify that the PIDs in question are in fact part of the Symantec package by examining the path to executable images that back the processes. If they are part of the Symantec AV software package, you'll need to look in to configuring it to trust your application, or disable it while you run this code (not recommended), or simply ignore errors of this type.