我从Authenticode签名的PE文件中获得PKCS #7 SignedData。我想在这样的对话框中显示它:
这是一个标准的Windows对话框,就像您点击PE文件的数字签名标签上的详细信息一样。
知道怎么做吗?
我更喜欢C#解决方案,但标准C API也可以工作(我可以创建一个C ++ / CLI接口。)
答案 0 :(得分:3)
这需要大量的研究和一些逆向工程,但我最终还是让它发挥了作用。
魔术功能是CryptUIDlgViewSignerInfo()
。
CryptUIDlgViewSignerInfo 功能显示一个对话框,其中包含已签名邮件的签名者信息。
不幸的是,它与唯一参数的定义CRYPTUI_VIEWSIGNERINFO_STRUCT
在任何头文件中都不存在。首先,您需要声明:
<强> CryptUI.h 强>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT {
DWORD dwSize;
HWND hwndParent;
DWORD dwFlags;
LPCTSTR szTitle;
CMSG_SIGNER_INFO *pSignerInfo;
HCRYPTMSG hMsg;
LPCSTR pszOID;
DWORD_PTR dwReserved;
DWORD cStores;
HCERTSTORE *rghStores;
DWORD cPropSheetPages;
LPCPROPSHEETPAGE rgPropSheetPages;
} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;
#ifdef UNICODE
#define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoW
#else
#define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoA
#endif
BOOL WINAPI CryptUIDlgViewSignerInfo(
_In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi
);
#ifdef __cplusplus
} // extern "C"
#endif
现在,这是一个C ++ CLI函数,但如果你调整开头,它应该很容易在普通的C中工作。当然,您也想要做一些更好的错误检查,但这只是一个概念验证:
// Link against these libraries
#pragma comment (lib, "Crypt32")
#pragma comment (lib, "Cryptui")
void CertHelper::DoStuff(array<Byte>^ data) {
// http://stackoverflow.com/questions/17689154
pin_ptr<Byte> pData = &data[0];
CERT_BLOB blob;
blob.cbData = data->Length;
blob.pbData = pData;
BOOL res;
DWORD MsgAndCertEncodingType;
DWORD ContentType;
DWORD FormatType;
HCERTSTORE hCertStore;
HCRYPTMSG hMsg;
res = CryptQueryObject(
CERT_QUERY_OBJECT_BLOB, // dwObjectType [in]
&blob, // pvObject [in]
CERT_QUERY_CONTENT_FLAG_ALL, // dwExpectedContentTypeFlags [in]
CERT_QUERY_FORMAT_FLAG_BINARY, // dwExpectedFormatTypeFlags [in]
0, // dwFlags [in]
&MsgAndCertEncodingType, // pdwMsgAndCertEncodingType [out]
&ContentType, // pdwContentType [out]
&FormatType, // pdwFormatType [out]
&hCertStore, // phCertStore [out]
&hMsg, // phMsg [out]
NULL // ppvContext [out]
);
// Get the SignerInfo - call once to get size
DWORD cb;
res = CryptMsgGetParam(
hMsg, // hCryptMsg [in]
CMSG_SIGNER_INFO_PARAM, // dwParamType [in]
0, // dwIndex [in]
NULL, // pvData [out]
&cb // pcbData [in, out]
);
CMSG_SIGNER_INFO* signerinfo = (CMSG_SIGNER_INFO*)LocalAlloc(LPTR, cb);
res = CryptMsgGetParam(
hMsg, // hCryptMsg [in]
CMSG_SIGNER_INFO_PARAM, // dwParamType [in]
0, // dwIndex [in]
signerinfo, // pvData [out]
&cb // pcbData [in, out]
);
// Initialize the View Signer Info structure
CRYPTUI_VIEWSIGNERINFO_STRUCT vsi;
memset(&vsi, 0, sizeof(vsi));
vsi.dwSize = sizeof(vsi);
vsi.hwndParent = NULL; // TODO
vsi.dwFlags = 0; // SHDocvw.dll passes 0x14
vsi.szTitle = NULL;
vsi.pSignerInfo = signerinfo;
vsi.hMsg = hMsg;
vsi.pszOID = "1.3.6.1.5.5.7.3.3"; // XCN_OID_PKIX_KP_CODE_SIGNING
// Show the dialog already!
res = CryptUIDlgViewSignerInfo(&vsi);
// Free resources
LocalFree(signerinfo);
if (hCertStore) CertCloseStore(hCertStore, 0);
if (hMsg) CryptMsgClose(hMsg);
}
为了参考起见,这是ViewCertProperties()
中来自shdocvw.dll
的重新提取。
答案 1 :(得分:1)
导致CryptUIDlgViewSignerInfo
调用的大部分工作似乎已经由.NET类System.Security.Cryptography.Pkcs.SignedCms
在内部完成。
填充CRYPTUI_VIEWSIGNERINFO_STRUCT
所需的两部分已经存在,SignedCms
的私有字段:
hMsg
是SignedCms.m_safeCryptMsgHandle
pSignerInfo
是SignerInfo.m_pbCmsgSignerInfo
如果我们可以调用一个假设的SignedCms.ShowSignerInfoDialog()
函数,或以某种方式访问这些成员而不进行反思,那将是不可思议的。
以下黑客确实有效!
class Program
{
static void Main(string[] args) {
var data = ...;
var cms = new SignedCms();
cms.Decode(data);
var pbCmsgSignerInfo = typeof(SignerInfo).GetField("m_pbCmsgSignerInfo", BindingFlags.NonPublic | BindingFlags.Instance);
var si = (SafeHandle)pbCmsgSignerInfo.GetValue(cms.SignerInfos[0]);
var safeCryptMessageHandle = typeof(SignedCms).GetField("m_safeCryptMsgHandle", BindingFlags.NonPublic | BindingFlags.Instance);
var hMsg = (SafeHandle)safeCryptMessageHandle.GetValue(cms);
var vsi = new CRYPTUI_VIEWSIGNERINFO_STRUCT {
dwSize = (uint)Marshal.SizeOf(typeof(CRYPTUI_VIEWSIGNERINFO_STRUCT)),
pSignerInfo = si,
hMsg = hMsg,
};
CryptUIDlgViewSignerInfo(ref vsi);
}
[DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CryptUIDlgViewSignerInfo(ref CRYPTUI_VIEWSIGNERINFO_STRUCT pcvsi);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CRYPTUI_VIEWSIGNERINFO_STRUCT
{
public UInt32 dwSize;
public IntPtr hwndParent;
public UInt32 dwFlags;
public string szTitle;
public SafeHandle pSignerInfo;
public SafeHandle hMsg;
[MarshalAs(UnmanagedType.LPStr)]
public string pszOID;
public UInt32 dwReserved;
public UInt32 cStores;
public IntPtr rghStores;
public UInt32 cPropSheetPages;
public IntPtr rgPropSheetPages;
}