iOS Reverse-UnCrackable Level 2

UnCrackable Level 2.app

没想到ios也有crackme,逆向的过程也是十分曲折,过程大概可以分为5大步,第一步是反调试的去除;第二步是在arm64位设备上运行;第三步是过文件完整性检查(md5);第四步是越狱检查;第五步是找到secret strings。

1.准备过程

首先在https://github.com/OWASP/owasp-mastg/tree/master/Crackmes/iOS/Level_02这里下载该ipa文件,ipa文件就是一个压缩包,里面存放着整个app的数据和运行的程序。

在整个过程中,我用的工具和设备包括:mac电脑,iPhone5s,ida pro,ghidra,r2

1.解压ipa文件

使用unzip解压之后出现一个Payload文件夹,检查一下可执行文件的类型

1
2
3
4
file Payload/UnCrackable\ Level\ 2.app/UnCrackable\ Level\ 2 

Payload/UnCrackable Level 2.app/UnCrackable Level 2: Mach-O universal binary with 2 architectures: [armv7:Mach-O armv7 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>] [arm64:Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>]

发现有armv7和arm64两个程序,这是为了对应手机芯片无论是哪种位数都可以让其运行,由于我的iOS是iPhone5s,是64位芯片,所以我们需要给这个程序瘦身,才能更好的对其进行分析。

1
2
3
lipo -thin arm64 ./UnCrackable\ Level\ 2 -o ./UnCrackable\ Level\ 2
file ./UnCrackable\ Level\ 2
./UnCrackable Level 2: Mach-O 64-bit executable arm64

这就瘦身成功了。也可以用rabin2 -x UnCrackable\ Level\ 2进行瘦身。

2.重打包和重签名

瘦身或者对程序进行了patch之后如何快速上传到手机里可以大大加快我们的分析速度,重打包便是将Payload文件夹压缩之后,将zip后缀改成ipa;重签名便是将ipa文件利用iOS App Signer进行再次签名,通过Xcode上传到手机。

我在这篇文章里写了详细步骤:https://bbs.pediy.com/thread-273935.htm

3.pass反调试

在iOS上运行该app时出现闪退情况,一开始以为是手机的问题,查阅资料之后才知道是anti-debugging,我们将首先看一下 viewDidLoad,因为它是在视图控制器之前加载函数和检查的地方,也是实现安全检查的常见地方。

