windows 快速關機的原理和實現

來源:互聯網
上載者:User

開啟工作管理員,按住“Ctrl”鍵的同時,再單擊工作管理員視窗中的菜單“關機→關閉”命令時,系統會快速地被關閉,同樣,在按住“Ctrl”鍵時,選擇其他命令(例如重新啟動)時,也會達到快速執行該命令的目的。
  
  同時,也出現了像SuperFast Shutdown一樣的快速關機軟體。
  
  在討論上述技巧原理之前,先說說Windows是如何關機的:Windows關機步驟涉及到Windows多個組件和多個過程,簡單的說,Windows的關機步驟不是大多數人認為的那麼簡單。基本的過程是這樣的:
  
  1. 使用者發起關機指令以後,發起關機指令的程式會通知Windows子系統CSRSS.EXE,CSRSS.EXE收到通知以後會和Winlogon.EXE做一個資料交換,接著由Winlogon.EXE通知CSRSS.EXE開始關閉系統的流程 。
  
  2. CSRSS.EXE收到Winlogon.EXE的通知以後,會依次查詢擁有頂層視窗的使用者進程,讓這些使用者進程退出。如果某一個使用者進程在一個預設的逾時時間5000毫秒(可以通過修改註冊表索引值HKEY_CURRENT_USER/Cont rol Panel/Desktop/ HungAppTimeout設定逾時時間)內沒有退出的話,Windows會顯示一個結束任務對話方塊用於詢問使用者是否結束這個任務。預設情況下將顯示這個對話方塊並一直保持而不會自動關閉。對於控制台程式來說,基本情況類似,只不過Windows使用HK EY_CURRENT_USER/Control Panel/Desktop/ WaitToKillAppTimeout值來設定逾時時間。
  
  3. 接著是輪到終止系統進程了。系統進程包括SMSS.EXE、Winlogon.EXE、Lsass.EXE等。Windows在終止系統進程的時候並不像終止使用者進程那樣如果無法在規定時間內終止則提示使用者,而是跳過這個進程,去執行下一個系統 進程的終止操作。使用的逾時時間和第2步使用的時間相同。
  
  上述3個步驟是整個Windows關機過程中最耗費時間的一段,大多數關機緩慢的原因都是因為這3個步驟引起的。完成前3個步驟以後,進入了關機操作的第4個階段,也是最後一個階段。
  
  4. Winlogon.EXE調用一個原生API函數NtShutdownSystem()來命令系統執行後面的掃尾工作。在這個階段裡面,Windows執行子系統會完成最後的關機操作,例如:裝置驅動在這個階段裡面完成一些驅動設定的特殊操作; 也是在這個階段,組態管理系統將被修改過的註冊表資料會寫到磁碟裡面。等除了電源管理以後的全部子系統完成退出以後,電源管理完成最後的操作:如重啟、關機等。
  
  瞭解了Windows的關機流程以後,下面分析一下前面說的快速關機操作是怎麼完成的。先分析一下SuperFast Shutdown的原理,SuperFast Shutdown是使用Visual Basic編寫的,體積很小,就15KB,經過分析以後得出一個令人驚訝的結論:SuperFast Shutdown首先使用RtlAdjustPrivilege()提升自己的許可權,然後直接調用NtShutdownSystem() 函數來完成關機過程。由於跳過了最為耗費時間的前3個步驟而直接進入第4個步驟,所以造成了能夠很快關機的假象。
  
  再看看工作管理員的快速關機是如何?的:分析結果也是類似於SuperFast Shutdown的原理,也是通過省略一些步驟來加快關機的速度。

 

那麼,為什麼在快速關機以後會出現設定丟失的情況呢?原因在於前3個步驟裡面有一個讓進程正常退出的可能。大多數軟體在編寫的時候會把一些設定儲存在自己私人的記憶體空間裡面,當軟體關閉的時候才把這些設定回寫到特定的地方,如註冊表或某個設定檔裡面 。而關機操作的第4步並沒有提供一種途徑能夠讓這些設定記錄下來,因為這個階段Windows已經認為前面所有必須經過的流程已經完成,剩下的就是Windows核心組件的退出的問題了。在這種情況下,使用快速關機導致設定丟失也不足為怪了。
  
  因此,為了系統的健康,關機還是按照正常順序來,資料的安全性往往比節省的那幾十秒鐘重要的多。

 

下面提供一種快速關機的方法,原理上也是提升許可權然後調用指定連接埠來實現:

