转载http://www.apkbus.com/forum.php?mod=viewthread&tid=240707&extra=page%3D1
盗版猖獗被反编译成为常态?谁偷了我的代码!
更多反编译的教程:
-------------------------------------------------------------
[size=21.3333339691162px]
怎样防止应用被破解?
(一)基础手段--混淆代码
public void *(android.view.View);
}
public <init>(android.content.Context, android.util.AttributeSet);
}
-------------------------------------------------------------
-------------------------------------------------------------
源码中有一个隐藏的类用于APK包的解析。这个类叫PackageParser,路径为frameworks\base\core\java\android\content\pm\PackageParser.java。当我们需要获取APK包的相关信息时,可以直接使用这个类,下面代码就是一个例子函数:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
private
PackageInfo parsePackage(String archiveFilePath,
int
flags){
PackageParser packageParser =
new
PackageParser(archiveFilePath);
DisplayMetrics metrics =
new
DisplayMetrics();
metrics.setToDefaults();
final
File sourceFile =
new
File(archiveFilePath);
PackageParser.Package pkg = packageParser.parsePackage(
sourceFile, archiveFilePath, metrics,
0
);
if
(pkg ==
null
) {
return
null
;
}
packageParser.collectCertificates(pkg,
0
);
return
PackageParser.generatePackageInfo(pkg,
null
, flags,
0
,
0
);
}
|
具体如何通过PackageParser获取签名信息在此处不做详述,具体代码请参考PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于如何在Android应用开发中使用隐藏的类及方法,可以参看我的这篇文章: 《Android应用开发中如何使用隐藏API》 。
紧接着,我们就可以通过packageInfo.signatures来访问到APK的签名信息。还需要说明的是 Android中Signature和Java中Certificate的对应关系。它们的关系如下面代码所示:
1
2
3
4
5
|
pkg.mSignatures =
new
Signature[certs.length];
for
(
int
i=
0
; i<N; i++) {
pkg.mSignatures =
new
Signature(
certs.getEncoded());
}
|
OK,获取到APK签名证书之后,就剩下比对了。这个简单,功能函数如下所示:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
private
boolean
IsSignaturesSame(Signature[] s1, Signature[] s2) {
if
(s1 ==
null
) {
return
false
;
}
if
(s2 ==
null
) {
return
false
;
}
HashSet<Signature> set1 =
new
HashSet<Signature>();
for
(Signature sig : s1) {
set1.add(sig);
}
HashSet<Signature> set2 =
new
HashSet<Signature>();
for
(Signature sig : s2) {
set2.add(sig);
}
// Make sure s2 contains all signatures in s1.
if
(set1.equals(set2)) {
return
true
;
}
return
false
;
}
|
(三)源程序使用C层编写
(四)DEX文件隐藏(加壳技术 )
所谓apk的加壳技术和pc exe的加壳原理一样,就是在程序的外面再包裹上另外一段代码,保护里面的代码不被非法修改或反编译,在程序运行的时候优先取得程序的控制权做一些我们自己想做的工作。
一、对抗JD-GUI原理
通常在对apk进行反编译的时候用到的最多的两个工具就是apk-tool和dex2jar。利用这两个工具将apk首先反编译成classes.dex然后再将classes.dex反编译成jar文件或者将apk直接反编译成jar文件;得到jar文件以后就可以利用JD-GUI将得到的jar文件打开就可以直接查看apk的java源码了。我们花了那么大心思写的程序就这么容易被别人拿到源码是不是很不甘心,现在我就告诉你对抗JD-GUI查看源码的方法。我们在用JD-GUI查看源码时有时有些函数的根本看不到直接提示error错误,我们就利用这点来保护我们的apk。原来JD-GUI在将经过混淆处理的jar里面的class字节码文件转成java文件时,遇到函数中根本走不到的分支的特殊实现时就会提示函数error。这时我们只要查看这些提示error的文件或者函数对应的源码是有什么语句引起的,将这些语句加到我们的源码中就可以防止利用JD-GUI去查看我们的apk源码了。
二、原理实现
(1)假如我们的apk onCreate的函数实现如下:
1
2
3
4
|
[url=home.php?mod=space&uid=
389554
]
@Override
[/url]
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); }
|
(2)将我们的apk经过混淆处理后经过签名导出我们的apk,我们用dex2jar工具将我们的apk转换成jar文件
(3)用JD-GUI打开我们的jar文件就可以看到我们的apk onCreate函数的源码了。如下:
(4)这时我们在apk onCreate函数里面加上不可能的特殊分支语句,代码如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switch
( )
{
case
:
JSONObject jsoObj;
String date=
null
;
String second=
null
;
try
{
jsoObj=
new
JSONObject();
date=jsoObj.getString(
"date"
);
second=jsoObj.getString(
"second"
);
}
catch
(JSONException e)
{ e.printStackTrace(); } test.settime(date,second);
break
;
} }
|
1
2
3
4
|
class
test
{
public
static
void
settime(String a,String b){}
}
|
(5)我们用(2)中同样的方法将apk转成jar文件,然后用JD-GUI打开会看到提示error错误。如下:
根据上面的讲述相信大家对对抗JD-GUI的方法有了一定的了解,我只是举了其中的一个方法,之所以说是特殊的分支语句是因为不是所有的分支语句都可以让JD-GUI提示error。
快捷的APK反逆向解决方案