您的位置:首页 > 移动开发 > Android开发

Android逆向工程研究

2015-06-23 23:38 405 查看
Android逆向工程研究

一、在进行Android逆向工程之反编译之前需要准备好一些必要的工具:

1、apktool——该工具主要用于对Android应用安装包(*.apk)进行拆包与打包工具。

拆包简单命令:java -jar apktool.jar d <path\*.apk> -o <path>

打包简单命令:java -jar apktool.jar b <path> -o <path\*.apk>

2、dex2jar——该工具主要用于对解压出来的安装包中classes.dex文件转换成*.jar包。

3、jd-gui——该工具用于查看JAVA字节码。

4、auto_signapk——该工具用于签名Android应用安装包(*.apk)。

签名简单命令:java -jar signapk.jar <public-sign-file> <private-sign-file> <path\*.apk(ps:需要签名apk包)> <path\*.apk(签名成功apk包)>

5、额外,可能还需要smali.jar(把反编译出来的*.smali文件包重新打包成classes.dex。)与baksmali.jar(用于反编译classes.dex)工具包。

签名简单命令:java -jar smali.jar <path> -o <path\×.dex>

签名简单命令:java -jar baksmali.jar <path\×.dex> -o <path>

备注:*代表任意字符串

二、如何看懂反编译出来smali汇编文件

#static fields->定义静态变量的标记

#instance fields->定义实例变量的标记

#direct methods->定义静态方法的标记

#virtual methods->定义非静态方法的标记

.parameter->方法参数

.prologue->方法开始(此定义无意义)

invoke-super->调用父函数

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

const-string vo, "phone"

invoke-direct->调用private(访问类型)函数

invoke-virtual->调用protected或public(访问类型)函数

return-void->函数返回void数据类型

.end method->函数结束

new-instance->创建实例

iput-object->对象赋值

iget-object->调用对象

invoke-static->调用静态函数

.registers->这个指令指定方法中寄存器的总数。

.locals->这个指令指定方法中非参寄存器的总数。

1、原始类型(基本数据类型)

    V void(只能用定义返回值类型)

    Z boolean

    B byte

    S short

    C char

    I int

    J long(long类型比较特殊,它不是以首字母大写定义以便区分对象类型)。

    F float

    D Double

在Android虚拟机中变量存放是放在寄存器中。因为,Dalvik VM是基于寄存器的,而JVM是基于栈的;

Dalvik有专属的文件执行格式dex(dalvik executable),而JVM则执行的是java字节码。Dalvik VM比JVM速度更快,占用空间更少。

Davlik字节码中,寄存器都是32位的,能够支持任何类型;64位类型(Long/Double)用2个寄存器表示。

2、引用类型

(1)、对象

大写L开头表示一个对象类型。

例如:L<package>/<DirectoryName>/<className>;

 (1)、<package>/<DirectoryName>表示对象所在包名。

 (2)、<className>表示对象名称。

(2)、数组

