[英]Problems starting a process from a DLL in Windows Server 2008
I have a DLL which starts up some basic Windows programs: 我有一个DLL,可以启动一些基本的Windows程序:
using System;
using System.Diagnostics;
using Microsoft.Win32;
namespace ExternalProgram
{
public class Access
{
String applicationName = String.Empty;
public Access()
{
}
public void Telnet(string address)
{
applicationName = "telnet.exe " + address;
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
public void Ping(string address)
{
Process.Start("ping.exe", address + " -t");
//applicationName = "ping.exe " + address + " -t";
//ApplicationLoader.PROCESS_INFORMATION procInfo;
//ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
public void Putty(string address)
{
applicationName = "putty.exe " + address;
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
public void RemoteDesktop(string address)
{
applicationName = "mstsc.exe " + "/v " + address;
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
public void Browse(string address)
{
applicationName = GetDefaultBrowser() + " " + address;
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
private string GetDefaultBrowser()
{
string browser = string.Empty;
RegistryKey key = null;
try
{
key = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command", false);
//trim off quotes
browser = key.GetValue(null).ToString().ToLower().Replace("\"", "");
if (!browser.EndsWith("exe"))
{
//get rid of everything after the ".exe"
browser = browser.Substring(0, browser.LastIndexOf(".exe") + 4);
}
}
finally
{
if (key != null) key.Close();
}
return browser;
}
}
}
namespace ExternalProgram
{
/// <summary>
/// Class that allows running applications with full admin rights. In
/// addition the application launched will bypass the Vista UAC prompt.
/// </summary>
public class ApplicationLoader
{
#region Structures
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
#endregion
#region Enumerations
enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2
}
enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
#endregion
#region Constants
public const int TOKEN_DUPLICATE = 0x0002;
public const uint MAXIMUM_ALLOWED = 0x2000000;
public const int CREATE_NEW_CONSOLE = 0x00000010;
public const int IDLE_PRIORITY_CLASS = 0x40;
public const int NORMAL_PRIORITY_CLASS = 0x20;
public const int HIGH_PRIORITY_CLASS = 0x80;
public const int REALTIME_PRIORITY_CLASS = 0x100;
#endregion
#region Win32 API Imports
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
static extern uint WTSGetActiveConsoleSessionId();
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
#endregion
/// <summary>
/// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
/// </summary>
/// <param name="applicationName">The name of the application to launch</param>
/// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
/// <returns></returns>
public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo)
{
uint winlogonPid = 0;
IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
procInfo = new PROCESS_INFORMATION();
// obtain the currently active session id; every logged on user in the system has a unique session id
uint dwSessionId = WTSGetActiveConsoleSessionId();
// obtain the process id of the winlogon process that is running within the currently active session
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
if ((uint)p.SessionId == dwSessionId)
{
winlogonPid = (uint)p.Id;
}
}
// obtain a handle to the winlogon process
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
// obtain a handle to the access token of the winlogon process
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
{
CloseHandle(hProcess);
return false;
}
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
// I would prefer to not have to use a security attribute variable and to just
// simply pass null and inherit (by default) the security attributes
// of the existing token. However, in C# structures are value types and therefore
// cannot be assigned the null value.
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
// copy the access token of the winlogon process; the newly created token will be a primary token
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
{
CloseHandle(hProcess);
CloseHandle(hPToken);
return false;
}
// By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
// the window station has a desktop that is invisible and the process is incapable of receiving
// user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
// interaction with the new process.
STARTUPINFO si = new STARTUPINFO();
si.cb = (int)Marshal.SizeOf(si);
si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
// flags that specify the priority and creation method of the process
int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
// create a new process in the current user's logon session
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
applicationName, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo // receives information about new process
);
// invalidate the handles
CloseHandle(hProcess);
CloseHandle(hPToken);
CloseHandle(hUserTokenDup);
return result; // return the result
}
}
}
The ApplicationLoader
code I snagged from a blog online about bypassing Vista UAC. 我从网上博客中窃取了关于绕过Vista UAC的
ApplicationLoader
代码。 When I first wrote the code I noticed that the process would start, but that it would not be visible to the user, you could only see/kill the process through the process manager. 当我第一次编写代码时,我注意到该过程将启动,但对用户不可见,您只能通过过程管理器查看/杀死该过程。
The third-party ApplicationLoader
code resolved this issue on Vista and Win7. 第三方
ApplicationLoader
代码在Vista和Win7上解决了此问题。 I am able to see the process happily start and run fine. 我能够看到该过程愉快地启动并运行良好。
I just moved the DLL over to Windows Server 2008 and I am not seeing the process start at all. 我只是将DLL移到Windows Server 2008上,却完全看不到该过程开始。 No errors, no warnings.
没有错误,没有警告。 I disabled UAC on the server, rebooted, tried again and I saw no change.
我在服务器上禁用了UAC,重新启动,然后再次尝试,但没有发现任何变化。
I tried starting the process regularly as well as starting it using the application loader, no dice. 我尝试定期启动该过程以及使用应用程序加载器启动该过程,没有尝试。 It does start fine from
Run()
, though, so it is my code. 它确实可以从
Run()
开始,所以这是我的代码。
Any ideas? 有任何想法吗? Where do I begin on error logging for something like this?
我应该从哪里开始进行类似这样的错误记录? Do I still need the
ApplicationLoader
code at all, or is it breaking in Server 2008? 我还是仍然需要
ApplicationLoader
代码,还是在Server 2008中会破坏代码?
EDIT: I was able to track this issues further. 编辑:我能够进一步跟踪此问题。 The process is starting up successfully, but then immediately becomes not visible while loading DLLs.
该过程已成功启动,但随后在加载DLL时立即变得不可见。 I've seen this written about on Google, so I'm looking, but any other advice would be appreciated.
我已经在Google上看到过有关此内容的文章,因此我正在寻找,但其他建议也将不胜感激。
EDIT2: Discovery! EDIT2:发现! Logging in as Administrator instead of a user with administrative privileges yields different results -- process is alive but not visible.
以管理员身份而不是具有管理特权的用户身份登录会产生不同的结果-进程处于活动状态但不可见。
EDIT: I HAVE IDENTIFIED THE ISSUE AND HAVE NO IDEA TO SOLVE. 编辑:我已经确定了问题,没有解决的想法。 Would love help.
希望帮助。
So, here is what's going on in two different scenarios: 因此,这是在两种不同情况下发生的事情:
Scenario 1: Windows 7 (WORKING) 方案1:Windows 7(工作)
If I go to Start->Run->Ping.exe 127.0.0.1 -t and then open Task Manager I see PING.EXE opened under SEAN running in SESSION 1. 如果我转到开始->运行-> Ping.exe 127.0.0.1 -t,然后打开任务管理器,我会看到在SESSION 1中运行的SEAN下打开了PING.EXE。
If I run Ping.exe using Process.Start() PING.EXE opens up under SYSTEM running in SESSION 0. It is invisible because it is not running in the same session as I am currently working under. 如果我使用Process.Start()运行Ping.exe,则PING.EXE在SESSION 0中运行的SYSTEM下打开。它不可见,因为它不在与我当前正在使用的会话中运行。
If I run Ping.exe using StartProcessAndBypassUAC PING.EXE opens up under SYSTEM running in SESSION 1. It is visible to me. 如果我使用StartProcessAndBypassUAC运行Ping.exe,则PING.EXE在SESSION 1中运行的SYSTEM下打开。 Of note, the session ID here is the same as when I manually run ping.
值得注意的是,此处的会话ID与我手动运行ping时的会话ID相同。
Scenario 2: Windows Server 2008 (NOT WORKING) - UAC is 100% disabled and security policies disabled. 方案2:Windows Server 2008(不工作)-UAC已100%禁用,安全策略已禁用。
If I go to Start->Run->Ping.exe 127.0.0.1 -t and then open Task Manager I see PING.EXE opened under Administrator running in Session ID 2. 如果我转到“开始”->“运行”->“ Ping.exe 127.0.0.1 -t”,然后打开“任务管理器”,则会看到在会话ID 2中运行的“管理员”下打开了PING.EXE。
If I run it using Process.Start it opens up under SYSTEM in session 0 and is invisible. 如果我使用Process.Start运行它,它将在会话0的SYSTEM下打开,并且是不可见的。 If I run it using StartProcessAndBypassUAC it opens up under SYSTEM in session 1.
如果我使用StartProcessAndBypassUAC运行它,它将在会话1的SYSTEM下打开。
While it is opening it up in session 1 in both cases, I believe I am unable to see it because administrator is working in session 2 and ping is off in session 1. 虽然在两种情况下都在会话1中打开它,但我相信我看不到它,因为管理员正在会话2中工作,而ping在会话1中处于关闭状态。
How can I open up ping.exe in session 2 in server 2k8? 如何在服务器2k8的会话2中打开ping.exe?
I ran into a similar problem when I tried a working C# application on Windows Server 2008 for the first time. 第一次在Windows Server 2008上尝试正常运行的C#应用程序时,我遇到了类似的问题。 When I would try to launch a process it just wouldn't.
当我尝试启动一个流程时,它不会。
What solved my problem was instead of relying on the working directory, I used the complete path to the executable. 解决了我的问题的是,我没有使用工作目录,而是使用了可执行文件的完整路径。
Give this a try 试试这个
applicationName = @"C:\some\dir\putty.exe " + address;
I never came to a solid conclusion on how to automatically detect a user's ID when logged in remotely. 对于远程登录时如何自动检测用户ID的问题,我从未得出明确的结论。 Suspect this is a security concern.
怀疑这是一个安全问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.