青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

? 文件過濾系統(tǒng)驅(qū)動開發(fā) Filemon 學習筆記

? ??????????????????????????

?

WINDOWS 文件過濾系統(tǒng)驅(qū)動開發(fā),可用于硬盤還原,防病毒,文件安全防護,文件加密等諸多領域。而掌握核心層的理論及實踐,對于成為一名優(yōu)秀的開發(fā)人員不可或缺。

?

WINDOWS 文件過濾系統(tǒng)驅(qū)動開發(fā)的兩個經(jīng)典例子, Filemon SFilter ,初學者在經(jīng)過一定的理論積累后,對此兩個例子代碼的研究分析,會是步入驅(qū)動開發(fā)殿堂的重要一步,相信一定的理論積累以及貫穿剖析理解此兩個例程后,就有能力開始進行文件過濾系統(tǒng)驅(qū)動開發(fā)的實際工作了。

對于 SFilter 例子的講解,楚狂人的教程已經(jīng)比較流行,而 Filemon 例子也許因框架結(jié)構(gòu)相對明晰,易于剖析理解,無人貼出教程,本人在剖析 Filemon 的過程中積累的一些筆記資料,陸續(xù)貼出希望對初學者有所幫助,并通過和大家的交流而互相提高。

?

???????????????????? Filemon 學習筆記 第一篇:

?

?

Filemon 的大致架構(gòu)為,在此驅(qū)動程序中,創(chuàng)建了兩類設備對象。

一類設備對象用于和 Filemon 對應的 exe 程序通信,以接收用戶輸入信息,比如掛接或監(jiān)控哪個分區(qū),是否要掛接,是否要監(jiān)控,監(jiān)控何種操作等。此設備對象只創(chuàng)建了一個,在驅(qū)動程序的入口函數(shù) DriverEntry 中。此類設備對象一般稱為控制設備對象,并有名字,以方便應用層與其通信操作。

第二類設備對象用于掛接到所須監(jiān)控的分區(qū),比如 c :, d :或 e :, f :,以便攔截到引應用層對該分區(qū)所執(zhí)行的讀,寫等操作。此類設備對象為安全起見,一般不予命名,可根據(jù)須監(jiān)控多少分區(qū)而創(chuàng)建一個或多個。

?

驅(qū)動入口函數(shù)大致如下

?

NTSTATUS

DriverEntry(

??? IN PDRIVER_OBJECT DriverObject,

??? IN PUNICODE_STRING RegistryPath

??? )

