IA_IAPI::allInsns_t::const_iterator IA_x86Details::findTableInsn() { // Check whether the jump is our table insn! Expression::Ptr cft = currentBlock->curInsn()->getControlFlowTarget(); if(cft) { std::vector<Expression::Ptr> tmp; cft->getChildren(tmp); if(tmp.size() == 1) { Expression::Ptr cftAddr = tmp[0]; zeroAllGPRegisters z(currentBlock->current); cftAddr->apply(&z); parsing_printf("\tChecking indirect jump %s for table insn\n", currentBlock->curInsn()->format().c_str()); if(z.isDefined() && z.getResult()) { parsing_printf("\tAddress in jump\n"); return currentBlock->curInsnIter; } } } IA_IAPI::allInsns_t::const_iterator c = currentBlock->curInsnIter; while(!isTableInsn(c->second) && c != currentBlock->allInsns.begin()) { --c; } if(isTableInsn(c->second)) { return c; } return currentBlock->allInsns.end(); }
bool IA_x86Details::handleAdd(IA_IAPI& block) { parsing_printf("\t found add insn %s without obvious thunk\n", block.getInstruction()->format().c_str()); // Check table insn and bail if it's not of the mov eax, [eax] form // We do this indirectly: if there was already a displacment that we // could find in the table insn, we have a "table address"; otherwise, check adds if(tableInsn.addrFromInsn != 0) { return false; } // Use the add operand as our table base; we're handling tables of the form: // <reg = index> // add reg, $base // mov reg, [reg] // jmp *reg Expression::Ptr addExpr = block.getInstruction()->getOperand(1).getValue(); zeroAllGPRegisters z(block.getAddr()); addExpr->apply(&z); thunkInsn.insn = block.getInstruction(); thunkInsn.addrFromInsn = z.getResult(); thunkInsn.addrOfInsn = block.getAddr(); parsing_printf("\t setting thunk offset to 0x%lx (EXPERIMENTAL!)\n", thunkInsn.addrFromInsn); return thunkInsn.addrFromInsn != 0; }
void IA_x86Details::computeTableAddress() { // Extract displacement from table insn Expression::Ptr displacementSrc; if(tableInsn.insn->getCategory() == c_BranchInsn) { Expression::Ptr op = tableInsn.insn->getOperand(0).getValue(); std::vector<Expression::Ptr> tmp; op->getChildren(tmp); if(tmp.empty()) { displacementSrc = op; } else { displacementSrc = tmp[0]; } } else { parsing_printf("\tcracking table instruction %s\n", tableInsn.insn->format().c_str()); std::vector<Expression::Ptr> tmp; Expression::Ptr op = tableInsn.insn->getOperand(1).getValue(); if(!op) { parsing_printf("\ttable insn BAD! (no second operand)\n"); return; } if(tableInsn.insn->getOperation().getID() != e_lea) { op->getChildren(tmp); if(tmp.empty()) { parsing_printf("\ttable insn BAD! (not LEA, second operand not a deref)\n"); return; } displacementSrc = tmp[0]; } else { displacementSrc = op; } } zeroAllGPRegisters z(tableInsn.addrOfInsn + tableInsn.insn->size()); displacementSrc->apply(&z); if(!z.isDefined()) { parsing_printf("\ttable insn: %s, displacement %s, bind of all GPRs FAILED\n", tableInsn.insn->format().c_str(), displacementSrc->format().c_str()); return; } else { tableInsn.addrFromInsn = z.getResult(); } parsing_printf("\ttableInsn.addrFromInsn set to 0x%lx\n",tableInsn.addrFromInsn); }
void dyninst_analyze_address_taken(BPatch_addressSpace *handle, DICFG *cfg) { /* XXX: this is the most naive address-taken analysis that can be used by the * lbr_analysis_pass. More sophisticated ones can be (and are) plugged in in the pass. * This naive solution is provided only for comparison with more sophisticated ones. * * This analysis looks for instruction operands that correspond to known function addresses, * and then marks these functions as having their address taken. In particular, we * do /not/ look for function pointers stored in (static) memory, or for function * pointers that are computed at runtime. */ SymtabCodeSource *sts; CodeObject *co; std::vector<BPatch_object*> objs; handle->getImage()->getObjects(objs); assert(objs.size() > 0); const char *bin = objs[0]->pathName().c_str(); // Create a new binary object sts = new SymtabCodeSource((char*)bin); co = new CodeObject(sts); // Parse the binary co->parse(); BPatch_image *image = handle->getImage(); std::vector<BPatch_module *> *mods = image->getModules(); std::vector<BPatch_module *>::iterator mods_iter; for (mods_iter = mods->begin(); mods_iter != mods->end(); mods_iter++) { std::vector<BPatch_function *> *funcs = (*mods_iter)->getProcedures(false); std::vector<BPatch_function *>::iterator funcs_iter = funcs->begin(); for(; funcs_iter != funcs->end(); funcs_iter++) { co->parse((Address)(*funcs_iter)->getBaseAddr(), true); BPatch_flowGraph *fg = (*funcs_iter)->getCFG(); std::set<BPatch_basicBlock*> blocks; fg->getAllBasicBlocks(blocks); std::set<BPatch_basicBlock*>::iterator block_iter; for (block_iter = blocks.begin(); block_iter != blocks.end(); ++block_iter) { BPatch_basicBlock *block = (*block_iter); std::vector<Instruction::Ptr> insns; block->getInstructions(insns); std::vector<Instruction::Ptr>::iterator insn_iter; for (insn_iter = insns.begin(); insn_iter != insns.end(); ++insn_iter) { Instruction::Ptr ins = *insn_iter; std::vector<Operand> ops; ins->getOperands(ops); std::vector<Operand>::iterator op_iter; for (op_iter = ops.begin(); op_iter != ops.end(); ++op_iter) { Expression::Ptr expr = (*op_iter).getValue(); struct OperandAnalyzer : public Dyninst::InstructionAPI::Visitor { virtual void visit(BinaryFunction* op) {}; virtual void visit(Dereference* op) {} virtual void visit(Immediate* op) { address_t addr; ArmsFunction *func; switch(op->eval().type) { case s32: addr = op->eval().val.s32val; break; case u32: addr = op->eval().val.u32val; break; case s64: addr = op->eval().val.s64val; break; case u64: addr = op->eval().val.u64val; break; default: return; } func = cfg_->find_function(addr); if(func) { printf("Instruction [%s] references function 0x%jx\n", ins_->format().c_str(), addr); func->set_addr_taken(); } } virtual void visit(RegisterAST* op) {} OperandAnalyzer(DICFG *cfg, Instruction::Ptr ins) { cfg_ = cfg; ins_ = ins; }; DICFG *cfg_; Instruction::Ptr ins_; }; OperandAnalyzer oa(cfg, ins); expr->apply(&oa); } } } } } }