Android逆向工程

分析APK文件

要分析APK文件,首先要了解APK打包过程

安卓打包过程
  1. 打包资源文件(aapt)
    • 检查Manifest合法性
    • 将res和asserts目录的资源打包加密,生成resources.arsc
    • 生成加密后的Manifest
    • 将加密后的Manifest和resources.arsc打包压缩成resource.ap_
    • 生成R.java
  2. 处理aidl文件,生成相应java文件
  3. javac编译工程源代码,生成相应class文件
  4. 转换所有class文件,生成classes.dex文件
    • 将依赖jar和class文件转换为dex文件
  5. 打包生成apk
    • 将dex、resource.ap_以及so文件打包成apk
  6. 对apk文件进行签名
    • 可在build.gradle中指定签名文件
  7. apk文件对齐
    • 将apk包进行对齐处理,使apk包中的所有资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时速度会更快

打包过程就是一个编译、加密和打包的过程,因此逆向工程就是反编译、解密和解压了。

解压特别容易,将apk文件后缀改为rar,用解压工具就能将apk文件解压了。下图是微信解压的结果

微信apk解压结果

不同的apk文件解压后的内容不尽相同,但分析的思路都是一样的

  1. 一定包含加密后的Manifest文件
  2. 一定包含classes.dex文件。为了突破65536个方法数的限制,所以可能会有多个classes.dex。
  3. 如果项目中使用了so库,一般会在lib文件夹下
  4. 资源文件的中加密xml,可能在r文件夹,res文件夹下

使用了加壳措施的apk,由于加壳方案不一样,所以资源文件和dex文件的处理会有差异,这里不做深入讨论。

dex2jar

如果只是要了解别人的实现方案,那么解压后的classes.dex通过反编译即可得到jar包,再通过JD-GUI就可以看到大部分的源码了。

这里不赘述怎么使用dex2jar和JD-GUI,下图微信反编译后的结果

JD-GUI查看dex2jar结果
  1. 由于微信方法数较多,所以进行了分包,需要使用2.1以上版本的dex2jar,直接将apk文件作为输入,就可以导出jar包了。
  1. Activity是没有完全混淆,所以可读性还比较高。其他代码读起来会比较困难。

apktools

如需解密资源文件就要用到apktool。我们会用到的apktools的功能有:

  1. 反编译资源文件和classes.dex
  2. 将反编译的资源文件重新打包为apk

使用命令apktool d xxx.apk

微信反编译后的结果

可以看到使用apktools反编译的结果和直接解压和类似,主要的不同在于:

  1. 包括Manifest和资源文件中的xml都已经解密了
  2. class文件变成了smali文件夹,且里面的smali文件和反编译的jar包的类基本对应

了解Smali文件和语法

Smali是Dalvik的寄存器语言,语法比较简单,只是比较绕。下面以一个简单的Activity来了解Smali语法。

package com.netease.smali;

  import android.app.Activity;
  import android.os.Bundle;

  public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      }
  }
 .class public Lcom/netease/smali/MainActivity;
  .super Landroid/app/Activity;
  .source "MainActivity.java"

  # direct methods
  .method public constructor <init>()V
    .locals 0

    .prologue
    .line 14
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    return-void
  .end method

  # virtual methods
  .method protected onCreate(Landroid/os/Bundle;)V
    .locals 1
    .parameter "savedInstanceState"

    .prologue
    .line 18
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 19
    const/high16 v0, 0x7f03

    invoke-virtual {p0, v0}, Lcom/fusijie/helloworld/MainActivity;->setContentView(I)V

    .line 20
    return-void
  .end method
  • 前三行指明了类名,父类名,和源文件名。
  • 类名以“L”开头相信熟悉Jni的童鞋都比较清楚。
  • “#”是smali中的注释。
  • “.method”和“.end method”类似于Java中的大括号,包含了方法的实现代码段。
  • 方法的括号后面指明了返回类型,这同样类似与Jni的调用。
  • “.locals”指明了这个方法用到的寄存器数量,当然寄存器可以重复利用,从“V0”起算。
  • “.prologue”指定了代码开始处。
  • “.line”表明这是在java源码中的第几行,其实这个值无所谓是多少,可以任意修改,主要用于调试。
  • “invoke-direct”这是对方法的调用,可以看到这里调用了是Android.app.Activity的init方法,这在java里是隐式调用的。
  • “return-void”表明了返回类型,这和java不一样,即使没有返回值,也需要这样写。
  • 接下来是onCreate方法,“.parameter”指明了参数名,但是一般没有用,需要注意的是p0代表的是this,p1开始代表函数参数,静态函数没有this,所以从p0开始就代表参数。
  • 在实现里先是调用了父类的方法,然后再调用setContentView,注意这里给了一个传参。整形的传参,这个值是先赋给寄存器v0,然后再调用的使用传递进去的。smali中都是这么使用,所有的值必须通过寄存器来中转。这点和汇编很像。

详细的Smali语法可以参考进入Android Dalvik虚拟机之Dalvik指令集

修改Smali并打包

了解Smali语法后就可以尝试修改源码了。

例如,我们需要在Activity中显示一个Toast。通过Java,只需要在OnCreate中增加一行代码

 Toast.makeText(this, "Hello, Smali", Toast.LENGTH_LONG).show();

翻译为Smali就是:

    .line xx
    const-string v0, "Hello, Smali"

    const/4 v1, 0x1

    invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

除了这些,还有两个地方需要修改:

  1. “.locals 1”,因为本来只用到了v0,现在多用了一个v1,所以改为“.locals 2”。
  2. “.line xx” xx随意改为一个不重复的值即可。

最后通过apktool b即可将项目重新打包,再经过签名就能运行了。

应用加壳

有反编译二次打包的黑科技,就有apk加壳的保护方式。大部分经过加壳保护的apk,已经无法通过上述方案进行二次打包了。

应用加壳的基本原理是

  1. 对原始APK进行反编译,并记录其签名信息
  2. 将dex文件加密并放入assets文件夹中
  3. 使用自定义的Application接管apk原本的Application
  4. Applicaiton启动时首先进行签名验证
  5. 再解密dex并动态加载class文件

为了破解这类加壳应用,又出现了ZjDroid--脱壳神器

这类脱壳工具都是针对特定的加壳方案去做逆向工程,针对“爱加密”的加壳方案,也有文章专门进行分析:Apk脱壳圣战之---脱掉“爱加密”的壳

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容