今天寢室一堆人都打游戲,吵得睡不著,果斷起來把這一陣以來一直在糾結的關機小工具初步實現以及一些注意事項發上來,作為自己的一個備忘記錄,也作為其他人的一個參考。
- #include <windows.h>
- #include <iostream>
- using namespace std;
- void AjustPrivilege_LOGOFF()
- {
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp_logoff;
- OpenProcessToken(
- GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES |
- TOKEN_QUERY,
- &hToken
- );
- LookupPrivilegeValue(
- NULL,
- SE_DEBUG_NAME,
- &tkp_logoff.Privileges[0].Luid
- );
- tkp_logoff.PrivilegeCount=1;
- tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tkp_logoff,
- 0,
- (PTOKEN_PRIVILEGES)NULL,
- 0);
- }
- void AjustPrivilege_SHUTDOWN()
- {
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp_shutdown;
- OpenProcessToken(
- GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES |
- TOKEN_QUERY,
- &hToken
- );
- LookupPrivilegeValue(
- NULL,
- SE_SHUTDOWN_NAME,
- &tkp_shutdown.Privileges[0].Luid
- );
- tkp_shutdown.PrivilegeCount=1;
- tkp_shutdown.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tkp_shutdown,
- 0,
- (PTOKEN_PRIVILEGES)NULL,
- 0);
- }
- int main()
- {
- int choose;
- cout<<"choose:"<<endl<<"1-logoff"<<endl<<"2-shutdown"<<endl;
- cin>>choose;
- switch(choose)
- {
- case 1:
- AjustPrivilege_LOGOFF();
- ExitWindowsEx(EWX_LOGOFF,0);
- cout<<"now,logoff is start..."<<endl;
- break;
- case 2:
- AjustPrivilege_SHUTDOWN();
- ExitWindowsEx(EWX_SHUTDOWN,0);
- cout<<"now,shutdown is start..."<<endl;
- break;
- default:
- cout<<"fuck!"<<endl;
- break;
- }
- }
以上是目前為止的全部代碼。
下面做簡要分析。
- void AjustPrivilege_LOGOFF()
- {
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp_logoff;
- OpenProcessToken(
- GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES |
- TOKEN_QUERY,
- &hToken
- );
- LookupPrivilegeValue(
- NULL,
- SE_DEBUG_NAME,
- &tkp_logoff.Privileges[0].Luid
- );
- tkp_logoff.PrivilegeCount=1;
- tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tkp_logoff,
- 0,
- (PTOKEN_PRIVILEGES)NULL,
- 0);
- }
- void AjustPrivilege_SHUTDOWN()
- {
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp_shutdown;
- OpenProcessToken(
- GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES |
- TOKEN_QUERY,
- &hToken
- );
- LookupPrivilegeValue(
- NULL,
- SE_SHUTDOWN_NAME,
- &tkp_shutdown.Privileges[0].Luid
- );
- tkp_shutdown.PrivilegeCount=1;
- tkp_shutdown.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tkp_shutdown,
- 0,
- (PTOKEN_PRIVILEGES)NULL,
- 0);
- }
以上兩個函數是用於獲得關機層次的操作所需的權限的。此項是在win2k之後就加入了windows產品中的一個安全措施。要注意的是,在編寫代碼期間我曾連續4天糾結於這個問題。下面來詳細解析一下。
我們看到,兩個函數的內容其實上沒有太大區別,但是為什麼我要寫兩個呢?我在最初的時候並不知道要這麼寫,所以只寫了一個。但是悲劇的情況出現了。大家注意對比這兩條語句:
- LookupPrivilegeValue(
- NULL,
- SE_DEBUG_NAME,
- &tkp_logoff.Privileges[0].Luid
- );
- LookupPrivilegeValue(
- NULL,
- SE_SHUTDOWN_NAME,
- &tkp_shutdown.Privileges[0].Luid
- );
有沒有發現,第二個參數是不一樣的。我當時就不知道這個區別,卡在這裡很久。因為只寫了上頭一個,那麼就只能實現注銷,如果只寫了下頭一個,就只能實現關機,不論後面的ExitWindowsEx()函數的參數是EWX_LOGOFF還是EWX_SHUTDOWN。
也就是說,可以這樣理解:最終的操作其實主要是跟LookupPrivilegeValue()這個函數相關,而ExitWindowsEx()只是在最後操作時起一點作用。<---這部分是我個人的理解,希望大牛指正。
然後,我們回到這兩個函數來看。他們的作用已經說過,都是為了提升權限。那麼,方便一些比較懶的讀者不想去百度或者GOOGLE,每條語句我們都來分析一下好了,但不會做詳細講解,因為我自己都不太懂笑)。
- OpenProcessToken(
- GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES |
- TOKEN_QUERY,
- &hToken
- );
此函數用於獲取進程標記,最後一個參數便是我自己所創造的句柄。
- LookupPrivilegeValue(
- NULL,
- SE_DEBUG_NAME,
- &tkp_logoff.Privileges[0].Luid
- );
獲得本地機唯一的標識,注意,如果需要遠程關機,參數會有相應變化,具體情況請查閱最新版MSDN。
- tkp_logoff.PrivilegeCount=1;
- tkp_logoff.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
第一條語句用於指定操作的個數,第二條語句用於提升權限復制。這兩條語句我是沒有太明白的,詳細情況請查閱最新版MSDN。
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tkp_logoff,
- 0,
- (PTOKEN_PRIVILEGES)NULL,
- 0);
用於啟用或禁用特權一個有TOKEN_ADJUST_PRIVILEGES訪問的訪問令牌,這個函數我也不太明白,詳細情況請查閱最新版MSDN。
目前就完成了這些,只實現了本程序操作計算機進行注銷和關機,當然,如果想要加入重啟或者休眠之類的功能也是可以的,不過要記得添加相應的函數。只要記住一點,函數與操作相對應就OK。下一步准備實現定時功能。以我對自己的了解,查閱實例,分析實例,再加上編寫代碼和測試,沒有4天拿不下來,估計文章就得1周左右的時間了,如果有朋友想要看完這個系列估計有的等了。<---我估計沒人回看我這菜鳥寫的東西的(笑)...
不管怎麼說,盡請期待後續吧。
本文出自 “貓窩” 博客,請務必保留此出處http://moowoo.blog.51cto.com/2665885/532388