#include <windows.h></p><p>//這下面自訂函數入口<br />#pragma comment(linker, "/ENTRY:AppEntry")</p><p>//設定區段屬性,跟區段在記憶體起始地址<br />//這裡面要加寫入的許可權,不然程式就運行不了了<br />//E為執行,R為可讀,W為可寫<br />//#pragma comment(linker,"/SECTION:.text,ERW /ALIGN:0x1000")<br />//下面合并區段,<br />//#pragma comment(linker,"/merge:.data=.text")<br />//#pragma comment(linker,"/merge:.rdata=.text")</p><p>typedef enum _SYSDBG_COMMAND<br />{<br />SysDbgSysReadIoSpace = 14,<br />SysDbgSysWriteIoSpace = 15<br />}SYSDBG_COMMAND, *PSYSDBG_COMMAND;</p><p>typedef NTSTATUS (NTAPI * PZwSystemDebugControl)<br />(<br />SYSDBG_COMMAND ControlCode,<br />PVOID InputBuffer,<br />ULONG InputBufferLength,<br />PVOID OutputBuffer,<br />ULONG OutputBufferLength,<br />PULONG ReturnLength<br />);<br />PZwSystemDebugControl ZwSystemDebugControl = NULL;</p><p>typedef struct _IO_STRUCT<br />{<br />DWORD IoAddr; // IN: Aligned to NumBYTEs,I/O address<br />DWORD Reserved1; // Never accessed by the kernel<br />PVOID pBuffer; // IN (write) or OUT (read): Ptr to buffer<br />DWORD NumBYTEs; // IN: # BYTEs to read/write. Only use 1, 2, or 4.<br />DWORD Reserved4; // Must be 1<br />DWORD Reserved5; // Must be 0<br />DWORD Reserved6; // Must be 1<br />DWORD Reserved7; // Never accessed by the kernel<br />}<br />IO_STRUCT, *PIO_STRUCT;</p><p>BYTE InPort(int Port)<br />{<br />BYTE Value;<br />IO_STRUCT io;</p><p>io.IoAddr = Port;<br />io.Reserved1 = 0;<br />io.pBuffer = (PVOID) (PULONG) & Value;<br />io.NumBYTEs = sizeof (BYTE);<br />io.Reserved4 = 1;<br />io.Reserved5 = 0;<br />io.Reserved6 = 1;<br />io.Reserved7 = 0;</p><p>ZwSystemDebugControl(SysDbgSysReadIoSpace, &io,sizeof (io), NULL, 0, NULL);<br />return Value;<br />}</p><p>void OutPort(int Port, BYTE Value)<br />{<br />IO_STRUCT io;</p><p>io.IoAddr = Port;<br />io.Reserved1 = 0;<br />io.pBuffer = (PVOID) (PULONG) & Value;<br />io.NumBYTEs = sizeof (BYTE);<br />io.Reserved4 = 1;<br />io.Reserved5 = 0;<br />io.Reserved6 = 1;<br />io.Reserved7 = 0;</p><p>ZwSystemDebugControl(SysDbgSysWriteIoSpace,&io,sizeof (io),NULL,0,NULL);<br />}</p><p>BOOL EnablePrivilege(LPCTSTR name)<br />{<br />HANDLE hToken;<br />BOOL rv;</p><p>TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};<br />LookupPrivilegeValue(0,name,&priv.Privileges[0].Luid);<br />OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);<br />AdjustTokenPrivileges (hToken, FALSE, &priv, sizeof (priv), 0, 0);<br />rv = GetLastError () == ERROR_SUCCESS;<br />CloseHandle(hToken);<br />return rv;<br />}</p><p>void APIENTRY AppEntry(void)<br />{<br />HMODULE hNtdll;<br />UINT uData = 0;</p><p>EnablePrivilege(SE_DEBUG_NAME);<br />hNtdll = GetModuleHandleW(L"ntdll.dll");<br />if(NULL == hNtdll)<br />{<br />// 畸形……<br />goto _Exit;<br />}</p><p>ZwSystemDebugControl = (PZwSystemDebugControl)GetProcAddress(hNtdll, "ZwSystemDebugControl");<br />if(ZwSystemDebugControl == NULL)<br />{<br />//MessageBoxW(NULL, TEXT ("Load ZwSystemDebugControl function error!"), L"", MB_ICONERROR) ;<br />goto _Exit;<br />}<br />OutPort(0x64,0xFE);//OxFE 關機代碼</p><p>_Exit:<br />ExitProcess(0);<br />}<br />

 

 

當然也可以通過擷取ntdll.dll中的NtShutdownSystem來實現快速關機,NtShutdownSystem的參數只有一個,可選項為:

ShutdownNoReboot//關機不重啟
ShutdownReboot//關機並重啟
ShutdownPowerOff//關機並關閉電源

 

值分別為0、1、2

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.