这里使用的是r2分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
[0x100005520]> pdf @ method.ViewController.viewDidLoad
;-- func.1000054f4:
; CODE XREF from method.ViewController.viewDidLoad @ 0x100005528(x)
┌ 912: method.ViewController.viewDidLoad (int64_t arg1, void *arg_8h, void *instance, int64_t arg_60h, int64_t arg_70h);
│ ; arg int64_t arg1 @ x0
│ ; arg void *arg_8h @ sp+0x78
│ ; arg void *instance @ sp+0x80
│ ; arg int64_t arg_60h @ sp+0xd0
│ ; arg int64_t arg_70h @ sp+0xe0
│ ; var int64_t var_0h_3 @ sp+0x8
│ ; var int64_t var_0h @ sp+0x10
│ ; var int64_t var_0h_2 @ sp+0x18
│ ; var int64_t var_20h @ sp+0x20
│ ; var int64_t var_20h_2 @ sp+0x28
│ ; var int64_t var_30h @ sp+0x30
│ ; var int64_t var_30h_2 @ sp+0x38
│ ; var int64_t var_40h @ sp+0x40
│ ; var int64_t var_40h_2 @ sp+0x48
│ ; var int64_t var_50h @ sp+0x50
│ ; var int64_t var_50h_2 @ sp+0x58
│ ; var int64_t var_60h @ sp+0x60
│ ; var int64_t var_60h_2 @ sp+0x68
│ 0x1000054f4 ffc301d1 sub sp, sp, 0x70
│ 0x1000054f8 fa6702a9 stp x26, x25, [var_20h]
│ 0x1000054fc f85f03a9 stp x24, x23, [var_30h]
│ 0x100005500 f65704a9 stp x22, x21, [var_40h]
│ 0x100005504 f44f05a9 stp x20, x19, [var_50h]
│ 0x100005508 fd7b06a9 stp x29, x30, [var_60h]
│ 0x10000550c fd830191 add x29, arg_60h
│ 0x100005510 f30300aa mov x19, x0 ; arg1
│ 0x100005514 f30b00f9 str x19, [var_0h]
│ 0x100005518 1f2003d5 nop
│ 0x10000551c 684c0458 ldr x8, section.21.__DATA.__objc_superrefs ; 0x10000dea8
│ ;-- pc:
│ 0x100005520 e80f00f9 str x8, [var_0h_2]
│ 0x100005524 1f2003d5 nop
│ 0x100005528 81360458 ldr x1, str.viewDidLoad ; 0x100009c94 ; char *selector
│ 0x10000552c e0430091 add x0, instance ; void *instance
│ 0x100005530 89100094 bl sym.imp.objc_msgSendSuper2 ; void *objc_msgSendSuper2(void *instance, char *selector)
│ 0x100005534 41018052 movz w1, 0xa
│ 0x100005538 000080d2 movz x0, 0
│ 0x10000553c 3b100094 bl sym.imp.dlopen
│ 0x100005540 f40300aa mov x20, x0
│ 0x100005544 c1cc0210 adr x1, str.ptrace ; 0x10000aedc
│ 0x100005548 1f2003d5 nop
│ 0x10000554c 3a100094 bl sym.imp.dlsym
│ 0x100005550 e80300aa mov x8, x0
│ 0x100005554 e0130032 orr w0, wzr, 0x1f
│ 0x100005558 01008052 movz w1, 0
│ 0x10000555c 020080d2 movz x2, 0
│ 0x100005560 03008052 movz w3, 0
│ 0x100005564 1f2003d5 nop
│ 0x100005568 e00314aa mov x0, x20
│ 0x10000556c 2c100094 bl sym.imp.dlclose
│ 0x100005570 1f2003d5 nop
│ 0x100005574 60460458 ldr x0, reloc.NSThread ; 0x10000de40 ; void *instance
│ 0x100005578 1f2003d5 nop
│ 0x10000557c 22340458 ldr x2, 0x10000dc00
│ 0x100005580 1f2003d5 nop
│ 0x100005584 21340458 ldr x1, str.detachNewThreadSelector:toTarget:withObject: ; 0x100009ca4 ; char *selector
│ 0x100005588 e30313aa mov x3, x19
│ 0x10000558c 040080d2 movz x4, 0
│ 0x100005590 6e100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005594 580000b0 adrp x24, section.24.__DATA.__data ; 0x10000e000
│ 0x100005598 1f430639 strb wzr, [x24, 0x190]
│ 0x10000559c 59000090 adrp x25, 0x10000d000
│ 0x1000055a0 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ 0x1000055a4 1f2003d5 nop
│ 0x1000055a8 54330458 ldr x20, str.defaultManager ; 0x100009cd1
│ 0x1000055ac e10314aa mov x1, x20 ; char *selector
│ 0x1000055b0 66100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x1000055b4 fd031daa mov x29, x29
│ 0x1000055b8 76100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x1000055bc f60300aa mov x22, x0
│ 0x1000055c0 1f2003d5 nop
│ 0x1000055c4 b5320458 ldr x21, str.fileExistsAtPath: ; 0x100009ce0
│ 0x1000055c8 026f0310 adr x2, str.cstr._Applications_Cydia.app ; 0x10000c3a8
│ 0x1000055cc 1f2003d5 nop
│ 0x1000055d0 e10315aa mov x1, x21 ; char *selector
│ 0x1000055d4 5d100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x1000055d8 f70300aa mov x23, x0
│ 0x1000055dc e00316aa mov x0, x22 ; void *instance
│ 0x1000055e0 63100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌─< 0x1000055e4 37070035 cbnz w23, 0x1000056c8
│ │ 0x1000055e8 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ │ 0x1000055ec e10314aa mov x1, x20 ; char *selector
│ │ 0x1000055f0 56100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │ 0x1000055f4 fd031daa mov x29, x29
│ │ 0x1000055f8 66100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ │ 0x1000055fc f60300aa mov x22, x0
│ │ 0x100005600 426e0310 adr x2, str.cstr._Library_MobileSubstrate_MobileSubstrate.dylib ; 0x10000c3c8
│ │ 0x100005604 1f2003d5 nop
│ │ 0x100005608 e10315aa mov x1, x21 ; char *selector
│ │ 0x10000560c 4f100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │ 0x100005610 f70300aa mov x23, x0
│ │ 0x100005614 e00316aa mov x0, x22 ; void *instance
│ │ 0x100005618 55100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌──< 0x10000561c 77050035 cbnz w23, 0x1000056c8
│ ││ 0x100005620 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ ││ 0x100005624 e10314aa mov x1, x20 ; char *selector
│ ││ 0x100005628 48100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ ││ 0x10000562c fd031daa mov x29, x29
│ ││ 0x100005630 58100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ ││ 0x100005634 f60300aa mov x22, x0
│ ││ 0x100005638 826d0310 adr x2, str.cstr._bin_bash ; 0x10000c3e8
│ ││ 0x10000563c 1f2003d5 nop
│ ││ 0x100005640 e10315aa mov x1, x21 ; char *selector
│ ││ 0x100005644 41100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ ││ 0x100005648 f70300aa mov x23, x0
│ ││ 0x10000564c e00316aa mov x0, x22 ; void *instance
│ ││ 0x100005650 47100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌───< 0x100005654 b7030035 cbnz w23, 0x1000056c8
│ │││ 0x100005658 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ │││ 0x10000565c e10314aa mov x1, x20 ; char *selector
│ │││ 0x100005660 3a100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │││ 0x100005664 fd031daa mov x29, x29
│ │││ 0x100005668 4a100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ │││ 0x10000566c f60300aa mov x22, x0
│ │││ 0x100005670 c26c0310 adr x2, str.cstr._usr_sbin_sshd ; 0x10000c408
│ │││ 0x100005674 1f2003d5 nop
│ │││ 0x100005678 e10315aa mov x1, x21 ; char *selector
│ │││ 0x10000567c 33100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │││ 0x100005680 f70300aa mov x23, x0
│ │││ 0x100005684 e00316aa mov x0, x22 ; void *instance
│ │││ 0x100005688 39100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌────< 0x10000568c f7010035 cbnz w23, 0x1000056c8
│ ││││ 0x100005690 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ ││││ 0x100005694 e10314aa mov x1, x20 ; char *selector
│ ││││ 0x100005698 2c100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ ││││ 0x10000569c fd031daa mov x29, x29
│ ││││ 0x1000056a0 3c100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ ││││ 0x1000056a4 f60300aa mov x22, x0
│ ││││ 0x1000056a8 026c0310 adr x2, str.cstr._etc_apt ; 0x10000c428
│ ││││ 0x1000056ac 1f2003d5 nop
│ ││││ 0x1000056b0 e10315aa mov x1, x21 ; char *selector
│ ││││ 0x1000056b4 25100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ ││││ 0x1000056b8 f50300aa mov x21, x0
│ ││││ 0x1000056bc e00316aa mov x0, x22 ; void *instance
│ ││││ 0x1000056c0 2b100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌─────< 0x1000056c4 75000034 cbz w21, 0x1000056d0
│ │└└└└─> 0x1000056c8 e8030032 orr w8, wzr, 1
│ │ 0x1000056cc 08430639 strb w8, [x24, 0x190]
│ └─────> 0x1000056d0 ff0700f9 str xzr, [var_0h_3]
│ 0x1000056d4 1f2003d5 nop
│ 0x1000056d8 412a0458 ldr x1, str.writeToFile:atomically:encoding:error: ; 0x100009cf2 ; char *selector
│ 0x1000056dc 606b0310 adr x0, str.cstr.ABCD ; 0x10000c448 ; void *instance
│ 0x1000056e0 1f2003d5 nop
│ 0x1000056e4 226c0310 adr x2, str.cstr._private_wut.txt ; 0x10000c468
│ 0x1000056e8 1f2003d5 nop
│ 0x1000056ec f6030032 orr w22, wzr, 1
│ 0x1000056f0 e3030032 orr w3, wzr, 1
│ 0x1000056f4 e4031e32 orr w4, wzr, 4
│ 0x1000056f8 e5230091 add x5, arg_8h
│ 0x1000056fc 13100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005700 e00740f9 ldr x0, [arg_8h] ; 0x4 ; 4 ; void *instance
│ 0x100005704 1d100094 bl sym.imp.objc_retain ; void objc_retain(void *instance)
│ 0x100005708 f50300aa mov x21, x0
│ ┌─< 0x10000570c 150200b4 cbz x21, 0x10000574c
│ │ 0x100005710 202747f9 ldr x0, [x25, 0xe48] ; 0xe0 ; 224 ; void *instance
│ │ 0x100005714 e10314aa mov x1, x20 ; char *selector
│ │ 0x100005718 0c100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │ 0x10000571c fd031daa mov x29, x29
│ │ 0x100005720 1c100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ │ 0x100005724 f40300aa mov x20, x0
│ │ 0x100005728 1f2003d5 nop
│ │ 0x10000572c e1270458 ldr x1, str.removeItemAtPath:error: ; 0x100009d19 ; char *selector
│ │ 0x100005730 c2690310 adr x2, str.cstr._private_wut.txt ; 0x10000c468
│ │ 0x100005734 1f2003d5 nop
│ │ 0x100005738 030080d2 movz x3, 0
│ │ 0x10000573c 03100094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ │ 0x100005740 e00314aa mov x0, x20 ; void *instance
│ │ ; CODE XREF from str.base64DataFromString: @ +0x1(x)
│ │ 0x100005744 0a100094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌──< 0x100005748 02000014 b 0x100005750
│ │└─> 0x10000574c 16430639 strb w22, [x24, 0x190]
│ │ ; CODE XREF from method.ViewController.viewDidLoad @ 0x100005748(x)
│ └──> 0x100005750 1f2003d5 nop
│ 0x100005754 e0370458 ldr x0, reloc.UIApplication ; 0x10000de50 ; void *instance
│ 0x100005758 1f2003d5 nop
│ 0x10000575c a1260458 ldr x1, str.sharedApplication ; 0x100009d31 ; char *selector
│ 0x100005760 fa0f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005764 fd031daa mov x29, x29
│ 0x100005768 0a100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x10000576c f40300aa mov x20, x0
│ 0x100005770 1f2003d5 nop
│ 0x100005774 20370458 ldr x0, reloc.NSURL ; 0x10000de58 ; void *instance
│ 0x100005778 1f2003d5 nop
│ 0x10000577c e1250458 ldr x1, str.URLWithString: ; 0x100009d43 ; char *selector
│ 0x100005780 42680310 adr x2, str.cstr.cydia:__package_com.example.package ; 0x10000c488
│ 0x100005784 1f2003d5 nop
│ 0x100005788 f00f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x10000578c fd031daa mov x29, x29
│ 0x100005790 00100094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x100005794 f60300aa mov x22, x0
│ 0x100005798 1f2003d5 nop
│ 0x10000579c 21250458 ldr x1, str.canOpenURL: ; 0x100009d52 ; char *selector
│ 0x1000057a0 e00314aa mov x0, x20 ; void *instance
│ 0x1000057a4 e20316aa mov x2, x22
│ 0x1000057a8 e80f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x1000057ac f70300aa mov x23, x0
│ 0x1000057b0 e00316aa mov x0, x22 ; void *instance
│ 0x1000057b4 ee0f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ 0x1000057b8 e00314aa mov x0, x20 ; void *instance
│ 0x1000057bc ec0f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ ┌─< 0x1000057c0 77000034 cbz w23, 0x1000057cc
│ │ 0x1000057c4 e8031f2a mov w8, wzr
│ │ 0x1000057c8 08430639 strb w8, [x24, 0x190]
│ └─> 0x1000057cc e00315aa mov x0, x21 ; void *instance
│ 0x1000057d0 e70f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ 0x1000057d4 1f2003d5 nop
│ 0x1000057d8 94230458 ldr x20, 0x10000dc48
│ 0x1000057dc e00313aa mov x0, x19 ; void *instance
│ 0x1000057e0 e10314aa mov x1, x20 ; char *selector
│ 0x1000057e4 d90f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x1000057e8 fd031daa mov x29, x29
│ 0x1000057ec e90f0094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x1000057f0 f50300aa mov x21, x0
│ 0x1000057f4 1f2003d5 nop
│ 0x1000057f8 c1220458 ldr x1, str.setNumberOfLines: ; 0x100009d67 ; char *selector
│ 0x1000057fc e2030032 orr w2, wzr, 1
│ 0x100005800 d20f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005804 e00315aa mov x0, x21 ; void *instance
│ 0x100005808 d90f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ 0x10000580c e00313aa mov x0, x19 ; void *instance
│ 0x100005810 e10314aa mov x1, x20 ; char *selector
│ 0x100005814 cd0f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005818 fd031daa mov x29, x29
│ 0x10000581c dd0f0094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x100005820 f50300aa mov x21, x0
│ 0x100005824 1f2003d5 nop
│ 0x100005828 81210458 ldr x1, str.setAdjustsFontSizeToFitWidth: ; 0x100009d79 ; char *selector
│ 0x10000582c e2030032 orr w2, wzr, 1
│ 0x100005830 c60f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005834 e00315aa mov x0, x21 ; void *instance
│ 0x100005838 cd0f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ 0x10000583c e00313aa mov x0, x19 ; void *instance
│ 0x100005840 e10314aa mov x1, x20 ; char *selector
│ 0x100005844 c10f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005848 fd031daa mov x29, x29
│ 0x10000584c d10f0094 bl sym.imp.objc_retainAutoreleasedReturnValue ; void objc_retainAutoreleasedReturnValue(void *instance)
│ 0x100005850 f30300aa mov x19, x0
│ 0x100005854 1f2003d5 nop
│ 0x100005858 41200458 ldr x1, str.sizeToFit ; 0x100009d97 ; char *selector
│ 0x10000585c bb0f0094 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
│ 0x100005860 e00313aa mov x0, x19 ; void *instance
│ 0x100005864 c20f0094 bl sym.imp.objc_release ; void objc_release(void *instance)
│ 0x100005868 fd7b46a9 ldp x29, x30, [var_60h]
│ 0x10000586c f44f45a9 ldp x20, x19, [var_50h]
│ 0x100005870 f65744a9 ldp x22, x21, [var_40h]
│ 0x100005874 f85f43a9 ldp x24, x23, [var_30h]
│ 0x100005878 fa6742a9 ldp x26, x25, [var_20h]
│ 0x10000587c ffc30191 add sp, arg_70h
└ 0x100005880 c0035fd6 ret
1
2
3
0x10000553c      bl sym.imp.dlopen #运行dlopen(0,0xa),获取当前进程句柄
0x10000554c bl sym.imp.dlsym #运行dlsym(x0,"ptrace"),获取ptrace函数地址
0x100005564 blr x8 #运行ptrace(0x1f,0,0,0),

