3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

windows内核情景分析---进程线程2

發(fā)布時(shí)間:2023/11/30 windows 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 windows内核情景分析---进程线程2 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

二、線程調(diào)度與切換

眾所周知:Windows系統(tǒng)是一個(gè)分時(shí)搶占式系統(tǒng),分時(shí)指每個(gè)線程分配時(shí)間片,搶占指時(shí)間片到期前,中途可以被其他更高優(yōu)先級(jí)的線程強(qiáng)制搶占。

背景知識(shí):每個(gè)cpu都有一個(gè)TSS,叫‘任務(wù)狀態(tài)段’。這個(gè)TSS內(nèi)部中的一些字段記錄著該cpu上當(dāng)前正在運(yùn)行的那個(gè)線程的一些信息(如ESP0記錄著該線程的內(nèi)核棧位置,IO權(quán)限位圖記錄著當(dāng)前線程的IO空間權(quán)限)

IO空間有64KB,IO權(quán)限位圖中的每一位記錄著對(duì)應(yīng)IO地址的IN、OUT許可權(quán)限,所以IO權(quán)限位圖本身有8KB大小,TSS中就就記錄著當(dāng)前線程IO權(quán)限位圖的偏移位置。

每當(dāng)切換線程時(shí):自然要跟著修改TSS中的ESP0和IO權(quán)限位圖。TSS0中為什么要保存當(dāng)前線程的內(nèi)核棧位置?原因是:每當(dāng)一個(gè)線程內(nèi)部,從用戶模式進(jìn)入內(nèi)核模式時(shí),需要將cpu中的esp換成該線程的內(nèi)核棧(各線程的內(nèi)核棧是不同的)每當(dāng)進(jìn)入內(nèi)核模式時(shí),cpu就自動(dòng)從TSS中找到ESP0,然后MOV?ESP,?TSS.ESP0,換成內(nèi)核棧后,cpu然后在內(nèi)核棧中壓入浮點(diǎn)寄存器和標(biāo)準(zhǔn)的5個(gè)寄存器:原cs、原eip、原ss、原esp、原eflags。這就是為什么需要在TSS中記錄當(dāng)前線程的內(nèi)核棧地址。(注意ESP0并不是棧底地址,而是要壓入保存寄存器處的存放地址)

與線程切換相關(guān)的數(shù)據(jù)結(jié)構(gòu)定義:

Struct?KPCR?//處理器控制塊(內(nèi)核中的fs寄存器總是指向這個(gè)結(jié)構(gòu)體的基址)

{

???KPCR_TIB?Tib;

???KPCR*?self;//方便尋址

???KPRCB*?Prcb;

???KIRQL?irql;//物理上表示cpu的當(dāng)前中斷級(jí),邏輯上理解為當(dāng)前線程的中斷級(jí)更好

???USHORT*?IDT;//本cpu的中斷描述符表的地址

???USHORT*?GDT;//本cpu的全局描述符表的地址

???KTSS*?TSS;//本cpu上當(dāng)前線程的信息(ESP0)

???…

}

Struct?KPCR_TIB

{

???Void*?ExceptionList;//當(dāng)前線程的內(nèi)核seh鏈表頭結(jié)點(diǎn)地址

???Void*?StackBase;//內(nèi)核棧底地址

???Void*?StackLimit;//棧的提交邊界

???…

???KPCR_TIB*?self;//方便尋址

}

Struct?KPRCB

{

???…

???KTHREAD*?CurrentThread;//本cpu上當(dāng)前正在運(yùn)行的線程

???KTHREAD*?NextThread;//將剝奪(即搶占)當(dāng)前線程的下一個(gè)線程

??KTHREAD*?IdleThread;//空轉(zhuǎn)線程

??BOOL?QuantumEnd;//重要字段。指當(dāng)前線程的時(shí)間片是否已經(jīng)用完。

??LIST_ENTRY?WaitListHead;//本cpu的等待線程隊(duì)列

??ULONG?ReadSummary;//各就緒隊(duì)列中是否為空的標(biāo)志

??ULONG?SelectNextLast;

??LIST_ENTRY?DispatcherReadyListHead[32];//對(duì)應(yīng)32個(gè)優(yōu)先級(jí)的32個(gè)就緒線程隊(duì)列

??FX_SAVE_AREA?NpxSaveArea;

??…

}

typedef?struct?_KSWITCHFRAME??//切換幀(用來(lái)保存切換線程)

{

PVOID?ExceptionList;//保存線程切換時(shí)的內(nèi)核she鏈表(不是用戶空間中的seh)

Union
{

BOOLEAN?ApcBypassDisable;//用于首次調(diào)度

UCHAR?WaitIrql;//用于保存切換時(shí)的WaitIrql

};

//實(shí)際上首次時(shí)為KiThreadStartup,以后都固定為call?KiSwapContextInternal后面的那條指令

????PVOID?RetAddr;//保存發(fā)生切換時(shí)的斷點(diǎn)地址(以后切換回來(lái)時(shí)從這兒繼續(xù)執(zhí)行)

}?KSWITCHFRAME,?*PKSWITCHFRAME;

typedef?struct?_KTRAP_FRAME?//Trap現(xiàn)場(chǎng)幀

{

???------------------這些是KiSystemService保存的---------------------------

????ULONG?DbgEbp;

????ULONG?DbgEip;

????ULONG?DbgArgMark;

????ULONG?DbgArgPointer;

????ULONG?TempSegCs;

????ULONG?TempEsp;

????ULONG?Dr0;

????ULONG?Dr1;

????ULONG?Dr2;

????ULONG?Dr3;

????ULONG?Dr6;

????ULONG?Dr7;

????ULONG?SegGs;

????ULONG?SegEs;

????ULONG?SegDs;

????ULONG?Edx;//xy?這個(gè)位置不是用來(lái)保存edx的,而是用來(lái)保存上個(gè)Trap幀,因?yàn)門rap幀是可以嵌套的

????ULONG?Ecx;?//中斷和異常引起的自陷要保存eax,系統(tǒng)調(diào)用則不需保存ecx

????ULONG?Eax;//中斷和異常引起的自陷要保存eax,系統(tǒng)調(diào)用則不需保存eax

????ULONG?PreviousPreviousMode;

????struct?_EXCEPTION_REGISTRATION_RECORD?FAR?*ExceptionList;//上次seh鏈表的開頭地址

????ULONG?SegFs;

????ULONG?Edi;

????ULONG?Esi;

????ULONG?Ebx;

ULONG?Ebp;

----------------------------------------------------------------------------------------

ULONG?ErrCode;//發(fā)生的不是中斷,而是異常時(shí),cpu還會(huì)自動(dòng)在棧中壓入對(duì)應(yīng)的具體異常碼在這兒

-----------下面5個(gè)寄存器是由int?2e內(nèi)部本身保存的或KiFastCallEntry模擬保存的現(xiàn)場(chǎng)---------

????ULONG?Eip;

????ULONG?SegCs;

????ULONG?EFlags;

????ULONG?HardwareEsp;

ULONG?HardwareSegSs;

---------------以下用于用于保存V86模式的4個(gè)寄存器也是cpu自動(dòng)壓入的-------------------

????ULONG?V86Es;

????ULONG?V86Ds;

????ULONG?V86Fs;

ULONG?V86Gs;

}?KTRAP_FRAME,?*PKTRAP_FRAME;

下面這個(gè)核心函數(shù)用來(lái)切換線程(從當(dāng)前線程切換到新線程去)。這個(gè)函數(shù)的原型是:

BOOL?FASTCALL?KiSwapContex(KTHREAD*?Currentthread*,?KTHREAD*?NewThread);

返回值表示下次切換回來(lái)時(shí)是否需要手動(dòng)掃描執(zhí)行內(nèi)核APC。這個(gè)函數(shù)的匯編代碼為:

@KiSwapContext@8:???//開頭的@表示fastcall調(diào)用約定

{

sub?esp,?4?*?4?//騰出局部變量空間

//保存這4個(gè)寄存器,因?yàn)镵iSwapContextInternal函數(shù)內(nèi)部要使用這幾個(gè)寄存器

????mov?[esp+12],?ebx

????mov?[esp+8],?esi

????mov?[esp+4],?edi

????mov?[esp+0],?ebp

????mov?ebx,?fs:[KPCR_SELF]?//ebx=當(dāng)前cpu的KPCR*

????mov?edi,?ecx?//edi=?KiSwapContext的第一個(gè)參數(shù),即CurrentThread

????mov?esi,?edx?//edi=?KiSwapContext的第而個(gè)參數(shù),即NewThread

????movzx?ecx,?byte?ptr?[edi+KTHREAD_WAIT_IRQL]?//ecx=當(dāng)前線程的WaitIrql

call?@KiSwapContextInternal@0??//調(diào)用真正的切換工作函數(shù)

這中間已經(jīng)被切換到新線程去了,當(dāng)前線程已經(jīng)讓出cpu,掛入了就緒隊(duì)列。需要等到下次重新被調(diào)度運(yùn)行時(shí),才又從這兒的斷點(diǎn)處繼續(xù)向下執(zhí)行下去

mov?ebp,?[esp+0]??//這條指令就是斷點(diǎn)處,以后切換回來(lái)時(shí)就從這個(gè)斷點(diǎn)處繼續(xù)執(zhí)行

????mov?edi,?[esp+4]

????mov?esi,?[esp+8]

????mov?ebx,?[esp+12

????add?esp,?4?*?4

????ret

}

下面的函數(shù)完成真正的切換工作(返回值表示切換回來(lái)后是否需要手動(dòng)掃描執(zhí)行內(nèi)核apc)

@KiSwapContextInternal@0:??//edi指向當(dāng)前線程,esi指向要切換到的新線程,ebx指向當(dāng)前KPCR*

{

inc?dword?ptr?es:[ebx+KPCR_CONTEXT_SWITCHES]??//遞增當(dāng)前cpu上發(fā)生的歷史線程切換計(jì)數(shù)

????push?ecx??//保存本線程切換時(shí)的WaitIrql

push?[ebx+KPCR_EXCEPTION_LIST]?//保存本線程切換時(shí)的內(nèi)核seh鏈表

-------------------------至此,上面的兩條push連同本函數(shù)的返回地址(即斷點(diǎn)地址),就構(gòu)成了一個(gè)切換幀。當(dāng)前線程切換時(shí)的內(nèi)核棧頂位置就在此處-----------------------------

AfterTrace:

????mov?ebp,?cr0

????mov?edx,?ebp??//將cr0寄存器保存在edx中(cr0的Bit3位“TaskSwitched”標(biāo)志位,與浮點(diǎn)運(yùn)算相關(guān))

SetStack:

????mov?[edi+KTHREAD_KERNEL_STACK],?esp?//保存本線程切換時(shí)的內(nèi)核棧頂位置

mov?eax,?[esi+KTHREAD_INITIAL_STACK]?//eax=新線程的內(nèi)核棧底地址

--------------------------------------------------------------------------------

????cli??//下面檢查Npx浮點(diǎn)寄存器,要關(guān)中斷

????movzx?ecx,?byte?ptr?[esi+KTHREAD_NPX_STATE]?//ecx=新線程的Npx狀態(tài)

????and?edx,?~(CR0_MP?+?CR0_EM?+?CR0_TS)

????or?ecx,?edx

????or?ecx,?[eax?-?(NPX_FRAME_LENGTH?-?FN_CR0_NPX_STATE)]?//獲得新線程需要的cr0

????cmp?ebp,?ecx

????jnz?NewCr0?//如果新線程需要的cr0不同于當(dāng)前的cr0,則修改當(dāng)前cr0為新線程的cr0

StackOk:

Sti

--------------------------------------------------------------------------------

mov?esp,?[esi+KTHREAD_KERNEL_STACK]?//關(guān)鍵。恢復(fù)成新線程當(dāng)初被切換時(shí)的內(nèi)核棧頂

????mov?ebp,?[esi+KTHREAD_APCSTATE_PROCESS]?//ebp=目標(biāo)進(jìn)程

????mov?eax,?[edi+KTHREAD_APCSTATE_PROCESS]?//eax=當(dāng)前進(jìn)程

????cmp?ebp,?eax??//檢查是否是切換到同一個(gè)進(jìn)程中的其他線程(若是。就不用切換LDT和cr3)

jz?SameProcess?

//若切換到其他進(jìn)程中的線程,則要同時(shí)修改LDT和CR3

????mov?ecx,?[ebp+KPROCESS_LDT_DESCRIPTOR0]

????or?ecx,?[eax+KPROCESS_LDT_DESCRIPTOR0]

????jnz?LdtReload?//如果兩個(gè)進(jìn)程的LDT不同,就要換用不同的LDT

UpdateCr3:

????mov?eax,?[ebp+KPROCESS_DIRECTORY_TABLE_BASE]

????mov?cr3,?eax?//關(guān)鍵。將cr3換成目標(biāo)進(jìn)程的頁(yè)目錄

SameProcess:

????xor?eax,?eax

????mov?gs,?ax

????mov?eax,?[esi+KTHREAD_TEB]?//新線程的TEB地址

????mov?[ebx+KPCR_TEB],?eax?//當(dāng)前KPCR中的TEB指向新線程的TEB

mov?ecx,?[ebx+KPCR_GDT]

//修改GDT中的TEB描述符,指向新線程的TEB

????mov?[ecx+0x3A],?ax

????shr?eax,?16

????mov?[ecx+0x3C],?al

????mov?[ecx+0x3F],?ah

????mov?eax,?[esi+KTHREAD_INITIAL_STACK]?//eax=新線程的內(nèi)核棧底位置

????sub?eax,?NPX_FRAME_LENGTH?//跳過(guò)浮點(diǎn)保存區(qū)空間

????test?dword?ptr?[eax?-?KTRAP_FRAME_SIZE?+?KTRAP_FRAME_EFLAGS],?EFLAGS_V86_MASK

????jnz?NoAdjust?//檢查新線程是否運(yùn)行在V86模式

????sub?eax,?KTRAP_FRAME_V86_GS?-?KTRAP_FRAME_SS?//跳過(guò)V86保存區(qū)

NoAdjust:

????mov?ecx,?[ebx+KPCR_TSS]

????mov?[ecx+KTSS_ESP0],?eax??//關(guān)鍵,修改TSS中的ESP0,指向新線程的內(nèi)核棧底

????mov?ax,?[ebp+KPROCESS_IOPM_OFFSET]

????mov?[ecx+KTSS_IOMAPBASE],?ax??//修改TSS中的IO權(quán)限位圖偏移指向新進(jìn)程中的IO權(quán)限位圖

????inc?dword?ptr?[esi+KTHREAD_CONTEXT_SWITCHES]?//遞增線程的切換次數(shù)(也即歷史調(diào)度次數(shù))

????pop?[ebx+KPCR_EXCEPTION_LIST]?//將當(dāng)前KPCR中記錄的seh鏈表恢復(fù)成新線程的seh鏈表

????pop?ecx?//ecx=新線程原來(lái)切換前的WaitIrql

????cmp?byte?ptr?[ebx+KPCR_PRCB_DPC_ROUTINE_ACTIVE],?0?//檢查當(dāng)前是否有DPC函數(shù)處于活動(dòng)狀態(tài)

????jnz?BugCheckDpc?//藍(lán)屏

//至此,cpu中的寄存器內(nèi)容全部換成了新線程的那些寄存器,從這個(gè)意思上說(shuō),此時(shí)就已完成了全部切換工作,下面的代碼都是在新線程的環(huán)境中運(yùn)行了。

--------------------------------新線程環(huán)境---------------------------------------

????cmp?byte?ptr?[esi+KTHREAD_PENDING_KERNEL_APC],?0

????jnz?CheckApc?//看到?jīng)],每次線程得到重新調(diào)度運(yùn)行前,都會(huì)掃描執(zhí)行內(nèi)核apc隊(duì)列中的函數(shù)

????xor?eax,?eax?

????ret?//此處返回值表示沒(méi)有內(nèi)核apc

CheckApc:

????cmp?word?ptr?[esi+KTHREAD_SPECIAL_APC_DISABLE],?0?//檢查是否禁用了APC

????jnz?ApcReturn

????test?cl,?cl??//檢查WaitIrql,如果是APC級(jí),就在本函數(shù)內(nèi)部返回前,發(fā)出apc中斷

????jz?ApcReturn

????//if(SPECIAL?APC?沒(méi)禁用?&&?WaitIrql!=PASSIVE_LEVEL),切換回來(lái)時(shí)就先執(zhí)行內(nèi)核APC

????mov?cl,?APC_LEVEL

????call?@HalRequestSoftwareInterrupt@4?//發(fā)出一個(gè)apc中斷

????or?eax,?esp?//既然發(fā)出apc中斷了,那么就return?FALSE表示無(wú)需手動(dòng)掃描執(zhí)行apc

ApcReturn:

????setz?al

ret??//此處返回值表示切回來(lái)后是否需要手動(dòng)掃描執(zhí)行apc

//當(dāng)這個(gè)函數(shù)返回時(shí),之前已經(jīng)換成新線程的內(nèi)核棧了。當(dāng)函數(shù)返回后,將回到KiSwapContext中,當(dāng)KiSwapContext返回到調(diào)用方時(shí),那個(gè)調(diào)用方就是新線程當(dāng)初調(diào)用的KiSwapContext的函數(shù),這樣,就沿著新線程的內(nèi)核棧,逐級(jí)向上回溯到新線程中了。因此,可以說(shuō),切換內(nèi)核棧,即是切換線程。

LdtReload:

????mov?eax,?[ebp+KPROCESS_LDT_DESCRIPTOR0]

????test?eax,?eax??//檢測(cè)目標(biāo)進(jìn)程有沒(méi)有LDT

????jz?LoadLdt

????mov?ecx,?[ebx+KPCR_GDT]

????mov?[ecx+KGDT_LDT],?eax?//改指目標(biāo)進(jìn)程的LDT

????mov?eax,?[ebp+KPROCESS_LDT_DESCRIPTOR1]

????mov?[ecx+KGDT_LDT+4],?eax//改指目標(biāo)進(jìn)程的LDT

????/*?Write?the?INT21?handler?*/

????mov?ecx,?[ebx+KPCR_IDT]

????mov?eax,?[ebp+KPROCESS_INT21_DESCRIPTOR0]

????mov?[ecx+0x108],?eax

????mov?eax,?[ebp+KPROCESS_INT21_DESCRIPTOR1]

????mov?[ecx+0x10C],?eax

????mov?eax,?KGDT_LDT

LoadLdt:

????lldt?ax

????jmp?UpdateCr3

NewCr0:

????mov?cr0,?ecx

????jmp?StackOk

BugCheckDpc:

????mov?eax,?[edi+KTHREAD_INITIAL_STACK]

????push?0

????push?eax

????push?esi

????push?edi

????push?ATTEMPTED_SWITCH_FROM_DPC

????call?_KeBugCheckEx@20???//藍(lán)屏提示:“嘗試從活動(dòng)DPC例程中切換線程”

}

如上:線程從KiSwapContextInternal這個(gè)函數(shù)內(nèi)部切換出去,某一時(shí)刻又切換回這個(gè)函數(shù)內(nèi)。

或者也可以理解為:線程從KiSwapContext這個(gè)函數(shù)切換出去,某一時(shí)刻又切換回這個(gè)函數(shù)內(nèi)。

(注:可以hook這兩個(gè)函數(shù),來(lái)達(dá)到檢測(cè)隱藏進(jìn)程的目的)

明白了線程切換的過(guò)程,所做的工作后,接下來(lái)看:線程的切換時(shí)機(jī)(也即一個(gè)線程什么時(shí)候會(huì)調(diào)用

KiSwapContext這個(gè)函數(shù)把自己切換出去),相信這是大伙最感興趣的問(wèn)題。

三、線程的調(diào)度策略與切換時(shí)機(jī)

調(diào)度策略:Windows嚴(yán)格按優(yōu)先級(jí)調(diào)度線程。

優(yōu)先級(jí)分成32個(gè),每個(gè)cpu對(duì)應(yīng)有32個(gè)就緒線程隊(duì)列。每當(dāng)要發(fā)生線程切換時(shí),就根據(jù)調(diào)度策略從32條就緒隊(duì)列中,按優(yōu)先級(jí)從高到低的順序掃描(同一個(gè)就緒隊(duì)列中,由于優(yōu)先級(jí)相同,則按FIFO順序掃描),這樣,從32條就緒隊(duì)列中,找到優(yōu)先級(jí)最高的那個(gè)候選就緒線程,給予調(diào)度執(zhí)行。

當(dāng)一個(gè)線程得到調(diào)度執(zhí)行時(shí),如果一直沒(méi)有任何其他就緒線程的優(yōu)先級(jí)高于本線程,本線程就可以暢通無(wú)阻地一直執(zhí)行下去,直到本次的時(shí)間片用完。但是如果本次執(zhí)行的過(guò)程中,如果有個(gè)就緒線程的優(yōu)先級(jí)突然高于了本線程,那么本線程將被搶占,cpu將轉(zhuǎn)去執(zhí)行那個(gè)線程。但是,這種搶占可能不是立即性的,只有在當(dāng)前線程的irql在DISPATCH_LEVEL以下(不包括),才會(huì)被立即搶占,否則,推遲搶占(即把那個(gè)高優(yōu)先級(jí)的就緒線程暫時(shí)記錄到當(dāng)前cpu的KPCR結(jié)構(gòu)中的NextThread字段中,標(biāo)記要將搶占)。

切換時(shí)機(jī):一句話【時(shí)片、搶占、等、主動(dòng)】

1、?時(shí)間片耗盡

2、?被搶占

3、?因等待事件、資源、信號(hào)時(shí)主動(dòng)放棄cpu(如調(diào)用WaitForSingleObject)

4、?主動(dòng)切換(如主動(dòng)調(diào)用SwitchToThread這個(gè)Win32?API)

但是:即使到了切換時(shí)機(jī)了,也只有當(dāng)線程的irql在DISPATCH_LEVEL以下(不包括)時(shí),才可以被切換出去,否則,線程將繼續(xù)占有cpu,一直等到irql降到DISPATCH_LEVEL以下。

線程的狀態(tài)(不含掛起態(tài),其實(shí)掛起態(tài)本質(zhì)上也是一種等待態(tài))

1、Ready就緒態(tài)(掛入相應(yīng)的就緒隊(duì)列)

2、某一時(shí)刻得到調(diào)度變成Running運(yùn)行態(tài)

3、因等待某一事件、信號(hào)、資源等變成Waiting等待狀態(tài)

4、Standby狀態(tài)。指處于搶占者狀態(tài)(NextThread就是自己)

5、DeferredReady狀態(tài)。指‘將’進(jìn)入就緒態(tài)。

先看一下主動(dòng)放棄cpu,切換線程的函數(shù)

NTSTATUS?NtYieldExecution()

{

????NTSTATUS?Status?=?STATUS_NO_YIELD_PERFORMED;

????KIRQL?OldIrql;

????PKPRCB?Prcb?=?KeGetCurrentPrcb();//當(dāng)前cpu的控制塊

????PKTHREAD?Thread?=?KeGetCurrentThread(),?NextThread;

if?(Prcb->ReadySummary==0)

?return?Status;//如果沒(méi)有其他線程處于就緒態(tài),就不用切換了

//重要。線程的調(diào)度過(guò)程與切換過(guò)程,本身就運(yùn)行在SynchLevel,目的是防止在執(zhí)行調(diào)度、切換工作的過(guò)程中又被切換了出去。因此,可以說(shuō),調(diào)度、切換這個(gè)過(guò)程是原子的。

????OldIrql?=?KeRaiseIrqlToSynchLevel();//先提到SynchLevel,再做調(diào)度、切換工作

????if?(Prcb->ReadySummary!=0)//如果當(dāng)前cpu上有就緒線程

????{

????????KiAcquireThreadLock(Thread);

????????KiAcquirePrcbLock(Prcb);

????????if?(Prcb->NextThread?!=?NULL)

NextThread?=?Prcb->NextThread;//優(yōu)先選擇那個(gè)等待搶占的線程

????????Else?//如果當(dāng)前沒(méi)有候選搶占線程,就從就緒隊(duì)列調(diào)度出一個(gè)線程

?NextThread?=?KiSelectReadyThread(1,?Prcb);????????

????????if?(NextThread)

????????{

????????????Thread->Quantum?=?Thread->QuantumReset;//設(shè)置下次調(diào)度運(yùn)行的時(shí)間片

????????????Thread->Priority?=?KiComputeNewPriority(Thread,?1);//略微降低一個(gè)優(yōu)先級(jí)

????????????KiReleaseThreadLock(Thread);

????????????KiSetThreadSwapBusy(Thread);//標(biāo)記本線程正在被切換

Prcb->CurrentThread?=?NextThread;//標(biāo)記已切換到下一個(gè)線程

????????????Prcb->NextThread?=?NULL;//初始運(yùn)行時(shí)尚未有任何搶占者線程

????????????NextThread->State?=?Running;//標(biāo)記線程狀態(tài)正在運(yùn)行

????????????Thread->WaitReason?=?WrYieldExecution;//標(biāo)記本線程上次被切換的原因是主動(dòng)放棄

????????????KxQueueReadyThread(Thread,?Prcb);//將本線程轉(zhuǎn)入就緒隊(duì)列

????????????Thread->WaitIrql?=?APC_LEVEL;//這將導(dǎo)致下次切換回來(lái)時(shí)會(huì)自動(dòng)發(fā)出apc中斷

????????????MiSyncForContextSwitch(NextThread);

????????????KiSwapContext(Thread,?NextThread);//真正切換到目標(biāo)線程

????????????---------------------------華麗的分割線---------------------------------------

????????????Status?=?STATUS_SUCCESS;//本線程下次切回來(lái)時(shí)繼續(xù)從這里執(zhí)行下去

????????}

????????else

????????{

????????????KiReleasePrcbLock(Prcb);

????????????KiReleaseThreadLock(Thread);

????????}

????}

????KeLowerIrql(OldIrql);//完成調(diào)度、切換過(guò)程后,降低到原irql(這個(gè)過(guò)程可能會(huì)執(zhí)行apc)

????return?Status;

}

//下面就是調(diào)度策略:按優(yōu)先級(jí)從高到低的順序掃描32條就緒隊(duì)列,取下最高優(yōu)先級(jí)的線程

PKTHREAD

KiSelectReadyThread(IN?KPRIORITY?Priority,//指調(diào)度出的線程必須>=這個(gè)優(yōu)先級(jí)

????????????????????IN?PKPRCB?Prcb)//指定cpu

{

????ULONG?PrioritySet;

????LONG?HighPriority;//含有就緒線程的最高優(yōu)先級(jí)隊(duì)列

????PLIST_ENTRY?ListEntry;

????PKTHREAD?Thread?=?NULL;//調(diào)度出來(lái)的線程

????PrioritySet?=?Prcb->ReadySummary?>>?Priority;

????if?(!PrioritySet)?goto?Quickie;

????BitScanReverse((PULONG)&HighPriority,?PrioritySet);//從高位到地位掃描那個(gè)標(biāo)志位圖

????HighPriority?+=?Priority;

????ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority])?==?FALSE);

