《九阴真经: iOS黑客攻防秘籍》新书发布,干货满满,快来看看吧!

iOS 安全论坛 - 专注于研究 iOS 安全

 找回密码
 立即注册
查看: 8269|回复: 11

iOS抖音越狱检测分析

[复制链接]

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
发表于 2020-1-31 13:05:51 | 显示全部楼层 |阅读模式
一、准备工作
工具
在本文中,用到的工具有IDA Pro,Frida。其他工具安装方式请自行查阅,这里简单说下frida

Frida是跨平台的函数级跟踪工具,可以提高分析效率。利用该工具可以很方便的调用进程内部函数;在实际分析过程中,lldb一般用来定位反调试,崩溃和指令级别的分析,而frida主要用作函数级别的分析,如修改函数输入参数和返回值,打印调用栈,跟踪调用的API流,用作逆向分析和渗透测试再好不过。
Frida安装分两部分:

1. 在越狱机从cydia源build.frida.re安装frida-server,安装成功后便会自动在手机上以daemon执行server
2. PC上用pip安装frida-tools即可。注意win上容易安装失败,即使成功也可能出现缺少dll的问题,该如何解决呢?可以在参考编译好的版本:https://pypi.org/project/frida/#files。例如Windows x64下使用python3.7安装frida,就不需要编译安装,也不会出现各种错。


脱壳
首先我们进行静态分析,第一步要脱壳,常见的工具有dump-decrypted/frida-ios-dump/clutch等工具。先来看看App哪些模块需要脱壳,从下面可以看到App内部模块有Aweme,AwemeDylib和两个第三方Rtc库,对这两个动态库进行脱壳,然后拖到IDA分析。
  1. Process.enumerateModulesSync().forEach(function(e){if(e.path.indexOf('.app')!=-1){console.log(e.path)}})
  2. .../Aweme.app/Aweme
  3. .../Aweme.app/Frameworks/AgoraRtcEngineKit.framework/AgoraRtcEngineKit
  4. .../Frameworks/ByteRtcEngineKit.framework/ByteRtcEngineKit
  5. .../Aweme.app/Frameworks/AwemeDylib.framework/AwemeDylib
复制代码

二、越狱检测分析
(1) 在IDA字符串窗口和函数窗口查找jail,jeil,jb,break,cydia,substrate,bash,apt,ssh等关键字 。
(2)使用fiddler等抓包工具捕获app所有网络请求,在url和body中查找jail,jeil,jb,break等关键字。如果body加密则需要跟踪和逆向。 (网络请求定位到代码逻辑,可以从跟踪URLWithString甚至connect开始)。
(3)使用frida对常用越狱检测函数对应的系统调用进行跟踪access,creat,faccessatgetxattr,getxattr,link,listxattr,lstat,open,opendir,readlink,realpath,stat,statfs,symlink,这样可以检测到所有函数级。
(4)在IDA汇编中搜索SVC指令,这样能检测出指令级系统调用。


1. 初步检测
首先找到比较明显的痕迹,例如函数名字符串,检测到得到如下函数:

  1. [ANSMetadata computeIsJailbroken];  
  2. [ASSStaticInfoCollector checkJB)];  
  3. [ASSStaticInfoCollectorOpen checkJB]  
  4. [AWECloudJailBreakUtility jailbroken];  
  5. [AWEYAMInfoHelper isJailBroken]  
  6. [BDADeviceHelper isJailBroken];  
  7. [BDLogDeviceHelper isJailBroken]  
  8. [IESLiveDeviceInfo isJailBroken]  
  9. [HMDCrashBinaryImage isJailBroken];  
  10. [HMDInfo isJailBroken]  
  11. [MobClick isJailbroken]  
  12. [TTAdSplashDeviceHelper isJailBroken];  
  13. [TTInstallDeviceHelper isJailBroken]  
  14. [UAConveniece deviceWasJailed];  
  15. [UIDevice btd_isJailBroken]  
  16. [UMANProtocolData isDeviceJailBreak]  
  17. [WXOMTAHelper isJB]
复制代码

进行分析以后可以找到如下检测逻辑:
(1) 文件系统检测        
  1. /bin/bash
  2. /Applications/Cydia.app
  3. /Library/MobileSubstrate/MobileSubstrate.dylib
  4. /user/Applictations
  5. /user/Continers/Bundle/Application
  6. /usr/sbin/sshd
  7. /etc/apt
  8. /Applications/RockApp.app,
  9. /Applications/Icy.app,
