• 引言

关于快速重启和关闭计算机,网上有不少软件在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 shutdownIoConfigureCrashDump(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 actionsArguments: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)         //传入的参数为0hal!HalReturnToFirmware+0x13:
fffff800`05412d7b 3bcd            cmp     ecx,ebp
fffff800`05412d7d 7419            je      hal!HalReturnToFirmware+0x30 (fffff800`05412d98)        //传入的参数为1,跳转到hal!HalpShutdownhal!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],cxhal!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 oncetypedef 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);
}

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

  1. Windows驱动开发学习记录- x86 InlineHook字节数计算(使用Hook Api lib 0.4 for C)

    Hook Api lib 0.4 for C原文及源代码地址链接 < [原创]Hook Api lib 0.4 for C > 一.使用背景 最新在学习SSDT Inline Hook,一 ...

  2. Windows驱动开发学习笔记(七)—— 多核同步内核重载

    Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...

  3. Windows驱动开发学习笔记(六)—— Inline HOOK

    Windows驱动开发学习笔记(六)-- Inline HOOK SSDT HOOK Inline Hook 挂钩 执行流程 脱钩 实验一:3环 Inline Hook 实验二:0环 Inline H ...

  4. Windows驱动开发学习笔记(五)—— SSDT HOOK

    Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...

  5. Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)

    Windows驱动开发学习笔记(四)-- 3环与0环通信(常规方式) 设备对象 创建设备对象 设置数据交互方式 创建符号链接 IRP与派遣函数 IRP的类型 其它类型的IRP 派遣函数 派遣函数注册位 ...

  6. Windows驱动开发学习笔记(三)—— 内核空间内核模块

    Windows驱动开发学习笔记(三)-- 内核空间&内核模块 内核空间 实验 第一步:编译如下代码 第二步:将 .sys 文件拷贝到虚拟机中 第三步:部署 .sys 文件并运行 第四步:创建一 ...

  7. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

  8. Windows驱动开发学习笔记(一)—— 环境配置第一个驱动程序

    Windows驱动开发学习笔记(一)-- 环境配置&第一个驱动程序 环境配置 第一个驱动程序 环境配置 安装VS2010:https://pan.baidu.com/s/1uZWWxCtB60 ...

  9. windows驱动开发学习

    序言]  很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资 料少有关系.大多学的驱动开发资料都以英文为主,这样让很多驱动初学者很头疼.本人从 事驱动开发时间不长也不短, ...

最新文章

  1. Qt Linguist基于文本ID的翻译
  2. UG集成显卡 显示成烂面
  3. 征战蓝桥 —— 2013年第四届 —— C/C++A组第10题——大臣的旅费
  4. 别放任这些小毛病不管!它会扩大还会造成重大危险
  5. 优化 Azure 成本,实现财务目标
  6. spring(1)Spring之旅
  7. wireless 时好时断的一些解决的建议
  8. OpenCV-图像处理(27、模板匹配(Template Match))
  9. vs2012程序打包部署下载InstallShield2015LimitedEdition的下载及安装打包整套教程
  10. 用户流量红利消退的下半场,淘宝如何保持高速增长?
  11. Mysql 中英文排序
  12. 中图分类法----O 数理科学和化学
  13. 关于Java单例模式的思考
  14. linux 从samba拷贝,提升samba复制速度,树莓派外接硬盘读取从40M到110M(2020-11-15更新)...
  15. 目录遍历,PHP 遍历一个文件夹下所有文件和子文件夹的方法
  16. python生成桌面路径(winreg)
  17. 牛客网软件测试面试题总结
  18. 爬虫day3,通过爬虫有道翻译实现汉译英
  19. 广义可加模型GAM在python上的复现
  20. 草根网站的不完全的建设规划

热门文章

  1. 蛊惑者马云发家史(曾推毛氏运动唐僧团队)三
  2. 计算机键盘打字基础知识,电脑打字基础知识,新手自学【入门篇】
  3. oj2783: 编程题A-按要求输入输出
  4. SML中的local
  5. 二极管、三极管、晶闸管的区别
  6. xctf攻防世界 MISC高手进阶区 Banmabanma
  7. Windows7 Ubuntu 双系统安装卸载工具备份
  8. 建成 5000 多间「梦想中心」后,他们决定将技术开源
  9. SEO 已死,LLMO 万岁
  10. springboot 2.x学习实践 <一>