Ring0和Ring3如何進行通訊

2021-10-04 21:46:51 字數 3231 閱讀 1584

可以用這個底層函式建立乙個與ring3進行通訊的控制裝置物件。使用這個函式需要注意,它生成的裝置物件具有預設的安全屬性,需要有管理員許可權的程序才可以開啟這個裝置物件。對於我們用來通訊的控制裝置來說,肯定是需要乙個裝置名稱的,上面我們還提到,裝置名是無法直接被使用者層所開啟的,需要一些特殊的操作,而這個操作具體就是,我們為當前裝置物件建立乙個符號鏈結名,用來被ring3層開啟。而這些名稱的定義也有乙個確定的規範:

#define device_object_name  l"\\device\\kt_deviceobjectname"    

//驅動之間用的 命名規範就是這樣,最後'\\'後面的字串是可以自己定義的

#define device_link_name l"\\dosdevices\\kt_devicelinkname"

//ring3和ring0之間通訊

rtlinitunicodestring

(&deviceobjectname, device_object_name)

;//建立與ring3層通訊的控制裝置物件 也稱之為cdo control device object

status =

iocreatedevice

( driverobject,0,

&deviceobjectname,

file_device_unknown,

file_device_secure_open,

false,

//是否獨佔,若獨佔,在某一時刻只能被開啟乙個控制代碼

&deviceobject );

if(!nt_success

(status)

)rtlinitunicodestring

(&devicelinkname, device_link_name)

;//為了和ring3層進行通訊,建立乙個符號鏈結名

status =

iocreatesymboliclink

(&devicelinkname,

&deviceobjectname );

if(!nt_success

(status)

)

//通過ring0的裝置物件的裝置鏈結名進行開啟獲取裝置物件控制代碼

devicehandle =

createfile(_t

("\\\\.\\kt_devicelinkname"),

//需要轉義字元\\.\kt_devicelinkname

generic_read | generic_write,

file_share_read | file_share_write,

null

, open_existing,

file_flag_no_buffering,

null

);

一旦連線裝置成功,則需要像裝置傳送裝置請求:

//createfile失敗函式返回不是null,而是invalid_handle_value

if(devicehandle != invalid_handle_value)

經過前面的一些鋪墊,接下來我們進入今日正題,來看一下自定義控制碼的方法:

#define   my_ioctl_code				\

ctl_code \

( \

file_device_unknown,\

//未知的型別

0x911

, \ //生成功能號的核心數字,並且不大於0xfff,0x000~0x7ff被微軟預留

method_neither, \ //資料傳輸的方式,重點

file_any_access \ //檔案操作的許可權

)

我們可以用上面這種方式,來設定乙個自己的裝置控制碼,ctl_code是乙個sdk的巨集:

#define ctl_code( devicetype, function, method, access ) (                 \

((devicetype) << 16) | ((access) << 14) | ((function) << 2) | (method) \

)

其中用來區分資料是以何種方式傳輸到核心層的引數,是第三引數,其總共有三種方式(直接輸入和輸出歸結為直接方式),分別是:

#define method_buffered                 0   

//緩衝區

#define method_in_direct 1

//直接輸入方式

#define method_out_direct 2

//直接輸出方式

#define method_neither 3

//原始方式

method_buffered:

若使用這種方式傳輸資料,那麼我們的資料將會通過pirp->associatedirp.systembuffer來進行使用者層輸入與輸出資料的緩衝,ring0將資料進行拷貝,而不是直接對ring3層位址進行訪問,所以這種方式比較安全。

method_in_direct/method_out_direct:

使用這種方式傳輸資料,我們的輸入也將會通過pirp->associatedirp.systembuffer來進行使用者層輸入資料的緩衝,而輸出資料是以mdl對映的方式,鎖定使用者區的記憶體,直到ring0完成i/o請求之後,ring3層才可以訪問這塊記憶體,也算是相對安全的一種方式。in和out的區別是對於開啟裝置的許可權,當唯讀開啟,使用method_in_direct成功,method_out_direct失敗。如果讀寫許可權,則都可以。

method_neither:

使用這種方式傳輸資料,我們通過pio_stack_location->parameters.deviceiocontrol.type3inputbuffer獲取使用者層輸入位址,輸出資料位址通過pirp->userbuffer來存放。使用這種方式時候,驅動可以直接對使用者層位址進行讀寫,所以一定要注意對使用者區提供的位址進行檢查(小心藍屏),看看引數是否合法。使用probeforread和probeforwrite函式來進行位址校驗。

ring0和ring3的區別

現在 核心程式和應用程式之間的本質區別。除了能用wdk編寫核心程式和閱讀一部分windows的核心 之外,我們還需要了解它們的本質是什麼,它們和我們熟悉的應用程式有什麼區別。intel的x86處理器是通過ring級別來進行訪問控制的,級別共分4層,從ring0到ring3 後面簡稱r0 r1 r2 ...

Ring0建立事件Ring3設定事件

同步事件 synchronizationevent 當事件物件為激發時,如遇到kewaitforxx等核心函式,事件物件則自動變回未激發態 通知事件 notificationevent 當事件物件為激發時,如遇到kewaitforxx等核心函式,事件物件則不會自動變回未激發態 ring0 建立事件 ...

Ring0 鍊錶

一般驅動層不使用資料結構,一般ring3層 雙向鍊錶可以將鍊錶形成乙個環.blink指標指向前乙個元素,flink指標指向下乙個元素.typedef struct list entry list entry,plist entry,restricted pointer prlist entry 初始...