locked
Help with making C# service spawn process to take desktop screenshots RRS feed

  • Question

  • I'm currently attempting to write a C# windows service that spawns a child process to take desktop screenshots.  I've looked into and read many tutorials and blogs stating that you have to duplicate the tokenID of the winlogon process, ect...but I've been unable to get it to work.  All of the win32 functions return TRUE, hence they were successfull, but the child process is never executed.  Does anybody see anything wrong with my code?  Also, the service runs under LocalSystem.  Here's the code I'm using.

    Code Snippet

    Process[] processes = Process.GetProcessesByName("explorer");
    IntPtr hProcess = ProcessUtility.OpenProcess((uint)ProcessUtility.MAXIMUM_ALLOWED, false, (uint)processes[0].Id);

    IntPtr tokenHandle = IntPtr.Zero;
    bool ret = ProcessUtility.OpenProcessToken(hProcess, (uint)(ProcessUtility.TOKEN_READ | ProcessUtility.TOKEN_DUPLICATE |
    ProcessUtility.TOKEN_QUERY | ProcessUtility.TOKEN_ASSIGN_PRIMARY), ref tokenHandle);
    Console.WriteLine(ret);
    uint tokenID = 0;
    uint len = 0;
    ret = ProcessUtility.GetTokenInformation(tokenHandle, ProcessUtility.TOKEN_INFORMATION_CLASS.TokenSessionId, ref tokenID, sizeof(uint), ref len);
    Console.WriteLine("{0} {1} {2}", ret, tokenID, len);

    ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTES();
    sa.Length = Marshal.SizeOf(sa);

    ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
    si.cb = Marshal.SizeOf(si);
    si.lpDesktop = "Winsta0\\Default";

    ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();

    string filename = AppDomain.CurrentDomain.BaseDirectory + "\\RackScanCapture.exe";
    string cmdLine = "\"" + filename + "\" " + deviceKey;
    ProcessUtility.CreateProcessAsUser(tokenHandle, filename, cmdLine, ref sa, ref sa, false, 0, IntPtr.Zero, AppDomain.CurrentDomain.BaseDirectory, ref si, ref pi);


    And here are my DLLImport definitions, in case somebody sees a typo.

    Code Snippet

    [DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
    ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
    string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
    ref PROCESS_INFORMATION lpProcessInformation);

    [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
    public static extern bool DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    Int32 ImpersonationLevel, Int32 dwTokenType,
    ref IntPtr phNewToken);

    [DllImport("kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern UInt32 WTSGetActiveConsoleSessionId();

    [DllImport("wtsapi32.dll", EntryPoint = "WTSQueryUserToken", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern bool WTSQueryUserToken(ulong SessionId, ref IntPtr phToken);

    [DllImport("user32.dll", EntryPoint = "WaitForInputIdle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern UInt32 WaitForInputIdle(IntPtr hProcess, UInt32 dwMilliseconds);

    [DllImport("kernel32.dll", EntryPoint = "WaitForSingleObject", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern UInt32 WaitForSingleObject(IntPtr hHandle, Int32 dwMilliseconds);

    [DllImport("kernel32.dll", EntryPoint = "OpenProcess", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, bool bInheritHandle, UInt32 dwProcessID);

    [DllImport("advapi32.dll", EntryPoint = "OpenProcessToken", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle);

    [DllImport("advapi32.dll", EntryPoint = "GetTokenInformation", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
    ref UInt32 TokenInformation, UInt32 TokenInformationLength, ref uint ReturnLength);


    Wednesday, August 6, 2008 3:03 PM

All replies

  • One more thing I just realized, my RackScanCapture.exe child process I'm attempting to run IS being executed, but it seems to be suspended in memory and never executes.
    Wednesday, August 6, 2008 3:29 PM