????ListEntry?=?Prcb->DispatcherReadyListHead[HighPriority].Flink;//隊(duì)列中的第一個(gè)線程

????Thread?=?CONTAINING_RECORD(ListEntry,?KTHREAD,?WaitListEntry);

????ASSERT(HighPriority?==?Thread->Priority);//確保優(yōu)先級(jí)符合

????ASSERT(Thread->Affinity?&?AFFINITY_MASK(Prcb->Number));//確保cpu親緣性

????ASSERT(Thread->NextProcessor?==?Prcb->Number);//確保是在那個(gè)cpu中等待調(diào)度

????if?(RemoveEntryList(&Thread->WaitListEntry))//取下來(lái)

????????Prcb->ReadySummary?^=?PRIORITY_MASK(HighPriority);//如果隊(duì)列變空了,修改對(duì)應(yīng)的標(biāo)志位

Quickie:

????return?Thread;

}

每當(dāng)一個(gè)非實(shí)時(shí)線程被切換出去,放棄cpu后,系統(tǒng)都會(huì)略微降低該線程的優(yōu)先級(jí),以免該線程總是占住cpu不放。下面的函數(shù)就是做這個(gè)目的。

SCHAR??KiComputeNewPriority(IN?PKTHREAD?Thread,//非實(shí)時(shí)線程

????????????????????????????IN?SCHAR?Adjustment)//‘調(diào)減量’

{

????SCHAR?Priority;

????Priority?=?Thread->Priority;//原優(yōu)先級(jí)

????if?(Priority?<?LOW_REALTIME_PRIORITY)//只對(duì)非實(shí)時(shí)性線程做調(diào)整

{

//先減去‘恢減量’(對(duì)應(yīng)于喚醒線程時(shí)系統(tǒng)臨時(shí)提高的優(yōu)先級(jí)量,現(xiàn)在要把它恢復(fù)回去)

????????Priority?-=?Thread->PriorityDecrement;?

????????//再減去‘調(diào)減量’,這才是真正的調(diào)整,上面只是恢復(fù)優(yōu)先級(jí)

????????Priority?-=?Adjustment;

????????if?(Priority?<?Thread->BasePriority)

?Priority?=?Thread->BasePriority;//優(yōu)先級(jí)不管怎么調(diào),不能低于基本優(yōu)先級(jí)

????????Thread->PriorityDecrement?=?0;

????}

????return?Priority;

}

下面的函數(shù)用來(lái)將現(xiàn)場(chǎng)加入指定cpu的相應(yīng)優(yōu)先級(jí)的就緒隊(duì)列

VOID??KxQueueReadyThread(IN?PKTHREAD?Thread,IN?PKPRCB?Prcb)

{

????BOOLEAN?Preempted;

????KPRIORITY?Priority;

????ASSERT(Prcb?==?KeGetCurrentPrcb());

????ASSERT(Thread->State?==?Running);

????ASSERT(Thread->NextProcessor?==?Prcb->Number);

????{

????????Thread->State?=?Ready;//有運(yùn)行態(tài)改為就緒態(tài)

????????Priority?=?Thread->Priority;

????????Preempted?=?Thread->Preempted;//表示是否是因?yàn)楸粨屨荚蚨尦龅腸pu

????????Thread->Preempted?=?FALSE;

????????Thread->WaitTime?=?KeTickCount.LowPart;//記錄上次被切換的時(shí)間

?????

???????//若是被搶占原因讓出的cpu,就把那個(gè)線程加入隊(duì)列的開頭,以平衡它的怒氣,否則加入尾部

???Preempted???InsertHeadList(&Prcb->DispatcherReadyListHead[Priority],

???????????????????????????????????&Thread->WaitListEntry)?:

????????????????????InsertTailList(&Prcb->DispatcherReadyListHead[Priority],

???????????????????????????????????&Thread->WaitListEntry);

????????Prcb->ReadySummary?|=?PRIORITY_MASK(Priority);//標(biāo)志相應(yīng)的就緒隊(duì)列不空

????????KiReleasePrcbLock(Prcb);

????}

}

前面說(shuō)的主動(dòng)切換。但主動(dòng)切換是非常少見的,一般都是不情愿的,被動(dòng)切換。典型的被動(dòng)切換情形是:

每觸發(fā)一次時(shí)鐘中斷(通常每10毫秒觸發(fā)一次),就會(huì)在時(shí)鐘中斷的isr中遞減當(dāng)前線程KTHREAD結(jié)構(gòu)中的Quantum字段(表示剩余時(shí)間片),當(dāng)減到0時(shí)(也即時(shí)間片耗盡時(shí)),會(huì)將KPCRB結(jié)構(gòu)中的QuantumEnd字段標(biāo)記為TRUE。同時(shí),當(dāng)cpu在每次掃描執(zhí)行完DPC隊(duì)列中的函數(shù)后,irql將降到DISPATCH_LEVEL以下,這時(shí)系統(tǒng)會(huì)檢查QuantumEnd字段,若發(fā)現(xiàn)時(shí)間片已經(jīng)用完(可能已經(jīng)用完很久了),就會(huì)調(diào)用下面的函數(shù)切換線程,這時(shí)切換線程的一種典型時(shí)機(jī)。

VOID?KiQuantumEnd()?//每次時(shí)間片自然到期后執(zhí)行這個(gè)函數(shù)

{

????PKPRCB?Prcb?=?KeGetCurrentPrcb();

????PKTHREAD?NextThread,?Thread?=?Prcb->CurrentThread;//當(dāng)前線程

????if?(InterlockedExchange(&Prcb->DpcSetEventRequest,?0))//檢查是否有‘觸發(fā)DPC事件’的請(qǐng)求

????????KeSetEvent(&Prcb->DpcEvent,?0,?0);

????KeRaiseIrqlToSynchLevel();//提升到SynchLevel,準(zhǔn)備調(diào)度、切換

????KiAcquireThreadLock(Thread);

????KiAcquirePrcbLock(Prcb);

????if?(Thread->Quantum?<=?0)//確認(rèn)該線程的時(shí)間片已到期

????{

????????if?((Thread->Priority?>=?LOW_REALTIME_PRIORITY)?&&

????????????????????????????????(Thread->ApcState.Process->DisableQuantum))

????????{

????????????Thread->Quantum?=?MAX_QUANTUM;//實(shí)時(shí)線程可以禁用時(shí)間片機(jī)制

????????}

????????else

????????{

????????????Thread->Quantum?=?Thread->QuantumReset;//設(shè)置下次調(diào)度時(shí)的時(shí)間片

????????????Thread->Priority?=?KiComputeNewPriority(Thread,1);//降低一個(gè)優(yōu)先級(jí)(以免占住cpu)

????????????if?(Prcb->NextThread?!=?NULL)

????????????{

????????????????NextThread?=?Prcb->NextThread//直接使用這個(gè)候選的線程

????????????????Thread->Preempted?=?FALSE;//因?yàn)槭菚r(shí)間片到期發(fā)生的切換,所以不是被搶占

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

????????????else

????????????{?

??NextThread?=?KiSelectReadyThread(Thread->Priority,?Prcb);//調(diào)度出一個(gè)線程

//表示這個(gè)線程已被選中處于候選搶占狀態(tài),將立馬上架投入運(yùn)行

????????????????NextThread->State?=?Standby;?

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

????????}

????}

????KiReleaseThreadLock(Thread);

KiSetThreadSwapBusy(Thread);//標(biāo)記當(dāng)前線程正在被切換

????Prcb->CurrentThread?=?NextThread;//標(biāo)記為切換到下一個(gè)線程了

????Prcb->NextThread?=?NULL;//初始運(yùn)行時(shí)沒(méi)有搶占者線程

????NextThread->State?=?Running;//已在運(yùn)行了

????Thread->WaitReason?=?WrQuantumEnd;//標(biāo)記上次被切換的原因是時(shí)間片到期

????KxQueueReadyThread(Thread,?Prcb);//當(dāng)前線程轉(zhuǎn)入就緒隊(duì)列

????Thread->WaitIrql?=?APC_LEVEL;//?這將導(dǎo)致下次切換回來(lái)時(shí)會(huì)自動(dòng)發(fā)出apc中斷

KiSwapContext(Thread,?NextThread);//正式切換到新線程

---------------------------華麗的分割線---------------------------------------

????KeLowerIrql(DISPATCH_LEVEL);

}

除了時(shí)間片自然到期,線程被切換外,線程還可以在運(yùn)行的過(guò)程中被其他高優(yōu)先級(jí)線程,強(qiáng)制搶占而切換。

如一個(gè)線程調(diào)用ResumeThread將別的線程恢復(fù)調(diào)度時(shí),自己會(huì)檢查那個(gè)剛被恢復(fù)成就緒態(tài)的線程是否因優(yōu)先級(jí)高于自己而要搶占本線程,如果是,就會(huì)切換到那個(gè)線程。因此這個(gè)api內(nèi)部有切換線程的可能

ULONG??KeResumeThread(IN?PKTHREAD?Thread)?//恢復(fù)指定目標(biāo)線程

{

????KLOCK_QUEUE_HANDLE?ApcLock;

????ULONG?PreviousCount;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);//當(dāng)前irql一定<=DISPATCH_LEVEL

????KiAcquireApcLock(Thread,?&ApcLock);//鎖定apc隊(duì)列,同時(shí)提升irql到DISPATCH_LEVEL

????PreviousCount?=?Thread->SuspendCount;

????if?(PreviousCount)

????{

????????Thread->SuspendCount--;//遞減掛起計(jì)數(shù)

//若掛起計(jì)數(shù)減到0,喚醒目標(biāo)線程,進(jìn)入就緒隊(duì)列或者變成搶占者線程

????????if?((!Thread->SuspendCount)?&&?(!Thread->FreezeCount))?

????????{

????????????KiAcquireDispatcherLockAtDpcLevel();

????????????Thread->SuspendSemaphore.Header.SignalState++;

????????????KiWaitTest(&Thread->SuspendSemaphore.Header,?IO_NO_INCREMENT);//嘗試喚醒它

????????????KiReleaseDispatcherLockFromDpcLevel();

????????}

????}

KiReleaseApcLockFromDpcLevel(&ApcLock);//注意這個(gè)函數(shù)只釋放apc隊(duì)列鎖,不降低irql

//關(guān)鍵函數(shù)。降低當(dāng)前線程的irql,同時(shí)先檢查是否有搶占者線程,若有,先執(zhí)行搶占切換。

????KiExitDispatcher(ApcLock.OldIrql);?

????return?PreviousCount;//返回之前的掛起計(jì)數(shù)

}

//下面這個(gè)函數(shù)的主功能是降回當(dāng)前線程的irql到指定OldIrql。不過(guò)在正式的降低前,會(huì)先檢查是否發(fā)生了搶占,若有,就先執(zhí)行線程切換,等下次切換回來(lái)后再降低當(dāng)前線程的irql。

//這個(gè)函數(shù)經(jīng)常在系統(tǒng)中的其它線程的運(yùn)行狀態(tài)一改變后,就主動(dòng)調(diào)用。其目的是檢測(cè)是否為此而發(fā)生了可能的搶占現(xiàn)象,若已發(fā)生,就立即進(jìn)行搶占式切換。比如,改變了某其它線程的優(yōu)先級(jí),喚醒了某其他的線程,掛起恢復(fù)了某其他線程,給某線程掛入了一個(gè)APC等等操作后,都會(huì)調(diào)用,以嘗試立即切換。

VOID??FASTCALL?//注意,這個(gè)函數(shù)只能在DISPATCH_LEVEL及其以上irql級(jí)別調(diào)用

KiExitDispatcher(IN?KIRQL?OldIrql)?//降低irql,檢測(cè)是否有搶占

{

????PKPRCB?Prcb?=?KeGetCurrentPrcb();

????PKTHREAD?Thread,?NextThread;

????BOOLEAN?PendingApc;

????ASSERT(KeGetCurrentIrql()?>=?DISPATCH_LEVEL);?//確保

????KiCheckDeferredReadyList(Prcb);

????if?(OldIrql?>=?DISPATCH_LEVEL)//如果要降回的irql不在DISPATCH_LEVEL以下,那就不能切換

????{

????????if?((Prcb->NextThread)?&&?!(Prcb->DpcRoutineActive))

????????????HalRequestSoftwareInterrupt(DISPATCH_LEVEL);

????????goto?Quickie;

????}

if?(!Prcb->NextThread)//如果沒(méi)有搶占者線程,那很好,直接降低irql就是

?goto?Quickie;

????//若發(fā)現(xiàn)有搶占發(fā)生,下面將執(zhí)行搶占切換

????KiAcquirePrcbLock(Prcb);

????NextThread?=?Prcb->NextThread;

????Thread?=?Prcb->CurrentThread;

KiSetThreadSwapBusy(Thread);

????Prcb->CurrentThread?=?NextThread;

????Prcb->NextThread?=?NULL;

????NextThread->State?=?Running;

????KxQueueReadyThread(Thread,?Prcb);

????Thread->WaitIrql?=?OldIrql;//可以肯定:OldIrql=APC_LEVEL或PASSIVE_LEVEL,并且:如果原irql是在AP_LEVEL的話,KiSwapContext內(nèi)部會(huì)在返回前發(fā)出apc中斷

PendingApc?=?KiSwapContext(Thread,?NextThread);

-------------------------------------華麗的分割線---------------------------------------

?//如果切回來(lái)后發(fā)現(xiàn)阻塞有內(nèi)核apc,需要手動(dòng)掃描執(zhí)行apc(可以肯定原irql不是APC_LEVEL)???

if?(PendingApc)?

{

????????ASSERT(OldIrql?==?PASSIVE_LEVEL);//可以肯定原來(lái)是PASSIVE_LEVEL級(jí)

????????KeLowerIrql(APC_LEVEL);//當(dāng)然要先降到APC級(jí)別去

????????KiDeliverApc(KernelMode,?NULL,?NULL);//切換回來(lái)后,自己手動(dòng)掃描執(zhí)行內(nèi)核apc

????}

Quickie:

????KeLowerIrql(OldIrql);//本函數(shù)真正的工作:降低到指定irql

}

//如上,上面的函數(shù)在降低irql前,先嘗試檢測(cè)是否發(fā)生了搶占式切換。若有,立即切換。

否則,降低irql。注意降低irql到DISPATCH_LEVEL下以后,也可能會(huì)因?yàn)橹皶r(shí)間片早已到期,但是在DISPATCH_LEVEL以上遲遲沒(méi)有得到切換,現(xiàn)在降到下面了就會(huì)引發(fā)線程切換(遲來(lái)的切換!)

當(dāng)一個(gè)線程被喚醒時(shí)(如isr中將某線程喚醒),往往會(huì)提高其優(yōu)先級(jí),導(dǎo)致發(fā)生搶占。一旦發(fā)現(xiàn)某個(gè)線程的優(yōu)先級(jí)高于當(dāng)前線程的優(yōu)先級(jí)(并且也高于上一個(gè)候選的搶占者線程的優(yōu)先級(jí)),系統(tǒng)就會(huì)把這個(gè)線程作為新的候選搶占者線程記錄到KPCRB結(jié)構(gòu)的NextThread字段中。這樣,只要時(shí)機(jī)一成熟嗎,就會(huì)發(fā)生搶占式切換。

下面的函數(shù)用來(lái)喚醒一個(gè)線程

VOID??FASTCALL

KiUnwaitThread(IN?PKTHREAD?Thread,

???????????????IN?LONG_PTR?WaitStatus,

???????????????IN?KPRIORITY?Increment)//略微提高的優(yōu)先級(jí)量(以便目標(biāo)線程盡快得到調(diào)度)

{

????KiUnlinkThread(Thread,?WaitStatus);//從所有等待對(duì)象的線程鏈表中脫鏈

????Thread->AdjustIncrement?=?(SCHAR)Increment;//要調(diào)整的優(yōu)先級(jí)量

????Thread->AdjustReason?=?AdjustUnwait;//跳轉(zhuǎn)原因?yàn)閱拘?/p>

????KiReadyThread(Thread);//關(guān)鍵函數(shù)。將線程轉(zhuǎn)為就緒態(tài)

}

下面的函數(shù)用來(lái)將一個(gè)線程轉(zhuǎn)為就緒態(tài)

VOID??KiReadyThread(IN?PKTHREAD?Thread)

{

????IN?PKPROCESS?Process?=?Thread->ApcState.Process;

????if?(Process->State?!=?ProcessInMemory)

????????ASSERT(FALSE);//藍(lán)屏

????else?if?(!Thread->KernelStackResident)//如果該線程的內(nèi)核棧被置換到外存了

????{

????????ASSERT(Process->StackCount?!=?MAXULONG_PTR);

????????Process->StackCount++;

????????ASSERT(Thread->State?!=?Transition);

????????Thread->State?=?Transition;

????????ASSERT(FALSE);//藍(lán)屏

????}

????else

????????KiInsertDeferredReadyList(Thread);//實(shí)質(zhì)函數(shù)

}

VOID?KiInsertDeferredReadyList(IN?PKTHREAD?Thread)

{

????Thread->State?=?DeferredReady;//將進(jìn)入就緒態(tài)

????Thread->DeferredProcessor?=?0;//0號(hào)cpu

????KiDeferredReadyThread(Thread);//實(shí)質(zhì)函數(shù),就緒化指定線程

}

//下面的函數(shù)將指定線程轉(zhuǎn)換為‘就緒態(tài)’或者‘搶占態(tài)’

//也可理解為‘就緒化’某個(gè)線程,但特殊處理?yè)屨记樾?#xff08;搶占態(tài)是一種特殊的就緒態(tài))

VOID?FASTCALL??KiDeferredReadyThread(IN?PKTHREAD?Thread)

{

PKPRCB?Prcb;

BOOLEAN?Preempted;

ULONG?Processor?=?0;//一律掛入0號(hào)cpu的就緒隊(duì)列

KPRIORITY?OldPriority;//目標(biāo)線程的當(dāng)前優(yōu)先級(jí)

????PKTHREAD?NextThread;

????if?(Thread->AdjustReason?==?AdjustBoost)?//if是線程首次啟動(dòng)時(shí)的調(diào)整優(yōu)先級(jí)?。。。

????else?if?(Thread->AdjustReason?==?AdjustUnwait)?//if是喚醒時(shí)調(diào)整的優(yōu)先級(jí)?。。。

????Preempted?=?Thread->Preempted;

????OldPriority?=?Thread->Priority;

????Thread->Preempted?=?FALSE;

????Thread->NextProcessor?=?0;

????Prcb?=?KiProcessorBlock[0];

????KiAcquirePrcbLock(Prcb);

????if?(KiIdleSummary)//如果0號(hào)cpu運(yùn)行著空轉(zhuǎn)線程,目標(biāo)線程的優(yōu)先級(jí)肯定高于那個(gè)空轉(zhuǎn)線程

????{

????????KiIdleSummary?=?0;

????????Thread->State?=?Standby;//將目標(biāo)程序改為‘搶占態(tài)’

????????Prcb->NextThread?=?Thread;//指向自己

????????KiReleasePrcbLock(Prcb);

????????return;

????}

????Thread->NextProcessor?=?(UCHAR)Processor;//0

????NextThread?=?Prcb->NextThread;//獲得0號(hào)cpu上的原搶占者線程

????if?(NextThread)//如果原來(lái)已有一個(gè)搶占者線程

????{

????????ASSERT(NextThread->State?==?Standby);//可以確定那個(gè)線程處于搶占態(tài)

????????if?(OldPriority?>?NextThread->Priority)//若高于原‘搶占者線程’的優(yōu)先級(jí)?

????????{

????????????NextThread->Preempted?=?TRUE;//標(biāo)志那個(gè)搶占者線程又被目標(biāo)線程搶占了

????????????Prcb->NextThread?=?Thread;//更改新的搶占者線程,時(shí)機(jī)一成熟就搶占

????????????Thread->State?=?Standby;//更為搶占態(tài)

????????????NextThread->State?=?DeferredReady;//原搶占者線程進(jìn)入將就緒態(tài)

????????????NextThread->DeferredProcessor?=?Prcb->Number;//0

????????????KiReleasePrcbLock(Prcb);

????????????KiDeferredReadyThread(NextThread);//原搶占者線程轉(zhuǎn)入0號(hào)cpu就緒隊(duì)列

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

????????}

????}

????else//如果原來(lái)沒(méi)有搶占者線程(最典型的情況)

????{

????????NextThread?=?Prcb->CurrentThread;

????????if?(OldPriority?>?NextThread->Priority)//如果優(yōu)先級(jí)高于當(dāng)前運(yùn)行的那個(gè)線程

????????{

????????????if?(NextThread->State?==?Running)

?NextThread->Preempted?=?TRUE;//標(biāo)記已被搶占

????????????Prcb->NextThread?=?Thread;?//指定搶占者線程,時(shí)機(jī)一成熟就搶占

????????????Thread->State?=?Standby;//標(biāo)記目標(biāo)線程處于搶占態(tài)了

????????????KiReleasePrcbLock(Prcb);

????????????if?(KeGetCurrentProcessorNumber()?!=?0)

???????????????KiIpiSend(AFFINITY_MASK(Thread->NextProcessor),?IPI_DPC);//給0號(hào)cpu發(fā)一個(gè)通知

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

????????}

}

//如果目標(biāo)線程的優(yōu)先級(jí)低于當(dāng)前的搶占者線程,也低于當(dāng)前運(yùn)行中的線程

????Thread->State?=?Ready;//更為就緒態(tài)

????Thread->WaitTime?=?KeTickCount.LowPart;//記錄上次被切換的時(shí)間

????//如果目標(biāo)線程上次是因?yàn)楸粨屨级谐龅腸pu,現(xiàn)在就掛入隊(duì)頭(平衡怒氣)

????Preempted???InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority],

