Windows驱动开发学习记录-驱动中快速重启关闭计算机之一

  •  引言

        关于快速重启和关闭计算机,网上有不少软件在Ring3下调用ZwShutdownSystem (NtShutdownSystem)来实现,虽然速度很快,但还至少经历一些流程,比如向设备驱动发送停机通知等。以下内容摘自<<深入解析Windows操作系统 第6版(下册)>>  P528:

        一旦Csrss已经完成了向系统进程传达系统停机的通知,Winlogon最后调用执行体子系统函数 NtShutdownSystem,从而结束停机过程。 NtShutdownSystem 函数又调用 PoSetSystemPowerState函数,来协调设备驱动程序和执行体子系统其余部分(即插即用管理器、电源管理器、执行体、I/O管理器、配置管理器和内存管理器)的停机处理。
        例如,PoSetSystemPowerState调用I/O管理器,以便给那些已经请求过停机通知的所有设备驱动程序发送停机I/O包。这一动作使得设备驱动程序有机会在Windows退出以前执行任何必要的特殊处理。工作者线程的内存栈被换入,配置管理器将任何修改过的注册表数据刷新到磁盘上,内存管理器将所有己修改过的且包含了文件数据的页面写回到它们各自的文件中。如果“在停机时清除页面文件”的选项已被打开,那么,内存管理器在这时候清除页面文件。I/O管理器还会被再次调用,以便告诉文件系统驱动程序;系统正在进行停机。系统停机过程最终在电源管理器中结束。电源管理器所执行的动作取决于用户指定的是停机、重新引导,还是关闭电源。

         可以看到调用NtShutdownSystem还有不少处理的东西,所以我在想能不能调用更底层的实现来更快速的关机。

        再者有些防止关机的程序也是Hook了NtShutdownSystem,我们想办法用更底层的实现可以绕过Hook,不过话说已经在内核层驱动了,有啥不能干的呢^_^。

  • NtShutdownSystem分析

        下面的分析主要采用ReactOS、WindowsXP的代码以及Windbg调试:

<<ReactOS>>
NTSTATUS
NTAPI
NtShutdownSystem(IN SHUTDOWN_ACTION Action)
{
    POWER_ACTION PowerAction;

    /* Convert to power action */
    if (Action == ShutdownNoReboot)
    {
        PowerAction = PowerActionShutdown;
    }
    else if (Action == ShutdownReboot)
    {
        PowerAction = PowerActionShutdownReset;
    }
    else if (Action == ShutdownPowerOff)
    {
        PowerAction = PowerActionShutdownOff;
    }
    else
    {
        return STATUS_INVALID_PARAMETER;
    }

    /* Now call the power manager */
    DPRINT("Setting state to: %lx\n", PowerAction);
    return NtSetSystemPowerState(PowerAction,
                                 PowerSystemSleeping3,
                                 POWER_ACTION_OVERRIDE_APPS |
                                 POWER_ACTION_DISABLE_WAKES |
                                 POWER_ACTION_CRITICAL);
}

        这里调试的是NtSetSystemPowerState,再来看看NtSetSystemPowerState的实现(截取主要内容),可以看出最终调用PopGracefulShutdown

<<Windows XP>>
NTSYSAPI
NTSTATUS
NTAPI
NtSetSystemPowerState (
    IN POWER_ACTION SystemAction,
    IN SYSTEM_POWER_STATE LightestSystemState,
    IN ULONG Flags                  // POWER_ACTION_xxx flags
    )
{
    KPROCESSOR_MODE         PreviousMode;
    ......
    CmSetLazyFlushState(FALSE);
    ......
    if (PopAction.Shutdown) {

		//
		// Force reacquisition of the dev list. We will be telling Pnp
		// to unload all possible devices, and therefore Pnp needs us to
		// release the Pnp Engine Lock.
		//
		IoFreePoDeviceNotifyList(&PopAction.DevState->Order);
		PopAction.DevState->GetNewDeviceList = TRUE;

		//
		// We shut down via a system worker thread so that the
		// current active process will exit cleanly.
		//

		if (PsGetCurrentProcess() != PsInitialSystemProcess) {

			ExInitializeWorkItem(&PopShutdownWorkItem,
								 &PopGracefulShutdown,
								 NULL);

			ExQueueWorkItem(&PopShutdownWorkItem,
							PO_SHUTDOWN_QUEUE);

			// Clean up in prep for wait...
			ASSERT(!PolicyLockOwned);

			//
			// If we acquired the timer refresh lock (can happen if we promoted to shutdown)
			// then we need to release it so that suspend actually suspends.
			//
			if (TimerRefreshLockOwned) {
				ExReleaseTimeRefreshLock();
			}

			// And sleep until we're terminated.

			// Note that we do NOT clean up the dev state -- it's now
			// owned by the shutdown worker thread.

			// Note that we also do not unlock the pagable image
			// section referred to by ExPageLockHandle -- this keeps
			// all of our shutdown code in memory.

			KeSuspendThread(KeGetCurrentThread());

			return STATUS_SYSTEM_SHUTDOWN;
		} else {
			PopGracefulShutdown (NULL);
		}
    }
    ......

}

        接着再看PopGracefulShutdown,可以看到这里也做了很多,IO管理器的关闭,配置管理器的关闭,缓存管理器的关闭等。在这里修改的文件、注册表等信息将被写到磁盘。最终调用PopShutdownSystem

