【iOS逆向】某某小说content逆向分析

admin 2024年12月3日22:18:41评论23 views字数 10887阅读36分17秒阅读模式

0

前言

    文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口均已做脱敏处理。

    严正声明禁止用于商业和非法用途,否则由此产生的一切后果与作者本人无关。若有侵权,请在vx【amuncocoL】联系作者。

1

抓包及定位

iOS抓包章节详情如下:

【iOS逆向】某某小说content逆向分析

图中可见content像是base64编码,复制出来解码看是否为明文【iOS逆向】某某小说content逆向分析

【iOS逆向】某某小说content逆向分析

     很显然不行奥...

    那大概率是经过了某个算法加密后base64encode的。

    okay~  

    content是由接口返回,客户端进行解密后正常展示给用户浏览的

ps: 能直接解码就没必要记录咯 家银们... 

2

content解密定位
‍‍‍‍‍‍‍‍‍

第一步中我们已经怀疑了content是由base64编码的,那客户端收到响应后那第一步肯定是要先base64decode的,那我们先trace下看看 是否是这样的吧。

在Objective-C中base64解码是使用NSData类中的实例方法 

initWithBase64EncodedString:options:

使用frida-trace trace下 执行以下命令:

frida-trace -UF -m "-[NSData initWithBase64EncodedString:options:]"

【iOS逆向】某某小说content逆向分析

可以看到抓包的content和trace打印的入参是一致,那就证明我们的判断是正确的。content确实先进行base64decode,打印下堆栈继续往下跟~

0x103f51b60 Rxxxxxxg!0x36d9b60 (0x1036d9b60)0x1008f1038 +[BBAES dataFromString:encoding:]0x1053ba140 -[SSBookCrypto decryptContent:keyVersion:shouldDecompress:]0x1053b99cc -[SSBookCrypto decryptChapterContent:completion:]0x105428f04 Rxxxxxxg!0x4bb0f04 (0x104bb0f04)0x105429158 Rxxxxxxg!0x4bb1158 (0x104bb1158)0x10542aa84 Rxxxxxxg!0x4bb2a84 (0x104bb2a84)0x101175b10 Rxxxxxxg!0x8fdb10 (0x1008fdb10)0x1ba0d69a8 libdispatch.dylib!_dispatch_call_block_and_release0x1ba0d7524 libdispatch.dylib!_dispatch_client_callout0x1ba0ba6fc libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$armv810x1ba38f6bc CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__0x1ba38a590 CoreFoundation!__CFRunLoopRun0x1ba389ba8 CoreFoundation!CFRunLoopRunSpecific0x1c44f9344 GraphicsServices!GSEventRunModal0x1be4c53e4 UIKitCore!UIApplicationMain

从上面堆栈中可以推断这两个函数比较可疑 

函数一:-[SSBookCrypto decryptContent:keyVersion:shouldDecompress:]函数二:-[SSBookCrypto decryptChapterContent:completion:]

那我们到IDA中看下这两个函数做了什么事情~

【iOS逆向】某某小说content逆向分析

我们在IDA的fuctions窗口搜索要分析的函数名时,搜索不到~ 看来该样本品符号都给抹除了。

【iOS逆向】某某小说content逆向分析

感兴趣的可以去试着恢复符号。

我这里直接用frida hook
-[SSBookCrypto decryptChapterContent:completion:]

地址减去moduleBaseAddr = 0x4b41934定位到ida

2‍‍

-[SSBookCrypto decryptChapterContent:completion:]‍‍

先附IDA伪代码

