今天寝室一堆人都打游戏,吵得睡不着,果断起来把这一阵以来一直在纠结的关机小工具初步实现以及一些注意事项发上来,作为自己的一个备忘记录,也作为其他人的一个参考。
- #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周左右的时间了,如果有朋友想要看完这个系列估计有的等了。<---我估计没人回看我这菜鸟写的东西的(笑)...
不管怎么说,尽请期待后续吧。