允许程序特权在启动时从任何帐户更改 PC 名称?
Posted
技术标签:
【中文标题】允许程序特权在启动时从任何帐户更改 PC 名称?【英文标题】:Allow program priveledges to change PC Name from any account on startup? 【发布时间】:2013-08-04 22:05:56 【问题描述】:我正在编写一个基本程序,它在启动时将 PC 的活动 NIC 发送到服务器并适当地更改 PC 的主机名。该过程概述如下。
程序执行流程:
-
由任何帐户自动启动
收集活动 NIC 地址
向服务器发送 NIC 地址
接收分配的 PC 主机名
比较当前和分配的主机名
必要时更改主机名
我让程序按照设计完美地执行步骤 1-5。它能够收集活动的 NIC 地址,为服务器准备数据包并接收响应。问题出在程序到达第 6 步时。在 Windows XP 上,如果仅以管理员身份登录,程序会毫无问题地更改主机名。在 Windows Vista、7 和 8 上,该程序无法更改计算机主机名(由于需要 UAC 提升),或者如果登录到没有管理员权限的用户帐户,则它缺乏必要的权限。
在向程序添加应用程序清单以向用户和 Windows 发出程序需要管理员权限的信号后,程序无法启动,因为 Windows Vista 及更高版本不会在启动时启动需要管理员权限的程序。
在之前的清单修改之后,我在计算机上创建了一个单独的用户帐户,该帐户是管理员,以便程序可以模拟管理员帐户并拥有对计算机的完全访问权限,而无需活动用户是管理员。再次在 Windows XP 上完美运行。在 Windows 7 上,程序会抛出“Permission Denied”消息。我已经使用 advapi32.dll 和 userenv.dll 尝试了 Process.Start 和 C Sharp 模拟,如下所示。
在启动时允许程序权限从任何帐户更改 PC 名称的最佳方法是什么?
process.start 方法
ProcessStartInfo myProcess = new ProcessStartInfo(path);
myProcess.UserName = username;
myProcess.Password = MakeSecureString(password);
myProcess.WorkingDirectory = @"C:\Windows\System32";
myProcess.UseShellExecute = false;
myProcess.Verb = "runas";
Process.Start(myProcess);
模拟方法
static void Imp()
WindowsImpersonationContext m_ImpersonationContext = null;
WindowsIdentity m_ImpersonatedUser;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
const int SecurityImpersonation = 2;
const int TokenType = 1;
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_PROVIDER_DEFAULT = 0;
try
if (RevertToSelf())
Console.WriteLine("Before impersonation: " +
WindowsIdentity.GetCurrent().Name);
String userName = "sfadmin";
//IntPtr password = GetPassword();
if (LogonUser(userName, Environment.MachineName,
"d31ux3", LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
if (DuplicateToken(token, SecurityImpersonation, ref tokenDuplicate) != 0)
m_ImpersonatedUser = new WindowsIdentity(tokenDuplicate);
using (m_ImpersonationContext = m_ImpersonatedUser.Impersonate())
if (m_ImpersonationContext != null)
Console.WriteLine("After Impersonation succeeded: " +
Environment.NewLine +
"User Name: " +
WindowsIdentity.GetCurrent(
TokenAccessLevels.MaximumAllowed).Name +
Environment.NewLine +
"SID: " +
WindowsIdentity.GetCurrent(
TokenAccessLevels.MaximumAllowed).User.Value);
#region LoadUserProfile
// Load user profile
ProfileInfo profileInfo = new ProfileInfo();
profileInfo.dwSize = Marshal.SizeOf(profileInfo);
profileInfo.lpUserName = userName;
profileInfo.dwFlags = 1;
Boolean loadSuccess =
LoadUserProfile(tokenDuplicate, ref profileInfo);
if (!loadSuccess)
Console.WriteLine("LoadUserProfile() failed with error code: " +
Marshal.GetLastWin32Error());
throw new Win32Exception(Marshal.GetLastWin32Error());
if (profileInfo.hProfile == IntPtr.Zero)
Console.WriteLine(
"LoadUserProfile() failed - HKCU handle " +
"was not loaded. Error code: " +
Marshal.GetLastWin32Error());
throw new Win32Exception(Marshal.GetLastWin32Error());
#endregion
CloseHandle(token);
CloseHandle(tokenDuplicate);
// Do tasks after impersonating successfully
//AccessFileSystem();
RunAs("SolarFrost.exe", "sfadmin", "d31ux3");
// Access HKCU after loading user's profile
//AccessHkcuRegistry(profileInfo.hProfile);
// Unload user profile
// MSDN remarks
// http://msdn.microsoft.com/en-us/library/bb762282(VS.85).aspx
// Before calling UnloadUserProfile you should
// ensure that all handles to keys that you have opened in the
// user's registry hive are closed. If you do not
// close all open registry handles, the user's profile fails
// to unload. For more information, see Registry Key
// Security and Access Rights and Registry Hives.
UnloadUserProfile(tokenDuplicate, profileInfo.hProfile);
// Undo impersonation
m_ImpersonationContext.Undo();
else
Console.WriteLine("DuplicateToken() failed with error code: " +
Marshal.GetLastWin32Error());
throw new Win32Exception(Marshal.GetLastWin32Error());
catch (Exception Ex)
System.IO.File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", Ex.ToString() + "\r\n");
finally
if (token != IntPtr.Zero) CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero) CloseHandle(tokenDuplicate);
Console.WriteLine("After finished impersonation: " +
WindowsIdentity.GetCurrent().Name);
【问题讨论】:
【参考方案1】:您可以在 Windows 中使用Task Scheduler 设置任务。无论是否有人登录,都将任务设置为在启动时运行。还要确保任务在highest privilege(复选框)运行。这应该可以解决您的问题。
【讨论】:
我的印象是任务计划程序是供用户为他们的工作站安排任务的。考虑到我打算在完成后将该程序上线供其他人使用,任务计划程序中列出的程序是否看起来不如 ms-config >> 启动(或 Windows 8 任务管理器 >> 启动)中列出的程序专业? 我最初将此程序编码为 Windows 服务,但是由于我计划稍后也启用该程序以安装 .NET 框架(需要桌面交互),我相信这也会扼杀我以前的服务理念. @CoderWalker 我看不出这两种变体之间的“专业性”有什么区别。你有没有看过你的系统上安排了什么? - 例如,即使是 Adobe 也通过这种机制安排它的更新。我也没有理由将此程序作为服务保留在系统中,因为它只会在系统启动时做一些有用的事情......以上是关于允许程序特权在启动时从任何帐户更改 PC 名称?的主要内容,如果未能解决你的问题,请参考以下文章
如何在应用程序启动时从 java 代码更改 Hibernate connection.url 属性
iPad 应用程序名称和启动画面在模拟器上与 iPad 设备不同
安全架构 - 驱动 UI 和特权(权利)的设置 - 基于角色,每个用户帐户