运行ptrace函数时使用了PT_DENY_ATTACH宏,这样的目的就是拒绝调试器附加;

运行到ptrace之后就寄了。所以要想调试的话需要对文件进行patch之后再压缩成ipa包,传给iOS。经过lldb得知,运行到 100005564处blr x8就是调用ptrace,所以我们把这行汇编变为nop即可。

用r2进行patch很方便,如下

4.点击vertify没有反应

重打包之后在iOS内打开app,输入一些数据后点击vertify,但是并没有反应。这是怎么回事呢?我们调试一下试试,点击这个动作对应的是handleButtonClick方法,所以去逆一下该方法流程。在网上搜了一下用r2去patch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# re-open file in read/write mode
oo+

# Fix offset to LC_COMMAND_64
s 0x1000052d8
oo+
wa add x21, x22, 0x20

# Remove unnecessary check for LC_COMMAND==LC_SEGMENT
s 0x100005304
oo+
wa NOP

# Fix sizeof(segment_command_64)
s 0x100005328
oo+
wa add x20, x23, 0x48

# Fix sizeof(section_64)
s 0x100005350
oo+
wa add x20, x20, 0x50

# Fix register size for section_64.addr and section_64.size
s 0x100005360
oo+
wa ldp x8, x1, [x20, 0x20]

