乐趣区

关于ios:iOS逆向某不知名App越狱检测

1. 指标
此篇文本为入门文章,大家莫抱过多冀望。此文章的目标是教大家如何从 UI 动手,去定位本人想要的货色。
2. 操作环境

mac 零碎
frida-ios-dump:砸壳
已越狱 iOS 设施:脱壳及 frida 调试
IDA Pro:动态剖析

3. 流程
寻找切入点
启动 App 后,界面如下图:

IMG_67EF545277E4-1
剖析过程
从界面能够看出,App 检测到越狱后,会弹出一个弹窗,文案为越狱手机存在平安危险,做 iOS 开发的都晓得,最终这文案显示前,会调用 UILabel 类的 setText: 办法。咱们 trace 该办法并打印堆栈:
js 代码:
{onEnter(log, args, state) {log(-[UILabel setText:${new ObjC.Object(args[2])}]);   log(‘UILabel setText called from:\n’ +         Thread.backtrace(this.context, Backtracer.ACCURATE)         .map(DebugSymbol.fromAddress).join(‘\n’) + ‘\n’);  },  onLeave(log, retval, state) {}}
要害日志如下:
-[UILabel setText: 越狱手机存在平安危险]UILabel setText called from:0x1eaa7d0f4 UIKitCore!-[_UIAlertControllerView _updateMessageLabelContents]0x1eaa756f8 UIKitCore!-[_UIAlertControllerView _prepareMesssageLabel]0x1eaa750f8 UIKitCore!-[_UIAlertControllerView _prepareViewsAndAddConstraints]0x1eaa75048 UIKitCore!-[_UIAlertControllerView setAlertController:]0x1eaa61740 UIKitCore!-[UIAlertController loadView]0x1ead35ed8 UIKitCore!-[UIViewController loadViewIfRequired]0x1ead36628 UIKitCore!-[UIViewController view]0x1ead4ddd4 UIKitCore!-[UIViewController _setPresentationController:]0x1ead461f4 UIKitCore!-[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:]0x1ead47ccc UIKitCore!-[UIViewController _presentViewController:withAnimationController:completion:]0x1ead4a3a8 UIKitCore!__63-[UIViewController _presentViewController:animated:completion:]_block_invoke0x1ead4a8a4 UIKitCore!-[UIViewController _performCoordinatedPresentOrDismiss:animated:]0x1ead4a300 UIKitCore!-[UIViewController _presentViewController:animated:completion:]0x1ead4a560 UIKitCore!-[UIViewController presentViewController:animated:completion:]0x10128253c GeneralApp!0xd253c (0x1000d253c)0x1be344a38 libdispatch.dylib!_dispatch_call_block_and_release
应用 frida-ios-dump 砸壳后,再应用 IDA Pro 编译 ipa 文件。
跳转到内存 0x1000d253c 地位

