Android逆向基础知识补习
Smali
Smali是Android虚拟机的反汇编语言。在安卓逆向中是非常重要的,就类似于汇编语言。
推荐一个AS的插件,java2smali,可以将java代码转换为smali,可以让人更好的实践理解smali。
java 类型 smail 描述符
boolean Z
byte B
short S
char C
int I
long J
float F
double D
void V
数组 L
对象 [../../
Smali方法返回关键字和其后面可以跟的数据类型
return byte
return short
return int
return char
return boolean
return float
return-wide double
return-wide long
return-void void
return-object 数组
return-object object
数据转换指令
int-to-long 整型转为长整型
float-to-int 单精度浮点型转为整型
int-tobyte 整型转为字节类型
neg-int 求补指令,对整数求补
not-int 求反指令,对整数求反
比较指令
cmpl-类型 VC,VA,VB,比较VA,VB较小值
cmpg-类型 VC,VA,VB 比较VA,VB较大值
数据定义指令
const-string 字符串值
const-class 字节码对象赋值
const/4 最大存放4位数值(-8到7)
const/16 最大存放16位数值(-32768到32767)
const 最大存放32位数值
const/high16 只存放高16位数值
const-wide 最大存放64位数值
const-wide/16 最大存放16位数值
const-wide/32 最大存放32位数值
const-wide/high16 只存放高16位数值
变量操作指令
move v1,v2
将v2中的值移入到v1寄存器中(4位,支持int型)
move/from16 v1,v2
将16位的v2寄存器中的值移入到8位的v1寄存器这
move/16 v1,v2
将16位的v2寄存器中的值移入到16位的v1寄存器中
move-wide v1,v2
将16位的v2寄存器中的值移入到v1寄存器对中
move-wide/from16 v1,v2
将16位的v2寄存器(一组)中的值移入到8位的v1寄存器在中
move-wide/16 v1,v2
将16位的v2寄存器(一组)中的值移入到16位的v1寄存器中
move-object v1,v2
将v2中的对象指针移入到v1寄存器中
move-object v1,v2
将v2中的对象指针移入到v1寄存器中
move-object/from16 v1,v2
将16位的v2寄存器中的对象指针移入到v1(8位)寄存器中
move-object/16 v1,v2
将16位的v2寄存器中的对象指针移入到v1(16位)寄存器中
move-result v1
将这个指令的上一条指令计算结果,移入到v1寄存器中(需要配合invoke-staic、invoke-virtual等指令使用)
move-result-object v1
将上条计算结果的对象指针移入v1寄存器
move-result-wide
v1将上条计算结果(双字)的对象指针移入v1寄存器
move-exception
v1 将异常移入v1寄存器,用于捕获try-catch语句中的异常
条件跳转指令
if-eq vA,vB,:cond_ 如果vA等于vB,则跳转
if-ne vA,vB, :cond_ 如果vA不等于vB,则跳转
if-lt vA,vB, :cond_ 如果vA小于vB,则跳转
if-le vA,vB, :cond_ 如果vA小于等于vB,则跳转
if-gt vA,vB, :cond_ 如果vA大于vB,则跳转
if-ge vA,vB, :cond_ 如果vA大于等于vb,则跳转
if-eqz vA,:cond_ 如果vA等于0,则跳转
if-nez vA,:cond_ 如果vA不等于0,在跳转
if-ltz vA,:cond_ 如果vA小于0,则跳转
if-lez vA,:cond_ 如果vA小于等于0,则跳转
if-gtz vA,:cond_ 如果vA大于0,则跳转
if-gez vA,:cond_ 如果vA大于等于0,则跳转
Smali关键词
.class 包名+类名
.super 父类类名
.source 源文件名称
.implements 接口实现
.field 定义变量
.method/.end method 方法的开始与结束
.locals 方法内使用的v开头的寄存器个数
.prologue 表示方法中代码的开始处
.line 对于java中的行数
.paramter/.param 指定的方法参数
.annotation./end annotation 注解的开始和结束
.registers 表示该方法使用到的寄存器的个数
.local 表示方法中非参数的变量
.cond_N 条件分支,配合if使用
.goto_N goto跳转标记
寄存器
v变量表示方法中非参数变量
p变量表示方法中参数变量
方法调用指令
invoke-direct 调用私有方法和构造方法
invoke-virtual 调用普通的实例方法,(被public,protected或没有修饰符的方法)
invoke-static 调用静态方法
invoke-super 调用父类方法
invoke-interface 调用接口中的方法
查壳
厂商 | 常见特征so文件或其它文件 | 常见java代码(反编译classes.dex) |
---|---|---|
娜迦 | libchaosvmp.so、libddog.so、libfdog.so | |
娜迦企业版 | libedog.so | |
爱加密 | libexec.so、libexecmain.so、ijiami.dat | s.h.e.l.l.S |
爱加密企业版 | ijiami.ajm | |
梆梆免费版 | libsecexe.so、libsecmain.so、libSecShell.so | com.secneo.apkwrapper.ApplicationWrapper、com.SecShell.SecShell.ApplicationWrapper、com.secneo.apkwrapper.AW |
梆梆企业版 | libDexHelper.so、libDexHelper-x86.so | |
360 | libprotectClass.so、libjiagu.so、libjiagu_art.so、libjiagu_x86.so、libjiagu_x64.so、libjiagu_a64.so | com.stub.StubApp |
通付盾 | libegis.so、libNSaferOnly.so | |
网秦 | libnqshield.so | |
百度 | libbaiduprotect.so | com.baidu.protect.StubApplication |
阿里聚安全 | aliprotect.dat、libsgmain.so、libsgsecuritybody.so、libmobisec.so | |
腾讯 | libtup.so、libexec.so、libshell.so、mix.dex、lib/armeabi/mix.dex、lib/armeabi/mixz.dex | com.tencent.StubShell.TxAppEntry |
腾讯御安全 | libtosprotection.armeabi.so、libtosprotection.armeabi-v7a.so、libtosprotection.x86.so | |
网易易盾 | libnesec.so | |
APKProtect | libAPKProtect.so | |
几维安全 | libkwscmm.so、libkwscr.so、libkwslinker.so | |
顶像科技 | libx3g.so | |
盛大 | libapssec.so | |
瑞星 | librsprotect.so |
主流的Android app保护厂商的产品:梆梆、腾讯、爱加密、360、阿里和百度。这些厂商是来实现app的保护的相关原理如下:
360:将原有的dex文件加密后存储在libjiagu.so、libjiagu_art.so,在运行时动态释放并解密。
阿里:将原有的dex文件拆分为两部分,一部分主体保存为libmobisecy.so,另一部分包含了一部分class_data_item和code_item。在运行的时候将两部分释放在内存中,并修复相关的指针,恢复数据之间的连接关系。同时一些annotation_off被设置为无效的值。
百度:将一些class_data_item存储在dex文件的外部,在运行时恢复与主体的dex的连接关系。在dex文件加载后,其头部的魔数,校验和以及签名值会被擦除。同时某些方法被改写,使得其在执行前相关的指令才会被恢复,在执行之后便立即擦除。
梆梆:提前准备了一个odex或oat文件,并加密保存为外部的jar文件,运行时解密;同时hook了libc.so中的一些函数,如read,write,mmap等,监视其操作区域是否包含了dex的头部,保证无法使用这些函数对dex文件进行操作。
爱加密:同样是加密原有的dex文件,在运行时整体释放并解密,只不过其释放的处于固定路径下的临时文件的名字是随机的。
腾讯:提供选项可以指定需要保护的方法。如果某个方法被保护,则在dex文件中的相关class_data_item中无法看到其数据,即为一个假的class_data_item;在运行时释放真正的class_data_item并连接到dex文件上,但是其code_item却一直存在于原有的dex文件中。同样,一些annotation_off和debug_info_off被填充为无效值来阻止静态反编译。只支持在DVM环境下运行。