复制代码
(2)沙盒完整性检测
system函数
(3)环境变量检测

使用environ检测MobileSubstrate环境变量
(4)mmap检测
(5)进程检测

检测相关的进程,如 Cydia  afpd 等
(6)scheme检测

检测 scheme 是否能打开,如 cydia://。

2. 深度检测
使用frida工具跟踪前面提到的系统调用。插句题外话,frida的-f参数目前是不能用的,也就是不能以-f启动app(其实老一些的iOS是可以的),所以只能附加进程进行跟踪,然而frida在附加进程的时候会有几秒延迟导致App初始化时执行的函数和数据包无法跟踪到,怎么解决呢?简单做法是写个tweak,在%ctor里sleep几秒就可以了。跟踪代码可以参考我git中的antijailbreak.js代码。得到如下结果:
  1. 0x107b49140 AwemeDylib!YjA2MGM5NGQ3MTI5MjljYTA2Y2Y2Yjc3YzM2ZjAxYzAK
  2. 0x107b69938 AwemeDylib!0x1f19938
  3. 0x107b6e794 AwemeDylib!0x1f1e794

  4. stat /Applications/Cydia.app
  5. 0x107b49150 AwemeDylib!YjA2MGM5NGQ3MTI5MjljYTA2Y2Y2Yjc3YzM2ZjAxYzAK
  6. 0x107b69938 AwemeDylib!0x1f19938
  7. 0x107b6e794 AwemeDylib!0x1f1e794

  8. stat /Library/MobileSubstrate/MobileSubstrate.dylib
  9. syscall 5
  10. syscall open /Library/MobileSubstrate/MobileSubstrate.dylib
  11. 0x107b49140 AwemeDylib!YjA2MGM5NGQ3MTI5MjljYTA2Y2Y2Yjc3YzM2ZjAxYzAK
  12. 0x107b69938 AwemeDylib!0x1f19938
  13. 0x107b68c20 AwemeDylib!YzE0NjZkZDJjZWMyYzdhODdkMzNjNjhkYTI2ZmJhNGIK

  14. stat /Applications/Cydia.app
  15. 0x107b49150 AwemeDylib!YjA2MGM5NGQ3MTI5MjljYTA2Y2Y2Yjc3YzM2ZjAxYzAK
  16. 0x107b69938 AwemeDylib!0x1f19938
  17. 0x107b68c20 AwemeDylib!YzE0NjZkZDJjZWMyYzdhODdkMzNjNjhkYTI2ZmJhNGIK

  18. stat /Library/MobileSubstrate/MobileSubstrate.dylib
  19. syscall open /Library/MobileSubstrate/MobileSubstrate.dylib
  20. 0x107b4f700 AwemeDylib!MmNiMjczYTdiMjAzZjc5ODljZDg5MDBlZGQ3NmZmOTUK
  21. 0x107b68c84 AwemeDylib!YzE0NjZkZDJjZWMyYzdhODdkMzNjNjhkYTI2ZmJhNGIK

  22. stat /Applications/iGameGuardian.app
  23. 0x107b4f800 AwemeDylib!MmNiMjczYTdiMjAzZjc5ODljZDg5MDBlZGQ3NmZmOTUK
  24. 0x107b68c84 AwemeDylib!YzE0NjZkZDJjZWMyYzdhODdkMzNjNjhkYTI2ZmJhNGIK

  25. stat /Applications/GamePlayer.app
复制代码

