Проверка цифровой подписи на EXE

Мой .NET exe подписан с помощью signtool. Используя этот код, я могу проверить правильность самого сертификата:

var cert = X509Certificate.CreateFromSignedFile("application.exe");
var cert2 = new X509Certificate2(cert.Handle);
bool valid = cert2.Verify();

Однако это проверяет сам сертификат, а не подпись EXE. Поэтому, если EXE подделан, этот метод не обнаруживает его.

Как проверить подпись?

Ответ 1

Вам нужно вызвать функцию (P/Invoke) WinVerifyTrust() из wintrust.dll. Существует (насколько мне известно) никакой альтернативы в управляемом .NET.

Вы можете найти документацию по этому методу здесь.

Кто-то уже задал этот вопрос на SO. Это не было принято, но это должно быть правильно (я только прокручивал). Посмотрите.

Вы также можете взглянуть на это руководство, но они действительно делают то же самое.

Ответ 2

Чтобы проверить целостность подписанного .exe файла, мы можем использовать метод StrongNameSignatureVerificationEx:

[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
public static extern bool StrongNameSignatureVerificationEx(
        string wszFilePath, bool fForceVerification, ref bool pfWasVerified);    

var assembly = Assembly.GetExecutingAssembly();
bool pfWasVerified = false;
if (!StrongNameSignatureVerificationEx(assembly.Location, true, ref pfWasVerified))
{           
    // it a patched .exe file!   
}

Но этого недостаточно. Возможно удалить подпись, а затем снова применить/воссоздать ее! (для этого есть много инструментов). В этом случае вам нужно хранить открытый ключ вашей подписи где-нибудь (в качестве ресурса), а затем сравнить его с новым/настоящим открытым ключом. подробнее здесь

Ответ 3

Я искал github и нашел Azure Microsoft С# code, который использует объект PowerShell для проверки действительной подписи Authenticode.

    /// <summary>
    /// Check for Authenticode Signature
    /// </summary>
    /// <param name="providedFilePath"></param>
    /// <returns></returns>
    private bool VerifyAuthenticodeSignature(string providedFilePath)
    {
        bool isSigned = true;
        string fileName = Path.GetFileName(providedFilePath);
        string calculatedFullPath = Path.GetFullPath(providedFilePath);

        if (File.Exists(calculatedFullPath))
        {
            Log.LogMessage(string.Format("Verifying file '{0}'", calculatedFullPath));
            using (PowerShell ps = PowerShell.Create())
            {
                ps.AddCommand("Get-AuthenticodeSignature", true);
                ps.AddParameter("FilePath", calculatedFullPath);
                var cmdLetResults = ps.Invoke();

                foreach (PSObject result in cmdLetResults)
                {
                    Signature s = (Signature)result.BaseObject;
                    isSigned = s.Status.Equals(SignatureStatus.Valid);
                    if (isSigned == false)
                    {
                        ErrorList.Add(string.Format("!!!AuthenticodeSignature status is '{0}' for file '{1}' !!!", s.Status.ToString(), calculatedFullPath));
                    }
                    else
                    {
                        Log.LogMessage(string.Format("!!!AuthenticodeSignature status is '{0}' for file '{1}' !!!", s.Status.ToString(), calculatedFullPath));
                    }
                    break;
                }
            }
        }
        else
        {
            ErrorList.Add(string.Format("File '{0}' does not exist. Unable to verify AuthenticodeSignature", calculatedFullPath));
            isSigned = false;
        }

        return isSigned;
    }