{

??? NTSTATUS??????????????? ntStatus;

??? PDEVICE_OBJECT????????? guiDevice;

??? WCHAR?????????????????? deviceNameBuffer[]? = L"\\Device\\Filemon";

??? UNICODE_STRING????????? deviceNameUnicodeString;

??? WCHAR?????????????????? deviceLinkBuffer[]? = L"\\DosDevices\\Filemon";

??? UNICODE_STRING????????? deviceLinkUnicodeString;

??? ULONG?????????????????? i;

?

??? DbgPrint (("Filemon.SYS: entering DriverEntry\n"));

??? FilemonDriver = DriverObject;

?

??? //???

??? // Setup the device name

??? //???

??? RtlInitUnicodeString (&deviceNameUnicodeString,

????????????????????????? deviceNameBuffer );

?

??? //

??? // Create the device used for GUI communications

??? // 此設備對象用來和用戶交互信息

??? ntStatus = IoCreateDevice ( DriverObject,

??????????????????????????????? sizeof(HOOK_EXTENSION),

??????????????????????????????? &deviceNameUnicodeString,

??????????????????????????????? FILE_DEVICE_FILEMON,

??????????????????????????????? 0,

?????????????????? ?????????????TRUE,

??????????????????????????????? &guiDevice );

?

??? //

??? // If successful, make a symbolic link that allows for the device

??? // object's access from Win32 programs

??? //

??? if(NT_SUCCESS(ntStatus)) {

?

??????? //

??????? // Mark this as our GUI device

??????? //

??????? ((PHOOK_EXTENSION) guiDevice->DeviceExtension)->Type = GUIINTERFACE;

?

??????? //

??????? // Create a symbolic link that the GUI can specify to gain access

??????? // to this driver/device

??????? //

??????? RtlInitUnicodeString (&deviceLinkUnicodeString,

????????????????????????????? deviceLinkBuffer );

??????? ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,

???????????????????????????????????????? &deviceNameUnicodeString );

??????? if(!NT_SUCCESS(ntStatus)) {

?

??????????? DbgPrint (("Filemon.SYS: IoCreateSymbolicLink failed\n"));

??????????? IoDeleteDevice( guiDevice );

??????????? return ntStatus;???????????

??????? }

?

??????? //

??????? // Create dispatch points for all routines that must be handled.

?? ?????// All entry points are registered since we might filter a

??????? // file system that processes all of them.

??????? //

??????? for( i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {

?

??????????? DriverObject->MajorFunction[i] = FilemonDispatch;

??????? }

#if DBG???????

??????? //

??????? // Driver unload is only set if we are debugging Filemon. This is

??????? // because unloading a filter is not really safe - threads could

??????? // be in our fastio routines (or about to enter them), for example,

?? ?????// and there is no way to tell. When debugging, we can risk the

??????? // occasional unload crash as a trade-off for not having to

??????? // reboot as often.

??????? //

??????? // DriverObject->DriverUnload = FilemonUnload;

#endif // DBG

?

??????? //

??????? // Set up the Fast I/O dispatch table

??????? //

??????? DriverObject->FastIoDispatch = &FastIOHook;

?

??? } else {

?

??????? //

??????? // If something went wrong, cleanup the device object and don't load

??????? //

??????? DbgPrint(("Filemon: Failed to create our device!\n"));

??????? return ntStatus;

??? }

?

??? //

??? // Initialize the name hash table

??? //

??? for(i = 0; i < NUMHASH; i++ ) HashTable[i] = NULL;

?

??? //

??? // Find the process name offset

??? //

??? ProcessNameOffset = FilemonGetProcessNameOffset();// 為了得到當前進程名字

?

??? //

??? // Initialize the synchronization objects

??? //

#if DBG

??? KeInitializeSpinLock( &CountMutex );

#endif

??? ExInitializeFastMutex( &LogMutex );

??? ExInitializeResourceLite( &FilterResource );

??? ExInitializeResourceLite( &HashResource );

?

??? //

??? // Initialize a lookaside for file names

??? //

??? ExInitializeNPagedLookasideList( &FullPathLookaside, NULL, NULL,

??????????????????????????? ???? 0, MAXPATHLEN, 'mliF', 256 );

?

??? //

??? // Allocate the first output buffer

??? //

? ??CurrentLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) );

??? if( !CurrentLog ) {

?

??????? //

??????? // Oops - we can't do anything without at least one buffer

??????? //

??????? IoDeleteSymbolicLink( &deviceLinkUnicodeString );

??????? IoDeleteDevice( guiDevice );

??????? return STATUS_INSUFFICIENT_RESOURCES;

??? }

?

??? //

??? // Set the buffer pointer to the start of the buffer just allocated

??? //

??? CurrentLog->Len? = 0;

??? CurrentLog->Next = NULL;

??? NumLog = 1;

?

??? return STATUS_SUCCESS;

}

?

在此驅(qū)動入口點函數(shù)中,主要做了生成新的設備對象,此設備對象用來和應用層信息交互,比如應用層向驅(qū)動傳遞需要掛接或者監(jiān)控的分區(qū)盤符,或者是否掛接盤符,是否監(jiān)控操作等。

上面創(chuàng)建設備對象的代碼為:

ntStatus = IoCreateDevice ( DriverObject,

??????????????????????????????? sizeof(HOOK_EXTENSION),

??????????????????????????????? &deviceNameUnicodeString,

??? ????????????????????????????FILE_DEVICE_FILEMON,

??????????????????????????????? 0,

??????????????????????????????? TRUE,

??????????????????????????????? &guiDevice );

?

??? //

??? // If successful, make a symbolic link that allows for the device

??? // object's access from Win32 programs

??? //

