安卓应用程序
Why Android?
-
app - 移动互联网的入口
-
安全研究的交集
-
Android的市场份额
逆向安卓应用的目的?
-
Flag?
-
漏洞?
-
恶意代码
-
好奇心?
认识APK文件
-
清单文件 AndroidManifest.xml
-
xml文件
-
二进制数据
-
内容
-
包名 名称 图标 targetSDK 版本号
-
需要的权限列表
-
使用的组件信息
-
Android应用四大组件
-
Activity 可视界面:生命周期,启动模式
-
Service 服务:前台与后台
-
BroadCast Recevicer 广播:发送接收,静态动态
-
Content Provide 内容提供者: URI 数据库 增删查改
-
-
DEX文件
-
Java -> dex
-
Daivik/ART虚拟机
-
-
Magic: dex.035
-
-
so文件
-
C/C++ -> so
-
JNI
-
第三方库 (opencv、unity)
-
架构: armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64 ...
-
-
签名文件
为什么要签名?
-
防篡改
-
App升级
-
代码或数据共享: QQ&微信&王者荣耀
-
-
META-INF目录
-
MANIFEST.MF 所有文件SHA1/SHA256的base64编码
-
CERT.SF MANIFEST.MF文件SHA1/SHA256的base64编码
-
CERT.RSA/.DES 签名的公钥,SF签名后的数据
修改文件会导致签名发生变化? NO
签名格式 v1 v2
可在此目录中标记渠道号,记录应用市场来源
-
Android应用的逆向分析与技巧
逆技: 一机(root) 一APK 一椅 一钛合金眼
逆向流程:反编译 -》 目标定位 《-》核心目标逆向
类比追女生: 信息搜集 -》 找突破口 《-》核心突破口
1. 反编译
关注文件
-
Manifest 可读的xml文件
-
Res 可读的资源
-
dex Dex -> Smali -> Java
-
so elf -> asm -> C++
-
dex -> smali baksmali -> java
elf -> arm指令 :
-
IDA
-
Radare2
-
Ghidra
Arm指令 -> C++ :
-
IDA F5
-
Ghidra
-
Arm指令是cpu指令,几乎不会出错
2. 定位逆向目标
-
关键字定位
-
字符串关键字
-
代码关键字
-
Grep大法
-
-
资源定位
-
定位UI中资源变量名
-
res目录中寻找改变量对应索引
-
smali
-
-
日志定位
-
adb logcat | grep
-
日志文件
-
app目录下
-
sdcard
-
-
App内置的日志文件
-
重打包
-
hook
-
-
Smali注入 打印字符串
-
-
调用栈跟踪
-
ddms method profiling
-
hook 系统函数打印 callback
-
3. 核心目标逆向
静态分析
-
直接分析smali代码
-
类
-
基本数据类型
-
寄存器
-
函数和函数调用
-
代码块和转跳 goto
-
-
分析伪java代码
-
直接分析arm指令
-
寄存器 SP, PC, LR
-
传参方式 低于4个用寄存器 多用堆栈
-
转跳 B,BL, BX, BLX
-
储存器访问
-
数据处理
-
arm和thumb切换 thumb指令占两个字节
-
-
分析伪C++代码
动态调试
-
Android Studio无源码调试
-
配置APP为可调试状态
-
重打包app,使debuggable为true
-
修改系统设置ro.debuggable的值为1
-
Xposed插件
-
-
反编译apk将smali导入AndroidStudio工程
-
安装smalidea插件
-
-
新建remote调试,并配置好端口
-
以调试模式启动app,开始调试
-
amstar t–D–W-ncom.anything/.someActivity
-D debug -W wait for debuger
-
下断点
-
-
-
IDA调试android so
-
IDA导入so文件
-
root设备上启动android_server
-
adb push/chmod
-
x86/ arm32/ arm64
-
-
IDA新建RemoteAndroidDebuger,配置调试端口
adb forward tcp:23946 tcp:23946
-
选取目标进程,断点调试
-
断点地址=基地址+相对偏移
-
loadso的时候挂起
-
区分arm和thumb
-
-
-
Smali代码注入 (插桩)
-
注入方法
反编译->修改smali代码->重打包
-
使用场景
-
批量打印log
-
控制流分析
-
数据流分析
-
-
可能存在的问题
-
重打包失败
-
签名检查
-
寄存器维护
-
-
-
Hook技术
-
使用场景
-
注入到目标代码,改变执行结果
-
获取某一状态下的变量值
-
-
hook的本质
-
代码注入
-
-
Hook工具
-
Xposed 替换app_process
-
Frida Ptrace注入
-
-
动静结合
Android应用安全保护和对抗
如何保护Android应用?
反编译 => 目标定位 => 核心目标逆向
干扰反编译 代码混淆 反调试 加壳
1. 干扰反编译
-
利用反编译工具的bug或漏洞
-
AndroidManifest.xml
-
dex
-
So
-
-
转换成伪代码时的bug
-
Smali->Java
-
Arm指令->C++
-
-
链接资源文件时的bug
-
特殊的资源文件
-
超长的资源id
-
案例
-
2017年12月,apktool XXE漏洞导致远程代码执行
-
添加大量的无效代码,耗尽反编译工具的CPU
-
添加无效的资源文件,使apktool编译失败
-
资源id越界导致链接时Crash
-
添加特殊编码字符,使反编译工具Crash
对抗
-
反编译时不链接资源文件–no-resource
-
使用新版本的反编译工具
-
分析底层的反编译代码
-
Smali
-
Arm指令
-
-
打造自己的逆向工具链
2. 代码混淆
目的
目的:将代码变得难以阅读
变量名、类名、方法名混淆
-
超长名字 00o0ooo00ooo000ooo
-
相似字符 mabin -> m4bln
-
特定含义的代码 intint = 5
-
特殊编码 ȷava \u0237
-
难以阅读的字符
字符串加密
-
编码
ascii码、Base64、Unicode
-
自己实现的字符串加密
自写函数实现的加密方法
控制流混淆
-
运算混淆 a + b -> a + c/d – c/d + b
-
控制流伪造
-
控制流平坦化
代码混淆工具
-
Java代码
-
ProGuard
-
DexGuard
-
-
C++代码
-
OLLVM
-
混淆带来的问题
-
运行不稳定
-
开发调试困难
-
执行效率低
什么APP会使用混淆
-
受众基础大的APP不会使用“变态”的混淆方式
-
即使混淆,也只是一小部分核心逻辑
-
老版本的APP一般不会混淆
-
纯混淆的CTF题目很无聊
-
企业级的APP
对抗代码混淆
-
变量名、类名、方法名混淆
-
变量重命名jeb、重打包
-
寻找老版本app
-
根据开源代码映射
-
自动化 -> 自动化相似代码检测
-
-
字符串加密
-
静态分析替换
-
动态hook
-
-
控制流混淆
-
优化反编译工具
-
符号执行
-
硬核逆向 状态机、经验、耐心
-
3. 反调试
-
Ptrace
先占坑:自己ptrace自己
-
检测Trace Pid的值
/proc/pid/status 和/proc/pid/task/pid/status
普通状态下,Tracer Pid这项应该为0;调试状态下为调试进程的PID
-
检测调试器
-
进程名
-
gdb_server
-
android-server
-
-
端口号
-
IDA:23946
-
Frida: 27042
-
-
内存特征码
-
-
基于时间的检测
看两段代码之间时间,看是否被下断点
-
多种策略结合
-
多进程ptrace
-
暗桩
-
守护进程
-
断点扫描
-
对抗反调试
-
找到所有的检测点并Patch
-
抢占先机式的Hook
-
开启上帝模式–修改系统
4. 加壳与脱壳
加固
-
Dex加固
-
指令抽取
-
Dex加密
-
Java -> C
-
-
So加固
无源码
-
So加密
-
section 加密
-
函数动态加解密
有源码
-
虚拟机(vmp)
-
各种壳
-
dex加密过程
加固后的APK运行过程
Process.start -> Application创建 -> attachBaseContext -> onCreate -> onStart -> onResume -> Activity生命周期
在程序运行时dump内存
脱壳
Dex脱壳
-
Dex脱壳
-
Hook dex加载函数
-
Dump内存重建dex
-
定制化系统
-
-
脱壳工具
-
dumpDex
-
FDex2
-
Frida
-
So脱壳
-
解密so
-
hook loader
-
修复section
-
dump内存
-
-
vmp
-
硬逆
-
状态机
-
虚拟机入口
-