安卓逆向概要-Android逆向
1、工具的技巧
Jadx-gui工具
搜索中文
首先需要在首选项那里将设置Unicode 字符转义关闭。
开发者助手
根据布局ID来定位程序
通过开发者助手的定位ID
在mt管理器dex文件中搜索ID,搜索类型选择整数。
算法助手
自定义hook
在jeb中,在方法悬浮,可以看到详细信息。
1 | org.json.JSONObject.has(java.lang.String) : boolean |
在算法助手中填写,参考文章如下:
APP攻防–安卓逆向&JEB动态调试&LSPosed模块&算法提取&Hook技术 - 了了青山见 - 博客园。
ida
ida动态调试
前置信息
函数的基本介绍:
| 函数名 | 描述 |
|---|---|
android_dlopen_ext() 、dlopen()、do_dlopen() |
这三个函数主要用于加载库文件。android_dlopen_ext 是系统的一个函数,用于在运行时动态加载共享库。与标准的 dlopen() 函数相比,android_dlopen_ext 提供了更多的参数选项和扩展功能,例如支持命名空间、符号版本等特性。 |
find_library() |
find_library() 函数用于查找库,基本的用途是给定一个库的名字,然后查找并返回这个库的路径。 |
call_constructors() |
call_constructors() 是用于调用动态加载库中的构造函数的函数。 |
init |
库的构造函数,用于初始化库中的静态变量或执行其他需要在库被加载时完成的任务。如果没有定义init函数,系统将不会执行任何动作。需要注意的是,init函数不应该有任何参数,并且也没有返回值。 |
init_array |
init_array是ELF(Executable and Linkable Format,可执行和可链接格式)二进制格式中的一个特殊段(section),这个段包含了一些函数的指针,这些函数将在main()函数执行前被调用,用于初始化静态局部变量和全局变量。 |
jni_onload |
这是Android JNI(Java Native Interface)中的一个函数。当一个native库被系统加载时,该函数会被自动调用。JNI_OnLoad可以做一些初始化工作,例如注册你的native方法或者初始化一些数据结构。如果你的native库没有定义这个函数,那么JNI会使用默认的行为。JNI_OnLoad的返回值应该是需要的JNI版本,一般返回JNI_VERSION_1_6。 |
下断点时机:
应用级别的:java_com_XXX;
外壳级别的:JNI_Onload,.init,.init_array(反调试);
系统级别的:fopen,fget,dvmdexfileopen(脱壳);
ida调试流程
ida前置操作:
1.在IDA目录下的dbgsrv,选择跟手机架构一致的server
2.adb push as /data/local/tmp/
移动后将android_server64重命名为as,修改as权限为可执行。
3.进入手机端命令:adb shell
4.切换获取手机的root权限:su
5.跳到对应路径:cd /data/local/tmp/
6.提权:chmod 777 as
7.XappDebug hook(手机里打开这个app,把需要破解的软件开了)
闪退的话,在mt管理器中运行命令终端,setenforce 0 就可以解决问题。
可以先通过下面命令确认问题:
调试确认SELinux问题
为了澄清是否因为SELinux导致的问题,可先执行:
1 | setenforce 0 (临时禁用掉SELinux) |
如果问题消失了,基本可以确认是SELinux造成的权限问题,需要通过正规的方式来解决权限问题。
遇到权限问题,在logcat或者kernel的log中一定会打印avc denied提示缺少什么权限,可以通过命令过滤出所有的avc denied,再根据这些log各个击破:
1 | cat /proc/kmsg | grep avc |
或
1 | dmesg | grep avc |
8.运行端口转发
第一个bat脚本:
1 | @echo on %关闭回显命令% |
第二个bat脚本:
1 | @echo on %关闭回显命令% |
com.zj.demo/.ui.ChallengeEight(是类的启动类)
8.1 运行二个bat脚本。
8.2将程序的so拉到ida中,下断点。
8.3 选择调试器
8.4 点击进程选项
8.5 选择主机名以及端口。
8.6 接着附加到进程
- 7 输入搜索包名
8.8 选择要附加的进程
成功使用ida调试。
其他问题
qtscrcpy无法触控手机问题解决方案
开启USB安装,USB调试(安全设置)既可。
ida脚本
放到plugins目录下,然后右在ida中键就会有的
frida
建议下载16.1.0版本,新版本的函数名做了更新,一些就的函数无法使用
workon查看环境
1 | workon |
进入环境,要CMD才行的
1 | workon 环境名 |
查看手机是什么cpu
1 | adb shell getprop ro.product.cpu.abi |
所以要将arm64位的下载下来
将frida服务端放到/data/local/tmp目录下
1 | adb push .\frida-server-16.1.0-android-x86 /data/local/tmp/ |
修改文件权限,要可执行
adb进入手机shell
1 | adb shell |
此时已经运行了frida了
在
1 | C:\Users\用户名\Envs\fribatest\Scripts |
下运行
1 | frida-ps -U |
frida-ps -U为查看手机运行进程,下面的-U wuaipojie中的wuaipojie就是手机运行的进程来着。
如果运行成功,说明server端已经安装完成。
1 | D:\reserve\Andriod\WORKON_HOME\fribatest\Scripts\frida.exe -U wuaipojie -l hook.js |
Android studio
Android studio代理设置
代理设置如下图所示:
2、逆向功能实现
每个页面都是一个activity,页面的跳转可以通过修改类来实现。
可以通过修改xml文件来跳转。
也可以通过修改dex文件的代码逻辑来修改。
去除广告
通过lsposed加载算法助手,在模块中点击算法助手,接下来选择想要hook的app,勾选。接着打开算法助手,在应用栏中选择需要hook的app,点击应用总开关,接着选择弹窗定位,返回键可取消。‘
横幅广告
算法助手选择布局查看,然后复制图片的ID,在mt管理器或者np管理器(推荐MT文件管理器VIP会员版 2.14.5)中选择XML搜索。
搜索类型选择资源ID。
动态调试
搜索按钮:
搜索出来后右键解析,既可转换成代码。
下断点
手机开启adb权限
.debug模式启动
1 | adb shell am start -D -n com.zj.demo/.ui.MainActivity |
- adb shell am start -D -n
- adb shell am start -D -n 包名/类名
- am start -n 表示启动一个activity
- am start -D 表示将应用设置为可调试模式
类名在在AndroidManifest.xml里查看,去掉前面的报名就是类名了。
命令运行上面的adb代码。
1 | adb shell am start -D -n com.zj.demo/.ui.MainActivity |
点击附上,图如下:
成功后,看局部变量。截图如下:
然后在手机上运行程序,触发一下断点。
注意事项
Xappdebug的系统框架需要勾选起来,需要重新开机。
3、逆向的基础知识点
3.1、签名
目前签名分成v1-v4
Android 目前支持以下四种应用签名方案:
- v1 方案:基于 JAR 签名。
- v2 方案:APK 签名方案 v2(在 Android 7.0 中引入)
- v3 方案:APK 签名方案 v3(在 Android 9 中引入)
- v4 方案:APK 签名方案 v4(在 Android 11 中引入)
过签名
绕过针对dex中签名检验
首先就是重新签名原来的app,安装后,签名校验的定位,就是通过算法助手,开启log捕获,利用app的签名不对闪退的机制来获取日志,
点击算法助手的右上开始,捕获log日志。
在log中找到获取到校验签名的方法。
然后在mt管理器中在dex文件搜索
签名校验的方法名,找到对应的逻辑,通过Jadx-gui编译成java代码方便查看后再看dex中修改相关逻辑,可以通过修改函数的最后返回值。
io重定向过签名检验
在apk读取安装包信息的时候,让其读取原来的APk安装包,这样就不会有任何问题了。
3.2、Xposed介绍
什么是Xposed?
Xposed是一款可以在不修改APK的情况下影响程序运行的框架,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。在这个框架下,我们可以编写并加载自己编写的插件APP,实现对目标apk的注入拦截等。
参考文章:正己
Xposed原理
用自己实现的app_process替换掉了系统原本提供的app_process,加载一个额外的jar包,入口从原来的: **com.android.internal.osZygoteInit.main()被替换成了: de.robv.android.xposed.XposedBridge.main()**,
创建的Zygote进程就变成Hook的Zygote进程了,从而完成对zygote进程及其创建的Dalvik/ART虚拟机的劫持(zytoge注入)
Xposed的发展及免root框架
| 名称 | 地址 | 支持版本 | 是否免root |
|---|---|---|---|
| xposed | https://github.com/rovo89/Xposed | 2.3-8.1 | 否 |
| EDXposed | https://github.com/ElderDrivers/EdXposed | 8.0-10 | 否 |
| LSPosed | https://github.com/LSPosed/LSPosed | 8.1-13 | 否 |
| VirtualXposed | https://github.com/android-hacker/VirtualXposed | 5.0-10.0 | 是 |
| 太极 | https://www.coolapk.com/apk/me.weishu.exp | 5.0-13 | 是 |
| 两仪 | https://www.coolapk.com/apk/io.twoyi | 8.1-13 | 是 |
| 天鉴 | https://github.com/Katana-Official/SPatch-Update | 6-10 | 是 |
Xposed可以做什么?
1.修改app布局:上帝模式
2.劫持数据,修改参数值、返回值、主动调用等。例:微信防撤回、步数修改、一键新机
应用变量
Xposed环境配置
前置
ubuntu虚拟机镜像,感谢沐阳哥提供的镜像!!!
内置:
Frida开发环境- 动态分析及开发工具:android-studio
- 动态分析工具:ddms
- 静态分析工具:jadx1.4.4
- 动静态分析工具:jeb
- 动态分析工具:集成HyperPwn
- 静态分析工具:010 editor
- 抓包工具:Charles
- 抓包工具:WireShark
- 动态分析工具:unidbg
vm虚拟机:https://www.vmware.com/cn/products/workstation-pro/workstation-pro-evaluation.html
(或下载我打包好的)
激活码自行百度哦
第一步,安装虚拟机调整路径,输入激活码
第二步,导入镜像,文件->打开->选择解压好的镜像
第三步,点击运行,待初始化,输入密码:toor
- Android Studio创建新项目
- 将下载的xposedBridgeApi.jar包拖进libs文件夹
- 右击jar包,选择add as library
- 修改xml文件配置
1 | <!-- 是否是xposed模块,xposed根据这个来判断是否是模块 --> |
5.修改build.gradle,将此处修改为compileOnly 默认的是implementation
1 | implementation 使用该方式依赖的库将会参与编译和打包 |
6.新建–>Folder–>Assets Folder,创建xposed_init(不要后缀名):只有一行代码,就是说明入口类
7.新建Hook类,实现IXposedHookLoadPackage接口,然后在handleLoadPackage函数内编写Hook逻辑
1 | import de.robv.android.xposed.IXposedHookLoadPackage; |
继承了IXposedHookLoadPackag便拥有了hook的能力
Xpoosed常用API
An efficient Hook API and Xposed Module solution built in Kotlin
1.Hook普通方法
修改返回值
1 | XposedHelpers.findAndHookMethod("com.zj.wuaipojie.Demo", loadPackageParam.classLoader, "a", String.class, new XC_MethodHook() { |
修改参数
1 | XposedHelpers.findAndHookMethod("com.zj.wuaipojie.Demo", loadPackageParam.classLoader, "a", String.class, new XC_MethodHook() { |
2.Hook复杂&自定义参数
1 | Class a = loadPackageParam.classLoader.loadClass("类名"); XposedBridge.hookAllMethods(a, "方法名", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); } }); |
3.Hook替换函数
1 | Class a = classLoader.loadClass("类名") |
4.Hook加固通杀
1 | XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() { |
3.3、ELF文件
ELF(Executable and Linkable Format)是一种可执行和可链接的文件格式,是linux底下二进制文件,可以理解为windows下的PE文件,在Android中可以比作SO,方便函数的移植,在常用于保护Android软件,增加逆向难度。
ELF文件的主要组成部分包括:
- ELF Header:文件头,描述文件的基本信息
- Program Header Table:程序头表,描述进程映像的布局
- Section Header Table:节区头表,描述文件的各个节区
| 节区名 | 描述 |
|---|---|
| .text | 代码段,存放程序的指令 |
| .data | 数据段,存放已初始化的全局变量和静态变量 |
| .rodata | 只读数据段,存放只读数据 |
| .bss | 未初始化数据段,存放未初始化的全局变量和静态变量 |
| .symtab | 符号表,存放符号信息 |
| .strtab | 字符串表,存放字符串数据 |
| .dynsym | 动态符号表,存放动态链接需要的符号信息 |
| .dynamic | 动态链接信息,存放动态链接器需要的信息 |
3.4、NDK开发
NDK(Native Development Kit)是一套用于开发Android应用程序的工具集,它允许您在C/C++中编写性能关键的部分代码,并将这些代码与Java代码进行连接。
步骤:
1.下载NDK和CMake
2.新建一个项目,往下拉,找到”c++”这个选项
3.查看CMakeLists.txt和编写native-lib.cpp
下面是cmakelist.txt和native-lib.cpp文件的作用以及简要说明:
| 文件名 | 作用 | 说明 |
|---|---|---|
| CMakeLists.txt | 构建配置文件 | CMakeLists.txt是用于配置NDK项目的构建系统的文件。它指定了构建所需的源文件、依赖项、编译选项等。在构建过程中,CMake会根据该文件的指示生成对应的构建脚本,用于编译本地代码并生成本地库。 |
| native-lib.cpp | 本地代码实现文件 | native-lib.cpp是包含本地代码实现的文件。它定义了通过Java和本地代码之间进行通信的本地方法。该文件中的函数实现将被编译为本地库,供Java代码调用。 |
1 | public class MainActivity extends AppCompatActivity { |
1 | # For more information about using CMake with Android Studio, read the |
1 |
|
JNI的前世今生
NDK是开发套件,JNI才是调用的框架。所以与其说是NDK开发,不如说是JNI的开发。不过NDK是Android提供的开发套件。JNI可不是,JNI全称Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。
JNI的两种注册方式
jni静态注册方式
1 |
|
数据类型
下面是一些常见的C++数据类型和它们在Java中的对应关系,以及它们在JNI动态注册中的数据类型签名(signature):
| C++ 数据类型 | Java 数据类型 | JNI 数据类型签名 |
|---|---|---|
| jint | int | “I” |
| jboolean | boolean | “Z” |
| jbyte | byte | “B” |
| jchar | char | “C” |
| jshort | short | “S” |
| jlong | long | “J” |
| jfloat | float | “F” |
| jdouble | double | “D” |
| jobject | Object | “Ljava/lang/Object;” |
| jstring | String | “Ljava/lang/String;” |
| jarray | Array | “[elementType” |
| jobjectArray | Object[] | “[Ljava/lang/Object;” |
| jbooleanArray | boolean[] | “[Z” |
| jbyteArray | byte[] | “[B” |
| jcharArray | char[] | “[C” |
| jshortArray | short[] | “[S” |
| jintArray | int[] | “[I” |
| jlongArray | long[] | “[J” |
| jfloatArray | float[] | “[F” |
| jdoubleArray | double[] | “[D” |
在JNI动态注册中,需要使用正确的数据类型签名来声明本地方法。例如,如果你要注册一个返回int类型的本地方法,其数据类型签名应为I。
4、逆向实战
去广告
关键字:initsdk、loadad、initad等
| 广告关键词 | 厂商 | 文档 |
|---|---|---|
| com.qq.e.ads | 腾讯优量汇广告 | https://developers.adnet.qq.com/doc/android/union/union_splash |
| CSJAD、TTAdSdk、bytedance、pangolin | 穿山甲广告 | https://www.csjplatform.com/supportcenter/5395 |
| ADMob、google.ads | 谷歌广告 | https://developers.google.com/admob/android/app-open?hl=zh-cn#extend |
| TorchAd | 360广告 | https://easydoc.soft.360.cn/doc?project=186589faed863b0a24f15f9bcbafd5c7&doc=2cbbbe19c5cb90f5e7a41c7037b0029a&config=title_menu_toc |
| kwad | 快手广告 | https://u.kuaishou.com/home/help/detail/1334/1370/1310 |
| baidu.mobads | 百度广告 | http://bce.ssp.baidu.com/mssp/sdk/BaiduMobAds_MSSP_bd_SDK_android_v5.1.pdf |
| MimoSdk | 米盟广告 | https://t5.a.market.xiaomi.com/download/AdCenter/0d3a369516ee146e8a9d5c290985939da4624fe0a/AdCenter0d3a369516ee146e8a9d5c290985939da4624fe0a.html |
| sigmob.sdk | sigmob广告 | https://doc.sigmob.com/#/Sigmob%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/SDK%E9%9B%86%E6%88%90%E8%AF%B4%E6%98%8E/Android/SDK%E6%8E%A5%E5%85%A5%E9%85%8D%E7%BD%AE/ |
| TradPlus | TradPlus聚合广告 | https://service.cocos.com/document/zh/tradplusad.html |
通过免广告关键字来实现部分广告的去除。
首先通过mt的activity的监听器监听启动类,在jadx-ui中分析相关的广告类启动器,在mt中直接注释掉就行了。
签名校验
先对app重新签名,app会闪退,在算法助手里打开app的闪退拦截,在日志里分析拦截的包是哪个类触发的,跟踪这些代码,使其方法放回空。
去掉更新弹窗
首先使用算法助手打开弹窗定位
布局优化
使用开发助手
获取日志后查看其方法名,在电脑上jadx中分析就行了。
5、其他问题
无法解决adb调试问题,APP闪退
- 调试确认SELinux问题
为了澄清是否因为SELinux导致的问题,可先执行:
1 | setenforce 0 (临时禁用掉SELinux) |
如果问题消失了,基本可以确认是SELinux造成的权限问题,需要通过正规的方式来解决权限问题。
frida17版本和17以下的版本特性不同,函数名称已改变
端口占用
发生下面问题
phoenix:/data/local/tmp # ./frida-server-14.2.18-android-arm64
Unable to start: Error binding to address 127.0.0.1:27042: Address already in use
解决方法:
1 | ps -ef | grep frida |












































