WriteFile() function exits successfully but not writing bytes on hard disk - c

I want to directly read and write on hard disk partitions. I'm using C by accessing the test partition G: (2GB) for this purpose. I have successfully read the bytes sector wise. I want to read the bytes from sector 1 and writem them to sector 3908880 but i'm not able to write on the disk. Interestingly the WriteFile() method executes successfully but when i use WinHex Editor to view the bytes. It does not show up.
I have seen some similar questions which described the privilege problems but i don't have a privilege problem the function executes successfully but does not write the bytes.
Here is my code:
HANDLE getDeviceHandle(wchar_t* partition, char mode)
{
HANDLE device;
int retCode = 1;
if (mode == 'r')
{
device = CreateFile(
partition, // Partition to open
GENERIC_READ, // Access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
}
else if(mode == 'w')
{
device = CreateFile(
partition, // Partition to open
GENERIC_READ | GENERIC_WRITE, // Access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
}
if (device == INVALID_HANDLE_VALUE)
retCode = -1;
if(retCode == 1)
return device;
else
return NULL;
}
int WriteSector(HANDLE device ,BYTE* bytesToWrite, DWORD size, int sectorNo )
{
char buffForPrint[512] = { 0 };
int Code = 0;
DWORD byteswritten;
int NoOfSectorsOnPartition = 0;
DWORD bytesReturnedSize = 0;
if (NULL == device)
{
printf("Exiting from WriteSector\n");
return 0;
}
else
{
int ret = getNoOfSectors(device, bytesReturnedSize);
if (-1 != ret)
{
NoOfSectorsOnPartition = ret;
if (sectorNo > NoOfSectorsOnPartition)
{
printf("Selected sector out of range");
Code = -1;
return Code;
}else
{
DWORD status;
if (!DeviceIoControl(device, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0, &status, NULL))
{
// error handling; not sure if retrying is useful
}else if (!WriteFile(device, bytesToWrite, size, &byteswritten, NULL))
{
printf("Error in writing.Error Code: %i\n", GetLastError());
Code = -1;
return Code;
}
else
{
printf("Sector Written\n");
Code = 1;
}
}
}
}
return Code;
}
int main()
{
static BYTE read[512];
HANDLE hand;
int sector =1;
hand = getDeviceHandle(L"\\\\.\\G:", 'r');
if (ReadSector(hand, read, 512, sector) == 1)
{
printf("successfully read sector %i\n", sector);
}
sector = 3908880;
hand = getDeviceHandle(L"\\\\.\\G:", 'w');
if (WriteSector(hand,read,SECTOR_SIZE,sector) == 1) //SECTOR_SIZE 512
{
printf("successfully wrote sector %i\n",sector);
}
CloseHandle(hand); // Close the handle
getch();
}

Related

PE FILE reading in c

I need to check if file is PE file or not. I need to check first two byte is MZ or not and I did this.
This is my task: When verifying the PE format, not only according to the MZ expression, but also using the conditions that the IMAGE_NT_HEADERS structure is read and the Signature field is verified by reading the IMAGE_FILE_HEADER field and the Machine field is equal to the Th value IMAGE_FILE_MACHINE_I386 or IMAGE_FILE_MACHINE_AMD64.
I cannot figure how can do the rest of them. I hope you can help me.
int checkPE(char *file){
int fd=open(file,READ_FLAGS,0777);
char buffer[TWOBYTE+1] = {'\0'};
size_t bytes_read;
char ch;
if(fd==-1){ //if file cannot be opened give a error message.
perror("The file cannot be opened.\n");
return -1;
}
bytes_read = read(fd,buffer,TWOBYTE);
if(bytes_read==-1){
perror("Error while reading file\n");
return -1;
}
if(strcmp(buffer,MZ)!=0){
return -1;
}
int closeFlag = close(fd);
if(closeFlag==-1){
perror("The file cannot be closed.\n");
return -1;
}
}
There is nothing more than just parsing some structures. You have already the algorithm. I assume that you just need the implementation. Consider the following example utility.
PS: For further details, just comment it below.
#include <stdio.h>
#include <windows.h>
BOOL CheckValidity(BYTE* baseAddress);
int main(int argc, char* argv[]) {
if (argc != 2)
{
printf("You didn't specified a PE file.\n");
printf("Usage: CheckPEImage.exe <Full path of PE File>\n");
return -1;
}
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return -1;
HANDLE hMemoryMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMemoryMap)
return -2;
PBYTE baseAddress = (PBYTE)MapViewOfFile(hMemoryMap, FILE_MAP_READ, 0, 0, 0);
if (!baseAddress)
return -3;
printf("PE Image is %s.\n", CheckValidity(baseAddress) ? "valid" : "invalid");
getchar();
return 0;
}
BOOL CheckValidity(BYTE* baseAddress)
{
PIMAGE_DOS_HEADER lpDosHeader;
PIMAGE_FILE_HEADER lpFileHeader;
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_OPTIONAL_HEADER lpOptionalHeader;
lpDosHeader = (PIMAGE_DOS_HEADER)baseAddress;
lpNtHeaders = (PIMAGE_NT_HEADERS)(baseAddress + lpDosHeader->e_lfanew);
if (lpDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return FALSE;
if (lpNtHeaders->Signature != IMAGE_NT_SIGNATURE)
return FALSE;
if (lpNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 && lpNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
return FALSE;
return TRUE;
}

How to extend a volume programmatically

My requirement is to extend drive volume through program. When I used IOCTL_DISK_GROW_PARTITION in DeviceIO to extend it, the disk management shows the new modified size while the size of the drive in This PC (My Computer) remains unchanged.
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to device
IOCTL_DISK_GROW_PARTITION, // dwIoControlCode
(LPVOID) lpInBuffer, // input buffer
(DWORD) nInBufferSize, // size of the input buffer
NULL, // lpOutBuffer
0, // nOutBufferSize
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
Through some analysis I found that while using this API the MBR of the disk is modified but the cluster bitmap of drive is not changed. I want to know the correct way of using this DeviceIO to expand a volume or some other API to do the same process.
need understand different between disk driver, which maintain info about disk layout and partitions (it size, offset from disk begin, style (gpt or mbr) ) and file system, which mount this partition.
IOCTL_DISK_GROW_PARTITION - this ioctl is handled by disk driver and extend partition, but this can not have effect for file system, which not handle this ioctl and have no knowledge at all that partition was extended. so you need additional ioctl use FSCTL_EXTEND_VOLUME - this ioctl already send and handle to file-system.
so if we have to do next steps
send IOCTL_DISK_GROW_PARTITION with
DISK_GROW_PARTITION as input buffer
send IOCTL_DISK_UPDATE_DRIVE_SIZE with DISK_GEOMETRY
as output buffer
send IOCTL_DISK_GET_PARTITION_INFO_EX with
PARTITION_INFORMATION_EX as output for get actual size of
partition now.
calculate new size of the volume, in sectors
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
(dg we got at step 2 and PartitionEntry at step 3)
finally use FSCTL_EXTEND_VOLUME
full code can be like next
int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2)
{
if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0;
if (!PartitionEntry2->PartitionNumber) return +1;
if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1;
if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1;
return 0;
}
DWORD ExtendTest(HANDLE hDisk)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
GET_LENGTH_INFORMATION gli;
if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL))
{
return GetLastError();
}
DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX),
(int (__cdecl *)(const void *, const void *))SortPartitions );
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
LARGE_INTEGER EndOffset;
LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length;
EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart;
if (EndOffset.QuadPart > MaximumOffset.QuadPart)
{
//??
__debugbreak();
}
else if (EndOffset.QuadPart < MaximumOffset.QuadPart)
{
DISK_GROW_PARTITION dgp;
dgp.PartitionNumber = PartitionEntry->PartitionNumber;
dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart;
WCHAR sz[128];
swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber);
HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
// +++ begin extend
BOOL fOk = FALSE;
DISK_GEOMETRY dg;
if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0)
)
{
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition,
sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0);
}
if (!fOk)
{
GetLastError();
}
//--- end extend
CloseHandle(hPartition);
}
}
// else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
DWORD ExtendTest()
{
HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD err = ExtendTest(hDisk);
CloseHandle(hDisk);
return err;
}
return GetLastError();
}

