亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

《Undocumented Windows 2000 Secrets》翻譯 --- 第五章(3)

瀏覽:86日期:2023-08-27 10:31:57

第五章 監(jiān)控 Native API 調(diào)用

翻譯: Kendiv( [email protected] )

更新: Thursday, March 24, 2005

聲明:轉(zhuǎn)載請(qǐng)注明出處,并保證文章的完整性,本人保留譯文的所有權(quán)利。

本書設(shè)計(jì)的 hook 機(jī)制的最大特色就是它是完全數(shù)據(jù)驅(qū)動(dòng)的( data-driven )。只需簡(jiǎn)單的增加一個(gè)新的 API 符號(hào)表,該 hook dispatcher 就可適應(yīng) Windows 2000 的新版本。而且,通過(guò)向 apdSdtFormats[] 數(shù)組中加入新的 API 函數(shù)的格式化字符串就可在任何時(shí)候記錄對(duì)這些附加的 API 函數(shù)的調(diào)用。這并不需要編寫任何附加的代碼 ---API Spy 的動(dòng)作可完全由一組字符串來(lái)確定!不過(guò),在定義新的格式化字符串是必須要小心,因?yàn)?w2k_spy.sys 是運(yùn)行于內(nèi)核模式的驅(qū)動(dòng)程序。因?yàn)樵谶@一系統(tǒng)層次上,系統(tǒng)不能溫和的處理發(fā)生錯(cuò)誤。給 Win32 API 函數(shù)提供了一個(gè)無(wú)效的參數(shù)并不是問(wèn)題 ----- 你會(huì)收到一個(gè)錯(cuò)誤提示窗口,同時(shí)程序會(huì)被系統(tǒng)自動(dòng)終止。在內(nèi)核模式下,一個(gè)微小的訪問(wèn)違規(guī)都會(huì)引發(fā)系統(tǒng)藍(lán)屏。因此,一定要小心。在需要的地方如果沒(méi)有出現(xiàn)一個(gè)正確的格式化控制 ID 或缺失了這一 ID 都會(huì)使你的系統(tǒng)徹底崩潰。即使一個(gè)簡(jiǎn)單的字符串有時(shí)都是致命的!

現(xiàn)在僅剩 SpyHookInitializeEx() 中的那一大塊 ASM 代碼還未討論,這段代碼由 SpyHook2 和 SpyHook9 標(biāo)識(shí)。這段代碼的一個(gè)有趣的特性是:在 SpyHookInitializeEx() 被調(diào)用的時(shí)候,它們從來(lái)都不會(huì)被執(zhí)行。在進(jìn)入 SpyHookInitializeEx() 后,函數(shù)代碼將跳過(guò)這一整段代碼,然后在 SpyHook9 標(biāo)簽處開始恢復(fù)執(zhí)行,此處包含 aSpyHooks[] 數(shù)組的初始化代碼。這一大塊 ASM 代碼只有通過(guò) aSpyHooks[] 數(shù)組中的 Handler 成員才能進(jìn)入。稍候,我將展示這些進(jìn)入點(diǎn)是如何連接到 SDT 的。

在設(shè)計(jì)這段 ASM 代碼時(shí),我的重要目標(biāo)之一就是使其是完全非侵入式的。截獲操作系統(tǒng)調(diào)用非常危險(xiǎn),因?yàn)槟銖膩?lái)不會(huì)知道被調(diào)用的代碼是否會(huì)依賴調(diào)用上下文( calling context )的某些未知特性。理論上來(lái)說(shuō),這些 ASM 代碼完全符合 __stdcall 約定,但仍存在出錯(cuò)的可能性。我不得不選擇將原始的 Native API 處理例程放入幾乎完全相同的環(huán)境中,這意味著這些原始函數(shù)將使用最初的參數(shù)堆棧并且可以訪問(wèn)所有的 CPU 寄存器,就像它們被正常調(diào)用一樣。當(dāng)然,必須接受由于插入 hook 所帶來(lái)的最低限度的危險(xiǎn),否則,監(jiān)控將不可能實(shí)現(xiàn)。在這里,有意義的改動(dòng)就是維護(hù)堆棧中的返回地址。如果你翻回到 5-3 ,你會(huì)發(fā)現(xiàn)在進(jìn)入函數(shù)時(shí),調(diào)用者的返回地址并不位于堆棧的頂部。 SpyHookInitializeEx() 中的 hook dispatcher 占用了此地址,將它自己的 SpyHook6 標(biāo)簽的地址寫在了這里。因此,原始 Native API 處理例程將被打斷,然后進(jìn)入 SpyHook6 中,這樣 hook dispatcher 才能檢查原始 Native API 處理例程的參數(shù)和它要返回的數(shù)據(jù)。

