Я пытаюсь вызвать метод 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);
}
}
}