Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is a securestring marshalled to unmanaged code?

What prompted this question: I'm trying to change the account under which a windows service runs. I decided to use the win32 api rather than WMI and started looking at ChangeServiceConfig.

I thought I could simply use the SecureString type in the unmanaged method signature and it would work fine. Hmmm, not quite. This made me wonder, does anyone know what native (win32) type the SecureString class is marshalled as (by default) to unmanaged code?

like image 427
Kepboy Avatar asked Dec 08 '25 08:12

Kepboy


1 Answers

I never got an answer to the question in the title, so I still don't know SecureString is marshalled to unmanaged code.

I did, however, get my code working by using the suggestions in some of the other answers. I have provided the code below.

internal static class NativeService
{
    ...
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ChangeServiceConfig(IntPtr hService, uint nServiceType, uint nStartType, uint nErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, [In] char[] lpDependencies, string lpServiceStartName, IntPtr lpPassword, string lpDisplayName);
    ...
    public const uint SERVICE_NO_CHANGE = 0xffffffff;
}

internal class ClassThatConfiguresService
{
    ...
    public void ConfigureStartupAccount(IntPtr service, string userName, SecureString password)
    {
        passwordPointer = Marshal.SecureStringToGlobalAllocUnicode(password);
        try
        {
            if(!NativeService.ChangeServiceConfig(service, NativeService.SERVICE_NO_CHANGE, NativeService.SERVICE_NO_CHANGE, NativeService.SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, userName, passwordPointer, null))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        finally
        {
            Marshal.ZeroFreeGlobalAllocUnicode(passwordPointer);
        }
    }
    ...
}

Instead of Marshal.SecureStringToBSTR I used Marshal.SecureStringToGlobalAllocUnicode because thats's what the unmanaged function expects, but other than that it works a treat.

Hopefully someone else finds this useful. Kep.

like image 171
Kepboy Avatar answered Dec 10 '25 20:12

Kepboy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!