本帖最后由 wruih 于 2016-4-5 12:14 编辑
安装ipa不知为何,这个ipa在我的iPhone 5, iOS 8.1.2上安装之后无法启动,每次启动均会闪退;我采用了ldid重签名和把app放在/Applications下的方案,都没有解决闪退的问题,不知道是不是出题人故意留给我们的一道坎?我没有深究这个问题,而是尝试在我的iPhone 4s, iOS 6.1.3安装此ipa,竟意外发现app可以成功打开了,如图所示:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/6/61aa6e7a93ce3bf5229d5fa75dabe4f45a7434dd.PNG
把玩app安装成功之后,我们先随便操作一下,看看针对不同的输入,这个app会给我们怎样的反馈。先直接点击“进入”,发现此app直接退出了;再次打开app,输入snakeninny,结果出现了“密码错误”的提示,如图所示:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/3/338b07e3f147811f659f7c1e8fd16342f6258538.PNG
跟我一起思考——
错误提示一定是由代码控制的;既然弹出了错误提示,说明在弹出错误提示的代码之前,一定有输入是否错误的判断;它应该就是我们的输入与正确答案是否相同的判断。因为点击“进入”之后弹框,那么判断操作一定是在按钮的响应函数之后发生的;如果能够找到这个按钮响应函数,就可以顺藤摸瓜,找到这个判断。
那么我们今天的任务,就是找到这个判断的代码,从而找到正确答案。开始操作!
用Cycript找到“进入”按钮的响应函数这个步骤在书上已经不知道重复多少遍了,接下来的操作主要以代码表示,伴以少量解说,跟紧喽!
FunMaker-4s:~ root# ps -e PID TTY TIME CMD 1 ?? 0:31.21 /sbin/launchd 26 ?? 5:53.88 /usr/libexec/UserEventAgent (System)... 3060 ?? 0:02.52 /var/mobile/Applications/3E693339-7347-4129-887D-1DBE0C0587AE/level1.app/level1 3079 ?? 0:00.02 /usr/libexec/launchproxy /usr/sbin/sshd -i 3082 ?? 0:00.28 sshd: root@ttys000 3083 ttys000 0:00.04 -sh 3084 ttys000 0:00.01 ps -eFunMaker-4s:~ root# cycript -p level1cy# ?expandexpand == truecy# [[UIApp keyWindow] recursiveDescription]@"<UIWindow: 0x1fde5d30; frame = (0 0; 320 480); autoresize = W+H; layer = <UIWindowLayer: 0x1fde5e30>>... | | <UIButton: 0x1fd5acd0; frame = (110 348; 100 30); opaque = NO; layer = <CALayer: 0x1fd5ac50>> | | | <UIButtonLabel: 0x20872890; frame = (31 4; 37 22); text = '\xe8\xbf\x9b\xe5\x85\xa5'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x208729f0>> | | <UIImageView: 0x1fd59030; frame = (0 420; 125.5 40); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1fd596e0>> | | <UILabel: 0x1fd58820; frame = (246 430; 64 20); text = '\xe9\x98\xbf\xe9\x87\x8c\xe9\x92\xb1\xe7\x9b\xbe'; clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x1fd587f0>> | | <UIImageView: 0x1fd57c40; frame = (218 427.5; 25 25); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1fd57ca0>>"cy# button = #0x1fd5acd0#"<UIButton: 0x1fd5acd0; frame = (110 348; 100 30); opaque = NO; layer = <CALayer: 0x1fd5ac50>>"cy# [button setHidden:YES]“进入”按钮不见了,界面变成了这样:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/d/d49ad67cc1c4c6b9b8ea9651261ef852d9170d4b.PNG
继续操作:
cy# [button allTargets][NSSet setWithArray:@[#"<ViewController: 0x20869990>"]]]cy# [button allControlEvents]64cy# [button actionsForTarget:#0x20869990 forControlEvent:64]@["onClick"]好了,按钮的响应函数是[ViewController onClick],开始分析汇编代码。
从[ViewController onClick]出发,找到答案[ViewController onClick]的汇编执行流程如图所示:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/6/6683c53559d0fe1061a489c5706ce45847f77709.png
整个流程并不复杂(比书上的几个例子要简单得多,大致浏览一遍,你就一定会注意到下图这个红色的方块:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/a/acbb6167f3a62521bac22fd95c4f878fc4cbfdff.jpg
它的汇编代码是:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/7/76d12a3c5a32f184a19c99f6bec92db21a99e465.png很明显,这段汇编代码从textField里读text,转换成UTF8String之后和某个东西作判断,并根据判断结果跳转。这个现象跟我们上一节作出的预测不谋而合,我们在这段代码的开头下个断点,然后单步执行,看看每个objc_msgSend都是做的什么操作。
先用debugserver挂载level1:
FunMaker-4s:~ root# debugserver *:1234 -a level1debugserver-199 for armv7.Listening to port 1234...然后用LLDB连过去:
192:~ snakeninny$ lldb(lldb) process connect connect://localhost:12342015-10-19 16:29:37.015 lldb[15434:956234] Metadata.framework [Error]: couldn't get the client portProcess 3112 stopped* thread #1: tid = 0x1e03, 0x3c606eb4 libsystem_kernel.dylib`mach_msg_trap + 20, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x3c606eb4 libsystem_kernel.dylib`mach_msg_trap + 20libsystem_kernel.dylib`mach_msg_trap:-> 0x3c606eb4 <+20>: pop {r4, r5, r6, r8} 0x3c606eb8 <+24>: .long 0xe12fff1e ; unknown opcodelibsystem_kernel.dylib`mach_msg_overwrite_trap: 0x3c606ebc <+0>: mov r12, sp 0x3c606ec0 <+4>: push {r4, r5, r6, r8}(lldb) cProcess 3112 resuming在0000B76A下断点(这些操作也都在书上重复过无数遍了,下面还是以码代字):
(lldb) image list -o -f[ 0] 0x00054000 /var/mobile/Applications/3E693339-7347-4129-887D-1DBE0C0587AE/level1.app/level1(0x0000000000058000)[ 1] 0x00077000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x0000000000077000)[ 2] 0x0328e000 /Users/snakeninny/Library/Developer/Xcode/iOS DeviceSupport/6.1.3 (10B329)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation[ 3] 0x0328e000 /Users/snakeninny/Library/Developer/Xcode/iOS DeviceSupport/6.1.3 (10B329)/Symbols/System/Library/Frameworks/UIKit.framework/UIKit...(lldb) br s -a '0x00054000+0x0000B76A'Breakpoint 1: where = level1`___lldb_unnamed_function36$$level1 + 202, address = 0x0005f76a(lldb)点击按钮,触发断点:
Process 3112 stopped* thread #1: tid = 0x1e03, 0x0005f76a level1`___lldb_unnamed_function36$$level1 + 202, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0005f76a level1`___lldb_unnamed_function36$$level1 + 202level1`___lldb_unnamed_function36$$level1:-> 0x5f76a <+202>: movw r0, #0x346c 0x5f76e <+206>: mov r10, r4 0x5f770 <+208>: movt r0, #0x1 0x5f774 <+212>: ldr.w r8, [sp, #0x10](lldb) ni...Process 3112 stopped* thread #1: tid = 0x1e03, 0x0005f792 level1`___lldb_unnamed_function36$$level1 + 242, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0005f792 level1`___lldb_unnamed_function36$$level1 + 242level1`___lldb_unnamed_function36$$level1:-> 0x5f792 <+242>: movw r1, #0x3492 0x5f796 <+246>: movt r1, #0x1 0x5f79a <+250>: add r1, pc 0x5f79c <+252>: ldr r5, [r1](lldb) po $r0snakeninny(lldb) ni...Process 3112 stopped* thread #1: tid = 0x1e03, 0x0005f7a0 level1`___lldb_unnamed_function36$$level1 + 256, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0005f7a0 level1`___lldb_unnamed_function36$$level1 + 256level1`___lldb_unnamed_function36$$level1:-> 0x5f7a0 <+256>: blx 0x6ff18 ; symbol stub for: objc_msgSend 0x5f7a4 <+260>: mov r4, r0 0x5f7a6 <+262>: mov r0, r6 0x5f7a8 <+264>: mov r1, r5(lldb) p (char *)$r1(char *) $3 = 0x39eb1d27 "UTF8String"(lldb) niProcess 3112 stopped* thread #1: tid = 0x1e03, 0x0005f7a4 level1`___lldb_unnamed_function36$$level1 + 260, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0005f7a4 level1`___lldb_unnamed_function36$$level1 + 260level1`___lldb_unnamed_function36$$level1:-> 0x5f7a4 <+260>: mov r4, r0 0x5f7a6 <+262>: mov r0, r6 0x5f7a8 <+264>: mov r1, r5 0x5f7aa <+266>: blx 0x6ff18 ; symbol stub for: objc_msgSend(lldb) p (char *)$r0(char *) $4 = 0x1c520110 "snakeninny"(lldb) niProcess 3112 stopped...* thread #1: tid = 0x1e03, 0x0005f7aa level1`___lldb_unnamed_function36$$level1 + 266, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0005f7aa level1`___lldb_unnamed_function36$$level1 + 266level1`___lldb_unnamed_function36$$level1:-> 0x5f7aa <+266>: blx 0x6ff18 ; symbol stub for: objc_msgSend 0x5f7ae <+270>: mov r5, r0 0x5f7b0 <+272>: ldrb r0, [r5] 0x5f7b2 <+274>: cmp r0, #0x0(lldb) p (char *)$r1(char *) $5 = 0x39eb1d27 "UTF8String"(lldb) po $r0Sp4rkDr0idKit(lldb) niProcess 3112 stopped* thread #1: tid = 0x1e03, 0x0005f7ae level1`___lldb_unnamed_function36$$level1 + 270, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0005f7ae level1`___lldb_unnamed_function36$$level1 + 270level1`___lldb_unnamed_function36$$level1:-> 0x5f7ae <+270>: mov r5, r0 0x5f7b0 <+272>: ldrb r0, [r5] 0x5f7b2 <+274>: cmp r0, #0x0 0x5f7b4 <+276>: beq 0x5f7d6 ; <+310>(lldb) p (char *)$r0(char *) $7 = 0x1d016640 "Sp4rkDr0idKit"...看到了一个可疑的字符串“Sp4rkDr0idKit”,你应该已经猜到了,它就是我们的答案(不信的话自己试一下 http://7xibfi.com1.z0.glb.clouddn.com/images/emoji/apple/wink.png?v=0 )。知其然,还要知其所以然,我们继续分析,看看正确的判断逻辑是怎样的。
分析判断逻辑顺着上面的代码,我们接着分析:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/1/160f2d949696728f13f99e409121f88e6cdd8883.png
每一行汇编是什么意思,我都已经标注在图里了,强烈建议你先自己分析一遍,有不明白的地方再看图,然后自己再分析一遍,直到自己能独立分析为止。
值得一提的是,这个判断逻辑有一个bug——即我们输入的字符串,只需要含有“Sp4rkDr0idKit”这个前缀就可以了,而不用全文匹配这个字符串,如图所示:
http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/0/0cffc46ebba4c26fcd8f6c83934f482d82f6c054.PNG |