??? if(NT_SUCCESS(ntStatus)) {

?

??????? //

??????? // Mark this as our GUI device

??????? //

??????? ((PHOOK_EXTENSION) guiDevice->DeviceExtension)->Type = GUIINTERFACE;

?

??????? //

??????? // Create a symbolic link that the GUI can specify to gain access

??????? // to this driver/device

??????? //

??????? RtlInitUnicodeString (&deviceLinkUnicodeString,

????????????????????????????? deviceLinkBuffer );

??????? ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,

???????????????????????????????????????? &deviceNameUnicodeString );

??????? if(!NT_SUCCESS(ntStatus)) {

?

??????????? DbgPrint (("Filemon.SYS: IoCreateSymbolicLink failed\n"));

??????????? IoDeleteDevice( guiDevice );

??????????? return ntStatus;???????? ???

??????? }

上面代碼完成的功能為創(chuàng)建了用于與應用層交互的控制設備對象,名字在參數(shù) &deviceNameUnicodeString, 中。設備對象創(chuàng)建成功后又調(diào)用 IoCreateSymbolicLink 創(chuàng)建了一個符號連接,以便于應用層交互。

?

在入口點函數(shù) DriverEntry 代碼中,還有一處代碼:

ProcessNameOffset = FilemonGetProcessNameOffset();// 為了得到當前進程名字。

此函數(shù)體如下:

ULONG

FilemonGetProcessNameOffset(

??? VOID

??? )

