【问题标题】:reflection is possible on obfuscation可以对混淆进行反思
【发布时间】:2010-09-22 12:35:20
【问题描述】:

自上周以来,我一直在努力解决这个问题。我混淆了我的应用程序的 exe。我们的应用程序是在线网络应用程序的离线工具。客户端将安装此应用程序并连接一次互联网,应用程序将下载相关信息并存储在客户端计算机上的 xml 文件中以供进一步显示。出于安全目的,我们正在加密这些 xml 文件。不幸的是,我们在 exe 中有一个 GetCryptXML 方法,它将读取客户端机器上的加密 settings.xml 并在解密后返回它。此 setting.xml 还包含其他 xml 的加密密钥。

我在这里面临的问题是,即使经过混淆,人们也可以通过传递混淆名称来调用 GetCryptXML 方法。

有什么办法可以解决这个问题吗?

这是我解决问题的想法,但我不确定如何实施。

我的想法:调用我的函数的唯一方法是使用 InvokeMember() 函数通过反射。在调用此函数之前,他/她需要使用 this 加载程序集。

Assembly.LoadFrom("myapplication.exe")

如果 myapplication.exe 中的代码可以识别哪个应用程序正在尝试加载我,那么如果它不是预期的应用程序,我们可以限制它们加载。不知道怎么解决。

非常感谢任何帮助。

谢谢。

【问题讨论】:

  • 您可能已经意识到这一点,但没有 100% 的解决方案可以解决您的问题。如果加密文件是离线存储的,而解密代码/密钥是离线存储的,用户可以总是使用该代码/密钥来解密文件。通过使用混淆等,你只能让他更难,而不是阻止他这样做。
  • 我看不出问题,如果有人有加密的 XML 文件,你的应用程序那么他们有数据和密钥来解密它,那么他们解密它有什么问题?
  • 解密密钥在 encryptedFile 中。除非用户执行 GetCryptXML 方法,否则他将无法获取数据。这就是我要保护对 GetCryptXML 方法的调用的原因。
  • 不幸的是你不能。即使您可以设法阻止 GetCryptXML 运行,他们仍然拥有实际代码,并且可以反编译并删除检查(混淆只会使反编译更烦人)。

标签: c# security reflection assemblies obfuscation


【解决方案1】:

混淆不会改变 .net 或您的应用程序的基础 - 最后,它所做的只是使其更难阅读,并尝试添加反编译工具无法处理的情况......但无论哪种方式,IL还在那里。如果你给他们加密的文本(xml)和密钥(通过网络发送或隐藏在你的代码中),他们可以解密它。你所做的只是让它变得更难,而不是不可能。

可以做的一件事是strong name 您的程序集,并验证您的类型的调用者来自具有StrongNameIdentityPermission 属性的特定强命名程序集。请注意,KeeperOfTheSoul 是正确的——在 4.0 之前的 .net 版本中,完全信任程序集可以绕过这一点(据我了解,在 4.0 中,此属性不再使用身份权限,只有在存在正确证据时才会成功)。

您还可以编写代码以通过System.Diagnostics.StackTrace 获取调用堆栈,并检查调用方法以验证其是否为预期调用者之一。这意味着执行速度要慢一些,代码更多,但您可以控制它。

编辑 See here 了解如何使用 StrongNameIdentityPermission。这是一篇关于inspecting the stack trace 的文章。同样,请注意,这些都不是灵丹妙药,但如果您认为值得花时间,则可以为攻击者增加一个障碍。 (请记住,在互联网时代,只要一个成功的攻击者就可以让任意数量的人在谷歌上搜索结果)

【讨论】:

  • 但是以完全信任运行的应用程序可以对运行时环境进行任何更改,包括声明强命名身份,因此检查将始终通过。
  • @KeeperOfTheSoul 添加了关于 .net4 和此权限的注释...我相信您在直到 4.0 之前是正确的,但在 4.0 中它不再使用身份权限。我得回来测试一下。
  • 您能给我举个强名称的例子吗?如何验证strongNameidentityPermission?谢谢。
  • 也许吧,但是 StackTrace 也有缺陷,因为堆栈跟踪可以被伪造(因为您不控制运行时环境),而且由于 JIT 的方法内联,堆栈跟踪不是始终如一。
  • @KeeperOfTheSoul 也正确。实际上,当您将代码提供给某人时,他们拥有它(即使您对其进行编译和混淆),这是一个大道理。这实际上是关于多层保护,以及对开发人员和攻击者来说保护/破解系统值得做多少工作。正如我所说,“你所做的只是让它变得更难,而不是不可能”
【解决方案2】:

如果您想限制对特定程序集的方法的访问,您可以执行以下操作:

    private void RestrictedMethod() {
        Assembly calling = Assembly.GetCallingAssembly();
        if(calling.FullName != "myapplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null") {
            throw new InvalidOperationException();
        }
        // Do method work...
        return;
    }

这种方法的一个优点是,如果有人使用来自未经授权的程序集的反射,则调用将失败。

【讨论】:

  • 除非我伪造调用程序集,如果我控制运行时(即任何以完全信任运行的应用程序),我可以做到这一点。此时我可以让 Assembly.GetCallingAssembly 返回我喜欢的任何值。
  • 这可能是真的。也许我在这方面的回答是不完整的。有问题的函数似乎在 .exe 文件中,问题的含义是 exe 外部的某些代码(换句话说,.dll)可以调用此方法。这意味着解决方案的一部分是任何此类代码都不能完全信任地运行,这应该由 exe 控制,例如在另一个 AppDomain 中运行 dll 代码。
【解决方案3】:

如果可以通过反射调用某些东西,那么它必须可以(以某种方式)通过常规代码调用。

我建议不要这样做(因为没有办法完全阻止那些坚持执行他们不应该执行的代码的人)。

如果您真的有兴趣做这样的事情,您可以打破 C# 的 OO 原则,将您的所有方法设为私有。这样,只有从类内部执行的代码才能定期调用它们。其他人都必须通过 Reflection 调用它们(并且通过 Reflection 调用私有成员通常被认为是不好的做法)。

奇怪的是,我想得越多,该方法可能无论如何都应该标记为私有,因为您不希望每个人都能够调用它。调用者应该必须通过一个公共门面调用,这将确定您是否被允许调用该方法......并且只允许授权调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 2023-02-10
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多