# Fix register size for segment_command_64.vmaddr:
s 0x100005364
oo+
wa ldr x9, [x23, 0x18]

# Fix register size for baseaddr and section_64.addr
s 0x100005368
oo+
wa add x8, x8, x22

# Fix register size for section_64.addr and segment_command_64.vmaddr
s 0x10000536c
oo+
wa sub x8, x8, x9

# Fix register size for CC_MD5's first argument
s 0x100005370
oo+
wa mov x0,x8

# Write secret
s 0x10000e000
oo+
wz uMqEK/JCNg+njduTS840mrac3zjLP1kpwV508f0119E=

5.pass jailbreak-check

当我以为能调试的时候,发现这里有检查Cydia的存在来判断设备是否越狱,如果检测到则退出,

去ida里找一下代码。

可以看到fileExistsAtPath判断这些文件是否存在;

可以查看该网址是否可以被打开,如果Cydia被安装。

观察代码发现,所有的检查都和LABEL_6的 byte_10000E190 = 1有关系,所以我们只需要在最后一个 byte_10000E190 = 1处将 byte_10000E190 = 1修改为 byte_10000E190 = 0即可

效果如下

6.Decryption Failed

看字好像是由于加解密有点问题才导致不能正常运行该流程,通过交叉引用字符串找到该函数;好像是进行了md5的校验,如果对程序进行了patch,md5值就会不同。

