今天寢室一堆人都打遊戲,吵得睡不著,果斷起來把這一陣以來一直在糾結的關機小工具初步實現以及一些注意事項發上來,作為自己的一個備忘記錄,也作為其他人的一個參考。

 

  1. #include <windows.h> 
  2. #include <iostream> 
  3. using namespace std; 
  4.  
  5. void AjustPrivilege_LOGOFF() 
  6.     HANDLE hToken; 
  7.     TOKEN_PRIVILEGES tkp_logoff; 
  8.      
  9.     OpenProcessToken( 
  10.         GetCurrentProcess(), 
  11.         TOKEN_ADJUST_PRIVILEGES | 
  12.         TOKEN_QUERY, 
  13.         &hToken 
  14.         ); 
  15.  
  16.     LookupPrivilegeValue( 
  17.         NULL, 
  18.         SE_DEBUG_NAME, 
  19.         &tkp_logoff.Privileges[0].Luid 
  20.         ); 
  21.  
  22.     tkp_logoff.PrivilegeCount=1; 
  23.     tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 
  24.  
  25.     AdjustTokenPrivileges( 
  26.         hToken,    
  27.         FALSE,    
  28.         &tkp_logoff,    
  29.         0, 
  30.         (PTOKEN_PRIVILEGES)NULL,  
  31.         0); 
  32.  
  33. void AjustPrivilege_SHUTDOWN() 
  34.     HANDLE hToken; 
  35.     TOKEN_PRIVILEGES tkp_shutdown; 
  36.      
  37.     OpenProcessToken( 
  38.         GetCurrentProcess(), 
  39.         TOKEN_ADJUST_PRIVILEGES | 
  40.         TOKEN_QUERY, 
  41.         &hToken 
  42.         ); 
  43.  
  44.     LookupPrivilegeValue( 
  45.         NULL, 
  46.         SE_SHUTDOWN_NAME, 
  47.         &tkp_shutdown.Privileges[0].Luid 
  48.         ); 
  49.  
  50.     tkp_shutdown.PrivilegeCount=1; 
  51.     tkp_shutdown.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 
  52.  
  53.     AdjustTokenPrivileges( 
  54.         hToken,    
  55.         FALSE,    
  56.         &tkp_shutdown,    
  57.         0, 
  58.         (PTOKEN_PRIVILEGES)NULL,  
  59.         0); 
  60.  
  61. int main() 
  62.     int choose; 
  63.  
  64.     cout<<"choose:"<<endl<<"1-logoff"<<endl<<"2-shutdown"<<endl; 
  65.     cin>>choose; 
  66.  
  67.     switch(choose) 
  68.     { 
  69.     case 1: 
  70.         AjustPrivilege_LOGOFF(); 
  71.         ExitWindowsEx(EWX_LOGOFF,0); 
  72.         cout<<"now,logoff is start..."<<endl; 
  73.         break
  74.     case 2: 
  75.         AjustPrivilege_SHUTDOWN(); 
  76.         ExitWindowsEx(EWX_SHUTDOWN,0); 
  77.         cout<<"now,shutdown is start..."<<endl; 
  78.         break
  79.     default
  80.         cout<<"fuck!"<<endl; 
  81.         break
  82.     } 

以上是目前為止的全部程式碼。

下面做簡要分析。

 

 

  1. void AjustPrivilege_LOGOFF() 
  2.     HANDLE hToken; 
  3.     TOKEN_PRIVILEGES tkp_logoff; 
  4.      
  5.     OpenProcessToken( 
  6.         GetCurrentProcess(), 
  7.         TOKEN_ADJUST_PRIVILEGES | 
  8.         TOKEN_QUERY, 
  9.         &hToken 
  10.         ); 
  11.  
  12.     LookupPrivilegeValue( 
  13.         NULL, 
  14.         SE_DEBUG_NAME, 
  15.         &tkp_logoff.Privileges[0].Luid 
  16.         ); 
  17.  
  18.     tkp_logoff.PrivilegeCount=1; 
  19.     tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 
  20.  
  21.     AdjustTokenPrivileges( 
  22.         hToken,    
  23.         FALSE,    
  24.         &tkp_logoff,    
  25.         0, 
  26.         (PTOKEN_PRIVILEGES)NULL,  
  27.         0); 
  28.  
  29. void AjustPrivilege_SHUTDOWN() 
  30.     HANDLE hToken; 
  31.     TOKEN_PRIVILEGES tkp_shutdown; 
  32.      
  33.     OpenProcessToken( 
  34.         GetCurrentProcess(), 
  35.         TOKEN_ADJUST_PRIVILEGES | 
  36.         TOKEN_QUERY, 
  37.         &hToken 
  38.         ); 
  39.  
  40.     LookupPrivilegeValue( 
  41.         NULL, 
  42.         SE_SHUTDOWN_NAME, 
  43.         &tkp_shutdown.Privileges[0].Luid 
  44.         ); 
  45.  
  46.     tkp_shutdown.PrivilegeCount=1; 
  47.     tkp_shutdown.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 
  48.  
  49.     AdjustTokenPrivileges( 
  50.         hToken,    
  51.         FALSE,    
  52.         &tkp_shutdown,    
  53.         0, 
  54.         (PTOKEN_PRIVILEGES)NULL,  
  55.         0); 

