实战基础知识

抓包环境

全局抓包工具 Http v7 、 Http debugger pro

代理抓包工具 Charles 、 Fiddler
VPN 抓包工具 HttpCanary:通过vpn去实现抓包过程

网卡抓包工具 WireShark:利用网卡实现抓包
手机抓包工具 tcpdump

Hook 抓包工具 r0Capture:利用HOOK技术实现抓包过程,通过在数据加密之前,利用某库中的read,write函数将数据读取出来,实现抓包过程

抓包的细节:

为什么我们可以实现在没有获取到服务器的密钥的过程中却可以获取到客户端向服务器发送的请求?

这里其实利用的是中间人攻击,在客户端和服务器之间插入了一个代理服务器,使得客户端和代理服务器进行了通信,代理服务器和服务器进行了通信。

img

抓包过程中,代理服务器向客户端发送返回证书(公钥),之后客户端产生随机数(密钥),并且利用公钥对对称密钥进行加密,之后向代理服务器发送加密之后的对称密钥,使得我们的代理服务器可以利用密钥对于密文进行解密。获取了数据之后,再进行代理服务器与服务器之间的通信。

所以我们可以看到的是,我们是很随便就可以去劫持到发送的数据包,流量包的,那为了使得安全,出现了对于证书的检测,通过去判断证书的路径以及证书链,去查看发送给客户端的证书是否是可靠的来判断是否能够对其进行通信,只有存在于官方的证书库中的证书才能被允许通过(证书库存在于本地,通过特殊手段可以将代理服务器的证书导入证书库)

数字签名:

通常情况下证书和证书派发机构会有数字签名的过程,通常的数字签名会有多个加密过程,也可能是前一半一个加密过程后一半一个加密过程,在过程中会把加密之前的数据和加密之后的数据发送给服务器端,数字签名会将加密之后的数据进行加密再比对原始数据来判断加密过程是否被篡改。

app界面控件的查看:

为了使得我们可以通过控件去更好的找到执行函数以及定位到我们的主要目标函数中去,我们可以利用android studio的uiautomatorviewer工具来去定位控件。

路径:android\Sdk\tools\bin\uiautomatorviewer

通过利用截屏的方式,可以直接去查看我们的控件对应的信息,同时可能会因为程序中禁止了截屏的过程而使得无法去实现这个功能

Android开发中隐藏软键盘

context.getSystemService("input_method")).hideSoftInputFromWindow(view.getWindowToken(), 0)//这部分代码通过context(通常是一个Activity的实例或者应用的Context)调用getSystemService方法来获取一个特定的系统服务。在这个例子中,它请求的是"input_method"服务,hideSoftInputFromWindow方法参数数一为隐藏软键盘的窗口,第二个是隐藏软键盘的额外选项

我们如何去定位到关键代码:

  1. 控件ID,setOnClickListener()函数,通过去利用uiautomatorviewer工具,实现通过已知的控件ID去锁定到目标函数

  2. 人肉搜索,通过去寻找相关或者是可疑的字符串(搜索链接,加密的参数名,同一个数据包)进行函数定位,实现关键代码的获取。

  3. 快速定位方法:Hook常见的系统函数,假如app有调用就去打印相应的函数堆栈

  4. 在自制的沙盒中运行,打印app运行过程中的指令、函数调用关系、

  5. 总结,对应控件ID以及人肉搜索的过程去定位关键代码的难度较大,由于可能会开启禁用截屏或者是通过反射等手段去隐藏和加密关键字符串,使得我们难以去利用控件字符串等方法定位,所以对于关键的系统函数进行Hook是普遍的方法

    cmd命令:

    frida -UF -l test.js  //将test.js注入到运行的程序中
    

利用frida去hook程序中的普通函数并获取参数:

Java.perform(function() {
    var JsonRequest = Java.use("com.dodonew.online.http.JsonRequest");//获取相应的"包名"
    console.log(JsonRequest);//输出获取的类
    JsonRequest.paraMap.implementation= function(a)//对于类中方法的实现,参数不用去限定类型
    {
        console.log("arg:",a);//输出当前参数
        this.paraMap(a);//再次调用该方法,使得正常执行
    }
        JsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation= function(a,b)//这里在方法之后又进行了overload,这是因为函数该函数中有多个重载(函数名相同,参数不同),所以要选取相应对应的参数
    {
        console.log("arg:",a,b);
        this.addRequestMap(a,b);
    }
}
);

由于这样我们只能获取相应已知变量名的数据,那我们应该怎么去一次性获取数据呢?在HashMap中我们通过toString()方法来实现:

import java.util.HashMap;

public class one11 {
    public static void main(String[] args) {
        HashMap<Object , Object> objectHashMap = new HashMap<Object, Object>();
        objectHashMap.put("key1", "value1");
        objectHashMap.put("key2", "value2");
        System.out.println(objectHashMap.toString());
    }
}

我们可以发现的是假如直接去使用toString方法的话,不能够该数据进行打印,而且输出的是Object方法的数据结构

这是因为我们在复写这个方法的时候 JsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation= function(a,b)利用的是java.util.Map', 'int'的类型,这个类型不能使用HashMap的toString方法(这个方法被重写了的)但是接收Map这个类型实际上接收的是Object类型,没有对其进行重写操作

所以我们利用方法Java.cast()去接收由HashMap重写的方法

        var bb =Java.cast(a,Java.use("java.util.HashMap"))//通过bb去接收HashMap方法作用在a参数上
        console.log("args:",bb.toString());

结果:

    JsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation= function(a,b)
    {
        console.log("addRequestMap.arg:",a,b);
        console.log("username",a.get("username"));
        console.log("userPwd",a.get("userPwd"));
        var bb =Java.cast(a,Java.use("java.util.HashMap"))
        console.log("args:",bb.toString());
        this.addRequestMap(a,b);
    }
addRequestMap.arg: [object Object] 0
username 1695662819
userPwd yhwhxudu
args: {loginImei=Androidnull, equtype=ANDROID, userPwd=yhwhxudu, username=1695662819}
posted @ 2024-07-24 15:02  fisherman-ovo  阅读(67)  评论(0)    收藏  举报