-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1501 lines (1387 loc) · 86 KB
/
atom.xml
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>passerbycrk</title>
<link href="/atom.xml" rel="self"/>
<link href="https://passerbycrk.github.io/"/>
<updated>2019-10-05T02:38:43.961Z</updated>
<id>https://passerbycrk.github.io/</id>
<author>
<name>passerbycrk</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>iOS能力探索-自动生成视图唯一标识</title>
<link href="https://passerbycrk.github.io/2018/10/10/uiview_unique_id/"/>
<id>https://passerbycrk.github.io/2018/10/10/uiview_unique_id/</id>
<published>2018-10-10T04:00:00.000Z</published>
<updated>2019-10-05T02:38:43.961Z</updated>
<content type="html"><![CDATA[<h2 id="What"><a href="#What" class="headerlink" title="What"></a>What</h2><p>我们知道苹果提供了手动给控件添加可访问性(Accessibility)的能力,然而这样做的工作量大且不一定能满足需求,只能另辟蹊径从技术自动化方向去尝试解决这个问题。</p>
<h2 id="Why"><a href="#Why" class="headerlink" title="Why"></a>Why</h2><p>由于组内有不少技术性项目(自动化测试、自动化埋点等…)都需要有唯一标识的能力,于是有了此次的探索。</p>
<a id="more"></a>
<h2 id="How"><a href="#How" class="headerlink" title="How"></a>How</h2><p>在组内小范围讨论了一番并结合网络检索后,总结出以下2种方案:</p>
<ol>
<li><code>视图栈方案</code>: 运行时获得视图栈,动态生成唯一标识。</li>
<li><code>脚本(配置)方案</code>: 提前生成唯一标识的配置数据,然后在运行时进行绑定。</li>
</ol>
<p>为了方便理解,接下来会用同一个案例来讲述两个方案的差别<br>如下图所示,有一个继承自UIViewController的类V1,其树形结构是用@property关键字声明的递归属性树(为了方便理解,已经由黑白名单策略过滤了私有变量,无效变量等节点)<br>矩形代表ViewController,圆形代表View,菱形代表Object<br><img src="https://i.loli.net/2018/10/08/5bbb26702ed46.png" alt="eg-w480"></p>
<h3 id="视图栈方案"><a href="#视图栈方案" class="headerlink" title="视图栈方案"></a>视图栈方案</h3><p>先说<code>视图栈方案</code>,目前业内开源库里接受度较高的解决方案是<a href="https://github.com/yulingtianxia/TBUIAutoTest" target="_blank" rel="external">TBUIAutoTest</a>,其<a href="http://yulingtianxia.com/blog/2016/03/28/Add-UITest-Label-for-UIAutomation/" target="_blank" rel="external">原理</a>可以简述为:</p>
<ul>
<li>如果是类的属性变量,则用属性的变量名作为唯一标识。</li>
<li>如果是局部变量,则用其来源的内容作为唯一标识。</li>
</ul>
<p>图解如下:</p>
<p><img src="https://i.loli.net/2018/10/08/5bbb26705c870.png" alt="view_stack-w1080"></p>
<p>该方案也暴露出以下问题:</p>
<blockquote>
<p>被复用的视图D,在被复用的父视图A和父视图B中的变量名都是d1,用该方案则会出现同一个unique_id对应多个视图的情况。<br>虽然可以通过运行时的视图栈index来进行区分,但是会出现另一个问题,就是视图的层级可能发生变化,导致unique_id不稳定。</p>
</blockquote>
<p>为了解决以上问题,也引出了接下来要重点说明的<code>配置(脚本)方案</code>。</p>
<h3 id="配置-脚本-方案"><a href="#配置-脚本-方案" class="headerlink" title="配置(脚本)方案"></a>配置(脚本)方案</h3><p>要优化标识可能一致的问题,可以收敛要处理的类的范围,即只处理ViewController继承类的属性树,这也是该方案的关键点。<br>一般来说ViewController被复用的可能性不高,即使真的复用程度高,也可以配合后端下发唯一标识来解决相对定位的问题。</p>
<p>具体实现步骤如下:<br>1.生成配置数据</p>
<ul>
<li>获得所有VC // objc_getClassList()</li>
<li>递归遍历VC持有的属性树 // class_copyPropertyList()</li>
<li>保存属性树上每个结点的keypath并生成其唯一标识 // md5(keypath)</li>
</ul>
<p>2.保存格式化后的数据(json) </p>
<ul>
<li>格式化保存VC的属性树数据(可以静态写入本地文件或保存在远端等)</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">// 格式参考</div><div class="line">{</div><div class="line"> PRKHomeViewController : {</div><div class="line"> "dce359c476c4ae262e6f958a3e647c25":"guideView",</div><div class="line"> "f1a282bdbf688604b1dc1f5c94df1ada":"myView",</div><div class="line"> "f958a3e6860f688601dcf1ad62e6f958":"myView.loadingView",</div><div class="line"> ...</div><div class="line"> },</div><div class="line"> PRKDetailViewController : {</div><div class="line"> "b1dc1f5c94df1ad62e6f958aa3e68606":"navbar",</div><div class="line"> "c4ae262e6f958a3e6860e266f958a3e6":"navbar.titleLbl",</div><div class="line"> ...</div><div class="line"> },</div><div class="line"> ...</div><div class="line">}</div></pre></td></tr></table></figure>
<p>3.关联配置数据<br>关联数据有两种情况</p>
<ul>
<li>已知unique_id获取视图对象</li>
</ul>
<blockquote>
<p>因为之前已经生成好配置文件,那我们只需要在运行时索引配置表,通过unique_id找到对应的keypath,再通过KVC机制获取到对应的视图对象。</p>
</blockquote>
<p>关键代码如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> @brief 传入unique_id和rootVC对象,获得视图</div><div class="line"> @param uniqueId 唯一标识</div><div class="line"> @param rootRef 当前的ViewController</div><div class="line"> @return 对应的视图</div><div class="line"> */</div><div class="line">- (id)refForUniqueId:(NSString *)uniqueId inRootRef:(id)rootRef {</div><div class="line"> if (uniqueId.length <= 0) {</div><div class="line"> return nil;</div><div class="line"> }</div><div class="line"> id aObj = [[PRKUniqueIdSession sharedSession].uniqueIdRefCache objectForKey:uniqueId];</div><div class="line"> if (nil != rootRef && [aObj isKindOfClass:[NSDictionary class]]) {</div><div class="line"> return [(NSDictionary *)aObj objectForKey:[NSString stringWithFormat:@"%p",rootRef]];</div><div class="line"> }</div><div class="line"> if (nil == aObj && rootRef && uniqueId) {</div><div class="line"> // NOTE: try to find object by KVC</div><div class="line"> NSString *keyPath = [[PRKUniqueIdSession sharedSession] keyPathForUniqueId:uniqueId inRootClass:[rootRef class]];</div><div class="line"> id ref = nil;</div><div class="line"> @try {</div><div class="line"> ref = [rootRef valueForKeyPath:keyPath];</div><div class="line"> } @catch (NSException *exception) {</div><div class="line"> } @finally {</div><div class="line"> if (ref) {</div><div class="line"> NSString *uniqueId = [[PRKUniqueIdSession sharedSession] uniqueIdForKeyPath:keyPath inRootClass:[rootRef class]];</div><div class="line"> [(NSObject *)ref setPrk_sfRootRef:rootRef];</div><div class="line"> [(NSObject *)ref setPrk_sfUniqueId:uniqueId];</div><div class="line"> aObj = ref;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> return aObj;</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>已知视图对象获取unique_id</li>
</ul>
<blockquote>
<p>用runtime的提供的相关API找到对象的varName以及对象的ViewController,再通过配置表定位到他的unique_id。</p>
</blockquote>
<p>关键代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line">// @category: NSObject+uniqueId</div><div class="line">- (NSString *)prk_sfUniqueId {</div><div class="line"> NSString *result = (NSString *)objc_getAssociatedObject(self, _kNSObject_prk_sfUniqueId);</div><div class="line"> // NOTE: 初始化赋值</div><div class="line"> if (nil == result && [self isKindOfClass:[UIResponder class]]) {</div><div class="line"> // NOTE: 兼容性逻辑,在此初始化一番</div><div class="line"> NSString *varName = [(UIResponder *)self prk_findNameWithInstance:(UIResponder *)self];</div><div class="line"> UIViewController *rootRef = [(UIResponder *)self prk_findViewController];</div><div class="line"> if (varName.length > 0 && rootRef) {</div><div class="line"> // NOTE:遍历对应rootRef的所有keypath的lastObject对应的ref匹配,匹配则返回对应值</div><div class="line"> NSDictionary *map = [[PRKUniqueIdSession sharedSession] uniqueIdKeyPathMapInRootClass:[rootRef class]];</div><div class="line"> if (map.count <= 0) {</div><div class="line"> return result;</div><div class="line"> }</div><div class="line"> NSMutableArray *maybelist = [NSMutableArray arrayWithCapacity:map.allValues.count];</div><div class="line"> for (NSString *aKeyPath in map.allValues) {</div><div class="line"> if ([aKeyPath hasSuffix:varName]) {</div><div class="line"> [maybelist addObject:[map allKeysForObject:aKeyPath].lastObject];</div><div class="line"> }</div><div class="line"> }</div><div class="line"> for (NSString *uniqueId in maybelist) {</div><div class="line"> // 该方法已给self赋值unique_id</div><div class="line"> id ref = [PRKUinqueIdKit prk_fetchRefForUniqueId:uniqueId inRootRef:rootRef];</div><div class="line"> if (ref == self) {</div><div class="line"> return uniqueId;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> return result;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>同样我们再图解一番该方案:</p>
<p><img src="https://i.loli.net/2018/10/08/5bbb26705acde.png" alt="vc_tree-w1080"></p>
<blockquote>
<p>用视图的keypath作为唯一标识(为了让unique_id长度一致,对其进行了md5编码)能保证在同一个VC下,被复用的视图的唯一标识不同,解决了视图栈方案的唯一标识重复问题。<br>被复用的视图D,在其父视图A下的唯一标识分别是md5(o1.a1.d1)和md5(o1.a2.d1),在父视图B中的唯一标识是md5(b1.d1)</p>
</blockquote>
<h4 id="模块设计图"><a href="#模块设计图" class="headerlink" title="模块设计图"></a>模块设计图</h4><p>介于尚未获得公司的开源许可,暂放一张模块设计图供大家参考。</p>
<p><img src="https://i.loli.net/2018/10/07/5bb9ec7e41a9c.png" alt="模块设计图-w640"></p>
<h2 id="TODO"><a href="#TODO" class="headerlink" title="TODO"></a>TODO</h2><p>最后再说明下目前脚本(配置)方案的局限性:只覆盖了通过@property方式或者iVar方式声明的属性。<br>以下是需要完善的地方及其解决方案的思考:</p>
<ul>
<li>完善手动赋值情况: 提供生成唯一标识的规则</li>
<li>VC被复用的场景: 可以通过服务器下发配合客户端赋值来解决</li>
<li>列表元素类型(UITableViewCell、UICollectionViewCell): 可以通过服务器下发配合客户端赋值来解决</li>
<li>局部变量: 可以复用TBUIAutoTest的方案临时解决(待完善)</li>
</ul>
<h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul>
<li><a href="http://yulingtianxia.com/blog/2016/03/28/Add-UITest-Label-for-UIAutomation/" target="_blank" rel="external">为 UIAutomation 添加自动化测试标签的探索</a></li>
<li><a href="https://testerhome.com/topics/6642" target="_blank" rel="external">Macaca UI 自动化利器-为你的应用自动添加控件 ID 探索</a></li>
<li><a href="http://appium.io/" target="_blank" rel="external">Appium</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="What"><a href="#What" class="headerlink" title="What"></a>What</h2><p>我们知道苹果提供了手动给控件添加可访问性(Accessibility)的能力,然而这样做的工作量大且不一定能满足需求,只能另辟蹊径从技术自动化方向去尝试解决这个问题。</p>
<h2 id="Why"><a href="#Why" class="headerlink" title="Why"></a>Why</h2><p>由于组内有不少技术性项目(自动化测试、自动化埋点等…)都需要有唯一标识的能力,于是有了此次的探索。</p>
</summary>
<category term="iOS" scheme="https://passerbycrk.github.io/tags/iOS/"/>
</entry>
<entry>
<title>iOS逆向分析和注入-微信防撤回</title>
<link href="https://passerbycrk.github.io/2018/03/26/iOS%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E5%92%8C%E6%B3%A8%E5%85%A5-%E5%BE%AE%E4%BF%A1%E9%98%B2%E6%92%A4%E5%9B%9E/"/>
<id>https://passerbycrk.github.io/2018/03/26/iOS逆向分析和注入-微信防撤回/</id>
<published>2018-03-26T04:00:00.000Z</published>
<updated>2019-10-05T02:38:43.961Z</updated>
<content type="html"><![CDATA[<p>复习iOS逆向知识,以微信消息防撤回为例,一步一步分析调试,到完成插件注入。</p>
<a id="more"></a>
<hr>
<h3 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h3><p><code>越狱iPhone 5s (iOS 10.1.1)</code> 并安装了以下软件:</p>
<blockquote>
<p><code>OpenSSH</code>: 实现在越狱手机上远程进行 ssh 服务,通过 ssh,即可以通过终端连接 iPhone 进行控制。<br><code>dumpdecrypted</code>: 砸壳工具。<br><code>Cycript</code>: 脚本语言工具,用于 hook 正在运行的进程,并实时注入代码。<br><code>debugserver</code>: 用于连接手机进行 lldb 调试的工具。用 Xcode 在手机上进行 app 调试即可在iPhone目录的 /Developer/usr/bin/ 中生成。</p>
</blockquote>
<p><code>苹果电脑 (macOS High Sierra 10.13.3)</code> 并安装了以下软件:</p>
<blockquote>
<p><code>frida-ios-dump</code>: 砸壳利器。<br><code>class_dump</code>: dump 目标对象的 class 信息的工具。<br><code>Hopper_Disassembler</code>: 静态分析工具。<br><code>usbmuxd</code>: 端口转发,可以让我们通过 usb 连接手机进行 ssh、lldb 调试等。<br><code>lldb</code>: 调试神器,用过的都说好 (/Applications/Xcode.app/Contents/Developer/usr/bin/lldb)。<br><code>theos</code>: 插件编写IDE。</p>
</blockquote>
<hr>
<h3 id="流程概述"><a href="#流程概述" class="headerlink" title="流程概述"></a>流程概述</h3><ul>
<li>砸壳: <code>frida-ios-dump</code>、<code>dumpdecrypted</code>、<code>Clutch</code></li>
<li>分析调试: <ul>
<li>静态分析: <code>class-dump</code>、<code>Hopper Disassembler</code></li>
<li>动态分析: <code>Cycript</code>、<code>Logify</code>、<code>lldb+debugserver</code></li>
</ul>
</li>
<li>编写插件并注入: <code>theos</code></li>
</ul>
<hr>
<h3 id="砸壳"><a href="#砸壳" class="headerlink" title="砸壳"></a>砸壳</h3><p>推荐使用<code>frida-ios-dump</code>,下面会分别以<code>frida-ios-dump</code>和<code>dumpdecrypted</code>为例进行砸壳,实际情况任选一个使用即可。</p>
<h4 id="frida-ios-dump"><a href="#frida-ios-dump" class="headerlink" title="frida-ios-dump"></a>frida-ios-dump</h4><p>1.获取app信息 <code>frida-ios-dump/dump.py -l</code></p>
<pre><code># frida-ios-dump/dump.py -l
PID Name Identifier
----- -------------- -------------------------------
92311 微信 com.tencent.xin
- App Store com.apple.AppStore
- Cydia com.saurik.Cydia
- FaceTime com.apple.facetime
- Safari com.apple.mobilesafari
...
</code></pre><p>2.根据app信息进行砸壳 <code>frida-ios-dump/dump.py [bundle id|name]</code></p>
<pre><code># frida-ios-dump/dump.py com.tencent.xin
Start the target app com.tencent.xin
Dumping 微信 to /var/folders/7b/c3cyxy3j0t7_tgnt0dh5wc240000gn/T
start dump /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
WeChat.fid: 100%|█████████████████████████████████████████████████| 71.8M/71.8M [00:06<00:00, 11.1MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/WCDB.framework/WCDB
WCDB.fid: 100%|███████████████████████████████████████████████████| 2.49M/2.49M [00:00<00:00, 9.10MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/MMCommon.framework/MMCommon
MMCommon.fid: 100%|█████████████████████████████████████████████████| 979k/979k [00:00<00:00, 7.56MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/MultiMedia.framework/MultiMedia
MultiMedia.fid: 100%|█████████████████████████████████████████████| 6.61M/6.61M [00:00<00:00, 10.8MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/mars.framework/mars
mars.fid: 100%|███████████████████████████████████████████████████| 8.49M/8.49M [00:00<00:00, 11.2MB/s]
network_setting.html: 139MB [00:25, 5.62MB/s]
0.00B [00:00, ?B/s]
Generating "微信.ipa"
</code></pre><p>砸壳成功后会在当前目录下生成去壳后的安装包<code>微信.ipa</code>。</p>
<h4 id="dumpdecrypted"><a href="#dumpdecrypted" class="headerlink" title="dumpdecrypted"></a>dumpdecrypted</h4><p>1.获取app安装路径 <code>ps -e | grep /var/</code></p>
<pre><code># ps -e | grep /var/
92817 ?? 0:16.99 /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
92867 ?? 0:00.20 /private/var/containers/Bundle/Application/FD3685C9-80D5-419E-B106-DF466545003E/News.app/PlugIns/NewsNotificationServiceExtension.appex/NewsNotificationServiceExtension
93182 ttys000 0:00.02 grep /var/
</code></pre><p>2.根据app安装路径进行砸壳 <code>DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /path/to/app/executablename</code></p>
<pre><code># DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
mach-o decryption dumper
DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.
[+] detected 64bit ARM binary in memory.
[+] offset to cryptid found: @0x1000b4cf8(from 0x1000b4000) = cf8
[+] Found encrypted data at address 00004000 of length 59457536 bytes - type 1.
[+] Opening /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a plain MACH-O image
[+] Opening WeChat.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset cf8
[+] Closing original file
[+] Closing dump file
</code></pre><p>成功后会在当前目录下生成WeChat.decrypted,也就是砸壳后的执行文件。</p>
<!-- ![](dumpdecrypted.png) -->
<p><img src="https://i.loli.net/2018/03/26/5ab8ff4210f46.png" alt=""> </p>
<hr>
<h3 id="分析调试"><a href="#分析调试" class="headerlink" title="分析调试"></a>分析调试</h3><h4 id="Cycript-动态分析工具"><a href="#Cycript-动态分析工具" class="headerlink" title="Cycript (动态分析工具)"></a>Cycript (动态分析工具)</h4><p>官网: <a href="http://www.cycript.org/" target="_blank" rel="external">http://www.cycript.org/</a></p>
<blockquote>
<p>Cycript允许开发人员调试和修改iOS和Mac OS X上运行的应用程序。<br>Cycript是一个理解Objective-C语法的javascript解释器,它能够挂钩正在运行的进程,能够在运行时修改应用的很多东西。</p>
</blockquote>
<p>调试命令 <code>cycript [-p <pid|name>]</code><br>可以先通过 <code>ps -e | grep /var</code>命令找到对应pid</p>
<pre><code># cycript -p WeChat
cy# [[[UIWindow keyWindow] rootViewController] _printHierarchy].toString()
`<MMTabBarController 0x14606ae00>, state: appeared, view: <UILayoutContainerView 0x145da6420>
| <MMUINavigationController 0x146179800>, state: appeared, view: <UILayoutContainerView 0x145d99460>
| | <NewMainFrameViewController 0x1460ff600>, state: disappeared, view: <MMUIHookView 0x145d8efa0> not in the window
| | <BaseMsgContentViewController 0x146983e00>, state: appeared, view: <UIView 0x145d7d440>
| <MMUINavigationController 0x14618b000>, state: disappeared, view: <UILayoutContainerView 0x145d9dda0> not in the window
| | <ContactsViewController 0x146191000>, state: disappeared, view: (view not loaded)
| <MMUINavigationController 0x14613a800>, state: disappeared, view: <UILayoutContainerView 0x145da0ec0> not in the window
| | <FindFriendEntryViewController 0x146859200>, state: disappeared, view: (view not loaded)
| <MMUINavigationController 0x1461a4e00>, state: disappeared, view: <UILayoutContainerView 0x145da3950> not in the window
| | <MoreViewController 0x146172c00>, state: disappeared, view: (view not loaded)`
</code></pre><h4 id="Logify-静态分析工具"><a href="#Logify-静态分析工具" class="headerlink" title="Logify (静态分析工具)"></a>Logify (静态分析工具)</h4><p>介绍: <a href="http://iphonedevwiki.net/index.php/Logify" target="_blank" rel="external">http://iphonedevwiki.net/index.php/Logify</a></p>
<blockquote>
<p>Logify是一种实用工具,可以将类的头文件(.h文件)作为输入,并生成MobileSubstrate文件(.xm文件)。<br>作用:能自动Hook该类所有的方法,并生成打印日志信息代码,方便开发人员看到在使用过程中调用了某些方法。</p>
</blockquote>
<pre><code># logify.pl BaseMsgContentViewController.h > Tweak.xm
</code></pre><h4 id="Logos-语法"><a href="#Logos-语法" class="headerlink" title="Logos 语法"></a>Logos 语法</h4><p>介绍: <a href="http://iphonedevwiki.net/index.php/Logos" target="_blank" rel="external">http://iphonedevwiki.net/index.php/Logos</a></p>
<blockquote>
<p>可以在MobileSubstrate文件(.xm文件)中使用的语法</p>
</blockquote>
<h4 id="Theos-NIC-动态分析工具"><a href="#Theos-NIC-动态分析工具" class="headerlink" title="Theos-NIC (动态分析工具)"></a>Theos-NIC (动态分析工具)</h4><p>介绍: <a href="http://iphonedevwiki.net/index.php/NIC" target="_blank" rel="external">http://iphonedevwiki.net/index.php/NIC</a></p>
<blockquote>
<p>Theos NIC templates内置了多种种Theos工程类型的模板。<br>用于编写iOS越狱设备的插件。</p>
</blockquote>
<p>创建一个追踪logify的插件工程:</p>
<pre><code># nic.pl
NIC 2.0 - New Instance Creator
------------------------------
[1.] iphone/activator_event
[2.] iphone/application_modern
[3.] iphone/cydget
[4.] iphone/flipswitch_switch
[5.] iphone/framework
[6.] iphone/ios7_notification_center_widget
[7.] iphone/library
[8.] iphone/notification_center_widget
[9.] iphone/preference_bundle_modern
[10.] iphone/tool
[11.] iphone/tweak
[12.] iphone/xpc_service
Choose a Template (required): 11
Project Name (required): TWeak-Logify-WX
Package Name [com.yourcompany.tweak-logify-wx]: cn.theos.tweak.wx.logify
Author/Maintainer Name [dabing]: author name
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.xin
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:
Instantiating iphone/tweak in tweaklogifywx/...
Done.
</code></pre><p>工程文件结构如下:</p>
<pre><code># tree
.
└── tweaklogifywx
├── Makefile
├── TWeakLogifyWX.plist
├── Tweak.xm
└── control
</code></pre><p>将<code>Logify</code>生成的<code>Tweak.xm</code>覆盖掉工程中的<code>Tweak.xm</code><br>用文本编辑器打开<code>Makefile</code>文件,在文件的开头增加iOS设备的ip地址和ssh端口等信息:</p>
<pre><code>THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 2333
ARCHS = arm64
TRAGET = iphone:latest:9.0
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = TWeakLogifyWX
TWeakLogifyWX_FILES = Tweak.xm
logifyWX_FRAMEWORKS = UIKit Foundation CoreGraphics
logifyWX_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
install.exec "killall -9 SpringBoard"
</code></pre><p>编译打包安装:</p>
<pre><code># make package install
> Making all for tweak TWeakLogifyWX…
==> Preprocessing Tweak.xm…
==> Compiling Tweak.xm (arm64)…
==> Linking tweak TWeakLogifyWX (arm64)…
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated]
==> Generating debug symbols for TWeakLogifyWX (arm64)…
warning: no debug symbols in executable (-arch arm64)
==> Merging tweak TWeakLogifyWX…
==> Signing TWeakLogifyWX…
> Making stage for tweak TWeakLogifyWX…
dm.pl: building package `cn.theos.tweak.wx.logify:iphoneos-arm' in `./packages/cn.theos.tweak.wx.logify_0.0.1-1+debug_iphoneos-arm.deb'
==> Installing…
Selecting previously unselected package cn.theos.tweak.wx.logify.
(Reading database ... 2279 files and directories currently installed.)
Preparing to unpack /tmp/_theos_install.deb ...
Unpacking cn.theos.tweak.wx.logify (0.0.1-1+debug) ...
Setting up cn.theos.tweak.wx.logify (0.0.1-1+debug) ...
install.exec "killall -9 SpringBoard"
</code></pre><blockquote>
<p><code>注意</code>:一般该Tweak.xm仍然无法执行,需要进行修改:<br>去掉 .cxx_destruct 方法<br>将 HBLogDebug 改为 NSLog<br>去掉所有的 weak 属性<br>将头文件(.h文件)中的@class和@protocol声明都拷贝至Tweak.xm (或去掉所有delegate并将所有参数对象类型改为id)。</p>
</blockquote>
<p>安装成功后会在设备中新增以下两个文件:</p>
<pre><code>/Library/MobileSubstrate/DynamicLibraries/TWeakLogifyWX.dylib
/Library/MobileSubstrate/DynamicLibraries/TWeakLogifyWX.plist
</code></pre><p>打开<code>Cydia-已安装</code>可以看到插件已经安装成功:<br><!-- ![](cydia_tweak_logify.png) --><br><img src="https://i.loli.net/2018/03/26/5ab8ff5fb7680.png" alt=""></p>
<h4 id="idevicesyslog-iOS日志查看工具"><a href="#idevicesyslog-iOS日志查看工具" class="headerlink" title="idevicesyslog (iOS日志查看工具)"></a>idevicesyslog (iOS日志查看工具)</h4><p>介绍: <a href="https://github.com/libimobiledevice/libimobiledevice" target="_blank" rel="external">https://github.com/libimobiledevice/libimobiledevice</a></p>
<blockquote>
<p>是<code>libimobiledevice</code>下的一个子工具,可以实时追踪iOS设备日志。</p>
</blockquote>
<pre><code># idevicesyslog | grep "BaseMsgContentViewController"
</code></pre><p>重新运行app,执行收到消息和撤回消息的case,可以分别获取两份log:</p>
<table>
<thead>
<tr>
<th>接收消息log</th>
<th>撤回消息log</th>
</tr>
</thead>
<tbody>
<tr>
<td><!--![](tweak_logify_receive.png)--><img src="https://i.loli.net/2018/03/26/5ab8ff8fec23e.png" alt=""></td>
<td><!--![](tweak_logify_revoke.png)--><img src="https://i.loli.net/2018/03/26/5ab8ffa58c601.png" alt=""></td>
</tr>
</tbody>
</table>
<p>整理后log对比可以发现可疑方法调用<br><code>-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:]</code></p>
<h4 id="class-dump-静态分析工具"><a href="#class-dump-静态分析工具" class="headerlink" title="class-dump (静态分析工具)"></a>class-dump (静态分析工具)</h4><p>介绍: <a href="http://stevenygard.com/projects/class-dump/" target="_blank" rel="external">http://stevenygard.com/projects/class-dump/</a></p>
<blockquote>
<p>这是一个检查存储在Mach-O文件Objective-C运行时信息的命令行实用工具。<br>能生成classes、categories、protocols定义的头文件(.h文件)。(与<code>otool -ov</code>命令获取的信息类似,但可读性更高)</p>
</blockquote>
<pre><code># class-dump -HA WeChat -o ./Headers
</code></pre><p>获得头文件以及方法的<code>IMP address</code></p>
<p>例如:<code>-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:] // IMP=0x0000000102129454</code></p>
<h4 id="Hopper-Disassembler-分析工具"><a href="#Hopper-Disassembler-分析工具" class="headerlink" title="Hopper Disassembler (分析工具)"></a>Hopper Disassembler (分析工具)</h4><p>介绍: <a href="https://www.hopperapp.com" target="_blank" rel="external">https://www.hopperapp.com</a></p>
<blockquote>
<p>是一款32位和64位的二进制反汇编器,反编译和调试。可以使用此工具拆开你想要的任何二进制。</p>
</blockquote>
<p>使用方法很简单:将二进制文件拖入软件中,等待处理完成即可。<br>(完整解析微信app需要很长一段时间,可以前置该流程进行解析处理)</p>
<h4 id="lldb-debugserver-动态分析"><a href="#lldb-debugserver-动态分析" class="headerlink" title="lldb+debugserver (动态分析) "></a>lldb+debugserver (动态分析) </h4><p>1.打开微信后,在连接至设备的控制台中键入<code>debugserver *:1234 -a "WeChat"</code>启动debugserver。<br>2.从控制台打开新窗口,键入<code>lldb</code>进入调试,再键入<code>process connect connect://192.168.1.19:1234</code>连接1234端口。<br><!--![](lldb+debugserver.png)--><br><img src="https://i.loli.net/2018/03/26/5ab8ffdbe43a2.png" alt=""></p>
<p>(此处连接上需要一点时间,可以上个厕所,连接上后键入<code>c</code>(continue)后app就可以正常运行了)<br>连接成功后<code>lldb</code>窗口会出现以下内容:</p>
<pre><code>(lldb) process connect connect://192.168.1.19:1234
Process 73244 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00000001900f5164 libsystem_kernel.dylib`__fcntl + 8
libsystem_kernel.dylib`__fcntl:
-> 0x1900f5164 <+8>: b.lo 0x1900f517c ; <+32>
0x1900f5168 <+12>: stp x29, x30, [sp, #-0x10]!
0x1900f516c <+16>: mov x29, sp
0x1900f5170 <+20>: bl 0x1900d9e8c ; cerror
Target 0: (WeChat) stopped.
(lldb) c
Process 73244 resuming
</code></pre><p>获取<a href="https://baike.baidu.com/item/aslr" target="_blank" rel="external"><code>aslr</code></a>的<code>offset</code>。(每次启动都不同)<br>其中第一列[X]是image的序号,不用管;第二列是<code>aslr</code>的<code>offset</code>(也就是对应image的虚拟内存slide);第三列是image的全路径和slide之后的基地址,也不用管~所以第二列就是我们需要的信息。</p>
<pre><code>(lldb) image list -o -f
[ 0] 0x0000000000048000 /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat(0x0000000100048000)
[ 1] 0x0000000104a20000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/usr/lib/dyld
[ 2] 0x0000000104970000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x0000000104970000)
[ 3] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/CallKit.framework/CallKit
[ 4] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/Accelerate.framework/Accelerate
[ 5] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/Intents.framework/Intents
[ 6] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/usr/lib/libbz2.1.0.dylib
[ 7] 0x0000000104aa4000 /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/WCDB.framework/WCDB(0x0000000104aa4000)
[ 8] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
...
</code></pre><p>得到<code>aslr</code>的<code>offset</code>:<code>0x0000000000048000</code> (不同的发布版本偏移量不一定相同)<br>再根据<code>class-dump</code>获得的头文件,找到对应的方法,在后面可以看到<code>IMP</code>的<code>offset</code>。<br><code>-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:] // IMP=0x0000000102129454</code><br>通过<code>br</code>命令设置断点(aslr_offset + IMP_offset)</p>
<pre><code>(lldb) br s -a '0x0000000000048000+0x0000000102129454'
Breakpoint 1: where = WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492, address = 0x0000000102171454
</code></pre><p>进入断点</p>
<pre><code>Process 73244 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000102171454 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492
WeChat`ClearDataItem::compareTime:
-> 0x102171454 <+4373492>: stp x24, x23, [sp, #-0x40]!
0x102171458 <+4373496>: stp x22, x21, [sp, #0x10]
0x10217145c <+4373500>: stp x20, x19, [sp, #0x20]
0x102171460 <+4373504>: stp x29, x30, [sp, #0x30]
Target 0: (WeChat) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000102171454 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492
frame #1: 0x0000000104d5b980 MMCommon`_callExtension + 480
frame #2: 0x0000000102ccfaac WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16294476
frame #3: 0x0000000102cda958 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16339192
frame #4: 0x0000000102cdb60c WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16342444
frame #5: 0x0000000104d5b980 MMCommon`_callExtension + 480
frame #6: 0x0000000102f89414 WeChat`ClearSessionItem::compareVideo(std::__1::shared_ptr<ClearSessionItem> const&, std::__1::shared_ptr<ClearSessionItem> const&) + 1516048
...
</code></pre><p>python+Hopper Disassembler 获取调用栈</p>
<pre><code>>>> hex(0x0000000102171454-0x0000000000048000)
'0x102129454' // -[BaseMsgContentViewController OnMsgRevoked:n64MsgId:]
>>> hex(0x0000000102ccfaac-0x0000000000048000)
'0x102c87aac' // -[CMessageMgr onRevokeMsg:]
</code></pre><p>使用Hopper Disassembler可以定位调用方法名,此处我们发现可疑函数调用<code>-[CMessageMgr onRevokeMsg:]</code></p>
<hr>
<h3 id="编写插件并注入"><a href="#编写插件并注入" class="headerlink" title="编写插件并注入"></a>编写插件并注入</h3><p>创建插件工程</p>
<pre><code># nic.pl
NIC 2.0 - New Instance Creator
------------------------------
[1.] iphone/activator_event
[2.] iphone/application_modern
[3.] iphone/cydget
[4.] iphone/flipswitch_switch
[5.] iphone/framework
[6.] iphone/ios7_notification_center_widget
[7.] iphone/library
[8.] iphone/notification_center_widget
[9.] iphone/preference_bundle_modern
[10.] iphone/tool
[11.] iphone/tweak
[12.] iphone/xpc_service
Choose a Template (required): 11
Project Name (required): Tweak-crack-WX
Package Name [com.yourcompany.tweak-crack-wx]:
Author/Maintainer Name [dabing]:
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.xin
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:
Instantiating iphone/tweak in tweakcrackwx/...
Done.
</code></pre><p>Tweak.xm</p>
<pre><code>%hook CMessageMgr
- (void)onRevokeMsg:(id)arg1 {
// do nothing
}
%end
</code></pre><p>安装</p>
<pre><code># make package install
> Making all for tweak TweakcrackWX…
make[2]: Nothing to be done for `internal-library-compile'.
> Making stage for tweak TweakcrackWX…
dm.pl: building package `com.yourcompany.tweak-crack-wx:iphoneos-arm' in `./packages/com.yourcompany.tweak-crack-wx_0.0.1-2+debug_iphoneos-arm.deb'
==> Installing…
Selecting previously unselected package com.yourcompany.tweak-crack-wx.
(Reading database ... 2277 files and directories currently installed.)
Preparing to unpack /tmp/_theos_install.deb ...
Unpacking com.yourcompany.tweak-crack-wx (0.0.1-2+debug) ...
Setting up com.yourcompany.tweak-crack-wx (0.0.1-2+debug) ...
install.exec "killall -9 SpringBoard"
</code></pre><p>打开<code>Cydia-已安装</code>可以看到插件已经安装成功:</p>
<!-- ![](cydia_tweak_crack.png) -->
<p><img src="https://i.loli.net/2018/03/26/5ab8ffc14995d.png" alt=""></p>
<p>接下来重新运行微信,试试消息撤回的case,发现消息撤回已经被阻止了,任务完成~<br>(文章特意选了个软柿子案例,实际情况可能不会这么容易找到关键函数,需要反复调试验证)</p>
<hr>
<h3 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h3><p><a href="https://github.com/passerbycrk/PRK_iOSRE/tree/master/Demo/WeChat_MsgRevoke_theos" target="_blank" rel="external">GitHub/passerbycrk/PRK_iOSRE/Demo/WeChat_MsgRevoke_theos</a></p>
<hr>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="http://iosre.com/" target="_blank" rel="external">iOSRE</a><br><a href="https://www.frida.re/" target="_blank" rel="external">frida</a><br><a href="https://github.com/AloneMonkey/frida-ios-dump" target="_blank" rel="external">frida-ios-dump</a><br><a href="http://iphonedevwiki.net/" target="_blank" rel="external">iphonedevwiki</a><br><a href="https://wizardforcel.gitbooks.io/ios-sec-wiki/" target="_blank" rel="external">iOS Security</a><br><a href="http://iospark.me/2017/07/14/iOS-Reverse-Debug-Cheatsheet/" target="_blank" rel="external">iOS Reverse Debug Cheatsheet</a><br><a href="http://iosre.com/t/debugserver-lldb-gdb/65" target="_blank" rel="external">一步一步用debugserver + lldb代替gdb进行动态调试</a><br><a href="https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653577384&idx=1&sn=b44a9c9651bf09c5bea7e0337031c53c&scene=0#wechat_redirect" target="_blank" rel="external">移动App入侵与逆向破解技术-iOS篇</a></p>
]]></content>
<summary type="html">
<p>复习iOS逆向知识,以微信消息防撤回为例,一步一步分析调试,到完成插件注入。</p>
</summary>
<category term="Tutorial" scheme="https://passerbycrk.github.io/tags/Tutorial/"/>
<category term="iOSRE" scheme="https://passerbycrk.github.io/tags/iOSRE/"/>
</entry>
<entry>
<title>mac下配置wine环境</title>
<link href="https://passerbycrk.github.io/2017/07/04/install_wine/"/>
<id>https://passerbycrk.github.io/2017/07/04/install_wine/</id>
<published>2017-07-04T04:00:00.000Z</published>
<updated>2018-10-08T13:08:46.520Z</updated>
<content type="html"><![CDATA[<p>转自:<a href="https://404forest.com/2015/10/12/%E5%9C%A8mac%E4%B8%8B%E9%85%8D%E7%BD%AEwine%E7%8E%AF%E5%A2%83%E2%80%94%E2%80%94%E8%87%AA%E5%B7%B1wine%E4%B8%80%E4%B8%AA%E5%B0%8F%E6%B8%B8%E6%88%8F/" target="_blank" rel="external">在mac下配置wine环境——自己wine一个小游戏</a></p>
<hr>
<p>当我们想要在 mac 上运行 labview 等 windows 下的大型软件时,使用 PD 等虚拟机可以很好的解决需求;然而如果我们只想玩些同人小游戏什么的,再开一个操作系统就觉得有点累赘了,这时我们可以选择wine,更加轻量的执行 windows 应用。</p>
<a id="more"></a>
<p>wine 的另一个好处时可以将 windows 应用打包成 APP,这样就可以直接拷贝给别人玩儿了!</p>
<p>下面是踩过很多坑后总结出来的比较方便的在 mac 上配置 wine 的流程。</p>
<h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>安装 Xcode</p>
<p>从 <a href="https://itunes.apple.com/us/app/xcode/id497799835" target="_blank" rel="external">Mac Apple Store</a> 安装</p>
<p>安装 XQuzrtz</p>
<p>在<a href="https://www.xquartz.org/" target="_blank" rel="external">这里</a>下载安装。</p>
<p>安装 homebrew</p>
<pre><code>$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
</code></pre><p>温馨提示:homebrew 的源可选择使用清华大学TUNA镜像源提升速度</p>
<hr>
<h4 id="安装-wine"><a href="#安装-wine" class="headerlink" title="安装 wine"></a>安装 wine</h4><p>安装 wine</p>
<pre><code>$ brew install wine
</code></pre><p>安装 winetricks</p>
<pre><code>$ brew install winetricks
</code></pre><hr>
<h4 id="运行应用程序"><a href="#运行应用程序" class="headerlink" title="运行应用程序"></a>运行应用程序</h4><p>现在我们已经可以执行 windows 应用程序啦。终端下输入</p>
<pre><code>$ wine setup.exe
</code></pre><p>就可以执行 setup.exe。</p>
<p>执行</p>
<pre><code>$ msiexec /i setup.msi
</code></pre><p>可以执行msi格式的安装程序。</p>
<hr>
<h4 id="安装常用库"><a href="#安装常用库" class="headerlink" title="安装常用库"></a>安装常用库</h4><p>虽然理论上我们已经可以跑 windows 应用程序了,但是游戏还不能玩哦。因为很多依赖都没有安装,比如 .NET Framework,比如 DirectX9,比如 VCRUNTIME 等等。这时候我们需要 winetricks 来帮助我们安装库。</p>
<pre><code>$ winetricks dotnet35 d3dx9 xna31
</code></pre><p>已有库的列表可通过 <code>winetricks list</code> 来查询。加参数 <code>-q</code> 可以静默安装。</p>
<p>不过 winetricks 这东西内置了复杂的 conflict 系统,有冲突时就不给安装。。比如先装完 .net 2.0再装 .net 3.5会报错。只能选择直接装 .net 3.5。</p>
<p>wine 有一份应用程序的<a href="https://appdb.winehq.org/" target="_blank" rel="external">兼容性文档</a>,在装软件时可以先来查阅一下,会有兼容性评级和一些安装说明,<strong>十分好用!</strong></p>
<hr>
<h4 id="打包"><a href="#打包" class="headerlink" title="打包"></a>打包</h4><p>简易的 wineskin 小教程!</p>
<p><a href="http://wineskin.urgesoftware.com/tiki-index.php?page=Downloads" target="_blank" rel="external">下载 wineskin</a></p>
<p>安装<code>engine</code>和<code>wrapper</code>。不过 wineskin 自带下载没速度,还是到<a href="https://www.mediafire.com/folder/8p4vcab6414gv/" target="_blank" rel="external">mediafire</a>下载吧。<br>下载时注意版本要和wine对应哦!</p>
<p>都安装好<code>engine</code>和<code>wrapper</code>后,点击 Create new blank wrapper,输入文件名创建新包,弹出的提示都选 cancel,先不安装。</p>
<p>在<code>wrapper</code>里,运行 wineskin.app</p>
<p>选择 Advanced, tool 里有 winetricks 来装常用库,Configuration 中的 Windows EXE 中输入的应用程序路径就是最终打包成品 APP 双击运行的应用。如果有安装程序的话,路径填进去,选择 Test Run 跑一下。最后再把启动 exe 填进去。</p>
<p>PS. 如果之前在 wine 中装过程序了,直接把<code>~/.wine</code>下的 <code>driver_c</code>文件夹彻底拷贝到<code>wrapper/Content/Resources</code>下,然后指定下 exe 路径就可以直接拿来用。</p>
<p>wine 坑多坑大,很多程序不能完美运行,报错是免不了的,不要慌,google 多查一查!解决不了的,还是打开 PD 吧。</p>
<hr>
<h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">运行环境</div><div class="line">macOS Sierra</div><div class="line">10.12.5 (16F73)</div></pre></td></tr></table></figure>
<p>测试运行IDAPro v6.8绿色版成功</p>
<p><img src="http://osnpczeks.bkt.clouddn.com/wine_run_ida.png" alt=""></p>
<p><a href="https://down.52pojie.cn/Tools/Disassemblers/IDA_Pro_v6.8_and_Hex-Rays_Decompiler_%28ARM,x64,x86%29_Green.rar" target="_blank" rel="external">下载windows版IDA</a></p>
]]></content>
<summary type="html">
<p>转自:<a href="https://404forest.com/2015/10/12/%E5%9C%A8mac%E4%B8%8B%E9%85%8D%E7%BD%AEwine%E7%8E%AF%E5%A2%83%E2%80%94%E2%80%94%E8%87%AA%E5%B7%B1wine%E4%B8%80%E4%B8%AA%E5%B0%8F%E6%B8%B8%E6%88%8F/" target="_blank" rel="external">在mac下配置wine环境——自己wine一个小游戏</a></p>
<hr>
<p>当我们想要在 mac 上运行 labview 等 windows 下的大型软件时,使用 PD 等虚拟机可以很好的解决需求;然而如果我们只想玩些同人小游戏什么的,再开一个操作系统就觉得有点累赘了,这时我们可以选择wine,更加轻量的执行 windows 应用。</p>
</summary>
<category term="Mac" scheme="https://passerbycrk.github.io/tags/Mac/"/>
<category term="Install" scheme="https://passerbycrk.github.io/tags/Install/"/>
</entry>
<entry>
<title>Xcode Framework制作流程详情整理</title>
<link href="https://passerbycrk.github.io/2017/06/06/xcode_build_framework/"/>
<id>https://passerbycrk.github.io/2017/06/06/xcode_build_framework/</id>
<published>2017-06-06T04:00:00.000Z</published>
<updated>2019-10-05T02:38:43.959Z</updated>
<content type="html"><![CDATA[<p>转自: <a href="https://my.oschina.net/u/2304447/blog/552859" target="_blank" rel="external">Xcode 7 Framework制作流程详情整理</a></p>
<hr>
<p>1、新建iOS->Framework & Library->Cocoa Touch Framework</p>
<p>2、选择next进入下一步</p>
<p>3、在PROJECT->Deployment Target->iOS Deployment Target选择你需要支持的最低系统。</p>
<p>同样的操作在TARGETS中,Deployment Info->Deployment Target</p>
<a id="more"></a>
<p>4、由于我的framework需要支持iOS7,所以在第2、3步中进行了相应的设置。Build时会发现有️ld: warning: embedded dylibs/frameworks only run on iOS 8 or later警告,这是因为工程默认编译设置的是Dynamic Framework。这种编译只有在iOS8以后才能使用。</p>
<p>5、针对第4步中所出现的问题,根据需求我的工程不需要使用动态framework,以使用其动态更新的功能。动态库可以分开发布,在运行时查找并存入内存,但苹果只允许他自己用,到iOS8以后才开放给开发者。因此,我需要将Dynamic Framework更换为Static Library静态模式。设置路径为Build Settings->Linking->Mach-O Type->Static Library</p>
<p>6、这里要注意,在编译时,不要将图片文件放在工程里面,否则编译后framework中会出现大量的零散图片文件在里面。这时需要将图片等资源放在.bundle文件中。</p>
<p>7、这样打包的framework依然有问题,如果你用了Category,别人在用你的framework时会发生崩溃。这时别人在引用时需要在工程中other linker flags中添加-objC如果依然有问题,再添加-all_load。</p>
<p>8、终于编译成功,但发现很多关于符号表的警告,这时需要将Generate Debug Symbols设置为NO即可关闭符号表警告。</p>
<p>9、但是我需要支持bitcode,以上设置后并不能使framework支持bitcode,因此还需要进行额外的设置一个命令让其支持bit code。在TAGETS的Build setting中搜索Other C Flags,添加命令“-fembed-bitcode”。同样的设置在PROJECT中。如果不进行以上操作。别人在集成你的framework时可以编译,亦可以真机测试。唯独在打包时会发出警告并打包失败。警告为framework不支持bitcode!</p>
<p>10、无论SDK还是Framework都需要暴露公共的头文件以供使用者读取和。在TARGETS->Build Phases->Headers里面,有三种类别。Public(公共的),这里存放供其他人查看的header。Private(私有的)这里存放私有的Header,以上两个Headers存放位置都会暴露出来,所有人可以查看。有些Header是不想给别人看到的。这种header放在第三个类Project中。</p>
<p>11、打包。Edit Scheme->Build Configuration->选为Release然后Run.</p>
<p>直接导出方法:</p>
<pre><code>1.添加 target --> other -->aggregate
2.在新建的Target里边添加一个脚本:Build Phases -->new Run Script Phase
3.填入下面脚本到 Run Script
</code></pre><p><strong>查询framework支持架构:打开终端 lipo -info +路径</strong></p>
<pre><code># begin =============================================
# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos -arch armv7 -arch armv7s -arch arm64 clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator -arch x86_64 clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${SRCROOT}/Products/"
# end ===============================================
</code></pre><p>PS:脚本需要跑一遍真机,再跑一遍模拟器才会build success</p>
]]></content>
<summary type="html">
<p>转自: <a href="https://my.oschina.net/u/2304447/blog/552859" target="_blank" rel="external">Xcode 7 Framework制作流程详情整理</a></p>
<hr>
<p>1、新建iOS-&gt;Framework &amp; Library-&gt;Cocoa Touch Framework</p>
<p>2、选择next进入下一步</p>
<p>3、在PROJECT-&gt;Deployment Target-&gt;iOS Deployment Target选择你需要支持的最低系统。</p>
<p>同样的操作在TARGETS中,Deployment Info-&gt;Deployment Target</p>
</summary>
<category term="Tutorial" scheme="https://passerbycrk.github.io/tags/Tutorial/"/>
</entry>
<entry>
<title>多米尼克体系-编码表</title>
<link href="https://passerbycrk.github.io/2017/03/29/memory_encoding/"/>
<id>https://passerbycrk.github.io/2017/03/29/memory_encoding/</id>
<published>2017-03-29T04:00:00.000Z</published>
<updated>2019-10-05T02:38:43.959Z</updated>
<content type="html"><![CDATA[<h4 id="声母编码"><a href="#声母编码" class="headerlink" title="声母编码"></a>声母编码</h4><p>声母正好20个,可以规划为2x10赋予10个数两组编码<br><br><br>bpmf-dtnl-gkh-jqx-zcsr-yw<br><br><br>特殊:aoe iuv 都当做是0</p>
<a id="more"></a>
<table>
<thead>
<tr>
<th>0</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
<th>9</th>
</tr>
</thead>
<tbody>
<tr>
<td>d</td>
<td>y</td>
<td>z</td>
<td>m</td>
<td>s</td>
<td>w</td>
<td>l</td>
<td>q</td>
<td>b</td>
<td>j</td>
</tr>
<tr>
<td>c</td>
<td>t</td>
<td>r</td>
<td>k</td>
<td>p</td>
<td>h</td>
<td>n</td>
<td>f</td>
<td>x</td>
<td>g</td>
</tr>
</tbody>
</table>
<hr>
<h4 id="0-9-编码"><a href="#0-9-编码" class="headerlink" title="0~9 编码"></a>0~9 编码</h4><table>
<thead>
<tr>
<th style="text-align:center">数字</th>
<th style="text-align:center">声母</th>
<th style="text-align:center">联想</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">0</td>
<td style="text-align:center">d</td>
<td style="text-align:center">蛋/洞/鼎/盾</td>
</tr>
<tr>
<td style="text-align:center">1</td>
<td style="text-align:center">y</td>
<td style="text-align:center">雁/蚁/鱼/鹰</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td style="text-align:center">z</td>
<td style="text-align:center">嘴/粽/枣/砖</td>
</tr>
<tr>
<td style="text-align:center">3</td>
<td style="text-align:center">m</td>
<td style="text-align:center">矛/帽/马/锚</td>
</tr>
<tr>
<td style="text-align:center">4</td>
<td style="text-align:center">s</td>
<td style="text-align:center">伞/锁/扇/梳</td>
</tr>
<tr>
<td style="text-align:center">5</td>
<td style="text-align:center">w</td>
<td style="text-align:center">碗/蛙/网/瓦</td>
</tr>
<tr>
<td style="text-align:center">6</td>
<td style="text-align:center">l</td>
<td style="text-align:center">锣/龙/狼/螺</td>
</tr>
<tr>
<td style="text-align:center">7</td>
<td style="text-align:center">q</td>
<td style="text-align:center">球/桥/枪/钳</td>
</tr>
<tr>
<td style="text-align:center">8</td>
<td style="text-align:center">b</td>
<td style="text-align:center">豹/靶/蚌/笔</td>
</tr>
<tr>
<td style="text-align:center">9</td>
<td style="text-align:center">j</td>
<td style="text-align:center">酒/剑/剪/锯</td>
</tr>
</tbody>
</table>
<hr>
<h4 id="00-99-编码"><a href="#00-99-编码" class="headerlink" title="00~99 编码"></a>00~99 编码</h4><table>
<thead>
<tr>
<th style="text-align:center">数字</th>
<th style="text-align:left">声母</th>
<th style="text-align:center">生物</th>
<th style="text-align:left">行为</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">00</td>
<td style="text-align:left">dd-dc-cd-cc</td>
<td style="text-align:center">大盗</td>
<td style="text-align:left">蒙面持短刀</td>
</tr>
<tr>
<td style="text-align:center">01</td>
<td style="text-align:left">dy-dt-cy-ct</td>
<td style="text-align:center">导游</td>
<td style="text-align:left">持小喇叭举小旗</td>
</tr>
<tr>
<td style="text-align:center">02</td>
<td style="text-align:left">dz-dr-cz-cr</td>
<td style="text-align:center">队长/DZ</td>
<td style="text-align:left">臂章五道杠</td>
</tr>
<tr>
<td style="text-align:center">03</td>
<td style="text-align:left">dm-dk-cm-ck</td>
<td style="text-align:center">达摩</td>
<td style="text-align:left">头顶有三排戒疤</td>
</tr>
<tr>
<td style="text-align:center">04</td>
<td style="text-align:left">ds-dp-cs-cp</td>
<td style="text-align:center">袋鼠</td>
<td style="text-align:left">肚子上有个口袋</td>
</tr>
<tr>
<td style="text-align:center">05</td>
<td style="text-align:left">dw-dh-cw-ch</td>
<td style="text-align:center">典韦</td>
<td style="text-align:left">持双戟</td>
</tr>
<tr>
<td style="text-align:center">06</td>
<td style="text-align:left">dl-dn-cl-cn</td>
<td style="text-align:center">大佬</td>
<td style="text-align:left">(北野武)戴墨镜+叼雪茄</td>
</tr>
<tr>
<td style="text-align:center">07</td>
<td style="text-align:left">dq-df-cq-cf</td>
<td style="text-align:center">大乔</td>
<td style="text-align:left">持灯笼守望着天空大海和你的回忆</td>
</tr>
<tr>
<td style="text-align:center">08</td>
<td style="text-align:left">db-dx-cb-cx</td>
<td style="text-align:center">大白/大饼</td>
<td style="text-align:left">碳纤维充气白外套/写代码</td>
</tr>
<tr>
<td style="text-align:center">09</td>
<td style="text-align:left">dj-dg-cj-cg</td>
<td style="text-align:center">妲己</td>
<td style="text-align:left">漏出狐狸尾巴</td>
</tr>
<tr>
<td style="text-align:center">10</td>
<td style="text-align:left">yd-yc-td-tc</td>
<td style="text-align:center">玉帝</td>
<td style="text-align:left">头戴皇冠</td>
</tr>
<tr>
<td style="text-align:center">11</td>
<td style="text-align:left">yy-yt-ty-tt</td>
<td style="text-align:center">爷爷</td>
<td style="text-align:left">带着老花镜</td>
</tr>
<tr>
<td style="text-align:center">12</td>
<td style="text-align:left">yz-yr-tz-tr</td>
<td style="text-align:center">鸭子</td>
<td style="text-align:left">扁扁的嘴巴+展开的鸭掌</td>
</tr>
<tr>
<td style="text-align:center">13</td>
<td style="text-align:left">ym-yk-tm-tk</td>
<td style="text-align:center">姚明/樱木</td>
<td style="text-align:left">红色的头发+灌篮</td>
</tr>
<tr>
<td style="text-align:center">14</td>
<td style="text-align:left">ys-yp-ts-tp</td>
<td style="text-align:center">耶稣</td>
<td style="text-align:left">绑在十字架上</td>
</tr>
<tr>
<td style="text-align:center">15</td>
<td style="text-align:left">yw-yh-tw-th</td>
<td style="text-align:center">叶问</td>
<td style="text-align:left">打咏春拳</td>
</tr>
<tr>
<td style="text-align:center">16</td>
<td style="text-align:left">yl-yn-tl-tn</td>
<td style="text-align:center">月老</td>
<td style="text-align:left">牵红线</td>
</tr>
<tr>
<td style="text-align:center">17</td>
<td style="text-align:left">yq-yf-tq-tf</td>
<td style="text-align:center">月骑</td>
<td style="text-align:left">骑黑豹+持月刃</td>
</tr>
<tr>
<td style="text-align:center">18</td>
<td style="text-align:left">yb-yx-tb-tx</td>
<td style="text-align:center">伊布</td>
<td style="text-align:left">从精灵球里出来</td>
</tr>
<tr>
<td style="text-align:center">19</td>
<td style="text-align:left">yj-yg-tj-tg</td>
<td style="text-align:center">杨戬</td>
<td style="text-align:left">持三叉戟+三眼</td>
</tr>
<tr>
<td style="text-align:center">20</td>
<td style="text-align:left">zd-zc-rd-rc</td>
<td style="text-align:center">周董</td>
<td style="text-align:left">“哎呦不错哟”</td>
</tr>
<tr>
<td style="text-align:center">21</td>
<td style="text-align:left">zy-zt-ry-rt</td>
<td style="text-align:center">赵云</td>
<td style="text-align:left">持龙胆枪和青釭剑</td>
</tr>
<tr>
<td style="text-align:center">22</td>
<td style="text-align:left">zz-zr-rz-rr</td>
<td style="text-align:center">庄周/蜘蛛</td>
<td style="text-align:left">骑鲲/吐丝结网</td>
</tr>
<tr>
<td style="text-align:center">23</td>
<td style="text-align:left">zm-zk-rm-rk</td>
<td style="text-align:center">掌门</td>
<td style="text-align:left">《九阴真经》</td>
</tr>
<tr>
<td style="text-align:center">24</td>
<td style="text-align:left">zs-zp-rs-rp</td>
<td style="text-align:center">宙斯</td>
<td style="text-align:left">手持雷霆和宙斯之盾</td>
</tr>
<tr>
<td style="text-align:center">25</td>
<td style="text-align:left">zw-zh-rw-rh</td>
<td style="text-align:center">张伟/纣王</td>
<td style="text-align:left">吃小龙虾过敏/好酒淫乐</td>
</tr>
<tr>
<td style="text-align:center">26</td>
<td style="text-align:left">zl-zn-rl-rn</td>
<td style="text-align:center">蟑螂</td>
<td style="text-align:left">头上有两黑色大触须</td>
</tr>
<tr>
<td style="text-align:center">27</td>
<td style="text-align:left">zq-zf-rq-rf</td>
<td style="text-align:center">朱雀</td>
<td style="text-align:left">全身火焰献祭</td>
</tr>
<tr>
<td style="text-align:center">28</td>
<td style="text-align:left">zb-zx-rb-rx</td>
<td style="text-align:center">张苞</td>
<td style="text-align:left">继承丈八蛇矛</td>
</tr>
<tr>
<td style="text-align:center">29</td>
<td style="text-align:left">zj-zg-rj-rg</td>
<td style="text-align:center">张角</td>
<td style="text-align:left">头戴黄巾可引雷</td>
</tr>
<tr>
<td style="text-align:center">30</td>
<td style="text-align:left">md-mc-kd-kc</td>
<td style="text-align:center">马东/麦兜</td>
<td style="text-align:left">奇葩说议长/猪鼻子端着一碗鱼丸粗面</td>
</tr>
<tr>
<td style="text-align:center">31</td>
<td style="text-align:left">my-mt-ky-kt</td>
<td style="text-align:center">马云/蚂蚁</td>
<td style="text-align:left">淘宝董事长/成群结队搬运糖</td>
</tr>
<tr>
<td style="text-align:center">32</td>
<td style="text-align:left">mz-mr-kz-kr</td>
<td style="text-align:center">蚂蚱</td>
<td style="text-align:left">啃食庄稼</td>
</tr>
<tr>
<td style="text-align:center">33</td>
<td style="text-align:left">mm-mk-km-kk</td>
<td style="text-align:center">孟母/妈妈</td>
<td style="text-align:left">收拾行李准备搬家/围裙+颠勺</td>
</tr>
<tr>
<td style="text-align:center">34</td>
<td style="text-align:left">ms-mp-ks-kp</td>
<td style="text-align:center">牧师</td>
<td style="text-align:left">一身黑袍持法杖施法</td>
</tr>
<tr>
<td style="text-align:center">35</td>
<td style="text-align:left">mw-mh-kw-kh</td>
<td style="text-align:center">猫王</td>
<td style="text-align:left">飞机头</td>
</tr>
<tr>
<td style="text-align:center">36</td>
<td style="text-align:left">ml-mn-kl-kn</td>
<td style="text-align:center">马良</td>
<td style="text-align:left">用神笔画龙点睛</td>
</tr>
<tr>
<td style="text-align:center">37</td>
<td style="text-align:left">mq-mf-kq-kf</td>
<td style="text-align:center">米奇</td>
<td style="text-align:left">拿着彩色气球</td>
</tr>
<tr>