Android反编译笔记


APK是Android Package的缩写,即Android安装包(APK)。APK是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。APK文件和sis一样,把android sdk编译的工程打包成一个安装程序文件,格式为apk。

APK文件其实是zip格式,但后缀名被修改为apk,通过UnZip解压后,可以看到Dex文件,Dex是Dalvik VM executes的简称,即Android Dalvik执行程序,并非Java ME的字节码而是Dalvik字节码。

apk反编译就是通过使用apk反编译工具将apk文件中的源文件和资源反编译出来,得到的源文件和资源文件可以进行处理后再进行编译,以达到系统解剖分析,个性化定制,汉化等目的。

使用ApkTool及Dex2jar逆向Android的应用程序APK,

并用jd-gui查看java源代码。


ApkTool.jar

反编译使用的命令

apktool.jar d HelloWord.apk

反编译结束后会在同目录生成一个同名文件夹,里面有反编译后的所有信息。

反编译后我们可以看到,各种资源文件,向res里面的图片以及界面资源等。还可以看到AndroidManifest.xml里面的内容。


Dex2jar

要从APK文件获得JAR包需要使用专门的工具dex2jar。dex2jar 是一个用来将 Android 的 Dalvik Executable (.dex) format 文件转成 Java 类文件的工具。

用dex2jar反编译的到源码,查看源码结构。

Dex2jar是一款可以将calsses.dex反编译得到java的工具,但还不是成熟,得到的源码并不完全准确。

使用apktool反编译得到apk的classes.dex文件,然后取出里面的calsses.dex文件到Dex2jar目录下

使用命令

dex2jar.bat classes.dex

dex2jar会把classes.dex反编译为classes_dex2jar.jar文件,就在dex2jar的目录下,反编译成jar包


jd-gui

反编译完成之后,用jd-gui(一款查看源码的工具)打开这个jar包。这个java源码虽然不完整,但是大致逻辑是很清楚的。当然这个反编译是不可逆的,也就是说用这段源码想重新编译为原来apk的样子可能性很低,程序越复杂越低。这里可以看到变量名以及类名还很自然,如果加入混淆之后,变量名和类名都很难分清。


了解smali结构

使用Apktool反编译apk后,会在反编译目录下生成一个smali文件夹,里面存放着的就是所有反编译出的smali文件,这些文件会根据程序包的层次结构生成相应的目录,程序中所有的类都会在相应的目录下生成独立的smali文件。baksmali在反编译文件时,会为每个类单独生成了一个smali文件,内部类作为一个独立的类,它也拥有自己独立的smali文件,其文件名以“外部类名$内部类名”的形式定义。如HelloWorld\smali\com\example\helloworld目录下的R$layout.smali文件。

打开HelloWorld文件夹下的AndroidManifest.xml文件,其中有如下片段的代码:

<activity android:label="@string/app_name"

            android:name="com.example.helloworld.MainActivity">

  <intent-filter>

  <action android:name="android.intent.action.MAIN" />

  <category android:name="android.intent.category.LAUNCHER" />

  </intent-filter>

  </activity>

其中,android.intent.category.LAUNCHER表示这个Activity可以通过LAUNCHER来启动,android.intent.action.MAIN表示MainActivity为helloworld程序的主Activity,我们一般分析代码,就从主Activity入手。helloworld的完整类名是:com.example.helloworld.MainActivity

分析程序的主Activity

使用记事本打开HelloWorld\smali\com\example\helloworld\MainActivity.smali文件。每个smali文件都由若干条语句组成,所有语句都遵循着同一套语法规范。

如前三行代码:

  .class public Lcom/example/helloworld/MainActivity;

  .super Landroid/app/Activity;

  .source "MainActivity.java"

分别表示具有public访问权限的类com/example/helloworld/MainActivity,其父类是android/app/Activity,源文件名是MainActivity.java。

再比如:

 .field private info:Ljava/lang/String;
  //表示一个私有字段info, 它的类型为“Ljava/lang/String;”

  一些常见的Smali语法如下:

  .field private isFlag:z  定义变量

  .method  方法

  .parameter  方法参数

  .prologue  方法开始

  .line 12  此方法位于第12行

  invoke-super  调用父函数

  const/high16  v0, 0x7fo3  把0x7fo3赋值给v0

  invoke-direct  调用函数

  return-void  函数返回void

  .end method  函数结束

  new-instance  创建实例

  iput-object  对象赋值

  iget-object  调用对象

  invoke-static  调用静态函数

Android代码混淆

Android代码混淆是Android平台应用开发者经常使用到的一种防止被反编译破解分析的方法。由于Android应用程序主要是由Java语言编写的,Java源代码编译成的中间字节码文件,非常容易被反编译成Java源码。为了防止这种现象出现,就出现了代码混淆技术。

混淆就是对待发布的程序代码进行重新组织和整理,经过混淆后的程序保持原有功能不变,但混淆后的代码很难被反编译,即使反编译成功,也很难看出原来程序的真正语义。

阅读反编译的Java代码方法

在学习代码混淆技术的过程中,我们通过一种阅读反编译Java代码的方法来验证代码混淆的效果。

使用开源的dex2jar结合jd-gui工具,可以轻松实现将Dalvik虚拟机(DVM)的字节码到Java源代码的转换。其中,dex2jar用来将DVM字节码转换成Java语言的字节码,从而生成jar文件。jd-gui负责将jar文件转换成Java源文件供阅读。

关于JVM字节码和DVM字节码的区别

不同于JVM基于堆栈,DVM是基于寄存器的。

JVM字节码由一个或多个.class文件组成,而DVM字节码只由一个.dex文件构成。

JVM字节码使用不同的操作码来进行对象比较和null类型比较,而DVM则使用同一操作码进行比较。

对Android代码进行混淆

在Eclipse中打开crack工程,在工程目录中我们发现了proguard-project.txt和project.properties两个文件。我们就通过配置这两个文件来进行代码混淆。

打开project.properties文件,取消下边一行的注释:

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

(${sdk.dir}变量为当前主机Android SDK目录路径)。这行语句的作用是指定使用Android SDK中附带的proguard工具对代码进行混淆。混淆的具体配置在proguard-project.txt文件中进行。这里我们使用默认的混淆处理。

混淆配置完成后,在Eclipse中导出新的crack.apk。在Eclipse的Package Explorer中选中工程的根节点,在右键菜单里找到Android Tools。选择“Export Unsigned Application Package”菜单项,并选择新crack.apk的保存路径,我们不妨覆盖掉原来的crack.apk。这样,新生成的crack.apk已经经过了代码混淆处理。

如果要特别指定程序中某个jar包不需要被混淆,在proguard-project.txt中需要到-keep关键字指令。

重新反编译阅读Java代码,对比混淆前后效果.

重新使用dex2jar和jd-gui工具查看反编译后的Java代码,方法同步骤一所述。可以看到新的Java程序代码。可以看到,经过代码混淆后,一些Java类名已经做了处理。对于代码量很大的程序来讲,这无疑大大增加了逆向分析的难度。

使用proguard不建议对某些特殊地方的Java元素进行混淆,除了:自定义的静态方法代码。

最后由 不一样的少年 编辑于2016年08月18日 13:27