防止反编译的代码
我们都知道JAVA是一种解析型语言,这就决定JAVA文件编译后不是机器码,而是一个字节码文件,也就是CLASS文件。而这样的文件是存在规律的,经过反编译工具是可以还原回来的。例如Decafe、FrontEnd,YingJAD和Jode等等软件。下面是《Nokia中Short数组转换算法》
类中Main函数的ByteCode:0 ldc #162 invokestatic #185 astore_16 return其源代码是:short [] pixels = parseImage("/ef1s.png");
我们通过反编译工具是可以还原出以上源代码的。而通过简单的分析,我们也能自己写出源代码的。
第一行:ldc #16
ldc为虚拟机的指令,作用是:压入常量池的项,形式如下ldc index这个index就是上面的16,也就是在常量池中的有效索引,当我们去看常量池的时候,我们就会找到index为16的值为String_info,里面存了/ef1s.png.
所以这行的意思就是把/ef1s.pn作为一个String存在常量池中,其有效索引为16。
第二行:2 invokestatic #18
invokestatic为虚拟机指令,作用是:调用类(static)方法,形式如下
invokestatic indexbyte1 indexbyte2
其中indexbyte1和indexbyte2必须是在常量池中的有效索引,而是指向的类型必须有Methodref标记,对类名,方法名和方法的描述符的引用。
所以当我们看常量池中索引为18的地方,我们就会得到以下信息:
Class Name : cp_info#1
Name Type : cp_info#19
1 和19都是常量池中的有效索引,值就是右边<中的值,再往下跟踪我就不多说了,有兴趣的朋友可以去JAVA虚拟机规范。
这里我简单介绍一下parseImage(Ljava/lang/String;)[S 的意思。
这就是parseImage这个函数的运行,我们反过来看看parseImage的原型就明白了
short [] parseImage(String)
那么Ljava/lang/String;就是说需要传入一个String对象,而为什么前面要有一个L呢,这是JAVA虚拟机用来表示这是一个Object。如果是基本类型,这里就不需要有L了。然后返回为short的一维数组,也就是对应的[S。是不是很有意思,S对应着Short类型,而“[”对应一维数组,那有些朋友要问了,两维呢,那就“[[”,呵呵,是不是很有意思。
好了,调用了函数,返回的值要保存下来吧。那么就是第三行要做的事情了。
2. C#怎样防止反编译
我使用的方法是利用加壳工具:virboxProtectorStandalone。直接进行加壳。高级混淆、虚拟化代码、智能压缩等加密策略。如果要授权控制,可使用许可版本的virboxProtector。
未经加壳保护的 ILspy 反编译效果如下:
public int add(int a, int b){
return a + b;}public int div(int a, int b){
return a / b;}public int mul(int a, int b){
return a * b;}public int sub(int a, int b){
return a - b;}
解决方案:
深思自主研发了为 C# .net 语言做保护的外壳(Virbox Protector)。将C# .net 编译成的执行程序(.exe),动态库(.dll)直接拖入加壳工具即可完成保护操作,十分方便。并且在效果上已经完全看不到源码中的逻辑。
加密后的效果
public int add(int a, int b){
return (int)dm.dynamic_method((object)this, System.Reflection.MethodBase.GetCurrentMethod(), 16416u, 21, 16384u, 32u, 31516u, 5).Invoke(this, new object[]
{
this,
a,
b
});}
public int div(int a, int b){
return (int)dm.dynamic_method((object)this, System.Reflection.MethodBase.GetCurrentMethod(), 16956u, 21, 16924u, 32u, 31516u, 2).Invoke(this, new object[]
{
this,
a,
b
});}
public int mul(int a, int b){
return (int)dm.dynamic_method((object)this, System.Reflection.MethodBase.GetCurrentMethod(), 16776u, 21, 16744u, 32u, 31516u, 3).Invoke(this, new object[]
{
this,
a,
b
});}
public int sub(int a, int b){
return (int)dm.dynamic_method((object)this, System.Reflection.MethodBase.GetCurrentMethod(), 16596u, 21, 16564u, 32u, 31516u, 4).Invoke(this, new object[]
{
this,
a,
b
});}
架构支持
IIS 服务架构的后台逻辑 DLL 文件
windows PC 应用程序 EXE 文件
windows PC 应用程序动态库 DLL 文件
UG等第三方绘图工具使用的 DLL 文件
Unity3d 编译使用的 DLL 文件
3. 如何防止Unity3D代码被反编译
根本的解决办法是:先对DLL加密,然后在Unity的源码中加载程序DLL之前进行解密。
这就需要通过逆向工程获得相应的Unity源码或者是直接向Unity购买Source Code License。
4. 如何防止你的 jar 被反编译
Java世界的防护盾:如何抵挡反编译的侵袭
作为一门广泛应用的语言,Java的解释特性使其易受反编译威胁。然而,通过巧妙的策略和工具,我们可以有效提高代码的安全性。以下是几种防范措施,它们各有其适用场景和潜在挑战:
- 服务器端隔离:将Java程序部署在服务器端,限制直接访问,如通过API接口,降低被破解的可能性。
- Class文件加密:通过自定义ClassLoader实现解密,保护核心代码免受未经授权的访问。但是,这需要在运行时进行解密,增加了复杂性和潜在的性能损失。
- 本地化代码转换:牺牲一定的跨平台性,将代码转换为本地机器代码,降低反编译的难度,但可能影响代码的移植性。
- 代码混淆艺术:包括符号混淆、数据混淆、控制混淆和预防性混淆,它们是基本保护手段。符号混淆混淆方法和变量名,数据混淆则处理数据的存储和访问方式,控制混淆扰乱程序逻辑,预防性混淆则针对特定反编译器进行针对性设计。
- 符号混淆:通过工具如1stBarrier、JShrink和SourceGuard,将代码中的标识符改头换面,使反编译者难以识别其原始含义,同时保留必要部分以保持功能。
- 数据混淆:增加数据处理的复杂性,如使用非标准编码,使得反编译后的代码难以解读数据结构。
- 控制混淆:混淆控制流,如引入额外计算,提升反编译的难度,但可能影响程序性能。
- 预防性混淆:针对特定工具的策略,利用其破解过程中的弱点,提升防护层次。
让我们以SCJP模拟考试软件为例,它巧妙地运用了这些技术。核心题库类被分解为独立模块,部分采用C++开发,如题库访问模块,专门处理Windows下的安全接口。关键步骤如下:
- 接口初始化:生成随机SessionKey,确保合法用户通过认证并加密数据,如图8所示。
- 数据访问接口:经过认证后,对题库进行加密访问。只有特定模块才能解密,甚至可以采用双向认证以增强安全性。
尽管这些方法增加了代码的复杂性和保护性,但没有绝对的安全。随着技术的进步,反编译技术也在不断演进,因此持续更新和优化混淆策略至关重要。记住,防护是一场马拉松,而非短跑。
5. 怎么防止Java开发出来的程序被别人反编译
防止Java开发出来的程序被别人反编译有很多种方法,下面给你介绍几种:
1、隔离Java程序
最简单的方法就是让用户不能够访问到Java Class程序,这种方法是最根本的方法,具体实现有多种方式。例如,开发人员可以将关键的Java Class放在服务器端,客户端通过访问服务器的相关接口来获得服务,而不是直接访问Class文件。这样黑客就没有办法反编译Class文件。目前,通过接口提供服务的标准和协议也越来越多,例如 HTTP、Web Service、RPC等。但是有很多应用都不适合这种保护方式,例如对于单机运行的程序就无法隔离Java程序。
2、对Class文件进行加密
为了防止Class文件被直接反编译,许多开发人员将一些关键的Class文件进行加密,例如对注册码、序列号管理相关的类等。在使用这些被加密的类之前,程序首先需要对这些类进行解密,而后再将这些类装载到JVM当中。这些类的解密可以由硬件完成,也可以使用软件完成。
3、转换成本地代码
将程序转换成本地代码也是一种防止反编译的有效方法。因为本地代码往往难以被反编译。开发人员可以选择将整个应用程序转换成本地代码,也可以选择关键模块转换。如果仅仅转换关键部分模块,Java程序在使用这些模块时,需要使用JNI技术进行调用。
4、代码混淆
代码混淆是对Class文件进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能(语义)。但是混淆后的代码很难被反编译,即反编译后得出的代码是非常难懂、晦涩的,因此反编译人员很难得出程序的真正语义。从理论上来说,黑客如果有足够的时间,被混淆的代码仍然可能被破解,甚至目前有些人正在研制反混淆的工具。但是从实际情况来看,由于混淆技术的多元化发展,混淆理论的成熟,经过混淆的Java代码还是能够很好地防止反编译。
不同保护技术比较希望能给大家带来参考: