允许程序特权在启动时从任何帐户更改 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 我看不出这两种变体之间的“专业性”有什么区别。你有没有看过你的系统上安排了什么? - 例如,即使是 Adob​​e 也通过这种机制安排它的更新。我也没有理由将此程序作为服务保留在系统中,因为它只会在系统启动时做一些有用的事情......

以上是关于允许程序特权在启动时从任何帐户更改 PC 名称?的主要内容,如果未能解决你的问题,请参考以下文章

如何在应用程序启动时从 java 代码更改 Hibernate connection.url 属性

iPad 应用程序名称和启动画面在模拟器上与 iPad 设备不同

安全架构 - 驱动 UI 和特权(权利)的设置 - 基于角色,每个用户帐户

Microsoft Windows权限提升漏洞(CVE-2015-1701)

C# Winform 模拟无法正常工作

无法通过类方法更改对象的值