html tool

2019年7月8日星期一

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中的大致差不多。


没有评论:

发表评论