{

??? PEPROCESS?????? curproc;

??? int???????????? i;

?

??? curproc = PsGetCurrentProcess();// 調(diào)用 PsGetCurrentProcess 取得 KPEB 基址

?

??? // 然后搜索 KPEB ,得到 ProcessName 相對 KPEB 的偏移量

??? // Scan for 12KB, hoping the KPEB never grows that big!

??? //

? ??for( i = 0; i < 3*PAGE_SIZE; i++ ) {

????

??????? if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {

?

??????????? return i;

??????? }

??? }

?

??? //

??? // Name not found - oh, well

??? //

??? return 0;

?

這個函數(shù)通過查找 KPEB (Kernel?Process?Environment?Block) ,取得進程名, GetProcessNameOffset 主要是調(diào)用 PsGetCurrentProcess 取得 KPEB 基址,然后搜索 KPEB ,得到 ProcessName 相對 KPEB 的偏移量,存放在全局變量 ProcessNameOffset 中,得到此偏移量的作用是:無論當前進程為哪個,其名字在 KPEB 中的偏移量不變,所以都可以通過此偏移量得到。而在入口點函數(shù) DriverEntry 執(zhí)行時,當前進程必為系統(tǒng)進程,所以在此函數(shù)中方便地根據(jù)系統(tǒng)進程名 SYSNAME #define SYSNAME? ??"System" )得到此偏移量。

?

分發(fā)函數(shù)剖析:

在入口點函數(shù)中,通過代碼:

for( i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {

?

??????????? DriverObject->MajorFunction[i] = FilemonDispatch;

??????? }

簡單地把各個分發(fā)例程設置成了 FilemonDispatch; 然后我們追蹤其函數(shù)體:

?

NTSTATUS

FilemonDispatch(

??? IN PDEVICE_OBJECT DeviceObject,

??? IN PIRP Irp

??? )

{

??? //

??? // Determine if its a request from the GUI to us, or one that is

??? // directed at a file system driver that we've hooked

??? //

??? if( ((PHOOK_EXTENSION) DeviceObject->DeviceExtension)->Type == GUIINTERFACE ) {

?

??????? return FilemonDeviceRoutine( DeviceObject, Irp );

?

??? } else {

?

??????? return FilemonHookRoutine( DeviceObject, Irp );

??? }

}

?

函數(shù)體先判斷需要處理 IRP 包的設備對象的類型,看是屬于控制設備對象,還是屬于用于掛接并監(jiān)控文件讀寫操作的過濾設備對象。如果是屬于后者 則進入: FilemonHookRoutine( DeviceObject, Irp )

此函數(shù)是攔截文件操作的中心,在其中獲得了被操作的文件名字,并且根據(jù)操作類型,在

switch( currentIrpStack->MajorFunction ) {

}

中針對不同的 MajorFunction ,打印出相關操作信息。

因此函數(shù)體太長 不再全部列出。

其函數(shù)體總體框架為:得到被操作的文件名字,打印相關操作信息,然后下發(fā) IRP 到底層驅(qū)動。

在下發(fā) IRP 到底層驅(qū)動處理前,本層驅(qū)動必須負責設置下層 IO 堆棧的內(nèi)容。這樣下一層驅(qū)動調(diào)用 IoGetCurrentIrpStackLocation() 時能得到相應的數(shù)據(jù)。

設置下層 IO 堆棧的內(nèi)容,一般用兩個函數(shù)來實現(xiàn):

IoCopyCurrentIrpStackLocationToNext( Irp )

此函數(shù)一般用在本驅(qū)動設置了完成例程時調(diào)用,把本層 IO _STACK_LOCATION 中的參數(shù) copy 到下層,但與完成例程相關的參數(shù)信息例外。因為本驅(qū)動設置的完成例程只對本層驅(qū)動有效。

IoSkipCurrentIrpStackLocationToNext(Irp)

此函數(shù)的作用是:直接把本層驅(qū)動 IO 堆棧的內(nèi)容設置為下層驅(qū)動 IO 堆棧指針的指向。因兩層驅(qū)動 IO 堆棧的內(nèi)容完全一致,省卻 copy 過程。

?

而在 Filemon 的處理中,它用了一個特別的辦法,沒有調(diào)用此兩個函數(shù), FilemonHookRoutine 函數(shù)體里面有三句代碼:

?

??? PIO_STACK_LOCATION? currentIrpStack = IoGetCurrentIrpStackLocation(Irp);

PIO_STACK_LOCATION? nextIrpStack??? = IoGetNextIrpStackLocation(Irp);

?

*nextIrpStack = *currentIrpStack;// 此步設置了下層驅(qū)動的 IO_STACK_LOCATION

直接設置了下層驅(qū)動 IO 堆棧的值。

?

FilemonHookRoutine 函數(shù)里,用一個宏實現(xiàn)了復雜的獲得攔截到的被操作文件的名字:

?

if( FilterOn && hookExt->Hooked ) {

?

? ??????GETPATHNAME( createPath );

}

?

GETPATHNAME( createPath ) 宏展開為:

?

#define GETPATHNAME(_IsCreate)????????????????????????????????????????????????? \

??????? fullPathName = ExAllocateFromNPagedLookasideList( &FullPathLookaside ); \

??????? if( fullPathName ) {??????????????????????????????????????????????????? \

??????????? FilemonGetFullPath( _IsCreate, FileObject, hookExt, fullPathName ); \

??????? } else {??????????????????????????????????????????????????????????????? \

??????????? fullPathName = InsufficientResources;?????????????????????????????? \

??????? }?????

?

在函數(shù): FilemonGetFullPath( _IsCreate, FileObject, hookExt, fullPathName ) 中實現(xiàn)了獲得被操作的文件名字,此函數(shù)代碼較多,判斷條件復雜,理解起來比較麻煩,下面重點講解。

對函數(shù) FilemonGetFullPath 的理解關鍵在于理順結(jié)構(gòu),

此函數(shù)的功能就是獲得文件名字,獲得文件名字一般在三種狀態(tài)下:

一:在打開文件請求中,但在打開文件前。

二:在打開文件請求中,但在打開文件后,通過在本層驅(qū)動中設置完成例程。在完成例程中獲得。

三:在過濾到讀寫等操作時。

而在此函數(shù)中,它包含了第一種和第三種方法,通過一些煩瑣的條件判斷,先判斷出目前是處于什么狀態(tài)中,然后根據(jù)不同狀態(tài)采取不同方法。

先分析當在第一種條件下,此函數(shù)的處理方法,可以精煉為如下:

?

?

VOID

FilemonGetFullPath(

??? BOOLEAN createPath,

??? PFILE_OBJECT fileObject,

??? PHOOK_EXTENSION hookExt,

??? PCHAR fullPathName

??? )

{

?????? ULONG????? ?????????pathLen, prefixLen, slashes;

??? PCHAR?????????????? pathOffset, ptr;

??? BOOLEAN???????????? gotPath;

??? PFILE_OBJECT??????? relatedFileObject;

???

??? ANSI_STRING???????? fileName;

??? ANSI_STRING???????? relatedName;

???

??? UNICODE_STRING? ????fullUniName;

?

?

?????? prefixLen = 2; // "C:"

?

?????? if( !fileObject ) {

?

??????? sprintf( fullPathName, "%C:", hookExt->LogicalDrive );

??????? return;

??? }

?

??????

??? //

??? // Initialize variables

??? //

??? fileName.Buffer = NULL;

??? relatedName.Buffer = NULL;

??? gotPath = FALSE;

?

?????? if( !fileObject->FileName.Buffer)

?????? {

????????????? sprintf( fullPathName, "%C:", hookExt->LogicalDrive);

????????????? return;

?????? }else

????????????? DbgPrint("fileOjec->FileName:%s",fileObject->FileName);

?

?????? ?if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fileObject->FileName, TRUE ))) {

?

??????????? sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );

