Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C#
Article

Launch your app into session 1 using a service helper application written in C#

Rate me:
Please Sign up or sign in to vote.
4.39/5 (17 votes)
13 May 20071 min read 90.9K   2.4K   34   15
Launch your application into session 1 using a service in session 0 (C#) under the local system account

Introduction

This is the same article which I have written earlier in Native C++ code. (Launch your application from session 0 to session 1 in Vista using a service helper application at VistaSessions.asp)

Luzius Kalt mailed me a C# version of the service which would work well for those who wanted the code on the .NET platform.

Since I got many requests to post the article in .NET, I am posting the code I received from Luzius.

To acknowledge his efforts, I am posting this as a separate article.

Using the code

The heart of the application logic is the service. This is what launches the helper application into session 1.

Hence only the service has been rewritten in C#.

The code rewritten in C# uses PINVOKE to execute native API's.

The application Custom message sender which sends the message to the service to launch the application as well as the code which will access HKCU in the registry (refer to my article VistaSessions.asp) is still in native code.

I will update that too soon.

The following structures and API's from Win32 have been declared in C#

C#
// Structure for the CreateProcessAsuser API
[StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }
//Structure for the DuplicateTokenEx API
        enum TOKEN_TYPE : int
        {
            TokenPrimary = 1,
            TokenImpersonation = 2
        }
//Structure for the SetTokenInformation API
        public enum TOKEN_INFORMATION_CLASS : int
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin,
            MaxTokenInfoClass  
        // MaxTokenInfoClass should always be the last enum
        }
//Structure for CreateProcess API
        [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;
        }
//Structure for CreateProcess API
        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }
//Structure for LookupPriveleges API
       [StructLayout(LayoutKind.Sequential)]
        internal struct LUID
        {
            public int LowPart;
            public int HighPart;
        }//end struct
//For the TOKEN PRIVILEGES STRUCTURE
        [StructLayout(LayoutKind.Sequential)]
        internal struct LUID_AND_ATRIBUTES
        {
            public LUID Luid;
            public int Attributes;
        }//end struct
//Structure for the AdjustTokenPrivileges API

        [StructLayout(LayoutKind.Sequential)]
        internal struct TOKEN_PRIVILEGES
        {
            internal int PrivilegeCount;
            //LUID_AND_ATRIBUTES
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            internal int[] Privileges;
        }

//Defined for Token rights

        public const int READ_CONTROL = 0x00020000;
        public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
        public const int STANDARD_RIGHTS_READ = READ_CONTROL;
        public const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
        public const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
        public const int STANDARD_RIGHTS_ALL = 0x001F0000;
        public const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
        public const int TOKEN_ASSIGN_PRIMARY = 0x0001;
        public const int TOKEN_DUPLICATE = 0x0002;
        public const int TOKEN_IMPERSONATE = 0x0004;
        public const int TOKEN_QUERY = 0x0008;
        public const int TOKEN_QUERY_SOURCE = 0x0010;
        public const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
        public const int TOKEN_ADJUST_GROUPS = 0x0040;
        public const int TOKEN_ADJUST_DEFAULT = 0x0080;
        public const int TOKEN_ADJUST_SESSIONID = 0x0100;
        public const int TOKEN_ALL_ACCESS_P = (STANDARD_RIGHTS_REQUIRED |
                                      TOKEN_ASSIGN_PRIMARY |
                                      TOKEN_DUPLICATE |
                                      TOKEN_IMPERSONATE |
                                      TOKEN_QUERY |
                                      TOKEN_QUERY_SOURCE |
                                      TOKEN_ADJUST_PRIVILEGES |
                                      TOKEN_ADJUST_GROUPS |
                                      TOKEN_ADJUST_DEFAULT);
        public const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | 
                      TOKEN_ADJUST_SESSIONID;
        public const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
        public const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
                                      TOKEN_ADJUST_PRIVILEGES |
                                      TOKEN_ADJUST_GROUPS |
                                      TOKEN_ADJUST_DEFAULT;
        public const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;

