frida内存检索svc指令查找sendto和recvfrom进行hook抓包
利用wirkeshake抓包初步分析
配置本地PC的ip为192.168.5.150并在上面运行server,然后在pixel手机上安装client_连接192.168.5.150服务器.apk,手机ip为192.168.5.221,在PC上通过wireshake进行抓包。如下所示,看到No.14是手机发给server的HTTP GET包,No.17为server发给手机的HTTP报文。
追踪http流,可以看到server返回给手机一个字符串“hello world"。
常规抓包方案
根据上面分析,apk使用的http通信,采用tcp协议。
2.1 尝试Java层使用tcp通信的常规hook点,如下所示。
java.net.SocketInputStream. socketRead0
java.net.SocketOutputStream. socketWrite0
2.2尝试JNI层使用tcp通信的常规hook点。
apk直接调用libc.so中接口实现收发包,一般tcp是使用send和recv函数,而udp使用sendto和recvfrom函数。查看libc源码,send最终还是调用的sendto,而sendto通过系统调用实现。recv原理与send一致,所以我们直接hook住libc.so的recvfrom和sendto正常是可以拿到tcp和udp的包。
经过实验分析,上面两种方法都没有能抓到包,那么剩下的可能就是so中通过系统调用实现了sendto和recvfrom函数,下面对此猜想进行分析验证。
进一步分析
3.1 先利用frida_fart对apk进行脱壳,脱壳后看到onCreate函数native化了,加载了一个libnative-lib.so,还有一个jni函数stringFromJNI。
3.2 解压apk取出libnative-lib.so,利用IDA分析,但是打不开报如下错误。
利用readelf查看,section段查看结果如下,也是不正常的。我利用010Editor打开这个so进行ELF解析,也会报错。
3.3 使用frida去dump出运行时的so,核心代码如下。
将这个so拉入IDA进行分析,这次不会报错了,使用ctrl+F5反编译,查看到so中使用系统调用实现了sendto和recvfrom,如下所示。
查看sub_2BD8的汇编代码,看到svc 0指令对应的机器码是“00 00 00 EF"。
因为上面分析的so是加壳的so,所以我们无法确定svc指令的真实地址,所以需要从内存中根据机器码找到svc指令,然后通过hook住svc指令,去dump收发包数据。
frida脚本实现
4.1 寻找hook时机,一般加壳so的解码在init或者init_array中实现,它们在so加载过程中会进行调用,所以选择java层加载so完毕后进行hook,代码如下。
4.2 根据libnative-lib.so模块的基地址和偏移,从内存中匹配svc 0的机器码,并反汇编出附近的指令进行匹配,如果找到了svc 0,则对其地址进行hook。
4.3 hook住svc 0后打印收发包的data部分。
首先查看sendto和recvfrom的机器码分别是290和292, 如下所示。
查看sendto原型如下,在它执行前打印出r0即fd,r1即buffer,r2即buffersize。在它执行后打印r0即sendto的返回值也就是真正发送出去的包的长度。recvfrom原理与之一致。
下面在sendto和recvfrom执行完毕后,打印出收发包的data部分以及调用栈。
4.4 运行frida脚本,同时支持dump出so和抓包,并打印出了调用栈。
如下是发包数据,可以看到apk做了一次HTTP GET的操作。
如下是收包数据,可以看到收到的真实数据为“helloworld"。
综上,frida抓包结果与wireshake抓包结果是一致的,同时也是可以利用frida dump出的运行中的so以及调用栈,分析so中收发包函数的流程。