locked
"Arithmetic operation resulted in an overflow." C# RRS feed

  • Question

  • Regarding the script below, a user replied that they were able to get the shared C# script working via removing a variable. I am not versed in C# and I am having a hard time figuring out the fix. Any ideas?

    Was getting the following error:

    Exception calling "ReadPrivilege" with "1" argument(s): "Arithmetic operation resulted in an overflow."
    At line:232 char:1
    + $blah = $lsa.ReadPrivilege("SeInteractiveLogonRight")
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : OverflowException

    Had to remove the 'elemOff' variable and just use 'buffer' directly.   The casting to (int) was causing overflow.

    Thanks for script

    # All of this C# code is used to call the Win32 API function we need, and deal with its output.
    
    $csharp = @'
        using System;
        using System.Runtime.InteropServices;
        using System.Security;
        using System.Security.Principal;
        using System.ComponentModel;
    
        namespace LsaSecurity
        {
            using LSA_HANDLE = IntPtr;
    
            [StructLayout(LayoutKind.Sequential)]
            public struct LSA_OBJECT_ATTRIBUTES
            {
                public int Length;
                public IntPtr RootDirectory;
                public IntPtr ObjectName;
                public int Attributes;
                public IntPtr SecurityDescriptor;
                public IntPtr SecurityQualityOfService;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct LSA_UNICODE_STRING
            {
                public ushort Length;
                public ushort MaximumLength;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string Buffer;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct LSA_ENUMERATION_INFORMATION
            {
               public IntPtr PSid;
            }
    
            sealed public class Win32Sec
            {
                [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
                           SuppressUnmanagedCodeSecurityAttribute]
                public static extern uint LsaOpenPolicy(LSA_UNICODE_STRING[] SystemName,
                                                        ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
                                                        int AccessMask,
                                                        out IntPtr PolicyHandle);
    
                [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
                           SuppressUnmanagedCodeSecurityAttribute]
                public static extern uint LsaEnumerateAccountsWithUserRight(LSA_HANDLE PolicyHandle,
                                                                            LSA_UNICODE_STRING[] UserRights,
                                                                            out IntPtr EnumerationBuffer,
                                                                            out int CountReturned);
    
                [DllImport("advapi32")]
                public static extern int LsaNtStatusToWinError(int NTSTATUS);
    
                [DllImport("advapi32")]
                public static extern int LsaClose(IntPtr PolicyHandle);
    
                [DllImport("advapi32")]
                public static extern int LsaFreeMemory(IntPtr Buffer);
            }
    
            public class LsaWrapper : IDisposable
            {
                public enum Access : int
                {
                    POLICY_READ = 0x20006,
                    POLICY_ALL_ACCESS = 0x00F0FFF,
                    POLICY_EXECUTE = 0X20801,
                    POLICY_WRITE = 0X207F8
                }
    
                const uint STATUS_ACCESS_DENIED = 0xc0000022;
                const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
                const uint STATUS_NO_MEMORY = 0xc0000017;
                const uint STATUS_NO_MORE_ENTRIES = 0xc000001A;
    
                IntPtr lsaHandle;
    
                public LsaWrapper()
                    : this(null)
                { }
    
                // local system if systemName is null
                public LsaWrapper(string systemName)
                {
                    LSA_OBJECT_ATTRIBUTES lsaAttr;
                    lsaAttr.RootDirectory = IntPtr.Zero;
                    lsaAttr.ObjectName = IntPtr.Zero;
                    lsaAttr.Attributes = 0;
                    lsaAttr.SecurityDescriptor = IntPtr.Zero;
                    lsaAttr.SecurityQualityOfService = IntPtr.Zero;
                    lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
                    lsaHandle = IntPtr.Zero;
                
                    LSA_UNICODE_STRING[] system = null;
    
                    if (systemName != null)
                    {
                        system = new LSA_UNICODE_STRING[1];
                        system[0] = InitLsaString(systemName);
                    }
    
                    uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
                                                      (int)Access.POLICY_ALL_ACCESS,
                                                      out lsaHandle);
                    if (ret == 0) { return; }
    
                    if (ret == STATUS_ACCESS_DENIED)
                    {
                        throw new UnauthorizedAccessException();
                    }
                    if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
                    {
                        throw new OutOfMemoryException();
                    }
                    throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
                }
    
                public SecurityIdentifier[] ReadPrivilege(string privilege)
                {
                    LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
                    privileges[0] = InitLsaString(privilege);
                    IntPtr buffer;
                    int count = 0;
                    uint ret = Win32Sec.LsaEnumerateAccountsWithUserRight(lsaHandle, privileges, out buffer, out count);
                
                    if (ret == 0)
                    {
                        SecurityIdentifier[] sids = new SecurityIdentifier[count];
    
                        for (int i = 0, elemOffs = (int)buffer; i < count; i++)
                        {
                            LSA_ENUMERATION_INFORMATION lsaInfo = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure(
                                (IntPtr)elemOffs, typeof(LSA_ENUMERATION_INFORMATION));
    
                            sids[i] = new SecurityIdentifier(lsaInfo.PSid);
    
                            elemOffs += Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION));
                        }
    
                        return sids;
                    }
    
                    if (ret == STATUS_ACCESS_DENIED)
                    {
                        throw new UnauthorizedAccessException();
                    }
                    if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
                    {
                        throw new OutOfMemoryException();
                    }
    
                    throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
                }
    
                public void Dispose()
                {
                    if (lsaHandle != IntPtr.Zero)
                    {
                        Win32Sec.LsaClose(lsaHandle);
                        lsaHandle = IntPtr.Zero;
                    }
                    GC.SuppressFinalize(this);
                }
    
                ~LsaWrapper()
                {
                    Dispose();
                }
    
                public static LSA_UNICODE_STRING InitLsaString(string s)
                {
                    // Unicode strings max. 32KB
                    if (s.Length > 0x7ffe)
                       throw new ArgumentException("String too long");
                    LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
                    lus.Buffer = s;
                    lus.Length = (ushort)(s.Length * sizeof(char));
                    lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
                    return lus;
                }
            }
        }
    '@
    
    Add-Type -TypeDefinition $csharp
    
    # Here's the code that uses the C# classes we've added.
    
    $lsa = New-Object LsaSecurity.LsaWrapper
    $sids = $lsa.ReadPrivilege('SeInteractiveLogonRight')
    
    # ReadPrivilege() returns an array of [SecurityIdentifier] objects.  We'll try to translate them into a more human-friendly
    # NTAccount object here (which will give us a Domain\User string), and output the value whether the translation succeeds or not.
    
    foreach ($sid in $sids)
    {
        try
        {
            $sid.Translate([System.Security.Principal.NTAccount]).Value
        }
        catch
        {
            $sid.Value
        }
    }

    Wednesday, October 23, 2019 10:06 PM

