Frida 的 介 绍 是 “Frida 是 平 台 原 生 App 的“Greasemonkey”,专业一点来说就是一种动态插桩工具,可以插入一些代码到原生App的内存空间去动态地监视和修改其行为,这些原生平台可以是Windows、Mac、Linux、Android或者iOS,同时Frida还是开源的。
Frida通过将JavaScript脚本插入到App的内存中来对App的逻辑进行跟踪和监控,甚至重新修改程序的逻辑,实现逆向开发和分析人员想要实现的功能,这样的方式也可以称为Hook(钩住,即通过钩子机制与钩子函数建立关联)。
客户端(电脑主机)安装直接使用命令
服务端(手机端)安装
在GitHub上找到与客户端版本相同且与手机硬件架构相同的服务端进行下载,下载后上传到手机/data/local/tmp
目录下,添加可执行权限,进行运行即可
CLI模式直接通过命令行将JS脚本注入到进程中,对APP进程进行操作。
RPC模式又称为远程过程调用模式,这种模式利用Python对Hook的Js脚本进行包装,但实际上对进程进行操作的还是Js脚本。
这种模式是建立在目标App已经启动的情况下,frida直接利用ptrace原理将Hook的Js脚本注入程序而完成Hook操作。
这种模式将启动App的权力交由Frida来控制,当使用此模式时,即使App已经启动还是会将App重新启动并注入Hook的JS脚本。
setTimeout函数本身是JS提供的一个函数,通过这个函数可以将FridaHook脚本的函数延迟注入到目标进程,在App有加固情况下比较好用比如: Root检测、Wifi代理检测
这个函数和setTimeout()函数类似,都是用于指定要执行的函数,不同的是setTimeout可以用于指定Frida注入App多长时间后执行函数,往往用于延时注入。
Java.perform() 函数表示将参数中的函数注入到Java运行时,如果没有该函数的包裹注入目标App进程会提示如下图的报错信息:
从内存中获取指定类(包名.类名)的handle句柄,相当于Java中通过反射机制获取到的Class对象。
这段代码表示每秒调用一次show()方法,其中一个方法没有返回值和参数,另一个方法有返回值和参数
Hook 该程序show方法的Frida脚本
执行如下命令:
Objection集成的功能主要支持Android和iOS两大移动平台。在对Android的支持中,Objection可以快速完成诸如内存搜索、类和模块搜索、方法Hook以及打印参数、返回值、调用栈等常用功能,是一个非常方便的逆向必备工具和内存漫游神器。
使用命令安装:
Objection默认通过USB连接设备,不必和Frida的命令行一样通过-U参数指定USB模式连接,主要通过-g参数指定注入的进程并通过explore命令进入REPL模式。在进入REPL模式后便可以使用Objection进行Hook的常用命令
常用基础命令:
使用jadx反编译工具反编译apk文件,搜索root检测相关代码
找到包名为目标APP包名的那个方法,跟踪代码
然后根据root检测逻辑编写绕过检测的js代码,具体代码略
上面的方法有个缺点就是只能针对特定的APP绕过,下面介绍通用的绕过方式
直接Hook java.io.FIle类的exists方法,这个方式的好处是:
1.其他APP不敢对这个类进行混淆
2.这个类一定存在于内存中无需延迟注入
仔细观察方法一种root检测部分截图的代码,发现使用的是Java基础类File的exists()方法进行检测
因此我们可以直接对File进行Hook,代码如下
HttpURLConnection属于原生的网络通信库,从Android 5(2014年)开始,Android官方不再推荐使用HttpClient。Android 6.0的SDK中去掉了HttpClient的支持。 在Android 9之后,Android更是彻底取消了对HTTPClient的支持,因此可以说原生的网络通信库就只剩下了HttpURLConnection。
因为网络通信的操作涉及异步、多线程和效率等问题,在HttpURLConnection中并未对这些操作进行完整的封装,而是交给了开发者去完成,因此就出现了第二类网络通信框架——第三方HTTP(S)网络请求框架。okhttp 是大名鼎鼎的Square公司的开源网络请求框架,有2、3、4几个大版 本,目前主流使用的是okhttp3。相比HttpUrlConnection,okhttp3更加优雅和高效,大部分Android第三方网络框架(比如Retrofit2网络通信框架)也都是基于okhttp3的再封装。
另外,还有Volley网络通信框架,它是在2013年 的Google I/O大会上被推出的基于HttpUrlConnection的一款异步 网络请求框架和图片加载框架,Volley特别适合数据量小、通信频繁的网络操作。
1.通过传入目标网络地址来新建一个URL对象,然后通过 openConnection()函数获取一个HttpURLConnection实例
2.获取到HttpURLConnection实例后,按照HTTP建立连接的流程设置HTTP请求头和参数信息例如:
setRequestMethod()函数设置HTTP请求方法
setRequestProperty() 设置请求参数
setConnectionTimeout() 函数设置连接超时时间
setReadTimeout()函数设置接收超时时间
3.调用HttpURLConnection实例的getInputStream()方法与服务器连接并获取到服务器返回的输入流,对输入流完成读取,最终调用disconnection()方法将HTTP连接关闭掉。
实例:
从HttpURLConnection基础开发流程我们发现几个关键的收发包函数
1.URL类的构造函数,其包含了目标网址的字符串。
2.setRequestMethod()和setRequestProperty()方法设置请求头和请求参数等信息。
3.getInputStream()方法获取response服务器响应数据。
Objection hook java.net.HttpURL类构造函数的方法
Hook setRequestProperty()方法,发现无日志信息
Hook java.net.HttpURLConnection
整个类的方法调用,观察调用了哪些方法
当hook HttpURLConnection类的方法时,没有打印出预想的setRequestProperty()、setRequestMethod()等方法的调用,这是因为HttpURLConnection是一个抽象类,无法创建对象实例所以内存中没有对象实例,需要Hook它的子类实例。
HttpURLConnection类定义
通过断点调试查看实现HttpURLConnection的子类实例
在获取HttpURLConnection对象后断点
HttpURLConnectoin具体实现类com.android.okhttp.internal.huc.HttpURLConnectionImpl
hook com.android.okhttp.internal.huc.HttpURLConnectionImpl类获取请求头部和参数信息
执行结果如下:
1.创建一个OkhttpClient客户端对象
2.创建Request对象设置header、body、url等参数
3.使用OkhttpClient客户端将Request请求封装成Call对象后,调用enqueue()方法产生一次真实的网络请求,onResponse()等回调方法处理网络请求结果(网络请求可分为同步和异步两种,在Android中主要使用异步)
MainActivity代码:
example代码
从Okhttp3基础开发流程我们发现几个关键的点
1.请求的服务器URL。
2.使用的协议版本,比如HTTP/1.0或者HTTP/1.1等。
3.请求头Header以及请求的Body数据。
4.请求的返回数据。
如果通过Hook的方式实现另类的“抓包”,那么我们的需求是保留URL、请求Body和headers以及请求的返回数据。可以在okhttpClient.newCall(request)函数中找到我们关注的请求Request对象,而这个对象中会包含我们关注的1、2、3项。但是由于Okhttp3设计的原因,如果按照HttpURLConnection自吐脚本输出Request和Response的难度比较大。
通过查看OkHttp3官方API发现可以在构造OkhttpClient对象时设置代理,之后的请求就会发送到代理服务器。
一般来说开发者使用OkHttpClient创建客户端对象并不会使用proxy方法设置代理,但是我们可以通过Frida Hook的方式在调用build()方法时强行设置代理,这样就能在不设置WIFI代理或VPN代理的方式抓取到请求包。Frida代码如下:
运行效果
pip3
install
frida==12.8.0
pip3
install
frida-tools==5.3.0
pip3
install
frida==12.8.0
pip3
install
frida-tools==5.3.0
adb push frida
adb shell
su
cd
/data/local/tmp
chmod
777 frida
.
/frida
adb push frida
adb shell
su
cd
/data/local/tmp
chmod
777 frida
.
/frida
frida -U APP进程 -l HookJs脚本.js
frida -U APP进程 -l HookJs脚本.js
frida -U -f App进程 -l HookJs脚本.js --no-pause
frida -U -f App进程 -l HookJs脚本.js --no-pause
package
com.example.demo02;
import
android.os.Bundle;
import
android.util.Log;
import
androidx.appcompat.app.AppCompatActivity;
public
class
example
extends
AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose);
while
(
true
){
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e){
e.printStackTrace();
}
show();
show(
"---parameter---"
);
}
}
public
static
void
show(){
Log.d(
"---no parameter---"
,
"show方法日志打印"
);
}
public
static
boolean
show(String tag){
Log.d(tag,
"show方法日志打印"
);
return
true
;
}
}
package
com.example.demo02;
import
android.os.Bundle;
import
android.util.Log;
import
androidx.appcompat.app.AppCompatActivity;
public
class
example
extends
AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose);
while
(
true
){
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e){
e.printStackTrace();
}
show();
show(
"---parameter---"
);
}
}
public
static
void
show(){
Log.d(
"---no parameter---"
,
"show方法日志打印"
);
}
public
static
boolean
show(String tag){
Log.d(tag,
"show方法日志打印"
);
return
true
;
}
}
frida -U com.example.demo02 -l 6_example.js
frida -U com.example.demo02 -l 6_example.js
pip3 install
-
U objection
pip3 install
-
U objection
objection -g com.roysue.httpurlconnectiondemo(包名) explore
objection -g com.roysue.httpurlconnectiondemo(包名) explore
jobs命令:作业系统很好用,用于查看和管理当前所执行Hook的任务
查看当前hook任务: jobs list
终止hook任务: jobs
kill
id
内存漫游相关命令:
列出当前内存中所有类:android hooking list classes
搜索内存中包含关键字的类: android hooking search class 关键字
搜索内存中包含关键字的方法: android hooking search methods 关键字
列出指定类中的所有方法: android hooking list class_methods 类完整路径
列出当前APP四大组件: android hooking list activities|services|receivers|providers
Hook相关命令:
Hook指定的方法: android hooking
watch
class_method 方法名称 --dump-args --dump-backtrace --dump-
return
Hook某个类的所有方法: android hooking
watch
class 类名
jobs命令:作业系统很好用,用于查看和管理当前所执行Hook的任务
查看当前hook任务: jobs list
终止hook任务: jobs
kill
id
内存漫游相关命令:
列出当前内存中所有类:android hooking list classes
搜索内存中包含关键字的类: android hooking search class 关键字
搜索内存中包含关键字的方法: android hooking search methods 关键字
列出指定类中的所有方法: android hooking list class_methods 类完整路径
列出当前APP四大组件: android hooking list activities|services|receivers|providers
Hook相关命令:
Hook指定的方法: android hooking
watch
class_method 方法名称 --dump-args --dump-backtrace --dump-
return
Hook某个类的所有方法: android hooking
watch
class 类名
package
com.roysue.httpurlconnectiondemo;
import
androidx.appcompat.app.AppCompatActivity;
import
android.os.Bundle;
import
android.util.Log;
import
java.io.IOException;
import
java.io.InputStream;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.nio.charset.StandardCharsets;
public
class
MainActivity
extends
AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new
Thread(
new
Runnable() {
@Override
public
void
run() {
while
(
true
){
try
{
URL url =
new
URL(
"https://www.baidu.com"
);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(
"GET"
);
connection.setRequestProperty(
"token"
,
"r0ysue666"
);
connection.setConnectTimeout(
8000
);
connection.setReadTimeout(
8000
);
connection.connect();
InputStream in = connection.getInputStream();
int
bufferSize =
1024
;
byte
[] buffer =
new
byte
[bufferSize];
StringBuffer sb =
new
StringBuffer();
while
((in.read(buffer)) != -
1
) {
sb.append(
new
String(buffer));
}
Log.d(
"r0ysue666"
, sb.toString());
connection.disconnect();
}
catch
(IOException e) {
e.printStackTrace();
}
try
{
Thread.sleep(
10
*
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
package
com.roysue.httpurlconnectiondemo;
import
androidx.appcompat.app.AppCompatActivity;
import
android.os.Bundle;
import
android.util.Log;
import
java.io.IOException;
import
java.io.InputStream;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.nio.charset.StandardCharsets;
public
class
MainActivity
extends
AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new
Thread(
new
Runnable() {
@Override
public
void
run() {
while
(
true
){
try
{
URL url =
new
URL(
"https://www.baidu.com"
);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(
"GET"
);
connection.setRequestProperty(
"token"
,
"r0ysue666"
);
connection.setConnectTimeout(
8000
);
connection.setReadTimeout(
8000
);
connection.connect();
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2024-2-2 10:35
被Alvinlight编辑
,原因: