绕过某应用的越狱检测

前言


在打开应用时有一个弹窗


尝试使用lookinserver看不到这个弹窗页面,用flex又选不中。。。
决定在lldb中打印界面

正常启动应用

debugserver -x auto 127.0.0.1:2345 /var/containers/Bundle/Application/3504397A-96FA-47A4-B647-1108815092FD/CIOS.app/CIOS

然后刚点完continue就

Process 2611 exited with status = 45 (0x0000002d) 

这看起来就是ptrace,但是给ptrace下断点断点并不会触发。不过先启动应用,再以debugserver附加的方式并不会触发该反调试。
因为我太菜了,没有头绪,这里直接用大佬的AntiAntiDebug绕过了反调试。

正常lldb进入应用后

(lldb) pviews
error: libarclite_iphoneos.a(arclite.o) failed to load objfile for /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a
<_UIAlertControllerShimPresenterWindow: 0x131daac80; frame = (0 0; 414 896); opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x281f5aa00>; layer = <UIWindowLayer: 0x2811914c0>>
   | <UIView: 0x131dac370; frame = (0 0; 414 896); autoresize = W+H; layer = <CALayer: 0x281191760>>
   | <UITransitionView: 0x131dba380; frame = (0 0; 414 896); autoresize = W+H; layer = <CALayer: 0x2811e7de0>>
   |    | <UIView: 0x131ea4030; frame = (0 0; 414 896); layer = <CALayer: 0x2811ae720>>
   |    | <UIView: 0x131dad0b0; frame = (0 0; 414 896); userInteractionEnabled = NO; layer = <CALayer: 0x281191720>>
   |    | <_UIKeyboardLayoutAlignmentView: 0x131dacd00; frame = (0 896; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x2811917a0>>
   |    | <_UIAlertControllerView: 0x131db0d10; frame = (72 390; 270 126.5); layer = <CALayer: 0x281192460>>
   |    |    | <UIView: 0x131db12f0; frame = (0 0; 270 126.5); layer = <CALayer: 0x281192480>>
   |    |    |    | <_UIAlertControllerInterfaceActionGroupView: 0x131db1460; frame = (0 0; 270 126.5); opaque = NO; gestureRecognizers = <NSArray: 0x281f45d40>; layer = <CALayer: 0x2811924a0>>
   |    |    |    |    | <_UIDimmingKnockoutBackdropView: 0x131db2f00; frame = (0 0; 270 126.5); clipsToBounds = YES; layer = <CALayer: 0x2811929c0>>
   |    |    |    |    |    | <UIVisualEffectView: 0x131db32a0; frame = (0 0; 270 126.5); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x2811929e0>> clientRequestedContentView effect=<UIBlurEffect: 0x2812f8840> style=UIBlurEffectStyleSystemVibrantBackgroundRegular
   |    |    |    |    |    |    | <_UIVisualEffectBackdropView: 0x131db3680; frame = (0 0; 270 126.5); autoresize = W+H; userInteractionEnabled = NO; layer = <UICABackdropLayer: 0x281192a20>>
   |    |    |    |    |    |    | <_UIVisualEffectContentView: 0x131db38b0; frame = (0 0; 270 126.5); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x281192f00>>
   |    |    |    |    | <UIView: 0x131db16d0; frame = (0 0; 270 126.5); clipsToBounds = YES; layer = <CALayer: 0x281192520>>
   |    |    |    |    |    | <_UIInterfaceActionGroupHeaderScrollView: 0x13209bc00; frame = (0 0; 270 82); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x281f47630>; layer = <CALayer: 0x281193c60>; contentOffset: {0, 0}; contentSize: {270, 82}; adjustedContentInset: {0, 0, 0, 0}>
   |    |    |    |    |    |    | <UIView: 0x131db5bb0; frame = (0 0; 270 82); layer = <CALayer: 0x281193a60>>
   |    |    |    |    |    |    |    | <UIView: 0x131db6710; frame = (0 0; 270 0); clipsToBounds = YES; layer = <CALayer: 0x281193de0>>
   |    |    |    |    |    |    |    | <UILabel: 0x131db6a80; frame = (16 20; 238 42.5); text = '当前程序存在风险,继续使用可能造成安全隐患'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x283291310>>
   |    |    |    |    |    |    |    |    | <_UILabelContentLayer: 0x2811f3980> (layer)
.........
.........

就是一个很单纯的UIAlertControllerView

动态分析


给UIAlertController下断点,这是UIKit的方法,不需要先找地址,直接下符号断点就可以:

br s -n '-[UIAlertController setMessage:]'

断点被触发:

2020-07-26 21:30:59.353 CIOS[2630:148641] [AntiAntiDebug] - sysctl query trace status.
2020-07-26 21:30:59.353 CIOS[2630:148641] [AntiAntiDebug] trace status reomve success!
2020-07-26 21:30:59.799 CIOS[2630:148641] [AntiAntiDebug] - sysctl query trace status.
2020-07-26 21:30:59.799 CIOS[2630:148641] [AntiAntiDebug] trace status reomve success!
2020-07-26 21:30:59.890 CIOS[2630:148641] [AntiAntiDebug] - sysctl query trace status.
2020-07-26 21:30:59.890 CIOS[2630:148641] [AntiAntiDebug] trace status reomve success!
Process 2630 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000189509d40 UIKit`-[UIAlertController setMessage:]
UIKit`-[UIAlertController setMessage:]:
->  0x189509d40 <+0>:  stp    x22, x21, [sp, #-0x30]!
    0x189509d44 <+4>:  stp    x20, x19, [sp, #0x10]
    0x189509d48 <+8>:  stp    x29, x30, [sp, #0x20]
    0x189509d4c <+12>: add    x29, sp, #0x20            ; =0x20 
    0x189509d50 <+16>: mov    x20, x0
    0x189509d54 <+20>: mov    x0, x2
    0x189509d58 <+24>: bl     0x1819b4190               ; objc_retain
    0x189509d5c <+28>: mov    x19, x0
Target 0: (CIOS) stopped.

查看调用栈

(lldb) sbt
2020-07-26 21:31:01.228 CIOS[2630:148641] The device is jail broken!
2020-07-26 21:31:01.233 CIOS[2630:148641] The device is jail broken!
2020-07-26 21:31:01.238 CIOS[2630:148641] countyueye=1;;;;yueyu=7
2020-07-26 21:31:01.240 CIOS[2630:148641] The device is jail broken!
2020-07-26 21:31:01.241 CIOS[2630:148641] The device is jail broken!
2020-07-26 21:31:01.245 CIOS[2630:148641] countyueye=1;;;;yueyu=7
  ==========================================xia0LLDB===========================================
  BlockSymbolFile    Not Set The Block Symbol Json File, Try 'sbt -f'
  =============================================================================================
  frame #0: [file:0x187c19d40 mem:0x189509d40] UIKit`-[UIAlertController setMessage:] + 0 
  frame #1: [file:0x1879878d8 mem:0x1892778d8] UIKit`-[UIAlertView initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:] + 192 
  frame #2: [file:0x101ced0c0 mem:0x101ced0c0] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #3: [file:0x101cb4ac0 mem:0x101cb4ac0] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #4: [file:0x101cb3c9c mem:0x101cb3c9c] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #5: [file:0x1804fe9a0 mem:0x181dee9a0] libdispatch.dylib`_dispatch_client_callout + 16 
  frame #6: [file:0x1804ff6cc mem:0x181def6cc] libdispatch.dylib`dispatch_once_f + 56 
  frame #7: [file:0x101cb3c38 mem:0x101cb3c38] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #8: [file:0x100a65898 mem:0x100a65898] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #9: [file:0x100a64ba4 mem:0x100a64ba4] CIOS`===[E]===:error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..The process has been returned to the state before expression evaluation.
  frame #10: [file:0x1877e9e48 mem:0x1890d9e48] UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 380 
  frame #11: [file:0x1879f637c mem:0x1892e637c] UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3452 
  frame #12: [file:0x1879fbe24 mem:0x1892ebe24] UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1684 
  frame #13: [file:0x187a108b0 mem:0x1893008b0] UIKit`__84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke.3147 + 48 
  frame #14: [file:0x1879f90b8 mem:0x1892e90b8] UIKit`-[UIApplication workspaceDidEndTransaction:] + 168 
  frame #15: [file:0x1831f0884 mem:0x184ae0884] FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 36 
  frame #16: [file:0x1831f06f0 mem:0x184ae06f0] FrontBoardServices`-[FBSSerialQueue _performNext] + 176 
  frame #17: [file:0x1831f0aa0 mem:0x184ae0aa0] FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 56 
  frame #18: [file:0x1815f542c mem:0x182ee542c] CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 
  frame #19: [file:0x1815f4d9c mem:0x182ee4d9c] CoreFoundation`__CFRunLoopDoSources0 + 540 
  frame #20: [file:0x1815f29a8 mem:0x182ee29a8] CoreFoundation`__CFRunLoopRun + 744 
  frame #21: [file:0x181522da4 mem:0x182e12da4] CoreFoundation`CFRunLoopRunSpecific + 424 
  frame #22: [file:0x1877e2fc8 mem:0x1890d2fc8] UIKit`-[UIApplication _run] + 652 
  frame #23: [file:0x1877ddc9c mem:0x1890cdc9c] UIKit`UIApplicationMain + 208 
  frame #24: [file:0x10084a8e8 mem:0x10084a8e8] CIOS`main + 88
  frame #25: [file:0x18053159c mem:0x181e2159c] libdyld.dylib`start + 4 

脚本没起作用,不过地址已经得到了,地址对应的方法

101ced0c0   +[UIAlertView makeAlert:]
101cb4ac0  -[AuthenConfig initialize]
101cb3c9c  sub_101CB3C40
。。。。

静态分析



在sub_101CB3C40函数中调用了-[AuthenConfig initialize]
观察一下这个方法:

类型一

      *(_QWORD *)&v13 = "/Applications/Cydia.app";
      *((_QWORD *)&v13 + 1) = "/Library/MobileSubstrate/MobileSubstrate.dylib";
      *(_QWORD *)&v14 = "/bin/bash";
      *((_QWORD *)&v14 + 1) = "/usr/sbin/sshd";
      *(_OWORD *)&v130.st_dev = v13;
      *(_OWORD *)&v130.st_uid = v14;
      v130.st_atimespec.tv_sec = (__darwin_time_t)"/etc/apt";
      while ( 1 )
      {
        v15 = objc_msgSend(&OBJC_CLASS___NSFileManager, "defaultManager");
        v16 = (void *)objc_retainAutoreleasedReturnValue(v15);
        v17 = objc_msgSend(v7[14], "stringWithUTF8String:", *((_QWORD *)&v130.st_dev + v12));
        v18 = objc_retainAutoreleasedReturnValue(v17);
        v19 = (unsigned __int64)objc_msgSend(v16, "fileExistsAtPath:", v18);
        objc_release(v18);
        objc_release(v16);
        if ( v19 & 1 )
          break;
        if ( (unsigned __int64)++v12 > 4 )
        {
          NSLog(CFSTR("The device is NOT jail broken!"));
          v20 = 0;
          goto LABEL_18;
        }
      }
      NSLog(CFSTR("The device is jail broken!"));
      v20 = 10;
。。。。。。
      v23 = objc_msgSend(&OBJC_CLASS___NSFileManager, "defaultManager");
      v24 = (void *)objc_retainAutoreleasedReturnValue(v23);
      v25 = (unsigned __int64)objc_msgSend(v24, "fileExistsAtPath:",   CFSTR("/User/Applications/"));
。。。。。。
      v38 = objc_msgSend(&OBJC_CLASS___NSFileManager, "defaultManager");
      v39 = (void *)objc_retainAutoreleasedReturnValue(v38);
      v40 = (unsigned __int64)objc_msgSend(v39, "fileExistsAtPath:", CFSTR("/private/var/lib/apt/"));
。。。。。。
        v26 = objc_msgSend(&OBJC_CLASS___NSFileManager, "defaultManager");
        v27 = (void *)objc_retainAutoreleasedReturnValue(v26);
        v28 = v27;
        v29 = objc_msgSend(v27, "contentsOfDirectoryAtPath:error:", CFSTR("/User/Applications/"), 0LL);
。。。。。。
      v52 = objc_msgSend(
              &OBJC_CLASS___NSFileHandle,
              "fileHandleForReadingAtPath:",
              CFSTR("/Applications/Cydia.app/Cydia"));
      v53 = (void *)objc_retainAutoreleasedReturnValue(v52);
      v54 = v53;
      v55 = objc_msgSend(v53, "readDataOfLength:", 1024LL);
。。。。。。
      v33 = objc_msgSend(&OBJC_CLASS___UIApplication, "sharedApplication");
      v34 = (void *)objc_retainAutoreleasedReturnValue(v33);
      v35 = objc_msgSend(&OBJC_CLASS___NSURL, "URLWithString:", CFSTR("cydia://"));
      v36 = objc_retainAutoreleasedReturnValue(v35);
      v37 = (unsigned __int64)objc_msgSend(v34, "canOpenURL:", v36);

这里就是简单的通过fileExistsAtPath、contentsOfDirectoryAtPath、fileHandleForReadingAtPath和canOpenURL检测越狱特有的文件,这个非常好hook

%hook NSFileManager

- (BOOL)fileExistsAtPath:(NSString *)path 
{
	NSArray<NSString *> *jailFile = @[
		@"/Applications/Cydia.app",
		@"/bin/bash",
		@"/Library/MobileSubstrate/MobileSubstrate.dylib",
		@"/usr/sbin/sshd",
		@"/etc/apt",
		@"/User/Applications/",
		@"/private/var/lib/apt/",
  	];
	for(NSString *jail in jailFile)
	{
		if([path containsString:jail])
		{
			return NO;
		}
	}
  
	return %orig(path);
}

%end

%hook NSFileManager

- (NSArray<NSString *> *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError * _Nullable *)error
{
	if([path containsString:@"/User/Applications/"])
		path = @"/User";

	return %orig;
}

%end

%hook NSFileHandle

+ (id)fileHandleForReadingAtPath:(NSString *)path
{
	if([path containsString:@"/Applications/Cydia.app/Cydia"])
		path = @"/Applications";
	
	return %orig;
}

%end

%hook UIApplication

- (BOOL)canOpenURL:(NSURL *)url 
{
	if([[url absoluteString] isEqualToString:@"cydia://"])
    	return NO;

	return %orig;
}
%end

类型二

if ( !stat("/Library/MobileSubstrate/MobileSubstrate.dylib", &v130)
        || !stat("/Applications/Cydia.app", &v130)
        || !stat("/var/lib/cydia/", &v130)
        || !stat("/var/cache/apt", &v130) )

这个是通过c函数stat检测越狱文件,可以用MSHookFunction去hook

static int(*orig_stat)(const char* path,struct stat *buf);
int new_stat(const char *path,struct stat *buf)
{
    if(strcmp(path,"/Library/MobileSubstrate/MobileSubstrate.dylib") == 0
		|| strcmp(path,"/Applications/Cydia.app") == 0
		|| strcmp(path,"/var/lib/cydia/") == 0
		|| strcmp(path,"/var/cache/apt") == 0)
        
		return -1;
    
    return orig_stat(path,buf);
}

类型三

          _dyld_get_image_name(v45);
          v46 = (void *)objc_alloc(&OBJC_CLASS___NSString);
          v47 = _dyld_get_image_name(v45);
          v48 = objc_msgSend(v46, "initWithUTF8String:", v47);
          if ( !objc_msgSend(v48, "compare:", CFSTR("/usr/lib/libSystem.B.dylib")) )
            ++v43;
          v44 += (unsigned __int64)objc_msgSend(v48, "containsString:", CFSTR("/Library/MobileSubstrate"));

这里通过_dyld_get_image_name检测当前被加载的动态库,也可以用MSHookFunction去hook

static const char * (*orig_dyld_get_image_name)(int image_index);
const char *new_dyld_get_image_name(int image_index)
{
	char *result = NULL;
	result = (char *)orig_dyld_get_image_name(image_index);
	if([[NSString stringWithUTF8String:result] containsString:@"MobileSubstrate"])
		result = (char *)"";
 
	return (char *)result;
}

还有
%ctor 
{
	@autoreleasepool
	{
        MSHookFunction((void *)_dyld_get_image_name,(void *)new_dyld_get_image_name,(void **)&orig_dyld_get_image_name);
        MSHookFunction((void *)stat,(void *)new_stat,(void **)&orig_stat);
	}
}

这样就没有弹窗了:

(lldb) c
Process 2647 resuming
。。。。。。
2020-07-26 22:15:13.937 CIOS[2647:150077] The device is NOT jail broken!
。。。。。。

其实也可以通过NSLog的信息去搜string,查看交叉引用并逐个下断点:


QQ20200726-222159

参考


1 Like