降权启动进程

Win7下有些进程需要以管理员权限启动,比如安装程序。但又需要这个具有管理员权限的进程启动一个非管理员权限的进程。要实现这一点,方法很简单,首先得到受限的Token,然后由这个Token调用CreateProcessAsUser

WIN7/VS2010 (de_elevate_start_process.cpp) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "stdafx.h"
#include <Windows.h>
#include <UserEnv.h>
#include <WinBase.h>
#include <WinSafer.h>

#pragma comment(lib, "Userenv.lib")

// 获取不含管理员权限的Token
HANDLE CreateNormalUserToken()
{
  SAFER_LEVEL_HANDLE hLevel = NULL;
  if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &hLevel, NULL))
  {
      return NULL;
  }

  HANDLE hRestrictedToken = NULL;
  if (!SaferComputeTokenFromLevel(hLevel, NULL, &hRestrictedToken, 0, NULL))
  {
      hRestrictedToken = NULL;
  }
  SaferCloseLevel(hLevel);
  return hRestrictedToken;
};

// 从管理员进程,创建非管理员进程
BOOL DeElevateStartProcess(TCHAR* cmd)
{
  const HANDLE hRestToken = CreateNormalUserToken();
  if (NULL == hRestToken)
  {
      return FALSE;
  }

  DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
  LPVOID pEnv = NULL;
  if(CreateEnvironmentBlock(&pEnv, hRestToken, TRUE))
  {
      dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
  }
  else
  {
      pEnv = NULL;
  }

  PROCESS_INFORMATION pi;
  STARTUPINFO si;    
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb= sizeof(STARTUPINFO);
  si.lpDesktop = _T("winsta0\\default"); //default input desktop for the interactive window station
  ZeroMemory(&pi, sizeof(pi));

  const BOOL bResult = CreateProcessAsUser(hRestToken,    // client's access token
                      NULL,                   // file to execute
                      cmd,      // command line
                      NULL,                   // pointer to process SECURITY_ATTRIBUTES
                      NULL,                   // pointer to thread SECURITY_ATTRIBUTES
                      FALSE,                  // handles are not inheritable
                      dwCreationFlags,        // creation flags
                      pEnv,                   // pointer to new environment block
                      NULL,                   // name of current directory
                      &si,                    // pointer to STARTUPINFO structure
                      &pi                     // receives information about new process
                      );
  if (bResult)
  {
      CloseHandle(pi.hProcess);
      CloseHandle(pi.hThread);
  }
  if (pEnv)
  {
      DestroyEnvironmentBlock(pEnv);
  }
  CloseHandle(hRestToken);
  return bResult;
}

int _tmain(int argc, _TCHAR* argv[])
{
  TCHAR cmd[] = _T("notepad.exe");
  DeElevateStartProcess(cmd);
  return 0;
}

需要创建出的进程支持拖拽的看这里:创建支持拖拽的进程