#include "pcodeinject.hh"
#include "architecture.hh"
void InjectPayload::readParameter(const Element *el,string &name,uint4 &size)
{
name = "";
size = 0;
int4 num = el->getNumAttributes();
for(int4 i=0;i<num;++i) {
if (el->getAttributeName(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");
}
void InjectPayload::orderParameters(void)
{
int4 id = 0;
for(int4 i=0;i<inputlist.size();++i) {
inputlist[i].index = id;
id += 1;
}
for(int4 i=0;i<output.size();++i) {
output[i].index = id;
id += 1;
}
}
void InjectPayload::restoreXml(const Element *el)
{
paramshift = 0;
dynamic = false;
int4 num = el->getNumAttributes();
for(int4 i=0;i<num;++i) {
const string &elname(el->getAttributeName(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();
}
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; AddrSpace *codeSpace = glb->getDefaultCodeSpace();
AddrSpace *uniqSpace = glb->getUniqueSpace();
icontext.baseaddr = Address(codeSpace,0x1000); icontext.nextaddr = icontext.baseaddr;
for(int4 i=0;i<sizeInput();++i) { InjectParameter ¶m( getInput(i) );
icontext.inputlist.emplace_back();
icontext.inputlist.back().space = uniqSpace;
icontext.inputlist.back().offset = uniqReserve;
icontext.inputlist.back().size = param.getSize();
inputList.push_back(uniqReserve);
uniqReserve += 0x20;
}
for(int4 i=0;i<sizeOutput();++i) {
InjectParameter ¶m( getOutput(i) );
icontext.output.emplace_back();
icontext.output.back().space = uniqSpace;
icontext.output.back().offset = uniqReserve;
icontext.output.back().size = param.getSize();
outputList.push_back(uniqReserve);
uniqReserve += 0x20;
}
emitter = emulator.buildEmitter(glb->pcodeinjectlib->getBehaviors(),uniqReserve);
inject(icontext,*emitter);
delete emitter;
emitter = (PcodeEmit *)0;
if (!emulator.checkForLegalCode())
throw LowlevelError("Illegal p-code in executable snippet");
built = true;
}
uintb ExecutablePcode::evaluate(const vector<uintb> &input)
{
build(); 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<input.size();++i)
emulator.setVarnodeValue(inputList[i], input[i]);
while(!emulator.getHalt())
emulator.executeCurrentOp();
return emulator.getTempValue(outputList[0]);
}
PcodeInjectLibrary::~PcodeInjectLibrary(void)
{
vector<InjectPayload *>::iterator iter;
for(iter=injection.begin();iter!=injection.end();++iter)
delete *iter;
}
void PcodeInjectLibrary::registerCallFixup(const string &fixupName,int4 injectid)
{
pair<map<string,int4>::iterator,bool> check;
check = callFixupMap.insert( pair<string,int4>(fixupName,injectid) );
if (!check.second) throw LowlevelError("Duplicate <callfixup>: "+fixupName);
while(callFixupNames.size() <= injectid)
callFixupNames.push_back("");
callFixupNames[injectid] = fixupName;
}
void PcodeInjectLibrary::registerCallOtherFixup(const string &fixupName,int4 injectid)
{
pair<map<string,int4>::iterator,bool> check;
check = callOtherFixupMap.insert( pair<string,int4>(fixupName,injectid) );
if (!check.second) throw LowlevelError("Duplicate <callotherfixup>: "+fixupName);
while(callOtherTarget.size() <= injectid)
callOtherTarget.push_back("");
callOtherTarget[injectid] = fixupName;
}
void PcodeInjectLibrary::registerCallMechanism(const string &fixupName,int4 injectid)
{
pair<map<string,int4>::iterator,bool> check;
check = callMechFixupMap.insert( pair<string,int4>(fixupName,injectid) );
if (!check.second) throw LowlevelError("Duplicate <callmechanism>: "+fixupName);
while(callMechTarget.size() <= injectid)
callMechTarget.push_back("");
callMechTarget[injectid] = fixupName;
}
void PcodeInjectLibrary::registerExeScript(const string &scriptName,int4 injectid)
{
pair<map<string,int4>::iterator,bool> check;
check = scriptMap.insert( pair<string,int4>(scriptName,injectid) );
if (!check.second) throw LowlevelError("Duplicate <script>: "+scriptName);
while(scriptNames.size() <= injectid)
scriptNames.push_back("");
scriptNames[injectid] = scriptName;
}
int4 PcodeInjectLibrary::getPayloadId(int4 type,const string &nm) const
{
map<string,int4>::const_iterator iter;
if (type == InjectPayload::CALLFIXUP_TYPE) {
iter = callFixupMap.find(nm);
if (iter == callFixupMap.end())
return -1;
}
else if (type == InjectPayload::CALLOTHERFIXUP_TYPE) {
iter = callOtherFixupMap.find(nm);
if (iter == callOtherFixupMap.end())
return -1;
}
else if (type == InjectPayload::CALLMECHANISM_TYPE) {
iter = callMechFixupMap.find(nm);
if (iter == callMechFixupMap.end())
return -1;
}
else {
iter = scriptMap.find(nm);
if (iter == scriptMap.end())
return -1;
}
return (*iter).second;
}
string PcodeInjectLibrary::getCallFixupName(int4 injectid) const
{
if ((injectid < 0)||(injectid >= callFixupNames.size()))
return "";
return callFixupNames[injectid];
}
string PcodeInjectLibrary::getCallOtherTarget(int4 injectid) const
{
if ((injectid < 0)||(injectid >= callOtherTarget.size()))
return "";
return callOtherTarget[injectid];
}
string PcodeInjectLibrary::getCallMechanismName(int4 injectid) const
{
if ((injectid < 0)||(injectid >= callMechTarget.size()))
return "";
return callMechTarget[injectid];
}
int4 PcodeInjectLibrary::restoreXmlInject(const string &src,const string &nm,int4 tp,const Element *el)
{
int4 injectid = allocateInject(src, nm, tp);
getPayload(injectid)->restoreXml(el);
registerInject(injectid);
return injectid;
}