首页
社区
课程
招聘
[原创]Hook入门与抓包
发表于: 2024-1-3 15:28 25639

[原创]Hook入门与抓包

2024-1-3 15:28
25639

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对象
                        URL url = new URL("https://www.baidu.com");
                        // URL对象的openConnection()方法获取HttpURLConnection对象的实例
                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                        // 设置网络请求头部参数
                        connection.setRequestMethod("GET");
                        connection.setRequestProperty("token","r0ysue666");
                        connection.setConnectTimeout(8000);
                        connection.setReadTimeout(8000);
 
                        connection.connect(); // 开始连接
                        // 通过HttpURLConnection对象实例的getInputStream()方法获取网络请求响应的数据流
                        InputStream in = connection.getInputStream();
 
                        //if(in.available() > 0){
 
                        // 每次写入1024字节
                        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());
                        // 关闭HTTP网络请求
                        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对象
                        URL url = new URL("https://www.baidu.com");
                        // URL对象的openConnection()方法获取HttpURLConnection对象的实例
                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                        // 设置网络请求头部参数
                        connection.setRequestMethod("GET");
                        connection.setRequestProperty("token","r0ysue666");
                        connection.setConnectTimeout(8000);
                        connection.setReadTimeout(8000);
 
                        connection.connect(); // 开始连接
                        // 通过HttpURLConnection对象实例的getInputStream()方法获取网络请求响应的数据流

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-2-2 10:35 被Alvinlight编辑 ,原因:
收藏
免费 29
支持
分享
最新回复 (18)
雪    币: 3458
活跃值: (2668)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
插个眼。以后可能有用呢!
2024-1-4 10:13
0
雪    币: 271
活跃值: (311)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢支持
2024-1-4 11:09
0
雪    币: 1037
活跃值: (1780)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
来自肉丝大佬的赞赏
2024-1-4 11:40
0
雪    币: 271
活跃值: (311)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
wooyunking 来自肉丝大佬的赞赏
知识的搬运工
2024-1-4 11:44
0
雪    币: 31
活跃值: (3269)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
r0syue 的文章, 可能是 Frida 的 beganing book , 这两天也被这个卡壳了。
文章不错。 
2024-1-4 14:06
0
雪    币: 271
活跃值: (311)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
calleng r0syue 的文章, 可能是 Frida 的 beganing book , 这两天也被这个卡壳了。 文章不错。
感谢大佬的肯定
2024-1-4 16:02
0
雪    币: 31
活跃值: (3269)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
Alvinlight 感谢大佬的肯定
鄙人菜鸡一只。。不敢当佬。5 年修炼估计还差不多吧。
2024-1-4 16:52
0
雪    币: 1027
活跃值: (261)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
9
已经认真学习,感谢分享!
2024-1-12 16:54
0
雪    币: 587
活跃值: (1002)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
佬,Okhttp3 Hook客户端强行设置代理,可以具体讲一下吗?手机和电脑的环境怎么配置的,我刚刚试了一下,电脑用的花瓶,没有抓到包,请教一下大佬
2024-1-15 14:38
0
雪    币: 416
活跃值: (157)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢大佬分享
2024-2-4 17:12
0
雪    币: 3614
活跃值: (31036)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2024-2-5 09:45
1
雪    币: 19
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2024-2-15 16:23
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
不错哟,感谢分享
2024-4-18 19:56
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
不错哟 感谢分享
2024-4-25 10:12
0
雪    币: 202
活跃值: (1255)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
群主,怎么hook获取requestbody呢
2024-8-27 17:24
0
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
有用,插个眼
2024-9-9 23:42
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
有用,差个眼
2024-10-2 20:25
0
雪    币: 282
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
插个眼。以后可能有用呢!
2024-10-9 09:34
0
游客
登录 | 注册 方可回帖
返回
//