如何在Vista中运行NOT提升(.NET)
我有一个应用程序,我必须以pipe理员身份运行。
该应用程序的一小部分是使用Process.Start启动其他应用程序
启动的应用程序也将作为pipe理员运行,但我宁愿看到他们作为“正常”用户运行。
我如何做到这一点?
/约翰/
WinSafer API允许一个进程作为一个有限的,普通的,或提升的用户启动。
样本用法:
CreateSaferProcess(@"calc.exe", "", SaferLevel.NormalUser);
源代码:
//http://odetocode.com/Blogs/scott/archive/2004/10/28/602.aspx public static void CreateSaferProcess(String fileName, String arguments, SaferLevel saferLevel) { IntPtr saferLevelHandle = IntPtr.Zero; //Create a SaferLevel handle to match what was requested if (!WinSafer.SaferCreateLevel( SaferLevelScope.User, saferLevel, SaferOpen.Open, out saferLevelHandle, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } try { //Generate the access token to use, based on the safer level handle. IntPtr hToken = IntPtr.Zero; if (!WinSafer.SaferComputeTokenFromLevel( saferLevelHandle, // SAFER Level handle IntPtr.Zero, // NULL is current thread token. out hToken, // Target token SaferTokenBehaviour.Default, // No flags IntPtr.Zero)) // Reserved { throw new Win32Exception(Marshal.GetLastWin32Error()); } try { //Now that we have a security token, we can lauch the process //using the standard CreateProcessAsUser API STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = String.Empty; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); // Spin up the new process Boolean bResult = Windows.CreateProcessAsUser( hToken, fileName, arguments, IntPtr.Zero, //process attributes IntPtr.Zero, //thread attributes false, //inherit handles 0, //CREATE_NEW_CONSOLE IntPtr.Zero, //environment null, //current directory ref si, //startup info out pi); //process info if (!bResult) throw new Win32Exception(Marshal.GetLastWin32Error()); if (pi.hProcess != IntPtr.Zero) Windows.CloseHandle(pi.hProcess); if (pi.hThread != IntPtr.Zero) Windows.CloseHandle(pi.hThread); } finally { if (hToken != IntPtr.Zero) Windows.CloseHandle(hToken); } } finally { WinSafer.SaferCloseLevel(saferLevelHandle); } }
P / Invoke声明:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace PInvoke { public class WinSafer { /// <summary> /// The SaferCreateLevel function opens a SAFER_LEVEL_HANDLE. /// </summary> /// <param name="scopeId">The scope of the level to be created.</param> /// <param name="levelId">The level of the handle to be opened.</param> /// <param name="openFlags">Must be SaferOpenFlags.Open</param> /// <param name="levelHandle">The returned SAFER_LEVEL_HANDLE. When you have finished using the handle, release it by calling the SaferCloseLevel function.</param> /// <param name="reserved">This parameter is reserved for future use. IntPtr.Zero</param> /// <returns></returns> [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern bool SaferCreateLevel(SaferLevelScope scopeId, SaferLevel levelId, SaferOpen openFlags, out IntPtr levelHandle, IntPtr reserved); /// <summary> /// The SaferComputeTokenFromLevel function restricts a token using restrictions specified by a SAFER_LEVEL_HANDLE. /// </summary> /// <param name="levelHandle">SAFER_LEVEL_HANDLE that contains the restrictions to place on the input token. Do not pass handles with a LevelId of SAFER_LEVELID_FULLYTRUSTED or SAFER_LEVELID_DISALLOWED to this function. This is because SAFER_LEVELID_FULLYTRUSTED is unrestricted and SAFER_LEVELID_DISALLOWED does not contain a token.</param> /// <param name="inAccessToken">Token to be restricted. If this parameter is NULL, the token of the current thread will be used. If the current thread does not contain a token, the token of the current process is used.</param> /// <param name="outAccessToken">The resulting restricted token.</param> /// <param name="flags">Specifies the behavior of the method.</param> /// <param name="lpReserved">Reserved for future use. This parameter should be set to IntPtr.EmptyParam.</param> /// <returns></returns> [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern bool SaferComputeTokenFromLevel(IntPtr levelHandle, IntPtr inAccessToken, out IntPtr outAccessToken, SaferTokenBehaviour flags, IntPtr lpReserved); /// <summary> /// The SaferCloseLevel function closes a SAFER_LEVEL_HANDLE that was opened by using the SaferIdentifyLevel function or the SaferCreateLevel function.</summary> /// <param name="levelHandle">The SAFER_LEVEL_HANDLE to be closed.</param> /// <returns>TRUE if the function succeeds; otherwise, FALSE. For extended error information, call GetLastWin32Error.</returns> [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern bool SaferCloseLevel(IntPtr levelHandle); } //class WinSafer /// <summary> /// Specifies the behaviour of the SaferComputeTokenFromLevel method /// </summary> public enum SaferTokenBehaviour : uint { /// <summary></summary> Default = 0x0, /// <summary>If the OutAccessToken parameter is not more restrictive than the InAccessToken parameter, the OutAccessToken parameter returns NULL.</summary> NullIfEqual = 0x1, /// <summary></summary> CompareOnly = 0x2, /// <summary></summary> MakeInert = 0x4, /// <summary></summary> WantFlags = 0x8 } /// <summary> /// The level of the handle to be opened. /// </summary> public enum SaferLevel : uint { /// <summary>Software will not run, regardless of the user rights of the user.</summary> Disallowed = 0, /// <summary>Allows programs to execute with access only to resources granted to open well-known groups, blocking access to Administrator and Power User privileges and personally granted rights.</summary> Untrusted = 0x1000, /// <summary>Software cannot access certain resources, such as cryptographic keys and credentials, regardless of the user rights of the user.</summary> Constrained = 0x10000, /// <summary>Allows programs to execute as a user that does not have Administrator or Power User user rights. Software can access resources accessible by normal users.</summary> NormalUser = 0x20000, /// <summary>Software user rights are determined by the user rights of the user.</summary> FullyTrusted = 0x40000 } /// <summary> /// The scope of the level to be created. /// </summary> public enum SaferLevelScope : uint { /// <summary>The created level is scoped by computer.</summary> Machine = 1, /// <summary>The created level is scoped by user.</summary> User = 2 } public enum SaferOpen : uint { Open = 1 } } //namespace PInvoke
来自: http : //go.microsoft.com/fwlink/?LinkId=81232
一个经常被问到的问题是如何从一个提升的过程中启动一个未升级的应用程序,或者更基本的是,如果我运行升级后如何使用未升级的令牌启动一个过程。 由于没有直接的方法来做到这一点,所以通常可以通过以标准用户身份启动原始应用程序来避免这种情况,并且仅仅提升那些需要pipe理权限的应用程序部分。 这样,总是有一个非升级的过程,可以用来启动额外的应用程序作为当前login的桌面用户。 然而,有时候,升级的stream程需要让另一个应用程序不升级。 这可以通过在Windows Vista中使用任务计划程序来完成。 提升的进程可以注册一个任务,以当前login的桌面用户身份运行。
这里是一个如何安排未升级过程的例子(再次来自同一个链接)
//--------------------------------------------------------------------- // This file is part of the Microsoft .NET Framework SDK Code Samples. // // Copyright (C) Microsoft Corporation. All rights reserved. // //This source code is intended only as a supplement to Microsoft //Development Tools and/or on-line documentation. See these other //materials for detailed information regarding Microsoft code samples. // //THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //PARTICULAR PURPOSE. //--------------------------------------------------------------------- /**************************************************************************** * Main.cpp - Sample application for Task Scheduler V2 COMAPI * Component: Task Scheduler * Copyright (c) 2002 - 2003, Microsoft Corporation * This sample creates a task to that launches as the currently logged on deskup user. The task launches as soon as it is registered. * ****************************************************************************/ #include "stdafx.h" #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <comdef.h> #include <comutil.h> //Include Task header files - Included in Windows Vista Beta-2 SDK from MSDN #include <taskschd.h> #include <conio.h> #include <iostream> #include <time.h> using namespace std; #define CLEANUP \ pRootFolder->Release();\ pTask->Release();\ CoUninitialize(); HRESULT CreateMyTask(LPCWSTR, wstring); void __cdecl wmain(int argc, wchar_t** argv) { wstring wstrExecutablePath; WCHAR taskName[20]; HRESULT result; if( argc < 2 ) { printf("\nUsage: LaunchApp yourapp.exe" ); return; } // Pick random number for task name srand((unsigned int) time(NULL)); wsprintf((LPWSTR)taskName, L"Launch %d", rand()); wstrExecutablePath = argv[1]; result = CreateMyTask(taskName, wstrExecutablePath); printf("\nReturn status:%d\n", result); } HRESULT CreateMyTask(LPCWSTR wszTaskName, wstring wstrExecutablePath) { // ------------------------------------------------------ // Initialize COM. TASK_STATE taskState; int i; HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if( FAILED(hr) ) { printf("\nCoInitializeEx failed: %x", hr ); return 1; } // Set general COM security levels. hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); if( FAILED(hr) ) { printf("\nCoInitializeSecurity failed: %x", hr ); CoUninitialize(); return 1; } // ------------------------------------------------------ // Create an instance of the Task Service. ITaskService *pService = NULL; hr = CoCreateInstance( CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService ); if (FAILED(hr)) { printf("Failed to CoCreate an instance of the TaskService class: %x", hr); CoUninitialize(); return 1; } // Connect to the task service. hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); if( FAILED(hr) ) { printf("ITaskService::Connect failed: %x", hr ); pService->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Get the pointer to the root task folder. This folder will hold the // new task that is registered. ITaskFolder *pRootFolder = NULL; hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder ); if( FAILED(hr) ) { printf("Cannot get Root Folder pointer: %x", hr ); pService->Release(); CoUninitialize(); return 1; } // Check if the same task already exists. If the same task exists, remove it. hr = pRootFolder->DeleteTask( _bstr_t( wszTaskName), 0 ); // Create the task builder object to create the task. ITaskDefinition *pTask = NULL; hr = pService->NewTask( 0, &pTask ); pService->Release(); // COM clean up. Pointer is no longer used. if (FAILED(hr)) { printf("Failed to CoCreate an instance of the TaskService class: %x", hr); pRootFolder->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Get the trigger collection to insert the registration trigger. ITriggerCollection *pTriggerCollection = NULL; hr = pTask->get_Triggers( &pTriggerCollection ); if( FAILED(hr) ) { printf("\nCannot get trigger collection: %x", hr ); CLEANUP return 1; } // Add the registration trigger to the task. ITrigger *pTrigger = NULL; hr = pTriggerCollection->Create( TASK_TRIGGER_REGISTRATION, &pTrigger ); pTriggerCollection->Release(); // COM clean up. Pointer is no longer used. if( FAILED(hr) ) { printf("\nCannot add registration trigger to the Task %x", hr ); CLEANUP return 1; } pTrigger->Release(); // ------------------------------------------------------ // Add an Action to the task. IExecAction *pExecAction = NULL; IActionCollection *pActionCollection = NULL; // Get the task action collection pointer. hr = pTask->get_Actions( &pActionCollection ); if( FAILED(hr) ) { printf("\nCannot get Task collection pointer: %x", hr ); CLEANUP return 1; } // Create the action, specifying that it is an executable action. IAction *pAction = NULL; hr = pActionCollection->Create( TASK_ACTION_EXEC, &pAction ); pActionCollection->Release(); // COM clean up. Pointer is no longer used. if( FAILED(hr) ) { printf("\npActionCollection->Create failed: %x", hr ); CLEANUP return 1; } hr = pAction->QueryInterface( IID_IExecAction, (void**) &pExecAction ); pAction->Release(); if( FAILED(hr) ) { printf("\npAction->QueryInterface failed: %x", hr ); CLEANUP return 1; } // Set the path of the executable to the user supplied executable. hr = pExecAction->put_Path( _bstr_t( wstrExecutablePath.c_str() ) ); if( FAILED(hr) ) { printf("\nCannot set path of executable: %x", hr ); pExecAction->Release(); CLEANUP return 1; } hr = pExecAction->put_Arguments( _bstr_t( L"" ) ); if( FAILED(hr) ) { printf("\nCannot set arguments of executable: %x", hr ); pExecAction->Release(); CLEANUP return 1; } // ------------------------------------------------------ // Save the task in the root folder. IRegisteredTask *pRegisteredTask = NULL; hr = pRootFolder->RegisterTaskDefinition( _bstr_t( wszTaskName ), pTask, TASK_CREATE, _variant_t(_bstr_t( L"S-1-5-32-545")),//Well Known SID for \\Builtin\Users group _variant_t(), TASK_LOGON_GROUP, _variant_t(L""), &pRegisteredTask); if( FAILED(hr) ) { printf("\nError saving the Task : %x", hr ); CLEANUP return 1; } printf("\n Success! Task successfully registered. " ); for (i=0; i<100; i++)//give 10 seconds for the task to start { pRegisteredTask->get_State(&taskState); if (taskState == TASK_STATE_RUNNING) { printf("\nTask is running\n"); break; } Sleep(100); } if (i>= 100) printf("Task didn't start\n"); //Delete the task when done hr = pRootFolder->DeleteTask( _bstr_t( wszTaskName ), NULL); if( FAILED(hr) ) { printf("\nError deleting the Task : %x", hr ); CLEANUP return 1; } printf("\n Success! Task successfully deleted. " ); // Clean up. CLEANUP CoUninitialize(); return 0; }
我有相同的要求,我来解决使用Windows的任务调度程序服务。
因此,首先将Task Scheduler Managed Wrapper
库添加到您的项目中,并使用此代码创build一个任务,将其configuration为以受限用户身份运行( td.Principal.RunLevel = TaskRunLevel.LUA;
),注册任务,运行任务并完成后,删除任务。
// Get the service on the local machine using (var ts = new TaskService()) { const string taskName = "foo"; // Create a new task definition and assign properties var td = ts.NewTask(); td.RegistrationInfo.Description = "start foo.exe as limited user"; // Create an action that will launch foo.exe, with argument bar in workingdir C:\\ td.Actions.Add(new ExecAction("C:\\foo.exe", "bar", "C:\\")); td.Settings.Priority = ProcessPriorityClass.Normal; // run with limited token td.Principal.RunLevel = TaskRunLevel.LUA; td.Settings.AllowDemandStart = true; td.Settings.DisallowStartIfOnBatteries = false; td.Settings.StopIfGoingOnBatteries = false; // Register the task in the root folder var ret = ts.RootFolder.RegisterTaskDefinition(taskName, td); var fooTask = ts.FindTask(taskName, true); if (null != fooTask ) { if (fooTask.Enabled) { fooTask.Run(); Thread.Sleep(TimeSpan.FromSeconds(1)); // find process and wait for Exit var processlist = Process.GetProcesses(); foreach(var theprocess in processlist) { if (theprocess.ProcessName != "foo") continue; theprocess.WaitForExit(); break; } } } // Remove the task we just created ts.RootFolder.DeleteTask(taskName); }