diff --git a/PNTransformDriver.cpp b/PNTransformDriver.cpp index 7078adfe15019d309fe81d88398df71fb023681e..11783621d0dca72e1bd0567a0802e1ab8bb77e51 100644 --- a/PNTransformDriver.cpp +++ b/PNTransformDriver.cpp @@ -25,6 +25,7 @@ #include <fstream> #include <sstream> #include <iomanip> +#include <memory> // #include "beaengine/BeaEngine.h" #include "General_Utility.hpp" #include "PNIrdbManager.hpp" @@ -58,15 +59,15 @@ using namespace IRDB_SDK; char* get_current_dir_name(void) { - char* pwd = getenv("PWD"); - char tmp[PATH_MAX]; - struct stat a,b; - if (pwd && !stat(".",&a) && !stat(pwd,&b) && - a.st_dev==b.st_dev && a.st_ino==b.st_ino) - return strdup(pwd); - if (getcwd(tmp,sizeof(tmp))) - return strdup(tmp); - return 0; + char* pwd = getenv("PWD"); + char tmp[PATH_MAX]; + struct stat a,b; + if (pwd && !stat(".",&a) && !stat(pwd,&b) && + a.st_dev==b.st_dev && a.st_ino==b.st_ino) + return strdup(pwd); + if (getcwd(tmp,sizeof(tmp))) + return strdup(tmp); + return 0; } //TODO: this var is a hack for TNE @@ -105,7 +106,7 @@ static bool CompareValidationRecordAscending(validation_record a, validation_rec PNTransformDriver::PNTransformDriver(VariantID_t *pidp,string BED_script, pqxxDB_t *pqxx_if) : - pn_regex(NULL), pqxx_interface(pqxx_if) + pqxx_interface(pqxx_if) { //TODO: throw exception? assert(pidp != NULL); @@ -129,18 +130,12 @@ PNTransformDriver::PNTransformDriver(VariantID_t *pidp,string BED_script, pqxxDB PNTransformDriver::~PNTransformDriver() { - //NOTE: because I now handle shared objects, I clean up orig_virp - //as I create use it, deleting here caused errors, I had to - //ensure orig_virp is NULL, which I could do, but it is just as - //easy to destroy it myself when I am finished with it. -// if(orig_virp != NULL) -// delete orig_virp; } //TODO: redesign the way inferences are added void PNTransformDriver::AddInference(PNStackLayoutInference *inference, int level) { -//TODO: throw exceptions + //TODO: throw exceptions if(level < 0) assert(false); if(inference == NULL) @@ -198,14 +193,6 @@ void PNTransformDriver::SetDoAlignStack(bool align_stack) void PNTransformDriver::AddBlacklist(set<string> &blacklist) { this->blacklist.insert(blacklist.begin(),blacklist.end()); - -/* - set<string>::iterator it; - for(it = blacklist.begin();it != blacklist.end();it++) - { - this->blacklist.insert(*it); - } -*/ } void PNTransformDriver::AddBlacklistFunction(string func_name) @@ -262,7 +249,7 @@ bool PNTransformDriver::PaddingTransformHandler(PNStackLayout *layout, Function_ layout->Shuffle();//one final shuffle layout->AddRandomPadding(do_align); - + if(!Sans_Canary_Rewrite(layout,func)) { undo(func); @@ -276,20 +263,9 @@ bool PNTransformDriver::PaddingTransformHandler(PNStackLayout *layout, Function_ else { cerr<<"PNTransformDriver: Final Transformation Success: "<<layout->ToString()<<endl; -// transformed_history[layout->GetLayoutName()].push_back(layout); - // finalize_record fr; - // fr.layout = layout; - // fr.func = func; - // fr.firp = orig_virp; - // finalization_registry.push_back(fr); - // undo(func); success = true; - //undo_list.clear(); - //reset_undo(func->getName()); } - //orig_virp->writeToDB(); - return success; } @@ -311,30 +287,20 @@ bool PNTransformDriver::LayoutRandTransformHandler(PNStackLayout *layout, Functi //TODO: do I need to check for success at this point? Sans_Canary_Rewrite(layout,func); cerr<<"PNTransformDriver: Final Transformation Success: "<<layout->ToString()<<endl; -// transformed_history[layout->GetLayoutName()].push_back(layout); - // finalize_record fr; - // fr.layout = layout; - // fr.func = func; - // fr.firp = orig_virp; - // finalization_registry.push_back(fr); - // undo(func); success = true; - //undo_list.clear(); - //reset_undo(func->getName()); } - //orig_virp->writeToDB(); return success; } bool PNTransformDriver::IsBlacklisted(Function_t *func) { - if(sanitized.find(func) != sanitized.end()) - { - cerr<<"PNTransformDriver:: Sanitized Function "<<func->getName()<<endl; - sanitized_funcs++; - return true; - } + if(sanitized.find(func) != sanitized.end()) + { + cerr<<"PNTransformDriver:: Sanitized Function "<<func->getName()<<endl; + sanitized_funcs++; + return true; + } // @todo: specify regex patterns in black list file instead // of special-casing here @@ -342,21 +308,22 @@ bool PNTransformDriver::IsBlacklisted(Function_t *func) // filter out _L_lock_* // filter out _L_unlock_* - if (func->getName().find("_L_lock_") == 0 || - func->getName().find("_L_unlock_") == 0 || - func->getName().find("__gnu_") != string::npos || - func->getName().find("cxx_") != string::npos|| - func->getName().find("_cxx") != string::npos || - func->getName().find("_GLOBAL_") != string::npos || - func->getName().find("_Unwind") != string::npos || - func->getName().find("__timepunct") != string::npos || - func->getName().find("__timepunct") != string::npos || - func->getName().find("__numpunct") != string::npos|| - func->getName().find("__moneypunct") != string::npos || - func->getName().find("__PRETTY_FUNCTION__") != string::npos || - func->getName().find("__cxa") != string::npos || - blacklist.find(func->getName()) != blacklist.end()) -// if(blacklist.find(func->getName()) != blacklist.end()) + if ( + func->getName().find("_L_lock_") == 0 || + func->getName().find("_L_unlock_") == 0 || + func->getName().find("__gnu_") != string::npos || + func->getName().find("cxx_") != string::npos|| + func->getName().find("_cxx") != string::npos || + func->getName().find("_GLOBAL_") != string::npos || + func->getName().find("_Unwind") != string::npos || + func->getName().find("__timepunct") != string::npos || + func->getName().find("__timepunct") != string::npos || + func->getName().find("__numpunct") != string::npos|| + func->getName().find("__moneypunct") != string::npos || + func->getName().find("__PRETTY_FUNCTION__") != string::npos || + func->getName().find("__cxa") != string::npos || + blacklist.find(func->getName()) != blacklist.end() + ) { cerr<<"PNTransformDriver: Blacklisted Function "<<func->getName()<<endl; blacklist_funcs++; @@ -395,19 +362,15 @@ void PNTransformDriver::InitNewFileIR(File_t* this_file, IRDBObjects_t *const ir { this_file=pidp->getMainFile(); } + //Always modify a.ncexe first. This is assumed to be what the constructor of FileIR_t will return if //the variant ID is used alone as the parameter to the constructor. orig_virp = irdb_objects->addFileIR(pidp->getBaseID(), this_file->getBaseID());// new FileIR_t(*pidp, this_file); assert(orig_virp && pidp); -#if 0 - int elfoid=orig_virp->getFile()->getELFOID(); - pqxx::largeobject lo(elfoid); - lo.to_file(pqxx_interface->getTransaction(),"readeh_tmp_file.exe"); -#endif elfiop=new EXEIO::exeio; elfiop->load((char*)"a.ncexe"); - + EXEIO::dump::header(cout,*elfiop); EXEIO::dump::section_headers(cout,*elfiop); @@ -418,7 +381,7 @@ void PNTransformDriver::InitNewFileIR(File_t* this_file, IRDBObjects_t *const ir template <class T> struct file_less : binary_function <T,T,bool> { - bool operator() (const T& x, const T& y) const {return x->getURL() < y->getURL() ;} + bool operator() (const T& x, const T& y) const {return x->getURL() < y->getURL() ;} }; void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) @@ -436,7 +399,7 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) cerr<<"PNTransformDriver ERROR: no_validation_level greater than highest level in the hierarchy, exiting."<<endl; exit(1); } - + //TODO: I refactored PN, but to keep the refactoring simple, I did not change the use of the class field "orig_virp" //now that I am protecting shared objects, it might be better to pass this variable around, or at least change the @@ -447,7 +410,7 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) // now that we've loaded the FileIR, we can init the reg expressions needed for this object. - pn_regex=new PNRegularExpressions; + pn_regex=make_unique<PNRegularExpressions>(); //Sanity check: make sure that this file is actually a.ncexe, if not assert false for now @@ -474,9 +437,9 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) set<File_t*,file_less<File_t*> > sorted_files; for(set<File_t*>::iterator it=pidp->getFiles().begin(); - it!=pidp->getFiles().end(); - ++it - ) + it!=pidp->getFiles().end(); + ++it + ) { File_t* this_file=*it; sorted_files.insert(this_file); @@ -484,9 +447,9 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) for(set<File_t*,file_less<File_t*> >::iterator it=sorted_files.begin(); - it!=sorted_files.end()&&!timeExpired; - ++it - ) + it!=sorted_files.end()&&!timeExpired; + ++it + ) { File_t* this_file=*it; assert(this_file); @@ -507,7 +470,7 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) //the complete path is not currently in the DB for a shared object //I have to loop through the map for now. for(map<string, map<string, double> >::iterator it=coverage_map.begin(); - it!=coverage_map.end()&&!timeExpired; ++it) + it!=coverage_map.end()&&!timeExpired; ++it) { key = it->first; @@ -528,7 +491,6 @@ void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) cerr<<"######PreFile Report: Accumulated results prior to processing file: "<<url<<"######"<<endl; - //Print_Report(); cout<<"PNTransformDriver: Protecting File: "<<url<<endl; GenerateTransformsHidden(file_coverage_map); @@ -600,11 +562,11 @@ static bool is_exit_insn(Instruction_t* prev) // check for fixed_call const auto reloc_it=find_if(ALLOF(prev->getRelocations()), [&](const Relocation_t* r) - { return r->getType()=="fix_call_fallthrough"; } ); + { return r->getType()=="fix_call_fallthrough"; } ); if(reloc_it!=end(prev->getRelocations())) return false; - - + + if(prev->getFallthrough()==NULL && prev->getTarget()==NULL) { const auto dp=DecodedInstruction_t::factory(prev); @@ -616,9 +578,9 @@ static bool is_exit_insn(Instruction_t* prev) if(ib_targets) { const auto out_of_function_it=find_if(ALLOF(*ib_targets), [&](const Instruction_t* i) - { + { return i->getFunction() != prev->getFunction(); - } ) ; + } ) ; if(out_of_function_it!=end(*ib_targets)) return true; // detected this as an exit node. @@ -658,9 +620,9 @@ static bool check_for_cond_frame(Function_t *func, ControlFlowGraph_t* cfg) const auto is_rsp_sub= [](const DecodedInstruction_t &d) -> bool { return - (d.getMnemonic() == /*string(d.Instruction.Mnemonic)==*/"sub" && /* is sub */ - d.getOperand(0)->isRegister() /* ((d.Argument1.ArgType&0xFFFF0000)==REGISTER_TYPE+GENERAL_REG )*/ && /* and arg1 is a register */ - d.getOperand(0)->getRegNumber()==4 /*(d.Argument1.ArgType&0x0000FFFF)==REG4*/); /* and is the stack pointer. */ + (d.getMnemonic() == /*string(d.Instruction.Mnemonic)==*/"sub" && /* is sub */ + d.getOperand(0)->isRegister() /* ((d.Argument1.ArgType&0xFFFF0000)==REGISTER_TYPE+GENERAL_REG )*/ && /* and arg1 is a register */ + d.getOperand(0)->getRegNumber()==4 /*(d.Argument1.ArgType&0x0000FFFF)==REG4*/); /* and is the stack pointer. */ }; const auto is_rsp_sub_insn= [&](const Instruction_t* i) -> bool @@ -688,7 +650,7 @@ static bool check_for_cond_frame(Function_t *func, ControlFlowGraph_t* cfg) cout<<"Found cond-frame in "<<func->getName()<<" because "<<i->getDisassembly()<<endl; return false; } - + } return true; } @@ -710,7 +672,7 @@ static bool check_for_push_pop_coherence(Function_t *func) -//cerr<<"Found "<<prologue_pushes<<" pushes in "<<func->getName()<<endl; + //cerr<<"Found "<<prologue_pushes<<" pushes in "<<func->getName()<<endl; // keep a map that keeps the count of pops for each function exit. map<Instruction_t*, int> pop_count_per_exit; @@ -719,9 +681,9 @@ static bool check_for_push_pop_coherence(Function_t *func) // now, look for pops, and fill in that map. for( - set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it + set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); + it!=func->getInstructions().end(); + ++it ) { Instruction_t* insn=*it; @@ -747,7 +709,7 @@ static bool check_for_push_pop_coherence(Function_t *func) if(exit_insn) { -//cerr<<"Found exit insn ("<< d2.CompleteInstr << ") for pop ("<< d.CompleteInstr << ")"<<endl; + //cerr<<"Found exit insn ("<< d2.CompleteInstr << ") for pop ("<< d.CompleteInstr << ")"<<endl; map<Instruction_t*, int>::iterator mit; mit=pop_count_per_exit.find(exit_insn); if(mit == pop_count_per_exit.end()) // not found @@ -757,12 +719,12 @@ static bool check_for_push_pop_coherence(Function_t *func) } else { -// -// some pops dont match exit points because they follow a call instruction where arguments were pushed. -// so, we don't immediately error if the pop doesn't match to an exit point. -// -// cerr<<"Could not find exit insn for pop ("<< hex << insn->getBaseID() <<":"<< d.CompleteInstr << " at " << insn->getAddress()->getVirtualOffset() << ")"<<endl; -// return false; + // + // some pops dont match exit points because they follow a call instruction where arguments were pushed. + // so, we don't immediately error if the pop doesn't match to an exit point. + // + // cerr<<"Could not find exit insn for pop ("<< hex << insn->getBaseID() <<":"<< d.CompleteInstr << " at " << insn->getAddress()->getVirtualOffset() << ")"<<endl; + // return false; } } } @@ -773,9 +735,9 @@ static bool check_for_push_pop_coherence(Function_t *func) // stack first. Also handy as this allows "fixed" calls to be ignored. // but, since exits with 0 pops aren't in the map, we don't need an explicit check for them. for( - map<Instruction_t* ,int>::iterator it=pop_count_per_exit.begin(); - it!=pop_count_per_exit.end(); - ++it + map<Instruction_t* ,int>::iterator it=pop_count_per_exit.begin(); + it!=pop_count_per_exit.end(); + ++it ) { pair<Instruction_t*const,int> map_pair=*it; @@ -822,14 +784,14 @@ static bool check_for_push_pop_coherence(Function_t *func) <<hex<<"0x"<<insn->getAddress()->getVirtualOffset()<<endl; return false; } - + } else { cerr<<"Sanitizing function "<<func->getName()<<" because prologue has more than 1 subrsp? "<<endl; return false; } - + } return true; @@ -837,30 +799,30 @@ static bool check_for_push_pop_coherence(Function_t *func) /* * check_for_bad_variadic_funcs -- Look for functions of this form: - 0x0000000000418108 <+0>: push rbp - 0x0000000000418109 <+1>: mov rbp,rsp - 0x000000000041810c <+4>: sub rsp,0x100 - 0x0000000000418113 <+11>: mov DWORD PTR [rbp-0xd4],edi - 0x0000000000418119 <+17>: mov QWORD PTR [rbp-0xe0],rsi - 0x0000000000418120 <+24>: mov QWORD PTR [rbp-0x98],rcx - 0x0000000000418127 <+31>: mov QWORD PTR [rbp-0x90],r8 - 0x000000000041812e <+38>: mov QWORD PTR [rbp-0x88],r9 - 0x0000000000418135 <+45>: movzx eax,al - 0x0000000000418138 <+48>: mov QWORD PTR [rbp-0xf8],rax - 0x000000000041813f <+55>: mov rcx,QWORD PTR [rbp-0xf8] - 0x0000000000418146 <+62>: lea rax,[rcx*4+0x0] - 0x000000000041814e <+70>: mov QWORD PTR [rbp-0xf8],0x41818d - 0x0000000000418159 <+81>: sub QWORD PTR [rbp-0xf8],rax - 0x0000000000418160 <+88>: lea rax,[rbp-0x1] - 0x0000000000418164 <+92>: mov rcx,QWORD PTR [rbp-0xf8] - 0x000000000041816b <+99>: jmp rcx - <leaves function> - -This is a common IDApro failure, as the computed jump is strange for IDA. - -We check for this case by looking for the movzx before EAX is/used otherwise . - -Return value: true if function is OK to transform, false if we find the pattern. + 0x0000000000418108 <+0>: push rbp + 0x0000000000418109 <+1>: mov rbp,rsp + 0x000000000041810c <+4>: sub rsp,0x100 + 0x0000000000418113 <+11>: mov DWORD PTR [rbp-0xd4],edi + 0x0000000000418119 <+17>: mov QWORD PTR [rbp-0xe0],rsi + 0x0000000000418120 <+24>: mov QWORD PTR [rbp-0x98],rcx + 0x0000000000418127 <+31>: mov QWORD PTR [rbp-0x90],r8 + 0x000000000041812e <+38>: mov QWORD PTR [rbp-0x88],r9 + 0x0000000000418135 <+45>: movzx eax,al + 0x0000000000418138 <+48>: mov QWORD PTR [rbp-0xf8],rax + 0x000000000041813f <+55>: mov rcx,QWORD PTR [rbp-0xf8] + 0x0000000000418146 <+62>: lea rax,[rcx*4+0x0] + 0x000000000041814e <+70>: mov QWORD PTR [rbp-0xf8],0x41818d + 0x0000000000418159 <+81>: sub QWORD PTR [rbp-0xf8],rax + 0x0000000000418160 <+88>: lea rax,[rbp-0x1] + 0x0000000000418164 <+92>: mov rcx,QWORD PTR [rbp-0xf8] + 0x000000000041816b <+99>: jmp rcx + <leaves function> + + This is a common IDApro failure, as the computed jump is strange for IDA. + + We check for this case by looking for the movzx before EAX is/used otherwise . + + Return value: true if function is OK to transform, false if we find the pattern. */ bool check_for_bad_variadic_funcs(Function_t *func, const ControlFlowGraph_t* cfg) @@ -910,17 +872,17 @@ bool check_for_bad_variadic_funcs(Function_t *func, const ControlFlowGraph_t* cf static EXEIO::section* find_section(VirtualOffset_t addr, EXEIO::exeio *elfiop) { - for ( int i = 0; i < elfiop->sections.size(); ++i ) - { - EXEIO::section* pSec = elfiop->sections[i]; - assert(pSec); - if(pSec->get_address() > addr) - continue; - if(addr >= pSec->get_address()+pSec->get_size()) - continue; - - return pSec; -} + for ( int i = 0; i < elfiop->sections.size(); ++i ) + { + EXEIO::section* pSec = elfiop->sections[i]; + assert(pSec); + if(pSec->get_address() > addr) + continue; + if(addr >= pSec->get_address()+pSec->get_size()) + continue; + + return pSec; + } return NULL; } @@ -975,33 +937,33 @@ bool PNTransformDriver::check_jump_tables(Instruction_t* insn) if(table_entry!=0) { -// cout << "found possible table entry "<<hex<<table_entry<<" from func "<<insn->getFunction()->getName()<<endl; + // cout << "found possible table entry "<<hex<<table_entry<<" from func "<<insn->getFunction()->getName()<<endl; jump_tab_entries.insert(table_entry); } } - + return check_jump_table_entries(jump_tab_entries,insn->getFunction()); - + } bool PNTransformDriver::check_jump_table_entries(set<int> jump_tab_entries,Function_t* func) { for( - set<Instruction_t*>::const_iterator it=orig_virp->getInstructions().begin(); - it!=orig_virp->getInstructions().end(); - ++it + set<Instruction_t*>::const_iterator it=orig_virp->getInstructions().begin(); + it!=orig_virp->getInstructions().end(); + ++it ) { Instruction_t* ftinsn=*it;; AddressID_t* addr=ftinsn->getAddress(); int voff=addr->getVirtualOffset(); - + // check to see if this instruction is in my table if(jump_tab_entries.find(voff)!=jump_tab_entries.end()) { // it is! - + // now, check to see if the instruction is in my function if(func !=ftinsn->getFunction()) { @@ -1021,58 +983,58 @@ bool PNTransformDriver::check_jump_table_entries(set<int> jump_tab_entries,Funct bool PNTransformDriver::backup_until(const char* insn_type_regex, Instruction_t *& prev, Instruction_t* orig, bool recursive) { prev=orig; - regex_t preg; + regex_t preg; - assert(0 == regcomp(&preg, insn_type_regex, REG_EXTENDED)); + assert(0 == regcomp(&preg, insn_type_regex, REG_EXTENDED)); - int max=10000; - while(preds[prev].size()==1 && max-- > 0) - { - // get the only item in the list. - prev=*(preds[prev].begin()); + int max=10000; + while(preds[prev].size()==1 && max-- > 0) + { + // get the only item in the list. + prev=*(preds[prev].begin()); - // get I7's disassembly - auto disasm_p=DecodedInstruction_t::factory(prev); + // get I7's disassembly + auto disasm_p=DecodedInstruction_t::factory(prev); auto &disasm=*disasm_p; - // check it's the requested type - if(regexec(&preg, disasm.getDisassembly().c_str() /*CompleteInstr*/, 0, NULL, 0) == 0) - { - regfree(&preg); - return true; - } - - // otherwise, try backing up again. - } - - if(recursive) - { - Instruction_t* myprev=prev; - // can't just use prev because recursive call will update it. - for(InstructionSet_t::iterator it=preds[myprev].begin(); - it!=preds[myprev].end(); ++it) - { - Instruction_t* pred=*it; - //Disassemble(pred,disasm); - auto disasmp=DecodedInstruction_t::factory(pred); - auto &disasm=*disasmp; - // check it's the requested type - if(regexec(&preg, disasm.getDisassembly().c_str()/*CompleteInstr*/, 0, NULL, 0) == 0) - { - regfree(&preg); - return true; - } - if(backup_until(insn_type_regex, prev, pred)) - { - regfree(&preg); - return true; - } - // reset for next call - prev=myprev; - } - } - regfree(&preg); + // check it's the requested type + if(regexec(&preg, disasm.getDisassembly().c_str() /*CompleteInstr*/, 0, NULL, 0) == 0) + { + regfree(&preg); + return true; + } + + // otherwise, try backing up again. + } + + if(recursive) + { + Instruction_t* myprev=prev; + // can't just use prev because recursive call will update it. + for(InstructionSet_t::iterator it=preds[myprev].begin(); + it!=preds[myprev].end(); ++it) + { + Instruction_t* pred=*it; + //Disassemble(pred,disasm); + auto disasmp=DecodedInstruction_t::factory(pred); + auto &disasm=*disasmp; + // check it's the requested type + if(regexec(&preg, disasm.getDisassembly().c_str()/*CompleteInstr*/, 0, NULL, 0) == 0) + { + regfree(&preg); + return true; + } + if(backup_until(insn_type_regex, prev, pred)) + { + regfree(&preg); + return true; + } + // reset for next call + prev=myprev; + } + } + regfree(&preg); return false; } @@ -1081,10 +1043,10 @@ void PNTransformDriver::calc_preds() preds.clear(); for(const auto &insn : orig_virp->getInstructions()) { - if(insn->getTarget()) - preds[insn->getTarget()].insert(insn); - if(insn->getFallthrough()) - preds[insn->getFallthrough()].insert(insn); + if(insn->getTarget()) + preds[insn->getTarget()].insert(insn); + if(insn->getFallthrough()) + preds[insn->getFallthrough()].insert(insn); } } @@ -1097,108 +1059,108 @@ void PNTransformDriver::calc_preds() bool PNTransformDriver::check_for_PIC_switch_table64(Instruction_t* insn, const DecodedInstruction_t& disasm) { - /* here's the pattern we're looking for */ + /* here's the pattern we're looking for */ #if 0 I1: 0x000000000044425a <+218>: cmp DWORD PTR [rax+0x8],0xd // bounds checking code, 0xd cases. -I2: 0x000000000044425e <+222>: jbe 0x444320 <_gedit_tab_get_icon+416> - -<snip> -I3: 0x0000000000444264 <+228>: mov rdi,rbp // default case, also jumped to via indirect branch below -<snip> -I4: 0x0000000000444320 <+416>: mov edx,DWORD PTR [rax+0x8] -I5: 0x0000000000444323 <+419>: lea rax,[rip+0x3e1b6] # 0x4824e0 -I6: 0x000000000044432a <+426>: movsxd rdx,DWORD PTR [rax+rdx*4] -I7: 0x000000000044432e <+430>: add rax,rdx -I8: 0x0000000000444331 <+433>: jmp rax // relatively standard switch dispatch code - - -D1: 0x4824e0: .long 0x4824e0-L1 // L1-LN are labels in the code where case statements start. -D2: 0x4824e0: .long 0x4824e0-L2 -.. -DN: 0x4824e0: .long 0x4824e0-LN + I2: 0x000000000044425e <+222>: jbe 0x444320 <_gedit_tab_get_icon+416> + + <snip> + I3: 0x0000000000444264 <+228>: mov rdi,rbp // default case, also jumped to via indirect branch below + <snip> + I4: 0x0000000000444320 <+416>: mov edx,DWORD PTR [rax+0x8] + I5: 0x0000000000444323 <+419>: lea rax,[rip+0x3e1b6] # 0x4824e0 + I6: 0x000000000044432a <+426>: movsxd rdx,DWORD PTR [rax+rdx*4] + I7: 0x000000000044432e <+430>: add rax,rdx + I8: 0x0000000000444331 <+433>: jmp rax // relatively standard switch dispatch code + + + D1: 0x4824e0: .long 0x4824e0-L1 // L1-LN are labels in the code where case statements start. + D2: 0x4824e0: .long 0x4824e0-L2 + .. + DN: 0x4824e0: .long 0x4824e0-LN #endif - // for now, only trying to find I4-I8. ideally finding I1 would let us know the size of the - // jump table. We'll figure out N by trying targets until they fail to produce something valid. + // for now, only trying to find I4-I8. ideally finding I1 would let us know the size of the + // jump table. We'll figure out N by trying targets until they fail to produce something valid. - Instruction_t* I8=insn; - Instruction_t* I7=NULL; - Instruction_t* I6=NULL; - Instruction_t* I5=NULL; - // check if I8 is a jump - if(disasm.getMnemonic() != "jmp") - return true; + Instruction_t* I8=insn; + Instruction_t* I7=NULL; + Instruction_t* I6=NULL; + Instruction_t* I5=NULL; + // check if I8 is a jump + if(disasm.getMnemonic() != "jmp") + return true; - // return if it's a jump to a constant address, these are common - if(disasm.getOperand(0)->isConstant()) - return true; - // return if it's a jump to a memory address - if(disasm.getOperand(0)->isMemory()) - return true; + // return if it's a jump to a constant address, these are common + if(disasm.getOperand(0)->isConstant()) + return true; + // return if it's a jump to a memory address + if(disasm.getOperand(0)->isMemory()) + return true; - // has to be a jump to a register now + // has to be a jump to a register now - // backup and find the instruction that's an add before I8 - if(!backup_until("add", I7, I8)) - return true; + // backup and find the instruction that's an add before I8 + if(!backup_until("add", I7, I8)) + return true; - // backup and find the instruction that's an movsxd before I7 - if(!backup_until("movsxd", I6, I7)) - return true; + // backup and find the instruction that's an movsxd before I7 + if(!backup_until("movsxd", I6, I7)) + return true; - // backup and find the instruction that's an lea before I6 - if(!backup_until("lea", I5, I6)) - return true; + // backup and find the instruction that's an lea before I6 + if(!backup_until("lea", I5, I6)) + return true; - auto i5_disasmp=DecodedInstruction_t::factory(I5); // Disassemble(I5,disasm); - auto &i5_disasm=*i5_disasmp; + auto i5_disasmp=DecodedInstruction_t::factory(I5); // Disassemble(I5,disasm); + auto &i5_disasm=*i5_disasmp; - if(!i5_disasm.getOperand(1)->isMemory()) - return true; - if(!i5_disasm.getOperand(1)->isPcrel()) - return true; + if(!i5_disasm.getOperand(1)->isMemory()) + return true; + if(!i5_disasm.getOperand(1)->isPcrel()) + return true; - // note that we'd normally have to add the displacement to the - // instruction address (and include the instruction's size, etc. - // but, fix_calls has already removed this oddity so we can relocate - // the instruction. - int D1=strtol(i5_disasm.getOperand(1)->getString().c_str(), NULL, 16); + // note that we'd normally have to add the displacement to the + // instruction address (and include the instruction's size, etc. + // but, fix_calls has already removed this oddity so we can relocate + // the instruction. + int D1=strtol(i5_disasm.getOperand(1)->getString().c_str(), NULL, 16); - // find the section with the data table - EXEIO::section *pSec=find_section(D1,elfiop); + // find the section with the data table + EXEIO::section *pSec=find_section(D1,elfiop); - // sanity check there's a section - if(!pSec) - return true; + // sanity check there's a section + if(!pSec) + return true; - const char* secdata=pSec->get_data(); + const char* secdata=pSec->get_data(); - // if the section has no data, abort - if(!secdata) - return true; + // if the section has no data, abort + if(!secdata) + return true; - set<int> table_entries; - int offset=D1-pSec->get_address(); - int entry=0; - for(int i=0;table_entries.size()<5;i++) - { - // check that we can still grab a word from this section - if((int)(offset+sizeof(int)) > (int)pSec->get_size()) - break; + set<int> table_entries; + int offset=D1-pSec->get_address(); + int entry=0; + for(int i=0;table_entries.size()<5;i++) + { + // check that we can still grab a word from this section + if((int)(offset+sizeof(int)) > (int)pSec->get_size()) + break; - const int *table_entry_ptr=(const int*)&(secdata[offset]); - int table_entry=*table_entry_ptr; + const int *table_entry_ptr=(const int*)&(secdata[offset]); + int table_entry=*table_entry_ptr; - //put in set -> d1+table_entry - table_entries.insert(D1+table_entry); + //put in set -> d1+table_entry + table_entries.insert(D1+table_entry); - offset+=sizeof(int); - entry++; + offset+=sizeof(int); + entry++; - } + } - return check_jump_table_entries(table_entries,insn->getFunction()); + return check_jump_table_entries(table_entries,insn->getFunction()); } void PNTransformDriver::SanitizeFunctions() @@ -1208,19 +1170,19 @@ void PNTransformDriver::SanitizeFunctions() sanitized.clear(); for( - set<Function_t*>::const_iterator func_it=orig_virp->getFunctions().begin(); - func_it!=orig_virp->getFunctions().end(); - ++func_it - ) + set<Function_t*>::const_iterator func_it=orig_virp->getFunctions().begin(); + func_it!=orig_virp->getFunctions().end(); + ++func_it + ) { Function_t *func = *func_it; assert(func); for( - set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it - ) + set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); + it!=func->getInstructions().end(); + ++it + ) { Instruction_t* instr = *it; @@ -1245,7 +1207,7 @@ void PNTransformDriver::SanitizeFunctions() // exits the function. If so, sanitize both funcs. TargetFunctionCheck(instr,instr->getTarget()); - + } // if it's not already sanitized @@ -1263,7 +1225,7 @@ void PNTransformDriver::SanitizeFunctions() // if it's not already sanitized if(sanitized.find(func)==sanitized.end()) { - if(!check_for_PIC_switch_table64(instr,disasm)) + if(!check_for_PIC_switch_table64(instr,disasm)) { pic_jump_table_sanitized++; sanitized.insert(func); @@ -1274,8 +1236,8 @@ void PNTransformDriver::SanitizeFunctions() if(sanitized.find(func)==sanitized.end()) { if(instr->getEhCallSite() && - instr->getEhCallSite()->getLandingPad() && - instr->getEhCallSite()->getLandingPad()->getFunction()!=func) + instr->getEhCallSite()->getLandingPad() && + instr->getEhCallSite()->getLandingPad()->getFunction()!=func) { eh_sanitized++; sanitized.insert(func); @@ -1325,10 +1287,10 @@ void PNTransformDriver::SanitizeFunctions() cerr<<"Sanitization Report:"<<"\nThe following "<<sanitized.size()<< " functions were sanitized from this file:"<<endl; for( - set<Function_t*>::const_iterator it=sanitized.begin(); - it!=sanitized.end(); - ++it - ) + set<Function_t*>::const_iterator it=sanitized.begin(); + it!=sanitized.end(); + ++it + ) { Function_t *func=*it; if(func != NULL) @@ -1386,7 +1348,7 @@ inline bool PNTransformDriver::TargetFunctionCheck(Instruction_t* a, Instruction template <class T> struct func_less : binary_function <T,T,bool> { - bool operator() (const T& x, const T& y) const {return x->getName() < y->getName() ;} + bool operator() (const T& x, const T& y) const {return x->getName() < y->getName() ;} }; //Speculation note: @@ -1417,14 +1379,14 @@ void PNTransformDriver::GenerateTransformsHidden(map<string,double> &file_covera func->getName()<<endl; break; } - + if(getenv("PN_ONLYTRANSFORM") && funcs_attempted!=atoi(getenv("PN_ONLYTRANSFORM"))) { cout<<"Skipping function "<<dec<<funcs_attempted<<", named: "<<func->getName()<<endl; funcs_attempted++; continue; } - + //TODO: remove this at some point when I understand if this can happen or not assert(func != NULL); @@ -1490,10 +1452,10 @@ void PNTransformDriver::GenerateTransformsHidden(map<string,double> &file_covera //If the number of null inferences encountered equals the number of inferences //that are possible (based on the starting level which may not be 0), then //the function is not transformable. -// if((int)transform_hierarchy.size()-starting_level == null_inf_count) -// not_transformable.push_back(func->getName()); + // if((int)transform_hierarchy.size()-starting_level == null_inf_count) + // not_transformable.push_back(func->getName()); //TODO: is there a better way of checking this? -// else + // else if(layouts.size() == 0) { @@ -1605,11 +1567,10 @@ void PNTransformDriver::GenerateTransformsHidden(map<string,double> &file_covera //returns true if all validate vrs validate without any failures. void PNTransformDriver::ShuffleValidation(vector<validation_record> &vrs) { -// bool success = true; for(unsigned int i=0;i<vrs.size()&&!timeExpired;i++) { PNStackLayout *layout = vrs[i].layouts[vrs[i].layout_index]; - + while(layout != NULL&&!timeExpired) { //using padding transform handler since I now @@ -1620,7 +1581,6 @@ void PNTransformDriver::ShuffleValidation(vector<validation_record> &vrs) //does not even attempt it. if(!PaddingTransformHandler(layout,vrs[i].func,true)) { -// success = false; //we will assume all subsequent layouts require shuffle validation. //if it doesn't, the padding transform handler will add //padding and shuffle without shuffle validation. @@ -1645,7 +1605,7 @@ void PNTransformDriver::ShuffleValidation(vector<validation_record> &vrs) } } -// return success; + // return success; } //Alters the passed in validation record to record the layout information, and @@ -1708,9 +1668,6 @@ void PNTransformDriver::Register_Finalized(vector<validation_record> &vrs,unsign //could change when the modification is finalized. transformed_history[fr.layout->GetLayoutName()].push_back(fr.layout); -//DEBUG: turning off undo to accumulate for now. A bug in modifying zsh -//seems to indicate this functionality (registration) is broken. -// undo(vrs[index].func); //make sure this function is registered only (undo any prior mods) cout<<"registering "<<fr.func->getName()<<" layout "<<fr.layout->GetLayoutName()<<endl; } @@ -1800,49 +1757,10 @@ bool PNTransformDriver::Validate_Recursive(vector<validation_record> &vrs, unsig return false; } - + } } - - - - -// //NOTE: this only_validate_list functionality may not be needed any more, consider removing -// //TODO: for now, only validate if the only_validate_list doesn't have any contents and -// //the level does not equal the never_validate level. I may want to allow the only validate -// //list to be empty, in which case a pointer is better, to check for NULL. -// bool do_validate = true; -// if(only_validate_list.size() != 0) -// { -// if(only_validate_list.find(func->getName()) == only_validate_list.end()) -// do_validate = false; -// } - -// do_validate = do_validate && (level != no_validation_level); - - -// //Go through each layout in the level of the hierarchy in order. -// for(unsigned int i=0;i<layouts.size()&&!timeExpired;i++) -// { -// //TODO: I need to have the ability to make transformations optional -// if(layouts[i]->IsCanarySafe()) -// success = CanaryTransformHandler(layouts[i],func,do_validate); -// else if(layouts[i]->IsPaddingSafe()) -// success = PaddingTransformHandler(layouts[i],func,do_validate); -// //if not canary or padding safe, the layout can only be randomized -// else -// success = LayoutRandTransformHandler(layouts[i],func,do_validate); - -// if(!success && (int)transform_hierarchy.size()-1 == level && i == layouts.size()-1) -// failed.push_back(func); -// else if(success) -// break; -// } -// } -// } -// } - void PNTransformDriver::Finalize_Transformation() { cout<<"Finalizing Transformation: Committing all previously validated transformations ("<<finalization_registry.size()<<" functions)"<<endl; @@ -1862,9 +1780,9 @@ void PNTransformDriver::Finalize_Transformation() //Commit changes for each file. //TODO: is this necessary, can I do one write? for(set<FileIR_t*>::iterator it=registered_firps.begin(); - it!=registered_firps.end(); - ++it - ) + it!=registered_firps.end(); + ++it + ) { FileIR_t *firp = *it; cout<<"Writing to DB: "<<firp->getFile()->getURL()<<endl; @@ -1908,7 +1826,7 @@ void PNTransformDriver::Print_Report() for(it = transformed_history.begin(); it != transformed_history.end(); it++) { total_transformed += it->second.size(); - + //TODO: sort by layout type then print for(unsigned int i=0;i<it->second.size();i++) { @@ -2051,7 +1969,7 @@ vector<PNStackLayout*> PNTransformDriver::GenerateInferences(Function_t *func,in { cerr << "PNTransformDriver: Generating Layout Inference for " << transform_hierarchy[level][inf]->GetInferenceName() << endl; PNStackLayout *tmp = (transform_hierarchy[level][inf])->GetPNStackLayout(func); - + if (tmp == NULL) { cerr << "PNTransformDriver: NULL Inference Generated" << endl; @@ -2121,75 +2039,6 @@ bool PNTransformDriver::Validate(FileIR_t *virp, string name) return true; assert(0); // functionality deprecated. -#if 0 - cerr<<"PNTransformDriver: Validate(): "<<name<<endl; - - string dirname = "p1.xform/" + name; - string cmd = "mkdir -p " + dirname; - int res=system(cmd.c_str()); - assert(res!=-1); - - string aspri_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.aspri"; - string bspri_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.bspri"; - ofstream aspriFile; - aspriFile.open(aspri_filename.c_str()); - - if(!aspriFile.is_open()) - { - assert(false); - } - - cerr<<"Pre genreate SPRI"<<endl; - - if(virp == NULL) - { - //Generate spri for previous files - for(set<FileIR_t*>::iterator it=registered_firps.begin(); - it!=registered_firps.end(); - ++it - ) - { - FileIR_t *firp = *it; - firp->GenerateSPRI(aspriFile,false); - } - } - //generate spri for the current file - else - virp->GenerateSPRI(aspriFile,false); // p1.xform/<function_name>/a.irdb.aspri - cerr<<"Post genreate SPRI"<<endl; - aspriFile.close(); - - char new_instr[1024]; - //This script generates the aspri and bspri files; it also runs BED - sprintf(new_instr, "%s %d %s %s", BED_script.c_str(), orig_progid, aspri_filename.c_str(), bspri_filename.c_str()); - - //If OK=BED(func), then commit - int rt=system(new_instr); - int actual_exit = -1; -// int actual_signal = -1; - if (WIFEXITED(rt)) actual_exit = WEXITSTATUS(rt); -// else actual_signal = WTERMSIG(rt); - int retval = actual_exit; - - //TODO: I have set exit code status 3 to indicate spasm failure - //if spasm fails, there is no point in continuing. - assert(retval != 3); - - //TODO: was I supposed to do something with actual_signal? - - string asm_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm"; - string bin_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm.bin"; - string map_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm.map"; - string rm_command="rm -f "; - rm_command+=bspri_filename + " "; - rm_command+=asm_filename + " "; - rm_command+=bin_filename + " "; - rm_command+=map_filename + " "; - - ignore_result(system(rm_command.c_str())); // don't bother with an error check. - - return (retval == 0); -#endif } unsigned int PNTransformDriver::GetRandomCanary() @@ -2200,30 +2049,13 @@ unsigned int PNTransformDriver::GetRandomCanary() */ return pn_options->getCanaryValue(); -#if 0 -/* note: this code is being careful to get a full 32-bits of entropy, and rand() is only promising 16-bits of entropy. - */ - //TODO: check for bias. - stringstream canary; - canary.str(""); - - //canary<<hex<<pn_options->GetCanaryValue(); - for(int i=0;i<8;i++) - { - canary<<hex<< (rand()%16); - } - unsigned int ret_val; - sscanf(canary.str().c_str(),"%x",&ret_val); - - return ret_val; -#endif } bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *func) { auto cfgp=ControlFlowGraph_t::factory(func); auto &cfg=*cfgp; - + string esp_reg; string word_dec; if (FileIR_t::getArchitectureBitWidth() == 32) @@ -2312,13 +2144,13 @@ bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *f //The number should be positive, but we want negative so //convert to negative c.ret_offset = c.ret_offset * -1; - + if (verbose_log) cerr << "c.canary_val = " << hex << c.canary_val << " c.ret_offset = " << dec << c.ret_offset << " c.esp_offset = " << c.esp_offset << " floating canary offset = " << floating_canary_offset << " (max: " << layout->GetAlteredAllocSize()-layout->GetOriginalAllocSize()<< ")" << endl; canaries.push_back(c); } - + //bool stack_alloc = false; int max = PNRegularExpressions::MAX_MATCHES; regmatch_t *pmatch = new regmatch_t[max]; @@ -2373,24 +2205,20 @@ bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *f stringstream ss; ss << hex << layout->GetAlteredAllocSize(); - + disasm_str = "sub " + esp_reg +", 0x"+ss.str(); if (verbose_log) cerr << "PNTransformDriver: New Instruction = " << disasm_str << endl; virp->registerAssembly(instr, disasm_str); -/* - if(!instr->assemble(disasm_str)) - return false; -*/ //stack_alloc = true; for (unsigned int i = 0; i < canaries.size(); ++i) { ss.str(""); ss<<"mov "<<word_dec<<" ["<<esp_reg<<"+0x"<<hex<<canaries[i].esp_offset - <<"], 0x"<<hex<<canaries[i].canary_val; + <<"], 0x"<<hex<<canaries[i].canary_val; instr = P1_insertAssemblyAfter(virp,instr,ss.str()); if(i==0) instr->setComment("Canary Setup Entry: "+ss.str()); @@ -2426,7 +2254,7 @@ bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *f //for now don't do a canary check on calls in these situations. else if(layout->IsStaticStack() && regexec(&(pn_regex->regex_call), disasm_str.c_str(),5,pmatch,0)==0) { - + if(verbose_log) cerr<<"PNTransformDriver: Canary Rewrite: inserting call canary check"<<endl; @@ -2457,8 +2285,6 @@ bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *f orig_layout->SetCanaries(canaries); -// orig_layout->SetBaseID(func->getBaseID()); -// orig_layout->SetEntryID(func->getEntryPoint()->getBaseID()); EhUpdater_t eh_update(orig_virp, func, layout); if(!eh_update.execute()) @@ -2503,7 +2329,7 @@ static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* ins { Instruction_t* ft=insn->getFallthrough(); Instruction_t* targ=insn->getTarget(); - + /* if there's a fallthrough, but no targ, and the fallthrough is in the function */ if(ft && !targ && func->getInstructions().find(ft)!=func->getInstructions().end()) return ft; @@ -2523,56 +2349,55 @@ static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* ins // int PNTransformDriver::prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, Instruction_t *instr,int offset) { - Function_t* func=cfg->getFunction(); + const auto func = cfg->getFunction(); assert(func); - BasicBlock_t* entry_block=cfg->getEntry(); + const auto entry_block = cfg->getEntry(); if(!entry_block) return offset; /* find the instruction in the vector */ - set<Instruction_t*>::iterator it= func->getInstructions().find(instr); + const auto it = find(ALLOF(entry_block->getInstructions()),instr); /* if the instruction isn't in the entry block, give up now */ - if( it == func->getInstructions().end()) + if( it == entry_block->getInstructions().end()) return offset; - + Instruction_t* insn=*it, *prev=NULL; - for(int i=0;insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i, insn=GetNextInstruction(prev,insn, func)) + for(int i=0; insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i, insn=GetNextInstruction(prev,insn, func)) { assert(insn); const auto dp=DecodedInstruction_t::factory(insn); const auto &d=*dp; - string disasm_str=d.getDisassembly() /*CompleteInstr*/; - - //if(strstr(d.CompleteInstr, "push")!=NULL) + string disasm_str=d.getDisassembly(); + if(d.getMnemonic()=="push") return offset; - + int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch=new regmatch_t[max]; // (max*sizeof(regmatch_t)); + auto pmatch=make_unique<regmatch_t[]>(max); + /* check for a stack alloc */ - if(regexec(&(pn_regex->regex_stack_alloc), d.getDisassembly().c_str() /*CompleteInstr*/, 5, pmatch, 0)==0) + if(regexec(&(pn_regex->regex_stack_alloc), d.getDisassembly().c_str(), 5, pmatch.get(), 0)==0) { - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { + if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) + { string matched=""; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - unsigned int ssize; - if(str2uint(ssize, matched.c_str()) != STR2_SUCCESS) - { + int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; + matched = disasm_str.substr(pmatch[1].rm_so,mlen); + //extract K + unsigned int ssize; + if(str2uint(ssize, matched.c_str()) != STR2_SUCCESS) + { return offset; - } + } // found! // mov ... [rsp+offset] ... // sub rsp, ssize // note: offset is negative - + // sanity check that the allocation iss bigger than the neg offset assert((unsigned)ssize==(unsigned)ssize); if(-offset>(int)ssize) @@ -2581,13 +2406,13 @@ int PNTransformDriver::prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, // success return offset+ssize; - } + } return offset; } // else, check next instruction - + } return offset; @@ -2614,7 +2439,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru const auto disasmp = DecodedInstruction_t::factory(instr); const auto &disasm =*disasmp; disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - + //the disassmebly of lea has extra tokens not accepted by nasm, remove those tokens if(regexec(&(pn_regex->regex_lea_hack), disasm_str.c_str(), max, pmatch, 0) == 0) { @@ -2636,7 +2461,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru matched = ""; } - + if(instr->getFunction() && instr->getFunction()->getUseFramePointer() && regexec(&(pn_regex->regex_add_rbp), disasm_str.c_str(), 5, pmatch, 0) == 0) { @@ -2658,7 +2483,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru cerr << "PNTransformDriver: Convrting to "<<lea_string.str()<<endl; virp->registerAssembly(instr,lea_string.str()); - + } else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), 5, pmatch, 0)==0) { @@ -2713,35 +2538,18 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru stringstream ss; ss << hex << layout->GetAlteredAllocSize(); - + disasm_str = "sub "+esp_reg+", 0x"+ss.str(); if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); - -/* - if(!instr->assemble(disasm_str)) - return false; -*/ - - //stack_alloc = true; } else if(regexec(&(pn_regex->regex_and_esp), disasm_str.c_str(), max, pmatch, 0)==0) { if(verbose_log) cerr << "PNTransformDriver: and_esp pattern matched, ignoring"<<endl; -/* - cerr<<"PNTransformDriver: Transforming AND ESP instruction"<<endl; - - disasm_str = "nop"; - - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - - if(!instr->assemble(disasm_str)) - return false; -*/ } else if(regexec(&(pn_regex->regex_esp_scaled_nodisp), disasm_str.c_str(), max, pmatch, 0)==0) { @@ -2764,7 +2572,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru { if(verbose_log) cerr<<"PNTransformDriver: Displacement of [esp+reg*scale] is Zero, Ignoring Transformation"<<endl; - + return true; } @@ -2777,17 +2585,11 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru assert(mlen==1); disasm_str.replace(pmatch[1].rm_so,mlen,matched); - + if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); - -/* - if(!instr->assemble(disasm_str.c_str())) - return false; -*/ - } else if(regexec(&(pn_regex->regex_esp_only), disasm_str.c_str(), max, pmatch, 0)==0) { @@ -2810,7 +2612,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru { if(verbose_log) cerr<<"PNTransformDriver: Displacement of [esp] is Zero, Ignoring Transformation"<<endl; - + return true; } @@ -2820,17 +2622,12 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru matched = esp_reg+"+0x"+ss.str(); int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; disasm_str.replace(pmatch[1].rm_so,mlen,matched); - + if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); -/* - if(!instr->assemble(disasm_str.c_str())) - return false; -*/ - } #if 1 else if(regexec(&(pn_regex->regex_esp_direct_negoffset), disasm_str.c_str(), 5, pmatch, 0)==0) @@ -2856,7 +2653,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru { if(verbose_log) cerr<<"PNTransformDriver: ignoring, not in prologue "<<endl; - + } else { @@ -2871,22 +2668,22 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru // sanity assert(new_offset<0); - + stringstream ss; ss<<hex<<(- new_offset); // neg sign already in string - + matched = "0x"+ss.str(); - + disasm_str.replace(pmatch[1].rm_so,mlen,matched); - + if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - + virp->registerAssembly(instr,disasm_str); } } #endif -//TODO: the regular expression order does matter, scaled must come first, change the regex so this doesn't matter + //TODO: the regular expression order does matter, scaled must come first, change the regex so this doesn't matter else if(regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), 5, pmatch, 0)==0 || regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), 5, pmatch, 0)==0) { @@ -2901,14 +2698,14 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru //TODO: I don't think this can happen but just in case assert(offset >= 0); - - + + // an ESP+<scale>+<const> that points at // the saved reg area isn't likely realy indexing the saved regs. assume it's in the // local var area instead. int new_offset = 0; if((int)offset==(int)layout->GetOriginalAllocSize() && - regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), 5, pmatch2, 0)==0) + regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), 5, pmatch2, 0)==0) { if(verbose_log) cerr<<"JDH: PNTransformDriver: found esp+scale+const pointing at saved regs."<<endl; @@ -2916,23 +2713,19 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru } else new_offset=layout->GetNewOffsetESP(offset); - + stringstream ss; ss<<hex<<new_offset; matched = "0x"+ss.str(); - + disasm_str.replace(pmatch[1].rm_so,mlen,matched); - + if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); -/* - if(!instr->assemble(disasm_str.c_str())) - return false; -*/ } //TODO: the regular expression order does matter, scaled must come first, change the regex so this doesn't matter //for lea esp, [ebp-<const>] it is assumed the <const> will not be in the stack frame, so it should be ignored. @@ -2966,7 +2759,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru ss<<hex<<new_offset; matched = "0x"+ss.str(); - + disasm_str.replace(pmatch[1].rm_so,mlen,matched); if(verbose_log) @@ -2975,11 +2768,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru virp->registerAssembly(instr,disasm_str); -/* - if(!instr->assemble(disasm_str.c_str())) - return false; -*/ - + } //if we get an instruction where ebp is the index, transform it using the //offset as the lookup (the second pattern matched), however, it is assumed @@ -3016,18 +2805,13 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru ss<<hex<<new_offset; matched = "0x"+ss.str(); - + disasm_str.replace(pmatch[2].rm_so,mlen,matched); if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); - -/* - if(!instr->assemble(disasm_str.c_str())) - return false; -*/ } else if(regexec(&(pn_regex->regex_stack_dealloc), disasm_str.c_str(), 5, pmatch, 0)==0) { @@ -3059,16 +2843,12 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru ss << hex <<layout->GetAlteredAllocSize(); disasm_str = "add "+esp_reg+", 0x"+ss.str(); - + if(verbose_log) cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; virp->registerAssembly(instr,disasm_str); -/* - if (!instr->assemble(disasm_str)) - return false; -*/ } else { @@ -3076,7 +2856,7 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru { cerr<<"PNTransformDriver: No Pattern Match"; if(strstr(disasm_str.c_str(), "rsp")!=NULL || - strstr(disasm_str.c_str(), "esp")!=NULL) + strstr(disasm_str.c_str(), "esp")!=NULL) cerr<<"BUT CAUTION ******************* esp/rsp found in instruction."; cerr<<endl; } @@ -3090,78 +2870,9 @@ inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instru //void PNTransformDriver::undo(map<Instruction_t*, Instruction_t*> undo_list, Function_t *func) void PNTransformDriver::undo(Function_t *func) { - string func_name = func->getName(); - - //rollback any changes - cerr<<"PNTransformDriver: Undo Transform: "<<undo_list[func].size()<<" instructions to rollback for function "<<func_name<<endl; - for( - map<Instruction_t*, Instruction_t*>::const_iterator mit=undo_list[func].begin(); - mit != undo_list[func].end(); - ++mit) - { -#if 1 - assert(0); // functionality removed. -#else - Instruction_t* alt = mit->first; - Instruction_t* orig = mit->second; - - P1_copyInstruction(orig,alt); - - orig_virp->unregisterAssembly(alt); - - //TODO: apparently there is a issue with this delete. - //When using the padding/shuffle transformation PN terminates - //for some reason with no segfault. Removing this delete - //solves the issue. Using the canary transformation, I haven't - //observed the same issue however there are fewer undos when - //using the canary transform. -// delete orig; -#endif - } - - for(set<Instruction_t*>::const_iterator it=inserted_instr[func].begin(); - it != inserted_instr[func].end(); - ++it - ) - { -#if 1 - assert(0); // functionality removed. -#else - orig_virp->unregisterAssembly(*it); - orig_virp->getInstructions().erase(*it); - func->getInstructions().erase(*it); - delete *it; -#endif - } - - for(set<AddressID_t*>::const_iterator it=inserted_addr[func].begin(); - it != inserted_addr[func].end(); - ++it - ) - { -#if 1 - assert(0); // functionality removed. -#else - orig_virp->getAddresses().erase(*it); - delete *it; -#endif - } - //reset_undo(func->getName()); - - undo_list.erase(func); - inserted_instr.erase(func); - inserted_addr.erase(func); - //undo_list.clear(); + assert(undo_list.size() == 0); // functionality removed. } -/* - void PNTransformDriver::reset_undo(string func) - { - undo_list.erase(func); - inserted_instr.erase(func); - inserted_addr.erase(func); - } -*/ bool PNTransformDriver::WriteStackIRToDB() @@ -3193,10 +2904,10 @@ bool PNTransformDriver::WriteStackIRToDB() for(unsigned int j = 0; j < mem_objects.size(); j++) { IRDB_SDK::DatabaseID_t new_id = irdb_manager.InsertStackObject( - layouts[laynum]->getFunctionName(), - mem_objects[j]->getOffset(), - mem_objects[j]->getSize(), - PNIrdbManager::IRS_PEASOUP); + layouts[laynum]->getFunctionName(), + mem_objects[j]->getOffset(), + mem_objects[j]->getSize(), + PNIrdbManager::IRS_PEASOUP); // DEBUG cerr<< "\tOffset = " << mem_objects[j]->getOffset() << " Size = "<<mem_objects[j]->getSize() << endl; diff --git a/PNTransformDriver.hpp b/PNTransformDriver.hpp index c14019824e9305a3501ce9ca50bd420949e86303..2eeaf44937e1fbf8b10589fa57fd3043eac57314 100644 --- a/PNTransformDriver.hpp +++ b/PNTransformDriver.hpp @@ -77,7 +77,7 @@ class PNTransformDriver bool do_shared_object_protection; std::vector< std::vector<PNStackLayoutInference*> > transform_hierarchy; - PNRegularExpressions *pn_regex; + unique_ptr<PNRegularExpressions> pn_regex; std::set<std::string> blacklist; std::set<IRDB_SDK::Function_t*> sanitized; std::set<std::string> only_validate_list; diff --git a/SConstruct b/SConstruct index 74143aaa4455ca885111b55d02300922b437a0e8..2bc901f4162d009c74d7a3e5963a9684ee76650e 100644 --- a/SConstruct +++ b/SConstruct @@ -43,7 +43,7 @@ env.Replace(debug=ARGUMENTS.get("debug",0)) # build in debug mode? # # Required: need these flag to appropriately include/link IRDB files. # -env.Append(CXXFLAGS=" -std=c++11 ") # enable c++11 +env.Append(CXXFLAGS=" -std=c++17 ") # enable c++17 env.Append(LINKFLAGS=" -Wl,-unresolved-symbols=ignore-in-shared-libs ") # irdb libs may have symbols that resolve OK at runtime, but not linktime.