-
Notifications
You must be signed in to change notification settings - Fork 5
/
about.html
716 lines (566 loc) · 35.2 KB
/
about.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>about</title>
<style type="text/css">
body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: white;
padding: 30px; }
body > *:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }
a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
text-decoration: none; }
h1 tt, h1 code {
font-size: inherit; }
h2 tt, h2 code {
font-size: inherit; }
h3 tt, h3 code {
font-size: inherit; }
h4 tt, h4 code {
font-size: inherit; }
h5 tt, h5 code {
font-size: inherit; }
h6 tt, h6 code {
font-size: inherit; }
h1 {
font-size: 28px;
color: black; }
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }
hr {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}
body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }
li p.first {
display: inline-block; }
li {
margin: 0; }
ul, ol {
padding-left: 30px; }
ul :first-child, ol :first-child {
margin-top: 0; }
dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }
blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
table {
padding: 0;border-collapse: collapse; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
img {
max-width: 100%; }
span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }
.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:0 auto;
}
}
@media print {
table, pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
</style>
</head>
<body>
<h1 id="toc_0">iOS上基于NetworkExtension的实现流量分类的系统</h1>
<blockquote>
<p>备注信息,后续删除</p>
<p>命名:iTrafficeClassifier</p>
<p>iOS app服务器:app.ainassine.cn</p>
<p>app下载地址:https://app.ainassine.cn/download.html</p>
<p>app.ainassine.cn => 119.23.215.159</p>
<p>PerAppProxy端口:10808</p>
<p>bundleID查询地址:http://www.ainassine.cn/AppStore_Crawler_Demo/index.html</p>
<p>bundleID查询服务器端口:5000</p>
<p>目前在iOS <= 12.1版本上<code>PerAppProxy</code>存在漏洞,在<code>iOS 12.1.1 beta 2</code>版本上有修复,如果用户需要使用基于<code>UDP</code>协议实现的语音、视频通话的话,需要升级至<code>iOS 12.1.1 beta 2</code>,否则会引起iPhone重启。</p>
</blockquote>
<h2 id="toc_1">0x00 概述</h2>
<blockquote>
<p>项目需求背景描述,工具功能概述,工具运行环境概述,限制概述。</p>
</blockquote>
<p>随着信息技术的不断发展,互联网用户的人数也在不断增多。更多技术上的创新,更多新设备的研发,让人们在接入互联网的方式上有了更多的选择。现如今,人们接入互联网的方式已经不再仅仅局限于桌面浏览器,更多移动设备,比如手机、平板等,给人们提供更多更加便利的上网方式。「论证以上」<br>
在移动设备上,接入互联网主要以APP的形式,当然诸多浏览器也算是APP的一种。现行主流移动端操作系统主要分为Android和iOS两大阵营,无论在哪一阵营中,其中的APP功能遍及到人们日常工作生活的方方面面,可以说现代人的生活已经越来越离不开这些APP。APP数目多,种类多,与使用者关系十分密切,有研究者证实,通过用户移动设备的APP安装情况可以分析出这个用户的人物画像,包括人物性格、喜好,乃至政治倾向、性取向可以被分析出来。移动APP涉及到金融交易、社交信息等各种极为敏感的数据,也使自己成为了无数灰黑产人员眼中的目标,导致移动APP的信息安全受到极大的关注。<br>
有关移动流量分析已经有前人做了大量工作。「举例」但是这些工作主要集中在Android平台上,对iOS涉及较少。虽然流量产生于平台并在平台之间进行交流,但是不同平台由于语言不通,同一个APP在实现的时候会产生变化,而且来自不同平台的流量会有不同的特征,如果不实际验证并不能保证理论的完全正确性。<br>
本文提供了一套名为iTrafficClassifier的系统,在iOS平台上搭建起了一套用于流量分析的系统。先前在iOS平台上并没有类似的尝试,可以说是iOS平台上第一个有效的工具。本工具基于iOS 9.0+的NetworkExtension API,实现了对iOS设备上流量的分析。可以为以下研究提供有效的支撑:1. 流量分类,本系统可以抓取特定APP的流量,并且进行标记,保证流量的纯净;2. 本系统将流量抓取与定位相结合,能够为流量数据与地理位置之间的联系的研究提供有效支持;3. 同样,我们可以实现内容拦截功能。4. 我们可以给用户展现其流量的具体使用情况,弥补了相关的不足。</p>
<h2 id="toc_2">0x01 系统架构</h2>
<p>!<a href="https://raw.githubusercontent.com/Joeeyy/test/master/system%20arch.png"></a><br>
客户端设计、功能,服务器设计、功能,客户端服务器通信设计。</p>
<p>客户端主要功能模块由PacketTunnel、PerAppProxy支撑。</p>
<blockquote>
<p>TODO:</p>
<p><del>1. 百度地图API接入完成位置信息获取</del><br>
2. ContentFilter接入完成内容过滤</p>
</blockquote>
<p>iTrafficClassifier 主要分为客户端和服务器两部分,客户端就是安装在iPhone上的APP,由于使用模块的限制,APP不能够上架的AppStore,但是可以用其他的方式发布,提供给需要的用户下载。在客户端上主要完成数据的采集,主要包括流量信息和位置信息。iTrafficClassifier客户端APP在使用的过程中离不开和服务器的配合,客户端APP的运行需要服务器的支持,同时客户端收集的数据也需要上传到服务器进行整合,以提供更多服务。服务器细分可以分为三类:代理服务器、数据管理服务器和查询服务器。代理服务器主要负责流量的转发,让我们获取流量信息的同时保证用户正常使用手机中受监控的APP。查询服务器主要是用来支撑APP运行的,APP在运行期间可能需要查询自己的状态,或者确认某个APP的bundle ID,都可以从查询服务器进行获取。数据管理服务器负责收集数据,主要包括客户端对流量的标签数据、客户端记录的位置数据等。</p>
<p>BundleID查询服务器使用频率应该不高,属于附属产品,可以提供给其他用户查询某些中国区APP的bundle ID,由Python 3.6.5 提供服务。对于本系统,主要承担在iOS端工具编译时提供目标的bundle ID的任务。</p>
<p>应用服务器是为了支撑iOS端工具使用而建立的一系列脚本的集合。</p>
<blockquote>
<p>目前阶段:</p>
<ol>
<li>确定APP终端所在公网IP(IP+端口,如果终端在局域网环境中的话)。<br>
<del>2. 接收定位数据,并按照imei号码存储。</del></li>
</ol>
</blockquote>
<p>流量抓取服务器主要完成对SOCKS5服务器转发的流量的抓取工作。</p>
<blockquote>
<p>在这个过程中,明确的应该是目的应用服务器(终端上APP真正请求的服务器)的地址。由此就可以完成<strong>服务器地址</strong>和<strong>应用</strong>的对应关系的确定。</p>
</blockquote>
<h2 id="toc_3">0x02 客户端</h2>
<h3 id="toc_4">流量标记</h3>
<p>利用iOS提供的<a href="https://developer.apple.com/documentation/networkextension">NetworkExtension</a>中的<code>PerAppProxy</code>,我们可以以<code>NEAppProxyFlow</code>的形式获取目标APP的通信流量信息,包括流量来自哪个APP的信息,由此完成流量的按APP标记工作。<code>metaData.sourceAppSigningIdentifier</code>是我们获取源APP信息的属性,获取之后的标志符是以<code>BundleID</code>的形式呈现的,所以我们需要获取一些目标APP的<code>BundleID</code>,参看<a href="#BundleID%E6%9F%A5%E8%AF%A2%E6%9C%8D%E5%8A%A1%E5%99%A8">BundleID查询服务器</a>。</p>
<p>!<a href="https://raw.githubusercontent.com/Joeeyy/test/master/clientStructure.png"></a><br>
上图展示了客户端上流量标记的工作原理。以出方向的流量为例,符合<code>PerAppProxy规则</code>的来自上层APP的流量会被以<code>NEAppProxyFlow</code>的形式转发到<code>PerAppProxy</code>模块进行处理,而相关处理的主要实行者就是<code>PerAppProxy Provider</code>。在这个层面上已经能够获取流量的大部分信息,其中最为主要的用来确定流量来自哪个APP的<code>metaData.sourceAppSigningIdentifier</code>已经能够获取,但是流量的IP信息事实上还不能够完全确定。对于TCP流量来说,我们可以通过将<code>NEAppProxyFlow</code>转为<code>NEAppProxyTCPFlow</code>获得其<code>remoteEndpoint</code>属性,从而得知<code>NEAppProxyFlow</code>的目的地地址,但是<code>NEAppProxyTCPFlow</code>没有提供相对应的<code>localEndpoint</code>属性,当然如果只是对流量做标记的话我们对本地地址关心的程度并不是很大,但是我们依然可以通过一些方法来获得本地的IP地址,比如通过<code>createTCPConnection</code>函数与服务器建立一个TCP连接,从而可以通过该连接获得本地IP地址,不过如果终端在局域网环境下,这种方法仅能获得终端的局域网地址,如果需要公网IP,可以通过本系统中实现的<a href="#%E5%85%AC%E7%BD%91IP%E7%A1%AE%E5%AE%9A%E6%9C%8D%E5%8A%A1%E5%99%A8">公网IP确定服务器</a> 来完成。对于UDP流量来说,与TCP流量恰恰相反,当我们把<code>NEAppProxyFlow</code>转为<code>NEAppProxyUDPFlow</code>后,我们只能获得其<code>localEndpoint</code>属性,而无法获得<code>remoteEndpoint</code>属性,只有我们读出<code>NEAppProxyUDPFlow</code>中的datagrams后,才能获得这些datagrams的目的地址。之后根据流量协议的不同,经由<code>SOCKS5 Tunnel</code>按照不同的协议流程发往代理服务器,并在发送的同时在本地数据库中记录流量的信息,完成流量的标记工作。</p>
<p><em>流量标记数据上传</em><br>
JSON格式:</p>
<div><pre><code class="language-none">{
"idfa": xxxxxx,
"app": xxx.xxx.xxx,
"data": {
"srcIP": String,
"srcPort": String,
"dstIP": String,
"dstPort": String,
"time": String,
"length": int,
"protocol": String,
}
...
}</code></pre></div>
<p>服务器接收后,按照不同ifda、app,对应存放在ifda目录下的{app}.log文本中。<br>
<a href="https://app.ainassine.cn/test/checkin/353B317C-0B24-4C0F-B840-92A77F6350BC/com.tencent.mQQi.log">国际版QQ的记录示例</a></p>
<h3 id="toc_5">位置记录</h3>
<p>利用<a href="http://lbsyun.baidu.com/index.php?title=ios-locsdk/guide/create-project/manual-create">百度定位SDK</a>实现。百度对iOS原生的定位服务进行了封装,在其基础上提供了语义化的定位结果,但是百度没有对iOS中<a href="https://developer.apple.com/documentation/corelocation/cllocationmanager/1620547-allowdeferredlocationupdates">allowdeferredlocationupdates</a>的函数进行封装,导致如果本APP被杀死,将无法继续进行定位服务。<strong>但是只要程序在后台,就能保证长期活动</strong>。</p>
<p><em>定位返回数据</em><br>
1. location: <br></p>
<blockquote>
<p>location是iOS原生的定位结果,属于<a href="https://developer.apple.com/documentation/corelocation/cllocation">CLLocation</a>类型。以下内容均可以在<a href="https://developer.apple.com/documentation/corelocation/cllocation">CLLocation</a>中找到,有更详细了解的需求请移步。</p>
</blockquote>
<p><strong>主要属性</strong>:<br>
<code>coordinate: CLLocationCoordinate2D</code>: 定位获得的二维地理坐标,经纬度。<br>
<code>altitude: CLLocationDistance</code>: 定位获得的海拔高度。<br>
<code>horizontalAccuracy: CLLocationAccuracy</code>: 水平定位精度,单位为<code>米</code>。<br>
<code>verticalAccuracy: CLLocationAccuracy</code>: 垂直定位精度,单位为<code>米</code>。<br>
<code>floor: CLFloor?</code>: 定位获得的楼层数,不是所有定位都有结果,也不是所有的iPhone都支持。<br>
<code>speed: CLLocationSpeed</code>: 定位获得的设备移动速度,单位为<code>米每秒</code>。<br>
<code>course: CLLocationDirection</code>: 定位获得的设备的方向,以与正北方向的相对夹角衡量。<br>
<code>timestamp: Date</code>: 定位结果产生的时间点。<br>
<br>
2. rgcData: <br></p>
<blockquote>
<p>rgcData属于Baidu定位SDK定义的<a href="http://wiki.lbsyun.baidu.com/cms/iosloc/docs/v1_2_1/html/interface_b_m_k_location_re_geocode.html">BMKLocationReGeocode</a>类,是对iOS定位结果的一种补充,对定位结果进行了语义解释。</p>
</blockquote>
<p><code>country: NSString</code>: 定位所在的国家。<br>
<code>countryCode: NSString</code>: 国家编码。<br>
<code>province: NSString</code>: 省份名称。<br>
<code>city: NSString</code>: 城市名称。<br>
<code>district: NSString</code>: 区名称。<br>
<code>street: NSString</code>: 街道名称。<br>
<code>streetNumber: NSString</code>: 街区号码。<br>
<code>cityCode: NSString</code>: 城市编码。<br>
<code>adCode: NSString</code>: 行政区划编码。<br>
<code>locationDescribe: NSString</code>: 定位地点在什么地方周围的语义化描述信息。
<code>poiList: NSArray<BMKLocationPoi*></code>: 语义化结果,表示该定位点周围的poi列表。</p>
<p><span id="定位数据上传">
<em>定位数据上传</em><br>
定位数据是由BaiduLocation SDK产生的,每隔大约15s会有一次定位结果。本APP不在手机上保留定位结果,在获得定位结果后就通过HTTP POST以JSON的形式上传到服务器,JSON格式如下:</p>
<div><pre><code class="language-none">{
"idfa": xxxxxxxxx,
"location": {
"coordinate": (double,double),
"horizontalAccuracy": double,
"altitude": double,
"verticalAccuracy": double,
"floor": int?,
"speed": double,
"course": double,
"timestamp": Date
},
"rgcData": {
"country": String,
"countryCode": String,
"province": String,
"city": String,
"cityCode": String,
"district": String,
"street": String,
"streetNumber": String,
"adCode": String,
"locationDescribe": String,
"poiList": list,[]cd
}
}</code></pre></div>
<p><del>其中<code>imei</code>用于确定iPhone终端。也可以获得设备的<code>UUID</code>作为唯一标志。</del><br>
根据<a href="https://blog.csdn.net/Sir_Coding/article/details/68943033">iOS - 获取设备标识符UUID/UDID/IMEI等</a>,iOS上获取<code>IMEI</code>、<code>IMSI</code>、<code>UDID</code>已经不再可能。而<code>UUID</code>作为唯一标志符比较繁琐,参考<a href="https://www.jianshu.com/p/9e885c3e6b0a">获取iOS设备唯一标示UUID——Swift版</a>这里使用<code>IDFA</code>作为唯一标志符,<strong>要求用户允许追踪</strong>。<code>IDFA</code>会在用户卸载iPhone上所有相关开发商的APP后重置。<code>353B317C-0B24-4C0F-B840-92A77F6350BC</code>是一个样例。</p>
<h3 id="toc_6">内容过滤</h3>
<h3 id="toc_7">数据库</h3>
<p><strong>Network Flow logs</strong><br>
flow_id(int), src_ip(String), src_port(String), dst_ip(String), dst_port(String), time(String), proto(String), length(int), app(String), direction(String)</p>
<p><strong>APP Config</strong><br>
key(String), value(String)</p>
<h2 id="toc_8">0x03 服务端</h2>
<h3 id="toc_9">代理服务器</h3>
<blockquote>
<p>服务器地址:119.23.215.159:10808 </p>
</blockquote>
<p>SOCKS5服务器源码来自<a href="https://github.com/postageapp/ss5">Github</a>。为了适应aliyun服务器<em>专用网络</em>没有公网网卡的缺陷,改动了其中开启UDP服务的代码,使其监听端口为<code>0.0.0.0</code>而非某个公网IP。根据<a href="https://stackoverflow.com/questions/53361320/is-there-a-timeout-for-udp-in-socks5">StackOverflow</a>,为了保证UDP通话通畅进行,修改了SOCKS5实现中关于UDP连接超时的设置,由原来的<code>60</code>修改为<code>6000</code>,单位为<code>秒</code>。<br>
<strong>SOCKS5参考</strong><br>
<a href="https://www.ietf.org/rfc/rfc1928.txt">RFC 1928</a>,定义了<code>SOCKS5</code>协议的基本通信流程。<br>
<a href="https://tools.ietf.org/html/rfc1929">RFC 1929</a>,<code>SOCKS5</code>用户名密码认证过程。<br>
<a href="https://tools.ietf.org/html/rfc1961">RFC 1961</a>,<code>SOCKS5</code>GSS-API方式认证过程。</p>
<h3 id="toc_10">流量抓取服务器</h3>
<blockquote>
<p>利用TCPDump配合脚本实现<br>
-d、-dd、-ddd意义不明。<br></p>
</blockquote>
<p><em>TCPDump的使用</em>:<br>
参照<a href="http://www.tcpdump.org/manpages/tcpdump.1.html">说明</a>。</p>
<p><em>重要选项</em>:<br>
<code>-w file</code>:保存抓取结果到文件<em>file</em>中。<br>
<code>-B buffer_size</code>或<code>--buffer-size=buffer_size</code>:设置操作系统抓取的缓冲区大小,单位为KiB(1024字节)。<br>
<code>-c count</code>:抓取<em>count</em>个packet后退出。<br>
<code>-C file_size</code>:在向文件写入一个新的packet前,检查文件大小是否超过<em>file_size</em>设置,如果超过,则关闭当前文件并打开一个新的文件进行写入。后续文件命名为<code>-w</code>设定的文件名加序号。<em>file_size</em>的单位为<strong>百万字节</strong>(1,000,000字节,而非1,048,576字节)。<br>
<code>-D</code>或<code>--list-interfaces</code>:列出系统中可用的网络接口,以及在哪些接口上可以进行流量抓取。对于每个接口,会打印序号、接口名,可能还会打印有关接口的描述信息。接口名或者接口序号可以被提供给<code>-i</code>参数用来指定在哪个接口上进行流量抓取。如果<em>tcpdump</em>在编译过程中使用的<em>libpcap</em>过老,缺少<a href="http://www.tcpdump.org/manpages/pcap_findalldevs.3pcap.html">pcap_findalldevs</a>(3PCAP)函数,<code>-D</code>参数将不被支持。<br>
<code>-F file</code>:使用<em>file</em>作为输入的正则式文件。<br>
<code>-i interface</code>或<code>--interface=interface</code>:监听<em>interface</em>。如果没有设置,<em>tcpdump</em>将寻找系统中序号最小的接口(本地回环除外)进行监听,结果很有可能是<code>eth0</code>。<br>
<code>-n</code>:不要将地址转为名称,比如将IP、端口号转为域名。<br>
<code>-Q direction</code>或<code>--direction=direction</code>:选择抓取报文的方向为<em>direction</em>,有<em>in</em>、<em>out</em>、<em>inout</em>可选。不是所有的平台都支持。<br></p>
<p><em>执行设计</em>:<br>
首先我们的流量是来自客户端,经由SOCKS5协议传输到服务器上,再由服务器与目的服务器进行通信的。这其中设计很多packet换头的操作。在我们的SOCKS5服务器看来,无论客户端身处什么样的网络环境(客户端有可能身处某内网,本身IP是局域网IP),他都只能看到该客户端在公网上的IP和端口,而客户端需要进行交互的服务器无疑是暴露在公网上的,也就是说,目的服务器的IP、端口与其提供的服务之间存在着长期、稳定的对应关系,这样我们就能完成<strong>流量的APP分类</strong>。那么如何在抓取后区别来自不同的客户端的流量呢?在比较粗略的粒度上,如果终端是通过运营商网络直接接入互联网,那么他的IP地址就是其自身的真实IP地址。但是如果终端是经由路由器之类的设备接入网络,那么只有通过其IP地址和端口号去鉴识其身份。现在系统内只是简单获取终端的公网IP,后续需要尝试获取公网IP、端口号,并且证实这一对应关系的正确性。终端需要周期上报自身的特征以及IP。</p>
<blockquote>
<p><strong>一个示例的tcpdump执行命令</strong><br>
tcpdump -w t.pcap -C 1 [expression]<br>
<em>tcpdump</em>将会抓取满足expression的流量,并将结果保存在<em>t.pcap</em>中,如果<em>t.pcap</em>大小超过了1百万字节(约为1MB),那么就会保存在新的文件t.pcapnum中,其中num从1自增。<br></p>
<p><strong>关于expression</strong><br>
沟通需求后再确定,目前来看可以只抓ipv4的部分。</p>
</blockquote>
<p><span id="BundleID查询服务器"></p>
<h3 id="toc_11">BundleID查询服务器</h3>
<blockquote>
<p>地址:http://www.ainassine.cn/AppStore_Crawler_Demo/index.html</p>
</blockquote>
<p>为了更方便的实现查询iOS APP的<code>BundleID</code>,本人写了一个<code>APP Crawler</code>放在<a href="https://github.com/Joeeyy/app_crawler">Github</a>上。相关细节后续补上。</p>
<h3 id="toc_12">应用服务器</h3>
<h4 id="toc_13">1 定位数据接收服务器</h4>
<blockquote>
<p>地址:<br>
http://119.23.215.159/test/checkin/locRec.php </p>
<p>服务器操作系统:<br>
LSB Version: :core-4.1-amd64:core-4.1-noarch<br>
Distributor ID: CentOS<br>
Description: CentOS Linux release 7.2.1511 (Core)<br>
Release: 7.2.1511<br>
Codename: Core </p>
<p>apache版本:
Server version: Apache/2.4.6 (CentOS)<br>
Server built: Jun 27 2018 13:48:59 </p>
<p>PHP版本:
PHP 5.4.16 (cli) (built: Apr 12 2018 19:02:01)<br>
Copyright (c) 1997-2013 The PHP Group<br>
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies </p>
</blockquote>
<p>定位数据以<code>JSON</code>格式通过<code>HTTP POST</code>方式上传到服务器。服务器采用PHP实现,负责接收数据,并且以<code>locRec{UUID}.log</code>的形式对不同iPhone终端的定位数据进行保存。样例请看<a href="https://app.ainassine.cn/test/checkin/locRec353B317C-0B24-4C0F-B840-92A77F6350BC.log">这里</a>。</p>
<p><span id="公网IP确定服务器"></p>
<h4 id="toc_14">2 公网IP确定服务器</h4>
<blockquote>
<p>地址:<br>
http://119.23.215.159/test/checkin/checkin.php</p>
</blockquote>
<p>类似定位数据接收服务器,应用在启动后会以<code>HTTP POST</code>的形式,带自己的<code>UUID</code>请求服务地址,从而获得自己的<code>公网IP</code>地址。。</p>
<h4 id="toc_15">3 流量标记上传服务器</h4>
<h2 id="toc_16">0x04 通信设计</h2>
<p>客户端服务器之间的通信主要通过HTTP请求实现。为了尽量降低服务器压力,流量处理服务器和其他服务器分离进行。</p>
<h3 id="toc_17">位置信息通信</h3>
<p>参照<a href="#%E5%AE%9A%E4%BD%8D%E6%95%B0%E6%8D%AE%E4%B8%8A%E4%BC%A0">定位数据上传</a></p>
<h2 id="toc_18">0x05 应用分析</h2>
<p>客户端开销 <mark>[TODO]</mark></p>
<p>服务器容量 <mark>[TODO]</mark></p>
<h2 id="toc_19">0x06 成果对比</h2>
<h2 id="toc_20">0x07 参考</h2>
<p>[1] <a href="https://forums.developer.apple.com/message/339578#339578">Reboot caused by my AppProxy handling UDPFlows</a><br>
[2] <a href="https://forums.developer.apple.com/thread/107013">Does NetworkExtension know which app the data flow comes from?</a><br>
[3] <a href="https://github.com/postageapp/ss5">SOCKS5 Server</a><br>
[4] <a href="https://stackoverflow.com/questions/53361320/is-there-a-timeout-for-udp-in-socks5">Is there a timeout for UDP in SOCKS5?</a><br>
[5] <a href="https://tools.ietf.org/html/rfc1928">RFC 1928</a><br>
[6] <a href="https://tools.ietf.org/html/rfc1929">RFC 1929</a><br>
[7] <a href="https://tools.ietf.org/html/rfc1961">RFC 1961</a><br>
[8] <a href="https://github.com/ashleymills/Reachability.swift/blob/master/Sources/Reachability.swift">网络环境变化检测</a></p>
<p>智能机用户情况:https://venturebeat.com/2018/09/11/newzoo-smartphone-users-will-top-3-billion-in-2018-hit-3-8-billion-by-2021/</p>
<h2 id="toc_21">一些文献</h2>
<h3 id="toc_22">Robust Smartphone App Identification Via Encrypted Network Traffic Analysis</h3>
<p>时间:09 August 2017<br>
作者:https://ieeexplore.ieee.org/abstract/document/8006282/authors<br>
发表于:IEEE Transactions on Information Forensics and Security </p>
<p>提出了一种利用机器学习技术基于旁路数据(加密报文的长度、方向)对APP进行指纹提取和识别的技术,并对APP指纹在不同时间、不同设备、不同版本APP中的变化。</p>
<p>效果,测试了110中Google商店上流行的APP,并能在六个月后以96%的准确率识别他们。</p>
<p>介绍:
1. 智能机的消费增速快。引用Gartner的调查结果。[1]
2. APP使用广泛。引用Flurry的调查结果。[2]
3. 使用者花费大量时间在众多APP上。引用Nielson的调查结果。[3]
4. 智能机现在是接入互联网的最普遍方式。引用Guardian的调查结果。[4]
5. 智能机产生的流量是台式机、平板、移动路由设备产生的流量的和的两倍。引用Telegraph的调查结果。[5]
6. 以上各点将智能机置于所有想要研究公众流量的人的焦点中。</p>
<ol>
<li>通过一个人装的APP可以对人物进行画像。[6]</li>
<li>网络流量指纹提取是近年的新领域。机器学习的手段可以应用到该领域上。[7]</li>
<li>近年APP的指纹提取和识别在以下几种方法上没有取得进展:基于端口的指纹提取(由于APP主要基于HTTP和HTTPS进行数据传输),经典的网页指纹提取(由于APP总是以XML、JSON这样的文本形式进行数据传输,其中不含富文本信息),CDN的使用使得域名解析、IP地址查询、DNS解析或者TLS握手无法被用作鉴定根据。</li>
<li>本文提供的技术的应用场景:针对特定APP的攻击,针对特定用户的攻击,网络管理,广告和市场营销。</li>
<li>是对AppScanner,应用扫描框架,的扩展。[8]</li>
</ol>
<p>相关工作
1. 工作站和浏览器的流量分析已经有很多工作。[9]
2. 智能机的流量通信与工作站和浏览器的流量分析有不同。[10]-[13]</p>
<p>流量分析方法
1. 工作站上传统的流量分析方法。</p>
<p>智能机流量分析的方法
NetProfiler,使用一种UI Fuzzing的方法来模拟在一个APP上的操作,并同时记录log和流量。他们分析的是Payload。[20]
提出了一种利用设备产生的特殊流量模式识别整个设备的框架。训练时间长。[21]
提出了一种能够从加密的802.11帧中识别智能机APP的系统。但是系统测试样本小,长时间训练反而会产生副作用。[22]
they have no way to collect accurate ground truth, i.e., a labelled dataset that is free of noise from other apps.
!!!虽然本系统声称“Indeed, our methodology minimises noise by running a single app at a time, and we still had to filter 13% of the traffic collected because it was background traffic from other apps.”,他们始终无法保证app的流量的纯洁性。</p>
<hr>
<h3 id="toc_23">AntMonitor: A System for Monitoring from Mobile Devices</h3>
<p>时间:August 17 - 17, 2015<br>
发表于:C2B(1)D '15 Proceedings of the 2015 ACM SIGCOMM Workshop on Crowdsourcing and Crowdsharing of Big (Internet) Data</p>
<p>AntMonitor - Android设备上被动流量分析的系统。
给用户对监控数据的选择权<br>
不需要root<br>
支持客户端流量分析<br>
支持大量的、细粒度的、富含语义的流量收集。</p>
<p>能够支撑以下几个研究方面:
1. 从边缘进行网络测量
2. 移动流量分析
3. 隐私泄露检测和一些其他的可疑行为</p>
<p>介绍<br>
大规模上<br>
细粒度上<br>
对用户的吸引性上 </p>
<hr>
<h3 id="toc_24">PrivacyGuard: A VPN-based Platform to Detect Information Leakage on Android Devices</h3>
<p>时间:October 12 - 12, 2015<br>
发表于:SPSM '15 Proceedings of the 5th Annual ACM CCS Workshop on Security and Privacy in Smartphones and Mobile Devices
Pages 15-26 </p>
</body>
</html>