/* ### * 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" namespace ghidra { AttributeId ATTRIB_DYNAMIC = AttributeId("dynamic",70); AttributeId ATTRIB_INCIDENTALCOPY = AttributeId("incidentalcopy",71); AttributeId ATTRIB_INJECT = AttributeId("inject",72); AttributeId ATTRIB_PARAMSHIFT = AttributeId("paramshift",73); AttributeId ATTRIB_TARGETOP = AttributeId("targetop",74); ElementId ELEM_ADDR_PCODE = ElementId("addr_pcode",89); ElementId ELEM_BODY = ElementId("body",90); ElementId ELEM_CALLFIXUP = ElementId("callfixup",91); ElementId ELEM_CALLOTHERFIXUP = ElementId("callotherfixup",92); ElementId ELEM_CASE_PCODE = ElementId("case_pcode",93); ElementId ELEM_CONTEXT = ElementId("context",94); ElementId ELEM_DEFAULT_PCODE = ElementId("default_pcode",95); ElementId ELEM_INJECT = ElementId("inject",96); ElementId ELEM_INJECTDEBUG = ElementId("injectdebug",97); ElementId ELEM_INST = ElementId("inst",98); ElementId ELEM_PAYLOAD = ElementId("payload",99); ElementId ELEM_PCODE = ElementId("pcode",100); ElementId ELEM_SIZE_PCODE = ElementId("size_pcode",101); /// \brief Parse an \ or \ element describing an injection parameter /// /// \param decoder is the stream decoder /// \param name is used to pass back the parameter name /// \param size is used to pass back the parameter size void InjectPayload::decodeParameter(Decoder &decoder,string &name,uint4 &size) { name = ""; size = 0; uint4 elemId = decoder.openElement(); for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_NAME) name = decoder.readString(); else if (attribId == ATTRIB_SIZE) { size = decoder.readUnsignedInteger(); } } decoder.closeElement(elemId); 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 element must be current and already opened. /// \param decoder is the stream decoder void InjectPayload::decodePayloadAttributes(Decoder &decoder) { paramshift = 0; dynamic = false; for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_PARAMSHIFT) { paramshift = decoder.readSignedInteger(); } else if (attribId == ATTRIB_DYNAMIC) dynamic = decoder.readBool(); else if (attribId == ATTRIB_INCIDENTALCOPY) incidentalCopy = decoder.readBool(); else if (attribId == ATTRIB_INJECT) { string uponType = decoder.readString(); if (uponType == "uponentry") name = name + "@@inject_uponentry"; else name = name + "@@inject_uponreturn"; } } } /// Elements are processed until the first child that isn't an \ or \ tag /// is encountered. The \ element must be current and already opened. /// \param decoder is the stream decoder void InjectPayload::decodePayloadParams(Decoder &decoder) { for(;;) { uint4 subId = decoder.peekElement(); if (subId == ELEM_INPUT) { string paramName; uint4 size; decodeParameter(decoder,paramName,size); inputlist.push_back(InjectParameter(paramName,size)); } else if (subId == ELEM_OUTPUT) { string paramName; uint4 size; decodeParameter(decoder,paramName,size); output.push_back(InjectParameter(paramName,size)); } else break; } 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