|
Ok, I've am doing something wrong but not sure what. I've written this quick and simple 'hello world' driver Driver Entry routine to demonstrate my dillema.
Using the methods you suggested previously, I define the first disk device, then try to open it with ZwOpenFile (I figured ZwCreateFile will make one if it doesn't exist, not something we want to have happen, so I only want to open an existing device.) This is where the driver fails... status from the ZwOpenFile operation is '-1073741788' and file_status->status is '-2141904312', so obviously the operation didn't work. But I don't understand why, and more importantly how to fix it! Likewise it never gets to the ZwReadFile operation so that I can at least in WinDbg look at the MBR in the array to ensure it is correctly read, specifically looking quickly at the '55 AA' at the end.
#include "ntddk.h"
#include "ntddk.h"
#include "ntdddisk.h"
#include "stdarg.h"
#include "stdio.h"
#include <ntddvol.h>
#include <mountdev.h>
#include "ntstrsafe.h"
typedef unsigned char BYTE, *PBYTE, *LPBYTE;
typedef int BOOL, *PBOOL, *LPBOOL;
typedef BYTE BOOLEAN, *PBOOLEAN;
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
typedef unsigned long ULONG, *PULONG;
typedef unsigned short WORD, *PWORD, *LPWORD;
typedef char TCHAR;
typedef void *PVOID;
typedef unsigned short UINT2;
typedef unsigned int UINT4;
VOID OnUnload( IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("OnUnload called!\n");
}
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath )
{
UNICODE_STRING PhysicalDeviceName;
WCHAR PhysicalDeviceNameBuffer[64];
ULONG DiskNumber;
HANDLE MBR;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
IO_STATUS_BLOCK file_status;
OBJECT_ATTRIBUTES obj_attrib;
DWORD disk_MBR[512] = {0x0};
DbgPrint("I loaded!\n");
theDriverObject->DriverUnload = OnUnload;
DiskNumber = 0;
MBR = NULL;
RtlStringCbPrintfW(PhysicalDeviceNameBuffer,
sizeof(PhysicalDeviceNameBuffer),
L"\\Device\\Harddisk%d", DiskNumber);
RtlInitUnicodeString(&PhysicalDeviceName,
&PhysicalDeviceNameBuffer[0]);
DbgPrint("Disk name %ws\n", PhysicalDeviceNameBuffer);
InitializeObjectAttributes(&obj_attrib,
&PhysicalDeviceName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = ZwOpenFile(&MBR,
GENERIC_READ | GENERIC_WRITE,
&obj_attrib,
&file_status,
0,
FILE_NON_DIRECTORY_FILE);
if (status != STATUS_SUCCESS){
DbgPrint("Failed to open the disk!\n");
DbgPrint("Disk Status = %x\n", file_status);
}
else {
DbgPrint("Successfully opened the disk.\n");
DbgPrint("Disk Handle = %x\n", MBR);
}
if (MBR != NULL){
status = ZwReadFile(MBR,
NULL,
NULL,
NULL,
&ioStatus,
disk_MBR,
512,
NULL,
NULL);
if (NT_SUCCESS(status)){
DbgPrint("Disk %d MBR read successfully.\n", DiskNumber);
}
else
{
DbgPrint("Disk %d MBR read failed!\n", DiskNumber);
}
}
return STATUS_SUCCESS;
}
Now I decided to see if it was just the "\\Device\Harddisk0" that had caused the failure, so I modified the driver to look at "\\Device\Harddisk0\DR0", and the device was successfully opened.
RtlStringCbPrintfW(PhysicalDeviceNameBuffer,
sizeof(PhysicalDeviceNameBuffer),
L"\\Device\\Harddisk%d\\DR0", DiskNumber);
However, now the ZwReadFile is failing with status '-1073741811', so even if you can open the disk in this manner, you still can't read it. Unless I'm still doing something wrong.
grrr.....
|
|
|
|
|
You are getting error STATUS_INVALID_PARAMETER.
You must be doing some thing wrong.
Is your driver filter in disk stack?
On which system are you trying all this?
Why didn't you use IoCallDriver mechanism.
|
|
|
|
|
I am pretty sure I'm doing something wrong with a parameter... lol. I am sure it has something to do with how I am trying to open it but I am running out of ideas.
>Is your driver filter in disk stack?
Not in this initial scenario. The code previously listed is the entire hello world driver I am experimenting in. Once it works correctly I will implement it in the infamous diskperf-based filter driver to be executed while in the disk stack.
>On which system are you trying all this?
XP SP3 Virtual Machine
>Why didn't you use IoCallDriver mechanism?
Because you had suggested to use this method instead. Besides to send an IRP down to the driver(s) below me (similarly to how you sent it in your sector.sys) would require me to have a pointer to the device I want to manipulate and as of right now, I only have a name.
Furthermore, it seems many say the zwcreatefile should work but I haven't found a working solution yet. http://www.osronline.com/showThread.cfm?link=23865[^] & http://www.pcreview.co.uk/forums/thread-535046.php[^]
Tried various names to identify the raw disk but soo far none have worked out:
L"\\DosDevices\\PhysicalDrive%d"
L"\\??\\PhysicalDrive%d"
L"\\\\.\\PhysicalDrive%d"
L"\\Device\\Harddisk%d"
Of course those name issues could really be a problem with the ZwCreateFile since I've been trying various versions of that as well.
status = ZwCreateFile(&MBR,
GENERIC_READ | GENERIC_WRITE,
&obj_attrib,
&file_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
BTW,
How did you convert the -# to the text error code?
Brian
modified on Saturday, March 27, 2010 1:14 AM
|
|
|
|
|
Progress... but not entirely.
From the hello world driver I was able to read and write to a raw disk via:
DiskNumber = 0;
RtlStringCbPrintfW(PhysicalDeviceNameBuffer,
sizeof(PhysicalDeviceNameBuffer),
L"\\DosDevices\\PhysicalDrive%d", DiskNumber);
RtlInitUnicodeString(&PhysicalDeviceName, &PhysicalDeviceNameBuffer[0]);
InitializeObjectAttributes(&obj_attrib,
&PhysicalDeviceName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = ZwCreateFile(&MBR,
FILE_READ_DATA | FILE_WRITE_DATA,
&obj_attrib,
&file_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (status != STATUS_SUCCESS){
DbgPrint("Failed to open the disk!\n");
DbgPrint("Disk Status = %X\n", file_status);
DbgPrint("Operation Status = %u\n", status);
}
else {
DbgPrint("Successfully opened the disk.\n");
DbgPrint("Disk Handle = %x\n", MBR);
}
if (MBR != NULL){
offset.QuadPart = 0;
status = ZwReadFile(MBR,
NULL,
NULL,
NULL,
&ioStatus,
readBuffer,
sizeof(readBuffer),
&offset,
NULL);
After inserting the equivalent of this code (few variable name changes, etc) into the diskperf equivalent of DiskPerfIrpCompletion() so that only on IRP_MN_START_DEVICE does it try to read/write from the disk. However, with same device name as the above example when ZwCreateFile runs it fails with an error of: (-1073741810) or 3221225486 = "A device which does not exist was specified." This occurs for disk0 at boot time, and disk1 (a usb I added after fully in the OS). That doesn't make any sense to me. I could possibly see disk0 failing, but not disk1 when the OS is in the same state as when the hello world driver ran. Thoughts?
|
|
|
|
|
Yeah I had suspicion that in MN_START_DEVICE whether doing IO will be successful or not.
Try doing your operations in it's completion.
If that doesn't succeed, then you can do one thing:--
When a first IO (read/write) comes to the device do your own operation on the device object below (and not o n the your own filter device object). In this case then you should not use Zw calls but you should target your IRPs to lower device object using IoCallDriver. Zw call will send the IRP from top of the stack. And since your device is in the stack which is already holding the IOs will get another IO generated by you. And you will end up in a deadlock.
|
|
|
|
|
Unfortunately I think I am doing it in the completion routine of IRP_MN_START_DEVICE (run in DiskPerfIrpCompletion()). Ok, doing the operation in the first IO op comes sounds reasonable... it will obviously be taking operations at that time... lol. So lets see... an IO flag initialized to zero and then increment it so its only done on the first operation and not every operation... need to have a function take in IRP_MJ_READ & IRP_MJ_WRITE easy enough...
Now building the IRP with IoCallDriver should be pretty easy only catch I'm seeing on that is do I just send it to the next device below me as below or as in your driver you had a pointer to the specific raw disk to read.
myIRP_MJ_READ-WRITE_TRAP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
MajorFunc = (IoCtl==IOCTL_SECTOR_READ) ? IRP_MJ_READ : IRP_MJ_WRITE;
lDiskOffset.QuadPart = (pDiskObj->ulSectorSize) * (pDiskLoc->ullSectorNum);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pIrp = IoBuildSynchronousFsdRequest(MajorFunc, pDiskObj->pDiskDevObj, pBuff,
pDiskObj->ulSectorSize, &lDiskOffset,
&Event, &ioStatus);
IF it is the latter, I have proven I can get a working name for the raw disk (L"\\DosDevices\\PhysicalDrive%d"), but how do I convert that to something I can use as a target of my irp to gurantee I get the raw disk (sort of the reverse action of ObQueryNameString) to represent your pDiskDevObj? Can I use the deviceExtension->PhysicalDeviceObject which is set during Add_Device?
The next question that I see then is since I can't use the ZwRead/WriteFile operations because Zw calls will send the IRP from top of the stack. And since my device is in the stack which is already holding the IOs will get another IO generated by me and I will end up in a deadlock.... How does ZwSetSecurityObject get a Handle (an action that takes ZwCreateFile typically)? Or does that not matter now, since I've read/written to the raw disk already by this point and all other irps received are passed through me (other than this first one) or will this too end in deadlock? Is there a way to do ZwSetSecurityObject without causing deadlock prior to releasing the first trapped irp?
|
|
|
|
|
Hi. Thanks. It looks like you're doing everything right here, but oddly, I'm getting far different numbers than what this driver is returning. When I read sector 0, I get the main boot record which starts with 3 numbers and then the ASCII representation for NTFS. This software seems to be pulling data from a sector other than Logical Block Address 0.
|
|
|
|
|
Can you post your command which you are executing to get the data?
|
|
|
|
|
Hi Deepak,
Thanks. Certainly. I'm just calling ReadFile() from a Win32 usermode app on Windows Vista. The subroutine is below. Maybe I'm missing something, but I can't see what could possibly be different. When I read sector 0 using this subroutine, I get the MBR of my drive. When I use your driver to read raw disk sector 0, I get an entirely different set of numbers. But it must be reading a sector somewhere, because I can see the sector fixup in the data that your driver returns. Odd. I'm still working on the problem. There's always a reason.
DWORD ReadSector(LPSTR volume, ULONGLONG sector, unsigned char *q)
{
ULONGLONG ull, ull1;
unsigned long ul, ul1;
unsigned long bytesread = 0;
unsigned long sectorsize = 512;
char sstr[STRINGLENGTH], device[STRINGLENGTH];
HANDLE hDriver;
strcpy_s(device, volume);
_strupr_s(device);
hDriver = CreateFile(device,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
0);
if(hDriver != INVALID_HANDLE_VALUE)
{
ull = sector * sectorsize;
ul = (unsigned long) ull;
ull >>= 32;
ul1 = (unsigned long) ull;
SetFilePointer(hDriver, ul, (PLONG) &ul1, FILE_BEGIN);
if(!ReadFile(hDriver, q, sectorsize, &bytesread, NULL))
{
sprintf_s(sstr, sizeof(sstr), "Error reading sector. Error = %d", GetLastError());
PleaseWait(sstr);
}
CloseHandle(hDriver);
}
else
{
sprintf_s(sstr, sizeof(sstr), "Error opening driver %s", volume);
PleaseWait(sstr);
}
return(bytesread);
}
|
|
|
|
|
What is the Volume name here, I mean the input to your ReadSector function. I think you are giving input here as \\.\PhysicalDriveX. And what are you giving inputs to the "DiskSector" utility. Is /disk or /partition? /disk is for the entire disk starting from sector 0 while /partition is from the starting of partition which will not be starting of the disk.
|
|
|
|
|
Hi Deepak,
The volume names are \\.\PhysicalDriveX and \\.\X: They both work. I'm reading drives 0 and 1 ( c: and d: ). They both have an MBR on sector 0. (d: is a bootable drive as well). I can see the MBR's and the MFT's, etc. on both drives.
I run your software with the command line:
disksector /disk 1 /read 0
Totally different numbers on sector 0. It's really odd. As far as I can tell, everything looks correct in your source code. Can you see your MBR using this software? I have no idea yet what I could be doing wrong.
|
|
|
|
|
hmm ok.
AFAIK, MBR is just one, it can't be present on both the drives. Infact it is not at all present on drives (partitions).
I think you are talking about Boot Sector (or Boot Record) of specific drives (partitions). MBR stands for Master Boot Record and is present on the start of properly partitioned hard disk. MBR contains info about partitions on the hard drive in a Partition Table (Like start and end of partition, type of partition, etc). It contains other info also (I dont remember offhand right now). Typically after 64 starting sectors (it is a typical value, it can vary also), first partition area starts.
So when you read \\.\PhysicalDriveX, you are reading from the starting of the harddisk (i.e MBR will be read). When you read drives i.e (\\.\C:\), then you are reading at a offset on the harddisk (typically 64 sectors as said above) and it's first sector will be a boot sector (if bootable partition).
Ok So far so good. Now about the my utility. Below I have pasted the usage of utility again.
DiskSector {/disk | /partition} <rawdisk number | partition number> {/read | /write} <sectornumber> {/unload}
Options Meanings :--
{/disk | /partition} <rawdisk number | partition number>
Disk and Parition options are mutually exclusive
Disk numbering starts from 0 while partition starts from 1
{/read | /write} <sectornumber>
Read and Write options are mutually exclusive
Sector numbering starts from 0
{/unload} This option simply unloads the support driver
e.g "DiskSector /disk 0 /read 0" will read raw sector 0 of harddisk 0
From the above usage it is evident that I am referring /disk as the physicaldrive (i.e the hard disk) and it's numbering starts from 0 (and not 1) while /partition refers to partitions (i.e drives) and their numbering starts from 1 (and not 0).
I hope all above helped, please forgive me if all above was confusing
|
|
|
|
|
Thanks Deepak. Sorry. Yes, I meant Boot Sector. The command line I'm using is:
disksector /disk 1 /read 0
The response is this:
33C0 8ED0 BC00 7C8E C08E D8BE 007C BF00 06B9 0002 FCF3 A450 681C 06CB FBB9 0400
....
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 55AA
When I use ReadFile() to read the same sector from the same drive the response is this:
EB52 904E 5446 5320 2020 2000 0208 0000 0000 0000 00F8 0000 3F00 FF00 0008 0000
....
6F20 7265 7374 6172 740D 0A00 0000 0000 0000 0000 0000 0000 809D B2CA 0000 55AA
Note the fixups are the same, and the output from ReadFile() contains the NTFS designator after the first 3 bytes, which is correct. I can't figure out where the data from your utility is coming from.
|
|
|
|
|
hmm Are you intending to read the first disk attached (i.e PhysicalDrive0) to your system?
If yes then your command line should be "disksector /disk 0 /read 0"
I already told you that disk numbering starts from 0, 1, 2 and so on.
Let me know if you were intending to read first disk of your system.
|
|
|
|
|
Thanks Deepak. No, I was reading drive D: "/disk 1". But I've tested both drives with both pieces of software. Same results on both drives.
|
|
|
|
|
Ok since you are reading a drive, it is a partition and not a physical disk.
Even if it is on a different disk, you should specify it as partition.
try "/partition 2".
See usage correctly, partition numbering starts as 1,2,3,... while disk numbering starts as 0,1,2,...
|
|
|
|
|
Again, The command line I'm using is:
disksector /disk 1 /read 0
Does that not read a raw disk sector?
|
|
|
|
|
There is a difference between disk and drives.
With disk here I am talking about here as physical disks as exposed by the storage stack.
While partition are different partitions on the hard drive.
If you intend to read a drive, you need to give /partition option.
If you are reading a physical drive then you need to give /disk option.
|
|
|
|
|
I don't think you're understanding what I'm saying Deepak. I have two disk drives. \\.\PhysicalDrive0 is disk drive c: and \\.\PhysicalDrive1 is disk drive d:
I've tested everything thoroughly using the ReadFile() command. Everything corresponds to the literature regarding what an NTFS raw disk drive should look like. I'm reading sector 0, the Boot Sector from both drives. Let's stop the confusion here and talk about the first disk. \\.\PhysicalDrive0. What command do you use to read the Boot Sector, raw disk sector 0, on your 1st physical drive. And when you do read it, do you see the Boot Sector, or something else?
By Boot Sector, I mean this:
http://www.ntfs.com/ntfs-partition-boot-sector.htm
This should be in sector 0 of your first physical drive. This is what I see when I use the ReadFile() command.
|
|
|
|
|
If I use:
disksector /partition 1 /read 1
I get error code 1167.
|
|
|
|
|
In my personal option, "/partition 1" is not enough to represent the "c:".
Here I list all the "DR/DP" in my machine.
\Device\Harddisk2\DP(1)0-0+9
\Device\Harddisk2\DR8
\Device\Harddisk1\DP(4)0x9c4024000-0x270fc8000+7
\Device\Harddisk1\DP(3)0x753006000-0x27101d000+6
\Device\Harddisk1\DP(2)0x4e1fe8000-0x27101d000+5
\Device\Harddisk1\DP(1)0x1000-0x4e1fe6000+4
\Device\Harddisk0\DP(2)0xcd9300000-0x1869e00000+3
\Device\Harddisk0\DP(1)0x6500000-0xcd2e00000+2
\Device\Harddisk1\DR1
\Device\Harddisk0\DR0
You can find the hard disk info about my machine.
1. Harddisk0\DR0 --- a fixed device
It contains two partitions like DP(1) and DP(2). They represent "c:" and "d:"
2. Harddisk1\DR1 --- a fixed device
It contains two partitions like DP(1), DP(2), DP(3) and DP(4). They represent "g:", "h:", "i:", and "j:"
3. Harddisk2\DR8 --- a removable device
It contains two partitions like DP(1). It represent "k:"
Summary
------------------------------
C: Harddisk0 \ DR0 \ DP(1)
D: Harddisk0 \ DR0 \ DP(2)
G: Harddisk1 \ DR1 \ DP(1)
H: Harddisk1 \ DR1 \ DP(2)
I: Harddisk1 \ DR1 \ DP(3)
J: Harddisk1 \ DR1 \ DP(4)
K: Harddisk2 \ DR8 \ DP(1)
So "/partition 1" will have three options like "c:", "g:" and "k:". The choice will be made by the code in DiskSector.
|
|
|
|
|
I'd like to read sectors from my SD card and i have problem - it is recognized as disk but calling
DiskSector /disk 1 /read 0
returns "DeviceIoControl Failed and error code is 1167". it means that the resource may be out of sync.
Is there sth. I can do about that? (sorry for my english)
|
|
|
|
|
1>errors in directory c:\disksector\src\exe
1>link : error LNK2001: unresolved external symbol _mainCRTStartup
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _strncat referenced in function _cleanupDriver@0
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _printf referenced in function _uninstallDriver@0
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _memset referenced in function _uninstallDriver@0
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _free referenced in function _DoDeviceIoCtl@24
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _getc referenced in function _DoDeviceIoCtl@24
1>c:\disksector\src\exe\sector_io.obj : error LNK2001: unresolved external symbol __iob
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _malloc referenced in function _DoDeviceIoCtl@24
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol _strtoul referenced in function _main
1>c:\disksector\src\exe\sector_io.obj : error LNK2019: unresolved external symbol __strtoui64 referenced in function _main
1>c:\disksector\bin\fre_wxp_x86\i386\disksector.exe : error LNK1120: 10 unresolved externals
Can you recommend what to change to resolve the above link failure?
|
|
|
|
|
You need to point to the correct lib path.
I have not used 7600 DDK yet, but looks like their lib path has changed.
Look into the SOURCES file and check out the LIBS, and try to find their location in 7600 DDK install path.
|
|
|
|
|
Just add this line to the sources file:
USE_MSVCRT=1
|
|
|
|
|