Answers

  • What you are really doing is wrapping P/Invoke (unmanaged Win32 API) using .NET in PowerShell.

    If you are not very experienced with P/Invoke and unmanaged code (particularly concepts like pointers and marshalling), you are likely to be in over your head very quickly.

    Therefore, your question is not trivial and may be entirely outside the scope of this forum.

    How about starting with explaining what the script is supposed to do? What problem are you solving?


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Bill_Stewart Tuesday, April 14, 2020 5:01 PM
    Wednesday, October 23, 2019 10:12 PM

All replies

  • Sorry but this is not a C# forum. Please post C# issues in the correct forum.


    \_(ツ)_/

    Wednesday, October 23, 2019 10:09 PM
  • Also you do not need that right to translate a SID.


    \_(ツ)_/

    Wednesday, October 23, 2019 10:10 PM
  • What you are really doing is wrapping P/Invoke (unmanaged Win32 API) using .NET in PowerShell.

    If you are not very experienced with P/Invoke and unmanaged code (particularly concepts like pointers and marshalling), you are likely to be in over your head very quickly.

    Therefore, your question is not trivial and may be entirely outside the scope of this forum.

    How about starting with explaining what the script is supposed to do? What problem are you solving?


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Bill_Stewart Tuesday, April 14, 2020 5:01 PM
    Wednesday, October 23, 2019 10:12 PM
  • I appreciate the reply. Looking back at the post, I do regret not putting more details in. Basically, this was sourced from another post in this forum, and the solution seemed fairly complete. I would have linked it, but I joined pretty much just for this issue. Short story is that I need to query local security policies, but couldn't find a good way to do that. The original post is named "Query the Local Computer Policy with Powershell". Sorry again, had just hit a wall after a long day.
    Thursday, October 24, 2019 1:10 PM
  • Apologies for the lack of detail and background on the issue. See my reply above. I will dig in and do some more research.
    Thursday, October 24, 2019 1:11 PM
  • Query the local computer policy with PowerShell - what problem are you trying to solve?

    -- Bill Stewart [Bill_Stewart]

    Thursday, October 24, 2019 1:36 PM
  • To get this information locally we would use SECEDIT to dump the settings. There is really no other way.

    To get the settings for the current user use "WHOAMI" which will show the available user capabilities and which ones are currently enabled.


    \_(ツ)_/

    Thursday, October 24, 2019 4:10 PM