那么如何绕过呢?先把程序进行瘦身为64位的arm,并且对其patch能够在64位机器内运行,然后将text段提取出来算md5。

1
2
3
4
5
6
7
8
9
#!/bin/bash

rm -f textSection
out=$(r2 -q -c "iS" "UnCrackable Level 2" | grep text)
echo $out
addr=$(echo $out | cut -d ' ' -f4)
size=$(echo $out | cut -d ' ' -f3)
echo $addr $size
r2 -q -c "pr $size @ $addr > textSection" "UnCrackable Level 2"

最后通过frida-trace对程序检查进行绕过。

先运行frida-trace -U Uncrackable2 -m “+[NSString stringWithCString:encoding:]”

再修改__ handlers__/NSStringstringWithCString_encoding_.js文件。

最后运行frida-trace -U Uncrackable2 -m “+[NSString stringWithCString:encoding:]”出现Failed to attach: process with pid 21420 either refused to load frida-agent, or terminated during injection,出错了,看样子是在注入hook的时候出错了,难道是还有什么没有注意到的地方,再次回到Viewdidload,看到detachNewThreadSelector,这个函数是

通过查看得知大概调用的是detachNewThreadSelector(0x10000dc00, x19, 0),x19内是ViewController,这个函数大概意思就是调用ViewController的abc方法,该方法会在新的线程里执行,我们继续追踪一下看看;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
[0x100005488]> pdf @ method.ViewController.abc
; CODE XREF from method.ViewController.viewDidLoad @ 0x10000557c
; CODE XREF from str.v32_0:8__UIApplication_16__UIUserNotificationSettings_24 @ +0x15
;-- func.1000053f4:
┌ 256: method.ViewController.abc (int64_t arg1);
│ ; var int64_t var_ch @ sp+0xc
│ ; var int64_t var_44h @ sp+0x44
│ ; var int64_t var_7ch @ sp+0x7c
│ ; var int64_t var_b4h @ sp+0xb4
│ ; var int64_t var_ech @ sp+0xec
│ ; var int64_t var_f0h @ sp+0xf0
│ ; var int64_t var_f8h @ sp+0xf8
│ ; var int64_t var_0h @ sp+0x118
│ ; var int64_t var_119h @ sp+0x119
│ ; var int64_t var_0h_2 @ sp+0x380
│ ; var int64_t var_0h_3 @ sp+0x388
│ ; var int64_t var_0h_4 @ sp+0x38c
│ ; var int64_t var_40h @ sp+0x390
│ ; var int64_t var_40h_2 @ sp+0x398
│ ; var int64_t var_10h @ sp+0x3a0
│ ; var int64_t var_10h_2 @ sp+0x3a8
│ ; var int64_t var_20h @ sp+0x3b0
│ ; var int64_t var_20h_2 @ sp+0x3b8
│ ; var int64_t var_30h @ sp+0x3c0
│ ; var int64_t var_30h_2 @ sp+0x3c8
│ ; arg int64_t arg1 @ x0
│ 0x1000053f4 fc6fbca9 stp x28, x27, [var_40h]!
│ 0x1000053f8 f65701a9 stp x22, x21, [var_10h]
│ 0x1000053fc f44f02a9 stp x20, x19, [var_20h]
│ 0x100005400 fd7b03a9 stp x29, x30, [var_30h]
│ 0x100005404 fdc30091 add x29, var_30h
│ 0x100005408 ff430ed1 sub sp, sp, 0x390
│ 0x10000540c f3c30391 add x19, var_f0h
│ 0x100005410 ff1b01b9 str wzr, [var_0h] ; arg1
│ 0x100005414 ffef00b9 str wzr, [var_ech] ; arg1
│ 0x100005418 e80b1fb2 orr x8, xzr, 0xe0000000e
│ 0x10000541c 280080f2 movk x8, 0x1
│ 0x100005420 684a01f9 str x8, [var_0h_2]
│ 0x100005424 e8030032 orr w8, wzr, 1 ; arg1
│ 0x100005428 a8831cb8 stur w8, [var_0h_3]
│ 0x10000542c 8b100094 bl sym.imp.getpid ; int getpid(void)
│ ; int getpid(void)
│ 0x100005430 a0c31cb8 stur w0, [var_0h_4]
│ 0x100005434 1f2003d5 nop
│ 0x100005438 d45f0358 ldr x20, reloc.mach_task_self_ ; 0x10000c030
│ 0x10000543c f5f30191 add x21, var_7ch
│ 0x100005440 16518052 movz w22, 0x288
│ ┌─< 0x100005444 05000014 b 0x100005458
│ │ ; CODE XREF from method.ViewController.abc @ 0x1000054c8
│ ┌──> 0x100005448 e8674439 ldrb w8, [var_119h] ; [0x119:4]=-1 ; 281
│ ┌───< 0x10000544c 08051837 tbnz w8, 3, 0x1000054ec ; unlikely
│ │╎│ 0x100005450 800c8052 movz w0, 0x64 ; 'd'
│ │╎│ 0x100005454 fc100094 bl sym.imp.usleep ; int usleep(int s)
│ │╎│ ; int usleep(-1)
│ │╎│ ; CODE XREF from method.ViewController.abc @ 0x100005444
│ │╎└─> 0x100005458 800240b9 ldr w0, [x20]
│ │╎ 0x10000545c e1231f32 orr w1, wzr, 0x3fe
│ │╎ 0x100005460 e2d30291 add x2, var_b4h
│ │╎ 0x100005464 e3b30391 add x3, var_ech
│ │╎ 0x100005468 e4f30191 add x4, var_7ch
│ │╎ 0x10000546c e5130191 add x5, var_44h
│ │╎ 0x100005470 e6330091 add x6, var_ch
│ │╎ 0x100005474 f1100094 bl sym.imp.task_get_exception_ports
│ │╎ 0x100005478 e8ef40b9 ldr w8, [var_ech] ; [0xec:4]=-1 ; 236
│ │╎ 0x10000547c 1f000071 cmp w0, 0
│ │╎ 0x100005480 0409407a ccmp w8, 0, 4, eq
│ │╎┌─< 0x100005484 20010054 b.eq 0x1000054a8 ; likely
│ │╎│ 0x100005488 090080d2 movz x9, 0
│ │╎│ ; CODE XREF from method.ViewController.abc @ 0x1000054a4
│ ┌────> 0x10000548c aa7a69b8 ldr w10, [x21, x9, lsl 2]
│ ╎│╎│ 0x100005490 4a050011 add w10, w10, 1
│ ╎│╎│ 0x100005494 5f090071 cmp w10, 2
│ ┌─────< 0x100005498 a2020054 b.hs 0x1000054ec ; unlikely
│ │╎│╎│ 0x10000549c 29050091 add x9, x9, 1
│ │╎│╎│ 0x1000054a0 3f0108eb cmp x9, x8
│ │└────< 0x1000054a4 43ffff54 b.lo 0x10000548c ; likely
│ │ │╎│ ; CODE XREF from method.ViewController.abc @ 0x100005484
│ │ │╎└─> 0x1000054a8 760200f9 str x22, [x19]
│ │ │╎ 0x1000054ac a00301d1 sub x0, var_0h_2
│ │ │╎ 0x1000054b0 e1031e32 orr w1, wzr, 4
│ │ │╎ 0x1000054b4 e2e30391 add x2, var_f8h
│ │ │╎ 0x1000054b8 e3c30391 add x3, var_f0h
│ │ │╎ 0x1000054bc 040080d2 movz x4, 0
│ │ │╎ 0x1000054c0 050080d2 movz x5, 0
│ │ │╎ 0x1000054c4 da100094 bl sym.imp.sysctl
│ │ │└──< 0x1000054c8 00fcff34 cbz w0, 0x100005448 ; unlikely
│ │ │ 0x1000054cc 00cd0210 adr x0, str.__ViewController_abc_ ; 0x10000ae6c
│ │ │ 0x1000054d0 1f2003d5 nop
│ │ │ 0x1000054d4 61cd0250 adr x1, str._Users_berndt_Projects_uncrackable_app_iOS_Level2_UnDebuggable_ViewController.m ; 0x10000ae82
│ │ │ 0x1000054d8 1f2003d5 nop
│ │ │ 0x1000054dc a3cf0250 adr x3, str.junk__0 ; 0x10000aed2
│ │ │ 0x1000054e0 1f2003d5 nop
│ │ │ 0x1000054e4 c2118052 movz w2, 0x8e
│ │ │ 0x1000054e8 1a100094 bl sym.imp.__assert_rtn ; void __assert_rtn(const char *assertion, const char *file, unsigned int line, const char *function)
│ │ │ ; void __assert_rtn(-1, -1, -1, -1)
│ │ │ ; CODE XREFS from method.ViewController.abc @ 0x10000544c, 0x100005498
│ └─└───> 0x1000054ec 00008052 movz w0, 0
└ 0x1000054f0 54100094 bl sym.imp.exit ; void exit(int status) ; method.ViewController.viewDidLoad
└ ; void exit(-1)

