bool IA_IAPI::isFrameSetupInsn(Instruction::Ptr i) const { if(i->getOperation().getID() == e_mov) { if(i->readsMemory() || i->writesMemory()) { parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, not a reg-reg move\n", FILE__, __LINE__, i->format().c_str()); //return false; } if(i->isRead(stackPtr[_isrc->getArch()]) && i->isWritten(framePtr[_isrc->getArch()])) { if((unsigned) i->getOperand(0).getValue()->size() == _isrc->getAddressWidth()) { return true; } else { parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, size mismatch for %d-byte addr width\n", FILE__, __LINE__, i->format().c_str(), _isrc->getAddressWidth()); } } } return false; }
void SpringboardBuilder::generateBranch(Address from, Address to, codeGen &gen) { gen.invalidate(); gen.allocate(16); gen.setAddrSpace(addrSpace_); gen.setAddr(from); insnCodeGen::generateBranch(gen, from, to); springboard_cerr << "Generated springboard branch " << hex << from << "->" << to << dec << endl; #if 0 #include "InstructionDecoder.h" using namespace Dyninst::InstructionAPI; Address base = 0; InstructionDecoder deco(gen.start_ptr(),gen.size(),Arch_aarch64); Instruction::Ptr insn = deco.decode(); while(base<gen.used()+5) { std::stringstream rawInsn; unsigned idx = insn->size(); while(idx--) rawInsn << hex << setfill('0') << setw(2) << (unsigned int) insn->rawByte(idx); cerr << "\t" << hex << base << ": " << rawInsn.str() << " " << insn->format(base) << dec << endl; base += insn->size(); insn = deco.decode(); } #endif }
void LivenessAnalyzer::summarizeBlockLivenessInfo(Function* func, Block *block, bitArray &allRegsDefined) { if (blockLiveInfo.find(block) != blockLiveInfo.end()){ return; } livenessData &data = blockLiveInfo[block]; data.use = data.def = data.in = abi->getBitArray(); using namespace Dyninst::InstructionAPI; Address current = block->start(); InstructionDecoder decoder( reinterpret_cast<const unsigned char*>(getPtrToInstruction(block, block->start())), block->size(), block->obj()->cs()->getArch()); Instruction::Ptr curInsn = decoder.decode(); while(curInsn) { ReadWriteInfo curInsnRW; liveness_printf("%s[%d] After instruction %s at address 0x%lx:\n", FILE__, __LINE__, curInsn->format().c_str(), current); if(!cachedLivenessInfo.getLivenessInfo(current, func, curInsnRW)) { curInsnRW = calcRWSets(curInsn, block, current); cachedLivenessInfo.insertInstructionInfo(current, curInsnRW, func); } data.use |= (curInsnRW.read & ~data.def); // And if written, then was defined data.def |= curInsnRW.written; liveness_printf("%s[%d] After instruction at address 0x%lx:\n", FILE__, __LINE__, current); liveness_cerr << " " << regs1 << endl; liveness_cerr << " " << regs2 << endl; liveness_cerr << " " << regs3 << endl; liveness_cerr << "Read " << curInsnRW.read << endl; liveness_cerr << "Written " << curInsnRW.written << endl; liveness_cerr << "Used " << data.use << endl; liveness_cerr << "Defined " << data.def << endl; current += curInsn->size(); curInsn = decoder.decode(); } liveness_printf("%s[%d] Liveness summary for block:\n", FILE__, __LINE__); liveness_cerr << " " << regs1 << endl; liveness_cerr << " " << regs2 << endl; liveness_cerr << " " << regs3 << endl; liveness_cerr << "Used " << data.in << endl; liveness_cerr << "Def " << data.def << endl; liveness_cerr << "Use " << data.use << endl; liveness_printf("%s[%d] --------------------\n---------------------\n", FILE__, __LINE__); allRegsDefined |= data.def; return; }
bool Injector::inject(std::string libname) { int_process *proc = proc_->llproc(); pthrd_printf("Injecting %s into process %d\n", libname.c_str(), proc->getPid()); if (!checkIfExists(libname)) { perr_printf("Library %s doesn't exist\n", libname.c_str()); proc->setLastError(err_nofile, "File doesn't exist\n"); return false; } Codegen codegen(proc_, libname); if (!codegen.generate()) { perr_printf("Could not generate code\n"); proc->setLastError(err_internal, "Error in code generation"); return false; } int_iRPC::ptr irpc = int_iRPC::ptr(new int_iRPC(codegen.buffer().start_ptr(), codegen.buffer().size(), false, true, codegen.buffer().startAddr())); // Don't try to execute a library name... irpc->setStartOffset(codegen.startOffset()); #if defined(DEBUG_DISASSEMBLE) cerr << "Setting starting offset to " << hex << codegen.startOffset() << endl; cerr << "And starting address is " << codegen.buffer().startAddr() << dec << endl; unsigned char *ptr = codegen.buffer().start_ptr(); ptr += codegen.startOffset(); Offset size = codegen.buffer().size() - codegen.startOffset(); InstructionDecoder d(ptr, size, proc_->getArchitecture()); Offset off = 0; while (off < size) { Instruction::Ptr insn = d.decode(); cerr << hex << off + codegen.startOffset() + codegen.buffer().startAddr() << " : " << insn->format() << endl; off += insn->size(); } off = 0; while (off < size) { cerr << hex << off + codegen.startOffset() + codegen.buffer().startAddr() << ": " << (int) ptr[off] << dec << endl; off++; } #endif //Post, but doesn't start running yet. bool result = rpcMgr()->postRPCToProc(proc, irpc); if (!result) { pthrd_printf("Error posting RPC to process %d\n", proc->getPid()); return false; } //Set the internal state so that this iRPC runs. int_thread *thr = irpc->thread(); thr->getInternalState().desyncState(int_thread::running); irpc->setRestoreInternal(true); //Run the IRPC and wait for completion. proc->throwNopEvent(); result = int_process::waitAndHandleEvents(false); if (!result) { perr_printf("Error waiting for and handling events\n"); return false; } //TODO: Any mechanism for error checks? return true; }
boost::tuple<Instruction::Ptr, Instruction::Ptr, bool> IA_x86Details::findMaxSwitchInsn(Block *start) { std::set<Block *> visited; std::vector<Block *> WL; Block *curBlk; int depth = 0; bool foundMaxSwitch = false; bool foundCondBranch = false; WL.push_back(start); Instruction::Ptr compareInsn, condBranchInsn; bool compareOnTakenBranch = false; for(unsigned j=0;j < WL.size(); j++) { curBlk = WL[j]; visited.insert(curBlk); foundMaxSwitch = false; foundCondBranch = false; const unsigned char* buf = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(curBlk->start())); if( buf == NULL ) { parsing_printf("%s[%d]: failed to get pointer to instruction by offset\n", FILE__, __LINE__); return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); } InstructionDecoder dec(buf, curBlk->size(), currentBlock->_isrc->getArch()); Instruction::Ptr i; Address curAdr = curBlk->start(); while((i = dec.decode())) { if(i->getCategory() == c_CompareInsn) // check for cmp { parsing_printf("\tFound jmp table cmp instruction %s at 0x%lx\n", i->format().c_str(), curAdr); compareInsn = i; foundMaxSwitch = true; } if(i->getCategory() == c_BranchInsn && i->allowsFallThrough()) { parsing_printf("\tFound jmp table cond br instruction %s at 0x%lx\n", i->format().c_str(), curAdr); condBranchInsn = i; foundCondBranch = true; Block::edgelist::const_iterator tit = curBlk->targets().begin(); bool taken_hit = false; bool fallthrough_hit = false; for ( ; tit != curBlk->targets().end(); ++tit) { ParseAPI::Edge *t = *tit; if (t->type() == COND_TAKEN && (visited.find(t->trg()) != visited.end())) { taken_hit = true; } if ((t->type() == COND_NOT_TAKEN || t->type() == FALLTHROUGH) && (visited.find(t->trg()) != visited.end())) { fallthrough_hit = true; } } parsing_printf("\tfindMaxSwitchInsn: taken_hit: %d, fallthrough_hit: %d\n", taken_hit, fallthrough_hit); compareOnTakenBranch = taken_hit && !fallthrough_hit; break; } curAdr += i->size(); } if(foundMaxSwitch && foundCondBranch) break; // done // look further back Block::edgelist::const_iterator sit = curBlk->sources().begin(); depth++; // We've seen depth 2 in libc et al if(depth > 2) return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); for( ; sit != curBlk->sources().end(); ++sit) { ParseAPI::Edge * s = *sit; // ignore return edges if(s->type() == RET) continue; if(s->type() == CALL) return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); Block * src = s->src(); if( (visited.find( src ) == visited.end())) { WL.push_back(src); } } } WL.clear(); parsing_printf("\tfindMaxSwitchInsn: table on taken branch: %d, returning: %d\n", compareOnTakenBranch, foundMaxSwitch && foundCondBranch); return boost::make_tuple(compareInsn, condBranchInsn, compareOnTakenBranch); }
bool IA_x86Details::handleCall(IA_IAPI& block) { parsing_printf("\tchecking call at 0x%lx for thunk\n", block.getAddr()); if(!block.isRealCall()) { parsing_printf("\tthunk found at 0x%lx, checking for add\n", block.getAddr()); block.advance(); thunkInsn.addrFromInsn = block.getAddr(); Instruction::Ptr addInsn = block.getInstruction(); if(addInsn) parsing_printf("\tinsn after thunk: %s\n", addInsn->format().c_str()); else parsing_printf("\tNO INSN after thunk at 0x%lx\n", thunkInsn.addrFromInsn); if(addInsn) { std::set<RegisterAST::Ptr> boundRegs; if(addInsn->getOperation().getID() == e_pop) { addInsn->getWriteSet(boundRegs); block.advance(); addInsn = block.getInstruction(); } if(addInsn && ((addInsn->getOperation().getID() == e_add) || (addInsn->getOperation().getID() == e_lea))) { Expression::Ptr op0 = addInsn->getOperand(0).getValue(); Expression::Ptr op1 = addInsn->getOperand(1).getValue(); for(std::set<RegisterAST::Ptr>::const_iterator curReg = boundRegs.begin(); curReg != boundRegs.end(); ++curReg) { op0->bind(curReg->get(), Result(u64, 0)); op1->bind(curReg->get(), Result(u64, 0)); } Result imm = addInsn->getOperand(1).getValue()->eval(); Result imm2 = addInsn->getOperand(0).getValue()->eval(); if(imm.defined) { Address thunkDiff = imm.convert<Address>(); parsing_printf("\tsetting thunkInsn.addrFromInsn to 0x%lx (0x%lx + 0x%lx)\n", thunkInsn.addrFromInsn+thunkDiff, thunkInsn.addrFromInsn, thunkDiff); thunkInsn.addrOfInsn = block.getPrevAddr(); thunkInsn.addrFromInsn = thunkInsn.addrFromInsn + thunkDiff; return true; } else if(imm2.defined) { Address thunkDiff = imm2.convert<Address>(); parsing_printf("\tsetting thunkInsn.addrFromInsn to 0x%lx (0x%lx + 0x%lx)\n", thunkInsn.addrFromInsn+thunkDiff, thunkInsn.addrFromInsn, thunkDiff); thunkInsn.addrOfInsn = block.getPrevAddr(); thunkInsn.addrFromInsn = thunkInsn.addrFromInsn + thunkDiff; return true; } else { parsing_printf("\tadd insn %s found following thunk at 0x%lx, couldn't bind operands!\n", addInsn->format().c_str(), thunkInsn.addrFromInsn); } } } thunkInsn.addrFromInsn = 0; } thunkInsn.addrFromInsn = 0; thunkInsn.addrOfInsn = 0; thunkInsn.insn.reset(); return false; }
ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, Address a) { liveness_cerr << "calcRWSets for " << curInsn->format() << " @ " << hex << a << dec << endl; ReadWriteInfo ret; ret.read = abi->getBitArray(); ret.written = abi->getBitArray(); ret.insnSize = curInsn->size(); std::set<RegisterAST::Ptr> cur_read, cur_written; curInsn->getReadSet(cur_read); curInsn->getWriteSet(cur_written); liveness_printf("Read registers: \n"); for (std::set<RegisterAST::Ptr>::const_iterator i = cur_read.begin(); i != cur_read.end(); i++) { MachRegister cur = (*i)->getID(); if (cur.getArchitecture() == Arch_ppc64) cur = MachRegister((cur.val() & ~Arch_ppc64) | Arch_ppc32); liveness_printf("\t%s \n", cur.name().c_str()); MachRegister base = cur.getBaseRegister(); if (cur == x86::flags || cur == x86_64::flags){ if (width == 4){ ret.read[getIndex(x86::of)] = true; ret.read[getIndex(x86::cf)] = true; ret.read[getIndex(x86::pf)] = true; ret.read[getIndex(x86::af)] = true; ret.read[getIndex(x86::zf)] = true; ret.read[getIndex(x86::sf)] = true; ret.read[getIndex(x86::df)] = true; ret.read[getIndex(x86::tf)] = true; ret.read[getIndex(x86::nt_)] = true; } else { ret.read[getIndex(x86_64::of)] = true; ret.read[getIndex(x86_64::cf)] = true; ret.read[getIndex(x86_64::pf)] = true; ret.read[getIndex(x86_64::af)] = true; ret.read[getIndex(x86_64::zf)] = true; ret.read[getIndex(x86_64::sf)] = true; ret.read[getIndex(x86_64::df)] = true; ret.read[getIndex(x86_64::tf)] = true; ret.read[getIndex(x86_64::nt_)] = true; } } else{ base = changeIfMMX(base); ret.read[getIndex(base)] = true; } } liveness_printf("Write Registers: \n"); for (std::set<RegisterAST::Ptr>::const_iterator i = cur_written.begin(); i != cur_written.end(); i++) { MachRegister cur = (*i)->getID(); if (cur.getArchitecture() == Arch_ppc64) cur = MachRegister((cur.val() & ~Arch_ppc64) | Arch_ppc32); liveness_printf("\t%s \n", cur.name().c_str()); MachRegister base = cur.getBaseRegister(); if (cur == x86::flags || cur == x86_64::flags){ if (width == 4){ ret.written[getIndex(x86::of)] = true; ret.written[getIndex(x86::cf)] = true; ret.written[getIndex(x86::pf)] = true; ret.written[getIndex(x86::af)] = true; ret.written[getIndex(x86::zf)] = true; ret.written[getIndex(x86::sf)] = true; ret.written[getIndex(x86::df)] = true; ret.written[getIndex(x86::tf)] = true; ret.written[getIndex(x86::nt_)] = true; } else { ret.written[getIndex(x86_64::of)] = true; ret.written[getIndex(x86_64::cf)] = true; ret.written[getIndex(x86_64::pf)] = true; ret.written[getIndex(x86_64::af)] = true; ret.written[getIndex(x86_64::zf)] = true; ret.written[getIndex(x86_64::sf)] = true; ret.written[getIndex(x86_64::df)] = true; ret.written[getIndex(x86_64::tf)] = true; ret.written[getIndex(x86_64::nt_)] = true; } } else{ base = changeIfMMX(base); ret.written[getIndex(base)] = true; if ((cur != base && cur.size() < 4) || isMMX(base)) ret.read[getIndex(base)] = true; } } InsnCategory category = curInsn->getCategory(); switch(category) { case c_CallInsn: // Call instructions not at the end of a block are thunks, which are not ABI-compliant. // So make conservative assumptions about what they may read (ABI) but don't assume they write anything. ret.read |= (abi->getCallReadRegisters()); if(blk->lastInsnAddr() == a) { ret.written |= (abi->getCallWrittenRegisters()); } break; case c_ReturnInsn: ret.read |= (abi->getReturnReadRegisters()); // Nothing written implicitly by a return break; case c_BranchInsn: if(!curInsn->allowsFallThrough() && isExitBlock(blk)) { //Tail call, union of call and return ret.read |= ((abi->getCallReadRegisters()) | (abi->getReturnReadRegisters())); ret.written |= (abi->getCallWrittenRegisters()); } break; default: { bool isInterrupt = false; bool isSyscall = false; if ((curInsn->getOperation().getID() == e_int) || (curInsn->getOperation().getID() == e_int3)) { isInterrupt = true; } static RegisterAST::Ptr gs(new RegisterAST(x86::gs)); if (((curInsn->getOperation().getID() == e_call) && /*(curInsn()->getOperation().isRead(gs))) ||*/ (curInsn->getOperand(0).format(curInsn->getArch()) == "16")) || (curInsn->getOperation().getID() == e_syscall) || (curInsn->getOperation().getID() == e_int) || (curInsn->getOperation().getID() == power_op_sc)) { isSyscall = true; } if (curInsn->getOperation().getID() == power_op_svcs) { isSyscall = true; } if (isInterrupt || isSyscall) { ret.read |= (abi->getSyscallReadRegisters()); ret.written |= (abi->getSyscallWrittenRegisters()); } } break; } return ret; }
bool IA_IAPI::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, const set<Address>& knownTargets) const { // Collapse down to "branch" or "fallthrough" switch(type) { case COND_TAKEN: case DIRECT: case INDIRECT: type = DIRECT; break; case CALL: case RET: case COND_NOT_TAKEN: case FALLTHROUGH: case CALL_FT: default: return false; } parsing_printf("Checking for Tail Call \n"); context->obj()->cs()->incrementCounter(PARSE_TAILCALL_COUNT); if (tailCalls.find(type) != tailCalls.end()) { parsing_printf("\tReturning cached tail call check result: %d\n", tailCalls[type]); if (tailCalls[type]) { context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL); return true; } return false; } bool valid; Address addr; boost::tie(valid, addr) = getCFT(); Function* callee = _obj->findFuncByEntry(_cr, addr); Block* target = _obj->findBlockByEntry(_cr, addr); // check if addr is in a block if it is not entry. if (target == NULL) { std::set<Block*> blocks; _obj->findCurrentBlocks(_cr, addr, blocks); if (blocks.size() == 1) { target = *blocks.begin(); } else if (blocks.size() == 0) { // This case can happen when the jump target is a function entry, // but we have not parsed the function yet, // or when this is an indirect jump target = NULL; } else { // If this case happens, it means the jump goes into overlapping instruction streams, // it is not likely to be a tail call. parsing_printf("\tjumps into overlapping instruction streams\n"); for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { parsing_printf("\t block [%lx,%lx)\n", (*bit)->start(), (*bit)->end()); } parsing_printf("\tjump to 0x%lx, NOT TAIL CALL\n", addr); tailCalls[type] = false; return false; } } if(curInsn()->getCategory() == c_BranchInsn && valid && callee && callee != context && target && !context->contains(target) ) { parsing_printf("\tjump to 0x%lx, TAIL CALL\n", addr); tailCalls[type] = true; return true; } if (curInsn()->getCategory() == c_BranchInsn && valid && !callee) { if (target) { parsing_printf("\tjump to 0x%lx is known block, but not func entry, NOT TAIL CALL\n", addr); tailCalls[type] = false; return false; } else if (knownTargets.find(addr) != knownTargets.end()) { parsing_printf("\tjump to 0x%lx is known target in this function, NOT TAIL CALL\n", addr); tailCalls[type] = false; return false; } } if(allInsns.size() < 2) { if(context->addr() == _curBlk->start() && curInsn()->getCategory() == c_BranchInsn) { parsing_printf("\tjump as only insn in entry block, TAIL CALL\n"); tailCalls[type] = true; return true; } else { parsing_printf("\ttoo few insns to detect tail call\n"); context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL); tailCalls[type] = false; return false; } } if ((curInsn()->getCategory() == c_BranchInsn)) { //std::map<Address, Instruction::Ptr>::const_iterator prevIter = //allInsns.find(current); // Updated: there may be zero or more nops between leave->jmp allInsns_t::const_iterator prevIter = curInsnIter; --prevIter; Instruction::Ptr prevInsn = prevIter->second; while ( isNopInsn(prevInsn) && (prevIter != allInsns.begin()) ) { --prevIter; prevInsn = prevIter->second; } prevInsn = prevIter->second; if(prevInsn->getOperation().getID() == e_leave) { parsing_printf("\tprev insn was leave, TAIL CALL\n"); tailCalls[type] = true; return true; } else if(prevInsn->getOperation().getID() == e_pop) { if(prevInsn->isWritten(framePtr[_isrc->getArch()])) { parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn->format().c_str()); tailCalls[type] = true; return true; } } else if(prevInsn->getOperation().getID() == e_add) { if(prevInsn->isWritten(stackPtr[_isrc->getArch()])) { bool call_fallthrough = false; if (_curBlk->start() == prevIter->first) { for (auto eit = _curBlk->sources().begin(); eit != _curBlk->sources().end(); ++eit) { if ((*eit)->type() == CALL_FT) { call_fallthrough = true; break; } } } if (call_fallthrough) { parsing_printf("\tprev insn was %s, but it is the next instruction of a function call, not a tail call %x %x\n", prevInsn->format().c_str()); } else { parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn->format().c_str()); tailCalls[type] = true; return true; } } else parsing_printf("\tprev insn was %s, not tail call\n", prevInsn->format().c_str()); } } tailCalls[type] = false; context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL); return false; }