[是数组表示方式

[I表示一个int类型的一维数组。

[[I表示一个int类型的二维数组。

字符串(String)类型数据表示为[Ljava/lang/String

3、方法和字段

(1)、方法定义

方法开始与结束表示

.method <访问类型> <静态或是非静态> methodName()V

...

.end method

有返回值方法定义:

例如:以引用类型(类对象)返回方式:<methodName>(III)L<package>/<DirectoryName>/<className>;

      以数组返回方式:<methodName>(L<package>/<DirectoryName>/<className>)[?->(?单代表任意基本数据类型)。

无返回值方法定义:

例如:<methodName>()V(以V作为任意方法的无返回值数据类型定义)。

所以:无论任何方法想以什么类型返回就在对应方法后添加什么类型即可。

(2)、方法调用

L<package>/<DirectoryName>/<className>;-><methodName(IBZ)>

(3)、字段(属性)定义

.field <访问类型(private、public、默认等)> <fieldName>:L<package>/<DirectoryName>/<className>;

即表示:.field 访问类型 字段名 字段类型

(4)、字段调用

L<package>/<DirectoryName>/<ClassName>;-><fieldName>:Ljava/lang/String;

即表示:包名,字段名和各字段类型

ps:还有许多标识没有一一列出,请大家自行学习。

三、实例(反编译微信包)

在进行反编译应用包之前,我们要确定反编译工具包是否准备好。

在此反编译中,我将以微信包反编译作为反编译实例来讲解,首先需要下载微信安装包,我以微信5.2版本为例子;

让我给大家讲解如何成功反编译Android应用签名包,让自己的移动设备能顺利运行两个相同内容不同包名的共存微信包(应用包)。

ps:我推荐Virtuous Ten Studio工具,整合了上面我之所讲述工具包。此工具非常之强大。

在此我不使用此工具,我会使用上面我之所讲述工具包,并讲解其使用的方法或是步骤。

注意:在重编译打包时,如果报属性字段没有定义的字眼,而此文件中又能找到此定义的属性字段,那代表是此文件的编码格式不是UTF-8。

而并不是apktool工具包本身的问题,修改文件编码即可。

1、反编译微信包(应用包)的方法有很多种。以下简单罗列下我所知道的几种方式。

   (1)、方式一(最简单方式):

       (1)、修改AndroidManifest.xml文件中的包名属性(package)值。

       (2)、然后通过apktool工具包反编译出来的smali文件夹中新建与在AndroidManifest.xml文件中修改的包名属性(package)值相同的文件夹路径。

       (3)、重编译打包、签名。

   (2)、方式二:

       (1)、反编译微信包(通过apktool工具反编译)。

       (2)、修改替换AndroidManifest.xml文件中的包名属性(package)值。

        例如:com.tencent.mm 修改成com.xxx.xxx

       (3)、修改替换AndroidManifest.xml文件中定义的activity、service、provider、receiver、permission等标签中包含相同包名属性的值。

        例如:com.tencent.mm 修改成com.xxx.xxx

       (4)、修改替换所有smali汇编文件中包含相同包名的值(例如:com.tencent.xx com/tencent/xx)。

        例如:com.tencent.xx修改成com.xxx.xxx 或是:com/tencent/xx修改成com/xxx/xxx

       (5)、把所有调用动态库文件(lib\*.so结尾的文件)类都新建一个stub子类继承原始目录下面的类。

        (备注:原始目录下面的文件以及目录结构已经被我们修改,你需要新建以前目录结构、在导入是so动态库文件引用到的类文件。此步骤比较复杂牵扯调用的类比较多,所以需要细心)。

       (6)、修改完成之后,重编译打包、签名。

   (3)、方式三:

       (1)、反编译微信包(通过apktool工具反编译)。

       (2)、修改替换AndroidManifest.xml文件中的包名属性(package)值。

        例如:com.tencent.mm 修改成com.xxx.xxx

       (3)、修改替换AndroidManifest.xml文件中定义的activity、service、provider、receiver、permission等标签中包含相同包名属性的值。

        例如:com.tencent.mm 修改成com.xxx.xxx

       (4)、修改替换所有smali汇编文件中包含相同包名的值(例如:com.tencent.xx com/tencent/xx)。

        例如:com.tencent.xx修改成com.xxx.xxx 或是:com/tencent/xx修改成com/xxx/xxx

       (5)、修改动态库文件(lib\*.so结尾的文件);通过使用16进制编辑器修改,把相同包名字符串修改替换成目标字符串。

        例如:com.tencent.xx修改成com.xxx.xxx 或是:com/tentcent/xx修改成c
ae72
om/xxx/xxx 或是:com_tencent_xx修改成com_xxx_xxx

       (6)、此不修改之后,还不一定能成功,则此还需要通过IDA Pro工具查找修改。

       (7)、修改完成之后,重编译打包、签名。

       

四、解决Android验证安装的应用包合法性(解决签名不一致问题)

经过上面的几种方案操作后,生产出来的共存应用包只能算是初步的实现了在一部手机中能成功地安装多个相同应用不同的包名的APK。

因为当你使用的时候会提示此应用不合法。所以,要实现或是解决应用签名验证问题。

Android应用包一但由开发者签名打包成apk之后,在apk包中META_INF目录下会生成3个文件。

主要保存着对对非文件夹的非签名的文件资源经过SHA-1+base64编码后的值。在安装应用之后,会在应用中对程序合法性的进行验证判断。所以需要绕过签名认证机制。

绕过应用签名验证不合法问题;签名的校验的方式大概分为本地smali文件签名校验,网络签名校验,动态库签名校验。
(1).本地smali文件签名校验
   (1)、找出反编译出来的smali文件当中存在有Signature类的引用(此步骤用于定位签名验证代码地方)。
   (2)、找到判断签名验证的代码块,有类似if-nez或是if-eqz判断地方做绕过判断修改就可以咯。
(2).网络签名校验
   (1)、通过手机抓包比对正常的apk与反编译过的apk返回的public_key数据内容是不一致的。
   (2)、把正常的public_key添加到APK中,搜索Signature类的引用,定位到签名的代码块。
   (3)、将public_key值定义个字符串变量(const-string v0, "xxxxx...")然后传递给寄存器变量就搞定了。
(3)、动态库签名校验(此验证相对封闭更安全)。
   (1)、此方法在这不做单独说明了与(1)、(2)两点类似修改办法。
   (2)、最后也是要通过16进制编辑器编辑修改so动态库文件相应的签名验证代码块的。

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息