android-re
Android逆向
apk文件结构
文件 | 解释 |
---|---|
assets目录 | 存放apk的静态资源文件,如视频、音频、图片等。 |
lib/目录 | arm64-v8a 只用于64位的Android设备;armeabi-v7a 基本通用所有Android设备;x86 常见用于安卓模拟器,其目录下的.so 文件是c/c++编译的动态链接库。 |
META-INF目录 | 保存应用的签名信息,相当于apk的身份证。用于验证apk的完整性,即:文件是否被修改。 |
res目录 | 存放资源文件,包括图片、字符串等等。apk的脸蛋由layout文件设计。 |
AndroidManifest.xml |
apk的应用清单信息,描述了应用的名字,版本,权限,引用的库等等信息。相当于元数据(metadata)。 |
classes.dex |
apk运行的主要逻辑。这是java源码编译后生成的java字节码文件。 |
resources.arsc |
编译后的二进制资源文件。它是一个映射表,映射着资源和id,通过id找对应的资源。 |
AndroidManifest.xml
整个应用程序的信息描述文件,定义了应用程序中包含的Activity、Service、Content Provider和BroadcastReceiver组件信息。每个应用程序根目录下包含一个AndroidManifest.xml文件,且文件名不能修改。
属性 | 描述 |
---|---|
versionCode |
版本号,主要用来更新,例如:12 |
versionName |
版本名,给用户看的,例如:1.2 |
package |
包名,例如:com.zj.52pj.demo |
uses-permission android:name="" |
应用权限,例如:android.permission.INTERNET 代表网络权限 |
android:label="@string/app_name" |
应用名称 |
android:icon="@mipmap/ic_launcher" |
应用图标路径 |
android:debuggable="true" |
应用是否开启debug权限 |
应用双开
即一个apk安装两遍,成为两个相同应用程序。
应用汉化
Dalvik、ART
- Dalvik是Google专门为Android设计的一个虚拟机,有其专属的文件格式
.dex
(Dalvik executable) - Art(Android Runtime)相当于Dalvik的升级版,本质与Dalvik无异。
Smali
Smali是Dalvik虚拟机使用的一种汇编语言,通过对Android应用的反编译得来(主要是反编译.dex文件)。常用于安卓应用的逆向工程、分析和修改。
–>Smali语法<–
修改Smali代码逻辑可实现应用破解,例如跳过大会员检测。理解成C#中的IL代码,修改IL代码也能达到变更应用逻辑的效果,只不过修改方式不同:
- IL:C#中需要用到Harmony类库,编写修改IL代码的patch(本质上是c#代码),然后实现运行时修改(动态)。
- Smali:反汇编apk,编辑根目录下
classes.dex
核心逻辑文件,再保存重新签名、覆盖安装应用,是编译时修改(静态)。
安卓四大组件
组件 | 描述 |
---|---|
Activity(活动) | 每个Activity都表示一个界面。如MainActivity主界面。一个安卓应用必须通过Activity来运行和启动,Activity的生命周期交给系统管理。 |
Service(服务) | 在后台执行长时间操作且没有用户界面的组件。如:后台播放音乐、下载文件等。 |
Broadcast Receiver(广播接收器) | 用于接收广播,并做出反应 的组件。常见的系统广播有:通知时区的改变、电量低、语言改变等。 |
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状态时调用状态。 |
跳过广告/弹窗的方法
广告分为:
- 启动广告(开屏广告)
- 弹窗/更新广告
- 横幅广告
开屏广告的流程:启动activity -> 广告activity -> 主页activity
Q:如何找到广告activity的类名?
A:mt管理器 - 左上角三横杠 - Activity记录,打开服务,再进入你的应用,会自动捕捉所有显示过的activity,包括广告的。
方法1 - 修改加载时间
即,通过修改广告activity本身的代码(如将延迟时间设为零)来跳过广告。下例:
1 |
|
- 广告超时跳转 (
jump()
方法)
jump()
方法被用来跳过广告,并且只会在广告页面暂停后跳转。this.hasPaused
用来检查广告是否已经暂停。如果还没有暂停(即广告未跳过),它会跳转到ChallengeThird
活动并关闭当前的AdActivity
。
loadAd()
方法
- 该方法用来启动广告的加载逻辑,并且设置了一个超时定时器(3 秒)。
this.timeoutHandler.sendEmptyMessageDelayed(MSG_AD_TIMEOUT, 3000)
会在 3 秒后发送一个消息 (MSG_AD_TIMEOUT
) 来触发广告跳过。
- Handler 处理超时 (
timeoutHandler
)
timeoutHandler
是一个Handler
,它接收到MSG_AD_TIMEOUT
消息时,会调用jump()
方法来跳过广告。m0timeoutHandler$lambda-0()
这个方法会在消息触发时检查当前窗口是否有焦点,如果有焦点,就调用jump()
跳过广告。
- 生命周期控制
onCreate()
:页面创建时会调用loadAd()
来加载广告并设置 3 秒超时。onRestart()
:当页面重启时,hasPaused
被重置为false
,并立刻调用jump()
跳过广告。onStop()
:当页面停止时,会移除超时消息并标记hasPaused
为true
。onDestroy()
:页面销毁时没有额外逻辑,调用父类的onDestroy()
。
具体方法:
- 修改超时消息的延时:可以减少
MSG_AD_TIMEOUT
的延时,快速跳过广告。
修改这一行:
1 |
|
将3000改成50,但不可改成零。因为若没有延时,消息立即被处理,那么hasPaused
可能还是true
的状态,无法进行jump()
的逻辑。
(通过Smali代码修改)
直接调用跳转:可以通过反射或修改代码,直接在
onCreate()
或onRestart()
中调用jump()
来跳过广告。没试过。。
方法2 - Activity切换定位,修改Intent的Activity类名
Q:如何找到相关类在Smali代码中的引用?
A:1. mt管理器(或np)打开classes.dex
- 搜索原始类名,如
com.zj.wuaipojie.ui.AdActivity
,搜索类型为类名
- 找到正确的类后,长摁 - 复制 - 选择最后一项,如
Lcom/zj/wuaipojie/ui/AdActivity;
这是类在Smali中引用时的名字。 - 将复制的新名字填入搜索框,搜索类型为
代码
下例Intent:
1 |
|
将
1 |
|
中的AdActivity
改成页面Activity即可实现跳过广告。
跳过弹窗法一 - 修改xml中的versionCode
考虑到弹窗有一部分是更新提示,可以改版本号跳过更新检测。即,修改AndroidManifest.xml
中versionCode
和versionName
。
(适用于已知最新版本号的前提)
跳过弹窗法二 - Hook弹窗(算法助手)
(针对那些劫持返回键的弹窗)
算法助手 - 开启对应应用的应用总开关
和UI
下的弹窗定位(返回键可取消)
,再点击右上角的小三角启动应用。被劫持的返回键又能用了!
(屏蔽关键词弹窗)
算法助手 - 开启对应应用的应用总开关
和 UI
下的屏蔽关键词弹窗
,输入弹窗中模糊/精确的关键词,如”广告”,即可一键屏蔽所有使用该关键词的广告!
跳过弹窗法三 - 修改dex代码
step1:定位弹窗位于哪个方法中。可利用 算法助手 - 日志 - 某个Dialog弹窗 - 调用堆栈
查看。
step2:一般弹窗需要调用 xxxDialog.show()
方法才能显示。因此把Smali中调用.show()
方法的语句注释掉即可。
跳过横幅广告的方法
step1: 开发助手 - 布局查看(需启用无障碍权限)- 切到横幅应用 - 点击悬浮窗上的放大镜图标 - 定位横幅广告 - 复制View Id(Hex)
step2: mt管理器 - 进入目标应用apk - XML搜索
- 搜索刚刚复制的View Id
(十六进制,搜索类型 资源ID
)
下例:
1 |
|
要跳过横幅,只需把宽高全调成0dp
即可。
Jeb Decompiler
一款安卓的反编译工具,可进行动态调试。
利用 Jeb 动态调试
简记一个步骤。
打开安卓usb调试功能。设置 - 点击版本号7次进入开发者选项 - 启用
USB调试
设置应用可调试权限(debuggable)。打开
AndroidManifest.xml
- 添加android:debuggable="true"
- 保存覆盖安装pc命令行输入adb指令。
1
2
3
4adb shell am start -D -n 包名/类名
例如:
adb shell am start -D -n com.zj.wuaipojie/.ui.MainActivity打开jeb,拖入应用apk反编译。点击
开始
图标开始调试。确保进程名和你的应用一致(图中为
com.zj.wuaipojie
),点击附上
。正式开始调试。光标停在某一行smali字节码上,
ctrl+B
下断点。
Log插桩
Log插桩指的是反编译APK文件时,在对应的smali文件里,添加相应的smali代码,将程序中的关键信息,以log日志的形式进行输出。