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); } }
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; }
DysectErrorCode Backend::irpc(Process::ptr process, string libraryPath, string funcName, void *arg, int argLength) { int funcAddrOffset = -1, argOffset = -1; bool result, found = false; unsigned char *begin, *end, *c, *buffer; unsigned long size, *valuePtr, *ptr, value; string libraryName; Symtab *symtab = NULL; Address loadAddress; Offset funcOffset; vector<SymtabAPI::Function *> functions; if (symtabs.find(libraryPath) == symtabs.end()) { result = Symtab::openFile(symtab, libraryPath.c_str()); if (result == false) { DYSECTWARN(false, "Failed to find file %s for symtab", libraryPath.c_str()); return Error; } } else { symtab = symtabs[libraryPath]; } libraryName = basename(libraryPath.c_str()); LibraryPool &libs = process->libraries(); LibraryPool::iterator libsIter; for (libsIter = libs.begin(); libsIter != libs.end(); libsIter++) { Library::ptr libraryPtr = *libsIter; if (libraryPtr->getName().find(libraryName) == string::npos) continue; loadAddress = (*libsIter)->getLoadAddress(); found = true; DYSECTLOG(true, "found library %s at 0x%lx", libraryName.c_str(), loadAddress); break; } if (found == false) { DYSECTWARN(false, "Failed to find library %s", libraryName.c_str()); return Error; } begin = call_snippet_begin; end = call_snippet_end; size = (unsigned long)*end - (unsigned long)*begin; for (c = begin; c != end; c++) { valuePtr = (unsigned long *)c; if (*valuePtr == 0x1122334455667788) { funcAddrOffset = (long)(c - begin); } if (*valuePtr == 0xaabbccddeeffaabb) { argOffset = (long)(c - begin); } } result = symtab->findFunctionsByName(functions, funcName); if (result == false || functions.size() < 1) { DYSECTWARN(false, "Failed to find %s function", funcName.c_str()); return Error; } funcOffset = functions[0]->getOffset(); DYSECTLOG(true, "found %s at offset 0x%lx", funcName.c_str(), funcOffset); buffer = (unsigned char *)malloc(size); if (!buffer) { DYSECTWARN(false, "Failed to allocate %d bytes for target %d", size); return Error; } memcpy(buffer, begin, size); c = buffer + funcAddrOffset; value = loadAddress + funcOffset; memcpy(c, &value, sizeof(unsigned long)); c = buffer + argOffset; memcpy(c, arg, argLength); IRPC::ptr irpc; irpc = IRPC::createIRPC((void *)buffer, size, false); if (!irpc) { DYSECTWARN(false, "Failed to create IRPC in target"); return Error; } result = process->postIRPC(irpc); if (!result) { DYSECTWARN(false, "Failed to post IRPC in target"); return Error; } DYSECTLOG(true, "irpc successful for target"); return OK; }
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; }