在調(diào)用原始處理例程之前, dispatcher 將建立一個(gè) SPY_CALL (參見 列表 5-3 )控制塊,該控制塊中包含它稍候?qū)?huì)用到的參數(shù)。其中的一些參數(shù)在正確記錄 API 調(diào)用時(shí)會(huì)用到,另外一些則提供了有關(guān)調(diào)用者的信息,因此 dispatcher 可以在寫完 log 后,把控制返回給調(diào)用者,就像什么都沒(méi)有發(fā)生一樣。 Spy 設(shè)備在它的全局?jǐn)?shù)據(jù)塊 DEVICE_CONTEXT 中維護(hù)著一個(gè) SPY_CALL 結(jié)構(gòu)的數(shù)組,可通過(guò)全局變量 gpDeviceContext 來(lái)訪問(wèn)。 Hook Dispatcher 通過(guò)檢查 SPY_CALL 結(jié)構(gòu)中的 InUse 成員來(lái)在數(shù)組中找到一個(gè)空的 SPY_CALL 。 Hook Dispatcher 使用 CPU 的 XCHG 指令來(lái)加載和設(shè)置該成員的值(譯注: XCHG 指令可以保證此操作為原子操作)。這一點(diǎn)非常重要,因?yàn)楫?dāng)代碼運(yùn)行于多線程環(huán)境中時(shí),讀寫全局?jǐn)?shù)據(jù)時(shí)必須采取保護(hù)措施以避免條件競(jìng)爭(zhēng)。如果在數(shù)組中找到了一個(gè)空的 SPY_CALL , dispatcher 就會(huì)將調(diào)用者的線程 ID (通過(guò) PsGetCurrentThreadId() 獲取)、與當(dāng)前 API 函數(shù)相關(guān)的 SPY_HOOK_ENTRY 結(jié)構(gòu)的地址以及整個(gè)參數(shù)堆棧保存到該 SPY_CALL 結(jié)構(gòu)中。需要復(fù)制的參數(shù)的字節(jié)數(shù)取自 KiArqumentTable 數(shù)組,該數(shù)組保存在系統(tǒng)的 SDT 中。如果所有的 SPY_CALL 都被使用了,原始的 API 函數(shù)處理例程將被調(diào)用而不會(huì)產(chǎn)生任何日志記錄。

必須采用 SPY_CALL 數(shù)組是因?yàn)?Windows 2000 的多線程本性。當(dāng) Native API 函數(shù)被暫停( suspended )時(shí),這種情況就會(huì)經(jīng)常出現(xiàn) ---- 此時(shí),另一個(gè)線程將獲得控制權(quán),然后在它自己的時(shí)間片( time slice )內(nèi)調(diào)用另一個(gè) Native API 函數(shù)。這意味著 Spy 設(shè)備的 Hook Dispatcher 必須允許在任何時(shí)間和任何執(zhí)行點(diǎn)上的重進(jìn)入( reenter )。如果 Hook Dispatcher 有單一的全局 SPY_CALL 存儲(chǔ)區(qū)域,它就可能在處于等待狀態(tài)的線程使用完之前被當(dāng)前運(yùn)行的線程覆寫( overwritten )。而這種情況正是藍(lán)屏的最佳候選人。為了進(jìn)一步了解 Native API 的嵌套,我在 Spy 的 DEVICE_CONTEXT 結(jié)構(gòu)中增加了 dLevel 和 dMisses 成員。無(wú)論何時(shí)只要重進(jìn)入 hook dispatcher (如,向 SPY_CALL 數(shù)組中增加一個(gè)新的 SPY_CALL ) dLevel 都不會(huì)累加一個(gè) 1 。如果超過(guò)了最大嵌套層數(shù)(如, SPY_CALL 數(shù)組已滿), dMisses 就會(huì)累加一個(gè) 1 ,來(lái)標(biāo)識(shí)丟失了一個(gè)日志記錄。根據(jù)我的觀察,在實(shí)際環(huán)境下,可以很容易的發(fā)現(xiàn)嵌套層達(dá)到 4 。這表示即時(shí)在高負(fù)載( heavy-load )的情況下, Native API 也會(huì)被重進(jìn)入,因此,我將嵌套層數(shù)的上限設(shè)為 256 。