???????????????????????????????&Thread->WaitListEntry)?:

????????????????InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority],

???????????????????????????????&Thread->WaitListEntry);

????Prcb->ReadySummary?|=?PRIORITY_MASK(OldPriority);//更改相應(yīng)就緒隊(duì)列的標(biāo)志

????KiReleasePrcbLock(Prcb);

}

如上,上面這個(gè)函數(shù)用于將線程掛入0號(hào)cpu的就緒隊(duì)列或者置為搶占者線程。

四、進(jìn)程、線程的優(yōu)先級(jí)

線程的調(diào)度策略是嚴(yán)格按優(yōu)先級(jí)的,因此,優(yōu)先級(jí),不妨叫做‘調(diào)度優(yōu)先級(jí)’。那么優(yōu)先級(jí)是啥,是怎么確定的呢?

先要弄清幾個(gè)概念:

進(jìn)程的優(yōu)先級(jí)類:每種優(yōu)先級(jí)類對(duì)應(yīng)一種基本優(yōu)先級(jí)

進(jìn)程的基本優(yōu)先級(jí):為各個(gè)線程的默認(rèn)基本優(yōu)先級(jí)

線程的基本優(yōu)先級(jí):每個(gè)線程剛創(chuàng)建時(shí)的基本優(yōu)先級(jí)繼承它所屬進(jìn)程的基本優(yōu)先級(jí),但可以人為調(diào)整

線程的當(dāng)前優(yōu)先級(jí):又叫時(shí)機(jī)優(yōu)先級(jí)。當(dāng)前優(yōu)先級(jí)可以浮動(dòng),但永遠(yuǎn)不會(huì)降到該線程的基本優(yōu)先級(jí)下面

系統(tǒng)調(diào)度線程時(shí),是以線程的當(dāng)前優(yōu)先級(jí)為準(zhǔn)的,它才不管你的基本優(yōu)先級(jí)是什么,你所屬的進(jìn)程的基本優(yōu)先級(jí)又是什么,它只看你的當(dāng)前優(yōu)先級(jí)。

進(jìn)程基本優(yōu)先級(jí)與線程基本優(yōu)先級(jí)是一種水漲船高的關(guān)系。進(jìn)程的基本優(yōu)先級(jí)變高了,那么它里面的各個(gè)線程的基本優(yōu)先級(jí)也會(huì)跟著升高對(duì)應(yīng)的幅度。各個(gè)線程初始創(chuàng)建時(shí)的基本優(yōu)先級(jí)等于其進(jìn)程的基本優(yōu)先級(jí)

線程的基本優(yōu)先級(jí)與線程的當(dāng)前優(yōu)先級(jí)也是一種水漲船高的關(guān)系。線程的基本優(yōu)先級(jí)升高了,那么線程的當(dāng)前優(yōu)先級(jí)也會(huì)跟著升高對(duì)應(yīng)的幅度。另外:線程的當(dāng)前優(yōu)先級(jí)可以隨時(shí)變化(比如每次一讓出cpu時(shí)就略微降低那么一點(diǎn)點(diǎn)優(yōu)先級(jí)),但是永遠(yuǎn)不會(huì)降到其基本優(yōu)先級(jí)以下。基本優(yōu)先級(jí)就是它的最低保障!

綜上,可理解為:線程基本優(yōu)先級(jí)相對(duì)于進(jìn)程的基本優(yōu)先級(jí),線程的當(dāng)前優(yōu)先級(jí)相對(duì)于線程的基本優(yōu)先級(jí)

線程1的當(dāng)前優(yōu)先級(jí)???????????????????線程2的當(dāng)前優(yōu)先級(jí)??????????????????線程3的當(dāng)前優(yōu)先級(jí)

線程1的基本優(yōu)先級(jí)???????????????????線程2的基本優(yōu)先級(jí)??????????????????線程3的基本優(yōu)先級(jí)

????????????????????????????????????進(jìn)程的基本優(yōu)先級(jí)

------------------------------------------------------------------------------------------

系統(tǒng)中總共分32個(gè)優(yōu)先級(jí):0到31,其中又分為兩段。0到15的是非實(shí)時(shí)優(yōu)先級(jí),16-31的表示實(shí)時(shí)優(yōu)先級(jí)。

#define?LOW_PRIORITY?0

#define?LOW_RELATIVE_PRIORITY??15?//最低的實(shí)時(shí)優(yōu)先級(jí)

#define?HIGH_PRIORITY?31//最高的實(shí)時(shí)優(yōu)先級(jí),也是整個(gè)系統(tǒng)最高的優(yōu)先級(jí)

SetPriorityClass這個(gè)Win32?API改變的就是一個(gè)進(jìn)程的優(yōu)先級(jí)類,而一種優(yōu)先級(jí)類對(duì)應(yīng)一種基本優(yōu)先級(jí),所以這個(gè)函數(shù)實(shí)際上改變的是進(jìn)程的基本優(yōu)先級(jí)。實(shí)際上最終調(diào)用到下面的函數(shù)

KPRIORITY

KeSetPriorityAndQuantumProcess(IN?PKPROCESS?Process,

???????????????????????????????IN?KPRIORITY?Priority,//新的基本優(yōu)先級(jí)

???????????????????????????????IN?UCHAR?Quantum?OPTIONAL)//新的時(shí)間片