??????????? return;

??????? }

?

?????? ?

??????? pathLen = fileName.Length + prefixLen;

??????? relatedFileObject = fileObject->RelatedFileObject;

?

????????????? ? //

??????? // Only look at related file object if this is a relative name

??????? //

??????? if( fileObject->FileName.Buffer[0] != L'\\' &&

??????????? relatedFileObject && relatedFileObject->FileName.Length ) {

???????????????????? DbgPrint("relatedFileObject filename : %s",relatedFileObject->FileName);

?????? ???????

???????????????????? if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &relatedName, &relatedFileObject->FileName, TRUE ))) {

?

??????????????

??????????????? sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );

??????????????? RtlFreeAnsiString( &fileName );

??????????????? return;

??????????? }

??????????? pathLen += relatedName.Length+1;

??????? }

?

????????????? if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {

?

??????????? sprintf( fullPathName, "%C:", hookExt->LogicalDrive );

??????? }

?

????????????? ?if( pathLen >= MAXPATHLEN ) {

???????????

??????????? strcat( fullPathName, " <Name Too Long>" );

?

??????? } else {

???

??????????? //

??????????? // Now we can build the path name

??????????? //

?????? ?????fullPathName[ pathLen ] = 0;

???????????

??????????? pathOffset = fullPathName + pathLen - fileName.Length;

??????????? memcpy( pathOffset, fileName.Buffer, fileName.Length + 1 );

???

??????????? if( fileObject->FileName.Buffer[0] != L'\\' &&

???? ???????????relatedFileObject && relatedFileObject->FileName.Length ) {

?

??????????????? //

??????????????? // Copy the component, adding a slash separator

??????????????? //

??????????????? *(pathOffset - 1) = '\\';

??????????????? pathOffset -= relatedName.Length + 1;

???????????????????

??????????????? memcpy( pathOffset, relatedName.Buffer, relatedName.Length );

?

??????????????? //

??????????????? // If we've got to slashes at the front zap one

??????????????? //

??????????????? if( pathLen > 3 && fullPathName[2] == '\\' && fullPathName[3] == '\\' )? {

???????????????????

??????????????????? strcpy( fullPathName + 2, fullPathName + 3 );

??????????????? }

??????????? }

??????? }?

??????

?

}

上面的精簡后的函數(shù)代碼為只考慮目前處于第一種情況,即打開文件請求中,但文件尚未打開時。

在此時,文件的名字信息存儲在文件對象 fileObject->FileName, fileObject->RelatedFileObject->FileName, FileObject->FileName RelatedObject 的相對路徑, 通過對兩者的解析組合出文件名字。

?

?

而在 FilemonGetFullPath 函數(shù)體中的另一段代碼:

?

?

FilemonGetFullPath

