最近发现大家很多问题都涉及到了混淆器的概念,特发此贴,希望在大家的学习过程中有所借鉴。
最近试用了几个Java混淆器(Java Obfuscator),感觉没有一个完全另人满意的,
于是想干脆自己写一个得了。翻了几页Java虚拟机规范之后突发奇想,别的混淆器
都是在编译好的byte code上做文章,能不能从源码直接编译成经过混淆的class文
件呢?就这样花了一个多星期的时间写了一个Java混淆编译器(Java Obfuscator
Compiler)。
Q: 什么是混淆器?
A: 由于Java程序运行时是动态连接的,因此编译成的目标文件中包含有符号表,
使得Java程序很容易被反编译,混淆器可以打乱class文件中的符号信息,使反向
工程变得非常困难。
Q: 现有的混淆器有什么问题?
A: 现有的混淆器都是对编译好的class文件进行混淆,这样就需要编译和混淆两个
步骤。并不是所有的符号都需要混淆,如果你开发的是一个类库,或者某些类需要
动态装载,那些公共API就必须保留符号不变,这样别人才能使用你的类库。现有
的混淆器提供了GUI或脚本的方式来对那些需要保留的符号名称进行配置,如果程
序较大时配置工作变得很复杂,而程序一旦修改配置工作又要重新进行。某些混淆
器能够调整字节码的顺序,使反编译更加困难,但我经历过混淆之后的程序运行出
错的情况。
Q: Java混淆编译器是如何工作的?
A: Java混淆编译器是在Sun JDK中提供的Java编译器(javac)的基础上完成的,修
改了代码生成过程,对编译器生成的中间代码进行混淆,最后再生成class文件,
这样编译和混淆只需要一个步骤就可以完成。另外可以在源程序中插入符号保留指
令来控制哪些符号需要保留,不需要单独的配置。
Q: 如何安装和运行JOC?
A: 下载joc.jar (http://www.apusic.com/product/cpsy.htm),运行java -jar
joc.jar就可以启动Java混淆编译器,joc的命令行参数和javac完全相同,但增加
了一个新的参数-Xobfuscate,它的用法如下:
-Xobfuscate:;
其中;指定混淆级别,可以是以下几种级别:
-Xobfuscate:none 不进行混淆
-Xobfuscate:private 对所有private访问级别的元素进行混淆
-Xobfuscate:package 对所有private或package private元素进行混
淆
-Xobfuscate:protected 对所有private, package private,
protected元素进行混淆
-Xobfuscate:public 对所有的元素都进行混淆
-Xobfuscate:all 相当于-Xobfuscate:public
如果使用-Xobfuscate不带级别参数,则相当于-Xobfuscate:package
Q: 如何使用符号保留指令?
A: 除了在命令行用-Xobfuscate参数控制符号混淆级别外,还可以在源代码中使用
符号保留指令来控制那些符号需要保留,符号保留指令是一个Java文档注释指令,
可以插入在类和类成员的文档注释中,例如:
/**
* This class should preserve.
* @preserve
*/
public class Foo {
/**
* You can specify which field should be preserved.
* @preserve
*/
private int x;
/**
* This field is not preserved.
*/
private int y;
/**
* You can also preserve methods.
* @preserve
*/
public void hello() {}
/**
* This method is not preserved.
*/
private void collect() {}
}
如果没有@preserve指令,则根据混淆级别及成员的访问级别来确定符号是否保留
。
对于类的符号保留指令可以附带一个保留级别参数,来控制类成员的符号保留,包
括:
@preserve 仅对类名进行保留,类成员的保留根据
-Xobfuscate命令行参数决定
@preserve public 保留所有public成员
@preserve protected 保留所有public和protected成员
@preserve package 保留所有public, protected, package private成
员
@preserve private 保留所有成员
@preserve all 相当于@preserve private
Q: JOC有哪些限制?
A: 不支持分别编译,必须对所有的源文件进行混淆编译。
最后给出一个JOC混淆的效果:
源文件:
import java.awt.event.*;
import javax.swing.*;
public class AboutBox extends JDialog
{
public AboutBox()
{
initForm();
}
JPanel panel1 = new JPanel();
JButton button1 = new JButton();
JLabel jLabel2 = new JLabel();
JTextArea jTextArea1 = new JTextArea();
/**
* NOTE: The following code is required by the form designer.
* It can be modified using the form editor. Do not
* modify it using the code editor.
*/
private void initForm()
{
this.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE
);
this.getContentPane().setLayout( new java.awt.CardLayout());
this.setModal( true );
this.setResizable( false );
this.setTitle( "About..." );
panel1.setLayout( null );
button1.setText( "OK" );
button1.setBounds( 272, 168, 88, 24 );
panel1.add( button1 );
jLabel2.setText( "File System Viewer for Swing 1.1.1" );
jLabel2.setVerticalAlignment( SwingConstants.TOP );
jLabel2.setBounds( 64, 32, 240, 56 );
panel1.add( jLabel2 );
jTextArea1.setFont( new java.awt.Font( "Dialog", 0, 10 ));
jTextArea1.setLineWrap( true );
jTextArea1.setOpaque( false );
jTextArea1.setText( "This computer program is protected by
copyright law." );
jTextArea1.setWrapStyleWord( true );
jTextArea1.setBounds( 8, 112, 256, 80 );
panel1.add( jTextArea1 );
this.getContentPane().add( panel1, "Card1" );
this.setSize( 376, 228 );
button1.addActionListener( new java.awt.event.ActionListener(){
public void actionPerformed( java.awt.event.ActionEvent
ev ){
button1_actionPerformed( ev );
}});
}
private void button1_actionPerformed(ActionEvent ev)
{
this.dispose();
}
}
经Javac编译后用JAD反编译的结果:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.text.JTextComponent;
public class AboutBox extends JDialog
{
JPanel panel1;
JButton button1;
JLabel jLabel2;
JTextArea jTextArea1;
public AboutBox()
{
panel1 = new JPanel();
button1 = new JButton();
jLabel2 = new JLabel();
jTextArea1 = new JTextArea();
initForm();
}
private void initForm()
{
setDefaultCloseOperation(2);
getContentPane().setLayout(new CardLayout());
setModal(true);
setResizable(false);
setTitle("About...");
panel1.setLayout(null);
button1.setText("OK");
button1.setBounds(272, 168, 88, 24);
panel1.add(button1);
jLabel2.setText("File System Viewer for Swing 1.1.1");
jLabel2.setVerticalAlignment(1);
jLabel2.setBounds(64, 32, 240, 56);
panel1.add(jLabel2);
jTextArea1.setFont(new Font("Dialog", 0, 10));
jTextArea1.setLineWrap(true);
jTextArea1.setOpaque(false);
jTextArea1.setText("This computer program is protected by
copyright law.");
jTextArea1.setWrapStyleWord(true);
jTextArea1.setBounds(8, 112, 256, 80);
panel1.add(jTextArea1);
getContentPane().add(panel1, "Card1");
setSize(376, 228);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionevent)
{
button1_actionPerformed(actionevent);
}
});
}
private void button1_actionPerformed(ActionEvent actionevent)
{
dispose();
}
}
经JOC混淆编译后用JAD反编译的结果:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.text.JTextComponent;
public class AboutBox extends JDialog
{
JPanel _$1;
JButton _$2;
JLabel _$3;
JTextArea _$4;
public AboutBox()
{
_$1 = new JPanel();
_$2 = new JButton();
_$3 = new JLabel();
_$4 = new JTextArea();
_$1();
}
private void _$1()
{
2;
this;
JVM INSTR swap
setDefaultCloseOperation();
getContentPane().setLayout(new CardLayout());
true;
this;
JVM INSTR swap
setModal();
false;
this;
JVM INSTR swap
setResizable();
"About...";
this;
JVM INSTR swap
setTitle();
_$1.setLayout(null);
_$2.setText("OK");
_$2;
168;
272;
JVM INSTR swap
24;
88;
JVM INSTR swap
setBounds();
_$1.add(_$2);
_$3.setText("File System Viewer for Swing 1.1.1");
_$3.setVerticalAlignment(1);
_$3;
32;
64;
JVM INSTR swap
56;
240;
JVM INSTR swap
setBounds();
_$1.add(_$3);
_$4;
JVM INSTR new #13 ;;
JVM INSTR dup
0;
"Dialog";
JVM INSTR swap
10;
Font();
setFont();
_$4.setLineWrap(true);
_$4.setOpaque(false);
_$4.setText("This computer program is protected by copyright
law.");
_$4.setWrapStyleWord(true);
_$4;
112;
8;
JVM INSTR swap
80;
256;
JVM INSTR swap
setBounds();
_$1.add(_$4);
getContentPane().add(_$1, "Card1");
376;
this;
JVM INSTR swap
228;
setSize();
_$2.addActionListener(new IIlIlIIIIlllIIII(this));
return;
}
private void _$1(ActionEvent actionevent)
{
dispose();
}
/*
static void access$0(AboutBox aboutbox, ActionEvent actionevent)
{
actionevent;
aboutbox;
JVM INSTR swap
_$1();
return;
}
*/
// Unreferenced inner classes:
/* anonymous class */
final class IIlIlIIIIlllIIII
implements ActionListener
{
public void actionPerformed(ActionEvent actionevent)
{
AboutBox.access$0(AboutBox.this, actionevent);
}
{
AboutBox.this;
this;
JVM INSTR swap
this$0;
}
}
}
elgs 回复于:2003-12-26 13:03:43
唉, 为什么要人为制造障碍。
南非蜘蛛 回复于:2003-12-26 13:11:41
不错,顶
猫小 回复于:2003-12-26 13:29:34
这就是Java软件面临的挑战
目前,由于黑客的频繁活动,使得Java类文件面临着反编译的挑战。有一些工具能够对Java源代码进行反工程,其结果甚至以比普通Java文件更可读的方式, 尽管普通的Java文件(由于代码风格不同)有注释。许可证和软件过期对于用户们来说将变得无用 。因此,防止软件被反编译或使得反编译的结果变得无意义对于Java来说非常重要。
一个Java类文件不一定非要存储在一个真正的文件里;它可以存在存贮器缓冲区,或从一个网络流获得。尽管防火墙和网络协议如TCP/IP有安全策略,黑客仍能打破访问限制获取一些类。尽管这些类能被混淆,他们(黑客)能够一步一步地分析和猜出每个指令的目的。如果这些代码是关键技术部分,例如是大产品的许可证或时间期满部分,反编译和分析指令的努力似乎很值得。如果这些关键类被隐藏或被一个关键字加密,黑客的非法入侵就很困难了。而且,未认证的软件复制对智能产权是普遍的攻击。还没有一个较好的通用方案来解决这类问题。
混淆器能够保护软件使之不被反编译。它通过混淆类文件使得反编译无效,并把敏感的名字指代变成另一个名字空间,这样可以使反编译的结果毫无疑义。混淆器有“完全”和“快速”两种选项,能处理任何Java产品包括API,应用程序和小程序。它遵从Java虚机规范。
Sun 中国技术开发中心开发的JADE就是为解决上述问题而设计的。
可以去官方网站看看:)
流浪的狗 回复于:2003-12-26 13:33:02
经过混淆后的java应用程序对java虚拟机有要求了,这样就违背了一次编写,到处运行的初衷了!
猫小 回复于:2003-12-26 13:45:53
Class文件的结构是这样:它包含一个常数池(constant pool)这个里面就存放了变量和方法的名称等一些和Class相关的东西,我们通常所说的混淆就是把这个常数池里面的东东弄乱,这样做只是为了骗过反编译器和你,呵呵:)这样反编译出的东西一般是编译不过去的。
也就是说混淆器是针对反编译器的,不针对编译器 :)
流浪的狗 回复于:2003-12-26 13:57:20
咿呀!混淆后的class文件拿到别的运行时系统下,java虚拟机绝对不认识。
cctech 回复于:2003-12-26 15:41:30
猫小大侠:
我就是上一次发帖子请教混淆器的问题的,这对我很重要,因为我辛苦编写的代码,编译后反编译一下,几乎是全部正确的。所以我想到要混淆,你上面转发的文章我也看过,我没有试成,根据网上的资料,我先后用了retroguard,jode,jodo等,都没有试成功,我所以还得请教:
1、是否能直接混淆*.java文件
2、我是在编辑器中编写的,是否不能被识别(因为格式没有可视化工具那样规整?)
3、我用javac -jar dest.jar source*.java编译的jar文件也没有混淆成功。
4、我在JB9里的混淆器中也没有试成功,所以我知道是我方法有问题。
以上问题,望能赐教,谢谢!cctech@vip.sina.com
netkiller 回复于:2003-12-26 20:56:22
越搞越慢...
不支持..对于高手来说..这不算什么...
如果反编译..我要的不是源程序.而是文件中的有用的东东..
如:数据库连接密码(有很多用户喜欢放在class)
建议使用程序签名技术..非对称加密程序..除非你有证书.不然...
elgs 回复于:2003-12-27 09:34:12
如果有人处心积虑要反编译你的源代码, 你应该很高兴才对! 这证明了你的辛苦没有白费啊! 我们受微软的不良影响太深了, 微软一个封闭的体系, 死亡是迟早的。
netkiller 回复于:2003-12-27 12:07:58
为什么出现 编译器?????
原始是机器码。
之后是汇遍
它们最终产生的代码都是机器码。
这也是为什么C/C++为什么火的原因。编译出来的东东又小,又快(注:小,快,不是因为他是C。而是他的编译器一流。当时palcas编译器的速度也非常快。注:JVM编译无论如果优化也不可能超越C。)
因为当时的机器很慢。。内存小。所以要编译。这样就不用一个解释器(他可站内存,和CPU,如JVM)
随着技术发展。。
CPU越来越快。内存也越大。。
而编译器技术又太复杂,能写编译器的人屈指可数。
这时出现解释器。(上学时都应该做过语法分析器吧,实现一下shell)
如win basic .... ,unix perl,awk,sed,tcl......
解释器发展一段时间后。。发现不理想。反回到编译器。(因为PC相的速度还是慢)
但解释器在UNIX平台上。发展越火。。UNIX多运行 mainframe
gonme xwindow整个都是用解释程序实现。(他比KDE慢。因为KDE是C++写的,哈哈)
猫小 回复于:2003-12-27 17:45:59
引用:原帖由 "cctech" 发表:
猫小大侠:
我就是上一次发帖子请教混淆器的问题的,这对我很重要,因为我辛苦编写的代码,编译后反编译一下,几乎是全部正确的。所以我想到要混淆,你上面转发的文章我也看过,我没有试成,根据网上的资料,我..........
之所以发此贴是因为最近感觉到有些朋友在问相关的问题
关于混淆器我没有做过实验,你所说的问题有待探讨和研究
如果上面所转文章有错误,请你指正一下帮助后来阅读的朋友,谢谢
chujian 回复于:2003-12-29 10:37:40
很复杂的东西,就算反编译过来,看也看的够呛,能连冠着看的懂的,我相信他也是会写这样的程序的,所以混淆编译意义也不大。
netkiller 回复于:2003-12-29 13:03:12
其实。从另一个角度看。。我也支持混淆器。
因为国内的公司。。真不要脸。。
给别人的东西改改。就说是自己研发的。
中国在这方面还没有相关法。。。
chujian 回复于:2003-12-30 00:25:05
是中国人不要脸
netkiller 回复于:2003-12-30 09:04:31
我听国外的朋友说。。外国人歧视中国人..
办签证时.其它国家的人.几分种.
到中国人时.就开始百般刁难。。。
(不过听收只要给送他20美金就OK了:))
sylpjx 回复于:2003-12-30 09:27:59
chujian你是哪儿人,如果你也是中国人的话,那你也就不要脸了,如果你不是中国人,请你出来说明到底是什么原因说中国人不要脸和要脸的标准是什么?
garydo 回复于:2003-12-30 09:39:04
下载joc.jar (http://www.apusic.com/product/cpsy.htm)
这个东东根本打不开!
chujian 回复于:2003-12-31 11:31:24
因为我是中国人,所以要被别人骂不要脸。
就是因为中国人不要脸,所以我被骂了也无奈。
wuxingwww 回复于:2004-03-13 17:29:50
因为混淆的只是私有变量,把本来见名知义的变量换成了一堆数字或是其它无意义的变量,包括私有函数都被混淆编译。而公有接口并不影响。
sakulagi 回复于:2004-03-13 21:48:55
引用:原帖由 "chujian"]是中国人不要脸
发表:
嘿嘿嘿,说什么哪?
sakulagi 回复于:2004-03-13 21:53:28
引用:原帖由 "netkiller" 发表:
为什么出现 编译器?????
原始是机器码。
之后是汇遍
它们最终产生的代码都是机器码。
这也是为什么C/C++为什么火的原因。编译出来的东东又小,又快(注:小,快,不是因为他是C。而是他的编译器一流。当?.........
我怎么觉得好像GNome比KDE快?另外,能不能介绍一下gnome是用什么语言写的?
还有,其实非对称加密和数字签名需要很多资源,总不能卖给最终用户的java产品都是加密过的,一边解密一便执行吧?所以个人觉得混淆器还是有市场的。
说得不对的话,请多指正。:)
原文链接:http://bbs.chinaunix.net/viewthread.php?tid=231125
转载请注明作者名及原文出处
2013年2月20日 星期三
Java混淆编译器(转)
Labels:
Java
在文字的世界裡尋找心靈的共鳴,遠山藍以溫柔的筆觸分享書籍的力量與生活的智慧。無論是細膩的書評、深刻的人生感悟,還是技術與創新的新奇發現,每篇文章都是一次內心的療癒旅程。希望透過閱讀,帶領讀者在忙碌的生活中找到一片寧靜與啟發。讓我們一起,在書香中遇見更好的自己!
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言