起動時に PC のアクティブな NIC をサーバーに送信し、PC のホスト名を適切に変更する基本的なプログラムを作成しています。プロセスの概要を以下に示します。
プログラム実行プロセス:
- どのアカウントでも自動的に開始
- アクティブな NIC アドレスを収集します
- NICアドレスをサーバーに送信
- 割り当てられた PC ホスト名を受け取ります
- 現在のホスト名と割り当てられたホスト名を比較します
- 必要に応じてホスト名を変更します
手順 1 ~ 5 を完全に設計どおりに実行するプログラムがあります。アクティブな NIC アドレスを収集し、サーバー用のパケットを準備し、応答を受信できます。問題は、プログラムがステップ 6 に達したときです。Windows XP では、管理者としてサインインした場合のみ、プログラムは問題なくホスト名を変更します。Windows Vista、7、および 8 では、プログラムはコンピューターのホスト名を変更できません (UAC 昇格が必要なため)。または、管理者権限を持たないユーザー アカウントにサインインした場合、必要な権限がありません。
プログラムに管理者権限が必要であることをユーザーと Windows に通知するためにアプリケーション マニフェストをプログラムに追加すると、Windows Vista 以降では起動時に管理者権限が必要なプログラムが開始されないため、プログラムの起動に失敗します。
以前のマニフェストの変更後、プログラムが管理者アカウントを偽装し、アクティブなユーザーが管理者である必要なくコンピューターに完全にアクセスできるように、管理者であるコンピューターに別のユーザー アカウントを作成しました。Windows XP でも問題なく動作しました。Windows 7 の場合、プログラムは「許可が拒否されました」というメッセージをスローします。以下に示すように、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);
}