将C#编译为本机代码?

80

我有点困惑如何将.NET字节码编译成本地代码,或者说我对最终结果感到困惑。请您耐心等待,我会尽力梳理我所理解的内容,让您帮忙找出我可能遗漏的部分。

我想要做的是将用C#编写的应用程序编译为常规本地代码,就像我如果用C语言编写一样。我的理由与性能无关,而与一定程度的保护有关。我知道我的最终目标不是不可能(甚至并不是很困难)被绕过,但我只是觉得反汇编x86汇编比反汇编Reflector给我的内容更加困难。

现在,如果我将我的C#应用程序放入Reflector中,我基本上会得到我的源代码。通常情况下,当我将未编译的C/C++应用程序放入IDAPro中并使用HexRays反编译器时,我没有完全得到相同程度的反编译,并且必须沉浸在x86反汇编中以理解逻辑流程。据我所知,这种优秀的反编译是因为应用程序处于MSIL状态而不是HexRays尝试反编译的更简洁的本机代码。

我不担心客户机仍然需要.NET运行时,我不想规避任何问题。我想在我的程序上运行常规软件混淆程序,像upx这样的程序,在.NET二进制文件中执行失败。

据我了解,从这个相关问题中得知,ngen可以实现我想要的功能。我尝试使用ngen,但是将输出文件从C:\Windows\assemblies\...\applicationName.ni.exe目录复制到可以双击的某个位置后,尝试运行它会产生一个关于它不是“有效的Win32应用程序”的错误。此外,当我将applicationName.ni.exe放入反编译工具Reflector时,得到的结果与只有applicationName.exe的结果相同。既然applicationName.ni.exe应该是本地代码,我期望Reflector会出错,但是它没有。如果这是我应该做的方式,为什么Reflector仍然给我如此好的反编译结果呢?

因此,为了总结我的主要问题:如何将我的.NET程序编译成本机二进制文件,使得Reflector无法轻易地反编译?或者说,保护使用.NET语言编写的产品不被新手逆向工程师破解的最佳实践是什么?

如果需要其他工具,我更喜欢免费且不像Codewall这样的工具。

谢谢!

更新:我明白我所寻找的东西可能会限制某些语言特性,如反射机制,但我想我可以接受这一点。我的代码中没有任何明确的Assembly.Load调用或类似的内容。但是那些不能被替换为GetProcAddress/LoadLibrary调用吗?


2
在代码保护器/障碍物中,大多数都是商业化的,如果你不是软件开发公司,那么价格也相对昂贵。然而,即使是顶级商业保护器,也可能会在完成任务后出现许多代码运行问题。 - Chris Marisic
我需要类似的功能,也是出于安全原因。我的C#应用程序需要解密一个分别分发给每个用户的配置文件(每个文件都不同)。当然问题在于,解密的代码和算法需要在C#中,如果可以轻易地重新创建,则存在风险。我对此没有替代解决方案感到困惑。 - Ant Waters
11个回答

33

我刚在正确配置的 .proj 上验证了 VS2015Windows 8.1 上的 .Net Native,并针对特定架构进行编译 (可能有些过度,尚未验证)。这将生成一个本地文件,使你的代码更加“难以逆向工程”,我无法通过 DotPeek(JetBrains 的免费 .Net 反编译器) 读取 .dll


21
太棒了!六年后,我的梦想终于实现了。 ;) - mrduclaw
10
请注意,这是针对Windows 10通用应用程序而非WPF或WinForms的。也就是说,适用于Windows 8.1及以上版本。 - Eric Eskildsen
3
@EricEskildsen,所以您不能为WPF/WinForms编译成本地应用程序吗? - Redoman
1
@jj_ 用.NET Native?据我所知没有。话虽如此,今天可能有其他编译WPF/WinForms为本地的方式——我有一段时间没有检查过这个领域了。 - Eric Eskildsen
1
@EricEskildsen 是的,Delphi是其中之一(以及其对应的开源项目Lazarus)。 - Redoman

33

这不是ngen.exe的工作方式。 它仅在前期运行JIT编译器以生成.ni.exe或.ni.dll模块。该二进制文件不包含元数据,仅包含从方法体的IL生成的机器代码。CLR仍然必须找到原始程序集。只有这样才能确定是否有可用的ngen-ed镜像,以便使用其中的机器代码而不是从程序集的IL生成它。

ngen.exe仅加速应用程序的温暖启动时间,仅此而已。

我的常规建议是,对于任何有兴趣反汇编我的程序集的人,请指向sourceforge.net。它拥有由通常比我更好的程序员编写和维护的千兆字节源代码,有时甚至带有良好的注释。如果您的混淆器效果不佳,请寻找更好的混淆器。有很多选择。


2
谢谢!这正是我想要了解的关于 ngen 的解释。你有没有关于好用、免费的混淆器的建议? - mrduclaw
2
我只知道好用且免费的反汇编器。反汇编器必须是免费的,收费会破坏使用它的目的。好的混淆器需要花钱购买。Visual Studio自带一个叫Dotfuscator的混淆器。我从未听说过有公司销售基于经过Dotfuscator保护的破解源代码的产品。这表明它的效果很好。 - Hans Passant

19

昨天在Build 2014上,微软宣布了.NET Native。根据常见问题解答,"... 首先,我们将专注于使用.NET Native的Windows商店应用程序。 长远来看,我们将继续改进所有.NET 应用程序的本机编译。"


