本文介绍了C#实现从签名文件中获取SignedCms的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C ++ CRYPT32.DLL从签名的c#程序集dll中提取SignedCms对象。



 私有静态只读int CERT_QUERY_OBJECT_FILE = 0x00000001; 
私有静态只读int CERT_QUERY_CONTENT_FLAG_ALL = 0x00003ffe;
私有静态只读int CERT_QUERY_FORMAT_FLAG_ALL = 0x0000000e;
私有静态只读int CMSG_ENCODED_MESSAGE = 29;

[DllImport( CRYPT32.DLL,EntryPoint = CryptQueryObject,CharSet = CharSet.Auto,SetLastError = true)]
私有静态外部布尔CryptQueryObject(
int dwObjectType ,
IntPtr pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
IntPtr pdwMsgAndCertEncodingType,
IntPtr pdwContentType,
IntPtr pdwContentType,
IntPtr phCertStore,
IntPtr phMsg,
IntPtr ppvContext
);

[DllImport( crypt32.dll,CharSet = CharSet.Auto,SetLastError = true)]
私有静态外部布尔CryptMsgGetParam(
IntPtr hCryptMsg,int dwParamType,int dwIndex ,IntPtr pvData,ref int pcbData);

公共静态SignedCms GetSignedCmsFromFile(string fileName)
{
var pvObject = Marshal.StringToHGlobalUni(fileName);
var phMessage = Marshal.AllocHGlobal(IntPtr.Size);
var pvData = IntPtr.Zero;

试试
{
SignedCmssignedCms = null;
var成功= CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
pvObject,
CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
IntPtr.Zero,
b IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
phMessage,
IntPtr.Zero);

如果(成功)
{
var hMessage = Marshal.ReadIntPtr(phMessage);
var cbData = 0;
成功= CryptMsgGetParam(
hMessage,
CMSG_ENCODED_MESSAGE,
0,
IntPtr.Zero,
ref cbData);

如果(成功)
{
var data = new byte [cbData];
pvData = Marshal.AllocHGlobal(sizeof(byte)* data.Length);

成功= CryptMsgGetParam(
hMessage,
CMSG_ENCODED_MESSAGE,
0,
pvData,
ref cbData);

如果(成功)
{
Marshal.Copy(pvData,data,0,cbData);
signedCms = new SignedCms();

试试
{
signedCms.Decode(data);
File.WriteAllBytes(fileName + .export,数据);
}
catch(CryptographicException)
{
signedCms = null;
}
}
}
}

返回签名Cms;
}
最后
{
if(pvObject!= IntPtr.Zero)
Marshal.FreeHGlobal(pvObject);

if(phMessage!= IntPtr.Zero)
Marshal.FreeHGlobal(phMessage);

if(pvData!= IntPtr.Zero)
元帅FreeHGlobal(pvData);
}
}

该函数运行良好,但是由于crypt32.dll函数被贬低了我正在寻找一个纯C#实现,它执行相同的操作并提供SignedCms对象。



到目前为止,我能找到的最接近的X509Certificate。

  X509Certificate2 cert = new X509Certificate2(fileName)


-



以及几乎所有详细信息:



在github上,我找到了一个托管示例,读取了PE标头:



所有零件都应完成工作。


I am having an implementation using C++ CRYPT32.DLL to extract a SignedCms object from a signed c# assembly dll.