以上兩個函式是用於獲得關機層次的操作所需的許可權的。此項是在win2k之後就加入了windows產品中的一個安全措施。要注意的是,在編寫程式碼期間我曾連續4天糾結於這個問題。下面來詳細解析一下。

我們看到,兩個函式的內容其實上沒有太大區別,但是為什麼我要寫兩個呢?我在最初的時候並不知道要這麼寫,所以只寫了一個。但是悲劇的情況出現了。大家注意對比這兩條語句:

 

  1. LookupPrivilegeValue( 
  2.         NULL, 
  3.         SE_DEBUG_NAME, 
  4.         &tkp_logoff.Privileges[0].Luid 
  5.         ); 
  6.  
  7. LookupPrivilegeValue( 
  8.         NULL, 
  9.         SE_SHUTDOWN_NAME, 
  10.         &tkp_shutdown.Privileges[0].Luid 
  11.         ); 

有沒有發現,第二個引數是不一樣的。我當時就不知道這個區別,卡在這裡很久。因為只寫了上頭一個,那麼就只能實現登出,如果只寫了下頭一個,就只能實現關機,不論後面的ExitWindowsEx()函式的引數是EWX_LOGOFF還是EWX_SHUTDOWN。

也就是說,可以這樣理解:最終的操作其實主要是跟LookupPrivilegeValue()這個函式相關,而ExitWindowsEx()只是在最後操作時起一點作用。<—這部分是我個人的理解,希望大牛指正。

然後,我們回到這兩個函式來看。他們的作用已經說過,都是為了提升許可權。那麼,方便一些比較懶的讀者不想去百度或者GOOGLE,每條語句我們都來分析一下好了,但不會做詳細講解,因為我自己都不太懂(笑)。

 

  1. OpenProcessToken(
  2. GetCurrentProcess(),
  3. TOKEN_ADJUST_PRIVILEGES |
  4. TOKEN_QUERY,
  5. &hToken
  6. );

此函式用於獲取程式標記,最後一個引數便是我自己所創造的控制程式碼。

 

  1. LookupPrivilegeValue( 
  2.         NULL, 
  3.         SE_DEBUG_NAME, 
  4.         &tkp_logoff.Privileges[0].Luid 
  5.         ); 

獲得本地機唯一的標識,注意,如果需要遠端關機,引數會有相應變化,具體情況請查閱最新版MSDN

 

  1. tkp_logoff.PrivilegeCount=1; 
  2. tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 

第一條語句用於指定操作的個數,第二條語句用於提升許可權複製。這兩條語句我是沒有太明白的,詳細情況請查閱最新版MSDN

 

  1. AdjustTokenPrivileges( 
  2.         hToken,    
  3.         FALSE,    
  4.         &tkp_logoff,    
  5.         0, 
  6.         (PTOKEN_PRIVILEGES)NULL,  
  7.         0); 

用於啟用或禁用特權一個有TOKEN_ADJUST_PRIVILEGES訪問的訪問令牌,這個函式我也不太明白,詳細情況請查閱最新版MSDN

 

目前就完成了這些,只實現了本程式操作計算機進行登出和關機,當然,如果想要加入重啟或者休眠之類的功能也是可以的,不過要記得新增相應的函式。只要記住一點,函式與操作相對應就OK。下一步準備實現定時功能。以我對自己的瞭解,查閱例項,分析例項,再加上編寫程式碼和測試,沒有4天拿不下來,估計文章就得1周左右的時間了,如果有朋友想要看完這個系列估計有的等了。<—我估計沒人回看我這菜鳥寫的東西的(笑)…

 

不管怎麼說,盡請期待後續吧。