task_get_exception_ports:是一个在用户态可以使用的task API,可以查询task的异常端口,而mach的异常消息都会发送到异常端口,所以我们通过它来验证调试器是否设置了这样的端口,看起来好像可以反调试,看看代码中的该函数可以干什么

task_get_exception_ports(mac_task_self,0x3fe,arg_b4h,arg_ech,arg_7ch,arg_44h,arg_ch),0x3fe代表EXC_MASK_*全部的情况。就是所有的异常情况只要被检索到,这个app就会被认为在debugger状态中,将会打破循环直接退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Function - Return send rights to the target task's exception ports.
SYNOPSIS

kern_return_t task_get_exception_ports
(task_t task,
exception_mask_t exception_types,
exception_mask_array_t old_exception_masks,
old_exception_masks old_exception_count,
exception_port_array_t old_exception_ports,
exception_behavior_array_t old_behaviors,
exception_flavor_array_t old_flavors);

PARAMETERS

task
[in task send right] The task for which to return the exception ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception ports are desired:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

EXC_MASK_RPC_ALERT
Exceptional condition encountered during execution of RPC.

old_exception_masks
[out array of exception_mask_t] An array, each element being a mask specifying for which exception types the corresponding element of the other arrays apply.

old_exception_count
[pointer to in/out scalar] On input, the maximum size of the array buffers; on output, the number of returned sets returned.