在調(diào)用原始的 API 處理例程之前, Hook Dispatcher 會(huì)保存所有的 CPU 寄存器(包括 EFLAGS ),隨后執(zhí)行路徑將導(dǎo)向函數(shù)的進(jìn)入點(diǎn)。這會(huì)在 列表 5-3 中的 SpyHook5 標(biāo)簽之前立即完成。此時(shí), SpyHook6 將位于棧頂,僅隨其后的是調(diào)用者的參數(shù)。一旦 API 處理例程推出了,控制將被傳回到 hook dispatcher 的 SpyHook6 標(biāo)簽。從此處開始執(zhí)行的代碼也被設(shè)計(jì)為非入侵的。此時(shí),主要目標(biāo)是允許調(diào)用者可以看到調(diào)用上下文,這和原始 API 函數(shù)建立的上下文幾乎完全一致。 Dispatcher 的主要問(wèn)題是要能立即找到保存有當(dāng)前 API 調(diào)用信息的 SPY_CALL 結(jié)構(gòu)。唯一可以依賴的就是調(diào)用者的線程 ID ,該 ID 保存在 SPY_CALL 結(jié)構(gòu)的 hThread 成員中。因此, Dispatcher 循環(huán)遍歷整個(gè) SPY_CALL 數(shù)組以尋找匹配的線程 ID 。注意,代碼不會(huì)關(guān)心 fmuse 標(biāo)志的值;這并不是必須的,因?yàn)閿?shù)組中所有未使用的 SPY_CALL 結(jié)構(gòu)的 hThread 都被設(shè)為了 0 ,這是系統(tǒng)空閑線程的 ID 。循環(huán)會(huì)在到達(dá)數(shù)組結(jié)尾時(shí)終止。否則的話(譯注:即沒(méi)有找到匹配的線程 ID ), Dispatcher 不會(huì)將控制返回給調(diào)用者,因?yàn)檫@樣做將是致命的。在這種情況下,代碼的選擇余地很小,因此,它會(huì)進(jìn)入 KeBugCheck() ,這樣做的結(jié)果當(dāng)然是使系統(tǒng)以受控的方式終止。不過(guò)這種情況應(yīng)該從來(lái)不會(huì)發(fā)生,但如果它發(fā)生了,那表示系統(tǒng)必然出現(xiàn)了很嚴(yán)重的錯(cuò)誤,因此,使系統(tǒng)終止是最佳解決方案。

如果發(fā)現(xiàn)了匹配的 SPY_CALL , Hook Dispatcher 將結(jié)束它的工作。最后的動(dòng)作是調(diào)用日志記錄函數(shù) SpyHookProtocol() ,需要給該函數(shù)傳入一個(gè)指向 SPY_CALL 結(jié)構(gòu)的指針。日志記錄所需的信息都保存在該結(jié)構(gòu)中。當(dāng) SpyHookProtocol() 返回后, Dispatcher 就釋放它剛才使用的 SPY_CALL ,恢復(fù)所有的 CPU 寄存器,然后返回到調(diào)用者。

API HOOK 協(xié)議

一個(gè)好的 API Spy 應(yīng)該可以在原始函數(shù)被調(diào)用后還能察看它使用的參數(shù),因?yàn)楹瘮?shù)可能會(huì)通過(guò)傳入的緩沖區(qū)返回附加的數(shù)據(jù)。因此,日志函數(shù) SpyHookProtocol() 在 hook 例程結(jié)束時(shí)將被調(diào)用,而此時(shí) API 函數(shù)還未返回到調(diào)用者。在討論它的實(shí)現(xiàn)秘訣之前,請(qǐng)先看看下面給出的兩個(gè)示例性的協(xié)議( Protocol ),它們會(huì)為你提供一個(gè)大概的方向。 5-6 是在命令行下執(zhí)行 dir c: 時(shí)產(chǎn)生的日志文件的快照。

