• Android hook方式抓包


    前言

    在跟大佬学习的时候发现另一种抓包方式,采用frida hook socket 字节流即可,哪里还需要管什么证书绑定,双向认证?

    HTTP抓包原理

    样本案例

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            findViewById<Button>(R.id.btn).setOnClickListener {
                thread(name = "learnHttp") {
                    val url = URL("http://www.baidu.com/")
                    val urlConnection = url.openConnection() as HttpURLConnection
                    try {
                        val ins: InputStream = BufferedInputStream(urlConnection.inputStream)
                        val readBytes = ins.readBytes()
                        Log.d("MainActivity", String(readBytes))
                        ins.close()
                    } catch (e: java.lang.Exception) {
                        Log.e("MainActivity", "error", e);
                    } finally {
                        urlConnection.disconnect()
                    }
                }
    
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    我们分析HttpURLConnection如何发送网络请求才能明白一些hook点,这里使用Android Studio自带的profiler。

    在这里插入图片描述
    在这里插入图片描述

    当然上面分析比较多路径,这里采用别的方式分析,我们知道http会通过socket进行通信必然要通过socket输入输出流,然后断点获取输入流和输出流的地方即可。

    在这里插入图片描述

    可以看到最终返回的时java.net.SocketInputStream.
    在这里插入图片描述
    然后你只需要在下一个断点在这个类所有读取方法上
    在这里插入图片描述

    可以看到会走到其相关read
    在这里插入图片描述
    我们观察下这个字节数组数据方法

    在这里插入图片描述
    在这里插入图片描述
    可以看到这个就是我们需要的相关数据,当然IDE显示的数据可能不是很正确。因为结构体body是被gzip压缩的。

    所以我们这里使用frida hook这个类的读写函数即可。对http请求也如法复制即可。所以大佬根据上面的原理写出了如下的代码

    //一个16进制打印工具
    function jhexdump(array,off,len) {
        var ptr = Memory.alloc(array.length);
        for(var i = 0; i < array.length; ++i)
            Memory.writeS8(ptr.add(i), array[i]);
        //console.log(hexdump(ptr, { offset: off, length: len, header: false, ansi: false }));
        //console.log(hexdump(ptr, { offset: 0, length: array.length, header: false, ansi: false }));
    }
    
    function hook_socket(){
        Java.perform(function(){
            Java.use("java.net.SocketOutputStream").write.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.write(bytearry,int1,int2);
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log("write bytearray contents=>\r\n", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                //console.log(jhexdump(bytearry));
                return result;
            }
            
    
            Java.use("java.net.SocketInputStream").read.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.read(bytearry,int1,int2);
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log("read bytearray contents=>\r\n", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                // console.log(jhexdump(bytearry));
                return result;
            }
    
        })
    }
    
    
    function main(){
    	hook_socket()
    }
    setImmediate(main)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    我们举例说明:
    在这里插入图片描述

    将上面的16进制拷贝到010editor

    在这里插入图片描述
    其中响应体被gzip压缩

    在这里插入图片描述
    我们把压缩内容内容保存的桌面取名httpcontent.gz

    在这里插入图片描述
    在这里插入图片描述
    解压得到正确输出

    HTTPS抓包原理

    如法炮制断点输出流写入
    在这里插入图片描述
    在这里插入图片描述
    如果无法关联源码可以请导入AOSP中extern/okhttp 源码(需要改包名等,内部使用jarjar.jar工具替换的)

    在这里插入图片描述

    com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream
    
    • 1

    输入流同理
    在这里插入图片描述
    在这里插入图片描述

    在Android10 上面的代码可能有变化

    以下为大佬写的写的相关代码

    function jhexdump(array,off,len) {
        var ptr = Memory.alloc(array.length);
        for(var i = 0; i < array.length; ++i)
            Memory.writeS8(ptr.add(i), array[i]);
        //console.log(hexdump(ptr, { offset: off, length: len, header: false, ansi: false }));
        //console.log(hexdump(ptr, { offset: 0, length: array.length, header: false, ansi: false }));
    }
    
    function hook_socket(){
        Java.perform(function(){
            console.log("hook_socket;")
            
    
            Java.use("java.net.SocketOutputStream").write.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.write(bytearry,int1,int2);
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log("write bytearray contents=>\r\n", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                //console.log(jhexdump(bytearry));
                return result;
            }
            
    
            Java.use("java.net.SocketInputStream").read.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.read(bytearry,int1,int2);
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log("read bytearray contents=>\r\n", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                // console.log(jhexdump(bytearry));
                return result;
            }
    
        })
    }
    
    
    function hook_SSLsocketandroid8(){
        Java.perform(function(){
            console.log("hook_SSLsocket")
            
            Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.write(bytearry,int1,int2);
                //console.log("HTTPS write result,bytearry,int1,int2=>",result,bytearry,int1,int2)
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log("bytearray contents=>", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                console.log(jhexdump(bytearry));
                return result;
            }
            
    
            
            Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function(bytearry,int1,int2){
                var result = this.read(bytearry,int1,int2);
                console.log("HTTPS read result,bytearry,int1,int2=>",result,bytearry,int1,int2)
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                //console.log("bytearray contents=>", ByteString.of(bytearry).hex())
                //console.log(jhexdump(bytearry,int1,int2));
                //console.log(jhexdump(bytearry));
                return result;
            }
            
    
        })
    }
    
    
    function hook_SSLsocket2android10(){
        Java.perform(function(){
            console.log(" hook_SSLsocket2")
            var ByteString = Java.use("com.android.okhttp.okio.ByteString");
            Java.use("com.android.org.conscrypt.NativeCrypto").SSL_write.implementation = function(long,NS,fd,NC,bytearray,int1,int2,int3){
                var result = this .SSL_write(long,NS,fd,NC,bytearray,int1,int2,int3);
                console.log("SSL_write(long,NS,fd,NC,bytearray,int1,int2,int3),result=>",long,NS,fd,NC,bytearray,int1,int2,int3,result)
                console.log(ByteString.of(bytearray).hex());
                return result;
            }
            Java.use("com.android.org.conscrypt.NativeCrypto").SSL_read.implementation = function(long,NS,fd,NC,bytearray,int1,int2,int3){
                var result = this .SSL_read(long,NS,fd,NC,bytearray,int1,int2,int3);
                console.log("SSL_read(long,NS,fd,NC,bytearray,int1,int2,int3),result=>",long,NS,fd,NC,bytearray,int1,int2,int3,result)
                console.log(ByteString.of(bytearray).hex());
                return result;
            }      
        })
    }
    
    function main(){
        console.log("Main")
       // hook_socket();
       hook_SSLsocketandroid8();
        //hook_SSLsocket2android10();
    }
    setImmediate(main)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
  • 相关阅读:
    02Redis的命令行客户端和桌面客户端的下载和安装
    【Lua 入门基础篇(十)】文件I/O
    MATLAB入门一基础知识
    嵌入式系统关于晶振的问题汇总
    MySQL 5与MySQL 8的区别
    用 Rcpp 访问 C++ 代码
    OpenGL之着色器
    项目实战——对战回放和排行榜
    C语言函数递归调用
    Vue2基础用法及案例
  • 原文地址:https://blog.csdn.net/qfanmingyiq/article/details/127779533