به نام دانای بر حق
مقدمه
گاهی اوقات تیم های برنامه نویسی ، اشخاص و یا شرکت ها نیازمند بررسی کد های خود هستند، تا از نظر فنی کمی و کیفی بتوانند کدهای خودشون رو انالیز کنند و نتیجه گیری و یا تغییر رویکرد داشته باشند، و گاهی سادگی کار در بررسی کد ها مطرح میشود و گهگاهی ارزیابی عملکرد برنامه نویسان مورد مداقه و ارزیابی قرار میگیرد. من به شخص خیلی از پروژه ها رو پس از پایان مورد ارزیابی قرار می دهم تا عملکرد خودم رو پایش کنم و قوت قلب بگیریم.
گاهی اوقات این ابزار شامل آنالیز ایستا static و برخی اوقات آنالیز dynamic یا پویا می باشند که به آنها میپردازیم. ما قصد داریم تا در این مورد ابزار های به روز و متعددی که قالبا متن بازی یا همان اوپن سورس میباشند به تفکیک معرفی کنیم و شیوه عملکرد ، رویکرد و نحوه نصب و کار با ابزار های آنالیز و ارزیابی کد ها در سیستم عامل لینوکس توزیع Ubuntu با هم بررسی میکنیم.
-
CLOC
این نرم فزار از نوع آنالیز ایستا کد می باشد که برای شمارش بلاک های کد، تعداد خطوط و تعداد توضیحات (comments) نوشته شده در سورس کدها مورد استفاده قرار می گیرد. ابزاری بسیار دقیق است و فایل های تکراری را نیز نادیده میگیرد و سرعت قابل توجهی دارد با تفکیک زبان های برنامه نویسی بسیار تا کنون ۱۵۹ زبان برنامه نویسی به فهرست زیر:
ABAP (abap) ActionScript (as) Ada (ada, adb, ads, pad) ADSO/IDSM (adso) AMPLE (ample, dofile, startup) Ant (build.xml) Apex Trigger (trigger) Arduino Sketch (ino, pde) ASP (asa, asp) ASP.Net (asax, ascx, asmx, aspx, config, master, sitemap, webinfo) Assembly (asm, s, S) AutoHotkey (ahk) awk (awk) Bourne Again Shell (bash) Bourne Shell (sh) C (c, ec, pgc) C Shell (csh, tcsh) C# (cs) C++ (C, c++, cc, cpp, cxx, pcc) C/C++ Header (h, H, hh, hpp) CCS (ccs) Clojure (clj) ClojureScript (cljs) CMake (cmake, CMakeLists.txt) COBOL (cbl, CBL, cob, COB) CoffeeScript (coffee) ColdFusion (cfm) ColdFusion CFScript (cfc) CSS (css) CUDA (cu) Cython (pyx) D/dtrace (d) DAL (da) Dart (dart) diff (diff) DITA (dita) DOS Batch (bat, BAT, btm, BTM, cmd, CMD) DTD (dtd) ECPP (ecpp) Elixir (ex, exs) ERB (ERB, erb) Erlang (erl, hrl) Expect (exp) F# (fs, fsi) Focus (focexec) Fortran 77 (f, F, f77, F77, for, FOR, FTN, ftn, pfo) Fortran 90 (f90, F90) Fortran 95 (f95, F95) Go (go) Grails (gsp) Groovy (gant, gradle, groovy) Haml (haml) Handlebars (handlebars, hbs) Harbour (hb) Haskell (hs, lhs) HLSL (cg, cginc, shader) HTML (htm, html) IDL (idl) IDL/Qt Project/Prolog (pro) InstallShield (ism) Java (java) Javascript (js) JavaServer Faces (jsf, xhtml) JCL (jcl) JSON (json) JSP (jsp, jspf) Kermit (ksc) Korn Shell (ksh) Kotlin (kt) LESS (less) lex (l) Lisp (el, lisp, lsp, sc) Lisp/Julia (jl) Lisp/OpenCL (cl) LiveLink OScript (oscript) Lua (lua) m4 (ac, m4) make (am, gnumakefile, Gnumakefile, makefile, Makefile) MATLAB (m) Maven (pom, pom.xml) Modula3 (i3, ig, m3, mg) MSBuild script (csproj, vbproj, vcproj, wdproj, wixproj) MUMPS (mps, m) Mustache (mustache) MXML (mxml) NAnt script (build) NASTRAN DMAP (dmap) Objective C (m) Objective C++ (mm) OCaml (ml, mli, mll, mly) Oracle Forms (fmt) Oracle Reports (rex) Pascal (dpr, p, pas) Pascal/Puppet (pp) Patran Command Language (pcl, ses) Perl (perl, plh, plx, pm) Perl/Prolog (PL, pl) PHP (php, php3, php4, php5) PHP/Pascal (inc) Pig Latin (pig) PL/I (pl1) PowerShell (ps1) Prolog (P) Protocol Buffers (proto) PureScript (purs) Python (py) QML (qml) R (R) Racket (rkt, rktl, sch, scm, scrbl, ss) Razor (cshtml) Rexx (rexx) RobotFramework (robot, tsv) Ruby (rake, rb) Ruby HTML (rhtml) Rust (rs) SAS (sas) SASS (sass, scss) Scala (scala) sed (sed) SKILL (il) SKILL++ (ils) Smarty (smarty, tpl) Softbridge Basic (sbl, SBL) SQL (psql, sql, SQL) SQL Data (data.sql) SQL Stored Procedure (spc.sql, spoc.sql, sproc.sql, udf.sql) Standard ML (fun, sig, sml) Swift (swift) Tcl/Tk (itk, tcl, tk) Teamcenter met (met) Teamcenter mth (mth) Titanium Style Sheet (tss) TypeScript (ts) Unity-Prefab (mat, prefab) Vala (vala) Vala Header (vapi) Velocity Template Language (vm) Verilog-SystemVerilog (sv, svh, v) VHDL (VHD, vhd, vhdl, VHDL) vim script (vim) Visual Basic (bas, cls, ctl, dsr, frm, VB, vb, VBA, vba, vbs, VBS) Visual Fox Pro (sca, SCA) Visualforce Component (component) Visualforce Page (page) Windows Message File (mc) Windows Module Definition (def) Windows Resource File (rc, rc2) WiX include (wxi) WiX source (wxs) WiX string localization (wxl) XAML (xaml) xBase (prg) xBase Header (ch) XML (XML, xml) XQuery (xq, xquery) XSD (xsd, XSD) XSLT (xsl, XSL, xslt, XSLT) yacc (y) YAML (yaml, yml)
این نرم افزار به شکل زیر نصب میکند:
npm install -g cloc # https://www.npmjs.com/package/cloc sudo apt-get install cloc # Debian, Ubuntu sudo yum install cloc # Red Hat, Fedora sudo pacman -S cloc # Arch sudo pkg install cloc # FreeBSD sudo port install cloc # Mac OS X with MacPorts
نحوه استفاده:
cd /var/www/PROJECT/ cloc .
نمونه خروجی کد:
۴۱۶ text files. ۳۹۸ unique files. ۷۹ files ignored. github.com/AlDanial/cloc v 1.70 T=1.97 s (171.4 files/s, 34928.3 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- JavaScript 144 5234 7359 22712 JSON 75 0 0 14939 Markdown 99 4368 2 12578 CoffeeScript 2 148 86 840 HTML 2 18 0 215 CSS 3 14 11 85 YAML 7 7 0 66 TypeScript 3 15 42 56 make 1 14 4 32 XML 2 0 0 22 ------------------------------------------------------------------------------- SUM: 338 9818 7504 51545 -------------------------------------------------------------------------------
-
SLOCCount
SLOCCount ابزار بسیار موفق برای شمارش تعداد خطوط کد ها می باشد که تحت لایسنس GPL است و قابلیت شمارش کد ها را با تفکیک زبان های کدنویسی شده در پروژه های بسیار بزرگ و کوچک با سرعت بسیاز زیادی را داراست. این ابزار جزو ابزار آنالیز ایستا میباشد که قابلیت شمار کد به زبان های زیر را داراست:
- Ada (.ada, .ads, .adb)
- Assembly (.s, .S, .asm)
- awk (.awk)
- Bourne shell and variants (.sh)
- C (.c)
- C++ (.C, .cpp, .cxx, .cc)
- C shell (.csh)
- COBOL (.cob, .cbl) as of version 2.10
- C# (.cs) as of version 2.11
- Expect (.exp)
- Fortran (.f)
- Haskell (.hs) as of version 2.11
- Java (.java)
- lex/flex (.l)
- LISP/Scheme (.el, .scm, .lsp, .jl)
- Makefile (makefile) – not normally shown.
- Modula-3 (.m3, .i3) as of version 2.07
- Objective-C (.m)
- Pascal (.p, .pas)
- Perl (.pl, .pm, .perl)
- PHP (.php, .php[3456], .inc) as of version 2.05
- Python (.py)
- Ruby (.rb) as of version 2.09
- sed (.sed)
- SQL (.sql) – not normally shown.
- TCL (.tcl, .tk, .itk)
- Yacc/Bison (.y)
از مهم ترین ویژگی های این نرم افزار محاسبه ی قیمت حدودی نرم افزار، محاسبه تعداد کاربرانی به صورت استاندارد با توجه به تاریخ شروع و پایان بایستی روی آنها کار کنند، محاسبه حقوق و دستمزد کاربران به صورت ماهیانه از ویژگی های منحصر به فرد این نرم افزار میباشد که اعتبار خاصی به آن بخشیده است.
برای نصب آن میتوانید از repo های رسمی Ubuntu به شکل زیر نصب کنید.
sudo apt-get install sloccount
نحوه استفاده برای سورس کدها:
cd /var/www/PROJECT/ sloccount .
نمونه خروجی:
Finding a working MD5 command.... Found a working MD5 command. Computing results. SLOC Directory SLOC-by-Language (Sorted) ۱۴۲۳۷ node_modules javascript=14237 ۸۲۴۰ assets javascript=8240 ۲۰۳ top_dir javascript=203 ۲۲ nbproject xml=22 ۰ www (none) Totals grouped by language (dominant language first): javascript: 22680 (99.90%) xml: 22 (0.10%) Total Physical Source Lines of Code (SLOC) = 22,702 Development Effort Estimate, Person-Years (Person-Months) = 5.31 (63.69) (Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05)) Schedule Estimate, Years (Months) = 1.01 (12.12) (Basic COCOMO model, Months = 2.5 * (person-months**0.38)) Estimated Average Number of Developers (Effort/Schedule) = 5.26 Total Estimated Cost to Develop = $ 716,983 (average salary = $56,286/year, overhead = 2.40). SLOCCount, Copyright (C) 2001-2004 David A. Wheeler SLOCCount is Open Source Software/Free Software, licensed under the GNU GPL. SLOCCount comes with ABSOLUTELY NO WARRANTY, and you are welcome to redistribute it under certain conditions as specified by the GNU GPL license; see the documentation for details. Please credit this data as "generated using David A. Wheeler's 'SLOCCount'."
-
ESLint
ESLint یک ابزار آنالیز پویا است که در سال ۲۰۱۳ توسط Nicholas C. Zakas توسعه داده شده است که وظیفه اصلی آن بررسی بسامد یا فرکانس استفاده از کد ها میباشد. وظیفه دیگر آن پیدا کردن الگو های مشکل ساز و همچنین پیشنهاد راه حل صحیح برای آن است که همه این کارها را با مانیتور کردن کد ها هنگام استفاده به صورت علمی انجام میدهد، می توان گفت که به برنامه plug یا وصل میشود و در کنش ها و واکنش های آن پس از آنالیز کامل به شما گزارش صحیحی از نرم افزار میدهد، البته عملکرد آن بی نقص نیست ولی بسیار مهندسی شده و دقیق است. حقیر پس از استفاده از آن بسیاری از مشکلات خود را به راحتی حل کردم و گامی بسیار بزرگ در راستایی حرفه ای شدن است چه بسا یزرگترین ضعف آن این است که فقط از زبان جاوا اسکریپت پشتیبانی میکند و بر پایه آن نوشته شده است.
نحوه نصب در پزوژه های مبتنی بر nodejs:
npm install eslint --save-dev
نحوه استفاده:
ابتدا فایل json آن را پیکربندی کنید سپس با اجرا خروجی های آن را مشاهده نمایید.
-
CCPCheck
این ابزار Corss-Platform بوده و می تواند تا حد قابل قبولی در روند برنامه نویسی امن و بررسی کد به ما کمک کند. [ لینک ]
قابلیت integrate شدن با IDE های مختلف را دارد. از انجایی که مایکروسافت هم علاقه خاصی به گیت پیدا کرده ( The largest Git repo on the planet ) شاید شماهم از git برای مدیریت سورس ها استفاده می کنید، پس می توان از این ابزار بخوبی استفاده کرد و در هنگام commit سورس ها توسط این ابزار اسکن شود تا درصد خطا کمتر گردد و علاوه بر این، کمی فرآیند بررسی آنالیز کدها بصورت خودکار انجام شود. موارد استفاده از این ابزار تنها گیت نمی باشد بلکه می توان در Jenkins ، Tortoise SVN و … نیز استفاده کرد.
-
FlawFinder
یک ابزار دیگر برای بررسی کدهای C/C++ می باشد. یکی از قابلیت های که داره اینه فایل patch رو هم با پارامتر --patch (-P)
به عنوان ورودی قبول میکنه شما می تونید diff بین سورس ها رو با ابزار مورد بررسی قراربدین. در حالیکه ابزار CPPCheck اسکن برروی فایل سورس انجام میده و ورودی Patch File رو نمیتونه اسکن کنه. [ لینک ]
-
Clang Static Analyzer
این ابزار بخشی از پروژه Clang می باشد که می توان بصورت جداگانه نیز از آن استفاده کرد. [لینک]
بصورت زیر می توان از این ابزار استفاده کرد:
$ scan-build [scan-build options] <command> [command options] $ scan-build make $ scan-build make -j4 $ scan-build gcc -c t1.c t2.c $ scan-build ./configure $ scan-build make
این ابزار در مقایسه با ابزارهای داینامیک مانند valgrind و یا حتی santizier های خود clang بسیار متفاوت عمل می کند. بدین دلیل که ابزارهای داینامیک تنها بخشی از کدهایی که اجرا می شوند را مورد بررسی قرار می دهند بنابراین در آنالیز استاتیک بخش هایی از کد مورد بررسی قرار می گیرند که شاید اصلا اجرا نشوند. با استفاده از سوییچ -o می تونیم مسیری رو مشخص کنیم تا ریپورت های مربوطه بصورت فایل html ذخیره بشوند. مسیر پیش فرض /tmp است. بعد از اجرای ابزار در مسیر دلخواه فایل index.html مثل تصویر زیر ایجاد میشود که خلاصه ای اسکن انجام شده به همراه فایل های دیگری که روند تشخیص و تریگر شدن باگ ها را نشان می دهد.
-
Scitools Understand
ابزاری بسیار معروف و کامل برای آنالیز سورس کدها بررسی متغیرها،توابع، کلاس ها و اینکه در چه جایی تعریف شده اند، استفاده می گردند و یا مقادیر آن تغییر خواهد کرد مورد استفاده قرار می گیرد. زبان های برنامه نویسی قابل پشتیبانی توسط این ابزار :
Ada: Understand supports Ada83, Ada95, Ada05 and Ada2012 code separately, or in combination. Assembly Understand currently supports Coldfire 68k, JIPSE MIL-STD-1750A, and IBM System 370. C/C++: Understand analyzes K&R or ANSI C source code and most constructs of the C++ language. Understand works with any C compiler, and has been tested with most of the popular ones. Note that C++ templates are now supported using the strict parser in Understand. Objective C, Objective C++, C++11, and C++14 are also supported using the strict parser C#: Understand supports all versions up to and including 6.0. Cobol: Understand supports COBOL 85. FORTRAN: Understand supports FORTRAN 77, FORTRAN 90, FORTRAN 95, FORTRAN 2003, and FORTRAN 2008 in both free and fixed format. Extensions supported include Harris FORTRAN and DEC FORTRAN. We often expand Understand to support common compiler extensions. If you find that the compiler extensions you are using are not currently supported, contact us at support@scitools.com. Java: Understand supports most of JDK 1.3, 1.4, 5, 6, and 7. Specifically, the generics introduced in JDK 5 are not currently supported. Source code containing generics may be analyzed but generics information will be ignored. JOVIAL: JOVIAL73 and JOVIAL3 are supported. Delphi/Pascal: Understand supports all versions of Embarcadero’s Delphi language and Embarcadero’s Turbo Pascal language. It also supports ISO 7185: 1990 (also known as Unextended Pascal) with HP Pascal extensions. You can also enable support for Ingres embedded SQL statements. PL/M: The standard version for PL/M 80/86 is supported. Python: Understand supports Python Version 2 and Python Version 3. VHDL: We support VHDL-87, VHDL-93, and VHDL-2001. Visual Basic [.NET]: VB 2002 through 2015 are supported. Web Languages: Understand supports PHP, HTML, CSS, and JavaScript. XML is also a supported language that Understand provides several metrics for: counts for total lines, code lines, blank lines, and comment lines.
وقتی به عنوان یک برنامه نویس میخوایین توی یک پروژه مشارکت داشته باشین براتون ممکنه سخت باشه تا ساختار و نحوه کار دستتون بیاد اما این ابزار آنالیز سورس ها رو خیلی راحتتر میکنه و بدرستی روابط بین توابع و ساختار کدنویسی در اون پروژه رو متوجه خواهید شد. تصویر زیر اطلاعاتی با جزییات کامل در مورد یک فایل رو در اختیارمان قرار خواهد داد:
بخش پرکاربرد دیگری از این ابزار در منوی کلیک راست آن می باشد که با توجه به بخشی که برروی آن کلیک می کنید (متغییر، توابع، کلاس ها، ساختارها و …) گزینه هایی که در اختیار ما قرار میگیرد متفاوت خواهد بود:
قابلیت بعدی این ابزار ایجاد گراف است که می توانیم مورادی چون CFG, ارتباط بین توابع call graphs و … بصورت جامع داشته باشیم. در تصویر زیر من گزینه Called by از تصویر فوق را برروی تابع ospf_flood_delayed_lsa_ack انجام دادم، میخواهم بدانم که این تابع توسط چه توابع دیگری اجرا می شود و نقطه آغازین در رسیدن روند اجرا به آن چگونه است.
ابزار understand می تواند باتوجه استانداردهای کدنویسی موجود و یا استاندارد های تعریف شده توسط خودمان سورس ها را بررسی کند و مشکلات مدنظرمان را به ما گزارش دهد.
-
valgrind
درواقع یک فریمورک instrumentation است که برای ساخت ابزارهای آنالیز خودکارمورد استفاده قرار میگیره. که موقع نصب چند ابزار هم در اختیارما قرار میده تا بتونیم باگ هایی مرتبط با مبحث thread و حافظه رو در برنامه هامون کشف کنیم. اولین نکته که باید بگم در مورد نحوه تلفظ اسم این ابزاره که همه ما برای بار اول اشتباه میکنیم و یک چیز کاملا طبیعیه:
۱.۱. How do you pronounce “Valgrind”?
The “Val” as in the word “value”. The “grind” is pronounced with a short ‘i’ — ie. “grinned” (rhymes with “tinned”) rather than “grined” (rhymes with “find”).
Don’t feel bad: almost everyone gets it wrong at first.
خوب هم می توانیم سورس آن را از این لینک [+] دانلود و کامپایل کنیم و یا از با استفاده از apt-get install valgrind درون سیستم خودمون نصب کنیم. بعد از نصب ابزارهای مختلفی مثل callgrind, helgrind, DRD , … در اختیارمان قرار میگیر. در ادامه نحوه اجرای ابزار Memcheck را برروی یک سورس ساده انجام خواهیم داد:
# valgrind --leak-check=yes ./valgrind_test1 ==۷۷۵۴== Memcheck, a memory error detector ==۷۷۵۴== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==۷۷۵۴== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==۷۷۵۴== Command: ./valgrind_test1 ==۷۷۵۴== This is a simple chunks overlapping problem This is also referenced as Nonadjacent Free Chunk Consolidation Attack Let's start to allocate 5 chunks on the heap: chunk p1 from 0x5203040 to 0x5203428 chunk p2 from 0x5203470 to 0x5203858 chunk p3 from 0x52038a0 to 0x5203c88 chunk p4 from 0x5203cd0 to 0x52040b8 chunk p5 from 0x5204100 to 0x52044e8 Let's free the chunk p4. In this case this isn't coealesced with top chunk since we have p5 bordering top chunk after p4 Let's trigger the vulnerability on chunk p1 that overwrites the size of the in use chunk p2 with the size of chunk_p2 + size of chunk_p3 ==۷۷۵۴== Invalid write of size 4 ==۷۷۵۴== at 0x40099A: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== Address 0x5203428 is 0 bytes after a block of size 1,000 alloc'd ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400748: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== Now during the free() operation on p2, the allocator is fooled to think that the nextchunk is p4 ( since p2 + size_p2 now point to p4 ) This operation will basically create a big free chunk that wrongly includes p3 Now let's allocate a new chunk with a size that can be satisfied by the previously freed chunk Our malloc() has been satisfied by our crafted big free chunk, now p6 and p3 are overlapping and we can overwrite data in p3 by writing on chunk p6 chunk p6 from 0x5204530 to 0x5204d00 chunk p3 from 0x52038a0 to 0x5203c88 Data inside chunk p3: ==۷۷۵۴== Invalid read of size 1 ==۷۷۵۴== at 0x4E88CC0: vfprintf (vfprintf.c:1632) ==۷۷۵۴== by 0x4E89EF0: buffered_vfprintf (vfprintf.c:2320) ==۷۷۵۴== by 0x4E8732C: vfprintf (vfprintf.c:1293) ==۷۷۵۴== by 0x4E8F7F6: fprintf (fprintf.c:32) ==۷۷۵۴== by 0x400AC7: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== Address 0x5203c88 is 0 bytes after a block of size 1,000 alloc'd ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400764: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC Let's write something inside p6 Data inside chunk p3: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ==۷۷۵۴== ==۷۷۵۴== HEAP SUMMARY: ==۷۷۵۴== in use at exit: 5,000 bytes in 4 blocks ==۷۷۵۴== total heap usage: 6 allocs, 2 frees, 7,000 bytes allocated ==۷۷۵۴== ==۷۷۵۴== 1,۰۰۰ bytes in 1 blocks are definitely lost in loss record 1 of 4 ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400748: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== ==۷۷۵۴== 1,۰۰۰ bytes in 1 blocks are definitely lost in loss record 2 of 4 ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400764: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== ==۷۷۵۴== 1,۰۰۰ bytes in 1 blocks are definitely lost in loss record 3 of 4 ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400780: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== ==۷۷۵۴== 2,۰۰۰ bytes in 1 blocks are definitely lost in loss record 4 of 4 ==۷۷۵۴== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==۷۷۵۴== by 0x400A0B: main (in /home/pwn/Desktop/valgrind_test1) ==۷۷۵۴== ==۷۷۵۴== LEAK SUMMARY: ==۷۷۵۴== definitely lost: 5,000 bytes in 4 blocks ==۷۷۵۴== indirectly lost: 0 bytes in 0 blocks ==۷۷۵۴== possibly lost: 0 bytes in 0 blocks ==۷۷۵۴== still reachable: 0 bytes in 0 blocks ==۷۷۵۴== suppressed: 0 bytes in 0 blocks ==۷۷۵۴== ==۷۷۵۴== For counts of detected and suppressed errors, rerun with: -v ==۷۷۵۴== ERROR SUMMARY: 7 errors from 6 contexts (suppressed: 0 from 0)
خوب در بالا مشاهده میکنیم که باگ برای هیپ گزارش کرده است. ابزار پیش فرض valgrind نیز memcheck است که ست نمودن –leak-check اطلاعاتی بیشتری در اختیارمان قرار خواهد گرفت.
-
قابلیت های Sanitizer
این قابلیت توسط گوگل ایجاد شده است تا بخشی از LLVM باشد [لینک] . در gcc4.8 نیز قابلیت های مانند ASAN,TSAN نیز پشتیبانی می شود. استفاده از sanitizers در روند فازینگ میتونه خیلی مفید باشه اما چون instrumentation در زمان کامپایل انجام میشه پس نیاز به سورس برنامه خواهیم داشت. بهرحال باید این مورد رو همیشه یادمون باشه که استفاده از این قابلیت تنها برای تست برنامه مورد استفاده قرار میگیرند و محصول نهایی نباید با این سوییچ ها کامپایل شود.
ASAN برای تشخیص خطاهای Use after free, Heap/Stack buffer overflow, Memory leaks, … مورد استفاده قرار میگیرد. برای استفاده از ASAN در Clang می توان از -fsanitize=address
استفاده کرد. MemorySanitizer به ما این اطمینان را می دهد که دارای overhead کمتری نسبت به Valgrind است و سرعت بالاتری در روند اجرا و تست ها را خواهیم داشت.
خوب سورس قبل که توسط Valgrind چک کردیم حالا با استفاده از ASAN اون رو بررسی می کنیم:
# gcc valgrind_test1.c -fsanitize=address -o valgrind_test1 # ./valgrind_test1 This is a simple chunks overlapping problem This is also referenced as Nonadjacent Free Chunk Consolidation Attack Let's start to allocate 5 chunks on the heap: chunk p1 from 0x61900000fa80 to 0x61900000fe68 chunk p2 from 0x61900000f580 to 0x61900000f968 chunk p3 from 0x61900000f080 to 0x61900000f468 chunk p4 from 0x61900000eb80 to 0x61900000ef68 chunk p5 from 0x61900000e680 to 0x61900000ea68 Let's free the chunk p4. In this case this isn't coealesced with top chunk since we have p5 bordering top chunk after p4 Let's trigger the vulnerability on chunk p1 that overwrites the size of the in use chunk p2 with the size of chunk_p2 + size of chunk_p3 ================================================================= ==۱۰۶۳۸==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61900000fe68 at pc 0x000000400e48 bp 0x7fff4f2fc8b0 sp 0x7fff4f2fc8a0 WRITE of size 4 at 0x61900000fe68 thread T0 #۰ 0x400e47 in main (/home/pwn/Desktop/valgrind_test1+0x400e47) #۱ 0x7f1ff50cf82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #۲ 0x400928 in _start (/home/pwn/Desktop/valgrind_test1+0x400928) 0x61900000fe68 is located 0 bytes to the right of 1000-byte region [0x61900000fa80,0x61900000fe68) allocated by thread T0 here: #۰ 0x7f1ff5510602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #۱ 0x400ace in main (/home/pwn/Desktop/valgrind_test1+0x400ace) #۲ 0x7f1ff50cf82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 main Shadow bytes around the buggy address: 0x0c327fff9f70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c327fff9fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa 0x0c327fff9fd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff9fe0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff9ff0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==۱۰۶۳۸==ABORTING
مشاهده می کنیم که مشکل سرریز هیپ در سورس کدهایمان وجود دارد.
و اما نکته آخر که می تونیم در جهت داشتن برنامه ای امن بگیم، به جای نادیده گرفتن پیام های کامپایلری و suppress کردن آنها، بهتره که کدها رو بررسی و خطاها رو رفع کنیم. ممکنه درحین بررسی کدها با خطاهای زیادی روبرو بشین و با خودتون بگین که : “من کد رو درست نوشتم و بدرستی کارمیکنه بنابراین خطاها و اخطارهایی که میبینم False-Positive است!” اما شاید اینطور هم نباشه و کدی که شما نوشتین یک Smell Code باشه! و از پیچیدگی بیجا و صحیح ننوشتن کد دارین اون اخطار و خطا رو دریافت می کنین. پس با دقت بیشتر کدهاتون رو بررسی کنین و بجای پاک کردن صورت مسئله سعی در رفع مشکلات داشته باشید. هرچند هیچ چیزی عاری از خطا نیست و درصدی خطا چه در کد و چه در ابزارها وجود دارد و خواهد داشت.
دیدگاهتان را بنویسید لغو پاسخ