MFC 关机小软件

关机函数和进程提权

    Windows下的关机函数是ExitWindowEx, 函数原型为:

BOOL WINAPI ExitWindowsEx(

   __in           UINT        uFlags,

   __in           DWORD dwReason

)

功能上有“关闭系统”,“注销用户”,“锁定工作站”3中操作。在Windows NT内核的操作系统中,进程需要拥有SE_SHUTDOWN_NAME权限才能成功调用此函数。

进程的权限记录在进程的令牌当中,进程的令牌是一种核心对象,它保存了用户的安全配置信息,例如用户的SID、组的UID以及各种权限等,令牌也记录一个已登录会话的引用和内核使用的默认安全设置。进程的令牌在进程被创建时产生,继承于父进程。下面来看如何是区别当前操作系统版本,以及使本进程拥有SE_SHUTDOWN_NAME权限。

Windows的系统的版本信息使用一个结构体OSVERSIONINFO表示,定义如下:

typedef struct _OSVERSIONINFO {  

DWORD   dwOSVersionInfoSize;   //本结构体的大小

DWORD   dwMajorVersion;           //主版本号

DWORD   dwMinorVersion;         //副版本号

DWORD   dwBuildNumber;          //创建号

DWORD   dwPlatformId;               //平台ID,用于区分是否NT内核

TCHAR    szCSDVersion[128];      //记录补丁之类的信息

} OSVERSIONINFO;

获取系统的版本信息的函数是GetVersionEx, 函数原型为:

BOOL GetVersionEx(

   LPOSVERSIONINFO    lpVersionInformation   // 指向存储获得信息的结构体

)

现在,我们已经知道关机程序的大体流程如下:

...

OSVERSIONINFO   verinfo;

verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

if(GetVersionEx(&verinfo) == 0) {     //获得版本信息

    printf("error in GetVersionEx \n");

    return 0;

}

if(verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {

        ...   //获得SE_SHUTDOWN_NAME权限

}

ExitWindowsEx(EWX_FORCE, 0);   //关机

下面来看获得权限一部分。要使进程的权限改变,就是改变他的令牌的属性。首先,得获取现有进程的令牌,使用函数OpenProcessToken, 他的原型如下:

BOOL WINAPI OpenProcessToken(

   __in     HANDLE       ProcessHandle,   //进程的句柄

   __in     DWORD       DesiredAccess,   //令牌的访问权限

   __out    PHANDLE   TokenHandle      //存储获得的令牌的指针

)

本进程的句柄可以用函数GetCurrentProcess()函数得到。要使进程拥有SE_SHUTDOWN_NAME权限,实际上就是使该进程的令牌拥有该权限对应的LUID值。获得某个权限对应的LUID值可以使用函数LookupPrivilegeValue,原型如下:

BOOL WINAPI LookupPrivilegeValue(

   __in_opt       LPCTSTR lpSystemName,   //系统名,本系统为NULL

   __in             LPCTSTR    lpName,             //权限名

   __out          PLUID          lpLuid                //获得的LUID

)

知道了这些之后,将进程的令牌对照进行调整,进程便拥有我们想要的权限了,这里用到函数AdjustTokenPrivileges,原型如下:

BOOL WINAPI AdjustTokenPrivileges(

   __in              HANDLE                         TokenHandle,   //要更改的令牌

   __in             BOOL                               DisableAllPrivileges,  

   __in_opt       PTOKEN_PRIVILEGES    NewState,

   __in            DWORD                           BufferLength,

   __out_opt      PTOKEN_PRIVILEGES   PreviousState, //用以在更改后保存先前的令牌

   __out_opt      PDWORD                        ReturnLength

)

现在我们也知道了获得SE_SHUTDOWN_NAME权限的大体流程:

HANDLE token;

TOKEN_PRIVILEGES tp;

if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) ){

LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME, &(tp.Privileges[0].Luid));

tp.PrivilegeCount = 1;

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(token, FALSE, &tp, 0, NULL, 0);

}

总程序如下:

#include <windows.h>
#include <stdio.h>

int main()
{
    OSVERSIONINFO verinfo;
    HANDLE token;
     TOKEN_PRIVILEGES tp;
     verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

     if(GetVersionEx(&verinfo) == 0)
    {
         printf("error in GetVersionEx \n");
         return 0;
     }

     if(verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
     {
          if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) )
           {
                LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &(tp.Privileges[0].Luid));
                 tp.PrivilegeCount = 1;
                   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                  AdjustTokenPrivileges(token, FALSE, &tp, 0, NULL, 0);
            }

     }
     ExitWindowsEx(EWX_FORCE, 0);
     return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值