在Windows XP登录屏幕(.NET / Pinvoke)上运行进程(使用GUI)
我需要在登录屏幕上编写一个运行应用程序(使用gui,例如calc.exe )的小服务 。
我已经找到了这个问题(和答案): 在Windows 7欢迎屏幕上运行一个进程
如果您不理解这是如何工作的,请阅读代码注释:
// grab the winlogon process Process winLogon = null; foreach (Process p in Process.GetProcesses()) { if (p.ProcessName.Contains("winlogon")) { winLogon = p; break; } } // grab the winlogon's token IntPtr userToken = IntPtr.Zero; if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken)) { log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error()); } // create a new token IntPtr newToken = IntPtr.Zero; SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES(); tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes); SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES(); threadAttributes.nLength = Marshal.SizeOf(threadAttributes); // duplicate the winlogon token to the new token if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out newToken)) { log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error()); } TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES(); tokPrivs.PrivilegeCount = 1; LUID seDebugNameValue = new LUID(); if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue)) { log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error()); } tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1]; tokPrivs.Privileges[0].Luid = seDebugNameValue; tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // escalate the new token's privileges if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)) { log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error()); } PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = "Winsta0\\Winlogon"; // start the process using the new token if (!CreateProcessAsUser(newToken, "calc.exe", null, ref tokenAttributes, ref threadAttributes, true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero, "C:\\Windows\\System32", ref si, out pi)) { log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error()); } Process _p = Process.GetProcessById(pi.dwProcessId); if (_p != null) { log("Process " + _p.Id + " Name " + _p.ProcessName); } else { log("Process not found"); }
它适用于Windows 7.使用XP时,我在调用CreateProcessAsUser
遇到错误1349 ERROR_BAD_TOKEN_TYPE
(MSDN: 令牌的类型不适合其尝试使用。 )。
如何在Windows XP中实现这一点? 它不一定是上面的代码,但它应该作为一项服务(使用系统帐户?)。
感谢您对Fluxer的支持
这肯定与权限问题有关(Windows Vista和7在安全性方面有显着变化)。 而不是试图获取winlogon.exe的令牌并冒充它,尝试通过WTSQueryUserToken
获取用户令牌,如下所示:
WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);
用以上语句替换用于获取标记的OpenProcessToken行。
你的新代码应该是这样的:
// if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | //TOKEN_DUPLICATE, out userToken)) // { // log("ERROR: OpenProcessToken returned false - " + //Marshal.GetLastWin32Error()); // } WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);
你的dll是这样导入的:
[DllImport("Kernel32.dll", SetLastError = true)] [return:MarshalAs(UnmanagedType.U4)] public static extern int WTSGetActiveConsoleSessionId ( );
您只需要用此代码替换我注释掉的部分。
- LINQ左外连接查询错误:OuterApply没有相应的密钥
- DispatchTimer – 如果上一个tick仍在运行,则阻止触发tick事件
- 在使用F5时,最终似乎没有在C#控制台应用程序中执行
- 如何将日期格式化为本地化的Short MonthDay字符串
- String.Format计算预期args的数量
- 在Window Application中使用HttpContext.Current.Server.MapPath?
- 使用LINQ查找多个属性的重复项
- 当我执行输入手势时,为什么不设置MenuItem.InputGestureText会导致MenuItem激活?
- 使用INotifyPropertyChanged绑定到Silverlight中的字典