[Android]反编译查看、修改源码、逆向分析以及⼆次打包签名
本⽂我们将来探讨关于Android的反编译。通常来说,我们在开发过程中的apk出于DEBUG状态,我们并没有给予APK⼀个特定的签名,⽽是编译系统默认给apk⼀个签名。在发布到应⽤商城时,我们会⽤⾃⼰的签名⽂件来签名apk,以防⽌被其他⼈恶意篡改apk。当然,我们也会利⽤Android的混淆技术或者⼀些加固技术来防⽌apk被反编译造成源码泄漏。
所以,本⽂只能针对于没有被签名、混淆、加固过的apk,对于绝⼤多数市⾯上的apk来说,如果你想要通过反编译得到⾥⾯的重要源码,那是⾏不通的。如果apk⽤了加固技术,那根本要反编译都很困难。
我先列举⼀下我们将会⽤到的⼏个⼯具:
apktool.jar:查看apk包下的l和res⽂件夹内容。
dex2jar.jar:把apk中的classes.dex转为⼀个jar包
jdgui:通过上⾯获得的jar包,利⽤这个⼯具打开
baksmali.jar:把apk中的classes.dex转为为smali源码
smali:把smali⽂件编译打包成classes.dex的⼯具
signapk.jar 把我们重新⽣成的apk重新签名
废话少说,我们来⾃⼰写个Demo,编译出⼀个apk,这个apk很简单,我们在AActivity输⼊密码:123456之后才能启动到BActivity,否则提⽰密码错误。
源码如下:
public class AActivity extends ActionBarActivity {
Button btn;
EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.bt);
et = (EditText) findViewById();
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String pwd = et.getText().toString();
if("123456".equals(pwd)){
startActivity(new Intent(AActivity.this,BActivity.class));
Toast.makeText(AActivity.this, "登录成功", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(AActivity.this, "密码错误", Toast.LENGTH_LONG).show();
}
}
});
}
我们的运⾏截图是这样:
好的,接下来我们来尝试解开apk⾥⾯的内容。把apk⽂件的后缀名改成.zip的压缩格式,打开:
从apk的⽬录来看:
res:我们的资源⽬录
META-INF:⼀些信息配置,这⾥我们可以不关⼼。
resources.arsc:编译资源时⽣成的⽂件,资源能根据配置索引到相应的资源就是依赖了它。 classes.dex:源码编译打包后的⽂件。
l:⼤家都知道了
⾸先,我们来看下如何查看apk的源码,我们提取出classes.dex,把classes.dex放到dex2jar的⽂件夹⾥⾯,然后打开cmd,cd进⼊dex2jar的⽂件⽬录,输⼊命令:dex2jar.bat classes.dex
可以发现⽂件夹⾥⾯⽣成了⼀个classes_dex2jar.jar,我们把这个jar包提取出来,⽤jd-gui这个⼯具来打开,可以直接将jar包拖曳到jd-gui上打开,如下:
到此,我们就完成了反编译的源码查看。
⽽apk⾥⾯的res⽬录⼀些xml⽂件和l,由于已经被编译成⼆进制⽂件,我们⽆法直接打开查看。可以由apktool.jar这个⼯具来反编译还原成我们能打开查看的⽂件。
同样在cmd⾥⾯ cd进⼊apktool.jar所在的⽂件夹,把我们的apk放进来,后缀名可以是被我们改成的zip后缀,或者是原先的.apk后缀。
敲⼊命令:apktool d Demo.zip
在⽂件夹中⽣成了⼀个⽂件夹,⾥⾯所有的xml⽂件我们就可以打开查看了,
⽐如查看l:
到这⾥我们已经学会了反编译查看apk源码。接下来我们再来看看如何修改apk进⾏⼆次打包。
在上⾯我们写的apk中,需要输⼊123456才能登录进第⼆个界⾯,。并且会弹出Toast提⽰。
我们来修改成输⼊123即可进⼊第⼆个界⾯。
⾸先,我们需要把classex.dex转为smali⽂件,利⽤baksmali.jar这个⼯具,如下:
我们把classex.dex复制到baksmali.jar所在的⽂件夹,然后cd进⼊这个⽂件夹之后,敲⼊命令: java -jar baksmali-2.0.3.jar -x classes.dex
可以发现⽬录⽣成了个out⽂件夹,⾥⾯存放的就是我们的源码,不过是smali格式的,如果想要深层次的去修改源码则需要先学习smali的语法构造。这⾥我们简单的修改⼏个数值,进⼊out⽂件中,依次点开⽂件夹可以发现好⼏个smali⽂件,我们发现AActivity的有AActivity.smali⽂件和AActivity1.smali是和匿名内部类有关,这跟我们在开发中打开出匿名内部类的类名是⼀样的。由于这⾥我们只是⽤到了点击事件,所以这个AActivity$1.smali就是点击事件的匿名内部类的实现了,我们打开这个⽂件。
打开后发现都是我们不熟悉的语法,
⾸先:
.class Lcom/example/demo/AActivity$1; 我们定义的类
.super Ljava/lang/Object; 继承的超类,默认是Object
.source “AActivity.java” 对应的源⽂件
.# interfaces
.implements Landroid/view/View$OnClickListener;
这个是实现的接⼝
下⾯的# instance fields、# direct methods、# virtual methods则是这个类定义的字段、⽅法了。
我们重点来看onClick⽅法:
# virtual methods
.method public onClick(Landroid/view/View;)V
.registers 8
.param p1, "v"# Landroid/view/View;
.prologue
const/4 v5, 0x1
.line 27
iget-object v1, p0, Lcom/example/demo/AActivity$1;->this$0:Lcom/example/demo/AActivity;
iget-object v1, v1, Lcom/example/demo/AActivity;->et:Landroid/widget/EditText;
invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v1
invoke-interface {v1}, Landroid/text/Editable;->toString()Ljava/lang/String;android获取真正的签名
move-result-object v0
.line 28
.local v0, "pwd":Ljava/lang/String;
const-string v1, "123456"
invoke-virtual {v1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v1
if-eqz v1, :cond_2f
.line 29
iget-object v1, p0, Lcom/example/demo/AActivity$1;->this$0:Lcom/example/demo/AActivity;
new-instance v2, Landroid/content/Intent;
iget-object v3, p0, Lcom/example/demo/AActivity$1;->this$0:Lcom/example/demo/AActivity;
const-class v4, Lcom/example/demo/BActivity;
invoke-direct {v2, v3, v4}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
invoke-virtual {v1, v2}, Lcom/example/demo/AActivity;->startActivity(Landroid/content/Intent;)V
.line 30
iget-object v1, p0, Lcom/example/demo/AActivity$1;->this$0:Lcom/example/demo/AActivity;
const-string v2, "\u767b\u5f55\u6210\u529f"
invoke-static {v1, v2, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-res
ult-object v1
invoke-virtual {v1}, Landroid/widget/Toast;->show()V
.line 34
:goto_2e
return-void
.line 32
:cond_2f
iget-object v1, p0, Lcom/example/demo/AActivity$1;->this$0:Lcom/example/demo/AActivity;
const-string v2, "\u5bc6\u7801\u9519\u8bef"
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论