Beispiel #1
0
void BinaryEdit::makeInitAndFiniIfNeeded()
{
    using namespace Dyninst::SymtabAPI;

    Symtab* linkedFile = getAOut()->parse_img()->getObject();

    // Disable this for .o's and static binaries
    if( linkedFile->isStaticBinary() || 
        linkedFile->getObjectType() == obj_RelocatableFile ) 
    {
        return;
    }

    bool foundInit = false;
    bool foundFini = false;
    vector <Function *> funcs;
    if (linkedFile->findFunctionsByName(funcs, "_init")) {
        foundInit = true;
    }
    if (linkedFile->findFunctionsByName(funcs, "_fini")) {
        foundFini = true;
    }
    if( !foundInit )
    {
        Offset initOffset = linkedFile->getInitOffset();
        Region *initsec = linkedFile->findEnclosingRegion(initOffset);
        if(!initOffset || !initsec)
        {
            unsigned char* emptyFunction = NULL;
            int emptyFuncSize = 0;
#if defined(arch_x86) || defined(arch_x86_64)
            static unsigned char empty_32[] = { 0x55, 0x89, 0xe5, 0xc9, 0xc3 };
            static unsigned char empty_64[] = { 0x55, 0x48, 0x89, 0xe5, 0xc9, 0xc3 };
            if(linkedFile->getAddressWidth() == 8)
            {
                emptyFunction = empty_64;
                emptyFuncSize = 6;
            }
            else
            {
                emptyFunction = empty_32;
                emptyFuncSize = 5;
            }
#elif defined (arch_power)
            static unsigned empty[] = {0x4e800020};
            emptyFunction = (unsigned char*) empty;
            emptyFuncSize = 4;
#endif //defined(arch_x86) || defined(arch_x86_64)
            linkedFile->addRegion(highWaterMark_, (void*)(emptyFunction), emptyFuncSize, ".init.dyninst",
                                  Dyninst::SymtabAPI::Region::RT_TEXT, true);
            highWaterMark_ += emptyFuncSize;
            lowWaterMark_ += emptyFuncSize;
            linkedFile->findRegion(initsec, ".init.dyninst");
            assert(initsec);
            linkedFile->addSysVDynamic(DT_INIT, initsec->getMemOffset());
            startup_printf("%s[%d]: creating .init.dyninst region, region addr 0x%lx\n",
                           FILE__, __LINE__, initsec->getMemOffset());
        }
        startup_printf("%s[%d]: ADDING _init at 0x%lx\n", FILE__, __LINE__, initsec->getMemOffset());
        Symbol *initSym = new Symbol( "_init",
                                      Symbol::ST_FUNCTION,
                                      Symbol::SL_GLOBAL,
                                      Symbol::SV_DEFAULT,
                                      initsec->getMemOffset(),
                                      linkedFile->getDefaultModule(),
                                      initsec,
                                      UINT_MAX );
        linkedFile->addSymbol(initSym);
    }
    if( !foundFini )
    {
        Offset finiOffset = linkedFile->getFiniOffset();
        Region *finisec = linkedFile->findEnclosingRegion(finiOffset);
        if(!finiOffset || !finisec)
        {
            unsigned char* emptyFunction = NULL;
            int emptyFuncSize = 0;
#if defined(arch_x86) || defined(arch_x86_64)
            static unsigned char empty_32[] = { 0x55, 0x89, 0xe5, 0xc9, 0xc3 };
            static unsigned char empty_64[] = { 0x55, 0x48, 0x89, 0xe5, 0xc9, 0xc3 };
            if(linkedFile->getAddressWidth() == 8)
            {
                emptyFunction = empty_64;
                emptyFuncSize = 6;
            }
            else
            {
                emptyFunction = empty_32;
                emptyFuncSize = 5;
            }

#elif defined (arch_power)
            static unsigned empty[] = {0x4e800020};
            emptyFunction = (unsigned char*) empty;
            emptyFuncSize = 4;

#elif defined (arch_aarch64)
            static unsigned char empty[] = { 
                0xfd, 0x7b, 0xbf, 0xa9, 
                0xfd, 0x03, 0x00, 0x91, 
                0xfd, 0x7b, 0xc1, 0xa8, 
                0xc0, 0x03, 0x5f, 0xd6};
            emptyFunction = empty;
            emptyFuncSize = 16;
#endif //defined(arch_x86) || defined(arch_x86_64)

            linkedFile->addRegion(highWaterMark_, (void*)(emptyFunction), emptyFuncSize, ".fini.dyninst",
                                  Dyninst::SymtabAPI::Region::RT_TEXT, true);
            highWaterMark_ += emptyFuncSize;
            lowWaterMark_ += emptyFuncSize;
            linkedFile->findRegion(finisec, ".fini.dyninst");
            assert(finisec);
            linkedFile->addSysVDynamic(DT_FINI, finisec->getMemOffset());
            startup_printf("%s[%d]: creating .fini.dyninst region, region addr 0x%lx\n",
                           FILE__, __LINE__, finisec->getMemOffset());

        }
        startup_printf("%s[%d]: ADDING _fini at 0x%lx\n", FILE__, __LINE__, finisec->getMemOffset());
        Symbol *finiSym = new Symbol( "_fini",
                                      Symbol::ST_FUNCTION,
                                      Symbol::SL_GLOBAL,
                                      Symbol::SV_DEFAULT,
                                      finisec->getMemOffset(),
                                      linkedFile->getDefaultModule(),
                                      finisec,
                                      UINT_MAX );
        linkedFile->addSymbol(finiSym);
    }
}
Beispiel #2
0
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;
}
Beispiel #3
0
bool BinaryEdit::writeFile(const std::string &newFileName) 
{
   // Step 1: changes. 


      inst_printf(" writing %s ... \n", newFileName.c_str());

      Symtab *symObj = mobj->parse_img()->getObject();

      // link to the runtime library if tramp guards are currently enabled
      if ( !symObj->isStaticBinary() && !BPatch::bpatch->isTrampRecursive() ) {
          assert(!runtime_lib.empty());
          symObj->addLibraryPrereq((*runtime_lib.begin())->fileName());
      }

      if( symObj->isStaticBinary() && isDirty() ) {
         if( !doStaticBinarySpecialCases() ) {
	   cerr << "Failed to write file " << newFileName << ": static binary handler failed" << endl;
	   return false;
         }
      }

   	  delayRelocation_ = false;
      relocate();
      
      vector<Region*> oldSegs;
      symObj->getAllRegions(oldSegs);

      //Write any traps to the mutatee
      if (canUseTraps()) {
         trapMapping.shouldBlockFlushes(false);
         trapMapping.flush();
      }

      // Now, we need to copy in the memory of the new segments
      for (unsigned i = 0; i < oldSegs.size(); i++) {
         codeRange *segRange = NULL;
         if (!memoryTracker_->find(oldSegs[i]->getMemOffset(), segRange)) {
#if 0
            // Looks like BSS
            if (newSegs[i].name == ".bss")
#endif
               continue;
            //inst_printf (" segment name: %s\n", newSegs[i].name.c_str());
            //assert(0);
         }
         //inst_printf(" ==> memtracker: Copying to 0x%lx from 0x%lx\n", 
         //newSegs[i].loadaddr, segRange->get_local_ptr());
	 memoryTracker* mt = dynamic_cast<memoryTracker*>(segRange);
	 assert(mt);
	 if(mt->dirty) {
            oldSegs[i]->setPtrToRawData(segRange->get_local_ptr(), oldSegs[i]->getMemSize());
	 }
	 
         //newSegs[i].data = segRange->get_local_ptr();
      }

      // Okay, that does it for the old stuff.

      // Now we need to get the new stuff. That's all the allocated memory. First, big
      // buffer to hold it.

      void *newSectionPtr = malloc(highWaterMark_ - lowWaterMark_);

      pdvector<codeRange *> writes;
      memoryTracker_->elements(writes);

      for (unsigned i = 0; i < writes.size(); i++) {
         assert(newSectionPtr);
         memoryTracker *tracker = dynamic_cast<memoryTracker *>(writes[i]);
         assert(tracker);
         //inst_printf("memory tracker: 0x%lx  load=0x%lx  size=%d  %s\n", 
         //tracker->get_local_ptr(), tracker->get_address(), tracker->get_size(),
         //tracker->alloced ? "[A]" : "");
         if (!tracker->alloced) continue;

         // Copy whatever is in there into the big buffer, at the appropriate address
         assert(tracker->get_address() >= lowWaterMark_);
         Address offset = tracker->get_address() - lowWaterMark_;
         assert((offset + tracker->get_size()) < highWaterMark_);
         void *ptr = (void *)(offset + (Address)newSectionPtr);
         memcpy(ptr, tracker->get_local_ptr(), tracker->get_size());
      }
            
      // Righto. Now, that includes the old binary - by design - 
      // so skip it and see what we're talking about size-wise. Which should
      // be less than the highWaterMark, so we can double-check.

      // Next, make a new section. We have the following parameters:
      // Offset vaddr: we get this from Symtab - "first free address with sufficient space"
      // std::string name: without reflection, ".dyninstInst"
      // unsigned long flags: these are a SymtabAPI abstraction. We're going with text|data because
      //    we might have both.
      // bool loadable: heck yeah...
        
      Region *newSec = NULL;
      symObj->findRegion(newSec, ".dyninstInst");
      if (newSec) {
         // We're re-instrumenting - will fail for now
         fprintf(stderr, "ERROR:  unable to open/reinstrument previously instrumented binary %s!\n", newFileName.c_str());
         return false;
      }

      symObj->addRegion(lowWaterMark_,
                        newSectionPtr,
                        highWaterMark_ - lowWaterMark_,
                        ".dyninstInst",
                        Region::RT_TEXTDATA,
                        true);
	  fprintf(stderr,"Write lowWater : %lx, highWater : %lx\n",lowWaterMark_,highWaterMark_);
      
      symObj->findRegion(newSec, ".dyninstInst");
      assert(newSec);

      
      if (mobj == getAOut()) {
         // Add dynamic symbol relocations
         for (unsigned i=0; i < dependentRelocations.size(); i++) {
            Address to = dependentRelocations[i]->getAddress();
            Symbol *referring = dependentRelocations[i]->getReferring();
            /*
              if (!symObj->isStaticBinary() && !symObj->hasReldyn() && !symObj->hasReladyn()) {
              Address addr = referring->getOffset();
              bool result = writeDataSpace((void *) to, getAddressWidth(), &addr);
              assert(result);
              continue;
              }
            */
               
            // Create the relocationEntry
            relocationEntry localRel(to, referring->getMangledName(), referring,
                                     relocationEntry::getGlobalRelType(getAddressWidth(), referring));
	    
            /*
              if( mobj->isSharedLib() ) {
              localRel.setRelAddr(to - mobj->imageOffset());
              }
            */
            
            symObj->addExternalSymbolReference(referring, newSec, localRel);
            
            /*
              newSymbol = new Symbol(referring->getName(), 
              Symbol::ST_FUNCTION, 
              Symbol::SL_GLOBAL,
              Symbol::SV_DEFAULT, 
              (Address)0, 
              symObj->getDefaultModule(),
              NULL, 
              8,
              true, 
              false);
              symObj->addSymbol(newSymbol, referring);
              if (!symObj->hasReldyn() && symObj->hasReladyn()) {
              newSec->addRelocationEntry(to, newSymbol, relocationEntry::dynrel, Region::RT_RELA);
              } else {
              newSec->addRelocationEntry(to, newSymbol, relocationEntry::dynrel);
              }
            */
         }
      }
      
      pdvector<Symbol *> newSyms;
      buildDyninstSymbols(newSyms, newSec, symObj->getOrCreateModule("dyninstInst",
                                                                     lowWaterMark_));
      for (unsigned i = 0; i < newSyms.size(); i++) {
         symObj->addSymbol(newSyms[i]);
      }
      
      // Okay, now...
      // Hand textSection and newSection to DynSymtab.
        
      // First, textSection.
        
      // From the SymtabAPI documentation: we have the following methods we want to use.
      // Symtab::addSection(Offset vaddr, void *data, unsigned int dataSize, std::string name, 
      //                    unsigned long flags, bool loadable)
      // Symtab::updateCode(void *buffer, unsigned size)
      // Symtab::emit(std::string filename)
        
      // First, text
      assert(symObj);
      
      
      // And now we generate the new binary
      //if (!symObj->emit(newFileName.c_str())) {
      if (!symObj->emit(newFileName.c_str())) {
         SymtabError lastError = Symtab::getLastSymtabError();
         showErrorCallback(109, Symtab::printError(lastError));
         return false;
      }
   return true;
}
Beispiel #4
0
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;
}
Beispiel #5
0
BinaryEdit *BinaryEdit::openFile(const std::string &file, 
                                 PatchMgrPtr mgr, 
                                 Dyninst::PatchAPI::Patcher *patch,
                                 const std::string &member) {
    if (!OS::executableExists(file)) {
        startup_printf("%s[%d]:  failed to read file %s\n", FILE__, __LINE__, file.c_str());
        std::string msg = std::string("Can't read executable file ") + file + (": ") + strerror(errno);
        showErrorCallback(68, msg.c_str());
        return NULL;
    }
    
    fileDescriptor desc;
    if (!getStatFileDescriptor(file, desc)) {
        startup_printf("%s[%d]: failed to create file descriptor for %s!\n",
                       FILE__, __LINE__, file.c_str());
        return NULL;
    }
    
    // Open the mapped object as an archive member
    if( !member.empty() ) {
        desc.setMember(member);
    }

    BinaryEdit *newBinaryEdit = new BinaryEdit();
    if (!newBinaryEdit) {
        startup_printf("%s[%d]: failed to create binary representation for %s!\n",
                       FILE__, __LINE__, file.c_str());
    }

    newBinaryEdit->mobj = mapped_object::createMappedObject(desc, newBinaryEdit);
    if (!newBinaryEdit->mobj) {
        startup_printf("%s[%d]: failed to create mapped object for %s\n",
                       FILE__, __LINE__, file.c_str());
        return NULL;
    }

    /* PatchAPI stuffs */
    if (!mgr) {
       newBinaryEdit->initPatchAPI();
    } else {
       newBinaryEdit->setMgr(mgr);
       assert(patch);
       newBinaryEdit->setPatcher(patch);
    }
    newBinaryEdit->addMappedObject(newBinaryEdit->mobj);
    /* End of PatchAPI stuffs */

    // We now need to access the start of the new section we're creating.

    // I'm going through the mapped_object interface for now - 
    // I assume we'll pass it to DynSymtab, then add our base
    // address to it at the mapped_ level. 
    Symtab* linkedFile = newBinaryEdit->getAOut()->parse_img()->getObject();
    Region *newSec = NULL;
    linkedFile->findRegion(newSec, ".dyninstInst");
    if (newSec) {
         // We're re-instrumenting - will fail for now
         fprintf(stderr, "ERROR:  unable to open/reinstrument previously instrumented binary %s!\n", file.c_str());
         return NULL;
    }
    Address base = linkedFile->getFreeOffset(50*1024*1024);
    base += (1024*1024);
    base -= (base & (1024*1024-1));

    newBinaryEdit->highWaterMark_ = base;
    newBinaryEdit->lowWaterMark_ = newBinaryEdit->highWaterMark_;
	//CHEN MODIFIED, this can reserve space for plt table, or even for inline code region
	//newBinaryEdit->highWaterMark_ += 0x100000;

    // Testing

    newBinaryEdit->makeInitAndFiniIfNeeded();

    newBinaryEdit->createMemoryBackingStore(newBinaryEdit->getAOut());
    newBinaryEdit->initialize();

    //Don't count initialization in determining dirty
    newBinaryEdit->isDirty_ = false; //!(foundInit && foundFini);
    return newBinaryEdit;
}