新睿云

> 知识库 > java socket hook方式的App抓包 Java Socket 编程原理

java socket hook方式的App抓包 Java Socket 编程原理

作者/来源:新睿云 发布时间:2019-12-04

Java Socket编程而言,有两个基本概念,另一个是ServerSocket,另一个是Socket。服务端和客户端中间根据Socket建立连结,之后它们就可以进行通信了。首先ServerSocket将在服务端监听某个端口,当发现客户端有Socket来试图连结它时,它会accept该Socket的连结请求,与此同时在服务端建立另一个相匹配的Socket与之进行通信。这样就有两个Socket了,客户端和服务端各另一个。


对于Socket中间的通信其实很简单,服务端往Socket的输出流里面写东西,客户端就可以根据Socket的输入流读取相匹配的內容。Socket与Socket中间是双向连通的,因此客户端也可以往相匹配的Socket输出流里面写东西,然后服务端相匹配的Socket的输入流就可以读出相匹配的內容。
相关推荐文章《对象数据库是什么?互操作性优势巨大


服务端代码
服务端从Socket的InputStream中读取数据的操作也是阻塞式的,假如从输入流中没有读取到数据信息程序会一直在那里不动,直到客户端往Socket的输出流中写入了数据信息,或关闭了Socket的输出流。当然,对于客户端的Socket也是同样如此。在操作完以后,整个程序结束前记得关闭相匹配的资源,即关闭相匹配的IO流和Socket。


客户端代码
对于客户端往Socket的输出流里面写数据信息传递给服务端要注意一点,假如写操作之后程序不是相匹配着输出流的关闭,而是进行其他阻塞式的操作(比如从输入流里面读数据),记住要flush一下,只有这样服务端才能收到客户端发送的数据信息,否则可能会引起两边无限的互相等待。在稍后讲到客户端和服务端与此同时读和写的时候会说到这个问题。


java socket


2、客户端和服务端与此同时读和写
前面已经说了Socket中间是双向通信的,它既可以接收数据,与此同时也可以发送数据。


服务端代码
在上述代码中首先我们从输入流中读取客户端发送过来的数据信息,接下来我们再往输出流里面写入数据信息给客户端,接下来关闭相匹配的资源文件。而实际上上述代码可能并不会按照我们预先设想的方式运行,因为从输入流中读取数据是另一个阻塞式操作,在上述的while循环中当读到数据信息的时候就会执行循环体,否则就会阻塞,这样后面的写操作就永远都执行不了了。除非客户端相匹配的Socket关闭了阻塞才会停止,while循环也会跳出。针对这种可能永远无法执行下去的情况的解决方法是while循环需要在里面有条件的跳出来,纵观上述代码,在不断变化的也只有取到的长度len和读到的数据信息了,len已经是不能用的了,唯一能用的就是读到的数据信息了。针对这种情况,通常我们都会约定另一个结束标记,当客户端发送过来的数据信息包含某个结束标记时就说明当前的数据信息已经发送完毕了,这个时候我们就可以进行循环的跳出了。
在上述代码中,当服务端读取到客户端发送的结束标记,即“eof”时就会结束数据信息的接收,终止循环,这样后续的代码又可以继续进行了。


客户端代码
在上述代码中我们先是给服务端发送了一段数据信息,之后读取服务端返回来的数据信息,跟之前的服务端一样在读的过程中有可能导致程序一直挂在那里,永远跳不出while循环。这段代码配合服务端的第一段代码就正好让我们分析服务端永远在那里接收数据,永远跳不出while循环,也就没有之后的服务端返回数据信息给客户端,客户端也就不可能接收到服务端返回的数据信息。解决方法如服务端第二段代码所示,在客户端发送数据完毕后,往输出流里面写入结束标记告诉服务端数据信息已经发送完毕了,同样服务端返回数据信息完毕后也发另一个标记告诉客户端。


APP抓包


证书检查
App本身使用私密的HTTPS证书,而不信任我们配置到系统根证书的ca证书,这个时候一般使用JustTrustMe插件可以解决。
可是由于JustTrustMe是通过hook网络库的证书检查逻辑实现的,如果网络库的源代码存在混淆,那么JustTrustMe则无法定位到源代码,也就无法成功拦截。

双向证书认证
服务器检查了客户端的证书,此时此刻需要通过逆向得到客户端证书,然后配置到我们的代理层。需要逆向手段实现,而且几乎没有傻瓜化方案。

App设置不走系统代理
App的源代码逻辑可以定制代理方案,可以设置不走代理,或者走App特殊设定的代理。此时此刻我们配置的系统代理不能生效,那么无法通过charles抓包。
这个时候一般通过VPN来实现,比如PacketCapture。可是通过架设VPN的方式,基本上都是在App内部操作,实际在请求太多的情况下,App并不是特别好操作。
所以很早之前我就设计过一个通过JavaSocket对象进行抓包的方案,不过随着时间流逝方案逐渐的不那么好用了。所以现在找时间重构了她。整个过程我遇到过的问题可以大概列举一下。

SSL Socket Hook源代码重入问题
我们知道,SSLSocket底层就是基于普通的Socket,那么我们对Socket对象监控,其实应该监控SSLSocket,可是我们的源代码不能写死说当遇到SSL的时候,放弃对Socket对象监控。 
这个时候我们的逻辑里面,会出现SSLSocket的数据流和Socket的数据流两份。其中Socket的流量是密文,需要考虑如何分辨以及如何保证数据不不重复解码。
目前通过线程变量,控制reentryFlag实现,我只能期待SSLSocket和Socket的读写一定发生在同一个线程。否则我的方案会直接紊乱。

TCP粘包拆包
在存在连接池,或者链接复用场景下,一个App的多个请求可能在同一个链接中发生。这导致的问题,流量不是单纯的一读一写。
我们需要自己重报文中解析出每个HTTP请求和响应报文。 这设计到HTTP协议的完整识别,包括HTTP报文长度计算,HTTP报文分段传输等问题。

推荐相关应用:DDoS高防IP   对象存储

热门标签
new year
在线咨询
咨询热线 400-1515-720
投诉与建议
{{item.description}}

—您的烦恼我们已经收到—

我们会将处理结果发送至您的手机

请耐心等待