/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pcodeinject.hh" #include "architecture.hh" /// \brief Read in an \ or \ XML tag describing an injection parameter /// /// \param el is the XML element /// \param name is used to pass back the parameter name /// \param size is used to pass back the parameter size void InjectPayload::readParameter(const Element *el,string &name,uint4 &size) { name = ""; size = 0; int4 num = el->getNumAttributes(); for(int4 i=0;igetAttributeName(i) == "name") name = el->getAttributeValue(i); else if (el->getAttributeName(i) == "size") { istringstream s(el->getAttributeValue(i)); s.unsetf(ios::dec | ios::hex | ios::oct); s >> size; } } if (name.size()==0) throw LowlevelError("Missing inject parameter name"); } /// Input and output parameters are assigned a unique index void InjectPayload::orderParameters(void) { int4 id = 0; for(int4 i=0;i tag. /// Derived classes may restore from a parent tag and then invoke the /// base class method. /// \param el is the XML element void InjectPayload::restoreXml(const Element *el) { paramshift = 0; dynamic = false; int4 num = el->getNumAttributes(); for(int4 i=0;igetAttributeName(i)); if (elname == "paramshift") { istringstream s(el->getAttributeValue(i)); s.unsetf(ios::dec | ios::hex | ios::oct); s >> paramshift; } else if (elname == "dynamic") dynamic = xml_readbool(el->getAttributeValue(i)); else if (elname == "incidentalcopy") incidentalCopy = xml_readbool(el->getAttributeValue(i)); } const List &list(el->getChildren()); List::const_iterator iter; for(iter=list.begin();iter!=list.end();++iter) { const Element *subel = *iter; if (subel->getName() == "input") { string paramName; uint4 size; readParameter(subel,paramName,size); inputlist.push_back(InjectParameter(paramName,size)); } else if (subel->getName() == "output") { string paramName; uint4 size; readParameter(subel,paramName,size); output.push_back(InjectParameter(paramName,size)); } } orderParameters(); } /// \param g is the Architecture owning \b snippet /// \param src is a string describing the \e source of the snippet /// \param nm is the formal name of the snippet ExecutablePcode::ExecutablePcode(Architecture *g,const string &src,const string &nm) : InjectPayload(nm,EXECUTABLEPCODE_TYPE), emulator(g) { glb = g; emitter = (PcodeEmit *)0; source = src; built = false; } void ExecutablePcode::build(void) { if (built) return; InjectContext &icontext(glb->pcodeinjectlib->getCachedContext()); icontext.clear(); uintb uniqReserve = 0x10; // Temporary register space reserved for inputs and output AddrSpace *codeSpace = glb->getDefaultCodeSpace(); AddrSpace *uniqSpace = glb->getUniqueSpace(); icontext.baseaddr = Address(codeSpace,0x1000); // Fake address icontext.nextaddr = icontext.baseaddr; for(int4 i=0;ipcodeinjectlib->getBehaviors(),uniqReserve); inject(icontext,*emitter); delete emitter; emitter = (PcodeEmit *)0; if (!emulator.checkForLegalCode()) throw LowlevelError("Illegal p-code in executable snippet"); built = true; } /// The caller provides a list of concrete values that are assigned to the /// input parameters. The number of values and input parameters must match, /// and values are assigned in order. Input parameter order is determined either /// by the order of tags in the defining XML. This method assumes there is /// exactly 1 relevant output parameter. Once the snippet is executed the /// value of this parameter is read from the emulator state and returned. /// \param input is the ordered list of input values to feed to \b this script /// \return the value of the output parameter after script execution uintb ExecutablePcode::evaluate(const vector &input) { build(); // Build the PcodeOpRaws (if we haven't before) emulator.resetMemory(); if (input.size() != inputList.size()) throw LowlevelError("Wrong number of input parameters to executable snippet"); if (outputList.size() == 0) throw LowlevelError("No registered outputs to executable snippet"); for(int4 i=0;i::iterator iter; for(iter=injection.begin();iter!=injection.end();++iter) delete *iter; } /// \brief Map a \e call-fixup name to a payload id /// /// \param fixupName is the formal name of the call-fixup /// \param injectid is the integer id void PcodeInjectLibrary::registerCallFixup(const string &fixupName,int4 injectid/* , vector targets */) { pair::iterator,bool> check; check = callFixupMap.insert( pair(fixupName,injectid) ); if (!check.second) // This symbol is already mapped throw LowlevelError("Duplicate : "+fixupName); while(callFixupNames.size() <= injectid) callFixupNames.push_back(""); callFixupNames[injectid] = fixupName; } /// \brief Map a \e callother-fixup name to a payload id /// /// \param fixupName is the formal name of the callother-fixup /// \param injectid is the integer id void PcodeInjectLibrary::registerCallOtherFixup(const string &fixupName,int4 injectid) { pair::iterator,bool> check; check = callOtherFixupMap.insert( pair(fixupName,injectid) ); if (!check.second) // This symbol is already mapped throw LowlevelError("Duplicate : "+fixupName); while(callOtherTarget.size() <= injectid) callOtherTarget.push_back(""); callOtherTarget[injectid] = fixupName; } /// \brief Map a \e call \e mechanism name to a payload id /// /// \param fixupName is the formal name of the call mechanism /// \param injectid is the integer id void PcodeInjectLibrary::registerCallMechanism(const string &fixupName,int4 injectid) { pair::iterator,bool> check; check = callMechFixupMap.insert( pair(fixupName,injectid) ); if (!check.second) // This symbol is already mapped throw LowlevelError("Duplicate : "+fixupName); while(callMechTarget.size() <= injectid) callMechTarget.push_back(""); callMechTarget[injectid] = fixupName; } /// \brief Map a \e p-code \e script name to a payload id /// /// \param scriptName is the formal name of the p-code script /// \param injectid is the integer id void PcodeInjectLibrary::registerExeScript(const string &scriptName,int4 injectid) { pair::iterator,bool> check; check = scriptMap.insert( pair(scriptName,injectid) ); if (!check.second) // This symbol is already mapped throw LowlevelError("Duplicate