• ReactOs是怎么实现系统调用的。。 老毛文章学习笔记


    1. stub函数

    __declspec(naked) __stdcall

    NtReadFile(

    {

           __asm {

                  push       ebp

                  mov ebp, esp

                  mov eax,152           // 系统调用号

                  lea   edx, 8[ebp]     // lea  edx, [ebp +8]   ,这样edx 便指向了用户空间堆栈第一个参数的地址

                  int    0x2E             //系统自陷指令。。进入内核。。。

                  pop ebp               // 恢复堆栈

                  ret   9

           }

    }

    2. 系统初始化 系统调用门的代码:

    VOID INIT_FUNCTION

    KeInitExceptions(VOID)

    /*

     * FUNCTION: Initalize CPU exception handling

     */

    {

       ……

       set_trap_gate(0, (ULONG)KiTrap0, 0);

       set_trap_gate(1, (ULONG)KiTrap1, 0);

       set_trap_gate(2, (ULONG)KiTrap2, 0);

       set_trap_gate(3, (ULONG)KiTrap3, 3);

       ……

       set_system_call_gate(0x2d,(int)interrupt_handler2d);

       set_system_call_gate(0x2e,(int)KiSystemService);

    }

    3.所以在cpu自陷到内核中时,便执行KiSystemService.  KiSystemService的工作有两个:

    1. 使用edx把参数从用户地址空间中拷贝到内核堆栈中。

    2. 根据eax在SSDT或Shadow SSDT中找到系统调用的起始地址..

    1) 先判断在系统调用在哪个SSDT中

    说明:     

      在windows中有 KeServiceDescriptorTable保存了SSDT的相关内容。。早期windows只有一个SSDT , 我称为MainSSDT , 后来把GDI的东西移到内核win32k.sys后又实用了一个SSDT。。称为Shadow SSDT 所以共有两个SSDT。。Main SSDT保存的系统调用号都小于x01000, 后一个大于0x1000, 而mainSSDT大约有248个系统调用。。。  Shadow SSDT有600多调用....

    所以把系统调用右移8位然后与0x10便知道使用哪个SSDT 了。。。。

     

    2) 根据系统调用号知道找到函数的地址 。。

    分析下KiSystemService的代码:(看到AT&T的汇编 就头大。。。 )

     

     

        /* Construct a trap frame on the stack */

        /* Error code */
        pushl $0    
        pushl %ebp
        pushl %ebx
        pushl %esi
        pushl %edi
        pushl %fs
        /* Load PCR selector into fs */
        movl  $PCR_SELECTOR, %ebx
        movl  %ebx, %fs

        /* Save the old exception list */
        movl         %fs:KPCR_EXCEPTION_LIST, %ebx
        pushl %ebx
        /* Put the exception handler chain terminator */
        movl         $0xffffffff, %fs:KPCR_EXCEPTION_LIST
        /* Get a pointer to the current thread */
        movl         %fs:KPCR_CURRENT_THREAD, %esi
        /* Save the old previous mode */
        movl         $0, %ebx
        movb         %ss:KTHREAD_PREVIOUS_MODE(%esi), %bl
        pushl        %ebx
               /* Set the new previous mode based on the saved CS selector */
        movl         0x24(%esp), %ebx
        cmpl         $KERNEL_CS, %ebx
        jne          L1
        movb         $KernelMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
        jmp          L3
    L1:
        movb         $UserMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
    L3:

        /* Save other registers */   
        pushl %eax
        pushl %ecx
        pushl %edx
        pushl %ds
        pushl %es
        pushl %gs
        pushl $0     /* DR7 */
        pushl $0     /* DR6 */
        pushl $0     /* DR3 */
        pushl $0     /* DR2 */
        pushl $0     /* DR1 */
        pushl $0     /* DR0 */
        pushl $0     /* XXX: TempESP */
        pushl $0     /* XXX: TempCS */
        pushl $0     /* XXX: DebugPointer */
        pushl $0     /* XXX: DebugArgMark */
        pushl $0     /* XXX: DebugEIP */
        pushl $0     /* XXX: DebugEBP */

               /* Load the segment registers */
        movl  $KERNEL_DS, %ebx
        movl  %ebx, %ds
        movl  %ebx, %es
        movl  %ebx, %gs

               /* Save the old trap frame pointer (over the EDX register??) */
               movl KTHREAD_TRAP_FRAME(%esi), %ebx
        movl %ebx, 0x3C(%esp)
     
        /* Save a pointer to the trap frame in the TCB */
        movl %esp, KTHREAD_TRAP_FRAME(%esi)
     
               /*  Set ES to kernel segment  */
               movw $KERNEL_DS,%bx
               movw %bx,%es

               /*  Allocate new Kernel stack frame  */
               movl %esp,%ebp

               /*  Users's current stack frame pointer is source  */
               movl %edx,%esi

               /*  Determine system service table to use  */            //决定使用哪个SSDT
               cmpl  $0x0fff, %eax                                               //判断系统调用号是否大约0x1000
               ja    new_useShadowTable

               /*  Check to see if EAX is valid/inrange  */
               cmpl  %es:_KeServiceDescriptorTable + 8, %eax
               jbe   new_serviceInRange
               movl  $STATUS_INVALID_SYSTEM_SERVICE, %eax
               jmp   new_done

    new_serviceInRange:

               /*  Allocate room for argument list from kernel stack  */
               movl  %es:_KeServiceDescriptorTable + 12, %ecx
               movl  %es:(%ecx, %eax, 4), %ecx
               subl  %ecx, %esp

               /*  Copy the arguments from the user stack to the kernel stack  */
               movl %esp,%edi                               //堆栈拷贝
               rep  movsb

               /*  DS is now also kernel segment  */
               movw %bx, %ds
       
        /* Call system call hook */
        pushl %eax
        call _KiSystemCallHook
        popl %eax

               /*  Make the system service call  */
               movl  %es:_KeServiceDescriptorTable, %ecx
               movl  %es:(%ecx, %eax, 4), %eax                         //系统调用的函数的起始地址    系统调用号* 4
               call  *%eax

    #if CHECKED
               /*  Bump Service Counter  */
    #endif

               /*  Deallocate the kernel stack frame  */
               movl %ebp,%esp

        /* Call the post system call hook and deliver any pending APCs */
        pushl %ebp
        pushl %eax
        call _KiAfterSystemCallHook
        addl $8,%esp

               jmp  new_done

    new_useShadowTable:

               subl  $0x1000, %eax

               /*  Check to see if EAX is valid/inrange  */
               cmpl  %es:_KeServiceDescriptorTableShadow + 24, %eax
               jbe   new_shadowServiceInRange
               movl  $STATUS_INVALID_SYSTEM_SERVICE, %eax
               jmp   new_done

    new_shadowServiceInRange:

               /*  Allocate room for argument list from kernel stack  */
               movl  %es:_KeServiceDescriptorTableShadow + 28, %ecx
               movl  %es:(%ecx, %eax, 4), %ecx
               subl  %ecx, %esp

               /*  Copy the arguments from the user stack to the kernel stack  */
               movl %esp,%edi
               rep movsb

               /*  DS is now also kernel segment  */
               movw %bx,%ds

        /* Call system call hook */
        pushl %eax
        call _KiSystemCallHook
               popl %eax
     
               /*  Make the system service call  */
               movl  %es:_KeServiceDescriptorTableShadow + 16, %ecx
               movl  %es:(%ecx, %eax, 4), %eax
               call  *%eax

    #if CHECKED
               /*  Bump Service Counter  */
    #endif

               /*  Deallocate the kernel stack frame  */
               movl %ebp,%esp

        /* Call the post system call hook and deliver any pending APCs */
        pushl %esp
        pushl %eax
        call _KiAfterSystemCallHook
        addl $8,%esp

    new_done:

               /* Restore the user context */
        /* Get a pointer to the current thread */
               movl %fs:0x124, %esi
     
               /* Restore the old trap frame pointer */
               movl 0x3c(%esp), %ebx
        movl %ebx, KTHREAD_TRAP_FRAME(%esi)
     
        /* Skip debug information and unsaved registers */
        addl $0x30, %esp
        popl %gs
        popl %es
        popl %ds
        popl %edx
        popl %ecx
        addl $0x4, %esp   /* Don't restore eax */

        /* Restore the old previous mode */
        popl %ebx
        movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)

        /* Restore the old exception handler list */
        popl %ebx
        movl %ebx, %fs:KPCR_EXCEPTION_LIST
     
        popl %fs
        popl %edi
        popl %esi
        popl %ebx
        popl %ebp
        addl $0x4, %esp  /* Ignore error code */
      
               iret

     

  • 相关阅读:
    1363:小球(drop)
    ifstream ofstream c++中读写文件
    线性筛
    Network of Schools POJ
    Beautiful numbers CodeForces
    ipone6界面设计标准
    目前的前端框架有哪些
    什么是react native
    nth-child() 选择器
    html{height:100%}的意义以及body背景色的解析推断
  • 原文地址:https://www.cnblogs.com/herso/p/1516933.html
Copyright © 2020-2023  润新知