請(qǐng)對(duì)比 5-6 中列出的日志項(xiàng)和 列表 5-6 給出的協(xié)議格式化字符串。在 示列 5-1 中, NtOpenFile() 和 NtClose() 的格式化字符串分別對(duì)應(yīng) 5-6 中的第一行和第四行。它們有著驚人的相似處;每一個(gè)格式化控制 ID 都緊隨在一個(gè) % 號(hào)后(參考 5-2 ),與其相關(guān)的參數(shù)項(xiàng)將包含在協(xié)議中。不過(guò),協(xié)議還包含一些附加的信息,這些信息明顯不屬于格式字符串。稍后我將解釋這種差異的原因。

示例 5-2 給出了一個(gè)協(xié)議項(xiàng)的一般格式。每一項(xiàng)包含相同個(gè)數(shù)的域,這些域采用分隔符隔開。這樣分隔可以使程序很容易的解析它。這些域按照如下的一組簡(jiǎn)單的基本規(guī)則來(lái)構(gòu)建:

l 所有的數(shù)字都已十六進(jìn)制表示,沒(méi)有 0 前綴或常見的前綴“ 0x ”

l 函數(shù)的多個(gè)參數(shù)由逗號(hào)隔開

l 字符串參數(shù)將位于一對(duì)雙引號(hào)中

l 結(jié)構(gòu)體成員的值由“ . ”符號(hào)隔開

圖 5-6. 命令 dir c: 的示列協(xié)議

'%s=NtOpenFile(%+,%n,%o,%i,%n, %n) '

18:sO=NtOpenFile(+46C.18,nl00001,o'??C:',i0.1,n3,n4021)lBFEE5AE05B6710,278,2

'%s=NtClose(%-l)'

lB:sO=NtClose(-46C.18='??C:')lBFEE5AE05B6710,278,l

示列 5-1. 比較格式化字符串和協(xié)議項(xiàng)

<#> : <status>=<function> (<arguments>) <time> , <thread>, <handles>

示列 5-2. 協(xié)議項(xiàng)的一般格式

l 與句柄相關(guān)的對(duì)象名稱和句柄的值采用“ = ”進(jìn)行分割。

l 日期 / 時(shí)間的 stamp 為 1601-01-01 至今逝去的毫秒數(shù),其格式依賴 Windows 2000 的基本時(shí)間格式,精度可達(dá)到 1/10 毫秒。

l 線程 ID 是調(diào)用 API 函數(shù)的線程的唯一數(shù)字標(biāo)識(shí)。

l 句柄計(jì)數(shù)的狀態(tài)表示當(dāng)前注冊(cè)到 Spy 設(shè)備句柄列表中的句柄的數(shù)量。協(xié)議函數(shù)使用該列表查找與對(duì)象名稱相關(guān)的句柄。

圖 5-7. 命令 type c:boot.ini 的示列協(xié)議

圖 5-7 是在控制臺(tái)中執(zhí)行: type c:boot.ini 命令產(chǎn)生的 API Spy 協(xié)議結(jié)果。下面給出日志項(xiàng)中的某些列的含義:

l 在 0x31 行,調(diào)用了 NtCreateFile() 來(lái)打開 ??c:boot.ini 文件。( o”??c:boot.ini” )該函數(shù)返回的 NTSTATUS 的值為 0 ( s0 ),即 STATUS_SUCCESS ,并分配了一個(gè)新的文件句柄,其值為 0 小 8 ,該句柄屬于進(jìn)程 0x46c ( +46C.18 )。因此,句柄計(jì)數(shù)從 1 增加到 2 。

l 在 0x36 行, type 命令將文件 ??c:boot.ini 的前 512 個(gè)字節(jié)( n200 )讀入位于線性地址 0x0012F5B4 處的緩沖區(qū)中,并把從 NtCreateFile() 獲取的句柄解析給 NtReadFile() 函數(shù)。系統(tǒng)成功的返回 512 字節(jié)( io.200 )。

l 在 0x39 行,將處理另一塊 512 個(gè)字節(jié)的文件塊。這一次,將到達(dá)文件的末尾,因此 NtReadFile() 僅返回了 75 個(gè)字節(jié)( io.4B )。顯然,我的 boot.ini 文件的大小為: 512+75=587 字節(jié)。

