Введение
Техника анализа программ
В информатике символическое исполнение (также символическая оценка или симбекс) — это метод анализа программы для определения, какие входные данные приводят к выполнению каждой её части. Интерпретатор отслеживает выполнение программы, используя символические значения для входных данных вместо фактических, как это происходит при обычном выполнении программы. В результате получаются выражения, представленные через эти символы, для выражений и переменных в программе, а также ограничения, выраженные через эти символы, для возможных результатов каждой условной ветви. В конечном итоге, возможные входные данные, вызывающие выполнение ветви, можно определить, решив эти ограничения. Область символического моделирования применяет ту же концепцию к аппаратному обеспечению. Символьные вычисления применяют эту концепцию к анализу математических выражений.
In computer science, symbolic execution (also symbolic evaluation or symbex) is a means of analyzing a program to determine what inputs cause each part of a program to execute. An interpreter follows the program, assuming symbolic values for inputs rather than obtaining actual inputs as normal execution of the program would. It thus arrives at expressions in terms of those symbols for expressions and variables in the program, and constraints in terms of those symbols for the possible outcomes of each conditional branch. Finally, the possible inputs that trigger a branch can be determined by solving the constraints. The field of symbolic simulation applies the same concept to hardware. Symbolic computation applies the concept to the analysis of mathematical expressions.
Взрыв траектории
Символическое выполнение всех достижимых путей программы не масштабируется для больших программ. Количество достижимых путей в программе растет экспоненциально с увеличением размера программы и может быть даже бесконечным в случае программ с неограниченным количеством итераций циклов. Решения проблемы взрыва путей обычно используют эвристики для поиска путей с целью увеличения покрытия кода, сокращения времени выполнения за счет параллелизации независимых путей или объединения схожих путей. Одним из примеров объединения является верификация, которая "использует статическое символическое выполнение для усиления эффекта динамического символического выполнения".
Эффективность, зависящая от программы
Символическое исполнение позволяет анализировать программу по путям выполнения, что является преимуществом по сравнению с анализом программы по входным данным, как это делают другие методы тестирования (например, динамический анализ программ). Однако, если небольшое количество входных данных приводит к одному и тому же пути выполнения программы, то выигрыш от такого подхода по сравнению с тестированием каждого входного значения по отдельности незначителен.
Альязинг памяти
Символическое выполнение усложняется, когда к одному и тому же участку памяти можно обращаться под разными именами (алиасинг). Алиасинг не всегда удается определить статически, поэтому механизм символического выполнения не может понять, что изменение значения одной переменной влечет за собой изменение другой.
Массивы
Поскольку массив представляет собой набор множества различных значений, символические исполнители должны либо рассматривать весь массив как одно значение, либо рассматривать каждый элемент массива как отдельную ячейку памяти. Проблема рассмотрения каждого элемента массива по отдельности заключается в том, что ссылка, такая как "A[i]", может быть определена только динамически, когда значение переменной i известно конкретно. Cloud9 и Otter используют этот подход, реализуя модели для операций с файловой системой, сокетами, межпроцессным взаимодействием и т.п., создавая полную копию состояния системы. Символические инструменты выполнения, основанные на виртуальных машинах, решают проблему окружения, создавая полную копию состояния виртуальной машины. Например, в S2E каждое состояние является независимым снимком виртуальной машины, который может быть выполнен отдельно. Этот подход избавляет от необходимости написания и поддержки сложных моделей и позволяет символически выполнять практически любой исполняемый файл. Однако, он требует больших затрат памяти (снимки виртуальных машин могут быть значительного размера).
Инструменты
URL-адрес целевого инструмента | Может ли кто-либо использовать его | Открытый исходный код | Загружаемый
--- | --- | --- | ---
angr libVEX на основе (поддерживает x86, x86 64, ARM, AARCH64, MIPS, MIPS64, PPC, PPC64 и Java) http://angr.io/ | Да | Да | Да
BE PUM x86 https://github.com/NMHai/BE PUM | Да | Да | Да
BINSEC x86, ARM, RISC V (32 бита) http://binsec.github.io | Да | Да | Да
crucible LLVM, JVM, etc. https://github.com/GaloisInc/crucible | Да | Да | Да
ExpoSE JavaScript https://github.com/ExpoSEJS/ExpoSE | Да | Да | Да
FuzzBALL VineIL / Native http://bitblaze.cs.berkeley.edu/fuzzball.html | Да | Да | Да
GenSym LLVM https://github.com/Generative Program Analysis/GenSym | Да | Да | Да
Jalangi2 JavaScript https://github.com/Samsung/jalangi2 | Да | Да | Да
janala2 Java https://github.com/ksen007/janala2 | Да | Да | Да
JaVerT JavaScript https://www.doc.ic.ac.uk/~pg/publications/FragosoSantos2019JaVerT.pdf | Да | Да | Да
JBSE Java https://github.com/pietrobraione/jbse | Да | Да | Да
jCUTE Java https://github.com/osl/jcute | Да | Да | Да
KeY Java http://www.keyproject.org/ | Да | Да | Да
Kite LLVM http://www.cs.ubc.ca/labs/isd/Projects/Kite/ | Да | Да | Да
KLEE LLVM https://klee.github.io/ | Да | Да | Да
Kudzu JavaScript http://webblaze.cs.berkeley.edu/2010/kudzu/kudzu.pdf | Да | Да | Да
MPro Ethereum Virtual Machine (EVM) / Native https://sites.google.com/view/smartcontractanalysis/home | Да | Да | Да
Maat Ghidra P-code / SLEIGH https://maat.re/ | Да | Да | Да
Manticore x86 64, ARMv7, Ethereum Virtual Machine (EVM) / Native https://github.com/trailofbits/manticore/ | Да | Да | Да
Mayhem Binary http://forallsecure.com | Да | Да | Да
Mythril Ethereum Virtual Machine (EVM) / Native https://github.com/ConsenSys/mythril | Да | Да | Да
Otter C https://bitbucket.org/khooyp/otter/overview | Да | Да | Да
Oyente NG Ethereum Virtual Machine (EVM) / Native http://www.comp.ita.br/labsca/waiaf/papers/RafaelShigemura paper 16.pdf | Да | Да | Да
Pathgrind Native 32 bit Valgrind на основе https://github.com/codelion/pathgrind | Да | Да | Да
Pex .NET Framework http://research.microsoft.com/en-us/projects/pex/ | Да | Да | Да
pysymemu x86 64 / Native https://github.com/feliam/pysymemu/ | Да | Да | Да
Rosette Dialect of Racket https://emina.github.io/rosette/ | Да | Да | Да
Rubyx Ruby http://www.cs.umd.edu/~avik/papers/ssarorwa.pdf | Да | Да | Да
S2E x86, x86 64, ARM / User и kernel mode binaries http://s2e.systems/ | Да | Да | Да
Symbolic PathFinder (SPF) Java Bytecode https://github.com/SymbolicPathFinder | Да | Да | Да
SymDroid Dalvik bytecode http://www.cs.umd.edu/~jfoster/papers/symdroid.pdf | Да | Да | Да
SymJS JavaScript https://core.ac.uk/download/pdf/24067593.pdf | Да | Да | Да
SymCC LLVM https://www.s3.eurecom.fr/tools/symbolic execution/symcc.html | Да | Да | Да
Triton x86, x86 64, ARM и AArch64 https://triton.quarkslab.com | Да | Да | Да
Verifast C, Java https://people.cs.kuleuven.be/~bart.jacobs/verifast | Да | Да | Да
Предыдущие версии инструментов
EXE — более ранняя версия KLEE. Описание EXE можно найти здесь.