Cydia是由Jay Freeman(saurik)领导、Okori Group及加州大学圣巴巴拉分校(UCSB)合作开发的,专为使用iPhone、iPad等苹果设备的越狱用户提供的类似于App Store的软件商店,以方便用户安装不被App Store接受的程序。它也是一个软件仓库的聚合器,包含几个被社区信任的源,大部分软件包的稳定版本都可以在这些源中找到,不过用户也可以自定义添加软件。
要安装Cydia,首先需要对苹果设备进行越狱,只有越狱后的设备才能正常使用Cydia,如图2-1所示。
图2-1 iPhone越狱
如图2-2所示,Cydia主页下方的工具栏共5个图标,分别是“Cydia”“软件源”“变更”“已安装”“搜索”,下面说明其具体功能。
图2-2 Cydia主页
❑Cydia:点击该图标即进入Cydia主页。该页面与App Store类似,包含一些热门deb软件的介绍和说明。其中,右上角的“重建加载”键,用于在页面显示不正常时重刷加载页面。主页页面最底部显示的是当前设备类型、系统版本、Cydia版本等信息。
❑软件源:一个deb软件库的索引。单击右上角的“编辑”,然后单击左上角的“添加”,在源地址输入栏中输入正确的源地址,再单击“添加源”,即可完成对软件源的添加,如图2-3所示。
图2-3 添加软件源
❑变更:点击该图标,显示Cydia中已添加的软件源列表中软件的版本变化情况。如图2-4所示,可根据实际情况对已安装软件进行更改。
图2-4 软件变更
❑已安装:通过Cydia安装的软件都会在此处展示,可以对已安装的软件进行卸载、更新等操作,如图2-5所示。
图2-5 软件卸载
❑搜索:可以搜索需要安装的软件名字。如果搜索所需的软件无果,则可以在添加包含该软件的软件源后重新搜索。
如果设备越狱后依然无法正常使用Cydia,则可尝试通过爱思助手安装由Electra越狱团队发布的Sileo作为替代。
Magisk是由吴泓霖开发的一套开放源代码的Android(5.0以上版本)自定义工具,内置了Magisk Manager(图形化管理界面)、Root管理工具、SELinux补丁等功能。Magisk同时提供了在不修改系统文件的情况下更改/system或/vendor分区内容的接口。利用其与Xposed类似的模块系统,开发者可以对系统进行修改或对所安装的软件功能进行修改等。
本节主要介绍如何使用Magisk对Android设备进行Root操作。这就先要对设备的BootLoader状态进行解锁,只有解锁后才可以通过刷机等一系列操作完成Root。现在国内大部分手机厂商已经彻底关闭了BootLoader解锁方式。因此这里使用Google生产的Pixel系列手机进行Root操作演示。
将手机的BootLoader状态解锁,在开发者模式下开启OEM unlocking,如图2-6所示。
图2-6 开启OEM unlocking
进入BootLoader模式:
adb reboot bootloader
在BootLoader模式下解锁BootLoader程序,根据屏幕提示进行如下操作:
fastboot flashing unlock 或 fastboot oem unlock
在Google官网中下载设备对应的系统镜像:https://developers.google.com/android/images# taimen。解压缩镜像文件,将其中的boot.img推送到手机的SD卡中,安装Magisk,并对boot.img进行patch(打补丁)操作。Magisk会将处理后的boot.img存放在/sdcard/Download目录中,并重命名为magisk_patched-xxxx.img。具体操作流程如图2-7所示。
图2-7 修改boot.img
将修补后的boot.img文件复制到本地计算机,接着将该文件临时写入需要进行Root操作的设备中。
adb pull /sdcard/Download/magisk_patched-23000_T5HA4.img .
adb reboot bootloader
fastboot boot magisk_patched-23000_T5HA4.img
如图2-8所示,重启设备后进入系统,Magisk应该已经成功安装。如果Magisk显示未安装,则可能是安装失败,需要按照之前的步骤重新尝试。但成功安装Magisk后获取的Root权限为临时Root权限,为了转为永久Root权限,要进入Magisk主页,选择Install(选择安装)→Direct Install(直接安装),安装完成后选择Reboot(重启设备)。重启完成后,设备的临时Root权限将被转换为永久Root权限。
图2-8 Android设备Root
除此之外,还可以通过命令行将经过补丁处理的boot.img文件直接写入需要进行Root操作的设备中以获取永久Root权限。但该boot.img文件需要与目标系统的设备完全匹配,否则可能导致系统无法启动或Wi-Fi无法连接。因此,建议优先使用Magisk获取永久Root权限。
adb pull /sdcard/Download/magisk_patched-23000_T5HA4.img .
adb reboot bootloader
fastboot flash boot magisk_patched-23000_T5HA4.img
至此,彻底完成了设备的Root工作。之后我们可以在此设备上任意安装所需工具。
EdXposed是一款适用于Android系统的Hook框架。它是基于Riru构建的ART Hook框架,最初用于Android Pie。EdXposed使用YAHFA或SandHook技术进行Hook操作,支持Android 8到Android 11的系统版本。它提供了与原版Xposed相同的XposedBridge API,可在Android高权限模式下运行,并在不修改App文件的情况下修改程序的运行情况。基于EdXposed,开发者可以创建许多功能强大的Xposed模块,且这些模块能在功能不冲突的情况下同时运作。
前面对Android设备进行Root操作时已经了解了如何安装Magisk。EdXposed可通过Magisk进行安装,在其模块功能中搜索Riru和EdXposed模块并选择适配自己系统的版本进行安装。同时安装EdXposed Manager客户端方便后续管理EdXposed插件。打开EdXposed Manager,软件首页中提示“EdXposed框架已激活”,说明EdXposed框架已经成功安装到当前的设备中。如果提示未激活,则可能是因为选择的Riru和EdXposed模块版本与当前系统不匹配,在Magisk中删除已经安装的模块,重新下载对应版本的模块即可。EdXposed安装成功后如图2-9所示。
图2-9 安装EdXposed框架
EdXposed框架提供了与原版Xposed框架相同的XposedBridge API,因此基于该框架编写的模块与原版Xposed框架编写的模块是完全兼容的。因为这两个Hook框架使用的API相同,所以EdXposed框架的使用方法和Xposed框架是一致的。如果之前已有Xposed模块的开发经验,则可以略过后面的教程,直接进行EdXposed模块开发。
创建Xposed的模块时可根据交互情况选择工程模板。此处为了让大家快速上手Xposed模块的开发,会通过简单的不需要交互的范例进行讲解。首先,通过Android Studio创建一个No Activity的工程,如图2-10所示。
图2-10 创建Xposed工程
此时创建的为普通Android应用工程,接下来需要在工程的AndroidManifest.xml文件中增加以下3个属性值,用于将该应用转化为Xposed模块:
# 标记该应用为Xposed模块,用于Xposed框架识别
<meta-data android:name="xposedmodule" android:value="true" />
# 对该Xposed模块的描述
<meta-data
android:name="xposeddescription"
android:value="Edxposed demo!" />
# 模块支持的最低API版本
<meta-data android:name="xposedminversion" android:value="54" />
添加完属性值的AndroidManifest.xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hook.xposed">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="Edxposed Xposed Test" />
<meta-data
android:name="xposedminversion"
android:value="54" />
</application>
</manifest>
有两种添加XposedBridge API开发依赖的方式。
1)通过Gradle添加,即在该工程的app目录下的build.gradle文件中添加开发时所需的XposedBridge API环境,如下:
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
}
在工程根目录的settings.gradle的repositories属性中增加如下配置项:
repositories {
jcenter()
}
2)下载XposedBridgeApi-82.jar,将该JAR包放置到工程app目录下的libs文件中,以添加开发时所需的XposedBridge API环境,同时在build.gradle文件中进行如下配置:
dependencies {
compileOnly files('libs/XposedBridgeApi-82.jar')
}
配置Hook模块的入口,用于通知EdXposed框架该模块是从哪里开始启动的。在该工程的main目录下新建assets文件夹,并在该文件夹下创建名为xposed_init的文件。将作为入口的class完整路径写入该文件即可,代码如下:
com.hook.xposed.InitHook
以上配置完成后就可以正式开始使用EdXposed框架来进行Hook操作了。Hook操作主要使用了Xposed中两个比较重要的函数:handleLoadPackage,用于在包加载时进行回调并获取对应的classLoader;findAndHookMethod,用于对指定类中的函数进行Hook操作。它们的详细定义如下:
/**
* Edxposed框架注入应用时的回调
*/
public void handleLoadPackage(final LoadPackageParam lpparam)
/**
* Edxposed提供的Hook方法
* @param className 需要执行Hook操作的类名
* @param classLoader classLoader
* @param methodName 需要执行Hook操作的方法名
* @param parameterrypesAndCallback 目标方法的参数类型和回调
* @return
*/
findAndHookMethod(string className,ClassLoader classLoader,parameterTypesAndCallback)
具体使用方法可以参考模块入口类InitHook中的代码,如下:
public class InitHook implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
findAndHookMethod(
"需要执行Hook操作的类名",
lpparam.classLoader,
"需要执行Hook操作的函数名",
"需要执行Hook操作的函数参数",
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// 执行方法前进行Hook拦截,通常用于修改传入的参数
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 执行方法后进行Hook拦截,通常用于修改函数的返回值
}
}
);
}
}
现在所有开发Hook模块的准备工作已经完成,正式开始实战操作。
先准备一款用于测试目标应用,该应用界面展示了一个按钮,单击即可显示返回值。运行效果如图2-11所示。
图2-11 测试应用
下面是该应用的核心代码。当单击“开始点击”按钮时程序会调用getTextViewShowData函数获取需要展示的数据。我们的目标是通过Hook的方式拦截并替换该函数的返回数据。
package com.test.demo;
......
public class FirstFragment extends Fragment {
......
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
Message ms = new Message();
Bundle mb = new Bundle();
mb.putString("test",getTextViewShowData());
ms.setData(mb);
handle.sendMessage(ms);
}
}).start();
}
});
}
public String getTextViewShowData() {
return "Hello, welcome to here!!!";
}
......
}
接下来开始编写Hook代码。首先确认目前函数名和其所在类的全路径,在此演示示例中目标函数没有接收参数,因此不用关注参数问题。
public class HookDemo implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
findAndHookMethod(
"com.test.demo.FirstFragment",
lpparam.classLoader,
"getTextViewShowData",
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
// 在方法执行后进行Hook拦截,通常用于修改函数的返回值
param.setResult("该返回结果已经被Hook!!!");
}
});
}
}
将开发的Hook模块应用进行签名打包后安装到目标设备中,在EdXposed Manager客户端的模块管理中启用该模块,并重启设备使该Hook模块生效。具体操作参考图2-12。
图2-12 安装Hook模块
设备完成重启后,Hook模块的功能已经正常生效。打开目标应用并单击“开始点击”按钮,界面上展示的就是被我们替换后的内容。具体效果如图2-13所示。
图2-13 Hook测试
实际场景中目标应用的代码量通常比较大,应用打包时DEX文件中的引用方法往往已经超过65 536个,因此会拆分成多个DEX文件。而Hook框架默认对应用中的主DEX文件执行操作,因此可能出现类的路径和方法名都正确,却无法调用目标方法的情况。Android系统加载DEX文件后,会创建一个Application类,并调用其attach方法。attach方法会接收一个参数,即Context对象。通过Context对象,可以获取相应DEX文件的ClassLoader,这个ClassLoader包含了该DEX文件中所有类的信息。因此,只要对attach方法进行Hook操作,就能获取Context对象,并进一步获取ClassLoader,也就能搜索到目标类。这解决了对多DEX应用进行Hook操作时难以定位目标方法的问题,具体实现代码如下:
// 多DEX应用支持
findAndHookMethod("android.app.Application",
loadPackageParam.classLoader,
"attach",
Context.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
Context context = (Context) param.args[0];
ClassLoader classLoader = context.getClassLoader();
// 此处开始正常进行Hook操作
......
}
}
);
注意
此方法不仅对多DEX应用有效,在针对加壳应用进行Hook操作时也能收到令人惊喜的效果。
在真实环境对函数进行Hook操作时,目标函数往往都是带有参数的,而上述示例中的函数是无参的,下面介绍如何执行带参数的函数Hook操作。假设上述Hook操作示例中的函数带有两个参数,代码如下:
......
public String getTextViewShowData(String input, int count) {
return "Hello, welcome to here!!!";
}
......
Java语言是支持函数重载的,即在同一个类中可以存在多个函数名称相同但参数列表不同的函数。编写Hook代码时如果仅指定目标方法名而未指定该方法接受的参数类型,将导致Hook模块无法准确定位到该函数。因此,在Hook带参数的目标方法时必须指定匹配的参数类型。以上述函数为例,带参数的函数Hook操作如下:
XposedHelpers.findAndHookMethod("com.demo.app.MainActivity", lpparam.classLoader, "getTextViewShowData", String.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// 在getTextViewShowData方法执行前拦截并修改
param.setResult("this function is be hooked!!!");
}
});
例子中函数接收的参数都是标准类型,然而在工作或学习中需要通过反编译的方式确定目标函数名和其所在类,然后编写Hook模块。这时经常会遇到函数的参数是自定义类型而不是标准数据类型的情况。针对此种情况,Xposed也提供了解决方案,具体代码如下:
Class<?> customClass = XposedHelpers.findClass("自定义变量的完整路径", classLoader);
findAndHookMethod(
"目标类名",
classLoader,
"目标方法名",
String.class,
customClass,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
}
}
);
Frida是面向开发人员、逆向工程师和安全研究人员的支持多平台的动态测试工具包。使用者可以通过该工具将JavaScript代码片段或自定义的库注入Windows、macOS、Linux、iOS、Android平台的应用程序中,注入的JavaScript代码在执行时可以完全访问宿主程序的内存、hook函数,甚至可在进程内调用本地函数。同时,Frida还为使用者提供了一系列基于Frida API构建的简单工具。使用者既可以直接使用这些API,也可以根据具体的场景按需对这些API进行调整。
Frida分为客户端和服务端两部分,需要两者配合才能正常使用。下面将以macOS和Android平台为例对该工具的安装和使用进行介绍。官网推荐使用pip方式进行安装,Python最好为3.0以上的版本。
$ pip3 install frida-tools
首先,安装Frida服务端到Android手机端。在https://github.com/frida/frida/releases下载相应版本的服务端程序,然后通过下列命令进行安装并启动:
adb push frida-server /data/local/tmp
adb shell // 进入到Android的命令行模式
$ su // 切换到Root模式
# chemod a+x /data/local/tmp/frida-server
# ./data/local/tmp/frida-server
然后,为保证客户端和服务端的正常通信,需要进行端口映射,如下:
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
可通过frida-ps -U命令验证之前部署的Frida服务是否正常运行,该命令用于查询出当前Android设备中所有正在运行的进程。
# 查询USB连接设备上的进程信息
$ frida-ps -U
PID Name
----- -------------------------------------------------------
5805 com.google.android.gms
5366 com.google.android.gms.persistent
11067 com.google.android.gms.ui
7371 com.google.android.gms.unstable
5649 com.google.android.googlequicksearchbox
5592 com.google.android.googlequicksearchbox:interactor
5628 android.process.media
Frida提供了6个对新手用户非常友好的命令行工具:frida-ls-devices、frida-trace、frida-ps、frida、frida-discover、frida-kill。这些工具可以让使用者在无须自己开发注入模块的情况下快速上手Frida。
1)frida-ls-devices是一个用于列出附加设备的命令行工具,在与多个设备交互时非常有用。
$ frida-ls-devices
Id Type Name
---------------- ------ ------------
local local Local System
CVH7N15A20001095 usb Nexus 6P
socketremote Local Socket
2)frida-trace工具可以用来追踪指定函数的调用情况,传入的参数都是可以使用通配符的,在分析应用程序时非常有帮助。
# 跟踪进程中的recv*和send* API的调用
$ frida-trace -i "recv*" -i "send*" <进程名>
# 在应用程序中跟踪ObjC方法的调用
$ frida-trace -m "ObjC" <进程名>
# 在设备中打开应用程序并跟踪函数call的调用
$ frida-trace -U -f <进程名> -I "call"
# 在Android设备上的指定应用程序中跟踪所有JNI(Java Native Interface,Java本地接口)函数调用
$ frida-trace -U -i "Java_*" <进程名>
注意
参数中的-U代表的是USB,当参数中加入-U参数时说明该命令的操作对象是通过USB连接的设备。
3)frida-ps是一个用于列出进程的命令行工具,在与远程系统进行交互时非常有用。
# 显示通过USB连接的设备上的进程信息
$ frida-ps -U
# 显示通过USB连接的设备上活跃的进程信息
$ frida-ps -Ua
# 显示通过USB连接的设备上安装的应用信息
$ frida-ps -Uai
4)frida可以模拟出类似于IPython(Interactive Python,增强版Python交互式解释器)或Cycript的交互窗口,让使用者可以快速和轻松地实现对目标进程的调试,如图2-14所示。
图2-14 frida使用示例
# Frida通过USB连接到设备上的Chrome浏览器,并在调试模式下加载test.js
$ frida -U Chrome -l test.js --debug
5)frida-discover是一个用于发现程序内部函数的工具,经常配合frida-trace使用。先通过frida-discover发现程序中的函数,然后可以使用frida-trace对发现的函数进行跟踪。
# 发现应用程序中的内部函数
$ frida-discover -n <进程名>
$ frida-discover -p <进程ID>
6)frida-kill是一个用于“杀死”进程的命令行工具,使用时需要通过frida-ls-devices和frida-ps工具中分别识别的设备ID和进程ID。
$ frida-kill -D <DEVICE-ID> <PID>
# 查询当前连接的设备
$ frida-ls-devices
Id Type Name
---------------- ------ ------------
local local Local System
CVH7N15A20001095 usb Nexus 6P
socketremote Local Socket
# 列出指定设备上活跃的进程信息
$ frida-ps -D CVH7N15A20001095 -a
PID Name
----- -------------------------------------------------------
5805 com.google.android.gms
5366 com.google.android.gms.persistent
11067 com.google.android.gms.ui
7371 com.google.android.gms.unstable
5649 com.google.android.googlequicksearchbox
5592 com.google.android.googlequicksearchbox:interactor
5628 android.process.media
# 结束指定设备上的进程
$ frida-kill -D CVH7N15A20001095 5805
Frida框架支持Python语言,可以通过Python编程实现更多复杂的需求。在使用Python开发Frida模块前需要了解Frida的attach和spawn两种模式,其具体区别如表2-1所示。
表2-1 Frida的attach和spawn模式
attach模式下,Frida附加到已经运行的目标进程并注入其agent:
#附加到目标进程
process = frida.attach(target_process)
# 加载jscode到目标进程
script = process.create_script(script_code)
script.load()
spawn模式下,Frida启动目标进程并注入其agent:
# 启动指定的进程
pid = device.spawn([packename])
# 附加到新创建的进程
process = device.attach(pid)
# 加载jscode到目标进程
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
# 新创建的进程为挂起状态,调用resume函数将进程恢复
device.resume(pid)
在正式开发前,还需要了解在Python代码中Frida如何连接到目标设备。Frida提供了3种连接指定设备的方式。
# 获取指定设备ID的设备
device = frida.get_device_manager().get_device("device id")
# 获取远程的设备
manager = frida.get_device_manager()
device = manager.add_remote_device("30.128.25.128:8080")
# 获取通过USB连接的设备
device = frida.get_usb_device()
使用Frida结合Python来加载JavaScript代码以对Android应用进行Hook,示例如下:
import sys
import frida
# 获取通过USB连接的设备
device = frida.get_usb_device()
# 启动指定的进程
pid = device.spawn(["com.frida.test"])
# 附加到新创建的进程
session = device.attach(pid)
# 新创建的进程为挂起状态,调用resume函数将进程恢复
device.resume(pid)
jscode = """
Java.perform(function(){
var main=Java.use("com.frida.test.MainActivity");
main.test.implementation = function()
{
console.log("You have been Hooked");
}
});
"""
def on_message(message,data):
# message的类型为map,取出key payload 的value
print(message["payload"])
script = session.create_script(jscode)
# 设置message回调函数为on_message,JavaScript代码调用send就会将其发送到on_message
script.on("message",on_message)
script.load()
sys.stdin.read()
Frida是一个非常强大的Hook框架,不但可以对 Java层的代码进行Hook操作,还可以对Native层进行Hook操作,代码示例如下:
import frida
import sys
# 获取通过USB连接的设备
device = frida.get_usb_device()
# 启动指定的进程
pid = device.spawn(["com.frida.test"])
# 附加到新创建的进程
session = device.attach(pid)
# 新创建的进程为挂起状态,调用resume恢复进程
device.resume(pid)
jscode = """
var openPtr = Module.findExportByName("libc.so", "open");
Interceptor.attach(openPtr, {
onEnter : function(args){
var pathPtr = args[0];
send("open called ! path="+pathPtr.readUtf8String());
},
onLeave : function(retval){
send("open leave.....");
}
});
"""
def on_message(message, data):
# message的类型为map,取出key payload 的value
print(message["payload"])
script = session.create_script(jscode)
# 设置message回调函数为on_message,Java Script代码调用send就会将其发送到on_message
script.on("message", on_message)
script.load()
sys.stdin.read()
至此,我们已经熟练掌握Frida的操作,建议各位读者立刻找一个目标应用去实际操作一下!
Objection是基于Frida框架开发的自动化Hook工具包,该工具支持Android和iOS平台。如果不擅长进行代码开发,但又想使用Frida进行一些复杂的Hook操作,那Objection将是一个非常不错的工具。
Objection中集成的Frida依赖Python 3.x版本,因此安装Objection需要准备匹配的环境。可使用以下命令进行安装:
pip3 install objection
完成安装后在终端中输入objection命令,执行结果如图2-15所示,这说明该工具已经安装成功。正式使用Objection前需要在手机端启动frida-server,并进行端口转发。
图2-15 Objection安装示例
Objection默认采用attach模式进行Hook操作,通过应用的包名或者bundleID附加需要调试的目标应用,进入Objection提供的交互界面,这是个类似于IPython的交互环境。
objection -g [packageName/bundleID] explore
如果我们需要在应用启动时就进行Hook操作,则可以通过--startup-command的方式启动Objection,示例如下:
objection -g packageName explore --startup-command'android
hooking watch class_method xxxx'
启动Objection后,想要查看目标应用程序在设备内的存储路径,直接在交互界面输入env命令即可,结果如图2-16所示。
图2-16 使用Objection分析应用
如目标应用为Android应用,则可通过以下命令查看该应用的组件信息:
# 查看应用的Activity组件信息
android hooking list activities
# 查看应用的Service组件信息
android hooking list services
# 查看应用的Broadcast Receiver组件信息
android hooking list receivers
既能查看目标应用的组件信息,亦可启动目标应用的组件:
# 启动指定的Activity组件
android intent launch_activity [class_activity]
# 启动指定的Service组件
android intent launch_service [class_service]
对目标应用已加载到内存中的类和方法执行相关操作:
# 查看内存中所有的类
android/ios hooking list classes
# 查看指定类中的所有方法
android/ios hooking list class_methods <class_name>
# 查找指定特征的类
android/ios hooking search classes <class_name>
# 查找指定特征的方法
android/ios hooking search methods <method_name>
使用Objection进行Hook操作:
# 对指定类中的所有方法进行Hook操作
android/ios hooking watch class [class_name]
# 对指定类中的指定方法进行Hook操作
# --dump-args : 打印参数
# --dump-backtrace : 打印调用栈
# --dump-return : 打印返回值
android/ios hooking watch class_method [class_name] --dump-args --dump-backtrace --dump-return
# 设置返回值,目前仅支持bool类型
android/ios hooking set return_value [class_name] false
# 生成Frida的Hook代码
android/ios hooking generate simple [class_name]
调用执行目标应用中的方法:
# 搜索指定类的实例, 获取该类的实例ID
search instances search instances [class_name]
# 通过实例ID直接调用该类中的方法
android heap execute [instance_id] [method_name]
如果目标应用启用SSL校验,则可通过Objection对其进行关闭:
android/ios sslpinning disable
目标应用内存操作如下:
# 枚举当前进程模块
memory list modules
# 查看指定模块的导出函数
memory list exports [lib_name]
# 将导出函数的结果保存到指定的文件中
memory list exports [lib_name] --json result.json
# 搜索内存
memory search --string --offsets-only
其他常用命令如下:
# 尝试对抗Root检测
android root disable
# 尝试模拟Root环境
android root simulate
# 截图
android/ios ui screenshot [image.png]
# 对抗越狱检测
ios jailbreak disable
# 导出KeyChain中的内容
ios keychain dump
# 尝试关闭iOS生物特征认证
ios ui biometrics_bypass
# 执行shell命令
android shell_exec [command]
Tweak是一款依赖Cydia Substrate框架的越狱插件开发工具。该工具创建dylib动态库注入宿主进程中,以完成各种Hook操作,让开发者在不需要破解iOS系统的情况下,快速开发出功能强大的Tweak插件。
进行Tweak开发前需要安装Theos环境。Theos提供了一组工具和库,可以帮助开发者快速创建、编译和部署Tweak。具体环境配置命令如下:
# 将Theos下载并安装到指定目录中
git clone --recursive https://github.com/theos/theos.git
/opt/theos
# 将Theos添加到环境变量中
export THEOS=/opt/theos
export PATH='$THEOS/bin:$PATH'
# 安装签名工具,用于对编译完成后的文件进行签名
brew install ldid
Theos环境搭建完成后就可以开始创建Tweak工程了。首先,在终端中执行nic.pl命令,根据输出的提示信息选择Tweak模板进行创建。然后,按照提示依次输入工程名称、包名、作者名称等信息,即可完成创建,具体命令如下:
$ nic.pl
NIC 2.0 - New Instance Creator
------------------------------
[1.] iphone/activator_event
[2.] iphone/activator_listener
[3.] iphone/application
[4.] iphone/application_swift
[5.] iphone/control_center_module-11up
[6.] iphone/cydget
[7.] iphone/flipswitch_switch
[8.] iphone/framework
[9.] iphone/library
[10.] iphone/notification_center_widget
[11.] iphone/notification_center_widget-7up
[12.] iphone/preference_bundle
[13.] iphone/preference_bundle_swift
[14.] iphone/theme
[15.] iphone/tool
[16.] iphone/tool_swift
[17.] iphone/tweak
[18.] iphone/tweak_swift
[19.] iphone/tweak_with_simple_preferences
[20.] iphone/xpc_service
[21.] iphone/xpc_service_modern
Choose a Template (required): 17
Project Name (required): TestTweak
Package Name [com.yourcompany.testtweak]: com.test.tweak
Author/Maintainer Name [AYL]: AYL
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.springboard
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:
Instantiating iphone/tweak in testtweak/...
Done.
命令执行成功后将在当前目录下创建一个名为testtweak的工程目录。工程目录中默认生成4个文件,具体文件信息如图2-17所示。
图2-17 Tweak工程目录示例
❑control:该文件中包含当前工程的配置信息,如工程名称、包名、作者名称、版本号及相关依赖等。
❑Makefile:主要用于自动化构建工程,文件中指定了待编译的源代码、依赖信息和编译配置信息等。
❑TestTweak.plist:用于存储配置信息。配置信息中的Bundle ID决定了当前工程对哪些应用生效。具体配置信息如下:
{ Filter = { Bundles = ( "com.test.demo","com.test.demo1" ); }; }
❑Tweak.x:Theos生成的源代码文件,该文件中的代码使用Logos语法进行开发。具体代码示例如下:
%hook ClassName
// Hooking a class method
+(id)sharedInstance {
return %orig;
}
// Hooking an instance method with an argument.
- (void)messageName:(int)argument {
%orig;
}
// Hooking an instance method with no arguments.
- (id)noArguments {
%orig;
}
%end
正式进行Tweak插件开发前还需要学习一下Logos语法。Logos是Cydia Substrate框架所提供的一组用于实现Hook操作的宏定义,语法简单,便于开发者快速针对目标应用进行Hook开发。下面将简单介绍一些经常用到的语法,如果想要更加深入地学习Logos语法则可以看官方文档。
1)%hook和%end组合,用于对目标类进行Hook。在代码块中可以直接写入Hook操作的目标方法,代码示例如下:
%hook ClassName
// Hooking a class method
+(id)sharedInstance {
return %orig;
}
%end
2)%group和%end组合,用于对Logos代码进行分组管理,每个声明的组都需要使用%ctor和%init进行初始化操作,代码示例如下:
%group testGroup
%hook ClassName
// Hooking a class method
+(id)sharedInstance {
return %orig;
}
%end
%end
%ctor {
%init(testGroup);
}
3)%new,用于在进行Hook操作的目标类中添加新的方法,代码示例如下:
%hook ClassName
%new
- (void)addNewMethod {
}
%end
4)%orig,调用原始方法,可以传入自定义参数和接收原始方法的返回值,示例代码如下:
%hook ClassName
- (int)add:(int)a to:(int)b {
if (a != 0) {
// Return original result if `a` is not 0
return %orig;
}
// Otherwise, use 1 as `a`
return %orig(1, b);
}
%end
5)%log,输出目标方法的调用信息,包括函数的类名、参数等,代码示例如下:
%hook ClassName
- (void)targetMethod:(id)arg1 {
%log
}
%end
现在开始开发第一个Tweak插件,以目标进程SpringBoard为例进行讲解。
对SpringBoard进程中的[SpringBoard applicationDidFinishLaunching]方法进行Hook操作,添加弹窗代码。SpringBoard启动时会出现弹窗,具体代码如下:
#import <SpringBoard/SpringBoard.h>
%hook SpringBoard
-(void)applicationDidFinishLaunching:(id)application {
%orig;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Test"
message:@"Tweak test!!!"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alert show];
}
%end
在编译安装该插件之前还需要设置目标手机的IP地址,否则插件将安装失败。配置完成后便可在终端中切换到工程所在目录进行编译安装。相关命令如下:
# 设置Tweak插件安装到目标手机的IP地址,否则安装将失败
export THEOS_DEVICE_IP=[目标手机IP]
# 编译并安装Tweak插件
make do
安装成功后SpringBoard将重新启动并加载Tweak插件,效果如图2-18所示。至此,我们已经初步掌握了Tweak工具的使用。
图2-18 Tweak Hook效果
Drozer是由MWR InfoSecurity开发的针对Android应用的安全测试框架。该框架是一款交互式的安全测试工具,支持用于真实的Android设备和模拟器。安全人员或开发者借助Drozer可以通过测试应用与其他应用的交互开展复杂的测试活动,只需很少时间即可评估与Android应用安全相关的问题,从而快速发现Android应用中的安全漏洞。
Drozer运行需要依赖Python2.x和Java环境,在正式安装使用Drozer前需要先将其依赖的运行环境配置好。如图2-19所示,Drozer分为两部分,一部分是客户端,另一部分是手机端代理。手机端代理需要安装在目标设备上,用于在客户端和目标设备通信时进行数据代理转发。Drozer的官网下载地址为https://labs.f-secure.com/tools/drozer。
图2-19 Drozer下载
以macOS系统为例进行客户端安装介绍,在终端中切换到存放drozer-2.4.4-py2-none-any.whl文件的目录下,然后运行以下命令:
# Drozer依赖Python 2.x,此处的pip 必须为Python 2.x的版本
pip install drozer-2.4.4-py2-none-any.whl --ignore-installed
pyOpenSSL
安装Drozer运行时所必需的依赖:
pip install protobuf==3.17.3 pyOpenSSL Twisted service_identity
# 安装 Mac Command Line
xcode-select --install
注意
安装过程中可能会遇到网络原因导致下载文件超时报错的情况,此时重新执行命令直到安装成功即可。
使用数据线将手机设备与PC设备连接起来,安装代理到手机上并开启服务。在PC终端中执行端口转发命令和连接手机命令后,效果如图2-20所示,即可正式开始使用Drozer工具。
# 端口转发
adb forward tcp:31415 tcp:31415
# 连接Drozer
drozer console connect
图2-20 Drozer运行效果
1)通过app.package.info模块查看目标应用的基本信息:
dz> run app.package.info -a package_name
2)查看目标应用的攻击面,主要是指Android四大组件中将export属性设置为ture的组件:
dz> run app.package.attacksurface package_name
3)查看目标应用的暴露的组件信息:
# 查看暴露的Activity组件
dz> run app.activity.info -a package_name
# 查看暴露的Service组件
dz> run app.service.info -a package_name
# 查看暴露的Broadcast组件
dz> run app.broadcast.info -a package_name
# 查看暴露的Content Provider 组件
dz> run app.provider.info -a package_name
4)尝试启动导出的Activity组件,可通过该功能对组件进行拒绝服务漏洞的检测:
# 启动时使用空action
dz> run app.activity.start --component package_name activity_name
# 启动时指定action
dz> run app.activity.start --component package_name activity_name
--action android.intent.action.XXX
5)对目标应用进行敏感数据泄露检测:
# 获取目标应用中对外暴露的URI
dz> run scanner.provider.finduris -a package_name
# 通过暴露的URI进行信息检索
dz> run app.provider.query content://uri/passwords/ --vertical
6)对目标应用进行注入漏洞检测:
dz> run scanner.provider.injection -a package_name
7)对目标应用进行目录遍历漏洞检测,示例命令如下:
dz> run scanner.provider.traversal -a package_name
8)对目标应用进行全局可读或可写文件检测:
# 全局可写文件检测
dz> run scanner.misc.writablefiles --privileged/data/data/pacakge_name
# 全局可读文件检测
dz> run scanner.misc.readablefiles --privileged/data/data/pacakge_name