/* Add a path constraint */ void PathManager::addPathConstraint(const triton::arch::Instruction& inst, triton::engines::symbolic::SymbolicExpression* expr) { triton::engines::symbolic::PathConstraint pco; triton::ast::AbstractNode* pc = nullptr; triton::uint64 srcAddr = 0; triton::uint64 dstAddr = 0; triton::uint32 size = 0; pc = expr->getAst(); if (pc == nullptr) throw triton::exceptions::PathManager("PathManager::addPathConstraint(): The PC node cannot be null."); /* If PC_TRACKING_SYMBOLIC is enabled, Triton will track path constraints only if they are symbolized. */ if (triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::PC_TRACKING_SYMBOLIC) && !pc->isSymbolized()) return; /* If ONLY_ON_TAINTED is enabled and the expression untainted, Triton will skip the storing process. */ if (triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::ONLY_ON_TAINTED) && !expr->isTainted) return; /* Basic block taken */ srcAddr = inst.getAddress(); dstAddr = pc->evaluate().convert_to<triton::uint64>(); size = pc->getBitvectorSize(); if (size == 0) throw triton::exceptions::PathManager("PathManager::addPathConstraint(): The PC node size cannot be zero."); if (pc->getKind() == triton::ast::ZX_NODE) pc = pc->getChilds()[1]; /* Multiple branches */ if (pc->getKind() == triton::ast::ITE_NODE) { triton::uint64 bb1 = pc->getChilds()[1]->evaluate().convert_to<triton::uint64>(); triton::uint64 bb2 = pc->getChilds()[2]->evaluate().convert_to<triton::uint64>(); triton::ast::AbstractNode* bb1pc = (bb1 == dstAddr) ? triton::ast::equal(pc, triton::ast::bv(dstAddr, size)) : triton::ast::lnot(triton::ast::equal(pc, triton::ast::bv(dstAddr, size))); triton::ast::AbstractNode* bb2pc = (bb2 == dstAddr) ? triton::ast::equal(pc, triton::ast::bv(dstAddr, size)) : triton::ast::lnot(triton::ast::equal(pc, triton::ast::bv(dstAddr, size))); pco.addBranchConstraint(bb1 == dstAddr, srcAddr, bb1, bb1pc); pco.addBranchConstraint(bb2 == dstAddr, srcAddr, bb2, bb2pc); this->pathConstraints.push_back(pco); } /* Direct branch */ else { pco.addBranchConstraint(true, srcAddr, dstAddr, triton::ast::equal(pc, triton::ast::bv(dstAddr, size))); this->pathConstraints.push_back(pco); } }
void Architecture::buildSemantics(triton::arch::Instruction& inst) const { if (!this->cpu) throw std::runtime_error("Architecture::buildSemantics(): You must define an architecture."); /* Pre IR processing */ inst.preIRInit(); /* If the symbolic and taint engine are disable we skip the processing */ if (!triton::api.isSymbolicEngineEnabled() && !triton::api.isTaintEngineEnabled()) return; /* Backup the symbolic engine in the case where only taint is available. */ if (!triton::api.isSymbolicEngineEnabled()) triton::api.backupSymbolicEngine(); /* Processing */ this->cpu->buildSemantics(inst); /* Post IR processing */ inst.postIRInit(); /* * If the symbolic engine is disable we delete symbolic * expressions and AST nodes. Note that if the taint engine * is enable we must compute semanitcs to spread the taint. */ if (!triton::api.isSymbolicEngineEnabled()) { std::set<triton::ast::AbstractNode*> uniqueNodes; std::vector<triton::engines::symbolic::SymbolicExpression*>::iterator it; for (it = inst.symbolicExpressions.begin(); it != inst.symbolicExpressions.end(); it++) { triton::api.extractUniqueAstNodes(uniqueNodes, (*it)->getAst()); triton::api.removeSymbolicExpression((*it)->getId()); } if (!triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::AST_DICTIONARIES)) { /* Remove node only if AST_DICTIONARIES is disabled */ triton::api.freeAstNodes(uniqueNodes); } inst.symbolicExpressions.clear(); triton::api.restoreSymbolicEngine(); } /* * If the symbolic engine is defined to process symbolic * execution only on tainted instructions, we delete all * expressions untainted and their AST nodes. */ if (triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::ONLY_ON_TAINTED)) { std::set<triton::ast::AbstractNode*> uniqueNodes; std::vector<triton::engines::symbolic::SymbolicExpression*> newVector; std::vector<triton::engines::symbolic::SymbolicExpression*>::iterator it; for (it = inst.symbolicExpressions.begin(); it != inst.symbolicExpressions.end(); it++) { if ((*it)->isTainted == triton::engines::taint::UNTAINTED) { triton::api.extractUniqueAstNodes(uniqueNodes, (*it)->getAst()); triton::api.removeSymbolicExpression((*it)->getId()); } else newVector.push_back(*it); } if (!triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::AST_DICTIONARIES)) { /* Remove node only if AST_DICTIONARIES is disabled */ triton::api.freeAstNodes(uniqueNodes); } inst.symbolicExpressions = newVector; } /* * If the symbolic engine is defined to process symbolic * execution only on symbolized expressions, we delete all * concrete expressions and their AST nodes. */ if (triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::ONLY_ON_SYMBOLIZED)) { std::set<triton::ast::AbstractNode*> uniqueNodes; std::vector<triton::engines::symbolic::SymbolicExpression*> newVector; std::vector<triton::engines::symbolic::SymbolicExpression*>::iterator it; for (it = inst.symbolicExpressions.begin(); it != inst.symbolicExpressions.end(); it++) { if ((*it)->getAst()->isSymbolized() == false) { triton::api.extractUniqueAstNodes(uniqueNodes, (*it)->getAst()); triton::api.removeSymbolicExpression((*it)->getId()); } else newVector.push_back(*it); } if (!triton::api.isSymbolicOptimizationEnabled(triton::engines::symbolic::AST_DICTIONARIES)) { /* Remove node only if AST_DICTIONARIES is disabled */ triton::api.freeAstNodes(uniqueNodes); } inst.symbolicExpressions = newVector; } }
void x86Cpu::buildSemantics(triton::arch::Instruction &inst) { if (!inst.getType()) throw std::runtime_error("x8664Cpu::buildSemantics(): You must disassemble the instruction before."); triton::arch::x86::semantics::build(inst); }
void x86Cpu::disassembly(triton::arch::Instruction &inst) { csh handle; cs_insn* insn; size_t count; /* Check if the opcodes and opcodes' size are defined */ if (inst.getOpcodes() == nullptr || inst.getOpcodesSize() == 0) throw std::runtime_error("x86Cpu::disassembly(): Opcodes and opcodesSize must be definied."); /* Open capstone */ if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK) throw std::runtime_error("x86Cpu::disassembly(): Cannot open capstone."); /* Init capstone's options */ cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL); /* Let's disass and build our operands */ count = cs_disasm(handle, inst.getOpcodes(), inst.getOpcodesSize(), inst.getAddress(), 0, &insn); if (count > 0) { cs_detail* detail = insn->detail; for (triton::uint32 j = 0; j < count; j++) { /* Init the disassembly */ std::stringstream str; str << insn[j].mnemonic << " " << insn[j].op_str; inst.setDisassembly(str.str()); /* Init the instruction's type */ inst.setType(capstoneInstToTritonInst(insn[j].id)); /* Init operands */ for (triton::uint32 n = 0; n < detail->x86.op_count; n++) { cs_x86_op *op = &(detail->x86.operands[n]); switch(op->type) { case X86_OP_IMM: inst.operands.push_back(triton::arch::OperandWrapper(triton::arch::ImmediateOperand(op->imm, op->size))); break; case X86_OP_MEM: { triton::arch::MemoryOperand mem = inst.popMemoryAccess(); /* Set the size if the memory is not valid */ if (!mem.isValid()) mem.setPair(std::make_pair(((op->size * BYTE_SIZE_BIT) - 1), 0)); /* LEA if exists */ triton::arch::RegisterOperand base(triton::arch::x86::capstoneRegToTritonReg(op->mem.base)); triton::arch::RegisterOperand index(triton::arch::x86::capstoneRegToTritonReg(op->mem.index)); triton::arch::ImmediateOperand disp(op->mem.disp, op->size); triton::arch::ImmediateOperand scale(op->mem.scale, op->size); mem.setBaseReg(base); mem.setIndexReg(index); mem.setDisplacement(disp); mem.setScale(scale); inst.operands.push_back(triton::arch::OperandWrapper(mem)); break; } case X86_OP_REG: inst.operands.push_back(triton::arch::OperandWrapper(inst.getRegisterState(triton::arch::x86::capstoneRegToTritonReg(op->reg)))); break; default: break; } } } /* Set branch */ if (detail->groups_count > 0) { for (triton::uint32 n = 0; n < detail->groups_count; n++) { if (detail->groups[n] == X86_GRP_JUMP) inst.setBranch(true); if (detail->groups[n] == X86_GRP_JUMP || detail->groups[n] == X86_GRP_CALL || detail->groups[n] == X86_GRP_RET) inst.setControlFlow(true); } } cs_free(insn, count); } else throw std::runtime_error("x86Cpu::disassembly(): Failed to disassemble the given code."); cs_close(&handle); return; }