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; }
void parse_block::getInsns(Insns &insns, Address base) { using namespace InstructionAPI; Offset off = firstInsnOffset(); const unsigned char *ptr = (const unsigned char *)getPtrToInstruction(off); if (ptr == NULL) return; InstructionDecoder d(ptr, getSize(),obj()->cs()->getArch()); while (off < endOffset()) { Instruction::Ptr insn = d.decode(); insns[off + base] = insn; off += insn->size(); } }
void instrumentBasicBlock(BPatch_function * function, BPatch_basicBlock *block) { Instruction::Ptr iptr; void *addr; unsigned char bytes[MAX_RAW_INSN_SIZE]; size_t nbytes, i; // iterate backwards (PatchAPI restriction) PatchBlock::Insns insns; PatchAPI::convert(block)->getInsns(insns); PatchBlock::Insns::reverse_iterator j; for (j = insns.rbegin(); j != insns.rend(); j++) { // get instruction bytes addr = (void*)((*j).first); iptr = (*j).second; nbytes = iptr->size(); assert(nbytes <= MAX_RAW_INSN_SIZE); for (i=0; i<nbytes; i++) { bytes[i] = iptr->rawByte(i); } bytes[nbytes] = '\0'; // apply filter mainDecoder->decode((uint64_t)addr,iptr); if (mainDecoder->isCall()&&mainDecoder->isCall_indirect()) { instrumentCallIns(addr, bytes, nbytes, PatchAPI::convert(function), PatchAPI::convert(block),mainDecoder->isCall_indirect()); } else if (mainDecoder->isIndirectJmp()) { instrumentIndirectJmpIns(addr, bytes, nbytes, PatchAPI::convert(function), PatchAPI::convert(block)); } else if (mainDecoder->needDepie()) { instrumentInstruction(addr, bytes, nbytes, PatchAPI::convert(function), PatchAPI::convert(block)); } } }
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); }
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; }
/* returns true if the call leads to: * -an invalid instruction (or immediately branches/calls to an invalid insn) * -a block not ending in a return instruction that pops the return address * off of the stack */ bool IA_IAPI::isFakeCall() const { assert(_obj->defensiveMode()); if (isDynamicCall()) { return false; } // get func entry bool tampers = false; bool valid; Address entry; boost::tie(valid, entry) = getCFT(); if (!valid) return false; if (! _cr->contains(entry) ) { return false; } if ( ! _isrc->isCode(entry) ) { mal_printf("WARNING: found function call at %lx " "to invalid address %lx %s[%d]\n", current, entry, FILE__,__LINE__); return false; } // get instruction at func entry const unsigned char* bufPtr = (const unsigned char *)(_cr->getPtrToInstruction(entry)); Offset entryOff = entry - _cr->offset(); InstructionDecoder newdec( bufPtr, _cr->length() - entryOff, _cr->getArch() ); IA_IAPI *ah = new IA_IAPI(newdec, entry, _obj, _cr, _isrc, _curBlk); Instruction::Ptr insn = ah->curInsn(); // follow ctrl transfers until you get a block containing non-ctrl // transfer instructions, or hit a return instruction while (insn->getCategory() == c_CallInsn || insn->getCategory() == c_BranchInsn) { boost::tie(valid, entry) = ah->getCFT(); if ( !valid || ! _cr->contains(entry) || ! _isrc->isCode(entry) ) { mal_printf("WARNING: found call to function at %lx that " "leaves to %lx, out of the code region %s[%d]\n", current, entry, FILE__,__LINE__); return false; } bufPtr = (const unsigned char *)(_cr->getPtrToInstruction(entry)); entryOff = entry - _cr->offset(); delete(ah); newdec = InstructionDecoder(bufPtr, _cr->length() - entryOff, _cr->getArch()); ah = new IA_IAPI(newdec, entry, _obj, _cr, _isrc, _curBlk); insn = ah->curInsn(); } // calculate instruction stack deltas for the block, leaving the iterator // at the last ins'n if it's a control transfer, or after calculating the // last instruction's delta if we run off the end of initialized memory int stackDelta = 0; int addrWidth = _isrc->getAddressWidth(); static Expression::Ptr theStackPtr (new RegisterAST(MachRegister::getStackPointer(_isrc->getArch()))); Address curAddr = entry; while(true) { // exit condition 1 if (insn->getCategory() == c_CallInsn || insn->getCategory() == c_ReturnInsn || insn->getCategory() == c_BranchInsn) { break; } // calculate instruction delta if(insn->isWritten(theStackPtr)) { entryID what = insn->getOperation().getID(); int sign = 1; switch(what) { case e_push: sign = -1; //FALLTHROUGH case e_pop: { int size = insn->getOperand(0).getValue()->size(); stackDelta += sign * size; break; } case e_pusha: case e_pushad: sign = -1; //FALLTHROUGH case e_popa: case e_popad: if (1 == sign) { mal_printf("popad ins'n at %lx in func at %lx changes sp " "by %d. %s[%d]\n", ah->getAddr(), entry, 8 * sign * addrWidth, FILE__, __LINE__); } stackDelta += sign * 8 * addrWidth; break; case e_pushf: case e_pushfd: sign = -1; //FALLTHROUGH case e_popf: case e_popfd: stackDelta += sign * 4; if (1 == sign) { mal_printf("popf ins'n at %lx in func at %lx changes sp " "by %d. %s[%d]\n", ah->getAddr(), entry, sign * 4, FILE__, __LINE__); } break; case e_enter: //mal_printf("Saw enter instruction at %lx in isFakeCall, " // "quitting early, assuming not fake " // "%s[%d]\n",curAddr, FILE__,__LINE__); // unhandled case, but not essential for correct analysis delete ah; return false; break; case e_leave: mal_printf("WARNING: saw leave instruction " "at %lx that is not handled by isFakeCall %s[%d]\n", curAddr, FILE__,__LINE__); // unhandled, not essential for correct analysis, would // be a red flag if there wasn't an enter ins'n first and // we didn't end in a return instruction break; case e_and: // Rounding off the stack pointer. mal_printf("WARNING: saw and instruction at %lx that is not handled by isFakeCall %s[%d]\n", curAddr, FILE__, __LINE__); delete ah; return false; break; case e_sub: sign = -1; //FALLTHROUGH case e_add: { Operand arg = insn->getOperand(1); Result delta = arg.getValue()->eval(); if(delta.defined) { int delta_int = sign; switch (delta.type) { case u8: case s8: delta_int *= (int)delta.convert<char>(); break; case u16: case s16: delta_int *= (int)delta.convert<short>(); break; case u32: case s32: delta_int *= delta.convert<int>(); break; default: assert(0 && "got add/sub operand of unusual size"); break; } stackDelta += delta_int; } else if (sign == -1) { delete ah; return false; } else { mal_printf("ERROR: in isFakeCall, add ins'n " "at %lx (in first block of function at " "%lx) modifies the sp but failed to evaluate " "its arguments %s[%d]\n", ah->getAddr(), entry, FILE__, __LINE__); delete ah; return true; } break; } default: { fprintf(stderr,"WARNING: in isFakeCall non-push/pop " "ins'n at %lx (in first block of function at " "%lx) modifies the sp by an unknown amount. " "%s[%d]\n", ah->getAddr(), entry, FILE__, __LINE__); break; } // end default block } // end switch } if (stackDelta > 0) { tampers=true; } // exit condition 2 ah->advance(); Instruction::Ptr next = ah->curInsn(); if (NULL == next) { break; } curAddr += insn->size(); insn = next; } // not a fake call if it ends w/ a return instruction if (insn->getCategory() == c_ReturnInsn) { delete ah; return false; } // if the stack delta is positive or the return address has been replaced // with an absolute value, it's a fake call, since in both cases // the return address is gone and we cannot return to the caller if ( 0 < stackDelta || tampers ) { delete ah; return true; } delete ah; return false; }
func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHandler) { using namespace Dyninst::InstructionAPI; const pdvector<func_instance *> *funcs = findFuncVectorByMangled(dtorHandler); if( funcs != NULL ) { return funcs->at(0); } /* * If the symbol isn't found, try looking for it in a call in the * .fini section. It is the last call in .fini. * * The pattern is: * * _fini: * * ... some code ... * * call dtor_handler * * ... prologue ... */ Symtab *linkedFile = parse_img()->getObject(); Region *finiRegion = NULL; if( !linkedFile->findRegion(finiRegion, ".fini") ) { vector<Dyninst::SymtabAPI::Function *> symFuncs; if( linkedFile->findFunctionsByName(symFuncs, "_fini") ) { finiRegion = symFuncs[0]->getRegion(); }else{ logLine("failed to locate .fini Region or _fini function\n"); return NULL; } } if( finiRegion == NULL ) { logLine("failed to locate .fini Region or _fini function\n"); return NULL; } // Search for last call in the function Address dtorAddress = 0; unsigned bytesSeen = 0; const unsigned char *p = reinterpret_cast<const unsigned char *>(finiRegion->getPtrToRawData()); InstructionDecoder decoder(p, finiRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); Instruction::Ptr lastCall; Instruction::Ptr curInsn = decoder.decode(); while(curInsn && curInsn->isValid() && bytesSeen < finiRegion->getDiskSize()) { InsnCategory category = curInsn->getCategory(); if( category == c_CallInsn ) { lastCall = curInsn; break; } bytesSeen += curInsn->size(); curInsn = decoder.decode(); } if( !lastCall.get() || !lastCall->isValid() ) { logLine("heuristic for finding global destructor function failed\n"); return NULL; } Address callAddress = finiRegion->getMemOffset() + bytesSeen; RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); Expression::Ptr callTarget = lastCall->getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global destructor function\n"); return NULL; } callTarget->bind(&thePC, Result(s64, callAddress)); Result actualTarget = callTarget->eval(); if( actualTarget.defined ) { dtorAddress = actualTarget.convert<Address>(); }else{ logLine("failed to find global destructor function\n"); return NULL; } if( !dtorAddress || !parse_img()->codeObject()->cs()->isValidAddress(dtorAddress) ) { logLine("invalid address for global destructor function\n"); return NULL; } // A targ stub should have been created at the address func_instance *ret = NULL; if( (ret = findFuncByEntry(dtorAddress)) == NULL ) { logLine("unable to find global destructor function\n"); return NULL; } inst_printf("%s[%d]: set global destructor address to 0x%lx\n", FILE__, __LINE__, dtorAddress); return ret; }
func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorHandler) { using namespace Dyninst::InstructionAPI; const pdvector<func_instance *> *funcs = findFuncVectorByMangled(ctorHandler); if( funcs != NULL ) { return funcs->at(0); } /* If the symbol isn't found, try looking for it in a call instruction in * the .init section * * On Linux, the instruction sequence is: * ... * some instructions * ... * call call_gmon_start * call frame_dummy * call ctor_handler * * On FreeBSD, the instruction sequence is: * ... * some instructions * ... * call frame_dummy * call ctor_handler */ Symtab *linkedFile = parse_img()->getObject(); Region *initRegion = NULL; if( !linkedFile->findRegion(initRegion, ".init") ) { vector<Dyninst::SymtabAPI::Function *> symFuncs; if( linkedFile->findFunctionsByName(symFuncs, "_init") ) { initRegion = symFuncs[0]->getRegion(); }else{ logLine("failed to locate .init Region or _init function\n"); return NULL; } } if( initRegion == NULL ) { logLine("failed to locate .init Region or _init function\n"); return NULL; } // Search for last of a fixed number of calls #if defined(os_freebsd) const unsigned CTOR_NUM_CALLS = 2; #else const unsigned CTOR_NUM_CALLS = 3; #endif Address ctorAddress = 0; unsigned bytesSeen = 0; unsigned numCalls = 0; const unsigned char *p = reinterpret_cast<const unsigned char *>(initRegion->getPtrToRawData()); InstructionDecoder decoder(p, initRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); Instruction::Ptr curInsn = decoder.decode(); while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() && bytesSeen < initRegion->getDiskSize()) { InsnCategory category = curInsn->getCategory(); if( category == c_CallInsn ) { numCalls++; } if( numCalls < CTOR_NUM_CALLS ) { bytesSeen += curInsn->size(); curInsn = decoder.decode(); } } if( numCalls != CTOR_NUM_CALLS ) { logLine("heuristic for finding global constructor function failed\n"); return NULL; } Address callAddress = initRegion->getMemOffset() + bytesSeen; RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); Expression::Ptr callTarget = curInsn->getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global constructor function\n"); return NULL; } callTarget->bind(&thePC, Result(s64, callAddress)); Result actualTarget = callTarget->eval(); if( actualTarget.defined ) { ctorAddress = actualTarget.convert<Address>(); }else{ logLine("failed to find global constructor function\n"); return NULL; } if( !ctorAddress || !parse_img()->codeObject()->cs()->isValidAddress(ctorAddress) ) { logLine("invalid address for global constructor function\n"); return NULL; } func_instance *ret; if( (ret = findFuncByEntry(ctorAddress)) == NULL ) { logLine("unable to create representation for global constructor function\n"); return NULL; } inst_printf("%s[%d]: set global constructor address to 0x%lx\n", FILE__, __LINE__, ctorAddress); return ret; }
void TextRewriter::organizeNewText() { /** * */ unsigned int textSize = 0; textSize = textRegion->getRegionSize(); oldText = (unsigned char*) textRegion->getPtrToRawData(); newText = (unsigned char*) calloc (1, sizeof(unsigned char) * textSize); memcpy(newText, oldText, textSize); //InstructionDecoder decoder(oldText, textSize, Arch_x86_64); InstructionDecoder decoder(oldText, textSize, Arch_x86); Instruction::Ptr i = decoder.decode(); long unsigned int currentTextOffset = 0; while (i != NULL) { //vector<Operand> operands; //i->getOperands(operands); //if (operands.size() > 0) { // Expression::Ptr exp = operands[0].getValue(); // Result res = exp->eval(); // Immediate::makeImmediate(Result(u64, 2^32)); // fprintf(stderr, "results: %s\n", res.format().c_str()); //} unsigned char* dotTextRaw = (unsigned char*) i->ptr(); //fprintf(stderr, "%i bytes > %s -- ", i->size(), i->format().c_str()); //for (int x = 0; x < i->size(); x++) { // fprintf(stderr, " %x ", dotTextRaw[x]); //} //fprintf(stderr, "\n"); if (i->readsMemory()) { if (/*dotTextRaw[0] == 0xa1 && */i->size() == 5 || i->size() == 6) { unsigned int* dataOperand = i->size() == 5 ? (unsigned int*)(dotTextRaw + 1) : (unsigned int*)(dotTextRaw + 2); // Interpret as int to reverse bytes in memory automatically fprintf(stderr, "Data operand: %p\n", (void*) ((unsigned int)*dataOperand)); unsigned int data = *dataOperand; unsigned char* tmp = (unsigned char*) dataOperand; if (dataRegion->isOffsetInRegion((*relocs)[data]) || bssRegion->isOffsetInRegion((*relocs)[data])) { // Hacky, depends on teh 32-bit instructions int tmp = i->size() == 5 ? 1 : 2; *((unsigned int*)(newText + currentTextOffset + tmp)) = (*relocs)[data]; } } } //if (dotTextRaw[0] == 0xa1 && i->size() == 9) { // fprintf(stdout, "%i bytes > %s\n", i->size(), i->format().c_str()); // unsigned int* dataOperand = (unsigned int*)(dotTextRaw + 1); // if (dataOperand[0] > 134518284) { // ((unsigned int*)(((unsigned char*) dotTextRawMuta) + currentTextOffset + 1))[0] = 134518520; // } //} currentTextOffset += i->size(); i = decoder.decode(); } // Assign the data region to point at the new buffer if (!textRegion->setPtrToRawData((void*) newText, textRegion->getRegionSize())) { fprintf(stderr, "Failed to set pointer to raw text!\n"); exit(EXIT_FAILURE); } }