{

…………………..

…………………..

…………………..

if( !gotPath && !createPath ) {

?

???????

??????? fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool,

??????????????????????????????????????????????????????????????? MAXPATHLEN*sizeof(WCHAR) );

?

??????? if( fileNameInfo &&

??????????? FilemonQueryFile(hookExt->FileSystem, fileObject, FileNameInformation,

???????????????????????????? fileNameInfo, (MAXPATHLEN - prefixLen - 1)*sizeof(WCHAR) )) {

?

??????????? fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;

????? ??????fullUniName.Buffer = fileNameInfo->FileName;

??????????? if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fullUniName, TRUE ))) {

?

??????????????? fullPathName[ fileName.Length + prefixLen ] = 0;

?

??????????????? if( hookExt->Type == NPFS ) {

???????????????????

??????????????????? strcpy( fullPathName, NAMED_PIPE_PREFIX );

?

??????????????? } else if( hookExt->Type == MSFS ) {

?

??????????????????? strcpy( fullPathName, MAIL_SLOT_PREFIX );

?

??????????????? } else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {

?

??????????????????? sprintf( fullPathName, "%C:", hookExt->LogicalDrive );

?

??????????????? } else {

???????????????

??????????????????? //

??????????????????? // No prefix for network devices

???????? ???????????//

??????????????? }

?

??????????????? memcpy( &fullPathName[prefixLen], fileName.Buffer, fileName.Length );

??????????????? gotPath = TRUE;

??????????????? RtlFreeAnsiString( &fileName );

??????????????? fileName.Buffer = NULL;

??????????? }

?? ?????}

??????? if( fileNameInfo ) ExFreePool( fileNameInfo );

}

………………….

…………………..

………………………

}

?

上面這段代碼是處理另外一種情況,即是在其他讀寫請求中,自己根據(jù)攔截到的 fileObject 構(gòu)建 IRP ,下發(fā)到底層,以此來查詢文件名信息。整個過程還是易于理解的。

?

在理清這兩種脈絡后,再剖析此整個函數(shù),就很容易理解整個函數(shù)代碼了。

代碼中對 MajorFunction == IRP_MJ_CREATE_NAMED_PIPE

