乐于分享
好东西不私藏

ios逆向某购物app谷歌cronet抓包检测绕过

ios逆向某购物app谷歌cronet抓包检测绕过

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关;本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文涉及的技术而导致的任何意外,作者均不负责。

抓包分析

打开app下拉抓主页抓包

可以看到抓不到商品信息的数据只有一些零散的无用数据

先猜测可能是常见的sslpinning

ios里面用ssl kill switch 开启下试一试

还是不行依旧是一些无用数据

脱壳分析

脱壳

依旧用CrackerXI 先关app 再脱壳

一般情况下都在这个路径

iPhone:/var/mobile/Documents/CrackerXI root# pwd
/var/mobile/Documents/CrackerXI
iPhone:/var/mobile/Documents/CrackerXI root#

解压

unzip JD4iPhone_170234_CrackerXI.ipa

之后可以看到有一个Payload文件夹里面就是脱壳好的macho以及依赖文件

分析脱壳文件

参考来源
https://bbs.kanxue.com/thread-277996.htm

这文章介绍了cronet怎么才能抓到包,值得一看

所以我们需要找到cronet二进制文件并导入到本地

找到了在这个路径下
JD4iPhone.app\Frameworks\Cronet.framework
我们把下面的文件导入到本地并进行反编译分析

cronet反编译分析

谷歌源码链接
https://github.com/huningxin/chromium-old/blob/ddccd3f6dba62870a038ecb7d68b28038fcbe5d9/net/socket/ssl_client_socket_impl.cc#L347

源码中校验位置

  SSL_CTX_set_custom_verify(ssl_ctx_.get(), SSL_VERIFY_PEER,
                  CertVerifyCallback);

我们直接搜关键字没搜索到可以找一些特征值搜索

可以看到他下面有一个60 * 60 也就是3600
转一下16进制就是 0xE10
!!!这里不用考虑大小端因为是立即数
ida 搜索一下

一共涉及到三个函数我们一个一个看
前两个明显不是
第三个感觉比较像 3600是最后一个参数
贴一下反编译代码

__int64 sub_25A3DC()
{
  __int64 v0; // x19
  __int64 v1; // x0
  __int64 v2; // x0
  __int64 v3; // x0
  __int64 v4; // x21
  __int64 v5; // x0

  v0 = sub_BA758(16);
  *(_QWORD *)(v0 + 8) = 0;
  sub_340DBC();
  *(_DWORD *)v0 = sub_2E9678(0, 0, 0, 0, 0);
  v1 = sub_2F1BD4();
  v2 = sub_2E7BB8(v1);
  sub_2E9950(v0 + 8, v2);
  sub_2E50CC(*(_QWORD *)(v0 + 8), sub_25A4F0, 0);
  sub_2E970C(*(_QWORD *)(v0 + 8), 1);
  sub_2E9130(*(_QWORD *)(v0 + 8), 1, sub_2597E0);
  sub_2E9074(*(_QWORD *)(v0 + 8), 769);
  sub_2EBE88(*(_QWORD *)(v0 + 8), sub_25A520);
  sub_2EBDBC(*(_QWORD *)(v0 + 8), 3600);
  v3 = sub_2E9764(*(_QWORD *)(v0 + 8), 1);
  v4 = *(_QWORD *)(v0 + 8);
  v5 = sub_16F420(v3);
  sub_2E8E8C(v4, v5);
  sub_2E96C0(*(_QWORD *)(v0 + 8), sub_25A550);
  sub_2892E4(*(_QWORD *)(v0 + 8));
  return
 v0;
}

同时满足三个参数和最后一个函数的只有这个

 sub_2E9130(*(_QWORD *)(v0 + 8), 1, sub_2597E0);

所以说关键的函数应该是sub_2597E0

我们需要看下sub_2597E0干了什么

__int64 __fastcall sub_2597E0(__int64 a1)
{
  __int64 v2; // x0
  __int64 v3; // x0

  v2 = sub_25A340();
  v3 = sub_259808(v2, a1);
  return
 sub_259818(v3);
}

实际上应该返回数字代表状态,是否检验通过 实际的检测在sub_259818里面
如下 有兴趣的可以简单看下逻辑

