Posted on 2008-09-06 08:55
沒畫完的畫 閱讀(1905)
評論(1) 編輯 收藏 引用 所屬分類:
Windows Driver
2008.09.04
首先應該了解下在 Windows 下面,應用層(Ring3)跟內核(Ring0)的通信是如何進行的。
先不管內核(Ring0),先把 Ring3 弄明白再說
Google 到了下面一段代碼

/**//* The code of interest is in the subroutine GetDriveGeometry. The
code in main shows how to interpret the results of the IOCTL call. */
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)


{
HANDLE hDevice; // handle to the drive to be examined
BOOL bResult; // results flag
DWORD junk; // discard results
hDevice = CreateFile("\\\\.\\PhysicalDrive0", // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive

{
return (FALSE);
}
bResult = DeviceIoControl(hDevice, // device to be queried
IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform
NULL, 0, // no input buffer
pdg, sizeof(*pdg), // output buffer
&junk, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O

CloseHandle(hDevice);
return (bResult);
}
int main(int argc, char *argv[])


{
DISK_GEOMETRY pdg; // disk drive geometry structure
BOOL bResult; // generic results flag
ULONGLONG DiskSize; // size of the drive, in bytes
bResult = GetDriveGeometry (&pdg);
if (bResult)

{
printf("Cylinders = %I64d\n", pdg.Cylinders);
printf("Tracks per cylinder = %ld\n", (ULONG) pdg.TracksPerCylinder);
printf("Sectors per track = %ld\n", (ULONG) pdg.SectorsPerTrack);
printf("Bytes per sector = %ld\n", (ULONG) pdg.BytesPerSector);
DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
(ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
printf("Disk size = %I64d (Bytes) = %I64d (Mb)\n", DiskSize,
DiskSize / (1024 * 1024));
}
else

{
printf("GetDriveGeometry failed. Error %ld.\n", GetLastError());
}
return ((int)bResult);
}



上述的程序,用 CreateFile 打開 “\\\\.\\PhysicalDrive0” 這個設備,
據說 PhysicalDrive0 這個設備就是“第一塊物理硬盤”了,至少是不是一定就是引導盤,不太清楚
問題1:PhysicalDrive0 是不是一定就是引導盤??
然后通過 DeviceIoControl() 與 設備交互
最后 CloseHandle()
打開設備就像打開文件一樣,如果把 DeviceIoControl() 換成 WriteFile 呢, 哈哈哈,,試一下先
BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)


{
HANDLE hDevice; // handle to the drive to be examined
BOOL bResult; // results flag
DWORD junk; // discard results
hDevice = CreateFile("\\\\.\\PhysicalDrive0", // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive

{
return (FALSE);
}
DWORD dwRet = 0 ;

if( WriteFile(hDevice, "abc", 3, &dwRet, NULL) == FALSE)

{
printf("Error WriteFile: LastErrorCode = %d \n", ::GetLastError());
return FALSE;
};

CloseHandle(hDevice);
return (bResult);
}

為了安全起見,在虛擬機下運行,運行結果如下:
Error WriteFile: LastErrorCode = 5
查了 ErrorLookUp
5 的錯誤是 Access is denied.
哈哈~~~如果 WriteFile 成功不就見鬼了!!!
從安全的角度來看,NT以上的系統好像是不能直接對硬盤的絕對扇區操作的,至于 WriteFile PhysicalDrive0 失敗的具體原因,不太清楚。
問題2: WriteFile PhysicalDrive0 失敗的具體原因? (ReadFile沒試,理論上應當也會失敗)
總結一下:
1、關于 CreateFile 時所使用的設備名
一些標準設備的設備名,微軟已經定義好了,
比如 PhysicalDrive0 這些,如果是自己的驅動所創建的設備,當然名字可以任由自己取
在 CreateFile 打開設備時,設備的名字通常為 \\.\DeviceName (在C++中的字符串則表示為
\\\\.\\DeviceName)
在驅動.sys 當然需要做一些東西,才可以讓應用層通過這個設備名來訪問(具體見下集分解)
2、DeviceIoControl() 這個函數是與驅動層通信的關鍵
一個操作碼,一個輸入緩沖區,一個輸出緩沖區
具體做什么,可以當然需要驅動與應用程序之間事先商量好的,
微軟同樣定義了一些標準設備的操作碼,在 winioctl.h 文件中
今天好累, 去睡覺了~~~~~
問題列表:
問題1:PhysicalDrive0 是不是一定就是引導的硬盤??
-- 未解決
問題2:WriteFile PhysicalDrive0 失敗的具體原因? (ReadFile沒試,理論上應當也會失敗)
-- 未解決
問題3:如果驅動層在響應DeviceIoControl 時阻塞,那么應用層在調用 DeviceIoContorl() 是不是也會阻塞?
-- 未解決