Asynchronous named Windows pipe communication via overlapped IO

I'm using overlapped IO to read and write a single Windows pipe in C code simultantiously. I want to write a synchronous function to read and write data from seperate threads. If you are using synchronous IO you cannot read and write the pipe simultaniously. My client and my server are using the same write/read functions. Time by time my client sends data that is never received by the server. Does anyone have an idea how this could happen? If I use synchronous IO in the client everything works as expected.
The server pipe is opened by the following cmd:
CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
instances, PIPE_BUF_SIZE, PIPE_BUF_SIZE, 0, NULL);
The client pipe is opend this way:
CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
I'm using these read function:
int readBytesPipeCommChannel(PipeCommChannelData* comm, uint32_t* amount)
OVERLAPPED osRead;
memset(&osRead, 0, sizeof(osRead));
osRead.hEvent = comm->readAsyncIOEvent;
int err = 0;
if(!ReadFile(comm->pipeH, comm->receiveBuffer, sizeof(comm->receiveBuffer), amount, &osRead))
{
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
if(WaitForSingleObject(osRead.hEvent, INFINITE))
{
GetOverlappedResult(comm->pipeH, &osRead, amount, TRUE);
}
else
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
else if(err != ERROR_BROKEN_PIPE)
{
return PIPE_READ_ERROR;
}
}
if(err == ERROR_BROKEN_PIPE)
return PIPE_BROKEN_ERR;
return PIPE_OK;
}
And last but not least the write function:
int sendBytesPipeCommChannel(PipeCommChannelData* comm, const uint8_t* bytes, uint32_t amount)
{
OVERLAPPED osWrite;
memset(&osWrite, 0, sizeof(osWrite));
osWrite.hEvent = comm->writeAsyncIOEvent;
uint32_t bytesWritten = 0;
for(uint32_t curPos = 0; curPos < amount; curPos += bytesWritten)
{
if(!WriteFile(comm->pipeH, &bytes[curPos], (amount - curPos), &bytesWritten, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING)
return PIPE_WRITE_ERR;
if(!WaitForSingleObject(osWrite.hEvent, INFINITE))
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
}
return PIPE_OK;
}
The documentation for ReadFile says:
If hFile was opened with FILE_FLAG_OVERLAPPED, the following conditions are in effect:
The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to get the actual number of bytes read.
This applies even if the operation completes synchronously.

Read specific sector on hard drive using C language on windows

i have tried this code it works when i read a sector from an USB flash drive but it does'nt work with any partiton on hard drive , so i want to know if it's the same thing when you try to read from usb or from hard drive
int ReadSector(int numSector,BYTE* buf){
int retCode = 0;
BYTE sector[512];
DWORD bytesRead;
HANDLE device = NULL;
device = CreateFile("\\\\.\\H:", // Drive to open
GENERIC_READ, // Access mode
FILE_SHARE_READ, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device != NULL)
{
SetFilePointer (device, numSector*512, NULL, FILE_BEGIN) ;
if (!ReadFile(device, sector, 512, &bytesRead, NULL))
{
printf("Error in reading disk\n");
}
else
{
// Copy boot sector into buffer and set retCode
memcpy(buf,sector, 512);
retCode=1;
}
CloseHandle(device);
// Close the handle
}
return retCode;}
The problem is the sharing mode. You have specified FILE_SHARE_READ which means that nobody else is allowed to write to the device, but the partition is already mounted read/write so it isn't possible to give you that sharing mode. If you use FILE_SHARE_READ|FILE_SHARE_WRITE it will work. (Well, provided the disk sector size is 512 bytes, and provided the process is running with administrator privilege.)
You're also checking for failure incorrectly; CreateFile returns INVALID_HANDLE_VALUE on failure rather than NULL.
I tested this code successfully:
#include <windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
int retCode = 0;
BYTE sector[512];
DWORD bytesRead;
HANDLE device = NULL;
int numSector = 5;
device = CreateFile(L"\\\\.\\C:", // Drive to open
GENERIC_READ, // Access mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 1;
}
SetFilePointer (device, numSector*512, NULL, FILE_BEGIN) ;
if (!ReadFile(device, sector, 512, &bytesRead, NULL))
{
printf("ReadFile: %u\n", GetLastError());
}
else
{
printf("Success!\n");
}
return 0;
}