l 在 0x3C 行, NtClose() 成功的釋放了指向 ??c:boot.ini 的文件句柄( -46.18=”??c:boot.ini” ),因此,句柄計(jì)數(shù)將從 2 減少為 1 。

現(xiàn)在,你應(yīng)該已經(jīng)明白 Spy 協(xié)議的 API 是如何構(gòu)建的了,這會(huì)幫助你掌握協(xié)議生成機(jī)制的細(xì)節(jié),接下來(lái)我們將討論這一機(jī)制。在前面我曾提及過(guò),用于日志記錄的主要 API 函數(shù)是 SpyHookProtocol() 。 列表 5-7 給出了該函數(shù),它將使用 SPY_CALL 結(jié)構(gòu)中的數(shù)據(jù)來(lái)為每個(gè) API 函數(shù)生成一個(gè)協(xié)議記錄并將其寫入一個(gè)環(huán)形緩沖區(qū)中,這里的 SPY_CALL 結(jié)構(gòu)由 Hook Dispatcher 傳入。一個(gè) Spy 設(shè)備的客戶端可以通過(guò) IOCTL 調(diào)用來(lái)讀去這一協(xié)議。每個(gè)記錄項(xiàng)都是一行文本,每行都由單個(gè)行結(jié)束符(即 C 語(yǔ)言中的 ”n” )表示行的結(jié)束。通過(guò)使用內(nèi)核的 Mutext KMUTEX kmProtcol 來(lái)實(shí)現(xiàn)串行讀去協(xié)議緩沖區(qū), kmProtocol 位于 Spy 設(shè)備的全局結(jié)構(gòu) DEVICE_CONTEXT 中。 列表 5-7 中的 SpyHookWait() 和 SpyHookRelease() 函數(shù)用于請(qǐng)求和釋放此 Mutext 對(duì)象。所有對(duì)協(xié)議緩沖區(qū)的訪問(wèn)都必須由 SpyHookWait() 預(yù)處理并在結(jié)束時(shí)由 SpyHookRelease() 處理, SpyHookProtocol() 函數(shù)展示了這種行為。

NTSTATUS SpyHookWait (void)

{

return MUTEX_WAIT (gpDeviceContext->kmProtocol);

}

// -----------------------------------------------------------------

LONG SpyHookRelease (void)

{

return MUTEX_RELEASE (gpDeviceContext->kmProtocol);

}

// -----------------------------------------------------------------

// <#>:<status>=<function>(<arguments>)<time>,<thread>,<handles>

void SpyHookProtocol (PSPY_CALL psc)

{

LARGE_INTEGER liTime;

PSPY_PROTOCOL psp = &gpDeviceContext->SpyProtocol;

KeQuerySystemTime (&liTime);

SpyHookWait ();

if (SpyWriteFilter (psp, psc->pshe->pbFormat,

psc->adParameters,

psc->dParameters))

{

SpyWriteNumber (psp, 0, ++(psp->sh.dCalls)); // <#>:

SpyWriteChar (psp, 0, ':');

// <status>=

SpyWriteFormat (psp, psc->pshe->pbFormat, // <function>

psc->adParameters); // (<arguments>)

SpyWriteLarge (psp, 0, &liTime); // <time>,

SpyWriteChar (psp, 0, ',');

SpyWriteNumber (psp, 0, (DWord) psc->hThread); // <thread>,

SpyWriteChar (psp, 0, ',');

SpyWriteNumber (psp, 0, psp->sh.dHandles); // <handles>

SpyWriteChar (psp, 0, 'n');

}

SpyHookRelease ();

return;

}

列表 5-7. 主要的 Hook 協(xié)議函數(shù) SpyHookProtocol()

如果你比較一下 列表 5-7 給出的 SpyHookProtocol() 函數(shù)的主要部分和 示列 5-2 給出的協(xié)議項(xiàng)的一般格式,將很容易找出那個(gè)語(yǔ)句生成了協(xié)議項(xiàng)中的哪一個(gè)域( fIEld )。這樣一來(lái)一切就很清楚了為什么 列表 5-6 中的協(xié)議字符串沒(méi)有說(shuō)明整個(gè)數(shù)據(jù)項(xiàng) --- 有些獨(dú)立于功能的數(shù)據(jù)將由 SpyHookProtocol() 添加,而這將不需要格式字符串的幫助。 SpyHookProtocl() 的核心調(diào)用是 SpyWriteFormat() ,該函數(shù)生成 <status>=<function>[<arguments>] 部分,這依賴于與要記錄的當(dāng)前 API 函數(shù)相關(guān)的格式字符串。請(qǐng)參考位于隨書光盤的 srcw2k_spy 目錄下的源文件 w2k_spy.c 和 w2k_spy.h ,以獲取 Spy 設(shè)備驅(qū)動(dòng)程序中使用的 SpyWrite*() 函數(shù)的更多實(shí)現(xiàn)信息。

