一、环境安装
1.1、安装Java环境
1.2、安装SDK环境
1.3、安装NDK环境
二、APK
2.1、文件结构
2.2、打包流程
2.3、安装流程
应用安装涉及目录:
system/app ----->系统自带的应用程序,获得adb root权限才能删除。
data/app ------->用户程序安装的目录,安装时把apk文件复制到此目录。
data/data -------> 存放应用程序的数据
data/dalvik-cache ------>将apk中dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一) 。
安装过程:
复制apk安装包到data/app目录下,解压并扫描安装包,把dex文件保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。
三、虚拟机
1、Java虚拟机--->Java字节码 ---->基于栈架构。
2、dalvik虚拟机(jit机制)---->android5.0以下---->dalvik字节码---->基于寄存器架构。
3、art虚拟机(aot机制)---->android5.0以上
注意:
.dex ---->dexopt--->.odex dalvik加载执行的odex文件。
.dex --->dex2oat --->.oat art加载执行的是oat文件。
四、Java逆向知识
4.1、dex文件反汇编工具
.java ---> .class ---->.dex ---->smail。
在这个过程中会使用三种工具
使用dx.jar工具将.class文件打包成.dex文件
使用baksmail.jar工具将.dex文件反编译成.smail文件
使用smail.jar工具将.smail文件打包成.dex文件。
4.2、dalvik字节码
数据类型对应:
dalvik Java
V ------------->void
Z ------------->boolean
B ------------->byte
C ------------->char
S ------------->short
I ------------->int
J ------------->long
F------------->float
D------------->double
L------------->java类类型
[------------->数组类型
字段:
Lorg/cocos2dx/lua/AppActivity;->handler:Landroid/os/Handler;
包名 类名 变量名 类型
方法:
Lpackage/name/ObjectName;->MethodName(III)Z
Lpackage/name/ObjectName:表示的是当前这个方法所在的类。
L是Java类类型,package/name/是包名,ObjectName是类名MethodName这部分表示的方法名
(III)Z:表示的是方法的签名信息,由方法参数列表(III)和返回值(Z)构成。
(III)表示三个int型参数;Z表示返回值类型为boolean。
4.3、dalvik指令集
基础字节码:名称后缀/字节码后缀 目的寄存器 源寄存“-”这个符号在有的指令里面没有的名称后缀是wide,表示数据宽度为64位,字节码后缀是from16,表示源寄存器为16位。
如move-wide/from16 vAA,VBBBB
move为基础字节码,即opcode、wide为名称后缀,标识指令操作的数据宽度为64位、from16为字节码后缀,标识源为一个16位的寄存器引用变量、vAA为目的寄存器,它始终在源的前面,取值范围为v0~v255 vBBBB为源寄存器,取值范围为v0~v65535。
dalvik指令集中大多数指令用到了寄存器作为目的的操作数或源操作数,其中A/B/C/D/E/F/G/H代表一个4位数值,AA/BB/CC...../GG代表一个8位的数值,AAAA/BBBB/...../GGGG代表一个16位的数值。
4.4、空操作指令
空操作指令的助记符为nop。它的值为00,通常nop指令被用来对齐代码之用,无实际操作。
4.5、数据操作指令
数据操作指令为move。 move 指令根据字节码大小与类型不同,后面会跟上不同的后缀。
move vA,vB:将v寄存器的值赋给vA寄存器,源寄存器与目的寄存器都为4位。
move/from16 vAA,vBBBB:将vBBBB寄存器的值赋给vAA寄存器,源寄存器为16位,目的寄存器为8位。
move/16 vAAAA,vBBBB:将vBBBB寄存器的值赋给vAAAA寄存器,源寄存器与目的寄存器都为16位。
move wide vA,vB:为4位的寄存器对赋值。源寄存器与目的寄存器都为4位。
move object vA,vB:object是对象的意思,那这里就是为对象赋值。源寄存器与目的寄存器都为4位。
move object/from16 vAA,vBBBB:为对象赋值。源寄存器为16位,目的寄存器为8位。
move-object/16 vAA,vBBBB:为对象赋值。源寄存器与目的寄存器都为16位。
move result vAA:将上一个invoke类型指令操作的单字非对象结果赋给vAA寄存器。
move result wide vAA:将上一个invoke类型指令操作的双字非对象结果赋给vAA寄存器。
move result object vAA:将上一个invoke类型指令操作的对象结果赋给vAA寄存器。
move-exception vAA:保存运行时发生的异常到vAA寄存器,这条指令必须是异常发生时的异常处理器的一条指令。否则的话指令无效。
总结:move指令有三种作用:第一种作用:进行赋值操作、第二种作用:move-result 接收返回值操作、第三种作用:处理异常的操作
4.6、返回指令
return就是返回的意思。
return-void:表示函数从一个void方法返回,返回值为空。
return vAA:表示函数返回一个32位非对象类型的值,返回值寄存器为8位的寄存器vAA。
return-wide vAA:表示函数返回一个64位非对象类型的值,返回值为8位的寄存器对vAA。
return-object vAA:这里面出现了object,表示函数返回一个对象类型的值。返回值为8位的寄存器vAA。
4.7、数据定义指令
数据定义指令用来定义程序中用到的常量,字符串,类等数据。
const/4 vA,#+B:将数值符号扩展为32位后赋给寄存器vA。
const/16 vAA,#+BBBB”:将数据符号扩展为32位后赋给寄存器vAA
const vAA,#+BBBBBBBB:将数值赋给寄存器vAA。
const/bigh16 vAA,#+BBBB0000:将数值右边零扩展为32位后赋给寄存器vAA。
const-wide/16 vAA,#+BBBB:将数值符号扩展为64位后赋给寄存器对vAA。
const-wide/32 vAA,#+BBBBBBBB:将数值符号扩展为64位后赋给寄存器vAA
const-wide vAA,#HBBBBBBBBBBBBBBBB:将数值赋给寄存器vAA。
const-wide/high16 vAA,#+BBBB000000000000:将数值右边零扩展为64位后赋给寄存器vAA。
const-string vAA,string@BBBB:通过字符串索引构造一个字符串并赋给寄存器vAA。
const-string/jumbo vAA,string@BBBBBBBB:通过字符串索引(较大)构造一个字符串并赋给寄存器vAA。
const-class vAA,type@BBBB:通过类型索引获取一个类引用并赋给寄存器vAA。
const-class/jumbo vAAAA,type@BBBBBBBB:通过给定的类型索引获取一个类引用并赋给寄存器vAAAA。这条指令占用两个字节,值为0xooff(Android4.0中新增的指令)。
4.8、实例操作指令
check-cast vAA,type@BBBB:将vAA寄存器中的对象引用转换成指定的类型。
如果失败会报出ClassCastException异常。
如果类型B指定的是基本类型,对于非基本类型的A来说,运行时始终会失败。
instance-of vA,vB,type@CCCC:判断vB寄存器中的对象引用是否可以转换成指定的类型。
如果可以vA寄存器赋值为1,否则A寄存器赋值为0。
new-instance vAA,type@BBBB:构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器。类型符type指定的类型不能是数组类。
4.9、数值操作指令
数组操作包括获取数组长度,新建数组,数组赋值,数组元素取值与赋值等操作。
array-length vA,vB:获取给定vB寄存器中数组的长度并将值赋给vA寄存器。数组长度指的是数组的条目个数。
new-array vA,vB,type@CCCC:构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器。
filled-new-array {vc,vD,vE,vF,vG},type@BBBB:构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还指定了参数的个数,vC~vG是使用到的参数寄存序列。
4.10、异常指令
“throw vAA”抛出vAA寄存器中指定类型的异常。
4.11、跳出指令
Dalvik指令集中有三种跳转指令:
1、goto:无条件跳转。
2、switch:分支跳转
packed-switch:有规律跳转、sparse-switch:无规律跳转。
3、if:条件跳转
if-eq:等于/if-ne:不等于、if-lt:小于/if-le:小于等于
if-gt:大于/if-ge:大于等于、if-eqz:等于0/if-nez:不等于0
if-ltz:小于0/if-lez:小于等于0、if-gtz:大于0/if-gez:大于等于0
4.12、比较指令
比较指令用于对两个寄存器的值(浮点型或长整型)进行比较。
大于(1) /等于(0) /小于(-1)=>cmpg、cmp、大于(-1)/等于(0)/小于(1)=>cmpl
4.13、字段操作指令
普通字段=>iget读/iput写
静态字段=>sget读/sput写
4.14、方法调用指令
根据方法类型不同,共有5条方法调用指令。
invoke-virtual :调用实例的虚方法 ----->Java中的普通方法
invoke-super :调用实例的父类/基类方法 ----->Java中的父类
invoke direct :调用实例的直接方法----->Java中的构造方法
invoke-static :调用实例的静态方法----->Java中的静态方法
invoke-interface :调用实例的接口方法------>Java中的接口
4.15、数据转换指令
数据转换指令用于将一种类型的数值转换成另一种类型。
它的格式为“opcode vA,vB”,vB寄存器存放需要转换的数据,转换后的结果保存在vA寄存器中。
neg-数据类型=>求补
not-数据类型=>求反
数据类型1-to数据类型2=>将数据类型1转换为数据类型2。
4.16、数据运算指令
add/sub/mul/div/rem 加/减/乘/除/模
and/or/xor 与/或/异或
shl/shr/ushr 有符号左移/有符号右移/无符号右移。
五、smali文件分析
5.1、描述类的信息
在打开smali文件的时候,它的头三行描述了当前类的一些信息
.class<访问权限>[修饰关键字]<类名>
.super<父类名>
.source<源文件名>
.class指令表示当前的类名,类的访问权限是public,类名为LHelloWorld,类开头的L表示后面跟随的字符串是一个类。
.super指定了当前类所继承的父类,后面指的就是这个父类的类名,L表示后面跟字符串是一个类。
source行代码为空:因为经过混淆的dex文件,反编译出来的smali代码可能没有源文件信息。
5.2、静态字段
# static fields
. field<访问权限>static[修饰关键字]<字段名>:<字段类型>
baksmali在生成smali文件时,会在静态字段声明的起始处添加注释“static fields”,注释以#开头。
访问权限包括:private、protected、public修饰关键字为字段其他属性。
5.3、实例字段
# instance fields
.field<访问权限>[修饰关键字]<字段名>:<字段类型>
5.4、直接方法
# direct methods
.method<访问权限>[ 修饰关键字]<方法原型>、
<.registers>、<.locals> [.param] [.prologue][.line]<代码体>
.end method
#direct method 是注释,是baksmali添加的,访问权限和修饰关键字 跟字段是一样的。方法原型 描述了方法的名称、参数与返回值。
.registers 指令指定了方法中寄存器的总数,这个数里是参数和本地变里总和。
.param 表明了方法的参数,每个.param指令表示一个参数,方法使用了几个参数就有几个.parameter指令。
.prologue 指定了代码的开始处,混淆过的代码可能去掉了该指令。
.line 指明了该处代码在源代码中的行号,同样,淆后的代码可能去掉了行号。
.local 使用这个指定表明方法中非参寄存器
5.5、虚方法
虚方法指的是从父类中继承的方法或者实现接口的方法,它的声明跟直接方法相同。
# virtual methods
.method<访问权限>[修饰关键字]<方法原型><.registers> <.locals>[.param][.prologue][.line]<代码体>.end method
5.6、接口
# interfaces
.implements<接口名>
#interfaces是注释
.implements是接口关键字,后面的接口名是DexClassDef结构中interfacesOff字段指定的内容。
5.7、注解
.annotation[注解属性]<注解类名>[注解字段 = 值].end annotation
5.8、实例分析
使用程序代码中支付成功的逻辑代码替换掉支付取消的代码
保存并编译修改后的代码
编译后将会生成新的apk文件,安装重新运行即可。
5.9、RE文件管理器逆向
第一步附加模拟器
第二步执行命令:adb shell dumpsys activity top
第三步使用代码查看器查看广告代码