What does it mean for ReadFile to be "completing asynchronously", and why is it an error?

I'm (synchronously) reading serial input in Windows using ReadFile(), but instead of waiting for the serial port to have input then returning that as I thought it should, ReadFile() instead returns immediately with a value of FALSE, and a GetLastError() of 0. (Yes, I'm certain I have the right error code and am not making syscalls in between).
The ReadFile() documentation says that when the function "is completing asynchronously, the return value is zero (FALSE)." How is it that a synchronous read can be completing asychronously? Why would this be an error? It's worth noting that the data read is garbage data, as one might expect.
More generally, how can I force ReadFile() to behave like a simple synchronous read of a serial port, or at least behave something like the UNIX read()?
Edit: Here is some source code:
HANDLE my_connect(char *port_name)
{
DCB dcb;
COMMTIMEOUTS timeouts;
HANDLE hdl = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
GetCommState(port_name, &dcb);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(SetCommState(hdl, &dcb) == 0)
{
fprintf(stderr, "SetCommState failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
/* TODO: Set a variable timeout. */
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 5000; /* wait 5s for input */
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 5000;
if(SetCommTimeouts(hdl, &timeouts) == 0)
{
fprintf(stderr, "SetCommTimeouts failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
return hdl;
}
int my_disconnect(HANDLE hdl)
{
return CloseHandle(hdl);
}
int my_send(HANDLE hdl, char *cmd)
{
DWORD nb = 0;
if(WriteFile(hdl, cmd, strlen(cmd), &nb, NULL) == 0)
{
fprintf(stderr, "WriteFile failed with error code %d.\n",
GetLastError());
return -1;
}
return (int) nb;
}
int my_receive(HANDLE hdl, char *dst, int dstlen)
{
int i;
DWORD r;
BOOL err;
char c = '\0';
for (i = 0; i < dstlen; err = ReadFile(hdl, &c, 1, &r, NULL))
{
if (err == 0)
{
fprintf(stderr, "ReadFile failed with error code %d.\n",
GetLastError());
return -1;
}
if (r > 0)
{
dst[i++] = c;
if (c == '\n') break;
}
}
if (i == dstlen)
{
fprintf(stderr, "Error: read destination buffer not large enough.\
Recommended size: 256B. Your size: %dB.\n", dstlen);
return -1;
}
else
{
dst[i] = '\0'; /* null-terminate the string. */
}
return i;
}
And my test code:
HANDLE hdl = my_connect("COM4");
char *cmd = "/home\n"; /* basic command */
char reply[256];
my_send(hdl, cmd);
my_receive(hdl, reply, 256);
puts(reply);
It's not completing asynchronously. If it were, GetLastError would return ERROR_IO_PENDING.
To do synchronous I/O, open the file without FILE_FLAG_OVERLAPPED.
It should not be possible for ReadFile to fail without a valid GetLastError code. ReadFile only returns false when the driver sets a non-success status code.

Resources