Вызов метода crypt32.dll из CryptProtectData из собственного кода - PullRequest
0 голосов
/ 24 августа 2018

Я пытаюсь вызвать метод crypt32.dll CryptProtectData из управляемого кода, но мне кажется, что типы маршалинга не совсем соответствуют описанию моего делегата:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CryptProtectDataDelegate(
    IntPtr pDataIn,             // DATA_BLOB*
    //StringBuilder szDataDescr,  // LPCWSTR
    [MarshalAs(UnmanagedType.LPWStr)] string szDataDescr,   // LPCWSTR
    IntPtr pOptionalEntropy,    // DATA_BLOB*
    int pvReserved,             // PVOID 
    IntPtr pPromptStruct,       // CRYPTPROTECT_PROMPTSTRUCT*
    int dwFlags,                // DWORD 
    IntPtr pDataOut             // DATA_BLOB*
);

, который при вызове

bool theResult = cryptProtectData(
    pDataIn,
    null,
    IntPtr.Zero,    // null,
    0,              // null,
    IntPtr.Zero,    // null,
    flag,
    pDataOut);

вызывает исключение

+ CryptProtectDataDelegate :: Invoke 'разбалансировал стек.Это вероятно потому, что управляемая подпись PInvoke не совпадает с неуправляемой целевой подписью.Убедитесь, что соглашение о вызовах и параметры подписи PInvoke соответствуют целевой неуправляемой подписи. '

Собственное определение для CryptProtectData равно

DPAPI_IMP BOOL CryptProtectData(
  DATA_BLOB                 *pDataIn,
  LPCWSTR                   szDataDescr,
  DATA_BLOB                 *pOptionalEntropy,
  PVOID                     pvReserved,
  CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
  DWORD                     dwFlags,
  DATA_BLOB                 *pDataOut
);

, где DPAPI_IMP определяется как

#define DPAPI_IMP DECLSPEC_IMPORT

Я уверен, что допустимые представления типов, которые я должен использовать для параметров в определении делегата?

Предполагается, что PVOID являетсяvoid *, я нашел некоторую документацию, которая предполагает, что он может быть представлен как int, а б / к это может быть null, я установил его на 0 (https://docs.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-behavior).


Ниже приведен пример, который должен быть полным и работоспособным (который может привести к сбою)

using System;
using System.Runtime.InteropServices;

namespace CallNativeDLLs
{
    static class NativeMethods
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
    }

    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate bool CryptProtectDataDelegate(
            IntPtr pDataIn,             // DATA_BLOB*
            //StringBuilder szDataDescr,  // LPCWSTR
            [MarshalAs(UnmanagedType.LPWStr)] string szDataDescr,   // LPCWSTR
            IntPtr pOptionalEntropy,    // DATA_BLOB*
            int pvReserved,             // PVOID 
            IntPtr pPromptStruct,       // CRYPTPROTECT_PROMPTSTRUCT*
            int dwFlags,                // DWORD 
            IntPtr pDataOut             // DATA_BLOB*
        );

        static void Main(string[] args)
        {
            IntPtr pDll = NativeMethods.LoadLibrary(@"c:\windows\system32\crypt32.DLL");

            IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "CryptProtectData");

            var cryptProtectData = (CryptProtectDataDelegate)Marshal.GetDelegateForFunctionPointer(
                pAddressOfFunctionToCall,
                typeof(CryptProtectDataDelegate));

            IntPtr pDataIn = Marshal.StringToHGlobalAnsi("hi");
            int flag = (int)0x4; //CRYPTPROTECT_LOCAL_MACHINE 
            var pDataOut = new IntPtr();

            // EXCEPTION thrown here
            bool theResult = cryptProtectData(
                pDataIn,
                null,
                IntPtr.Zero,    // null,
                0,              // null,
                IntPtr.Zero,    // null,
                flag,
                pDataOut);

            bool result = NativeMethods.FreeLibrary(pDll);

            Console.WriteLine(theResult);
        }
    }
}

Обновление: Используя ссылку Эми , выполняются следующие (хотя я еще не пытался расшифровать строку, а CRYPTPROTECT_LOCAL_MACHINE слабый)

using System;
using System.Runtime.InteropServices;

namespace CallNativeDLLs
{
    static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct DATA_BLOB
        {
            public int cbData;
            public IntPtr pbData;
        }

        [Flags]
        public enum CryptProtectPromptFlags
        {
            CRYPTPROTECT_PROMPT_ON_UNPROTECT = 0x1,
            CRYPTPROTECT_PROMPT_ON_PROTECT = 0x2
        }

        [Flags]
        public enum CryptProtectFlags
        {
            CRYPTPROTECT_UI_FORBIDDEN = 0x1,
            CRYPTPROTECT_LOCAL_MACHINE = 0x4,
            CRYPTPROTECT_CRED_SYNC = 0x8,
            CRYPTPROTECT_AUDIT = 0x10,
            CRYPTPROTECT_NO_RECOVERY = 0x20,
            CRYPTPROTECT_VERIFY_PROTECTION = 0x40
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct CRYPTPROTECT_PROMPTSTRUCT
        {
            public int cbSize;
            public CryptProtectPromptFlags dwPromptFlags;
            public IntPtr hwndApp;
            public String szPrompt;
        }

        [DllImport("Crypt32.dll",
            SetLastError = true,
            CharSet = System.Runtime.InteropServices.CharSet.Auto)]     
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptProtectData(
            ref DATA_BLOB pDataIn,
            String szDataDescr,
            ref DATA_BLOB pOptionalEntropy,
            IntPtr pvReserved,
            ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
            CryptProtectFlags dwFlags,
            ref DATA_BLOB pDataOut
        );
    }

    class Program
    {
        static void Main(string[] args)
        {
            IntPtr pbData = Marshal.StringToHGlobalAnsi("hi");
            var pDataIn = new NativeMethods.DATA_BLOB{cbData=0,pbData=pbData};
            var pOptionalEntropy = new NativeMethods.DATA_BLOB();
            var pPromptStruct = new NativeMethods.CRYPTPROTECT_PROMPTSTRUCT();
            var pDataOut = new NativeMethods.DATA_BLOB();

            bool theResult = NativeMethods.CryptProtectData(
                ref pDataIn,
                null,
                ref pOptionalEntropy, // null,
                IntPtr.Zero,          // null,
                ref pPromptStruct,    // null,
                NativeMethods.CryptProtectFlags.CRYPTPROTECT_LOCAL_MACHINE,
                ref pDataOut);

            Console.WriteLine(theResult);
        }
    }
}
...