__int64 __fastcall sub_104B41934(__int64 a1){  __int64 v1; // x23  __int64 v2; // x19  __int64 v3; // x20  void *v4; // x0  int v5; // w24  void *v6; // x0  void *v7; // x0  id v8; // x0  void *v9; // x24  __int64 v10; // x0  void *v11; // x0  void *v12; // x0  id v13; // x0  id v14; // x0  id v15; // x0  __int64 v16; // x0  __int64 v17; // x0  __int64 v18; // x0  __int64 v19; // x1  __int64 v20; // x0  void *v21; // x0  void *v22; // x0  id v23; // x0  id v24; // x0  id v25; // x0  __int64 v26; // x0  __int64 v27; // x0  __int64 v28; // x0  __int64 v29; // x0  __int64 v30; // x1  __int64 v31; // x0  void *v32; // x0  void *v33; // x0  id v34; // x0  id v35; // x0  id v36; // x0  __int64 v37; // x0  __int64 v38; // x0  __int64 v39; // x0  void *v40; // x0  id v41; // x0  id v42; // x0  __int64 v43; // x0  void *v44; // x0  void *v45; // x0  id v46; // x0  id v47; // x0  id v48; // x0  __int64 v49; // x0  __int64 v50; // x0  __int64 v51; // x0  id v52; // x0  __int64 v53; // x1  __int64 v54; // x0  __int64 v55; // x0  __int64 v56; // x0  __int64 v58; // [xsp+30h] [xbp-E0h]  id v59; // [xsp+58h] [xbp-B8h]  char v60; // [xsp+B0h] [xbp-60h]  v1 = a1;  v2 = sub_104B4249C();  v3 = ((__int64 (*)(void))sub_104B42500)();  v4 = (void *)sub_1001F8800(v2);  objc_retainAutoreleasedReturnValue(v4);  v5 = sub_1001DDF38(v2);  sub_104B425EC();  sub_100329CA8(v2);  if ( v5 == 2 )  {    objc_autoreleasePoolPush();    v20 = sub_104B42468(&v60);    sub_104B424CC(v20);    v21 = (void *)sub_1001C6AF0(v2);    objc_retainAutoreleasedReturnValue(v21);    v22 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);    v23 = objc_retainAutoreleasedReturnValue(v22);    v24 = objc_retainAutorelease(v23);    v25 = sub_100196A30(v24);    v26 = sub_104B4259C(v25, v25);    v27 = sub_104B4255C(v26);    v28 = sub_104B42494(v27);    v29 = sub_104B424E0(v28);    v58 = sub_104B42500(v29);    v18 = sub_104B425FC(v58, v30);LABEL_13:    v42 = (id)sub_104B42470(v18, v19);    goto LABEL_14;  }  if ( (unsigned __int16)v5 == 1 )  {    objc_autoreleasePoolPush();    v31 = sub_104B42468(&v60);    sub_104B424CC(v31);    v32 = (void *)sub_1001C6AF0(v2);    objc_retainAutoreleasedReturnValue(v32);    v33 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);    v34 = objc_retainAutoreleasedReturnValue(v33);    v35 = objc_retainAutorelease(v34);    v36 = sub_100196A30(v35);    v37 = sub_104B4259C(v36, v36);    v38 = sub_104B42494(v37);    v39 = sub_104B42460(v38);    sub_104B424E0(v39);    v40 = (void *)sub_104B42624(&OBJC_CLASS___SSResult);    v41 = sub_1002AA5B0(v40);    objc_retainAutoreleasedReturnValue(v41);    v42 = (id)sub_1002CF858(v2);    if ( v3 )      v42 = (id)sub_104B42508(v42);  }  else  {    if ( !(_WORD)v5 )    {      v6 = (void *)sub_1001E4748(v1);      objc_retainAutoreleasedReturnValue(v6);      if ( sub_10024D838() )      {        sub_1002CF858(v2);        v7 = (void *)sub_104B42624(&OBJC_CLASS___SSResult);        v8 = sub_1002AA5B0(v7);        objc_retainAutoreleasedReturnValue(v8);        v9 = objc_autoreleasePoolPush();        v10 = sub_104B42468(&v60);        sub_104B424CC(v10);        v11 = (void *)sub_1001C6AF0(v2);        objc_retainAutoreleasedReturnValue(v11);        v12 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);        v13 = objc_retainAutoreleasedReturnValue(v12);        v14 = objc_retainAutorelease(v13);        v15 = sub_100196A30(v14);        v16 = sub_104B4259C(v15, v15);        v17 = sub_104B4255C(v16);        sub_104B42494(v17);        objc_autoreleasePoolPop(v9);        if ( v3 )          v18 = sub_104B42508(v18);      }      else      {        v59 = (id)sub_104B42500(0LL);        sub_104B425FC(v59, v53);        objc_release(v59);      }      goto LABEL_13;    }    objc_autoreleasePoolPush();    v43 = sub_104B42468(&v60);    sub_104B424CC(v43);    v44 = (void *)sub_1001C6AF0(v2);    objc_retainAutoreleasedReturnValue(v44);    v45 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);    v46 = objc_retainAutoreleasedReturnValue(v45);    v47 = objc_retainAutorelease(v46);    v48 = sub_100196A30(v47);    v49 = sub_104B4259C(v48, v48);    v50 = sub_104B42494(v49);    v51 = sub_104B42460(v50);    sub_104B424E0(v51);    v52 = sub_1002AA5B0(&OBJC_CLASS___SSResult);    v42 = objc_retainAutoreleasedReturnValue(v52);    if ( v3 )      v42 = (id)sub_104B42508(v42);  }LABEL_14:  v54 = sub_104B42458(v42);  v55 = sub_104B42460(v54);  v56 = sub_104B42450(v55);  return sub_104B42448(v56);}

先打印下函数入参 <SSChapterContent: 0x28329bde0>发现是对象,frida打印输出对象属性

var obj = ObjC.Object(args[2]).$ivars;    for (var k in obj){        log(k, obj[k]);    }

【iOS逆向】某某小说content逆向分析

上边图中对象属性中encryptChapterContent正是抓包的content密文。

目前可以确定在调用函数:

-[SSBookCrypto decryptChapterContent:completion:]

之前是没有解密过的,思路正确往下接着分析。

【iOS逆向】某某小说content逆向分析

sub_1001E4748()

调用:ObjC_msgsend 

调用:decryptContent函数

对应地址:0x4b420c4

【iOS逆向】某某小说content逆向分析

3

sub_4b420c4

该函数对应

-[SSBookCryptodecryptContent:                  keyVersion:            shouldDecompress:]

【iOS逆向】某某小说content逆向分析

繁琐的分析过程就不再说了,重点在注释这块~

总结下:

1. 第一步调用oc中的json序列表处理为oc对象。2. 第二步取出对象中的content密文调用sub_10007904进行base64 decode3. 第三步实例化BBAES、SSCryptoManager对象没啥好说的4. 第四步调用sub_1037bd3a4即-[SSCryptoManager decryptByData:version:error:]后面主要分析第四步-[SSCryptoManager decryptByData:version:error:]函数

【iOS逆向】某某小说content逆向分析

4

-[SSCryptoManager decyptByData:version:error:]

__int64 __fastcall sub_1037BD3A4(__int64 a1, __int64 a2, __int64 a3, __int64 a4, id a5, __int64 a6, __int64 a7, __int64 a8, int a9, int a10, __int64 a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23, int a24, int a25, int a26, int a27, int a28, int a29, int a30, int a31, int a32, int a33, int a34, int a35, int a36, int a37, int a38, int a39, int a40, int a41, int a42, int a43, int a44, int a45, int a46, int a47, __int64 a48){  __int64 v48; // x30  __int64 v49; // x0  _QWORD *v50; // x4  _QWORD *v51; // x21  int v52; // w3  int v53; // w22  void *v54; // x23  __int64 v55; // x1  void *v56; // x2  id v57; // x19  id v58; // x0  id v59; // x0  id v60; // x0  id v61; // x0  id v62; // x26  __int64 v63; // x0  void *v64; // x0  id v65; // x0  id v66; // x0  id v67; // x0  __int64 v68; // x0  __int64 v69; // x0  __int64 v70; // x0  __int64 v71; // x0  __int64 v72; // x0  void *v73; // x0  id v74; // x0  id v75; // x0  id v76; // x0  __int64 v77; // x0  __int64 v78; // x1  __int64 v79; // x2  __int64 v80; // x3  __int64 v81; // x0  void *v82; // x0  id v83; // x0  id v84; // x0  __int64 v85; // x0  __int64 v86; // x0  void *v87; // x0  id v88; // x0  id v89; // x0  __int64 v90; // x0  __int64 v91; // x0  __int64 v92; // x0  void *v93; // x0  id v94; // x0  id v95; // x0  __int64 v96; // x1  id v97; // x0  id v98; // x0  id v99; // x0  id v100; // x25  __int64 v101; // x0  __int64 v102; // x0  void *v103; // x0  id v104; // x0  id v105; // x0  __int64 v106; // x0  __int64 v107; // x0  __int64 v108; // x0  __int64 v109; // x0  id v110; // x0  __int64 v111; // x1  __int64 v112; // x2  __int64 v113; // x3  void *v114; // x0  id v115; // x0  id v116; // x0  __int64 v117; // x0  id v119; // [xsp+18h] [xbp+18h]  v49 = sub_1037BE298(a1, v48, a3, a4, a5);  v51 = v50;  v53 = v52;  v54 = (void *)v49;  v57 = sub_1037BE360(v49, v55, v56);  if ( !v53 )    sub_100247FE8(v54);  v58 = sub_10020FF00(v54);  if ( objc_retainAutoreleasedReturnValue(v58) )  {    // dataFromString:encoding:    v59 = sub_1001E3068(&OBJC_CLASS___BBAES);    objc_retainAutoreleasedReturnValue(v59);    // originKeyData    v60 = sub_100270FF8(v54);    objc_retainAutoreleasedReturnValue(v60);    // decryptedDataFromData:IV:key:    // 0x180adb66feac8a6ceec7755ed624561a    v61 = sub_1001E4808(&OBJC_CLASS___BBAES);    v62 = objc_retainAutoreleasedReturnValue(v61);    // objc_release    sub_1037BE220();    // objc_release    sub_1037BE210();    objc_autoreleasePoolPush();    sub_1037BE1F0();    sub_1037BE2FC();    sub_1037BE258(v63);    sub_1037BE2E4();    v64 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);    v65 = objc_retainAutoreleasedReturnValue(v64);    v66 = objc_retainAutorelease(v65);    v67 = sub_100196A30(v66);    sub_1037BE1FC(v67);    sub_1037BE220();    sub_1037BE370(v68);    v119 = v62;    // true    if ( (unsigned __int64)sub_1037BE2E4() > 0xF )    {      v97 = sub_100343040(v57);      objc_retainAutoreleasedReturnValue(v97);      sub_1037BE2E4();      v98 = sub_100343040(v57);      objc_retainAutoreleasedReturnValue(v98);      // decryptedDataFromData:IV:key:      // 0x1036d99dc      v99 = sub_1001E4808(&OBJC_CLASS___BBAES);      v100 = objc_retainAutoreleasedReturnValue(v99);      v62 = objc_autoreleasePoolPush();      sub_1037BE1F0();      sub_1037BE2FC();      v102 = sub_1037BE258(v101);      sub_1037BE324(v102);      v103 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);      v104 = objc_retainAutoreleasedReturnValue(v103);      v105 = objc_retainAutorelease(v104);      v106 = sub_1037BE3C8(v105);      v107 = sub_1037BE1FC(v106);      v108 = sub_1037BE31C(v107);      v109 = sub_1037BE3A8(v108);      if ( v100 && sub_1037BE324(v109) )      {        v110 = objc_retain(v100);        v62 = v110;      }      else      {        v114 = (void *)sub_1001FB710(&OBJC_CLASS___NSError);        v115 = objc_retainAutoreleasedReturnValue(v114);        v116 = objc_autorelease(v115);        v110 = (id)sub_1037BE344(v116);      }      sub_1037BE274(v110, v111, v112, v113);      sub_1037BE220();      sub_1037BE210();    }    else    {      objc_autoreleasePoolPush();      v69 = sub_1037BE1F0();      v70 = sub_1037BE354(v69);      v71 = sub_1037BE258(v70);      v72 = sub_1037BE3D0(v71);      v73 = (void *)sub_1003421A0(v72);      v74 = objc_retainAutoreleasedReturnValue(v73);      v75 = objc_retainAutorelease(v74);      v76 = sub_100196A30(v75);      v77 = sub_1037BE1FC(v76);      v81 = sub_1037BE274(v77, v78, v79, v80);      sub_1037BE370(v81);      v82 = (void *)sub_1001FB710(&OBJC_CLASS___NSError);      v83 = objc_retainAutoreleasedReturnValue(v82);      v84 = objc_autorelease(v83);      sub_1037BE344(v84);    }    objc_release(v119);  }  else  {    objc_autoreleasePoolPush();    v85 = sub_1037BE1F0();    v86 = sub_1037BE354(v85);    sub_1037BE27C(v86);    v87 = (void *)sub_1003421A0(&OBJC_CLASS___NSString);    v88 = objc_retainAutoreleasedReturnValue(v87);    v89 = objc_retainAutorelease(v88);    v90 = sub_1037BE368(v89);    v91 = sub_1037BE1FC(v90);    v92 = sub_1037BE208(v91);    sub_1037BE370(v92);    v93 = (void *)sub_1001FB710(&OBJC_CLASS___NSError);    v94 = objc_retainAutoreleasedReturnValue(v93);    v95 = objc_autorelease(v94);    v62 = 0LL;    *v51 = v95;  }  v117 = sub_1037BE26C(v95, v96);  sub_1037BE290(v117);  return sub_1037BE23C(v62);}

【iOS逆向】某某小说content逆向分析

上图为分析的思路,最终可以倒推到:

v99=sub_101E4808()

恢复符号后是

+[BBAES decryptedDataFromData:IV:key:] 

trace下这个函数看看~

【iOS逆向】某某小说content逆向分析

从上图可以看到这个函数被多次调用

其中相关的调用 key和iv都可以拿到~

把content进行base64解码后转成hex,

仔细分析可以看出iv为前16字节。

【iOS逆向】某某小说content逆向分析

撒花~到这AES解密基本结束了 不过还没完~ 

【iOS逆向】某某小说content逆向分析

5

gzip压缩

decryptByData:version:error: 分析完了,接着回到

-[SSBookCrypto decryptChapterContent:completion:]

继续分析

【iOS逆向】某某小说content逆向分析

可以看到AES解密后的bytes由v13接收, v14=v13。

紧接着调用sub_1001E2E28() 

-[NSData dataByGZipDecompressingDataWithError:]

从函数名可以知道是gzip解压,验证下看看

【iOS逆向】某某小说content逆向分析

古德古德 歪瑞古德!

你以为到这里就结束了吗?

不不不

【iOS逆向】某某小说content逆向分析

6

动态key、iv

不绕圈了 该样本的key、iv是动态下发的。

其实站在开发者的角度思考,如果采用客户端固定key和iv的话 没必要将上面的iv放到response由服务端下发~

接着再细细分析一番 发现端倪~

【iOS逆向】某某小说content逆向分析

过程细节就不说了,上图getService函数取了crypt/register的响应进行base64解码前16字节为iv 后为key

【iOS逆向】某某小说content逆向分析

【iOS逆向】某某小说content逆向分析

7‍‍

总结

该样本难度一般, 适合练手~ 

🐴赛克有点重 望理解~

旨在记录,大佬轻喷~

文中有错误的地方,还请各位大佬斧正~

撒花~ ✿✿ヽ(°▽°)ノ✿下次再会。

原文始发于微信公众号(小白逆向之旅):【iOS逆向】某某小说content逆向分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月3日22:18:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【iOS逆向】某某小说content逆向分析http://cn-sec.com/archives/3463712.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息