<<Windows XP>>
VOID
PopGracefulShutdown (
    IN PVOID WorkItemParameter
    )
{
    PVOID         Context;
    ......
    if (PoCleanShutdownEnabled()) {
        //
        // Terminate all processes.  This will close all the handles and delete
        // all the address spaces.  Note the system process is kept alive.
        //
        PsShutdownSystem ();

        ......

    }
    //
    // Terminate Plug-N-Play.
    //

    PpShutdownSystem (TRUE, 0, &Context);

    ExShutdownSystem (0);

    //
    // Send shutdown IRPs to all drivers that asked for it.
    //

    IoShutdownSystem (0);
    
    //
    // Scrub the object directories
    //
    if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
        ObShutdownSystem (0);
    }

    //
    // Close the registry and the associated handles/file objects.
    //
    CmShutdownSystem ();
    
    ......
    
    MmShutdownSystem (0);

    //
    // Inform drivers of the system shutdown state.
    // This will finish shutting down Io and Mm.
    // After this is complete,
    // NO MORE REFERENCES TO PAGABLE CODE OR DATA MAY BE MADE.
    //

    // ISSUE-2000/03/14-earhart: shutdown filesystems in dev shutdown
    IoConfigureCrashDump(CrashDumpDisable);
    CcWaitForCurrentLazyWriterActivity();
    ExShutdownSystem(1);
    IoShutdownSystem(1);
    MmShutdownSystem(1);

    ......

    HalSetWakeEnable(FALSE);

    ......

    PpShutdownSystem (TRUE, 1, &Context);

    ExShutdownSystem (2);

    if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
        ObShutdownSystem (2);
    }

    //
    // Any allocated pool left at this point is a leak.
    //

    MmShutdownSystem (2);

    //
    // Implement shutdown style action -
    // N.B. does not return (will bugcheck in preference to returning).
    //

    PopShutdownSystem(PopAction.Action);
}

        接着看 PopShutdownSystem,可以看出最终调用的是HalReturnToFirmware

<<Windows XP>>
VOID
PopShutdownSystem (
    IN POWER_ACTION SystemAction
    )
/*++

Routine Description:

    Routine to implement a Shutdown style power actions

Arguments:

    SystemAction    - Action to implement (must be a valid shutdown type)

Return Value:

    Status

--*/
{

    //
    // Tell the debugger we are shutting down
    //

    KD_SYMBOLS_INFO SymbolInfo = {0};
    SymbolInfo.BaseOfDll = (PVOID)KD_REBOOT;
    DebugService2(NULL, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);

    //
    // Perform the final shutdown operation
    //

    switch (SystemAction) {
        case PowerActionShutdownReset:

            //
            // Reset the system
            //

            PopInvokeSystemStateHandler (PowerStateShutdownReset, NULL);

            //
            // Didn't do it, go for legacy function
            //

            HalReturnToFirmware (HalRebootRoutine);
            break;

        case PowerActionShutdownOff:
        case PowerActionShutdown:


            //
            // Power down the system
            //

            PopInvokeSystemStateHandler (PowerStateShutdownOff, NULL);

            //
            // Didn't do it, go for legacy function
            //

            HalReturnToFirmware (HalPowerDownRoutine);

            //
            // Due to simulations we can try to power down on systems
            // which don't support it
            //

            PoPrint (PO_ERROR, ("PopShutdownSystem: HalPowerDownRoutine returned\n"));
            HalReturnToFirmware (HalRebootRoutine);
            break;

        default:
            //
            // Got some unexpected input...
            //
            HalReturnToFirmware (HalRebootRoutine);
    }

    KeBugCheckEx (INTERNAL_POWER_ERROR, 5, 0, 0, 0);
}
  • HalReturnToFirmware分析

