网络抓包06 - Socket抓包

TCP

            thread {
                val socket = Socket("xx.xxx.xxx.xx", 8888)
                socket.soTimeout = 3000
                val os = socket.getOutputStream()
                Log.e("Socket", "class name = ${os::class.java.canonicalName}")
                os.write(0x00)
            }

运行代码,得知 OutputStream 是 SocketOutputStream 。

调用 write 相关方法,跟踪方法堆栈会走到:

    private native void socketWrite0(FileDescriptor fd, byte[] b, int off,
                                     int len) throws IOException;

对应 jni 方法为:

/*
 * Class:     java_net_SocketOutputStream
 * Method:    socketWrite0
 * Signature: (Ljava/io/FileDescriptor;[BII)V
 */
JNIEXPORT void JNICALL
SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
                                              jobject fdObj,
                                              jbyteArray data,
                                              jint off, jint len) 

继续往下跟踪可以得知它调用了 Net_send 方法。

我们还可以使用 IDA 来帮助分析其方法调用链。

先看 SocketOutputStream.c 被编译到了哪个 so 文件里面。

搜索 SocketOutputStream.c,发现在  里面:

filegroup {
    name: "libopenjdk_native_srcs",
    visibility: [
        "//libcore",
    ],
    srcs: [
        "SocketOutputStream.c",
    ],
}

搜索 libopenjdk_native_srcs,发现在  里面:

cc_defaults {
    name: "libopenjdk_native_defaults",
    srcs: [":libopenjdk_native_srcs"],

搜索 libopenjdk_native_defaults,发现:

cc_library_shared {
    name: "libopenjdk",
    visibility: [
        "//art/build/apex",
    ],
    apex_available: [
        "com.android.art",
        "com.android.art.debug",
    ],
    defaults: ["libopenjdk_native_defaults"],
    shared_libs: [
        "libopenjdkjvm",
    ],
}

// Debug version of libopenjdk. Depends on libopenjdkjvmd.
cc_library_shared {
    name: "libopenjdkd",
    visibility: [
        "//art/build/apex",
    ],
    apex_available: [
        "com.android.art.debug",
    ],
    defaults: ["libopenjdk_native_defaults"],
    shared_libs: [
        "libopenjdkjvmd",
    ],
}

编译出来的 so 叫 libopenjdk,如果是 debug 编译的后面带个 d。

使用 find 命令找到文件位置(不同的Android版本位置不一样),将 libopenjdk.so 拖出来,放到 IDA 里面看,因为系统代码是不会混淆的,所以非常方便的可以找到符号位置:

.text:000000000002A64C                               EXPORT SocketOutputStream_socketWrite0
.text:000000000002A64C                               SocketOutputStream_socketWrite0         ; DATA XREF: LOAD:0000000000001DC0↑o
.text:000000000002A64C                                                                       ; .data:0000000000037CE0↓o
.text:000000000002A64C
.text:000000000002A64C                               var_10018= -0x10018
.text:000000000002A64C                               s= -0x10010
.text:000000000002A64C                               var_10= -0x10
.text:000000000002A64C                               var_s0=  0
.text:000000000002A64C                               var_s10=  0x10
.text:000000000002A64C                               var_s20=  0x20
.text:000000000002A64C                               var_s30=  0x30
.text:000000000002A64C                               var_s40=  0x40
.text:000000000002A64C                               var_s50=  0x50
.text:000000000002A64C
.text:000000000002A64C                               ; __unwind {

右键查看调用图:

可以看到,红色圈圈的这条调用链看名字就很可疑,实际上也确实是发送数据的调用链方法。

最后的 sendto 方法是紫色的,我们看看:

.plt:00000000000337F0                               ; ssize_t sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len)
.plt:00000000000337F0                               .sendto                                 ; CODE XREF: Java_sun_nio_ch_DatagramChannelImpl_send0+BC↑p
.plt:00000000000337F0                                                                       ; Java_sun_nio_ch_DatagramDispatcher_write0+38↑p
.plt:00000000000337F0                                                                       ; Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData+40↑p
.plt:00000000000337F0                                                                       ; NET_Send+54↑p
.plt:00000000000337F0                                                                       ; NET_SendTo+5C↑p
.plt:00000000000337F0 10 00 00 D0                   ADRP            X16, #off_356D8@PAGE
.plt:00000000000337F4 11 6E 43 F9                   LDR             X17, [X16,#off_356D8@PAGEOFF]
.plt:00000000000337F8 10 62 1B 91                   ADD             X16, X16, #off_356D8@PAGEOFF
.plt:00000000000337FC 20 02 1F D6                   BR              X17

到了 plt 里面,说明调用的是其他 so 中的方法,其实就是 libc.so 中的方法。

将 libc.so 拖出来,找到 sendto 方法看看,sendto 会调用到 __sendto 里面,还注意到系统调用使用的寄存器是 X8:

.text:00000000000A2F00                               ; =============== S U B R O U T I N E =======================================
.text:00000000000A2F00
.text:00000000000A2F00
.text:00000000000A2F00                               ; unsigned __int64 __fastcall _sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t)
.text:00000000000A2F00                               __sendto                                ; DATA XREF: .data:off_C6BE0↓o
.text:00000000000A2F00                               ; __unwind {
.text:00000000000A2F00 C8 19 80 D2                   MOV             X8, #0xCE
.text:00000000000A2F04 01 00 00 D4                   SVC             0
.text:00000000000A2F08 1F 04 40 B1                   CMN             X0, #1,LSL#12
.text:00000000000A2F0C 00 94 80 DA                   CNEG            X0, X0, HI
.text:00000000000A2F10 28 67 FF 54                   B.HI            __set_errno_internal
.text:00000000000A2F10
.text:00000000000A2F14 C0 03 5F D6                   RET
.text:00000000000A2F14                               ; } // starts at A2F00

可以看到,这里有个系统调用,值是 0xCE,也就是 206。看看 206 表示的意思:

#define __NR_sendto 206
__SYSCALL(__NR_sendto, sys_sendto)

所以,我们甚至可以直接使用系统调用来发送 socket 请求。

与 sendto 对应的 recvfrom 是一样的分析过程,就不赘述了。

UDP

运行代码:

            thread {
                val buf: ByteArray = "hello android! ".toByteArray()
                val sendSocket = DatagramSocket()
                val serverAddress = InetAddress.getByName("10.249.50.96")
                val outPacket = DatagramPacket(buf, buf.size, serverAddress, 8889)
                sendSocket.send(outPacket)
                sendSocket.close()
            }

断点得到堆栈:

sendto:724, ForwardingOs (libcore.io)
sendto:689, IoBridge (libcore.io)
send:126, PlainDatagramSocketImpl (java.net)
send:721, DatagramSocket (java.net)
invoke:31, SocketActivity$fillButtonLayout$2$1 (com.aprz.mytestdemo.socket)
invoke:26, SocketActivity$fillButtonLayout$2$1 (com.aprz.mytestdemo.socket)
run:30, ThreadsKt$thread$thread$1 (kotlin.concurrent)

最后会走到 libcore.io.Linux 类的 sendtoBytes 方法:

    private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
    private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;

对应JNI方法为:

static jint Linux_sendtoBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaInetAddress, jint port) {
    ScopedBytesRO bytes(env, javaBytes);
    if (bytes.get() == NULL) {
        return -1;
    }

    return NET_IPV4_FALLBACK(env, ssize_t, sendto, javaFd, javaInetAddress, port,
                             NULL_ADDR_OK, bytes.get() + byteOffset, byteCount, flags);
}

可以看到,它也是调用了 sendto 方法。

所以只需要 hook libc 的 sendto 与 recvfrom 就可以拿到 tcp 与 udp socket 的所有数据。

SSLSocket

之前我们分析了 SSLSocket 的调用堆栈,我们关注的是 SSL_read 与 SSL_write方法。

SSLSocket 也是一个 Socket,当我们 hook 了 sendto 与 recvfrom 方法之后,能拿到 SSLSocket 的数据吗?

