TK抓包协议分析:So层逆向

环境

  • 手机
    • 小米8
  • 版本
    • 33.4.3

准备

  • 抓包失败

  • 开了抓包以后APP直接是网络无连接了,并且抓到的请求也是不正常的,下面我们就开始定位

日志分析

  • 可以从日志分析入手,看看有没有什么异常的报错

  • 使用 adb logcat 命令查看

      1. 先用 adb logcat -c 请一下日志
      2. 执行 adb logcat 命令
      3. 然后打开tiktok app
      4. 出现发生错误这个页面后停止 adb locat 命令
      5. 把文件保存到本地进行分析
  • 定位(整个日志中,只有此处有发送网络请求而且失败,所以一眼定位这里)

    图片描述

  • 日志里找到有一个请求URL的位置并且有一个|Exception in CronetUrlRequest 像是网络错误的请求所以分析一下这个位置

jadx反编译

  1. 拿上面的这个Exception in CronetUrlRequest 去jdax里进行搜索

  2. 上面搜索到三个位置,后两个是同一个函数,所以hook一下这两个地方,打印下堆栈

  3. 直接右键复制为Frida片段就可以了

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    Java.perform(function () {

        let g = Java.use("org.chromium.g");

        g["LIZ"].implementation = function (i, i2, str) {

            console.log(`g.LIZ is called: i=${i}, i2=${i2}, str=${str}`);

            let result = this["LIZ"](i, i2, str);

            console.log(`g.LIZ result=${result}`);

            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

            return result;

        };

        let CronetUrlRequest = Java.use("com.ttnet.org.chromium.net.impl.CronetUrlRequest");

        CronetUrlRequest["onError"].implementation = function (i, i2, i3, str, j) {

            console.log(`CronetUrlRequest.onError is called: i=${i}, i2=${i2}, i3=${i3}, str=${str}, j=${j}`);

            this["onError"](i, i2, i3, str, j);

            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

        };

    })

  4. 打印结果

  5. 上面图片可以看到所有的打印都是走的CronetUrlRequest.onError这个函数,他是一个Native层的方法 那下面来分析一下So层

定位So

  • 直接把app文件 重命名一下 .apk 改为.zip

  • 直接找到tiktok-33-4-3.zip\lib\arm64-v8a 这里面有很多so文件,怎么定位到我们需要的so文件那

  • 我这里使用grep进行搜索

    grep的作用就是搜索到我们要定位的字符串在那个So文件里

    grep的安装可以看这个 https://blog.youkuaiyun.com/qq_29752857/article/details/140169107

  1. 把.apk后缀改为.zip

  2. 压解到一个文件夹

  3. cd 到解压文件夹的 \lib\arm64-v8a目录 打开cmd

  4. 执行命令 grep -r "CronetUrlRequest" *

    图片描述

  5. 显示在 libsscronet.so 这个So文件中