VOID
HalReturnToFirmware(
    IN FIRMWARE_ENTRY Routine
    )



{
    switch (Routine) {
        case HalPowerDownRoutine:

#if defined(NEC_98)

            HalpPowerDownFlag = TRUE;

#endif // defined(NEC_98)

        case HalHaltRoutine:
        case HalRestartRoutine:
        case HalRebootRoutine:

            InbvAcquireDisplayOwnership();

            //
            // Never returns
            //

            HalpReboot();
            break;
        default:
            DbgPrint("HalReturnToFirmware called\n");
            DbgBreakPoint();
            break;
    }
}

        最终调用的是HalpReboot,在xp上,HalpReboot处理一些CMOS数据和PCI数据,就不再深入分析了。

        WinXP下FIRMWARE_ENTRY 定义如下      

typedef enum _FIRMWARE_REENTRY {
        HalHaltRoutine,
        HalPowerDownRoutine,
        HalRestartRoutine,
        HalRebootRoutine,
        HalInteractiveModeRoutine,
        HalMaximumRoutine
} FIRMWARE_REENTRY, * PFIRMWARE_REENTRY;

        HalReturnToFirmware也是我们可调用的最底层接口,因为它是导出的,可以在驱动中直接使用。

        在Win7 x64环境下Windbg反汇编的结果如下,跳转逻辑已用颜色标记出来

1: kd> uf hal!HalReturnToFirmware 
hal!HalReturnToFirmware:
fffff800`05412d68 48895c2408      mov     qword ptr [rsp+8],rbx
fffff800`05412d6d 55              push    rbp
fffff800`05412d6e 4883ec20        sub     rsp,20h
fffff800`05412d72 bd01000000      mov     ebp,1
fffff800`05412d77 85c9            test    ecx,ecx
fffff800`05412d79 7422            je      hal!HalReturnToFirmware+0x35 (fffff800`05412d9d)         //传入的参数为0

hal!HalReturnToFirmware+0x13:
fffff800`05412d7b 3bcd            cmp     ecx,ebp
fffff800`05412d7d 7419            je      hal!HalReturnToFirmware+0x30 (fffff800`05412d98)        //传入的参数为1,跳转到hal!HalpShutdown

hal!HalReturnToFirmware+0x17:
fffff800`05412d7f 7e05            jle     hal!HalReturnToFirmware+0x1e (fffff800`05412d86)       //传入小于0的数值,非法     

