Devpia, C#포럼에서 어떤 분께서 프로세스(실행중인 프로그램)에 대한 정보를 가져오는 질문에 대해서

시삽인 남정현님께서 답한 내용입니다.

 

Vista 및 7등 Windows계열에서는 권한 문제때문에 프로세스 정보를 얻어오지 못할 수 있다고 합니다.

아래 기재된 링크를 통해서 UAC권한상승에 대한 문제를 해결하고 아래 샘플코드에서 프로세스 정보에 접근하는 방법을 소개 하고 있습니다.

 

 

 

 

- 이하 원문

(http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=116488&ref=116486&page=1#Contents116488)

 

 

다음의 샘플 코드를 참고하시면 되겠습니다. 아래 코드는, Windows Vista 이후의 운영 체제의 경우, 권한이 없기 때문에 프로세스에 대한 토큰을 열 수 없어서 사용자 이름을 가져오지 못할 수 있으며, 이를 해결하려면 해당 프로그램을 UAC 매니페스트를 지정하여 권한 상승 (Elevation) 처리를 해야 합니다. UAC 권한 상승에 대한 자세한 정보는 http://sjpison.tistory.com/68 를 참고하시면 도움될 것입니다.

 

namespace ConsoleApplication1
{
    using System;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    static class ProcessExtension
    {
        #region P/Invoke

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool LookupAccountSid(
            string lpSystemName,
            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
            StringBuilder lpName,
            ref uint cchName,
            StringBuilder ReferencedDomainName,
            ref uint cchReferencedDomainName,
            out SID_NAME_USE peUse);

        #endregion // P/Invoke

        #region Constants

        [NonSerialized]
        public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000u;

        [NonSerialized]
        public const uint STANDARD_RIGHTS_READ = 0x00020000u;

        [NonSerialized]
        public const uint TOKEN_ASSIGN_PRIMARY = 0x0001u;

        [NonSerialized]
        public const uint TOKEN_DUPLICATE = 0x0002u;

        [NonSerialized]
        public const uint TOKEN_IMPERSONATE = 0x0004u;

        [NonSerialized]
        public const uint TOKEN_QUERY = 0x0008u;

        [NonSerialized]
        public const uint TOKEN_QUERY_SOURCE = 0x0010u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_GROUPS = 0x0040u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_DEFAULT = 0x0080u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_SESSIONID = 0x0100u;

        [NonSerialized]
        public const uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);

        [NonSerialized]
        public const uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
            TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
            TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
            TOKEN_ADJUST_SESSIONID);

        [NonSerialized]
        public const uint NO_ERROR = 0u;

        [NonSerialized]
        public const uint ERROR_INSUFFICIENT_BUFFER = 122u;

        #endregion // Constants

        #region Enum Values

        [Serializable]
        public enum TOKEN_INFORMATION_CLASS : uint
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin
        }

        [Serializable]
        public enum SID_NAME_USE : uint
        {
            SidTypeUser = 1,
            SidTypeGroup,
            SidTypeDomain,
            SidTypeAlias,
            SidTypeWellKnownGroup,
            SidTypeDeletedAccount,
            SidTypeInvalid,
            SidTypeUnknown,
            SidTypeComputer
        }

        #endregion // Enum Values

        #region Structures

        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_USER
        {
            public SID_AND_ATTRIBUTES User;
        }

        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public struct SID_AND_ATTRIBUTES
        {
            public IntPtr Sid;
            public int Attributes;
        }

        #endregion // Structures

        public static byte[] GetSIDByteArr(Process targetProcess)
        {
            int MAX_INTPTR_BYTE_ARR_SIZE = 512;
            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr processHandle = IntPtr.Zero;
            byte[] sidBytes;

            try
            {
                try { processHandle = targetProcess.Handle; }
                catch { return null; }

                // Get the Process Token
                if (!OpenProcessToken(processHandle, TOKEN_READ, out tokenHandle))
                    throw new Exception("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());

                uint tokenInfoLength = 0;
                bool result;
                result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, tokenInfoLength, out tokenInfoLength);  // get the token info length
                IntPtr tokenInfo = Marshal.AllocHGlobal((int)tokenInfoLength);
                result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInfo, tokenInfoLength, out tokenInfoLength);  // get the token info

                // Get the User SID
                if (result)
                {
                    TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInfo, typeof(TOKEN_USER));
                    sidBytes = new byte[MAX_INTPTR_BYTE_ARR_SIZE];  // Since I don't yet know how to be more precise w/ the size of the byte arr, it is being set to 512
                    Marshal.Copy(tokenUser.User.Sid, sidBytes, 0, MAX_INTPTR_BYTE_ARR_SIZE);  // get a byte[] representation of the SID
                }
                else
                    throw new Exception("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());

                return sidBytes;
            }
            finally
            {
                if (!tokenHandle.Equals(IntPtr.Zero))
                    CloseHandle(tokenHandle);
            }
        }

        public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName, out int win32ErrorCode)
        {
            StringBuilder name = new StringBuilder();
            uint cchName = (uint)name.Capacity;

            StringBuilder referencedDomainName = new StringBuilder();
            uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;

            SID_NAME_USE sidUse;
            byte[] sid = GetSIDByteArr(targetProcess);

            if (sid == null)
            {
                win32ErrorCode = Marshal.GetLastWin32Error();
                userName = null;
                domainName = null;
                return false;
            }

            win32ErrorCode = (int)NO_ERROR;

            if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
                referencedDomainName, ref cchReferencedDomainName, out sidUse))
            {
                win32ErrorCode = Marshal.GetLastWin32Error();

                if (win32ErrorCode == ERROR_INSUFFICIENT_BUFFER)
                {
                    name.EnsureCapacity((int)cchName);
                    referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
                    win32ErrorCode = (int)NO_ERROR;

                    if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
                        referencedDomainName, ref cchReferencedDomainName, out sidUse))
                        win32ErrorCode = Marshal.GetLastWin32Error();
                }
            }

            if (win32ErrorCode == 0)
            {
                userName = name.ToString();
                domainName = referencedDomainName.ToString();
                return true;
            }
            else
            {
                userName = null;
                domainName = null;
                return false;
            }
        }

        public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName)
        {
            int win32ErrorCodeToIgnore = 0;
            return GetUserAndDomainName(targetProcess, targetSystemName, out userName, out domainName, out win32ErrorCodeToIgnore);
        }

        public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName, int win32ErrorCode)
        {
            return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCode);
        }

        public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName)
        {
            int win32ErrorCodeToIgnore = 0;
            return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCodeToIgnore);
        }
    }

 

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            foreach (Process eachProcess in Process.GetProcesses())
            {
                string imageName = eachProcess.ProcessName;
                string userName = null;
                string domainName = null;
                string result = null;

                if (ProcessExtension.GetUserAndDomainName(eachProcess, out userName, out domainName))
                    result = userName + "@" + domainName;
                else
                    result = "(Access Denied)";

                Console.WriteLine("{0} / {1}", imageName, result);
            }
        }
    }
}

 

+ Recent posts