此时可以看到果然AwemeDylib是有猫腻的,只不过把OC函数名进行了混淆,同时存在字符串加密,那么接下来就是分析这些混淆名的函数。由上面结果的调用栈,分析AwemeDylib中的代码,可以找到若干个经过函数名混淆的函数,其中两个函数长这样:
  1. __int64 check_jb()
  2. {
  3.   v2 = __ldar((unsigned int *)&unk_25B617C);
  4.   v27 = (unsigned __int64)&unk_25B617C;
  5.   v21 = "stringWithCString:encoding:";
  6.   v20 = "defaultManager";
  7.   v19 = "fileExistsAtPath:";
  8.   v3 = 3649499418LL;
  9.   do
  10.   {
  11.     while ( 1 )
  12.     {
  13.       while ( 1 )
  14.       {
  15.         while ( 1 )
  16.         {
  17.           while ( 1 )
  18.           {
  19.             while ( (signed int)v3 > 39081286 )
  20.             {
  21.               if ( (signed int)v3 <= 244706462 )
  22.               {
  23.                 if ( (signed int)v3 > 126009263 )
  24.                 {
  25.                   if ( (_DWORD)v3 == 229581047 )
  26.                   {
  27.                     v0 = v30;
  28.                     v3 = 3270936340LL;
  29.                   }
  30.                 }
  31.                 else if ( (_DWORD)v3 == 39081287 )
  32.                 {
  33.                   __stlr(0, (unsigned int *)&unk_25B617C);
  34.                   v28 = (Dl_info *)&v18;
  35.                   v6 = __ldar((unsigned int *)&v18);
  36.                   if ( !(unsigned int)&v18 )
  37.                   {
  38.                     cydialib = 47;              // /Applications/Cydia.app
  39.                     byte_2443F01 = 65;
  40.                     ....
  41.                   }
  42.                   __stlr(0, (unsigned int *)&unk_25B6180);
  43.                   v7 = objc_msgSend(&OBJC_CLASS___NSString, v21, &cydialib, 4LL);
  44.                   objc_retainAutoreleasedReturnValue(v7);
  45.                   v8 = objc_msgSend(&OBJC_CLASS___NSFileManager, v20);
  46.                   v9 = v8;
  47.                   v10 = (void *)objc_retainAutoreleasedReturnValue(v8);
  48.                   v11 = (unsigned __int64)objc_msgSend(v10, v19, v7);
  49.                   objc_release(v9);
  50.                   if ( v11 & 1 )
  51.                     v12 = 1;
  52.                   else
  53.                     v12 = access(&cydialib, 0) == 0;
  54.                   v31 = 538;
  55.                   objc_release(v7);
  56.                   if ( v12 )
  57.                     v3 = 4208507086LL;
  58.                   else
  59.                     v3 = 2699417432LL;
  60.                 }
  61.               }
  62.               else if ( (signed int)v3 <= 1095875126 )
  63.               {
  64.                 if ( (_DWORD)v3 == 1034641429 )
  65.                   v4 = 1;
  66.                 else
  67.                   v4 = v1;
  68.                 if ( (_DWORD)v3 == 1034641429 )
  69.                   v5 = -257687223;
  70.                 else
  71.                   v5 = v3;
  72.                 if ( (_DWORD)v3 == 244706463 )
  73.                   v1 = 0;
  74.                 else
  75.                   v1 = v4;
  76.                 if ( (_DWORD)v3 == 244706463 )
  77.                   v3 = 4037280073LL;
  78.                 else
  79.                   v3 = v5;
  80.               }
  81.               else
  82.               {
  83.                 switch ( (_DWORD)v3 )
  84.                 {
  85.                   case 0x4151BA37:
  86.                     v0 = 1;
  87.                     v3 = 3270936340LL;
  88.                     break;
  89.                   case 0x5B3EC3D2:
  90.                     v29 = v28;
  91.                     if ( dladdr(&_stat, v28) )
  92.                       v3 = 3416709257LL;
  93.                     else
  94.                       v3 = 244706463LL;
  95.                     break;
  96.                   case 0x60C3A04F:
  97.                     v23 = 304;
  98.                     v22 = 214;
  99.                     v3 = 1530840018LL;
  100.                     break;
  101.                 }
  102.               }
  103.             }
  104.             if ( (signed int)v3 > -1024030957 )
  105.               break;
  106.             if ( (signed int)v3 > -1595549865 )
  107.             {
  108.               if ( (_DWORD)v3 == -1595549864 )
  109.               {
  110.                 v13 = __ldar((unsigned int *)v3);
  111.                 __stlr(0, (unsigned int *)&unk_25B6184);
  112.                 v14 = objc_msgSend(&OBJC_CLASS___NSFileManager, v20);
  113.                 objc_retainAutoreleasedReturnValue(v14);
  114.                 v15 = objc_msgSend(&OBJC_CLASS___NSString, v21, &byte_2443F20, 4LL);
  115.                 objc_retainAutoreleasedReturnValue(v15);
  116.                 v16 = (unsigned __int64)objc_msgSend(v14, v19, v15);
  117.                 objc_release(v15);
  118.                 objc_release(v14);
  119.                 if ( v16 )
  120.                   v3 = 1095875127LL;
  121.                 else
  122.                   v3 = 1623433295LL;
  123.               }
  124.             }
  125.             else if ( (_DWORD)v3 == -1895695304 )
  126.             {
  127.               libsyskern = 47;                  // /usr/lib/system/libsystem_kernel.dylib
  128.               byte_2443ED1 = 117;
  129.               .....
  130.             }
  131.             else if ( (_DWORD)v3 == -1799416459 )
  132.             {
  133.               if ( !strcmp(v28->dli_fname, &libsyskern) )
  134.                 v3 = 244706463LL;
  135.               else
  136.                 v3 = 1034641429LL;
  137.             }
  138.           }
  139.           if ( (signed int)v3 <= -257687224 )
  140.             break;
  141.           if ( (_DWORD)v3 == -257687223 )
  142.           {
  143.             v30 = v1 & 1;
  144.             v26 = 240;
  145.             v25 = 208;
  146.             v3 = 229581047LL;
  147.           }
  148.           else
  149.           {
  150.             if ( (_DWORD)v3 == -86460210 )
  151.               v0 = 1;
  152.             if ( (_DWORD)v3 == -86460210 )
  153.               v3 = 3270936340LL;
  154.             else
  155.               v3 = (unsigned int)v3;
  156.           }
  157.         }
  158.         if ( (_DWORD)v3 != -878258039 )
  159.           break;
  160.         v24 = 583;
  161.         v3 = 2495550837LL;
  162.       }
  163.       if ( (_DWORD)v3 != -645467878 )
  164.         break;
  165.       if ( v27 )
  166.         v3 = 39081287LL;
  167.       else
  168.         v3 = 2399271992LL;
  169.     }
  170.   }
  171.   while ( (_DWORD)v3 != -1024030956 );
  172.   return v0 & 1;
  173. }

  174. void YjA2MGM5_check_jb(__int64 a1)
  175. {
  176.   v68 = a1;
  177.   v2 = __ldar(__stack_chk_guard);
  178.   if ( !__stack_chk_guard )
  179.   {
  180.     v1 = (unsigned int *)&cydia;
  181.     cydia = 47;                                 // /Applications/Cydia.app
  182.     byte_24435C1 = 65;
  183.     ....
  184.   }
  185.   __stlr(0, (unsigned int *)&unk_25B5CDC);
  186.   v3 = __ldar(v1);
  187.   if ( !(_DWORD)v1 )
  188.   {
  189.     substrate = 47;                             // /Library/MobileSubstrate/MobileSubstrate.dylib
  190.     byte_24435E1 = 76;
  191.     ....
  192.   }
  193.   __stlr(0, (unsigned int *)&unk_25B5CE0);
  194.   v4 = __ldar((unsigned int *)((char *)&dword_0 + 1));
  195.   __stlr(0, (unsigned int *)&unk_25B5CE4);
  196.   v5 = __ldar(v1);
  197.   if ( !(_DWORD)v1 )
  198.   {                                             // /Library/TweakInject
  199.     twea = 47;
  200.     byte_2443621 = 76;
  201.     ....
  202.   }
  203.   __stlr(0, (unsigned int *)&unk_25B5CE8);
  204.   v69 = &v50;
  205.   memset(&v67, 0, 0x90uLL);
  206.   v66 = 0;
  207.   v64 = 0u;
  208.   v65 = 0u;
  209.   v63 = 0u;
  210.   v62 = 0;
  211.   v60 = 0u;
  212.   v61 = 0u;
  213.   v58 = 0;
  214.   v56 = 0u;
  215.   v57 = 0u;
  216.   v55 = 0u;
  217.   v51 = 0u;
  218.   v52 = 0u;
  219.   v54 = 0;
  220.   v53 = 0u;
  221.   strcpy((char *)&v63, &cydia);
  222.   strcpy((char *)&v59, &substrate);
  223.   strcpy((char *)&v55, &byte_244360F);          // file_sys
  224.   strcpy((char *)&v51, &twea);
  225.   if ( !__libc_do_syscall(573, v6, v7, v8, v9, v10, v11, v12, &v51, &v67, v37, v38, v39, v40, v41)
  226.     && (WORD2(v67) & 0xF000) == 40960
  227.     || !stat((const char *)&v63, (struct stat *)&v67) )
  228.   {
  229.     goto LABEL_14;
  230.   }
  231.   v13 = stat((const char *)&v59, (struct stat *)&v67);
  232.   if ( !(_DWORD)v13 )
  233.     JUMPOUT(__CS__, sub_1EF91A0(v13, v14, v15, v16, v17, v18, v19, v20) + 52);
  234.   v21 = (void *)syscall(5, &v59, 0LL);
  235.   if ( (signed int)v21 >= 1 )
  236.   {
  237.     __libc_do_syscall(239, v22, v23, v24, v25, v26, v27, v28, v21, v36, v37, v38, v39, v40, v41);
  238. LABEL_14:
  239.     qword_25B5CB0(6LL, 77LL);
  240.     v29 = 1LL;
  241.     goto LABEL_15;
  242.   }
  243.   if ( !access((const char *)&v63, 4) )
  244.     goto LABEL_14;
  245.   v29 = 0LL;
  246. LABEL_15:
  247.   v30 = (__int64)v69;
  248.   v69[1] = 0LL;
  249.   *(_QWORD *)(v30 + 16) = 0LL;
  250.   *(_QWORD *)v30 = 0LL;
  251.   v47 = &off_206CD00;
  252.   v38 = 0LL;
  253.   std::__1::ios_base::init((std::__1::ios_base *)&v47, &v40);
  254.   v48 = 0LL;
  255.   v49 = -1;
  256.   v37 = off_206CB88;
  257.   v47 = (void **)off_206CBD8;
  258.   v39 = off_206CBB0;
  259.   std::__1::basic_streambuf<char,std::__1::char_traits<char>>::basic_streambuf(&v40);
  260.   v42 = 0LL;
  261.   v40 = off_20C7460;
  262.   v44 = 0LL;
  263.   v45 = 0LL;
  264.   v43 = 0LL;
  265.   v46 = 24;
  266.   v31 = strlen((const char *)&v55);
  267.   v32 = sub_DF61FC(&v39, (__int64)&v55, v31);
  268.   std::__1::basic_ostream<char,std::__1::char_traits<char>>::operator<<(v32, v29);
  269.   sub_E21700((__int64 *)&v37, v30);
  270.   v33 = *(char *)(v30 + 23);
  271.   if ( v33 >= 0 )
  272.     v34 = (void *)v30;
  273.   else
  274.     v34 = *(void **)v30;
  275.   if ( v33 >= 0 )
  276.     v35 = *(unsigned __int8 *)(v30 + 23);
  277.   else
  278.     v35 = *(_QWORD *)(v30 + 8);
  279.   std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::append(v68, v34, v35);
  280.   v37 = off_206CB88;
  281.   v47 = (void **)off_206CBD8;
  282.   v39 = off_206CBB0;
  283.   v40 = off_20C7460;
  284.   if ( SHIBYTE(v44) & 0x80000000 )
  285.     operator delete(v42);
  286.   std::__1::basic_streambuf<char,std::__1::char_traits<char>>::~basic_streambuf(&v40);
  287.   std::__1::basic_iostream<char,std::__1::char_traits<char>>::~basic_iostream(&v37, off_206CBF8);
  288.   std::__1::basic_ios<char,std::__1::char_traits<char>>::~basic_ios(&v47);
  289.   if ( *(char *)(v30 + 23) & 0x80000000 )
  290.     operator delete(*(void **)v30);
  291. }
