前言
在打开应用时有一个弹窗
尝试使用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,查看交叉引用并逐个下断点: