functiongetSocketData(fd){ console.log("fd:",fd); var socketType=Socket.type(fd) if(socketType!=null){ var res="type:"+socketType+",loadAddress:"+JSON.stringify(Socket.localAddress(fd))+",peerAddress"+JSON.stringify(Socket.peerAddress(fd)); return res; }else{ return"type:"+socketType; } }
functionhook_jni_tcp(){ var sendtoPtr=Module.getExportByName("libc.so","sendto"); var recvfromPtr=Module.getExportByName("libc.so","recvfrom"); console.log("sendto:",sendtoPtr,",recvfrom:",recvfromPtr); //sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len) Interceptor.attach(sendtoPtr,{ onEnter:function(args){ var fd=args[0]; var buff=args[1]; var size=args[2]; var sockdata=getSocketData(fd.toInt32()); console.log(sockdata); console.log(hexdump(buff,{length:size.toInt32()})); }, onLeave:function(retval){
} }); //recvfrom(int fd, void *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len) Interceptor.attach(recvfromPtr,{ onEnter:function(args){ this.fd=args[0]; this.buff=args[1]; this.size=args[2]; }, onLeave:function(retval){ var sockdata=getSocketData(this.fd.toInt32()); console.log(sockdata); console.log(hexdump(this.buff,{length:this.size.toInt32()})); } }); }
// Configure the socket's ciphers, TLS versions, and extensions. ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket); if (connectionSpec.supportsTlsExtensions()) { Platform.get().configureTlsExtensions( sslSocket, address.url().host(), address.protocols()); }
// Force handshake. This can throw! sslSocket.startHandshake(); // block for session establishment SSLSession sslSocketSession = sslSocket.getSession(); if (!isValid(sslSocketSession)) { thrownew IOException("a valid ssl session was not established"); } Handshake unverifiedHandshake = Handshake.get(sslSocketSession);
// Verify that the socket's certificates are acceptable for the target host. if (!address.hostnameVerifier().verify(address.url().host(), sslSocketSession)) { X509Certificate cert = (X509Certificate) unverifiedHandshake.peerCertificates().get(0); thrownew SSLPeerUnverifiedException("Hostname " + address.url().host() + " not verified:" + "\n certificate: " + CertificatePinner.pin(cert) + "\n DN: " + cert.getSubjectDN().getName() + "\n subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert)); } //这里是证书的校验 // Check that the certificate pinner is satisfied by the certificates presented. address.certificatePinner().check(address.url().host(), unverifiedHandshake.peerCertificates());
// Success! Save the handshake and the ALPN protocol. String maybeProtocol = connectionSpec.supportsTlsExtensions() ? Platform.get().getSelectedProtocol(sslSocket) : null; socket = sslSocket; source = Okio.buffer(Okio.source(socket)); sink = Okio.buffer(Okio.sink(socket)); handshake = unverifiedHandshake; protocol = maybeProtocol != null ? Protocol.get(maybeProtocol) : Protocol.HTTP_1_1; success = true; } catch (AssertionError e) { if (Util.isAndroidGetsocknameError(e)) thrownew IOException(e); throw e; } finally { if (sslSocket != null) { Platform.get().afterHandshake(sslSocket); } if (!success) { closeQuietly(sslSocket); } } }
//上面流程走完。ssl的连接就建立起来了。继续跟踪后。走到下一个关键拦截器CallServerInterceptor.java。我们直接看拦截器函数实现部分 @Overridepublic Response intercept(Chain chain)throws IOException { ... //前面的代码应该是准备header的数据。我就都省略了。下面这个函数是发送请求的关键函数 httpCodec.finishRequest(); ... } //继续往后跟踪flush @OverridepublicvoidfinishRequest()throws IOException { sink.flush(); } //继续跟踪sink.write @Overridepublicvoidflush()throws IOException { if (closed) thrownew IllegalStateException("closed"); if (buffer.size > 0) { sink.write(buffer, buffer.size); } sink.flush(); } //继续往后看write @Overridepublicvoidwrite(Buffer source, long byteCount)throws IOException { checkOffsetAndCount(source.size, 0, byteCount); ... sink.write(source, toWrite); ... } //这个write就到一个关键的位置了。这个out对象就是我们关心的类了。我们查一下out的类型 @Overridepublicvoidwrite(Buffer source, long byteCount)throws IOException { ... //out对象的类型是com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream out.write(head.data, head.pos, toCopy); ... } //接下来我们就可以去找SSLOutputStream的write了。我们在调试中跟踪过去失败了。那么直接去翻源码把。下面是对应的write publicvoidwrite(byte[] buf, int offset, int byteCount)throws IOException { ... ssl.write(Platform.getFileDescriptor(socket), buf, offset, byteCount,writeTimeoutMilliseconds); ... } //继续看ssl.write。这个ssl的类型是SslWrapper。找到对应的write如下。 voidwrite(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) throws IOException { NativeCrypto.SSL_write(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); } //继续找NativeCrypto类的SSL_write函数。到这里就结束了。终于到达java调用链的最后一层了。 staticnativevoidSSL_write(long sslNativePointer, FileDescriptor fd, SSLHandshakeCallbacks shc, byte[] b, int off, int len, int writeTimeoutMillis) throws IOException;
staticnativeintSSL_read(long sslNativePointer, FileDescriptor fd, SSLHandshakeCallbacks shc, byte[] b, int off, int len, int readTimeoutMillis)throws IOException;
functiongetSocketData2(stream){ var data0=stream.this$0.value; var sockdata=data0.socket.value; return sockdata; } //SSLOutputStream write(byte[] buf, int offset, int byteCount) //SSLInputStream read(byte[] buf, int offset, int byteCount) functionhook_ssl2(){ var SSLOutputClass=Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream"); SSLOutputClass.write.overload('[B', 'int', 'int').implementation=function(buf,off,cnt){ console.log(getSocketData2(this)); print_bytes(buf); returnthis.write(buf,off,cnt); }; var SSLInputClass=Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream"); SSLInputClass.read.overload('[B', 'int', 'int').implementation=function(buf,off,cnt){ var res=this.read(buf,off,cnt); console.log(getSocketData2(this)); print_bytes(buf); return res; } }
intSSL_write(SSL *ssl, constvoid *buf, int num){ ... ret = ssl->method->write_app_data(ssl, &needs_handshake, (constuint8_t *)buf, num); ... }
继续看ssl3_write_app_data的实现
1 2 3 4 5 6
intssl3_write_app_data(SSL *ssl, int *out_needs_handshake, constuint8_t *buf, int len){ ... int ret = do_ssl3_write(ssl, SSL3_RT_APPLICATION_DATA, &buf[tot], nw); ... }
staticintdo_ssl3_write(SSL *ssl, int type, constuint8_t *buf, unsigned len){ ... /* Add any unflushed handshake data as a prefix. This may be a KeyUpdate * acknowledgment or 0-RTT key change messages. |pending_flight| must be clear * when data is added to |write_buffer| or it will be written in the wrong * order. */ if (ssl->s3->pending_flight != NULL) { OPENSSL_memcpy( out, ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset, flight_len); BUF_MEM_free(ssl->s3->pending_flight); ssl->s3->pending_flight = NULL; ssl->s3->pending_flight_offset = 0; } if (!tls_seal_record(ssl, out + flight_len, &ciphertext_len, max_out - flight_len, type, buf, len)) { return-1; } ssl_write_buffer_set_len(ssl, flight_len + ciphertext_len); ... /* we now just need to write the buffer */ return ssl3_write_pending(ssl, type, buf, len); }
//将数组转换成c++的byte[]。并且hexdump打印结果 functionprint_bytes(bytes) { var buf = Memory.alloc(bytes.length); Memory.writeByteArray(buf, byte_to_ArrayBuffer(bytes)); console.log(hexdump(buf, {offset: 0, length: bytes.length, header: false, ansi: true})); } //将java的数组转换成js的数组 functionbyte_to_ArrayBuffer(bytes) { var size=bytes.length; var tmparray = []; for (var i = 0; i < size; i++) { var val = bytes[i]; if(val < 0){ val += 256; } tmparray[i] = val } return tmparray; } // java.net.Socket$init(ip,port) 获取ip和端口 // socketWrite0(FileDescriptor fd, byte[] b, int off,int len) 获取发送的数据 // socketRead0(FileDescriptor fd,byte b[], int off, int len,int timeout) 获取接受的数据 functionhook_tcp(){ var socketClass= Java.use("java.net.Socket"); socketClass.$init.overload('java.net.InetAddress', 'int').implementation=function(ip,port){ console.log("socket$init ",ip,":",port); returnthis.$init(ip,port); }; var outputClass=Java.use("java.net.SocketOutputStream"); outputClass.socketWrite0.implementation=function(fd,buff,off,len){ console.log("tcp write fd:",fd); print_bytes(buff); returnthis.socketWrite0(fd,buff,off,len); };
var inputClass=Java.use("java.net.SocketInputStream"); inputClass.socketRead0.implementation=function(fd,buff,off,len,timeout){ var res=this.socketRead0(fd,buff,off,len,timeout); console.log("tcp read fd:",fd) print_bytes(buff); return res; }; } //SSL_write(long sslNativePointer, FileDescriptor fd, // SSLHandshakeCallbacks shc, byte[] b, int off, int len, int writeTimeoutMillis) //SSL_read(long sslNativePointer, FileDescriptor fd, SSLHandshakeCallbacks shc, // byte[] b, int off, int len, int readTimeoutMillis) functiongetSocketData(fd){ console.log("fd:",fd); var socketType=Socket.type(fd) if(socketType!=null){ var res="type:"+socketType+",loadAddress:"+JSON.stringify(Socket.localAddress(fd))+",peerAddress"+JSON.stringify(Socket.peerAddress(fd)); return res; }else{ return"type:"+socketType; } } functiongetSocketData2(stream){ var data0=stream.this$0.value; var sockdata=data0.socket.value; return sockdata; } functionhook_ssl(){ var NativeCryptoClass= Java.use("com.android.org.conscrypt.NativeCrypto"); NativeCryptoClass.SSL_write.implementation=function(sslPtr,fd,shc,b,off,len,timeout){ console.log("enter SSL_write"); print_bytes(b); returnthis.SSL_write(sslPtr,fd,shc,b,off,len,timeout); }; NativeCryptoClass.SSL_read.implementation=function(sslPtr,fd,shc,b,off,len,timeout){ console.log("enter SSL_read"); var res=this.SSL_read(sslPtr,fd,shc,b,off,len,timeout); print_bytes(b); return res; }; } //SSLOutputStream write(byte[] buf, int offset, int byteCount) //SSLInputStream read(byte[] buf, int offset, int byteCount) functionhook_ssl2(){ var SSLOutputClass=Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream"); SSLOutputClass.write.overload('[B', 'int', 'int').implementation=function(buf,off,cnt){ console.log(getSocketData2(this)); print_bytes(buf); returnthis.write(buf,off,cnt); }; var SSLInputClass=Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream"); SSLInputClass.read.overload('[B', 'int', 'int').implementation=function(buf,off,cnt){ var res=this.read(buf,off,cnt); console.log(getSocketData2(this)); print_bytes(buf); return res; } } //jni的ssl的加密数据hook functionhook_jni_ssl_enc(){ var writePtr=Module.getExportByName("libc.so","write"); var readPtr=Module.getExportByName("libc.so","read"); console.log("write:",writePtr,",read:",readPtr); Interceptor.attach(writePtr,{ onEnter:function(args){ var fd=args[0]; var buff=args[1]; var size=args[2]; var sockdata=getSocketData(fd.toInt32()); if(sockdata.indexOf("tcp")){ console.log(sockdata); console.log(hexdump(buff,{length:size.toInt32()})); } }, onLeave:function(retval){
} }); Interceptor.attach(readPtr,{ onEnter:function(args){ this.fd=args[0]; this.buff=args[1]; this.size=args[2]; }, onLeave:function(retval){ var sockdata=getSocketData(this.fd.toInt32()); if(sockdata.indexOf("tcp")){ console.log(sockdata); console.log(hexdump(this.buff,{length:this.size.toInt32()})); } } }); } //jni的ssl明文数据hook functionhook_jni_ssl(){ var sslWritePtr=Module.getExportByName("libssl.so","SSL_write"); var sslReadPtr=Module.getExportByName("libssl.so","SSL_read"); console.log("sslWrite:",sslWritePtr,",sslRead:",sslReadPtr); var sslGetFdPtr=Module.getExportByName("libssl.so","SSL_get_rfd"); var sslGetFdFunc=new NativeFunction(sslGetFdPtr,'int',['pointer']);
//int SSL_write(SSL *ssl, const void *buf, int num) Interceptor.attach(sslWritePtr,{ onEnter:function(args){ var sslPtr=args[0]; var buff=args[1]; var size=args[2]; var fd=sslGetFdFunc(sslPtr); var sockdata=getSocketData(fd); console.log(sockdata); console.log(hexdump(buff,{length:size.toInt32()}));
}, onLeave:function(retval){
} }); //int SSL_read(SSL *ssl, void *buf, int num) Interceptor.attach(sslReadPtr,{ onEnter:function(args){ this.sslPtr=args[0]; this.buff=args[1]; this.size=args[2]; }, onLeave:function(retval){ var fd=sslGetFdFunc(this.sslPtr); var sockdata=getSocketData(fd); console.log(sockdata); console.log(hexdump(this.buff,{length:this.size.toInt32()})); } }); }
functionhook_jni_tcp(){ var sendtoPtr=Module.getExportByName("libc.so","sendto"); var recvfromPtr=Module.getExportByName("libc.so","recvfrom"); console.log("sendto:",sendtoPtr,",recvfrom:",recvfromPtr); //sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len) Interceptor.attach(sendtoPtr,{ onEnter:function(args){ var fd=args[0]; var buff=args[1]; var size=args[2]; var sockdata=getSocketData(fd.toInt32()); console.log(sockdata); console.log(hexdump(buff,{length:size.toInt32()})); }, onLeave:function(retval){
} }); //recvfrom(int fd, void *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len) Interceptor.attach(recvfromPtr,{ onEnter:function(args){ this.fd=args[0]; this.buff=args[1]; this.size=args[2]; }, onLeave:function(retval){ var sockdata=getSocketData(this.fd.toInt32()); console.log(sockdata); console.log(hexdump(this.buff,{length:this.size.toInt32()})); } }); }
val resourceStream = resources.openRawResource(R.raw.infinisign_cert) val keyStoreType = KeyStore.getDefaultType() val keyStore = KeyStore.getInstance(keyStoreType) keyStore.load(resourceStream, null) val trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm() val trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm) trustManagerFactory.init(keyStore) val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustManagerFactory.trustManagers, null) val url = URL("http://infinisign.com/") val urlConnection = url.openConnection() as HttpsURLConnection urlConnection.sslSocketFactory = sslContext.socketFactory