复制代码
经过分析可知,App存在SVC指令级别的越狱检测并封装成函数__libc_do_sycall,同时也调用了syscall函数来隐藏api调用。通过跟踪__libc_do_syscall和iOS系统调用号,可以发现的系统调用有:  read/close/getpid/getppid/open/sysctl/stat64/getdirentries64。使用frida跟踪一下 libc_do_syscall 函数的脚本代码如下:
  1. Interceptor.attach(Module.findExportByName(null, "__libc_do_syscall"), {
  2.     onEnter: function(args) {
  3.         var callnum = args[0].toInt32() - 233;
  4.         if (false) {
  5.         } else if (callnum == 3) {
  6.             // read
  7.         } else if (callnum == 5) {
  8.             console.log('open ' + args[8].readUtf8String());
  9.         } else if (callnum == 6) {
  10.             // close
  11.         } else if (callnum == 20) {
  12.             // getpid
  13.         } else if (callnum == 39) {
  14.             // getppid
  15.         } else if (callnum == 202) {
  16.             // sysctl
  17.         } else if (callnum == 294) {
  18.             // shared_region_check_np
  19.         } else if (callnum == 340) {
  20.             console.log('stat64 ' + args[8].readUtf8String());
  21.         } else if (callnum == 344) {
  22.             // getdirentries64
  23.         } else {
  24.             console.log('__libc_do_syscall() ' + callnum);
  25.         }
  26.     }
  27. });