实际上是不能的,因为SSL_write 并不是调用的 sendto 方法:

SSL_write ->
ssl->method->write_app_data ->
tls_write_app_data ->
do_tls_write ->
ssl_write_buffer_flush(ssl); ->
tls_write_buffer_flush(ssl); ->
BIO_write(ssl->wbio.get(), buf->data(), buf->size());

static const BIO_METHOD methods_sockp = {
    BIO_TYPE_SOCKET, "socket",
    sock_write,      sock_read,
    NULL /* puts */, NULL /* gets, */,
    sock_ctrl,       NULL /* create */,
    sock_free,       NULL /* callback_ctrl */,
};

最后到了 socket_write 方法:

static int sock_write(BIO *b, const char *in, int inl) {
  bio_clear_socket_error();
#if defined(OPENSSL_WINDOWS)
  int ret = send(b->num, in, inl, 0);
#else
  int ret = (int)write(b->num, in, inl);
#endif
  BIO_clear_retry_flags(b);
  if (ret <= 0) {
    if (bio_socket_should_retry(ret)) {
      BIO_set_retry_write(b);
    }
  }
  return ret;
}

所以,我们可以 hook libc 的 write 与 read 方法,可以得到 SSLSocket 的数据,不过这里的数据是加密了的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891471.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 工具库每日推荐 【sqlparse】

文章目录 引言SQL解析工具的重要性今日推荐:sqlparse工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:SQL查询分析器案例分析高级特性自定义格式化处理多个语句扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 Python工具库每日推荐 专…

文件的读写、FileStream

//现在在desktop\10.13文件夹下的读写文件,由上知空空如也。 if (File.Exists(@"C:\Users\11442\Desktop\10.13\FILE.txt")) { File.Delete(@"C:\Users\11442\Desktop\10.13\FILE.txt"); File.Create(@"C:\Users\11442\Desktop\10.13\FIL…

(IOS)VMware虚拟机上安装win10系统(超详细)

简介 虚拟机是一种软件实现的计算机系统&#xff0c;可以在现有的操作系统平台上运行一个或多个虚拟的操作系统。它通过在主机操作系统上创建一个虚拟的硬件平台&#xff0c;并在其上运行一个完整的操作系统&#xff0c;来模拟一个真实的物理计算机。虚拟机可以提供一种隔离的…

多线程代码案例

案例一.单例模式 单例模式是一种设计模式;类似于棋谱,有固定套路,针对一些特定场景可以给出一些比较好的解决方案; 只要按照设计模式来写代码,就可以保证代码不会太差,保证了代码的下限; --------------------------------------------------------------------------------…

接口测试面试题含答案

1、解释一下正向和逆向测试。 正向测试&#xff1a;针对接口设计预期的功能和行为&#xff0c;验证接口是否按照预期工作。 逆向测试&#xff1a;针对错误输入、不合理的条件或非预期的使用方式&#xff0c;验证接口是否能够适当地处理这些情况并提供合理的错误处理。 2、什…

Windows11下 安装 Docker部分疑难杂症(Unexpecter WSL error)

装了大半天Docker desktop终于装好了&#xff0c;网上有的主流教程就不复述了&#xff0c;主要说一下网上没有的教程。 以下是遇到的问题&#xff1a; 首先&#xff0c;启用或关闭Windows确保里面与虚拟机有关的几个都要选上 没有Hyper-V参考此文 但是我这里都勾选了&#x…

Unity/VS 消除不想要的黄色警告

方法一&#xff1a;单个消除 在要关闭的代码前一行写上#pragma warning disable 警告代码编码 在要关闭代码行下面一行写上#pragma warning restore 警告代码编码 精准的关闭指定地方引起的代码警告&#xff0c;不会过滤掉无辜的代码 #pragma warning disable 0162,1634HandleL…

react实现实时计时的最简方式

js中时间的处理&#xff0c;不借助于moment/dayjs这样的工具库&#xff0c;原生获取格式化的时间&#xff0c;最简单的实现方式可以参考下面这样。 实现效果 代码实现 封装hooks import { useState, useEffect } from "react";export function useCountTime() {c…

