virtual bool check(SpPoint* pt) { PatchFunction* f = sp::Callee(pt); if (!f) return false; sp_print("StackArrayChecker"); // getAllVariables PatchObject* obj = pt->obj(); using namespace Dyninst::ParseAPI; using namespace Dyninst::SymtabAPI; SymtabCodeSource* cs = static_cast<SymtabCodeSource*>(obj->co()->cs()); Symtab* sym = cs->getSymtabObject(); std::vector<Symbol*> symbols; std::vector<SymtabAPI::Function*> funcs; sym->getAllFunctions(funcs); for (unsigned i = 0; i < funcs.size(); i ++) { if (funcs[i]->getOffset() == f->addr()) { std::vector<localVar*> vars; funcs[i]->getLocalVariables(vars); for (unsigned j = 0; j < vars.size(); j ++) { typeArray* t = vars[j]->getType()->getArrayType(); if (!t) continue; sp_print("%s: [%lx, %lx]", vars[j]->getName().c_str(), t->getLow(), t->getHigh()); } } } return true; }
// This should only be called on a known indirect branch... bool IA_powerDetails::parseJumpTable(Block* currBlk, std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges) { Address initialAddress = currentBlock->current; toc_reg.reset(new RegisterAST(ppc32::r2)); TOC_address = currentBlock->_obj->cs()->getTOC(); toc_visitor.reset(new detail::TOCandOffsetExtractor(TOC_address)); toc_visitor->toc_reg = toc_reg; // If there are no prior instructions then we can't be looking at a // jump through a jump table. if(currentBlock->allInsns.size() < 2) { parsing_printf("%s[%d]: allInsns.size() == %d, ret false", FILE__, __LINE__, currentBlock->allInsns.size()); return false; } // Check if the previous instruction is a move to CTR or LR; // if it is, then this is the pattern we're familiar with. The // register being moved into CTR or LR has the address to jump to. patternIter = currentBlock->curInsnIter; patternIter--; RegisterAST::Ptr jumpAddrReg; static RegisterAST::Ptr linkReg(new RegisterAST(ppc32::lr)); static RegisterAST::Ptr countReg(new RegisterAST(ppc32::ctr)); std::set<RegisterAST::Ptr> regs; if(patternIter->second->getOperation().getID() == power_op_mtspr && (patternIter->second->isWritten(linkReg) || patternIter->second->isWritten(countReg))) { regs.clear(); patternIter->second->getReadSet(regs); if(regs.size() != 1) { parsing_printf("expected mtspr to read 1 register, insn is %s\n", patternIter->second->format().c_str()); return false; } jumpAddrReg = *(regs.begin()); parsing_printf("%s[%d]: JUMPREG %s mtspr at prev insn %s \n", FILE__, __LINE__, jumpAddrReg->format().c_str(), patternIter->second->format().c_str()); dfgregs.insert(jumpAddrReg->getID()); } else { parsing_printf("%s[%d]: couldn't find mtspr at prev insn %s, ret false", FILE__, __LINE__, patternIter->second->format().c_str()); return false; } assert(jumpAddrReg); // In the pattern we've seen, if the instruction previous to this is // an add with a result that ends up being used as the jump address, // then we're adding a relative value we got from the table to a base // address to get the jump address; in other words, the contents of // the jump table are relative. tableIsRelative = false; if(patternIter != currentBlock->allInsns.begin()) { patternIter--; if(patternIter->second->getOperation().getID() == power_op_add && patternIter->second->isWritten(*(regs.begin()))) { tableIsRelative = true; } } parsing_printf(" TableIsRelative %d\n", tableIsRelative); patternIter = currentBlock->curInsnIter; jumpStartAddress = 0; adjustEntry = 0; tableStartAddress = 0; adjustTableStartAddress = 0; foundAdjustEntry = false; parsing_printf("\t TOC_address 0x%lx\n", TOC_address); if(!TOC_address) { // Find addi-addis instructions to determine the jump table start address. // These instructions can be anywhere in the function before the // indirect jump.Hence parse through the current block and previous block // till we reach the function entry. Block* worklistBlock = currBlk; std::set <Block*> visited; std::deque<Block*> worklist; worklist.insert(worklist.begin(), worklistBlock); visited.insert(worklistBlock); Intraproc epred; parsing_printf("Looking for table start address over blocks to function entry\n"); while(!worklist.empty()) { worklistBlock= worklist.front(); worklist.pop_front(); parsing_printf("\tAddress low 0x%lx high 0x%lx current block 0x%lx low 0x%lx high 0x%lx \n", worklistBlock->low(), worklistBlock->high(), currentBlock->current, currBlk->low(), currBlk->high()); Address blockStart = worklistBlock->start(); const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart)); parsing_printf(" Block start 0x%lx \n", blockStart); InstructionDecoder dec(b, worklistBlock->size(), currentBlock->_isrc->getArch()); IA_IAPI IABlock(dec, blockStart, currentBlock->_obj, currentBlock->_cr, currentBlock->_isrc, worklistBlock); while(IABlock.getInstruction() && !IABlock.hasCFT()) { IABlock.advance(); } patternIter = IABlock.curInsnIter; findTableAddrNoTOC(&IABlock); if(!jumpStartAddress) { jumpStartAddress = tableStartAddress; } if (tableStartAddress != 0) { jumpStartAddress = tableStartAddress; parsing_printf("\t\tjumpStartAddress 0x%lx \n", jumpStartAddress); break; } std::for_each(boost::make_filter_iterator(epred, worklistBlock->sources().begin(), worklistBlock->sources().end()), boost::make_filter_iterator(epred, worklistBlock->sources().end(), worklistBlock->sources().end()), boost::bind(detail_ppc::processPredecessor, _1, boost::ref(visited), boost::ref(worklist))); } } else if (tableIsRelative) { if(!parseRelativeTableIdiom()) { return false; } } else { parsing_printf("\t Table is not relative and we know the TOC is 0x%lx, searching for table base\n", TOC_address); foundAdjustEntry = false; scanForAdjustOrBase(patternIter, currentBlock->allInsns.begin(), jumpAddrReg); if (!tableStartAddress) { // Keep looking in the immediate predecessor - XLC for (Block::edgelist::const_iterator e_iter = currBlk->sources().begin(); e_iter != currBlk->sources().end(); ++e_iter) { Address blockStart = (*e_iter)->src()->start(); const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart)); InstructionDecoder dec(b, (*e_iter)->src()->size(), currentBlock->_isrc->getArch()); IA_IAPI IABlock(dec, blockStart, currentBlock->_obj, currentBlock->_cr, currentBlock->_isrc, (*e_iter)->src()); // Cache instructions while(IABlock.getInstruction() && !IABlock.hasCFT()) { IABlock.advance(); } IA_IAPI::allInsns_t::const_iterator localIter = IABlock.curInsnIter; findTableBase(localIter, IABlock.allInsns.begin()); } } } const Block::edgelist & sourceEdges = currBlk->sources(); if(sourceEdges.size() != 1 || (*sourceEdges.begin())->type() == CALL) { parsing_printf("%s[%d]: jump table not properly guarded, ret false\n", FILE__, __LINE__); return false; } // We could also set this = jumpStartAddress... if (tableStartAddress == 0) { parsing_printf("%s[%d]: couldn't find table start addr, ret false\n", FILE__, __LINE__); return false; } parsing_printf("%s[%d]: table start addr is 0x%x\n", FILE__, __LINE__, tableStartAddress); int maxSwitch = 0; Block* sourceBlock = (*sourceEdges.begin())->src(); Address blockStart = sourceBlock->start(); const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart)); InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch()); IA_IAPI prevBlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc, sourceBlock); while(!prevBlock.hasCFT() && prevBlock.getInstruction()) { prevBlock.advance(); } parsing_printf("%s[%d]: checking for max switch...\n", FILE__, __LINE__); bool foundBranch = false; IA_IAPI::allInsns_t::reverse_iterator iter; for(iter = prevBlock.allInsns.rbegin(); iter != prevBlock.allInsns.rend(); iter++) { parsing_printf("\t\tchecking insn 0x%x: %s for cond branch + compare\n", iter->first, iter->second->format().c_str()); if(iter->second->getOperation().getID() == power_op_bc) // make this a true cond. branch check { foundBranch = true; } else if(foundBranch && (iter->second->getOperation().getID() == power_op_cmpi || iter->second->getOperation().getID() == power_op_cmpli)) { maxSwitch = iter->second->getOperand(2).getValue()->eval().convert<int>() + 1; break; } } parsing_printf("%s[%d]: After checking: max switch %d\n", FILE__, __LINE__, maxSwitch); if(!maxSwitch){ return false; } Address jumpStart = 0; Address tableStart = 0; bool is64 = (currentBlock->_isrc->getAddressWidth() == 8); std::vector<std::pair< Address, EdgeTypeEnum> > edges; if(TOC_address) { if (tableIsRelative) { void *jumpStartPtr = currentBlock->_isrc->getPtrToData(jumpStartAddress); parsing_printf("%s[%d]: jumpStartPtr (0x%lx) = %p\n", FILE__, __LINE__, jumpStartAddress, jumpStartPtr); if (jumpStartPtr) jumpStart = (is64 ? *((Address *)jumpStartPtr) : *((uint32_t *)jumpStartPtr)); parsing_printf("%s[%d]: jumpStart 0x%lx, initialAddr 0x%lx\n", FILE__, __LINE__, jumpStart, initialAddress); if (jumpStartPtr == NULL) { return false; } } void *tableStartPtr = currentBlock->_isrc->getPtrToData(tableStartAddress); parsing_printf("%s[%d]: tableStartPtr (0x%lx) = %p\n", FILE__, __LINE__, tableStartAddress, tableStartPtr); tableStart = *((Address *)tableStartPtr); if (tableStartPtr) tableStart = (is64 ? *((Address *)tableStartPtr) : *((uint32_t *)tableStartPtr)); else { return false; } parsing_printf("\t... tableStart 0x%lx\n", tableStart); bool tableData = false; for(int i=0;i<maxSwitch;i++){ Address tableEntry = adjustEntry + tableStart + (i * 4 /*instruction::size()*/); parsing_printf("\t\tTable entry at 0x%lx\n", tableEntry); if (currentBlock->_isrc->isValidAddress(tableEntry)) { int jumpOffset; if (tableData) { jumpOffset = *((int *)currentBlock->_isrc->getPtrToData(tableEntry)); } else { jumpOffset = *((int *)currentBlock->_isrc->getPtrToInstruction(tableEntry)); } parsing_printf("\t\t\tjumpOffset 0x%lx\n", jumpOffset); Address res = (Address)(jumpStart + jumpOffset); if (currentBlock->_isrc->isCode(res)) { edges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT)); parsing_printf("\t\t\tEntry of 0x%lx\n", (Address)(jumpStart + jumpOffset)); } } else { parsing_printf("\t\tAddress not valid!\n"); } } } // No TOC, so we're on Power32 Linux. Do the ELF thing. else { jumpStart = jumpStartAddress; tableStart = tableStartAddress; parsing_printf(" jumpStartaddress 0x%lx tableStartAddress 0x%lx \n", jumpStartAddress, tableStartAddress); if(toc_visitor->toc_contents) { void* tmp = NULL; if(currentBlock->_isrc->isValidAddress(jumpStartAddress)) { tmp = currentBlock->_isrc->getPtrToData(jumpStartAddress); if(!tmp) { tmp = currentBlock->_isrc->getPtrToInstruction(jumpStartAddress); } if(tmp) { jumpStart = *((Address*)tmp); parsing_printf("\t\tjumpStart adjusted to 0x%lx\n", jumpStart); } } if(currentBlock->_isrc->isValidAddress(tableStartAddress)) { tmp = currentBlock->_isrc->getPtrToData(tableStartAddress); if(!tmp) { tmp = currentBlock->_isrc->getPtrToInstruction(tableStartAddress); } if(tmp) { tableStart = *((Address*)tmp); parsing_printf("\t\ttableStart adjusted to 0x%lx\n", jumpStart); } } } if (jumpStart == 0) { #if defined(WITH_SYMTAB_API) // If jump table address is a relocation entry, this will be filled by the loader // This case is common in shared library where the table address is in the GOT section which is filled by the loader // Find the relocation entry for this address and look up its value Block* sourceBlock = (*sourceEdges.begin())->src(); Address blockStart = sourceBlock->start(); const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart)); InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch()); IA_IAPI IABlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc, sourceBlock); SymtabCodeSource *scs = dynamic_cast<SymtabCodeSource *>(IABlock._obj->cs()); SymtabAPI::Symtab * symtab = scs->getSymtabObject(); std::vector<SymtabAPI::Region *> regions; symtab->getAllRegions(regions); for (unsigned index = 0 ; index < regions.size(); index++) { if (regions[index]->getRegionType() == SymtabAPI::Region::RT_RELA || regions[index]->getRegionType() == SymtabAPI::Region::RT_REL) { std::vector<SymtabAPI::relocationEntry> relocs = regions[index]->getRelocations(); parsing_printf(" \t\trelocation size %d looking for 0x%lx\n", relocs.size(), jumpStartAddress); for (unsigned i = 0; i < relocs.size(); ++i) { parsing_printf(" \t 0x%lx => 0x%lx addend 0x%lx \n", relocs[i].rel_addr(),relocs[i].target_addr(), relocs[i].addend()); if (relocs[i].rel_addr() == jumpStartAddress) { jumpStart = relocs[i].addend(); break; } } break; } } #else // Can't parse relocation entries without Symtab return false; #endif } if (tableStart == 0) tableStart = jumpStart; if (!tableIsRelative) { jumpStart = 0; } parsing_printf(" jumpStartaddress 0x%lx tableStartAddress 0x%lx \n", jumpStart, tableStart); int entriesAdded = 0; for(int i = 0; i < maxSwitch; i++) { void* ptr = NULL; Address tableEntry = tableStart + i*4; // instruction::size(); if(currentBlock->_isrc->isValidAddress(tableEntry)) { ptr = currentBlock->_isrc->getPtrToInstruction(tableEntry); } if(ptr) { int jumpOffset = *((int *)ptr); edges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT)); parsing_printf("\t\t\t[0x%lx] -> 0x%lx (0x%lx in table)\n", tableEntry, jumpStart+jumpOffset, jumpOffset); ++entriesAdded; } else { parsing_printf("\t\t\t[0x%lx] -> [INVALID]\n", tableEntry); } } if(!entriesAdded) { parsing_printf("%s[%d]: no entries added from jump table, returning false\n", FILE__, __LINE__); return false; } parsing_printf("%s[%d]: Found %d entries in jump table, returning success\n", FILE__, __LINE__, entriesAdded); } // Sanity check entries in res for (std::vector<std::pair<Address, EdgeTypeEnum> >::iterator iter = edges.begin(); iter != edges.end(); iter++) { if ((iter->first) % 4) { parsing_printf("Warning: found unaligned jump table destination 0x%lx for jump at 0x%lx, disregarding table\n", iter->first, initialAddress); return false; } } // If we have found a jump table, add the targets to outEdges for (std::vector<std::pair<Address, EdgeTypeEnum> >::iterator iter = edges.begin(); iter != edges.end(); iter++) { parsing_printf("Adding out edge %d/0x%lx\n", iter->second, iter->first); outEdges.push_back(*iter); } return true; }
std::pair<bool, Address> IA_IAPI::getCFT() const { if(validCFT) return cachedCFT; Expression::Ptr callTarget = curInsn().getControlFlowTarget(); if (!callTarget) return make_pair(false, 0); // FIXME: templated bind(),dammit! callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current)); parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__, thePC[_isrc->getArch()]->format(curInsn().getArch()).c_str(), curInsn().format().c_str(), current); Result actualTarget = callTarget->eval(); #if defined(os_vxworks) int reloc_target = current; #if defined(arch_x86) ++reloc_target; #endif if (actualTarget.convert<Address>() == reloc_target) { // We have a zero offset branch. Consider relocation information. SymtabCodeRegion *scr = dynamic_cast<SymtabCodeRegion *>(_cr); SymtabCodeSource *scs = dynamic_cast<SymtabCodeSource *>(_obj->cs()); if (!scr && scs) { set<CodeRegion *> regions; assert( scs->findRegions(reloc_target, regions) == 1 ); scr = dynamic_cast<SymtabCodeRegion *>(*regions.begin()); } SymtabAPI::Symbol *sym = NULL; if (scr) { std::vector<SymtabAPI::relocationEntry> relocs = scr->symRegion()->getRelocations(); for (unsigned i = 0; i < relocs.size(); ++i) { if (relocs[i].rel_addr() == reloc_target) { sym = relocs[i].getDynSym(); if (sym && sym->getOffset()) { parsing_printf(" <reloc hit> "); actualTarget = Result(s64, sym->getOffset()); } break; } } } if (sym && sym->getOffset() == 0) { // VxWorks external call. // Need some external means to find the target. Address found; const std::string &sym_name = sym->getMangledName(); if (wtxFindFunction(sym_name.c_str(), 0x0, found)) { parsing_printf(" <wtx search hit> "); actualTarget = Result(s64, found); // We've effectively found a plt call. Update linkage table. _obj->cs()->linkage()[found] = sym_name; } else { parsing_printf(" <wtx fail %s> ", sym_name.c_str()); actualTarget.defined = false; } } } #endif if(actualTarget.defined) { cachedCFT = std::make_pair(true, actualTarget.convert<Address>()); parsing_printf("SUCCESS (CFT=0x%x)\n", cachedCFT.second); } else { cachedCFT = std::make_pair(false, 0); parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n", cachedCFT.second,callTarget->format(curInsn().getArch()).c_str()); } validCFT = true; if(isLinkerStub()) { parsing_printf("Linker stub detected: Correcting CFT. (CFT=0x%x)\n", cachedCFT.second); } return cachedCFT; }