复制代码

可得到以下结果:
  1. stat64 /Library/TweakInject
  2. stat64 /Library/TweakInject
  3. open /Library/LaunchDaemons/
  4. open /Library/MobileSubstrate/DynamicLibraries
  5. open /Library/MobileSubstrate/DynamicLibraries/ALS.plist.bak
  6. open /Library/MobileSubstrate/DynamicLibraries/AppList.plist
  7. open /Library/MobileSubstrate/DynamicLibraries/FLEXing.plist
  8. open /Library/MobileSubstrate/DynamicLibraries/GPSTravellerTweakVIP.plist.bak
  9. open /Library/MobileSubstrate/DynamicLibraries/MobileSafety.plist
  10. open /Library/MobileSubstrate/DynamicLibraries/PreferenceLoader.plist
  11. open /Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.plist
  12. open /Library/MobileSubstrate/DynamicLibraries/SSLKillSwitch2.plist
  13. open /Library/MobileSubstrate/DynamicLibraries/TSActivator.plist
  14. open /Library/MobileSubstrate/DynamicLibraries/TSEventTweak.plist
复制代码

根据该结果进行二次跟踪,又会得到一些检测文件,未防止有遗漏,可以将data段内存dump下来查看解密后的敏感路径
  1. /Library/TweakInject
  2. /Library/LaunchDaemons/
  3. /Library/MobileSubstrate/DynamicLibraries
  4. /Library/MobileSubstrate/MobileSubstrate.dylib
  5. /Applications/iGameGuardian.app
  6. /Applications/GamePlayer.app