C语言笔记 14

函数原型 函数的先后关系 我们把自己定义的函数isPrime()写在main函数上面 是因为C的编译器自上而下顺序分析你的代码&#xff0c;在看到isPrime的时候&#xff0c;它需要知道isPrime()的样子——也就是isPrime()要几个参数&#xff0c;每个参数的类型如何&#xff0c;返回什么…

图解C#高级教程(五):枚举器和迭代器

本章主要介绍 C# 当中枚举器、可枚举类型以及迭代器相关的知识。 文章目录 1. 枚举器和可枚举类型2. IEnumerator 和 IEnumerable 接口2.1 IEnumerator 接口2.2 IEnumerable 接口 3. 泛型枚举接口4. 迭代器4.1 使用迭代器创建枚举器4.2 使用迭代器创建可枚举类4.3 迭代器作为属…

uni-app 打包成app时 限制web-view大小

今天对接一个uni-app的app 内置对方h5 web-view的形式 需要对方在web-view顶部加点东西 对方打的app的web-view始终是全屏的状态&#xff0c;对方表示做不到我要的效果 emmmmmm。。。。。。 于是乎 自己搭了个demo 本地h5跑起来审查了下代码&#xff0c;发现web-view是给绝对定…

IP地址与CDN提升网络速度

视频流媒体、在线游戏、或是电商购物&#xff0c;互联网在我们的工作生活中愈加不可或缺&#xff0c;人们对于网络的加载速度要求也越来越严苛。而IP地址与CDN的协同工作&#xff0c;对于互联网速度增加与稳定起这重大的作用。 一、CDN的工作原理 CDN是由分布在全球各地的服务…

基于JAVA+SpringBoot+Vue的旅游管理系统

基于JAVASpringBootVue的旅游管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈喽兄…

使用XML实现MyBatis的基础操作

目录 前言 1.准备工作 1.1⽂件配置 1.2添加 mapper 接⼝ 2.增删改查操作 2.1增(Insert) 2.2删(Delete) 2.3改(Update) 2.4查(Select) 前言 接下来我们会使用的数据表如下&#xff1a; 对应的实体类为&#xff1a;UserInfo 所有的准备工作都在如下文章。 MyBatis 操作…

【论文速看】DL最新进展20241015-目标检测、图像超分

目录 【目标检测】【图像超分】 【目标检测】 [ECCV2024] LaMI-DETR: Open-Vocabulary Detection with Language Model Instruction 论文链接&#xff1a;https://arxiv.org/pdf/2407.11335 代码链接&#xff1a;https://github.com/eternaldolphin/LaMI-DETR 现有方法通过利…

Android ImageView scaleType使用

目录 一、src设置图片资源 二、scaleType设置图片缩放类型 三、scaleType具体表现 matrix&#xff1a; fitXY: fitStart&#xff1a; fitCenter&#xff1a; fitEnd: Center&#xff1a; centerCrop: centerInside&#xff1a; 控制ImageView和图片的大小保持一致…

【优选算法】(第四十一篇)

目录 被围绕的区域&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 迷宫中离⼊⼝最近的出⼝&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 被围绕的区域&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&a…

创建docker虚拟镜像,创建启动服务脚本

进入系统命令服务目录 编辑服务 [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/…

[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。

[旧日谈]关于Qt的刷新事件频率&#xff0c;以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。 最近在开发的时候&#xff0c;发现一个依赖事件来刷新渲染的控件会导致程序很容易异常和崩溃。 当程序在运行的时候&#xff0c;其实软件本身的负载并不高&#xff0c;所以…

【量化交易】聚宽安装

安装JQData 更换源&#xff1a; 如果使用的是pip默认的PyPI源&#xff0c;可以尝试更换为一个更快的国内镜像源。例如阿里云、豆瓣等提供的PyPI镜像。 更改方法可以通过设置环境变量或者在pip命令中直接指定&#xff1a; PS C:\Users\bilirjs\Documents> pip config set …