hal!HalReturnToFirmware+0x19:
fffff800`05412d81 83f903          cmp     ecx,3
fffff800`05412d84 7e17            jle     hal!HalReturnToFirmware+0x35 (fffff800`05412d9d)        //传入的参数小于等于3,也就是2和3时

hal!HalReturnToFirmware+0x1e:
fffff800`05412d86 488d0d13400100  lea     rcx,[hal! ?? ::FNODOBFM::`string' (fffff800`05426da0)]
fffff800`05412d8d e84e350100      call    hal!DbgPrint (fffff800`054262e0)
fffff800`05412d92 cc              int     3
fffff800`05412d93 e9ca000000      jmp     hal!HalReturnToFirmware+0xfa (fffff800`05412e62)

hal!HalReturnToFirmware+0x30:
fffff800`05412d98 e8cb010000      call    hal!HalpShutdown (fffff800`05412f68)

hal!HalReturnToFirmware+0x35:
fffff800`05412d9d ff1555550100    call    qword ptr [hal!_imp_InbvAcquireDisplayOwnership (fffff800`054282f8)]
fffff800`05412da3 4533c0          xor     r8d,r8d
fffff800`05412da6 8bd5            mov     edx,ebp
fffff800`05412da8 33c9            xor     ecx,ecx
fffff800`05412daa e895230000      call    hal!HalpMapPhysicalMemory64 (fffff800`05415144)
fffff800`05412daf 4885c0          test    rax,rax
fffff800`05412db2 740c            je      hal!HalReturnToFirmware+0x58 (fffff800`05412dc0)

hal!HalReturnToFirmware+0x4c:
fffff800`05412db4 b934120000      mov     ecx,1234h
fffff800`05412db9 66898872040000  mov     word ptr [rax+472h],cx

hal!HalReturnToFirmware+0x58:
fffff800`05412dc0 b9e8030000      mov     ecx,3E8h
fffff800`05412dc5 e8867bffff      call    hal!HalpAcquireCmosSpinLockEx (fffff800`0540a950)
fffff800`05412dca fa              cli
fffff800`05412dcb 803d33f6010000  cmp     byte ptr [hal!HalpTimeSourceInitializationComplete (fffff800`05432405)],0
fffff800`05412dd2 750d            jne     hal!HalReturnToFirmware+0x79 (fffff800`05412de1)

hal!HalReturnToFirmware+0x6c:
fffff800`05412dd4 ba64000000      mov     edx,64h
fffff800`05412dd9 b0fe            mov     al,0FEh
fffff800`05412ddb ee              out     dx,al
fffff800`05412ddc e981000000      jmp     hal!HalReturnToFirmware+0xfa (fffff800`05412e62)

hal!HalReturnToFirmware+0x79:
fffff800`05412de1 ba70000000      mov     edx,70h
fffff800`05412de6 b00b            mov     al,0Bh
fffff800`05412de8 ee              out     dx,al
fffff800`05412de9 8bcd            mov     ecx,ebp
fffff800`05412deb e8085b0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412df0 ba71000000      mov     edx,71h
fffff800`05412df5 ec              in      al,dx
fffff800`05412df6 8ad8            mov     bl,al
fffff800`05412df8 8bcd            mov     ecx,ebp
fffff800`05412dfa e8f95a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412dff 80e3bf          and     bl,0BFh
fffff800`05412e02 ba71000000      mov     edx,71h
fffff800`05412e07 8ac3            mov     al,bl
fffff800`05412e09 ee              out     dx,al
fffff800`05412e0a 8bcd            mov     ecx,ebp
fffff800`05412e0c e8e75a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412e11 ba70000000      mov     edx,70h
fffff800`05412e16 b00a            mov     al,0Ah
fffff800`05412e18 ee              out     dx,al
fffff800`05412e19 8bcd            mov     ecx,ebp
fffff800`05412e1b e8d85a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412e20 ba71000000      mov     edx,71h
fffff800`05412e25 ec              in      al,dx
fffff800`05412e26 8ad8            mov     bl,al
fffff800`05412e28 8bcd            mov     ecx,ebp
fffff800`05412e2a e8c95a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412e2f 80e3f6          and     bl,0F6h
fffff800`05412e32 ba71000000      mov     edx,71h
fffff800`05412e37 80cb06          or      bl,6
fffff800`05412e3a 8ac3            mov     al,bl
fffff800`05412e3c ee              out     dx,al
fffff800`05412e3d 8bcd            mov     ecx,ebp
fffff800`05412e3f e8b45a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412e44 ba70000000      mov     edx,70h
fffff800`05412e49 b015            mov     al,15h
fffff800`05412e4b ee              out     dx,al
fffff800`05412e4c 8bcd            mov     ecx,ebp
fffff800`05412e4e e8a55a0000      call    hal!KeStallExecutionProcessor (fffff800`054188f8)
fffff800`05412e53 e880a30000      call    hal!HalpResetAllProcessors (fffff800`0541d1d8)
fffff800`05412e58 e8d3010000      call    hal!HalpWriteResetCommand (fffff800`05413030)
fffff800`05412e5d e84e390100      call    hal!HalpHalt (fffff800`054267b0)

hal!HalReturnToFirmware+0xfa:
fffff800`05412e62 488b5c2430      mov     rbx,qword ptr [rsp+30h]
fffff800`05412e67 4883c420        add     rsp,20h
fffff800`05412e6b 5d              pop     rbp
fffff800`05412e6c c3              ret

        Win7 x64位下逻辑有所改变,从hal!HalReturnToFirmware+0x79 开始其实就为XP下HalpReboot的具体实现。

  • 代码实现

        综上所述,代码实现就比较简单了:

头文件定义

#pragma once

typedef enum _FIRMWARE_REENTRY {
        HalHaltRoutine,
        HalPowerDownRoutine,
        HalRestartRoutine,
        HalRebootRoutine,
        HalInteractiveModeRoutine,
        HalMaximumRoutine
} FIRMWARE_REENTRY, * PFIRMWARE_REENTRY;

//再定义导出函数 HalReturnToFirmware
EXTERN_C NTKERNELAPI VOID NTAPI HalReturnToFirmware(
        LONG lReturnType
);

实现

VOID ComputerPowerOffByHal()
{
        HalReturnToFirmware(HalPowerDownRoutine);
}

VOID ComputerResetByHal()
{
        HalReturnToFirmware(HalRebootRoutine);
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值