复制代码

经过几番折腾,最终就可以得到所有越狱检测逻辑了。











回复

使用道具 举报

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
 楼主| 发表于 2020-1-31 13:24:06 | 显示全部楼层
最后附上 frida hook 各种函数的脚本代码,很有用。
  1. function logtrace(ctx) {
  2.     var content = Thread.backtrace(ctx.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n';
  3.     if (content.indexOf('SubstrateLoader') == -1 && content.indexOf('JavaScriptCore') == -1 &&
  4.         content.indexOf('FLEXing.dylib') == -1 && content.indexOf('NSResolveSymlinksInPathUsingCache') == -1 &&
  5.         content.indexOf('MediaServices') == -1 && content.indexOf('bundleWithPath') == -1 &&
  6.         content.indexOf('CoreMotion') == -1 && content.indexOf('infoDictionary') == -1 &&
  7.         content.indexOf('objectForInfoDictionaryKey') == -1)  {
  8.             console.log(content);
  9.         return true;
  10.     }
  11.     return false;
  12. }

  13. function iswhite(path) {
  14.     if (path == null) return true;
  15.     if (path.startsWith('/var/mobile/Containers')) return true;
  16.     if (path.startsWith('/var/containers')) return true;
  17.     if (path.startsWith('/var/mobile/Library')) return true;
  18.     if (path.startsWith('/var/db')) return true;
  19.     if (path.startsWith('/private/var/mobile')) return true;
  20.     if (path.startsWith('/private/var/containers')) return true;
  21.     if (path.startsWith('/private/var/mobile/Library')) return true;
  22.     if (path.startsWith('/private/var/db')) return true;
  23.     if (path.startsWith('/System')) return true;
  24.     if (path.startsWith('/Library/Preferences')) return true;
  25.     if (path.startsWith('/Library/Managed')) return true;
  26.     if (path.startsWith('/usr')) return true;
  27.     if (path.startsWith('/dev')) return true;
  28.     if (path == '/AppleInternal') return true;
  29.     if (path == '/etc/hosts') return true;
  30.     if (path == '/Library') return true;
  31.     if (path == '/var') return true;
  32.     if (path == '/private/var') return true;
  33.     if (path == '/private') return true;
  34.     if (path == '/') return true;
  35.     if (path == '/var/mobile') return true;
  36.     if (path.indexOf('/containers/Bundle/Application') != -1) return true;
  37.     return false;
  38. }

  39. Interceptor.attach(Module.findExportByName(null, "access"), {
  40.     onEnter: function(args) {
  41.         if (args[0].isNull()) return;
  42.         var path = args[0].readUtf8String();
  43.         if (iswhite(path)) return;
  44.         console.log("access " + path);
  45.     }
  46. })

  47. Interceptor.attach(Module.findExportByName(null, "creat"), {
  48.     onEnter: function(args) {
  49.         if (args[0].isNull()) return;
  50.         var path = args[0].readUtf8String();
  51.         if (iswhite(path)) return;
  52.         if (logtrace(this)) console.log("creat " + path);
  53.     }
  54. })

  55. Interceptor.attach(Module.findExportByName(null, "dlopen"), {
  56.     onEnter: function(args) {
  57.         if (args[0].isNull()) return;
  58.         var path = args[0].readUtf8String();
  59.         if (!iswhite(path)) console.log("dlopen " + path);
  60.     }
  61. })

  62. Interceptor.attach(Module.findExportByName(null, "dlopen_preflight"), {
  63.     onEnter: function(args) {
  64.         if (args[0].isNull()) return;
  65.         var path = args[0].readUtf8String();
  66.         if (!iswhite(path)) console.log("dlopen_preflight " + path);
  67.     }
  68. })

  69. Interceptor.attach(Module.findExportByName(null, "faccessat"), {
  70.     onEnter: function(args) {
  71.         if (args[0].isNull()) return;
  72.         var path = args[1].readUtf8String();
  73.         if (iswhite(path)) return;
  74.         if (logtrace(this)) console.log("faccessat " + path);
  75.     }
  76. })

  77. Interceptor.attach(Module.findExportByName(null, "getxattr"), {
  78.     onEnter: function(args) {
  79.         if (args[0].isNull()) return;
  80.         var path = args[0].readUtf8String();
  81.         if (iswhite(path)) return;
  82.         if (logtrace(this)) console.log("getxattr " + path);
  83.     }
  84. })

  85. Interceptor.attach(Module.findExportByName(null, "link"), {
  86.     onEnter: function(args) {
  87.         if (args[0].isNull()) return;
  88.         var path = args[0].readUtf8String();
  89.         if (iswhite(path)) return;
  90.         if (logtrace(this)) console.log("link " + path);
  91.     }
  92. })

  93. Interceptor.attach(Module.findExportByName(null, "listxattr"), {
  94.     onEnter: function(args) {
  95.         if (args[0].isNull()) return;
  96.         var path = args[0].readUtf8String();
  97.         if (iswhite(path)) return;
  98.         if (logtrace(this)) console.log("listxattr " + path);
  99.     }
  100. })

  101. Interceptor.attach(Module.findExportByName(null, "lstat"), {
  102.     block: false,
  103.     onEnter: function(args) {
  104.         if (args[0].isNull()) return;
  105.         var path = args[0].readUtf8String();
  106.         if (iswhite(path)) return;
  107.         if (logtrace(this)) console.log("lstat " + path);
  108.     }
  109. })

  110. Interceptor.attach(Module.findExportByName(null, "open"), {
  111.     onEnter: function(args) {
  112.         if (args[0].isNull()) return;
  113.         var path = Memory.readUtf8String(args[0]);
  114.         if (iswhite(path)) return;
  115.         if (logtrace(this)) console.log("open " + path);
  116.     }
  117. })

  118. Interceptor.attach(Module.findExportByName(null, "opendir"), {
  119.     onEnter: function(args) {
  120.         if (args[0].isNull()) return;
  121.         var path = args[0].readUtf8String();
  122.         if (iswhite(path)) return;
  123.         if (logtrace(this)) console.log("opendir " + path);
  124.     }
  125. })

  126. Interceptor.attach(Module.findExportByName(null, "__opendir2"), {
  127.     onEnter: function(args) {
  128.         if (args[0].isNull()) return;
  129.         var path = args[0].readUtf8String();
  130.         if (iswhite(path)) return;
  131.         if (logtrace(this)) console.log("opendir2 " + path);
  132.     }
  133. })

  134. Interceptor.attach(Module.findExportByName(null, "readlink"), {
  135.     onEnter: function(args) {
  136.         if (args[0].isNull()) return;
  137.         var path = args[0].readUtf8String();
  138.         if (iswhite(path)) return;
  139.         if (logtrace(this)) console.log("readlink " + path);
  140.     }
  141. })

  142. Interceptor.attach(Module.findExportByName(null, "realpath"), {
  143.     onEnter: function(args) {
  144.         if (args[0].isNull()) return;
  145.         var path = args[0].readUtf8String();
  146.         if (iswhite(path)) return;
  147.         if (logtrace(this)) console.log("realpath " + path);
  148.     }
  149. })

  150. Interceptor.attach(Module.findExportByName(null, "realpath$DARWIN_EXTSN"), {
  151.     onEnter: function(args) {
  152.         if (args[0].isNull()) return;
  153.         var path = args[0].readUtf8String();
  154.         if (iswhite(path)) return;
  155.         if (logtrace(this)) console.log("realpath$DARWIN_EXTSN " + path);
  156.     }
  157. })

  158. Interceptor.attach(Module.findExportByName(null, "stat"), {
  159.     onEnter: function(args) {
  160.         if (args[0].isNull()) return;
  161.         var path = args[0].readUtf8String();
  162.         if (iswhite(path)) return;
  163.         if (logtrace(this)) console.log("stat " + path);
  164.     }
  165. })

  166. Interceptor.attach(Module.findExportByName(null, "statfs"), {
  167.     onEnter: function(args) {
  168.         if (args[0].isNull()) return;
  169.         var path = args[0].readUtf8String();
  170.         if (iswhite(path)) return;
  171.         if (logtrace(this)) console.log("statfs " + path);
  172.     }
  173. })

  174. Interceptor.attach(Module.findExportByName(null, "symlink"), {
  175.     onEnter: function(args) {
  176.         if (args[0].isNull()) return;
  177.         var path = args[0].readUtf8String();
  178.         if (iswhite(path)) return;
  179.         if (logtrace(this)) console.log("symlink " + path);
  180.     }
  181. })

  182. Interceptor.attach(Module.findExportByName(null, "syscall"), {
  183.     onEnter: function(args) {
  184.         if (args[0].isNull()) return;
  185.         var callnum = args[0].toInt32();
  186.         if (callnum == 180) return;
  187.         console.log("syscall " + args[0].toInt32());
  188.     }
  189. })
复制代码
回复

使用道具 举报

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
 楼主| 发表于 2020-1-31 13:40:05 | 显示全部楼层
抖音检测越狱的核心技术是使用 svc 汇编指令实现 syscall 的功能,调用中断号实现各种功能去检测越狱,不调用函数,从而躲避了各种hook,不易被绕过。
回复

使用道具 举报

0

主题

1

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2020-4-9 10:51:22 | 显示全部楼层
楼主您好,我在按照您给的方法测试的过程中发现frida hook __libc_do_syscall 返回的是null,
  1. var do_syscall_addr = Module.findExportByName(null, "__libc_do_syscall");
复制代码
,我的测试环境是iphone 6s, ios12.1.4
回复

使用道具 举报

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
 楼主| 发表于 2020-4-9 12:39:27 | 显示全部楼层
alex 发表于 2020-4-9 10:51
楼主您好,我在按照您给的方法测试的过程中发现frida hook __libc_do_syscall 返回的是null,,我的测试环 ...

不一定叫 libc_do_syscall 这个名字,符号名称去掉了,一般都是 sub_xxxxx 这种,所以你要自己分析去定位。
回复

使用道具 举报

6

主题

26

帖子

262

积分

中级会员

Rank: 3Rank: 3

积分
262
发表于 2020-4-26 15:47:21 | 显示全部楼层
请教一下动态库脱壳 怎么脱?和app的可执行文件一样?
回复

使用道具 举报

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
 楼主| 发表于 2020-4-26 15:59:09 | 显示全部楼层
时光机 发表于 2020-4-26 15:47
请教一下动态库脱壳 怎么脱?和app的可执行文件一样?

是的,书中第11章讲解重打包里描述了 dumpdecrypted 的原理,动态库也是可以脱的,在 229 页你可以看一下。
回复

使用道具 举报

6

主题

26

帖子

262

积分

中级会员

Rank: 3Rank: 3

积分
262
发表于 2020-4-28 11:33:44 | 显示全部楼层
exchen 发表于 2020-4-26 15:59
是的,书中第11章讲解重打包里描述了 dumpdecrypted 的原理,动态库也是可以脱的,在 229 页你可以看一下 ...

明白了 ,查了一下资料 lldb 也是能单独脱壳framework 的
回复

使用道具 举报

41

主题

109

帖子

609

积分

高级会员

Rank: 4

积分
609
发表于 2020-4-28 14:34:00 | 显示全部楼层
抖音这里的越狱判断只是一部分,只吧这些过了,还是被检测为越狱机器。
回复

使用道具 举报

119

主题

580

帖子

2607

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2607
 楼主| 发表于 2020-4-29 10:38:20 | 显示全部楼层
抖音已经更新了,上面的技术点只做学习和研究的思路,真正想完全解决还是要下很大的功夫的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|iOSHacker

GMT+8, 2021-10-18 09:01 , Processed in 0.026288 second(s), 19 queries .

iOS安全论坛

© 2017-2020 iOS Hacker Inc. 京ICP备17074153号-2

快速回复 返回顶部 返回列表