我正在为Windows实现进程提升助手。它是一个程序,它将以提升模式运行,并以管理员权限启动其他程序,而不显示额外的UAC提示。出于安全考虑,我希望确保只能执行用我的公司的Authenticode键进行数字签名的二进制文件。
WinVerifyTrust函数让我半途而废,但它只确保二进制文件由某个键签名,这是微软信任链的一部分。是否有一种相对简单的方法来执行Authenticode验证并确保它由我们的私钥签名?
发布于 2009-07-02 15:06:38
我相信你要找的是CryptQueryObject。
使用它,您应该能够将涉及的证书从PE中提取出来,并执行您想要的任何其他检查。
举个例子,这将把你带到一个HCRYPTMSG。在那里,您可以使用CryptMsgGetParam提取您想要的任何东西。我本来希望做一些更“健壮”的东西,但是这些API相当毛茸茸的,因为它们需要很多分支来处理它们所有的返回案例。
因此,下面是一个p/invoke-rific c#示例(我是从C开始的,但这基本上是不可读的):
static class Crypt32
{
//Omitting flag constants; you can look these up in WinCrypt.h
[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
int dwObjectType,
IntPtr pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
out int pdwMsgAndCertEncodingType,
out int pdwContentType,
out int pdwFormatType,
ref IntPtr phCertStore,
ref IntPtr phMsg,
ref IntPtr ppvContext);
}
class Program
{
static void Main(string[] args)
{
//Path to executable here
// I tested with MS-Office .exe's
string path = "";
int contentType;
int formatType;
int ignored;
IntPtr context = IntPtr.Zero;
IntPtr pIgnored = IntPtr.Zero;
IntPtr cryptMsg = IntPtr.Zero;
if (!Crypt32.CryptQueryObject(
Crypt32.CERT_QUERY_OBJECT_FILE,
Marshal.StringToHGlobalUni(path),
Crypt32.CERT_QUERY_CONTENT_FLAG_ALL,
Crypt32.CERT_QUERY_FORMAT_FLAG_ALL,
0,
out ignored,
out contentType,
out formatType,
ref pIgnored,
ref cryptMsg,
ref context))
{
int error = Marshal.GetLastWin32Error();
Console.WriteLine((new Win32Exception(error)).Message);
return;
}
//expecting '10'; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
Console.WriteLine("Context Type: " + contentType);
//Which implies this is set
Console.WriteLine("Crypt Msg: " + cryptMsg.ToInt32());
return;
}发布于 2009-10-25 00:43:39
要从已签名的代码中获取证书信息,请使用以下命令:
using System.Security.Cryptography.X509Certificates;
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(filename);
X509Certificate2 cert = new X509Certificate2(basicSigner);然后你就可以得到这样的证书细节:
Console.WriteLine(cert.IssuerName.Name);
Console.WriteLine(cert.SubjectName.Name);
// etc发布于 2017-10-16 12:48:03
这些是我用过的最讨厌的API
一句警告:比你想象的还要糟糕。
至少自从引入SHA-256签名(一直是这样吗?)之后,Authenticode就有可能有多个签名。它们不在PKCS-7签名消息中被编码为多个签名;相反,它们是OID_NESTED_SIGNATURE类型的未经身份验证的消息属性,每个属性包含另一个完整的PKCS-7签名消息。
如果任何签名都是有效的,并且来自受信任的证书链,WinVerifyTrust将告诉您该文件是有效的。然而,它不能告诉你哪些签名是有效的。如果然后使用CryptQueryObject读取完整的PKCS-7消息,并且只查看主签名的证书(如这里的代码示例和MSDN上的代码样例),则不一定要查看经过验证的证书。关联的签名可能与可执行文件不匹配,并且/或证书可能没有可信的CA链。
如果您使用主签名的详细信息来验证证书是您的软件信任之一,则容易受到WinVerifyTrust信任次要签名的情况的影响,但您的代码正在检查主签名的证书是否与您预期的一样,而且您没有注意到来自主证书的签名是无稽之谈。攻击者可以在不拥有其私钥的情况下使用您的公共证书,再加上颁发给其他人的其他代码签名证书,从而绕过发行者的这种检查。
从Win8开始,WinVerifyTrust可以选择性地验证特定的签名,因此您应该能够迭代这些签名以找到一个有效的签名和一个满足您的需求的签名。
不过,如果您必须与Win7 7兼容,据我所知,您所能管理的最好的是MsiGetFileSignatureInformation。从实验中(与这里的其他所有东西一样,实际的文档令人沮丧地模糊),当WinVerifyTrust信任一个证书时,它似乎返回了受信任的证书。但是,如果没有可信签名,它将返回主签名的证书,因此您仍然必须首先使用WinVerifyTrust检查该签名。
当然,这里也存在很多可能的时间检查/使用时间问题。
https://stackoverflow.com/questions/1072540
复制相似问题