//Defined for Process Rights
        public const uint MAXIMUM_ALLOWED = 0x2000000;
        public const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
        public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
        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;
        public const int CREATE_NEW_CONSOLE = 0x00000010;
        public const string SE_DEBUG_NAME = "SeDebugPrivilege";
        public const string SE_RESTORE_NAME = "SeRestorePrivilege";
        public const string SE_BACKUP_NAME = "SeBackupPrivilege";
        public const int SE_PRIVILEGE_ENABLED = 0x0002;
        public const int ERROR_NOT_ALL_ASSIGNED = 1300;

//structure for the Process32First API
   
[StructLayout(LayoutKind.Sequential)]
        private struct PROCESSENTRY32
        {
            public uint dwSize;
            public uint cntUsage;
            public uint th32ProcessID;
            public IntPtr th32DefaultHeapID;
            public uint th32ModuleID;
            public uint cntThreads;
            public uint th32ParentProcessID;
            public int pcPriClassBase;
            public uint dwFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szExeFile;
        }      
Rest of the code is straightforward. You can refer to my previous article to understand the core logic. You are free to use the code. You can contact me at jaisvar@gmail.com for more details. I am in the process of writing my second article about UAC tweaks soon.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect www.dizyatec.com
Singapore Singapore
I graduated from Nanyang Technological University, Singapore in May 2004.Currently I am working as a Technical Consultant. I am also doing my Masters of Computing in IT project management from NUS, Singapore.My interests include reading technical articles,watching movies and traveling.My main areas of work include Project Management, Software Analysis and Design,Building Enterprise Applications using Microsoft .NET technologies,smart phone application development (Windows Mobile 5.0 and Blackberry) and System Programing on Windows Platform & WinCE

Comments and Discussions

 
QuestionSome simplifications Pin
X-Tech10-May-12 13:18
X-Tech10-May-12 13:18 
1.
C#
WTSQueryUserToken(dwSessionId, ref hUserToken);

is not needed :P because hUserToken it newer used

2. Crazy loop with 5 or 6 diferent winapi functions calls to find corect winlogon can be done in C#:

C#
Process winLogon = null;
foreach (Process p in Process.GetProcesses()){
    if (p.SessionId == dwSessionId && p.ProcessName.Contains("winlogon")){
        winLogon = p;
        break;
    }
}

GeneralMy vote of 4 Pin
Member 802439017-Jan-12 21:19
Member 802439017-Jan-12 21:19 
GeneralMy vote of 4 Pin
mlcc200022-Sep-10 5:18
mlcc200022-Sep-10 5:18 
GeneralRe: My vote of 4 Pin
Member 802439017-Jan-12 21:00
Member 802439017-Jan-12 21:00 
GeneralRequest for code Pin
Member 450769716-Jun-10 17:09
Member 450769716-Jun-10 17:09 
GeneralPlease convert to VB Pin
KyferEz23-Feb-09 9:35
KyferEz23-Feb-09 9:35 
QuestionBut How do I launch an application under current user as elevated on session 1 ? Pin
Yukoop25-Nov-08 11:22
Yukoop25-Nov-08 11:22 
GeneralYou are a lifesaver Pin
pkorosi29-Jul-08 23:37
pkorosi29-Jul-08 23:37 
GeneralRe: You are a lifesaver Pin
Jaisvar30-Jul-08 2:32
Jaisvar30-Jul-08 2:32 
Generalthe declaration of SetTokenInformation is not correct Pin
curlfw3-Jun-07 14:31
curlfw3-Jun-07 14:31 
GeneralAs is the 1st parameter of CreateEnvironmentBlock Pin
Midi_Mick11-Jul-11 17:31
professionalMidi_Mick11-Jul-11 17:31 
QuestionHow to use? Pin
stevenyoung13-May-07 17:36
stevenyoung13-May-07 17:36 
AnswerRe: How to use? Pin
Jaisvar13-May-07 19:30
Jaisvar13-May-07 19:30 
GeneralRe: How to use? Pin
stevenyoung22-May-07 16:26
stevenyoung22-May-07 16:26 
GeneralRe: How to use? Pin
BugByter16-Aug-08 5:56
BugByter16-Aug-08 5:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.