__int64 __fastcall sub_259818(__int64 result)
{
  __int64 v1; // x19
  __int64 v2; // x0
  __int64 v3; // x0
  __int64 v4; // x22
  __int64 v5; // x1
  __int64 v6; // x0
  __int64 v7; // x1
  __int64 v8; // x22
  __int64 v9; // x23
  __int64 v10; // x24
  __int64 v11; // x0
  char
 v12; // nf
  char
 v13; // vf
  __int64 v14; // x8
  unsigned
 __int8 v15; // w9
  __int64 v16; // x10
  __int64 v17; // x11
  __int64 v18; // x21
  _QWORD *v19; // x25
  __int64 v20; // x26
  __int64 v21; // [xsp+18h] [xbp-168h] BYREF
  _QWORD v22[2]; // [xsp+20h] [xbp-160h] BYREF
  __int64 v23; // [xsp+30h] [xbp-150h] BYREF
  _QWORD v24[2]; // [xsp+38h] [xbp-148h] BYREF
  __int64 v25; // [xsp+50h] [xbp-130h] BYREF
  _QWORD v26[14]; // [xsp+58h] [xbp-128h] BYREF
  _QWORD v27[2]; // [xsp+C8h] [xbp-B8h] BYREF
  unsigned
 __int64 v28; // [xsp+D8h] [xbp-A8h] BYREF
  unsigned
 __int64 v29; // [xsp+E0h] [xbp-A0h] BYREF
  _QWORD v30[2]; // [xsp+E8h] [xbp-98h] BYREF
  unsigned
 __int64 v31; // [xsp+F8h] [xbp-88h] BYREF
  unsigned
 __int64 v32; // [xsp+100h] [xbp-80h] BYREF
  __int64 v33; // [xsp+108h] [xbp-78h] BYREF
  int
 v34; // [xsp+114h] [xbp-6Ch]
  _QWORD v35[3]; // [xsp+118h] [xbp-68h] BYREF

  v1 = result;
  if
 ( *(_DWORD *)(result + 296) != 1 )
    return
 sub_259B78(result);
  if
 ( !*(_QWORD *)(result + 136) )
  {
    v2 = sub_2E50D8(*(_QWORD *)(result + 304));
    v3 = sub_16F564(v2);
    sub_1E784(v1 + 136, v3);
    if
 ( *(_QWORD *)(v1 + 136) )
    {
      v4 = *(_QWORD *)(v1 + 904);
      if
 ( *(_DWORD *)(v4 + 68) )
      {
        memset
(v35, 170, sizeof(v35));
        sub_1229F8(v35);
        sub_16F0D4(v26, *(_QWORD *)(v1 + 136));
        sub_122B50(v35, "certificates", 12, v26);
        sub_12232C(v26);
        sub_122298(v26, v35);
        sub_122A54(v35);
        sub_25B0BC(v4, 74, v1 + 888);
        sub_12232C(v26);
      }
      v34 = -1431655766;
      if
 ( (unsigned int)sub_259D88(v1) )
      {
        sub_15E058(v1 + 144);
        *(_DWORD *)(v1 + 184) = v34;
        sub_25B194(&v33);
        sub_1E784(v1 + 176, v33);
        *(_DWORD *)(v1 + 296) = 0;
        return
 sub_259B78(v1);
      }
      *(_QWORD *)(v1 + 288) = sub_12090C();
      v6 = sub_259DD4(v1);
      v8 = v6;
      v9 = v7;
      if
 ( !v7 || (*(_BYTE *)(v1 + 799) = 1, !(unsigned int)sub_258BC4(v6, v7)) )
      {
        v31 = 0xAAAAAAAAAAAAAAAALL;
        v32 = 0xAAAAAAAAAAAAAAAALL;
        sub_2E91C0(*(_QWORD *)(v1 + 304), &v32, &v31);
        v30[0] = v32;
        v30[1] = v31;
        v28 = 0xAAAAAAAAAAAAAAAALL;
        v29 = 0xAAAAAAAAAAAAAAAALL;
        sub_2E916C(*(_QWORD *)(v1 + 304), &v29, &v28);
        v27[0] = v29;
        v27[1] = v28;
        v10 = *(_QWORD *)(*(_QWORD *)(v1 + 272) + 64LL);
        v11 = sub_25B194(&v25);
        if
 ( !v9 )
        {
          sub_25B168(v11);
          if
 ( v12 != v13 )
            v8 = v16;
          else

            v8 = v14;
          if
 ( v12 != v13 )
            v9 = v17;
          else

            v9 = v15;
        }
        v18 = sub_28B974(v1 + 384);
        v19 = v35;
        sub_EF4A4(v35, v30);
        if
 ( v35[2] >= 0 )
        {
          v20 = HIBYTE(v35[2]);
        }
        else

        {
          v19 = (_QWORD *)v35[0];
          v20 = v35[1];
        }
        sub_EF4A4(v24, v27);
        sub_15AEFC(v26, v25, v8, v9, v18, v19, v20);
        v22[0] = sub_259DF8;
        v22[1] = 0;
        v21 = v1;
        v23 = sub_25AB48(sub_25AB18, v22, &v21);
        *(_DWORD *)(v1 + 296) = (*(__int64 (__fastcall **)(__int64, _QWORD *, __int64, __int64 *, __int64, __int64))(*(_QWORD *)v10 + 16LL))(
                                  v10,
                                  v26,
                                  v1 + 144,
                                  &v23,
                                  v1 + 280,
                                  v1 + 888);
        sub_C822C(&v23);
        sub_15AFA8(v26);
        sub_BACF0(v24);
        sub_BACF0(v35);
        return
 sub_259B78(v1);
      }
      sub_D58C8(v26, "VerifyCert", "../../net/socket/ssl_client_socket_impl.cc", 1189);
      v5 = 4294967114LL;
    }
    else

    {
      sub_D58C8(v26, "VerifyCert", "../../net/socket/ssl_client_socket_impl.cc", 1143);
      v5 = 4294967129LL;
    }
    sub_2893C4(v26, v5);
    return
 1;
  }
  __break(0);
  return
 result;
}

我们已经定位到了检测点 我们开始写hook 看看能不能抓到包

frida hook

有两个思路,
1是hook检测函数
2是hookub_2E9130(*(_QWORD *)(v0 + 8), 1, sub_2597E0);这个函数入参
把最后一个参数函数进行替换
大家可以试一下
我用的是第二种

当然可以改一下源码重打包

一定记得用-f com.360buy.jdmobile 模式hook

我们这启动一下试一试
hook成功

抓包也成功了!!