請(qǐng)注意,這些代碼稍微有些危險(xiǎn)。這些代碼編寫與 1997 年是針對(duì) Windows NT 4.0 的。在移植到 Windows 2000 之后,當(dāng) hook 工作一段較長(zhǎng)時(shí)間后會(huì)偶爾引發(fā)藍(lán)屏。更糟糕的是,有些特殊的操作將立即引發(fā)藍(lán)屏,例如,在 My Favoriter 文本編輯器的 FileOpen 對(duì)話框中打開我的電腦時(shí)。在分析過(guò)多過(guò) crash dump 后,我發(fā)現(xiàn)是由于將 NULL 指針傳遞給了某些函數(shù)從而導(dǎo)致了系統(tǒng)崩潰。一但 Spy 設(shè)備試圖使用這些指針中的某個(gè)來(lái)記錄該指針引用的數(shù)據(jù)時(shí),系統(tǒng)就會(huì)崩潰。典型的就是,指向 IO_STATUS_BLOCK 結(jié)構(gòu)的指針,在 UNICODE_STRING 和 OBJECT_ATTRIBUTES 結(jié)構(gòu)中存在無(wú)效的字符串指針。我還發(fā)現(xiàn)某些有 Buffer 成員的 UNICODE_STRING 結(jié)構(gòu)沒(méi)有 結(jié)束符。因此,我再次強(qiáng)調(diào)你不應(yīng)該假定所有的 UNICODE_STRING 結(jié)構(gòu)都以 結(jié)束。在不能確定時(shí),請(qǐng)使用 Length 成員,它總能正確地告訴你在 Buffer 中存放的有效的字節(jié)數(shù)。

為了修正這一問(wèn)題,我為所有使用客戶指針的日志函數(shù)增加了指針有效性檢查。在結(jié)束時(shí),我使用第四章討論過(guò)的 SpyMemoryTestAddress() 函數(shù)來(lái)檢驗(yàn)一個(gè)線性地址指針是否指向一個(gè)有效的頁(yè)表項(xiàng)( PTE )。更詳細(xì)的信息請(qǐng)參考 列表 4-22 列表 4-24 。另一種可能的替代方案是使用結(jié)構(gòu)化異常( __try/__except )。

標(biāo)簽: Windows系統(tǒng)
主站蜘蛛池模板: 91香蕉视频免费在线观看 | 婷婷三级 | 欧美h网| 久久精品国产亚洲综合色 | 亚洲欧美视频一区二区 | 女女在线视频 | 久久国产精品视频一区 | 国产三级日本三级在线播放 | 亚洲精品乱码久久久久久蜜桃欧美 | 全免费毛片在线播放 | 亚洲图片国产日韩欧美 | 一级特黄色大片 | 日韩一区二区三区视频在线观看 | 呦系列视频一区二区三区 | 国产一二三四区在线观看 | 亚洲视频天天射 | 免费看全黄特黄毛片 | 国产精品亚洲欧美一级久久精品 | 能免费看黄的网站 | 九九九精品在线观看 | 亚洲主播在线 | 国产黑人在线 | 国产3区 | 久草在线播放视频 | 国产福利在线观看永久免费 | 综合久草 | 婷婷在线网站 | 1000部啪啪未满十八勿入福利 | 亚洲国产精品不卡毛片a在线 | 992人人草| 欧美日产欧美日产精品 | 久久久久国产一级毛片高清版 | 国产一区欧美 | 黄色短视频在线播放 | 在线观看免费情网站大全 | 欧美成人三级一区二区在线观看 | 亚洲欧洲一区二区三区在线 | 国产在线精品99一卡2卡 | 亚洲一区二区福利视频 | 1024国产基地 | 手机看片日韩国产一区二区 |