Android-课程总结
参考
正己老师的《安卓逆向这档事》
基础知识
与手机建立连接
模拟器
1 | adb connect 127.0.0.1:端口号 |
注意:我的是mumu模拟器,每次都要到多开器里面查看adb端口建立连接,但是正常应该可以直接adb devices&adb shell。模拟器是这样的TT
真机
手机开开发者版本和USB调试,然后通过数据线连接
- 有一些数据线只能充电,第一次连接电脑的时候手机上会弹出要求允许 USB 调试访问。确保你点击了“允许”按钮。
- 如果没弹出就换一根数据线/重启。
1 | adb devices |
文件传输
传文件进windows
1 | adb -s 127.0.0.1:16384 shell pm list packages |
推送文件至模拟器
1 | adb push "D:\LeStoreDownload\网页\frida-clr-16.5.7-windows-x86_64.dll\frida-clr-16.5.7-windows-x86_64.dll" /data/local/tmp/ |
软件安装
1 | adb install a.apk |
初识APK
APK:全称Android Package,相当于压缩文件,把.apk后缀改为.zip就可以解压
- assets目录 :存放apk静态资源,视频图片等。
- lib目录:armeabi-v7a基本通用所有android设备,arm64-v8a只适用于64位的android设备,x86常见用于android模拟器,其目录下的.so文件是c或c++编译的动态链接库文件。
- META-INF目录:存放签名信息,用来验证APK的完整性。
- res文件:资源文件,图片字符串等(会转为二进制格式)
- AndroidMainfest.xml文件:APK的应用清单,描述应用名字版本等
- classes.dex文件:classes.dex是Java源码编码后的java字节码,APK运行的主要逻辑
- resources.arsc:resources.arsc是编译后的二进制资源文件,它是一个映射表,映射着资源和id,通过R文件中的id就可以找到对应的资源
assets和res有什么不同?
assets主要存放的是应用内显示出来的图片,不会转为二进制格式
res是ui设计相关的文件,会转为二进制格式,经过压缩优化
JVM、Dalvik、ART
JVM是JAVA虚拟机,运行JAVA字节码程序
Dalvik是Google专门为Android设计的一个虚拟机,Dalvik有专属的文件执行格式dex(Dalvik executable)
Art(Android Runtime)相当于Dalvik的升级版,本质与Dalvik无异
安卓四大组件
组件 | 描述 |
---|---|
Activity(活动) | 在应用中的一个Activity可以用来表示一个界面,意思可以理解为“活动”,即一个活动开始,代表 Activity组件启动,活动结束,代表一个Activity的生命周期结束。一个Android应用必须通过Activity来运行和启动,Activity的生命周期交给系统统一管理。 |
Service(服务) | Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。 |
Broadcast Receiver(广播接收器) | 一个用于接收广播信息,并做出对应处理的组件。比如我们常见的系统广播:通知时区改变、电量低、用户改变了语言选项等。 |
Content Provider(内容提供者) | 作为应用程序之间唯一的共享数据的途径,Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。Android内置的许多数据都是使用Content Provider形式,供开发者调用的(如视频,音频,图片,通讯录等) |
Activity生命周期
函数名称 | 描述 |
---|---|
onCreate() | 一个Activity启动后第一个被调用的函数,常用来在此方法中进行Activity的一些初始化操作。例如创建View,绑定数据,注册监听,加载参数等。 |
onStart() | 当Activity显示在屏幕上时,此方法被调用但此时还无法进行与用户的交互操作。 |
onResume() | 这个方法在onStart()之后调用,也就是在Activity准备好与用户进行交互的时候调用,此时的Activity一定位于Activity栈顶,处于运行状态。 |
onPause() | 这个方法是在系统准备去启动或者恢复另外一个Activity的时候调用,通常在这个方法中执行一些释放资源的方法,以及保存一些关键数据。 |
onStop() | 这个方法是在Activity完全不可见的时候调用的。 |
onDestroy() | 这个方法在Activity销毁之前调用,之后Activity的状态为销毁状态。 |
onRestart() | 当Activity从停止stop状态恢进入start状态时调用状态。 |
动态调试
1.修改debug权限
方法一:在AndroidManifest.xml里添加可调试权限(在application里)
1 | android:debuggable="true" |
方法二:XappDebug模块hook对应的app
方法三:Magisk命令(重启失效)
1 | 1. adb shell #adb进入命令行模式 |
方法四:刷入MagiskHide Props Config模块
一般来说,在4选项中如果有ro.debuggable那就直接修改
没有的话就选5
修改ro.debuggable的值为1
2.端口转发以及开启adb权限
版本号点击七次开启开发者模式并开启adb调试权限
1 | adb forward tcp:9999 tcp:9999 |
3.下段点
ctrl+b下断点
4.debug模式启动
1 | adb shell am start -D -n com.zj.wuaipojie/.ui.MainActivity |
adb shell am start -D -n
adb shell am start -D -n 包名/类名
am start -n 表示启动一个activity
am start -D 表示将应用设置为可调试模式
5.Jeb附加调试进程
Log插桩
定义:Log插桩指的是反编译APK文件时,在对应的smali文件里,添加相应的smali代码,将程序中的关键信息,以log日志的形式进行输出。
1 | invoke-static {对应寄存器}, Lcom/mtools/LogUtils;->v(Ljava/lang/Object;)V |
smali及其语法
smali是Dalvik的寄存器语言,smali代码是dex反编译而来的。
关键字
名称 | 注释 |
---|---|
.class | 类名 |
.super | 父类名,继承的上级类名名称 |
.source | 源名 |
.field | 变量 |
.method | 方法名 |
.register | 寄存器 |
.end method | 方法名的结束 |
public | 公有 |
protected | 半公开,只有同一家人才能用 |
private | 私有,只能自己使用 |
.parameter | 方法参数 |
.prologue | 方法开始 |
.line xxx | 位于第xxx行 |
数据类型对应
smali类型 | java类型 | 注释 |
---|---|---|
V | void | 无返回值 |
Z | boolean | 布尔值类型,返回0或1 |
B | byte | 字节类型,返回字节 |
S | short | 短整数类型,返回数字 |
C | char | 字符类型,返回字符 |
I | int | 整数类型,返回数字 |
J | long (64位 需要2个寄存器存储) | 长整数类型,返回数字 |
F | float | 单浮点类型,返回数字 |
D | double (64位 需要2个寄存器存储) | 双浮点类型,返回数字 |
string | String | 文本类型,返回字符串 |
Lxxx/xxx/xxx | object | 对象类型,返回对象 |
常用指令
关键字 | 注释 |
---|---|
const | 重写整数属性,真假属性内容,只能是数字类型 |
const-string | 重写字符串内容 |
const-wide | 重写长整数类型,多用于修改到期时间。 |
return | 返回指令 |
if-eq | 全称equal(a=b),比较寄存器ab内容,相同则跳 |
if-ne | 全称not equal(a!=b),ab内容不相同则跳 |
if-eqz | 全称equal zero(a=0),z即是0的标记,a等于0则跳 |
if-nez | 全称not equal zero(a!=0),a不等于0则跳 |
if-ge | 全称greater equal(a>=b),a大于或等于则跳 |
if-le | 全称little equal(a<=b),a小于或等于则跳 |
goto | 强制跳到指定位置 |
switch | 分支跳转,一般会有多个分支线,并根据指令跳转到适当位置 |
iget | 获取寄存器数据 |
寄存器
在smail里所有操作通过寄存器来进行
- 本地寄存器:v开头数字结尾 v0
- 参数寄存器:p开头数字结尾 p0
Q :p0一定是第一个参数吗?
A:在static函数中p0对应第一个参数(因为java语法里没有static语法)
在非static函数中,p0代指 “this”,p1表示函数的第一个参数
实战原理
双开原理
- 修改包名:让手机系统认为这是2个APP实现,改变了应用的签名信息,如果有签名校验则可能闪退崩溃
- 修改Framework
- 通过虚拟化技术实现
- 以插件机制运行:利用反射替换,动态代{过}{滤}理,hook了系统的大部分与system—server进程通讯的函数,以此作为“欺上瞒下”的目的,欺骗系统“以为”只有一个apk在运行,瞒过插件让其“认为”自己已经安装。
去广告
启动广告流程:
- 启动Activity->广告Activity->主页Activity
修改方法:
- 修改加载时间
- Acitivity切换定位,修改Intent的Activity类名
弹窗定位&堆栈分析
修改方法:
1.修改xml中的versiocode
2.Hook弹窗(推荐算法助手开启弹窗定位)
3.修改dex弹窗代码
4.抓包修改响应体(也可以路由器拦截)
布局优化
1.开发者助手抓布局
2.MT管理器xml搜索定位
3.修改xml代码
1 | android:visibility="gone" |