从本机代码调用crypt32.dll CryptProtectData方法

时间:2018-08-24 19:06:53

标签: c# pinvoke marshalling cryptoapi

我正在尝试从托管代码中调用 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,而b / c可以表示为 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);
        }
    }
}

更新:使用 Amy的链接运行以下命令(尽管我尚未尝试解密字符串,并且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);
        }
    }
}

0 个答案:

没有答案