{

????KLOCK_QUEUE_HANDLE?ProcessLock;

????KPRIORITY?Delta;

????PLIST_ENTRY?NextEntry,?ListHead;

????KPRIORITY?NewPriority,?OldPriority;

????PKTHREAD?Thread;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

????if?(Process->BasePriority?==?Priority)?return?Process->BasePriority;

????if?(Priority==0)?Priority?=?1;//只有空轉(zhuǎn)線程的優(yōu)先級(jí)才能是0

????KiAcquireProcessLock(Process,?&ProcessLock);//獲得自旋鎖,同時(shí)提升irql到DISPATCH_LEVEL

if?(Quantum)

?Process->QuantumReset?=?Quantum;//修改進(jìn)程的時(shí)間片(也即里面各個(gè)線程的時(shí)間片)

????OldPriority?=?Process->BasePriority;

????Process->BasePriority?=?(SCHAR)Priority;//修改為新的基本優(yōu)先級(jí)

????Delta?=?Priority?-?OldPriority;//計(jì)算提升幅度(注意Delta可以是負(fù)數(shù))

????ListHead?=?&Process->ThreadListHead;

????NextEntry?=?ListHead->Flink;

????if?(Priority?>=?LOW_REALTIME_PRIORITY)//如果將基本優(yōu)先級(jí)提到了實(shí)時(shí)級(jí)別

????{

????????while?(NextEntry?!=?ListHead)//遍歷該進(jìn)程中的每個(gè)線程

????????{

????????????Thread?=?CONTAINING_RECORD(NextEntry,?KTHREAD,?ThreadListEntry);

????????????if?(Quantum)?Thread->QuantumReset?=?Quantum;//同時(shí)設(shè)置線程的時(shí)間片

????????????KiAcquireThreadLock(Thread);

????????????NewPriority?=?Thread->BasePriority?+?Delta;//水漲船高

????????????if?(NewPriority?<?LOW_REALTIME_PRIORITY)

????????????????NewPriority?=?LOW_REALTIME_PRIORITY;//?實(shí)時(shí)優(yōu)先級(jí)的最小值

????????????else?if?(NewPriority?>?HIGH_PRIORITY)

??

????

????????????????NewPriority?=?HIGH_PRIORITY;//?實(shí)時(shí)優(yōu)先級(jí)的最大值

????????????if?(!(Thread->Saturation)?||?(OldPriority?<?LOW_REALTIME_PRIORITY))

????????????{

????????????????Thread->BasePriority?=?(SCHAR)NewPriority;?//水漲船高

????????????????Thread->Quantum?=?Thread->QuantumReset;//當(dāng)前剩余時(shí)間片=初始時(shí)間片

????????????????Thread->PriorityDecrement?=?0;

????????????????KiSetPriorityThread(Thread,?NewPriority);//提高線程優(yōu)先級(jí)要做的附加工作

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

????????????KiReleaseThreadLock(Thread);

????????????NextEntry?=?NextEntry->Flink;//下一個(gè)線程

????????}

????}

????else//如果將基本優(yōu)先級(jí)提到了非實(shí)時(shí)級(jí)別

????{

????????while?(NextEntry?!=?ListHead)

????????{

????????????Thread?=?CONTAINING_RECORD(NextEntry,?KTHREAD,?ThreadListEntry);

????????????if?(Quantum)?Thread->QuantumReset?=?Quantum;

????????????KiAcquireThreadLock(Thread);

????????????NewPriority?=?Thread->BasePriority?+?Delta;

????????????if?(NewPriority?>=?LOW_REALTIME_PRIORITY)

????????????????NewPriority?=?LOW_REALTIME_PRIORITY?-?1;//非實(shí)時(shí)優(yōu)先級(jí)的最大值

????????????else?if?(NewPriority?<=?LOW_PRIORITY)

????????????????NewPriority?=?1;//非實(shí)時(shí)優(yōu)先級(jí)的最小值

????????????if?(!(Thread->Saturation)?||?(OldPriority?>=?LOW_REALTIME_PRIORITY))

????????????{

????????????????Thread->BasePriority?=?(SCHAR)NewPriority;//水漲船高

????????????????Thread->Quantum?=?Thread->QuantumReset;//當(dāng)前剩余時(shí)間片=初始的時(shí)間片

????????????????Thread->PriorityDecrement?=?0;

????????????????KiSetPriorityThread(Thread,?NewPriority);?//提高線程優(yōu)先級(jí)要做的附加工作

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

????????????KiReleaseThreadLock(Thread);

????????????NextEntry?=?NextEntry->Flink;//下一個(gè)線程

????????}

????}

????KiReleaseDispatcherLockFromDpcLevel();

KiReleaseProcessLockFromDpcLevel(&ProcessLock);

//降低到原irql,同時(shí)先檢查是否發(fā)生了搶占式切換(因?yàn)轱@式改變了線程的優(yōu)先級(jí),有可能讓其他線程的優(yōu)先級(jí)突然高于了當(dāng)前線程而要發(fā)生搶占現(xiàn)象,所以要檢測(cè)這種情況)

????KiExitDispatcher(ProcessLock.OldIrql);?

????return?OldPriority;

}

線程的基本優(yōu)先級(jí)一變了,它的當(dāng)前優(yōu)先級(jí)就會(huì)跟著變,線程的當(dāng)前優(yōu)先級(jí)一變了,那么就會(huì)有很多的附加工作要做,下面的函數(shù)就用來(lái)做這個(gè)工作(如改變就緒隊(duì)列、置為搶占者等)。

VOID??FASTCALL??//設(shè)置線程的當(dāng)前優(yōu)先級(jí)

KiSetPriorityThread(IN?PKTHREAD?Thread,

????????????????????IN?KPRIORITY?Priority)//新的當(dāng)前優(yōu)先級(jí)

{

????PKPRCB?Prcb;

????ULONG?Processor;

????BOOLEAN?RequestInterrupt?=?FALSE;

????KPRIORITY?OldPriority;

????PKTHREAD?NewThread;

????if?(Thread->Priority?!=?Priority)//if?優(yōu)先級(jí)變了

????{

????????for?(;;)

????????{

????????????if?(Thread->State?==?Ready)//如果目標(biāo)線程處于就緒態(tài)

????????????{

????????????????if?(!Thread->ProcessReadyQueue)//其實(shí)一般都會(huì)滿足這個(gè)條件

????????????????{

????????????????????Processor?=?Thread->NextProcessor;

????????????????????Prcb?=?KiProcessorBlock[Processor];

????????????????????KiAcquirePrcbLock(Prcb);

????????????????????//如果現(xiàn)在仍處于就緒態(tài),并且仍在那個(gè)cpu上等待

????????????????????if?((Thread->State?==?Ready)?&&?(Thread->NextProcessor?==?Prcb->Number))

????????????????????{

????????????????????????if?(RemoveEntryList(&Thread->WaitListEntry))//從原就緒隊(duì)列摘下

????????????????????????????Prcb->ReadySummary?^=?PRIORITY_MASK(Thread->Priority);

????????????????????????Thread->Priority?=?(SCHAR)Priority;//=更為新的優(yōu)先級(jí)

????????????????????????KiInsertDeferredReadyList(Thread);//掛入新的就緒隊(duì)列(或置為搶占態(tài))

????????????????????????KiReleasePrcbLock(Prcb);

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

????????????????????Else?…

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

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

????????????else?if?(Thread->State?==?Standby)?//如果目標(biāo)線程處于搶占態(tài)

????????????{

????????????????Processor?=?Thread->NextProcessor;

????????????????Prcb?=?KiProcessorBlock[Processor];

????????????????KiAcquirePrcbLock(Prcb);

????????????????if?(Thread?==?Prcb->NextThread)//如果仍處于搶占態(tài)

????????????????{

????????????????????OldPriority?=?Thread->Priority;

????????????????????Thread->Priority?=?(SCHAR)Priority;//更改優(yōu)先級(jí)

????????????????????if?(Priority?<?OldPriority)//如果優(yōu)先級(jí)降了(可能不再成為搶占者線程了)

????????????????????{

????????????????????????NewThread?=?KiSelectReadyThread(Priority?+?1,?Prcb);

????????????????????????if?(NewThread)//如果選出了一個(gè)比現(xiàn)在的優(yōu)先級(jí)更高的線程

????????????????????????{

????????????????????????????NewThread->State?=?Standby;

????????????????????????????Prcb->NextThread?=?NewThread;//更為新的搶占者線程

????????????????????????????KiInsertDeferredReadyList(Thread);//原搶占線程則轉(zhuǎn)入就緒隊(duì)列

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

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

????????????????????KiReleasePrcbLock(Prcb);

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

????????????????Else?…

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

????????????else?if?(Thread->State?==?Running)?//如果目標(biāo)線程正在運(yùn)行

????????????{

????????????????Processor?=?Thread->NextProcessor;

????????????????Prcb?=?KiProcessorBlock[Processor];

????????????????KiAcquirePrcbLock(Prcb);

????????????????if?(Thread?==?Prcb->CurrentThread)//如果仍在運(yùn)行

????????????????{

????????????????????OldPriority?=?Thread->Priority;

????????????????????Thread->Priority?=?(SCHAR)Priority;//更改優(yōu)先級(jí)

????????????????????if?((Priority?<?OldPriority)?&&?!(Prcb->NextThread))//可能會(huì)出現(xiàn)搶占

????????????????????{

????????????????????????NewThread?=?KiSelectReadyThread(Priority?+?1,?Prcb);

????????????????????????if?(NewThread)//?如果選出了一個(gè)比現(xiàn)在的優(yōu)先級(jí)更高的線程

????????????????????????{

????????????????????????????NewThread->State?=?Standby;

????????????????????????????Prcb->NextThread?=?NewThread;//出現(xiàn)了新的搶占線程

????????????????????????????RequestInterrupt?=?TRUE;//需要立即中斷

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

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

????????????????????KiReleasePrcbLock(Prcb);

????????????????????if?(RequestInterrupt)

????????????????????{

????????????????????????//通知目標(biāo)cpu進(jìn)行搶占切換

????????????????????????if?(KeGetCurrentProcessorNumber()?!=?Processor)

????????????????????????????KiIpiSend(AFFINITY_MASK(Processor),?IPI_DPC);

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

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

????????????????Else?…

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

????????????Else?…

????????????break;

????????}

????}

}

如上,這個(gè)函數(shù)改變目標(biāo)線程的優(yōu)先級(jí)為指定優(yōu)先級(jí),并根據(jù)目標(biāo)線程的當(dāng)前所處狀態(tài),最對(duì)應(yīng)的就緒隊(duì)列、搶占者線程調(diào)整。可見,強(qiáng)行改變某個(gè)線程的當(dāng)前優(yōu)先級(jí)并不是件簡(jiǎn)單的工作,需要全盤綜合考慮各方面因素,做出相應(yīng)的調(diào)整。

下面的函數(shù)是一個(gè)小型的封裝函數(shù):(他還會(huì)還原時(shí)間片)

KPRIORITY

KeSetPriorityThread(IN?PKTHREAD?Thread,

????????????????????IN?KPRIORITY?Priority)

{

????KIRQL?OldIrql;

????KPRIORITY?OldPriority;

????OldIrql?=?KiAcquireDispatcherLock();

????KiAcquireThreadLock(Thread);

????OldPriority?=?Thread->Priority;

????Thread->PriorityDecrement?=?0;

????if?(Priority?!=?Thread->Priority)//if?優(yōu)先級(jí)變了

????{

????????Thread->Quantum?=?Thread->QuantumReset;//關(guān)鍵。還原時(shí)間片

????????KiSetPriorityThread(Thread,?Priority);//再做真正的修改工作

????}

????KiReleaseThreadLock(Thread);

????KiReleaseDispatcherLock(OldIrql);

????return?OldPriority;

}

除了修改進(jìn)程的基本優(yōu)先級(jí)會(huì)影響到里面每個(gè)線程的基本優(yōu)先級(jí)和當(dāng)前優(yōu)先級(jí)外,也可以用下面的函數(shù)直接修改線程的基本優(yōu)先級(jí)和當(dāng)前優(yōu)先級(jí)。

NTSTATUS

NtSetInformationThread(IN?HANDLE?ThreadHandle,

???????????????????????IN?THREADINFOCLASS?ThreadInformationClass,

???????????????????????IN?PVOID?ThreadInformation,

???????????????????????IN?ULONG?ThreadInformationLength)

{

????…

????switch?(ThreadInformationClass)

????{

????????case?ThreadPriority://設(shè)置當(dāng)前優(yōu)先級(jí)

????????????Priority?=?*(PLONG)ThreadInformation;//這個(gè)值是相對(duì)于進(jìn)程基本優(yōu)先級(jí)的差值

????????????KeSetPriorityThread(&Thread->Tcb,?Priority);

????????????break;

????????case?ThreadBasePriority://設(shè)置基本優(yōu)先級(jí)

????????????Priority?=?*(PLONG)ThreadInformation;

????????????KeSetBasePriorityThread(&Thread->Tcb,?Priority);

????????????break;

????????case?…

????}//end?switch

}//end?func

線程的基本優(yōu)先級(jí)(非當(dāng)前優(yōu)先級(jí))可以用下面的函數(shù)設(shè)置:

LONG

KeSetBasePriorityThread(IN?PKTHREAD?Thread,

????????????????????????IN?LONG?Increment)//這個(gè)是相對(duì)于進(jìn)程基本優(yōu)先級(jí)的差值

{

????KIRQL?OldIrql;

????KPRIORITY?OldBasePriority,?Priority,?BasePriority;

????LONG?OldIncrement;

????PKPROCESS?Process;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

????Process?=?Thread->ApcState.Process;

????OldIrql?=?KiAcquireDispatcherLock();

????KiAcquireThreadLock(Thread);

????OldBasePriority?=?Thread->BasePriority;

????OldIncrement?=?OldBasePriority?-?Process->BasePriority;

if?(Thread->Saturation)?//如果是個(gè)飽和增量

?OldIncrement?=?16?*?Thread->Saturation;//16或-16

????Thread->Saturation?=?0;

????if?(abs(Increment)?>=?16)?//飽和增量

????????Thread->Saturation?=?(Increment?>?0)???1?:?-1;

????BasePriority?=?Process->BasePriority?+?Increment;//算得現(xiàn)在的基本優(yōu)先級(jí)

????if?(Process->BasePriority?>=?LOW_REALTIME_PRIORITY)

????{

????????Priority?=?BasePriority;//實(shí)時(shí)線程例外,當(dāng)前優(yōu)先級(jí)=基本優(yōu)先級(jí)

????}

????else

????{

?????????Priority?=?KiComputeNewPriority(Thread,?0);//其實(shí)就是當(dāng)前優(yōu)先級(jí)

//看到?jīng)],線程的基本優(yōu)先級(jí)一升高,它的當(dāng)前優(yōu)先級(jí)跟著升高對(duì)應(yīng)的幅度

?????????Priority?+=?(BasePriority?-?OldBasePriority);?

????}

????Thread->BasePriority?=?(SCHAR)BasePriority;//更改線程的基本優(yōu)先級(jí)

????Thread->PriorityDecrement?=?0;

????if?(Priority?!=?Thread->Priority)//如果當(dāng)前優(yōu)先級(jí)變了,做相關(guān)的附加工作

????{

????????Thread->Quantum?=?Thread->QuantumReset;

????????KiSetPriorityThread(Thread,?Priority);

????}

????KiReleaseThreadLock(Thread);

????KiReleaseDispatcherLock(OldIrql);

????return?OldIncrement;

}

五、線程局部存儲(chǔ):TLS

----對(duì)TLS這個(gè)概念陌生的朋友請(qǐng)先自己查閱相關(guān)資料。

TLS分為兩種方法:靜態(tài)tls、動(dòng)態(tài)tls。兩種方法都可以達(dá)到tls的目的。

靜態(tài)tls:

在編寫程序時(shí):只需在要聲明為tls的全局變量前加上__declspec(thread)關(guān)鍵字即可。如:

__declspec(thread)?int?g_a?=?1;

__declspec(thread)?int?g_b;

__declspec(thread)?int?g_c?=?0;

__declspec(thread)?int?g_d;

編譯器在遇到這樣的變量時(shí),自然會(huì)將這種變量當(dāng)做tls變量看待,編譯鏈接存放到pe文件的.tls節(jié)中,

Exe文件中可使用靜態(tài)tls,動(dòng)態(tài)庫(kù)文件中使用靜態(tài)tls則會(huì)有很大的缺點(diǎn),所以動(dòng)態(tài)庫(kù)文件中一般都使用動(dòng)態(tài)tls來(lái)達(dá)到tls的目的。為此,Windows專門提供了一組api和相關(guān)基礎(chǔ)設(shè)施來(lái)實(shí)現(xiàn)動(dòng)態(tài)tls。

DWORD?TlsAlloc():為當(dāng)前線程分配一個(gè)tls槽。返回本線程分得的槽號(hào)

BOOL?TlsSetValue(DWORD?idx,void*?val):寫數(shù)據(jù)到指定槽中

VOID*?TlsGetValue(DWORD?idx?):從指定槽中讀數(shù)據(jù)

BOOL?TlsFree(DWORD?idx);//釋放這個(gè)槽給進(jìn)程,使得其他線程可以分得這個(gè)槽

相關(guān)的結(jié)構(gòu):

Struct?PEB

{

???…

???RTL_BITMAP*??TlsBitmap;//標(biāo)準(zhǔn)的64位動(dòng)態(tài)tls分配標(biāo)志位圖(固定使用下面的64位結(jié)構(gòu))

???DWORD?TlsBitmapBits[2];//內(nèi)置的64bit大小的tls位圖(每一位標(biāo)志表示對(duì)應(yīng)tls槽的分配情況)

???…

}

Struct?RTL_BITMAP

{

???ULONG?SizeOfBitmap;//動(dòng)態(tài)tls位圖的大小,默認(rèn)就是8B(64bit)

???BYTE*?Buffer;//動(dòng)態(tài)tls位圖的地址,默認(rèn)就指向PEB結(jié)構(gòu)中的那個(gè)內(nèi)置的tls位圖。當(dāng)要使用的tls槽個(gè)數(shù)超過(guò)64個(gè)時(shí),將使用擴(kuò)展的tls位圖。

}

Struct?TEB

{

???…

???Void*?ThreadLocalStoragePointer;//本線程的那片靜態(tài)tls區(qū)的地址

???Void*?TlsSlots[64];//內(nèi)置的64個(gè)tls槽(每個(gè)槽中可以存放4B大小的任意數(shù)據(jù))

???Void*?TlsExpansionSlots;//另外擴(kuò)展的1024個(gè)tls槽

???…

}

下面的函數(shù)分配一個(gè)空閑的tls槽,返回分到的槽號(hào)(即索引)

DWORD?TlsAlloc()

{

????ULONG?Index;

RtlAcquirePebLock();

//先從標(biāo)準(zhǔn)的64位tls位圖中找到一個(gè)空閑的tls槽(也即未被其他線程占用的tls槽)

????Index?=?RtlFindClearBitsAndSet(NtCurrentPeb()->TlsBitmap,?1,?0);

????if?(Index?==?-1)//如果找不到

{

????//再去擴(kuò)展的tls槽位圖中查找

????????Index?=?RtlFindClearBitsAndSet(NtCurrentPeb()->TlsExpansionBitmap,?1,?0);

????????if?(Index?!=?-1)//如果找到了

????????{

????????????if?(NtCurrentTeb()->TlsExpansionSlots?==?NULL)

????????????{

????????????????NtCurrentTeb()->TlsExpansionSlots?=?HeapAlloc(GetProcessHeap(),

??????????????????????????????????????????????????HEAP_ZERO_MEMORY,1024?*?sizeof(PVOID));

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

????????????NtCurrentTeb()->TlsExpansionSlots[Index]?=?0;//分到對(duì)應(yīng)的槽后,自動(dòng)將內(nèi)容清0

????????????Index?+=?64;

????????}

????????else

????????????SetLastError(ERROR_NO_MORE_ITEMS);

????}

????else

????????NtCurrentTeb()->TlsSlots[Index]?=?0;?//分到對(duì)應(yīng)的槽后,自動(dòng)將內(nèi)容清0

????RtlReleasePebLock();

????return?Index;

}

下面的函數(shù)將數(shù)據(jù)寫入指定tls槽中

BOOL?TlsSetValue(DWORD?Index,?LPVOID?Value)

{

????if?(Index?>=?64)?//擴(kuò)展tls槽中

????{

????????if?(NtCurrentTeb()->TlsExpansionSlots?==?NULL)

????????{

????????????NtCurrentTeb()->TlsExpansionSlots?=?HeapAlloc(GetProcessHeap(),

???????????????????????????????????HEAP_ZERO_MEMORY,1024?*sizeof(PVOID));

????????}

????????NtCurrentTeb()->TlsExpansionSlots[Index?-?64]?=?Value;

????}

????else

????????NtCurrentTeb()->TlsSlots[Index]?=?Value;

????return?TRUE;

}

下面的函數(shù)讀取指定tls槽中的值

LPVOID?TlsGetValue(DWORD?Index)

{

????if?(Index?>=?64)

????????return?NtCurrentTeb()->TlsExpansionSlots[Index?-?64];

????else

????????return?NtCurrentTeb()->TlsSlots[Index];

}

下面的函數(shù)用來(lái)釋放一個(gè)tls槽給進(jìn)程

BOOL?TlsFree(DWORD?Index)

{

????BOOL?BitSet;

????RtlAcquirePebLock();

????if?(Index?>=?64)

{

???//檢測(cè)該tls槽是否已分配

???????BitSet?=?RtlAreBitsSet(NtCurrentPeb()->TlsExpansionBitmap,Index?-?64,1);

???????if?(BitSet)//若已分配,現(xiàn)在標(biāo)記為空閑

???????????RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap,Index?-?64,1);

????}

????else

????{

????????BitSet?=?RtlAreBitsSet(NtCurrentPeb()->TlsBitmap,?Index,?1);

????????if?(BitSet)

????????????RtlClearBits(NtCurrentPeb()->TlsBitmap,?Index,?1);

????}

????if?(BitSet)

????{

????????//將所有線程的對(duì)應(yīng)tls槽內(nèi)容清0

????????NtSetInformationThread(NtCurrentThread(),ThreadZeroTlsCell,&Index,sizeof(DWORD));

????}

????else

????????SetLastError(ERROR_INVALID_PARAMETER);

????RtlReleasePebLock();

????return?BitSet;

}

上面這些關(guān)于動(dòng)態(tài)tls的函數(shù)都不難理解。動(dòng)態(tài)tls功能強(qiáng)大,但使用起來(lái)不方便。靜態(tài)tls不好用在動(dòng)態(tài)庫(kù)中,比較局限,但靜態(tài)tls使用方便。話又說(shuō)回來(lái),靜態(tài)的tls的使用方便背后,又包含著較為復(fù)雜的初始化流程。下面看靜態(tài)tls的初始化流程。

回顧一下進(jìn)程創(chuàng)建時(shí)的啟動(dòng)流程:

在進(jìn)程啟動(dòng)時(shí),初始化主exe文件的函數(shù)內(nèi)部:

PEFUNC??LdrPEStartup(…)

{

???…

???Status?=?LdrFixupImports(NULL,?*Module);//加載子孫dll,修正IAT導(dǎo)入表

???Status?=?LdrpInitializeTlsForProccess();//初始化進(jìn)程的靜態(tài)tls

???if?(NT_SUCCESS(Status))

???{

??????LdrpAttachProcess();//發(fā)送一個(gè)ProcessAttach消息,調(diào)用該模塊的DllMain函數(shù)

??????LdrpTlsCallback(*Module,?DLL_PROCESS_ATTACH);//調(diào)用各模塊的tls回調(diào)函數(shù)?

???}

???…

}

鉆進(jìn)各個(gè)函數(shù)里面去看一下:

NTSTATUS?LdrFixupImports(…)

{

???…

???if?(TlsDirectory)

???{

???????TlsSize?=?TlsDirectory->EndAddressOfRawData-?TlsDirectory->StartAddressOfRawData

???????????????????+?TlsDirectory->SizeOfZeroFill;

???????if?(TlsSize?>?0?&&?NtCurrentPeb()->Ldr->Initialized)//if?動(dòng)態(tài)加載該模塊

???????????TlsDirectory?=?NULL;//?動(dòng)態(tài)加載的模塊不支持靜態(tài)tls

???}

???…

???if?(TlsDirectory?&&?TlsSize?>?0)//處理靜態(tài)加載的dll模塊中的靜態(tài)tls節(jié)

???????LdrpAcquireTlsSlot(Module,?TlsSize,?FALSE);

???…

}

在修正每個(gè)exe、dll文件的導(dǎo)入表時(shí),會(huì)檢查該文件中.tls節(jié)的大小。由于這個(gè)函數(shù)本身也會(huì)被LoadLibrary函數(shù)在內(nèi)部調(diào)用,所以,這個(gè)函數(shù)他會(huì)檢測(cè)是不是在動(dòng)態(tài)加載dll,若是,如果發(fā)現(xiàn)dll中含有靜態(tài)tls節(jié),就什么都不做。反之,若dll是在進(jìn)程啟動(dòng)階段靜態(tài)加載的,就會(huì)調(diào)用LdrpAcquireTlsSlot處理那個(gè)模塊中的tls節(jié)。具體是怎么處理的呢?我們看:

VOID?LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY?Module,?ULONG?Size,?BOOLEAN?Locked)

{

if?(!Locked)

RtlEnterCriticalSection?(NtCurrentPeb()->LoaderLock);

Module->TlsIndex?=?LdrpTlsCount;//記錄這個(gè)模塊tls節(jié)的索引(即tls號(hào))

LdrpTlsCount++;//遞增進(jìn)程中的tls節(jié)個(gè)數(shù)

LdrpTlsSize?+=?Size;//遞增進(jìn)程中tls節(jié)總大小

if?(!Locked)

RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);

}

如上,每個(gè)模塊在進(jìn)程啟動(dòng)時(shí)的靜態(tài)加載過(guò)程中,只是遞增一下進(jìn)程中總的tls節(jié)個(gè)數(shù)與大小,以及分配該模塊的tls節(jié)編號(hào),以便在進(jìn)程完全初始化完成(即加載了所有模塊)后,統(tǒng)一集中處理各模塊中的靜態(tài)tls節(jié)。

下面再看LdrPEStartup函數(shù)中調(diào)用的LdrpInitializeTlsForProccess函數(shù),顯然,這個(gè)函數(shù)是在LdrFixupImports函數(shù)加載了該exe依賴的所有子孫dll文件后才調(diào)用的。前面已經(jīng)統(tǒng)計(jì)完了該進(jìn)程中所有模塊的所有tls節(jié)的總大小以及tls節(jié)總個(gè)數(shù),現(xiàn)在就到調(diào)用這個(gè)函數(shù)集中統(tǒng)一處理該進(jìn)程的靜態(tài)tls時(shí)候了。我們看:

NTSTATUS?LdrpInitializeTlsForProccess()

{

PLIST_ENTRY?ModuleListHead;

PLIST_ENTRY?Entry;

PLDR_DATA_TABLE_ENTRY?Module;

PIMAGE_TLS_DIRECTORY?TlsDirectory;

PTLS_DATA?TlsData;

ULONG?Size;

if?(LdrpTlsCount?>?0)?//如果有模塊中存在tls節(jié)

{

?????????//分配一個(gè)tls描述符數(shù)組,用來(lái)記錄各模塊的tls節(jié)信息(注意分配的只是描述符,并不用來(lái)存放tls節(jié)體。另外,每個(gè)進(jìn)程的tls描述符數(shù)組都記錄在ntdll.dll模塊中的LdrpTlsArray全局變量中)

LdrpTlsArray?=?RtlAllocateHeap(RtlGetProcessHeap(),0,

LdrpTlsCount?*?sizeof(TLS_DATA));

ModuleListHead?=?&NtCurrentPeb()->Ldr->InLoadOrderModuleList;

Entry?=?ModuleListHead->Flink;

while?(Entry?!=?ModuleListHead)//遍歷所有含有tls節(jié)的靜態(tài)加載模塊

{

Module?=?CONTAINING_RECORD(Entry,?LDR_DATA_TABLE_ENTRY,?InLoadOrderLinks);

if?(Module->LoadCount?==-1?&&?Module->TlsIndex?!=?-1)

{

???????????????????//獲得pe文件中tls目錄的信息

TlsDirectory?=?RtlImageDirectoryEntryToData(Module->DllBase,

????????????????TRUE,IMAGE_DIRECTORY_ENTRY_TLS,&Size);

TlsData?=?&LdrpTlsArray[Module->TlsIndex];//指向該模塊對(duì)應(yīng)的描述符

//非0區(qū)在原模塊中的地址

TlsData->StartAddressOfRawData?=?TlsDirectory->StartAddressOfRawData;

//非0區(qū)的大小

TlsData->TlsDataSize?=?TlsDirectory->EndAddressOfRawData?-?TlsDirectory->

StartAddressOfRawData;

//0區(qū)的大小(即尚未初始化的tls變量總大小)

TlsData->TlsZeroSize?=?TlsDirectory->SizeOfZeroFill;

//tls回調(diào)函數(shù)數(shù)組的地址

if?(TlsDirectory->AddressOfCallBacks)

TlsData->TlsAddressOfCallBacks?=?TlsDirectory->AddressOfCallBacks;

else

TlsData->TlsAddressOfCallBacks?=?NULL;

TlsData->Module?=?Module;//該tls節(jié)所在的原模塊

//重要。回填到原模塊中,該tls節(jié)分得的索引。(寫復(fù)制機(jī)制可確保各進(jìn)程一份)

*(PULONG)TlsDirectory->AddressOfIndex?=?Module->TlsIndex;

}

Entry?=?Entry->Flink;

}

}

return?STATUS_SUCCESS;

}

如上,這個(gè)函數(shù)為進(jìn)程建立起一個(gè)tls描述符數(shù)組。

typedef?struct?_TLS_DATA?//tls節(jié)描述符

{

PVOID?StartAddressOfRawData;?//非0區(qū)在原模塊中的地址

DWORD?TlsDataSize;//?非0區(qū)的大小

DWORD?TlsZeroSize;//?0區(qū)大小

PIMAGE_TLS_CALLBACK?*TlsAddressOfCallBacks;//回調(diào)函數(shù)數(shù)組

PLDR_DATA_TABLE_ENTRY?Module;//所在模塊

}?TLS_DATA,?*PTLS_DATA;

非0區(qū)與0區(qū)是什么意思呢?tls節(jié)中各個(gè)變量可能有的沒(méi)有初值,凡是沒(méi)有初值的tls的變量都被安排到tls節(jié)的末尾,并且不予分配文件空間(這樣,可以節(jié)省文件體積),只記錄他們的總字節(jié)數(shù)即可。

__declspec(thread)?int?g_a?=?1;//已初始化,被安排到tls節(jié)中的非0區(qū)

__declspec(thread)?int?g_b;//被安排到0區(qū)

__declspec(thread)?int?g_c?=?0;//已初始化,被安排到tls節(jié)中的非0區(qū)

__declspec(thread)?int?g_d;?//被安排到0區(qū)

所有未予初始化的tls變量都默認(rèn)賦予初值0。

最后:每當(dāng)一個(gè)線程創(chuàng)建時(shí)的初始化工作如下:

NTSTATUS

LdrpAttachThread?(VOID)

{

?????。。。

Status?=?LdrpInitializeTlsForThread();//關(guān)鍵處。初始化每個(gè)線程的靜態(tài)tls

?????調(diào)用各dll的DllMain,略

return?Status;

}

如上,每當(dāng)一個(gè)線程初始運(yùn)行時(shí),除了會(huì)調(diào)用進(jìn)程中各個(gè)dll的DllMain函數(shù)外,還會(huì)初始化自己的靜態(tài)tls,建立起本線程獨(dú)立的一份靜態(tài)tls副本。如下:

NTSTATUS??LdrpInitializeTlsForThread(VOID)

{

PVOID*?TlsPointers;

PTLS_DATA?TlsInfo;

PVOID?TlsData;

ULONG?i;

PTEB?Teb?=?NtCurrentTeb();

Teb->StaticUnicodeString.Length?=?0;

Teb->StaticUnicodeString.MaximumLength?=?sizeof(Teb->StaticUnicodeBuffer);

Teb->StaticUnicodeString.Buffer?=?Teb->StaticUnicodeBuffer;

if?(LdrpTlsCount?>?0)//如果本進(jìn)程中有包含tls節(jié)的靜態(tài)模塊

{

?????????//將各模塊內(nèi)部的tls節(jié)提取出來(lái),連成一片,形成一塊‘tls片區(qū)’

TlsPointers?=?RtlAllocateHeap(RtlGetProcessHeap(),0,

???????LdrpTlsCount?*?sizeof(PVOID)?+?LdrpTlsSize);//頭部指針數(shù)組+所有tls塊的總大小

?????????//指向頭部后面的各tls節(jié)體部分

TlsData?=?(PVOID)((ULONG_PTR)TlsPointers?+?LdrpTlsCount?*?sizeof(PVOID));

Teb->ThreadLocalStoragePointer?=?TlsPointers;//指向本線程自己的那份tls的頭部?

TlsInfo?=?LdrpTlsArray;//指向本進(jìn)程的tls描述符數(shù)組

for?(i?=?0;?i?<?LdrpTlsCount;?i++,?TlsInfo++)

{

TlsPointers[i]?=?TlsData;//將數(shù)組指針指向?qū)?yīng)的tls塊

if?(TlsInfo->TlsDataSize)

{????

??????????????????//提取對(duì)應(yīng)模塊內(nèi)部的tls節(jié)體(非0區(qū)部分)到這兒來(lái)

memcpy(TlsData,?TlsInfo->StartAddressOfRawData,?TlsInfo->TlsDataSize);

TlsData?=?(PVOID)((ULONG_PTR)TlsData?+?TlsInfo->TlsDataSize);

}

if?(TlsInfo->TlsZeroSize)//0區(qū)部分

{

memset(TlsData,?0,?TlsInfo->TlsZeroSize);//自動(dòng)初始化為0

TlsData?=?(PVOID)((ULONG_PTR)TlsData?+?TlsInfo->TlsZeroSize);//跨過(guò)0區(qū)部分

}

}

}

return?STATUS_SUCCESS;

}

看到?jīng)],每個(gè)線程誕生之初,就將進(jìn)程中各模塊內(nèi)部的tls節(jié)提取出來(lái),復(fù)制到一個(gè)集中的地方存放,這樣,

嗎,每個(gè)線程都建立了一份自己連續(xù)的tls片區(qū)。以后,要訪問(wèn)tls變量時(shí),訪問(wèn)的都是自己的那份tls片區(qū),

當(dāng)然,如何訪問(wèn)?這離不開編譯器對(duì)靜態(tài)tls機(jī)制提供的支持。

編譯器在遇到__declspec(thread)關(guān)鍵字時(shí),會(huì)認(rèn)為那個(gè)變量是tls變量,將之編譯鏈接到pe文件的.tls節(jié)中存放,另外每條訪問(wèn)tls變量的高級(jí)語(yǔ)句都被做了恰當(dāng)?shù)木幾g。每個(gè)tls變量都被編譯為二級(jí)地址:

“Tls節(jié)號(hào).節(jié)內(nèi)偏移”,每個(gè)模塊的tls節(jié)號(hào)(即索引)保存在那個(gè)模塊的tls目錄中的某個(gè)固定字段中(詳見:?*(PULONG)TlsDirectory->AddressOfIndex?=?Module->TlsIndex?這條語(yǔ)句),這樣,編譯器從模塊的這個(gè)位置取得該模塊的tls節(jié)分得的節(jié)號(hào),以此節(jié)號(hào)為索引,根據(jù)TEB中的保存的那塊“tls片區(qū)”的頭部數(shù)組,找到對(duì)應(yīng)于本模塊tls節(jié)副本的位置,然后加上該tls變量在節(jié)內(nèi)的偏移,就正確找到對(duì)應(yīng)的內(nèi)存單元了。

六、進(jìn)程掛靠與跨進(jìn)程操作

前面總在說(shuō):“將一個(gè)線程掛靠到其他進(jìn)程的地址空間”,這是怎么回事?現(xiàn)在就來(lái)看一下。

當(dāng)父進(jìn)程要?jiǎng)?chuàng)建一個(gè)子進(jìn)程時(shí):會(huì)在父進(jìn)程中調(diào)用CreateProcess。這個(gè)函數(shù)本身是運(yùn)行在父進(jìn)程的地址空間中的,但是由它創(chuàng)建了子進(jìn)程,創(chuàng)建了子進(jìn)程的地址空間,創(chuàng)建了子進(jìn)程的PEB。當(dāng)要初始化子進(jìn)程的PEB結(jié)構(gòu)時(shí),由于PEB本身位于子進(jìn)程的地址空間中,如果直接訪問(wèn)PEB那是不對(duì)的,那將會(huì)映射到不同的物理內(nèi)存。所以必須掛靠到子進(jìn)程的地址空間中,去讀寫PEB結(jié)構(gòu)體中的值。下面的函數(shù)就是用來(lái)掛靠的

VOID?KeAttachProcess(IN?PKPROCESS?Process)?//將當(dāng)前線程掛靠到指定進(jìn)程的地址空間

{

????KLOCK_QUEUE_HANDLE?ApcLock;

????PKTHREAD?Thread?=?KeGetCurrentThread();

????if?(Thread->ApcState.Process?==?Process)?return;//如果已經(jīng)位于目標(biāo)進(jìn)程,返回

????if?((Thread->ApcStateIndex?!=?OriginalApcEnvironment)?||?(KeIsExecutingDpc()))

????????KeBugCheckEx(~);//藍(lán)屏錯(cuò)誤

????else

????{

????????KiAcquireApcLock(Thread,?&ApcLock);

????????KiAcquireDispatcherLockAtDpcLevel();//掛靠過(guò)程操作過(guò)程中禁止線程切換

????????KiAttachProcess(Thread,?Process,?&ApcLock,?&Thread->SavedApcState);//實(shí)質(zhì)函數(shù)

????}

}

VOID

KiAttachProcess(IN?PKTHREAD?Thread,//指定線程

????????????????IN?PKPROCESS?Process,//要掛靠到的目標(biāo)進(jìn)程

????????????????IN?PKLOCK_QUEUE_HANDLE?ApcLock,

????????????????IN?PRKAPC_STATE?SavedApcState)//保存原apc隊(duì)列狀態(tài)

{

????Process->StackCount++;//目標(biāo)線程的內(nèi)核棧個(gè)數(shù)遞增(也即增加線程個(gè)數(shù))

KiMoveApcState(&Thread->ApcState,?SavedApcState);//復(fù)制保存原apc隊(duì)列狀態(tài)

//每當(dāng)一掛靠,必然要清空原apc隊(duì)列

????InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);

????InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);

????Thread->ApcState.Process?=?Process;//關(guān)鍵。將表示當(dāng)前進(jìn)程的字段更為目標(biāo)進(jìn)程

????Thread->ApcState.KernelApcInProgress?=?FALSE;

????Thread->ApcState.KernelApcPending?=?FALSE;

????Thread->ApcState.UserApcPending?=?FALSE;

????if?(SavedApcState?==?&Thread->SavedApcState)//一般滿足

{

????//修改指向,但不管怎么修改,ApcState字段總是表示當(dāng)前apc狀態(tài)

????????Thread->ApcStatePointer[OriginalApcEnvironment]?=?&Thread->SavedApcState;

????????Thread->ApcStatePointer[AttachedApcEnvironment]?=?&Thread->ApcState;

????????Thread->ApcStateIndex?=?AttachedApcEnvironment;

????}

????if?(Process->State?==?ProcessInMemory)//if?沒(méi)被置換出去

????{

????????KiReleaseDispatcherLockFromDpcLevel();

????????KiReleaseApcLockFromDpcLevel(ApcLock);

????????KiSwapProcess(Process,?SavedApcState->Process);//實(shí)質(zhì)函數(shù)

????????//調(diào)用這個(gè)函數(shù)的目的是檢測(cè)可能的搶占切換條件是否已發(fā)生。(若已發(fā)生就趕緊切換)

????????KiExitDispatcher(ApcLock->OldIrql);//降到指定irql(同時(shí)檢查是否發(fā)生了搶占式切換)

????}

????Else?…

}

實(shí)質(zhì)性的函數(shù)是KiSwapProcess,繼續(xù)看

VOID?KiSwapProcess(IN?PKPROCESS?NewProcess,IN?PKPROCESS?OldProcess)

{

PKIPCR?Pcr?=?(PKIPCR)KeGetPcr();

//關(guān)鍵。修改cr3(存放進(jìn)程頁(yè)目錄的物理地址)寄存器為目標(biāo)進(jìn)程的頁(yè)表

????__writecr3(NewProcess->DirectoryTableBase[0]);

????Ke386SetGs(0);//將gs寄存器清0

????Pcr->TSS->IoMapBase?=?NewProcess->IopmOffset;//修改當(dāng)前線程的IO權(quán)限位圖為目標(biāo)進(jìn)程的那份

}

看到?jīng)],進(jìn)程掛靠的實(shí)質(zhì)工作,就是將cr3寄存器改為目標(biāo)寄存器的地址空間,這樣,線程的所有有關(guān)內(nèi)存的操作,操作的都是目標(biāo)進(jìn)程的地址空間。

明白了進(jìn)程掛靠后,理解跨進(jìn)程操作就很容易了。

一個(gè)進(jìn)程可以調(diào)用OpenProcess打開另一個(gè)進(jìn)程,取得目標(biāo)進(jìn)程的句柄后,就可調(diào)用VirtualAllocEx、WriteProcessMemory、ReadProcessMemory、CreateRemoteThread等函數(shù)操作那個(gè)進(jìn)程的地址空間。這些跨進(jìn)程操作的函數(shù)功能強(qiáng)大,而且?guī)в衅茐男?#xff0c;以至于往往被殺毒軟件重點(diǎn)封殺,特別是CreateRemoteThread這個(gè)函數(shù),冤啊。相關(guān)的示例代碼如下圖所示:

所有的跨進(jìn)程操作都必經(jīng)一步:打開目標(biāo)進(jìn)程。(這是一道需要重點(diǎn)把手的關(guān)口)

HANDLE

OpenProcess(DWORD?dwDesiredAccess,//申請(qǐng)的權(quán)限

????????????BOOL?bInheritHandle,//指本次打開得到的句柄是否可繼承給子進(jìn)程

????????????DWORD?dwProcessId)//目標(biāo)進(jìn)程的pid

{

????NTSTATUS?errCode;

????HANDLE?ProcessHandle;

????OBJECT_ATTRIBUTES?ObjectAttributes;

????CLIENT_ID?ClientId;

????ClientId.UniqueProcess?=?UlongToHandle(dwProcessId);

????ClientId.UniqueThread?=?0;

????InitializeObjectAttributes(&ObjectAttributes,NULL,

???????????????????????????????(bInheritHandle???OBJ_INHERIT?:?0),NULL,NULL);

????//調(diào)用系統(tǒng)服務(wù)打開進(jìn)程

????errCode?=?NtOpenProcess(&ProcessHandle,dwDesiredAccess,&ObjectAttributes,&ClientId);

????if?(!NT_SUCCESS(errCode))

????{

????????SetLastErrorByStatus(errCode);

????????return?NULL;

????}

????return?ProcessHandle;

}

NTSTATUS

NtOpenProcess(OUT?PHANDLE?ProcessHandle,

??????????????IN?ACCESS_MASK?DesiredAccess,

??????????????IN?POBJECT_ATTRIBUTES?ObjectAttributes,

??????????????IN?PCLIENT_ID?ClientId)//pid.tid

{

????KPROCESSOR_MODE?PreviousMode?=?KeGetPreviousMode();

????ULONG?Attributes?=?0;

????BOOLEAN?HasObjectName?=?FALSE;

????PETHREAD?Thread?=?NULL;

????PEPROCESS?Process?=?NULL;

????if?(PreviousMode?!=?KernelMode)

????{

????????_SEH2_TRY

????????{

????????????ProbeForWriteHandle(ProcessHandle);

????????????if?(ClientId)

????????????{

????????????????ProbeForRead(ClientId,?sizeof(CLIENT_ID),?sizeof(ULONG));

????????????????SafeClientId?=?*ClientId;

????????????????ClientId?=?&SafeClientId;

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

????????????ProbeForRead(ObjectAttributes,sizeof(OBJECT_ATTRIBUTES),sizeof(ULONG));

????????????HasObjectName?=?(ObjectAttributes->ObjectName?!=?NULL);

????????????Attributes?=?ObjectAttributes->Attributes;

????????}

????????_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

????????{

????????????_SEH2_YIELD(return?_SEH2_GetExceptionCode());

????????}

????????_SEH2_END;

????}

????else

????{

????????HasObjectName?=?(ObjectAttributes->ObjectName?!=?NULL);

????????Attributes?=?ObjectAttributes->Attributes;

????}

if?((HasObjectName)?&&?(ClientId))//不能同時(shí)給定進(jìn)程名與id

?return?STATUS_INVALID_PARAMETER_MIX;

????//傳遞當(dāng)前令牌以及要求的權(quán)限到AccessState中

????Status?=?SeCreateAccessState(&AccessState,&AuxData,DesiredAccess,

?????????????????????????????????&PsProcessType->TypeInfo.GenericMapping);

????//檢查當(dāng)前令牌是否具有調(diào)試特權(quán)(這就是為什么經(jīng)常在打開目標(biāo)進(jìn)程前要啟用調(diào)試特權(quán))

????if?(SeSinglePrivilegeCheck(SeDebugPrivilege,?PreviousMode))

????{

????????if?(AccessState.RemainingDesiredAccess?&?MAXIMUM_ALLOWED)

????????????AccessState.PreviouslyGrantedAccess?|=?PROCESS_ALL_ACCESS;

????????else

????????????AccessState.PreviouslyGrantedAccess?|=AccessState.RemainingDesiredAccess;

????????AccessState.RemainingDesiredAccess?=?0;

????}

????if?(HasObjectName)?//以對(duì)象名的方式查找該進(jìn)程對(duì)象

????{

????????Status?=?ObOpenObjectByName(ObjectAttributes,PsProcessType,PreviousMode,

????????????????????????????????????&AccessState,0,NULL,&hProcess);

????????SeDeleteAccessState(&AccessState);

????}

????else?if?(ClientId)

????{

????????if?(ClientId->UniqueThread)//根據(jù)tid查找線程、進(jìn)程對(duì)象

????????????Status?=?PsLookupProcessThreadByCid(ClientId,?&Process,?&Thread);

????????Else?//根據(jù)pid從獲活動(dòng)進(jìn)程鏈表中查找進(jìn)程對(duì)象,最常見

????????????Status?=?PsLookupProcessByProcessId(ClientId->UniqueProcess,&Process);

????????if?(!NT_SUCCESS(Status))

????????{

????????????SeDeleteAccessState(&AccessState);

????????????return?Status;

????????}

????????//在該進(jìn)程對(duì)象上打開一個(gè)句柄

????????Status?=?ObOpenObjectByPointer(Process,Attributes,&AccessState,0,

???????????????????????????????????????PsProcessType,PreviousMode,&hProcess);

????????SeDeleteAccessState(&AccessState);

????????if?(Thread)

?ObDereferenceObject(Thread);

????????ObDereferenceObject(Process);

????}

????else

????????return?STATUS_INVALID_PARAMETER_MIX;

????if?(NT_SUCCESS(Status))

????{

????????_SEH2_TRY

????????{

????????????*ProcessHandle?=?hProcess;//返回打開得到的進(jìn)程句柄

????????}

????????_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

????????{

????????????Status?=?_SEH2_GetExceptionCode();

????????}

????????_SEH2_END;

????}

????return?Status;

}

如上,這個(gè)函數(shù)在檢測(cè)權(quán)限滿足后,就打開目標(biāo)進(jìn)程,返回一個(gè)句柄給調(diào)用者。

看下面的典型跨進(jìn)程寫數(shù)據(jù)函數(shù):

NTSTATUS

NtWriteVirtualMemory(IN?HANDLE?ProcessHandle,//遠(yuǎn)程進(jìn)程

?????????????????????IN?PVOID?BaseAddress,

?????????????????????IN?PVOID?Buffer,

?????????????????????IN?SIZE_T?NumberOfBytesToWrite,

?????????????????????OUT?PSIZE_T?NumberOfBytesWritten?OPTIONAL)

{

????KPROCESSOR_MODE?PreviousMode?=?ExGetPreviousMode();

????PEPROCESS?Process;

????NTSTATUS?Status?=?STATUS_SUCCESS;

????SIZE_T?BytesWritten?=?0;

????if?(PreviousMode?!=?KernelMode)

????{

????????if?((((ULONG_PTR)BaseAddress?+?NumberOfBytesToWrite)?<?(ULONG_PTR)BaseAddress)?||

????????????(((ULONG_PTR)Buffer?+?NumberOfBytesToWrite)?<?(ULONG_PTR)Buffer)?||

????????????(((ULONG_PTR)BaseAddress?+?NumberOfBytesToWrite)?>?MmUserProbeAddress)?||

????????????(((ULONG_PTR)Buffer?+?NumberOfBytesToWrite)?>?MmUserProbeAddress))

????????{

????????????return?STATUS_ACCESS_VIOLATION;

????????}

????????_SEH2_TRY

????????{

????????????if?(NumberOfBytesWritten)?ProbeForWriteSize_t(NumberOfBytesWritten);

????????}

????????_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

????????{

????????????_SEH2_YIELD(return?_SEH2_GetExceptionCode());

????????}

????????_SEH2_END;

????}

????if?(NumberOfBytesToWrite)

????{

????????Status?=?ObReferenceObjectByHandle(ProcessHandle,PROCESS_VM_WRITE,PsProcessType,

???????????????????????????????????????????PreviousMode,?(PVOID*)&Process,NULL);

????????if?(NT_SUCCESS(Status))

????????{

????????????Status?=?MmCopyVirtualMemory(PsGetCurrentProcess(),Buffer,Process,

?????????????????????????????????????????BaseAddress,NumberOfBytesToWrite,

?????????????????????????????????????????PreviousMode,&BytesWritten);

????????????ObDereferenceObject(Process);

????????}

????}

????if?(NumberOfBytesWritten)

????{

????????_SEH2_TRY

????????{

????????????*NumberOfBytesWritten?=?BytesWritten;

????????}

????????_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

????????{

????????}

????????_SEH2_END;

????}

????return?Status;

}

NTSTATUS

MmCopyVirtualMemory(IN?PEPROCESS?SourceProcess,

????????????????????IN?PVOID?SourceAddress,

????????????????????IN?PEPROCESS?TargetProcess,

????????????????????OUT?PVOID?TargetAddress,

????????????????????IN?SIZE_T?BufferSize,

????????????????????IN?KPROCESSOR_MODE?PreviousMode,

????????????????????OUT?PSIZE_T?ReturnSize)

{

????NTSTATUS?Status;

????PEPROCESS?Process?=?SourceProcess;

????if?(SourceProcess?==?PsGetCurrentProcess())?Process?=?TargetProcess;

????if?(BufferSize?>?512)//需要使用MDL

????{

????????Status?=?MiDoMappedCopy(SourceProcess,SourceAddress,TargetProcess,TargetAddress,

????????????????????????????????BufferSize,PreviousMode,ReturnSize);

????}

????else

????{

????????Status?=?MiDoPoolCopy(SourceProcess,SourceAddress,TargetProcess,TargetAddress,

??????????????????????????????BufferSize,PreviousMode,ReturnSize);

????}

????return?Status;

}

NTSTATUS

MiDoMappedCopy(IN?PEPROCESS?SourceProcess,

???????????????IN?PVOID?SourceAddress,

???????????????IN?PEPROCESS?TargetProcess,

???????????????OUT?PVOID?TargetAddress,

???????????????IN?SIZE_T?BufferSize,

???????????????IN?KPROCESSOR_MODE?PreviousMode,

???????????????OUT?PSIZE_T?ReturnSize)

{

????PFN_NUMBER?MdlBuffer[(sizeof(MDL)?/?sizeof(PFN_NUMBER))?+?MI_MAPPED_COPY_PAGES?+?1];

????PMDL?Mdl?=?(PMDL)MdlBuffer;

????SIZE_T?TotalSize,?CurrentSize,?RemainingSize;

????volatile?BOOLEAN?FailedInProbe?=?FALSE,?FailedInMapping?=?FALSE,?FailedInMoving;

????volatile?BOOLEAN?PagesLocked;

????PVOID?CurrentAddress?=?SourceAddress,?CurrentTargetAddress?=?TargetAddress;

????volatile?PVOID?MdlAddress;

????KAPC_STATE?ApcState;

????BOOLEAN?HaveBadAddress;

????ULONG_PTR?BadAddress;

????NTSTATUS?Status?=?STATUS_SUCCESS;

????TotalSize?=?14?*?PAGE_SIZE;//每次拷貝14個(gè)頁(yè)面大小

????if?(BufferSize?<=?TotalSize)?TotalSize?=?BufferSize;

????CurrentSize?=?TotalSize;

????RemainingSize?=?BufferSize;

????while?(RemainingSize?>?0)

????{

????????if?(RemainingSize?<?CurrentSize)?CurrentSize?=?RemainingSize;

????????KeStackAttachProcess(&SourceProcess->Pcb,?&ApcState);//掛靠到源進(jìn)程

????????MdlAddress?=?NULL;

????????PagesLocked?=?FALSE;

????????FailedInMoving?=?FALSE;

????????_SEH2_TRY

????????{

????????????if?((CurrentAddress?==?SourceAddress)?&&?(PreviousMode?!=?KernelMode))

????????????{

????????????????FailedInProbe?=?TRUE;

????????????????ProbeForRead(SourceAddress,?BufferSize,?sizeof(CHAR));

????????????????FailedInProbe?=?FALSE;

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

????????????MmInitializeMdl(Mdl,?CurrentAddress,?CurrentSize);

????????????MmProbeAndLockPages(Mdl,?PreviousMode,?IoReadAccess);

????????????PagesLocked?=?TRUE;

????????????MdlAddress?=?MmMapLockedPagesSpecifyCache(Mdl,KernelMode,MmCached,?NULL,

??????????????????????????????????????????????????????FALSE,HighPagePriority);

????????????KeUnstackDetachProcess(&ApcState);//撤銷掛靠

????????????KeStackAttachProcess(&TargetProcess->Pcb,?&ApcState);//掛靠到目標(biāo)進(jìn)程

????????????if?((CurrentAddress?==?SourceAddress)?&&?(PreviousMode?!=?KernelMode))

????????????{

????????????????FailedInProbe?=?TRUE;

????????????????ProbeForWrite(TargetAddress,?BufferSize,?sizeof(CHAR));

????????????????FailedInProbe?=?FALSE;

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

????????????FailedInMoving?=?TRUE;

????????????RtlCopyMemory(CurrentTargetAddress,?MdlAddress,?CurrentSize);//拷貝

????????}

????????_SEH2_EXCEPT()。。。

???

????????if?(Status?!=?STATUS_SUCCESS)?return?Status;

????????KeUnstackDetachProcess(&ApcState);

????????MmUnmapLockedPages(MdlAddress,?Mdl);

????????MmUnlockPages(Mdl);

????????RemainingSize?-=?CurrentSize;

????????CurrentAddress?=?(PVOID)((ULONG_PTR)CurrentAddress?+?CurrentSize);

????????CurrentTargetAddress?=?(PVOID)((ULONG_PTR)CurrentTargetAddress?+?CurrentSize);

????}

????*ReturnSize?=?BufferSize;

????return?STATUS_SUCCESS;

}

看到?jīng)],要掛靠到目標(biāo)進(jìn)程中去復(fù)制數(shù)據(jù)。如果源進(jìn)程不是當(dāng)前進(jìn)程,還要先掛靠到源進(jìn)程中。

七、線程的掛起與恢復(fù)

SuspendThread->NtSuspendThread->PsSuspenThread->?KeSuspendThread,直接看KeSuspendThread函數(shù)

ULONG?KeSuspendThread(PKTHREAD?Thread)

{

????KLOCK_QUEUE_HANDLE?ApcLock;

????ULONG?PreviousCount;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

????KiAcquireApcLock(Thread,?&ApcLock);

????PreviousCount?=?Thread->SuspendCount;

????if?(Thread->ApcQueueable)

????{

????????Thread->SuspendCount++;//遞增掛起計(jì)數(shù)

????????if?(!(PreviousCount)?&&?!(Thread->FreezeCount))

????????{

????????????if?(!Thread->SuspendApc.Inserted)//if尚未插入那個(gè)‘掛起APC’

????????????{

????????????????Thread->SuspendApc.Inserted?=?TRUE;

????????????????KiInsertQueueApc(&Thread->SuspendApc,?IO_NO_INCREMENT);//插入‘掛起APC’

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

????????????else

????????????{

????????????????KiAcquireDispatcherLockAtDpcLevel();

????????????????Thread->SuspendSemaphore.Header.SignalState--;

????????????????KiReleaseDispatcherLockFromDpcLevel();

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

????????}

}

????KiReleaseApcLockFromDpcLevel(&ApcLock);

????KiExitDispatcher(ApcLock.OldIrql);

????return?PreviousCount;

}

這個(gè)專有的‘掛起APC’是一個(gè)特殊的APC,我們看他的工作:

VOID

KiSuspendThread(IN?PVOID?NormalContext,

????????????????IN?PVOID?SystemArgument1,

????????????????IN?PVOID?SystemArgument2)

{

????//等待掛起計(jì)數(shù)減到0

????KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore,Suspended,KernelMode,

??????????????????????????FALSE,NULL);

}

如上,向指定線程插入一個(gè)‘掛起APC’后,那個(gè)線程下次一得到調(diào)度,就會(huì)先執(zhí)行內(nèi)核中的所有APC,當(dāng)執(zhí)行到這個(gè)APC的時(shí)候,就會(huì)一直等到掛起計(jì)數(shù)降到0。換言之,線程剛一得到調(diào)度運(yùn)行的就會(huì),就又重新進(jìn)入等待了。因此,‘掛起態(tài)’也是一種特殊的‘等待態(tài)’。什么時(shí)候掛起計(jì)數(shù)會(huì)減到0呢?只有在別的線程恢復(fù)這個(gè)線程的掛起計(jì)數(shù)時(shí)。

ULONG?KeResumeThread(IN?PKTHREAD?Thread)

{

????KLOCK_QUEUE_HANDLE?ApcLock;

????ULONG?PreviousCount;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

????KiAcquireApcLock(Thread,?&ApcLock);

????PreviousCount?=?Thread->SuspendCount;

????if?(PreviousCount)

????{

????????Thread->SuspendCount--;//遞減掛起計(jì)數(shù)

????????if?((Thread->SuspendCount==0)?&&?(!Thread->FreezeCount))

????????{

????????????KiAcquireDispatcherLockAtDpcLevel();

????????????Thread->SuspendSemaphore.Header.SignalState++;

????????????//當(dāng)掛起計(jì)數(shù)減到0時(shí),喚醒目標(biāo)線程

????????????KiWaitTest(&Thread->SuspendSemaphore.Header,?IO_NO_INCREMENT);

????????????KiReleaseDispatcherLockFromDpcLevel();

????????}

????}

????KiReleaseApcLockFromDpcLevel(&ApcLock);

????KiExitDispatcher(ApcLock.OldIrql);

????return?PreviousCount;

}

就這樣簡(jiǎn)單。

當(dāng)一個(gè)線程處于等待狀態(tài)時(shí),可以指示本次睡眠是否可被強(qiáng)制喚醒,不必等到條件滿足

如:

DWORD?WaitForSingleObjectEx(

??HANDLE?hHandle,????????

??DWORD?dwMilliseconds,?

??BOOL?bAlertable????//指示本次等待過(guò)程中是否可以被其他線程(或其他線程發(fā)來(lái)的APC)強(qiáng)制喚醒。??

);

BOOLEAN

KeAlertThread(IN?PKTHREAD?Thread,

??????????????IN?KPROCESSOR_MODE?AlertMode)

{

????BOOLEAN?PreviousState;

????KLOCK_QUEUE_HANDLE?ApcLock;

????ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);

????KiAcquireApcLock(Thread,?&ApcLock);

????KiAcquireDispatcherLockAtDpcLevel();

????PreviousState?=?Thread->Alerted[AlertMode];//檢測(cè)是否收到了來(lái)自那個(gè)模式的強(qiáng)制喚醒要求

????if?(PreviousState==FALSE)

????{

????????if?((Thread->State?==?Waiting)?&&??//線程處于等待狀態(tài)

????????????(Thread->Alertable)?&&??//線程可被強(qiáng)制喚醒

????????????(AlertMode?<=?Thread->WaitMode))??//模式條件符合

????????{

????????????//強(qiáng)制喚醒那個(gè)線程

????????????KiUnwaitThread(Thread,?STATUS_ALERTED,?THREAD_ALERT_INCREMENT);

????????}

????????Else?//僅僅標(biāo)記已收到過(guò)來(lái)自那個(gè)模式的強(qiáng)制喚醒請(qǐng)求

????????????Thread->Alerted[AlertMode]?=?TRUE;

????}

????KiReleaseDispatcherLockFromDpcLevel();

????KiReleaseApcLockFromDpcLevel(&ApcLock);

????KiExitDispatcher(ApcLock.OldIrql);

????return?PreviousState;

}

注意AlertMode?<=?Thread->WaitMode條件指:用戶模式的強(qiáng)制喚醒請(qǐng)求不能喚醒內(nèi)核模式的等待。

八、DLL注入

前面講過(guò),每個(gè)進(jìn)程在啟動(dòng)的時(shí)候會(huì)加載主exe文件依賴的所有子孫dll。實(shí)際上,一般的Win32?GUI進(jìn)程

都會(huì)加載user32.dll模塊。這個(gè)模塊一加載,就會(huì)自動(dòng)搜索注冊(cè)表鍵?HKEY_LOCAL_MACHINE\Software\Microsoft\Windows?NT\CurrentVersion\Windows?下的值:AppInit_DLLs,該值是一個(gè)dll列表,user32.dll會(huì)讀取這個(gè)值,調(diào)用LoadLibrary加載里面的每個(gè)dll,因此我們可以把我們的dll名稱添加到這個(gè)列表中,達(dá)到dll注入的目的。在ReactOS源碼中能看到下面的代碼:

INT DllMain(???//User32.dll的DllMain

??????????IN?PVOID?hInstanceDll,

??????????IN?ULONG?dwReason,

??????????IN?PVOID?reserved)

{

???switch?(dwReason)

???{

??????case?DLL_PROCESS_ATTACH:

?????????Init();//會(huì)調(diào)用這個(gè)函數(shù)

?????????…

??????…

???}

?}

BOOL??Init(VOID)

{

??…

??LoadAppInitDlls();//會(huì)調(diào)用這個(gè)函數(shù)加載那些dll

??…

}

VOID??LoadAppInitDlls()

{

????szAppInit[0]?=?UNICODE_NULL;

????if?(GetDllList())//讀取這冊(cè)表鍵的值,將要加載的dll列表保存在全局變量szAppInit中

????{

????????WCHAR?buffer[KEY_LENGTH];

????????LPWSTR?ptr;

???size_t?i;

????????RtlCopyMemory(buffer,?szAppInit,?KEY_LENGTH);

for?(i?=?0;?i?<?KEY_LENGTH;?++?i)

{

if(buffer[i]?==?L'?'?||?buffer[i]?==?L',')//dll名稱之間必須用空格或逗號(hào)隔開

buffer[i]?=?0;

}

for?(i?=?0;?i?<?KEY_LENGTH;?)

{

if(buffer[i]?==?0)

++?i;

else

{

ptr?=?buffer?+?i;

i?+=?wcslen(ptr);

LoadLibraryW(ptr);//加載每個(gè)dll

}

}

????}

}

BOOL??GetDllList()

{

????NTSTATUS?Status;

????OBJECT_ATTRIBUTES?Attributes;

????BOOL?bRet?=?FALSE;

????BOOL?bLoad;

????HANDLE?hKey?=?NULL;

????DWORD?dwSize;

????PKEY_VALUE_PARTIAL_INFORMATION?kvpInfo?=?NULL;

????UNICODE_STRING?szKeyName?=?RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows?NT\\CurrentVersion\\Windows");

????UNICODE_STRING?szLoadName?=?RTL_CONSTANT_STRING(L"LoadAppInit_DLLs");

????UNICODE_STRING?szDllsName?=?RTL_CONSTANT_STRING(L"AppInit_DLLs");

????InitializeObjectAttributes(&Attributes,?&szKeyName,?OBJ_CASE_INSENSITIVE,?NULL,?NULL);

????Status?=?NtOpenKey(&hKey,?KEY_READ,?&Attributes);

????if?(NT_SUCCESS(Status))

????{

????????dwSize?=?sizeof(KEY_VALUE_PARTIAL_INFORMATION)?+?sizeof(DWORD);

????????kvpInfo?=?HeapAlloc(GetProcessHeap(),?0,?dwSize);

????????if?(!kvpInfo)

????????????goto?end;

???????//先要在那個(gè)鍵中建立一個(gè)DWORD值:LoadAppInit_DLLs,并將數(shù)值設(shè)為1

????????Status?=?NtQueryValueKey(hKey,&szLoadName,KeyValuePartialInformation,

?????????????????????????????????kvpInfo,dwSize,&dwSize);

????????RtlMoveMemory(&bLoad,kvpInfo->Data,kvpInfo->DataLength);

????????HeapFree(GetProcessHeap(),?0,?kvpInfo);

????????kvpInfo?=?NULL;

????????if?(bLoad)//if?需要加載初始列表的那些dll

????????{

????????????Status?=?NtQueryValueKey(hKey,&szDllsName,KeyValuePartialInformation,

?????????????????????????????????????NULL,0,&dwSize);

????????????kvpInfo?=?HeapAlloc(GetProcessHeap(),?0,?dwSize);

????????????Status?=?NtQueryValueKey(hKey,?&szDllsName,KeyValuePartialInformation,

?????????????????????????????????????kvpInfo,dwSize,&dwSize);

????????????if?(NT_SUCCESS(Status))

????????????{

????????????????LPWSTR?lpBuffer?=?(LPWSTR)kvpInfo->Data;

????????????????if?(*lpBuffer?!=?UNICODE_NULL)

????????????????{

????????????????????INT?bytesToCopy,?nullPos;

????????????????????bytesToCopy?=?min(kvpInfo->DataLength,?KEY_LENGTH?*?sizeof(WCHAR));

????????????????????if?(bytesToCopy?!=?0)

????????????????????{

????????????????????????//dll列表拷到全局變量

????????????????????????RtlMoveMemory(szAppInit,kvpInfo->Data,bytesToCopy);?

????????????????????????nullPos?=?(bytesToCopy?/?sizeof(WCHAR))?-?1;

????????????????????????szAppInit[nullPos]?=?UNICODE_NULL;

????????????????????????bRet?=?TRUE;

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

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

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

????????}

????}

end:

????if?(hKey)

????????NtClose(hKey);

????if?(kvpInfo)

????????HeapFree(GetProcessHeap(),?0,?kvpInfo);

????return?bRet;

}

因此,只需在那個(gè)鍵下面添加一個(gè)DWORD值:LoadAppInit_DLLs,設(shè)為1,然后在AppInit_DLLs值中添加我們的dll即可達(dá)到將我們的dll加載到任意GUI進(jìn)程的地址空間中。

總結(jié)

以上是生活随笔為你收集整理的windows内核情景分析---进程线程2的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

天堂久久天堂av色综合 | 亚洲精品鲁一鲁一区二区三区 | 国产区女主播在线观看 | 久久精品国产99久久6动漫 | 日本饥渴人妻欲求不满 | 亚洲午夜久久久影院 | 国产亚洲美女精品久久久2020 | 国产精品久久久久久亚洲毛片 | 国产精品办公室沙发 | 国产精品无码mv在线观看 | 久久www免费人成人片 | 成 人影片 免费观看 | 欧美丰满熟妇xxxx | 国产在热线精品视频 | 东京无码熟妇人妻av在线网址 | 妺妺窝人体色www在线小说 | 亚洲成av人片天堂网无码】 | 色综合久久久久综合一本到桃花网 | 任你躁在线精品免费 | av无码不卡在线观看免费 | 国产av一区二区精品久久凹凸 | 九月婷婷人人澡人人添人人爽 | 国产真实夫妇视频 | 成人精品视频一区二区三区尤物 | 中文字幕无码视频专区 | 国产精品a成v人在线播放 | a在线观看免费网站大全 | 色妞www精品免费视频 | 无码国产色欲xxxxx视频 | 爆乳一区二区三区无码 | 亚洲中文无码av永久不收费 | 亚洲自偷自偷在线制服 | 中文字幕无码热在线视频 | 人人爽人人澡人人人妻 | 夜精品a片一区二区三区无码白浆 | 无码人妻精品一区二区三区不卡 | 欧美zoozzooz性欧美 | 最近免费中文字幕中文高清百度 | 久久国产精品二国产精品 | 日本饥渴人妻欲求不满 | 亚洲国产午夜精品理论片 | 亚洲gv猛男gv无码男同 | 国产真人无遮挡作爱免费视频 | 久久99精品久久久久久 | 国产一区二区三区日韩精品 | 狠狠亚洲超碰狼人久久 | 2019nv天堂香蕉在线观看 | 精品夜夜澡人妻无码av蜜桃 | 日韩av无码一区二区三区 | 国产成人亚洲综合无码 | 国产另类ts人妖一区二区 | 日韩亚洲欧美中文高清在线 | 欧美怡红院免费全部视频 | 人妻与老人中文字幕 | 欧美丰满熟妇xxxx性ppx人交 | 日韩亚洲欧美中文高清在线 | 日日摸夜夜摸狠狠摸婷婷 | 国产精品久久久久无码av色戒 | 欧美丰满熟妇xxxx性ppx人交 | 强开小婷嫩苞又嫩又紧视频 | 亚洲欧美中文字幕5发布 | 国产内射爽爽大片视频社区在线 | 国产精品久久久久久久9999 | 熟女体下毛毛黑森林 | 久久国内精品自在自线 | 国产成人无码a区在线观看视频app | 蜜臀av在线播放 久久综合激激的五月天 | 国产精品久久精品三级 | 欧美亚洲日韩国产人成在线播放 | 大地资源网第二页免费观看 | 中文字幕无码日韩欧毛 | 最近免费中文字幕中文高清百度 | 在线天堂新版最新版在线8 | 亚洲色大成网站www国产 | 精品人人妻人人澡人人爽人人 | 成人无码视频免费播放 | 天堂а√在线中文在线 | 2020久久香蕉国产线看观看 | 亚洲高清偷拍一区二区三区 | 国产超碰人人爽人人做人人添 | 国产两女互慰高潮视频在线观看 | 国产精品成人av在线观看 | 亚洲色www成人永久网址 | 亚洲 a v无 码免 费 成 人 a v | 免费人成网站视频在线观看 | 中文亚洲成a人片在线观看 | 欧美兽交xxxx×视频 | 午夜精品一区二区三区在线观看 | 欧美怡红院免费全部视频 | 色婷婷综合激情综在线播放 | 国产一区二区不卡老阿姨 | 国产莉萝无码av在线播放 | 激情人妻另类人妻伦 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲爆乳大丰满无码专区 | 老熟妇仑乱视频一区二区 | 天天躁日日躁狠狠躁免费麻豆 | 成人无码视频免费播放 | 色综合视频一区二区三区 | 亚洲精品午夜无码电影网 | 成人影院yy111111在线观看 | 无码人妻丰满熟妇区五十路百度 | 一二三四在线观看免费视频 | 久久国语露脸国产精品电影 | 成 人 免费观看网站 | 欧美成人家庭影院 | 午夜丰满少妇性开放视频 | 亚洲精品午夜国产va久久成人 | 欧美freesex黑人又粗又大 | 国产午夜精品一区二区三区嫩草 | 大肉大捧一进一出视频出来呀 | 澳门永久av免费网站 | 国产亚洲精品久久久久久大师 | 精品国产国产综合精品 | 伊在人天堂亚洲香蕉精品区 | 小鲜肉自慰网站xnxx | 亚洲国产午夜精品理论片 | 亚洲天堂2017无码 | 无码一区二区三区在线 | 无码一区二区三区在线 | av人摸人人人澡人人超碰下载 | 免费无码av一区二区 | 亚洲狠狠色丁香婷婷综合 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 中文字幕无码av激情不卡 | 久久精品国产一区二区三区 | 偷窥日本少妇撒尿chinese | 国产激情综合五月久久 | 亚洲日本一区二区三区在线 | 综合激情五月综合激情五月激情1 | 波多野结衣乳巨码无在线观看 | 久久综合九色综合97网 | 国产精品第一区揄拍无码 | 精品亚洲成av人在线观看 | 久久国产自偷自偷免费一区调 | 无套内射视频囯产 | 未满小14洗澡无码视频网站 | 亚洲人成无码网www | 少妇久久久久久人妻无码 | 成人免费无码大片a毛片 | 中文字幕乱码中文乱码51精品 | 1000部夫妻午夜免费 | 性欧美大战久久久久久久 | 麻豆成人精品国产免费 | 欧美人与物videos另类 | 久青草影院在线观看国产 | 300部国产真实乱 | 精品厕所偷拍各类美女tp嘘嘘 | 人妻中文无码久热丝袜 | 亚洲中文字幕成人无码 | 亚洲精品久久久久avwww潮水 | 亲嘴扒胸摸屁股激烈网站 | 午夜福利电影 | 久久精品中文字幕一区 | 在线播放亚洲第一字幕 | 成人精品视频一区二区三区尤物 | 中文字幕人成乱码熟女app | 欧美 日韩 人妻 高清 中文 | 亚洲熟妇自偷自拍另类 | 精品国产福利一区二区 | 午夜时刻免费入口 | 又粗又大又硬又长又爽 | 国产亚洲精品久久久久久久久动漫 | 亚洲男人av香蕉爽爽爽爽 | 国产免费久久精品国产传媒 | 男女下面进入的视频免费午夜 | 国产麻豆精品精东影业av网站 | 日本大乳高潮视频在线观看 | 1000部夫妻午夜免费 | 少妇被粗大的猛进出69影院 | 国产亚洲精品久久久久久国模美 | 亚洲国产精品毛片av不卡在线 | 亚洲欧美综合区丁香五月小说 | 久久久av男人的天堂 | 精品无码国产一区二区三区av | 无码av免费一区二区三区试看 | 纯爱无遮挡h肉动漫在线播放 | 小泽玛莉亚一区二区视频在线 | 欧美成人高清在线播放 | 国产精品久久精品三级 | 丝袜美腿亚洲一区二区 | 久久久久久久女国产乱让韩 | 九月婷婷人人澡人人添人人爽 | 亚洲爆乳精品无码一区二区三区 | 中文字幕人妻丝袜二区 | 欧美性色19p | 中文字幕久久久久人妻 | 精品国产青草久久久久福利 | 亚洲人成网站色7799 | 日本成熟视频免费视频 | 俺去俺来也www色官网 | 大肉大捧一进一出好爽视频 | 久久久精品欧美一区二区免费 | 国产又爽又黄又刺激的视频 | 国产精品va在线观看无码 | 国产国产精品人在线视 | 日韩人妻少妇一区二区三区 | 亚洲天堂2017无码 | 最新国产麻豆aⅴ精品无码 | 精品国产成人一区二区三区 | 少妇人妻偷人精品无码视频 | 久久国产劲爆∧v内射 | 午夜免费福利小电影 | 亚洲色大成网站www国产 | 国产成人无码午夜视频在线观看 | 国产在线精品一区二区高清不卡 | 任你躁在线精品免费 | 成熟人妻av无码专区 | 午夜精品一区二区三区在线观看 | 日韩av激情在线观看 | 久久人人97超碰a片精品 | 漂亮人妻洗澡被公强 日日躁 | 亚洲熟熟妇xxxx | 给我免费的视频在线观看 | 国产精品久久久av久久久 | 国产精品久久福利网站 | 亚洲精品国产精品乱码不卡 | 强伦人妻一区二区三区视频18 | 狠狠噜狠狠狠狠丁香五月 | 成人一在线视频日韩国产 | 成人欧美一区二区三区黑人免费 | 天堂一区人妻无码 | 人妻aⅴ无码一区二区三区 | 丰腴饱满的极品熟妇 | 一本大道伊人av久久综合 | 国产亚洲精品精品国产亚洲综合 | 精品成人av一区二区三区 | 乌克兰少妇性做爰 | 波多野结衣高清一区二区三区 | 国产av一区二区三区最新精品 | 国产精品手机免费 | 国产亚洲精品久久久ai换 | 男女作爱免费网站 | 亚洲一区二区三区国产精华液 | 男人和女人高潮免费网站 | 亚洲成av人在线观看网址 | 日本丰满熟妇videos | 国产亚洲精品精品国产亚洲综合 | 中文无码成人免费视频在线观看 | 麻豆国产人妻欲求不满谁演的 | 丝袜美腿亚洲一区二区 | 兔费看少妇性l交大片免费 | 国产精品欧美成人 | 精品国产aⅴ无码一区二区 | 熟妇人妻无乱码中文字幕 | 丝袜美腿亚洲一区二区 | 在线观看国产午夜福利片 | 国产精品国产自线拍免费软件 | 日本xxxx色视频在线观看免费 | 欧美熟妇另类久久久久久不卡 | 午夜性刺激在线视频免费 | 狂野欧美性猛xxxx乱大交 | 成人女人看片免费视频放人 | 亚洲午夜久久久影院 | 免费看男女做好爽好硬视频 | 久久99精品久久久久久动态图 | 日韩亚洲欧美中文高清在线 | 中文字幕无码免费久久99 | 香蕉久久久久久av成人 | 国产精品怡红院永久免费 | 国产黑色丝袜在线播放 | 欧美野外疯狂做受xxxx高潮 | 99精品国产综合久久久久五月天 | 国产亚洲美女精品久久久2020 | 最近免费中文字幕中文高清百度 | 最新国产乱人伦偷精品免费网站 | 人妻有码中文字幕在线 | 精品国产麻豆免费人成网站 | 曰韩无码二三区中文字幕 | 最近中文2019字幕第二页 | 双乳奶水饱满少妇呻吟 | 国产两女互慰高潮视频在线观看 | 成人欧美一区二区三区黑人免费 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 免费无码午夜福利片69 | 红桃av一区二区三区在线无码av | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 狂野欧美性猛xxxx乱大交 | 国产黄在线观看免费观看不卡 | 粗大的内捧猛烈进出视频 | 蜜桃臀无码内射一区二区三区 | 国内揄拍国内精品人妻 | 熟妇人妻无码xxx视频 | 一本久久a久久精品vr综合 | 人妻人人添人妻人人爱 | 在线a亚洲视频播放在线观看 | 青草青草久热国产精品 | 久久zyz资源站无码中文动漫 | 国产女主播喷水视频在线观看 | 欧美丰满老熟妇xxxxx性 | 未满成年国产在线观看 | 久久国产精品_国产精品 | 亚洲精品综合五月久久小说 | 天海翼激烈高潮到腰振不止 | 麻豆国产97在线 | 欧洲 | 免费人成在线视频无码 | 波多野42部无码喷潮在线 | 粉嫩少妇内射浓精videos | 欧美放荡的少妇 | 中文字幕人妻无码一夲道 | 国产在线一区二区三区四区五区 | 久久无码中文字幕免费影院蜜桃 | 久久久久免费看成人影片 | 国产在线无码精品电影网 | 少妇性l交大片欧洲热妇乱xxx | 亲嘴扒胸摸屁股激烈网站 | 奇米影视888欧美在线观看 | 暴力强奷在线播放无码 | 国产精品.xx视频.xxtv | 欧美黑人性暴力猛交喷水 | 少妇性荡欲午夜性开放视频剧场 | 国产麻豆精品精东影业av网站 | 四十如虎的丰满熟妇啪啪 | 在线 国产 欧美 亚洲 天堂 | 奇米影视7777久久精品人人爽 | 欧美阿v高清资源不卡在线播放 | 免费人成在线视频无码 | 熟妇女人妻丰满少妇中文字幕 | 国产精品办公室沙发 | 午夜成人1000部免费视频 | 最近中文2019字幕第二页 | 性色欲情网站iwww九文堂 | 乌克兰少妇性做爰 | 亚洲中文字幕无码中字 | 波多野结衣高清一区二区三区 | 欧美 日韩 亚洲 在线 | 婷婷六月久久综合丁香 | 亚洲综合伊人久久大杳蕉 | 7777奇米四色成人眼影 | 曰韩无码二三区中文字幕 | 久久99精品久久久久久 | 无码人妻出轨黑人中文字幕 | 日本熟妇浓毛 | 婷婷六月久久综合丁香 | 欧美怡红院免费全部视频 | 精品水蜜桃久久久久久久 | 欧美日韩久久久精品a片 | 久久久久免费精品国产 | 国产精品亚洲一区二区三区喷水 | 真人与拘做受免费视频 | 国产美女精品一区二区三区 | 欧美国产亚洲日韩在线二区 | 2020久久超碰国产精品最新 | 国产人妻精品一区二区三区 | 精品厕所偷拍各类美女tp嘘嘘 | 亚洲色大成网站www国产 | 青青草原综合久久大伊人精品 | 99久久久无码国产精品免费 | 成人无码视频在线观看网站 | aⅴ亚洲 日韩 色 图网站 播放 | 国产精品久久国产精品99 | 国产亲子乱弄免费视频 | 青草青草久热国产精品 | 亚洲色无码一区二区三区 | 精品国产精品久久一区免费式 | 少妇无套内谢久久久久 | 久久99国产综合精品 | 扒开双腿吃奶呻吟做受视频 | 丰满少妇女裸体bbw | 18黄暴禁片在线观看 | 亚洲人亚洲人成电影网站色 | 国产69精品久久久久app下载 | 亚洲中文字幕无码一久久区 | 少女韩国电视剧在线观看完整 | 中文字幕无码av波多野吉衣 | 学生妹亚洲一区二区 | 动漫av一区二区在线观看 | 国产午夜无码精品免费看 | 国产乱人伦偷精品视频 | 国产日产欧产精品精品app | 欧美高清在线精品一区 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 东京一本一道一二三区 | 国精产品一品二品国精品69xx | 日韩视频 中文字幕 视频一区 | 2020最新国产自产精品 | 色狠狠av一区二区三区 | 亚洲成a人片在线观看日本 | 999久久久国产精品消防器材 | 中国女人内谢69xxxxxa片 | 久精品国产欧美亚洲色aⅴ大片 | 国产成人无码a区在线观看视频app | 久久 国产 尿 小便 嘘嘘 | 久久久国产精品无码免费专区 | 天干天干啦夜天干天2017 | 久久久婷婷五月亚洲97号色 | 精品日本一区二区三区在线观看 | 无码av免费一区二区三区试看 | 日本高清一区免费中文视频 | 国产明星裸体无码xxxx视频 | 2020久久香蕉国产线看观看 | 麻豆精品国产精华精华液好用吗 | 欧美激情综合亚洲一二区 | 精品乱码久久久久久久 | 国产精品美女久久久久av爽李琼 | 国产美女极度色诱视频www | 中文字幕av伊人av无码av | 亚洲熟妇色xxxxx欧美老妇 | 国产精品鲁鲁鲁 | 亚洲精品欧美二区三区中文字幕 | 无套内谢老熟女 | 久久综合九色综合欧美狠狠 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 蜜臀aⅴ国产精品久久久国产老师 | 麻豆精产国品 | 亚洲娇小与黑人巨大交 | 国产精品久久久 | 亚洲高清偷拍一区二区三区 | 人妻人人添人妻人人爱 | 麻豆人妻少妇精品无码专区 | 国产成人无码a区在线观看视频app | 色婷婷av一区二区三区之红樱桃 | 捆绑白丝粉色jk震动捧喷白浆 | 欧美熟妇另类久久久久久不卡 | www成人国产高清内射 | 无码一区二区三区在线观看 | 在线观看欧美一区二区三区 | 亚洲天堂2017无码 | 大肉大捧一进一出好爽视频 | 波多野结衣av在线观看 | 亚洲色在线无码国产精品不卡 | 欧洲熟妇精品视频 | 久久综合给久久狠狠97色 | 无码吃奶揉捏奶头高潮视频 | 男人扒开女人内裤强吻桶进去 | 精品一区二区不卡无码av | 免费网站看v片在线18禁无码 | 88国产精品欧美一区二区三区 | 在线 国产 欧美 亚洲 天堂 | 少妇的肉体aa片免费 | 一区二区三区乱码在线 | 欧洲 | 51国偷自产一区二区三区 | 无码一区二区三区在线观看 | 又大又黄又粗又爽的免费视频 | 在线播放亚洲第一字幕 | 久久www免费人成人片 | 亚洲中文字幕无码一久久区 | 国产香蕉尹人视频在线 | 麻豆精品国产精华精华液好用吗 | 少妇性l交大片 | 久久亚洲中文字幕精品一区 | 欧美丰满熟妇xxxx性ppx人交 | 免费无码一区二区三区蜜桃大 | 小鲜肉自慰网站xnxx | 亚洲熟妇自偷自拍另类 | 狠狠色噜噜狠狠狠狠7777米奇 | 黑森林福利视频导航 | 一本久久a久久精品亚洲 | 亚洲中文字幕无码中文字在线 | 少妇被粗大的猛进出69影院 | 亚洲精品中文字幕乱码 | 日日躁夜夜躁狠狠躁 | 国产va免费精品观看 | 大色综合色综合网站 | 免费网站看v片在线18禁无码 | 欧美人与动性行为视频 | 欧美激情内射喷水高潮 | 亚洲国产日韩a在线播放 | 亚洲va中文字幕无码久久不卡 | 少妇一晚三次一区二区三区 | 思思久久99热只有频精品66 | 人人爽人人爽人人片av亚洲 | 夜精品a片一区二区三区无码白浆 | 人妻少妇精品视频专区 | 欧美freesex黑人又粗又大 | 日本一区二区三区免费高清 | 国产精品99爱免费视频 | 久久天天躁狠狠躁夜夜免费观看 | 老头边吃奶边弄进去呻吟 | 国产精品igao视频网 | 亚洲人成影院在线观看 | 国内精品久久久久久中文字幕 | 97久久国产亚洲精品超碰热 | 在线精品亚洲一区二区 | 激情亚洲一区国产精品 | 国产精品亚洲一区二区三区喷水 | 波多野结衣乳巨码无在线观看 | 精品厕所偷拍各类美女tp嘘嘘 | 国产精品毛片一区二区 | а天堂中文在线官网 | 国产69精品久久久久app下载 | 日韩精品久久久肉伦网站 | 少妇无码一区二区二三区 | 久久人人97超碰a片精品 | 99久久精品国产一区二区蜜芽 | 人妻aⅴ无码一区二区三区 | 国产97在线 | 亚洲 | 日韩亚洲欧美精品综合 | 久久人人97超碰a片精品 | 婷婷五月综合缴情在线视频 | 天天综合网天天综合色 | 亚洲一区二区三区在线观看网站 | 秋霞特色aa大片 | 欧美激情综合亚洲一二区 | 国产成人久久精品流白浆 | 国产女主播喷水视频在线观看 | 女人被男人爽到呻吟的视频 | 国产精品18久久久久久麻辣 | 一区二区三区乱码在线 | 欧洲 | 亚洲春色在线视频 | 亚洲欧美精品伊人久久 | 国产特级毛片aaaaaa高潮流水 | 国产成人久久精品流白浆 | 久久亚洲国产成人精品性色 | 国产人妻人伦精品1国产丝袜 | 亚洲午夜久久久影院 | 性欧美疯狂xxxxbbbb | 十八禁视频网站在线观看 | 99久久久国产精品无码免费 | 国产猛烈高潮尖叫视频免费 | 午夜精品一区二区三区在线观看 | 一本色道婷婷久久欧美 | 女人色极品影院 | 久久人人爽人人爽人人片av高清 | 少妇一晚三次一区二区三区 | 国产人成高清在线视频99最全资源 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 久久亚洲精品成人无码 | 久久久久久av无码免费看大片 | 西西人体www44rt大胆高清 | 少女韩国电视剧在线观看完整 | 东京热一精品无码av | 国产亚洲精品久久久久久国模美 | 欧美日韩在线亚洲综合国产人 | 久久久久久av无码免费看大片 | 乱码av麻豆丝袜熟女系列 | 久久www免费人成人片 | 人人超人人超碰超国产 | 九九综合va免费看 | 国产成人无码a区在线观看视频app | 国产午夜手机精彩视频 | 四虎国产精品一区二区 | 成人免费视频视频在线观看 免费 | 黑人玩弄人妻中文在线 | 国产真人无遮挡作爱免费视频 | 天天躁夜夜躁狠狠是什么心态 | 少妇被粗大的猛进出69影院 | 中文字幕+乱码+中文字幕一区 | 香蕉久久久久久av成人 | 国产手机在线αⅴ片无码观看 | 久久午夜无码鲁丝片 | 999久久久国产精品消防器材 | 精品国产青草久久久久福利 | 精品久久综合1区2区3区激情 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 久久99精品久久久久久 | 久久国产精品萌白酱免费 | 亚洲 日韩 欧美 成人 在线观看 | 国产精品igao视频网 | 精品国产一区二区三区四区 | 国产成人无码一二三区视频 | 亚洲中文字幕在线观看 | 精品人妻人人做人人爽 | 免费无码午夜福利片69 | 午夜成人1000部免费视频 | 久久99精品久久久久久 | a在线观看免费网站大全 | 精品成在人线av无码免费看 | 日本丰满熟妇videos | 精品熟女少妇av免费观看 | 中文字幕+乱码+中文字幕一区 | 日韩av无码一区二区三区 | 国产成人综合美国十次 | 在线成人www免费观看视频 | 日本va欧美va欧美va精品 | 日韩精品无码免费一区二区三区 | 欧美熟妇另类久久久久久多毛 | 中文字幕中文有码在线 | 99精品国产综合久久久久五月天 | 日日噜噜噜噜夜夜爽亚洲精品 | 丝袜足控一区二区三区 | 国产极品美女高潮无套在线观看 | 亚洲成a人片在线观看无码3d | аⅴ资源天堂资源库在线 | 伊人久久大香线蕉av一区二区 | 国产精品沙发午睡系列 | 久久精品女人天堂av免费观看 | 日韩欧美群交p片內射中文 | 国内精品人妻无码久久久影院 | 无人区乱码一区二区三区 | 亚洲精品国产精品乱码视色 | 婷婷综合久久中文字幕蜜桃三电影 | 久久午夜无码鲁丝片 | 亚洲精品成a人在线观看 | 欧美熟妇另类久久久久久不卡 | 久久 国产 尿 小便 嘘嘘 | 精品国产精品久久一区免费式 | 天天综合网天天综合色 | 人人妻人人澡人人爽人人精品 | √8天堂资源地址中文在线 | 国产香蕉尹人视频在线 | 天天躁夜夜躁狠狠是什么心态 | 亚洲日韩中文字幕在线播放 | 国产疯狂伦交大片 | 台湾无码一区二区 | 国内精品久久毛片一区二区 | 97精品人妻一区二区三区香蕉 | 亚洲人成网站色7799 | 国产精品亚洲专区无码不卡 | 男女下面进入的视频免费午夜 | 精品国产一区二区三区四区在线看 | 中文精品无码中文字幕无码专区 | 天堂在线观看www | 大屁股大乳丰满人妻 | 久激情内射婷内射蜜桃人妖 | 国产精品第一区揄拍无码 | 亚洲色大成网站www国产 | 亚洲欧洲日本无在线码 | 欧美35页视频在线观看 | 欧美阿v高清资源不卡在线播放 | 玩弄中年熟妇正在播放 | 麻豆果冻传媒2021精品传媒一区下载 | 成在人线av无码免观看麻豆 | 少妇激情av一区二区 | 无码免费一区二区三区 | 国产真实乱对白精彩久久 | 一本久久a久久精品亚洲 | 美女毛片一区二区三区四区 | 国产无遮挡又黄又爽免费视频 | 国产网红无码精品视频 | 国产一精品一av一免费 | 牲欲强的熟妇农村老妇女 | 亚洲一区二区三区国产精华液 | 亚洲熟妇色xxxxx欧美老妇y | 久久国产精品精品国产色婷婷 | 欧美兽交xxxx×视频 | 亚洲 a v无 码免 费 成 人 a v | 精品乱码久久久久久久 | 日韩av无码中文无码电影 | av人摸人人人澡人人超碰下载 | 国产在线精品一区二区高清不卡 | 亲嘴扒胸摸屁股激烈网站 | 久久无码专区国产精品s | 国内精品人妻无码久久久影院 | 日韩精品无码免费一区二区三区 | 国产成人无码一二三区视频 | 亚洲自偷精品视频自拍 | 97久久精品无码一区二区 | 亚洲精品一区二区三区在线观看 | 动漫av一区二区在线观看 | 成人精品视频一区二区三区尤物 | 小鲜肉自慰网站xnxx | 国产成人无码a区在线观看视频app | 真人与拘做受免费视频 | 亚洲中文字幕久久无码 | 国产一区二区三区精品视频 | 无套内谢的新婚少妇国语播放 | 色诱久久久久综合网ywww | 男人和女人高潮免费网站 | 少妇无套内谢久久久久 | 性色欲网站人妻丰满中文久久不卡 | 日本熟妇大屁股人妻 | 成在人线av无码免费 | 无遮无挡爽爽免费视频 | 98国产精品综合一区二区三区 | 中文字幕av伊人av无码av | 荡女精品导航 | 俺去俺来也在线www色官网 | 久久99精品久久久久久动态图 | 亚洲 a v无 码免 费 成 人 a v | 亚洲午夜久久久影院 | 午夜男女很黄的视频 | 一本无码人妻在中文字幕免费 | 精品一区二区不卡无码av | 欧洲美熟女乱又伦 | 青草青草久热国产精品 | 中文字幕乱码亚洲无线三区 | 久久国产36精品色熟妇 | 亚洲国产日韩a在线播放 | 欧美成人午夜精品久久久 | 人妻有码中文字幕在线 | 少妇高潮喷潮久久久影院 | 国产熟妇高潮叫床视频播放 | 55夜色66夜色国产精品视频 | 精品久久久无码人妻字幂 | 男女性色大片免费网站 | 欧美一区二区三区视频在线观看 | 亚洲精品国产第一综合99久久 | 国产无遮挡又黄又爽又色 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 亚洲精品一区二区三区四区五区 | 欧美日韩一区二区免费视频 | 久久精品国产99久久6动漫 | 亚洲日韩一区二区 | 麻豆果冻传媒2021精品传媒一区下载 | 在线天堂新版最新版在线8 | 精品 日韩 国产 欧美 视频 | aa片在线观看视频在线播放 | 熟女俱乐部五十路六十路av | 日本xxxx色视频在线观看免费 | 亚洲aⅴ无码成人网站国产app | 欧美成人午夜精品久久久 | 日本精品人妻无码免费大全 | 亚洲va中文字幕无码久久不卡 | 免费无码肉片在线观看 | 亲嘴扒胸摸屁股激烈网站 | 成人aaa片一区国产精品 | 国产无遮挡又黄又爽又色 | 在线成人www免费观看视频 | 国模大胆一区二区三区 | 风流少妇按摩来高潮 | 天堂亚洲免费视频 | 久久精品女人天堂av免费观看 | 亚洲精品一区二区三区在线观看 | 久久99久久99精品中文字幕 | 5858s亚洲色大成网站www | 日产国产精品亚洲系列 | 2019nv天堂香蕉在线观看 | 久久精品人人做人人综合 | 午夜成人1000部免费视频 | 国产色视频一区二区三区 | 日日摸日日碰夜夜爽av | 中文字幕av伊人av无码av | 欧美日韩综合一区二区三区 | 成人影院yy111111在线观看 | 亚洲s码欧洲m码国产av | 日韩无码专区 | 国内精品久久毛片一区二区 | 婷婷五月综合激情中文字幕 | 日韩亚洲欧美中文高清在线 | 99久久久无码国产aaa精品 | 国精品人妻无码一区二区三区蜜柚 | 无码任你躁久久久久久久 | 人妻与老人中文字幕 | 人妻少妇精品无码专区二区 | 少妇邻居内射在线 | 在线欧美精品一区二区三区 | 国产婷婷色一区二区三区在线 | 国产日产欧产精品精品app | 伊人久久大香线蕉午夜 | 国产高潮视频在线观看 | 国产乱人偷精品人妻a片 | 97精品国产97久久久久久免费 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 久久视频在线观看精品 | 日日碰狠狠躁久久躁蜜桃 | 亚洲自偷自拍另类第1页 | 水蜜桃色314在线观看 | 亚洲精品一区二区三区四区五区 | 精品国产乱码久久久久乱码 | 2020久久超碰国产精品最新 | 色婷婷欧美在线播放内射 | 野狼第一精品社区 | 九月婷婷人人澡人人添人人爽 | 亚洲成a人片在线观看无码3d | 狂野欧美性猛xxxx乱大交 | 在线观看欧美一区二区三区 | 荫蒂被男人添的好舒服爽免费视频 | 对白脏话肉麻粗话av | 中国女人内谢69xxxxxa片 | 国产xxx69麻豆国语对白 | 亚洲人成人无码网www国产 | 久青草影院在线观看国产 | 国产婷婷色一区二区三区在线 | 少妇性荡欲午夜性开放视频剧场 | 亚洲国产日韩a在线播放 | 中文字幕无码日韩专区 | 老熟妇乱子伦牲交视频 | 国产亚洲tv在线观看 | 高清国产亚洲精品自在久久 | 夜先锋av资源网站 | 美女张开腿让人桶 | 少妇被黑人到高潮喷出白浆 | 欧美 丝袜 自拍 制服 另类 | 人妻天天爽夜夜爽一区二区 | 成年女人永久免费看片 | 2019午夜福利不卡片在线 | 久久久www成人免费毛片 | 欧美阿v高清资源不卡在线播放 | 亚洲成av人影院在线观看 | 国产精品igao视频网 | 亚洲经典千人经典日产 | 国产精品国产自线拍免费软件 | 精品成人av一区二区三区 | 黑人巨大精品欧美一区二区 | 日韩精品乱码av一区二区 | 男人扒开女人内裤强吻桶进去 | 亚洲精品无码人妻无码 | 色婷婷av一区二区三区之红樱桃 | 久久婷婷五月综合色国产香蕉 | 中文亚洲成a人片在线观看 | 国产无套内射久久久国产 | 日本免费一区二区三区最新 | 午夜肉伦伦影院 | 四虎永久在线精品免费网址 | 亚洲欧美国产精品专区久久 | 国产人妻人伦精品 | 亚洲一区二区三区播放 | 国产福利视频一区二区 | 亚洲一区二区三区在线观看网站 | 在线观看免费人成视频 | 成人欧美一区二区三区黑人 | 1000部啪啪未满十八勿入下载 | 欧美成人午夜精品久久久 | 中文字幕人妻丝袜二区 | 久久精品无码一区二区三区 | 亚洲国产精品一区二区美利坚 | 亚洲色欲色欲欲www在线 | 欧美人与禽zoz0性伦交 | 天堂无码人妻精品一区二区三区 | 日韩 欧美 动漫 国产 制服 | 国产人妖乱国产精品人妖 | 久久精品中文字幕一区 | 伊人久久婷婷五月综合97色 | 久久久av男人的天堂 | 国产成人一区二区三区在线观看 | 精品国产青草久久久久福利 | 99久久久无码国产aaa精品 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 精品无码国产自产拍在线观看蜜 | 国产片av国语在线观看 | 久久综合九色综合97网 | 日本熟妇浓毛 | 男女作爱免费网站 | 熟妇人妻无码xxx视频 | 伦伦影院午夜理论片 | 精品人妻中文字幕有码在线 | 丰满少妇高潮惨叫视频 | 国精产品一品二品国精品69xx | 日韩人妻无码一区二区三区久久99 | 女人被男人爽到呻吟的视频 | 人人澡人人妻人人爽人人蜜桃 | 狂野欧美性猛交免费视频 | 亚洲の无码国产の无码影院 | 中国大陆精品视频xxxx | 日韩精品无码一区二区中文字幕 | 人人妻人人藻人人爽欧美一区 | 久久国产精品偷任你爽任你 | 福利一区二区三区视频在线观看 | 男女作爱免费网站 | 婷婷六月久久综合丁香 | 精品欧洲av无码一区二区三区 | 日本护士xxxxhd少妇 | 久久精品中文字幕一区 | 久久久婷婷五月亚洲97号色 | a国产一区二区免费入口 | 欧美xxxx黑人又粗又长 | 国产人妻久久精品二区三区老狼 | 永久黄网站色视频免费直播 | 中文字幕精品av一区二区五区 | 久久人人97超碰a片精品 | 中文字幕乱妇无码av在线 | 麻豆果冻传媒2021精品传媒一区下载 | 亲嘴扒胸摸屁股激烈网站 | 欧美性生交活xxxxxdddd | 理论片87福利理论电影 | 白嫩日本少妇做爰 | 国产一区二区三区影院 | 久久zyz资源站无码中文动漫 | 亚洲无人区一区二区三区 | 在线 国产 欧美 亚洲 天堂 | 曰韩少妇内射免费播放 | 国产熟女一区二区三区四区五区 | 熟妇人妻激情偷爽文 | 无码国内精品人妻少妇 | 国内综合精品午夜久久资源 | 波多野结衣高清一区二区三区 | 无码国模国产在线观看 | 亚洲色在线无码国产精品不卡 | 亚洲欧美国产精品专区久久 | 久久精品国产日本波多野结衣 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 中文字幕无码免费久久9一区9 | 大色综合色综合网站 | 日韩av无码中文无码电影 | 丰满少妇熟乱xxxxx视频 | 精品熟女少妇av免费观看 | 又大又硬又黄的免费视频 | 激情综合激情五月俺也去 | 无码中文字幕色专区 | 国产精品久久久久9999小说 | 国产精品福利视频导航 | 久久久精品成人免费观看 | 国产成人久久精品流白浆 | 人人妻人人澡人人爽欧美精品 | 久精品国产欧美亚洲色aⅴ大片 | 国产精品理论片在线观看 | 东京热无码av男人的天堂 | 国产午夜福利亚洲第一 | 一本久道高清无码视频 | 三级4级全黄60分钟 | 四虎永久在线精品免费网址 | 中文字幕无码免费久久9一区9 | √天堂资源地址中文在线 | 一本一道久久综合久久 | 玩弄少妇高潮ⅹxxxyw | 日韩人妻无码中文字幕视频 | 色欲久久久天天天综合网精品 | 成人欧美一区二区三区黑人 | 狠狠色噜噜狠狠狠7777奇米 | 午夜成人1000部免费视频 | 亚洲综合色区中文字幕 | 成人欧美一区二区三区 | 色诱久久久久综合网ywww | 欧美激情内射喷水高潮 | 免费人成在线视频无码 | 婷婷丁香五月天综合东京热 | 熟女体下毛毛黑森林 | 在线天堂新版最新版在线8 | 国产精品久久久av久久久 | 国产熟妇高潮叫床视频播放 | 久久精品99久久香蕉国产色戒 | 国产精品亚洲а∨无码播放麻豆 | 亚洲熟熟妇xxxx | 天干天干啦夜天干天2017 | 青草青草久热国产精品 | 丰满少妇高潮惨叫视频 | 色一情一乱一伦一区二区三欧美 | 日本护士毛茸茸高潮 | 天天燥日日燥 | 国产免费久久久久久无码 | 中文字幕无码热在线视频 | 精品无人国产偷自产在线 | 亚洲一区二区三区含羞草 | 亚洲a无码综合a国产av中文 | 国产农村乱对白刺激视频 | 自拍偷自拍亚洲精品被多人伦好爽 | 性色欲网站人妻丰满中文久久不卡 | 国产精品多人p群无码 | 黑人巨大精品欧美黑寡妇 | 亚洲一区二区三区四区 | 色五月五月丁香亚洲综合网 | 久久亚洲中文字幕无码 | 亚洲熟妇色xxxxx欧美老妇 | 亚洲综合无码一区二区三区 | 在线观看欧美一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | 麻豆蜜桃av蜜臀av色欲av | 日韩无套无码精品 | 无码福利日韩神码福利片 | 97精品人妻一区二区三区香蕉 | av在线亚洲欧洲日产一区二区 | 性欧美牲交在线视频 | 欧美老妇交乱视频在线观看 | 欧美人与物videos另类 | 人妻互换免费中文字幕 | 中文字幕无码日韩专区 | 精品久久久久香蕉网 | 狠狠色欧美亚洲狠狠色www | 18精品久久久无码午夜福利 | 国产三级精品三级男人的天堂 | 日本精品人妻无码免费大全 | 久久精品中文字幕一区 | 熟女少妇在线视频播放 | 国产亚洲美女精品久久久2020 | 国产又粗又硬又大爽黄老大爷视 | 精品欧美一区二区三区久久久 | 伊人久久大香线焦av综合影院 | a在线亚洲男人的天堂 | 一二三四社区在线中文视频 | 国产乱子伦视频在线播放 | 蜜桃臀无码内射一区二区三区 | 国产精品久免费的黄网站 | 天天做天天爱天天爽综合网 | 狠狠色噜噜狠狠狠狠7777米奇 | 精品无码av一区二区三区 | 欧洲欧美人成视频在线 | 精品无人国产偷自产在线 | 又黄又爽又色的视频 | 国产极品美女高潮无套在线观看 | 日本精品人妻无码免费大全 | 国产精品资源一区二区 | 激情国产av做激情国产爱 | 麻豆国产丝袜白领秘书在线观看 | 捆绑白丝粉色jk震动捧喷白浆 | 丁香啪啪综合成人亚洲 | 国产麻豆精品精东影业av网站 | 天堂在线观看www | 亚洲色成人中文字幕网站 | 乱人伦人妻中文字幕无码久久网 | 一本一道久久综合久久 | 国产午夜手机精彩视频 | 亚洲国产av美女网站 | 丰满少妇熟乱xxxxx视频 | 天堂久久天堂av色综合 | 色窝窝无码一区二区三区色欲 | 亚洲中文字幕成人无码 | 国产亚洲欧美日韩亚洲中文色 | 国产偷国产偷精品高清尤物 | 99麻豆久久久国产精品免费 | 97资源共享在线视频 | 久久综合狠狠综合久久综合88 | 欧美性猛交xxxx富婆 | 国产偷自视频区视频 | 一本久久伊人热热精品中文字幕 | 九九热爱视频精品 | 国产成人无码专区 | 无码福利日韩神码福利片 | 性啪啪chinese东北女人 | 四虎影视成人永久免费观看视频 | 久久国产精品二国产精品 | 欧美 丝袜 自拍 制服 另类 | 国产一精品一av一免费 | 亚洲精品一区二区三区大桥未久 | 久久久久免费看成人影片 | 成人无码影片精品久久久 | 国产成人无码av一区二区 | 激情爆乳一区二区三区 | 老子影院午夜伦不卡 | 欧美精品一区二区精品久久 | 国产亲子乱弄免费视频 | 日本熟妇人妻xxxxx人hd | 国产精品毛片一区二区 | 精品国产国产综合精品 | 国产亚av手机在线观看 | 美女黄网站人色视频免费国产 | 玩弄人妻少妇500系列视频 | 久久国语露脸国产精品电影 | 亚洲一区二区三区偷拍女厕 | 亚洲爆乳精品无码一区二区三区 | 久久久无码中文字幕久... | 2019午夜福利不卡片在线 | 国产欧美亚洲精品a | 亚洲人成影院在线无码按摩店 | 亚洲国产成人a精品不卡在线 | 久久99精品国产麻豆蜜芽 | 狂野欧美性猛xxxx乱大交 | 久久99精品国产.久久久久 | 国产suv精品一区二区五 | 人人澡人人透人人爽 | 高清无码午夜福利视频 | 黑人巨大精品欧美一区二区 | 67194成是人免费无码 | 亚洲熟妇色xxxxx欧美老妇y | 乱人伦人妻中文字幕无码 | 无码国产色欲xxxxx视频 | 露脸叫床粗话东北少妇 | 亚洲日本在线电影 | 久9re热视频这里只有精品 | 丁香啪啪综合成人亚洲 | 理论片87福利理论电影 | 国产精品视频免费播放 | 久久精品中文闷骚内射 | 国产成人无码av在线影院 | 天堂а√在线中文在线 | 成熟人妻av无码专区 | 激情国产av做激情国产爱 | 一本加勒比波多野结衣 | 久久久久久国产精品无码下载 | 亚洲啪av永久无码精品放毛片 | 欧美激情综合亚洲一二区 | 小sao货水好多真紧h无码视频 | 国产香蕉尹人视频在线 | 欧美日韩亚洲国产精品 | 成熟妇人a片免费看网站 | 成人一在线视频日韩国产 | 无码中文字幕色专区 | 日韩精品一区二区av在线 | 亚洲人成网站色7799 | 青草视频在线播放 | 又大又硬又爽免费视频 | 少妇被粗大的猛进出69影院 | 成年美女黄网站色大免费全看 | 精品久久久中文字幕人妻 | 欧美成人家庭影院 | 亚洲欧美国产精品久久 | 欧洲vodafone精品性 | 亚洲精品无码国产 | 中文字幕人成乱码熟女app | 男女超爽视频免费播放 | 少妇厨房愉情理9仑片视频 | 精品国产av色一区二区深夜久久 | 樱花草在线社区www | 荫蒂被男人添的好舒服爽免费视频 | 少妇太爽了在线观看 | 1000部啪啪未满十八勿入下载 | a在线亚洲男人的天堂 | 无码国产激情在线观看 | 扒开双腿吃奶呻吟做受视频 | 美女毛片一区二区三区四区 | 欧美亚洲国产一区二区三区 | 人人爽人人爽人人片av亚洲 | 国产香蕉尹人视频在线 | 激情爆乳一区二区三区 | 国产特级毛片aaaaaaa高清 | 又大又硬又爽免费视频 | 亚洲精品久久久久久一区二区 | 亚洲s码欧洲m码国产av | 97资源共享在线视频 | 性欧美videos高清精品 | 亚无码乱人伦一区二区 | 亚洲午夜福利在线观看 | 欧美亚洲国产一区二区三区 | 亚洲欧美国产精品久久 | 在线视频网站www色 | 亚洲国产精品无码一区二区三区 | 欧美日韩在线亚洲综合国产人 | 国产 浪潮av性色四虎 | 成人影院yy111111在线观看 | 久久无码专区国产精品s | 久久亚洲中文字幕无码 | 76少妇精品导航 | 少妇高潮喷潮久久久影院 | 色五月丁香五月综合五月 | 日韩亚洲欧美中文高清在线 | 久久人人爽人人爽人人片av高清 | 日本精品久久久久中文字幕 | 久久综合给久久狠狠97色 | 国产亚洲人成a在线v网站 | 丁香花在线影院观看在线播放 | 麻豆果冻传媒2021精品传媒一区下载 | 少妇高潮喷潮久久久影院 | 欧美老人巨大xxxx做受 | 国产精品第一区揄拍无码 | 国产三级精品三级男人的天堂 | 国产无遮挡又黄又爽又色 | 伊人久久大香线蕉午夜 | 精品人人妻人人澡人人爽人人 | 波多野结衣av在线观看 | 激情五月综合色婷婷一区二区 | 最新国产麻豆aⅴ精品无码 | 国产人妻精品一区二区三区 | 精品国产av色一区二区深夜久久 | 久久视频在线观看精品 | 性生交大片免费看女人按摩摩 | 国精产品一区二区三区 | 精品久久久无码人妻字幂 | 曰韩少妇内射免费播放 | 亚洲午夜无码久久 | 亚洲国产欧美日韩精品一区二区三区 | 精品无人区无码乱码毛片国产 | 天下第一社区视频www日本 | 天海翼激烈高潮到腰振不止 | 亚洲人成网站色7799 | 亚洲午夜福利在线观看 | 免费中文字幕日韩欧美 | 国产亚洲精品久久久久久国模美 | 久久无码专区国产精品s | 国产亚洲精品久久久ai换 | 少妇性俱乐部纵欲狂欢电影 | 日本熟妇浓毛 | 精品国产aⅴ无码一区二区 | 国产农村乱对白刺激视频 | 丰满诱人的人妻3 | 东京热男人av天堂 | 亚洲熟妇色xxxxx欧美老妇y | 欧美freesex黑人又粗又大 | 天天躁日日躁狠狠躁免费麻豆 | 国产人妻精品一区二区三区不卡 | 少妇高潮喷潮久久久影院 | 精品亚洲成av人在线观看 | 色妞www精品免费视频 | 日产国产精品亚洲系列 | 精品国产一区二区三区四区在线看 | 又粗又大又硬又长又爽 | 性欧美牲交xxxxx视频 | 97夜夜澡人人双人人人喊 | 成人免费视频一区二区 | 亚洲欧洲无卡二区视頻 | 午夜精品久久久久久久久 | 亚洲乱码中文字幕在线 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国语自产偷拍精品视频偷 | 免费看男女做好爽好硬视频 | 欧美日韩视频无码一区二区三 | 在线看片无码永久免费视频 | 亚洲一区二区三区四区 | 亚洲天堂2017无码 | 欧美大屁股xxxxhd黑色 | 综合人妻久久一区二区精品 | 久久久久成人精品免费播放动漫 | 男女下面进入的视频免费午夜 | 免费观看又污又黄的网站 | 欧美性黑人极品hd | 人人妻人人澡人人爽人人精品 | 日本一卡2卡3卡四卡精品网站 | 无码av中文字幕免费放 | 波多野结衣一区二区三区av免费 | 丝袜 中出 制服 人妻 美腿 | 国产偷抇久久精品a片69 | 欧美 丝袜 自拍 制服 另类 | 天天综合网天天综合色 | 国产福利视频一区二区 | 又湿又紧又大又爽a视频国产 | 亚洲经典千人经典日产 | 一本一道久久综合久久 | 国产亲子乱弄免费视频 | 国产成人精品无码播放 | 国产精品久久久久9999小说 | 国产亚洲人成a在线v网站 | 三上悠亚人妻中文字幕在线 | 无码人妻少妇伦在线电影 | 婷婷六月久久综合丁香 | 人人妻人人澡人人爽欧美一区 | 少妇性l交大片欧洲热妇乱xxx | 蜜桃av抽搐高潮一区二区 | 欧美性生交活xxxxxdddd | 日韩欧美中文字幕在线三区 | 在线视频网站www色 | 给我免费的视频在线观看 | 精品无码国产一区二区三区av | 国产人妻精品一区二区三区 | 巨爆乳无码视频在线观看 | 久久人人97超碰a片精品 | av在线亚洲欧洲日产一区二区 | 亚洲精品一区二区三区四区五区 | 亚洲国产精品一区二区第一页 | 亚洲小说春色综合另类 | 东京热一精品无码av | 色综合久久久久综合一本到桃花网 | 黑人巨大精品欧美一区二区 | 日韩亚洲欧美中文高清在线 | 国产偷国产偷精品高清尤物 | 国精产品一区二区三区 | 国产两女互慰高潮视频在线观看 | 日本一区二区三区免费播放 | 性色欲网站人妻丰满中文久久不卡 | 亚洲人成影院在线观看 | 中文字幕久久久久人妻 | 久久亚洲日韩精品一区二区三区 | 兔费看少妇性l交大片免费 | 窝窝午夜理论片影院 | 水蜜桃亚洲一二三四在线 | 97夜夜澡人人双人人人喊 | 亚洲va欧美va天堂v国产综合 | www国产亚洲精品久久久日本 | 又湿又紧又大又爽a视频国产 | 国产人妻人伦精品1国产丝袜 | 亚洲熟妇色xxxxx欧美老妇 | 久久久国产一区二区三区 | 精品欧洲av无码一区二区三区 | 国产明星裸体无码xxxx视频 | 熟女少妇在线视频播放 | 国产亚洲精品久久久久久国模美 | 欧美日韩综合一区二区三区 | 午夜丰满少妇性开放视频 | 亚洲精品一区三区三区在线观看 | 国产免费久久久久久无码 | 久久亚洲a片com人成 | 国产午夜亚洲精品不卡下载 | 中文字幕乱码人妻二区三区 | 国产精品亚洲а∨无码播放麻豆 | 九九热爱视频精品 | 欧美日韩久久久精品a片 | 成人亚洲精品久久久久软件 | 亚洲中文字幕在线观看 | 国産精品久久久久久久 | 又大又硬又黄的免费视频 | 青草青草久热国产精品 | 大乳丰满人妻中文字幕日本 | 亚洲国产欧美日韩精品一区二区三区 | 中文毛片无遮挡高清免费 | 无遮挡国产高潮视频免费观看 | 亚洲综合色区中文字幕 | 亚洲精品国产精品乱码不卡 | 99久久久国产精品无码免费 | 成人精品视频一区二区 | 国产精品内射视频免费 | 人人澡人人妻人人爽人人蜜桃 | 强伦人妻一区二区三区视频18 | 亚洲 另类 在线 欧美 制服 | 亚欧洲精品在线视频免费观看 | 亚洲狠狠色丁香婷婷综合 | 久激情内射婷内射蜜桃人妖 | 妺妺窝人体色www婷婷 | 国内揄拍国内精品人妻 | 天海翼激烈高潮到腰振不止 | 亚洲欧美日韩综合久久久 | 国产精品无码永久免费888 | 成人精品天堂一区二区三区 | 亚洲一区二区三区国产精华液 | 国产成人无码午夜视频在线观看 | 欧美性生交活xxxxxdddd | 久久久婷婷五月亚洲97号色 | aa片在线观看视频在线播放 | 欧美乱妇无乱码大黄a片 | 夜精品a片一区二区三区无码白浆 | 无码国模国产在线观看 | 成人亚洲精品久久久久软件 | 国产精品久久久久久久影院 | 亚洲码国产精品高潮在线 | 中文字幕无线码 | 久久久久久九九精品久 | 亚洲乱码国产乱码精品精 | 熟妇人妻中文av无码 | 初尝人妻少妇中文字幕 | 一本加勒比波多野结衣 | 久久亚洲国产成人精品性色 | av香港经典三级级 在线 | 人人妻人人澡人人爽精品欧美 | 色五月五月丁香亚洲综合网 | 国精产品一区二区三区 | 国产又粗又硬又大爽黄老大爷视 | 又大又硬又爽免费视频 | 无码人妻精品一区二区三区下载 | 天堂在线观看www | 人妻少妇精品无码专区动漫 | 久久这里只有精品视频9 | 久久久精品人妻久久影视 | 国产一区二区不卡老阿姨 | 人人澡人人妻人人爽人人蜜桃 | 女人被男人躁得好爽免费视频 | 国产欧美亚洲精品a | 成 人 网 站国产免费观看 | 午夜男女很黄的视频 | 色综合久久久无码中文字幕 | 精品无码av一区二区三区 | 国产成人一区二区三区别 | 午夜福利一区二区三区在线观看 | 亚洲熟妇色xxxxx亚洲 | 东京热一精品无码av | 老司机亚洲精品影院无码 | 亚洲国产精品无码一区二区三区 | 国产激情综合五月久久 | 欧美高清在线精品一区 | 一本大道伊人av久久综合 | 成在人线av无码免观看麻豆 | 亚洲啪av永久无码精品放毛片 | 99久久婷婷国产综合精品青草免费 | 又大又硬又爽免费视频 | 国产精品.xx视频.xxtv | 人妻少妇精品视频专区 | 欧美猛少妇色xxxxx | 亚洲经典千人经典日产 | 亚洲中文无码av永久不收费 | 无码人妻黑人中文字幕 | 成人欧美一区二区三区黑人免费 | 日本一卡二卡不卡视频查询 | 黑人粗大猛烈进出高潮视频 | 国产偷抇久久精品a片69 | 久久综合色之久久综合 | 日韩精品无码免费一区二区三区 | 夜夜躁日日躁狠狠久久av | 日本精品人妻无码77777 天堂一区人妻无码 | 内射欧美老妇wbb | 天下第一社区视频www日本 | 欧美兽交xxxx×视频 | 中文字幕无码人妻少妇免费 | 亚洲精品一区三区三区在线观看 | 中文字幕人妻无码一夲道 | 蜜臀aⅴ国产精品久久久国产老师 | 老司机亚洲精品影院 | 中文字幕乱码中文乱码51精品 | 人妻天天爽夜夜爽一区二区 | 青青青爽视频在线观看 | 日韩精品无码一区二区中文字幕 | 日本爽爽爽爽爽爽在线观看免 | 全球成人中文在线 | 国产精品久久精品三级 | 俺去俺来也在线www色官网 | 久久久久亚洲精品男人的天堂 | 亚洲综合精品香蕉久久网 | 国产一区二区三区影院 | 性欧美videos高清精品 | 99re在线播放 | 强伦人妻一区二区三区视频18 | 两性色午夜视频免费播放 | 东京热男人av天堂 | 中文精品无码中文字幕无码专区 | 国产精品爱久久久久久久 | 无码国模国产在线观看 | 无码精品国产va在线观看dvd | 精品偷拍一区二区三区在线看 | 亚洲日韩一区二区 | 国语精品一区二区三区 | 少妇一晚三次一区二区三区 | 国语精品一区二区三区 | 国产精品久久久一区二区三区 | 亚洲色大成网站www | 欧洲美熟女乱又伦 | 4hu四虎永久在线观看 | 日日天干夜夜狠狠爱 | 全球成人中文在线 | 国产亚洲精品久久久久久久久动漫 | 色诱久久久久综合网ywww | 亚洲a无码综合a国产av中文 | 亚洲国产精品无码久久久久高潮 | 亚洲国产高清在线观看视频 | 夜夜影院未满十八勿进 | 国产激情无码一区二区 | 狂野欧美性猛交免费视频 | 在线精品亚洲一区二区 | 欧美国产日韩久久mv | 蜜桃臀无码内射一区二区三区 | 俺去俺来也在线www色官网 | 久久久中文久久久无码 | 成在人线av无码免观看麻豆 | 无码人妻久久一区二区三区不卡 | 日韩亚洲欧美中文高清在线 | 成人aaa片一区国产精品 | 成人无码视频在线观看网站 | 1000部啪啪未满十八勿入下载 | 欧美35页视频在线观看 | 精品人妻av区 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 乱人伦人妻中文字幕无码 | 装睡被陌生人摸出水好爽 | 国产在热线精品视频 | 丰满人妻一区二区三区免费视频 | 免费国产成人高清在线观看网站 | 青草视频在线播放 | 精品国产成人一区二区三区 | 久久无码中文字幕免费影院蜜桃 | 午夜时刻免费入口 | 国产成人综合在线女婷五月99播放 | 国产亚洲美女精品久久久2020 | 日韩精品久久久肉伦网站 | 正在播放东北夫妻内射 | 国语精品一区二区三区 | 久久久久亚洲精品中文字幕 | 色偷偷人人澡人人爽人人模 | 激情综合激情五月俺也去 | 国产精品无码一区二区桃花视频 | 久久亚洲精品中文字幕无男同 | 曰本女人与公拘交酡免费视频 | 亚洲区欧美区综合区自拍区 | 亚洲大尺度无码无码专区 | 又大又黄又粗又爽的免费视频 | 国产精品久久久 | 久久99精品久久久久久 | 欧美熟妇另类久久久久久多毛 | 日本va欧美va欧美va精品 | 精品乱子伦一区二区三区 | 东京热男人av天堂 | 中文精品无码中文字幕无码专区 | 青青久在线视频免费观看 | 精品国产一区二区三区四区在线看 | 国产黑色丝袜在线播放 | 性做久久久久久久久 | 精品国产精品久久一区免费式 | 18无码粉嫩小泬无套在线观看 | 天天做天天爱天天爽综合网 | 欧洲vodafone精品性 | 亚洲色偷偷偷综合网 | 亚洲第一无码av无码专区 | 国产精品久久久久久亚洲影视内衣 | 国产黄在线观看免费观看不卡 | 麻豆成人精品国产免费 | 国产精品无码永久免费888 | 国产福利视频一区二区 | 人妻熟女一区 | 精品国产aⅴ无码一区二区 | 欧美日韩久久久精品a片 | 国产成人无码av在线影院 | 日本爽爽爽爽爽爽在线观看免 | 无码人妻精品一区二区三区不卡 | 国内揄拍国内精品人妻 | 99er热精品视频 | 小sao货水好多真紧h无码视频 | 亚洲成色www久久网站 | 日韩精品成人一区二区三区 | 久久精品人人做人人综合 | 久久综合激激的五月天 | 中文无码精品a∨在线观看不卡 | 欧美真人作爱免费视频 | 又大又紧又粉嫩18p少妇 | 大肉大捧一进一出好爽视频 | 人人妻人人澡人人爽精品欧美 | 成人精品视频一区二区三区尤物 | 国产精品-区区久久久狼 | 在线播放无码字幕亚洲 | 东北女人啪啪对白 | 国产午夜福利亚洲第一 | 欧美日韩在线亚洲综合国产人 | 欧美大屁股xxxxhd黑色 | 亚洲精品一区二区三区婷婷月 | 亚洲色成人中文字幕网站 | 未满小14洗澡无码视频网站 | 最近免费中文字幕中文高清百度 | 国产国语老龄妇女a片 | 国产精品福利视频导航 | 久久亚洲国产成人精品性色 | 日本丰满护士爆乳xxxx | 日本熟妇人妻xxxxx人hd | 日韩人妻无码中文字幕视频 | 成人影院yy111111在线观看 | 99麻豆久久久国产精品免费 | 中文字幕精品av一区二区五区 | 大肉大捧一进一出视频出来呀 | 久久99热只有频精品8 | 东北女人啪啪对白 | 国产av一区二区精品久久凹凸 | 内射欧美老妇wbb | 亚洲精品综合一区二区三区在线 | 欧美国产亚洲日韩在线二区 | 99久久精品无码一区二区毛片 | 久在线观看福利视频 | 亚洲午夜福利在线观看 | 亚洲综合另类小说色区 | 狠狠躁日日躁夜夜躁2020 | 高中生自慰www网站 | 国产高清av在线播放 | 亚洲精品成a人在线观看 | 无码人妻精品一区二区三区下载 | 色欲久久久天天天综合网精品 | 精品人妻人人做人人爽 | 大地资源中文第3页 | 国产香蕉尹人综合在线观看 | 性啪啪chinese东北女人 | 亚洲乱码中文字幕在线 | 成年女人永久免费看片 | 人妻少妇被猛烈进入中文字幕 | 人人澡人人妻人人爽人人蜜桃 | 领导边摸边吃奶边做爽在线观看 | а天堂中文在线官网 | 久久精品99久久香蕉国产色戒 | 欧美性色19p | 亚洲熟女一区二区三区 | 熟女俱乐部五十路六十路av | 久久久国产精品无码免费专区 | 中文字幕中文有码在线 | 国产熟女一区二区三区四区五区 | 亚洲人成影院在线观看 | 成在人线av无码免观看麻豆 | 国产精品免费大片 | 丁香花在线影院观看在线播放 | 无码人妻av免费一区二区三区 | 色欲综合久久中文字幕网 | 亚洲欧美中文字幕5发布 | 永久免费观看国产裸体美女 | 熟妇激情内射com | 久久久国产一区二区三区 | 亚洲成熟女人毛毛耸耸多 | 欧美性色19p | 亚洲国产精品久久久天堂 | 国产一区二区三区四区五区加勒比 | 精品无码国产一区二区三区av | 久久久久久av无码免费看大片 | 日产精品99久久久久久 | 精品午夜福利在线观看 | 亚洲国产av精品一区二区蜜芽 | 久久午夜无码鲁丝片 | 影音先锋中文字幕无码 | 国精品人妻无码一区二区三区蜜柚 | 久久久久se色偷偷亚洲精品av | 亚洲乱亚洲乱妇50p | www成人国产高清内射 | 久久亚洲日韩精品一区二区三区 | 国产凸凹视频一区二区 | 男女猛烈xx00免费视频试看 | 国产精品多人p群无码 | 日本乱偷人妻中文字幕 | 乱人伦人妻中文字幕无码 | 天天摸天天透天天添 | 日本在线高清不卡免费播放 | 99久久精品日本一区二区免费 | 国产卡一卡二卡三 | 久久久久99精品国产片 | 精品人人妻人人澡人人爽人人 | 日本va欧美va欧美va精品 | 无码av免费一区二区三区试看 | 中文字幕色婷婷在线视频 | 天海翼激烈高潮到腰振不止 | 熟女少妇人妻中文字幕 | 久久精品丝袜高跟鞋 | 内射欧美老妇wbb | 国产成人无码一二三区视频 | 亚洲欧美中文字幕5发布 | 国产一区二区三区精品视频 | 搡女人真爽免费视频大全 | 久久国产精品偷任你爽任你 | 日本乱偷人妻中文字幕 | 精品国偷自产在线视频 | 日韩人妻无码一区二区三区久久99 | 国产成人综合美国十次 | 扒开双腿吃奶呻吟做受视频 | 国产莉萝无码av在线播放 | 亚洲小说春色综合另类 | 色老头在线一区二区三区 | 日日摸夜夜摸狠狠摸婷婷 | 麻豆人妻少妇精品无码专区 | 中文字幕无码av波多野吉衣 | 免费网站看v片在线18禁无码 | 97人妻精品一区二区三区 | 亚洲人成影院在线无码按摩店 | 欧美自拍另类欧美综合图片区 | 亚洲熟妇色xxxxx欧美老妇y | 亚洲 a v无 码免 费 成 人 a v | av无码电影一区二区三区 | 国产美女精品一区二区三区 | 亚洲国产欧美国产综合一区 | 亚洲另类伦春色综合小说 | 波多野结衣乳巨码无在线观看 | 国内精品九九久久久精品 | 捆绑白丝粉色jk震动捧喷白浆 | 久久国产精品偷任你爽任你 | 日本一区二区三区免费播放 | 又紧又大又爽精品一区二区 | 亚洲成在人网站无码天堂 | 亚洲中文字幕在线观看 | 1000部啪啪未满十八勿入下载 | 强伦人妻一区二区三区视频18 | av香港经典三级级 在线 | 波多野结衣av一区二区全免费观看 | 奇米影视888欧美在线观看 | 67194成是人免费无码 | 亚洲第一无码av无码专区 | 在线欧美精品一区二区三区 | 动漫av一区二区在线观看 | 中文字幕无码视频专区 | 欧美日韩亚洲国产精品 | 性生交大片免费看女人按摩摩 | 亚洲 欧美 激情 小说 另类 | 亚洲精品一区二区三区在线 | √天堂资源地址中文在线 | 99久久久无码国产aaa精品 | 欧美丰满老熟妇xxxxx性 | 欧美激情内射喷水高潮 | 三上悠亚人妻中文字幕在线 | 波多野结衣aⅴ在线 | 少妇太爽了在线观看 | 波多野结衣aⅴ在线 | 香港三级日本三级妇三级 | 亚洲精品一区二区三区大桥未久 | 国产真实乱对白精彩久久 | 18精品久久久无码午夜福利 | 国产麻豆精品精东影业av网站 | 亚洲人亚洲人成电影网站色 | 久久国内精品自在自线 | 亚洲区欧美区综合区自拍区 | 午夜嘿嘿嘿影院 | 日韩人妻系列无码专区 | 日本一卡二卡不卡视频查询 | 四虎永久在线精品免费网址 | 人妻天天爽夜夜爽一区二区 | 久久精品国产99久久6动漫 | 日本一区二区三区免费高清 | 国内精品人妻无码久久久影院 | 免费观看黄网站 | 无人区乱码一区二区三区 | 欧美肥老太牲交大战 | 欧美一区二区三区 | 偷窥日本少妇撒尿chinese | 偷窥村妇洗澡毛毛多 | 牲欲强的熟妇农村老妇女 | 最近中文2019字幕第二页 | 欧美精品无码一区二区三区 | 一个人看的www免费视频在线观看 | 精品无码一区二区三区爱欲 | 国产成人人人97超碰超爽8 | 亚洲色在线无码国产精品不卡 | 人人妻人人澡人人爽人人精品浪潮 | 少妇被黑人到高潮喷出白浆 | 精品偷自拍另类在线观看 | 夜夜躁日日躁狠狠久久av | 美女极度色诱视频国产 | 一个人看的www免费视频在线观看 | аⅴ资源天堂资源库在线 | 无码av中文字幕免费放 | 国产又爽又黄又刺激的视频 | 国产精品亚洲五月天高清 | 无码人妻久久一区二区三区不卡 | 亚洲 a v无 码免 费 成 人 a v | a片在线免费观看 | 国产欧美熟妇另类久久久 | 免费看男女做好爽好硬视频 | 无码av免费一区二区三区试看 | 国产成人一区二区三区在线观看 | 色一情一乱一伦一视频免费看 | 黄网在线观看免费网站 | 狠狠色丁香久久婷婷综合五月 | 久久精品人人做人人综合试看 | 亚洲午夜福利在线观看 | 国产片av国语在线观看 | 我要看www免费看插插视频 | 老熟女重囗味hdxx69 | 国产一区二区三区四区五区加勒比 | 婷婷丁香五月天综合东京热 | 国产精品久久久久9999小说 | 国产一区二区三区四区五区加勒比 | 精品无人区无码乱码毛片国产 | √天堂中文官网8在线 | 日日鲁鲁鲁夜夜爽爽狠狠 | 国产精华av午夜在线观看 | 99久久人妻精品免费二区 | 亚洲精品一区国产 | 国产成人精品久久亚洲高清不卡 | 给我免费的视频在线观看 | 国产国产精品人在线视 | 大乳丰满人妻中文字幕日本 | 老司机亚洲精品影院 | 成在人线av无码免观看麻豆 | 亚洲一区二区三区在线观看网站 | 俺去俺来也www色官网 | 俺去俺来也www色官网 | 伊人久久大香线焦av综合影院 |