Skip to content

Commit 9e77633

Browse files
committed
Handle calls and invalid instructions in vmentry_concolic.py
1 parent 17ac061 commit 9e77633

2 files changed

Lines changed: 55 additions & 30 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
# ruff: noqa: E402
4+
5+
import sys
6+
from pathlib import Path
7+
8+
ROOT = Path(__file__).resolve().parents[1]
9+
if str(ROOT) not in sys.path:
10+
sys.path.insert(0, str(ROOT))
11+
12+
from llvm import Opcode
13+
14+
from tools.vmentry_concolic import SymVal, combine_values
15+
16+
17+
def test_unknown_sources_are_deduplicated_across_repeated_composition() -> None:
18+
source = SymVal.unknown("source_rax()", 64)
19+
value = source
20+
21+
for _ in range(100):
22+
value = combine_values(value, source, Opcode.Add, 64)
23+
24+
assert value.unknowns == frozenset({"source_rax()"})
25+
26+
27+
if __name__ == "__main__":
28+
test_unknown_sources_are_deduplicated_across_repeated_composition()
29+
print("PASS unknown-source deduplication")

tools/vmentry_concolic.py

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
if str(ROOT) not in sys.path:
1313
sys.path.insert(0, str(ROOT))
1414

15-
from capstone import CS_GRP_CALL, CS_GRP_JUMP, CS_OP_IMM, CS_OP_MEM, CsInsn
15+
from capstone import CS_GRP_JUMP, CS_OP_IMM, CS_OP_MEM
1616
from capstone.x86_const import X86_REG_RIP
1717
from llvm import IntPredicate, Opcode, Value, create_context
1818

@@ -707,26 +707,40 @@ def run(self) -> ConcolicResult:
707707
for step in range(self.cfg.max_steps):
708708
state.steps = step + 1
709709
code = self.container.get_data(rip, 15)
710-
insn = sem.cs_disasm(rip, code)
711-
instruction = f"{insn.mnemonic} {insn.op_str}".strip()
712-
self._record_seed_candidates(insn, state)
710+
try:
711+
insn = sem.cs_disasm(rip, code)
712+
except ValueError:
713+
insn = None
714+
instruction = f"invalid {code[0]:#04x}"
715+
else:
716+
instruction = f"{insn.mnemonic} {insn.op_str}".strip()
717+
self._record_seed_candidates(insn, state)
713718
if len(self.trace) < self.cfg.trace_limit:
714719
self.trace.append(f"{rip:#x}: {instruction}")
715720

716-
if insn.group(CS_GRP_CALL) and rip in self.cfg.follow_calls:
717-
self._lift_followed_call(sem, insn)
718-
else:
719-
block = sem.get_or_create_block(rip)
720-
if (
721-
block.first_instruction is not None
722-
and block.first_instruction.opcode == Opcode.Ret
723-
):
721+
block = sem.get_or_create_block(rip)
722+
if (
723+
block.first_instruction is not None
724+
and block.first_instruction.opcode == Opcode.Ret
725+
):
726+
if insn is None:
727+
sem.lift_invalid(rip)
728+
else:
724729
sem.lift_instruction(insn)
725730

726731
block = sem.insn_blocks[rip]
727732
block_result = interp.execute_block(block)
728733
if isinstance(block_result, BoundaryResult):
729734
boundary = cast("BoundaryResult[SymVal]", block_result)
735+
if boundary.name == "__striga_call" and rip in self.cfg.follow_calls:
736+
target = boundary.target.concrete
737+
if target is not None:
738+
if len(self.trace) < self.cfg.trace_limit:
739+
self.trace.append(
740+
f"{rip:#x}: follow __striga_call -> {target:#x}"
741+
)
742+
rip = target
743+
continue
730744
state.boundary_call = boundary.name
731745
state.boundary_value = boundary.target
732746
stop = rip
@@ -820,24 +834,6 @@ def _record_seed_candidates(self, insn, state: ExecutionState) -> None:
820834
Seed("lea_addr", insn.address, addr, f"lea {insn.op_str}"),
821835
)
822836

823-
def _lift_followed_call(self, sem: Semantics, insn: CsInsn) -> None:
824-
block = sem.get_or_create_block(insn.address)
825-
if (
826-
block.first_instruction is not None
827-
and block.first_instruction.opcode == Opcode.Ret
828-
):
829-
block.first_instruction.erase_from_parent()
830-
else:
831-
return
832-
target = insn.operands[0].imm
833-
fallthrough = insn.address + insn.size
834-
with block.create_builder() as ir:
835-
sem.ir = ir
836-
sem.insn = insn
837-
sem.push(sem.const64(fallthrough))
838-
ir.br(sem.get_or_create_block(target))
839-
sem.module.verify_or_raise()
840-
841837
def _write_outputs(self, result: ConcolicResult) -> None:
842838
self.cfg.out_dir.mkdir(parents=True, exist_ok=True)
843839
(self.cfg.out_dir / "trace.txt").write_text(

0 commit comments

Comments
 (0)