【问题标题】:Verify Currently Running Executable验证当前运行的可执行文件
【发布时间】:2012-12-18 16:24:30
【问题描述】:

我正在寻找正确的方法来从该可执行文件中验证当前正在运行的可执行文件。 我已经找到了一种方法来计算当前正在运行的文件的 (SHA256) 哈希值。

问题是:我应该在哪里安全地存储这个哈希?如果我将它存储在配置文件中,恶意用户可以计算自己的哈希并替换它。如果我将它存储在可执行文件本身中,它可能会被十六进制编辑器覆盖。

我读到的一个建议是进行非对称加密(或者是解密),但我该怎么做呢?

一个要求是可执行代码在不同计算机上的哈希和加密/解密完全相同,否则我无法正确验证。这些计算机都将运行相同的操作系统,即 Windows XP(嵌入式)。

我已经签署了我所有的程序集,但我需要一些额外的安全性才能成功通过我们的安全目标。

对于那些知道的人,它涉及 FPT_TST.1.3:TSF 应为授权用户提供验证存储的 TSF 可执行代码完整性的能力。

【问题讨论】:

  • 如果怀疑执行的可执行文件可能已被编辑,这是否也意味着他们可以删除(nop'd)验证步骤本身?
  • 你应该弄清楚为什么强签名是不够的,而不是尝试找到解决它的方法。使用不同的密钥对相同的文件进行两次签名不会比使用一个签名更安全...
  • @AlexeiLevenkov 当然,具有足够访问权限的恶意用户可以简单地在命令行中使用SN -Vr 来禁用它
  • @MarcGravell 我理解这个问题,但这是安全目标所需要的,这就是我需要把它放在那里的原因。我只需要能够指出:看,我们有它,它就在那里,所以它可以从列表中划掉。
  • 您不能将校验和存储在可执行文件本身中,因为如果这样做,校验和就会改变。这是递归的。我建议将散列和 RSA 签名的散列放入外部文件中。 RSA 签名阻止用户创建的散列。当然,恶意用户仍然可以 NOP 校验和验证。因此,没有绝对安全的防弹方法。

标签: c# .net hash cryptography


【解决方案1】:

所有的 cmets,尤其是 Marc 的那个,都是有效的。

我认为最好的办法是查看验证码签名 - 这就是它们的用途。关键是 exe 或 dll 使用证书进行签名(将您的组织信息印入其中,就像 SSL 请求一样)并且修改后的版本不能(理论上加上所有正常的安全警告)用相同的证书重新签名证书。

根据要求(我这么说是因为这个“安全目标”有点模糊 - 验证代码完整性的能力可以很容易地成为如何在 Windows 资源管理器中检查文件的演练),这个本身就足够了(Windows 具有显示证书中发布者信息的内置功能),或者您可以编写一个例程来验证身份验证码证书。

请参阅此 SO Verify whether an executable is signed or not (signtool used to sign that exe),最佳答案链接指向一篇(诚然旧的)关于如何以编程方式检查身份验证证书的文章。

更新

继续 Marc 的建议 - 如果需要自编程检查,即使这样也不够。可执行文件可以被修改,删除检查,然后在没有证书的情况下部署。从而杀死它。

说实话 - 主机应用程序/环境确实应该有自己的检查(例如,需要有效的身份验证证书) - 如果代码不被修改非常重要,那么它应该有自己的步骤所以。我想你可能真的是在疯狂追逐。

只需代表您进行任何检查将花费最少的精力,而不必过多担心它显然提供的实际安全性 - 因为我认为您是从一个不可能的点开始的。如果真的有人想要破解您编写的代码的任何真正原因,那么试图破解它的将不仅仅是一个小学生。因此,您可以使用的任何解决方案(在 cmets 等中提到的那些)都将很容易被颠覆。

Rent-a-quote 最后一句话 解释我的“野鹅追逐”评论

遵循最弱链接原则 - 可执行文件的完整性仅与运行该可执行文件的主机的安全要求一样有效。

因此,在打开了 UAC 并打开所有安全功能的现代 Windows 机器上;例如,安装或运行未签名的代码非常困难。用户必须真的想要运行它。如果你把所有这些东西都降为零,那么它就相对简单了。在有根的 Android 手机上,很容易运行可以杀死手机的东西。这样的例子还有很多。

因此,如果您的代码将被部署到的 XP Embedded 环境首先没有对其实际运行的内容进行运行时安全检查(例如,要求所有应用程序都具有身份验证码证书的策略),那么您就从您开始'已经继承了比您实际应该提供的更低级别的安全性。再多的安全原语和例程都无法恢复它。

【讨论】:

  • 我见过这样的,但仍然不是我想要的。问题是,用户身份验证仅在程序本身中完成(使用定制的智能卡),因此验证也必须可以从程序内部访问。而且它不必非常安全,我认为它只需要在正常情况下是可能的。
  • 对不起,我认为要么全有,要么全无。您在组装中为检查安全性所做的任何事情都可能被您试图保护的过程所破坏。验证码不能。老实说,目标应用程序没有自己的验证步骤是很奇怪的——因为即使是内置的验证码检查也不能按照 Marc 的建议进行。
  • 嗯,安德拉斯,事情是清单的要求,不管它多么愚蠢。没有它,我们就无法通过认证并开始部署。当然,我们也会进行操作系统级别检查。该设备甚至还有压力感应开关,可以查看它是否已打开。
  • 好吧 - 冒着轻率的风险 - 只需提出可以通过的最低限度。您在问题中建议的文件内容的哈希检查应该这样做。它甚至没有资格作为“安全”,但如果它满足无关紧要的要求。
  • 我在最后的答案中添加了另一个块,以解释为什么我在这里似乎没有帮助。我希望它能充分说明我的立场。
【解决方案2】:

自 .NET 3.5 SP1 起,运行时不再检查强名称签名。 当您的程序集是强命名时,我建议通过代码检查签名。 将本机 mscoree.dll 与 p/Invoke 一起使用。

private static class NativeMethods
{
      [DllImport("mscoree.dll")]
      public static extern bool StrongNameSignatureVerificationEx([MarshalAs(UnmanagedType.LPWStr)] string wszFilePath, byte dwInFlags, ref byte pdwOutFlags);
}

您可以使用 assemlby 加载事件并检查加载到您(当前)应用程序域中的每个程序集:

AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;

private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
    Assembly loadedAssembly = args.LoadedAssembly;

    if (!VerifytrongNameSignature(loadedAssembly))
        // Do whatever you want when the signature is broken.
}

private static bool VerifytrongNameSignature(Assembly assembly)
{
     byte wasVerified = 0;

     return NativeMethods.StrongNameSignatureVerificationEx(assembly.Location, 1, ref wasVerified);
}

当然,有足够经验的人可以从你的程序集中修补“检查代码”,或者干脆从你的程序集中去掉强名称..

【讨论】:

猜你喜欢
  • 2013-10-15
  • 2016-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
相关资源
最近更新 更多