编写示例代码
通过自己编译且运行Socket示例的客户端(手机)与服务端代码,通过hook的方式来快速分析Socket发送流程。
客户端代码:
1 | import android.util.Log; |
服务端代码:
1 | # coding=utf-8 |
通过objection获取所有socket类
先通过objection的android hooking search 来查找相应的Socket类,并复制这些类到一个txt文件当中然后通过Alt+Shift+鼠标拖拽光标
的方式给所有类加上一句android hooking watch class
通过objection -g 包名 explore -c 文件名.txt
来在启动objection的时候批量hook这些类,当然这过程当中很可能经常会崩,把崩的那句一条条的删掉。
来到这里
虽然objection崩了,但是还是hook到了关键类的信息
1 | Called java.net.SocketOutputStream.write([B) |
java.net.AbstractPlainSocketImpl看到这个是一个抽象类就不用管这个类了。直接看SocketOutputStream
SocketOutputStream,通过Wallbreaker在内存当中搜索一下这个类的其中一个实例看看有没有我们需要的东西。
该实例的域里存在着两个对象,通过这两个对象可以拿到目标的ip(addr)、目标的port(port)、本地的发送端口(localPort)
那我们再看看java.net.SocketOutputStream
的函数的一些信息。
可以看到所有的函数最后都会经过private native void socketWrite0(FileDescriptor fd, byte[] b, int off, int len) throws IOException;
我们通过frida来打印一下它的参数是什么。
此处可以看到byte[]数组就是我们发送的数据~
此处附上打印byte数组的方法:
1 | function printByteArray(byteArray){ |
因为其是一个native函数,说明该函数是Java层与JNI层的一个“桥梁”,也就是Java的Socket最终发送到JNI的那么一个点。可以通杀Java层。
把刚才的那些hook点在文本当中去掉再用objection hook一遍,以便我们拿到服务端返回的信息的Hook点。
直接看源码。
看了源码之后发现,其最终走的是private native int socketRead0(FileDescriptor fd, byte b[], int off, int len, int timeout)
通过对比socketWrite0和SocketOutputStream的名称发现,这两个类可以说是成对出现的,即写——读
成对。
以上是SocketOutputStream和SocketInputStream两个hook点socketWrite0
和socketRead0
的分析流程。
hook ssl握手之前的点
按照上面的做法进行android hooking search ssl
,找到所有关于ssl的类,并把垃圾类都删掉之后进行objection的trace。时间关系这边直接给出那个待trace的类的log
1 | android hooking watch class android.net.SSLCertificateSocketFactory |
然后找到带有read或者write方法的类,只有这些类才是我们想要的类。
注意,可能也不会走这个ssl类,在OpenSSLSocketFactoryImpl.java有另一个ssl分支
而在android8.1以下没有这种情况,这是由于8.1以上这部分开始换成工厂模式重新编写了一下,android8.1以下ssl hook这个点OpenSSLSocketImpl即可。