但是它如何在VS2013中使用呢?我没有VS2015许可证,所以我想在VS2013中使用.Net Native。 - Eldar Zeynalov
1
@EldarZeynalov 也许你应该看看VS2015社区版? - user2278642

17

如果你想保护你的代码,混淆器是一种典型的方法。 Dotfuscator 一直在与反编译工具 Reflector 竞争,我们使用它来保护我们的产品。然而,在实践中,一个有技能的人可以轻松阅读混淆的代码。

编译成本地代码会破坏使用托管语言的目的。主要优势是允许目标运行时将IL即时编译为最适合目标CPU的内容。如果你希望不这样做,可以使用Mono中的预先编译选项


Dotfuscator只是混淆变量名称,使其更难读取吗?我知道我不会得到运行时优化,我可以接受这一点。我使用C#的主要目的是语法和库的易用性和美观性,巧妙的优化排在第二位。 - mrduclaw
26
“将代码编译为本机代码会破坏使用托管语言的初衷”--这不是正确的观点。 - zezba9000
托管的.NET语言的一个特点是它们可以被验证为安全。将可验证的安全IL编译成本地代码不会失去这个特定的功能。此外,您所描述的“主要优势”在现实中甚至不存在(即使在您最初撰写此答案的5年后也是如此):虽然在理论上可能,但.NET的JIT编译器非常保守,自其问世以来唯一值得注意的优化是改进了代码吞吐量。没有对发出的本机代码进行任何工作。 - IInspectable
1
也许拥有一种托管语言毕竟违背了拥有机器码的目的,即速度和功率 - 计算机本身的存在理由。 - Reversed Engineer

10

其他答案提到了微软的.NET本地编译器,但没有告诉您如何做。

这里是一个使用CoreRT编译C#项目为本机代码的教程。

注意: 我还必须注释掉以下行才能使所有内容正常工作:

<!-- <add key="helloworld" value="https://api.helloworld.org/v3/index.json" /> -->

输出是一个大约 4MB 大小的可执行文件:

事实上,使用.NET反编译器和本地代码反汇编工具IDA Pro都无法读取这段代码,并且将其视为本机代码。


8

Spoon(以前叫Xenocode)有一个产品可能符合您的需求。我们将其用于基于WPF的安装程序界面,这样我们就不必引导.NET来加载设置程序本身。


这看起来很棒,只是有点贵,因为我只是一个独立开发者,并不是为公司做这个。 - mrduclaw
的确价格有点贵。但它运行良好。 不确定是否存在任何开源或其他替代品。另一个缺点是它会导致非常大的可执行文件,但环境虚拟化非常流畅。 - dkackman

7

NGEN添加本机代码,但它不会删除MSIL。因此,任何操作MSIL的工具仍然可以使用。您还需要这个来进行反射,而真正的本地编译器则非常困难。


我的代码中没有明确使用反射,如果不需要,我也可以不用它。除了语言本身的一些限制外,这是否可行? - mrduclaw
你知道它,但是假设的C#到本地编译器不能真正假定它。 - MSalters

6

使用微软的.NET Native编译器,终于可以自动将使用托管代码(C#或Visual Basic)编写且目标为.NET Framework和Windows 10的应用程序编译成本地代码。

• 您的应用程序将提供本机代码的卓越性能。

• 您可以继续使用C#或Visual Basic进行编程。

• 您可以继续利用.NET Framework提供的资源,包括其类库、自动内存管理和垃圾回收以及异常处理等功能。

对于您的应用程序用户,.NET Native提供以下优势:

• 快速执行时间

• 一致快速的启动时间

• 低部署和更新成本

• 优化的应用程序内存使用

但是,.NET Native不仅涉及编译成本地代码。它还改变了.NET Framework应用程序的构建和执行方式。特别是:

• 在预编译期间,必需的.NET Framework部分被静态链接到您的应用程序中。这使得应用程序可以在.NET Framework的应用程序本地库下运行,并使编译器执行全局分析以提高性能。因此,即使在.NET Framework更新后,应用程序的启动也始终更快。

• .NET Native运行时针对静态预编译进行了优化,因此能够提供卓越的性能。同时,它保留了开发人员认为很有生产力的核心反射功能。

• .NET Native使用与C++编译器相同的后端,该编译器针对静态预编译方案进行了优化。

https://msdn.microsoft.com/en-us/library/dn584397(v=vs.110).aspx

仅在VS.NET 2015中可用。


5

这是一个免费的混淆器,非常不错:eazfuscator


9
免费试用30天。* - Daniel Kmak

3

我可能会问一下,您为什么要寻求这种类型的保护。我并不是在争论您是否需要这种保护,但我认为了解动机是值得的。

例如,如果您想要保护,因为您的系统中有一个算法,如果有人对其进行反向工程将会对安全造成灾难性影响,那么您可能需要考虑不同的方法。这意味着该算法存在缺陷,无论多少混淆或本地编译都无法帮助您。

如果是知识产权问题,那么我认为混淆可能是您在这里最佳的选择。这有点像在门上安锁。有人可以破解锁进去,但他们是有意这样做而不是轻易走进门来。


哦不,我的算法并没有做什么花哨的事情。它介于学术好奇和知识产权问题之间。我认为一个体面的(但免费的)混淆器可能就足够满足我的知识产权问题了,但我也有一个之前编写的定制代码打包器,我想在我的.NET应用程序上使用。有关混淆器的任何建议吗? - mrduclaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接