KeDetachProcess与KeAttachProcess的使用场景
KeDetachProcess
-
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-kedetachprocess
The KeDetachProcess routine is exported to support existing driver binaries and is obsolete. Use KeUnstackDetachProcess instead
[popexizhi:
https://blog.csdn.net/dasgk/article/details/17741289
KeDetachProcess
当线程从新的进程中脱离时(KeDetachProcess), 任何在新的进程地址空间中等待执行的未决的内核APCs被派发执行。随后SavedApcState 域的内容被拷贝回ApcState域。SavedApcState 域的内容被清空,线程的ApcStateIndex域被设为OriginalApcEnvironment,ApcStatePointer域更新,当前进程上下文切换到线程所属进程。
Dettach时,先派发APC State里面的APC,然后再恢复,也就是挂靠过程中线程被插apc现在要集中解决
[popexizhi: 总结一下,这里KeDetachProcess,是在 KeAttachProcess完成后,将线程从新的进程中脱离过程,这里要先处理APC队列,之后再恢复ApcState域]
]
code 分析
- + -
KeAttachProcess
KiAttachProcess - KeAttachProcess仅仅是对这个函数的封装
KiSwapProcess - 更换地址空间。(本质上就是重新加载CR3)
SwapContext - 更换上下文。一般不管地址空间的切换,只调整线程上下文。
KiSwapThred - 切换到链表中的下一个线程(SwapContext)调用
-
-----------------------------------------------------------------------------
/************************ KeAttachProcess ***************************/
// just wrapper
//
KeAttachProcess(EPROCESS *Process)
{
KiAttachProcess(Process,KeRaiseIrqlToSynchLevel);
}
/************************ KiAttachProcess ***************************/
KiAttachProcess(EPROCESS *Process,Irql){
//CurThread=fs:124h
//CurProcess=CurThread->ApcState.Process;
if(CurProcess!=Process){
//[popexizhi: 如果要attach 的process非当前进程,才如下操作:]
if(CurProcess->ApcStateIndex || KPCR->DpcRoutineActive)KeBugCheckEx...
//[popexizhi:如果当前进程有Apc状态的索引,这个应该是进入apc列表了 CurProcess->ApcStateIndex
//或者: KPCR 中 有DPC队列,这个是cpu的队列,这里注意是判断是不是这两种软中断中,如果是后面就KeBugCheckEx.. ,传说的系统崩溃吗?
//]
}
//if we already in process's context,
//[popexizhi: 要attach 的process 就是当前进程,恢复lrql,返回就ok,不用特殊处理了]
if(CurProcess==Process){KiUnlockDispatcherDatabase(Irql);return;}
Process->StackCount++;//[?-ok 1- 这是堆栈计数增加一个吗? 不是,参见下文]
// 注意代码中的Process->StackCount与进程的“堆栈”并无关系,而是指进程挂靠的嵌套深度。
// http://www.voidcn.com/article/p-umtyvddi-qc.html
KiMoveApcState(&CurThread->ApcState,&CurThread->SavedApcState);//[ 2-KiMoveApcState, 将当前线程的APC状态保持到SavedApcState中
// http://codewarrior.cn/ntdoc/win2k/ke/KiMoveApcState.htm
// This function moves the APC state from the source structure to the
// destination structure and reinitializes list headers as appropriate.
// init lists
CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0]; //[?]3 这里的ApcListHead[01].[Blink,Flink]分别是什么,这操作的目的是?
/* [popexizhi: 自己在另外的版本中查到的初始化如下: 这里的InitializeListHead与下面的区别是什么,只是这里做封装了吗?]
InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); //ApcState被初始化
InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
*/
CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0]; //[?]3 这里的ApcListHead[01].[Blink,Flink]分别是什么,这操作的目的是?
CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0];
CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1];
CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];;
//fill curtheads's fields
CurThread->ApcState.Process=Process;
//
CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0];
CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1];
CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];;
//fill curtheads's fields
CurThread->ApcState.Process=Process;
CurThread->ApcState.KernelApcInProgress=0;
CurThread->ApcState.KernelApcPending=0;
CurThread->ApcState.UserApcPending=0;
CurThread->ApcState.ApcStatePointer.SavedApcState=&CurThread->SavedApcState;
CurThread->ApcState.ApcStatePointer.ApcState=&CurThread->ApcState;
CurThread->ApcStateIndex=1;
//if process ready, just swap it...
if(!Process->State)//state==0, ready
{
KiSwapProcess(Process,CurThread->SavedApcState.Process);
KiUnlockDispatcherDatabase(Irql);
return;
}
CurThread->State=1; //ready?
CurThread->ProcessReadyQueue=1;
//put Process in Thread's waitlist
CurThread->WaitListEntry.Flink=&Process->ReadyListHead.Flink;
CurThread->WaitListEntry.Blink=Process->ReadyListHead.Blink;
Process->ReadyListHead.Flink->Flink=&CurThread->WaitListEntry.Flink;
Process->ReadyListHead.Blink=&CurThread->WaitListEntry.Flink;
// else, move process to swap list and wait
if(Process->State==1){//idle?
Process->State=2; //trans
Process->SwapListEntry.Flink=&KiProcessInSwapListHead.Flink;
Process->SwapListEntry.Blink=KiProcessInSwapListHead.Blink;
KiProcessInSwapListHead.Blink=&Process->SwapListEntry.Flink;
KiSwapEvent.Header.SignalState=1;
if(KiSwapEvent.Header.WaitListHead.Flink!=&KiSwapEvent.Header.WaitListHead.
Flink)
KiWaitTest(&KiSwapEvent,0xa); //fastcall
}
CurThread->WaitIrql=Irql;
KiSwapThread();
return;
}
从这个函数可以得到以下结论。进程可以处于以下状态——0(准备),1(Idle),2(Tra
ns——切换)。这证实了高层次的信息。KiAttachProcess使用了另外两个函数KiSwapProce
ss和KiSwapThread。
/************************* KiSwapProcess ****************************/
KiSwapProcess(EPROCESS* NewProcess, EPROCESS* OldProcess)
{
// just reload cr3 and small work with TSS
// TSS=KPCR->TSS;
// xor eax,eax
// mov gs,ax
TSS->CR3=NewProcess->DirectoryTableBase;//0x1c
// mov cr3,NewProcess->DirectoryTableBase
TSS->IopmOffset=NewProcess->IopmOffset;//0x66
if(WORD(NewProcess->LdtDescriptor)==0){lldt 0x00; return;//}
//GDT=KPCR->GDT;
(QWORD)GDT->0x48=(QWORD)NewProcess->LdtDescriptor;
(QWORD)GDT->0x108=(QWORD)NewProcess->Int21Descriptor;
lldt 0x48;
return;
}
切换进程上下文。正如我所料,这个函数只是重新加载CR3寄存器,再加上一点相关的操作。
例如,用IopmOffset域的值建立TSS中的I/O位图的偏移。还必需将选择子的值加载到ldt(只
用于VDM session)。
/************************* SwapContext ******************************/
SwapContext(NextThread,CurThread,WaitIrql)
{
NextThread.State=ThreadStateRunning; //2
KPCR.DebugActive=NextThread.DebugActive;
cli();
//Save Stack
CurThread.KernelStack=esp;
//Set stack
KPCR.StackLimit=NextThread.StackLimit;
KPCR.StackBase=NextThread.InitialStack;
tmp=NextThread.InitialStack-0x70;
newcr0=cr0&0xfffffff1|NextThread.NpxState|*(tmp+0x6c);
if(newcr0!=cr0)reloadcr0();
if(!*(tmp-0x1c)&0x20000)tmp-=0x10;
TSS=KPCB.TSS;
TSS->ESP0=tmp;
//set pTeb
KPCB.Self=NextThread.pTeb;
esp=NextThread.KernelStack;
sti();
//correct GDT
GDT=KPCB.GDT;
WORD(GDT->0x3a)=NextThread.pTeb;
BYTE(GDT->0x3c)=NextThread.pTeb>>16;
BYTE(GDT->0x3f)=NextThread.pTeb>>24;
//if we must swap processes, do it (like KiSwapProcess)
if(CurThread.ApcState.Process!=NextThread.ApcState.Process)
{
//******** like KiSwapProcess
}
NextThread->ContextSwitches++;
KPCB->KeContextSwitches++;
if(!NextThread->ApcState.KernelApcPending)return 0;
//popf;
// jnz HalRequestSoftwareInterrupt// return 0
return 1;
}
切换堆栈,修正GDT,以使FS寄存器指向TEB。如果线程属于当前进程,则不进行上下文切换
。否则,进行的操作和KiSwapProcess中的大致差不多。
没有评论:
发表评论