分析So

  • \lib\arm64-v8a下面找到libsscronet.so这个文件丢到ida64中

  • 按Shift F12 字符串搜索 CronetUrlRequest

    图片描述

  • 点击com/ttnet/org/chromium/net/impl/CronetUrlRequest

    图片描述

  • 进入sub_190028+8↓o 然后按tab键

    图片描述

  • Hook下这个位置 190028

    • 这里为了方便注释Hook的代码,拆分开写的

    • 主函数

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      function hook_dlopen(module_name, fun) {

          var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

          if (android_dlopen_ext) {

              Interceptor.attach(android_dlopen_ext, {

                  onEnter: function (args) {

                      pass

                  },

                  onLeave: function (retval) {

                      passa

                  }

              });

          }

      }

      function main() {

          hook_dlopen("libsscronet.so")

      }

      setImmediate(main)

      • 注释
        • Hook android_dlopen_ext 监控 .so 加载
        • 判断是不是我们要hook的"libsscronet.so"文件
    • onEnter

      1

      2

      3

      4

      5

      6

      7

      8

      9

      onEnter: function (args) {

          var pathptr = args[0];  // 读取第一个参数,它是一个指向动态库路径的指针

          if (pathptr) {  // 确保指针有效,避免 `null` 访问错误

              this.path = pathptr.readCString();  // 将指针解析成字符串,得到动态库的路径

              if (this.path.indexOf(module_name) >= 0) {  // 判断路径是否包含目标库名

                  this.canhook = true// 发现目标库,标记 `this.canhook = true`,表示可以 hook

              }

          }

      }

      • 注释
        1. onEnter 在目标函数(android_dlopen_ext)执行前触发
        2. 如果路径是否包含目标库名,把canhook设置为True
    • onLeave

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      onLeave: function (retval) { 

          if (this.canhook) {  // 只有在 onEnter 里确认目标库被加载了,才会执行 hook 逻辑

              let base_libsscronet = Module.findBaseAddress("libsscronet.so");  // 获取 libsscronet.so 的基地址

              let sub_190028 = base_libsscronet.add(0x190028);  // 计算 sub_190028 函数的地址(基地址 + 偏移 0x190028)

              console.log("hook", sub_190028);  // 打印目标函数的地址,便于调试

              Interceptor.attach(sub_190028, {  // Hook 目标函数

                  onEnter(args) { 

                      console.log("sub_190028 called, return address:", DebugSymbol.fromAddress(this.returnAddress)); 

                      // `this.returnAddress` 是调用 `sub_190028` 的上层函数的返回地址

                      // `DebugSymbol.fromAddress` 解析该地址,尝试获取调用 `sub_190028` 的函数名

                  }

              });

          }

      }

      • 注释

        1. this.returnAddress 返回的是调用者的地址

        2. DebugSymbol.fromAddress 是为了把地址转为函数名

  • 打印结果

  • 按G跳转到 0x18fae8

    • 偏移量在V16上
  • 点进 sub_18209C这个函数

    • .cc 文件是 C++ 源代码文件,它的作用与 .cpp 文件相同,通常用于存放 C++ 代码
  • 跟进sub_182194

  • 看到这块信息Hook一下 sub_20E814

    可以看到第二个是一个String ,所以hook代码要修改一下把第二个参数String也打印

    onLeave: function (retval) {  
        if (this.canhook) {  
            let base_libsscronet = Module.findBaseAddress("libsscronet.so");  
            let sub_20E814 = base_libsscronet.add(0x20E814);  
            console.log("hook", sub_20E814);  
            Interceptor.attach(sub_20E814, {  
                onEnter(args) {  
                    console.log("sub_20E814 called, return address:",args[1].readCString()), DebugSymbol.fromAddress(this.returnAddress);  
                }
            });
        }
    }
    
  • 输出结果

    图片描述

    • 这个地方明显不是,app已经出现连接失败了,后面过了一会才有的打印,说明这个打印已经晚了,如果是我们想要的位置,他应该在检测中进行打印
    • 上面的输出其实并没有什么有效信息

    分析引用

  • 那这样我们线索已经断了,先按X看一下这个函数都是有谁引用了 看看有没有线索

    • 看了半天感觉也没啥有用的东西,那下面我们整理一下已经有信息,来猜测一下,后续怎么进行

      1. 那目前我们根据已经有信息,看到代码里有用 ../../net/tt_net/ipc/ipc_channel_reader.cc" 这样的方式去写的

      2. 那可以猜测,我们真正需要Hook的那个函数也有可能是这样加载的,可以字符串搜索一下../../

      3. 看到有几个目录net base components等,我们是为了解决抓包问题,那很有可能是在net目录下(network),那来搜索一下 ../../net

      4. 还是比较多的,这个时候可以有选择的看一下,跟网络请求相关的quic ssl

      5. 最后定位到是 ../../net/socket/ssl_client_socket_impl.cc这个文件

    • 然后点进来看一下

      图片描述

    • hook下 20E7EC

    • 看到有一个叫HandleVerifyResult比较像,我们跳进去看一下0x3174dc

      • 如果打印不出 HandleVerifyResult 可以换个手机试下

    • 然后向上滑找到函数看一下是谁在引用, 因为怀疑这一段是 错误处理 所以先看一下谁调用他

      图片描述

    • 这里有两个点那个都可以,最后都是一个位置,进来之后继续找到函数看一下引用

      图片描述

    • 接着点进去,进去以后看到很多个函数都点开看一下,最后定位到sub_4913E8()上面

    • 我们可以搜一下SSL_CTX_set_custom_verify这是什么意思

    • 第三个参数是一个回调函数,这里他的返回值1表示成功,0表示失败,那我们手动把他Hook为0,让他不支持quic协议,实现降级

    • 就能成功绕过校验了~!

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      function hook_dlopen(module_name, fun) {

          var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

          if (android_dlopen_ext) {

              Interceptor.attach(android_dlopen_ext, {

                  onEnter: function (args) {

                      var pathptr = args[0];

                      if (pathptr) {

                          this.path = (pathptr).readCString();

                          if (this.path.indexOf(module_name) >= 0) {

                              this.canhook = true;

                          }

                      }

                  },

                  onLeave: function (retval) {

                      if (this.canhook) {

                          let verifyadd = Module.getExportByName("libsscronet.so","SSL_CTX_set_custom_verify");

                          Interceptor.attach(verifyadd,{

                              onEnter(args){

                                  Interceptor.attach(args[2],{

                                      onLeave(retval){

                                          retval.replace(0x0);

                                      }

                                  })

                              }

                          })

                      }

                  }

              });

          }

      }

