Skip to content

Symbolic Execution

Symbolic execution explores lifted LowUIR with SymbExpr values and optional solver-backed reachability or satisfiability queries.

Sources:

  • B2R2/src/MiddleEnd/SymbEval/SymbExecutor.fs
  • B2R2/src/MiddleEnd/SymbEval/SymbStateAccessor.fs
  • B2R2/src/MiddleEnd/SymbEval/SymbExpr.fs
  • B2R2/src/MiddleEnd/SymbEval/ISolver.fs
  • B2R2/src/MiddleEnd/SymbEval/SymbModel.fs
  • B2R2/src/MiddleEnd/SymbEval/SymbCallHook.fs
APIMeaning
SymbExecutor(hdl)Create a symbolic executor for a binary.
CreateState()Create a SymbState with BinSectionBackedMemory and no initial registers.
CreateState(options)Create a state with explicit StateCreationOptions<ISymbMemory, SymbExpr>.
Run(start, state, options)Run with SymbRunOptions.
Run(start, state, calls, query, solver)Convenience overload using call policy, query request, and solver.

CreateState(options) accepts StateCreationOptions<ISymbMemory, SymbExpr>.

type StateCreationOptions<'Memory, 'Value> =
{ Memory: InitialMemory<'Memory>
Registers: (RegisterID * 'Value)[] }
Initial memoryMeaning
EmptyMemoryStart from an empty symbolic memory object.
PreinitializedMemory memoryStart from a caller-provided symbolic memory object.
BinSectionBackedMemoryBack memory reads with loaded binary sections.

Initial registers are passed as (RegisterID * SymbExpr)[].

APIMeaning
ReachAddress targetAsk if execution can reach an address.
ReachState predicateAsk if execution can reach a state predicate.
SatisfyAddress targetAsk for concrete symbolic-input values reaching an address.
SatisfyState predicateAsk for concrete symbolic-input values reaching a state predicate.
AvoidAddresses addrsDiscard states whose PC reaches any address in the set.
AvoidState predicateDiscard states matching a predicate.
NoSolverRun without solver support.
CustomSolver solverUse an ISolver implementation.

Use SymbQueryRequest when the query also needs model values. This is the form used by the loginme solution to ask the solver for concrete bytes of a symbolic input buffer.

type SymbQueryRequest =
{ Query: SymbQuery
QueryValues: IQueryExpr }
FieldMeaning
QueryReachability or satisfiability query, such as SatisfyAddress endAddr.
QueryValuesSymbolic expressions or buffers to extract from the solver model.

QueryValues accepts any IQueryExpr. SymbByteBuffer implements IQueryExpr, so a buffer returned by SetArgumentSymbolicString can be used directly.

let buf = accessor.SetArgumentSymbolicString(0, "password")
let query =
{ Query = SatisfyAddress endAddr
QueryValues = buf }

SymbRunOptions.Default(query) creates a bounded default with no solver. SymbRunOptions.Default(query, solver) uses a solver. Defaults are FollowDirectInternalCalls, MaxDepth = 500, MaxStates = 4096, LoopBound = 1, RunTimeout = 30000, path pruning disabled, and stop at first answer enabled.

MemberMeaning
AddQueryValue value / AddQueryValues valuesAdd symbolic values to model extraction.
WithQueryValues valuesReplace model extraction values with a sequence or IQueryExpr.
AddQueryBuffer buffer / AddQueryBuffers buffersAdd symbolic byte buffers to model extraction.
AddAvoidAddress addr / AddAvoidAddresses addrsAdd addresses to avoid.
WithAvoidAddresses addrsReplace the avoid set.
WithAvoid avoid / AddAvoid avoidSet or combine avoid conditions.
AddAvoidState predicateAdd a predicate-based avoid condition.
StopAtCalls()Stop before calls.
FollowDirectInternalCalls()Follow direct internal calls.
WithCallHooks hooksUse a prepared hook registry.
RegisterCallHook(target, hook) / RegisterCallHooks hooksRegister symbolic call hooks.
WithSolver solverReplace the solver backend.
EnablePathPruning() / DisablePathPruning()Toggle solver-backed path pruning.
EnableStopAtFirstAnswer() / DisableStopAtFirstAnswer()Toggle early stop after an answer.
WithWarmUpRanges rangesPre-lift half-open address ranges [start, finish).
ResultMeaning
Reachable answersOne or more states reached the target.
UnreachableNo explored state reached the target.
Satisfiable answersOne or more concrete assignments satisfy the query.
UnsatisfiableNo explored assignment satisfies the query.
Unknown failuresExecution stopped or pruned before a complete answer.
TimedOut(timeout, result)Timeout with a partial result.

SymbSatisfiabilityAnswer.Model wraps solver values in SymbModel. SymbRunResult.GetSatisfiabilityAnswer() returns the first satisfiability answer or raises if none is available.

Common stop reasons are StoppedAtCall, DepthLimitReached, StateLimitReached, InvalidInstructionStopped, SideEffectStopped, EvaluationFailed, MissingSolverForQuery, SolverQueryFailed, and RunTimeoutReached. Common prune reasons are AvoidedAddress, AvoidedState, LoopBoundReached, InfeasiblePath, and SolverPruningFailed.

APIMeaning
SymbStateAccessor(hdl, state)Linux ABI accessor.
SymbStateAccessor(hdl, state, os)Accessor for a specific OS.
DefaultStringBoundDefault symbolic C-string payload length: 64.
DefaultStackTopDefault stack top: 0x7fffffffe000UL.
StateUnderlying SymbState.
WordType / WordBytesTarget word type and byte width.
StackPointerCurrent concrete stack pointer value.
WordValue(addr)Create a concrete word-sized SymbExpr.
CreateSymbolicBytes(name, length)Create symbolic byte variables without writing memory.
TryGetConcreteRegister ridRead a register as a concrete address, returning Result.
TryGetStackPointer() / TrySetStackPointer addrStack pointer access without throwing when unavailable.
TryPushToStack value / TryPopFromStack()Stack operations returning Result.
WriteSymbolicBuffer(name, addr, length)Write symbolic bytes at addr.
WriteSymbolicBuffer(name, addr, length, nullTerminate)Write symbolic bytes and optionally append a null byte.
AllocateSymbolicBuffer(name, length)Allocate stack space and write symbolic bytes.
AllocateSymbolicBuffer(name, length, nullTerminate)Allocate symbolic bytes with optional null termination.
SetArgumentBuffer(idx, buffer)Set an argument register to the buffer address.
AllocateSymbolicString(name) / AllocateSymbolicString(name, maxLength)Allocate a null-terminated symbolic string.
SetArgumentSymbolicString(idx, name) / SetArgumentSymbolicString(idx, name, maxLength)Allocate a symbolic string and pass it as an argument.

SymbStateAccessor also exposes common state-accessor members for registers, arguments, return values, and stack buffers.

APIMeaning
SetStackPointer(addr)Set the stack pointer register.
InitializeStack(stackTop)Initialize the stack pointer to an explicit address.
InitializeFramePointer()Initialize the frame pointer from the current stack pointer.
SetRegister(name, value) / GetRegister(name)Write or read a symbolic register value by architecture register name.
SetRegister(rid, value) / GetRegister(rid)Write or read a symbolic register value by RegisterID.
ZeroRegisters(names: string[]) / ZeroRegisters(rids: RegisterID[])Clear selected registers to zero values.
SetArgument(index, value)Set the ABI argument register at index.
GetReturnValue()Read the ABI return register.
AllocateStackBuffer(size)Reserve stack space and return its address.
PushToStack(value) / PopFromStack()Push or pop a word-sized value.
Field or memberMeaning
NamePrefix used for byte variable names.
AddressConcrete start address.
BytesSymbolic bytes in address order.
NullTerminatedTrue when a null byte was written after the symbolic bytes.
ValuesSame bytes, ready for query extraction.

SymbByteBuffer implements IQueryExpr, so it can be passed through AddQueryBuffer or combined with other query expressions.

APIMeaning
SymbExprSymbolic bit-vector expression: Const, Var, UnOp, BinOp, RelOp, Load, Ite, Cast, Extract, FuncApp, or Undef.
SymbExpr.zero typ / one typConcrete zero/one symbolic expressions.
SymbExpr.trueExpr / falseExpr1-bit LowUIR condition constants.
SymbExpr.relop op lhs rhsBuild a relational path-condition expression.
IQueryExpr.QueryValuesExpressions requested from a solver model.
QueryExpr.EmptyRequest no model values.
QueryExpr.Value exprRequest one symbolic expression value.
QueryExpr.Values exprsCombine multiple query expressions.

SymbRunOptions.Default(queryRequest, solver) copies queryRequest.QueryValues into the run options. The convenience overload executor.Run(start, state, calls, queryRequest, solver) uses the same request shape.

APIMeaning
ISolver.CheckSat smt2Run a satisfiability check over an SMT-LIB2 assertion script.
ISolver.GetModels smt2Return a raw solver model for an SMT-LIB2 assertion script.
SolverStatusParsed solver status: Sat, Unsat, or Unknown.
SolverValueOne named BitVector value returned by a solver.
SymbModel.ValuesRaw solver values.
SymbModel.TryGetValue name / GetValue nameRead a named model value.
SymbModel.GetByte name / GetByte exprRead a model value as a byte.
SymbModel.ReadBytes values / ReadBytes bufferMaterialize symbolic bytes.
SymbModel.ReadCString values / ReadCString bufferMaterialize a null-terminated ASCII string.
APIMeaning
SymbCallContextHook context: call site, target, return address, word type, endian, argument registers, and return register.
SymbCallHookFunction type: SymbCallContext -> SymbState -> Result<SymbState list, SymbEvalError>.
SymbCallHookRegistry()Empty hook registry.
SymbCallHookRegistry(hooks)Registry initialized from target-hook pairs.
Register(target, hook)Return a registry with one hook added.
RegisterMany hooksReturn a registry with many hooks added.
TryFind targetLook up a hook by concrete target address.
SymbCallHooks.strlenBuilt-in bounded symbolic model for strlen.
SymbCallHooks.strlenBounded maxScanSame model with an explicit scan bound.
let executor = SymbExecutor hdl
let state = executor.CreateState()
let accessor = SymbStateAccessor(hdl, state)
accessor.InitializeDefaultStack()
accessor.SetArgumentSymbolicString(0, "input", 16) |> ignore
let options =
SymbRunOptions.Default(ReachAddress 0x401080UL)
.WithAvoidAddresses [ 0x401050UL ]
match executor.Run(0x401000UL, state, options) with
| Reachable answers ->
answers
|> List.iter (fun answer ->
printfn "reachable at 0x%x" answer.Target)
| result ->
printfn "%A" result