??????? ?MajorFunction == IRP_MJ_CREATE_MAILSLOT ? 的判斷是為了辨別對攔截到的進程間的兩種通信方式:命名管道與郵槽的處理。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜欧美不卡精品aaaaa| 欧美激情一区二区三区在线| 在线观看亚洲视频啊啊啊啊| 国产日本欧美一区二区三区| 国产精品卡一卡二| 国产欧美一区二区三区国产幕精品| 国产精品亚洲欧美| 红桃视频国产精品| 亚洲免费精品| 久久国产精彩视频| 欧美 日韩 国产 一区| 91久久中文| 99精品国产在热久久下载| a91a精品视频在线观看| 欧美一级久久久| 欧美成人午夜77777| 99热免费精品在线观看| 久久电影一区| 欧美日韩亚洲视频一区| 国产一区二区在线免费观看| 亚洲人成小说网站色在线| 午夜视频一区在线观看| 老司机午夜精品| 99热免费精品| 免费观看成人网| 国产精品乱人伦中文| 亚洲黄色在线看| 久久精品国产亚洲aⅴ| 亚洲黄色小视频| 欧美在线亚洲| 国产精品久久久久一区| 亚洲精品国产精品国产自| 欧美在线二区| 99国产一区| 久久视频在线视频| 国产亚洲美州欧州综合国| 亚洲网站在线看| 亚洲国产一区二区三区a毛片| 欧美一级在线视频| 欧美午夜激情在线| 亚洲乱码日产精品bd| 鲁鲁狠狠狠7777一区二区| 在线亚洲观看| 欧美日本三区| 亚洲裸体视频| 亚洲国产片色| 免费一级欧美片在线观看| 精品福利免费观看| 老司机午夜免费精品视频| 久久国产精品久久精品国产 | 免费观看一区| 欧美一区二区精品在线| 国产精品免费在线| 午夜国产精品视频| 亚洲午夜国产成人av电影男同| 欧美人成网站| 中文欧美在线视频| 亚洲精选在线| 欧美三级视频在线| 亚洲少妇自拍| 亚洲色在线视频| 国产精品任我爽爆在线播放 | 亚洲国产精品综合| 欧美高清免费| av成人国产| 99re在线精品| 欧美调教vk| 欧美一级片一区| 午夜精品久久久久久久久久久久久| 亚洲欧洲av一区二区| 国产精品日韩在线| 久久久999精品| 久久久精品国产99久久精品芒果| 国产一区二区三区精品久久久| 欧美专区日韩视频| 久久乐国产精品| 日韩网站免费观看| 一区二区三区精密机械公司| 国产精品欧美一区喷水 | 最新日韩在线视频| 欧美三级特黄| 欧美在线视频在线播放完整版免费观看 | 黄色成人av网站| 欧美激情片在线观看| 欧美精品aa| 性色av一区二区三区红粉影视| 欧美伊人久久久久久午夜久久久久| 永久免费毛片在线播放不卡| 91久久中文| 国产亚洲在线观看| 欧美.www| 国产乱子伦一区二区三区国色天香| 久久免费高清视频| 欧美激情久久久久| 欧美中文日韩| 欧美精品日韩综合在线| 欧美一级视频一区二区| 美女啪啪无遮挡免费久久网站| 日韩亚洲欧美高清| 亚洲欧美日韩精品久久亚洲区| 亚洲高清色综合| 亚洲视频中文| 亚洲黄色av| 欧美一区二区在线看| 亚洲精品孕妇| 久久99伊人| 亚洲先锋成人| 久久亚洲色图| 久久国产精品久久精品国产 | 久久婷婷综合激情| 亚洲尤物视频网| 免费亚洲网站| 99精品热视频只有精品10| 先锋影音久久| 亚洲女女女同性video| 久久激五月天综合精品| 亚洲午夜一区二区三区| 鲁鲁狠狠狠7777一区二区| 欧美在线一级va免费观看| 欧美激情一区二区久久久| 久久亚洲色图| 国产欧美日韩精品a在线观看| 一本色道88久久加勒比精品 | 欧美精品亚洲精品| 久久人人爽国产| 国产精品视频在线观看| 亚洲精品国偷自产在线99热| 最近看过的日韩成人| 久久精品99国产精品| 亚洲欧美国产三级| 国产精品成人免费视频| 亚洲美女视频在线免费观看| 亚洲美女在线视频| 欧美成ee人免费视频| 蜜臀av一级做a爰片久久| 久久九九免费视频| 男人的天堂成人在线| 国产一区二区成人久久免费影院| 中文亚洲免费| 午夜在线a亚洲v天堂网2018| 国产精品国产三级国产普通话99| 亚洲欧洲日本一区二区三区| 亚洲人精品午夜| 欧美大色视频| 一区二区欧美亚洲| 亚洲中字在线| 国产精品亚洲综合一区在线观看| 国产精品99久久久久久久女警 | 欧美黄色视屏| 亚洲国产日韩在线| 欧美精品二区三区四区免费看视频| 免费永久网站黄欧美| 1000精品久久久久久久久 | 国产午夜精品在线| 久久久噜噜噜久久人人看| 麻豆乱码国产一区二区三区| 亚洲国产精品久久久久秋霞影院 | 一区二区三区国产在线观看| 欧美日韩中文字幕在线视频| 在线亚洲激情| 久久精品伊人| 91久久精品www人人做人人爽| 欧美理论在线播放| 亚洲视频一区二区| 久久久伊人欧美| 亚洲精品免费观看| 欧美日韩专区| 欧美在线一区二区三区| 欧美成人资源网| 亚洲在线黄色| 亚洲国产成人精品久久| 欧美日韩国产综合网| 午夜精品999| 亚洲国产日韩欧美一区二区三区| 亚洲香蕉网站| 在线看欧美视频| 欧美调教视频| 性做久久久久久免费观看欧美| 欧美黄色影院| 欧美一级成年大片在线观看| 亚洲国内高清视频| 国产精品推荐精品| 欧美成人精品在线播放| 香蕉av777xxx色综合一区| 亚洲高清一二三区| 欧美伊人久久久久久午夜久久久久 | 亚洲国产午夜| 国产精品日日摸夜夜摸av| 久久激五月天综合精品| 一区二区91| 欧美激情第9页| 久久国产精品99国产精| 一本不卡影院| 亚洲欧洲一区二区天堂久久| 国产欧美 在线欧美| 欧美母乳在线| 免费在线看一区| 久久久久久穴| 欧美与黑人午夜性猛交久久久| 99精品国产99久久久久久福利|