0x00 smali及其语法
smali是Dalvik的寄存器语言,smali代码是dex反编译而来的。
Smali是Dalvik虚拟机和ART运行时的寄存器指令语言,相当于Android平台的汇编语言。当APK被反编译时,DEX文件会转换为Smali代码(.smali文件),它是逆向分析的核心载体。
关键字
| 名称 | 注释 |
|---|---|
| .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 | 获取寄存器数据 |
“vip终结者”
-
定位方法:
搜索弹窗关键字(用jd-gui搜索字符串)、抓取按钮id(本质与前一个方法一样)
(字符串有时候是用unicode显示,搜关键文字搜不到的话可以试试搜对应的unicode)
(此处演示的是抓取按钮id)

-
修改方法:
修改判断、强制跳转、修改寄存器的值 (这里与反调试中修改标志位或者修改跳转指令类似)
demo代码例子(注释为正己所写):
|
|
寄存器机制
- 命名规则:
v0-vN本地寄存器,p0-pN参数寄存器- 关键特性:
- 非静态方法中
p0固定表示this指针- 静态方法中
p0对应第一个参数- 64位类型(long/double)占用两个连续寄存器(如v0-v1)

这里可以切换成Smali语言(但是java代码更好看一点)
0x02 activity的切换
| 组件 | 描述 |
|---|---|
| Activity(活动) | 在应用中的一个Activity可以用来表示一个界面,意思可以理解为“活动”,即一个活动开始,代表 Activity组件启动,活动结束,代表一个Activity的生命周期结束。一个Android应用必须通过Activity来运行和启动,Activity的生命周期交给系统统一管理。 |
| Service(服务) | Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。 |
| Broadcast Receiver(广播接收器) | 一个用于接收广播信息,并做出对应处理的组件。比如我们常见的系统广播:通知时区改变、电量低、用户改变了语言选项等。 |
| Content Provider(内容提供者) | 作为应用程序之间唯一的共享数据的途径,Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。Android内置的许多数据都是使用Content Provider形式,供开发者调用的(如视频,音频,图片,通讯录等) |
广告拦截实战
-
启动广告流程: 启动Activity->广告Activity->主页Activity
-
修改方法:
-
1.修改加载时间
此小节中用到了mt管理器的Activity管理器,可以用于记录广告用到的AdActivity类

然后通过类名搜索可以定位到代码位置

转换成java

阅读java代码,然后可以知道有一个3000毫秒广告显示时间,退回到smali代码中修改为零即可。
-
-
2.Acitivity切换定位,修改Intent的Activity类名(直接在AndroidManifest.xml文件中修改)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31<!---声明实现应用部分可视化界面的 Activity,必须使用 AndroidManifest 中的 <activity> 元素表示所有 Activity。系统不会识别和运行任何未进行声明的Activity。-----> <activity android:label="@string/app_name" android:name="com.zj.wuaipojie.ui.MainActivity" android:exported="true"> <!--当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动--> <!---指明这个activity可以以什么样的意图(intent)启动---> <intent-filter> <!--表示activity作为一个什么动作启动,android.intent.action.MAIN表示作为主activity启动---> <action android:name="android.intent.action.MAIN" /> <!--这是action元素的额外类别信息,android.intent.category.LAUNCHER表示这个activity为当前应用程序优先级最高的Activity--> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.zj.wuaipojie.ui.ChallengeFirst" /> <activity android:name="com.zj.wuaipojie.ui.ChallengeFifth" android:exported="true" /> <activity android:name="com.zj.wuaipojie.ui.ChallengeFourth" android:exported="true" /> <activity android:name="com.zj.wuaipojie.ui.ChallengeThird" android:exported="false" /> <activity android:name="com.zj.wuaipojie.ui.ChallengeSecond" android:exported="false" /> <activity android:name="com.zj.wuaipojie.ui.AdActivity" />
-
3.在classes.dex文件中查找并修改


图一为之前的查找内容,图二是类的一个smali路径代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24switch (position) { case 0: Intent intent = new Intent(); intent.setClass(it.getContext(), ChallengeFirst.class); it.getContext().startActivity(intent); return; case 1: Intent intent2 = new Intent(); intent2.setClass(it.getContext(), ChallengeSecond.class); it.getContext().startActivity(intent2); return; case 2: Intent intent3 = new Intent(); //new一个Intent, intent3.setClass(it.getContext(), AdActivity.class); //传入要切换的Acitivity的类名 it.getContext().startActivity(intent3); //启动对应的Activity return; case 3: Intent intent4 = new Intent(); intent4.setClass(it.getContext(), ChallengeFourth.class); it.getContext().startActivity(intent4); return; default: return; }
0x03 Activity生命周期
| 函数名称 | 描述 |
|---|---|
| onCreate() | 一个Activity启动后第一个被调用的函数,常用来在此方法中进行Activity的一些初始化操作。例如创建View,绑定数据,注册监听,加载参数等。 |
| onStart() | 当Activity显示在屏幕上时,此方法被调用但此时还无法进行与用户的交互操作。 |
| onResume() | 这个方法在onStart()之后调用,也就是在Activity准备好与用户进行交互的时候调用,此时的Activity一定位于Activity栈顶,处于运行状态。 |
| onPause() | 这个方法是在系统准备去启动或者恢复另外一个Activity的时候调用,通常在这个方法中执行一些释放资源的方法,以及保存一些关键数据。 |
| onStop() | 这个方法是在Activity完全不可见的时候调用的。 |
| onDestroy() | 这个方法在Activity销毁之前调用,之后Activity的状态为销毁状态。 |
| onRestart() | 当Activity从停止stop状态恢进入start状态时调用状态。 |

0x04 弹窗定位&堆栈分析
修改方法:
1.修改xml中的versioncode

2.Hook弹窗(推荐算法助手开启弹窗定位)
-
这里demo中的广告返回键被劫持,只能跟着广告走,就需要hook

3.修改dex弹窗代码
在算法助手里找到最新的日志,找到对应打方法名,然后搜索查找对应->show()代码,删掉或者注释掉就行

4.抓包修改响应体(也可以路由器拦截)
0x05 布局优化
1.开发者助手抓布局
2.MT管理器xml搜索定位
3.修改xml代码
- 用的软件:开发助手(可以识别到图片信息),通过搜索Veiw id(hex),可以查找到对应的xml文件,注意这里是xml文件不是之前的dex文件里搜索。


此处既可以修改图片显示的长宽,也可以通过加入下面这段代码隐藏(布局隐藏,文字图片都可以隐藏)。
|
|