The certificate used to sign the dll is expired but has a valid certificate chain inside. The important thing is that the certificate consists of three certificates which I all want to extract.

    private static readonly int CERT_QUERY_OBJECT_FILE = 0x00000001;
    private static readonly int CERT_QUERY_CONTENT_FLAG_ALL = 0x00003ffe;
    private static readonly int CERT_QUERY_FORMAT_FLAG_ALL = 0x0000000e;
    private static readonly int CMSG_ENCODED_MESSAGE = 29;

    [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool CryptQueryObject(
        int dwObjectType,
        IntPtr pvObject,
        int dwExpectedContentTypeFlags,
        int dwExpectedFormatTypeFlags,
        int dwFlags,
        IntPtr pdwMsgAndCertEncodingType,
        IntPtr pdwContentType,
        IntPtr pdwFormatType,
        IntPtr phCertStore,
        IntPtr phMsg,
        IntPtr ppvContext
    );

    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool CryptMsgGetParam(
        IntPtr hCryptMsg, int dwParamType, int dwIndex, IntPtr pvData, ref int pcbData );

    public static SignedCms GetSignedCmsFromFile(string fileName)
    {
        var pvObject = Marshal.StringToHGlobalUni(fileName);
        var phMessage = Marshal.AllocHGlobal(IntPtr.Size);
        var pvData = IntPtr.Zero;

        try
        {
            SignedCms signedCms = null;
            var success = CryptQueryObject(
                CERT_QUERY_OBJECT_FILE,
                pvObject,
                CERT_QUERY_CONTENT_FLAG_ALL,
                CERT_QUERY_FORMAT_FLAG_ALL,
                0,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                phMessage,
                IntPtr.Zero);

            if (success)
            {
                var hMessage = Marshal.ReadIntPtr(phMessage);
                var cbData = 0;
                success = CryptMsgGetParam(
                    hMessage,
                    CMSG_ENCODED_MESSAGE,
                    0,
                    IntPtr.Zero,
                    ref cbData);

                if (success)
                {
                    var data = new byte[cbData];
                    pvData = Marshal.AllocHGlobal(sizeof(byte) * data.Length);

                    success = CryptMsgGetParam(
                        hMessage,
                        CMSG_ENCODED_MESSAGE,
                        0,
                        pvData,
                        ref cbData);

                    if (success)
                    {
                        Marshal.Copy(pvData, data, 0, cbData);
                        signedCms = new SignedCms();

                        try
                        {
                            signedCms.Decode(data);
                            File.WriteAllBytes(fileName + ".export", data);
                        }
                        catch (CryptographicException)
                        {
                            signedCms = null;
                        }
                    }
                }
            }

            return signedCms;
        }
        finally
        {
            if (pvObject != IntPtr.Zero)
                Marshal.FreeHGlobal(pvObject);

            if (phMessage != IntPtr.Zero)
                Marshal.FreeHGlobal(phMessage);

            if (pvData != IntPtr.Zero)
                Marshal.FreeHGlobal(pvData);
        }
    }

The function works very well but since the crypt32.dll function is depricated I am looking for a pure C# implementation that is doing the same and provides the SignedCms object.

The closest what I could find so far is the X509Certificate.

X509Certificate2 cert = new X509Certificate2(fileName)

CryptQueryObject function


Solution

Thanks to the post below I could implement a pure C# method to extract the SignedCms.

The only thing that is not fitting perfectly is that the startindex is off by 8 bytes and the size is 10 bytes smaller.

    public static SignedCms GetSignedCmsFromFile(string fileName)
    {
        var result = new SignedCms();

        uint startIndex = 0;
        uint size = 0;

        var reader = new PeHeaderReader(fileName);
        if (reader.Is32BitHeader)
        {
            startIndex = reader.OptionalHeader32.CertificateTable.VirtualAddress;
            size = reader.OptionalHeader32.CertificateTable.Size;
        }
        else
        {
            startIndex = reader.OptionalHeader64.CertificateTable.VirtualAddress;
            size = reader.OptionalHeader64.CertificateTable.Size;
        }

        //var data = File.ReadAllBytes(fileName).Skip((int)startIndex).Take((int)size).ToArray();

        //Somehow the start index and size are not fitting perfectly and I have to adapt them
        var data = File.ReadAllBytes(fileName).Skip((int)startIndex + 8).Take((int)size - 10).ToArray();

        result.Decode(data);

        return result;
    }
解决方案

I haven't found a CNG equivalent of the call but here is the specification which should let you extract the PKCS#7 which are the bytes for the SignedCms:

The spec says:

Here are nice overviews of the bytes in the PE header:- https://resources.infosecinstitute.com/presenting-the-pe-header/- https://www.red-gate.com/simple-talk/blogs/anatomy-of-a-net-assembly-pe-headers/

And almost all details: https://blog.kowalczyk.info/articles/pefileformat.html

On github I found a managed sample that reads the PE header: https://gist.github.com/augustoproiete/b51f29f74f5f5b2c59c39e47a8afc3a3

EDIT: The code on github was not reliable according to a comment of @martin-s and he succeeded with this alternative:

https://github.com/secana/PeNet

All pieces together should do the job.

这篇关于C#实现从签名文件中获取SignedCms的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 20:18