赞
踩
Android逆向
常用工具:
JDK/SDK/NDK
eclpise集成开发环境/Android Studio
AndroidKiller/jeb/jadx / GDA/Androidk逆向助手
IDA/GDB
apkhelper/getsign/APK上上签
模拟器(雷电3.59)
MT管理器/RE文件管理器
工具安装注意事项:
1.jdk安装路径中不能有中文
2.ndk的配置路径中不能有中文和空格,可以把它放在根目录
3.安装包文件不全,运行会出错
4.没有配置环境变量可以按住shift+右键=>”在此处打开命令窗口”选项
5.ndk安装正确的提示
D:\android-ndk-r10e>ndk-build
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
D:\android-ndk-r10e\build/core/build-local.mk:143: *** Android NDK: Aborting. Stop.
APK文件:
APK是Android Package的缩写,即Android安装包。APK是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。
APK文件目录:
assets 不经过 aapt 编译的资源文件
lib .so文件
META-INF 文件摘要,摘要加密和签名证书文件目录
CERT.RSA 公钥和加密算法描述
CERT.SF 加密文件,它是使用私钥对摘要明文加密后得到的 密文信息,只有使用私钥配对的公钥才能解密该文 件
MANIFEST.MF 程序清单文件,它包含包中所有文件的摘要明文
res 资源文件目录,二进制格式
drawable 图片
layout 布局
menu 菜单
resources.arsc 经过 aapt 编译过的资源文件
classes.dex 可执行文件
AndroidManifest.xml 配置文件
APK打包流程:
打包资源(res/assets/AndroidManifest.xml/Android基础类库)文件,生成 R.java和resources.ap_文件
处理AIDL文件,生成对应的.java文件
编译Java文件,生成对应的.class文件
把.class文件转化成Davik VM支持的.dex文件(.java=>.class=>.dex)
打包生成未签名的.apk文件
对未签名.apk文件进行签名
对签名后的.apk文件进行对齐处理
APK安装流程:
1.安装方式
系统程序安装
通过Android市场安装
ADB安装(adb devices:显示当前连接的设备;adb install 安装包路径)
手机自带安装
2.安装过程
复制APK安装包到/data/app目录下,解压并扫描安装包,把dex文 件(Dalvik字节码)保存到/data/dalvik-cache目录,并/data/data目录 下创建对应的应用数据目录。
3.安装后文件所在目录
/system/app
系统自带的应用程序,获得adb root权限才能删除
/data/app
用户程序安装的目录,安装时把apk文件复制到此目录
/data/data
存放应用程序的数据
/data/dalvik-cache
将apk中的dex文件安装到dalvik-cache目录下
4.卸载过程
删除安装过程中在上述三个目录下创建的文件及目录。
虚拟机:
1.java虚拟机
java字节码
基于栈架构
2.dalvik虚拟机(jit机制)
Android 5.0以下
dalvik字节码
dalvik可执行文件体积更小
基于寄存器架构
3.art虚拟机(aot机制)
Android 5.0版本及以上
注意:
.dex =>dexopt=>.odex dalvik加载执行的odex文件
.dex=>dex2oat=>.oat art加载执行的是oat文件
Dalvik字节码:
1.了解dalvik寄存器
dalvik中的寄存器都是32位
2.寄存器之v命名法与p命名法
参数寄存器 P0-Pn
局部变量寄存器 V0-Vn
3.dex文件反汇编工具
smali.jar\ddx.jar
4.类型
smali==>Java
V void
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L java类
[ 数组
5.字段
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
6.方法
Lpackage/name/ObjectName;->MethodName (III) Z
Dalvik指令:
基础字节码-名称后缀/字节码后缀 目的寄存器 源寄存器
名称后缀是wide,表示数据宽度为64位
字节码后缀是from16,表示源寄存器为16位
空操作指令
nop
数据操作指令
move(-wide/-object/-result/-result-object/-result-wide/- exception)
move(-wide/-object)/from16
move(-object)/16
返回指令(重点)
return-void(表示方法的放回值为空)
return(表示方法的反回值为32位非对象类型的值)
return-wide(表示方法的反回值为64位非对象类型的值)
return-object(表示方法的反回值为对象类型的值)
数据定义指令(重点)
const(-wide/-string/-class)
const/4
const(-wide)/16
const(-wide)/32
const(-wide)/high16
实例操作指令
check-cast(类型转换)
instance-of(检查)
new-instance(新建)
数组操作指令
array-length(获取数组长度)
new-array(新建数组)
filled-new-array(定义数组并初始化)
filled-new-array/range(定义数组并初始化/指定取值范围)
filled-array-data(数组元素取值与赋值)
异常指令(throw)
跳转指令(重点)
goto 紧跟一个标签直接跳转到标签所在位置
packed-switch(有规律)、sparse-switch(无规律)
if-eq(等于)/if-ne(不等于)
if-lt(小于)/if-le(小于等于)
if-gt(大于)/if-ge(大于等于)
比较指令(cmp)
大于(1)/等于(0)/小于(-1)=>cmpg、cmp
大于(-1)/等于(0)/小于(1)=>cmpl
字段操作指令
普通字段=>iget(读)/iput(写)
静态字段=>sget(读)/sput(写)
方法调用指令(重点)
invoke-virtual(调用实例的虚方法) Java当中的普通方法
invoke-super(调用实例的父类/基类方法)
invoke-direct(调用实例的直接方法) 调用java当中的构造方法
invoke-static(调用实例的静态方法)
invoke-interface(调用实例的接口方法)
数据转换指令
neg-数据类型=>求补
not-数据类型=>求反
数据类型1-to-数据类型2=>将数据类型1转换为数据类型2
数据运算指令
add/sub/mul/div/rem 加/减/乘/除/模
and/or/xor 与/或/非
sh1/shr/ushr 有符号左移/有符号右移/无符号右移
APK反编译与回编译:
先查壳,再反编译看验证
.apk文件==>反编译apk(dex/配置文件/资源文件(apk反编译败)) ==>修改关键文件实现自己的目的==>重新打包签名(无法重新打包) ==>apk安装后无法 运行。
apktool .dex=>.smali
dex2jar .dex=>.jar
Apktool工具实际上只反编译以下三种类型文件:
.xml文件、.dex文件、.arsc文件
去除广告和弹窗,撇开不存在于smali的这种情况,容易的就是 可以在XML中寻到Activity,难的就是寻不到,发生这种情况时, 就要分析代码,程序逻辑,抓住关键信息,界面和函数。
注意:
当字符串等关键信息搜不到时,可以从三个方向考虑:1.字符串 在so层;2.字符串被加密了3.结合了服务器,服务器返回,本地 显示。
smali文件:
无论是普通类、抽象类、接口类或者内部类,在反编译出的代码中,它 们都以单独的smali 文件来存放。每个 smali 文件都由若干条语句组成, 所有的语句都遵循着一套语法规范。
1.描述类的信息
.class < 访问权限> [ 修饰关键字] < 类名>
.super < 父类名>
.source <源文件名>
2. 静态字段
# static fields
.field < 访问权限> static [ 修饰关键字] < 字段名>:< 字段类型>
3.实例字段
# instance fields
.field < 访问权限> [ 修饰关键字] < 字段名>:< 字段类型>
4.直接方法
# direct methods
.method <访问权限> [ 修饰关键字] < 方法原型>
<.locals> “.locals ”指定了使用的局部变量的个数
[.param] “.param”指定了方法的参数
[.prologue] “.prologue ”指定了代码的开始处
[.line] “.line ”指定了该处指令在源代码中的行号
<代码体>
.end method
5. 虚方法的声明与直接方法相同,只是起始处的注释为“virtual methods”。
6.接口
# interfaces
.implements < 接口名>“.implements ”是接口关键字,后面的接口
名是 DexClassDef 结构中 interfacesOff 字段指定的内容。
7.注解
# annotations
.annotation [ 注解属性] < 注解类名>
[ 注解字段 = 值]
.end annotation
注解的作用范围可以是类、方法或字段。如果注解的作用范围是类, “.annotation ”指令会直接定义在 smali 文件中,如果是方法或字段,“.annotation ”指令则会包含在方法或字段定义中。
快速定位关键代码:
1.分析流程
搜索特征字符串
搜索关键api
通过方法名来判断方法的功能
2.快速定位关键代码
反编译APK程序
AndroidManifest.xml=>包名/系统版本/组件
程序的主activity(程序入口界面)
每个Android程序有且只有一个主Activity
分析程序的执行流程
需重点关注的application
application执行时间
授权验证
3.定位关键代码的技巧
信息反馈法(资源id/字符串)
特征函数法(api函数)
顺序查看法(分析程序执行流程/病毒分析)
代码注入法(动态调式/插入log/查看logcat/分析加解密)
栈跟踪法(动态调式/函数调用流程)
Method Profiling(方法剖析=>动态调式/热点分析//函数调用流程)
动态调式:
jdwp(调式有线协议)=>jdb
ddms(dalvik调式监视器服务)
通过该命令(adb shell getprop ro.debuggable)获取当前设备 ro.debuggable的值,当值为1时开启系统调试开关。
android.debuggable="true"
logcat(查看调式信息)/method profiling(跟踪程序的执行流程)
游戏内购:
去除可能会产生费用的危险权限
android.permission.SEND_SMS
android.permission.CALL_PHONE
支付接口
电信支付接口
logcat字符串定位(Egame支付成功/Egame支付Cancel/order id)=>搜索字符串,向上分析,回溯分析/函数名替换
联通支付接口
logcat字符串定位(Unicom支付cancel/Unicom支付成功)=> 在下面类修改处理,可以用goto或switch方法
移动支付接口
logcat字符串定位(购买道具:[] 成功/购买道具:[] 失败)=>在 下面类修改
特征码
中国移动 46000、46002、46007、46020
中国联通 46001、46006、46010
中国电信 46003、46005、46011
内购关键词
和游戏搜索方法名
onResult,onchinabilling,resulton,Paycenter, Callback
联通游戏搜索方法名
OnPayResult,PyaResulton,Activity,result,callback
电信爱游戏搜索方法名
paySuccess成功,payCancel取消,payFailed失败
移动mm搜索方法名
onBillingFinish,Billing,CallBack,onresult无用
对关键onsuccess()函数的筛选与定位
支付宝和银行卡方法名
handle,message
支付宝搜索字符
搜索字符串“9000”
360支付
onfinishedon,Activityresult
4399
notifyDeliverGoods
内购技巧
从静态代码分析程序逻辑,找到修改点
程序逻辑分析=>最重要的又是流程分析/流程图=>核心(层次)
关键性信息查找=>静态(整体分析与局部分析)/动态
Android NDK:
1. 如何编译原生程序
Application.mk(ARM硬件指令集/工程编译脚本/stl支持等)
Android.mk(编译选项/头文件/源文件及依赖库等)
local_path(call my-dir)
include $(clear_vars)
local_arm_mode:= arm指令模式
local_module:=模块名称
local_src_files:=源文件
build_executable(可执行文件)
build_shared_library(动态链接库)
build_static_library(静态链接库))
2. 原生程序的启动流程
原生程序的入口函数
动态库的加载/程序参数argc和argv的初始化
静态链接/动态链接(动态链接程序/动态链接库)
静态链接(crtbedin_static.o/crend_android.o)
动态链接(crtbegin_dynamic.o/crtend_android.o/加载 器 (system/bin/linker))
静态链接程序在启动时不需要额外的加载其他的动态库 (init/adbd/linker)
静态链接与动态链接程序的入口函数相同,动态链接程序 在执行入口函数前需要通过linker进行额外的初始化
main函数究竟何时被执行
静态链接(libc_init_static)/动态链接程序 (libc_init_dynamic)
3. 原生C++程序逆向分析
C++类的逆向
C++中的类可以理解为C语言中的结构体,每一个成员变 量就是一个结构字段,每一个成员函数的代码都被优化到 了类的外部,它们不占据存储空间
Android NDK对C++特性的支持(app_stl)
system
gabi++(rtti)=>gabi++_static/gabi_shared
stlport(rtti/stl)=>stlport_static/stlport_shared
gnustl(c++异常/rtti/stl)=>gnustl_static/gnustl_shared
4. Android NDK JNI API逆向分析
Android NDK提供了那些函数
Linux C/C++
Android NDK<=>JNI接口<=>java
JNINativeInterfasce(jni本地接口)
JNIInvokeInterface(jni调用接口)
移植/保护核心代码
如何静态分析Android NDK程序
file=>load file=>parse c header file=>jni.h=>structures
Android与ARM处理器:
ARM处理器架构概述
ARM处理器家族
Android支持的处理器架构
ARM/x86/MIPS
原生程序与ARM汇编语言:
原生程序逆向初步
代码混淆技术
ARM指令集
堆栈指针寄存器sp/堆栈寻址指令(stmfd压栈/ldmfd出栈)
存储器访问指令(str写入数据到存储器中/ldr从存储器中读取数 据到寄存器)
数据处理指令(mov)/带链接跳转指令(bl)
原生程序的生成过程(交叉编译/跨平台编译)
预处理(预处理指令) 编译 汇编 链接
必须了解的ARM知识
汇编:芯片,高级语言的逆向,中间语言
分析和修改汇编指令:赋值、跳转、算术运算、移位运算、堆栈操 作、内存读写指令、函数调用约定
Thumb(16位)、Thumb2(32位)、ARM(32位)
用户模式(usr):
不分组寄存器(R0-R7)
分组寄存器(R8-R14)
传递参数与返回值(R0-R3)
保存栈顶地址(R13/SP)
保存函数的返回地址(R14/LR)
程序计数器R15(PC)
状态寄存器CPSR
ARM处理器:
ARM状态(执行32位对齐指令的ARM指令)
Thumb状态(执行16位对齐的Thumb指令)
ARM汇编语言程序结构:
完整的ARM汇编程序
处理器架构定义
段定义
注释与标号
@=>单行注释
/**/=>多行注释
汇编器指令
子程序与参数传递
R0-R3这4个寄存器用来传递函数调用的第1到第4个参数,超 出的参数通过堆栈来传递
R0寄存器同时用来存放函数调用的返回值
被调用的函数在返回前无需恢复这些寄存器的内容
ARM指令集:
立即寻址(mov r0,#0x123)
寄存器寻址(mov r0,r1)
寄存器移位寻址(mov r0,r1,lsl #0x2)
LSL(逻辑左移)
LSR(逻辑右移)
ASR(算术右移)
ROR(循环右移)
RRX(带扩展的循环右移)
寄存器间接寻址(ldr r0,[r1])
基址寻址(ldr r0,[r1,#-4])
多寄存器寻址(ldmia r0,{r1,r2,r3,r4})
堆栈寻址(stmfd sp!,{r1-r7,lr}(入栈保护)/ldmfd sp,{r1-r7,lr}(出栈恢复))
ldmfa/stmfa
ldmea/stmea
ldmfd/stmfd
ldmed/stmed
块拷贝寻址
ldmia/stmia
ldmda/stmda
ldmib/stmib
ldmdb/stmdb
相对寻址
相对寻址以程序计算器pc的当前值作为基地址,指令中的地址 标号作为偏移量,将两者相加之后得到操作数有效地址ARM与 Thum指令集
指令格式
<opcode>:指令助记符
{<cond>}:执行条件
{s}:是否影响cpsr寄存器的值
{.w}:指令宽度说明符.w表示是32位
{.n}:指令宽度说明符.n表示16位
<rd>:目的寄存器
,<rn>:第一个操作数寄存器
{,<perand2>}:第二个操作数:立即数、寄存器、寄存器移位
eq:相等/z=1
ne:不相等/标志z=0
hi:无符号数大于/c=1,z=0
cs/hs:无符号数大于或等于/c=1
cc/lo:无符号数小于/c=0
ls:无符号数小于或等于/c=0,z=1
gt:有符号数大于/z=0,n=v
ge:有符号数大于或等于/n=v
lt:有符号数小于/n!=v
le:有符号数小于或等于/z=1,n!=v
mi:负数/n=1
pl:整数或0/n=0
vs:溢出/v=1
vc:没有溢出
跳转指令
B 无条件跳转
BL 带链接的无条件跳转
BX 带状态切换的无条件跳转
BLX 带链接和状态切换的无条件跳转
寄存器访问指令
ldr(<-)/ldrd
str(->)/strd
ldm(->)
stm(<-)
push(入栈)/pop(出栈)
swp
数据处理指令
数据传送指令(mov)/数据非传送指令(mvn)
算术运算指令
add/adc
sub/rsb/sbc/rsc
mul/mls/mla umull/umlal smull/smlal smlad/smlsd
sdiv/udiv
asr(算术右移指令)
逻辑运算指令
and/orr/eor 逻辑与/逻辑或/逻辑异或
bic(位清楚指令)
lsl/lsr 逻辑左移/逻辑右移
ror/rrx 循环右移/带扩展的循环右移
比较指令
cmp/cmn/tst/teq
其他指令
nop(空操作指令)
swi(软中断指令)
mrs(读状态寄存器指令)
msr(写状态寄存器指令)
ARM指令机器码:
B/BL指令
00001BD0 BEQ loc_1c04
31-28:cond=>0000
27-25:101
25-24:L=>B:0 /BL:1
23-0:offset:目标地址与该指令的相对偏移
offset:(1c04-(1bd0+8))/4=1011
0000 101 0 000000000000000000001011
0A 00 00 0B
00001BD0 0B 00 00 0A
LDR/STR指令
00001BC0 LDR R2,[R12]
00001BC0 00 20 9C E5
E5 9C 20 00
1110 01 011001 1100 0010 000000000000
cond 1110
指令标识 01
IPUBWL 011001
Rn:R12 1100
Rd:R2 0010
offset:0 000000000000
MOV指令
MOV R1, #0x56000000
56 14 A0 E3
E3 A0 14 56
1110 00 1 1101 0 0000 0001 0100 01010110
Thumb指令
CPSR寄存器
T位:1-thumb,0-arm
IDA Pro工具介绍:
交互式反汇编器,是典型的递归下降反汇编器。
导航条
蓝色 :表示常规的指令函数
黑色 :节与节之间的间隙
银白色 :数据内容
粉色 :表示外部导入符号
暗黄色: 表示ida未识别的内容
IDA主界面
IDA View三种反汇编视图:文本视图、图表视图、路径视图
Hex View 十六进制窗口
Struceures 结构体窗口
Enums 枚举窗口
Imports 导入函数窗口
Exports 导出函数窗口
Strings 字符串窗口
IDA常用功能及快捷键:
空格键:切换文本视图与图表视图
ESC:返回上一个操作地址
G:搜索地址和符号
N:对符号进行重命名
冒号键:常规注释
分号键:可重复注释
Alt+M:添加标签
Ctrl+M:查看标签
Ctrl+S:查看段的信息
代码数据切换
C=>代码 D=>数据 A=>ascii字符串 U=>解析成未定义的内容
X:查看交叉应用
F5:查看伪代码
Alt+T:搜索文本
Alt+B:搜索十六进制
IDA静态分析:
导入jni.h分析jni库函数
拷贝伪C代码到反汇编窗口
右键=>copy to -assembly-把伪c代码复制到反汇编窗口的汇 编代码。
IDA可以修改so的hex来修改so,edit=>edit-patchrogram
在这里建议使用winhex来实现。
IDA动态调试:
IDA调式界面
1.反汇编窗口
C 将当前地址处的数据解析成代码
P
2.十六进制窗口
编辑内存数据和代码
3.寄存器窗口
修改寄存器的值
4.模块窗口
模块路径和地址
5.线程窗口
6.栈窗口
7.输出信息窗口
IDA调式常用功能
1.断点和运行
设置断点 F2
设置断点不可用 Disable breakpoint
编辑断点 Edit breakpoint
删除断点 Delete breakpoint
继续运行 F9
查看当前所有断点 Ctrl+Alt+B
2.单步调式
单步步入 F7
单步步过 F8
运行到函数的返回地址 Ctrl+F7
运行到光标处 F4
3.IDC脚本
static main(void)
{
auto fp, dexAddress, end, size;
dexAddress = 0x77607640;
size = 0x19E118;
end = dexAddress + size;
fp = fopen("D:\\classes.dex", "wb");
for ( ; dexAddress < end; dexAddress++ )
fputc(Byte(dexAddress), fp);
}
4.修改内存数据
5.修改寄存器
修改PC寄存器时,最好在跳转指令改,当然如果你对程序流程 把握很好,可以随便PC,只要程序不出错
7.NOP函数或代码
NOP函数MOV R0,R0(00 00 A0 E1/00 1C)
清空指令(00 00 00 00/00 00)
函数头直接返回mov pc,lr(0E F0 A0 E1/F7 46)
8.改变执行流程
修改寄存器的值
修改跳转指令
注意:修改内存和修改代码的时机选择不同,因为修改内存和寄存 器,必须调式到某一处,才能让寄存器和内存是想要的值,此 时修改,而且数据的值一般对程序影响不大,而修改代码就不同了 如果已经走到了那一句代码,才去修改代码,是要报错的,提前在 它 运行到前面1-2条指令时修改代码。原因是PC指令预读三级流 水线:
1.读取指令
2.解析指令
3.执行指令
ADD R6,PC,R6 =>R6=PC+R6=847C+1840=9CBC+8? 9CC4
JNI_OnLoad下断方法技巧
so内寻找
基址+偏移
dvmloadnativecode函数
dlsym(handle,"jni_onload")
.init和.init_array下断技巧
linker大法,先勾选三项F9运行,再执行jdb,当目标so被加载 时通过基址+偏移下段
APK保护策略:
Java层混淆、资源混淆、SO层混淆(ollvm)
签名验证、文件验证、整包验证
本地验证、服务器验证、综合验证
本地验证
java层验证
so层验证
网络验证
java层验证
so层验证
通信/实时控制
服务器
判断验证
去签名验证
PackageManager
getAppSignature
签名hash值
signatures
反调试:
java层Debug类的isDebugged方法
native层的isDebugged方法
检测status文件的TracePid
检测开放端口
inotify 文件监控/proc/pid/maps等文件打开事件与检测其中内存运行的文件gettimeofday时间循环检测
fork父子循环检测
异常触发、非法指令、引入与异常信号陷阱
检测代码暂停时间
反-反调试:
修改java层isDebugged方法返回
利用py脚本HOOK native层Debug方法
HOOK open、fopen函数动态下断修改TracePid的值或修改为过反调试的内核
利用其他端口调式
修改内核改变文件打开事件响应与修改打开/proc/pid/maps后内存运行文件结果
HOOK gettimeofday函数让其不能循环
修改内核fork方法与多IDA挂起kill19等方法调式
修改异常指令信号与识别非法指令使用异常HOOK
HOOK 常用获取时间的系统函数
修改检测时间,让其只检测一次
常见加密算法:
古典密码学(以字符为基本加密单元)
移位密码/错位密码
替代密码/置换密码
现代密码学(以信息块为基本加密单元)
哈希算法
非对称加密与解密
椭圆曲线
数字签名
数据分组与校验
散列函数
用于数据完整性校验
MD 消息摘要算法
SHA 安全散列算法
MAC 消息认证算法
CRC 循环冗余校验算法
对称加密算法
加密密钥==解密密钥
流密码:指加密时每次加密一位或一个字节的明文。
同步流密码
同步性 无错误传递性 主动攻击性
音频/视频数据提供版权保护
自同步流密码
自同步性 错误传递有限性
主动攻击性 明文统计扩散性
RC4/SEAL
分组密码(http://www.seacha.com/tools/):指加密时将明文分 成固定长度的组,用同一密钥和算法对每一块加密,输出也是固 定长度的密文。
常用于网络加密
安全性=>扩散/混乱原则
实现性=>软件/硬件
ECB 电子密码本模式
CBC 密文链接模式
CFB 密文反馈模式
OFB 输出反馈模式
CTR 计数器模式
DES
DESede/3DES/Triple DES
AES
TEA
DEA
PBE
非对称加密算法
加密密钥!=解密密钥
公钥==>对外公开
私钥==>对外保密
私钥加密==>公钥解密
公钥加密==>私钥解密
DH 密钥交换算法
基于因子分解
RSA 数据加密/解密 数字签名
基于离散对数
ElGameal 数据加密/解密 数字签名
DSS数据签名标准=>DSA 数字签名
ECC 椭圆曲线加密算法
使用对称加密算法对数据进行加密与解密,使用非对称加密算法 对对称加密算法所使用的密钥进行加密与解密。
数字签名
私钥==>签名
公钥==>验证
单向认证
双向认证
RSA
DSA
ECC+DSA==>ECDSA 椭圆曲线数字签名算法
认证/鉴别服务
数据完整性服务
抗否认性服务
数字证书
消息摘要算法
对称加密算法
非对称加密算法
数字签名
鉴别/认证
数据保密性
数据完整性
抗否认性
证书管理
KeyTool
构建自签名证书
构建CA签发证书
OpenSSL
根证书
服务器证书
客户端证书
密钥库==>管理私钥
数字证书==>管理公钥
加密/解密
签名/验证
X.509
服务器数字证书
协议加解密分析:
协议与安全协议(服务器协议关键,就是先抓包,再解密)
概念:协议就是服务器与客户端交互信息的一种规则
客户端和服务器连接:实质都是连接服务器的IP地址和开放端口
POST:客户端提交数据给服务器
GET:客户端获取服务器数据
http,ftp,smtp:应用层
tcp,udp:传输层
IP:网络层
帧相关协议:数据链路层
HTTP/HTTP2
HTTPS协议=>https是基于sll/tls的http协议
ssl协议=>安全套接字层
tls协议=>传输层安全
socket=>tcp/udp=>http/ftp
抓包工具:
http/https
fiddler/charels
socket/tcp
抓网卡
wireshark/sniffer
防止代理
小米wifi+wpe
抓不到包原因:
1.如网游副本,有的就是没有包;
2.fiddler只能抓HTTP/HTTPS,如果是socket抓不到的;
3.在动态调试时,没有走到发包的地方。
tcpdump+Wireshark:
adb shell tcpdump -p -vv -s 0 -w /sdcard/capture.pcap 开始抓包
ctrl+c 结束抓包
adb pull /sdcard/capture.pcap 导出文件
Dex文件结构:
1.dex文件中的数据结构
u1/uint8_t=>表示1字节的无符号数
u2/uint16_t=>表示2字节的无符号数
u4/uint32_t=>表示4字节的无符号数
u8/unit64_t=>表示8字节的无符号数
sleb128=>有符号leb128,可变长度为1-5字节
uleb128=>无符号符号leb128,可变长度为1-5字节
uleb128p1=>无符号leb128值加1,可变长度为1-5字节
2.dex文件整体结构
struct DexFile {
DexHeader
DexStringId
DexTypeId
DexProtoId//对DexType进一步说明
DexFieldId
DexMethodId
DexClassDef
DexData
DexLink
}
以索引为线索
3.DEX的内存映射
与静态类似,只是变为xxxItem结构
ClassObject结构由六个部分组成:
PDvmDex:// DEX文件字段
super://超类
sfields://对应DexClassData结构中的staticFields静态字段
iFields://对应DexClassData结构中的instanceFields实例字段
directMethods://对应DexClassData结构中的directMethods直接方法字段
virtualMethods:///对应DexClassData结构中的virtualMethods虚方法字段
DexClassDef : class_def_item
DexClassData: class_data_item
DexFiled(staticFields): sfileds
DexFiled(instanceFields): ifileds
DexMethod(directMethods):directMethods
DexMethod(virtualMethods):virtualMethods
DexCode: code_item
ELF文件结构:
linux elf文件、windows pe文件
Android操作系统内核采用Linux内核框架实现 Android ELF文件
ELF文件整体结构:
ELF Header-->ELF文件头的位置是固定的
Segment Header Table-->ELF程序头描述的是段的相关信息
.init
.text
.rodata
.data
.symtab 符号表
.line
.strtab 字符串表
Section Header Table-->ELF节头表描述的是节区的信息
动态用段,静态用节
readelf的使用:
-a
-h
-l
-S
-e
-s
arsc文件:
arsc文件解析
xml文件:
xml文件解析及工具
xml加密
xml和arsc简单十六进制加密:
以arsc为例:在0x00000028h的文件偏移地址之前进行修改,如改头 部第一个HEX操作数为00。搜索字符,'1c' 搜索3下。把1c前面的 01改00,就可以了。看020行,头部字节流,把尾部的00改为和头 部一样。
思考:ARSC、xml文件很难去做单纯的动态加载,如DEX,这也是文件根本性质决定的,还有一个原因,就是安装后这个APK必须要打开。我们最多能做到的,在动态上(自然这就比外部混淆、十六进制加密要强些),就是用壳的apk,然后结合APK动态加载,让真实APK的资源文件是正确的,可以考虑动态代码生成(如动态生成真实APK的配置清单xml,而在asset文件夹下的APK压缩包中并没有配置清单xml),或者解密替换(这就分两种,你是保护xml\arsc文件,还是那些png等外部资源,当然原理一样,文件的加密解密)等。事实是,DEX和APK的动态加载往往必须要考虑资源怎么办的问题,解决方法往往是资源保护的一个反面,将动态加载需要的资源文件中数据先写在壳的资源文件中。毕竟,在代码与资源保护直接抉择,肯定是保护代码优先。
DEX类加载过程解析:
http://androidxref.com/
1.DEX文件优化与验证:
run_dexopt:
static const char* Dex_OPT_BIN = "/system/bin/dexopt"
\dexopt\Optmain.cpp:extractAndProcessZip() //读取和抽出dex,加上odex文件头,设置优化选项,可以看作DEX文件优化的主控函数
\vm\analysis\DexPrepare.cpp:dvmContinueOptimization()//写入odex文件,可以说优化与验证工作的完成就是写入odex文件
2.DEX文件解析:
\vm\RawDexFile.cpp:dvmRawDexFileOpen()//DEX文件解析的主控函数
\libdex\OptInvocation.cpp:dexOptGenerateCacheFileName()//生成该dex对应odex文件
\vm\DvmDex.cpp:dvmDexFileOpenFromFd()//完成对DEX文件映射,设置为只读文件,并进一步优化
\libdex\DexFile.cpp:dexFileParse()//解析DEX
在实践中,我们发现并不是所有的dexfileopenpartial都能断下来,但
_Z27dexOptGenerateCacheFileNamePKcS0
dvmdexfileopenfromfd
dexfileparse
这些函数一定能断下来,而dexfileopenpartial常常在有壳时,也就是真正dex出现时才可以断下来,由此可知,
其实dalvik很喜欢走的路就是用odex,而不是dex。dex文件只有在odex文件不好用时才去用,这与oat文件一致。
3.DEX类加载
\vm\native\dalvik_system_DexFile.cpp:
Dalvik_dalvik_system_DexFile_defineClassNative //类加载的主控函数
\vm\oo\Class.cpp:dvmDefineClass()//确认类加载描述符进行类加载
\vm\oo\Class.cpp:findClaaNoInit()//完成实际类加载工作
\vm\oo\Class.cpp:loadClassFromDex()//返回值是一个ClassObject结构体
往后便是FindClass、GetStaticMthodID、CallStaticMthod、dvmInterpretStd
so的加载、链接、执行过程解析:
begin.S:__linker_init
1.dlopen函数
dlfcn.cpp
2.整体流程
linker.cpp
do_dlopen函数:
find_library函数:完成对so的解析装载、分配、链接
CallConstructors函数:完成对so中.init和.initarray的执行
3.先看CallConstructors函数,从后面的执行来看
CallFunction("DT_INIT", init_func);
CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
4.回到find_library函数,看so的具体加载
find_library_interna
load_library是整个so加载的主控函数
5.so加载的详细步骤
解析装载:
elf_reader.Load函数包括了下列函数:
ReadElfHeader() &&
VerifyElfHeader() &&
ReadProgramHeader() &&
ReserveAddressSpace() &&
LoadSegments() &&
FindPhdr();
所以,so的装载是一种解析式装载,这与dex有一定区别,dex是先加载进行优化验证生成odex,再去解析odex文件,而so更像边解析边装载,在装载过程中主要解析是load段。
分配soinfo:
soinfo_alloc函数,生成了一个soinfo结构
链接:
soinfo_link_image函数,也就是soinfo结构链接镜像,从而得到一个以后用的镜像文件
so中用于动态链接的结构就是.dynamic节,即动态节区
a.定位动态节
b.解析动态节
c.加载依赖so
d.重定位:
主要函数为soinfo_relocate,此函数会被soinfo_link_image函数调用
解析重定位项:.rel(.plt安卓并不用),重定位表
导入符号信息:.dynsym, 符号表
修正需要重定位的地址
DEX类加载过程在加固脱壳应用:
1.dump dex,脱壳。
2.内存动态替换dex,dex自修改,自调用底层函数解析dex。
3.dex自解析重构,完成dex重组脱壳。
Linker在加固脱壳应用:
1.在.init和.intarray下断,若.initarray节存在dex解密,dump dex,也就是dex脱壳。
2.dump so再修复,也就是so脱壳,一般选择在jni_onload。
3.因为在.init和.intarray运行之后,如果有jni_onload,就调用,变相断jni_onload。
4.自定义linker。
5.HOOK dlopen等函数,判断是否加载了so,如果加载就解密,同理在整个so的装载、链接过程中可以对so进行变形后的修复,so解密脱壳最迟要在jni_onload,当然混淆等基于内部保护的不在考虑之列。
DEX文件加固:
DEX文件结构变形
DEX文件结构拼接隐藏
DEX文件整体加密
ELF文件加固:
ELF文件结构变形
so文件结构拼接隐藏
so文件反汇编注入
so文件整体加密、函数加密、区段加密、加壳
Apk保护:
1.app存在的危险
代码修改(广告植入、替换广告id)
资源修改(界面替换广告、链接替换)
破解(应用收费、内购)
篡改数据(无限金币、钻石)
加入恶意代码(木马、隐私、交易)
动态注入(数据拦截、窃取、修改)
本地数据修改、数据库文件修改
协议修改(服务器欺骗、向服务器发送假数据)
2.加固目的
需要防止逆向分析(防逆向)--防止核心代码被反编译
防止二次打包(防篡改)--校验完整性、签名、防止盗版
防止调式和注入(防调试)--防止动态调式,注入获取关键数据
防止应用数据窃取(防窃取)--加密敏感数据
防止协议直接被盗刷--加密协议通信
3.常见加固厂商
360/娜迦/梆梆
爱加密/阿里
百度//腾讯/网秦/通付盾
4.常用加固方式
类加载技术
针对apk中的classes.dex文件进行处理,放入特定的文件中,通 过native代码来对其运行时解密
使用厂商(娜迦/爱加密/梆梆)
对原dex文件整体压缩加密,保存在壳代理的dex文件尾部,加 载到内存中解密运行
使用厂商(360)
方法替换技术
将classes.dex文件中的方法代码进行提取,抽取方法,在运行 时对其进行动态解密还原
使用厂商(娜迦/梆梆)
5.加固厂商特征
娜迦:libchaosvmp.so, libddog.so libfdog.so
梆梆:libsecexe.so, libsecmain.so, libSecShell.so
梆梆企业版:libDexHelper.so, libDexHelper-x86.so
爱加密:libexec.so, libexecmain.so, ijiami.dat
360:libprotectClass.so, libjiagu.so; libjiagu.so, libjiagu_art.so; libjiagu.so, libjiagu_x86.so
百度:libbaiduprotect.so
阿里聚安全:aliprotect.dat, libsgmain.so, libsgsecuritybody.so
腾讯:libtup.so, libexec.so, libshell.so; mix.dex; lib/armeabi/mix.dex, lib/armeabi/mixz.dex
腾讯御安全:libtosprotection.armeabi.so, libtosprotection.armeabi-v7a.so, libtosprotection.x86.so
通付盾:libegis.so, libNSaferOnly.so
网秦:libnqshield.so
网易易盾:libnesec.so
APKProtect:libAPKProtect.so
几维安全:libkwscmm.so, libkwscr.so, libkwslinker.so
顶像科技:libx3g.so
6.脱壳手法
修改系统源码自动脱壳
通过hook方式对关键函数进行脱壳
开源工具如zjdroid,dexhunter进行脱壳
利用IDA或者GDB动态调式进行脱壳
分析virualapp
去框架HOOK
制作vm策略
实现vm置换
置换后销毁
其他
dex vmp(制作native oncreate)
典型非主流加固
脱壳机
虚拟机技术
加固技术:
第一代加固 DEX加密
proguard等混淆、其他弱加密
DEX字符串加密
静态DEX文件整体加密解密
资源加密(xml与arsc文件加密及十六进制加密)
对抗反编译(添加垃圾类)
反调试
自定义DexClassLoader
第二代加固 DEX抽取与SO加固
DEX动态加载(分为利用jni和自定义jni即自定义底层函数)
DEX代码抽取到外部(类抽取加密按需解密和动态方法修改替换)
SO加密
第三代加固 DEX动态解密与SO混淆
Dex代码动态解密
SO代码膨胀混淆
第四代加固 arm vmp
jni反射抽取方法成本地原生代码即半vmp(分为jni反射解密DEX方 法和完全翻译为C代码)
初级vm即dex opcode vm指令虚拟使用jni指令还原(分为自定义后 端编译器和jni反射置换表)
高级vm即解释框架dex opcode不存在还原使用解释引擎的vm文件
脱第一代壳:
内存Dump法
内存中寻找dex.035或者dey.036
/proc/xxx/maps中查找后,手动Dump
文件监视法
Dex优化生成odex
监视文件变化(inotifywait-for-Android)
监视DexOpt输出(notifywait-for-Android)
Hook法
Hook dvmDexFileOpenPartial
定制系统
修改安卓源码并刷机
脱第二代壳:
内存重组法
Dex ZjDroid
对付一切内存中完整的dex,包括壳与动态加载的jar
SO elfrebuild
构造soinfo,然后对其进行重建
Hook法
针对无代码抽取且Hook dvmDexFileOpenPartial失败
Hook dexFileParse
针对无代码抽取且Hook dexFileParse失败
Hook memcmp
定制系统
修改安卓源码并刷机-针对无抽取代码
DexHunter
绕过三进程反调试-修改系统源码
断点mmap调试,针对Hook dexFileParse无效
dexopt优化时,dvmContinueOptimization()->mmap()
静态脱壳机
分析SO壳逻辑并还原加密算法
自定义linker脱SO壳
脱第三代壳:
dex2oat
ART模式下,dex2oat生成oat时,内存中的DEX是完整的
定制系统
Hook Dalvik_dalvik_system_DexFile_defineClassNative
枚举所有DexClassDef,对所有的class,调用dvmDefineClass进行 强制加载
脱第四代壳
so + vmp
阶段发展(换个角度,要从解密后dex文件的状态来看)
静态:dex文件解密后以静态文件存储(如某一个文件夹下的odex文件)
动态:dex文件解密后也在内存中
整体加密:真实、完整的dex出现在内存中
抽取加密:真实、完整的dex从不出现在内存中
对于整体加密和抽取加密,从实现来看,整体加密就是把dex整体隐藏在so中,而抽取加密就是先从so里解密出一个待修复的dex文件,真正的dex从这个文件里抽取部分。
为什么dex从内存中抠出是不完整的?
1.dex内存中不连续(如修改DexHeader结构)
2.dex在内存中执行是以结构体存在的,如果修复时只修复结构体,根本没有修复dex/odex文件本身(如只修复DexMethod结构体)
3.dex文件的一些方法不是事先解密,而是用到再解密,用完就删掉(如百度加固的onCreate方法)
4.dex文件在加载或运行时,被HOOK,解密后,使之一些结构体或一些结构体的一些字段人为改为错误,或删除(如阿里加固对于annotionoff注解字段的处理)
5.dex文件本身就是错的,结构体的字段值错误,或方法是干扰无效的,在加载或运行时,被HOOK,解密修复成正确的,解密后再删掉或继续用错误部分填充。
三代脱壳机实现与关键函数:
规律:无论加固还是脱壳,都往底层发展。
1.dex优化与验证过程(实例:在dexFileParse函数HOOK)
2.虚拟机动态加载打开dex过程
3.dex类加载的过程
脱壳时机总结(DEX文件从打开到方法指令执行前):
1.打开dex文件时
存在dex优化验证时的打开和虚拟机本地native打开两种,分别对应着一代和二代脱壳。
2.加载类时:defineclassnative函数
虽然类加载过程的函数很多,但我们一般脱壳只在defineclassnative函数。
这里列举出类的整个加载过程的函数
defineclassnative函数分析与类加载概念
defineclass函数分析
findnoinit函数分析(包括了dvmLookupClass)
loadClassFromDEX函数分析
loadClassFromDEX0函数分析与解析概念
dvmLinkClass函数分析
loadMethodFromDEX函数分析
3.类的初始化时:dvmIsClassInitialized和dvmInitClass这两个函数
4.查找类FindClass
5.获得方法ID并调用方法 GetStaticMethodID,CallStaticVoidMethod
(其实在GetStaticMethodID执行了类的初始化,可以尝试从这里)
DEX自解析重构技术:
DexHunter介绍
DexHunter使用方法与注意
DexHunter源码详细分析
/dalvik/vm/native/dalvik_system_DexFile.cpp
https://github.com/zyq8709/DexHunter
https://github.com/kesuki/DexHunter
如果你想脱壳一个APP,在运行APP之前,你需要把“dexname”这个文件推入到手机的“/data/”文件夹下。在"dexname"的第一行是特征字符串(参照"slide.pptx").第二行是目标APP所在的数据路径(例如,/data/data/com.example.seventyfour.tencenttest/)。dexname文本必须是linux/Unix的风格形式,如果在windows下输入,则需要用winhex修改换行符的十六进制。你可以使用"logcat"命令获得log日志来判断壳是否已经脱下。一旦完成,生成的"whole.dex"文件就是想要的结果。
特征字符串:
360 /data/data/XXX/.jiagu/classes.dex
Ali /data/data/XXX/files/libmobisecy1.zip
Baidu /data/data/XXX/.1/classes.jar
Bangcle /data/data/XXX/.cache/classes.jar
Tencent /data/app/XXX-1.apk (/data/app/XXX-2.apk)
ijiami /data/data/XXX/cache/.
注意,他本身的系统img是4.4.3,如果想做到版本通用,只需要单单替换system.img就行。一定不能把他原版的img直接文件夹替换,那样模拟器会直接死翘翘。正在上传…重新上传取消
IDA自动插件源码分析与dexhunter比较:
相同点:
1.本质相同,也就是最根本的自解析重构思想和方法一样,都是主要采 用readsignleb128等自解析函数,进行自解析重构;
2.由于两种工具基本原理一样,所以需要升级,改进,和失效、缺陷的 地方,也是类似的;
3.都是类加载时的通用脱壳机,关键原理函数都是defineClassNative 函数。
不同点:
1.直接dump的方法不同,DexHunter用的是strcpy函数,而IDA脱 壳脚本用的是getword函数;
2.相比来言,IDA脱壳脚本重构的更为彻底一点,它把每个结构都进行 重构,把字段全部先初始化为0,然后利用直接dump或自解析重新获 取的办法填充回去;
3.IDA脱壳脚本得到的是一个ODEX,而DexHunter是一个DEX文 件,IDA脱壳脚本还重构了DEXHEADER头结构,修复了magic等字 段,这一点也比DexHunter较好。
4.使用的方式不同,DexHunter使用的方式是HOOK,而且对类进行了 主动一次性加载和初始化,而IDA脱壳脚本是一个脚本,其当初设计的 想法应该是当动态调试时,得到了正确的clazz结构体后,去使用。
5.总的来说,IDA脱壳脚本比DexHunter显得先进一点,但依然不是更 进一步彻底的重构,如annotionoff字段就是直接dump,但这个地方 往往会偏移出错,如阿里加固。
DexHunter升级:
脱壳神器ZjDroid:
1.介绍
zj是一个比较特殊的通用脱壳工具,是第一个利用系统组件漏洞来进行脱壳的脱壳机,也就是发广播,当zj接受到正确广播后,会根据pid,把广播发给pid,另pid进程返回信息。zj之所以特殊,它无法按照我说的划分为第几代脱壳,乃至现在依然可以风骚使用。这对于一个2014年就诞生的脱壳机而言是不可思议的。zj的核心是mcookie文件,而这个文件却介于解密后文件和解密后内存之间的中间状态。如果我们深入系统源码,就会发现cookie会被直接用于类结构体的生成,如果按照此定义,它应属于第2代-第3代脱壳机。但奇妙之处在于,只要存在解密,无论放不放在文件,也无论是解密的是dex还是jar、odex,理所应当都会有一个cookie出现。因此,除非真正的vmp,即完全通过编译器so壳去解释一个完全虚拟的文件或内存中的指令,否则zj都会有效果。zj很强大,但缺点也很明显,太容易被防。如果壳做好了系统组件保护策略,不允许第三方广播,或者对xpossed框架和类似zj插件进行保护,那么zj就无效。
2.zj使用全攻略:
zj不适合模拟器,适合真机,我们的调式机就非常理想,不同机器,运行效率差别很大。
安装xpossed框架:
adb install d:\xpossed.apk
安装框架,软重启
安装zj插件:
adb install d:\ZjDroid.apk
安装插件,勾选模块,软重启
安装目标游戏:
adb install d:\捕鱼达人3.apk
打开一个cmd,专门用于查看动态逆向信息:
adb shell
logcat | grep zjdroid-shell-org.cocos2d.fishingjoy3
记下PID,建议一定要把命令先写好
再打开一个cmd,运行zj命令
adb shell
su
查看内存中存在的dex的cookie信息:
am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{action:dump_dexinfo}'
观察log的cmd窗口,记下选择的dexpath信息,如果有dex就选dex,其次是jar,最后是apk
查看cookie的可加载类,顺便看看是否有自己想要的类:
am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{"action":"dump_class","dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'
dump出dex文件:
am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{"action":"dump_dexfile","dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'
dump出smali文件:
am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{action:backsmali, "dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'
等待一段时间,查看脱壳后的dex和smali文件:
ll /data/data/org.cocos2d.fishingjoy3/files
ll /data/data/org.cocos2d.fishingjoy3/files/smali/
把smali文件夹拷贝到sd卡,然后传到电脑:
adb pull /mnt/sdcard/smali/ d:\1
zj另外还可以:
内存dump,由于我们有dd,和更好的工具,一般不用zj去dump内存:
adb shell am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_mem","start":1234567,"length":123}'
运行自编写lua脱壳插件,找到解密函数,用lua调用java:
由于这需要我们编写lua代码,还要分析解密函数,如果做到了这样,我们有更好的办法去处理,一般也不用运行lua代码
adb shell am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"invoke","filepath":"****"}'
3.zj拓展
做如下修改即可解除一定的防zj保护:
a.在设备上创建特定目录(如/data/local)并 chmod 为777
b.复制zjdroid.apk到该目录,并修改文件名为zjdroid.jar
c.修改/data/data/de.robv.android.xposed.installer/conf/modules.list,模块代码文件修改为zjdroid.jar,然后重启设备即可。
DD大法:
dd if=/dev/zero of=sun.txt bs=1 count=1
if 代表输入文件。如果不指定if,默认就会从stdin中读取输入,/dev/zero 是一个字符设备,会不断返回0值字节(\0)。
of 代表输出文件。如果不指定of,默认就会将stdout作为默认输出。
bs 代表字节为单位的块大小。
count 代表被复制的块数。
抠DEX:
dex是看0x20处找大小,odex是看0x32处就有。
dd if=/proc/2175/mem of=/data/local/tmp/dump.dex skip=3077606936 bs=1 count=43576
GDB调试:
adb push d:\gdbserver /data/local/tmp/gdbserver
adb shell
su
chmod 777 /data/local/tmp/gdbserver
ps | grep com.zyx.wifi
ls /proc/1964/task
/data/local/tmp/gdbserver :31928 --attach 2968
adb forward tcp:31928 tcp:31928
启动本地gdb
target remote :31928
gcore,一直等待完成,时间比较久
b 下断点
c 继续运行到断点
s 等价于step into
n 等价于step over
bt 查看堆栈
info registers查看寄存器内容
info b 查看断点信息
delete break [n] 删除编号为n的断点
disas 0xFFFF,+20 显示这个地址后面 20 行内的汇编指令
kill 终止进程
脱掉梆梆的壳:
梆梆是把原dex文件加密放到了secData0.jar,所以直接拿到dex文件,修复配置文件的程序入口点就可以重打包完美运行。
open、mmap
dexfileopenpartial
dvmRawdexFileOpen
脱掉爱加密的壳:
爱加密在fopen,fget原因
dexfileopenpartial
openDexFileNative
defineClassNative
脱掉360的壳:
1.识别360加固的代数
2.第一代360脱壳:xposed插件脱壳
3.第二代360脱壳:so手动dump并修复、mmap手动脱壳、open+memcmp手动脱壳
4.第三代360脱壳:drizzledumper脱壳、dex2oat脱壳
VM修复:
一个结构,
fix (){
Method
offset
}
结合dex文件结构,opcode,偏移地址
00-FF 0-255
确定00 vm的opcode
00-A8 168
01-A9
02-AA
03-AB
脱掉百度的壳:
1.加密流程:
采用动态加载assets下的baiduprotect.jar。然后采用重写onCreate,用onCreate001代替,onCreate内容为修复onCreate001代码、执行onCreate001代码、清楚onCreate001代码。修复代码不能连续运行两次。
3.采用Hook DexParse来获取Dex相关数据,然后遍历ClassDef将所有onCreate001类直接解码。
4.Dump出修复好的Dex。
5.然而Dump的Dex还要修复(可以根据ClassDef自动修改)
Lcom/baidu/protect/A;->d(Ljava/lang/String;)V->解密方法
Lcom/baidu/protect/A;->e(Ljava/lang/String;)V->加密方法
Lcom/qsq/qianshengqian/XXXXX;->
onCreate001(Landroid/os/Bundle;)V->加解密传入参数
xdex脱壳机与骗出jni_onload的oncreate抽取指令
vm一维置换表和二维置换表
脱掉腾讯的壳:
libart.so
OpenMemory
R1是dex文件的地址,R2是dex文件的大小
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。