-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
2131 lines (1575 loc) · 436 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="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.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="/lib/font-awesome/css/font-awesome.min.css">
<script id="hexo-configurations">
var NexT = window.NexT || {};
var CONFIG = {"hostname":"yoursite.com","root":"/","scheme":"Gemini","version":"7.7.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":false,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"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"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
</script>
<meta name="description" content="分享一些bin学习日常">
<meta property="og:type" content="website">
<meta property="og:title" content="Coldshield's blog">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Coldshield's blog">
<meta property="og:description" content="分享一些bin学习日常">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Coldshield">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="http://yoursite.com/">
<script id="page-configurations">
// https://hexo.io/docs/variables.html
CONFIG.page = {
sidebar: "",
isHome : true,
isPost : false
};
</script>
<title>Coldshield's blog</title>
<noscript>
<style>
.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-header { opacity: initial; }
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion .logo-line-before i { left: initial; }
.use-motion .logo-line-after i { right: initial; }
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="container use-motion">
<div class="headband"></div>
<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="Toggle navigation bar">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
</div>
<div class="site-meta">
<div>
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">Coldshield's blog</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">Mostly PWN & RE</p>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
<i class="fa fa-search fa-fw fa-lg"></i>
</div>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section"><i class="fa fa-fw fa-home"></i>Home</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>About</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>Tags</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>Archives</a>
</li>
<li class="menu-item menu-item-links">
<a href="/links/" rel="section"><i class="fa fa-fw fa-link"></i>友链</a>
</li>
<li class="menu-item menu-item-search">
<a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>Search
</a>
</li>
</ul>
</nav>
<div class="site-search">
<div class="popup search-popup">
<div class="search-header">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<div class="search-input-container">
<input autocomplete="off" autocorrect="off" autocapitalize="off"
placeholder="Searching..." spellcheck="false"
type="search" class="search-input">
</div>
<span class="popup-btn-close">
<i class="fa fa-times-circle"></i>
</span>
</div>
<div id="search-result"></div>
</div>
<div class="search-pop-overlay"></div>
</div>
</div>
</header>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<main class="main">
<div class="main-inner">
<div class="content-wrap">
<div class="content">
<div class="posts-expand">
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/06/27/%E8%80%83%E7%A0%94%E7%BB%8F%E5%8E%86/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Coldshield">
<meta itemprop="description" content="分享一些bin学习日常">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Coldshield's blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2021/06/27/%E8%80%83%E7%A0%94%E7%BB%8F%E5%8E%86/" class="post-title-link" itemprop="url">考研经历</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-06-27 23:11:36" itemprop="dateCreated datePublished" datetime="2021-06-27T23:11:36+08:00">2021-06-27</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">Edited on</span>
<time title="Modified: 2021-06-29 10:49:10" itemprop="dateModified" datetime="2021-06-29T10:49:10+08:00">2021-06-29</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-comment-o"></i>
</span>
<span class="post-meta-item-text">Valine: </span>
<a title="valine" href="/2021/06/27/%E8%80%83%E7%A0%94%E7%BB%8F%E5%8E%86/#valine-comments" itemprop="discussionUrl">
<span class="post-comments-count valine-comment-count" data-xid="/2021/06/27/%E8%80%83%E7%A0%94%E7%BB%8F%E5%8E%86/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="考研经历(复旦大学计算机学院电子信息)"><a href="#考研经历(复旦大学计算机学院电子信息)" class="headerlink" title="考研经历(复旦大学计算机学院电子信息)"></a>考研经历(复旦大学计算机学院电子信息)</h1><blockquote>
<p>总算是毕业了,考研经验贴一直在拖拖拖,总算在六月底的某个夜里心血来潮来给学弟学妹们分享一些个人的考研经验了。之所以选择这个时间点,没有选择3 4月份复试完直接写,一方面是因为之前太懒了…抱歉hhhh;还有一方面是我觉得前期的那些准备工作网上都铺天盖地的,没必要把别人都总结好的东西再拿来干嚼一遍,我个人前期备考也基本是参考网文。</p>
</blockquote>
<h1 id="考研成绩"><a href="#考研成绩" class="headerlink" title="考研成绩"></a>考研成绩</h1><img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/psc" alt="img" style="zoom: 50%;">
<p>确实是靠数学和专业课撑起来的,去年疫情+暑期不能回校真的各种考验心态和时间规划,我个人9月前都是一直在家备考,受各种因素影响在政治和英语的投入很少,分数理所应当的低…..少到什么程度呢…..大概就是英语这方面我只有前期听课的单词基础和语法基础,然后政治我是从十月十一月开始准备的,所以建议你们最好暑假就开始刷一刷政治课,然后英语不要间断阅读训练和单词积累。</p>
<p>复试成绩高大概是因为本科做的事情(比如打CTF)还有毕设(Fuzzing相关)和那边的研究方向比较match,所以我现在(6月)就已经开始接触那边的论文和项目代码了,而且当时自己答的也还行,虽然情绪上有些紧张啥的,但提问就只是提问,只要能正常交流而且问题答上来就好了。</p>
<h2 id="初试(总成绩50-)"><a href="#初试(总成绩50-)" class="headerlink" title="初试(总成绩50%)"></a>初试(总成绩50%)</h2><blockquote>
<p>初试经验写在这你们看看就行,这些网上应该也是很多的,有些东西就是赘述了</p>
</blockquote>
<h3 id="数学"><a href="#数学" class="headerlink" title="数学"></a>数学</h3><p>分数:142</p>
<p>不夸张的讲,感觉今年数学二相对来说确实简单,拿到考卷的感觉就是很舒服,基础知识扎实的话会觉得没啥刁钻题,考的知识点也是平时上课笔记里都有的,当时考场上写的比平时要慢也剩了差不多半小时吧,写的慢是因为我希望简单不丢分。但是虽然这么说….填空题有一题计算的时候把π/2的倒数2/π脑抽地写了个2π,就还是丢了5分,然后剩下的两分是因为漏了一个点 漏了一个渐近线,所以做数学题细心还是很重要的,平时练题也不要懒计算量,该算就算。</p>
<p>要说分享什么经验的话,其实大佬网友们的经验应该都很全了,我的能作为补充就补充吧…</p>
<p>我高数是跟的汤家凤的基础课+强化课,他的1800我在前期写了数一的基础部分(当时不确定自己是考数一还是数二),后来因为408的内容太多我感觉写不完就没写了,本来确定考复旦后想换数二的1800写写高数强化,结果买来放那快递袋子都没拆,疫情+暑期+生产实习结束后在学校真就狂肝408去了,时间太紧只能自己balance。然后线代是跟的李永乐,也是因为时间紧,没来得及刷题,这俩主要就是靠我9月生产实习结束后实打实刷了高数讲义(汤)和线代讲义(李)而且做了很多题型笔记,各种体会考点+学习做题方法然后记下来。十一月底开始写真题写模拟卷,就是每见到一个题目就想这个题在考什么,能不能对应讲义上的题目类型,自己记不记得怎么解,笔记上有没有,如果记忆中没有这个知识点那就查漏补缺,这样刷下来一套卷子就是有价值的,然后整理这些卷子的错题还有各种解题方法,千万不能跳过自己不熟不会的地方(包括自己不熟悉的解题方法,特别是真题上的),写卷子跳过自己的弱点就是在浪费卷子+想不开,因为你不知道这些东西会不会在考试的时候碰到。还有计算量也要注意,暑期还有时间可以多练练,这些年真题给我的感觉就是计算量慢慢开始增大了。</p>
<p>emmm所以总的来说应该就是多记多见多算吧,还有基础知识的掌握是非常重要的,等你们写真题写到今年(2021)数二填空题最后一题就知道了,基础知识扎实的话可以秒杀,基础知识不扎实的就会干瞪眼算到头大。</p>
<h3 id="专业课"><a href="#专业课" class="headerlink" title="专业课"></a>专业课</h3><p>分数:123</p>
<blockquote>
<p>ps: 408真的很多,一定要给足时间投入</p>
</blockquote>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210627005807825.png" alt="image-20210627005807825" style="zoom: 33%;">
<p>这是去年复习408的时候发的签名,杀疯了哈哈哈哈。我最开始复习408应该是5,6月的样子吧,但是在家的时候5,6月真的各种心烦意乱,考试大作业报告什么的间断我一下就很难受,完全不能按照自己的理想计划来,所以一直到7月底我才复习完数据结构,就是刷完王道的那一整本书,然后八月复习完操作系统,9月一边生产实习一边复习计组,到10月初复习完计组又开始啃计网,然后十月底结束408的第一大轮复习。也就是说我从5月~10月才结束408的第一轮,不过我的第二轮复习只用了一个月,整个十一月我真的就是每天拿4~5个小时出来,抱着王道的四本书不停的抄、记,平均一周一本书(300多面),因为第二轮不用再完整的做题了,只用回顾错题,所以只是专注知识点复习的话就很快,肝起来就像期末考试一样的一直刷一直记。这四门课很大程度上还是啃了大二大三的老本,除了操作系统生疏一些(因为操作系统有很多概念和定义性的东西),计组计网我都算复习的比较快了。</p>
<p>感觉复习专业课知识就是反复地在理解的基础上记忆,然后自己画知识导图,每一门大课,每一章,我都有画过对应的知识导图。而且平时自己用到专业课知识也算比较频繁,认真看一看就很容易理解,关键在于记忆,看后面忘前面的感觉在后期真的会把人逼疯,列知识导图很重要,而且一般复习轮数推荐在两轮以上,这样配合知识导图会记得比较牢。</p>
<p>刷起真题来就是把知识运用到写题里然后查漏补缺,和数学一样,只要是印象中没有或者忘了的东西,全都要自己重新记一遍,然后把自己的易错点整理下来,如果存在理解性错误就赶紧重视。(这里有个小插曲哈哈哈哈哈,当时刷完近十几年的408真题之后,我用一张A4大小的纸整理了一整页的易错点还有查漏补缺的内容,考前半周的时候刷了一次,本来准备考前那个晚上再认真看一看的,结果发现它掉….掉….了…,虽然最后应该没有因为这张纸上面的知识点丢分,毕竟大部分是自己记忆下来了。所以你们要是用纸整理知识点什么的千万别弄丢,越到后期这种时间越宝贵,别因为丢了东西要重新花时间整理)</p>
<blockquote>
<p>补充:408真题和数学真题一样建议从后往前做,尽量保证选择题的正确率,考场上大概会有10分左右的东西在当年的王道资料上是没有的,如果碰到这种题不要慌,不会做先跳过就好了</p>
</blockquote>
<h3 id="英语-amp-政治"><a href="#英语-amp-政治" class="headerlink" title="英语&政治"></a>英语&政治</h3><p>保命分数没啥参考价值…..不过英语我倒是一直有听TED,然后扇贝阅读打卡。12月还报了一次六级,提前习惯了一下考试氛围,最后考了490多吧,比第一次六级高了60分,所以感觉坚持阅读和保持语感还是有用的。政治只能说肖秀荣牛逼,但是想拿高一点分数你自己还是得有话写,上海压不压分我不知道,但是我选择题34分的话,也就是说主观题我照着肖4写满了也只有27分,推荐不要学我只靠肖四肖八保命…..还是要好好听政治课的!</p>
<h2 id="复试(总成绩50-)"><a href="#复试(总成绩50-)" class="headerlink" title="复试(总成绩50%)"></a>复试(总成绩50%)</h2><p>复旦的复试分英语口语还有编程摸底、专业面试(英语口语10%,编程摸底40%,专业面试50%),而且今年也是线上复试,在专业面试之前会让你填一遍志愿,计算机学院这边AI和大数据组招的名额会特别多,可能招300人的话这两个方向就有200个人,当然也很卷。我报的系统软件与安全实验室这边只有16个名额,相对来说少很多,但大家的初试分数会更能让人接受一些,当然复旦主要还是看复试分数啦~(想想今年435的复试被刷了就知道什么水平了…..)</p>
<h3 id="英语口语"><a href="#英语口语" class="headerlink" title="英语口语"></a>英语口语</h3><p>时长5分钟,我硬刚了,准备的不是很多,只把408中的一些专业课知识的英文陈述背了背,语言组织就啃着我听TED的老本……</p>
<p>上来会有一段自我介绍,一分半钟左右,老师会根据你自我介绍中的信息进行提问,所以千万别给自己挖坑</p>
<p>我被问到的问题三个,但我第一个问题实在是听不清楚…….也不知道是我对那几个单词太生疏了还是老师麦糊听不清,大概就是说我提到manage myself然后啥啥啥的,说了几遍Sorry, I can’t hear clearly老师就跳过了……..当时根本顾不上紧张就换了一个…助理学生?和我对话,这个人离麦比较近所以听的清楚一点。然后就问了我dream job,好家伙,bin方向辣鸡CTFer的dream job那可是再熟悉不过了,当然是各种安全实验室,这里我说的还是挺多的,之后因为我自我介绍提到了比赛,所以问了问我得过什么奖就结束了。比网上某老哥被问到TCP/IP啥的要友好很多,自己基本还是会答,也有可能是因为老师看到我英语分数太低了不好意思问难(</p>
<h3 id="编程摸底"><a href="#编程摸底" class="headerlink" title="编程摸底"></a>编程摸底</h3><p>记得当时是时长3小时好像,这个刷题多刷就好,多刷多见识,考完初试自我感觉不错的话年过完了就开始刷吧,虽然我是主要按PAT甲准备的,刷了一百题左右的PAT还有寒假刷的二十几道leetcode上的动态规划,但是复旦这次考的全是leetcode上的原题(70 494 1448),所以机试还是得多刷一些leetcode,特别是PAT好像没啥动态规划,但是动态规划复旦每年都考,一定要记得刷一下动态规划的专题</p>
<h3 id="专业面试"><a href="#专业面试" class="headerlink" title="专业面试"></a>专业面试</h3><p>时长15分钟,先过心理关,不要太紧张,一群人围着你的时候该说什么说什么,也不要给自己挖坑,老师会顺着你说的话疯狂追问你,最好找一个有考研面试经验或者已经工作的学长学姐给你模拟面试一次,提前熟悉这个氛围后会好一些。</p>
<p>首先你的机试是必问的,记得考完机试去看看写出来的题还有没有更优解,没写出来的题怎么写。</p>
<p>毕设、项目、竞赛这种东西肯定也会问的,要不然就没啥好聊的了,所以推荐早点把毕设思路想明白,年底毕设选题的时候想清楚自己要做什么,如果有自己的小创新小优化就很好,不管是电话面试还是正式的专业面试都会有不错的印象。如果可以,尽量让自己做的东西和对方的研究方向match上,可以去看看他们发了什么论文,在做什么之类的。</p>
<p>至于面试加压,怎么说呢,保证自己态度要好,虚心接受,但是也别一被怼就怂成馒头弹不起来了,记得适当跟老师解释说明但也不要表现的很强硬,心平气和的交流很重要,就算你觉得老师误解了你的意思,你也一定要说明清楚,别含含糊糊的。</p>
<blockquote>
<p>补充:专业面试开始时也会有一个自我介绍,把本科做的事情大致说一说,别挖坑,因为老师会疯狂追问你。</p>
</blockquote>
<h2 id="电话面试"><a href="#电话面试" class="headerlink" title="电话面试"></a>电话面试</h2><p>这个是分数出来之后,看一看复试群里面的大致排名,觉得有希望就可以去联系老师了,老师会对你本科做的事情还有学习态度、学习能力创新能力之类的做一个估算,通过提问不断了解你,聊的东西可能比专业面试还要多,我当时和老师聊了差不多半小时的样子hhhh,聊完感觉挺好的。</p>
<p>然后是一些之前在学校被问到的东西,经典Q&A环节:</p>
<h1 id="Q-amp-A"><a href="#Q-amp-A" class="headerlink" title="Q&A"></a>Q&A</h1><h2 id="1-当初是什么让你在就业和考研中选择了考研?你是如何看待这两个选择的。"><a href="#1-当初是什么让你在就业和考研中选择了考研?你是如何看待这两个选择的。" class="headerlink" title="1.当初是什么让你在就业和考研中选择了考研?你是如何看待这两个选择的。"></a>1.当初是什么让你在就业和考研中选择了考研?你是如何看待这两个选择的。</h2><p>在大学刚入学那会就有读研的想法了,当年单纯是觉得这个机会能弥补高考的遗憾。再后来,自己在专业相关的比赛和冬夏令营结识了很多外校的朋友(包括已经工作的还有在读研的),从他们那了解到了一些院校、公司的情况和差别,感觉学术研究氛围更吸引我,所以在考研和就业之间决定了考研。</p>
<p>对于我个人的话,读研,在学术氛围里我能更好保持对专业知识的求知欲;直接进入社会工作,相对来说在知识层面就显得没那么专一。当然这两个选择要视自己实际情况而定,比如有的人就对研究不感冒,更偏爱实际生产中的体验和收获。当然读研也是一个能让我以后有更多选择余地的事情。</p>
<h2 id="2-在考研当中,学长认为什么是最重要的?如心态、计划等。"><a href="#2-在考研当中,学长认为什么是最重要的?如心态、计划等。" class="headerlink" title="2.在考研当中,学长认为什么是最重要的?如心态、计划等。"></a>2.在考研当中,学长认为什么是最重要的?如心态、计划等。</h2><p>个人认为心态比计划重要很多。如果执行能力没有那么强,或者说你定的计划太多太完美——想的太好,结果执行不能”落地”,那么这时候心态的重要性就凸显出来了。如果是真心想考研,面对一次又一次的计划落空,一次又一次的进度落后,你会怎么想?是继续严格执行计划,把自己的能动性逼出来;还是说根据实际情况,重新对自己的能力做出评价,换个目标?……</p>
<p>考研路上既有把厕所时间都安排到定点的人,也有不定确切计划走一步看一步的人,但这些都不是他们能否考高分的决定因素,决定最后考试能否考高分,就是面对考题时:会、记得、不写错。</p>
<p>个人觉得,保持”我要学会”的心态很重要,有一个好心态之后动态地安排学习计划,比如前一次执行效果不好,就反思后再重新安排。不管每轮或每月的学习计划执行的是否满意、最后冲刺阶段是否紧张,只要是面对知识,就在”我要学会”的驱动下质问自己会不会,之后为了掌握知识,你就学会了慢慢做出适合自己的计划调整。</p>
<h2 id="3-学长是如何为自己的考研做准备的,应该怎样安排考研复习计划比较好,怎样平衡竞赛与课业任务的?有什么妙招吗?"><a href="#3-学长是如何为自己的考研做准备的,应该怎样安排考研复习计划比较好,怎样平衡竞赛与课业任务的?有什么妙招吗?" class="headerlink" title="3.学长是如何为自己的考研做准备的,应该怎样安排考研复习计划比较好,怎样平衡竞赛与课业任务的?有什么妙招吗?"></a>3.学长是如何为自己的考研做准备的,应该怎样安排考研复习计划比较好,怎样平衡竞赛与课业任务的?有什么妙招吗?</h2><p>开始的时候首先了解院校、专业、科目、报录比之类的信息,这些在外面的各种考研平台都有,不必在这里细说。之后根据考试科目安排一个大致的复习框架和复习轮数之类的,当然这里也可以参考各大平台的上岸经验贴,科目经验网上到处都是,个人感觉没必要赘述(srds,6月写经验的时候还是写了哈哈哈哈哈),这些我很多也是照着网上的经验贴来的,然后按我前面说的,自己调整就可以了。</p>
<p>竞赛的话得看个人水平和科目掌握情况,如果自身能力比较强,考试科目掌握情况也比较好,想接着在竞赛上打出成绩,就视自己的精力参加(比如复旦那边上岸的好像就有经常打比赛做项目,最后复习三四个月400多分的人)。如果是本来就没有打过比赛,想趁着考研的学习劲头两手一起抓,好让自己在复试能有东西说,那么我的建议是尽量别。以我个人为参考,去年五六月份感觉自己缺少项目经验,想做个项目,结果在期末考试和复习的干扰之下根本没有那么多心思来管项目的东西,之后进入考研黄金期,就更难抽出心思来了。如果是真想复试有东西可以和老师聊,建议可以把毕设当成项目做,做出自己的小创新。</p>
<p>课业肯定要好好学。这个没啥好说的,根据大一二三的经验应该知道怎么做了,只不过是课业之后花更多时间备考。</p>
<h2 id="4-考研是一个持久战,你曾有没有动摇过,是什么让你坚持不懈一直走下去的?"><a href="#4-考研是一个持久战,你曾有没有动摇过,是什么让你坚持不懈一直走下去的?" class="headerlink" title="4.考研是一个持久战,你曾有没有动摇过,是什么让你坚持不懈一直走下去的?"></a>4.考研是一个持久战,你曾有没有动摇过,是什么让你坚持不懈一直走下去的?</h2><p>初期动摇还是挺普遍的,只是多少问题。面对突然的选择、面对两点一线(甚至疫情在家是床和桌子的两点一线)、面对高压的学习氛围、面对全精力的投入代价,对比起大一二相对来说舒服一些学习环境,肯定会觉得很难,怀疑自己是不是找实习会更好。</p>
<p>后来辛苦备考的时候,朋友圈一会是xxx在xx厂入职,一会是xxx在xx厂办的比赛中拿奖、拿到绿色直通,还有最后9、10月份的各种保研截图(特别是冬令营的队友保了北大….),都让我一度”怀疑人生”。</p>
<p>最后明确考研目标,首先是承认了自己的缺点,承认了自己学习、比赛上确实不如校外的朋友们,没能像他们一样把GPA拿的很高等等,既然我是羡慕他们的经历、而且想读研,那么当时的情境下就只能就靠考研这条路来突破,只能在这件事上”做更多功”,想不到别的办法。后期结合我之前提到的,带着”我要学会”的心态,就专注于能让我学会知识,拿到分的办法去了,在考场上面对考题都只是一直在问自己:”这题在考什么,我会不会”,而没有像当年高考一样想着”考不上怎么办,考的不好怎么办”。</p>
<p>我觉得当时那个情境配合自己的心态是我能坚持下来的一个核心原因。</p>
<h2 id="5-考研要注意哪些事情"><a href="#5-考研要注意哪些事情" class="headerlink" title="5.考研要注意哪些事情"></a>5.考研要注意哪些事情</h2><p>分条列举一部分吧,这个问题太宽泛了</p>
<p>生活上</p>
<ul>
<li>注意劳逸结合,让自己学习的时候精力充沛。比如作息这种,考研阶段每个人都不太一样,只能靠自己慢慢体会,调整。</li>
<li>娱乐时间不要太长。比如一下好多天不学,这样很容易让自己把刚学的知识忘掉,也比较难再进入状态。到了复习后期,个人建议是最多一周内选择一天的早+午或者午+晚休息</li>
<li>多吃点,吃好点。专注复习消耗大</li>
<li>让室友尽量配合。比如晚上不要打游戏</li>
<li>小心那些不理解你考研的朋友。</li>
<li>结不结伴考研要视自己性格还有朋友性格而定。我基本是全程一个人准备的,除了有问题要问同学以外。</li>
</ul>
<p>学习上首先保持好心态,列计划后学会调整,重复记忆很重要,”学会”最大。其他好像没啥好说的,网上经验贴这块应该是共通的….</p>
<p>感情上(如果有的话),需要两个人好好商量一下,毕竟是关系你们各自未来的事情。自己要提醒自己即使在感情最坏的情况下也不要影响考研,因为感情问题在考研上崴脚的人真的太多了。</p>
<p>工作考研以及二战啥的就不知道了….自己也没经历过</p>
<h2 id="6-考研期间有没有发生令你印象很深刻的事,或者受到谁给予的很大鼓励与帮助?如果有可以简要谈一谈,以及自己对此的感想吗?"><a href="#6-考研期间有没有发生令你印象很深刻的事,或者受到谁给予的很大鼓励与帮助?如果有可以简要谈一谈,以及自己对此的感想吗?" class="headerlink" title="6.考研期间有没有发生令你印象很深刻的事,或者受到谁给予的很大鼓励与帮助?如果有可以简要谈一谈,以及自己对此的感想吗?"></a>6.考研期间有没有发生令你印象很深刻的事,或者受到谁给予的很大鼓励与帮助?如果有可以简要谈一谈,以及自己对此的感想吗?</h2><p>印象很深刻的事,疫情就算一个,对此的感想只想说人要保持乐观,当初对于疫情考研这件事,有的人觉得疫情在家肯定复习不好,有的人会觉得疫情创造的环境是个机会。</p>
<p>还有我冬令营的北航研究生班助给予了我很多鼓励和帮助,真的很感谢他,暑假有一次在家情绪特别低落,特地找他从我的高考聊到考研,听我倾诉完之后他跟我说:”要多肯定自己”。因为人对他人的反馈是很敏感的,自我暗示也一样,对于成果和收获要及时给自己加之正反馈,这样在学的时候就能更有信心。</p>
<h2 id="7-学长对想要考研的学弟学妹们有什么建议?能说一声自己的经验吗?"><a href="#7-学长对想要考研的学弟学妹们有什么建议?能说一声自己的经验吗?" class="headerlink" title="7.学长对想要考研的学弟学妹们有什么建议?能说一声自己的经验吗?"></a>7.学长对想要考研的学弟学妹们有什么建议?能说一声自己的经验吗?</h2><p>上面该说的经验我都说的差不多了,多提一嘴的东西就是重复记忆,要记得学的时候把学到的东西都用笔记下来,还有错过的题目也是,考研毕竟是一个长期过程,才学到的东西说不定过一两个月就忘了,遗忘速度是很快的。</p>
<p>希望考研这个经历带给你们的不只是考研本身,而是在人生层面能带给你们成长,往后走能完完全全准备好的事会越来越少,大家都是第一次,只要不懈怠,在最后无论什么结果都会好受一些,加油!</p>
<h1 id="Others"><a href="#Others" class="headerlink" title="Others"></a>Others</h1><p>然后推荐一个我特别特别特别特别喜欢的经验贴,简直是我前期动摇时候的强心剂,真的很喜欢,我巴不得全文引用hhhhhh</p>
<blockquote>
<p><a href="https://zhuanlan.zhihu.com/p/26254149" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/26254149</a></p>
</blockquote>
<p>再晒一下6.27号到的录取通知书,给你们沾沾喜气~</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210627224747007.png" alt="image-20210627224747007" style="zoom:33%;">
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210627224821122.png" alt="image-20210627224821122" style="zoom: 25%;">
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210627224904232.png" alt="image-20210627224904232" style="zoom:24%;">
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/04/07/pwnable-kr%E2%80%94%E2%80%94shellshock/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Coldshield">
<meta itemprop="description" content="分享一些bin学习日常">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Coldshield's blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2021/04/07/pwnable-kr%E2%80%94%E2%80%94shellshock/" class="post-title-link" itemprop="url">pwnable.kr——shellshock</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-04-07 23:35:35 / Modified: 23:36:21" itemprop="dateCreated datePublished" datetime="2021-04-07T23:35:35+08:00">2021-04-07</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-comment-o"></i>
</span>
<span class="post-meta-item-text">Valine: </span>
<a title="valine" href="/2021/04/07/pwnable-kr%E2%80%94%E2%80%94shellshock/#valine-comments" itemprop="discussionUrl">
<span class="post-comments-count valine-comment-count" data-xid="/2021/04/07/pwnable-kr%E2%80%94%E2%80%94shellshock/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="pwnable-kr-——-shellshock"><a href="#pwnable-kr-——-shellshock" class="headerlink" title="pwnable.kr —— shellshock"></a>pwnable.kr —— shellshock</h1><p>题目有这样一串代码(shellshock.c)</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></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="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> setresuid(getegid(), getegid(), getegid());</span><br><span class="line"> setresgid(getegid(), getegid(), getegid());</span><br><span class="line"> system(<span class="string">"/home/shellshock/bash -c 'echo shock_me'"</span>);</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>因为有些知识记的不太清了这里就再复习一下euid,ruid,suid什么的</p>
<ul>
<li>ruid(real):用于在系统中标识用户,当用户成功登录一个UNIX系统后就唯一确定</li>
<li>euid(effective):用于系统决定用户对系统资源的访问权限,通常情况下等于ruid。当碰上程序属主设置了setuid位的时候,执行该程序会将euid改为文件属主</li>
</ul>
<p>gid同理,所以这里执行到system的时候已经有对应的组权限了(flag在对应组可读)</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210407125845099.png" alt="image-20210407125845099" style="zoom:80%;">
<p>然后就是构造触发shellshock漏洞的语句</p>
<p><a href="https://en.wikipedia.org/wiki/Shellshock_(software_bug)" target="_blank" rel="noopener">wiki上面有链接</a>,原理跟linux环境变量相关,bash中可以通过环境变量来导入function,此时的function也会当做普通环境变量来处理,具体就是<code>函数名='(){ ...; };'</code>,这样子的键值对,而在处理这个function变量的时候,有漏洞的bash版本只检查了前几个字符</p>
<p><code>STREQN ("() {", string, 4)</code></p>
<p>然后将整条字符串全部当做脚本代码处理了,本意应该是起子实例的时候,将这个函数的代码字符串直接跑到子实例bash中,供后续调用。但是这里并没有做语法检查或者结尾检查之类的,所以如果函数后面跟了命令也会被跑出来</p>
<p>所以利用流程就是export一个函数类型的环境变量,然后再起一个bash就会触发后续命令</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210407232747355.png" alt="image-20210407232747355" style="zoom:80%;">
<p>原理大致如下,再结合我们的程序代码,可以看到程序刚好用system起了一个bash,所以export我们的构造语句之后再跑程序就可以直接cat flag了</p>
<p>如图:</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210407233151874.png" alt="image-20210407233151874" style="zoom:80%;">
<p>好像后续有些版本export就会加前后缀什么的了,修复的方式这里不深究,以后需要再看</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/02/05/alf-fuzz-source-code-partly/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Coldshield">
<meta itemprop="description" content="分享一些bin学习日常">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Coldshield's blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2021/02/05/alf-fuzz-source-code-partly/" class="post-title-link" itemprop="url">alf-fuzz source code(partly)</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-02-05 16:29:23 / Modified: 22:14:45" itemprop="dateCreated datePublished" datetime="2021-02-05T16:29:23+08:00">2021-02-05</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-comment-o"></i>
</span>
<span class="post-meta-item-text">Valine: </span>
<a title="valine" href="/2021/02/05/alf-fuzz-source-code-partly/#valine-comments" itemprop="discussionUrl">
<span class="post-comments-count valine-comment-count" data-xid="/2021/02/05/alf-fuzz-source-code-partly/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>照着<a href="https://xz.aliyun.com/t/4314" target="_blank" rel="noopener">这篇博客</a>先把fuzz的门入了</p>
<h1 id="AFL源码粗略分析笔记"><a href="#AFL源码粗略分析笔记" class="headerlink" title="AFL源码粗略分析笔记"></a>AFL源码粗略分析笔记</h1><p>我是从<a href="https://xz.aliyun.com/t/4628" target="_blank" rel="noopener">这篇</a>和<a href="https://www.anquanke.com/post/id/201760" target="_blank" rel="noopener">这篇</a>开始看的,具体概念这两篇文章也写的很清楚了,下面只是记一些粗略的笔记</p>
<h2 id="afl-gcc-c"><a href="#afl-gcc-c" class="headerlink" title="afl-gcc.c"></a>afl-gcc.c</h2><p>afl-gcc主要是gcc的一个封装(wrapper),main中主要执行这三个函数:</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">find_as(argv[<span class="number">0</span>]);</span><br><span class="line"></span><br><span class="line">edit_params(argc, argv);</span><br><span class="line"></span><br><span class="line">execvp(cc_params[<span class="number">0</span>], (<span class="keyword">char</span>**)cc_params);</span><br></pre></td></tr></table></figure>
<h3 id="find-as:"><a href="#find-as:" class="headerlink" title="find_as:"></a>find_as:</h3><p>这个函数的作用是找到对应的编译器</p>
<h3 id="edit-params:"><a href="#edit-params:" class="headerlink" title="edit_params:"></a>edit_params:</h3><p>主要是对编译参数做一些设置,用<code>-B</code>指定了编译汇编器等,主要是为了插桩</p>
<p><img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/20190330215605-8fcb26f2-52f3-1.png" alt="img"></p>
<h3 id="execvp:"><a href="#execvp:" class="headerlink" title="execvp:"></a>execvp:</h3><p>用处理之后的编译参数进行源码编译</p>
<h2 id="afl-as-c和afl-as-h"><a href="#afl-as-c和afl-as-h" class="headerlink" title="afl-as.c和afl-as.h"></a>afl-as.c和afl-as.h</h2><p>就是这里进行的插桩,可以看到编译出来的代码多了一些插入的东西,比如<code>__afl_maybe_log</code></p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210127135753497.png" alt="image-20210127135753497" style="zoom:50%;">
<p>afl-as.c中的关键函数<code>add_instrumentation</code>,使用fprintf将插桩用的代码插入,用来统计覆盖率,这里大致看一下插桩的逻辑</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><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><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ( !pass_thru && !skip_intel && !skip_app && !skip_csect <span class="comment">//这四个变量为1时跳过对应的插桩,具体看后面的分析</span></span><br><span class="line"> && instr_ok && instrument_next && <span class="built_in">line</span>[<span class="number">0</span>] == <span class="string">'\t'</span> && <span class="built_in">isalpha</span>(<span class="built_in">line</span>[<span class="number">1</span>])<span class="comment">//这里line[0]和isalpha应该是对应汇编文件的格式判断插入的位置,没有深入研究,instr_ok和instrument_next看后面的分析</span></span><br><span class="line"> ) </span><br><span class="line"> {</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fprintf</span>(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, R(MAP_SIZE));<span class="comment">//插桩写入输出文件,R(MAP_SIZE)的作用是提供一个随机数标识插桩点,在后面分析trampoline_fmt_32会写到</span></span><br><span class="line"> instrument_next = <span class="number">0</span>;</span><br><span class="line"> ins_lines++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fputs</span>(<span class="built_in">line</span>, outf);<span class="comment">//原来的代码再写入输出文件</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//....(一些代码)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"> All right, this is where the actual fun begins. For one, we only want to</span></span><br><span class="line"><span class="comment"> instrument the .text section. So, let's keep track of that in processed</span></span><br><span class="line"><span class="comment"> files - and let's set instr_ok accordingly. </span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">line</span>[<span class="number">0</span>] == <span class="string">'\t'</span> && <span class="built_in">line</span>[<span class="number">1</span>] == <span class="string">'.'</span>) <span class="comment">//这个if分值就和注释写的一样,为了只在代码段进行插入,自己不习惯太乱的代码格式就自己稍微改了改了排版</span></span><br><span class="line"> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* OpenBSD puts jump tables directly inline with the code, which is</span></span><br><span class="line"><span class="comment"> a bit annoying. They use a specific format of p2align directives</span></span><br><span class="line"><span class="comment"> around them, so we use that as a signal. */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!clang_mode && instr_ok && !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"p2align "</span>, <span class="number">8</span>) </span><br><span class="line"> && <span class="built_in">isdigit</span>(<span class="built_in">line</span>[<span class="number">10</span>]) && <span class="built_in">line</span>[<span class="number">11</span>] == <span class="string">'\n'</span>) skip_next_label = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"text\n"</span>, <span class="number">5</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"section\t.text"</span>, <span class="number">13</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"section\t__TEXT,__text"</span>, <span class="number">21</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"section __TEXT,__text"</span>, <span class="number">21</span>)</span><br><span class="line"> ) </span><br><span class="line"> {</span><br><span class="line"> instr_ok = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>; </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"section\t"</span>, <span class="number">8</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"section "</span>, <span class="number">8</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"bss\n"</span>, <span class="number">4</span>) ||</span><br><span class="line"> !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">2</span>, <span class="string">"data\n"</span>, <span class="number">5</span>)</span><br><span class="line"> ) </span><br><span class="line"> {</span><br><span class="line"> instr_ok = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Detect off-flavor assembly (rare, happens in gdb). When this is</span></span><br><span class="line"><span class="comment"> encountered, we set skip_csect until the opposite directive is</span></span><br><span class="line"><span class="comment"> seen, and we do not instrument. </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".code"</span>))<span class="comment">//这里可以看到skip_csect是检测.code格式设置的,比较少见</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".code32"</span>)) skip_csect = use_64bit;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".code64"</span>)) skip_csect = !use_64bit;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Detect syntax changes, as could happen with hand-written assembly.</span></span><br><span class="line"><span class="comment"> Skip Intel blocks, resume instrumentation when back to AT&T. */</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".intel_syntax"</span>)) skip_intel = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".att_syntax"</span>)) skip_intel = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Detect syntax changes, as could happen with hand-written assembly.</span></span><br><span class="line"><span class="comment"> Skip Intel blocks, resume instrumentation when back to AT&T. */</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".intel_syntax"</span>)) skip_intel = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">".att_syntax"</span>)) skip_intel = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">line</span>[<span class="number">0</span>] == <span class="string">'#'</span> || <span class="built_in">line</span>[<span class="number">1</span>] == <span class="string">'#'</span>) </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">"#APP"</span>)) skip_app = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">"#NO_APP"</span>)) skip_app = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="comment">//上面这三个写的比较清楚就不解释辽</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//....(一些代码)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"> Conditional branch instruction (jnz, etc). We append the instrumentation</span></span><br><span class="line"><span class="comment"> right after the branch (to instrument the not-taken path) and at the</span></span><br><span class="line"><span class="comment"> branch destination label (handled later on). </span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">line</span>[<span class="number">0</span>] == <span class="string">'\t'</span>) <span class="comment">//这里有个比较重要的分支,当指令不是jmp而是一些条件跳转指令时,会在条件跳转指令之后进行插桩,还有对应的目标地址处(在后面处理)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">line</span>[<span class="number">1</span>] == <span class="string">'j'</span> && <span class="built_in">line</span>[<span class="number">2</span>] != <span class="string">'m'</span> && R(<span class="number">100</span>) < inst_ratio) <span class="comment">//这个int_ratio暂时没管是干嘛的...</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">fprintf</span>(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, R(MAP_SIZE));</span><br><span class="line"> ins_lines++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">Label of some sort. This may be a branch destination, but we need to</span></span><br><span class="line"><span class="comment">tread carefully and account for several different formatting</span></span><br><span class="line"><span class="comment">conventions. 这里就是在打上了Label的地方进行插桩,可能是跳转指令的目的地址</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"> <span class="comment">/* Everybody else: .L<whatever>: */</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strstr</span>(<span class="built_in">line</span>, <span class="string">":"</span>))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">line</span>[<span class="number">0</span>] == <span class="string">'.'</span>)<span class="comment">//判断到是一个Label</span></span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* .L0: or LBB0_0: style jump destination 跳转Label*/</span></span><br><span class="line"> <span class="keyword">if</span> ((<span class="built_in">isdigit</span>(<span class="built_in">line</span>[<span class="number">2</span>]) || (clang_mode && !<span class="built_in">strncmp</span>(<span class="built_in">line</span> + <span class="number">1</span>, <span class="string">"LBB"</span>, <span class="number">3</span>))) && R(<span class="number">100</span>) < inst_ratio) </span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* An optimization is possible here by adding the code only if the</span></span><br><span class="line"><span class="comment"> label is mentioned in the code in contexts other than call / jmp.</span></span><br><span class="line"><span class="comment"> That said, this complicates the code by requiring two-pass</span></span><br><span class="line"><span class="comment"> processing (messy with stdin), and results in a speed gain</span></span><br><span class="line"><span class="comment"> typically under 10%, because compilers are generally pretty good</span></span><br><span class="line"><span class="comment"> about not generating spurious intra-function jumps.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"> We use deferred output chiefly to avoid disrupting</span></span><br><span class="line"><span class="comment"> .Lfunc_begin0-style exception handling calculations (a problem on</span></span><br><span class="line"><span class="comment"> MacOS X). */</span></span><br><span class="line"> <span class="keyword">if</span> (!skip_next_label) instrument_next = <span class="number">1</span>; <span class="keyword">else</span> skip_next_label = <span class="number">0</span>;<span class="comment">//这里跟前面的那个标志也有关系</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* Function label (always instrumented, deferred mode). 函数Label*/</span></span><br><span class="line"> instrument_next = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"><span class="comment">//到这里大循环的插桩就结束了,之后还有补充的小块代码就不写了,主要就是这些:只在代码段插桩、在有函数Label(函数入口)和跳转Label处插桩,在条件条状指令之后插桩</span></span><br></pre></td></tr></table></figure>
<p>afl-as.h中就是具体的插桩代码,以32位为例来分析</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> u8* trampoline_fmt_32 =</span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">"/* --- AFL TRAMPOLINE (32-BIT) --- */\n"</span></span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">".align 4\n"</span></span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">"leal -16(%%esp), %%esp\n"</span></span><br><span class="line"> <span class="string">"movl %%edi, 0(%%esp)\n"</span></span><br><span class="line"> <span class="string">"movl %%edx, 4(%%esp)\n"</span></span><br><span class="line"> <span class="string">"movl %%ecx, 8(%%esp)\n"</span></span><br><span class="line"> <span class="string">"movl %%eax, 12(%%esp)\n"</span></span><br><span class="line"> <span class="string">"movl $0x%08x, %%ecx\n"</span> <span class="comment">//这里%08x就是前面fprintf中R(MAP_SIZE)的写入点,用作随机数标识</span></span><br><span class="line"> <span class="string">"call __afl_maybe_log\n"</span></span><br><span class="line"> <span class="string">"movl 12(%%esp), %%eax\n"</span></span><br><span class="line"> <span class="string">"movl 8(%%esp), %%ecx\n"</span></span><br><span class="line"> <span class="string">"movl 4(%%esp), %%edx\n"</span></span><br><span class="line"> <span class="string">"movl 0(%%esp), %%edi\n"</span></span><br><span class="line"> <span class="string">"leal 16(%%esp), %%esp\n"</span></span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">"/* --- END --- */\n"</span></span><br><span class="line"> <span class="string">"\n"</span>;</span><br></pre></td></tr></table></figure>
<p>payload根据实际效果删了一些宏定义啥的,看起来好看一点,emmm其实建议直接IDA反汇编看更好?….不过这里汇编有作者的注释帮着看,IDA反汇编图我在代码后面贴上了</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><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><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line">main_payload_32 = </span><br><span class="line"> <span class="string">"/* --- AFL MAIN PAYLOAD (32-BIT) --- */\n"</span></span><br><span class="line"> <span class="string">".text\n"</span></span><br><span class="line"> <span class="string">".att_syntax\n"</span></span><br><span class="line"> <span class="string">".code32\n"</span></span><br><span class="line"> <span class="string">".align 8\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_maybe_log:\n"</span></span><br><span class="line"> <span class="string">" lahf\n"</span> <span class="comment">//将EFLAGS 寄存器标志位加载到AH</span></span><br><span class="line"> <span class="string">" seto %al\n"</span> <span class="comment">//为溢出置位</span></span><br><span class="line"> </span><br><span class="line"> <span class="string">" /* Check if SHM region is already mapped. */\n"</span></span><br><span class="line"> <span class="string">" movl __afl_area_ptr, %edx\n"</span></span><br><span class="line"> <span class="string">" testl %edx, %edx\n"</span></span><br><span class="line"> <span class="string">" je __afl_setup\n"</span> <span class="comment">//检查共享内存指针是否到位</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_store:\n"</span></span><br><span class="line"> <span class="string">" /* Calculate and store hit for the code location specified in ecx. There\n"</span></span><br><span class="line"> <span class="string">" is a double-XOR way of doing this without tainting another register,\n"</span></span><br><span class="line"> <span class="string">" and we use it on 64-bit systems; but it's slower for 32-bit ones. */\n"</span></span><br><span class="line"> <span class="string">" movl __afl_prev_loc, %edi\n"</span></span><br><span class="line"> <span class="string">" xorl %ecx, %edi\n"</span></span><br><span class="line"> <span class="string">" shrl $1, %ecx\n"</span></span><br><span class="line"> <span class="string">" movl %ecx, __afl_prev_loc\n"</span></span><br><span class="line"> <span class="string">" incb (%edx, %edi, 1)\n"</span> <span class="comment">//根据随机数存储执行位置,算法在后文分析</span></span><br><span class="line"> The shared_mem[] <span class="built_in">array</span> is a <span class="number">64</span> kB SHM region passed to the instrumented binary</span><br><span class="line">by the caller. Every <span class="keyword">byte</span> <span class="built_in">set</span> in the output <span class="built_in">map</span> can be thought of as a hit <span class="keyword">for</span></span><br><span class="line">a particular (branch_src, branch_dst) tuple in the instrumented code.</span><br><span class="line"> </span><br><span class="line"> <span class="string">"__afl_return:\n"</span></span><br><span class="line"> <span class="string">" addb $127, %al\n"</span></span><br><span class="line"> <span class="string">" sahf\n"</span></span><br><span class="line"> <span class="string">" ret\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="string">".align 8\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_setup:\n"</span><span class="comment">//setup只会在最开始调用afl_maybe_log处触发,即main函数的最前面触发,主要是开启一个目标文件自己的fork循环用来记录执行路径(这个程序自己的fork循环就是forkserver)</span></span><br><span class="line"> <span class="string">" /* Do not retry setup if we had previous failures. */\n"</span></span><br><span class="line"> <span class="string">" cmpb $0, __afl_setup_failure\n"</span></span><br><span class="line"> <span class="string">" jne __afl_return\n"</span></span><br><span class="line"> <span class="string">" /* Map SHM, jumping to __afl_setup_abort if something goes wrong.\n"</span></span><br><span class="line"> <span class="string">" We do not save FPU/MMX/SSE registers here, but hopefully, nobody\n"</span></span><br><span class="line"> <span class="string">" will notice this early in the game. */\n"</span></span><br><span class="line"> <span class="string">" pushl %eax\n"</span></span><br><span class="line"> <span class="string">" pushl %ecx\n"</span></span><br><span class="line"> <span class="string">" pushl $.AFL_SHM_ENV\n"</span></span><br><span class="line"> <span class="string">" call getenv\n"</span></span><br><span class="line"> <span class="string">" addl $4, %esp\n"</span></span><br><span class="line"> <span class="string">" testl %eax, %eax\n"</span></span><br><span class="line"> <span class="string">" je __afl_setup_abort\n"</span></span><br><span class="line"> <span class="string">" pushl %eax\n"</span></span><br><span class="line"> <span class="string">" call atoi\n"</span></span><br><span class="line"> <span class="string">" addl $4, %esp\n"</span></span><br><span class="line"> <span class="string">" pushl $0 /* shmat flags */\n"</span></span><br><span class="line"> <span class="string">" pushl $0 /* requested addr */\n"</span></span><br><span class="line"> <span class="string">" pushl %eax /* SHM ID */\n"</span></span><br><span class="line"> <span class="string">" call shmat\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" cmpl $-1, %eax\n"</span></span><br><span class="line"> <span class="string">" je __afl_setup_abort\n"</span></span><br><span class="line"> <span class="string">" /* Store the address of the SHM region. */\n"</span></span><br><span class="line"> <span class="string">" movl %eax, __afl_area_ptr\n"</span></span><br><span class="line"> <span class="string">" movl %eax, %edx\n"</span></span><br><span class="line"> <span class="string">" popl %ecx\n"</span></span><br><span class="line"> <span class="string">" popl %eax\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_forkserver:\n"</span></span><br><span class="line"> <span class="string">" /* Enter the fork server mode to avoid the overhead of execve() calls. */\n"</span></span><br><span class="line"> <span class="string">" pushl %eax\n"</span></span><br><span class="line"> <span class="string">" pushl %ecx\n"</span></span><br><span class="line"> <span class="string">" pushl %edx\n"</span></span><br><span class="line"> <span class="string">" /* Phone home and tell the parent that we're OK. (Note that signals with\n"</span></span><br><span class="line"> <span class="string">" no SA_RESTART will mess it up). If this fails, assume that the fd is\n"</span></span><br><span class="line"> <span class="string">" closed because we were execve()d from an instrumented binary, or because\n"</span> </span><br><span class="line"> <span class="string">" the parent doesn't want to use the fork server. */\n"</span></span><br><span class="line"> <span class="string">" pushl $4 /* length */\n"</span></span><br><span class="line"> <span class="string">" pushl $__afl_temp /* data */\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">" /* file desc */\n"</span><span class="comment">//fork server向fuzzer传递执行状态码,199描述符(后面会说是什么)</span></span><br><span class="line"> <span class="string">" call write\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" cmpl $4, %eax\n"</span></span><br><span class="line"> <span class="string">" jne __afl_fork_resume\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_fork_wait_loop:\n"</span></span><br><span class="line"> <span class="string">" /* Wait for parent by reading from the pipe. Abort if read fails. */\n"</span></span><br><span class="line"> <span class="string">" pushl $4 /* length */\n"</span></span><br><span class="line"> <span class="string">" pushl $__afl_temp /* data */\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY(FORKSRV_FD) <span class="string">" /* file desc */\n"</span><span class="comment">//等待fuzzer传递命令,198描述符</span></span><br><span class="line"> <span class="string">" call read\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" cmpl $4, %eax\n"</span></span><br><span class="line"> <span class="string">" jne __afl_die\n"</span></span><br><span class="line"> <span class="string">" /* Once woken up, create a clone of our process. This is an excellent use"</span></span><br><span class="line"> <span class="string">" case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly"</span></span><br><span class="line"> <span class="string">" caches getpid() results and offers no way to update the value, breaking"</span></span><br><span class="line"> <span class="string">" abort(), raise(), and a bunch of other things :-( */\n"</span></span><br><span class="line"> <span class="string">" call fork\n"</span></span><br><span class="line"> <span class="string">" cmpl $0, %eax\n"</span></span><br><span class="line"> <span class="string">" jl __afl_die\n"</span></span><br><span class="line"> <span class="string">" je __afl_fork_resume\n"</span></span><br><span class="line"> <span class="string">" /* In parent process: write PID to pipe, then wait for child. */\n"</span></span><br><span class="line"> <span class="string">" movl %eax, __afl_fork_pid\n"</span></span><br><span class="line"> <span class="string">" pushl $4 /* length */\n"</span></span><br><span class="line"> <span class="string">" pushl $__afl_fork_pid /* data */\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">" /* file desc */\n"</span><span class="comment">//199描述符</span></span><br><span class="line"> <span class="string">" call write\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" pushl $0 /* no flags */\n"</span></span><br><span class="line"> <span class="string">" pushl $__afl_temp /* status */\n"</span></span><br><span class="line"> <span class="string">" pushl __afl_fork_pid /* PID */\n"</span></span><br><span class="line"> <span class="string">" call waitpid\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" cmpl $0, %eax\n"</span></span><br><span class="line"> <span class="string">" jle __afl_die\n"</span></span><br><span class="line"> <span class="string">" /* Relay wait status to pipe, then loop back. */\n"</span> <span class="comment">//wait statu指最开始那个进程等待到的 子进程返回来的 状态</span></span><br><span class="line"> <span class="string">" pushl $4 /* length */\n"</span></span><br><span class="line"> <span class="string">" pushl $__afl_temp /* data */\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">" /* file desc */\n"</span></span><br><span class="line"> <span class="string">" call write\n"</span></span><br><span class="line"> <span class="string">" addl $12, %esp\n"</span></span><br><span class="line"> <span class="string">" jmp __afl_fork_wait_loop\n"</span></span><br><span class="line"> </span><br><span class="line"> <span class="string">"__afl_fork_resume:\n"</span><span class="comment">//这里是每次forkserver fork出来的子进程都要执行的</span></span><br><span class="line"> <span class="string">" /* In child process: close fds, resume execution. */\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY(FORKSRV_FD) <span class="string">"\n"</span></span><br><span class="line"> <span class="string">" call close\n"</span></span><br><span class="line"> <span class="string">" pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">"\n"</span></span><br><span class="line"> <span class="string">" call close\n"</span></span><br><span class="line"> <span class="string">" addl $8, %esp\n"</span></span><br><span class="line"> <span class="string">" popl %edx\n"</span></span><br><span class="line"> <span class="string">" popl %ecx\n"</span></span><br><span class="line"> <span class="string">" popl %eax\n"</span></span><br><span class="line"> <span class="string">" jmp __afl_store\n"</span><span class="comment">//跳到前面的__afl_store</span></span><br><span class="line"></span><br><span class="line"> <span class="string">"__afl_die:\n"</span></span><br><span class="line"> <span class="string">" xorl %eax, %eax\n"</span></span><br><span class="line"> <span class="string">" call _exit\n"</span></span><br><span class="line"> </span><br><span class="line"> <span class="string">"__afl_setup_abort:\n"</span></span><br><span class="line"> <span class="string">" /* Record setup failure so that we don't keep calling\n"</span></span><br><span class="line"> <span class="string">" shmget() / shmat() over and over again. */\n"</span></span><br><span class="line"> <span class="string">" incb __afl_setup_failure\n"</span></span><br><span class="line"> <span class="string">" popl %ecx\n"</span></span><br><span class="line"> <span class="string">" popl %eax\n"</span></span><br><span class="line"> <span class="string">" jmp __afl_return\n"</span></span><br><span class="line"> </span><br><span class="line"> <span class="string">".AFL_VARS:\n"</span></span><br><span class="line"> <span class="string">" .comm __afl_area_ptr, 4, 32\n"</span></span><br><span class="line"> <span class="string">" .comm __afl_setup_failure, 1, 32\n"</span></span><br><span class="line"> <span class="string">" .comm __afl_prev_loc, 4, 32\n"</span></span><br><span class="line"> <span class="string">" .comm __afl_fork_pid, 4, 32\n"</span></span><br><span class="line"> <span class="string">" .comm __afl_temp, 4, 32\n"</span></span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">".AFL_SHM_ENV:\n"</span></span><br><span class="line"> <span class="string">" .asciz \""</span> SHM_ENV_VAR <span class="string">"\"\n"</span></span><br><span class="line"> <span class="string">"\n"</span></span><br><span class="line"> <span class="string">"/* --- END --- */\n"</span></span><br></pre></td></tr></table></figure>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210203133736042.png" alt="image-20210203133736042" style="zoom:80%;">
<h2 id="alloc-inl-c"><a href="#alloc-inl-c" class="headerlink" title="alloc-inl.c"></a>alloc-inl.c</h2><p>后面的代码中很多与内存相关的操作都是alloc-inl里面的,不缕一下的话不知所云…所以这里记录一下经常在afl-fuzz.c中看到的几个内存操作函数</p>
<p>作者原话:This allocator is not designed to resist malicious attackers (the canaries are small and predictable), but provides a robust and portable way to detect use-after-free, off-by-one writes, stale pointers, and so on.</p>
<p>里面的宏定义有一些类似:<code>__LINE__</code>,<code>__FUNCTION__</code>的,这是C编译器的内置宏,具体代表什么意思百度一下即可</p>
<ul>
<li><code>ALLOC_CHECK_SIZE(size)</code> malloc前检查size是否超过设置的最大chunk大小</li>
<li><code>ret = malloc(size + ALLOC_OFF_TOTAL);</code>经常出现的malloc方式,这里是<code>+ ALLOC_OFF_TOTAL</code>为了在chunk前8字节处存放一个4B的头部标志和size,还有一个1B的尾部标志</li>
<li><code>ALLOC_CHECK_RESULT(ret,size)</code> malloc后检查是否分配成功,若ret为NULL,这个size就会用于打印错误信息</li>
<li><code>TRK_ck_strdup</code>,(<strong>TRK</strong>开头 + ck + 一般函数名)的函数,主要进行如下两个操作<ul>
<li><code>void* ret = DFL_ck_strdup(str);</code>,(<strong>DFL</strong>开头)的函数就是正常的操作,比如这个<code>DFL_ck_strdup</code>就是用作者自己的一些逻辑+上面提到的三个主要步骤实现</li>
<li><code>TRK_alloc_buf(void* ret, const char* file, const char* func, u32 line)</code> ,将哪个文件、哪个函数、哪一行申请内存的信息用 哈希散列+链地址法 的方法存在了一个散列表中,主要为了后续的检查。带alloc的函数用来存放,带free的就是用来判断有没有错误之类的</li>
</ul>
</li>
<li></li>
</ul>
<h2 id="afl-fuzz-c"><a href="#afl-fuzz-c" class="headerlink" title="afl-fuzz.c"></a>afl-fuzz.c</h2><p>看完了插桩接下来就是看具体的fuzz逻辑了,这里大概有8000多行代码,慢慢缕吧</p>
<p>main函数前面的主逻辑就是一个处理输入参数的逻辑,里面还处理了一个non official参数 <code>-B</code>…这里是作者的注释,作用是指定bitmap,会影响<code>in_bitmap</code>这个全局变量</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* This is a secret undocumented option! It is useful if you find</span></span><br><span class="line"><span class="comment">an interesting test case during a normal fuzzing process, and want</span></span><br><span class="line"><span class="comment">to mutate it without rediscovering any of the test cases already</span></span><br><span class="line"><span class="comment">found during an earlier run.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">To use this mode, you need to point -B to the fuzz_bitmap produced</span></span><br><span class="line"><span class="comment">by an earlier run for the exact same binary... and that's it.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">I only used this once or twice to get variants of a particular</span></span><br><span class="line"><span class="comment">file, so I'm not making this an official setting. */</span></span><br></pre></td></tr></table></figure>
<p>处理完参数之后,首先 <code>setup_signal_handlers();check_asan_opts();</code>,设置一系列程序运行时的信号处理,比如超时如何处理,检查asan参数,然后还有一系列的设置和检查,具体还是看代码的7910行左右吧(2.52版本)</p>
<p>处理完参数之后就是一些操作</p>
<h3 id="main-part1"><a href="#main-part1" class="headerlink" title="main (part1)"></a>main (part1)</h3><p>因为函数属实有点多所以只记录了一些印象比较深的,建议想了解的话,每个函数点进去看看作者的注释说了什么,而且一些函数的作用在我前面开头提到的入门博客中有写,就不赘述了</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"> save_cmdline(argc, argv);<span class="comment">//保存当前命令</span></span><br><span class="line"> fix_up_banner(argv[optind]);<span class="comment">//跟运行时的标志有关系,显示一个运行示例的名字之类的,可以用-T指定这个banner</span></span><br><span class="line"> check_if_tty();</span><br><span class="line"> get_core_count();</span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> HAVE_AFFINITY</span></span><br><span class="line"> bind_to_free_cpu();</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* HAVE_AFFINITY */</span></span></span><br><span class="line"> check_crash_handling();</span><br><span class="line"> check_cpu_governor();</span><br><span class="line"> setup_post();</span><br><span class="line"> setup_shm();<span class="comment">//这一步为bitmap初始共享内存,供fuzzer分析、目标文件进行记录</span></span><br><span class="line"><span class="comment">//还初始化了virgin_bits(如果使用-B就不会),virgin_tmout,virgin_crash,内容均为0xFF</span></span><br><span class="line"> </span><br><span class="line"> init_count_class16();<span class="comment">//这里是为bitmap中的执行次数分类做准备</span></span><br><span class="line"> setup_dirs_fds();</span><br><span class="line"> read_testcases();</span><br><span class="line"> load_auto();</span><br><span class="line"> pivot_inputs();</span><br><span class="line"> <span class="keyword">if</span> (extras_dir) load_extras(extras_dir);</span><br><span class="line"> <span class="keyword">if</span> (!timeout_given) find_timeout();</span><br><span class="line"> detect_file_args(argv + optind + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (!out_file) setup_stdio_file();</span><br><span class="line"> check_binary(argv[optind]);</span><br><span class="line"> start_time = get_cur_time();</span><br><span class="line"> <span class="keyword">if</span> (qemu_mode)</span><br><span class="line"> use_argv = get_qemu_argv(argv[<span class="number">0</span>], argv + optind, argc - optind);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> use_argv = argv + optind;</span><br><span class="line"></span><br><span class="line"> perform_dry_run(use_argv);<span class="comment">//这个函数可以看看,主要是初始化forkserver后用我们提供的testcase进行初始测试,然后输出测试用例的一些结果信息</span></span><br><span class="line"><span class="comment">//里面子函数有很多关于fuzz细节相关的代码,建议研读</span></span><br></pre></td></tr></table></figure>
<h3 id="calibrate-case"><a href="#calibrate-case" class="headerlink" title="calibrate_case"></a>calibrate_case</h3><p><code>perform_dry_run</code>中主要就是这个函数用我们给的所有testcase对进行循环测试,<code>calibrate_case</code>第一次先调用<code>init_forkserver</code>将结构初始化(函数见下文),然后根据临时变量<code>stage</code>指定的次数,使用<code>run_target</code>进行循环测试(函数见下文),而且每次执行完都进行了一次<code>update_bitmap_score</code>(这个函数用于找到更快或者规模更小的用例来达到相同的效果),这里是循环体内的一部分代码</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">u32 cksum;<span class="comment">//这个变量在后面的hash会用到</span></span><br><span class="line"> <span class="keyword">if</span> (!first_run && !(stage_cur % stats_update_freq)) show_stats();<span class="comment">//这个是输出界面</span></span><br><span class="line">write_to_testcase(use_mem, q->len);<span class="comment">//输入测试用例的数据到一个临时文件,当做被测试文件的输入</span></span><br><span class="line"></span><br><span class="line"> fault = run_target(argv, use_tmout);<span class="comment">//fault是目标测试返回的错误类型</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* stop_soon is set by the handler for Ctrl+C. When it's pressed,</span></span><br><span class="line"><span class="comment"> we want to bail out quickly. */</span></span><br><span class="line"> <span class="keyword">if</span> (stop_soon || fault != crash_mode) <span class="keyword">goto</span> abort_calibration;<span class="comment">//如果不是crash(只记录crash的crash模式)</span></span><br><span class="line"></span><br><span class="line"> cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);<span class="comment">//对执行的trace bitmap做一次hash</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (q->exec_cksum != cksum)<span class="comment">//如果hash值发生变化,检测变化</span></span><br><span class="line"> {</span><br><span class="line"> u8 hnb = has_new_bits(virgin_bits);<span class="comment">//always 0,return 1 hit-count for a particular tuple,2 if new tuples(二元组是干什么的见官方文档吧,相当于执行路径,用bitmap记录的)</span></span><br><span class="line"> <span class="keyword">if</span> (hnb > new_bits) new_bits = hnb;</span><br><span class="line"> <span class="keyword">if</span> (q->exec_cksum)<span class="comment">//如果已经run过</span></span><br><span class="line"> {</span><br><span class="line"> u32 i;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < MAP_SIZE; i++) </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (!var_bytes[i] && first_trace[i] != trace_bits[i])<span class="comment">//用var_bytes记录执行变化了的位置</span></span><br><span class="line"> {</span><br><span class="line"> var_bytes[i] = <span class="number">1</span>;</span><br><span class="line"> stage_max = CAL_CYCLES_LONG;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> var_detected = <span class="number">1</span>;</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> q->exec_cksum = cksum;</span><br><span class="line"> <span class="built_in">memcpy</span>(first_trace, trace_bits, MAP_SIZE);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>循环体之后的代码,这里就针对<code>perform_dry_run</code>中单个测试用例的全部变化了,q就代表一个测试用例的结构体:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"> stop_us = get_cur_time_us();</span><br><span class="line"> total_cal_us += stop_us - start_us;<span class="comment">//统计时间用</span></span><br><span class="line"> total_cal_cycles += stage_max;</span><br><span class="line"> <span class="comment">/* OK, let's collect some stats about the performance of this test case.</span></span><br><span class="line"><span class="comment"> This is used for fuzzing air time calculations in calculate_score(). */</span></span><br><span class="line"> q->exec_us = (stop_us - start_us) / stage_max;<span class="comment">//每次执行的平均时间</span></span><br><span class="line"> q->bitmap_size = count_bytes(trace_bits);<span class="comment">//记录路径二元组的组数</span></span><br><span class="line"> q->handicap = handicap;</span><br><span class="line"> q->cal_failed = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> total_bitmap_size += q->bitmap_size;</span><br><span class="line"> total_bitmap_entries++;</span><br><span class="line"></span><br><span class="line"> update_bitmap_score(q);<span class="comment">//更新top_rated结构体</span></span><br><span class="line"> <span class="comment">//里面有一个minimize_bits函数,意思是设置一个只有0,1表示的是否有路径的minibitmap,相当于舍弃了原始bitmap的计数,只用一字节中的一位来表示</span></span><br><span class="line"> <span class="comment">/* If this case didn't result in new output from the instrumentation, tell</span></span><br><span class="line"><span class="comment"> parent. This is a non-critical problem, but something to warn the user</span></span><br><span class="line"><span class="comment"> about. */</span></span><br><span class="line"> <span class="keyword">if</span> (!dumb_mode && first_run && !fault && !new_bits) fault = FAULT_NOBITS;</span><br><span class="line"></span><br><span class="line">abort_calibration:</span><br><span class="line"> <span class="keyword">if</span> (new_bits == <span class="number">2</span> && !q->has_new_cov) </span><br><span class="line"> {</span><br><span class="line"> q->has_new_cov = <span class="number">1</span>;<span class="comment">//循环执行过程中路径发生过变化</span></span><br><span class="line"> queued_with_cov++;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/* Mark variable paths. 在循环中如有某次的trace变化了,对该测试用例进行记录*/</span></span><br><span class="line"> <span class="keyword">if</span> (var_detected) </span><br><span class="line"> {</span><br><span class="line"> var_byte_count = count_bytes(var_bytes);</span><br><span class="line"> <span class="keyword">if</span> (!q->var_behavior) </span><br><span class="line"> {</span><br><span class="line"> mark_as_variable(q);</span><br><span class="line"> queued_variable++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> stage_name = old_sn;</span><br><span class="line"> stage_cur = old_sc;</span><br><span class="line"> stage_max = old_sm;</span><br><span class="line"> <span class="keyword">if</span> (!first_run) show_stats();</span><br><span class="line"> <span class="keyword">return</span> fault;</span><br></pre></td></tr></table></figure>
<h3 id="init-forkserver"><a href="#init-forkserver" class="headerlink" title="init_forkserver"></a>init_forkserver</h3><p><code>calibrate_case</code>中的函数,<code>init_forkserver</code>的代码不难懂建议直接看,又因为比较长这里就不写太多了,主要就是打开了两个pipe(一个用于forkserver发送状态、一个用于fuzzer发送命令,管道描述符分别设置值为198和199,对应之前的<code>afl_maybe_log</code>)之后fork出一个fuzzer子进程并setsid,把子进程的stdout、stderr全关、做了一些设置之后用execv替换成目标文件的进程映象,正式成为供fuzzer控制的forkserver。对于这个结构师傅们给出了图,对应的操作点一边是前面的afl-as.h分析中可以看到,还有一边在fuzzer中的run_target函数(下文分析)</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210203145002.png" alt="image-20210203145001" style="zoom:80%;">
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210203145001.png" alt="QQ图片20210203145001" style="zoom:80%;">
<h3 id="run-target"><a href="#run-target" class="headerlink" title="run_target"></a>run_target</h3><p>这里截取了forkserver模式的部分代码用注释的方法分析</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Execute target application, monitoring for timeouts. Return status</span></span><br><span class="line"><span class="comment"> information. The called program will update trace_bits[]. */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> u8 <span class="title">run_target</span><span class="params">(<span class="keyword">char</span>** argv, u32 timeout)</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">it</span>;</span><span class="comment">//设置判断超时用</span></span><br><span class="line"> <span class="keyword">static</span> u32 prev_timed_out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> status = <span class="number">0</span>;</span><br><span class="line"> u32 tb4;</span><br><span class="line"> child_timed_out = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* After this memset, trace_bits[] are effectively volatile, so we</span></span><br><span class="line"><span class="comment"> must prevent any earlier operations from venturing into that</span></span><br><span class="line"><span class="comment"> territory. */</span></span><br><span class="line"> <span class="built_in">memset</span>(trace_bits, <span class="number">0</span>, MAP_SIZE);<span class="comment">//每次runtarget都会将bitmap置零</span></span><br><span class="line"> MEM_BARRIER();<span class="comment">//保护内存用</span></span><br><span class="line"> </span><br><span class="line"> s32 res;</span><br><span class="line"> <span class="comment">/* In non-dumb mode, we have the fork server up and running, so simply</span></span><br><span class="line"><span class="comment"> tell it to have at it, and then read back PID. */</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//下文的write和read是发送命令接收状态的具体位置</span></span><br><span class="line"> <span class="keyword">if</span> ((res = <span class="built_in">write</span>(fsrv_ctl_fd, &prev_timed_out, <span class="number">4</span>)) != <span class="number">4</span>) <span class="comment">//4B trigger forkserver,这里对应前面的hello message,正式启动,prev_time_out在这里是啥东西应该无所谓</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (stop_soon) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> RPFATAL(res, <span class="string">"Unable to request new process from fork server (OOM?)"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((res = <span class="built_in">read</span>(fsrv_st_fd, &child_pid, <span class="number">4</span>)) != <span class="number">4</span>) <span class="comment">//get the child's PID by the fork of forkserver</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (stop_soon) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> RPFATAL(res, <span class="string">"Unable to request new process from fork server (OOM?)"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (child_pid <= <span class="number">0</span>) FATAL(<span class="string">"Fork server is misbehaving (OOM?)"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Configure timeout, as requested by user, then wait for child to terminate. */</span></span><br><span class="line"> it.it_value.tv_sec = (timeout / <span class="number">1000</span>);</span><br><span class="line"> it.it_value.tv_usec = (timeout % <span class="number">1000</span>) * <span class="number">1000</span>;</span><br><span class="line"> setitimer(ITIMER_REAL, &it, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* The SIGALRM handler simply kills the child_pid and sets child_timed_out. */</span></span><br><span class="line"> s32 res;</span><br><span class="line"> <span class="keyword">if</span> ((res = <span class="built_in">read</span>(fsrv_st_fd, &status, <span class="number">4</span>)) != <span class="number">4</span>)<span class="comment">//这里调用read应该会阻塞,因为这个statu得等子进程退出或者出错啥的</span></span><br><span class="line"> <span class="comment">//此时forkserver还在waitpid,forkserver一旦接收到子进程的信号量就发statu到fuzzer这里</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (stop_soon) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> RPFATAL(res, <span class="string">"Unable to communicate with fork server (OOM?)"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!WIFSTOPPED(status)) child_pid = <span class="number">0</span>;<span class="comment">//已经停止了就将child_pid置零,防止在执行这几行代码时记录成time_out</span></span><br><span class="line"> it.it_value.tv_sec = <span class="number">0</span>;</span><br><span class="line"> it.it_value.tv_usec = <span class="number">0</span>;</span><br><span class="line"> setitimer(ITIMER_REAL, &it, <span class="literal">NULL</span>);<span class="comment">//这里都是0的话就是取消计时器</span></span><br><span class="line"></span><br><span class="line"> total_execs++;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Any subsequent operations on trace_bits must not be moved by the</span></span><br><span class="line"><span class="comment"> compiler below this point. Past this location, trace_bits[] behave</span></span><br><span class="line"><span class="comment"> very normally and do not have to be treated as volatile. */</span></span><br><span class="line"> MEM_BARRIER();</span><br><span class="line"></span><br><span class="line"> tb4 = *(u32*)trace_bits;</span><br><span class="line"></span><br><span class="line"> classify_counts((u32*)trace_bits);<span class="comment">//对trace_bits中的次数进行分类、重写</span></span><br><span class="line"> <span class="comment">//这里比较重要,第一次分析的时候没注意在run_target分类之后bitmap中每个字节只有9种状态,在前面calibrate_case里面有一个has_new_bits一直没看懂细节</span></span><br><span class="line"></span><br><span class="line"> prev_timed_out = child_timed_out;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*Report outcome to caller. 下面都是判断测试用例退出类型*/</span></span><br><span class="line"> <span class="keyword">if</span> (WIFSIGNALED(status) && !stop_soon) {</span><br><span class="line"> kill_signal = WTERMSIG(status);</span><br><span class="line"> <span class="keyword">if</span> (child_timed_out && kill_signal == SIGKILL) <span class="keyword">return</span> FAULT_TMOUT;</span><br><span class="line"> <span class="keyword">return</span> FAULT_CRASH;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and</span></span><br><span class="line"><span class="comment"> must use a special exit code. */</span></span><br><span class="line"> <span class="keyword">if</span> (uses_asan && WEXITSTATUS(status) == MSAN_ERROR)</span><br><span class="line"> {</span><br><span class="line"> kill_signal = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> FAULT_CRASH;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> FAULT_NONE;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="main-part2"><a href="#main-part2" class="headerlink" title="main(part2)"></a>main(part2)</h3><p>fuzzer的第二部分,部分删减,虽然说前面分析跑测试用例的部分已经把fuzzer原理缕了很多,但是这里开始才是变异的核心部分,有些可以参考sakura的<a href="https://www.anquanke.com/post/id/213432" target="_blank" rel="noopener">这篇文章</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><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"> cull_queue();<span class="comment">//用于精简提供的测试用例,算法在文章最开始提到的文章里面有写,是一个贪心策略,这里面的标记都是用的单个bit,用到了前面的minibitmap</span></span><br><span class="line"> show_init_stats();</span><br><span class="line"> seek_to = find_start_position();<span class="comment">//resume时用,正常状态为0</span></span><br><span class="line"></span><br><span class="line"> write_stats_file(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> save_auto();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (stop_soon) <span class="keyword">goto</span> stop_fuzzing;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> u8 skipped_fuzz;</span><br><span class="line"> cull_queue();</span><br><span class="line"> <span class="keyword">if</span> (!queue_cur) {<span class="comment">//queue_cur用来判断是否执行完一轮,当然初始进来的时候应该是默认为null</span></span><br><span class="line"> queue_cycle++;<span class="comment">//整个队列循环的次数</span></span><br><span class="line"> current_entry = <span class="number">0</span>;<span class="comment">//这个好像就是指第几个测试用例</span></span><br><span class="line"> cur_skipped_paths = <span class="number">0</span>;<span class="comment">//</span></span><br><span class="line"> queue_cur = <span class="built_in">queue</span>;</span><br><span class="line"> </span><br><span class="line"> show_stats();</span><br><span class="line"> <span class="comment">/* If we had a full queue cycle with no new finds, try</span></span><br><span class="line"><span class="comment"> recombination strategies next. */</span></span><br><span class="line"> <span class="keyword">if</span> (queued_paths == prev_queued) <span class="comment">//queue里的case数是否未变化</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (use_splicing) cycles_wo_finds++; <span class="comment">//开启拼接时cycles_wo_finds++</span></span><br><span class="line"> <span class="keyword">else</span> use_splicing = <span class="number">1</span>;<span class="comment">//否则开启拼接</span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> cycles_wo_finds = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> prev_queued = queued_paths;</span><br><span class="line"> <span class="keyword">if</span> (sync_id && queue_cycle == <span class="number">1</span> && getenv(<span class="string">"AFL_IMPORT_FIRST"</span>))<span class="comment">//这里是synchronize fuzz用的</span></span><br><span class="line"> sync_fuzzers(use_argv);</span><br><span class="line"> }</span><br><span class="line"> skipped_fuzz = fuzz_one(use_argv);<span class="comment">//关键函数,fuzz_one对当前queue进行一次完整测试,也是目前最长的一个函数,大约有1500行</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (!stop_soon && sync_id && !skipped_fuzz) {</span><br><span class="line"> <span class="keyword">if</span> (!(sync_interval_cnt++ % SYNC_INTERVAL))</span><br><span class="line"> sync_fuzzers(use_argv);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!stop_soon && exit_1) stop_soon = <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (stop_soon) <span class="keyword">break</span>;</span><br><span class="line"> queue_cur = queue_cur->next;</span><br><span class="line"> current_entry++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (queue_cur) show_stats();</span><br><span class="line"> write_bitmap();</span><br><span class="line"> write_stats_file(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> save_auto();</span><br><span class="line"></span><br><span class="line">stop_fuzzing:</span><br><span class="line"> SAYF(CURSOR_SHOW cLRD <span class="string">"\n\n+++ Testing aborted %s +++\n"</span> cRST,</span><br><span class="line"> stop_soon == <span class="number">2</span> ? <span class="string">"programmatically"</span> : <span class="string">"by user"</span>);</span><br><span class="line"> <span class="comment">/* Running for more than 30 minutes but still doing first cycle? */</span></span><br><span class="line"> <span class="keyword">if</span> (queue_cycle == <span class="number">1</span> && get_cur_time() - start_time > <span class="number">30</span> * <span class="number">60</span> * <span class="number">1000</span>) {</span><br><span class="line"> SAYF(<span class="string">"\n"</span> cYEL <span class="string">"[!] "</span> cRST</span><br><span class="line"> <span class="string">"Stopped during the first cycle, results may be incomplete.\n"</span></span><br><span class="line"> <span class="string">" (For info on resuming, see %s/README.)\n"</span>, doc_path);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> fclose(plot_file);</span><br><span class="line"> destroy_queue();</span><br><span class="line"> destroy_extras();</span><br><span class="line"> ck_free(target_path);</span><br><span class="line"> ck_free(sync_id);</span><br><span class="line"> alloc_report();</span><br><span class="line"> OKF(<span class="string">"We're done here. Have a nice day!\n"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(<span class="number">0</span>);</span><br></pre></td></tr></table></figure>
<h3 id="fuzz-one"><a href="#fuzz-one" class="headerlink" title="fuzz_one"></a>fuzz_one</h3><p>先看一下他的跳过策略</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (pending_favored) </span><br><span class="line">{</span><br><span class="line"> <span class="comment">/* If we have any favored, non-fuzzed new arrivals in the queue,</span></span><br><span class="line"><span class="comment"> possibly skip to them at the expense of already-fuzzed or non-favored</span></span><br><span class="line"><span class="comment"> cases. */</span></span><br><span class="line"> <span class="keyword">if</span> ((queue_cur->was_fuzzed || !queue_cur->favored) && UR(<span class="number">100</span>) < SKIP_TO_NEW_PROB) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//这里不满足favored或者non-fuzzed的话跳过概率是99%</span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (!dumb_mode && !queue_cur->favored && queued_paths > <span class="number">10</span>) </span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* Otherwise, still possibly skip non-favored cases, albeit less often.</span></span><br><span class="line"><span class="comment"> The odds of skipping stuff are higher for already-fuzzed inputs and</span></span><br><span class="line"><span class="comment"> lower for never-fuzzed entries. */</span></span><br><span class="line"> <span class="keyword">if</span> (queue_cycle > <span class="number">1</span> && !queue_cur->was_fuzzed) </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (UR(<span class="number">100</span>) < SKIP_NFAV_NEW_PROB) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//queue_cycle大于1且没有被fuzz过,跳过概率是75%</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (UR(<span class="number">100</span>) < SKIP_NFAV_OLD_PROB) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//fuzzed&&no-favored,有90%概率跳过</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>进入fuzz流程的话,就先将case map到内存</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">fd = <span class="built_in">open</span>(queue_cur->fname, O_RDONLY);</span><br><span class="line">len = queue_cur->len;</span><br><span class="line">orig_in = in_buf = mmap(<span class="number">0</span>, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, <span class="number">0</span>);<span class="comment">//MAP_PRIVATE在内存对文件的修改不会影响文件本身</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">close</span>(fd);</span><br></pre></td></tr></table></figure>
<p>然后有一个<code>CALIBRATION</code>阶段和<code>TRIMMING</code>阶段,前者是在之前<code>proform_dry_run</code>中如果校准失败就再次校准,后者主要是为了修剪文件长度啥的,如果修剪文件对执行路径没有影响就<code>make it permanent</code>,优化后续运行</p>
<p>之后是一个<code>PERFORMANCE SCORE</code>阶段为该case计分,影响后续的havoc stage</p>
<p>到这里就是主要的变异策略了,推荐<a href="https://paper.seebug.org/496/#part-2afl" target="_blank" rel="noopener">直接看文章吧</a>,后面节约时间我就先不写了,以后自己要写变异策略的时候再参考吧</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2021/01/11/pwnable-kr%E2%80%94%E2%80%94input-leg/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Coldshield">
<meta itemprop="description" content="分享一些bin学习日常">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Coldshield's blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a href="/2021/01/11/pwnable-kr%E2%80%94%E2%80%94input-leg/" class="post-title-link" itemprop="url">pwnable.kr——input+leg</a>
</h1>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-01-11 19:00:00" itemprop="dateCreated datePublished" datetime="2021-01-11T19:00:00+08:00">2021-01-11</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">Edited on</span>
<time title="Modified: 2021-03-19 18:25:21" itemprop="dateModified" datetime="2021-03-19T18:25:21+08:00">2021-03-19</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="fa fa-comment-o"></i>
</span>
<span class="post-meta-item-text">Valine: </span>
<a title="valine" href="/2021/01/11/pwnable-kr%E2%80%94%E2%80%94input-leg/#valine-comments" itemprop="discussionUrl">
<span class="post-comments-count valine-comment-count" data-xid="/2021/01/11/pwnable-kr%E2%80%94%E2%80%94input-leg/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="pwnable-kr-——-input"><a href="#pwnable-kr-——-input" class="headerlink" title="pwnable.kr —— input"></a>pwnable.kr —— input</h1><p>先看看题目代码</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210103152433405.png" alt="image-20210103152433405" style="zoom:80%;">
<h2 id="stage1"><a href="#stage1" class="headerlink" title="stage1"></a>stage1</h2><p>要求argc值为100,就是除文件名外还需要99个参数,<code>argv['A']="\x00"</code>,<code>argv['B']="\x20\x0a\x0d"</code>,要满足最后<code>argv[argc]=NULL</code></p>
<h2 id="stage2"><a href="#stage2" class="headerlink" title="stage2"></a>stage2</h2><p>要求从fd:0(stdin)处读出4字节<code>\x00\x0a\x00\xff</code>,从fd:2(stderr)处读出四字节<code>\x00\x0a\x02\xff</code>,这里直接读是读不了的,要使用dup2函数将文件描述符克隆到 0和2 </p>
<h2 id="stage3"><a href="#stage3" class="headerlink" title="stage3"></a>stage3</h2><p>设置一个环境变量,好说</p>
<h2 id="stage4"><a href="#stage4" class="headerlink" title="stage4"></a>stage4</h2><p>打开一个文件名是回车的文件,读四字节<code>\x00\x00\x00\x00</code></p>
<h2 id="stage5"><a href="#stage5" class="headerlink" title="stage5"></a>stage5</h2><img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210103153255873.png" alt="image-20210103153255873" style="zoom:80%;">
<p>这里好好学一下网络编程的一些东西,之前一直喜欢忽略</p>
<h3 id="socket函数(返回socke描述符)"><a href="#socket函数(返回socke描述符)" class="headerlink" title="socket函数(返回socke描述符)"></a>socket函数(返回socke描述符)</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/socket.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">socket</span><span class="params">(<span class="keyword">int</span> family,<span class="keyword">int</span> type,<span class="keyword">int</span> protocol)</span></span>;</span><br><span class="line"><span class="comment">//返回:若成功则为非负描述符,若出错则为-1</span></span><br></pre></td></tr></table></figure>
<p>family参数指明协议簇,决定了socket的地址类型,如AF_INET决定了要用IPv4地址(32位的)与端口号(16位的)的组合、AF_UNIX要使用一个绝对路径名作为地址</p>
<table>
<thead>
<tr>
<th>family</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>AF_INET (一般用)</td>
<td>IPv4协议</td>
</tr>
<tr>
<td>AF_INET6</td>
<td>IPv6协议</td>
</tr>
<tr>
<td>AF_LOCAL</td>
<td>Unix域协议</td>
</tr>
<tr>
<td>AF_ROUTE</td>
<td>路由套接字</td>
</tr>
<tr>
<td>AF_KEY</td>
<td>密钥套接字</td>
</tr>
</tbody></table>
<p>type参数指明socket类型</p>
<table>
<thead>
<tr>
<th>type</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>SOCK_STREAM</td>
<td>字节流套接字</td>
</tr>
<tr>
<td>SOCK_DGRAM</td>
<td>数据报套接字</td>
</tr>
<tr>
<td>SOCK_SEGPACKET</td>
<td>有序分组套接字</td>
</tr>
<tr>
<td>SOCK_RAW</td>
<td>原始套接字</td>
</tr>
</tbody></table>
<p>protocol指协议,一般赋值0让系统自动选择</p>
<p>(这三个参数更详细的内容可以在<a href="https://binhack.readthedocs.io/zh/latest/os/linux/syscall/socket.html" target="_blank" rel="noopener">这里</a>找到)</p>
<h3 id="sockaddr-in结构体"><a href="#sockaddr-in结构体" class="headerlink" title="sockaddr_in结构体"></a>sockaddr_in结构体</h3><p>用来设置具体地址给bind函数当做参数,因为一些字节序的原因不直接使用sockaddr,但两者目的等价;设置好协议簇之后,IP地址的sin_addr.s_addr可以用INADDR_ANY表示本机,也可以用具体的IP地址,如<code>inet_addr("192.168.1.1")</code>;然后端口号使用<code>hton()</code>封装,转换字节序</p>
<p><strong>这里题目的意思就是将我们<code>argv['C']</code>处的值作为绑定的端口号</strong></p>
<h3 id="bind、listen、accept、recv"><a href="#bind、listen、accept、recv" class="headerlink" title="bind、listen、accept、recv"></a>bind、listen、accept、recv</h3><p>设置好结构体后此程序作为服务端程序,bind对应端口,然后监听,listen函数的第一个参数即为监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。</p>
<p>这里accept返回的是新的已连接的socket描述字,和前面的监听socket描述字不一样,监听socket描述字一直存在,而当服务器完成某服务后已连接的socket描述字就会被关闭</p>
<p>之后使用recv接受四字节内容</p>
<p>更加具体的描述可以看<a href="http://images.cnblogs.com/cnblogs_com/skynet/201012/201012122157467258.png" target="_blank" rel="noopener">这篇文章</a>,同时这里还有一张图表示建立连接与TCP三次握手的关系</p>
<img src="http://images.cnblogs.com/cnblogs_com/skynet/201012/201012122157467258.png">
<h2 id="solution"><a href="#solution" class="headerlink" title="solution"></a>solution</h2><p>直接上代码</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">char</span> *P=<span class="string">"/home/pwner/Desktop/pwnable.kr/input2/input"</span>;<span class="comment">//写题时换成pwnable.kr那边的路径</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">char</span> *Argv[<span class="number">101</span>];</span><br><span class="line"> <span class="keyword">char</span> *Envp[<span class="number">2</span>];</span><br><span class="line"> <span class="comment">//argv</span></span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>;i<<span class="number">100</span>;i++)Argv[i]=<span class="string">"\x20"</span>;</span><br><span class="line"> Argv[<span class="string">'A'</span>]=<span class="string">"\x00"</span>;</span><br><span class="line"> Argv[<span class="string">'B'</span>]=<span class="string">"\x20\x0a\x0d"</span>;</span><br><span class="line"> Argv[<span class="number">100</span>]=<span class="literal">NULL</span>;<span class="comment">//设置参数</span></span><br><span class="line"> <span class="comment">//env</span></span><br><span class="line"> Envp[<span class="number">0</span>]=<span class="string">"\xde\xad\xbe\xef=\xca\xfe\xba\xbe"</span>;</span><br><span class="line"> Envp[<span class="number">1</span>]=<span class="literal">NULL</span>;<span class="comment">//设置环境变量</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> fd1=<span class="built_in">open</span>(<span class="string">"./infile"</span> , O_CREAT | O_RDWR , S_IRWXU | S_IRWXO | S_IRWXG);</span><br><span class="line"> <span class="keyword">int</span> fd2=<span class="built_in">open</span>(<span class="string">"./errfile"</span>, O_CREAT | O_RDWR , S_IRWXU | S_IRWXO | S_IRWXG);</span><br><span class="line"> <span class="comment">//这里创建两个文件打开后用于将0,2文件描述符覆盖</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">write</span>(fd1,<span class="string">"\x00\x0a\x00\xff"</span>,<span class="number">4</span>);</span><br><span class="line"> <span class="built_in">write</span>(fd2,<span class="string">"\x00\x0a\x02\xff"</span>,<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"> dup2(fd1,<span class="number">0</span>);</span><br><span class="line"> dup2(fd2,<span class="number">2</span>);</span><br><span class="line"> lseek(fd1,<span class="number">0</span>,SEEK_SET);<span class="comment">//写文件之后要调用lseek将文件指针重置一下</span></span><br><span class="line"> lseek(fd2,<span class="number">0</span>,SEEK_SET);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">close</span>(fd1);<span class="built_in">close</span>(fd2);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> fd3=<span class="built_in">open</span>(<span class="string">"./\x0a"</span>, O_CREAT | O_RDWR , S_IRWXU | S_IRWXO | S_IRWXG);<span class="comment">//这里创建需要的“回车”文件</span></span><br><span class="line"> <span class="built_in">write</span>(fd3,<span class="string">"\x00\x00\x00\x00"</span>,<span class="number">4</span>);</span><br><span class="line"> <span class="built_in">close</span>(fd3);</span><br><span class="line"></span><br><span class="line"> Argv[<span class="string">'C'</span>]=<span class="string">"8888"</span>;</span><br><span class="line"></span><br><span class="line"> execve(P,Argv,Envp);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>然后我解题的具体做法是进入pwnable服务器之后,cd /tmp ,mkdir ljc ,cd ljc ,touch solu.c , vim solu.c</p>
<p>然后把这段代码写进去,修改一下可执行文件的路径保存,再 ln -s flag /home/input2/flag 为了最后一步cat flag,gcc编译之后运行,此时就会等待stage5,再从一个新的命令行用python输入就行</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210104202957472.png" alt="image-20210104202957472" style="zoom: 67%;">
<h1 id="pwnable-kr-——-leg"><a href="#pwnable-kr-——-leg" class="headerlink" title="pwnable.kr —— leg"></a>pwnable.kr —— leg</h1><p>一道ARM汇编的题目,来入门一下arm的汇编</p>
<h2 id="ARM学习"><a href="#ARM学习" class="headerlink" title="ARM学习"></a>ARM学习</h2><p><a href="https://azeria-labs.com/writing-arm-assembly-part-1/" target="_blank" rel="noopener">从这个教程开始</a></p>
<p>搭环境我创了一个全新的ubuntu 20 虚拟机…装了大概一天的各种依赖等等,把python2装上去了,还有什么re2c,Ninja,meson,编译安装了一个qemu,东西还挺多的,然后又琢磨了一晚上qemu树莓派虚拟机的网络问题….照着<a href="https://wiki.qemu.org/Features/HelperNetworking" target="_blank" rel="noopener">这里</a>(这里的helper最后还是没用,琢磨了一个下午也没琢磨出来。。tcl)还是用<a href="https://azeria-labs.com/emulate-raspberry-pi-with-qemu/" target="_blank" rel="noopener">教程的指导</a>把树莓派虚拟机网络问题解决了,我起qemu的命令是这样的</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">stty intr ^]</span><br><span class="line">qemu-system-arm -kernel /home/coldshield/qemu_vms/kernel-qemu-4.4.34-jessie \</span><br><span class="line"> -cpu arm1176 \</span><br><span class="line"> -m 256 \</span><br><span class="line"> -M versatilepb \</span><br><span class="line"> -serial stdio \</span><br><span class="line"> -net nic \</span><br><span class="line"> -nic tap,ifname=tap0,script=no,downscript=no\</span><br><span class="line"> -append <span class="string">"root=/dev/sda2 rootfstype=ext4 rw console=ttyAMA0,115200"</span> \</span><br><span class="line"> -hda /home/coldshield/qemu_vms/2017-03-02-raspbian-jessie.img \</span><br><span class="line"> -no-reboot</span><br></pre></td></tr></table></figure>
<p>进去之后我是设置静态DNS还有网络,然后让虚拟机和host还有外网都能ping通,(参照过<a href="https://blog.csdn.net/mculover666/article/details/105664454" target="_blank" rel="noopener">这里</a>,后来自己又谷歌了一下静态配置,用了一个静态的IP还有DNS连上我的tap),然后因为镜像的磁盘空间不够又给手动扩了个容….参照<a href="https://yushulx.medium.com/how-to-resize-raspbian-image-for-qemu-on-windows-ac0b44075d8f" target="_blank" rel="noopener">这里</a>。还有树莓派虚拟机里面的gdb只能支持python2的gef,那个教程没更新了吧可能,用<a href="https://github.com/hugsy/gef-legacy" target="_blank" rel="noopener">gef-legacy</a>就行,反正全部弄清楚是啥然后搭起来断断续续搞了两三天的样子….</p>
<p>随手记一些教程上的东西,可能会特别粗略</p>
<h3 id="常见访存指令-amp-后缀"><a href="#常见访存指令-amp-后缀" class="headerlink" title="常见访存指令&后缀"></a>常见访存指令&后缀</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">ldr = Load Word</span><br><span class="line">ldrh = Load unsigned Half Word</span><br><span class="line">ldrsh = Load signed Half Word</span><br><span class="line">ldrb = Load unsigned Byte</span><br><span class="line">ldrsb = Load signed Bytes</span><br><span class="line"></span><br><span class="line">str = Store Word</span><br><span class="line">strh = Store unsigned Half Word</span><br><span class="line">strsh = Store signed Half Word</span><br><span class="line">strb = Store unsigned Byte</span><br><span class="line">strsb = Store signed Byte</span><br></pre></td></tr></table></figure>
<h3 id="一些寄存器"><a href="#一些寄存器" class="headerlink" title="一些寄存器"></a>一些寄存器</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">R0 – General purpose</span><br><span class="line">R1 – General purpose</span><br><span class="line">R2 – General purpose</span><br><span class="line">R3 – General purpose</span><br><span class="line">R4 – General purpose</span><br><span class="line">R5 – General purpose</span><br><span class="line">R6 – General purpose</span><br><span class="line">R7 – Holds Syscall Number 系统调用号</span><br><span class="line">R8 – General purpose</span><br><span class="line">R9 – General purpose</span><br><span class="line">R10 – General purpose</span><br><span class="line">R11 FP Frame Pointer 类似EBP</span><br><span class="line">R12 IP Intra Procedural Call </span><br><span class="line">R13 SP Stack Pointer 类似ESP,以字节为单位</span><br><span class="line">R14 LR Link Register 函数返回时存放返回地址</span><br><span class="line">R15 PC Program Counter 类似EIP,但实际内容不是存放next的地址,而是存放当前执行指令+2指令的地址(ARM模式值+8,Thumb模式值+4,这里应该是跟指令流水线有关?)</span><br><span class="line">CPSR – Current Program Status Register</span><br><span class="line"></span><br><span class="line">函数调用时前四个参数存在 r0-r3</span><br></pre></td></tr></table></figure>
<h3 id="Thumb"><a href="#Thumb" class="headerlink" title="Thumb"></a>Thumb</h3><p>When writing ARM shellcode, we need to get rid of NULL bytes and using 16-bit Thumb instructions instead of 32-bit ARM instructions reduces the chance of having them</p>
<p>可以用BX还有BLX指令设置寄存器最低位为1来切换ARM和Thumb模式,执行的时候最低位会被忽略所以不会产生地址对齐问题</p>
<p>具体的指令格式相关还是看<a href="https://azeria-labs.com/arm-instruction-set-part-3/" target="_blank" rel="noopener">教程</a>吧….这里记一个大概</p>
<figure class="highlight plain"><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">MNEMONIC{S}{condition} {Rd}, Operand1, Operand2</span><br><span class="line">MNEMONIC - 指令助记符</span><br><span class="line">{S} - 可选后缀,如果设置S,flags将根据操作结果进行更新</span><br><span class="line">{condition} - 执行指令所需的条件</span><br><span class="line">{Rd} - 目的寄存器,用于存储指令结果(不过后续提到的ldm不是)</span><br><span class="line">Operand1 - 寄存器或者立即数 </span><br><span class="line">Operand2 - 立即数或寄存器(可用于增加、偏移)</span><br></pre></td></tr></table></figure>
<h3 id="几种寻址方式"><a href="#几种寻址方式" class="headerlink" title="几种寻址方式"></a>几种寻址方式</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">ldr r2, [r0] 最普通的,有效地址就是r0的值(r0)</span><br><span class="line">ldr r1, [pc, #12] 这里有效地址是(PC)+12(arm模式 4单位对齐),不是当前执行指令地址加12</span><br><span class="line"></span><br><span class="line">str r2, [r1, #2] 这里有效地址是(r1)+2,r1不发生更改,offset</span><br><span class="line">str r2, [r1, #4]! 这里有效地址是(r1)+4,第一操作数有感叹号,所以r1发生更改 r1=r1+4 ,pre-indexed</span><br><span class="line">ldr r3, [r1], #4 这里有效地址是(r1),r1发生更改 r1=r1+4 ,post-indexed</span><br><span class="line"></span><br><span class="line">str r2, [r1, r2]</span><br><span class="line">str r2, [r1, r2]!</span><br><span class="line">ldr r3, [r1], r2</span><br><span class="line">这三种跟上面比较相似,只不过是把立即数换成了r2寄存器的值,更改的依然是r1(用r2的值相加)</span><br><span class="line"></span><br><span class="line">str r2, [r1, r2, LSL#2] 有效地址是(r1) + ((r2)<<2),offset</span><br><span class="line">str r2, [r1, r2, LSL#2]! 有效地址是(r1) + ((r2)<<2),r1发生更改 r1= (r1) + ((r2)<<2) ,pre-indexed</span><br><span class="line">ldr r3, [r1], r2, LSL#2 有效地址是(r1),r1发生更改 r1= (r1) + ((r2)<<2) ,post-indexed</span><br></pre></td></tr></table></figure>
<p>ARM中的立即数是最后操作数12中的,前8位(n)和后4位(r)的组合表示, v = n ror 2*r,循环右移得到,用于12位表示32位数</p>
<h3 id="访存指令-Multiple-amp-后缀"><a href="#访存指令-Multiple-amp-后缀" class="headerlink" title="访存指令(Multiple)&后缀"></a>访存指令(Multiple)&后缀</h3><p>这里有一串类似猝发式传送的指令</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">adr r0, words+12 /* address of words[3] -> r0 ,adr是取地址的指令*/</span><br><span class="line">ldr r1, array_buff_bridge /* address of array_buff[0] -> r1 */</span><br><span class="line">ldr r2, array_buff_bridge+4 /* address of array_buff[2] -> r2 */</span><br><span class="line"></span><br><span class="line">ldm r0, {r4,r5} /* words[3] -> r4 = 0x03; words[4] -> r5 = 0x04 */</span><br><span class="line">//ldm:load多个数据到目的寄存器,这里是将r0指向的连续内存数据分别load到r4 r5,默认情况下是r0增加的连续方向,此时执行后r0的值不会变</span><br><span class="line">stm r1, {r4,r5} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04 */</span><br><span class="line">//stm则是将r4 45中的内容存到r1所指的连续内存,默认也是r0增加方向,此时r1值不改变</span><br><span class="line"></span><br><span class="line">ldmia r0, {r4-r6} /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05; */</span><br><span class="line">stmia r1, {r4-r6} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04; r6 -> array_buff[2] = 0x05 */</span><br><span class="line">//这里是后缀的介绍还有指令写法可以写成r4-46,这样就是存3个了</span><br><span class="line">//后缀具体代表 -IA (increase after), -IB (increase before), -DA (decrease after), -DB (decrease before)</span><br><span class="line"></span><br><span class="line">ldmib r0, {r4-r6} /* words[4] -> r4 = 0x04; words[5] -> r5 = 0x05; words[6] -> r6 = 0x06 */</span><br><span class="line">stmib r1, {r4-r6} /* r4 -> array_buff[1] = 0x04; r5 -> array_buff[2] = 0x05; r6 -> array_buff[3] = 0x06 */</span><br><span class="line">ldmda r0, {r4-r6} /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */</span><br><span class="line">ldmdb r0, {r4-r6} /* words[2] -> r6 = 0x02; words[1] -> r5 = 0x01; words[0] -> r4 = 0x00 */</span><br><span class="line">stmda r2, {r4-r6} /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */</span><br><span class="line">stmdb r2, {r4-r5} /* r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00; */</span><br><span class="line">//后缀的不同用法,I(x)时指令后面的寄存器操作顺序是顺着来的,D(x)时指令后面的寄存器操作顺序是逆着来的,要注意差别。这里第一个寄存器都不会发生改变</span><br><span class="line"></span><br><span class="line">bx lr</span><br></pre></td></tr></table></figure>
<h3 id="push-amp-pop"><a href="#push-amp-pop" class="headerlink" title="push&pop"></a>push&pop</h3><p>ARM中虽然直接写stmdb sp!, {r0, r1} ldmia sp!, {r4, r5} 在汇编会被翻译为 push {r0, r1} pop {r4, r5}<br>但push , pop本质上是stmdb sp!和ldmia sp!的代名词</p>
<p>所以push操作时是先push r1再push r0,从右到左;pop操作时是先pop r4再pop r5,从左到右;</p>
<h3 id="条件执行相关"><a href="#条件执行相关" class="headerlink" title="条件执行相关"></a>条件执行相关</h3><p>下表列出了ARM中可用的条件代码,它们的含义以及测试的标志,条件码跟着指令助记符满足指令格式就行,比如addlt,addsne</p>
<table>
<thead>
<tr>
<th>Condition Code</th>
<th>Meaning (for cmp or subs)</th>
<th>Status of Flags</th>
</tr>
</thead>
<tbody><tr>
<td>EQ</td>
<td>Equal</td>
<td>Z==1</td>
</tr>
<tr>
<td>NE</td>
<td>Not Equal</td>
<td>Z==0</td>
</tr>
<tr>
<td>GT</td>
<td>Signed Greater Than</td>
<td>(Z==0) && (N==V)</td>
</tr>
<tr>
<td>LT</td>
<td>Signed Less Than</td>
<td>N!=V</td>
</tr>
<tr>
<td>GE</td>
<td>Signed Greater Than or Equal</td>
<td>N==V</td>
</tr>
<tr>
<td>LE</td>
<td>Signed Less Than or Equal</td>
<td>(Z==1) || (N!=V)</td>
</tr>
<tr>
<td>CS or HS</td>
<td>Unsigned Higher or Same (or Carry Set)</td>
<td>C==1</td>
</tr>
<tr>
<td>CC or LO</td>
<td>Unsigned Lower (or Carry Clear)</td>
<td>C==0</td>
</tr>
<tr>
<td>MI</td>
<td>Negative (or Minus)</td>
<td>N==1</td>
</tr>
<tr>
<td>PL</td>
<td>Positive (or Plus)</td>
<td>N==0</td>
</tr>
<tr>
<td>AL</td>
<td>Always executed</td>
<td>–</td>
</tr>
<tr>
<td>NV</td>
<td>Never executed</td>
<td>–</td>
</tr>
<tr>
<td>VS</td>
<td>Signed Overflow</td>
<td>V==1</td>
</tr>
<tr>
<td>VC</td>
<td>No signed Overflow</td>
<td>V==0</td>
</tr>
<tr>
<td>HI</td>
<td>Unsigned Higher</td>
<td>(C==1) && (Z==0)</td>
</tr>
<tr>
<td>LS</td>
<td>Unsigned Lower or same</td>
<td>(C==0) || (Z==0)</td>
</tr>
</tbody></table>
<p>Thumb模式下有分支条件执行,语法格式是这样的</p>
<figure class="highlight plain"><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">Syntax: IT{x{y{z}}} cond ,IT指令之后会跟一个条件执行块,最多四条指令,这四条指令的条件都由这条IT指令指出</span><br><span class="line"></span><br><span class="line">cond specifies the condition for the first instruction in the IT block(cond指出第一条指令的执行条件)</span><br><span class="line">x specifies the condition switch for the second instruction in the IT block(x指出第二条指令执行的条件是不是和cond一样,如果x是T,那么第二条指令和cond条件相同;如果是E,那么第二条指令和cond条件相反)</span><br><span class="line">y specifies the condition switch for the third instruction in the IT block(同上)</span><br><span class="line">z specifies the condition switch for the fourth instruction in the IT block(同上)</span><br></pre></td></tr></table></figure>
<p>所以Thumb模式下的条件执行指令块看起来就是这样的(这里直接偷图了):</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210111000847458.png" alt="image-20210111000847458" style="zoom:80%;">
<p>里面每个指令都是带条件的,并且符合IT指令的声明,常见的条件和相反条件有如下几个</p>
<table>
<thead>
<tr>
<th>Code</th>
<th>Meaning</th>
<th>Code</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>EQ</td>
<td>Equal</td>
<td>NE</td>
<td>Not Equal</td>
</tr>
<tr>
<td>HS (or CS)</td>
<td>Unsigned higher or same (or carry set)</td>
<td>LO (or CC)</td>
<td>Unsigned lower (or carry clear)</td>
</tr>
<tr>
<td>MI</td>
<td>Negative</td>
<td>PL</td>
<td>Positive or Zero</td>
</tr>
<tr>
<td>VS</td>
<td>Signed Overflow</td>
<td>VC</td>
<td>No Signed Overflow</td>
</tr>
<tr>
<td>HI</td>
<td>Unsigned Higher</td>
<td>LS</td>
<td>Unsigned Lower or Same</td>
</tr>
<tr>
<td>GE</td>
<td>Signed Greater Than or Equal</td>
<td>LT</td>
<td>Signed Less Than</td>
</tr>
<tr>
<td>GT</td>
<td>Signed Greater Than</td>
<td>LE</td>
<td>Signed Less Than or Equal</td>
</tr>
<tr>
<td>AL (or omitted)</td>
<td>Always Executed</td>
<td>(There is no opposite to AL)</td>
<td></td>
</tr>
</tbody></table>
<p>这里还有一段比较典型的将ARM切换成Thumb模式的代码:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">.syntax unified @ this is important!</span><br><span class="line">.text</span><br><span class="line">.global _start</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line"> .code 32</span><br><span class="line"> add r3, pc, #1 @ increase value of PC by 1 and add it to R3,执行到这里时PC指向cmp指令</span><br><span class="line"> bx r3 @ branch + exchange to the address in R3 -> switch to Thumb state because LSB = 1</span><br><span class="line"></span><br><span class="line"> .code 16 @ Thumb state</span><br><span class="line"> cmp r0, #10 </span><br><span class="line"> ite eq @ if R0 is equal 10...</span><br><span class="line"> addeq r1, #2 @ ... then R1 = R1 + 2</span><br><span class="line"> addne r1, #3 @ ... else R1 = R1 + 3</span><br><span class="line"> bkpt</span><br></pre></td></tr></table></figure>
<h3 id="分支指令(跳转)"><a href="#分支指令(跳转)" class="headerlink" title="分支指令(跳转)"></a>分支指令(跳转)</h3><p>三种分支指令:</p>
<ul>
<li>Branch (B)<ul>
<li>简单跳转</li>
</ul>
</li>
<li>Branch link (BL)<ul>
<li>将(当前执行指令地址+4)存入LR寄存器再跳转</li>
</ul>
</li>
<li>Branch exchange (BX) and Branch link exchange (BLX)<ul>
<li>和B/BL指令一样步骤 然后最低位为1时会切换模式 (ARM <-> Thumb)</li>
<li>必须用寄存器作为操作数</li>
</ul>
</li>
</ul>
<p>然后就是加上条件执行变成条件跳转了(跳转之后由于PC特性,会多读跳转目的处两条指令,实现自动PC+8?)</p>
<h3 id="函数栈"><a href="#函数栈" class="headerlink" title="函数栈"></a>函数栈</h3><p>先来看一个函数代码对应的汇编</p>
<p>main函数</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> a = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> b = <span class="number">2</span>;</span><br><span class="line"> res = <span class="built_in">max</span>(a, b);</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Dump of assembler code for function main:</span><br><span class="line">=> 0x000103e8 <+0>: push {r11, lr} @最开始执行到main时,lr存放的是<__libc_start_main+276> bl 0xb6ea4b28 <__GI_exit>,就是说这里将本函数的返回地址先存到了栈上</span><br><span class="line">@然后r11存放的是前一个函数的栈帧地址(作用等于rbp吧)</span><br><span class="line"> 0x000103ec <+4>: add r11, sp, #4 @新栈帧地址 直接sp+4得到,指向存放的lr</span><br><span class="line"> 0x000103f0 <+8>: sub sp, sp, #16 @开辟了4*4字节大小的栈帧</span><br><span class="line"> 0x000103f4 <+12>: mov r3, #0</span><br><span class="line"> 0x000103f8 <+16>: str r3, [r11, #-8] @r11-8处存放0(res)</span><br><span class="line"> 0x000103fc <+20>: mov r3, #1</span><br><span class="line"> 0x00010400 <+24>: str r3, [r11, #-12] @r11-12处存放1(a)</span><br><span class="line"> 0x00010404 <+28>: mov r3, #2</span><br><span class="line"> 0x00010408 <+32>: str r3, [r11, #-16] @r11-16处存放2(b)</span><br><span class="line"> 0x0001040c <+36>: ldr r0, [r11, #-12] @开始给要调用的函数赋值参数,把1给r0</span><br><span class="line"> 0x00010410 <+40>: ldr r1, [r11, #-16] @把2给r1,这里可以看出来参数传递顺序</span><br><span class="line"> 0x00010414 <+44>: bl 0x1042c <max> @把下个函数的返回地址存到lr后调用函数</span><br><span class="line"> 0x00010418 <+48>: str r0, [r11, #-8] @(返回值赋给res,然后再给r0)</span><br><span class="line"> 0x0001041c <+52>: ldr r3, [r11, #-8]</span><br><span class="line"> 0x00010420 <+56>: mov r0, r3</span><br><span class="line"> 0x00010424 <+60>: sub sp, r11, #4</span><br><span class="line"> 0x00010428 <+64>: pop {r11, pc} @这里由于PC的特性,感觉将之前的lr内容给到PC之后,PC自己又会自动+8多读两条指令</span><br></pre></td></tr></table></figure>
<p>上面代码中执行到+32处时栈帧看起来就是这样的(我这里sp指向栈顶后一个单元,可能有些实现会有不同):</p>
<img src="https://cdn.jsdelivr.net/gh/Coldshield/image_stored/image-20210111163416232.png" alt="image-20210111163416232" style="zoom:80%;">
<p>再来看max:</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"><span class="function"><span class="keyword">int</span> <span class="title">max</span><span class="params">(<span class="keyword">int</span> a,<span class="keyword">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> do_nothing();</span><br><span class="line"> <span class="keyword">if</span>(a<b) <span class="keyword">return</span> b;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">return</span> a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">Dump of assembler code for function max: @这里就不一行行解释了</span><br><span class="line">=> 0x0001042c <+0>: push {r11, lr}</span><br><span class="line"> 0x00010430 <+4>: add r11, sp, #4</span><br><span class="line"> 0x00010434 <+8>: sub sp, sp, #8</span><br><span class="line"> 0x00010438 <+12>: str r0, [r11, #-8]</span><br><span class="line"> 0x0001043c <+16>: str r1, [r11, #-12]</span><br><span class="line"> 0x00010440 <+20>: bl 0x1046c <do_nothing> @lr存入下一条指令地址然后跳转到do_nothing</span><br><span class="line"> 0x00010444 <+24>: ldr r2, [r11, #-8]</span><br><span class="line"> 0x00010448 <+28>: ldr r3, [r11, #-12]</span><br><span class="line"> 0x0001044c <+32>: cmp r2, r3</span><br><span class="line"> 0x00010450 <+36>: bge 0x1045c <max+48></span><br><span class="line"> 0x00010454 <+40>: ldr r3, [r11, #-12]</span><br><span class="line"> 0x00010458 <+44>: b 0x10460 <max+52></span><br><span class="line"> 0x0001045c <+48>: ldr r3, [r11, #-8]</span><br><span class="line"> 0x00010460 <+52>: mov r0, r3</span><br><span class="line"> 0x00010464 <+56>: sub sp, r11, #4</span><br><span class="line"> 0x00010468 <+60>: pop {r11, pc}</span><br></pre></td></tr></table></figure>
<p>do_nothing:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">do_nothing</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</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>
<figure class="highlight plain"><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">Dump of assembler code for function do_nothing: @由于do_nothing没有再调用其他函数,所以没有push lr,返回时也是直接bx lr</span><br><span class="line">=> 0x0001046c <+0>: push {r11} ; (str r11, [sp, #-4]!)</span><br><span class="line"> 0x00010470 <+4>: add r11, sp, #0</span><br><span class="line"> 0x00010474 <+8>: mov r3, #0</span><br><span class="line"> 0x00010478 <+12>: mov r0, r3</span><br><span class="line"> 0x0001047c <+16>: sub sp, r11, #0</span><br><span class="line"> 0x00010480 <+20>: pop {r11} ; (ldr r11, [sp], #4)</span><br><span class="line"> 0x00010484 <+24>: bx lr</span><br></pre></td></tr></table></figure>
<p>把函数调用看做一个树形结构的话,这里也可以看出叶子函数和非叶子函数的区别</p>
<p>OK到此为止对ARM的一些基础就知道的差不多了,来写题吧</p>
<h2 id="leg"><a href="#leg" class="headerlink" title="leg"></a>leg</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>{ </span><br><span class="line"> <span class="keyword">int</span> key=<span class="number">0</span>; </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Daddy has very strong arm! : "</span>); </span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &key); </span><br><span class="line"> <span class="keyword">if</span>( (key1()+key2()+key3()) == key ){ </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Congratz!\n"</span>); </span><br><span class="line"> <span class="keyword">int</span> fd = <span class="built_in">open</span>(<span class="string">"flag"</span>, O_RDONLY); </span><br><span class="line"> <span class="keyword">char</span> buf[<span class="number">100</span>]; </span><br><span class="line"> <span class="keyword">int</span> r = <span class="built_in">read</span>(fd, buf, <span class="number">100</span>); </span><br><span class="line"> <span class="built_in">write</span>(<span class="number">0</span>, buf, r); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span>{ </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"I have strong leg :P\n"</span>);</span><br><span class="line"> } </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>从c语言内容可以看出来,主要就是看key1、key2、key3的汇编然后计算和即可,先来看key1</p>
<figure class="highlight plain"><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">Dump of assembler code for function key1: </span><br><span class="line"> 0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!)</span><br><span class="line"> 0x00008cd8 <+4>: add r11, sp, #0 </span><br><span class="line"> 0x00008cdc <+8>: mov r3, pc </span><br><span class="line"> 0x00008ce0 <+12>: mov r0, r3 </span><br><span class="line"> 0x00008ce4 <+16>: sub sp, r11, #0 </span><br><span class="line"> 0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4) </span><br><span class="line"> 0x00008cec <+24>: bx lr</span><br></pre></td></tr></table></figure>
<p>这里就是考PC的特性,指向后两条指令处,即<code>0x00008ce4</code>,再来看key2</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Dump of assembler code for function key2: </span><br><span class="line"> 0x00008cf0 <+0>: push {r11} ; (str r11, [sp, #-4]!)</span><br><span class="line"> 0x00008cf4 <+4>: add r11, sp, #0</span><br><span class="line"> 0x00008cf8 <+8>: push {r6} ; (str r6, [sp, #-4]!)</span><br><span class="line"> 0x00008cfc <+12>: add r6, pc, #1</span><br><span class="line"> 0x00008d00 <+16>: bx r6</span><br><span class="line"> 0x00008d04 <+20>: mov r3, pc @跳转到这里的时候切成了Thumb模式,然后将r3赋值0x00008d08</span><br><span class="line"> 0x00008d06 <+22>: adds r3, #4 @ r3=0x00008d0C</span><br><span class="line"> 0x00008d08 <+24>: push {r3}</span><br><span class="line"> 0x00008d0a <+26>: pop {pc} @这里就是类似花指令的操作,接着执行</span><br><span class="line"> 0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)</span><br><span class="line"> 0x00008d10 <+32>: mov r0, r3 @此时r3=0x00008d0C</span><br><span class="line"> 0x00008d14 <+36>: sub sp, r11, #0</span><br><span class="line"> 0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4)</span><br><span class="line"> 0x00008d1c <+44>: bx lr</span><br></pre></td></tr></table></figure>
<p>所以key2返回<code>0x00008d0C</code>,再来看key3</p>
<figure class="highlight plain"><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">Dump of assembler code for function key3: </span><br><span class="line"> 0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!)</span><br><span class="line"> 0x00008d24 <+4>: add r11, sp, #0</span><br><span class="line"> 0x00008d28 <+8>: mov r3, lr</span><br><span class="line"> 0x00008d2c <+12>: mov r0, r3</span><br><span class="line"> 0x00008d30 <+16>: sub sp, r11, #0</span><br><span class="line"> 0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4)</span><br><span class="line"> 0x00008d38 <+24>: bx lr</span><br></pre></td></tr></table></figure>
<p>这里lr存的是在main里面的返回地址,去main里面看就知道是<code>0x00008d80</code></p>
<p>所以加起来就是0x1A770→108400,ssh过去就可以得到flag</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/04/08/ret2dl/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Coldshield">
<meta itemprop="description" content="分享一些bin学习日常">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Coldshield's blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">