image-20220911160319867
再按 F5:
__int64 __fastcall sub_1000D24D4(_QWORD a1){void v1; // x19  __int64 v2; // x20  void *v4; // [xsp+8h] [xbp-38h]  __int64 v5; // [xsp+10h] [xbp-30h]  __int64 (__fastcall v6)(); // [xsp+18h] [xbp-28h]  void v7; // [xsp+20h] [xbp-20h]  __int64 v8; // [xsp+28h] [xbp-18h]  v1 = (void )a1[4];  v2 = a1[5];  v4 = _NSConcreteStackBlock;  v5 = 3254779904LL;  v6 = sub_1000D2554;  v7 = &unk_101A29970;  v8 = objc_retain(a1[6]);  objc_msgSend(v1, “presentViewController:animated:completion:”, v2, 1LL, &v4);  return objc_release(v8);}
查找 sub_1000D24D4 函数的穿插援用,一层一层往上找,最终找到如下函数:
void __cdecl -UIViewController cft_presentViewController:presentType:presentCompletionHandler:dismissCompleteHandler:{id v6; // x21  id v7; // x20  UIViewController v8; // x24  void v9; // x19  __int64 v10; // x20  __int64 v11; // x21  void v12; // x0  __int64 v13; // x22  dispatch_semaphore_t v14; // x23  void v15; // x0  void v16; // x24  void v17; // x0  void v18; // x0  void v19; // x27  void v20; // x0  __int64 v21; // x28  void v22; // x0  void v23; // x0  void v24; // x25  void v25; // x0  __int64 v26; // x26  __int64 v27; // [xsp+8h] [xbp-A8h]  void v28; // [xsp+10h] [xbp-A0h]  __int64 v29; // [xsp+18h] [xbp-98h]  __int64 (__fastcall v30)(__int64); // [xsp+20h] [xbp-90h]  void v31; // [xsp+28h] [xbp-88h]  __int64 v32; // [xsp+30h] [xbp-80h]  __int64 v33; // [xsp+38h] [xbp-78h]  __int64 v34; // [xsp+40h] [xbp-70h]  UIViewController v35; // [xsp+48h] [xbp-68h]  __int64 v36; // [xsp+50h] [xbp-60h]  __int64 v37; // [xsp+58h] [xbp-58h]  v6 = a6;  v7 = a5;  v8 = self;  v9 = (void )objc_retain(a3);  v10 = objc_retain(v7);  v11 = objc_retain(v6);  v37 = 0LL;  v12 = objc_msgSend(v9,          “aspect_hookSelector:withOptions:usingBlock:error:”,          “viewDidDisappear:”,          0LL,          &off_101A2BF98,          &v37);  objc_unsafeClaimAutoreleasedReturnValue(v12);  v13 = objc_retain(v37);  if (!v13)  {v14 = dispatch_semaphore_create(0LL);    v28 = _NSConcreteStackBlock;    v29 = 3254779904LL;    v30 = sub_1000D23A0;    v31 = &unk_101A2BFB8;    v32 = objc_retain(v9);    v33 = objc_retain(v11);    v27 = objc_retain(v14);    v34 = v27;    v35 = v8;    v36 = objc_retain(v10);    v15 = objc_msgSend(&OBJC_CLASS___NSBlockOperation, “blockOperationWithBlock:”, &v28);    v16 = (void )objc_retainAutoreleasedReturnValue(v15);    v17 = objc_msgSend((void )qword_101F71BF8, “operations”);    v18 = (void )objc_retainAutoreleasedReturnValue(v17);    v19 = v18;    v20 = objc_msgSend(v18, “lastObject”);    v21 = objc_retainAutoreleasedReturnValue(v20);    objc_release(v21);    objc_release(v19);    if (v21)    {v22 = objc_msgSend((void )qword_101F71BF8, “operations”);      v23 = (void )objc_retainAutoreleasedReturnValue(v22);      v24 = v23;      v25 = objc_msgSend(v23, “lastObject”);      v26 = objc_retainAutoreleasedReturnValue(v25);      objc_msgSend(v16, “addDependency:”, v26);      objc_release(v26);      objc_release(v24);    }    objc_msgSend((void *)qword_101F71BF8, “addOperation:”, v16);    objc_release(v16);    objc_release(v36);    objc_release(v34);    objc_release(v33);    objc_release(v32);    objc_release(v27);  }  objc_release(v13);  objc_release(v11);  objc_release(v10);  objc_release(v9);}
接下来,同时跟踪 UILabel 的 setText: 办法和 UIViewController 的 cft_presentViewController:presentType:presentCompletionHandler:dismissCompleteHandler: 办法,获取到日志如下:
-[UIViewController cft_presentViewController:0x104928e00 presentType:0x1 presentCompletionHandler:0x16ec4e5a8 dismissCompleteHandler:0x16ec4e580]UIViewController cft_presentViewController called from:0x1012b9fdc GeneralApp!+[CFTAlertPresentController presentAlertController:presentCompletionHandler:dismissCompleteHandler:]0x1012d464c GeneralApp!-[LaunchingViewController start]0x1012d3360 GeneralApp!0x123360 (0x100123360)0x1be3457d4 libdispatch.dylib!_dispatch_client_callout0x1be2f3c1c libdispatch.dylib!_dispatch_lane_barrier_sync_invoke_and_complete0x1012d3310 GeneralApp!0x123310 (0x100123310)0x1012b9978 GeneralApp!0x109978 (0x100109978)0x1eb76ad1c UIKitCore!-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]0x1eb741a74 UIKitCore!-[UIViewAnimationState sendDelegateAnimationDidStop:finished:]0x1eb742048 UIKitCore!-[UIViewAnimationState animationDidStop:finished:]0x1c2e573c8 QuartzCore!CA::Layer::run_animation_callbacks(void*)0x1be3457d4 libdispatch.dylib!_dispatch_client_callout0x1be2f3008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp0x1be898b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__0x1be893a58 CoreFoundation!__CFRunLoopRun0x1be892fb4 CoreFoundation!CFRunLoopRunSpecific-[UILabel setText: 您的设施不平安]UILabel setText called from:0x1eaa7cfe8 UIKitCore!-[_UIAlertControllerView _updateTitleLabelContents]0x1eaa75544 UIKitCore!-[_UIAlertControllerView _prepareTitleLabel]0x1eaa750e8 UIKitCore!-[_UIAlertControllerView _prepareViewsAndAddConstraints]0x1eaa75048 UIKitCore!-[_UIAlertControllerView setAlertController:]0x1eaa61740 UIKitCore!-[UIAlertController loadView]0x1ead35ed8 UIKitCore!-[UIViewController loadViewIfRequired]0x1ead36628 UIKitCore!-[UIViewController view]0x1ead4ddd4 UIKitCore!-[UIViewController _setPresentationController:]0x1ead461f4 UIKitCore!-[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:]0x1ead47ccc UIKitCore!-[UIViewController _presentViewController:withAnimationController:completion:]0x1ead4a3a8 UIKitCore!__63-[UIViewController _presentViewController:animated:completion:]_block_invoke0x1ead4a8a4 UIKitCore!-[UIViewController _performCoordinatedPresentOrDismiss:animated:]0x1ead4a300 UIKitCore!-[UIViewController _presentViewController:animated:completion:]0x1ead4a560 UIKitCore!-[UIViewController presentViewController:animated:completion:]0x10128253c GeneralApp!0xd253c (0x1000d253c)0x1be344a38 libdispatch.dylib!_dispatch_call_block_and_release-[UILabel setText: 越狱手机存在平安危险]UILabel setText called from:0x1eaa7d0f4 UIKitCore!-[_UIAlertControllerView _updateMessageLabelContents]0x1eaa756f8 UIKitCore!-[_UIAlertControllerView _prepareMesssageLabel]0x1eaa750f8 UIKitCore!-[_UIAlertControllerView _prepareViewsAndAddConstraints]0x1eaa75048 UIKitCore!-[_UIAlertControllerView setAlertController:]0x1eaa61740 UIKitCore!-[UIAlertController loadView]0x1ead35ed8 UIKitCore!-[UIViewController loadViewIfRequired]0x1ead36628 UIKitCore!-[UIViewController view]0x1ead4ddd4 UIKitCore!-[UIViewController _setPresentationController:]0x1ead461f4 UIKitCore!-[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:]0x1ead47ccc UIKitCore!-[UIViewController _presentViewController:withAnimationController:completion:]0x1ead4a3a8 UIKitCore!__63-[UIViewController _presentViewController:animated:completion:]_block_invoke0x1ead4a8a4 UIKitCore!-[UIViewController _performCoordinatedPresentOrDismiss:animated:]0x1ead4a300 UIKitCore!-[UIViewController _presentViewController:animated:completion:]0x1ead4a560 UIKitCore!-[UIViewController presentViewController:animated:completion:]0x10128253c GeneralApp!0xd253c (0x1000d253c)0x1be344a38 libdispatch.dylib!_dispatch_call_block_and_release
在 cft_presentViewController:presentType:presentCompletionHandler:dismissCompleteHandler: 办法的调用栈,发现 [LaunchingViewController start] 办法,应用 ida pro 查看该函数:
void __cdecl -LaunchingViewController start{if ( !(~LODWORD(self->_launchAchieveOption) & 0x1FLL) )  {v2 = self;    self->_launchAchieveOption = 0LL;    v3 = ((id (__cdecl )(GuaTabBarController_meta , SEL))objc_msgSend)((GuaTabBarController_meta )&OBJC_CLASS___GuaTabBarController,           “shareTabBarController”);    v4 = objc_retainAutoreleasedReturnValue(v3);    v23 = _NSConcreteStackBlock;    v24 = 3254779904LL;    v25 = sub_100124684;    v26 = &unk_101A2BC20;    v5 = (void )objc_retain(v4);    v27 = v5;    v28 = v2;    +NaviService naviModelWithNaviRoot:withNaviHead:withSourceFrom:ret:;    if (v2->_adDetailDisplayController)    {v6 = objc_msgSend(v5, “viewControllers”, v23, v24, v25, v26);      v7 = (void )objc_retainAutoreleasedReturnValue(v6);      v8 = v7;      v9 = objc_msgSend(v7, “objectAtIndexedSubscript:”, 0LL, v23, v24, v25, v26);      v10 = (void )objc_retainAutoreleasedReturnValue(v9);      objc_msgSend(v10, “pushViewController:animated:”, v2->_adDetailDisplayController, 1LL, v23, v24, v25, v26);    }    v11 = objc_msgSend(&OBJC_CLASS___UIApplication, “sharedApplication”, v23, v24, v25, v26);    v12 = (void )objc_retainAutoreleasedReturnValue(v11);    v13 = v12;    v14 = objc_msgSend(v12, “delegate”, v23, v24, v25, v26);    v15 = (void )objc_retainAutoreleasedReturnValue(v14);    v16 = v15;    v17 = objc_msgSend(v15, “window”, v23, v24, v25, v26);    v18 = (void )objc_retainAutoreleasedReturnValue(v17);    objc_msgSend(v18, “setRootViewController:”, v5, v23, v24, v25, v26);    if ((unsigned int)+CFTJailBreakJudge deviceIsJailBreak )    {v19 = objc_msgSend(              &OBJC_CLASS___UIAlertController,              “alertControllerWithTitle:message:preferredStyle:”,              CFSTR(“ 您的设施不平安 ”),              CFSTR(“ 越狱手机存在平安危险 ”),              1LL,              v23,              v24,              v25,              v26);      v20 = (void )objc_retainAutoreleasedReturnValue(v19);      v21 = objc_msgSend(&OBJC_CLASS___UIAlertAction,              “actionWithTitle:style:handler:”,              CFSTR(“ 确定 ”),              0LL,              0LL,              v23,              v24,              v25,              v26);      v22 = objc_retainAutoreleasedReturnValue(v21);      objc_msgSend(v20, “addAction:”, v22, v23, v24, v25, v26);      +CFTAlertPresentController presentAlertController:;    }  }}
从函数中可发现越狱检测函数为 [CFTJailBreakJudge deviceIsJailBreak]:
bool __cdecl +CFTJailBreakJudge deviceIsJailBreak{CFTJailBreakJudge_meta v2; // x20  void v3; // x0  __int64 v4; // x0  void v5; // x0  void v6; // x19  void v7; // x0  void v8; // x22  __int64 v9; // x25  unsigned __int64 v10; // x26  uint32_t v11; // w0  uint32_t v12; // w20  uint32_t v13; // w21  void v14; // x25  const char v15; // x0  void v16; // x25  char v17; // w26  _BOOL8 v18; // x20  bool result; // w0  __int128 v20; // [xsp+0h] [xbp-140h]  __int128 v21; // [xsp+10h] [xbp-130h]  __int128 v22; // [xsp+20h] [xbp-120h]  __int128 v23; // [xsp+30h] [xbp-110h]  char v24; // [xsp+40h] [xbp-100h]  const __CFString v25; // [xsp+C0h] [xbp-80h]  const __CFString v26; // [xsp+C8h] [xbp-78h]  const __CFString v27; // [xsp+D0h] [xbp-70h]  const __CFString v28; // [xsp+D8h] [xbp-68h]  const __CFString v29; // [xsp+E0h] [xbp-60h]  __int64 v30; // [xsp+E8h] [xbp-58h]  v2 = self;  v25 = CFSTR(“/Applications/Cydia.app”);  v26 = CFSTR(“/Library/MobileSubstrate/MobileSubstrate.dylib”);  v27 = CFSTR(“/bin/bash”);  v28 = CFSTR(“/usr/sbin/sshd”);  v29 = CFSTR(“/etc/apt”);  v3 = objc_msgSend(&OBJC_CLASS___NSArray, “arrayWithObjects:count:”, &v25, 5LL);  v4 = objc_retainAutoreleasedReturnValue(v3);  v20 = 0u;  v21 = 0u;  v22 = 0u;  v23 = 0u;  v5 = (void )objc_retain(v4);  v6 = v5;  v7 = objc_msgSend(v5, “countByEnumeratingWithState:objects:count:”, &v20, &v24, 16LL, 0LL);  if (v7)  {v8 = v7;    v9 = (_QWORD )v21;    while (2)    {v10 = 0LL;      do      {        if ( (_QWORD )v21 != v9 )          objc_enumerationMutation(v6);        if ((unsigned __int64)objc_msgSend(v2,                                 “permissionForFile:”,                                 (_QWORD )(((_QWORD )&v20 + 1) + 8  v10),                                 (_QWORD)v20) & 1 )        {objc_release(v6);          goto LABEL_16;        }        ++v10;      }      while (v10 < (unsigned __int64)v8 );      v8 = objc_msgSend(v6, “countByEnumeratingWithState:objects:count:”, &v20, &v24, 16LL, (_QWORD)v20);      if (v8)        continue;      break;    }  }  objc_release(v6);  if (!((unsigned __int64)objc_msgSend(v2, “permissionForFile:”, CFSTR(“/User/Applications/”), (_QWORD)v20) & 1) )  {v11 = _dyld_image_count();    if (!v11)    {LABEL_14:      v18 = getenv(“DYLD_INSERT_LIBRARIES”) != 0LL;      goto LABEL_17;    }    v12 = v11;    v13 = 0;    while (1)    {v14 = (void *)objc_alloc(&OBJC_CLASS___NSString);      v15 = _dyld_get_image_name(v13);      v16 = objc_msgSend(v14, “initWithUTF8String:”, v15, (_QWORD)v20);      v17 = (unsigned __int64)objc_msgSend(v16, “containsString:”, CFSTR(“MobileSubstrate.dylib”), (_QWORD)v20);      objc_release(v16);      if (v17 & 1)        break;      if (v12 == ++v13)        goto LABEL_14;    }  }LABEL_16:  v18 = 1;LABEL_17:  return v18;}
后果
1、检测以下门路是否存在:

/Applications/Cydia.app/Library/MobileSubstrate/MobileSubstrate.dylib/bin/bash/usr/sbin/sshd/etc/apt
2、如果门路 /User/Applications/ 不存在,检测 getenv(“DYLD_INSERT_LIBRARIES”)是否存在
3、如果门路 /User/Applications/ 不存在,检测以后当初在运行的动静库是否蕴含 MobileSubstrate.dylib
End
浏览此文档的过程中遇到任何问题,请关注公众号【挪动端 Android 和 iOS 开发技术分享】或加 QQ 群【812546729

退出移动版