public static string sidFromProcess(IntPtr processHandle, Action <string> errorLog)
        {
            string resultSID = "";
            IntPtr _SID      = IntPtr.Zero;

            try
            {
                if (ProcessHandleToSidStruct(processHandle, out _SID, errorLog))
                {
                    if (!ConvertSidToStringSid(_SID, ref resultSID))
                    {
                        errorLog?.Invoke("Can't convert sid to string\n"
                                         + "LastWin32Error: " + Win32ApiUtils.LaseError());

                        // May return code `(1337) The security ID structure is invalid`
                        //  even tough not documented here:
                        //  (Maybe because the test try before the process had the chance to fill it with data?? fast at start??)
                        //      https://docs.microsoft.com/en-gb/windows/win32/api/sddl/nf-sddl-convertstringsidtosida?redirectedfrom=MSDN
                    }
                }
            }
            catch (Exception ex) {
                errorLog?.Invoke("Can't get sid from process\n"
                                 + "LastWin32Error: " + Win32ApiUtils.LaseError() + "\n" + ex.ToString());
            }

            if (resultSID == "")
            {
                errorLog?.Invoke("Can't get sid from process\n"
                                 + "LastWin32Error: " + Win32ApiUtils.LaseError());
            }

            return(resultSID);
        }
        public static bool ProcessHandleToSidStruct(IntPtr pToken, out IntPtr SID, Action <string> errorLog)
        {
            bool result = false;
            int  Access = TOKEN_QUERY;

            IntPtr procToken = IntPtr.Zero;

            SID = IntPtr.Zero;

            try
            {
                if (OpenProcessToken(pToken, Access, ref procToken))
                {
                    result = ProcessTokenToSidStruct(procToken, out SID, errorLog);
                    if (!result)
                    {
                        errorLog?.Invoke("Can't get sid token of process token\n"
                                         + "LastWin32Error: " + Win32ApiUtils.LaseError());
                    }

                    CloseHandle(procToken);
                }
                return(result);
            }
            catch (Exception ex)
            {
                errorLog?.Invoke("Can't get sid from process handle\n"
                                 + "LastWin32Error: " + Win32ApiUtils.LaseError() + "\n" + ex.ToString());
                return(false);
            }
        }
        /// <summary>
        /// Get Sid from process
        /// </summary>
        /// <param name="PID">process id</param>
        /// <param name="errorLog">how to handle errors</param>
        /// <remarks>If you try this too fast, you can get Error codes 0 (ERROR_SUCCESS) or 6 (INVALID_HANDLE)</remarks>
        /// <returns></returns>
        public static string sidFromProcess(uint PID, Action <string> errorLog)
        {
            string result = "";
            IntPtr handle = IntPtr.Zero;

            try
            {
                // Why Query is enough : .
                //      https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b
                handle = OpenProcess(ProcessAccessFlags.QueryInformation, false, PID);
                if (!handle.Equals(IntPtr.Zero))
                {
                    result = sidFromProcess(handle, errorLog);
                }

                if (handle.Equals(IntPtr.Zero))
                {
                    errorLog?.Invoke("Can't open handle for SID! (Got null)\n"
                                     + "LastWin32Error: " + Win32ApiUtils.LaseError());
                }
            }
            catch (Exception ex)
            {
                errorLog?.Invoke("Can't get sid from process\n"
                                 + "LastWin32Error: " + Win32ApiUtils.LaseError() + "\n" + ex.ToString());
            }
            finally
            {
                if (!handle.Equals(IntPtr.Zero))
                {
                    CloseHandle(handle);
                }
            }
            return(result);
        }
        private static bool ProcessTokenToSidStruct(IntPtr token, out IntPtr SID, Action <string> errorLog)
        {
            bool      result    = false;
            const int bufLength = 256; // actuall need 36

            TOKEN_USER tokUser;
            IntPtr     tokenInformation = IntPtr.Zero;

            SID = IntPtr.Zero;

            try
            {
                int dataLength = bufLength; // Usally you call GetTokenInformation() with null,0 to get size
                                            //          we skip that and give it 256 always (bigger than the actual 36)
                tokenInformation = Marshal.AllocHGlobal(dataLength);
                result           = GetTokenInformation(token,
                                                       TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, dataLength, ref dataLength);
                if (result)
                {
                    tokUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER));
                    SID     = tokUser.User.Sid;
                    if (SID == IntPtr.Zero)
                    {
                        errorLog?.Invoke("Sid in sid struct is null\n"
                                         + "LastWin32Error: " + Win32ApiUtils.LaseError());
                    }
                }
                else
                {
                    errorLog?.Invoke("Can't get sid struct from token\n"
                                     + "LastWin32Error: " + Win32ApiUtils.LaseError());
                }
            }
            catch (Exception ex)
            {
                errorLog?.Invoke("Can't get sid from process token\n"
                                 + "LastWin32Error: " + Win32ApiUtils.LaseError() + "\n" + ex.ToString());
                result = false;
            }
            finally
            {
                Marshal.FreeHGlobal(tokenInformation);
            }

            return(result);
        }