这里有比较多的patch方法,可以直接把exit给patch了(没有测试),还可以patch掉各种跳转判断

1
2
3
s 0x100005498
oo+
wa nop

重新打包,再次运行,当我认为可以找到secret strings时,发现还是报错,使用frida-trace进行hook时出现decryption failed;

https://hello-sherlock.github.io/2017/03/22/eight-Blog/#%E5%8A%A8%E6%80%81%E6%A3%80%E6%B5%8B得知,还有sysctl也可能有反调试,在0x1000054c4处有调用sysctl。

其实不需要查看这么仔细,直接在r2里看调用关系即可,在0x1000054ec处执行exit,而此地址有两个来源,是0x100005498和0x10000544c。都给patch成nop即可,下面是对比图

第一部分是没有patch过的;

第二部分是将0x10000544c处改为nop,发现在最后少了exit函数。

第三部分是0x100005498处改为nop;

至此,两处调用exit的函数均已消失。

使用frida-trace -U Uncrackable2 -m “+[NSString stringWithCString:encoding:]”进行hook就得到如下结果。

7.找到secret strings

我们已经在 ViewController.handleButtonClick 中看到了对 decrypt:password: 的调用,因此为了获取secret strings,我们可以用frida-trace来获取strings。

1
frida-trace -U Uncrackable2 -m "+[AESCrypt decrypt:password:]"

修改 __ handlers__/AESCrypt/decrypt_password_.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
* Auto-generated by Frida. Please modify to match the signature of +[AESCrypt encrypt:password:].
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/

{
/**
* Called synchronously when about to call +[AESCrypt encrypt:password:].
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
},

/**
* Called synchronously when about to return from +[AESCrypt encrypt:password:].
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
var secret = new ObjC.Object(ptr(retval)).toString()
log(`Decrypted secret: ${secret}`)
}
}

再使用以下命令hook,然后就可以获得strings了。

1
2
frida-trace -U Uncrackable2 -m "+[NSString stringWithCString:encoding:]" &
frida-trace -U Uncrackable2 -m "+[AESCrypt decrypt:password:]"

得到答案 MysuperSecretString