成功搞定

  • 就可以抓包并且上TikTok了

<think>好的,用户现在提到在设备上找不到/storage/emulated/0/Android/data/com.snssdk.api.embed目录对应的应用,怀疑可能是头条系软件如抖音的SDK创建的。我需要帮他分析这个可能性。 首先,我需要回忆一下Android应用的存储结构。通常,每个应用在Android/data下有自己的包名目录,用于存储应用数据。用户提到的路径中的包名是com.snssdk.api.embed,看起来像是SDK的包名,而不是主应用。比如,抖音的包名通常是com.ss.android.ugc.aweme,而头条是com.ss.android.article.video,所以这个包名明显不同。 接下来,用户猜测是头条系软件的SDK。字节跳动确实有很多SDK,比如登录、分享、广告等。很多SDK会以com.ss或com.bytedance开头,但用户提到的包名里有snssdk,这可能和社交网络服务SDK有关。比如,之前了解过抖音的SDK可能有不同的命名方式,但需要确认。 然后,用户想用抖音举例。假设抖音集成了某个SDK,该SDK可能需要独立存储数据,因此会创建自己的目录。比如,如果抖音使用了com.snssdk.api.embed这个SDK,可能在安装时该SDK作为依赖库被包含进来,但不会在应用列表里显示为一个独立应用。这时候,用户找不到对应的应用是正常的,因为这个包名属于SDK而非独立应用。 另外,用户可能担心这个目录的存在是否有隐私风险。需要解释SDK可能会存储缓存或临时数据,但如果是正规的SDK,通常会遵循数据存储规范,将数据存放在应用的私有目录中。不过,如果路径在Android/data下,其他应用无法直接访问,相对安全。但用户可能需要确认该目录是否属于已安装的应用的SDK。 然后,我需要提供用户检查的方法,比如通过包名查找应用,或者使用ADB命令查看已安装的包。如果查不到,很可能是SDK的目录。此外,用户可能想知道如何安全处理这个目录,比如清理缓存或删除,但需要提醒谨慎操作,避免影响应用功能。 最后,要总结可能性,并给出建议。确认该目录很可能是某应用集成的SDK创建的,尤其是头条系的应用如抖音,但需要进一步验证。同时,指导用户如何检查和应对,确保隐私安全。</think>--- ### **目录归属分析与可能性推测** 你提到的目录 `/storage/emulated/0/Android/data/com.snssdk.api.embed` 属于Android应用私有数据存储区域(`Android/data`),其命名规则通常遵循应用包名。 根据包名 `com.snssdk.api.embed` 的结构和命名习惯,**该目录极有可能是字节跳动(头条系)旗下某个SDK或服务的私有数据目录**。以下是具体分析: --- #### **1. 包名结构与头条系SDK的关联** - **包名特征**: - `com.snssdk`:`snssdk` 可能是 "Social Network Service SDK" 的缩写,与头条系的社交服务相关。 - `api.embed`:可能表示该SDK用于嵌入其他应用的API服务(例如登录、分享、视频播放等)。 - **头条系SDK的命名规律**: 字节跳动常用包名前缀包括 `com.ss`(如抖音国际版TikTok的包名 `com.ss.android.ugc.aweme`)或 `com.bytedance`(如抖音主包 `com.bytedance.sdk.openadsdk`)。 **`com.snssdk` 可能是其细分业务线(如社交功能SDK)的独立包名**。 --- #### **2. 可能性分析:与抖音的关联** **假设场景**:抖音(包名 `com.ss.android.ugc.aweme`)集成了 `com.snssdk.api.embed` 作为其SDK,用于实现以下功能: - **跨应用登录**:允许用户通过抖音账号登录第三方应用。 - **内容嵌入**:在其他应用中嵌入抖音视频播放器或推荐流。 - **数据采集**:收集用户行为数据(如观看时长、互动行为)用于广告推荐。 **目录作用**: 该目录可能存储SDK运行所需的缓存文件、配置文件或临时数据,例如: - 登录令牌(Token) - 视频缓存片段 - 埋点日志(用户行为记录) --- #### **3. 为何找不到对应应用?** - **SDK的隐蔽性**: `com.snssdk.api.embed` 是**内嵌在宿主应用(如抖音)中的SDK**,而非独立安装的APP,因此不会出现在应用列表里。 类似案例:微信的支付SDK包名为 `com.tencent.mm.opensdk`,但用户无法直接找到对应的“微信支付”应用。 - **厂商策略**: 头条系可能通过以下方式隐藏SDK的可见性: - 不注册桌面图标(无`Launcher Activity`)。 - 在`AndroidManifest.xml`中声明为系统组件(如`Service`或`ContentProvider`)。 --- #### **4. 验证方法** 若要确认该目录与抖音(或其他头条系应用)的关联,可通过以下步骤排查: 1. **查看目录更新时间**: - 进入 `/storage/emulated/0/Android/data/com.snssdk.api.embed`,检查文件修改时间。 - **操作抖音**(如播放视频、登录账号),观察目录内文件是否同步更新。 2. **通过ADB查询包信息**(需开启USB调试): ```bash adb shell pm list packages | grep "snssdk" ``` 若返回 `package:com.snssdk.api.embed`,说明该包已安装,但未暴露给用户界面。 3. **检查SDK依赖关系**: - 使用反编译工具(如`jadx`)打开抖音APK,查看其依赖库中是否包含 `com.snssdk.api.embed`。 - 搜索`build.gradle`中是否声明类似依赖: ```gradle implementation 'com.snssdk.api:embed:1.x.x' ``` --- #### **5. 安全与隐私建议** - **数据风险**: 若该目录存储了设备标识符(如IMEI)、行为日志等敏感信息,可能涉及隐私问题。可通过检查文件内容(需Root权限)初步判断。 - **应对措施**: - **清理缓存**:通过手机设置 → 存储 → 清理抖音缓存(可能连带清除SDK数据)。 - **限制权限**(需ADB): ```bash adb shell pm revoke com.snssdk.api.embed android.permission.READ_EXTERNAL_STORAGE adb shell pm revoke com.snssdk.api.embed android.permission.WRITE_EXTERNAL_STORAGE ``` - **物理删除目录**: 直接删除 `/Android/data/com.snssdk.api.embed`,但可能导致宿主应用(如抖音)功能异常。 --- ### **总结** 该目录大概率属于头条系SDK(如抖音、今日头条)的私有数据存储区,用于实现跨应用功能或数据采集。由于SDK不独立安装,用户无法直接关联到具体应用。若对隐私有顾虑,可通过清理缓存或限制权限减少风险,但需权衡功能完整性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值