From 729e38f335b518a9098c7a8ce05ffda0551f5d6f Mon Sep 17 00:00:00 2001 From: Jason Hiser <jdhiser@gmail.com> Date: Mon, 20 May 2019 13:26:54 -0400 Subject: [PATCH] removed p1 and mg --- SConscript | 2 - builtin_xforms/move_globals/SConscript | 29 - builtin_xforms/move_globals/SConstruct | 6 - builtin_xforms/move_globals/mg.cpp | 2215 ----------- builtin_xforms/move_globals/mg.hpp | 172 - builtin_xforms/move_globals/mg_driver.cpp | 213 -- .../move_globals/tests/test_spec.sh | 300 -- .../AnnotationBoundaryGenerator.cpp | 100 - .../AnnotationBoundaryGenerator.hpp | 40 - .../p1transform/DirectOffsetInference.cpp | 42 - .../p1transform/DirectOffsetInference.hpp | 39 - builtin_xforms/p1transform/EhUpdater.cpp | 195 - builtin_xforms/p1transform/EhUpdater.hpp | 33 - .../p1transform/General_Utility.cpp | 64 - .../p1transform/General_Utility.hpp | 28 - .../p1transform/OffsetInference.cpp | 1163 ------ .../p1transform/OffsetInference.hpp | 55 - builtin_xforms/p1transform/P1Inference.cpp | 43 - builtin_xforms/p1transform/P1Inference.hpp | 42 - builtin_xforms/p1transform/P1_utility.cpp | 341 -- builtin_xforms/p1transform/P1_utility.hpp | 61 - builtin_xforms/p1transform/PNIrdbManager.cpp | 158 - builtin_xforms/p1transform/PNIrdbManager.hpp | 73 - builtin_xforms/p1transform/PNMain.cpp | 614 ---- builtin_xforms/p1transform/PNRange.cpp | 90 - builtin_xforms/p1transform/PNRange.hpp | 47 - .../p1transform/PNRegularExpressions.cpp | 213 -- .../p1transform/PNRegularExpressions.hpp | 55 - builtin_xforms/p1transform/PNStackLayout.cpp | 757 ---- builtin_xforms/p1transform/PNStackLayout.hpp | 143 - .../p1transform/PNStackLayoutInference.hpp | 40 - .../p1transform/PNTransformDriver.cpp | 3230 ----------------- .../p1transform/PNTransformDriver.hpp | 202 -- .../PrecedenceBoundaryGenerator.hpp | 35 - .../PrecedenceBoundaryInference.cpp | 210 -- .../PrecedenceBoundaryInference.hpp | 40 - builtin_xforms/p1transform/Range.cpp | 70 - builtin_xforms/p1transform/Range.hpp | 43 - builtin_xforms/p1transform/SConscript | 27 - builtin_xforms/p1transform/SConstruct | 7 - .../p1transform/ScaledOffsetInference.cpp | 43 - .../p1transform/ScaledOffsetInference.hpp | 38 - builtin_xforms/p1transform/StackLayout.cpp | 253 -- builtin_xforms/p1transform/StackLayout.hpp | 77 - builtin_xforms/p1transform/canary.h | 12 - builtin_xforms/p1transform/globals.h | 146 - .../p1transform/integertransformdriver.cpp | 251 -- builtin_xforms/p1transform/nulltransform.cpp | 57 - .../p1transform/sample_meds_int.annot | 8 - .../p1transform/tests/test_buffer_overflow.c | 19 - .../p1transform/tests/test_buffer_overflow.sh | 120 - .../p1transform/tests/test_spec-x32.sh | 280 -- builtin_xforms/p1transform/tests/test_spec.sh | 286 -- .../p1transform/tests/test_spec17.sh | 231 -- builtin_xforms/p1transform/transformutils.cpp | 51 - builtin_xforms/p1transform/transformutils.h | 29 - 56 files changed, 13138 deletions(-) delete mode 100644 builtin_xforms/move_globals/SConscript delete mode 100644 builtin_xforms/move_globals/SConstruct delete mode 100644 builtin_xforms/move_globals/mg.cpp delete mode 100644 builtin_xforms/move_globals/mg.hpp delete mode 100644 builtin_xforms/move_globals/mg_driver.cpp delete mode 100755 builtin_xforms/move_globals/tests/test_spec.sh delete mode 100644 builtin_xforms/p1transform/AnnotationBoundaryGenerator.cpp delete mode 100644 builtin_xforms/p1transform/AnnotationBoundaryGenerator.hpp delete mode 100644 builtin_xforms/p1transform/DirectOffsetInference.cpp delete mode 100644 builtin_xforms/p1transform/DirectOffsetInference.hpp delete mode 100644 builtin_xforms/p1transform/EhUpdater.cpp delete mode 100644 builtin_xforms/p1transform/EhUpdater.hpp delete mode 100644 builtin_xforms/p1transform/General_Utility.cpp delete mode 100644 builtin_xforms/p1transform/General_Utility.hpp delete mode 100644 builtin_xforms/p1transform/OffsetInference.cpp delete mode 100644 builtin_xforms/p1transform/OffsetInference.hpp delete mode 100644 builtin_xforms/p1transform/P1Inference.cpp delete mode 100644 builtin_xforms/p1transform/P1Inference.hpp delete mode 100644 builtin_xforms/p1transform/P1_utility.cpp delete mode 100644 builtin_xforms/p1transform/P1_utility.hpp delete mode 100644 builtin_xforms/p1transform/PNIrdbManager.cpp delete mode 100644 builtin_xforms/p1transform/PNIrdbManager.hpp delete mode 100644 builtin_xforms/p1transform/PNMain.cpp delete mode 100644 builtin_xforms/p1transform/PNRange.cpp delete mode 100644 builtin_xforms/p1transform/PNRange.hpp delete mode 100644 builtin_xforms/p1transform/PNRegularExpressions.cpp delete mode 100644 builtin_xforms/p1transform/PNRegularExpressions.hpp delete mode 100644 builtin_xforms/p1transform/PNStackLayout.cpp delete mode 100644 builtin_xforms/p1transform/PNStackLayout.hpp delete mode 100644 builtin_xforms/p1transform/PNStackLayoutInference.hpp delete mode 100644 builtin_xforms/p1transform/PNTransformDriver.cpp delete mode 100644 builtin_xforms/p1transform/PNTransformDriver.hpp delete mode 100644 builtin_xforms/p1transform/PrecedenceBoundaryGenerator.hpp delete mode 100644 builtin_xforms/p1transform/PrecedenceBoundaryInference.cpp delete mode 100644 builtin_xforms/p1transform/PrecedenceBoundaryInference.hpp delete mode 100644 builtin_xforms/p1transform/Range.cpp delete mode 100644 builtin_xforms/p1transform/Range.hpp delete mode 100644 builtin_xforms/p1transform/SConscript delete mode 100644 builtin_xforms/p1transform/SConstruct delete mode 100644 builtin_xforms/p1transform/ScaledOffsetInference.cpp delete mode 100644 builtin_xforms/p1transform/ScaledOffsetInference.hpp delete mode 100644 builtin_xforms/p1transform/StackLayout.cpp delete mode 100644 builtin_xforms/p1transform/StackLayout.hpp delete mode 100644 builtin_xforms/p1transform/canary.h delete mode 100644 builtin_xforms/p1transform/globals.h delete mode 100644 builtin_xforms/p1transform/integertransformdriver.cpp delete mode 100644 builtin_xforms/p1transform/nulltransform.cpp delete mode 100644 builtin_xforms/p1transform/sample_meds_int.annot delete mode 100644 builtin_xforms/p1transform/tests/test_buffer_overflow.c delete mode 100755 builtin_xforms/p1transform/tests/test_buffer_overflow.sh delete mode 100755 builtin_xforms/p1transform/tests/test_spec-x32.sh delete mode 100755 builtin_xforms/p1transform/tests/test_spec.sh delete mode 100755 builtin_xforms/p1transform/tests/test_spec17.sh delete mode 100644 builtin_xforms/p1transform/transformutils.cpp delete mode 100644 builtin_xforms/p1transform/transformutils.h diff --git a/SConscript b/SConscript index 6e244b663..d564a1ca7 100644 --- a/SConscript +++ b/SConscript @@ -53,8 +53,6 @@ Export('env') # list of zipr plugins and irdb xforms to build transformDirs=''' builtin_xforms/add_lib - builtin_xforms/move_globals - builtin_xforms/p1transform builtin_xforms/resolve_callbacks zipr_push64_reloc_plugin zipr diff --git a/builtin_xforms/move_globals/SConscript b/builtin_xforms/move_globals/SConscript deleted file mode 100644 index 6d313e211..000000000 --- a/builtin_xforms/move_globals/SConscript +++ /dev/null @@ -1,29 +0,0 @@ -import os - - - -Import('env') - -# import and create a copy of the environment so we don't screw up anyone elses env. -myenv=env.Clone() - -cpppath=''' - $SECURITY_TRANSFORMS_HOME/third_party/elfio-code - $PEASOUP_HOME/irdb-libs/libEXEIO/include - $IRDB_SDK/include - ''' - - - -files=Glob( Dir('.').srcnode().abspath+"/*.cpp") - -pgm="move_globals.so" - -LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split("irdb-core irdb-cfg irdb-util irdb-transform irdb-deep StructDiv EXEIO ") -myenv.Append(CPPPATH=Split(cpppath)) -pgm=myenv.SharedLibrary(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) -install=myenv.Install("$SECURITY_TRANSFORMS_HOME/plugins_install/", pgm) -Default(install) - -Return('install') diff --git a/builtin_xforms/move_globals/SConstruct b/builtin_xforms/move_globals/SConstruct deleted file mode 100644 index c96332f04..000000000 --- a/builtin_xforms/move_globals/SConstruct +++ /dev/null @@ -1,6 +0,0 @@ - - - -env=Environment() -Export('env') -lib=SConscript("SConscript") diff --git a/builtin_xforms/move_globals/mg.cpp b/builtin_xforms/move_globals/mg.cpp deleted file mode 100644 index 412ce04fd..000000000 --- a/builtin_xforms/move_globals/mg.cpp +++ /dev/null @@ -1,2215 +0,0 @@ -#include "mg.hpp" - - -#include <assert.h> -#include <stdexcept> -#include <unistd.h> -#include <memory> -#include <inttypes.h> -#include <algorithm> -#include <elf.h> -#include <cctype> -#include <iomanip> -#include <cstdlib> -#include <random> - - -using namespace std; -using namespace IRDB_SDK; -using namespace EXEIO; - -#define ALLOF(s) begin(s), end(s) - -// use this to determine whether a scoop has a given name. -static struct ScoopFinder : binary_function<DataScoop_t*,string,bool> -{ - // declare a simple scoop finder function that finds scoops by name - bool operator()(const DataScoop_t* scoop, const string word) const - { - return (scoop->getName() == word); - }; -} finder; - -template<class S, class T> inline -static bool contains(const S &container, const T& value) -{ - return find(container.begin(), container.end(), value) != container.end(); -} - - - -static bool arg_has_memory(const DecodedOperand_t &arg) -{ - /* if it's relative memory, watch out! */ - if(arg.isMemory()) - return true; - - return false; -} - -static bool arg_has_relative(const DecodedOperand_t &arg) -{ - /* if it's relative memory, watch out! */ - if(arg.isMemory() && arg.isPcrel()) - return true; - return false; -} - -static DecodedOperandVector_t::iterator find_memory_operand(DecodedOperandVector_t &operands) -{ - // const auto operands=disasm.getOperands(); - auto the_arg=operands.end(); - if(operands.size()>0 && arg_has_memory(*operands[0])) - the_arg=next(operands.begin(),0); - if(operands.size()>1 && arg_has_memory(*operands[1])) - the_arg=next(operands.begin(),1); - if(operands.size()>2 && arg_has_memory(*operands[2])) - the_arg=next(operands.begin(),2); - if(operands.size()>3 && arg_has_memory(*operands[3])) - the_arg=next(operands.begin(),3); - return the_arg; -} - - -template< typename T > -static std::string to_hex_string( T i ) -{ - std::stringstream stream; - stream << "0x" - << std::hex << i; - return stream.str(); -} - - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::MoveGlobals_t( - VariantID_t *p_variantID, - FileIR_t *p_variantIR, - const string &p_dont_move, - const string &p_move_only, - const int p_max_mov, - const bool p_random, - const bool p_aggressive, - const bool p_use_stars) - : - Transform_t(p_variantIR), - exe_reader(NULL), - tied_unpinned(0), - tied_pinned(0), - tied_nochange(0), - ties_for_folded_constants(0), - dont_move(p_dont_move), - move_only(p_move_only), - max_moveables(p_max_mov), - random(p_random), - aggressive(p_aggressive), - m_use_stars(p_use_stars) - -{ - -} - -#if 0 -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -MEDS_Annotations_t& MoveGlobals_t<T_Sym, T_Rela, T_Rel, T_Dyn, T_Extractor>::getAnnotations() -{ - assert(m_use_stars); - return m_annotationParser->getAnnotations(); -} -#endif - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -int MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::execute(pqxxDB_t &pqxx_interface) -{ - - // read the executeable file - /* - int elfoid = this->getFileIR()->getFile()->getELFOID(); // from Transform base class - pqxx::largeobject lo(elfoid); - lo.to_file(pqxx_interface.getTransaction(),"readeh_tmp_file.exe"); - */ - - // load the executable. - this->exe_reader = new EXEIO::exeio; - assert(this->exe_reader); - this->exe_reader->load((char*)"a.ncexe"); - -#if 0 - STARS::IRDB_Interface_t STARS_analysis_engine(pqxx_interface); - STARS_analysis_engine.GetSTARSOptions().SetDeepLoopAnalyses(true); - STARS_analysis_engine.GetSTARSOptions().SetConstantPropagation(true); - if(m_use_stars) - { - STARS_analysis_engine.do_STARS(this->getFileIR()); - this->m_annotationParser = &STARS_analysis_engine.getAnnotations(); - assert(getenv("SELF_VALIDATE")==nullptr || getAnnotations().size() > 15); - - } - cout << "move_globals execute(): enter" << endl; - const auto annot_size = m_use_stars ? (size_t)this->getAnnotations().size() : (size_t)0 ; - cout << "size of annotation set: " << annot_size << endl; -#endif - if(m_use_stars) - { - auto deep_analysis=DeepAnalysis_t::factory(getFileIR(), aeSTARS, {"SetDeepLoopAnalyses=true", "SetConstantPropagation=true"}); - deep_global_static_ranges = deep_analysis -> getStaticGlobalRanges(); - sentinels = deep_analysis -> getRangeSentinels(); - cout<<dec; - cout<<"#ATTRIBUTE "<<deep_global_static_ranges->size() <<" num_global_static_range_annotations" <<endl; - cout<<"#ATTRIBUTE "<<sentinels->size() <<" num_sentinel_annotations" <<endl; - } - - - - - this->ParseSyms(exe_reader); - this->SetupScoopMap(); - this->FilterScoops(); - this->TieScoops(); - this->FindInstructionReferences(); // may record some scoops are tied together - this->FindDataReferences(); - this->FilterAndCoalesceTiedScoops(); - this->UpdateScoopLocations(); - this->PrintStats(); - - return 0; -} - -// go through the .symtab and .dynsym bits of the table and make scoops for each symbol. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::SetupScoopMap() -{ - for(auto &s : getFileIR()->getDataScoops()) - { - RangePair_t p(s->getStart()->getVirtualOffset(), s->getEnd()->getVirtualOffset()); - scoop_map[p]=s; - } -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -DataScoop_t* MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::findScoopByAddress(const IRDB_SDK::VirtualOffset_t a) const -{ - RangePair_t p(a,a); - auto smit=scoop_map.find(p); - if(smit==scoop_map.end()) - return NULL; - return smit->second; -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -bool MoveGlobals_t<T_Sym, T_Rela, T_Rel, T_Dyn, T_Extractor>::AreScoopsAdjacent(const DataScoop_t *a, const DataScoop_t *b) const -{ - bool adjacent = true; - const IRDB_SDK::VirtualOffset_t aStart = a->getStart()->getVirtualOffset(); - const IRDB_SDK::VirtualOffset_t aEnd = a->getEnd()->getVirtualOffset(); - const IRDB_SDK::VirtualOffset_t bStart = b->getStart()->getVirtualOffset(); - const IRDB_SDK::VirtualOffset_t bEnd = b->getEnd()->getVirtualOffset(); - IRDB_SDK::VirtualOffset_t FirstEnd, SecondStart; - if (aStart > bStart) - { - FirstEnd = bEnd; - SecondStart = aStart; - } - else - { - FirstEnd = aEnd; - SecondStart = bStart; - } - for (IRDB_SDK::VirtualOffset_t i = FirstEnd + 1; adjacent && (i < SecondStart); ++i) - { - DataScoop_t *c = this->findScoopByAddress(i); - if (c) - { - adjacent = false; // found intervening scoop before SecondStart - } - } - - return adjacent; -} // end of AreScoopsAdjacent() - -// go through the .symtab and .dynsym bits of the table and make scoops for each symbol. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::ParseSyms(EXEIO::exeio * readerp) -{ - - auto max_id=getFileIR()->getMaxBaseID(); - - if(getenv("MG_VERBOSE")) - cout<<"Initial scoops:"<<endl; - for(const auto &scoop : getFileIR()->getDataScoops()) - { - if(getenv("MG_VERBOSE")) - { - cout<<"scoop: "<<scoop->getName()<<" ("<<hex<<scoop->getStart()->getVirtualOffset() - <<"-"<<scoop->getEnd()->getVirtualOffset()<<")"<<endl; - } - - - - const auto moveable_sections=set<string>({ - ".interp", - ".note.ABI-tag", - ".note.gnu.build-id", - ".gnu.hash", - ".dynsym", - ".dynstr", - ".gnu.version", - ".gnu.version_r", - ".rel.dyn", - ".rel.plt", - ".rela.dyn", - ".rela.plt", - ".init_array", - ".fini_array", - ".jcr", - ".dynamic", - ".got", - ".got.plt" - }); - // white list some scoops as moveable, despite the symbol table - if(moveable_sections.find(scoop->getName())!=moveable_sections.end()) - { - cout<<"Register scoop "<<scoop->getName()<<" as movable"<<endl; - moveable_scoops.insert(scoop); - } - } - - assert(readerp); - auto elfiop=reinterpret_cast<ELFIO::elfio*>(readerp->get_elfio()); - assert(elfiop); - auto &reader=*elfiop; - - auto splits=0u; - - // for each section in the elf file. - auto n = (Elf_Half) reader.sections.size(); - for ( auto i = (Elf_Half ) 0; i < n; ++i ) - { - // For all sections - auto sec = reader.sections[i]; - char* max_splits = getenv("MG_MAX_SPLITS"); - - // if it's a symtab section - if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) - { - auto symbols = ELFIO::symbol_section_accessor ( reader, sec ); - - // for each symbol in the section - auto sym_no = symbols.get_symbols_num(); - for (auto i = (decltype(sym_no))0; i < sym_no; ++i ) - { - // check to see if we've been directed to not split everything up. - if (max_splits && (splits >= strtoul(max_splits, NULL, 0))) - break; - - auto name=std::string(); - auto value=(Elf64_Addr)0; // note: elf64_addr OK for 32-bit machines still. - auto size=(Elf_Xword)0; - auto bind=(unsigned char)0; - auto type=(unsigned char)0; - auto section=(Elf_Half)0; - auto other=(unsigned char)0; - - // elfio always takes a value of type Elf64-Addr regardless of mach type. - symbols.get_symbol( i, name, value, size, bind, type, section, other ); - - // if it's a symbol that describes an object (as opposed to a binding, or a function or a ...) - if(type==STT_OBJECT && (bind==STB_LOCAL || bind==STB_GLOBAL) && value!=0 && size!=0) - { - auto tosplit=getFileIR()->findScoop(value); - - // something went wrong if we can't find the scoop for this object. - if(tosplit==NULL) continue; - - cout << "Section: "<<sec->get_name() << " name="<< name << " size=" - <<hex<<size<< " addr="<<hex<<value<<" scoop: "<<tosplit->getName()<<endl; - - auto before=(DataScoop_t*)NULL, containing=(DataScoop_t*)NULL, after=(DataScoop_t*)NULL; - - if(getenv("MG_VERBOSE")) - { - cout<<"\ttosplit: "<<hex<<tosplit->getStart()->getVirtualOffset()<<"-" - <<tosplit->getEnd()->getVirtualOffset(); - } - - if(value+size-1 > tosplit->getEnd()->getVirtualOffset()) - { - cout<<"Skipping symbol "<<name<<" due to an object that's already split?"<<endl; - cout<<"Start (but not end) of "<<name<<" is in in object " << - tosplit->getName()<<":("<<hex<<tosplit->getStart()->getVirtualOffset()<<"-" << - tosplit->getEnd()->getVirtualOffset()<<")"<<endl;; - continue; // try next symbol - } - - if(moveable_scoops.find(tosplit)!=end(moveable_scoops)) - { - cout<<"Avoiding resplit of "<<name<<" due to an object that's already split?"<<endl; - // don't re-split something that's arlready moveable. - continue; - } - - getFileIR()->splitScoop(tosplit, value, size, before,containing,after,&max_id); - - if(getenv("MG_VERBOSE")) - { - if(before) - { - cout<<"\tBefore: "<<hex<<before->getStart()->getVirtualOffset() - <<"-"<<before->getEnd()->getVirtualOffset(); - } - cout<<"\tContaining: "<<hex<<containing->getStart()->getVirtualOffset() - <<"-"<<containing->getEnd()->getVirtualOffset(); - if(after) - { - cout<<"\tAfter: "<<hex<<after->getStart()->getVirtualOffset() - <<"-"<<after->getEnd()->getVirtualOffset(); - } - cout<<endl; - } - - assert(containing); - containing->setName(name); - moveable_scoops.insert(containing); - - splits++; - - - } - } - cout << std::endl; - } - - } - - // guarantee unique scoop names - auto scoop_names=set<string>(); - for(auto & s : getFileIR()->getDataScoops()) - { - while(scoop_names.find(s->getName())!=scoop_names.end()) - { - cout<<"Rename scoop because of name conflict: "<<s->getName()<<" --> "; - s->setName(s->getName()+"-renamed"); - cout<<s->getName()<<endl; - } - scoop_names.insert(s->getName()); - } - - cout<<"# ATTRIBUTE Non-Overlapping_Globals::data_scoop_splits_performed="<<dec<<splits<<endl; -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::FilterScoops() -{ - - - // filter using the move_only option - DataScoopSet_t move_only_scoops; - // for each word in move_only - istringstream mo_ss(move_only); - for_each(istream_iterator<string>(mo_ss), - istream_iterator<string>(), [&](const string & word) - { - // find the scoop - auto it=find_if(ALLOF(moveable_scoops), bind2nd(finder, word)); - // if found, insert into the move_only set. - if(it!=moveable_scoops.end()) - move_only_scoops.insert(*it); - - }); - - // update the moveable_scoops based on the move_only set. - if(move_only != "" ) - { - moveable_scoops.clear(); - moveable_scoops.insert(ALLOF(move_only_scoops)); - - if(getenv("MG_VERBOSE")) - { - cout<<"Moveable Scoops after move_only filter:"<<endl; - for(auto &s : moveable_scoops) - cout<<s->getName()<<endl; - cout<<endl; - - } - } - - - // filter based on the dont_move option - // for each word in dont_move - istringstream dm_ss(dont_move); - for_each(istream_iterator<string>(dm_ss), - istream_iterator<string>(), [&](const string & word) - { - // find scoop by that name. - auto it=find_if(ALLOF(moveable_scoops), bind2nd(finder,word)); - if(it!=moveable_scoops.end()) - { - moveable_scoops.erase(*it); - } - - }); - if(dont_move!="") - { - if(getenv("MG_VERBOSE")) - { - cout<<"Moveable Scoops after dont_move filter:"<<endl; - for(auto &s : moveable_scoops) - cout<<s->getName()<<endl; - cout<<endl; - - } - } - - if(max_moveables>0) - { - mt19937 generator(time(0)); - uniform_real_distribution<double> distribution(0.0,1.0); - while(moveable_scoops.size() > (unsigned)max_moveables) - { - if (random == true) - { - double rand_num = distribution(generator); - int rand_idx = (int) (rand_num * moveable_scoops.size()); - auto it = moveable_scoops.begin(); - advance(it, rand_idx); - moveable_scoops.erase(it); - } - else moveable_scoops.erase(prev(moveable_scoops.end())); - } - } -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::TieScoops() -{ - struct scoop_pairs_t - { - string first, second; - }scoop_pairs[] = { - { ".rel.dyn", ".rel.plt" }, // the dynamic linker goes through both sections together when LD_BIND_NOW is set. - { ".rela.dyn", ".rela.plt" } -// can't tie .got and .got.plt because of relro differences. -// can make insanity happen. -// { ".got", ".got.plt" } - }; - - for_each(ALLOF(scoop_pairs), [this](const scoop_pairs_t pair) - { - auto it1=find_if(ALLOF(moveable_scoops), bind2nd(finder,pair.first)); - auto it2=find_if(ALLOF(moveable_scoops), bind2nd(finder,pair.second)); - - // both exist, tie together. - if(it1!=moveable_scoops.end() && it2!=moveable_scoops.end()) - tied_scoops.insert(ScoopPair_t(*it1,*it2)); - - // first exists, rename for easier management later. - else if(it1!=moveable_scoops.end() && it2==moveable_scoops.end()) - (*it1)->setName(pair.first+" coalesced w/"+ pair.second); - - // second exists, rename for easier management later. - else if(it1==moveable_scoops.end() && it2!=moveable_scoops.end()) - (*it2)->setName(pair.first+" coalesced w/"+ pair.second); - - // or, none exists at all. - }); -} - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::HandleMemoryOperand(DecodedInstruction_t& disasm, const DecodedOperandVector_t::iterator the_arg, Instruction_t* insn, const DecodedOperandVector_t &the_arg_container) -{ - // no mem arg. - if(the_arg==the_arg_container.end()) - { - if(getenv("MG_VERBOSE")) - { - cout << "Note: "<<hex<<" no memory op in:"; - cout << insn->getBaseID()<<":"<<disasm.getDisassembly(); - cout << endl; - } - return; - } - - // shared objects don't need this, you have to use a pcrel addressing mode. - if(!arg_has_relative(**the_arg) && exe_reader->isDLL()) - { - if(getenv("MG_VERBOSE")) - { - cout << "Note: "<<hex<<" no dll-style address in:"; - cout << insn->getBaseID()<<":"<<disasm.getDisassembly(); - cout << endl; - } - return; - } - - const auto small_memory_threshold= exe_reader->isDLL() ? 10 : 4096*10; - - auto to1 = (DataScoop_t*) NULL; - // examine the memory operation to see if there's a pc-rel - if ((*the_arg)->isMemory() && - (*the_arg)->hasMemoryDisplacement() && - (*the_arg)->getMemoryDisplacementEncodingSize() == 4 - - ) - { - auto rel_addr1 = (VirtualOffset_t)(*the_arg)->getMemoryDisplacement() /*Memory.Displacement*/; - if (arg_has_relative(*(*the_arg))) - rel_addr1 += insn->getDataBits().size(); - to1 = DetectProperScoop(disasm, the_arg, insn, rel_addr1, false, the_arg_container); - - auto disp_offset = disasm.getMemoryDisplacementOffset(the_arg->get(),insn); // the_arg->Memory.DisplacementAddr-disasm.EIP; - auto disp_size = (*the_arg)->getMemoryDisplacementEncodingSize(); // the_arg->Memory.DisplacementSize; - assert((0 < disp_offset) && (disp_offset <= (insn->getDataBits().size() - disp_size))); - - // skip if not found, executable, or not moveable. - if (to1 && (to1->isExecuteable() || moveable_scoops.find(to1) == moveable_scoops.end())) - { - // do nothing, no log or action is necessary for pointers to code. - if(getenv("MG_VERBOSE")) - { - cout<<"Skipping (scoop exists, but exe scoop, or not moveable scoop) pcrel mem op in insn: " - << hex << insn->getBaseID()<<":"<<disasm.getDisassembly()<<" to " - << to1->getName()<<" (" - <<hex<<to1->getStart()->getVirtualOffset()<<"-" - <<hex<<to1->getEnd()->getVirtualOffset()<<")"<<endl; - } - } - else if(to1) - { - - // look for any pcrel relative relocs from fix_calls - Relocation_t* pcrel_reloc=FindRelocationWithType(insn,"pcrel"); - if(pcrel_reloc) - { - if(getenv("MG_VERBOSE")) - { - cout<<"Setting pcrel mem op in insn: " - << hex <<insn->getBaseID()<<":"<<disasm.getDisassembly()<<" to " - << to1->getName()<<" (" - <<hex<<to1->getStart()->getVirtualOffset()<<"-" - <<hex<<to1->getEnd()->getVirtualOffset()<<")"<<endl; - } - //ApplyPcrelMemoryRelocation(insn,to1); - pcrel_refs_to_scoops.insert({insn,to1}); - } - else - { - if(getenv("MG_VERBOSE")) - { - cout<<"Absolute mem-op to scoop in insn: " - << hex << insn->getBaseID()<<":"<<disasm.getDisassembly()<<" to " - << to1->getName()<<" (" - <<hex<<to1->getStart()->getVirtualOffset()<<"-" - <<hex<<to1->getEnd()->getVirtualOffset()<<")"<<endl; - } - //ApplyAbsoluteMemoryRelocation(insn,to1); - absolute_refs_to_scoops.insert({insn,to1}); - } - } - else if ( -small_memory_threshold < (int)rel_addr1 && (int)rel_addr1 < small_memory_threshold ) - { - if((0 != rel_addr1) && getenv("MG_VERBOSE")) - { - cout << "Note: "<<hex<<rel_addr1<<" not declared address in (low addr thresh) :"; - cout << insn->getBaseID()<<":"<<disasm.getDisassembly(); - cout << endl; - } - } - else - { - if ((0 != rel_addr1) && getenv("MG_VERBOSE")) - { - cout << "Note: "<<hex<<rel_addr1<<" not declared address in (no scoop):"; - cout << insn->getBaseID()<<":"<<disasm.getDisassembly(); - cout << endl; - } - } - } - else - { - if(getenv("MG_VERBOSE")) - { - cout << "Note: "<<hex<<" no address in:"; - cout << insn->getBaseID()<<":"<<disasm.getDisassembly(); - cout << endl; - } - } -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::ApplyPcrelMemoryRelocation(Instruction_t* insn, DataScoop_t* to) -{ - const auto disasmp=DecodedInstruction_t::factory(insn); - const auto &disasm=*disasmp; - auto operands=disasm.getOperands(); - -#if 1 - // don't change instructions that reference re-pinned scoops. - // This was necessary because we were not getting the zipr_unpin_plugin - // to undo our changes to the instruction in the case of a re-pinned scoop. - // That problem is fixed, but it is more efficient and safer to - // avoid editing instructions that reference re-pinned scoops. - if (this->moveable_scoops.find(to) == this->moveable_scoops.cend()) { - if (getenv("MG_VERBOSE")) { - cout << "Avoiding editing of insn at " << hex << insn->getBaseID() << " after repinning scoop " - << to->getName() << endl; - } - return; - } -#endif - - auto the_arg=find_memory_operand(operands); - assert(the_arg!=operands.end()); - unsigned int disp_offset=disasm.getMemoryDisplacementOffset(the_arg->get(),insn)/*the_arg->Memory.DisplacementAddr-disasm.EIP*/; - unsigned int disp_size=(*the_arg)->getMemoryDisplacementEncodingSize() /*the_arg->Memory.DisplacementSize*/; - Relocation_t* pcrel_reloc=FindRelocationWithType(insn,"pcrel"); - pcrel_reloc->setWRT(to); -// note about this case: the pcrel reloc already exists for the -// case where an instruction is moving. -// now the relocs WRT field indicates that the target might move too. -// will have to edit push_relocs.zpi to handle this. - assert(0<disp_offset && disp_offset<=(insn->getDataBits().size() - disp_size)); - assert(disp_size==4); - unsigned int new_disp=(*the_arg)->getMemoryDisplacement() /*the_arg->Memory.Displacement*/ - to->getStart()->getVirtualOffset(); - insn->setDataBits(insn->getDataBits().replace(disp_offset, disp_size, (char*)&new_disp, disp_size)); -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::ApplyAbsoluteMemoryRelocation(Instruction_t* insn, DataScoop_t* to) -{ - //DISASM disasm; - //Disassemble(insn,disasm); - const auto disasmp=DecodedInstruction_t::factory(insn); - const auto &disasm=*disasmp; - auto operands=disasm.getOperands(); - -#if 1 - // don't change instructions that reference re-pinned scoops. - // This was necessary because we were not getting the zipr_unpin_plugin - // to undo our changes to the instruction in the case of a re-pinned scoop. - // That problem is fixed, but it is more efficient and safer to - // avoid editing instructions that reference re-pinned scoops. - if (this->moveable_scoops.find(to) == this->moveable_scoops.cend()) { - if (getenv("MG_VERBOSE")) { - cout << "Avoiding editing of insn at " << hex << insn->getBaseID() << " after repinning scoop " - << to->getName() << endl; - } - return; - } -#endif - - auto the_arg = find_memory_operand(operands); - unsigned int disp_offset=disasm.getMemoryDisplacementOffset(the_arg->get(),insn) /*the_arg->Memory.DisplacementAddr-disasm.EIP*/; - unsigned int disp_size=(*the_arg)->getMemoryDisplacementEncodingSize() /*the_arg->Memory.DisplacementSize*/; - assert(0<disp_offset && disp_offset<=insn->getDataBits().size() - disp_size); - auto reloc=getFileIR()->addNewRelocation(insn,0, "absoluteptr_to_scoop",to); - (void)reloc; // just giving to the ir - - assert(0<disp_offset && disp_offset<=(insn->getDataBits().size() - disp_size)); - assert(disp_size==4); - unsigned int new_disp=(*the_arg)->getMemoryDisplacement() /*the_arg->Memory.Displacement*/ - to->getStart()->getVirtualOffset(); - insn->setDataBits(insn->getDataBits().replace(disp_offset, disp_size, (char*)&new_disp, disp_size)); -} - -// See if STARS analyzed the instruction and determined which scoop it references. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -DataScoop_t* MoveGlobals_t<T_Sym, T_Rela, T_Rel, T_Dyn, T_Extractor>::DetectAnnotationScoop(Instruction_t* insn) -{ - if (!m_use_stars) - return nullptr; - - const auto dgsr_it = deep_global_static_ranges->find(insn); - const auto dgsr_found = dgsr_it != deep_global_static_ranges->end(); - const auto sentinel_it = sentinels->find(insn); - const auto is_sentinel = sentinel_it != sentinels->end(); - - auto ReferencedScoop = (DataScoop_t*)nullptr; - if(dgsr_found && is_sentinel) - { - const auto StartAddr = dgsr_it->second; - ReferencedScoop = findScoopByAddress(StartAddr); - } - return ReferencedScoop; -} // end of DetectAnnotationScoop() - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -DataScoop_t* MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::DetectProperScoop(const DecodedInstruction_t& disasm, const DecodedOperandVector_t::iterator the_arg, Instruction_t* insn, VirtualOffset_t insn_addr, bool immed, const DecodedOperandVector_t &the_arg_container) -{ - assert(insn); - assert(immed || (the_arg != the_arg_container.end())); // immeds don't need an argument, but memory ops do. - if (immed && (0 == insn_addr)) - return NULL; // immed value of zero is not a scoop address - - const int small_memory_threshold = exe_reader->isDLL() ? 10 : 4096 * 10; - bool ValidImmed = immed && (small_memory_threshold <= ((int)insn_addr)); - - DataScoop_t *ret = this->findScoopByAddress(insn_addr); - - // so far, we haven't run into any problems with not finding a scoop. we could later. - if (!ret) - { - // check for things that _just_ run off the end of a scoop. - for (auto i = 0; (i < 8) && (ret == NULL); i++) - ret = findScoopByAddress(insn_addr - i); - // check for things that just miss the beginning of a scoop - for (auto i = 0; (i < 8) && (ret == NULL); i++) - ret = findScoopByAddress(insn_addr + i); - } - - // See if STARS analyzed the instruction and determined which scoop it references. - DataScoop_t *retSTARS = (immed && (!ValidImmed)) ? nullptr : this->DetectAnnotationScoop(insn); - -#if 1 - if (!ret) - { - if (nullptr != retSTARS) - { - cout << "Detected proper scoop using annotation, not using after DetectProperScoop failure for insn at " << hex << insn->getBaseID() << endl; - } - return ret; - } -#endif - - /* check to see if it's an elftable */ - if (find(ALLOF(elftable_nocodeptr_names), ret->getName()) != elftable_nocodeptr_names.end()) - { - /* it's an elftable, so we don't need to look so hard because */ - /* we probably aren't pointing to an elf table from an instruction */ - /* find middle of table */ - auto mid_of_table = (ret->getStart()->getVirtualOffset() / 2) + (ret->getEnd()->getVirtualOffset() / 2); - - /* look forward if above middle, else look backwards */ - const auto op = (insn_addr < mid_of_table) - ? [](const VirtualOffset_t i, const VirtualOffset_t j) { return i - j; } - : [](const VirtualOffset_t i, const VirtualOffset_t j) { return i + j; } - ; - - /* start at begin/end of table depending on direction */ - const auto addr = (insn_addr < mid_of_table) - ? ret->getStart()->getVirtualOffset() - : ret->getEnd()->getVirtualOffset() - ; - - /* scan 128 bytes looking for a relevant scoop */ - const auto thres = 128; - for (auto i = 1; i < thres; i++) - { - /* check what's here */ - auto candidate = findScoopByAddress(op(addr, i)); - if (candidate != NULL) - return candidate; - } - /* didn't find anything */ - } /* if elftable */ - - /* Not an elf table use conservative and/or aggressive heuristics*/ - ret = DetectProperScoop_ConsiderEndOfPrev(disasm, the_arg, insn, insn_addr, immed, ret, the_arg_container); - - if (!aggressive) - ret = DetectProperScoop_ConsiderStartOfNext(disasm, the_arg, insn, insn_addr, immed, ret, the_arg_container); - - if (nullptr != retSTARS) - { - if (nullptr == ret) - { - // ret = retSTARS; // Dangerous to use; e.g. mov [rdi+0x200],rax will cause edit of 0x200 because RDI was resolved by STARS to a scoop address - cout << "Detected proper scoop using annotation, not using after DetectProperScoop final failure for insn at " << hex << insn->getBaseID() << endl; - } - else if (retSTARS != ret) - { - // We have two different non-null choices. We will tie the two scoops - // together if they are adjacent, and pin them both otherwise. - if (this->AreScoopsAdjacent(ret, retSTARS)) // tie adjacent scoops - { - cout << "Tieing adjacent scoops due to STARS vs. DetectProperScoop conflict for insn at " << hex << insn->getBaseID() << endl; - if (ret->getStart()->getVirtualOffset() < retSTARS->getStart()->getVirtualOffset()) { - ScoopPair_t TiedPair(ret, retSTARS); - (void) this->tied_scoops.insert(TiedPair); - } - else { - ScoopPair_t TiedPair(retSTARS, ret); - (void) this->tied_scoops.insert(TiedPair); - } - } - else // not adjacent; must pin - { - cout << "Pinning non-adjacent scoops due to STARS vs. DetectProperScoop conflict for insn at " << hex << insn->getBaseID() << endl; - (void) this->moveable_scoops.erase(ret); - (void) this->moveable_scoops.erase(retSTARS); - } - } - - } - return ret; -} // end of DetectProperScoop() - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -DataScoop_t* MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::DetectProperScoop_ConsiderStartOfNext( - const DecodedInstruction_t& disasm, - const DecodedOperandVector_t::iterator mem_arg, - Instruction_t* insn, - VirtualOffset_t insn_addr, - bool immed, - DataScoop_t* candidate_scoop, - const DecodedOperandVector_t &mem_arg_container - ) -{ - - assert(immed || mem_arg!=mem_arg_container.end()); // immeds don't need an argument, but memory ops do. - - const auto is_lea=disasm.getMnemonic() /*string(disasm.Instruction.Mnemonic)*/==string("lea"); - const auto consider_multiple_sizes= is_lea || immed; - - auto strides= consider_multiple_sizes ? set<int>({1,2,4,8}) : set<int>({ (int)(*mem_arg)->getArgumentSizeInBytes() /*ArgSize/8*/}); - - // get other strides from the containing function - if(insn->getFunction()) - for_each(ALLOF(insn->getFunction()->getInstructions()), [&strides](Instruction_t* insn) - { - //auto d=DISASM({}); - //Disassemble(insn,d); - const auto dp=DecodedInstruction_t::factory(insn); - const auto &d=*dp; - - auto potential_stride=0; - // if( string(d.Instruction.Mnemonic)=="add " || string(d.Instruction.Mnemonic)=="sub " ) - if( d.getMnemonic()=="add" || d.getMnemonic()=="sub") - { - potential_stride=d.getImmediate(); //.Instruction.Immediat; - } - - //if(string(d.Instruction.Mnemonic)=="lea ") - if(d.getMnemonic()=="lea") - { - potential_stride=d.getOperand(1)->getMemoryDisplacement(); /*d.Argument2.Memory.Displacement; */ - } - - if(abs(potential_stride)<500 && potential_stride!=0) - { - strides.insert(potential_stride); - strides.insert(-potential_stride); - } - }); - - const auto stride_multipliers= set<int>({-1,1}); - - //const auto NO_REG=0; - const auto contains_base_reg = mem_arg!=mem_arg_container.end() && (*mem_arg)->hasBaseRegister(); // mem_arg ? mem_arg->Memory.BaseRegister != NO_REG : false; - const auto contains_index_reg = mem_arg!=mem_arg_container.end() && (*mem_arg)->hasIndexRegister(); // mem_arg ? mem_arg->Memory.IndexRegister != NO_REG : false; - const auto contains_reg = contains_base_reg || contains_index_reg; - const auto memory_access= mem_arg!=mem_arg_container.end() && !is_lea; - const auto is_direct_memory_access=memory_access && !contains_reg; - - // check for a direct memory access - if(is_direct_memory_access) - { - return candidate_scoop; - } - - - // calculate each offset=stride*multiplier pair - auto candidate_offsets=set<int>(); - for_each(ALLOF(strides), [&](const int stride) - { - for_each(ALLOF(stride_multipliers), [&](const int multiplier) - { - candidate_offsets.insert(stride*multiplier); - }); - - }); - - // how to tie two scoops - auto insert_scoop_pair=[&](DataScoop_t* a, DataScoop_t* b, int i, int offset) - { - const auto tied_scoop_pair = ScoopPair_t(a,b) ; - assert(tied_scoop_pair.first->getEnd()->getVirtualOffset()+1 == tied_scoop_pair.second->getStart()->getVirtualOffset()); - tied_scoops.insert(tied_scoop_pair); - cout<<" Tieing scoops "<<tied_scoop_pair.first->getName()<<" and "<<tied_scoop_pair.second->getName()<<" for i="<<dec<<i<<" offset="<<offset<<endl; - ties_for_folded_constants++; - }; - - // how to decide if a scoop at offset i should be tied. - // no scoop -> no tie - // un-tie-able scoop -> no tie - // else tie - auto should_tie=[&](const int i, DataScoop_t* prev_scoop) -> DataScoop_t* - { - DataScoop_t *this_scoop=findScoopByAddress(insn_addr+i); - // no scoop at this addr? - if(this_scoop==NULL) - return NULL; - // un-tie-able scoop at this addr? - if(find(ALLOF(elftable_nocodeptr_names), this_scoop->getName())!=elftable_nocodeptr_names.end()) - return NULL; - return this_scoop; - }; - - - // check each offset for a scoop that needings tieing tot his one. - for_each(ALLOF(candidate_offsets), [&](const int offset) - { - assert(offset!=0); - auto candidate_offset_scoop=findScoopByAddress(insn_addr+offset) ; - - // check to see if the offset is in a different scoop - if(candidate_scoop != candidate_offset_scoop) - { - - // yes, therefore we have to tie all scoops between the start and end together. - // stop if there's an untieable scoop in the way. - auto prev_scoop=candidate_scoop; - if(offset < 0 ) - { - for(auto i=(int)-1;i>=offset; i--) - { - auto this_scoop=should_tie(i,prev_scoop); - if(this_scoop) - { - if(this_scoop!=prev_scoop) - insert_scoop_pair(this_scoop,prev_scoop, i, offset); - prev_scoop=this_scoop; - } - else - break; - } - } - else - { - for(auto i=(int)1;i<=offset; i++) - { - auto this_scoop=should_tie(i,prev_scoop); - if(this_scoop) - { - if(this_scoop!=prev_scoop) - insert_scoop_pair(prev_scoop,this_scoop, i, offset); - prev_scoop=this_scoop; - } - else - break; - } - } - } - }); - - return candidate_scoop; -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -DataScoop_t* MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::DetectProperScoop_ConsiderEndOfPrev( - const DecodedInstruction_t& disasm, - const DecodedOperandVector_t::iterator the_arg, - Instruction_t* insn, - VirtualOffset_t insn_addr, - bool immed, - DataScoop_t* ret, - const DecodedOperandVector_t &the_arg_container - ) -{ - - // possibility for future work: identify cases where - // [addr+rbx*8] that came from something like =a[i-1]. And addr==a[-1]. - // for now, memory operands that actually access memory, there's no additional analysis needed - //if(!immed && string(disasm.Instruction.Mnemonic)!=string("lea ")) - if(!immed && disasm.getMnemonic()!=string("lea")) - // this should filter out cmp, move, test, add, with a memory operation - return ret; - - // now we have an immediate or an lea (i.e., no cmp reg, [mem] operations) - // that's pointing to a scoop. Let's check if it's a boundary between two scoops - if(insn_addr!=ret->getStart()->getVirtualOffset()) - // it's not, so just continue. - return ret; - - - // now look to see if there's a scoop regsitered that abuts this scoop; - DataScoop_t *scoop_for_prev=findScoopByAddress(insn_addr-1); - - // if not found, we know we aren't in a boundary case. - if(!scoop_for_prev) - return ret; - - /* check to see if the immediate next instruction dereferences the destination of an lea. */ - Instruction_t* next_insn=insn->getFallthrough(); - if(next_insn == NULL) - next_insn=insn->getTarget(); - - if(next_insn && disasm.getMnemonic() /*string(disasm.Instruction.Mnemonic)*/==string("lea")) - { - //DISASM lea_disasm; - //Disassemble(insn,lea_disasm); - const auto lea_disasmp=DecodedInstruction_t::factory(insn); - const auto &lea_disasm=*lea_disasmp;; - string dstreg=lea_disasm.getOperand(0)->getString(); // Argument1.ArgMnemonic; - - //DISASM next_disasm; - //Disassimble(next_insn,next_disasm); - const auto next_disasmp=DecodedInstruction_t::factory(next_insn); - const auto &next_disasm=*next_disasmp; - auto memarg_container=next_disasm.getOperands(); - const auto memarg=find_memory_operand(memarg_container); - - // if we found a memory operation that uses the register, with no indexing, then conclude that - // we must access the variable after the address (not the variable before the address) - // if(memarg && string(next_disasm.Instruction.Mnemonic)!="lea " && string(memarg->ArgMnemonic)==dstreg ) - if(memarg!=memarg_container.end() && next_disasm.getMnemonic()!="lea" && (*memarg)->getString()/*string(memarg->ArgMnemonic)*/==dstreg ) - return ret; - - } - - - // if we're in a function - // check that function for other references to scoop_for_prev - if(insn->getFunction()) - { - auto found_insn_it=find_if( - ALLOF(insn->getFunction()->getInstructions()), - [&](Instruction_t* func_insn) - { - // disassemble instruction - //DISASM func_insn_disasm; - //Disassemble(func_insn,func_insn_disasm); - const auto func_insn_disasmp=DecodedInstruction_t::factory(func_insn); - const auto &func_insn_disasm=*func_insn_disasmp; - auto func_insn_disasm_operands=func_insn_disasm.getOperands(); - - // enter instructions have 2 immediates, so we can't just "getImmediate()" - if(func_insn_disasm.getMnemonic()=="enter") - return false; - - // check the immediate - // if(getFileIR()->findScoop(func_insn_disasm.Instruction.Immediat) == scoop_for_prev) - if(scoop_for_prev->getStart()->getVirtualOffset() <= (VirtualOffset_t)func_insn_disasm.getImmediate() && - (VirtualOffset_t)func_insn_disasm.getImmediate() <= scoop_for_prev->getEnd()->getVirtualOffset()) - return true; // return from lamba that we found an insn. - - // don't bother with the memory check unless we're an LEA - //if(func_insn_disasm.Instruction.Mnemonic!=string("lea ")) - if(func_insn_disasm.getMnemonic()!=string("lea")) - return false; - - // check the memory -- find the argument that's the mem ref; - const auto the_arg=find_memory_operand(func_insn_disasm_operands); - if(the_arg!=func_insn_disasm_operands.end()) - { - // see if the lea has a scoop reference. - VirtualOffset_t addr=(*the_arg)->getMemoryDisplacement(); - if(arg_has_relative(*(*the_arg))) - addr+=insn->getDataBits().size(); - - if(getFileIR()->findScoop(addr) == scoop_for_prev) - return true; // return from lamba - - } - - // not found in this insn - return false; // lambda return - - - }); - - // no reference to prev_scoop found, just return; - if(found_insn_it==insn->getFunction()->getInstructions().end()) - { - return ret; - } - - } - - - // if we make it this far, we note that a single function has sketchy (aka address-generating) references - // to both scoop_for_prev and ret; - // in this case, we need to make keep these two scoops together since we can't tell which way the sketchy ref's go. - // for now, just record the sketchy refs. - - cout<<"Boundary note: instruction "<<insn->getBaseID()<<":"<<disasm.getDisassembly()<<" has immed/lea that points at boundary case."; - if(insn->getFunction()) - cout<<" In "<<insn->getFunction()->getName()<<"."; - cout<<endl; - cout<<"Keep together "<< - scoop_for_prev->getName()<<" ("<<hex<< scoop_for_prev->getStart()->getVirtualOffset()<<"-"<<scoop_for_prev->getEnd()->getVirtualOffset()<<") and "<< - ret->getName()<<" ("<<hex<< ret->getStart()->getVirtualOffset()<<"-"<<ret->getEnd()->getVirtualOffset()<<")"<<endl; - - tied_scoops.insert(ScoopPair_t(scoop_for_prev,ret)); - return ret; -} - - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::ApplyImmediateRelocation(Instruction_t *insn, DataScoop_t* to) -{ - const auto disasmp=DecodedInstruction_t::factory(insn); - const auto &disasm=*disasmp; - VirtualOffset_t rel_addr2=disasm.getImmediate(); // Instruction.Immediat; - -#if 1 // don't change instructions that reference re-pinned scoops. - // This was necessary because we were not getting the zipr_unpin_plugin - // to undo our changes to the instruction in the case of a re-pinned scoop. - // That problem is fixed, but it is more efficient and safer to - // avoid editing instructions that reference re-pinned scoops. - if (this->moveable_scoops.find(to) == this->moveable_scoops.cend()) { - if (getenv("MG_VERBOSE")) { - cout << "Avoiding editing of insn at " << hex << insn->getBaseID() << " after repinning scoop " - << to->getName() << endl; - } - return; - } -#endif - - /* - Relocation_t* reloc = new Relocation_t(BaseObj_t::NOT_IN_DATABASE, 0, "immedptr_to_scoop", to); - insn->getRelocations().insert(reloc); - getFileIR()->getRelocations().insert(reloc); - */ - auto reloc=getFileIR()->addNewRelocation(insn,0, "immedptr_to_scoop", to); - (void)reloc; // not used, just giving to the IR -// fixme: insn bits changed here - assert(strtoumax(disasm.getOperand(1)->getString().c_str() /*Argument2.ArgMnemonic*/, NULL, 0) == rel_addr2); - - VirtualOffset_t new_addr = rel_addr2 - to->getStart()->getVirtualOffset(); - assert(4 < insn->getDataBits().size()); - insn->setDataBits(insn->getDataBits().replace(insn->getDataBits().size()-4, 4, (char*)&new_addr, 4)); - - cout<<"Non-Overlapping_Globals::ApplyImmediateReloc::Setting "<<hex<<insn->getBaseID()<<" to "<<insn->getDisassembly()<<endl; -} - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::HandleImmediateOperand(const DecodedInstruction_t& disasm, const DecodedOperandVector_t::iterator the_arg, Instruction_t* insn) -{ - // shared objects don't need this, you have to use a pcrel addressing mode. - if(exe_reader->isDLL()) - { - return; - } - const int small_memory_threshold= exe_reader->isDLL() ? 10 : 4096*10; - - // enter instructions have 2 immediates, so we can't just "getImmediate()" - if(disasm.getMnemonic()=="enter") - return; - - VirtualOffset_t rel_addr2=disasm.getImmediate(); //Instruction.Immediat; - auto operands=disasm.getOperands(); - DataScoop_t *to2=DetectProperScoop(disasm, operands.end(), insn, rel_addr2, true, operands); - - - // skip if not found, executable, or not moveable. - if( to2 && (to2->isExecuteable() || moveable_scoops.find(to2) == moveable_scoops.end())) - { - // do nothing, no log or action is necessary for (potential) pointers to code or - // (potential) pointers to non-moveable data. - } - else if(to2) - { - - // there's no need to find pointers in other types of instructions, - // such as mul or vfmasubadd231 (yes, that's a real instruction on x86) - // note: yes other instructions may have a memory operand with a pointer, but that's handled above. - // this is for instruction's immediate fields, not their memory operand's displacement. - // - // compares, tests are often used because the compiler strength reduces. - // moves are used to load addresses into a register. - // adds are used to load addresses plus an offset into a register. - // here's an example where sub is used with a pointer: - // - // DegenCount[strchr(Alphabet,iupac)-Alphabet] = ... - // - // 0x0000000000402a99 <+25>: call 0x401620 <strchr@plt> - // 0x0000000000402a9e <+30>: mov rbp <- rax - // 0x0000000000402aa1 <+33>: mov rdi <- rbx - // 0x0000000000402aa4 <+36>: sub rbp <- 0x65b500 # note: constant is a poitner here! - // 0x0000000000402aab <+43>: eax <- ... - // 0x0000000000402ab0 <+48>: mov DWORD PTR [rbp*4+0x65b520] <- eax - - if(disasm.getMnemonic() == string("mov") || - disasm.getMnemonic() == string("cmp") || - disasm.getMnemonic() == string("test") || - disasm.getMnemonic() == string("add") || - disasm.getMnemonic() == string("sub") ) - { - if(getenv("MG_VERBOSE")) - { - cout<<"Found non-mem ref in insn: "<<insn->getBaseID()<<":"<<disasm.getDisassembly()<<" to " - << to2->getName() <<"(" - <<hex<<to2->getStart()->getVirtualOffset()<<"-" - <<hex<<to2->getEnd()->getVirtualOffset()<<")"<<endl; - } - - unsigned int size=immed_refs_to_scoops.size(); - immed_refs_to_scoops.insert({insn,to2}); - assert( (size+1)==immed_refs_to_scoops.size()); - - - - } - } - else - { - if ((int)rel_addr2 < -small_memory_threshold || (int) rel_addr2 > small_memory_threshold || getenv("MG_VERBOSE")) - { - if ((0 != rel_addr2) && getenv("MG_VERBOSE")) - { - cout << "Note: " << hex << rel_addr2 << " not declared address in:"; - cout << insn->getBaseID() << ":" << disasm.getDisassembly(); - cout << endl; - } - } - } -} - -// put in links between scoops and any references to them. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::FindInstructionReferences() -{ - - - for(InstructionSet_t::iterator iit=getFileIR()->getInstructions().begin(); - iit!=getFileIR()->getInstructions().end(); - ++iit - ) - { - Instruction_t* insn=*iit; - //DISASM disasm; - //Disassemble(insn,disasm); - auto disasmp=DecodedInstruction_t::factory(insn); - auto &disasm=*disasmp; - auto disasm_operands=disasm.getOperands(); - - // find memory arg. - const auto the_arg=find_memory_operand(disasm_operands); - - if(getenv("MG_VERBOSE")) - cout<<"Considering "<<hex<<insn->getBaseID()<<":"<<disasm.getDisassembly()<<endl; - HandleMemoryOperand(disasm,the_arg,insn, disasm_operands); - HandleImmediateOperand(disasm,the_arg,insn); - } - -} - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::ApplyDataRelocation(DataScoop_t *from, unsigned int offset, DataScoop_t* to) -{ - assert(to && from); - - const char* data=from->getContents().c_str(); - unsigned int byte_width=getFileIR()->getArchitectureBitWidth()/8; - VirtualOffset_t val=(VirtualOffset_t)NULL; - - if(byte_width==4) - val=*(int*)&data[offset]; - else if(byte_width==8) - val=*(long long*)&data[offset]; - else - assert(0); - - /* - Relocation_t* reloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, offset, "dataptr_to_scoop", to); - from->getRelocations().insert(reloc); - getFileIR()->getRelocations().insert(reloc); - */ - auto reloc=getFileIR()->addNewRelocation(from,offset, "dataptr_to_scoop", to); - (void)reloc; // just giving to ir - - VirtualOffset_t newval=val-to->getStart()->getVirtualOffset(); - - auto str=from->getContents(); - // create new value for pointer. - if(byte_width==4) - { - unsigned int intnewval=(unsigned int)newval; // 64->32 narrowing OK. - str.replace(offset, byte_width, (char*)&intnewval, byte_width); - } - else if(byte_width==8) - { - str.replace(offset, byte_width, (char*)&newval, byte_width); - } - else - assert(0); - from->setContents(str); -} - - - -// -// check if val is a pointer or part of a string that mimics a pointer -// -static inline bool is_part_of_string(VirtualOffset_t val, const DataScoop_t* from, const DataScoop_t* to, int offset) -{ - assert(from && to); - - // locate strings that look like pointers but aren't. e.g.: "ion\0" and "ren\0". Note that both are null terminated. - // this is a problem on 64-bit code because we screw up the string. - - // note: the most sigificant byte is 0, and the lower 3 signfiicant bytes are printable. - - - // the least significant byte is special. In a valid pointer, it's almost always 00 or 01 for 64-bit code or shared libraries, - // and 0x08 0x09 for 32-bit main executables. Very very rarely is it anything else. - // however, for 0x01, 0x08, and 0x09 aren't printable, so we don't confuse these bytes in a string for an address and we don't need to detect this. - if ( ((val >> 24) & 0xff) != 0 ) // check for non-0 - return false; - if ( !isprint(((val >> 16) & 0xff))) // and 3 printable characters. - return false; - if ( !isprint(((val >> 8) & 0xff))) - return false; - if ( !isprint(((val >> 0) & 0xff))) - return false; - - // number of bytes that must precede the pointer and be string bytes to disambiguate a string's end from a pointer. - const int string_preheader_size=4; - - // if we dont' have enough bytes of preheader, skip it. - if( offset < string_preheader_size ) - return false; - - // check each byte preceeding the candidate pointer to see if it's printable. - for(auto i=0;i<string_preheader_size;i++) - { - if(i>offset) - return false; - unsigned char b=from->getContents()[offset-i]; - if(!isprint(b)) - return false; - } - - // we found enough string chars before the (candidate) pointer value, so we think that a string is here, not a pointer. - if(getenv("MG_VERBOSE")) - { - cout<<"Found string as non-ref "<<hex<<val<<" at "<<from->getName()<<"+"<<offset<<" (" - <<hex<<from->getStart()->getVirtualOffset()<<"-" - <<hex<<from->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - return true; - -} - -// put in links between scoops and any references to them. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::FindDataReferences() -{ - unsigned int byte_width=getFileIR()->getArchitectureBitWidth()/8; - - typedef function<void (DataScoop_t*)> ScannerFunction_t; - - auto read_bytewidth=[&](const char* data, const int i) -> long long - { - auto val=(long long)0; - if(byte_width==4) - val=*(int*)&data[i]; - else if(byte_width==8) - val=*(long long*)&data[i]; - else - assert(0); - return val; - }; - - ScannerFunction_t got_scanner=[&](DataScoop_t* scoop) - { - // got scanner doesn't scan data section for shared objects since they can't have a constant address - if(exe_reader->isDLL()) - return; - - auto data=scoop->getContents().c_str(); - auto len=scoop->getContents().size(); - - for ( auto i=0u; i+byte_width-1<len; i+=byte_width) - { - const auto val=read_bytewidth(data,i); - auto to=findScoopByAddress(val); - if(to) - { - if(getenv("MG_VERBOSE")) - { - cout<<"Found ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<i<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,i,to}); - } - } - }; - - ScannerFunction_t default_scanner=[&](DataScoop_t* scoop) - { - // default scanner doesn't scan data section for shared objects since they can't have a constant address - if(exe_reader->isDLL()) - return; - - auto data=scoop->getContents().c_str(); - auto len=scoop->getContents().size(); - - // try not to overrun the array - for ( auto i=0u; i+byte_width-1<len; i+=byte_width) - { - auto val=read_bytewidth(data,i); - auto to=findScoopByAddress(val); - - if(to) - { - - auto aggressive_qualify_for_moving = [this](const DataScoop_t* from, - DataScoop_t* &to, - bool &move_ok, - bool &disqualifies_to, - const VirtualOffset_t addr, unsigned int offset_in_scoop - ) -> void - { - move_ok=true; - disqualifies_to=false; - if( !to->isExecuteable() && - moveable_scoops.find(to) != moveable_scoops.end() && - !is_part_of_string(addr,from,to,offset_in_scoop) - ) - { - return; - } - move_ok=false; - }; - - auto qualify_for_moving = [this](const DataScoop_t* from, - DataScoop_t* &to, - bool &move_ok, - bool &disqualifies_to, - const VirtualOffset_t addr, unsigned int offset_in_scoop - ) -> void - { - move_ok=true; - disqualifies_to=false; - - // if points at executable scoop, we aren't doing that here! - if(to->isExecuteable()) - { move_ok=false; disqualifies_to=false; return ; } - - // if not moveable, we aren't doing that here. - if ( moveable_scoops.find(to) == moveable_scoops.end()) - { move_ok=false; disqualifies_to=false; return ; } - - - /* the above worked ok-ish, but not great. trying this method to be more conservative */ - { move_ok=false; disqualifies_to=true; return ; } - -/* - // if this constant appears to be part of a string, skip it! - if(is_part_of_string(addr,from,to,offset_in_scoop)) - { move_ok=false; disqualifies_to=false; return ; } - - // very few variables start at an address that ends in 0x000 and often address-looking constants do - // if we see such an address, pin-and-win. - if ( (addr&0xfff) == 0x000 && addr==to->getStart()->getVirtualOffset()) - { move_ok=false; disqualifies_to=true; return ; } - - // if we point at the start of a scoop, it's OK to move. - if(addr==to->getStart()->getVirtualOffset()) - { move_ok=true; disqualifies_to=false; return ; } - - // if it points near a scoop, but not directly at it, it's hard to tell if it's moveable or not - if(abs((long)addr-(long)to->getStart()->getVirtualOffset()) < 16 ) - { move_ok=false; disqualifies_to=true; return ; } - - // else, it's pointing in the middle of a scoop, so it's probably not a - // pointer at all. - { move_ok=false; disqualifies_to=false; return ; } -*/ - - }; - - auto move_ok=false; - auto disqualifies_to=false; - if(aggressive) - aggressive_qualify_for_moving(scoop, to,move_ok,disqualifies_to,val, i); - else - qualify_for_moving(scoop, to,move_ok,disqualifies_to,val, i); - - if(move_ok) - { - if(getenv("MG_VERBOSE")) - { - cout<<"Found ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<i<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - - // put those bytes back in the string. - //ApplyDataRelocations(*sit,i,to); - - data_refs_to_scoops.insert({scoop,i,to}); - } - else - { - if(getenv("MG_VERBOSE")) - { - cout<<"Found ref-looking-constant "<<hex<<val<<" at "<<scoop->getName()<<"+"<<i<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") which would otherwise be to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - } - if(disqualifies_to) - { - if(getenv("MG_VERBOSE")) - { - cout<<"Ref-looking-constant "<<hex<<val<<" at "<<scoop->getName()<<"+"<<i<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") is inconclusive. Repinning " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - moveable_scoops.erase(to); - } - } - else - { - if((0 != val) && getenv("MG_VERBOSE")) - { - cout<<"Constant "<<hex<<val<<" at "<<scoop->getName()<<"+"<<i<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") doesn't point at scoop."<<endl; - } - } - } - }; - - ScannerFunction_t dynsym_scanner=[&](DataScoop_t* scoop) - { - const char* data=scoop->getContents().c_str(); - unsigned int len=scoop->getContents().size(); - T_Sym* symptr=(T_Sym*)data; - const char* end=data+len; - - while((const char*)symptr<end) - { - - VirtualOffset_t val=symptr->st_value; - DataScoop_t *to=findScoopByAddress(val); - if(to) - { - unsigned int offset=(unsigned int)((VirtualOffset_t)symptr)-((VirtualOffset_t)data); - offset+=((VirtualOffset_t)&symptr->st_value)-(VirtualOffset_t)symptr; - - if(getenv("MG_VERBOSE")) - { - - cout<<"Found dynsym:st_value ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<offset<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,offset,to}); - } - - symptr++; // next symbol - } - - }; - ScannerFunction_t rel_scanner=[&](DataScoop_t* scoop) - { - const char* data=scoop->getContents().c_str(); - unsigned int len=scoop->getContents().size(); - - T_Rela * symptr=(T_Rela*)data; - const char* end=data+len; - - while((const char*)symptr<end) - { - // handle offset field - { - VirtualOffset_t val=symptr->r_offset; - DataScoop_t *to=findScoopByAddress(val); - if(to) - { - unsigned int offset=(unsigned int)((VirtualOffset_t)symptr)-((VirtualOffset_t)data); - offset+=((VirtualOffset_t)&symptr->r_offset)-(VirtualOffset_t)symptr; - - if(getenv("MG_VERBOSE")) - { - cout<<"Found rela:r_offset ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<offset<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,offset,to}); - } - } - - symptr++; // next symbol - } - }; - ScannerFunction_t rela_scanner=[&](DataScoop_t* scoop) - { - const char* data=scoop->getContents().c_str(); - unsigned int len=scoop->getContents().size(); - - T_Rela * symptr=(T_Rela*)data; - const char* end=data+len; - - while((const char*)symptr<end) - { - // handle addend field - { - VirtualOffset_t val=symptr->r_addend; - DataScoop_t *to=findScoopByAddress(val); - if(to) - { - unsigned int offset=(unsigned int)((VirtualOffset_t)symptr)-((VirtualOffset_t)data); - offset+=((VirtualOffset_t)&symptr->r_addend)-(VirtualOffset_t)symptr; - - if(getenv("MG_VERBOSE")) - { - cout<<"Found rela:r_added ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<offset<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,offset,to}); - } - } - // handle offset field - { - VirtualOffset_t val=symptr->r_offset; - DataScoop_t *to=findScoopByAddress(val); - if(to) - { - unsigned int offset=(unsigned int)((VirtualOffset_t)symptr)-((VirtualOffset_t)data); - offset+=((VirtualOffset_t)&symptr->r_offset)-(VirtualOffset_t)symptr; - - if(getenv("MG_VERBOSE")) - { - cout<<"Found rela:r_offset ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<offset<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,offset,to}); - } - } - - symptr++; // next symbol - } - }; - ScannerFunction_t dynamic_scanner=[&](DataScoop_t* scoop) - { - const auto data=scoop->getContents().c_str(); - const auto len=scoop->getContents().size(); - auto symptr=(T_Dyn*)data; - const char* end=data+len; - - while((const char*)symptr<end) - { - - switch(symptr->d_tag) - { - case DT_INIT_ARRAY: - case DT_FINI_ARRAY: - case DT_GNU_HASH: - case DT_STRTAB: - case DT_SYMTAB: - case DT_PLTGOT: - case DT_JMPREL: - case DT_RELA: - case DT_VERNEED: - case DT_VERSYM: - { - const auto val=symptr->d_un.d_val; - auto *to=findScoopByAddress(val); - - if(to) - { - - auto offset=(unsigned int) (((VirtualOffset_t)symptr)-((VirtualOffset_t)data)); - offset+=((VirtualOffset_t)&symptr->d_un.d_val)-(VirtualOffset_t)symptr; - - if(getenv("MG_VERBOSE")) - { - - cout<<"Found .dynamic:d_val ref "<<hex<<val<<" at "<<scoop->getName()<<"+"<<offset<<" (" - <<hex<<scoop->getStart()->getVirtualOffset()<<"-" - <<hex<<scoop->getEnd()->getVirtualOffset()<<") to " - <<to->getName()<<" (" - <<hex<<to->getStart()->getVirtualOffset()<<"-" - <<hex<<to->getEnd()->getVirtualOffset()<<")"<<endl; - } - - data_refs_to_scoops.insert({scoop,offset,to}); - } - break; - } - default: // do nothing - - break; - } - - symptr++; // next symbol - } - - }; - - - // special scanners for special sections - const struct scoop_scanners_t - { string name; - ScannerFunction_t scanner_fn; - } scoop_scanners[] = { - { ".dynsym", dynsym_scanner }, - { ".got", got_scanner }, - { ".got.plt", got_scanner }, - { ".rel.dyn", rel_scanner }, - { ".rel.plt", rel_scanner }, - { ".rel.dyn coalesced w/.rel.plt", rel_scanner }, - { ".rela.dyn", rela_scanner }, - { ".rela.plt", rela_scanner }, - { ".rela.dyn coalesced w/.rela.plt", rela_scanner }, - { ".dynamic", dynamic_scanner } - }; - - // main algorithm: apply the right scanner for each scoop - for_each(ALLOF(getFileIR()->getDataScoops()), [&](DataScoop_t* scoop) - { - auto scanner=find_if(ALLOF(scoop_scanners), [&](const scoop_scanners_t scanner) - { - return scanner.name==scoop->getName(); - - }); - if(scanner!=end(scoop_scanners)) - scanner->scanner_fn(scoop); - else - default_scanner(scoop); - - }); -} - - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::FilterAndCoalesceTiedScoops() -{ - const auto is_in_dont_coalesce_scoops = [](const DataScoop_t* to_find) -> bool - { - - const string dont_coalesce_scoops[] = - { - ".dynamic", - ".jcr" - }; - const auto a_binder = bind1st(finder, to_find); - const auto it=find_if(ALLOF(dont_coalesce_scoops), a_binder); - - return (it!=end(dont_coalesce_scoops)); - }; - - - - // step 1: find everything that's tied to a pinned scoop and pin it. - // repeat until no changes. - bool changed=true; - while(changed) - { - changed=false; - for(auto it=tied_scoops.begin(); it!=tied_scoops.end(); /* nop */) - { - auto current=it++; - const ScoopPair_t& p=*current; - DataScoop_t* s1=p.first; - DataScoop_t* s2=p.second; - bool s1_moveable=contains(moveable_scoops, s1); - bool s2_moveable=contains(moveable_scoops, s2); - - if(is_in_dont_coalesce_scoops(s1) || is_in_dont_coalesce_scoops(s2)) - { - cout<<"Skipping coalesce of "<<s1->getName()<<" and "<<s2->getName()<<endl; - tied_scoops.erase(current); - continue; - } - - if(s1_moveable && s2_moveable) - { - // do nothing if they're both unpinned. - tied_unpinned++; - } - else if(s1_moveable) - { - tied_pinned++; - - // s1 is pinned to an unmoveable, so it's unmoveable. - cout<<"Re-pinning "<<s1->getName()<<endl; - moveable_scoops.erase(s1); - tied_scoops.erase(current); - changed=true; - } - else if(s2_moveable) - { - cout<<"Re-pinning "<<s2->getName()<<endl; - tied_pinned++; - // s2 is pinned to an unmoveable. - moveable_scoops.erase(s2); - tied_scoops.erase(current); - changed=true; - } - else - { - tied_nochange++; - tied_scoops.erase(current); - } - - - } - } - - // step 2, coalesce - changed=true; - while(changed) - { - changed=false; - for(auto it=tied_scoops.begin(); it!=tied_scoops.end(); ) - { - auto current=it++; - const ScoopPair_t& p=*current; - DataScoop_t* s1=p.first; - DataScoop_t* s2=p.second; - - - if(is_in_dont_coalesce_scoops(s1) || is_in_dont_coalesce_scoops(s2)) - { - cout<<"Skipping coalesce of "<<s1->getName()<<" and "<<s2->getName()<<endl; - continue; - } - - bool s1_moveable=contains(moveable_scoops, s1); - bool s2_moveable=contains(moveable_scoops, s2); - - // we previously removed anything that's pinned from moveable - if(s1_moveable && s2_moveable) - { - // assert order is right - assert(s1->getStart()->getVirtualOffset() < s2->getStart()->getVirtualOffset()); - - // check if these are adjacent. - if(s1->getEnd()->getVirtualOffset()+1 < s2->getStart()->getVirtualOffset()) - { - // pad s1 to fill hole - string new_contents=s1->getContents(); - new_contents.resize(s2->getStart()->getVirtualOffset()-s1->getStart()->getVirtualOffset()); - s1->getEnd()->setVirtualOffset(s2->getStart()->getVirtualOffset()-1); - } - else if(s1->getEnd()->getVirtualOffset()+1 == s2->getStart()->getVirtualOffset()) - { - // do nothing if they fit perfectly. - } - else - assert(0); // overlapping scoops? - - cout<<"Coalescing 2-tied, but unpinned scoops "<<s1->getName()<<" and "<<s2->getName()<<"."<<endl; - - - // update our inteneral data structures for how to apply relocs. - auto insn_fixup_updater=[s1,s2](set<Insn_fixup_t> &the_set) - { - unsigned int size=the_set.size(); - set<Insn_fixup_t> new_elements; - auto it=the_set.begin(); - while(it!=the_set.end()) - { - auto current = it++; - auto replacer=*current; - if(replacer.to == s2) - { - the_set.erase(current); - replacer.to=s1; - new_elements.insert(replacer); - } - } - the_set.insert(new_elements.begin(), new_elements.end()); - assert(size==the_set.size()); - }; - insn_fixup_updater(pcrel_refs_to_scoops); - insn_fixup_updater(absolute_refs_to_scoops); - insn_fixup_updater(immed_refs_to_scoops); - - auto scoop_fixup_updater=[s1,s2](set<Scoop_fixup_t> &the_set) - { - set<Scoop_fixup_t> new_elements; - auto it=the_set.begin(); - while(it!=the_set.end()) - { - auto current = it++; - if(current->to == s2 || current->from==s2) - { - auto replacer=*current; - if(replacer.to==s2) - replacer.to=s1; - - if(replacer.from==s2) - { - replacer.from=s1; - cout<<"Updating data_ref_to_scoops offset from "<<hex<<replacer.offset<<" to "<<replacer.offset+s1->getSize()<<endl; - replacer.offset+=s1->getSize(); - } - the_set.erase(current); - new_elements.insert(replacer); - } - } - the_set.insert(new_elements.begin(), new_elements.end()); - }; - scoop_fixup_updater(data_refs_to_scoops); - - for(auto &r : getFileIR()->getRelocations()) - { - // s2 just came into existence, didn't it? - // assert(r->getWRT()!=s2); - // yes, but there may be relocs pointing at the s2 part of - // a split object, and so the reloc might get updated to point to s2 instead. - if( r->getWRT()==s2) - { - r->setWRT(s1); - r->setAddend(r->getAddend()+s1->getSize()); - } - } - - - /* - don't remove scoop here, as it will delete s2. this bit is moved later. - getFileIR()->getAddresses().erase(s1->getEnd()); - getFileIR()->getAddresses().erase(s2->getStart()); - getFileIR()->getDataScoops().erase(s2); // remove s2 from the IR - */ - // s2's end addresss is about to go away, so - // update s1's end VO instead of using s2 end addr. - s1->getEnd()->setVirtualOffset(s2->getEnd()->getVirtualOffset()); - moveable_scoops.erase(s2); // remove it from our analysis - unsigned int old_s1_size=s1->getContents().size(); - s1->setContents(s1->getContents()+s2->getContents()); - s1->setName(s1->getName()+" coalesced w/"+ s2->getName()); - if(!s2->isRelRo()) - s1->clearRelRo(); - s1->setRawPerms( s1->getRawPerms() | s2->getRawPerms()); - - // we just created s2 in this pass, right? - // no, s2 could be one of the sections from the orig binary that we've been asked to move - // and it might have relocs for unpinning - //assert(s2->getRelocations().size()==0); // assert no relocs that're part of s2. - - // add s2's relocs to s1. - for(auto reloc : s2->getRelocations()) - { - cout<<"Adjusting reloc "<< s2->getName()<<"+"<<reloc->getOffset()<<":"<<reloc->getType()<<" to "; - - reloc->setOffset(reloc->getOffset()+old_s1_size); - - auto s1_relocs=s1->getRelocations(); - s1_relocs.insert(reloc); - s1->setRelocations(s1_relocs); - - cout << s1->getName()<<"+"<<reloc->getOffset()<<":"<<reloc->getType()<<endl; - } - - // tell s2 it has no relocs so when we remove it, they don't go away. - s2->setRelocations({}); - - // we've processed this one. - tied_scoops.erase(current); - auto scoop_pair_first_finder= - [s2](const ScoopPair_t& p2) - { - return (p2.first==s2); - }; - auto found=find_if(ALLOF(tied_scoops), scoop_pair_first_finder); - if( found!=tied_scoops.end()) - { - ScoopPair_t p2=*found; - p2.first=s1; - tied_scoops.erase(found); - tied_scoops.insert(p2); - } - assert(find_if(ALLOF(tied_scoops), scoop_pair_first_finder) ==tied_scoops.end()); - - // finally remove s2 from the IR. - getFileIR()->removeScoop(s2); - changed=true; - break; - } - else - assert(0); // why are there pinned scoops still? - } - } - // ensure we handled eveything. - assert(tied_scoops.size()==0); - -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::UpdateScoopLocations() -{ - - // apply all 3 types of relocs for instructions - for_each(ALLOF(pcrel_refs_to_scoops), - [this] (const Insn_fixup_t & it) - { - if (getenv("MG_VERBOSE")) - cout << "Applying pcrel w/wrt from " << it.from->getDisassembly() << " to " << it.to->getName() << " at " << hex << it.from->getBaseID() << endl; - ApplyPcrelMemoryRelocation(it.from,it.to); - }); - - for_each(ALLOF(absolute_refs_to_scoops), - [this] (const Insn_fixup_t & it) - { - if (getenv("MG_VERBOSE")) - cout << "Applying absptr_to_scoop from " << it.from->getDisassembly() << " to " << it.to->getName() << " at " << hex << it.from->getBaseID() << endl; - ApplyAbsoluteMemoryRelocation(it.from,it.to); - }); - - for_each(ALLOF(immed_refs_to_scoops), - [this] (const Insn_fixup_t & it) - { - if (getenv("MG_VERBOSE")) - cout << "Applying immedptr_to_scoop from " << it.from->getDisassembly() << " to " << it.to->getName() << " at " << hex << it.from->getBaseID() << endl; - ApplyImmediateRelocation(it.from, it.to); - }); - for_each(ALLOF(data_refs_to_scoops), - [this] (const Scoop_fixup_t & it) - { - if (getenv("MG_VERBOSE")) - cout << "Applying dataptr_to_scoop from " << it.from->getName() << " to " << it.to->getName() << " at " << hex << it.offset << endl; - ApplyDataRelocation(it.from, it.offset, it.to); - }); - - - // unpin all the moveable scoops. - for (auto sit : moveable_scoops) - { - VirtualOffset_t newend = sit->getEnd()->getVirtualOffset() - sit->getStart()->getVirtualOffset(); - sit->getEnd()->setVirtualOffset(newend); - sit->getStart()->setVirtualOffset(0); - } -} - -// would be nice to have a FindRelocation function that takes a parameterized type. -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -Relocation_t* MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::FindRelocationWithType(BaseObj_t* obj, std::string type) -{ - RelocationSet_t::iterator rit = obj->getRelocations().begin(); - for( ; rit!=obj->getRelocations().end(); rit++) - { - Relocation_t *reloc=*rit; - if (reloc->getType() == type) - return reloc; - } - return NULL; -} - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class T_Extractor> -void MoveGlobals_t<T_Sym,T_Rela,T_Rel,T_Dyn,T_Extractor>::PrintStats() -{ - const auto resorted_moveable_scoops=DataScoopSet_t(ALLOF(moveable_scoops)); - DataScoopSet_t unmoveable_scoops; - unsigned long long moveable_scoop_bytes=0; - unsigned long long unmoveable_scoop_bytes=0; - unsigned long long total_scoop_bytes=0; - - set_difference( - ALLOF(getFileIR()->getDataScoops()), - ALLOF(resorted_moveable_scoops), - inserter(unmoveable_scoops,unmoveable_scoops.end())); - - - if(getenv("MG_VERBOSE")) - { - cout<<"Moveable scoops: "<<endl; - for_each(ALLOF(moveable_scoops), [](DataScoop_t* scoop) - { - cout<<"\t"<<scoop->getName()<<", contents: "<<endl; - auto i=0u; - const auto max_prints_env=getenv("MG_MAX_SCOOP_CONTENT_PRINT"); - const auto max_prints=max_prints_env ? strtoul(max_prints_env,NULL,0) : 16ul; - - for(i=0;i+8<scoop->getSize() && i<max_prints;i+=8) - cout<<"\t\tat:"<<hex<<i<<" value:0x"<<hex<<*(uint64_t*)&scoop->getContents().c_str()[i]<<" "<<endl; - for(/* empty init */;i<scoop->getSize() && i<max_prints;i++) - cout<<"\t\tat:"<<hex<<i<<" value:0x"<<hex<< + *(uint8_t*)&scoop->getContents().c_str()[i]<<" "<<endl; - }); - cout<<"Not moveable scoops: "<<endl; - for_each(ALLOF(unmoveable_scoops), [](DataScoop_t* scoop) - { - cout<<"\t"<<scoop->getName()<<" at "<<hex<<scoop->getStart()->getVirtualOffset()<<endl; - }); - } - // gather number of moveable bytes - for_each(moveable_scoops.begin(), moveable_scoops.end(), [&moveable_scoop_bytes, &total_scoop_bytes](DataScoop_t* scoop) - { - moveable_scoop_bytes += scoop->getSize(); - total_scoop_bytes+=scoop->getSize(); - }); - - // gather number of unmoveable bytes - for_each(unmoveable_scoops.begin(), unmoveable_scoops.end(), [&unmoveable_scoop_bytes,&total_scoop_bytes](DataScoop_t* scoop) - { - unmoveable_scoop_bytes +=scoop->getSize(); - total_scoop_bytes+=scoop->getSize(); - }); - - assert(getenv("SELF_VALIDATE")==nullptr || moveable_scoops.size() >= 5); - assert(getenv("SELF_VALIDATE")==nullptr || (immed_refs_to_scoops.size() + pcrel_refs_to_scoops.size()+absolute_refs_to_scoops.size()) > 5); - - - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Total_data_items="<<dec<<unmoveable_scoops.size()+moveable_scoops.size()<<endl; - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Unmoveable_data_items="<<dec<<unmoveable_scoops.size()<<endl; - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Moveable_data_items="<<dec<<moveable_scoops.size()<<endl; - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Percent_data_items_moveable="<<std::fixed<<std::setprecision(1)<< ((float)moveable_scoops.size()/((float)(unmoveable_scoops.size()+moveable_scoops.size())))*100.00<<"%"<< endl; - - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Unmoveable_data_items_in_bytes="<<dec<<unmoveable_scoop_bytes<<endl; - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Moveable_data_items_in_bytes="<<dec<<moveable_scoop_bytes<<endl; - cout<<"# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Total_data_items_in_bytes="<<dec<<total_scoop_bytes<<endl; - cout << "# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Percent_data_item_bytes_moved="<<std::fixed<<std::setprecision(1) << ((double)moveable_scoop_bytes/(double)total_scoop_bytes)*100.00 <<"%"<< endl; - cout << "# ATTRIBUTE ASSURANCE_Non-Overlapping_Globals::Percent_data_item_bytes_not_moved=" << std::fixed <<std::setprecision(1)<< ((double)unmoveable_scoop_bytes/(double)total_scoop_bytes)*100.00 <<"%"<< endl; - - cout<<"# ATTRIBUTE Non-Overlapping_Globals::tied_scoops="<<dec<<tied_scoops.size()<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::pcrel_refs="<<dec<<pcrel_refs_to_scoops.size()<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::abs_refs="<<dec<<absolute_refs_to_scoops.size()<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::imm_refs="<<dec<<immed_refs_to_scoops.size()<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::data_refs="<<dec<<data_refs_to_scoops.size()<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::coalesced_scoops="<<dec<<tied_unpinned<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::repinned_scoops="<<dec<<tied_pinned<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::ties_for_folded_constants="<<dec<<ties_for_folded_constants<<endl; - cout<<"# ATTRIBUTE Non-Overlapping_Globals::tied_scoop_pairs_that_were_already_pinned="<<dec<<tied_nochange<<endl; - cout<<"#ATTRIBUTE mg::unmoveable_scoops="<<dec<<unmoveable_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::moveable_scoops="<<dec<<moveable_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::pcrel_refs="<<dec<<pcrel_refs_to_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::abs_refs="<<dec<<absolute_refs_to_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::imm_refs="<<dec<<immed_refs_to_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::data_refs="<<dec<<data_refs_to_scoops.size()<<endl; - cout<<"#ATTRIBUTE mg::coalesced_scoops="<<dec<<tied_unpinned<<endl; - cout<<"#ATTRIBUTE mg::repinned_scoops="<<dec<<tied_pinned<<endl; - cout<<"#ATTRIBUTE mg::ties_for_folded_constants="<<dec<<ties_for_folded_constants<<endl; - cout<<"#ATTRIBUTE mg::tied_scoop_pairs_that_were_already_pinned="<<dec<<tied_nochange<<endl; -} - - -// explicit instatnation for elf32 and elf64 -template class MoveGlobals_t<Elf32_Sym, Elf32_Rela, Elf32_Rel, Elf32_Dyn, Extractor32_t>; -template class MoveGlobals_t<Elf64_Sym, Elf64_Rela, Elf64_Rel, Elf64_Dyn, Extractor64_t>; - diff --git a/builtin_xforms/move_globals/mg.hpp b/builtin_xforms/move_globals/mg.hpp deleted file mode 100644 index 796be6f84..000000000 --- a/builtin_xforms/move_globals/mg.hpp +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef _LIBTRANSFORM_INSTRUCTIONCOUNT_H_ -#define _LIBTRANSFORM_INSTRUCTIONCOUNT_H_ - -#include <irdb-transform> -#include <irdb-deep> -#include <memory> -#include <map> -#include <set> -#include <tuple> - -#include <exeio.h> - -#include <elfio/elfio.hpp> -#include <elfio/elfio_symbols.hpp> -#include <elf.h> - -using Elf_Xword = uint64_t; -using Elf_Half = uint16_t; - -template <class T_Sym, class T_Rela, class T_Rel, class T_Dyn, class Extractor> -class MoveGlobals_t : public IRDB_SDK::Transform_t -{ - public: - MoveGlobals_t(IRDB_SDK::VariantID_t *p_variantID, - IRDB_SDK::FileIR_t*p_variantIR, - const std::string &p_dont_move, - const std::string &p_move_only, - const int p_max_moveables, - const bool p_random, - const bool p_aggrssive, - const bool p_use_stars=false); - - int execute(IRDB_SDK::pqxxDB_t &pqxx_interface); - - private: - - // MEDS_Annotation::MEDS_Annotations_t& getAnnotations(); - - void ParseSyms(EXEIO::exeio * reader); - void SetupScoopMap(); - void FilterScoops(); - void TieScoops(); - void FindInstructionReferences(); - void FindDataReferences(); - void UpdateScoopLocations(); - void FilterAndCoalesceTiedScoops(); - IRDB_SDK::Relocation_t* FindRelocationWithType(IRDB_SDK::BaseObj_t* obj, std::string type); - void PrintStats(); - void HandleMemoryOperand(IRDB_SDK::DecodedInstruction_t &disasm, const IRDB_SDK::DecodedOperandVector_t::iterator the_arg, - IRDB_SDK::Instruction_t* insn, const IRDB_SDK::DecodedOperandVector_t &the_arg_container); - void HandleImmediateOperand(const IRDB_SDK::DecodedInstruction_t& disasm, const IRDB_SDK::DecodedOperandVector_t::iterator the_arg, IRDB_SDK::Instruction_t* insn); - IRDB_SDK::DataScoop_t* DetectAnnotationScoop(IRDB_SDK::Instruction_t* insn); - IRDB_SDK::DataScoop_t* DetectProperScoop(const IRDB_SDK::DecodedInstruction_t& disasm, const IRDB_SDK::DecodedOperandVector_t::iterator the_arg, IRDB_SDK::Instruction_t* insn, - IRDB_SDK::VirtualOffset_t immed_addr, bool immed, const IRDB_SDK::DecodedOperandVector_t &the_arg_container); - - IRDB_SDK::DataScoop_t* DetectProperScoop_ConsiderEndOfPrev(const IRDB_SDK::DecodedInstruction_t& disasm, const IRDB_SDK::DecodedOperandVector_t::iterator the_arg, IRDB_SDK::Instruction_t* insn, - IRDB_SDK::VirtualOffset_t insn_addr, bool immed, IRDB_SDK::DataScoop_t* ret, const IRDB_SDK::DecodedOperandVector_t &the_arg_container); - IRDB_SDK::DataScoop_t* DetectProperScoop_ConsiderStartOfNext(const IRDB_SDK::DecodedInstruction_t& disasm, const IRDB_SDK::DecodedOperandVector_t::iterator the_arg, IRDB_SDK::Instruction_t* insn, - IRDB_SDK::VirtualOffset_t insn_addr, bool immed, IRDB_SDK::DataScoop_t* cand_scoop, const IRDB_SDK::DecodedOperandVector_t &the_arg_container); - - void ApplyImmediateRelocation(IRDB_SDK::Instruction_t *insn, IRDB_SDK::DataScoop_t* to); - void ApplyAbsoluteMemoryRelocation(IRDB_SDK::Instruction_t *insn, IRDB_SDK::DataScoop_t* to); - void ApplyPcrelMemoryRelocation(IRDB_SDK::Instruction_t *insn, IRDB_SDK::DataScoop_t* to); - void ApplyDataRelocation(IRDB_SDK::DataScoop_t *from, unsigned int offset, IRDB_SDK::DataScoop_t* to); - IRDB_SDK::DataScoop_t* findScoopByAddress(const IRDB_SDK::VirtualOffset_t a) const; - bool AreScoopsAdjacent(const IRDB_SDK::DataScoop_t *a, const IRDB_SDK::DataScoop_t *b) const; - - - std::vector<T_Sym> static_symbols; - std::vector<T_Sym> dynamic_symbols; - EXEIO::exeio* exe_reader; - - struct cmpByName { - bool operator()(const IRDB_SDK::DataScoop_t* a, const IRDB_SDK::DataScoop_t* b) const { - - return (a->getName() < b->getName()); - } - }; - std::set<IRDB_SDK::DataScoop_t*> moveable_scoops; - std::map<IRDB_SDK::DataScoop_t*,unsigned int> reasons; - - using ScoopPair_t = std::pair<IRDB_SDK::DataScoop_t*,IRDB_SDK::DataScoop_t*>; - - std::set<ScoopPair_t> tied_scoops; - - // sets to record what insns need to be fixed later. - struct Insn_fixup - { - IRDB_SDK::Instruction_t* from; IRDB_SDK::DataScoop_t* to; - - bool operator <(const struct Insn_fixup& rhs) const - { - return std::tie(from, to) < std::tie(rhs.from, rhs.to); - } - }; - using Insn_fixup_t = struct Insn_fixup; - std::set<Insn_fixup_t> pcrel_refs_to_scoops, absolute_refs_to_scoops, immed_refs_to_scoops; - - - // data references to scoops - struct Scoop_fixup - { - IRDB_SDK::DataScoop_t* from; unsigned int offset; IRDB_SDK::DataScoop_t* to; - - bool operator <(const struct Scoop_fixup & rhs) const - { - return std::tie(from, offset, to) < std::tie(rhs.from, rhs.offset, rhs.to); - } - }; - using Scoop_fixup_t = struct Scoop_fixup;; - std::set<Scoop_fixup_t> data_refs_to_scoops; - - - int tied_unpinned; - int tied_pinned; - int tied_nochange; - int ties_for_folded_constants; - - const std::string dont_move; - const std::string move_only; - - using RangePair_t = std::pair<IRDB_SDK::VirtualOffset_t,IRDB_SDK::VirtualOffset_t>; - struct cmpByRange - { - bool operator()(const RangePair_t& a, const RangePair_t& b) const { - - return (a.second < b.first); - } - }; - std::map<RangePair_t, IRDB_SDK::DataScoop_t*, cmpByRange> scoop_map; - - - const int max_moveables; - const bool random; - const bool aggressive; - const bool m_use_stars; - - - std::unique_ptr<IRDB_SDK::StaticGlobalStartMap_t > deep_global_static_ranges; - std::unique_ptr<IRDB_SDK::RangeSentinelSet_t> sentinels; - - -}; - -class Extractor64_t -{ - public: - Elf_Xword elf_r_sym (Elf_Xword a) { return ELF64_R_SYM (a); } - Elf_Xword elf_r_type(Elf_Xword a) { return ELF64_R_TYPE(a); } - unsigned char elf_st_bind(unsigned char a) { return ELF64_ST_BIND(a); } - unsigned char elf_st_type(unsigned char a) { return ELF64_ST_TYPE(a); } -}; -class Extractor32_t -{ - public: - Elf32_Word elf_r_sym (Elf32_Word a) { return ELF32_R_SYM (a); } - Elf32_Word elf_r_type(Elf32_Word a) { return ELF32_R_TYPE(a); } - unsigned char elf_st_bind(unsigned char a) { return ELF32_ST_BIND(a); } - unsigned char elf_st_type(unsigned char a) { return ELF32_ST_TYPE(a); } -}; - - -const static auto elftable_names= std::set<std::string> ({".dynamic",".got",".got.plt",".dynstr",".dynsym",".rel.dyn",".rela.dyn",".rel.plt",".rela.plt", ".gnu.version", ".gnu_version_r"}); -const static auto elftable_nocodeptr_names= std::set<std::string> ({".dynamic"}); - -using MoveGlobals32_t = class MoveGlobals_t<Elf32_Sym, Elf32_Rela, Elf32_Rel, Elf32_Dyn, Extractor32_t>; -using MoveGlobals64_t = class MoveGlobals_t<Elf64_Sym, Elf64_Rela, Elf64_Rel, Elf64_Dyn, Extractor64_t>; - - - -#endif - diff --git a/builtin_xforms/move_globals/mg_driver.cpp b/builtin_xforms/move_globals/mg_driver.cpp deleted file mode 100644 index 37033c7ef..000000000 --- a/builtin_xforms/move_globals/mg_driver.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include <stdlib.h> -#include <fstream> -#include <irdb-core> - -#include "mg.hpp" -#include <getopt.h> - -using namespace std; -using namespace IRDB_SDK; - -#define ALLOF(a) begin(a),end(a) - -class MoveGlobalsDriver_t : public TransformStep_t -{ - - -void usage(string programName) -{ - - auto et_names=string(); - for(const auto &str : elftable_names ) - et_names+=str+" "; - - cerr << "Usage: " << programName << " <variant id> <annotation file>" <<endl; - cout<<"--elftables-only,-o Move sections titled \""<<et_names<<"\""<<endl; - cout<<"--aggressive Use aggressive heuristics to move more variables (does not affect elftables) "<<endl; - cout<<"--no-conservative alias for --aggressive"<<endl; - cout<<"--conservative (default) Use conservative heuristics to increase reliability (does not affect elftables) "<<endl; - cout<<"--no-aggressive alias for --conservative"<<endl; - - cout<<endl; - cout<<"---- debugging options (power users only) "<<endl; - cout<<"--use-stars Enable STARS deep analysis for more analysis precision (current default). "<<endl; - cout<<"--no-use-stars Disable STARS deep analysis for more analysis precision. "<<endl; - cout<<"--move,-m Move only the given objects."<<endl; - cout<<"--dont,-d Dont move the listed objects (overrides --only)."<<endl; - cout<<"--number,-n Max number of scoops to move."<<endl; - cout<<"--random,-r Randomly select scoops to move."<<endl; - cout<<"--help,--usage,-?,-h Display this message"<<endl; -} - -DatabaseID_t variantID = BaseObj_t::NOT_IN_DATABASE; -string dont_move = ""; -string move_only = ""; -size_t max_moveables = 0; -bool random = false; -bool aggressive = false; -VariantID_t* pidp = nullptr; -const string programName=string("libmove_globals.so"); -bool use_stars=true; - -int parseArgs(const vector<string> step_args) -{ - - auto argv = vector<char*>({const_cast<char*>("libmove_globals.so")}); - transform(ALLOF(step_args), back_inserter(argv), [](const string &s) -> char* { return const_cast<char*>(s.c_str()); } ); - const auto argc = argv.size(); - - // Parse some options for the transform - const static struct option long_options[] = { - {"elftables-only", no_argument, 0, 'o'}, - {"use-stars", no_argument, 0, 's'}, - {"no-use-stars", no_argument, 0, 't'}, - {"move", required_argument, 0, 'm'}, - {"dont", required_argument, 0, 'd'}, - {"number", required_argument, 0, 'n'}, - {"aggressive", no_argument, 0, 'a'}, - {"no-aggressive", no_argument, 0, 'A'}, - {"conservative", no_argument, 0, 'A'}, - {"no-conservative", no_argument, 0, 'a'}, - {"random", no_argument, 0, 'r'}, - {"help", no_argument, 0, 'h'}, - {"usage", no_argument, 0, '?'}, - {0,0,0,0} - }; - auto short_opts="b:oh?m:d:n:aAst"; - while(1) - { - int c = getopt_long(argc, &argv[0], short_opts, long_options, nullptr); - if (c == -1) - break; - switch(c) { - case 0: - break; - case 'c': - case 'o': - // add elftables to move only list - for(const auto &str : elftable_names ) - move_only+= str+" "; - break; - case 's': - use_stars=true; - break; - case 't': - use_stars=false; - break; - case 'm': - move_only+=string(" ") + optarg; - break; - case 'd': - dont_move+=string(" ") + optarg; - break; - case 'n': - max_moveables+=strtoll(optarg,nullptr,0); - break; - case 'r': - random=true; - break; - case 'a': - cout<<"Setting aggressive mode"<<endl; - aggressive=true; - break; - case 'A': - cout<<"Setting conservative mode"<<endl; - aggressive=false; - break; - case '?': - case 'h': - usage("libmove_globals.so"); - return 1; - default: - break; - } - } - return 0; -} - - -int executeStep() -{ - variantID=getVariantID(); - auto irdb_objects=getIRDBObjects(); - - auto exit_code = (int) 0; - - /* setup the interface to the sql server */ - const auto pqxx_interface=irdb_objects->getDBInterface(); - BaseObj_t::setInterface(pqxx_interface); - - // get the variant info from the database - pidp=irdb_objects->addVariant(variantID); // new VariantID_t(variantID); - assert(pidp && pidp->isRegistered()==true); - auto transformExitCode = (int) 0; - - for(auto this_file : pidp->getFiles()) - { - try - { - /* read the IR from the DB */ - auto firp = irdb_objects->addFileIR(variantID, this_file->getBaseID()); // new FileIR_t(*pidp, this_file); - cout<<"Transforming "<<this_file->getURL()<<endl; - assert(firp && pidp); - - - /* - * Create a transformation and then - * invoke its execution. - */ - if (firp->getArchitectureBitWidth() == 64) - { - MoveGlobals64_t mg(pidp, firp, dont_move, move_only, max_moveables, random, aggressive, use_stars); - transformExitCode = mg.execute(*pqxx_interface); - } - else - { - MoveGlobals32_t mg(pidp, firp, dont_move, move_only, max_moveables, random, aggressive, use_stars); - transformExitCode = mg.execute(*pqxx_interface); - } - /* - * If everything about the transformation - * went okay, then we will write the updated - * set of instructions to the database. - */ - if (transformExitCode != 0) - { - cerr << programName << ": transform failed. Check logs." << endl; - exit_code=2; - } - } - catch (DatabaseError_t pnide) - { - cerr << programName << ": Unexpected database error: " << pnide << endl; - return 1; - } - catch (const std::exception &exc) - { - // catch anything thrown within try block that derives from std::exception - std::cerr << "Unexpected exception: " << exc.what(); - return 1; - } - catch (...) - { - cerr << programName << ": Unexpected error" << endl; - return 1; - } - } - - return exit_code; -} - -std::string getStepName(void) const override -{ - return std::string("move_globals"); -} - -}; - -extern "C" -shared_ptr<TransformStep_t> getTransformStep(void) -{ - return shared_ptr<TransformStep_t>(new MoveGlobalsDriver_t()); -} - diff --git a/builtin_xforms/move_globals/tests/test_spec.sh b/builtin_xforms/move_globals/tests/test_spec.sh deleted file mode 100755 index 053e5b478..000000000 --- a/builtin_xforms/move_globals/tests/test_spec.sh +++ /dev/null @@ -1,300 +0,0 @@ -#!/bin/bash - -# the bad boys -#benchmarks=" -# 400.perlbench -# 403.gcc -# 445.gobmk -# 450.soplex -# 453.povray -# 458.sjeng -# 464.h264ref -# 465.tonto -# 471.omnetpp -# 481.wrf -# 482.sphinx3 -# 483.xalancbmk -# " - -# all -all_benchmarks="400.perlbench 401.bzip2 403.gcc 410.bwaves 416.gamess 429.mcf 433.milc 434.zeusmp 435.gromacs 436.cactusADM 437.leslie3d 444.namd 445.gobmk 450.soplex 453.povray 454.calculix 456.hmmer 458.sjeng 459.GemsFDTD 462.libquantum 464.h264ref 465.tonto 470.lbm 471.omnetpp 473.astar 481.wrf 482.sphinx3 483.xalancbmk" - - -number=1 - -setup() -{ - - if [ ! -d spec2006 ]; then - # svn co ^/spec2006/trunk spec2006 - git clone --depth 1 http://git.zephyr-software.com/allzp/spec2006.git spec2006 - - fi - - if [[ ! -f /usr/bin/gfortran ]]; then - sudo apt-get install gfortran -y - fi - - cd spec2006/ - if [ ! -L bin ]; then - ln -s bin.power/ bin - fi - source shrc - bin/relocate -} - - -run_test() -{ - config_name=$1 - config=$2 - benchmarks="$3" - - all_configs_that_were_run="$all_configs_that_were_run $config_name" - - cd $SPEC - if [ ! -d result.$config_name ]; then - dropdb $PGDATABASE - createdb $PGDATABASE - $PEASOUP_HOME/tools/db/pdb_setup.sh - rm -Rf result/* - runspec --action scrub --config $config $benchmarks - - echo - echo "**************************************************************************" - echo "Starting test of $config_name" - echo "**************************************************************************" - echo - runspec --action validate --config $config -n $number $benchmarks - cp benchspec/CPU2006/*/exe/* result - mv result result.$config_name - for bench in $benchmarks - do - mv benchspec/CPU2006/$bench/run/build*/peasoup*/logs result.$config_name/$bench.log - done - fi - -} - -get_size_result() -{ - bench=$1 - if [ -e $bench ]; then - size=$(stat --printf="%s" $bench) - #echo -n "$size" - #LC_ALL= numfmt --grouping $size - #LC_ALL= printf "%'d" $size - #LC_NUMERIC=en_US printf "%'d" $size - #LC_NUMERIC=en_US printf "%'f" $size - #LC_NUMERIC=en_US printf "%'.f" $size - #LC_NUMERIC=en_US printf "%'10.10f" $size - #LC_NUMERIC=en_US /usr/bin/printf "%'d" $size - echo $size - else - echo -n "0" - fi -} - -get_result() -{ - bench=$1 - config=$2 - - results=$(cat $SPEC/result.$config/CPU2006.002.log|grep Success|grep $bench|grep ratio=|sed 's/.*ratio=//'|sed 's/,.*//') - - sum=0 - count=0 - for res in $results - do - sum=$(echo $sum + $res | bc) - count=$(echo $count + 1 | bc) - done - #echo sum=$sum - #echo count=$count - res=$(echo "scale=2; $sum / $count" | bc 2> /dev/null ) - - count=$(echo $res|wc -w) - - if [ $count = 1 ]; then - echo -n $res - else - echo -n "0" - fi - -} - -# global -all_configs_that_were_run="" - -get_raw_results() -{ - local configs="$all_configs_that_were_run" - - get_raw_perf_results "$configs" - get_raw_size_results "$configs" - get_raw_mg_results "$configs" - #get_raw_fde_results "$configs" -} - -get_raw_perf_results() -{ - configs=$* - first_config=$1 - echo "--------------------------------------------------------------" - echo "Performance results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $benchmarks - do - echo -n "$bench " - for config in $* - do - get_result $bench $config - echo -n " " - done - echo - done -} - -get_raw_size_results() -{ - echo "--------------------------------------------------------------" - echo "Size results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - echo -n "$(basename $bench _base.amd64-m64-gcc42-nn) " - for config in $* - do - if [[ $config == "baseline" ]]; then - file="$SPEC/result.$config/$(basename $bench)" - cp $file /tmp/foo.exe - strip /tmp/foo.exe - file="/tmp/foo.exe" - else - file="$SPEC/result.$config/$(basename $bench)" - fi - res=$(get_size_result $file) - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - - -get_raw_mg_results() -{ - echo "--------------------------------------------------------------" - echo "Move_globals unmoveable scoop count:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $benchmarks - do - echo -n $bench - for config in $* - do - file="$SPEC/result.$config/${bench}.log/move_globals.log" - res="N/A" - if [[ -f $file ]]; then - res=$(grep "ATTRIBUTE mg::unmoveable_scoops=" $file|sed "s|.*=||") - fi - echo -n " $res" - done - echo - done - echo "--------------------------------------------------------------" - echo "Move_globals moveable scoop count:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $benchmarks - do - echo -n $bench - for config in $* - do - file="$SPEC/result.$config/${bench}.log/move_globals.log" - res="N/A" - if [[ -f $file ]]; then - res=$(grep "ATTRIBUTE mg::moveable_scoops=" $file|sed "s|.*=||") - fi - echo -n " $res" - done - echo - done - -} - -get_raw_fde_results() -{ - echo "--------------------------------------------------------------" - echo "FDE results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - #printf "%-20s" $(basename $bench _base.amd64-m64-gcc42-nn) - echo -n $(basename $bench _base.amd64-m64-gcc42-nn) - for config in $* - do - file="$SPEC/result.$config/$(basename $bench)" - res=$(readelf -w $file |grep FDE|wc -l ) - #if [[ $config == "baseline" ]]; then - #else - #fi - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -main() -{ - zipr_flags=" --backend zipr --step-option zipr:--add-sections --step-option zipr:true" - trace_flags=" --step-option zipr:--traceplacement:on --step-option zipr:true" - relax_flags=" --step-option zipr:--relax:on --step-option zipr:true --step-option zipr:--unpin:on --step-option zipr:false" - nounpin_flags=" --step-option zipr:--unpin:on --step-option zipr:false" - split_flags=" --step-option fill_in_indtargs:--split-eh-frame " - icall_flags=" --step-option fix_calls:--no-fix-icalls " - p1flags=" --critical-step p1transform=on " - mg_flags_elftables=" --critical-step move_globals=on --step-option move_globals:--elftables" - mg_flags_conservative=" --critical-step move_globals=on " - mg_aggressive_flags=" --critical-step move_globals=on --step-option move_globals:--aggressive " - - - start_dir=$(pwd) - setup - - run_test baseline $SPEC/config/ubuntu14.04lts-64bit.cfg "$all_benchmarks" - run_test baseline-fpic $SPEC/config/ubuntu14.04lts-64bit-fpic.cfg "$all_benchmarks" - - # should be 100% success, tested by jdh on 8/28/17 as 100% success. - #PSOPTS="$zipr_flags " run_test zipr $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - PSOPTS="$zipr_flags $trace_flags " run_test zipr-trace $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags " run_test zipr-trace-fpic $SPEC/config/ubuntu14.04lts-64bit-fpic-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags $mg_flags_conservative" run_test mg-conservative-trace $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags $mg_flags_conservative" run_test mg-conservative-trace-fpic $SPEC/config/ubuntu14.04lts-64bit-fpic-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags $mg_flags_all $mg_aggressive_flags" run_test mg-aggressive-trace $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags $mg_flags_all $mg_aggressive_flags" run_test mg-aggressive-trace-fpic $SPEC/config/ubuntu14.04lts-64bit-fpic-withps.cfg "$all_benchmarks" - PSOPTS="$zipr_flags $trace_flags $mg_flags_elftables" run_test mgelftables-trace $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - - get_raw_results - - # get_raw_results baseline zipr zipr-trace split-no-fix-icalls split-no-fix-icalls-trace zipr-trace-p1 split-trace-p1 split-no-fix-icalls-trace-p1 zipr-trace-p1-rerun -} - -main "$@" - - - diff --git a/builtin_xforms/p1transform/AnnotationBoundaryGenerator.cpp b/builtin_xforms/p1transform/AnnotationBoundaryGenerator.cpp deleted file mode 100644 index d45f07e34..000000000 --- a/builtin_xforms/p1transform/AnnotationBoundaryGenerator.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "AnnotationBoundaryGenerator.hpp" -#include <map> - -#include <iostream> - -using namespace std; -using namespace IRDB_SDK; -//using namespace MEDS_Annotation; - - -vector<Range> AnnotationBoundaryGenerator::GetBoundaries(IRDB_SDK::Function_t *func) -{ - assert(0); -#if 0 - vector<Range> ranges; - -// std::multimap<VirtualOffset, MEDS_AnnotationBase> - MEDS_Annotations_t annotations = annotParser->getAnnotations(); - - for( - set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it - ) - { - Instruction_t* instr = *it; - VirtualOffset_t irdb_vo = instr->getAddress()->getVirtualOffset(); - - if (irdb_vo == 0) continue; - - VirtualOffset vo(irdb_vo); - - //std::pair<std::multimap<VirtualOffset, MEDS_AnnotationBase>::iterator,std::multimap<VirtualOffset, MEDS_AnnotationBase>::iterator> ret; - std::pair<MEDS_Annotations_t::iterator,MEDS_Annotations_t::iterator> ret; - ret = annotations.equal_range(vo); - MEDS_InstructionCheckAnnotation annotation; - MEDS_InstructionCheckAnnotation* p_annotation; - for (MEDS_Annotations_t::iterator it = ret.first; it != ret.second; ++it) - { - p_annotation=dynamic_cast<MEDS_InstructionCheckAnnotation*>(it->second); - if(p_annotation==NULL) - continue; - annotation = *p_annotation; - if (annotation.isValid() && annotation.isMemset()) - { - //cerr<<"Memset annot found"<<endl; - - int objectSize = annotation.getObjectSize(); - int offset = annotation.getStackOffset(); - - Range cur; - cur.SetOffset(offset); - cur.SetSize(objectSize); - - if (annotation.isEbpOffset()) - { - if(offset < 0) - { - ranges.push_back(cur); - } - - } else if (annotation.isEspOffset()) - { - if(offset >= 0) - { - ranges.push_back(cur); - } - } else - { - // something went wrong - assert(0); - } - } - } - } - - return ranges; -#endif -} diff --git a/builtin_xforms/p1transform/AnnotationBoundaryGenerator.hpp b/builtin_xforms/p1transform/AnnotationBoundaryGenerator.hpp deleted file mode 100644 index b426b5a37..000000000 --- a/builtin_xforms/p1transform/AnnotationBoundaryGenerator.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __ANNOTBOUNDGEN -#define __ANNOTBOUNDGEN -#include "PrecedenceBoundaryGenerator.hpp" -//#include "MEDS_AnnotationParser.hpp" -//#include "MEDS_AnnotationBase.hpp" -//#include "MEDS_InstructionCheckAnnotation.hpp" -// #include "VirtualOffset.hpp" - -#include <fstream> - -class AnnotationBoundaryGenerator : public PrecedenceBoundaryGenerator -{ -protected: -// MEDS_Annotation::MEDS_AnnotationParser *annotParser; -public: -// AnnotationBoundaryGenerator(MEDS_Annotation::MEDS_AnnotationParser *annotParser) : annotParser(annotParser){} - virtual std::vector<Range> GetBoundaries(IRDB_SDK::Function_t *func); -}; - -#endif diff --git a/builtin_xforms/p1transform/DirectOffsetInference.cpp b/builtin_xforms/p1transform/DirectOffsetInference.cpp deleted file mode 100644 index 4caaffe18..000000000 --- a/builtin_xforms/p1transform/DirectOffsetInference.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "DirectOffsetInference.hpp" - -using namespace std; -using namespace IRDB_SDK; - -DirectOffsetInference::DirectOffsetInference(OffsetInference *offset_inference) -{ - //TODO: throw exception - assert(offset_inference != NULL); - - this->offset_inference = offset_inference; -} - -PNStackLayout* DirectOffsetInference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetDirectAccessLayout(func); -} - -std::string DirectOffsetInference::GetInferenceName() const -{ - return "Direct Offset Inference"; -} diff --git a/builtin_xforms/p1transform/DirectOffsetInference.hpp b/builtin_xforms/p1transform/DirectOffsetInference.hpp deleted file mode 100644 index 2a0bd5d90..000000000 --- a/builtin_xforms/p1transform/DirectOffsetInference.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __DIRECTOFFSETINFERENCE -#define __DIRECTOFFSETINFERENCE - -#include "OffsetInference.hpp" -#include "PNStackLayoutInference.hpp" - -class DirectOffsetInference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - DirectOffsetInference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func); - virtual std::string GetInferenceName() const; -}; - - -#endif diff --git a/builtin_xforms/p1transform/EhUpdater.cpp b/builtin_xforms/p1transform/EhUpdater.cpp deleted file mode 100644 index 7bc97f361..000000000 --- a/builtin_xforms/p1transform/EhUpdater.cpp +++ /dev/null @@ -1,195 +0,0 @@ - -#include "EhUpdater.hpp" -#include <string> -#include <map> - -using namespace std; -using namespace IRDB_SDK; - -extern map<Function_t*, set<Instruction_t*> > inserted_instr; //used to undo inserted instructions - - -// see https://en.wikipedia.org/wiki/LEB128 -static bool read_uleb128 - ( uint64_t &result, - uint32_t& position, - const uint8_t* const data, - const uint32_t max) -{ - result = 0; - auto shift = 0; - while( position < max ) - { - auto byte = data[position]; - position++; - result |= ( ( byte & 0x7f ) << shift); - if ( ( byte & 0x80) == 0) - break; - shift += 7; - } - return ( position >= max ); - -} - -static string to_uleb128 (uint64_t value) -{ - auto output_str=string(""); - do - { - auto byte = value&0x7f; // low order 7 bits of value; - value >>= 7; - if (value != 0) // more bytes to come - byte |= 0x80; // set high order bit of byte; - - output_str.push_back(byte); - - } while (value != 0); - - return output_str; -} - -/* transform any eh handling info for the FDE program*/ -bool EhUpdater_t::update_program(EhProgram_t* ehpgm) -{ - assert(ehpgm); - const auto daf=ehpgm->getDataAlignmentFactor(); - const auto saved_reg_size=m_layout->GetSavedRegsSize(); - const auto orig_frame_size=m_layout->GetOriginalAllocSize(); - const auto altered_frame_size=m_layout->GetAlteredAllocSize(); - - /* change the offset, as needed, in a dwarf instruction. the offset is at location 'pos' */ - const auto change_offset=[&](string &dwarf_insn, const uint32_t offset_pos, const bool factored) -> void - { - /* handle */ - /* format: [(char)(opcode+reg#)] [(uleb128) offset/data_alignment_factor] */ - /* we need to adjust factored offset if it's greater than the saved reg size */ - auto factored_offset=uint64_t(0); - auto pos_to_read=(uint32_t)1; - const auto data=reinterpret_cast<const uint8_t*>(dwarf_insn.data()); - const auto res=read_uleb128(factored_offset,pos_to_read,data, dwarf_insn.size()); - assert(res); - auto offset=factored_offset; - if(factored) - offset*=daf; - if(offset>saved_reg_size) - { - const auto new_offset=offset+(altered_frame_size-orig_frame_size); - auto factored_new_offset=new_offset; - if(factored) - factored_new_offset/=daf; - - const auto encoded_factored_new_offset=to_uleb128(factored_new_offset); - auto new_dwarf_insn=string(""); - for(auto i=0U;i<offset_pos;i++) - new_dwarf_insn.push_back(dwarf_insn[i]); - new_dwarf_insn+=encoded_factored_new_offset; - dwarf_insn=new_dwarf_insn; - } - }; - auto tmppgm = ehpgm->getFDEProgram(); - for(auto &dwarf_insn : tmppgm) - { - auto opcode=dwarf_insn[0]; - auto opcode_upper2=(uint8_t)(opcode >> 6); - auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - switch(opcode_upper2) - { - /* case DW_CFA_offset: */ - /* reg should be restored from CFA+(offset*daf) */ - case 0x2: /* DW_CFA_offset: */ - { - change_offset(dwarf_insn,1, true); - break; - }; - case 0: - { - switch(opcode_lower6) - { - /* sanitize */ - case 0xd: /* DW_CFA_def_cfa_register: */ - { - /* [ (char)opcode ] [ (uleb)register ] */ - /* assert if register != sp (if bp not used) or bp (if bp is used) */ - /* never update this insn */ - assert(0); - } - /* handle */ - case 0xe: /* DW_CFA_def_cfa_offset: */ - { - /* [(char)opcode] [(uleb)offset] */ - /* if offset > saved reg size, new_offset=offset+(new_frame_size-old_frame_size) */ - change_offset(dwarf_insn,1,false); - break; - } - case 0x11: /*DW_CFA_def_cfa_offset_sf: */ - { - /* [(char)opcode] [(sleb)offset/data_alignment_factor] */ - /* if offset > saved reg size, new_offset=offset+(new_frame_size-old_frame_size) */ - assert(0); - } - - case 0x5: /*DW_CFA_offset_extended: */ - { - /* [ (char)opcode ] [ (uleb)reg # ] [ (uleb) offset] */ - /* we need to adjust factored offset if it's greater than the saved reg size */ - change_offset(dwarf_insn,2,true); - break; - } - - default: - break; - } - } - default: - break; - } - } - ehpgm->setFDEProgram(tmppgm); - return true; -} - -/* transform any eh handling info for the instruction */ -bool EhUpdater_t::update_instructions(Instruction_t* insn) -{ - const auto ehpgm=insn->getEhProgram(); - - /* no program == no update */ - if(ehpgm==NULL) - return true; - - const auto new_eh_pgm=m_firp->copyEhProgram(*ehpgm); - // const auto new_eh_pgm=new EhProgram_t(*ehpgm); - // m_firp->GetAllEhPrograms().insert(new_eh_pgm); - insn->setEhProgram(new_eh_pgm); - - return update_program(new_eh_pgm); -} - -/* transform any eh handling info for each instruction */ -bool EhUpdater_t::update_instructions() -{ - // for all instructions in the fuunction. - for(const auto& i: m_func->getInstructions()) - update_instructions(i); - // plus any instructions we allocated for the function -// inserted instrucctions are now part of m_func->getInstructions() -- were we updating this frame twice? -// for(const auto& i: inserted_instr[m_func]) -// update_instructions(i); - - return true; -} - - -/* transform any eh handling info for the function */ -bool EhUpdater_t::execute() -{ - if(m_func->getUseFramePointer()) /* no updates needed if a frame pointer is used */ - return true; - - /* can only update for p1 functions */ - if( ! m_layout->IsP1() ) - return false; - - return update_instructions(); -} - diff --git a/builtin_xforms/p1transform/EhUpdater.hpp b/builtin_xforms/p1transform/EhUpdater.hpp deleted file mode 100644 index cfd7b520b..000000000 --- a/builtin_xforms/p1transform/EhUpdater.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EhUpdater -#define EhUpdater - -#include <irdb-core> -#include "PNStackLayout.hpp" - -class EhUpdater_t -{ - public: - - EhUpdater_t(IRDB_SDK::FileIR_t* p_firp, IRDB_SDK::Function_t* p_func, PNStackLayout* p_layout) - : - m_firp(p_firp), - m_func(p_func), - m_layout(p_layout) - { - } - - bool execute(); - - private: - - bool update_instructions(); - bool update_instructions(IRDB_SDK::Instruction_t* insn); - bool update_program(IRDB_SDK::EhProgram_t* ehpgm); - - - IRDB_SDK::FileIR_t* m_firp; - IRDB_SDK::Function_t* m_func; - PNStackLayout* m_layout; -}; - -#endif diff --git a/builtin_xforms/p1transform/General_Utility.cpp b/builtin_xforms/p1transform/General_Utility.cpp deleted file mode 100644 index a344f1a23..000000000 --- a/builtin_xforms/p1transform/General_Utility.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "General_Utility.hpp" -#include <limits.h> -#include <cstdlib> -#include <cerrno> - -using namespace std; - -STR2NUM_ERROR str2int (int &i, char const *s, int base) -{ - char *end; - long l; - errno = 0; - l = strtol(s, &end, base); - if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) { - return STR2_OVERFLOW; - } - if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) { - return STR2_UNDERFLOW; - } - if (*s == '\0' || *end != '\0') { - return STR2_INCONVERTIBLE; - } - i = l; - return STR2_SUCCESS; -} - -//TODO: what if the string represents a negative number? Currently -//the number will be translated into an unsigned int. I could make this -//and incovertible situation. -STR2NUM_ERROR str2uint (unsigned int &i, char const *s, int base) -{ - char *end; - unsigned long l; - errno = 0; - l = strtoul(s, &end, base); - if ((errno == ERANGE && l == ULONG_MAX) || l > UINT_MAX) { - return STR2_OVERFLOW; - } - if (*s == '\0' || *end != '\0') { - return STR2_INCONVERTIBLE; - } - i = l; - return STR2_SUCCESS; -} diff --git a/builtin_xforms/p1transform/General_Utility.hpp b/builtin_xforms/p1transform/General_Utility.hpp deleted file mode 100644 index d03d12f37..000000000 --- a/builtin_xforms/p1transform/General_Utility.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef _GENERAL_UTILITY -#define _GENERAL_UTILITY - -enum STR2NUM_ERROR { STR2_SUCCESS, STR2_OVERFLOW, STR2_UNDERFLOW, STR2_INCONVERTIBLE }; -STR2NUM_ERROR str2int (int &i, char const *s, int base = 0); -STR2NUM_ERROR str2uint (unsigned int &i, char const *s, int base = 0); - -#endif diff --git a/builtin_xforms/p1transform/OffsetInference.cpp b/builtin_xforms/p1transform/OffsetInference.cpp deleted file mode 100644 index 36480114c..000000000 --- a/builtin_xforms/p1transform/OffsetInference.cpp +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "OffsetInference.hpp" -#include "General_Utility.hpp" -//#include "beaengine/BeaEngine.h" -#include <cassert> -#include <iostream> -#include <cstdlib> -#include <set> -#include <fstream> -#include "globals.h" - -using namespace std; -using namespace IRDB_SDK; - -static Relocation_t* FindRelocation(Instruction_t* insn, string type) -{ - RelocationSet_t::iterator rit; - for( rit=insn->getRelocations().begin(); rit!=insn->getRelocations().end(); ++rit) - { - Relocation_t& reloc=*(*rit); - if(reloc.getType()==type) - { - return &reloc; - } - } - return NULL; -} - - -extern int get_saved_reg_size(); - -//TODO: Use cfg entry point only, then use func instructions, - -//TODO: matching reg expressions use max match constant - -//TODO: negative offsets? - -//TODO: what if func is null? - -//TODO: everying operates on regex because when I first wrote this, I didn't -//know DISASM had much of this information. We should migrate to using -//this struct more. That goes for the entire PN code base as well. - -//TODO: The inferences generated are highly conservative in what functions -//are considered transformable. Look at how the dealloc_flag and alloc_count - -OffsetInference::~OffsetInference() -{ - //It is assumed that all pointers in the maps are unique - //this is supposed to be guaranteed by the mechanisms of this - //object - //TODO: add some asserts to ensure no double delete - - map<Function_t*,PNStackLayout*>::iterator it; - - for(it=direct.begin();it !=direct.end();it++) - { - delete (*it).second; - } - - for(it=scaled.begin();it !=scaled.end();it++) - { - delete (*it).second; - } - - for(it=all_offsets.begin();it !=all_offsets.end();it++) - { - delete (*it).second; - } -} - -/* - void OffsetInference::getInstructions(vector<Instruction_t*> &instructions,libIRDB::BasicBlock_t *block,set<libIRDB::BasicBlock_t*> &block_set) - { - instructions.insert(instructions.end(),block->getInstructions().begin(),block->getInstructions().end()); - block_set.insert(block); - - // cerr<<"OffsetInference: getInstructions(): predecessors = "<<block->GetPredecessors().size()<<" successors = "<<block->GetSuccessors().size()<<endl; - - for( - set<libIRDB::BasicBlock_t*>::const_iterator it = block->GetSuccessors().begin(); - it != block->GetSuccessors().end(); - ++it - ) - { - if(block_set.find(*it) == block_set.end()) - getInstructions(instructions,*it,block_set); - } - - for( - set<libIRDB::BasicBlock_t*>::const_iterator it = block->GetPredecessors().begin(); - it != block->GetPredecessors().end(); - ++it - ) - { - if(block_set.find(*it) == block_set.end()) - getInstructions(instructions,*it,block_set); - } - } -*/ - -StackLayout* OffsetInference::SetupLayout(Function_t *func) -{ - unsigned int stack_frame_size = 0; - int saved_regs_size = 0; - int out_args_size = func->getOutArgsRegionSize(); - bool push_frame_pointer = false; - bool save_frame_pointer = false; - - Instruction_t *entry = func->getEntryPoint(); - - if(pn_regex==NULL) - pn_regex=new PNRegularExpressions; - - // bool has_frame_pointer = false; - - int max = PNRegularExpressions::MAX_MATCHES; -// regmatch_t pmatch[max]; -// regmatch_t *pmatch=(regmatch_t*)malloc(max*sizeof(regmatch_t)); - regmatch_t *pmatch=new regmatch_t[max]; - memset(pmatch, 0,sizeof(regmatch_t) * max); - - assert(out_args_size >=0); - - //TODO: find the fallthrough of the entry block, and loop to it if necessary. - -/* - for( - vector<Instruction_t*>::const_iterator it=entry->getInstructions().begin(); - it!=entry->getInstructions().end(); - ++it - ) -*/ - string disasm_str; - //loop through fallthroughs of the entry (entry will be update on every iteration) - //until entry is null, or entry has left the function. - while(entry != NULL && (entry->getFunction()==func)) - { - - in_prologue[entry]=true; - string matched; - - //Instruction_t* instr=*it; - Instruction_t* instr = entry; - - const auto disasmp=DecodedInstruction_t::factory(instr); - const auto &disasm=*disasmp; - disasm_str = disasm.getDisassembly(); // CompleteInstr; - - if(verbose_log) - cerr << "OffsetInference: SetupLayout(): disassembled line = "<<disasm_str<< endl; - - //TODO: find push ebp, then count pushes to sub esp, stack alloc size and pushed size are fed to layout objects - //TODO: for now I assume all pushes are 32 bits, is this a correct assumption? - if(regexec(&(pn_regex->regex_push_ebp), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr << "OffsetInference: SetupLayout(): Push EBP Found"<<endl; - - push_frame_pointer = true; - - if(stack_frame_size != 0) - { - //TODO: handle this better - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Stack Frame Already Allocated, Ignoring Push EBP"<<endl; - - entry = entry->getFallthrough(); - continue; - } - -//TODO: ignoring this code for now, although it appears this code no longer -//makes sense anyway. Don't reset the saved regs if yous ee another push ebp -//just ignore it for now. EBP is usually pushed first, if it isn't -//it is likely not going to be used as a base pointer, in which case I really -//don't want to reset the saved regs count anyway. If it is a base pointer -//and pushed other than first, then I don't know how this func will work -//anyway. - -// else -// { -// saved_regs_size = 0; -// } - } - else if(regexec(&(pn_regex->regex_save_fp), disasm_str.c_str(), max, pmatch, 0)==0) - { - save_frame_pointer = true; - } - else if(regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Push (anything) Found"<<endl; - - if(stack_frame_size != 0) - { - //TODO: handle this better - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Stack Frame Already Allocated, Ignoring Push Instruction"<<endl; - - entry = entry->getFallthrough(); - continue; - } - -// cerr<<"PUSH FOUND: "<<disasm.CompleteInstr<<endl; -// cerr<<"PUSH Argument1: "<<hex<<(disasm.Argument1.ArgType & 0xF0000000)<<endl; -// cerr<<"PUSH Argument2: "<<hex<<(disasm.Argument2.ArgType & 0xF0000000)<<endl; - // cerr<<"CONST_TYPE = "<<hex<<CONSTANT_TYPE<<endl; - - //if the push is a constant, then check if the next instruction - //is an unconditional jmp, if so, ignore the push, assume - //the push is part of fixed calls. - if(disasm.getOperand(0)->isConstant() ) - { - //Grab the pushed value - assert(pmatch[1].rm_so >=0 && pmatch[1].rm_eo >=0); - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - //cerr<<"DEBUG DEBUG: Disasm match: "<<disasm.CompleteInstr<<endl; - -// if((it+1) != entry->getInstructions().end()) - if(entry->getFallthrough() != NULL) - { - Instruction_t* next = entry->getFallthrough(); - const auto next_disasmp=DecodedInstruction_t::factory(next); - const auto &next_disasm=*next_disasmp; - - //cerr<<"DEBUG DEBUG: Disasm next match: "<<next_disasm.CompleteInstr<<endl; - - if(next_disasm.isUnconditionalBranch() /*Instruction.BranchType == JmpType*/) - { - - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Found push matching fix calls pattern, ignoring the push (i.e., not recording the bytes pushed)."<<endl; - - - //find the indirect branch target instruction, and reset entry to this instruction, then continue execution of the loop. - - int target_addr_offset; - assert(str2int(target_addr_offset, matched.c_str())==STR2_SUCCESS); - - //TODO: it is better to make a map of ind branch targets, but this efficient enough for now. - - //Setting entry to null is a primitive way of checking if the target is in the same function - //if it isn't, entry will be NULL at the end of the loop. - auto found_reloc=false; - for(RelocationSet_t::iterator rit=instr->getRelocations().begin(); - rit!=instr->getRelocations().end(); - ++rit) - { - Relocation_t* reloc=*rit; - if(reloc->getType()==string("32-bit") || reloc->getType()==string("push64")) - { - found_reloc=true; - if(reloc->getWRT()==NULL) - { - break; - } - else - { - // getWRT returns an BaseObj, but this reloc type expects an instruction - // safe cast and check. - Instruction_t* wrt_insn=dynamic_cast<Instruction_t*>(reloc->getWRT()); - assert(wrt_insn); - if(wrt_insn->getFunction() == func) - { - entry = wrt_insn; - break; - } - } - } - } - - if(found_reloc) - { - entry=NULL; - for( - set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it - ) - { - Instruction_t *cur = *it; - - if(cur->getIndirectBranchTargetAddress() == NULL) - continue; - - int cur_ibta = (int)cur->getIndirectBranchTargetAddress()->getVirtualOffset(); - - //The target instruction is found, set entry to point to this instruction - //continue analysis from this instruction. - if(cur_ibta == target_addr_offset) - { - entry = cur; - break; - } - } - continue; - - } - } - } - } - //else the push value is registered - - //TODO: assuming 4 bytes here for saved regs - saved_regs_size += get_saved_reg_size(); - } - else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr << "OffsetInference: FindAllOffsets(): Found Stack Alloc"<<endl; - - //TODO: Is this the way this situation should be handled? - //The first esp sub instruction is considered the stack allocation, all other subs are ignored - //Given that I return when the first one is found, this is probably a useless check. - if(stack_frame_size != 0) - { - if(verbose_log) - cerr <<"OffsetInference: FindAllOffsets(): Stack Alloc Previously Found, Ignoring Instruction"<<endl; - - entry = entry->getFallthrough(); - continue; - } - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - //stack_frame_size = strtol(matched.c_str(),NULL,0); - if(str2uint(stack_frame_size, matched.c_str())!= STR2_SUCCESS) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //TODO: is this what I really want to do? - if(verbose_log) - cerr<<"OffsetInference: LayoutSetup(): Found non-integral stack allocation ("<<matched<<") before integral stack allocation, generating a null layout inference for function "<<func->getName()<<endl; - return NULL; - } - - //else - - if(verbose_log) - cerr<<"OffsetInference: LayoutSetup(): Stack alloc Size = "<<stack_frame_size<< - " Saved Regs Size = "<<saved_regs_size<<" out args size = "<<out_args_size<<endl; - - //TODO: with the new code for determine if a frame pointer exists - //I don't consider the case where the frame poitner is pushed but - //ebp is not setup like a frame pointer. In this case, ebp acts - //like a real general purpose register. - //The hack for now is to check if ebp is pushed, but the frame pointer - //is not saved. In this case, consider ebp as another saved reg - //and add to the save of the saved regs. - //When you fix this, look at PNTransformDriver in the canary_rewrite - //subroutine. You will see a case where there is a check for the frame - //pointer, and an additional 4 bytes is added. This should be removed - //in the future to only use the size of the saved regs, but - //this changes any ebp relative offset calculations to remove 4 bytes. - //Confusing, I know. - if(push_frame_pointer&&!save_frame_pointer) - saved_regs_size +=get_saved_reg_size(); - - //There is now enough information to create the PNStackLayout objects - if((unsigned)stack_frame_size<(unsigned)out_args_size) // what? - { - cerr<<"****************************************************************"<<endl; - cerr<<"****************************************************************"<<endl; - cerr<<"**Insanity coming from STARS, out_args_size > stack_frame_size**"<<endl; - cerr<<"****************************************************************"<<endl; - cerr<<"****************************************************************"<<endl; - return NULL; - } - return new StackLayout("All Offset Layout",func->getName(),stack_frame_size,saved_regs_size,(push_frame_pointer&&save_frame_pointer),out_args_size); - - } - } - entry = entry->getFallthrough(); - } - - return NULL; -} - -// Should we punt on the P1 transform when we see lea reg,[rsp+k] where -// the offset k takes us above the local stack frame, into saved regs or inargs -// or the return address? It is often the case that the address is used as a -// loop sentinel and no memory access occurs there, but failing to take into -// account the padding that gets inserted below that address causes problems. -// More precise analyses from STARS could be used to avoid punting on P1 altogether, -// but not many functions are affected in the typical binary. -#define PN_PUNT_ON_LEA_RSP_ABOVE_STACK_FRAME 1 - -//TODO: what about moving esp into a register? - -//TODO: Try catches for exceptions thrown by PNStackLayout, for now asserts will fail in PNStackLayout -void OffsetInference::FindAllOffsets(Function_t *func) -{ - StackLayout *pn_all_offsets = NULL; - StackLayout *pn_direct_offsets = NULL; - StackLayout *pn_scaled_offsets = NULL; - StackLayout *pn_p1_offsets = NULL; - - int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch = new regmatch_t[max]; - assert(pmatch); - memset(pmatch, 0, sizeof(regmatch_t) * max); - unsigned int stack_frame_size = 0; - unsigned int saved_regs_size = 0; - int ret_cnt = 0; - bool lea_sanitize = false; - - //TODO: hack for T&E to make inferences more conservative - bool dealloc_flag = false; - bool has_frame_pointer = false; - int alloc_count = 0; - - //TODO: a hack for when ebp is used as an index. If found - //only p1 should be attempted. - bool PN_safe = true; - - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): Looking at Function = " << func->getName() << endl; - -// libIRDB::ControlFlowGraph_t cfg(func); - -// libIRDB::BasicBlock_t *block = cfg.getEntry(); - - //TODO: this is an addition for TNE to detect direct recursion, - //in the future the call graph should be analyzed to find all recursion. -// Instruction_t *first_instr = *(block->getInstructions().begin()); - - Instruction_t *first_instr = func->getEntryPoint(); - -// pn_all_offsets = SetupLayout(block,func); - pn_all_offsets = SetupLayout(func); - - int out_args_size = func->getOutArgsRegionSize(); - if (pn_all_offsets != NULL) - { - stack_frame_size = pn_all_offsets->GetAllocSize(); - saved_regs_size = pn_all_offsets->GetSavedRegsSize(); - has_frame_pointer = pn_all_offsets->HasFramePointer(); - assert(out_args_size >= 0); - - pn_direct_offsets = new StackLayout("Direct Offset Inference", func->getName(), stack_frame_size, saved_regs_size, has_frame_pointer, out_args_size); - pn_scaled_offsets = new StackLayout("Scaled Offset Inference", func->getName(), stack_frame_size, saved_regs_size, has_frame_pointer, out_args_size); - //do not consider out args for p1 - pn_p1_offsets = new StackLayout("P1 Offset Inference", func->getName(), stack_frame_size, saved_regs_size, has_frame_pointer, 0); - } - else - { - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; - } - - //Just checking that the entry point has no predecessors - //assert(block->GetPredecessors().size() !=0); -#if 0 - //put all instructions into one vector - vector<Instruction_t*> instructions; - set<libIRDB::BasicBlock_t*> block_set; - - getInstructions(instructions,block,block_set); - if(instructions.size() != func->getInstructions().size()) - { - cerr<<"OffsetInference: FindAllOffsets(): Number of CFG found instructions does not equal Function_t found instructions"<<endl; - } - - //Checking that getInstructions hasn't screwed up - assert(instructions.size() != 0); -#endif - -//TODO: should I start modifying at the entry point? - for( - set<Instruction_t*>::const_iterator it = func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it - ) - { - string matched; - - Instruction_t* instr = *it; - DatabaseID_t InstID = instr->getBaseID(); - string disasm_str; - - const auto disasmp = DecodedInstruction_t::factory(instr); - const auto &disasm = *disasmp; - disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): ID =" << InstID << " disassembled line = " << disasm_str << endl; - -#if 0 -//TODO: find push ebp, then count pushes to sub esp, stack alloc size and pushed size are fed to layout objects -//TODO: for now I assume all pushes are 32 bits, is this a correct assumption? -if(regexec(&(pn_regex->regex_push_ebp), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr << "OffsetInference: FindAllOffsets(): Push EBP Found"<<endl; - -if(stack_frame_size != 0) -{ -//TODO: handle this better -cerr<<"OffsetInference: FindAllOffsets(): Stack Frame Already Allocated, Ignoring Push EBP"<<endl; -continue; -} -else -{ -saved_regs_size = 0; -} -} -else if(regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr<<"OffsetInference: FindAllOffsets(): Push (anything) Found"<<endl; - -if(stack_frame_size != 0) -{ -//TODO: handle this better -cerr<<"OffsetInference: FindAllOffsets(): Stack Frame Already Allocated, Ignoring Push Instruction"<<endl; -continue; -} -else -{ -//TODO: assuming 4 bytes here for saved regs -saved_regs_size += get_saved_reg_size(); -} -} -else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr << "OffsetInference: FindAllOffsets(): Found Stack Alloc"<<endl; - -//TODO: Is this the way this situation should be handled? -//The first esp sub instruction is considered the stack allocation, all other subs are ignored -if(stack_frame_size != 0) -{ -cerr <<"OffsetInference: FindAllOffsets(): Stack Alloc Previously Found, Ignoring Instruction"<<endl; -continue; -} - - -//extract K from: sub esp, K -if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) -{ -int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; -matched = disasm_str.substr(pmatch[1].rm_so,mlen); -//extract K -stack_frame_size = strtol(matched.c_str(),NULL,0); - -cerr<<"OffsetInference: FindAllOffsets(): Stack alloc Size = "<<stack_frame_size<< -" Saved Regs Size = "<<saved_regs_size<<" out args size = "<<out_args_size<<endl; - -//There is now enough information to create the PNStackLayout objects -pn_all_offsets = new PNStackLayout("All Offset Layout",func->getName(),stack_frame_size,saved_regs_size,out_args_size); -pn_direct_offsets = new PNStackLayout("Direct Offset Layout",func->getName(),stack_frame_size,saved_regs_size,out_args_size); -pn_scaled_offsets = new PNStackLayout("Scaled Offset Layout", func->getName(),stack_frame_size,saved_regs_size,out_args_size); -pn_p1_offsets = new PNStackLayout("P1 Layout",func->getName(),stack_frame_size,saved_regs_size,out_args_size); -} -} -else -#endif - - if (regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0) == 0) - { - Instruction_t* ft = instr->getFallthrough(); - const auto reloc1 = FindRelocation(instr, "32-bit"); - const auto reloc2 = FindRelocation(instr, "push64"); - - if (reloc1 != NULL || reloc2 != NULL) - { - /* definite a push from a fixed calls */ - } - else if (ft && !ft->getFallthrough() && - (ft->getTarget() == NULL || ft->getTarget()->getFunction() != instr->getFunction())) - { - /* probably a push/jmp converted by fix calls */ - /* can ignore this push */ - } - else if (!in_prologue[instr]) - { - cerr << "Found push instruction not in prologue, marking as not canary safe"; - cerr << "Insn =" << disasm_str << " ID = " << InstID << endl; - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - - } - } // end if push anything - - - /* check for an lea with an rsp in it -- needs to be done before other regex's */ - if (regexec(&(pn_regex->regex_lea_rsp), disasm_str.c_str(), 5, pmatch, 0) == 0) - { - if (verbose_log) - cerr << "OffsetInference: lea_rsp found: ID = " << InstID << endl; - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - if (verbose_log) - cerr << "OffsetInference: lea_rsp found const" << endl; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - // extract displacement - - int offset = disasm.getOperand(1)->getMemoryDisplacement() /*Argument2.Memory.Displacement*/; - if (offset < 0) - { - if (verbose_log) - cerr << "OffsetInference: lea_rsp neg offset sanitize" << endl; - lea_sanitize = true; - } - unsigned int uoffset = (unsigned int) offset; - /* if this lea is pointing to saved regs */ - if (uoffset >= stack_frame_size) - { - if (uoffset < (saved_regs_size + stack_frame_size)) { - if (verbose_log) - cerr << "OffsetInference: lea_rsp found in saved regs area" << endl; - lea_sanitize = true; - } - else { - if (verbose_log) - cerr << "OffsetInference: lea_rsp found above saved regs area BLAH BLAH" << endl; - } -#if PN_PUNT_ON_LEA_RSP_ABOVE_STACK_FRAME - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - cerr << "OffsetInference: lea_rsp above local frame, punting on P1 transform for func " << func->getName() << endl; - return; -#endif - } - else if (verbose_log) { - cerr << "OffsetInference: lea_rsp found in local stack frame" << endl; - } - } - } // end if lea_rsp - - // now, on to doing offset identification - if (regexec(&(pn_regex->regex_stack_dealloc_implicit), disasm_str.c_str(), max, pmatch, 0) == 0) - { - dealloc_flag = true; - //TODO: there needs to be a check of lea esp, [ebp-<const>] to make sure const is not in the current stack frame. - } - else if (regexec(&(pn_regex->regex_ret), disasm_str.c_str(), max, pmatch, 0) == 0) - { - ++ret_cnt; - } - else if(regexec(&(pn_regex->regex_and_esp), disasm_str.c_str(), max, pmatch, 0) == 0) - { - //TODO: decide how to better handle this option. - //Right now I am going to enforce in PNTransformDriver that - //the alignment instruction is removed. - - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): Layout is not canary safe" << endl; - - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - } // end if AND RSP with mask for stack alignment - else if (regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0) == 0) - { - //check if the stack allocation uses an integral offset. - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - // extract K - unsigned int scheck; - if (str2uint(scheck, matched.c_str()) != STR2_SUCCESS) - { - // If this occurs, then the found stack size is not a - // constant integer, so it must be a register. - - // Even though I am specifying only p1 should be performed - // I am still going to set this flag for all transforms. - pn_direct_offsets->SetStaticStack(false); - pn_scaled_offsets->SetStaticStack(false); - pn_all_offsets->SetStaticStack(false); - pn_p1_offsets->SetStaticStack(false); - PN_safe = false; - - // Consider this case not canary safe for now - // TODO: can I make this canary safe? - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - - if (verbose_log) - cerr << "OffsetInference: instruction contains a dynamic stack allocation, not pn_safe" << endl; - - // TODO: this output should be removed after TNE - // Only used to give Jason an indication that a - // non-static func has been detected. - - ofstream dynstackfile; - dynstackfile.open("dynamic_stack.log", fstream::out|fstream::app); - if (dynstackfile.is_open()) - { - // I don't think this can happen, but I really don't want - // to add a null pointer exception to TNE - if (instr == NULL || instr->getAddress() == NULL) - { - dynstackfile<<func->getName() << " : " << disasm_str << endl; - } - else - { - dynstackfile << func->getName() << " : " << hex << instr->getAddress()->getVirtualOffset() << " : " << disasm_str << endl; - } - dynstackfile.close(); - } - continue; - } - } - - ++alloc_count; - if (alloc_count > 1) - { - if (verbose_log) - cerr << "OffsetInference: integral stack allocations exceeded 1, abandon inference" << endl; - break; - } - } // end if stack allocation instruction - - // TODO: hack for TNE 2, if we see a jmp to an esp or ebp relative address, ignore this function entirely - // The reason is fix calls will fix an esp/ebp relative call by adding 4 to the original address and pushing - // before the inserted jmp. This gives the false impression that there is a boundary at this location - // and also gives a false impression that the location should be modified using the wrong boundary, even if - // p1 is used only. Specifically this occurred when the frame size was 0x20, and the call was to esp+0x1c - // the fix call because a jmp esp+0x20 which was outside the frame, and PN corrected by changing the offset - // to reflect the padding. - else if (disasm.isUnconditionalBranch() /*Instruction.BranchType == JmpType*/) - { - if (regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), max, pmatch, 0) == 0 || - regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), max, pmatch, 0) == 0 || - regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), max, pmatch, 0) == 0 || - regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), max, pmatch, 0) == 0) - { - cerr << "OffsetInference: FindAllOffsets(): Layout contains a jmp relative to esp or ebp, ignore function for now" << endl; - - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - - // TODO: cleanup memory, since this is all so ugly at the moment, I'm inclined to leak memory than - // to risk a segfault deleting a pointer. - return; - } - } // end if unconditional branch - else if (regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), max, pmatch, 0) == 0) - { - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): Found ESP Scaled Instruction" << endl; -#if 0 - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -#endif - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - // extract displacement - int offset = strtol(matched.c_str(), NULL, 0); - - if (pn_all_offsets != NULL) - { - pn_all_offsets->InsertESPOffset(offset); - } - if (pn_scaled_offsets != NULL) - { - pn_scaled_offsets->InsertESPOffset(offset); - } - - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): ESP Offset = " << offset << endl; - } - } // end if esp scaled - else if (regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), max, pmatch, 0) == 0) - { - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets: Found ESP Direct Instruction" << endl; -#if 0 - if (stack_frame_size <= 0) - { - cerr << "OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search" << endl; - break; - } -#endif - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - // extract displacement - - int offset = strtol(matched.c_str(), NULL, 0); - - if (pn_all_offsets != NULL) - { - pn_all_offsets->InsertESPOffset(offset); - } - if (pn_direct_offsets != NULL) - { - pn_direct_offsets->InsertESPOffset(offset); - } - - if (verbose_log) - cerr << "OffsetInference: FindAllOffsets(): ESP Offset = " << offset << endl; - } - } // end if esp direct access - else if (regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), max, pmatch, 0) == 0) - { - if (verbose_log) { - cerr << "OffsetInference: FindAllOffsets(): Found EBP Scaled Instruction" << endl; - } -#if 0 - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -#endif - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - - // extract displacement - int offset = strtol(matched.c_str(), NULL, 0); - -#if 0 - if(stack_frame_size - offset < 0) - { - cerr<<"OffsetInference: FindAllOffsets: Detected Negative ESP Offset, Aborting Offset Search"<<endl; - - pn_all_offsets = NULL; - pn_scaled_offsets = NULL; - pn_direct_offsets = NULL; - break; - } -#endif - - if (!has_frame_pointer && verbose_log) { - cerr << "BOGUS processing of EBP offset; not a frame pointer." << endl; - } - if (pn_all_offsets != NULL) - { - pn_all_offsets->InsertEBPOffset(offset); - } - if (pn_scaled_offsets != NULL) - { - pn_scaled_offsets->InsertEBPOffset(offset); - } - } - } // end if ebp scaled - else if(regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), max, pmatch, 0) == 0) - { - if (verbose_log) { - cerr << "OffsetInference: FindAllOffsets(): Found EBP Direct Instruction" << endl; - } -#if 0 - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -#endif - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - - // extract displacement - int offset = strtol(matched.c_str(), NULL, 0); - -#if 0 - if (stack_frame_size - offset < 0) - { - cerr << "OffsetInference: FindAllOffsets: Detected Negative ESP Offset, Aborting Offset Search" << endl; - - pn_all_offsets = NULL; - pn_scaled_offsets = NULL; - pn_direct_offsets = NULL; - break; - } -#endif - if (verbose_log) { - cerr << "OffsetInference: FindAllOffsets(): Extracted EBP offset = " << offset << endl; - if (!has_frame_pointer) { - cerr << "BOGUS processing of EBP offset; not a frame pointer." << endl; - } - } - - if (pn_all_offsets != NULL) - { - pn_all_offsets->InsertEBPOffset(offset); - } - if (pn_direct_offsets != NULL) - { - pn_direct_offsets->InsertEBPOffset(offset); - } - } - } // end if ebp direct - else if(regexec(&(pn_regex->regex_stack_dealloc), disasm_str.c_str(), max, pmatch, 0) == 0) - { - // if we find a dealloc, set a flag indicating as such - dealloc_flag = true; - - //TODO: if the amount to dealloc is not equal to the stack frame size - //exit inference - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so, mlen); - - // extract displacement - int offset = strtol(matched.c_str(), NULL, 0); - - //NOTE: I have seen cases where there is an add esp, 0x0000000 - //in unoptimized code. In this case, the compiler must have - //restored the stack already, ignore the instruction. - - //TODO: casting stack_frame_size, make sure it isn't larger than - //max int, I don't know what to do if I see this. - if(offset != (int)stack_frame_size && offset != 0) - { - if(verbose_log) - cerr<<"OffsetInference: stack deallocation detected with different size of allocation, abandon inference"<<endl; - //dealloc_flag = false; - - //TODO: hacked in for TNE, rewrite. - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; - } - } - - //TODO: this is a hack for cases when ebp is used as an index, - //in these cases, only attempt P1 for now, but in the future - //dynamic checks can be used to determine what object is referred to. - else if(regexec(&(pn_regex->regex_scaled_ebp_index), disasm_str.c_str(), 5, pmatch, 0)==0) - { - PN_safe = false; - if(verbose_log) - cerr<<"OffsetInference: instruction contains an ebp index, not pn_safe"<<endl; - //TODO: at this point I could probably break the loop, - } - //TODO: a hack for TNE to check for direct recursion to dial down padding - else if(regexec(&(pn_regex->regex_call), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(instr->getTarget() != NULL && instr->getTarget()->getAddress() != NULL) - { - if(instr->getTarget()->getAddress()->getVirtualOffset() == first_instr->getAddress()->getVirtualOffset()) - { - if(verbose_log) - cerr<<"OffsetInference: function contains a direct recursive call"<<endl; - - pn_direct_offsets->SetRecursive(true); - pn_scaled_offsets->SetRecursive(true); - pn_all_offsets->SetRecursive(true); - pn_p1_offsets->SetRecursive(true); - } - } - } - - else - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: No Pattern Match"<<endl; - } - } // end for all instructions - -//TODO: everything is horribly hacked and messy, redo this function. - - //if no dealloc is found, set all inferences to null - //TODO: this was hacked together quickly, one flag is preferable. - //TODO: there might be a memory leak here, see the objects deleted - //at the end of this function. - if(alloc_count>1 || lea_sanitize) - { - if(lea_sanitize) - cerr<<"OffsetInference: FindAllOffsets: lea_rsp that points to saved regs found "<<endl; - else if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Multiple integral stack allocations found, returning null inferences"<<endl; - - - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; - - } - else - { - - if(!dealloc_flag && ret_cnt == 0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Function is missing stack deallocaiton, but does not return, assuming transformable"<<endl; - dealloc_flag = true; - } - //TODO: I need to revisit this such that you can pass a pointer to PNStackLayout, - //and handle NULL accordingly. - - //TODO: this has become too hacky, redo. - if(!dealloc_flag) - { - pn_direct_offsets->SetPaddingSafe(false); - pn_scaled_offsets->SetPaddingSafe(false); - pn_all_offsets->SetPaddingSafe(false); - pn_p1_offsets->SetPaddingSafe(false); - } - - unsigned int aoi_size = pn_all_offsets->GetRanges().size(); - //TODO: causes a memory leak since I may reset to NULL, redo - - //if the size of aoi is the same as any other inference - //assume they are the same (insert a null layout entry) - if(pn_direct_offsets->GetRanges().size() != aoi_size) - direct[func] = new PNStackLayout(*pn_direct_offsets, func); - else - direct[func] = NULL; - - if(pn_scaled_offsets->GetRanges().size() != aoi_size) - scaled[func] = new PNStackLayout(*pn_scaled_offsets, func); - else - scaled[func] = NULL; - - //TODO: BIG TODO: There is quite a delema here. If p1 is the same as - //AOI, I don't want to generate it to save time, but what if a function - //has no coverage, so p1 is used, if I set it null here because the - //layouts are the same, I wont have any modification for that function. - p1[func] = new PNStackLayout(*pn_p1_offsets, func); - - all_offsets[func] = new PNStackLayout(*pn_all_offsets, func); - - if(!dealloc_flag) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: No Stack Deallocation Found"<<endl; - if(direct[func] != NULL && !direct[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: direct offset inference cannot be shuffled, generating null inference"<<endl; - direct[func] = NULL; - } - - if(scaled[func] != NULL && !scaled[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: scaled offset inference cannot be shuffled, generating null inference"<<endl; - scaled[func] = NULL; - } - - if(all_offsets[func] != NULL && !all_offsets[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: all offset inference cannot be shuffled, generating null inference"<<endl; - all_offsets[func] = NULL; - } - - p1[func] = NULL; - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: p1 inference by default cannot be shuffled, generating null inference"<<endl; - } - - if(!PN_safe) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Function not pn_safe, using only p1 (p1 may have been previously disabled)"<<endl; - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - } - } - - //memory clean up - delete pn_direct_offsets; - delete pn_scaled_offsets; - delete pn_all_offsets; - delete pn_p1_offsets; -} // end of OffsetInference::FindAllOffsets() - -//If map entry exists, return it, else perform boundary detection -//If no layout can be made, NULL is returned. -PNStackLayout* OffsetInference::GetPNStackLayout(Function_t *func) -{ - return GetLayout(all_offsets,func); -} - -PNStackLayout* OffsetInference::GetDirectAccessLayout(Function_t *func) -{ - return GetLayout(direct,func); -} - -PNStackLayout* OffsetInference::GetScaledAccessLayout(Function_t *func) -{ - return GetLayout(scaled,func); -} - -PNStackLayout* OffsetInference::GetP1AccessLayout(Function_t *func) -{ - return GetLayout(p1,func); -} - - -PNStackLayout* OffsetInference::GetLayout(map<Function_t*,PNStackLayout*> &mymap,Function_t *func) -{ - //No layout found, find all offset boundaries - if (mymap.find(func) == mymap.end()) - { - FindAllOffsets(func); - } - - //At this point an entry should be made for the function - assert(mymap.find(func) != mymap.end()); - - return mymap.find(func)->second; -} - -string OffsetInference::GetInferenceName() const -{ - return "All Offsets Inference"; -} diff --git a/builtin_xforms/p1transform/OffsetInference.hpp b/builtin_xforms/p1transform/OffsetInference.hpp deleted file mode 100644 index 71b2b7480..000000000 --- a/builtin_xforms/p1transform/OffsetInference.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __OFFSETSTACKLAYOUTINFERENCE -#define __OFFSETSTACKLAYOUTINFERENCE -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include <map> -#include <string> - -class OffsetInference : public PNStackLayoutInference -{ - -protected: - std::map<IRDB_SDK::Instruction_t*, bool> in_prologue; - std::map<IRDB_SDK::Function_t*,PNStackLayout*> direct; - std::map<IRDB_SDK::Function_t*,PNStackLayout*> scaled; - std::map<IRDB_SDK::Function_t*,PNStackLayout*> all_offsets; - std::map<IRDB_SDK::Function_t*,PNStackLayout*> p1; - - PNRegularExpressions *pn_regex; - - virtual void FindAllOffsets(IRDB_SDK::Function_t *func); - virtual PNStackLayout* GetLayout(std::map<IRDB_SDK::Function_t*,PNStackLayout*> &mymap, IRDB_SDK::Function_t *func); - // virtual void getInstructions(std::vector<IRDB_SDK::Instruction_t*> &instructions,IRDB_SDK::libIRDB::BasicBlock_t *block,std::set<IRDB_SDK::libIRDB::BasicBlock_t*> &block_set); - virtual StackLayout* SetupLayout(IRDB_SDK::Function_t *func); -public: - OffsetInference() : pn_regex(NULL) {} - virtual ~OffsetInference(); - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func); - virtual PNStackLayout* GetDirectAccessLayout(IRDB_SDK::Function_t *func); - virtual PNStackLayout* GetScaledAccessLayout(IRDB_SDK::Function_t *func); - virtual PNStackLayout* GetP1AccessLayout(IRDB_SDK::Function_t *func); - virtual std::string GetInferenceName() const; -}; - -#endif diff --git a/builtin_xforms/p1transform/P1Inference.cpp b/builtin_xforms/p1transform/P1Inference.cpp deleted file mode 100644 index 1487fddd6..000000000 --- a/builtin_xforms/p1transform/P1Inference.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "P1Inference.hpp" -#include <cstdlib> - -using namespace std; -using namespace IRDB_SDK; - -P1Inference::P1Inference(OffsetInference *offset_inference) -{ - this->offset_inference = offset_inference; -} - - -PNStackLayout* P1Inference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetP1AccessLayout(func); -} - - -std::string P1Inference::GetInferenceName() const -{ - return "P1 Inference"; -} diff --git a/builtin_xforms/p1transform/P1Inference.hpp b/builtin_xforms/p1transform/P1Inference.hpp deleted file mode 100644 index 28bf756ef..000000000 --- a/builtin_xforms/p1transform/P1Inference.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -//TODO: for now we can't trust the DB for the frame size, -//in the future the constructor should be passed the size as found -//by the database - -#ifndef __P1INFERENCE -#define __P1INFERENCE - -#include "PNStackLayoutInference.hpp" -#include "OffsetInference.hpp" - -class P1Inference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - P1Inference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func); - virtual std::string GetInferenceName() const; -}; - -#endif diff --git a/builtin_xforms/p1transform/P1_utility.cpp b/builtin_xforms/p1transform/P1_utility.cpp deleted file mode 100644 index 83d12539c..000000000 --- a/builtin_xforms/p1transform/P1_utility.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "P1_utility.hpp" -using namespace std; -using namespace IRDB_SDK; - -map<Function_t*, set<Instruction_t*> > inserted_instr; //used to undo inserted instructions -map<Function_t*, set<AddressID_t*> > inserted_addr; //used to undo inserted addresses - - -void setExitCode(FileIR_t* virp, Instruction_t* exit_code); - - -Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target) -{ - Instruction_t* newInsn = IRDB_SDK::insertAssemblyBefore(virp, first, assembly, target); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly) -{ - Instruction_t* newInsn = IRDB_SDK::insertAssemblyBefore(virp, first, assembly); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target) -{ - Instruction_t* newInsn = IRDB_SDK::insertAssemblyAfter(virp, first, assembly, target); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly) -{ - Instruction_t* newInsn = IRDB_SDK::insertAssemblyAfter(virp, first, assembly); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) -{ - Instruction_t* newInsn = IRDB_SDK::insertDataBitsAfter(virp, first, dataBits, target); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - -Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) -{ - Instruction_t* newInsn = IRDB_SDK::insertDataBitsBefore(virp, first, dataBits, target); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - -Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits) -{ - Instruction_t* newInsn = IRDB_SDK::insertDataBitsBefore(virp, first, dataBits); - Function_t* func = newInsn->getFunction(); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - -Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID, Function_t* func) -{ - auto newAddr=virp->addNewAddress(virp->getFile()->getBaseID(),0); - auto newInsn=virp->addNewInstruction(newAddr, func); - - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr) -{ - auto fileId=virp->getFile()->getBaseID(); - Function_t* func = template_instr->getFunction(); - auto newInsn=P1_allocateNewInstruction(virp,fileId,func); - inserted_instr[func].insert(newInsn); - inserted_addr[func].insert(newInsn->getAddress()); - return newInsn; -} - - -void P1_setInstructionAssembly(FileIR_t* virp,Instruction_t *p_instr, string p_assembly, Instruction_t *p_fallThrough, Instruction_t *p_target) -{ - IRDB_SDK::setInstructionAssembly(virp, p_instr, p_assembly, p_fallThrough, p_target); -} - - -string getRetDataBits() -{ - string dataBits; - dataBits.resize(1); - dataBits[0] = 0xc3; - return dataBits; -} - -string getJumpDataBits() -{ - string dataBits; - dataBits.resize(5); - dataBits[0] = 0xe9; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[2] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[3] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[4] = 0x00; // value doesn't matter -- we will fill it in later - return dataBits; -} - -// jns - jump not signed -string getJnsDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x79; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - return dataBits; -} - -// jz - jump zero -string getJzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x74; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -// jnz - jump not zero -string getJnzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x75; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -// jecxz - jump ecx zero -string getJecxzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0xe3; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exit_code) -{ - auto handler_code=(Instruction_t *)nullptr; - static auto breadcrumb=(DataScoop_t *)nullptr; - - - if (policy == P_CONTROLLED_EXIT) - { - const auto exit_code_str = virp->getArchitectureBitWidth()==64 ? - "mov rdi, " + std::to_string(exit_code) : - "mov ebx, " + std::to_string(exit_code); - - handler_code = P1_allocateNewInstruction(virp,fallthrough); - - P1_setInstructionAssembly(virp,handler_code,exit_code_str.c_str(), NULL,NULL); - auto syscall_num = virp->getArchitectureBitWidth()==64 ? - P1_insertAssemblyAfter(virp,handler_code,"mov rax, 60",NULL): - P1_insertAssemblyAfter(virp,handler_code,"mov eax, 1",NULL); - auto syscall_i = P1_insertAssemblyAfter(virp,syscall_num,"syscall",NULL); - syscall_i->setFallthrough(fallthrough); - } - else if (policy == P_HARD_EXIT) - { - handler_code = P1_allocateNewInstruction(virp,fallthrough); - P1_setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL); - handler_code->setComment("hlt ; hard exit requested"); - handler_code->setFallthrough(fallthrough); - } - else - { - handler_code= P1_allocateNewInstruction(virp,fallthrough); - P1_setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL); - handler_code->setComment("hlt ; Make this into a callback: jdh@getHandlerCode"); - handler_code->setFallthrough(fallthrough); - } - - - // now that we've created some handler code, pre-pend the breadcrumbs as necessary - if(pn_options->getDoBreadcrumbs()) - { - if(breadcrumb == nullptr) - { - auto sa=virp->addNewAddress(fallthrough->getAddress()->getFileID(), 0); - auto ea=virp->addNewAddress(fallthrough->getAddress()->getFileID(), 7); - auto contents=string(8,'\xff'); - breadcrumb=virp->addNewDataScoop("p1_breadcrumb", sa, ea, nullptr, 6, false, contents ); - } - - const auto func_id = fallthrough->getFunction()->getBaseID(); - auto new_insn_bits_start = string{0x48, (char)0xc7, 0x05, (char)0xf5, (char)0xff, (char)0xff, (char)0xff}; - auto new_insn_bits = new_insn_bits_start + string(reinterpret_cast<const char*>(&func_id), 4); - - // note: updates handler_code to be the newly inserted instruction - P1_insertDataBitsBefore(virp, handler_code, new_insn_bits); - - // add a pcrel reloc to the breadcrumb instruction, and link it to the breadcrumb scoop - (void)virp->addNewRelocation(handler_code, 0, "pcrel", breadcrumb); - - } - - /* note: may be breadcrumb code */ - return handler_code; -} - -Instruction_t* insertCanaryCheckBefore(FileIR_t* virp,Instruction_t *first, unsigned int canary_val, int esp_offset, Instruction_t *fail_code) -{ - auto do_zero=(first->getDisassembly().find("ret")!=string::npos); - stringstream ss; - const char *sp_reg="esp"; - if(virp->getArchitectureBitWidth()==64) - sp_reg="rsp"; - - ss<<"cmp dword ["<<sp_reg; - - bool esp_neg=false; - if(esp_offset <0) - { - ss<<"-"; - esp_offset = esp_offset*-1; - esp_neg=true; - } - else - ss<<"+"; - - ss<<"0x"<<hex<<esp_offset<<"], 0x"<<hex<<canary_val; - - //Insert the cmp before - Instruction_t* next = P1_insertAssemblyBefore(virp,first,ss.str()); - - //Then insert the jmp after the compare. - //The fallthrough of the inserted jmp will be a copy of the original - //instruction, still pointed to by "first". - P1_insertDataBitsAfter(virp,first,getJnzDataBits(),fail_code); - first->setComment("Canary Check: "+first->getComment()); - - //TODO: move canary zero to option - if(esp_neg) - esp_offset *= -1; - - if(do_zero) - insertCanaryZeroAfter(virp,first,esp_offset,fail_code); - - return next; - -} - -Instruction_t* insertCanaryZeroAfter(FileIR_t* virp, Instruction_t *first, int esp_offset, Instruction_t *fail_code) -{ - stringstream ss; - const char *sp_reg="esp"; - if(virp->getArchitectureBitWidth()==64) - { - sp_reg="rsp"; - ss<<"mov qword ["<<sp_reg; // clear all 64-bits - } - else - { - ss<<"mov dword ["<<sp_reg; - } - - if(esp_offset <0) - { - ss<<"-"; - esp_offset = esp_offset*-1; - } - else - ss<<"+"; - - ss<<"0x"<<hex<<esp_offset<<"], 0x0"; - - //Insert the cmp before - Instruction_t* next = P1_insertAssemblyAfter(virp,first,ss.str()); - first->setComment("Canary Zero: "+first->getComment()); - - return next; -} - -Relocation_t* createNewRelocation(FileIR_t* firp, Instruction_t* insn, string type, int offset) -{ - /* - Relocation_t* reloc=new Relocation_t; - insn->getRelocations().insert(reloc); - firp->getRelocations().insert(reloc); - - reloc->SetType(type); - reloc->SetOffset(offset); - */ - auto reloc=firp->addNewRelocation(insn,offset,type); - - return reloc; -} - diff --git a/builtin_xforms/p1transform/P1_utility.hpp b/builtin_xforms/p1transform/P1_utility.hpp deleted file mode 100644 index a9158f140..000000000 --- a/builtin_xforms/p1transform/P1_utility.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <irdb-core> -#include <irdb-transform> -#include "globals.h" - -using namespace IRDB_SDK; -using namespace std; - - -Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); -Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly); -Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); -Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly); -Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); -Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits); -Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); -Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits); -Instruction_t* P1_copyInstruction(Instruction_t* instr); -void P1_copyInstruction(Instruction_t* src, Instruction_t* dest); -Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID,Function_t* func); -Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr); -void P1_setInstructionAssembly(FileIR_t* virp,Instruction_t *p_instr, string p_assembly, Instruction_t *p_fallThrough, Instruction_t *p_target); - - -string getJumpDataBits(); -string getJnsDataBits(); -string getJzDataBits(); -string getJnzDataBits(); -string getJecxzDataBits(); -string getRetDataBits(); -Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exitcode ); - -//The esp offset is allowed to be negative, and is handled properly. -//Returns the pointer for the copied "first" instruction, which is at the -//end of the canary check block of instructions. -Instruction_t* insertCanaryCheckBefore(FileIR_t* virp,Instruction_t *first, unsigned int canary_val, int ret_offset, Instruction_t *fail_code); -Instruction_t* insertCanaryZeroAfter(FileIR_t* virp, Instruction_t *first, int esp_offset, Instruction_t *fail_code); - -Relocation_t* createNewRelocation(FileIR_t* firp, Instruction_t* insn, string type, int offset); - - - diff --git a/builtin_xforms/p1transform/PNIrdbManager.cpp b/builtin_xforms/p1transform/PNIrdbManager.cpp deleted file mode 100644 index 1e17b9a67..000000000 --- a/builtin_xforms/p1transform/PNIrdbManager.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "PNIrdbManager.hpp" - -#include <stdlib.h> -#include <set> -#include <algorithm> - -PNIrdbManager::PNIrdbManager(IRDB_SDK::DatabaseID_t variant_db_id) -{ - // look up this variant ID - m_variant_id = IRDB_SDK::VariantID_t::factory(variant_db_id); - assert(m_variant_id != NULL); - - // maintain a mapping of function name to Function_t object - m_file_ir = IRDB_SDK::FileIR_t::factory(m_variant_id.get()); - std::set<IRDB_SDK::Function_t*> function_set = m_file_ir->getFunctions(); - for (std::set<IRDB_SDK::Function_t*>::const_iterator it = function_set.begin(); - it != function_set.end(); it++) - { - m_function_map[(*it)->getName()] = *it; - } - - // create new table name (lowercase) - assert(!m_variant_id->getName().empty()); - m_table_name = m_variant_id->getName() + "_stack"; - std::transform(m_table_name.begin(), - m_table_name.end(), - m_table_name.begin(), - ::tolower); -} - -PNIrdbManager::~PNIrdbManager() -{ - // handled by unique_ptr - //delete m_file_ir; - //delete m_variant_id; -} - -void -PNIrdbManager::CreateTable() -{ -#if 1 - assert(0); // depreciated -#else - std::stringstream query; - query << "CREATE TABLE " << m_table_name << " (" - << "stack_id SERIAL PRIMARY KEY, " - << "source_id INTEGER, " - << "esp_offset INTEGER, " - << "size INTEGER, " - << "function_id INTEGER, " - << "instruction_id INTEGER DEFAULT (-1), " - << "range_start_address_id INTEGER DEFAULT (-1)," - << "range_end_address_id INTEGER DEFAULT (-1)," - << "doip INTEGER DEFAULT (-1)" - << ");"; - - IRDB_SDK::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -#endif - -} - -bool -PNIrdbManager::TableExists() -{ -#if 1 - assert(0); // depreciated -#else - // using pg_tables is Postgresql-specific - std::stringstream query; - query << "SELECT COUNT(tablename) FROM pg_tables WHERE " - << "tablename='" << m_table_name << "';"; - - IRDB_SDK::pqxxDB_t transaction; - transaction.IssueQuery(query); - assert(!transaction.IsDone()); - int table_count = atoi(transaction.GetResultColumn("count").c_str()); - return table_count > 0; -#endif -} - - -void -PNIrdbManager::ClearTable() -{ -#if 1 - assert(0); // depreciated -#else - std::stringstream query; - query << "TRUNCATE TABLE " << m_table_name << " CASCADE;"; - - IRDB_SDK::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -#endif -} - -void PNIrdbManager::DeleteSource(IRSource source) -{ -#if 1 - assert(0); // depreciated -#else - std::stringstream query; - query << "DELETE FROM " << m_table_name << " WHERE source_id=" << source - << ";"; - - IRDB_SDK::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -#endif -} - -IRDB_SDK::DatabaseID_t PNIrdbManager::InsertStackObject( - std::string function_name, - int offset, - unsigned int size, - IRSource source) -{ -#if 1 - assert(0); // depreciated -#else - assert(m_function_map.find(function_name) != m_function_map.end()); - IRDB_SDK::Function_t * func = m_function_map[function_name]; -std::cout << "IRDB: function name: " << function_name << ", ID: " << func->getBaseID(); - IRDB_SDK::pqxxDB_t transaction; - std::stringstream query; - query << "INSERT INTO " << m_table_name - << " (esp_offset, size, function_id, source_id) VALUES (" - << offset << "," << size << "," << func->getBaseID() << "," << source - << ") RETURNING stack_id; "; - - transaction.IssueQuery(query); - transaction.Commit(); - - return atoi(transaction.GetResultColumn("stack_id").c_str()); -#endif -} diff --git a/builtin_xforms/p1transform/PNIrdbManager.hpp b/builtin_xforms/p1transform/PNIrdbManager.hpp deleted file mode 100644 index 6aa3319ec..000000000 --- a/builtin_xforms/p1transform/PNIrdbManager.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PN_IRDB_MANAGER_HPP__ -#define __PN_IRDB_MANAGER_HPP__ - -#include <irdb-core> -#include <map> - -class PNIrdbManager -{ -public: - - enum IRSource { - IRS_PEASOUP, - IRS_DWARF - }; - - PNIrdbManager(IRDB_SDK::DatabaseID_t variant_db_id); - virtual ~PNIrdbManager(); - - // Create the IRDB table managed by this class - virtual void CreateTable(); - - // Check the existence of the IRDB table managed by this class - virtual bool TableExists(); - - // Delete the contents of the IRDB table managed by this class - virtual void ClearTable(); - - // Delete all stack objects from a given source - virtual void DeleteSource(IRSource source); - - // Add a stack object - virtual IRDB_SDK::DatabaseID_t InsertStackObject( - std::string function_name, - int offset, - unsigned int size, - IRSource source); - -protected: - - /// @brief Variant ID associated with this table manager - std::unique_ptr<IRDB_SDK::VariantID_t> m_variant_id; - - /// @brief File associated with this table manager - std::unique_ptr<IRDB_SDK::FileIR_t> m_file_ir; - - /// @brief Functions identified in this variant - std::map<std::string, IRDB_SDK::Function_t*> m_function_map; - - /// @brief Name of the table managed by this class - std::string m_table_name; -}; - -#endif // __PN_IRDB_MANAGER_HPP__ diff --git a/builtin_xforms/p1transform/PNMain.cpp b/builtin_xforms/p1transform/PNMain.cpp deleted file mode 100644 index e00ff8850..000000000 --- a/builtin_xforms/p1transform/PNMain.cpp +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - - -#include <iostream> -#include <limits.h> -//#include <unistd.h> -#include <getopt.h> -#include "PNStackLayoutInference.hpp" -#include "P1Inference.hpp" -#include "OffsetInference.hpp" -#include "ScaledOffsetInference.hpp" -#include "DirectOffsetInference.hpp" -#include "PNTransformDriver.hpp" - -#include "PrecedenceBoundaryInference.hpp" -#include "AnnotationBoundaryGenerator.hpp" -// #include "MEDS_AnnotationParser.hpp" - -#include <iostream> -#include <fstream> -#include <string> -#include <set> -#include <cstdlib> -#include <sstream> -#include <algorithm> -#include <functional> - -#include "globals.h" - -using namespace std; -using namespace IRDB_SDK; -// using namespace MEDS_Annotation; - -#define ALLOF(a) begin(a),end(a) - -bool verbose_log = false; - -PNOptions *pn_options; - -enum -{ - BED_SCRIPT_OPTION = CHAR_MAX+1, - BLACKLIST_OPTION, - COVERAGE_FILE_OPTION, - PN_THRESHOLD_OPTION, - CANARIES_OPTION, - BREADCRUMBS_OPTION, - ONLY_VALIDATE_OPTION, - NO_P1_VALIDATE_OPTION, - ALIGN_STACK_OPTION, - APRIORI_OPTION, - GROUND_TRUTH_OPTION, - SHARED_OBJECT_PROTECTION_OPTION, - MIN_STACK_PAD_OPTION, - MAX_STACK_PAD_OPTION, - RECURSIVE_MIN_STACK_PAD_OPTION, - RECURSIVE_MAX_STACK_PAD_OPTION, - SHOULD_DOUBLE_FRAME_SIZE_OPTION, - DOUBLE_THRESHOLD_OPTION, - SELECTIVE_CANARIES_OPTION, - SET_RANDOM_SEED, - SET_CANARY_VALUE, - SET_FLOATING_CANARY_OPTION, - SET_DETECTION_POLICY_OPTION, - SET_DETECTION_EXIT_CODE_OPTION -}; - - - -static struct option const long_options[] = -{ - {"bed_script",required_argument, nullptr, BED_SCRIPT_OPTION}, - {"blacklist",required_argument, nullptr, BLACKLIST_OPTION}, - {"coverage_file",required_argument, nullptr, COVERAGE_FILE_OPTION}, - {"pn_threshold",required_argument, nullptr, PN_THRESHOLD_OPTION}, - {"canaries", required_argument, nullptr, CANARIES_OPTION}, - {"breadcrumbs", required_argument, nullptr, BREADCRUMBS_OPTION}, - {"only_validate",required_argument, nullptr, ONLY_VALIDATE_OPTION}, - {"no_p1_validate",no_argument,nullptr,NO_P1_VALIDATE_OPTION}, - {"apriori_layout_file",required_argument, nullptr, APRIORI_OPTION}, - {"align_stack",no_argument,nullptr,ALIGN_STACK_OPTION}, - {"ground_truth",no_argument,nullptr,GROUND_TRUTH_OPTION}, - {"shared_object_protection",no_argument,nullptr,SHARED_OBJECT_PROTECTION_OPTION}, - {"min_stack_padding",required_argument, nullptr, MIN_STACK_PAD_OPTION}, - {"max_stack_padding",required_argument, nullptr, MAX_STACK_PAD_OPTION}, - {"recursive_min_stack_padding",required_argument, nullptr, RECURSIVE_MIN_STACK_PAD_OPTION}, - {"recursive_max_stack_padding",required_argument, nullptr, RECURSIVE_MAX_STACK_PAD_OPTION}, - {"should_double_frame_size",required_argument, nullptr, SHOULD_DOUBLE_FRAME_SIZE_OPTION}, - {"double_threshold_size",required_argument, nullptr, DOUBLE_THRESHOLD_OPTION,}, - {"selective_canaries",required_argument, nullptr, SELECTIVE_CANARIES_OPTION}, - {"random_seed",required_argument, nullptr, SET_RANDOM_SEED}, - {"canary_value",required_argument, nullptr, SET_CANARY_VALUE}, - {"floating_canary",no_argument, nullptr, SET_FLOATING_CANARY_OPTION}, - {"detection_policy",required_argument, nullptr, SET_DETECTION_POLICY_OPTION}, - {"detection_exit_code",required_argument, nullptr, SET_DETECTION_EXIT_CODE_OPTION}, - {nullptr, 0, NULL, 0} -}; - - -//TODO: PN will now p1 if no coverage is available, -//this is not desired for black box testing. -//Find a solution. - - -set<string> getFunctionList(const char * const p_filename) -{ - set<string> functionList; - - if(p_filename == nullptr) - return functionList; - - ifstream candidateFile; - candidateFile.open(p_filename); - - if(candidateFile.is_open()) - { - while(!candidateFile.eof()) - { - string functionName; - getline(candidateFile, functionName); - - functionList.insert(functionName); - } - - candidateFile.close(); - } - - return functionList; -} - - -//TODO: the coverage map should not use the function name since -//it is possible this will repeat when analyzing shared objects. -map<string, map<string,double> > getCoverageMap(const char * const filename,double cov_threshold) -{ - map<string, map<string,double> > coverage_map; - - int acceptable_cov = 0; - int total_funcs=0; - - if(filename == nullptr) - return coverage_map; - - ifstream coverage_file; - coverage_file.open(filename); - - if(coverage_file.is_open()) - { - while(!coverage_file.eof()) - { - //TODO: there is no sanity checking of this file - - string line; - getline(coverage_file, line); - - stringstream ss_line; - ss_line.str(line); - - string func_id,file,func_name; - ss_line>>func_id; - istringstream iss_fid(func_id); - getline(iss_fid,file,'+'); - getline(iss_fid,func_name,'+'); - - string scoverage; - ss_line>>scoverage; - - double coverage = strtod(scoverage.c_str(),nullptr); - - if(func_name.length() > 0 && func_name[0] != '.') - { - if(coverage > cov_threshold) - { - if(func_name.length() > 0 && func_name[0] != '.') - acceptable_cov++; - } - total_funcs++; - } - coverage_map[file][func_name]=coverage; - - cout<<"file: "<<file<<" func: "<<func_name<<" coverage: "<<coverage<<endl; - } - cout<<"Summary:"<<endl; - cout<<"\tTotal non-plt functions = "<<total_funcs<<endl; - cout<<"\tTotal non-plt functions exceeding "<<cov_threshold<<" threshold = "<<acceptable_cov<<" ("<<(double)acceptable_cov/total_funcs<<")"<<endl; - coverage_file.close(); - } - return coverage_map; -} - -void usage() -{ - printf("Usage TBD, exiting transform...\n"); - return; -} - -class P1Transform_t : public TransformStep_t -{ - - DatabaseID_t progid=BaseObj_t::NOT_IN_DATABASE; - string BED_script=""; - string blacklist_file=""; - string coverage_file=""; - string only_validate=""; - bool validate_p1=false; - bool align_stack=true; - bool floating_canary=false; - bool shared_object_protection=true; - double p1threshold=0.75; - bool do_ground_truth=false; - VariantID_t *pidp=nullptr; -public: - -P1Transform_t() -{ - auto env=getenv("PEASOUP_HOME"); - if(env==nullptr) - { - cerr<<"Must set $PEASOUP_HOME"<<endl; - assert(0); - exit(-1); - } - BED_script=string()+env+"/tools/bed.sh"; - blacklist_file=string()+env+"/tools/libc_functions.txt"; -} - -std::string getStepName(void) const override -{ - return "p1transform"; -} - - -int parseArgs(const vector<string> step_args) -{ - auto argv = vector<char*>({const_cast<char*>("libp1transform.so")}); - transform(ALLOF(step_args), back_inserter(argv), [](const string &s) -> char* { return const_cast<char*>(s.c_str()); } ); - const auto argc=argv.size(); - - - //Set the verbose flag - char *verbose = getenv("VERBOSE"); - if(verbose == nullptr) - verbose = getenv("PN_VERBOSE"); - - verbose_log = (verbose != nullptr); - -// progid = atoi(argv[0]); -// char buf[]="libp1transform.so"; -// argv[0]=buf; - - int c=0; - - // global class to store options to Pn - pn_options = new PNOptions(); - - while((c = getopt_long(argc, &argv[0], "", long_options, nullptr)) != -1) - { - switch(c) - { - case BED_SCRIPT_OPTION: - { - BED_script = optarg; - break; - } - case BLACKLIST_OPTION: - { - blacklist_file = optarg; - break; - } - case COVERAGE_FILE_OPTION: - { - coverage_file = optarg; - break; - } - case PN_THRESHOLD_OPTION: - { - p1threshold = strtod(optarg,nullptr); - // valid values are -1, and 0-1, inclusive. - // -1 means disabled. - if(p1threshold != -1 && (p1threshold <0 || p1threshold >1)) - { - //TODO: print a message call usage - usage(); - return 1; - } - break; - } - case CANARIES_OPTION: - { - if(strcasecmp("on",optarg)==0) - { - pn_options->setDoCanaries(true); - } - else if(strcasecmp("off",optarg)==0) - { - pn_options->setDoCanaries(false); - } - else - { - //TODO: print error message and usage - usage(); - return 1; - } - break; - } - case BREADCRUMBS_OPTION: - { - if(strcasecmp("on",optarg)==0) - { - pn_options->setDoBreadcrumbs(true); - } - else if(strcasecmp("off",optarg)==0) - { - pn_options->setDoBreadcrumbs(false); - } - else - { - //TODO: print error message and usage - usage(); - return 1; - } - break; - } - case ONLY_VALIDATE_OPTION: - { - only_validate=optarg; - break; - } - case NO_P1_VALIDATE_OPTION: - { - validate_p1 = false; - break; - } - case ALIGN_STACK_OPTION: - { - align_stack = true; - break; - } - case SHARED_OBJECT_PROTECTION_OPTION: - { - shared_object_protection=true; - break; - } - case GROUND_TRUTH_OPTION: - { - do_ground_truth=true; - break; - } - case MIN_STACK_PAD_OPTION: - { - int min_stack_padding = atoi(optarg); - if (min_stack_padding >= 0) - pn_options->setMinStackPadding(min_stack_padding); - break; - } - case MAX_STACK_PAD_OPTION: - { - int max_stack_padding = atoi(optarg); - if (max_stack_padding >= 0) - pn_options->setMaxStackPadding(max_stack_padding); - break; - } - case RECURSIVE_MIN_STACK_PAD_OPTION: - { - int recursive_min_stack_padding = atoi(optarg); - if (recursive_min_stack_padding >= 0) - pn_options->setRecursiveMinStackPadding(recursive_min_stack_padding); - break; - } - case RECURSIVE_MAX_STACK_PAD_OPTION: - { - int recursive_max_stack_padding = atoi(optarg); - if (recursive_max_stack_padding >= 0) - pn_options->setRecursiveMaxStackPadding(recursive_max_stack_padding); - break; - } - case DOUBLE_THRESHOLD_OPTION: - { - const auto double_threshold = atoi(optarg); - pn_options->setDoubleThreshold(double_threshold); - break; - } - - case SHOULD_DOUBLE_FRAME_SIZE_OPTION: - { - if(strcasecmp("true",optarg)==0) - pn_options->setShouldDoubleFrameSize(true); - else if(strcasecmp("false",optarg)==0) - pn_options->setShouldDoubleFrameSize(false); - else - { - cout<<"Error: should_double_frame_size option needs to be 'true' or 'false': found "<<optarg<<endl; - usage(); - return 1; - } - break; - } - case SELECTIVE_CANARIES_OPTION: - { - string file=optarg; - ifstream in(file.c_str()); - string word; - - if(!in) - { - cout << "Cannot open input file: "<<file<<endl;; - usage(); - return 1; - } - - while(in>>word) - pn_options->addSelectiveCanaryFunction(word); - - break; - } - case SET_RANDOM_SEED: - { - int the_seed=atoi(optarg); - cout<<"Setting random seed to: "<<dec<<the_seed<<endl; - pn_options->setRandomSeed(the_seed); - break; - } - case SET_CANARY_VALUE: - { - int the_val=strtoul(optarg, nullptr, 0); - cout<<"Setting canary value to: 0x"<<hex<<the_val<<endl; - pn_options->setCanaryValue(the_val); - break; - } - case SET_FLOATING_CANARY_OPTION: - { - floating_canary = true; - break; - } - case SET_DETECTION_POLICY_OPTION: - { - if(strcasecmp("exit",optarg)==0) - pn_options->setDetectionPolicy(P_CONTROLLED_EXIT); - else if(strcasecmp("halt",optarg)==0) - pn_options->setDetectionPolicy(P_HARD_EXIT); - else - pn_options->setDetectionPolicy(P_CONTROLLED_EXIT); - break; - } - case SET_DETECTION_EXIT_CODE_OPTION: - { - auto exit_code=(unsigned)atoi(optarg); - assert(exit_code >= 0 && exit_code <= 255); - pn_options->setDetectionExitCode(exit_code); - break; - } - - case '?': - { - //error message already printed by getopt_long - //TODO: exit? - usage(); - return 1; - } - default: - { - //TODO: invalid argument, and print usage - usage(); - return 1; - } - } - } - - - - // sanity check padding - assert(pn_options->getMaxStackPadding() >= pn_options->getMinStackPadding()); - assert(pn_options->getRecursiveMaxStackPadding() >= pn_options->getRecursiveMinStackPadding()); - - cout << "min_stack_padding: " << pn_options->getMinStackPadding() << endl; - cout << "max_stack_padding: " << pn_options->getMaxStackPadding() << endl; - cout << "recursive_min_stack_padding: " << pn_options->getRecursiveMinStackPadding() << endl; - cout << "recursive_max_stack_padding: " << pn_options->getRecursiveMaxStackPadding() << endl; - cout << "canaries: " << pn_options->getDoCanaries() << endl; - - return 0; -} - - -int executeStep() -{ - progid=getVariantID(); - auto irdb_objects=getIRDBObjects(); - //setup the interface to the sql server - - const auto pqxx_interface=irdb_objects->getDBInterface(); - BaseObj_t::setInterface(pqxx_interface); - - - try - { - // read the variant ID using variant id number = atoi(argv[1]) - pidp = irdb_objects->addVariant(progid); - - - // verify that we read it correctly. - assert(pidp->isRegistered()==true); - } - catch (DatabaseError_t pnide) - { - cout<<"Unexpected database error: "<<pnide<<endl; - exit(-1); - } - - set<std::string> blackListOfFunctions; - blackListOfFunctions = getFunctionList(blacklist_file.c_str()); - set<std::string> onlyValidateFunctions; - onlyValidateFunctions = getFunctionList(only_validate.c_str()); - map<string, map<string,double> > coverage_map = getCoverageMap(coverage_file.c_str(),p1threshold); - - cout<<"P1threshold parsed = "<<p1threshold<<endl; - - try - { - PNTransformDriver transform_driver(pidp,BED_script, pqxx_interface); - - cout << " detection_policy: " << pn_options->getDetectionPolicy() << endl; - cout << "detection_exit_code: " << pn_options->getDetectionExitCode() << " only active if controlled exit specified" << endl; - - transform_driver.SetMitigationPolicy(pn_options->getDetectionPolicy()); - transform_driver.SetDetectionExitCode(pn_options->getDetectionExitCode()); - - OffsetInference *offset_inference = new OffsetInference(); - - //TODO: hard coding the file in for now. - ifstream annotationFile("a.ncexe.infoannot", ifstream::in); - assert(annotationFile.is_open()); - -// AnnotationBoundaryGenerator *abgen = new AnnotationBoundaryGenerator(new MEDS_AnnotationParser(annotationFile)); - -// PrecedenceBoundaryInference *aggressive_memset_inference = new PrecedenceBoundaryInference(offset_inference,abgen); - - DirectOffsetInference *direct_offset_inference = new DirectOffsetInference(offset_inference); - ScaledOffsetInference *scaled_offset_inference = new ScaledOffsetInference(offset_inference); - P1Inference *p1 = new P1Inference(offset_inference); - // PrecedenceBoundaryInference *conservative_memset_inference = new PrecedenceBoundaryInference(p1, abgen); - - //Add new boundary inferences here - - //TODO: in addition to a hierarchy there should be equivalence classes, a failure in one member, is a failure for all. - -// transform_driver.AddInference(aggressive_memset_inference); - transform_driver.AddInference(offset_inference,1); - transform_driver.AddInference(direct_offset_inference,1); - transform_driver.AddInference(scaled_offset_inference,1); -// transform_driver.AddInference(conservative_memset_inference,1); - transform_driver.AddInference(p1,2); - - transform_driver.AddBlacklist(blackListOfFunctions); - transform_driver.AddOnlyValidateList(onlyValidateFunctions); - transform_driver.SetDoCanaries(pn_options->getDoCanaries()); - transform_driver.SetDoFloatingCanary(floating_canary); - transform_driver.SetDoAlignStack(align_stack); - transform_driver.SetCoverageMap(coverage_map); - transform_driver.SetCoverageThreshold(p1threshold); - transform_driver.SetProtectSharedObjects(shared_object_protection); - transform_driver.SetWriteStackIrToDb(do_ground_truth); - - //The passed in level must match a level that exists - if(! validate_p1) - transform_driver.SetNoValidationLevel(2); - - //Produce SLX transformation - transform_driver.GenerateTransforms(irdb_objects); - - } - catch (DatabaseError_t pnide) - { - cout<<"Unexpected database error: "<<pnide<<endl; - return -1; - } - -//TODO: Catch all other exceptions? - - return 0; -} - -}; - - -static shared_ptr<TransformStep_t> curInvocation; - -extern "C" -shared_ptr<TransformStep_t> getTransformStep(void) -{ - curInvocation.reset(new P1Transform_t()); - return curInvocation; -} - - diff --git a/builtin_xforms/p1transform/PNRange.cpp b/builtin_xforms/p1transform/PNRange.cpp deleted file mode 100644 index e94ec9ed3..000000000 --- a/builtin_xforms/p1transform/PNRange.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNRange.hpp" -#include <sstream> - -using namespace std; - -/* - PNRange::PNRange(int displacement_offset, unsigned int padding_size, const Range &range) : Range(range) - { - this->displacement_offset = displacement_offset; - this->padding_size = padding_size; - - new_size = size + padding_size; - } -*/ - -PNRange::PNRange(const PNRange &range) : Range(range) -{ - padding_size = range.padding_size; - displacement = range.displacement; -} - -PNRange::PNRange(const Range &range) : Range(range) -{ - padding_size = 0; - displacement = 0; -} - - -PNRange::PNRange() : Range() -{ - displacement = 0; - padding_size = 0; -} -unsigned int PNRange::GetPaddingSize() const -{ - return padding_size; -} - -int PNRange::GetDisplacement() const -{ - return displacement; -} - -void PNRange::SetDisplacement(int offset) -{ - displacement = offset; -} - -void PNRange::SetPaddingSize(unsigned int pad_size) -{ - padding_size = pad_size; -} - -void PNRange::Reset() -{ - padding_size = 0; - displacement = 0; -} - -string PNRange::ToString() const -{ - stringstream ss; - - ss<<Range::ToString()<<" Padding = "<<padding_size<<" Displacement = "<<displacement; - - return ss.str(); -} - - diff --git a/builtin_xforms/p1transform/PNRange.hpp b/builtin_xforms/p1transform/PNRange.hpp deleted file mode 100644 index 1665d051a..000000000 --- a/builtin_xforms/p1transform/PNRange.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNRANGE -#define __PNRANGE - -#include "Range.hpp" -#include <string> - -class PNRange : public Range -{ -protected: - int displacement; //add displacement to offset to get displaced base - unsigned int padding_size; -public: - PNRange(const PNRange &range); - PNRange(const Range &range); - PNRange(); - virtual ~PNRange() {} - virtual unsigned int GetPaddingSize() const; - virtual int GetDisplacement() const; - virtual void SetDisplacement(int offset); - virtual void SetPaddingSize(unsigned int pad_size); - virtual std::string ToString() const; - virtual void Reset(); - -}; - -#endif diff --git a/builtin_xforms/p1transform/PNRegularExpressions.cpp b/builtin_xforms/p1transform/PNRegularExpressions.cpp deleted file mode 100644 index 10c70b2f2..000000000 --- a/builtin_xforms/p1transform/PNRegularExpressions.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNRegularExpressions.hpp" -#include <cstdio> -#include <cstdlib> -#include <string.h> -#include <assert.h> -#include "irdb-core" - -using namespace std; - -#define FIRN(s) fill_in_reg_name((s)) -#define HEXNUM "([0][xX][0123456789abcdefABCDEF]+)|([01234356789]+)" -#define REGSTRING "[[:blank:]]*[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+[[:blank:]]*" -#define SCALE "[[:blank:]]*[*][[:blank:]]*[1248][[:blank:]]*" -#define WS "[[:blank:]]*" - -static char* fill_in_reg_name(const char *instring) -{ - - int width=IRDB_SDK::FileIR_t::getArchitectureBitWidth(); - static char outstring[200]; - - assert(strlen(instring)<sizeof(outstring)); - - strcpy(outstring,instring); - - char* p=outstring; - while((p=strstr(p,"%"))!=NULL) - { - assert(*p=='%'); - assert(*(p+1)=='b' || *(p+1)=='s'); // sanity check that it's %sp or %bp - assert(*(p+2)=='p'); - if(width==32) - *p='e'; - else if(width==64) - *p='r'; - else - assert(0),abort(); - } - return outstring; -} - -//TODO: for now the constructor exits the program in compilation of the regex fails -//Is throwing an exception a better option? -PNRegularExpressions::PNRegularExpressions() -{ - int errcode; - - // match "and esp, *" - if (regcomp(®ex_and_esp, FIRN("[[:blank:]]*and[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for and esp to compile\n"); - exit(1); - } - // match "ret" - if (regcomp(®ex_ret, FIRN("^ret[[:blank:]]*$"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for ret failed to compile\n"); - exit(1); - } - - /* match lea <anything> dword [<stuff>]*/ - if (regcomp(®ex_lea_hack, FIRN("(.*lea.*,.*)dword(.*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for lea hack failed to compile\n"); - exit(1); - } - - // match "[esp]" - if(regcomp(®ex_esp_only, FIRN(".*\\[(%sp)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp scaled addresses failed\n"); - exit(1); - } - - // match "[esp+reg*scale+disp]" - if(regcomp(®ex_esp_scaled, FIRN(".*\\[%sp" WS "[+].*[+](.+)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp scaled addresses failed\n"); - exit(1); - } - if((errcode=regcomp(®ex_lea_rsp, FIRN(".*lea.*\\[.*%sp.*(" HEXNUM ").*\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_lea_rsp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for regex_lea_rsp failed, code: %s\n", buf); - exit(1); - } - if((errcode=regcomp(®ex_esp_scaled_nodisp, FIRN(".*\\[%sp" WS "[+]" WS "" REGSTRING SCALE "(\\]).*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_scaled_nodisp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp scaled w/o displacement failed, code: %s\n", buf); - exit(1); - } - - if(regcomp(®ex_ebp_scaled,FIRN(".*\\[%bp" WS "[+]" WS ".*[-](.+)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for ebp scaled addresses failed\n"); - exit(1); - } - - if((errcode=regcomp(®ex_esp_direct, FIRN(".*\\[%sp" WS "[+]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_direct,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp direct addresses failed, code: %s\n",buf); - exit(1); - } - - if((errcode=regcomp(®ex_esp_direct_negoffset,FIRN(".*\\[%sp" WS "[-]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_direct_negoffset,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp direct addresses failed, code: %s\n",buf); - exit(1); - } - - - if(regcomp(®ex_ebp_direct,FIRN(".*\\[%bp" WS "[-]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp direct addresses failed\n"); - exit(1); - } - - // stack allocation: match sub esp , K - if (regcomp(®ex_stack_alloc, FIRN("[[:blank:]]*sub[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for <sub esp, K> failed to compile\n"); - exit(1); - } - - // stack deallocation: match add esp , K - if (regcomp(®ex_stack_dealloc, FIRN("[[:blank:]]*add[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for <add esp, K> failed to compile\n"); - exit(1); - } - - // stack deallocation that does not use an offset - if (regcomp(®ex_stack_dealloc_implicit, FIRN("([[:blank:]]*mov[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*%bp[[:blank:]]*)|([[:blank:]]*leave[[:blank:]]*)|([[:blank:]]*lea[[:blank:]]*%sp[[:blank:]]*,[[:blank:]]*\\[%bp[-].*\\][[:blank:]]*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for stack_dealloc_implicit failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_push_ebp, FIRN(".*push[[:blank:]]+(%bp).*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for push ebp failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_save_fp, FIRN(".*mov[[:blank:]]+(%bp)[[:blank:]]*,[[:blank:]]*(%sp).*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for save fp failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_push_anything, FIRN(".*push[[:blank:]]+(.*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for push (anything) failed to compile\n"); - exit(1); - } - - //looking for scaled accesses using ebp as the index - //eg. [ecx + ebp*1 - 0x21] - //Unlike other expressions, there are two pattern matches here - //the first is the scaling factor (if one exists), the second is the - //offset. - if (regcomp(®ex_scaled_ebp_index, FIRN(".*\\[.*[+]" WS "%bp[*]?(.*)[-](.+)\\].*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for scaled ebp index failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_call, FIRN("^call (.*)$"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for call failed to compile\n"); - exit(1); - } - - - if((errcode=regcomp(®ex_add_rbp,FIRN("add (" REGSTRING "), *%bp *"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_add_rbp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for regex_add_rbp failed, code: %s\n",buf); - exit(1); - } - - - -} diff --git a/builtin_xforms/p1transform/PNRegularExpressions.hpp b/builtin_xforms/p1transform/PNRegularExpressions.hpp deleted file mode 100644 index 91439a72e..000000000 --- a/builtin_xforms/p1transform/PNRegularExpressions.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNREGULAREXPRESSIONS -#define __PNREGULAREXPRESSIONS -#include <regex.h> - -class PNRegularExpressions -{ -public: - PNRegularExpressions(); - - regex_t regex_save_fp; - regex_t regex_ret; - regex_t regex_esp_scaled; - regex_t regex_esp_scaled_nodisp; - regex_t regex_ebp_scaled; - regex_t regex_esp_direct; - regex_t regex_esp_direct_negoffset; - regex_t regex_ebp_direct; - regex_t regex_stack_alloc; - regex_t regex_stack_dealloc; - regex_t regex_stack_dealloc_implicit; - regex_t regex_lea_hack; - regex_t regex_lea_rsp; - regex_t regex_esp_only; - regex_t regex_push_ebp; - regex_t regex_push_anything; - regex_t regex_and_esp; - regex_t regex_scaled_ebp_index; - regex_t regex_call; - regex_t regex_add_rbp; - - static const int MAX_MATCHES = 10; -}; - -#endif diff --git a/builtin_xforms/p1transform/PNStackLayout.cpp b/builtin_xforms/p1transform/PNStackLayout.cpp deleted file mode 100644 index f550133da..000000000 --- a/builtin_xforms/p1transform/PNStackLayout.cpp +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNStackLayout.hpp" -#include <cstdlib> -#include <algorithm> -#include <cassert> -#include <sstream> -#include <ctime> -#include "globals.h" -#include <irdb-core> - -//TODO: debug use only -#include <iostream> - -using namespace std; - -//TODO: so far it has been assumed that you insert then padd and shuffle -//but if a new element is added after shuffling or padding, what should I do? - -//TODO: we do not handle negative offsets relative to esp. These offsets will not be inserted -//into the layout, however if this case is encountered, offsets are changed here to avoid -//complications. This is primarily a problem with EBP offsets extending beyond the stack -//pointer. I have not observed this so far, but if this does happen, upon requesting a new -//offset the amount passed the stack pointer is calculated, and added to the new frame -//size to give a new EBP relative offset. ESP relative offsets require to adjustments - -static bool CompareRangeBaseOffset(PNRange *a, PNRange *b) -{ - return (a->getOffset() < b->getOffset()); -} - -static bool CompareRangeDisplacedOffset(PNRange *a, PNRange *b) -{ - return ((a->getOffset()+a->GetDisplacement()) < (b->getOffset()+b->GetDisplacement())); -} - - -unsigned int PNStackLayout::GetRandomPadding(unsigned int obj_size) -{ - int min,max; - - min = pn_options->getMinStackPadding(); - max = pn_options->getMaxStackPadding(); - - if(stack_layout.is_recursive) - { - min = pn_options->getRecursiveMinStackPadding(); - max = pn_options->getRecursiveMaxStackPadding(); - } - - - int pad = (rand() % (max+1-min)) + min; - if(isaligned) - { -//TODO: if previously padded, and not aligned, this will not gurantee alignment, so -//I should probably pass the memory object itself, so I can use all that information. - pad = pad + obj_size; - pad = pad - (pad % ALIGNMENT_BYTE_SIZE); - pad = pad - obj_size; - } - - //Finally, add padding equivalent to the original stack frame size - //this helps protect against very large overflows/underflows. - //align the original stack frame if not aligned, adding more bytes if necessary - //TODO: should this be scaled down if the func is recursive? - - - - if(pn_options->getShouldDoubleFrameSize() && obj_size < (uintptr_t)pn_options->getDoubleThreshold()) - { - //if the original frame size is not aligned, then add as many bytes as necessary to align it - //for example, if 3 bytes over alignment, and the alignment stride is 8, then add 8 - 3, or 5 bytes. - pad += (ALIGNMENT_BYTE_SIZE - (stack_layout.frame_alloc_size % ALIGNMENT_BYTE_SIZE)); - pad += stack_layout.frame_alloc_size; - } - - return pad; -} - -//TODO: a ToString function - -//TODO: return value if insert in out args region? - -//TODO: use of unsigned ints?? While making it easier here, it is prone to type errors by the user - -//TODO: negative offsets? - - -PNStackLayout::PNStackLayout(StackLayout stack_layout, IRDB_SDK::Function_t* func) : stack_layout(stack_layout) - -{ - ALIGNMENT_BYTE_SIZE=IRDB_SDK::FileIR_t::getArchitectureBitWidth()/sizeof(int); - //PNTransformDriver sets up the seed, I need a better way of handling this - //but for now assume it has been properly seeded. - //srand(time(NULL)); - - this->stack_layout = stack_layout; - isPadded = false; - isShuffled = false; - altered_alloc_size = stack_layout.frame_alloc_size; - - for(unsigned int i=0;i<stack_layout.mem_objects.size();i++) - { - PNRange *pn_obj = new PNRange(stack_layout.mem_objects[i]); - mem_objects.push_back(pn_obj); - } - - assert(func); - base_id = func->getBaseID(); - entry_id = 0; - if(func->getEntryPoint()!=NULL) - entry_id=func->getEntryPoint()->getBaseID(); - - m_func = func; -} - -PNStackLayout::PNStackLayout(const PNStackLayout &stack_layout): stack_layout(stack_layout.stack_layout) -{ - ALIGNMENT_BYTE_SIZE=IRDB_SDK::FileIR_t::getArchitectureBitWidth()/sizeof(int); - pn_layout_name = stack_layout.pn_layout_name; - isPadded = stack_layout.isPadded; - isShuffled = stack_layout.isShuffled; - isaligned = stack_layout.isaligned; - this->stack_layout = stack_layout.stack_layout; - altered_alloc_size = stack_layout.altered_alloc_size; - - for(unsigned int i=0;i<stack_layout.mem_objects.size();i++) - { - PNRange *pn_obj = new PNRange(*stack_layout.mem_objects[i]); - mem_objects.push_back(pn_obj); - } - - base_id = 0; - entry_id = 0; - m_func = NULL; -} - -PNStackLayout::~PNStackLayout() -{ - for(unsigned int i=0;i<mem_objects.size();i++) - { - delete mem_objects[i]; - } -} - -//Shuffle generates new displacement_offset values for each PNRange which represents -//a logical shuffling, it does not change the ordering of the mem_objects data structure. -void PNStackLayout::Shuffle() -{ - if(!IsShuffleSafe()) - return; - - //TODO: this function can be optimized to not randomize the mem_objects vector then resort - - int lowest_address = mem_objects[0]->GetDisplacement() + mem_objects[0]->getOffset(); - - //Find the lowest displacement offset - //This is in case the layout has been padded before shuffling. - //In this case, the element randomly selected to be the first element - //will be placed at the lowest displaced offset, rather than at 0. If 0 - //were used this would effectively remove any padding between 0 and the - //first memory object. - for(unsigned int i=1;i<mem_objects.size();i++) - { - int next_offset = mem_objects[i]->GetDisplacement() + mem_objects[i]->getOffset(); - if(lowest_address > next_offset) - lowest_address = next_offset; - } - - int random_index; - int start_index = 0; - - //if there are out args, the first element of the passed in vector - //is considered the out args and will not be shuffled - if(stack_layout.has_out_args) - { - start_index = 1; - } - - //Shuffle all regions except the lowest region if there are out args - for(int i=start_index;i<((int)mem_objects.size())-1;i++) - { - //TODO: There may be a bias here - random_index = i + (rand() % (mem_objects.size() - i)); - - assert(random_index>=i && random_index<(int)mem_objects.size()); - - PNRange *swap = mem_objects[i]; - mem_objects[i] = mem_objects[random_index]; - mem_objects[random_index] = swap; - } - - //If there aren't any out args, then the element at the lowest displaced - //address (displacement + offset) is considered the base address, - //if not previously padded this should be zero, in which case the - //new displacment will be 0. - //No check is needed for out args since the lowest_address should be 0 - //if there are out args - mem_objects[0]->SetDisplacement(lowest_address-mem_objects[0]->getOffset()); - - //generate new base addresses for each region - for(unsigned int i=1;i<mem_objects.size();i++) - { - //Displacement = New Location - original location - //Displacement + offset = new address - mem_objects[i]->SetDisplacement((mem_objects[i-1]->GetDisplacement()+mem_objects[i-1]->getOffset() + - mem_objects[i-1]->getSize() + mem_objects[i-1]->GetPaddingSize()) - - mem_objects[i]->getOffset()); - } - - //At this bound the mem_objects data structure has been randomized, sort by original base offset - sort(mem_objects.begin(),mem_objects.end(), CompareRangeBaseOffset); - - isShuffled = true; - - if(verbose_log) - { - cerr<<"PNStackLayout: Shuffle(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->getOffset()<<" Size = "<<mem_objects[i]->getSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - -PNStackLayout PNStackLayout::GetCanaryLayout() const -{ - PNStackLayout new_layout = *(this); - - new_layout.AddCanaryPadding(); - - return new_layout; -} - -//Adds padding for canaries between objects, or if padding -//exists, does nothing. -void PNStackLayout::AddCanaryPadding() -{ - // if(!IsPaddingSafe()) - // return; -//TODO: I should throw an exception, but for now I will just assert false if -//the layout is not padding safe but canary padding is requested. - if(!IsPaddingSafe()) - assert(false); - - -//TODO: I need to check the padding for each variable, but for now, I will assume -//if the layout is padded, it is padded enough for canaries - if(IsPadded()) - return; - - unsigned int size = 8; - -// Twitcher adds another guard -#ifdef TWITCHER_GUARD - size += 8; -#endif - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding =0; - - - unsigned int curpad = size; - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad+mem_objects[0]->GetPaddingSize()); - - for(unsigned int i=1;i<mem_objects.size();i++) - { - mem_objects[i]->SetDisplacement(total_padding+mem_objects[i]->GetDisplacement()); - curpad = size; - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad+mem_objects[i]->GetPaddingSize()); - } - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeBaseOffset); - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - if(verbose_log) - { - cerr<<"PNStackLayout: AddPadding(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->getOffset()<<" Size = "<<mem_objects[i]->getSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - - -/* - * roundUp - round number up to the nearest multiple . multiple must be power of 2. - */ -int roundUp(int numToRound, int multiple) -{ - assert((multiple & (multiple-1))==0); - return (numToRound + multiple - 1) & ~(multiple - 1); -} - -/* - Add padding between variables in the stack frame. If there are no out args, - padding is added below the lowest variable, but only if the stack frame - is not a p1 reduction. Hypotheses of the out args region are sometimes - incorrect. If the out args region is not identified, adding padding - below the lowest variable will result in all transforms incorrectly - transforming the stack. To avoid this, if the most conservative layout is found - (p1), no padding is added below the lowest variable. This way at least p1 - can transform these stack frames. - - Previous padding is added to, not removed. Padding may be added before or after - shuffling. -*/ -void PNStackLayout::AddRandomPadding(bool isaligned) -{ - if (!IsPaddingSafe()) - return; - - this->isaligned = isaligned; - - if (verbose_log) - cerr << "ALIGNMENT IS " << isaligned << endl; - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding = GetRandomPadding(0); - - //if there is no out args region, add padding below the memory object at esp - // if(!has_out_args) - //Only add padding from below the memory object at esp if there are no out args and - //the layout does not reduce to p1. The reasonf or including the check for a reduction - //to p1 was added because some times the out args is not found, causing all transforms - //to fail. For p1, padding from below doesn't add much anyway, so removing this - //diversification allows for a transform even if the out args have been incorrectly - //identified. - if (!stack_layout.has_out_args && (mem_objects.size() != 1)) - mem_objects[0]->SetDisplacement((int) total_padding + mem_objects[0]->GetDisplacement()); - else - { - mem_objects[0]->SetDisplacement(0); - total_padding = 0; - } - - unsigned int curpad = this->GetRandomPadding(mem_objects[0]->getSize()); - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad + mem_objects[0]->GetPaddingSize()); - - for (unsigned int i = 1; i < mem_objects.size(); ++i) - { - mem_objects[i]->SetDisplacement(total_padding + mem_objects[i]->GetDisplacement()); - curpad = GetRandomPadding(mem_objects[i]->getSize()); - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad + mem_objects[i]->GetPaddingSize()); - } - - - sort(mem_objects.begin(), mem_objects.end(), CompareRangeBaseOffset); - - int last = mem_objects.size() - 1; - int last_pad = mem_objects[last]->GetPaddingSize(); - if (verbose_log) - { - cerr << "Last object size=0x" << hex << last_pad << endl; - cerr << "altered_aloc_size=0x" << hex << altered_alloc_size << endl; - cerr << "total_padding=0x" << hex << total_padding << endl; - } - - int new_total_padding_size = roundUp(total_padding, ALIGNMENT_BYTE_SIZE); - mem_objects[last]->SetPaddingSize(mem_objects[last]->GetPaddingSize() + new_total_padding_size - total_padding); - total_padding = new_total_padding_size; - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - if (verbose_log) - { - cerr << "PNStackLayout: AddPadding(): " << ToString() << endl; - for (unsigned int i = 0; i < mem_objects.size(); ++i) - { - cerr << "\tOffset = " << mem_objects[i]->getOffset() << " Size = " << mem_objects[i]->getSize() << - " Padding = " << mem_objects[i]->GetPaddingSize() << " displ = " << mem_objects[i]->GetDisplacement() << endl; - } - } -} // end of PNStackLayout::AddRandomPadding() - -//Basically this is the same process as the random padding function, but the padding -//is determined by not by random, but by the location of each variable. -void PNStackLayout::AddDMZPadding() -{ - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding = stack_layout.frame_alloc_size; - - //if there is no out args region, add padding below the memory object at esp - // if(!has_out_args) - //Only add padding from below the memory object at esp if there are no out args and - //the layout does not reduce to p1. The reasonf or including the check for a reduction - //to p1 was added because some times the out args is not found, causing all transforms - //to fail. For p1, padding from below doesn't add much anyway, so removing this - //diversification allows for a transform even if the out args have been incorrectly - //identified. - if(!stack_layout.has_out_args && mem_objects.size() == 1) - mem_objects[0]->SetDisplacement((int)total_padding+mem_objects[0]->GetDisplacement()); - else - { - mem_objects[0]->SetDisplacement(0); - total_padding = 0; - } - - unsigned int curpad = (stack_layout.frame_alloc_size-mem_objects[0]->getOffset())-mem_objects[0]->getSize(); - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad+mem_objects[0]->GetPaddingSize()); - - for(unsigned int i=1;i<mem_objects.size();i++) - { - mem_objects[i]->SetDisplacement(total_padding+mem_objects[i]->GetDisplacement()); - curpad = (stack_layout.frame_alloc_size-mem_objects[i]->getOffset())-mem_objects[i]->getSize(); - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad+mem_objects[i]->GetPaddingSize()); - } - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeBaseOffset); - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - - if(verbose_log) - { - cerr<<"PNStackLayout: AddDMZPadding(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->getOffset()<<" Size = "<<mem_objects[i]->getSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - - -bool PNStackLayout::IsPadded() const -{ - return isPadded; -} - -bool PNStackLayout::IsShuffled() const -{ - return isShuffled; -} - - -unsigned int PNStackLayout::GetOriginalAllocSize() const -{ - return stack_layout.frame_alloc_size; -} - -unsigned int PNStackLayout::GetAlteredAllocSize() const -{ - return altered_alloc_size; -} - -unsigned int PNStackLayout::GetSavedRegsSize() const -{ - return stack_layout.saved_regs_size; -} - -PNRange* PNStackLayout::GetClosestRangeEBP(int loc) const -{ - //The size of the saved regs must be taken into consideration when transforming - //the EBP offset to an esp relative offset - return GetClosestRangeESP(((int)stack_layout.frame_alloc_size+(int)stack_layout.saved_regs_size) - loc); -} - -//Finds the range whose base_offset is the closest to -//loc without going over. -//If no match can be found a negative offset may have been -//passed, the algorithm failed, or the number of mem_objects -//is 0. In this case a null pointer is returned; -PNRange* PNStackLayout::GetClosestRangeESP(int loc) const -{ - if(verbose_log) - cerr<<"PNstackLayout: GetClosestRangeESP(): Seaching for ESP Offset "<<loc<<endl; - - if(loc >= (int)stack_layout.frame_alloc_size) - { - if(verbose_log) - { - //For now don't do anything if the loc is greater than the frame size - cerr<<"PNStackLayout: GetClosestRangeESP(): loc >= frame_alloc_size, Returning NULL"<<endl; - } - return NULL; - } - - if(loc < 0) - { - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): loc < 0 ("<<loc<<"), Returning NULL"<<endl; - return NULL; - } - - int index = stack_layout.GetClosestIndex(loc); - - if(index < 0) - { - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): Could Not Find Range, Returning NULL"<<endl; - return NULL; - } - - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): Found range "<<mem_objects[index]->ToString()<<endl; - - return mem_objects[index]; -} - -unsigned int PNStackLayout::GetNumberOfMemoryObjects() const -{ - return mem_objects.size(); -} - -string PNStackLayout::ToString() const -{ - stringstream ss; - - ss<<"Layout = "<<stack_layout.layout_name + "; Function = "<< - stack_layout.function_name <<"; Frame Alloc Size = "<<stack_layout.frame_alloc_size<<" Altered Frame Size ="<< - altered_alloc_size<<" Saved Regs Size = "<<stack_layout.saved_regs_size<<"; Out Args Size = "<< - stack_layout.out_args_size<<"; Number of Memory Objects = "<< mem_objects.size()<<"; Padded = "; - - if(isPadded) - ss<<"true"; - else - ss<<"false"; - - ss<<"; Shuffled = "; - - if(isShuffled) - ss<< "true"; - else - ss<<"false"; - - ss<<"; canary_safe = "; - if(this->IsCanarySafe()) - ss<<"true"; - else - ss<<"false"; - - return ss.str(); -} - - -string PNStackLayout::GetLayoutName() const -{ - return stack_layout.layout_name; -} - -string PNStackLayout::getFunctionName() const -{ - return stack_layout.function_name; -} - - -//A frame can be shuffled if there are two or more variables, not including -//the out arguments region. -bool PNStackLayout::IsShuffleSafe() const -{ - return (mem_objects.size() > 2) || (mem_objects.size() == 2 && !stack_layout.has_out_args); -} - -bool PNStackLayout::IsP1() const -{ - //for now this is actually identical (although negated) to the logic used in IsShuffleSafe() - //however, this might chagne in the future, so I am copying the logic - //from IsShuffleSafe - //For example, I would like to detect if an offset is inferred or actually - //encountered. Padding between the out args and the first variable - //can give the false impression of boundaries. - return !((mem_objects.size() > 2) || (mem_objects.size() == 2 && !stack_layout.has_out_args)); -} - - -unsigned int PNStackLayout::getOutArgsSize() const -{ - return stack_layout.out_args_size; -} - - -int PNStackLayout::GetNewOffsetESP(int esp_offset) const -{ - int new_offset = esp_offset; - - //If the esp relative address goes above or equal to the frame pointer, esp - //could be accessing incoming args or the saved registers - //(such as fomit-frame-pointer). In this case we simply add - //to the offset the size of the altered frame. - - //TODO: converting stack_layout.frame_alloc_size to int - //check if the size is greater than max int. This should - //never occur though. - if(esp_offset >= (int)stack_layout.frame_alloc_size) - { - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetESP: Offset greater than or equal to frame size, adjusting based on new frame size"<<endl; - //Get the number of bytes beyond the stack frame - new_offset = esp_offset-stack_layout.frame_alloc_size; - //add those bytes to the altered stack size - new_offset += altered_alloc_size; - } - else - { - PNRange *closest = GetClosestRangeESP(esp_offset); - - //TODO: I assume no negative ESP offsets, at this point if the esp offset is not found - //then we have an issue in the program, so assert(false) to uncover the problem. - if(closest == NULL) - { - assert(false); - } - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetESP: closest displacement = "<<closest->GetDisplacement()<<endl; - - new_offset = closest->GetDisplacement() + esp_offset; - } - - return new_offset; -} - -int PNStackLayout::GetNewOffsetEBP(int ebp_offset) const -{ - - //If the function doesn't use a frame pointer, then do not alter any ebp relative instructions. - if(!HasFramePointer()) - { - return ebp_offset; - } - - //In the event that an ebp relative offset extends beyond the stack pointer - //determine the distance beyond the stack pointer, and return - //the sum of this distance with the new frame size and saved register region size - if(ebp_offset > (int)GetOriginalAllocSize()+(int)GetSavedRegsSize()) - { - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetEBP: ebp offset extends passed stack pointer, maintaining relative position to esp"<<endl; - return ebp_offset-(int)GetOriginalAllocSize()+(int)altered_alloc_size; - } - - PNRange *closest = GetClosestRangeEBP(ebp_offset); - - //If no range can be found, since the above check finds - //offsets passed the stack pointer, it is assumed the ebp offset - //refers to a saved register (the space between the frame pointer - //and where local variables start). - //Often ebp relative addresses access saved registeres, if this - //happens, there is no need to do a conversion, as no padding - //is added between EBP and saved registers. The untouched offset - //is returned. - if(closest == NULL) - { - return ebp_offset; - } - - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetEBP: closest displacement = "<<closest->GetDisplacement()<<endl; - - int new_offset = ((int)GetOriginalAllocSize() + (int)GetSavedRegsSize() - ebp_offset); - new_offset += closest->GetDisplacement(); - new_offset = ((int)altered_alloc_size + (int)GetSavedRegsSize()) - new_offset; - - return new_offset; -} - -void PNStackLayout::ResetLayout() -{ - isPadded = false; - isShuffled = false; - for(unsigned int i=0;i<mem_objects.size();i++) - { - mem_objects[i]->Reset(); - } -} - -string PNStackLayout::ToMapEntry() const -{ - stringstream ss; - - ss << "" << stack_layout.layout_name << ";" << stack_layout.function_name << ";" << stack_layout.frame_alloc_size << ";" << - altered_alloc_size << ";" << stack_layout.saved_regs_size << ";" << stack_layout.out_args_size << ";" << mem_objects.size() << ";"; - - if(isPadded) - ss << "true"; - else - ss << "false"; - - ss << ";"; - - if(isShuffled) - ss << "true"; - else - ss << "false"; - - ss << ";"; - if(this->IsCanarySafe()) - ss << "true"; - else - ss << "false"; - - ss << ";"; - - if(canaries.size() > 0) - ss << std::hex << canaries[0].canary_val; - else - ss << 0; - - ss << ";"; - /*asj5b - add func id*/ - ss << std::hex << base_id; - ss << ";"; - ss << std::hex << entry_id; - - /* add canary offset */ - ss << ";"; - if(canaries.size() > 0) - ss << std::dec << canaries[0].floating_offset; - else - ss << 0; - - return ss.str(); -} diff --git a/builtin_xforms/p1transform/PNStackLayout.hpp b/builtin_xforms/p1transform/PNStackLayout.hpp deleted file mode 100644 index 003517c06..000000000 --- a/builtin_xforms/p1transform/PNStackLayout.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PNSTACKLAYOUT -#define __PNSTACKLAYOUT -#include "PNRange.hpp" -#include "StackLayout.hpp" -#include <string> -#include <vector> -#include <exception> -#include <assert.h> -#include "globals.h" -#include "canary.h" -#include <irdb-core> - -//NOTE: padding adds a value between max and min, plus the frame size -//I believe this was done to protect against a very large buffer -//overflow, but I'm not sure I have the example to demonstrate the -//effectiveness. If I had to guess, I think the example is if the -//attacker is trying to exceed the frame size, and the vulnerable buffer -//is at the bottom of the stack, but moved by us to the top, the -//overflow might exceed our padding and corrupt other stack frames. -//const int MIN_PADDING = 64; -//const int MAX_PADDING = 64; -//const int MAX_PADDING = MIN_PADDING*2; -//const int RECURSIVE_MIN_PADDING = 32; -//const int RECURSIVE_MAX_PADDING = RECURSIVE_MAX_PADDING*2; - - -class PNStackLayout -{ -protected: - int ALIGNMENT_BYTE_SIZE; - std::string pn_layout_name; - bool isPadded; - bool isShuffled; - bool isaligned;//should only be used internally, since I don't know if the raw stack is aligned. - //TODO: Storing pointers here but I did away with pointers in StackLayout since I was worried about - //possible memory leaks. I need pointers to return null, but I can achieve this functionality - //through aliasing. Consider removing the pointers for consistency. - std::vector<PNRange*> mem_objects; - - //NOTE: I chose composition over inheritence here, as I wanted to make it impossible to change the - //layout after a PNStackLayout has been created. The issue was if a new boundary was added - //after the layout had been padded/shuffled/etc, it would cause problems. This is avoided by - //this structure, but it is important to make a deap copy of the passed in stack_layout, which - //is achieved through the copy constructor for StackLayout. - StackLayout stack_layout; - unsigned int altered_alloc_size; - - std::vector<canary> canaries; - IRDB_SDK::DatabaseID_t base_id; - IRDB_SDK::DatabaseID_t entry_id; - - IRDB_SDK::Function_t *m_func; - - virtual void AddCanaryPadding(); - -public: - PNStackLayout(StackLayout stack_layout, IRDB_SDK::Function_t* func); - PNStackLayout(const PNStackLayout &stack_layout); - - virtual ~PNStackLayout(); - - virtual void Shuffle(); - //TODO: the max min and alignment size should also be optionally specified. - virtual void AddRandomPadding(bool isaligned=false); - //Adds on to previous padding and does not change any previous displacement - //changes. If you wish to only add DMZ padding, you must clear any previous - //padding. - //TODO: should I worry about alignment here? - - //DMZ padding is defined as the space between the original variable location - //and the end of the local variable region. The theory is, if the variable - //boundaries are correct, then this region should be untouched from any - //memory access. - virtual void AddDMZPadding(); - virtual bool IsPadded() const; - virtual bool IsShuffled() const; - //Remove any transformations, leaves the PNStackLayout as if the object had just been constructed. - virtual void ResetLayout(); - virtual unsigned int GetNumberOfMemoryObjects() const; - virtual PNRange* GetClosestRangeEBP(int loc) const; - virtual PNRange* GetClosestRangeESP(int loc) const; - virtual IRDB_SDK::Function_t* getFunction() const { return m_func; } - virtual unsigned int GetOriginalAllocSize() const; - virtual unsigned int GetAlteredAllocSize() const; - virtual unsigned int GetSavedRegsSize() const; - virtual std::string ToString() const; - virtual std::string ToMapEntry() const; - virtual std::string GetLayoutName() const; - virtual std::string getFunctionName() const; - virtual unsigned int getOutArgsSize() const; - virtual int GetNewOffsetESP(int ebp_offset) const; - virtual int GetNewOffsetEBP(int ebp_offset) const; - virtual PNStackLayout GetCanaryLayout() const; - virtual std::vector<PNRange*> GetRanges() const {return mem_objects;} - virtual bool IsCanarySafe() const - { - assert(pn_options); - return - stack_layout.is_canary_safe && // detected as safe. - pn_options->getDoCanaries() && // and we're allowed to do canaries. - pn_options->shouldCanaryFunction(stack_layout.getFunctionName()); // and we're allowed to do canaries on this function - } - virtual bool IsPaddingSafe()const {return stack_layout.is_padding_safe;} - virtual bool IsShuffleSafe() const ; - virtual bool IsP1() const; - virtual bool IsStaticStack()const {return stack_layout.is_static_stack;} - virtual bool HasFramePointer()const{return stack_layout.has_frame_pointer;} - virtual bool DoShuffleValidate()const {return !IsCanarySafe() && IsShuffleSafe();} - //memory leak? - //virtual StackLayout* GetStackLayout() { return new StackLayout(stack_layout); } - - virtual StackLayout GetStackLayout() { return StackLayout(stack_layout); } - - //This previously was a protected func, moved out for TNE, - //to support dynamic array padding, the name is a bit confusing. - virtual unsigned int GetRandomPadding(unsigned int obj_size=0); - - virtual void SetCanaries(std::vector<canary> can_vec) { canaries = can_vec; } - virtual void SetBaseID(int new_id) { base_id = new_id; } - virtual void SetEntryID(int new_id) { entry_id = new_id; } -}; - -#endif diff --git a/builtin_xforms/p1transform/PNStackLayoutInference.hpp b/builtin_xforms/p1transform/PNStackLayoutInference.hpp deleted file mode 100644 index 8bb252b75..000000000 --- a/builtin_xforms/p1transform/PNStackLayoutInference.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNSTACKLAYOUTINFERENCE -#define __PNSTACKLAYOUTINFERENCE -#include <irdb-core> -#include <irdb-cfg> -#include "StackLayout.hpp" -#include "PNStackLayout.hpp" -#include <string> -#include <map> - -class PNStackLayoutInference -{ - -public: - virtual ~PNStackLayoutInference(){} - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func)=0; - virtual std::string GetInferenceName()const=0; -}; - -#endif diff --git a/builtin_xforms/p1transform/PNTransformDriver.cpp b/builtin_xforms/p1transform/PNTransformDriver.cpp deleted file mode 100644 index d42a27c11..000000000 --- a/builtin_xforms/p1transform/PNTransformDriver.cpp +++ /dev/null @@ -1,3230 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "PNTransformDriver.hpp" -#include <cassert> -#include <algorithm> -#include <unistd.h> -#include <fstream> -#include <sstream> -#include <iomanip> -// #include "beaengine/BeaEngine.h" -#include "General_Utility.hpp" -#include "PNIrdbManager.hpp" -#include <cmath> -#include "globals.h" -#include <irdb-cfg> -#include "EhUpdater.hpp" - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <libgen.h> -#include <sys/types.h> -#include <sys/wait.h> - - -void ignore_result(int /* res */ ) { } - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - - - -#define MAX_JUMPS_TO_FOLLOW 100000 - -#define ALLOF(s) begin(s), end(s) - -using namespace std; -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; -} - -//TODO: this var is a hack for TNE -extern map<Function_t*, set<Instruction_t*> > inserted_instr; -extern map<Function_t*, set<AddressID_t*> > inserted_addr; - -void sigusr1Handler(int signum); -bool PNTransformDriver::timeExpired = false; - -static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* insn, Function_t* func); - - -int get_saved_reg_size() -{ - return FileIR_t::getArchitectureBitWidth()/(sizeof(char)*8); -} - -//TODO: Error message functions? - -//TODO: use of pointers? - -//TODO: Use CFG class for all instruction looping -//TODO: if stack access instruction are encountered before stack allocation, ignore them, after using CFG - -//Used for sorting layotus by number of memory objects in descending order -//TODO: change name to reflect descending order -static bool CompareBoundaryNumbersDescending(PNStackLayout *a, PNStackLayout *b) -{ - return (a->GetNumberOfMemoryObjects() > b->GetNumberOfMemoryObjects()); -} - -static bool CompareValidationRecordAscending(validation_record a, validation_record b) -{ - return (a.layouts[a.layout_index]->GetNumberOfMemoryObjects() < b.layouts[b.layout_index]->GetNumberOfMemoryObjects()); -} - - -PNTransformDriver::PNTransformDriver(VariantID_t *pidp,string BED_script, pqxxDB_t *pqxx_if) : - pn_regex(NULL), pqxx_interface(pqxx_if) -{ - //TODO: throw exception? - assert(pidp != NULL); - - srand(pn_options->getRandomSeed()); - - //TODO: throw exception? - this->pidp = pidp; - orig_progid = pidp->getOriginalVariantID(); - orig_virp = NULL; - this->BED_script = BED_script; - do_canaries = true; - do_floating_canary = false; - do_align = false; - no_validation_level = -1; - coverage_threshold = -1; - do_shared_object_protection = false; - m_mitigation_policy = P_CONTROLLED_EXIT; - m_exit_code = DEFAULT_DETECTION_EXIT_CODE; -} - -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 - if(level < 0) - assert(false); - if(inference == NULL) - assert(false); - - //if the level does not already exist, add empty vectors in transform_hierarchy - //until it does - while((int)transform_hierarchy.size()-1 < level) - { - vector<PNStackLayoutInference*> tmp; - transform_hierarchy.push_back(tmp); - } - - transform_hierarchy[level].push_back(inference); -} - -void PNTransformDriver::SetDoCanaries(bool do_canaries) -{ - this->do_canaries = do_canaries; - -#if 0 - //TODO: For the optimized TNE version I had to remove - //optional canaries. This would've been done by - //the finalize_transformation step, but for some reason - //I can't get the registration functionality to work - //assert false for now if the canaries are turned off - //to remind me to fix this. - assert(do_canaries); -#endif - if(!do_canaries) - { - cerr<<"************************************************************"<<endl; - cerr<<"************************************************************"<<endl; - cerr<<"** not doing canaries is not entirely supported. **"<<endl; - cerr<<"** This flag turns says that error amplification with **"<<endl; - cerr<<"** caranries is turnedoff , instead of just turning off **"<<endl; - cerr<<"** in the final layout. **"<<endl; - cerr<<"** TODO: this could be \"easily\" fixed by Ben, but no one**"<<endl; - cerr<<"** knows how and he is too busy. **"<<endl; - cerr<<"************************************************************"<<endl; - cerr<<"************************************************************"<<endl; - } -} - -void PNTransformDriver::SetDoFloatingCanary(bool do_floating_canary) -{ - this->do_floating_canary = do_floating_canary; -} - -void PNTransformDriver::SetDoAlignStack(bool align_stack) -{ - this->do_align = 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) -{ - blacklist.insert(func_name); -} - - -//This function was experimental, and I never did anything with it -void PNTransformDriver::AddOnlyValidateList(std::set<std::string> &only_validate_list) -{ - set<string>::iterator it; - for(it = only_validate_list.begin();it != only_validate_list.end();it++) - { - this->only_validate_list.insert(*it); - } -} - -void PNTransformDriver::SetCoverageMap(std::map<std::string,map<string,double> > coverage_map) -{ - this->coverage_map = coverage_map; -} - -void PNTransformDriver::SetNoValidationLevel(unsigned int no_validation_level) -{ - this->no_validation_level = no_validation_level; -} - -void PNTransformDriver::SetCoverageThreshold(double threshold) -{ - coverage_threshold = threshold; -} - -void PNTransformDriver::SetProtectSharedObjects(bool do_protection) -{ - do_shared_object_protection = do_protection; -} - - -bool PNTransformDriver::PaddingTransformHandler(PNStackLayout *layout, Function_t *func, bool validate) -{ - bool success = false; - - if(!validate) - cerr<<"PNTransformDriver: Function "<<func->getName()<<" is flagged to be transformed without validation"<<endl; - - cerr<<"PNTransformDriver: Function "<<func->getName()<<" is not canary safe, attempting shuffle validation"<<endl; - - if(validate && !ShuffleValidation(2,layout,func)) - { - cerr<<"PNTransformDriver: Shuffle Validation Failure"<<endl; - return success; - } - - layout->Shuffle();//one final shuffle - layout->AddRandomPadding(do_align); - - if(!Sans_Canary_Rewrite(layout,func)) - { - undo(func); - cerr<<"PNTransformDriver: Rewrite Failure: "<<layout->GetLayoutName()<<" Failed to Rewrite "<<func->getName()<<endl; - } - else if(validate && !Validate(orig_virp, func->getName())) - { - undo(func); - cerr<<"PNTransformDriver: Validation Failure: "<<layout->GetLayoutName()<<" Failed to Validate "<<func->getName()<<endl; - } - 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; -} - -bool PNTransformDriver::LayoutRandTransformHandler(PNStackLayout *layout, Function_t *func,bool validate) -{ - if(!validate) - cerr<<"PNTransformDriver: Function "<<func->getName()<<" is flagged to be transformed without validation"<<endl; - - bool success = false; - cerr<<"PNTransformDriver: Function "<<func->getName()<<" is not padding safe, attempting layout randomization only"<<endl; - - if(validate && !ShuffleValidation(2,layout,func)) - { - cerr<<"PNTransformDriver: Validation Failure: "<<layout->GetLayoutName()<<" Failed to Validate "<<func->getName()<<endl; - } - else - { - layout->Shuffle(); - //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; - } - - // @todo: specify regex patterns in black list file instead - // of special-casing here - - // 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()) - { - cerr<<"PNTransformDriver: Blacklisted Function "<<func->getName()<<endl; - blacklist_funcs++; - return true; - } - - return false; -} - - -void PNTransformDriver::GenerateTransformsInit() -{ - //TODO: have a thread safe timeExpired - timeExpired = false; - signal(SIGUSR1, sigusr1Handler); - total_funcs = 0; - blacklist_funcs = 0; - sanitized_funcs = 0; - push_pop_sanitized_funcs = 0; - function_check_sanitized = 0; - cond_frame_sanitized_funcs = 0; - jump_table_sanitized = 0; - bad_variadic_func_sanitized = 0; - pic_jump_table_sanitized = 0; - eh_sanitized = 0; - dynamic_frames = 0; - high_coverage_count = low_coverage_count = no_coverage_count = validation_count = 0; - not_transformable.clear(); - failed.clear(); -} - - -void PNTransformDriver::InitNewFileIR(File_t* this_file, IRDBObjects_t *const irdb_objects) -{ - if(this_file==NULL) - { - 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); - - //Calc preds is used for sanity checks. - //I believe it determines the predecessors of instructions - calc_preds(); -} - - -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() ;} -}; - -void PNTransformDriver::GenerateTransforms(IRDBObjects_t *const irdb_objects) -{ - if(transform_hierarchy.size() == 0) - { - cerr<<"PNTransformDriver: No Transforms have been registered, aborting GenerateTransforms"<<endl; - return; - } - GenerateTransformsInit(); - - //sanity check of no_validation_level - if(no_validation_level >= (int)transform_hierarchy.size()) - { - 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 - //name, something to consider - - //--------------------a.ncexe protection----------------------- - InitNewFileIR(NULL, irdb_objects); - - - // now that we've loaded the FileIR, we can init the reg expressions needed for this object. - pn_regex=new PNRegularExpressions; - - - //Sanity check: make sure that this file is actually a.ncexe, if not assert false for now - string url = orig_virp->getFile()->getURL(); - //TODO: basename is only used as a hack - //because of the way the url is stored in the db. - //The url should be fixed to be the absolute path. - if(url.find("a.ncexe")==string::npos) - { - assert(false); - } - - cout<<"PNTransformDriver: Protecting File: "<<url<<endl; - GenerateTransformsHidden(coverage_map["a.ncexe"]); - - - //-----------------------shared object protection---------------------------- - - //Transform any shared objects if shared object protection is on - //This will loop through all files stored in pidp and skip a.ncexe - if(do_shared_object_protection) - { - cout<<"PNTransformDriver: Shared Object Protection ON"<<endl; - set<File_t*,file_less<File_t*> > sorted_files; - - for(set<File_t*>::iterator it=pidp->getFiles().begin(); - it!=pidp->getFiles().end(); - ++it - ) - { - File_t* this_file=*it; - sorted_files.insert(this_file); - } - - - for(set<File_t*,file_less<File_t*> >::iterator it=sorted_files.begin(); - it!=sorted_files.end()&&!timeExpired; - ++it - ) - { - File_t* this_file=*it; - assert(this_file); - - string url = this_file->getURL(); - //if the file is a.ncexe skip it (it has been transformed already) - if(url.find("a.ncexe")!=string::npos) - continue; - - // read the db - InitNewFileIR(this_file, irdb_objects); - - map<string,double> file_coverage_map; - - string key; - //find the appropriate coverage map for the given file - //TODO: in theory this should be a simple map look up, but because - //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) - { - key = it->first; - - //TODO: basename is only used as a hack - //because of the way the url is stored in the db. - //The url should be fixed to be the absolute path. - key=string(basename((char*)key.c_str())); - - if(key.empty()) - continue; - - if(url.find(key)!=string::npos) - { - file_coverage_map=it->second; - break; - } - } - - - cerr<<"######PreFile Report: Accumulated results prior to processing file: "<<url<<"######"<<endl; - //Print_Report(); - - cout<<"PNTransformDriver: Protecting File: "<<url<<endl; - GenerateTransformsHidden(file_coverage_map); - } - } - - if (write_stack_ir_to_db) - { - WriteStackIRToDB(); - } - - if(timeExpired) - cerr<<"Time Expired: Commit Changes So Far"<<endl; - - Update_FrameSize(); // call before finalizing transformations - - //finalize transformation, commit to database - Finalize_Transformation(); - - //TODO: clean up malloced (new'ed) FileIR_t - - cerr<<"############################Final Report############################"<<endl; - Print_Report(); - Print_Map(); -} - -// count_prologue_pushes - -// start at the entry point of a function, and count all push instructions -static pair<int,int> get_prologue_data(Function_t *func) -{ - int count=0; - int subs=0; - Instruction_t* insn=NULL, *prev=NULL; - - // note: GetNextInstruction will return NULL if it tries to leave the function - // or encounters conditional control flow (it will follow past unconditional control flow - // it also stops at indirect branches (which may leave the function, or may generating - // multiple successors) - int i; - for(i=0,insn=func->getEntryPoint(); insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i,insn=GetNextInstruction(prev,insn, func)) - { - const auto dp=DecodedInstruction_t::factory(insn); - const auto &d=*dp; - if(d.getMnemonic() == "sub" && d.getOperand(0)->isRegister() && d.getOperand(0)->getRegNumber()==4 ) - { - subs++; - } - else if(d.getMnemonic() == "push") - { - if( d.getOperand(0)->isConstant() ) - { - // push imm followed by a jump outside the function. - // this is a call, don't count it as a push. - } - else - count++; - } - - prev=insn; - } - return pair<int,int>(count,subs); -} - - -static bool is_exit_insn(Instruction_t* prev) -{ - if(prev->getFallthrough()!=NULL && prev->getTarget()!=NULL) - return false; // cond branch - - // check for fixed_call - const auto reloc_it=find_if(ALLOF(prev->getRelocations()), [&](const Relocation_t* r) - { 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); - const auto &d=*dp; - if(d.isReturn() ) - return true; - - const auto ib_targets=prev->getIBTargets(); - 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. - } - - return NULL; // indirect branch of some unknown type? - } - - // target or fallthrough is null, but exactly 1 is non-null - - const auto next_insn = prev->getTarget() ? prev->getTarget() : prev->getFallthrough(); - assert(next_insn); - - return (next_insn->getFunction() != prev->getFunction()); -} - -Instruction_t* find_exit_insn(Instruction_t *insn, Function_t *func) -{ - Instruction_t *prev=NULL; - for(int i=0; insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i, insn=GetNextInstruction(prev,insn, func)) - { - prev=insn; - } - - return is_exit_insn(prev) ? prev : NULL; - -} - - -// check for a conditional frame -- that is, a cond branch before the sub resp -static bool check_for_cond_frame(Function_t *func, ControlFlowGraph_t* cfg) -{ - assert(func && cfg); - const auto b=cfg->getEntry(); - - - 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. */ - }; - - const auto is_rsp_sub_insn= [&](const Instruction_t* i) -> bool - { - const auto d=DecodedInstruction_t::factory(i); - return is_rsp_sub(*d); - }; - - if(!b) - return true; - - const auto has_rsp_sub_it= find_if(ALLOF(func->getInstructions()), is_rsp_sub_insn); - - if(has_rsp_sub_it == func->getInstructions().end()) - return true; - - for(const auto &i : b->getInstructions()) - { - if(is_rsp_sub_insn(i)) - { - return true; /* found the sub first. */ - } - if(i->getTarget() && i->getFallthrough()) /* is cond branch */ - { - cout<<"Found cond-frame in "<<func->getName()<<" because "<<i->getDisassembly()<<endl; - return false; - } - - } - return true; -} - -// check_for_push_pop_coherence - -// we are trying to check whether the function's prologue uses -// the same number of push as each exit to the function does. -// odd things happen if we can't match pushes and pops. -// but, we are actively trying to ignore pushes/pops related to calling another function. -// return true if push/pop coherence is OK. -// false otherwise. -static bool check_for_push_pop_coherence(Function_t *func) -{ - - // count pushes in the prologue - const pair<int,int> p=get_prologue_data(func); - const int prologue_pushes=p.first; - const int prologue_subrsps=p.second; - - - -//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; - map<Instruction_t*, int> found_leave_per_exit; - map<Instruction_t*, int> found_addrsp_per_exit; - - // now, look for pops, and fill in that map. - for( - set<Instruction_t*>::const_iterator it=func->getInstructions().begin(); - it!=func->getInstructions().end(); - ++it - ) - { - Instruction_t* insn=*it; - const auto dp=DecodedInstruction_t::factory(insn); - const auto &d=*dp; - if((d.getMnemonic()== "add" || d.getMnemonic() == "lea") && d.getOperand(0)->isRegister() && d.getOperand(0)->getRegNumber()==4) - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - if(exit_insn) - found_addrsp_per_exit[exit_insn]++; - } - //else if(string(d.Instruction.Mnemonic) == "leave ") - else if(d.getMnemonic() == "leave") - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - if(exit_insn) - found_leave_per_exit[exit_insn]++; - } - //else if(string(d.Instruction.Mnemonic)=="pop ") - else if(d.getMnemonic() == "pop") - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - - if(exit_insn) - { -//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 - pop_count_per_exit[exit_insn]=0; // init - - pop_count_per_exit[exit_insn]++; - } - 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; - } - } - } - - // now, look at each exit with pops, and verify the count matches the push count. - // we always allow an exit point from the function to have 0 pops, as things like - // calls to non-return functions (e.g., exit, abort, assert_fail) don't clean up the - // 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 - ) - { - pair<Instruction_t*const,int> map_pair=*it; - Instruction_t* insn=map_pair.first; - assert(insn); - - // do the check - if(prologue_pushes != map_pair.second && found_leave_per_exit[insn]==0) - { - cerr<<"Sanitizing function "<<func->getName()<<" because pushes don't match pops for an exit"<<endl; - return false; - } - } - - - for(const auto insn : func->getInstructions()) - { - if(!is_exit_insn(insn)) - continue; - if ( prologue_subrsps == 0) - { - if(found_leave_per_exit[insn]!=0 || found_addrsp_per_exit[insn]!=0) - { - cerr<<"Sanitizing function "<<func->getName()<<" because prologue subrsps=0 and leave=" - <<dec<<found_leave_per_exit[insn]<<", addrsps!="<<found_addrsp_per_exit[insn]<<" for an exit at " - <<hex<<"0x"<<insn->getAddress()->getVirtualOffset()<<endl; - return false; - } - } - else if ( prologue_subrsps == 1 ) - { - if(found_leave_per_exit[insn]==1 && found_addrsp_per_exit[insn]==0) - { - // this case is OK, there's a leave that matches the prologue - } - else if(found_leave_per_exit[insn]==0 && found_addrsp_per_exit[insn]==1) - { - // this case is OK, there's an addrsp that matches the prologue - } - else - { - cerr<<"Sanitizing function "<<func->getName()<<" because prologue subrsps=1 and leave=" - <<dec<<found_leave_per_exit[insn]<<", addrsps!="<<found_addrsp_per_exit[insn]<<" for an exit at " - <<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; -} - -/* - * 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. - -*/ -bool check_for_bad_variadic_funcs(Function_t *func, const ControlFlowGraph_t* cfg) -{ - BasicBlock_t *b=cfg->getEntry(); - - - /* sanity check that there's an entry block */ - if(!b) - return true; - - /* sanity check for ending in an indirect branch */ - if(!b->endsInIndirectBranch()) - return true; - - const auto& insns=b->getInstructions(); - - for(vector<Instruction_t*>::const_iterator it=insns.begin(); it!=insns.end(); ++it) - { - Instruction_t* insn=*it; - const auto dp=DecodedInstruction_t::factory(insn); - const auto &d=*dp; - - /* found the suspicious move insn first */ - const auto disassembly=d.getDisassembly(); - const auto c_str=disassembly.c_str(); - if(strcmp(c_str /*.CompleteInstr*/,"movzx eax, al")==0) - return false; - - - /* else, check for a use or def of rax in any of it's forms */ - if(strstr(c_str /*d.CompleteInstr*/,"eax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"rax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"ax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"ah")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"al")!=0) - return true; - } - - return true; -} - - -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; - } - return NULL; -} - -/* - * PNTransformDriver::check_jump_tables - - * - * look for jmp [reg*8+table_base] - */ -bool PNTransformDriver::check_jump_tables(Instruction_t* insn) -{ - /* quick check to skip most instructions */ - if(insn->getTarget() || insn->getFallthrough()) - return true; - - const auto dp=DecodedInstruction_t::factory(insn); - const auto &d=*dp; - - /* only look at jumps */ - //int branch_type = d.Instruction.BranchType; - if(!d.isUnconditionalBranch() ) - return true; - - /* make sure this is an indirect branch */ - if(!d.getOperand(0)->isMemory() ) - return true; - - if(d.getOperand(0)->getScaleValue() <4) - return true; - - int displacement=d.getOperand(0)->getMemoryDisplacement() ; - - EXEIO::section* pSec=find_section(displacement,elfiop); - - if(!pSec) - return true; - - const char *secdata=pSec->get_data(); - - if(!secdata) - return true; - - int offset=displacement-pSec->get_address(); - - set<int> jump_tab_entries; - for(int i=0;jump_tab_entries.size()<5;i++) - { - if((int)(offset+i*4+sizeof(int)) > (int) pSec->get_size()) - break; - - const int *table_entry_ptr=(const int*)&(secdata[offset+i*4]); - int table_entry=*table_entry_ptr; - - if(table_entry!=0) - { -// 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 - ) - { - 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()) - { - cout<<"Sanitizing function "<< func->getName()<< "due to jump-table to diff-func detected."<<endl; - return false; - } - else - { - // cout<<"Verified that the instruction is in my function, yay!"<<endl; - } - } - } - return true; - -} - -bool PNTransformDriver::backup_until(const char* insn_type_regex, Instruction_t *& prev, Instruction_t* orig, bool recursive) -{ - prev=orig; - regex_t preg; - - 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()); - - - // 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); - return false; -} - -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); - } -} - - - - -/* check if this instruction is an indirect jump via a register, - * if so, see if the jump location is in the same function. Return false if not in the same function. - */ -bool PNTransformDriver::check_for_PIC_switch_table64(Instruction_t* insn, const DecodedInstruction_t& disasm) -{ - - /* 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 -#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. - - 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; - - // 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 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; - - 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; - - // 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); - - // sanity check there's a section - if(!pSec) - return true; - - const char* secdata=pSec->get_data(); - - // 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; - - 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); - - offset+=sizeof(int); - entry++; - - } - - return check_jump_table_entries(table_entries,insn->getFunction()); -} - -void PNTransformDriver::SanitizeFunctions() -{ - - //TODO: for now, the sanitized list is only created for an individual IR file - sanitized.clear(); - - for( - 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 - ) - { - Instruction_t* instr = *it; - - if(instr == NULL) - continue; - - const auto disasmp=DecodedInstruction_t::factory(instr); - const auto &disasm=*disasmp; - string disasm_str = disasm.getDisassembly()/*CompleteInstr*/; - - - // check if there is a fallthrough from this function - // into another function. if so, sanitize both. - if(FallthroughFunctionCheck(instr,instr->getFallthrough())) - { - //check if instruciton is a call, unconditional jump, or ret - //all other instructions should have targets within the same function - //if not, filter the functions - //int branch_type = disasm.Instruction.BranchType; - if(!disasm.isReturn() && !disasm.isUnconditionalBranch() && !disasm.isCall() /*branch_type!=RetType && branch_type!=JmpType && branch_type!=CallType*/) - // check if instr->getTarget() (for cond branches) - // exits the function. If so, sanitize both funcs. - TargetFunctionCheck(instr,instr->getTarget()); - - - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_jump_tables(instr)) - { - jump_table_sanitized++; - sanitized.insert(func); - continue; - } - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - if(!check_for_PIC_switch_table64(instr,disasm)) - { - pic_jump_table_sanitized++; - sanitized.insert(func); - continue; - } - } - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - if(instr->getEhCallSite() && - instr->getEhCallSite()->getLandingPad() && - instr->getEhCallSite()->getLandingPad()->getFunction()!=func) - { - eh_sanitized++; - sanitized.insert(func); - continue; - } - } - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_push_pop_coherence(func)) - { - push_pop_sanitized_funcs++; - sanitized.insert(func); - continue; - } - } - auto cfgp=ControlFlowGraph_t::factory(func); - auto &cfg=*cfgp; - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_cond_frame(func, &cfg)) - { - cond_frame_sanitized_funcs++; - sanitized.insert(func); - continue; - } - } - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_bad_variadic_funcs(func,&cfg)) - { - bad_variadic_func_sanitized++; - sanitized.insert(func); - continue; - } - } - } - //TODO: print sanitized list. - - 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 - ) - { - Function_t *func=*it; - if(func != NULL) - cerr<<"\t"<<func->getName()<<endl; - } -} - -inline bool PNTransformDriver::FallthroughFunctionCheck(Instruction_t* a, Instruction_t* b) -{ - if(a == NULL || b == NULL) - return true; - - if(a->getFunction() == NULL || b->getFunction() == NULL) - return true; - - // nops that fall out of a function are probably padding between functions - if(a->getDisassembly()=="nop ") - return true; - - return FunctionCheck(a->getFunction(),b->getFunction()); - -} - -inline bool PNTransformDriver::FunctionCheck(Function_t* a,Function_t* b) -{ - if(a != b) - { - //To avoid null pointer exceptions I am not going to sanitize the - //null function - if(a != NULL) - { - if(sanitized.find(a)==sanitized.end()) - function_check_sanitized++; - sanitized.insert(a); - } - if(b != NULL) - { - if(sanitized.find(b)==sanitized.end()) - function_check_sanitized++; - sanitized.insert(b); - } - return false; - } - return true; -} - - -inline bool PNTransformDriver::TargetFunctionCheck(Instruction_t* a, Instruction_t* b) -{ - if(a == NULL || b == NULL) - return true; - - return FunctionCheck(a->getFunction(),b->getFunction()); -} - - -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() ;} -}; -//Speculation note: - -//Speculation note: -//Hypothesis generation assessment and refinement prior to modification. -//hypothesis assessment and refinement after modification is performed by the recursive validation subroutine. -void PNTransformDriver::GenerateTransformsHidden(map<string,double> &file_coverage_map) -{ - SanitizeFunctions(); - - vector<validation_record> high_covered_funcs, low_covered_funcs, not_covered_funcs,shuffle_validate_funcs; - - static int funcs_attempted=-1; - - set<Function_t*, func_less<Function_t*> > sorted_funcs(ALLOF(orig_virp->getFunctions())); - - //For each function - //Loop through each level, find boundaries for each, sort based on - //the number of boundaries, attempt transform in order until successful - //or until all inferences have been exhausted - for (auto func : sorted_funcs ) - - { - /* skip before the increment, so we don't emit the message more than once */ - if(getenv("PN_NUMFUNCSTOTRY") && funcs_attempted>=atoi(getenv("PN_NUMFUNCSTOTRY"))) - { - cerr<<dec<<"Aborting transforms after func number "<<funcs_attempted<<", which is: "<< - 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); - - cerr<<"PNTransformDriver: Function #"<<std::dec<<funcs_attempted<<": "<<orig_virp->getFile()->getURL()<<" "<<func->getName()<<endl; - funcs_attempted++; - - //Check if in blacklist - if(IsBlacklisted(func)) - { - cout<<"Detected function is blacklisted: "<<func->getName()<<endl; - continue; - } - - total_funcs++; - - //Level in the hierarchy to start at - int level=0; - double func_coverage = 0; - - //see if the function is in the coverage map - if(file_coverage_map.find(func->getName()) != file_coverage_map.end()) - { - //if coverage exists, if it is above or equal to the threshold - //do nothing, otherwise set hierachy to start at the level - //passed. - func_coverage = file_coverage_map[func->getName()]; - } - - //Function coverage must be strictly greater than the threshold - if(func_coverage <= coverage_threshold) - { - if(no_validation_level < 0) - { - cout<<"PNTransformDriver: Function "<<func->getName()<< - " has insufficient coverage, aborting transformation"<<endl; - continue; - } - else - { - level = no_validation_level; - - cout<<"PNTransformDriver: Function "<<func->getName()<< - " has insufficient coverage, starting at hierarchy at " - " level "<<level<<endl; - } - } - - - // Get a layout inference for each level of the hierarchy. Sort these layouts based on - // the number of memory objects detected (in descending order). Then try each layout - // as a basis for transformation until one succeeds or all layouts in each level of the - // hierarchy have been exhausted. - - //TODO: need to properly handle not_transformable and functions failing all transforms. - vector<PNStackLayout*> layouts; - for (; level < (int)transform_hierarchy.size() && layouts.size() == 0; ++level) - { - layouts = GenerateInferences(func, level); - } - - - //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()); - //TODO: is there a better way of checking this? -// else - - if(layouts.size() == 0) - { - not_transformable.push_back(func->getName()); - continue; - } - - - sort(layouts.begin(),layouts.end(),CompareBoundaryNumbersDescending); - - validation_record vr; - vr.hierarchy_index=level; - vr.layout_index=0; - vr.layouts=layouts; - vr.func=func; - - //For logging purposes I want to know if the layout for with the - //PN stack layout is a static stack frame. Since all inferences - //based the same stack frame should record the same result, taking - //the result from the first inference is okay. - if(!layouts[0]->IsStaticStack()) - dynamic_frames++; - - //Handle covered Shuffle Validate functions separately. - //I only suspect to see one function needing shuffle validation (main). - //Don't shuffle here. - if(layouts[0]->DoShuffleValidate() && func_coverage != 0) - { - //Note: Do not transform these functions, handled that elsewhere. - shuffle_validate_funcs.push_back(vr); - - if(func_coverage > coverage_threshold) - high_coverage_count++; - else - low_coverage_count++; - } - else - { - //Else go ahead and transform the layout. - layouts[0]->Shuffle(); - layouts[0]->AddRandomPadding(do_align); - - if(func_coverage == 0) - not_covered_funcs.push_back(vr); - else if(func_coverage <= coverage_threshold) - low_covered_funcs.push_back(vr); - else - high_covered_funcs.push_back(vr); - } - - } - - //TODO: I have seen some functions not require any modifications. In this case we should remove them from the - //vector. Not sure the best way to do this yet. For now ignore, because I have only seen it happen once (function start) - - //sort the validation records by the number of variables detected, - //to optimize validation time. - sort(high_covered_funcs.begin(),high_covered_funcs.end(),CompareValidationRecordAscending); - sort(low_covered_funcs.begin(),low_covered_funcs.end(),CompareValidationRecordAscending); - - //TODO: maybe validate those layouts with 3 or fewer variables first? - //the sorting approach I now do might sufficiently optimize that this - //isn't necessary. - Validate_Recursive(high_covered_funcs,0,high_covered_funcs.size()); - - - //In theory, functions with no coverage will not have any benefit from validation - //but coverage can sometimes be wrong. For example, if PIN failed, perhaps - //the coverage reflects functions that were executed only if the test - //run fails. Go ahead and attempt binary validation on non-covered functions. - //As an optimization I will validate non-covered funcs with functions with low coverage - //but in case a validation failure does occur, functions with no coverage - //are append to the low_covered_funcs vector. Appending to the end, as opposed to - //using one data structure for both should optimize binary search in the - //even of a validation failure, since all functions without coverage are clustered, - //and it is assumed functions with no coverage _SHOULD_ validate all the time. - low_covered_funcs.insert(low_covered_funcs.end(),not_covered_funcs.begin(),not_covered_funcs.end()); - this->Validate_Recursive(low_covered_funcs, 0, low_covered_funcs.size()); - - //NOTE: if you decide to handle not_covered_funcs separately, - //make sure you either use Validate_Recursive, or rewrite - //the instructions yourself. - - cerr<<"Functions to shuffle validate: "<<shuffle_validate_funcs.size()<<endl; - ShuffleValidation(shuffle_validate_funcs); - - if(!Validate(NULL,string(basename((char*)orig_virp->getFile()->getURL().c_str()))+"_accum")) - { - cerr<<"TEST ERROR: File: "<<orig_virp->getFile()->getURL()<<" does not pass accumulation validation, ignoring the file for now."<<endl; - - //TODO: carefully undo all finalization for this file, for now, - //just remove the FileIR_t from the registered_firps - registered_firps.erase(orig_virp); - - return; - } - else - { - cerr<<"File Accumulation Validation Success"<<endl; - } - - high_coverage_count +=high_covered_funcs.size(); - low_coverage_count +=low_covered_funcs.size(); - no_coverage_count +=not_covered_funcs.size(); - - //TODO: print file report -} - -//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 - //have PNStackLayout objects preven padding or shuffling - //if it is not appropriate. In theory I could just use - //one handler now, but since I know a canary should not - //be used here, I will explicitly use a function that - //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. - //Really this means if we have a P1 layout, we wont - //shuffle it because it can't be, so padding will be - //added and validated once. I make the assumption a layout - //never can switch to suddenly being canary safe. - layout = Get_Next_Layout(vrs[i]); - } - else - { - //else transformation was success, register the validation record - Register_Finalized(vrs,i,1); - break; - } - } - - if(layout == NULL) - { - failed.push_back(vrs[i].func); - cout<<"Shuffle Validation: Function: "<<vrs[i].func->getName()<<" has no additional inferences."<<endl; - } - } - -// return success; -} - -//Alters the passed in validation record to record the layout information, and -//for simplicity returns the next layout object (PNStackLayout*) -//returns NULL if no layout is next. -PNStackLayout* PNTransformDriver::Get_Next_Layout(validation_record &vr) -{ - //if the layout is not the last in the vector of layouts for the hierarchy, set the layout to the next layout - if(vr.layout_index != vr.layouts.size()-1) - { - vr.layout_index++; - } - //otherwise, continue looping through the hierarchy until inferences are generated. - else - { - vector<PNStackLayout*> layouts; - unsigned int level=vr.hierarchy_index; - for(;level<(unsigned int)transform_hierarchy.size()&&layouts.size()==0;level++) - { - layouts = GenerateInferences(vr.func, level); - } - - //If no layouts are found, then this function fails all validation attempts - if(layouts.size() == 0) - { - return NULL; - } - else - { - sort(layouts.begin(),layouts.end(),CompareBoundaryNumbersDescending); - - //update info in the validation record. - vr.layout_index=0; - vr.layouts=layouts; - vr.hierarchy_index=level; - } - } - - return vr.layouts[vr.layout_index]; -} - -int intermediate_report_count=0; -void PNTransformDriver::Register_Finalized(vector<validation_record> &vrs,unsigned int start, int length) -{ - if(length == 0) - return; - - cout<<"Register Finalized: Registering "<<length<<" functions"<<endl; - - for(int i=0;i<length;i++) - { - unsigned int index=i+start; - finalize_record fr; - fr.layout = vrs[index].layouts[vrs[index].layout_index]; - fr.func = vrs[index].func; - fr.firp = orig_virp; - registered_firps.insert(orig_virp); - finalization_registry.push_back(fr); - //placing layout in the history here, although the information - //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; - } - - intermediate_report_count += length; - - //print out intermedaite report every if the report count exceeds or equals 50 registered funcs - //since the last report. - if(intermediate_report_count >= 50) - { - cerr<<"############################INTERMEDIATE SUMMARY############################"<<endl; - //Print_Report(); - intermediate_report_count=0; - } -} - -//Assumed that passed in layouts have been transformed and are ready for validation. -bool PNTransformDriver::Validate_Recursive(vector<validation_record> &vrs, unsigned int start, int length) -{ - if (timeExpired || (length <= 0) || vrs.empty()) - return false; - - assert((start + length - 1) != vrs.size()); - - cout << "Validate Recursive: validating " << length << " funcs of " << vrs.size() << endl; - - //Rewrite all funcs - for (int i = 0; i < length; ++i) - { - unsigned int index = i + start; - PNStackLayout *layout = vrs[index].layouts[vrs[index].layout_index]; - - //make sure the function isn't already modified - undo(vrs[index].func); - - // Canary rewrite will determine if layout can be canaried. - // Finalization will remove canaries if appropriate. - this->Canary_Rewrite(layout,vrs[index].func); - } - - ++validation_count; - stringstream ss; - ss << "validation" << validation_count; - - if (Validate(orig_virp, ss.str())) - { - Register_Finalized(vrs, start, length); - return true; - } - else - { - //TODO: optimize here - for (int i = 0; i < length; ++i) - { - unsigned int index = i + start; - undo(vrs[index].func); - } - - if (length == 1) - { - cout << "Validate Recursive: Found problem function: " << vrs[start].func->getName() << " validating linearly" << endl; - - if (Get_Next_Layout(vrs[start]) == NULL) - { - failed.push_back(vrs[start].func); - cout << "Validate Recursive: Function: " << vrs[start].func->getName() << " has no additional inferences." << endl; - return false; - } - - vrs[start].layouts[vrs[start].layout_index]->Shuffle(); - vrs[start].layouts[vrs[start].layout_index]->AddRandomPadding(do_align); - - this->Validate_Recursive(vrs, start, length); - return false; - } - else - { - //Algorithm Idea: undo modifications half at a time, until the side of the vector of mods - //containing the error is found. If found, send to Validate_Recursive. - //Finalize all remaining. - - bool left_val, right_val; - left_val = Validate_Recursive(vrs,start,length/2); - right_val = Validate_Recursive(vrs,start+length/2,(length-(length/2))); - - if(left_val && right_val) - cerr<<"TESTING ERROR: TESTING THE WHOLE REPORTED FAILURE, TESTING THE HALVES REPORTS SUCCESS"<<endl; - - 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; - - //TODO: one more validation? - cerr<<"Sanity validation check....."<<endl; - - if( !Validate(NULL,"validation_final")) - { - cerr<<"TEST ERROR: Sanity validation failed!! Backing off all transformations (PN disabled for this program)."<<endl; - return; - } - else - cerr<<"Sanity validation passed."<<endl; - - - //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 - ) - { - FileIR_t *firp = *it; - cout<<"Writing to DB: "<<firp->getFile()->getURL()<<endl; - // firp->writeToDB(); skip, thanos does this! - } -} - -void PNTransformDriver::Update_FrameSize() -{ - map<string,vector<PNStackLayout*> >::const_iterator it; - for(it = transformed_history.begin(); it != transformed_history.end(); it++) - { - //TODO: how do we know which layout we want??? - for(unsigned int i=0;i<it->second.size();i++) - { - auto func = it->second[i]->getFunction(); - if (!func) continue; - - const auto alteredAllocSize = it->second[i]->GetAlteredAllocSize(); - if (alteredAllocSize > 0) - { - cout << "DEBUG: function: " << func->getName() << " orig size: " << func->getStackFrameSize() << " altered size: " << alteredAllocSize << endl; - func->setStackFrameSize(alteredAllocSize); - } - } - } -} - -void PNTransformDriver::Print_Report() -{ - cerr<<dec<<endl; - cerr<<"############################SUMMARY############################"<<endl; - - cerr<<"Functions Transformed"<<endl; - - map<string,vector<PNStackLayout*> >::const_iterator it; - int total_transformed = 0; - - - vector<string> history_keys; - 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++) - { - cerr<<"\t"<<it->second[i]->ToString()<<endl; - } - - history_keys.push_back(it->first); - } - - cerr<<"-----------------------------------------------"<<endl; - cerr<<"Non-Transformable Functions"<<endl; - - for(unsigned int i=0;i<not_transformable.size();++i) - { - cerr<<"\t"<<not_transformable[i]<<endl; - } - - cerr<<"-----------------------------------------------"<<endl; - cerr<<"Functions Failing All Validation"<<endl; - - for(unsigned int i=0;i<failed.size();++i) - { - cerr<<"\t"<<failed[i]->getName()<<endl; - } - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Statistics by Transform"<<endl; - - for(unsigned int i=0;i<history_keys.size();++i) - { - cerr<<"\tLayout: "<<history_keys[i]<<endl; - cerr<<"# ATTRIBUTE Layout="<<history_keys[i]<<endl; - vector<PNStackLayout*> layouts = transformed_history[history_keys[i]]; - - map<int,int> obj_histogram; - - cerr<<"\t\tTotal Transformed: "<<layouts.size()<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Total_Transformed="<<layouts.size()<<endl; - - int p1reductions = 0; - double mem_obj_avg = 0.0; - double mem_obj_dev = 0.0; - for(unsigned int laynum=0;laynum<layouts.size();++laynum) - { - if(layouts[laynum]->IsP1()) - p1reductions++; - - unsigned int num_objects = layouts[laynum]->GetNumberOfMemoryObjects(); - - if(obj_histogram.find(num_objects) == obj_histogram.end()) - obj_histogram[num_objects] = 1; - else - obj_histogram[num_objects] = obj_histogram[num_objects]+1; - - mem_obj_avg += num_objects; - } - mem_obj_avg = mem_obj_avg/(double)layouts.size(); - - for(unsigned int laynum=0;laynum<layouts.size();++laynum) - { - mem_obj_dev += pow((((double)layouts[laynum]->GetNumberOfMemoryObjects())-mem_obj_avg),2); - } - - mem_obj_dev = sqrt(mem_obj_dev/(double)layouts.size()); - - cerr<<"\t\tMemory Object Average: "<<mem_obj_avg<<endl; - cerr<<"\t\tMemory Object Deviation: "<<mem_obj_dev<<endl; - cerr<<"\t\tObject Histogram:"<<endl; - - map<int,int>::const_iterator hist_it; - for(hist_it = obj_histogram.begin();hist_it != obj_histogram.end();hist_it++) - { - cerr<<"\t\t\tMemory Objects: "<<hist_it->first<<" Instances: "<<hist_it->second<<endl; - } - - cerr<<"\t\tP1 Reductions: "<<p1reductions<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::P1_Reductions="<<p1reductions<<endl; - } - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Functions validated exceeding threshold: "<<high_coverage_count<<endl; - cerr<<"Functions validated with non-zero coverage below or equal to threshold: "<<low_coverage_count<<endl; - cerr<<"Functions modified with no coverage: "<<no_coverage_count<<endl; - cerr<<"Total recursive validations performed: "<<validation_count<<endl; - cerr<<"----------------------------------------------"<<endl; - cerr<<"Total dynamic stack frames: "<<dynamic_frames<<endl; - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Non-Blacklisted Functions \t"<<total_funcs<<endl; - cerr<<"Blacklisted Functions \t\t"<<blacklist_funcs<<endl; - cerr<<"Sanitized Functions \t\t"<<sanitized_funcs<<endl; - cerr<<"Push/Pop Sanitized Functions \t\t"<<push_pop_sanitized_funcs<<endl; - cerr<<"Function target/fallthorugh Sanitized Functions \t\t"<< function_check_sanitized <<endl; - cerr<<"Cond Frame Sanitized Functions \t\t"<<cond_frame_sanitized_funcs<<endl; - cerr<<"EH-land-pad-not-in-func Sanitized Functions \t\t"<<eh_sanitized<<endl; - cerr<<"Bad Variadic Sanitized Functions \t\t"<<bad_variadic_func_sanitized<<endl; - cerr<<"Jump table Sanitized Functions \t\t"<<jump_table_sanitized<<endl; - cerr<<"PIC Jump table Sanitized Functions \t\t"<<jump_table_sanitized<<endl; - cerr<<"Transformable Functions \t"<<(total_funcs-not_transformable.size())<<endl; - cerr<<"Transformed \t\t\t"<<total_transformed<<endl; - - - const auto pct_transformable_transformed=((double)(total_transformed)/(double)(total_funcs-not_transformable.size()))*100.00; - const auto pct_transformable=((double)(total_funcs-not_transformable.size())/(double)total_funcs)*100.00; - const auto pct_sanitized=((double)(sanitized_funcs)/(double)(total_funcs+sanitized.size()))*100.00; - - assert(getenv("SELF_VALIDATE")==nullptr || blacklist_funcs < 10); - assert(getenv("SELF_VALIDATE")==nullptr || pct_transformable > 10); - assert(getenv("SELF_VALIDATE")==nullptr || pct_transformable_transformed > 90); - assert(getenv("SELF_VALIDATE")==nullptr || pct_sanitized < 30); - - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_validated_exceeding_threshold="<<high_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_validated_with_nonZero_coverage_below_or_equal_to_threshold="<<low_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_modified_with_no_coverage="<<no_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Total_recursive_validations_performed="<<validation_count<<endl; - - cerr<<"# ATTRIBUTE Stack_Transformation::NonBlacklisted_Functions="<<total_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Blacklisted_Functions="<<blacklist_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Sanitized_Functions="<<sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::PushPop_Sanitized_Functions="<<push_pop_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::CondFrameSanitized_Functions="<<cond_frame_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::EH_land_pad_not_in_FuncSanitizedFunctions="<<eh_sanitized<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::BadVariadicSanitizedFunctions="<<push_pop_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::JumpTableSanitized_Functions="<<jump_table_sanitized<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::PICJumpTableSanitized_Functions="<<jump_table_sanitized<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Percent_of_Functions_that_are_Sanitized="<<pct_sanitized<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Total_Number_of_Functions="<<total_funcs<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Transformable_Functions="<<(total_funcs-not_transformable.size())<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Percent_of_Functions_that_are_Transformable="<<std::fixed <<std::setprecision(1)<< pct_transformable <<"%"<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Total_Transformed_Functions="<<total_transformed<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Percent_Transformable_Functions_Transformed="<<std::fixed<<std::setprecision(1)<< pct_transformable_transformed <<"%"<<endl; -} - - -vector<PNStackLayout*> PNTransformDriver::GenerateInferences(Function_t *func,int level) -{ - vector<PNStackLayout*> layouts; - - for (unsigned int inf = 0; inf < transform_hierarchy[level].size(); ++inf) - { - 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; - } - else - { - cerr << "PNTransformDriver: Inference Successfully Generated" << endl; - layouts.push_back(tmp); - } - } - - return layouts; -} - -bool PNTransformDriver::ShuffleValidation(int reps, PNStackLayout *layout,Function_t *func) -{ - if(!layout->DoShuffleValidate()) - return true; - - cerr<<"PNTransformDriver: ShuffleValidation(): "<<layout->GetLayoutName()<<endl; - - for(int i=0;i<reps;i++) - { - if(timeExpired) - return false; - - cerr<<"PNTransformDriver: ShuffleValidation(): Shuffle attempt "<<i+1<<endl; - - layout->Shuffle(); - - if(!Sans_Canary_Rewrite(layout, func)) - { - undo(func); - cerr<<"PNTransformDriver: ShuffleValidation(): Rewrite Failure: attempt: "<<i+1<<" "<< - layout->GetLayoutName()<<" Failed to Rewrite "<<func->getName()<<endl; - return false; - } - else if(!Validate(orig_virp,func->getName())) - { - undo(func); - cerr<<"PNTransformDriver: ShuffleValidation(): Validation Failure: attempt: "<<i+1<<" "<< - layout->GetLayoutName()<<" Failed to Validate "<<func->getName()<<endl; - return false; - } - else - { - undo(func); - } - } - - return true; -} - -// Validate the modifications for the passed in FileIR_t*, creating -// a directory structure for the generated spri files in a directory -// reflecting the passed in string. -// -// If the FileIR_t* is null, Validate will generate spri -// for as FileIR_t* that have been registered in the FileIR_t* -// registry (entries in this structure are made whenever -// a function has been registered for finalization). -// Passing NULL essentially provides a mechanism of revalidating all -// previously modified and validated functions. -bool PNTransformDriver::Validate(FileIR_t *virp, string name) -{ - if(!pn_options->getShouldSpriValidate()) - 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() -{ - - /* get a canary value from the options. - * assume the options package is returning a full 32-bits of entropy. - */ - 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) - { - esp_reg = "esp"; - word_dec = "dword"; - } - else - { - esp_reg = "rsp"; - word_dec = "qword"; - } - - if (verbose_log) - cout << "PNTransformDriver: CanaryRewrite: Rewriting function named " << func->getName() << endl; - - - //TODO: hack for TNE, assuming all virp is orig_virp now. - FileIR_t *virp = orig_virp; - - if (!orig_layout->IsCanarySafe()) - return Sans_Canary_Rewrite(orig_layout,func); - - PNStackLayout tmp = orig_layout->GetCanaryLayout(); - PNStackLayout *layout = &tmp; - vector<canary> canaries; - - vector<PNRange*> mem_objects = layout->GetRanges(); - - for (unsigned int i = 0; i < mem_objects.size(); ++i) - { - canary c; - - int floating_canary_offset = 0; - - if (do_floating_canary) - { - // nb: get_saved_reg_size is 4 or 8 depending on architecture - int reg_size = get_saved_reg_size(); - floating_canary_offset = (rand() % (layout->GetAlteredAllocSize() - layout->GetOriginalAllocSize() - reg_size)); - floating_canary_offset -= (floating_canary_offset % reg_size); - assert(floating_canary_offset >= 0); - c.floating_offset = floating_canary_offset; - } - else - { - c.floating_offset = 0; - } - - c.esp_offset = mem_objects[i]->getOffset() + mem_objects[i]->GetDisplacement() + mem_objects[i]->getSize(); - c.esp_offset += floating_canary_offset; - - assert(c.esp_offset >= 0); - - //TODO: make this random - c.canary_val = GetRandomCanary(); - - //bytes to frame pointer or return address (depending on if a frame - //pointer is used) from the stack pointer - c.ret_offset = (layout->GetAlteredAllocSize() + layout->GetSavedRegsSize()); - //if frame pointer is used, add 4/8 bytes to get to the return address - if (layout->HasFramePointer()) - c.ret_offset += get_saved_reg_size(); - - //Now with the total size, subtract off the esp offset to the canary - c.ret_offset = c.ret_offset - c.esp_offset; - - //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]; - memset(pmatch, 0, sizeof(regmatch_t) * max); - - const auto old_insns=func->getInstructions(); - for(auto instr : old_insns) - { - - string matched= ""; - string disasm_str = ""; - - const auto disasmp = DecodedInstruction_t::factory(instr); - const auto &disasm = *disasmp; - disasm_str = disasm.getDisassembly(); - - if (verbose_log) - cerr << "PNTransformDriver: Canary_Rewrite: Looking at instruction " << disasm_str << endl; - - //TODO: is the stack_alloc flag necessary anymore? - if (regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), 5, pmatch, 0) == 0) - { - if (verbose_log) - cerr << "PNTransformDriver: Canary Rewrite: Transforming Stack Alloc" << endl; - - //TODO: determine size of alloc, and check if consistent with alloc size? - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - 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) - { - // If this occurs, then the found stack size is not a - // constant integer, so it must be a register. - - //cerr<<"PNTransformDriver: Canary Rewrite: Stack alloc of non-integral type ("<<matched<<"), ignoring instruction "<<endl; - - // TODO: hack for TNE, assuming that instruction_rewrite - // will add padding to dynamic arrays. - this->Instruction_Rewrite(layout, instr, &cfg); - continue; - } - } - - //TODO: I need a check to see if the previous amount is equal to - //the expect stack frame, a check is done is the inference - //generation now, so it should be okay without it, - - 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; - instr = P1_insertAssemblyAfter(virp,instr,ss.str()); - if(i==0) - instr->setComment("Canary Setup Entry: "+ss.str()); - else - instr->setComment("Canary Setup: "+ss.str()); - if(verbose_log) - cerr << "PNTransformDriver: canary setup = " << ss.str() << endl; - } - } - else if(regexec(&(pn_regex->regex_ret), disasm_str.c_str(),5,pmatch,0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Canary Rewrite: inserting ret canary check"<<endl; - - - - - //This could probably be done once, but having the original instruction - //allows me to produce messages that indicate more precisely where - //the overflow occurred. - Instruction_t *handler_code = getHandlerCode(virp,instr,GetMitigationPolicy(),GetDetectionExitCode()); - - //insert canary checks - // - //TODO: may need to save flags register - - for(unsigned int i=0;i<canaries.size();i++) - { - instr = insertCanaryCheckBefore(virp,instr,canaries[i].canary_val,canaries[i].ret_offset, handler_code); - } - } - //if the stack is not believed to be static, I can't check the canary using esp. - //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; - - //This could probably be done once, but having the original instruction - //allows me to produce messages that indicate more precisely where - //the overflow occurred. - Instruction_t *handler_code = getHandlerCode(virp,instr,GetMitigationPolicy(),GetDetectionExitCode()); - - //insert canary checks - // - //TODO: may need to save flags register - for(unsigned int i=0;i<canaries.size();i++) - { - instr = insertCanaryCheckBefore(virp,instr,canaries[i].canary_val,canaries[i].esp_offset, handler_code); - } - // A call instruction could need to be rewritten, in addition to inserting a canary - // check before it. E.g. call [rsp+k] where [rsp+k] is in the incoming args region. - if (!this->Instruction_Rewrite(layout, instr, &cfg)) - return false; - } - //TODO: message if not static stack? - else - { - if(!this->Instruction_Rewrite(layout,instr, &cfg)) - return false; - } - } - - - 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()) - return false; - - return true; -} - -bool PNTransformDriver::Sans_Canary_Rewrite(PNStackLayout *layout, Function_t *func) -{ - //TODO: add return value - if(verbose_log) - cerr<<"PNTransformDriver: Sans Canary Rewrite for Function = "<<func->getName()<<endl; - - auto cfgp=ControlFlowGraph_t::factory(func); - auto &cfg=*cfgp; - - const auto old_insns=func->getInstructions(); - for(auto instr : old_insns) - { - string disasm_str = ""; - const auto disasm=DecodedInstruction_t::factory(instr); - disasm_str = disasm->getDisassembly(); - - if(verbose_log) - cerr<<"PNTransformDriver: Sans_Canary_Rewrite: Looking at instruction "<<disasm_str<<endl; - - if(!this->Instruction_Rewrite(layout, instr, &cfg)) - return false; - } - - EhUpdater_t eh_update(orig_virp, func, layout); - if(!eh_update.execute()) - return false; - - return true; -} - - - -static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* insn, Function_t* func) -{ - 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; - - /* if there's a target, but no fallthrough, and the target is in the function */ - if(!ft && targ && func->getInstructions().find(targ)!=func->getInstructions().end()) - return targ; - - return NULL; -} - -// -// PNTransformDriver::prologue_offset_to_actual_offset - -// Look in the CFG to see if instr is in the prologue before the stack allocation instruction. -// If so, attempt to adjust offset so that it is relative to the offset after the stack has -// been allocated. Return adjusted offset if succesfful, else unadjusted offset. -// -int PNTransformDriver::prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, Instruction_t *instr,int offset) -{ - Function_t* func=cfg->getFunction(); - assert(func); - BasicBlock_t* entry_block=cfg->getEntry(); - if(!entry_block) - return offset; - - /* find the instruction in the vector */ - set<Instruction_t*>::iterator it= func->getInstructions().find(instr); - - /* if the instruction isn't in the entry block, give up now */ - if( it == func->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)) - { - 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) - 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)); - - /* check for a stack alloc */ - if(regexec(&(pn_regex->regex_stack_alloc), d.getDisassembly().c_str() /*CompleteInstr*/, 5, pmatch, 0)==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) - { - 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) - return offset; - - // success - return offset+ssize; - - } - return offset; - - } - // else, check next instruction - - - } - - return offset; - -} - -inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instruction_t *instr, ControlFlowGraph_t* cfg) -{ - FileIR_t* virp = orig_virp; - - string esp_reg="esp"; - if (FileIR_t::getArchitectureBitWidth() == 64) - esp_reg = "rsp"; - - const int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch = new regmatch_t[max]; // (regmatch_t*)malloc(max*sizeof(regmatch_t)); - regmatch_t pmatch2[max]; - memset(pmatch, 0, sizeof(regmatch_t) * max); - memset(pmatch2, 0, sizeof(regmatch_t) * max); - - string matched = ""; - string disasm_str = ""; - 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) - { - if (verbose_log) - cerr << "PNTransformDriver: Transforming LEA Instruction" << endl; - - matched = ""; - for (int k = 1; k < 5; ++k) - { - if (pmatch[k].rm_so >= 0 && pmatch[k].rm_eo >= 0) - { - int mlen = pmatch[k].rm_eo - pmatch[k].rm_so; - matched.append(disasm_str.substr(pmatch[k].rm_so,mlen)); - } - } - disasm_str = matched; - if(verbose_log) - cerr<<"PNTransformDriver: New LEA Instruction = "<<disasm_str<<endl; - - matched = ""; - } - - - if(instr->getFunction() && instr->getFunction()->getUseFramePointer() && regexec(&(pn_regex->regex_add_rbp), disasm_str.c_str(), 5, pmatch, 0) == 0) - { - if(verbose_log) - cerr << "PNTransformDriver: found add rbp insn: "<<disasm_str<<endl; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - string dstreg=disasm_str.substr(pmatch[1].rm_so,mlen); - - int new_offset = layout->GetNewOffsetEBP(1); /* make sure we get something from within the stack frame */ - new_offset-=1; /* re-adjust for the -8 above */ - - stringstream lea_string; - if(virp->getArchitectureBitWidth()==64) - lea_string<<"lea "<<dstreg<<", [rbp+"<<dstreg<<" - 0x"<<std::hex<<new_offset<<"]"; - else - lea_string<<"lea "<<dstreg<<", [ebp+"<<dstreg<<" - 0x"<<std::hex<<new_offset<<"]"; - - if(verbose_log) - 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) - { - if(verbose_log) - cerr << "PNTransformDriver: Transforming Stack Alloc"<<endl; - - //TODO: determine size of alloc, and check if consistent with alloc size? - - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - 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) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //cerr<<"PNTransformDriver: Stack alloc of non-integral type ("<<matched<<"), ignoring instruction"<<endl; - - //TODO: hack for TNE, padd the allocation by adding a random - //amount to the register used to subtract from esp. - - stringstream ss_add; - stringstream ss_sub; - //TODO: I am uncertain how alignment will work in this situation - //if the layout is aligned, this will return a padding amount - //divisible by the alignment stride, however, without knowing - //the size of the object, this may not ensure alignment, it is - //up to the compiler to handle that else where. - auto rand_pad=layout->GetRandomPadding(); - ss_add<<"add "<<esp_reg<<" , 0x"<<hex<<rand_pad;//"0x500"; - ss_sub<<"sub "<<esp_reg<<" , 0x"<<hex<<rand_pad;//"0x500"; - - if(verbose_log) - { - cerr<<"PNTransformDriver: adding padding to dynamic stack allocation"<<endl; - cerr<<"PNTransformDriver: inserted instruction before = "<<ss_add.str()<<endl; - cerr<<"PNTransformDriver: inserted instruction after = "<<ss_sub.str()<<endl; - } - - Instruction_t *new_instr = P1_insertAssemblyBefore(virp,instr,ss_add.str(),NULL); - new_instr->setComment("Dynamic array padding:" +ss_add.str()); - - P1_insertAssemblyAfter(virp,instr,ss_sub.str(),NULL); - return true; - } - } - - 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) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP +scale w/o displacement Instruction ([esp+reg*scale])"<<endl; - - PNRange *closest = layout->GetClosestRangeESP(0); - - if(closest == NULL) - { - //There should always be a closet range to esp+0 - assert(false); - } - - int new_offset = closest->GetDisplacement(); - - assert(new_offset >= 0); - - if(new_offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Displacement of [esp+reg*scale] is Zero, Ignoring Transformation"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - matched=((string)"+ 0x")+ss.str()+"]"; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - 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) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP Only Instruction ([esp])"<<endl; - - PNRange *closest = layout->GetClosestRangeESP(0); - - if(closest == NULL) - { - //There should always be a closest range to esp+0 - assert(false); - } - - int new_offset = closest->GetDisplacement(); - - assert(new_offset >= 0); - - if(new_offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Displacement of [esp] is Zero, Ignoring Transformation"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - 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) - { - - if(verbose_log) - { - cerr<<"PNTransformDriver: Transforming ESP-k Relative Instruction"<<endl; - } - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - //TODO: I don't think this can happen but just in case - assert(offset > 0); - - int revised_offset=prologue_offset_to_actual_offset(cfg,instr,-offset); - - if(revised_offset<0) - { - if(verbose_log) - cerr<<"PNTransformDriver: ignoring, not in prologue "<<endl; - - } - else - { - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k revised_offset is "<<std::hex<<revised_offset<<endl; - int new_location = layout->GetNewOffsetESP(revised_offset); - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k new_location is "<<std::hex<<new_location<<endl; - int new_offset = new_location-layout->GetAlteredAllocSize(); - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k new_offset is "<<std::hex<<new_offset<<endl; - - // 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 - 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) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP Relative Instruction"<<endl; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - //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) - { - if(verbose_log) - cerr<<"JDH: PNTransformDriver: found esp+scale+const pointing at saved regs."<<endl; - new_offset=layout->GetNewOffsetESP(offset-1)+1; - } - 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. - //this should be validated prior to rewrite (i.e., this is a TODO, it hasn't been done yet). - else if(regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), 5, pmatch, 0)==0 || - regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming EBP Relative Instruction"<<endl; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Offset = "<<offset<<endl; - - int new_offset = layout->GetNewOffsetEBP(offset); - - if(new_offset == offset) - { - if(verbose_log) - cerr<<"PNTransformDriver: No offset transformation necessary, skipping instruction"<<endl; - - return true; - } - - 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; -*/ - - } - //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 - //that only p1 is performed in these cases. - //TODO: if this is encountered, insert a switch statement to evaluate at runtime - //which offset to use. e.g., [ecx+ebp*1-0x21], at run time evaluate ecx+0x21, - //and determine which reange it falls into, and jump to an instruction which - //uses the correct offset. - else if(regexec(&(pn_regex->regex_scaled_ebp_index), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming Scaled EBP Indexed Instruction"<<endl; - - int mlen = pmatch[2].rm_eo - pmatch[2].rm_so; - matched = disasm_str.substr(pmatch[2].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Offset = "<<offset<<endl; - - int new_offset = layout->GetNewOffsetEBP(offset); - - if(new_offset == offset) - { - if(verbose_log) - cerr<<"PNTransformDriver: No offset transformation necessary, skipping instruction"<<endl; - - return true; - } - - stringstream ss; - 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) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming Stack Dealloc Instruction"<<endl; - - //Check if the dealloc amount is 0. In unoptimized code, sometimes the - //compiler will reset esp, and then add 0 to esp - //In this case, do not deallocate the stack - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Dealloc Amount = "<<offset<<endl; - - if(offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Dealloc of 0 detected, ignoring instruction"<<endl; - - return true; - } - - stringstream ss; - 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 - { - if(verbose_log) - { - cerr<<"PNTransformDriver: No Pattern Match"; - if(strstr(disasm_str.c_str(), "rsp")!=NULL || - strstr(disasm_str.c_str(), "esp")!=NULL) - cerr<<"BUT CAUTION ******************* esp/rsp found in instruction."; - cerr<<endl; - } - } - return true; -} - - - -//TODO: there is a memory leak, I need to write a undo_list clear to properly cleanup -//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(); -} - -/* - void PNTransformDriver::reset_undo(string func) - { - undo_list.erase(func); - inserted_instr.erase(func); - inserted_addr.erase(func); - } -*/ - - -bool PNTransformDriver::WriteStackIRToDB() -{ - // DEBUG - cerr << "Writing stack IR to IRDB!" << endl; - - PNIrdbManager irdb_manager(this->pidp->getOriginalVariantID()); - if (!irdb_manager.TableExists()) - { - irdb_manager.CreateTable(); - } - else - { - irdb_manager.DeleteSource(PNIrdbManager::IRS_PEASOUP); - } - - std::map< std::string,std::vector<PNStackLayout*> >::const_iterator it = - transformed_history.begin(); - while (it != transformed_history.end()) - { - vector<PNStackLayout*> layouts = it->second; - for (unsigned int laynum = 0; laynum < layouts.size(); ++laynum) - { - // DEBUG - cerr << "Function: " << layouts[laynum]->getFunctionName() << endl; - - std::vector<PNRange*> mem_objects = layouts[laynum]->GetRanges(); - 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); - - // DEBUG - cerr<< "\tOffset = " << mem_objects[j]->getOffset() << " Size = "<<mem_objects[j]->getSize() << endl; - - // return with failure if any insertion fails - if (new_id == -1) - return false; - } - } - - it++; - } - - return true; -} - -void sigusr1Handler(int signum) -{ - PNTransformDriver::timeExpired = true; -} - -void PNTransformDriver::Print_Map() -{ - - map<string, vector<PNStackLayout*> >::const_iterator it; - - string exe_uri = orig_virp->getFile()->getURL(); - string map_uri = "p1.map"; - - ofstream map_file; - map_file.open(map_uri.c_str()); - - cerr << "exe_uri: " << exe_uri << endl; - cerr << "p1 map uri: " << map_uri << endl; - - map_file << "LAYOUT" << ";FUNCTION"<< ";FRAME_ALLOC_SIZE" << ";ALTERED_FRAME_SIZE" << ";SAVED_REG_SIZE" << ";OUT_ARGS_SIZE" << - ";NUM_MEM_OBJ" << ";PADDED" << ";SHUFFLED" << ";CANARY_SAFE" << ";CANARY" << ";FUNC_BASE_ID" << ";FUNC_ENTRY_ID" << ";CANARY_FLOATING_OFFSET" << "\n"; - - for(it = transformed_history.begin(); it != transformed_history.end(); it++) - { - for(unsigned int i=0;i<it->second.size();i++) - { - map_file << "" << it->second[i]->ToMapEntry() << endl; - } - - } - - map_file.close(); -} diff --git a/builtin_xforms/p1transform/PNTransformDriver.hpp b/builtin_xforms/p1transform/PNTransformDriver.hpp deleted file mode 100644 index c14019824..000000000 --- a/builtin_xforms/p1transform/PNTransformDriver.hpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNTRANSFORMDRIVER -#define __PNTRANSFORMDRIVER - -#include <vector> -#include <set> -#include <exeio.h> -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include <csignal> -#include "P1_utility.hpp" -#include <irdb-core> -#include <irdb-cfg> -#include "canary.h" -//#include <bea_deprecated.hpp> - - -//TODO: I should use the types defined by beaengine -//#define RetType 13 -//#define JmpType 11 -//#define CallType 12 - - -struct finalize_record -{ - Function_t *func; - PNStackLayout* layout; - FileIR_t *firp; -}; - -struct validation_record -{ - unsigned int hierarchy_index; - unsigned int layout_index; - vector<PNStackLayout*> layouts; - Function_t *func; -}; - - -class PNTransformDriver -{ - protected: - - IRDB_SDK::VariantID_t *pidp; - IRDB_SDK::FileIR_t *orig_virp; - EXEIO::exeio* elfiop; - std::string BED_script; - int orig_progid; - bool do_canaries; - bool do_floating_canary; - bool do_align; - //TODO: coverage map should not use function name as the key, since - //we may want to support coverage for shared objects. - std::map<std::string,std::map<std::string,double> > coverage_map; - int no_validation_level; - double coverage_threshold; - bool do_shared_object_protection; - - std::vector< std::vector<PNStackLayoutInference*> > transform_hierarchy; - PNRegularExpressions *pn_regex; - std::set<std::string> blacklist; - std::set<IRDB_SDK::Function_t*> sanitized; - std::set<std::string> only_validate_list; - //std::map<IRDB_SDK::Instruction_t*,std::string> undo_list; - //std::map<IRDB_SDK::Instruction_t*,IRDB_SDK::Instruction_t*> undo_list; - std::map<IRDB_SDK::Function_t*, std::map<IRDB_SDK::Instruction_t*,IRDB_SDK::Instruction_t*> > undo_list; - std::map< std::string,std::vector<PNStackLayout*> > transformed_history; - size_t blacklist_funcs; - size_t sanitized_funcs; - size_t push_pop_sanitized_funcs; - size_t cond_frame_sanitized_funcs; - size_t bad_variadic_func_sanitized; - size_t jump_table_sanitized; - size_t pic_jump_table_sanitized; - size_t eh_sanitized; - size_t total_funcs; - size_t dynamic_frames; - size_t function_check_sanitized; - std::vector<std::string> not_transformable; - std::vector<IRDB_SDK::Function_t*> failed; - std::vector<finalize_record> finalization_registry; - std::set<FileIR_t*> registered_firps; - int high_coverage_count, low_coverage_count, no_coverage_count, validation_count; - - // write stack objects to IRDB - bool write_stack_ir_to_db; - - mitigation_policy m_mitigation_policy; - unsigned m_exit_code; - - // a way to map an instruction to it's set of predecessors. - std::map< Instruction_t* , set<Instruction_t*> > preds; - -//virtual bool Rewrite(PNStackLayout *layout, IRDB_SDK::Function_t *func); -//virtual bool LayoutValidation(PNStackLayout *layout); -//virtual void undo(std::map<IRDB_SDK::Instruction_t*,std::string> undo_list, IRDB_SDK::Function_t *func); -//virtual void reset_undo(std::string func); - - virtual bool Validate(IRDB_SDK::FileIR_t *virp, std::string name); - virtual void undo( IRDB_SDK::Function_t *func); - virtual std::vector<PNStackLayout*> GenerateInferences(IRDB_SDK::Function_t *func, int level); - virtual bool ShuffleValidation(int reps, PNStackLayout *layout,IRDB_SDK::Function_t *func); - virtual void ShuffleValidation(std::vector<validation_record> &vrs); -//virtual void GenerateTransforms2(IRDB_SDK::FileIR_t *virp,std::vector<IRDB_SDK::Function_t*> funcs,std::string BED_script, int progid); -//virtual bool ValidateLayout(PNStackLayout *layout,std::string BED_script,int progid); -//virtual bool Canary_Rewrite(FileIR_t *virp, PNStackLayout *orig_layout,IRDB_SDK::Function_t *func); - - //altered for TNE hack for dyn array padding, assuming all virp is orig_virp - virtual bool Canary_Rewrite( PNStackLayout *orig_layout,IRDB_SDK::Function_t *func); - virtual bool Sans_Canary_Rewrite(PNStackLayout *orig_layout, IRDB_SDK::Function_t *func); - inline bool Instruction_Rewrite(PNStackLayout *layout, IRDB_SDK::Instruction_t *instr, ControlFlowGraph_t* cfg); - inline bool FunctionCheck(IRDB_SDK::Function_t* a, IRDB_SDK::Function_t* b); - inline bool TargetFunctionCheck(IRDB_SDK::Instruction_t* a, IRDB_SDK::Instruction_t* b); - inline bool FallthroughFunctionCheck(IRDB_SDK::Instruction_t* a, IRDB_SDK::Instruction_t* b); - - virtual PNStackLayout* Get_Next_Layout(validation_record &vr); - - virtual void Print_Report(); - virtual void Print_Map(); - virtual void Update_FrameSize(); -// virtual bool CanaryTransformHandler(PNStackLayout *layout, IRDB_SDK::Function_t *func,bool validate); - virtual bool PaddingTransformHandler(PNStackLayout *layout, IRDB_SDK::Function_t *func,bool validate); - virtual bool LayoutRandTransformHandler(PNStackLayout *layout, IRDB_SDK::Function_t *func, bool validate); - virtual void GenerateTransformsInit(); - virtual bool IsBlacklisted(IRDB_SDK::Function_t *func); - virtual unsigned int GetRandomCanary(); - virtual void GenerateTransformsHidden(std::map<std::string,double> &file_coverage_map); - void SanitizeFunctions(); -//virtual bool writeToDB(); - virtual bool WriteStackIRToDB(); - - virtual void Finalize_Transformation(); - void Register_Finalized(std::vector<validation_record> &vrs,unsigned int start, int length); - bool Validate_Recursive(std::vector<validation_record> &vrs, unsigned int start, int length);//,bool suspect=false); -//bool Validate_Linear(std::vector<validation_record> &vrs, unsigned int start, int length); - - // see .cpp - int prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, Instruction_t *instr,int offset); - bool check_jump_tables(Instruction_t* insn); - bool check_jump_table_entries(std::set<int> insn,Function_t *func); - bool check_for_PIC_switch_table64(Instruction_t* insn, const IRDB_SDK::DecodedInstruction_t& disasm); - bool backup_until(const char* insn_type, Instruction_t *& prev, Instruction_t* orig, bool recursive=false); - void calc_preds(); - void InitNewFileIR(File_t* this_file, IRDBObjects_t *const irdb_objects); - - - pqxxDB_t *pqxx_interface; - -public: - static bool timeExpired; - //TODO: use unsigned int? - - PNTransformDriver(IRDB_SDK::VariantID_t *pidp, std::string BED_script, pqxxDB_t *pqxx_if); - virtual ~PNTransformDriver(); - - //Level indicates the priority of the layout when attempting - //the transform. Levels start at 1 (the highest priority). A level less than 1 raises - //an exception (for now an assert will fail). If not level is - //provided, the default is level 1. - virtual void AddInference(PNStackLayoutInference *inference, int level=0); - virtual void AddBlacklist(std::set<std::string> &blacklist); - virtual void AddBlacklistFunction(std::string func_name); - virtual void AddOnlyValidateList(std::set<std::string> &only_validate_list); - virtual void SetDoCanaries(bool do_canaries); - virtual void SetDoFloatingCanary(bool do_floating_canary); - virtual void SetDoAlignStack(bool align_stack); - virtual void SetCoverageMap(std::map<std::string,std::map<std::string,double> > coverage_map); - virtual void SetNoValidationLevel(unsigned int no_validation_level); - virtual void SetCoverageThreshold(double threshold); - virtual void SetProtectSharedObjects(bool do_protection); - - virtual void GenerateTransforms(IRDBObjects_t *const irdb_objects); - virtual void SetWriteStackIrToDb(bool setting) { write_stack_ir_to_db = setting; } - - inline virtual mitigation_policy GetMitigationPolicy() const { return m_mitigation_policy; } - virtual void SetMitigationPolicy(mitigation_policy policy) { m_mitigation_policy = policy; } - virtual unsigned GetDetectionExitCode() const { return m_exit_code; } - virtual void SetDetectionExitCode(unsigned p_exitCode) { m_exit_code = p_exitCode; } -}; - -#endif - diff --git a/builtin_xforms/p1transform/PrecedenceBoundaryGenerator.hpp b/builtin_xforms/p1transform/PrecedenceBoundaryGenerator.hpp deleted file mode 100644 index e0c82b0fc..000000000 --- a/builtin_xforms/p1transform/PrecedenceBoundaryGenerator.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PRECEDENCEBOUNDGEN -#define __PRECEDENCEBOUNDGEN -#include <irdb-core> -#include <irdb-cfg> -#include "Range.hpp" -#include "StackLayout.hpp" - -class PrecedenceBoundaryGenerator -{ -public: - virtual ~PrecedenceBoundaryGenerator(){} - virtual std::vector<Range> GetBoundaries(IRDB_SDK::Function_t *func)=0; -}; - -#endif diff --git a/builtin_xforms/p1transform/PrecedenceBoundaryInference.cpp b/builtin_xforms/p1transform/PrecedenceBoundaryInference.cpp deleted file mode 100644 index 4e908b1a0..000000000 --- a/builtin_xforms/p1transform/PrecedenceBoundaryInference.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "OffsetInference.hpp" -#include "PrecedenceBoundaryInference.hpp" -#include "General_Utility.hpp" -//#include "beaengine/BeaEngine.h" -#include <cassert> -#include <iostream> -#include <cstdlib> -#include <set> -#include <fstream> -#include <algorithm> - -using namespace std; -using namespace IRDB_SDK; - - -static bool CompareRangeBaseOffset(Range a, Range b) -{ - return (a.getOffset() < b.getOffset()); -} - -//TODO: I am basically repeating this code from StackLayout.cpp for a slighly different purpose, I should abstract -//out a binary search utility. -//assuming the vector is sorted -static unsigned int GetClosestIndex(vector<Range> ranges, int loc) -{ - - int high = ((int)ranges.size())-1; - int low = 0; - int mid; - - while(low <= high) - { - mid = (low+high)/2; - if((loc < (ranges[mid].getOffset()+(int)ranges[mid].getSize())) && (loc >= ranges[mid].getOffset())) - return mid; - else if(loc > ranges[mid].getOffset()) - low = mid +1; - else - high = mid -1; - } - return -1; -} - - - -PNStackLayout* PrecedenceBoundaryInference::GetPNStackLayout(IRDB_SDK::Function_t *func) -{ - if(!base_inference || !pbgen) - return NULL; - - vector<Range> ranges = pbgen->GetBoundaries(func); - - cerr<<"PrecedenceBoundaryInference: ranges found = "<<ranges.size()<<endl; - if(ranges.size() == 0) - return NULL; - - PNStackLayout *base_layout = base_inference->GetPNStackLayout(func); - - if(!base_layout || !base_layout->IsStaticStack()) - return NULL; - - StackLayout precedence_layout(GetInferenceName(),base_layout->getFunctionName(),base_layout->GetOriginalAllocSize(), - base_layout->GetSavedRegsSize(), base_layout->HasFramePointer(), base_layout->getOutArgsSize()); - - //cerr<<"PrecedenceLayoutInference: inf name="<<GetInferenceName()<<" func name= "<<base_layout->getFunctionName()<<" stack alloc size="<<base_layout->GetOriginalAllocSize()<<" saved regs size="<<base_layout->GetSavedRegsSize()<<" has frame pointer="<< base_layout->HasFramePointer()<<" out args size="<< base_layout->getOutArgsSize()<<endl; - - - StackLayout slayout = base_layout->GetStackLayout(); - vector<Range> pnranges= slayout.GetRanges(); - - vector<Range> espranges; - - //TODO: for now I need to transform offsets to esp to keep everything consistent - for(unsigned int i=0;i<ranges.size();i++) - { - Range cur; - cur.SetOffset(ranges[i].getOffset()); - cur.SetSize(ranges[i].getSize()); - - if(ranges[i].getOffset() < 0) - { - cur.SetOffset(slayout.EBPToESP(-1*ranges[i].getOffset())); - } - espranges.push_back(cur); - } - - sort(espranges.begin(),espranges.end(),CompareRangeBaseOffset); - - - //get transitive closure of offsets - //TODO: should this be done in the generator? Requires knowing layout. - vector<Range> closure_ranges; - - Range cur; - cur.SetOffset(espranges[0].getOffset()); - cur.SetSize(espranges[0].getSize()); - - for(unsigned int i=1;i<espranges.size();i++) - { - int next_offset = espranges[i].getOffset(); - unsigned int next_size = espranges[i].getSize(); - - //if the next element's offset falls in the current range's boundary - //and its size exceeds the current range's boundary, then expand the - //current range to include this range. - - //TODO: casting cur.getSize() to an int in two places below. - //make sure size isn't greater than int max, although I don't - //think this will happen and I don't know what to do if I see - //it occur. - if((next_offset >= cur.getOffset()) && - (next_offset < ((int)cur.getSize()+cur.getOffset())) && - ((next_offset+next_size) > (cur.getOffset()+cur.getSize()))) - { - cur.SetSize(next_size + (next_offset-cur.getOffset())); - } - else if(next_offset > (cur.getOffset() + (int)cur.getSize())) - { - closure_ranges.push_back(cur); - cur.SetOffset(next_offset); - cur.SetSize(next_size); - } - //else the next bound is completely inside the cur, so ignore. - } - - closure_ranges.push_back(cur); - - //insert all the precedence boundaries - for(unsigned int i=0;i<closure_ranges.size();i++) - { - precedence_layout.InsertESPOffset(closure_ranges[i].getOffset()); - precedence_layout.InsertESPOffset(closure_ranges[i].getOffset()+closure_ranges[i].getSize()); - } - - for(unsigned int i=0;i<pnranges.size();i++) - { - //look for the offset and the offset+size for each pnrange - //if not found, -1 is returned, and in this case we want to insert - //the offset into the inference. Otherwise, the location exists inside - //one of the precedence boundaries, and therefore we should not insert. - if(GetClosestIndex(closure_ranges,pnranges[i].getOffset()) < 0) - precedence_layout.InsertESPOffset(pnranges[i].getOffset()); - - if(GetClosestIndex(closure_ranges,pnranges[i].getOffset()+pnranges[i].getSize()) < 0) - precedence_layout.InsertESPOffset(pnranges[i].getOffset()+pnranges[i].getSize()); - } - - //Since I am using annotations about calls to find offsets, there better - //be an out arguments region, if not, consider the loweset object the out - //args region and produce a new precedence_layout - //TODO: in the future I may want the option in stack layout to set - //the out args region after the fact. - if(precedence_layout.getOutArgsRegionSize() == 0) - { - vector<Range> inserted_ranges = precedence_layout.GetRanges(); - - sort(inserted_ranges.begin(),inserted_ranges.end(),CompareRangeBaseOffset); - - unsigned int args_size = inserted_ranges[0].getOffset()+inserted_ranges[0].getSize(); - - StackLayout revised_playout(GetInferenceName(),base_layout->getFunctionName(),base_layout->GetOriginalAllocSize(), - base_layout->GetSavedRegsSize(), base_layout->HasFramePointer(), args_size); - - for(unsigned int i=1;i<inserted_ranges.size();i++) - { - revised_playout.InsertESPOffset(inserted_ranges[i].getOffset()+inserted_ranges[i].getSize()); - } - -//I don't know why I marked these as not canary safe originally, I think this was -//to be somewhat conservative if the layout was incorrect, allowing the program -//to be agnostic to the change, but I am going to remove this requirement. -//and I have removed, as of this version, this inference from P1 -// revised_playout.SetCanarySafe(false); - - return new PNStackLayout(revised_playout, func); - } - -//I don't know why I marked these as not canary safe originally, I think this was -//to be somewhat conservative if the layout was incorrect, allowing the program -//to be agnostic to the change, but I am going to remove this requirement. -//and I have removed, as of this version, this inference from P1 -// precedence_layout.SetCanarySafe(false); - - return new PNStackLayout(precedence_layout, func); -} - -string PrecedenceBoundaryInference::GetInferenceName() const -{ - return string("Precedence Boundary Inference using "+(base_inference == NULL? "NULL" : base_inference->GetInferenceName())); -} diff --git a/builtin_xforms/p1transform/PrecedenceBoundaryInference.hpp b/builtin_xforms/p1transform/PrecedenceBoundaryInference.hpp deleted file mode 100644 index f5c9cb2a8..000000000 --- a/builtin_xforms/p1transform/PrecedenceBoundaryInference.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PRECEDENCEBOUNDLAYOUTINFERENCE -#define __PRECEDENCEBOUNDLAYOUTINFERENCE -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include "PrecedenceBoundaryGenerator.hpp" -#include <map> -#include <string> - -class PrecedenceBoundaryInference : public PNStackLayoutInference -{ -protected: - PNStackLayoutInference *base_inference; - PrecedenceBoundaryGenerator *pbgen; -public: - //deconstructor? - PrecedenceBoundaryInference(PNStackLayoutInference *inf, PrecedenceBoundaryGenerator *pbgen) : base_inference(inf) ,pbgen(pbgen) {/*TODO: exception if passed null?*/} - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func); - virtual std::string GetInferenceName() const; -}; -#endif diff --git a/builtin_xforms/p1transform/Range.cpp b/builtin_xforms/p1transform/Range.cpp deleted file mode 100644 index f0b5d79b1..000000000 --- a/builtin_xforms/p1transform/Range.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "Range.hpp" -#include <sstream> - -using namespace std; - -Range::Range() -{ - offset = 0; - size = 0; -} -/* - Range::Range(int base_offset, unsigned int size) - { - this->base_offset = base_offset; - this->size = size; - } -*/ -Range::Range(const Range &range) -{ - offset = range.offset; - size = range.size; -} - -int Range::getOffset() const -{ - return offset; -} - -unsigned int Range::getSize() const -{ - return size; -} - -void Range::SetOffset(int offset) -{ - this->offset = offset; -} - -void Range::SetSize(unsigned int size) -{ - this->size = size; -} - -string Range::ToString() const -{ - stringstream ss; - ss<<"Offset = "<<offset<<" Size = "<<size; - return ss.str(); -} diff --git a/builtin_xforms/p1transform/Range.hpp b/builtin_xforms/p1transform/Range.hpp deleted file mode 100644 index 8aa377b78..000000000 --- a/builtin_xforms/p1transform/Range.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __RANGE -#define __RANGE - -#include <string> - -class Range -{ -protected: - int offset; - unsigned int size; -public: - Range(); - // Range(int base_offset, unsigned int size); - Range(const Range &range); - virtual int getOffset() const; - virtual unsigned int getSize() const; - virtual void SetOffset(int offset); - virtual void SetSize(unsigned int size); - virtual std::string ToString() const; -}; - -#endif diff --git a/builtin_xforms/p1transform/SConscript b/builtin_xforms/p1transform/SConscript deleted file mode 100644 index 8e1b35d99..000000000 --- a/builtin_xforms/p1transform/SConscript +++ /dev/null @@ -1,27 +0,0 @@ -import os - -Import('env') -myenv=env.Clone() - - -LIBS= " irdb-cfg irdb-transform irdb-core EXEIO " - -cpppath=''' - $IRDB_SDK/include - $PEASOUP_HOME/irdb-libs/libEXEIO/include - ''' - -libpath="$SECURITY_TRANSFORMS_HOME/lib" -myenv.Append(LIBPATH=Split(libpath)) -myenv.Append(CPPPATH=Split(cpppath)) - - - - -all_files="P1_utility.cpp PNTransformDriver.cpp PNStackLayout.cpp PNRange.cpp Range.cpp OffsetInference.cpp DirectOffsetInference.cpp ScaledOffsetInference.cpp P1Inference.cpp PNRegularExpressions.cpp PNMain.cpp StackLayout.cpp General_Utility.cpp AnnotationBoundaryGenerator.cpp PrecedenceBoundaryInference.cpp PNIrdbManager.cpp EhUpdater.cpp" - -p1=myenv.SharedLibrary("p1transform.so", Split(all_files), LIBS=Split(LIBS)) -install=myenv.Install("$SECURITY_TRANSFORMS_HOME/plugins_install/", p1) -Default(install) - -Return('install') diff --git a/builtin_xforms/p1transform/SConstruct b/builtin_xforms/p1transform/SConstruct deleted file mode 100644 index b3bd01322..000000000 --- a/builtin_xforms/p1transform/SConstruct +++ /dev/null @@ -1,7 +0,0 @@ - - - -env=Environment() -Export('env') -lib=SConscript("SConscript") -Return('lib') diff --git a/builtin_xforms/p1transform/ScaledOffsetInference.cpp b/builtin_xforms/p1transform/ScaledOffsetInference.cpp deleted file mode 100644 index ff863da2a..000000000 --- a/builtin_xforms/p1transform/ScaledOffsetInference.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "ScaledOffsetInference.hpp" -#include <cassert> - -using namespace std; -using namespace IRDB_SDK; - -ScaledOffsetInference::ScaledOffsetInference(OffsetInference *offset_inference) -{ - //TODO: throw exception - assert(offset_inference != NULL); - - this->offset_inference = offset_inference; -} - -PNStackLayout* ScaledOffsetInference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetScaledAccessLayout(func); -} - -std::string ScaledOffsetInference::GetInferenceName() const -{ - return "Scaled Offset Inference"; -} diff --git a/builtin_xforms/p1transform/ScaledOffsetInference.hpp b/builtin_xforms/p1transform/ScaledOffsetInference.hpp deleted file mode 100644 index bd9f85cf5..000000000 --- a/builtin_xforms/p1transform/ScaledOffsetInference.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __SCALEDOFFSETINFERENCE -#define __SCALEDOFFSETINFERENCE - -#include "OffsetInference.hpp" -#include "PNStackLayoutInference.hpp" - -class ScaledOffsetInference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - ScaledOffsetInference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(IRDB_SDK::Function_t *func); - virtual std::string GetInferenceName() const; - -}; -#endif diff --git a/builtin_xforms/p1transform/StackLayout.cpp b/builtin_xforms/p1transform/StackLayout.cpp deleted file mode 100644 index 7fd54c87d..000000000 --- a/builtin_xforms/p1transform/StackLayout.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "StackLayout.hpp" -#include <cassert> -#include <iostream> -#include "globals.h" - -using namespace std; - -StackLayout::StackLayout(const std::string &layout_name, const std::string &function_name, unsigned int frame_alloc_size, - unsigned int saved_regs_size, bool frame_pointer,unsigned int out_args_size) -{ - assert(out_args_size <= frame_alloc_size); - - this->layout_name = layout_name; - this->function_name = function_name; - this->frame_alloc_size = frame_alloc_size; - this->saved_regs_size = saved_regs_size; - this->has_frame_pointer = frame_pointer; - this->out_args_size = out_args_size; - has_out_args = out_args_size > 0; - is_canary_safe = true; - is_padding_safe = true; - //TODO: is static stack hacked in for TNE, needs a redesign - is_static_stack = true;//innocent 'til proven guilty. - is_recursive = false; //innocent 'til proven guilty - - //The initial layout is one entry the size of the stack frame. - //The size is minus the out args size, if greater than 0 - //an out args memory object is pushed below. - //The offset is following the out args region, if one exists. - PNRange frame; - frame.SetOffset((int)out_args_size); - frame.SetSize((int)frame_alloc_size-(int)out_args_size); - - //If there are out args, then it is automatically pushed as a mem_objects - //starting at 0. - if(has_out_args) - { - if(out_args_size != frame_alloc_size) - { - PNRange out_args; - out_args.SetOffset(0); - out_args.SetSize((int)out_args_size); - mem_objects.push_back(out_args); - } - else - { - frame.SetOffset(0); - frame.SetSize((int)out_args_size); - } - } - - //Push frame last to ensure the mem_objects vector is sorted - //by offset if there is an out args region - mem_objects.push_back(frame); -} - -StackLayout::StackLayout(const StackLayout &layout) -{ - this->layout_name = layout.layout_name; - this->function_name = layout.function_name; - this->frame_alloc_size = layout.frame_alloc_size; - this->saved_regs_size = layout.saved_regs_size; - this->out_args_size = layout.out_args_size; - this->has_frame_pointer = layout.has_frame_pointer; - has_out_args = layout.out_args_size > 0; - is_canary_safe = layout.is_canary_safe; - is_padding_safe = layout.is_padding_safe; - is_static_stack = layout.is_static_stack; - is_recursive = layout.is_recursive; - - for(unsigned int i=0;i<layout.mem_objects.size();i++) - { - this->mem_objects.push_back(layout.mem_objects[i]); - } -} - -void StackLayout::InsertESPOffset(int offset) -{ - //No Negative offsets allowed - if(offset < 0) - { - cerr<<"StackLayout: InsertESPOffset(): Negative Offset Encountered, Ignoring Insert"<<endl; - //assert(false); - return; - } - - if(verbose_log) - cerr<<"StackLayout: Attempting to insert offset "<<offset<<endl; - - - if(offset >= (int)frame_alloc_size) - { - //This can happen when an esp offset is accessing stored registers or function parameters - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset is larger than or equal to the allocated stack, Ignoring insert"<<endl; - return; - } - - if(has_out_args) - { - //If there are out args, mem_objects[0] is assumed to be the out args region - //if the new offset being inserted is in this range, the offset is ignored. - //The out args region is not divided - if(offset < (int)mem_objects[0].getSize()) - { - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset in out args region, Ignoring insert"<<endl; - return; - } - } - - PNRange new_range; - - new_range.SetOffset(offset); - - int index = GetClosestIndex(offset); - - if(index < 0) - { - //TODO: don't assert false, ignore, but for now I want to find when this happens - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Could not Find Range to Insert Into, Asserting False for Now"<<endl; - //TODO: throw exception or ignore? - assert(false); - } - - //This should never happen, but just in case, assert false. - if(index > ((int)mem_objects.size())-1) - assert(false); //TODO: throw exception - - if(verbose_log) - cerr<<"PNStackLayout: InsertESPOffset(): found offset = "<< - mem_objects[index].getOffset()<<endl; - //If offset is unique, insert it after the closest - //range (closest base address with out going over offset) - if(offset != mem_objects[index].getOffset()) - { - if(index+1 == (int)mem_objects.size()) - mem_objects.push_back(new_range); - else - mem_objects.insert(mem_objects.begin()+index+1,new_range); - } - //else no need to insert, the offset already exists - else - { - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset already exists, ignoring insert"<<endl; - return; - } - - //The memory object that was divided has to have its size adjusted - //based on where the new memory object was inserted (its offset). - mem_objects[index].SetSize(mem_objects[index+1].getOffset()-mem_objects[index].getOffset()); - - //If the location of the newly inserted range is the end of the vector - //then the size will be the difference between the frame size and the - //offset of the new range - if((int)mem_objects.size() == index+2) - mem_objects[index+1].SetSize(((int)frame_alloc_size)-mem_objects[index+1].getOffset()); - //Otherwise it is the difference between the next offset and the current offset - else - mem_objects[index+1].SetSize(mem_objects[index+2].getOffset()-mem_objects[index+1].getOffset()); - - if(verbose_log) - { - cerr<<"Stacklayout: Insert Successful, Post Insert Offsets"<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i].getOffset()<<endl; - } - } -} - -void StackLayout::InsertEBPOffset(int offset) -{ - //The size of the saved regs must be taken into consideration when transforming - //the EBP offset to an esp relative offset - if(verbose_log) - cerr<<"StackLayout: InsertEBPOffset(): Offset="<<offset<<" frame alloc size="<<frame_alloc_size<<" saved regs size="<<saved_regs_size<<endl; - int esp_conversion = EBPToESP(offset);//((int)frame_alloc_size+(int)saved_regs_size) - offset; - - //It is possible to have ebp offsets that extend beyond the stack pointer. I haven't seen it - //but still. If this occurs, ignore the insert. We currently do not handle this case - if(esp_conversion >= 0) - InsertESPOffset(esp_conversion); - else - { - if(verbose_log) - cerr<<"PNStackLayout: InsertEBPOffset: Coverted EBP offset to negative ESP offset, ignoring insert"<<endl; - } -} - -unsigned int StackLayout::GetClosestIndex(int loc) const -{ - int high = ((int)mem_objects.size())-1; - int low = 0; - int mid; - - while(low <= high) - { - mid = (low+high)/2; - if((loc < (mem_objects[mid].getOffset()+(int)mem_objects[mid].getSize())) && (loc >= mem_objects[mid].getOffset())) - return mid; - else if(loc > mem_objects[mid].getOffset()) - low = mid +1; - else - high = mid -1; - } - return -1; -} - - -unsigned int StackLayout::GetAllocSize() -{ - return frame_alloc_size; -} - -unsigned int StackLayout::GetSavedRegsSize() -{ - return saved_regs_size; -} - -unsigned int StackLayout::getOutArgsRegionSize() -{ - return out_args_size; -} - -//TODO: maybe this should be an unsigned int, since I am assuming it is -//positive. -int StackLayout::EBPToESP(int offset) -{ - return ((int)frame_alloc_size+(int)saved_regs_size) - offset; -} diff --git a/builtin_xforms/p1transform/StackLayout.hpp b/builtin_xforms/p1transform/StackLayout.hpp deleted file mode 100644 index 033d276c7..000000000 --- a/builtin_xforms/p1transform/StackLayout.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __STACKLAYOUT -#define __STACKLAYOUT -#include "PNRange.hpp" -#include <vector> -#include <string> - -class StackLayout -{ -protected: - //frame_alloc_size is the amount subtracted from esp to set up the stack - //saved regs size is the size in bits of the number of registers pushed after ebp but before the stack alloc instruction - - std::vector<Range> mem_objects; - unsigned int frame_alloc_size; - unsigned int saved_regs_size; - std::string function_name; - unsigned int out_args_size; - bool has_out_args; - bool has_frame_pointer; - bool is_canary_safe; - bool is_padding_safe; - bool is_static_stack; - bool is_recursive; - std::string layout_name; - -public: - -//NOTE: the following todo came from PNStackLayout where the insert functionality used to be, I am not sure what it means -//anymore, but just in case it is useful in the future, here is that original comment. -//TODO: change the code such that only inserts are allowed in the stack alloc region, create two frame sizes, local and total - StackLayout(const std::string &layout_name, const std::string &function_name, unsigned int frame_alloc_size, - unsigned int saved_regs_size, bool frame_pointer, unsigned int out_args_size); - StackLayout(const StackLayout &layout); - virtual ~StackLayout() {} - virtual void InsertESPOffset(int offset); - virtual void InsertEBPOffset(int offset); - virtual int EBPToESP(int offset); - - virtual std::string getFunctionName() const { return function_name; }; - virtual std::string GetLayoutName() const { return layout_name; }; - virtual unsigned int GetAllocSize(); - virtual unsigned int GetSavedRegsSize(); - virtual unsigned int getOutArgsRegionSize(); - virtual bool HasFramePointer(){return has_frame_pointer;} - virtual void SetCanarySafe(bool val){ is_canary_safe = val;} - //TODO: handle this better. - virtual void SetPaddingSafe(bool val){ is_padding_safe = val; is_canary_safe = is_canary_safe && val;} - virtual void SetStaticStack(bool val){ is_static_stack = val; } - virtual void SetRecursive(bool val){ is_recursive = val; } - virtual std::vector<Range> GetRanges() { return mem_objects; } - //TODO: why is this public - virtual unsigned int GetClosestIndex(int loc) const; - - friend class PNStackLayout; -}; - -#endif diff --git a/builtin_xforms/p1transform/canary.h b/builtin_xforms/p1transform/canary.h deleted file mode 100644 index 369620036..000000000 --- a/builtin_xforms/p1transform/canary.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __CANARY_H -#define __CANARY_H - -struct canary -{ - unsigned int canary_val; - int ret_offset;//Should be negative, the value to subtract from esp if esp is at ret addr - int esp_offset; - int floating_offset; -}; - -#endif diff --git a/builtin_xforms/p1transform/globals.h b/builtin_xforms/p1transform/globals.h deleted file mode 100644 index 973064c0a..000000000 --- a/builtin_xforms/p1transform/globals.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __GLOBALS -#define __GLOBALS - -#include <set> -#include <string> -#include <stdlib.h> -#include <sys/types.h> -#include <unistd.h> -#include <limits.h> - - - -extern bool verbose_log; - -#define DEFAULT_DETECTION_EXIT_CODE 189 - -// make sure these match values in detector_handlers.h in the strata library -enum mitigation_policy -{ - P_NONE=0, - P_CONTINUE_EXECUTION, - P_CONTROLLED_EXIT, - P_CONTINUE_EXECUTION_SATURATING_ARITHMETIC, - P_CONTINUE_EXECUTION_WARNONLY, - P_HARD_EXIT -}; - - - -class PNOptions -{ - public: - // default configuration parameters go here - PNOptions() { - // specify defaults; - min_stack_padding = 128; - max_stack_padding = min_stack_padding*2; - recursive_min_stack_padding = 64; - recursive_max_stack_padding = recursive_min_stack_padding*2; - do_canaries = true; - do_breadcrumbs = false; - do_selective_canaries = false; - should_double_frame_size=true; - random_seed=getpid(); - canary_value=0; - canary_value_inited=false; - double_threshold=32*1024; // 32kb - spri_validate=false; - detection_policy=P_HARD_EXIT; - detection_exit_code=DEFAULT_DETECTION_EXIT_CODE; - } - - void setMinStackPadding(int val) { min_stack_padding = val; } - void setMaxStackPadding(int val) { max_stack_padding = val; } - void setRecursiveMinStackPadding(int val) { recursive_min_stack_padding = val; } - void setRecursiveMaxStackPadding(int val) { recursive_max_stack_padding = val; } - void setShouldDoubleFrameSize(bool val) { should_double_frame_size = val; } - void setRandomSeed(int val) { random_seed = val; } - void setCanaryValue(int val) { canary_value = val; canary_value_inited=true; } - void setDoubleThreshold(int val) { double_threshold = val; } - - int getMinStackPadding() const { return min_stack_padding; } - int getMaxStackPadding() const { return max_stack_padding; } - int getRecursiveMinStackPadding() const { return recursive_min_stack_padding; } - int getRecursiveMaxStackPadding() const { return recursive_max_stack_padding; } - bool getShouldDoubleFrameSize() const { return should_double_frame_size; } - bool getShouldSpriValidate() const { return spri_validate; } - int getDoubleThreshold() { return double_threshold; } - int getRandomSeed() { return random_seed; } - int getCanaryValue() - { - if (canary_value_inited) - return canary_value; - else - return (rand()&0xffff) | (rand()<<16); - } - - void setDoCanaries (bool canaries ) { do_canaries = canaries; } - void setDoBreadcrumbs(bool breadcrumbs) { do_breadcrumbs = breadcrumbs; } - - bool getDoCanaries() const { return do_canaries; } - bool getDoBreadcrumbs() const { return do_breadcrumbs; } - - void addSelectiveCanaryFunction(std::string func) { do_selective_canaries = true; canary_functions.insert(func);} - bool shouldCanaryFunction(std::string func) - { - if(do_selective_canaries) - { - bool notfound = (canary_functions.find(func)==canary_functions.end()); - bool found=!notfound; - return found; - } - else - return getDoCanaries(); - } - - void setDetectionPolicy(mitigation_policy p_policy) { detection_policy = p_policy; } - mitigation_policy getDetectionPolicy() const { return detection_policy; } - unsigned getDetectionExitCode() const { return detection_exit_code; } - void setDetectionExitCode(unsigned p_exitCode) { detection_exit_code = p_exitCode; } - - private: - int min_stack_padding; - int max_stack_padding; - int recursive_min_stack_padding; - int recursive_max_stack_padding; - bool do_canaries; - bool do_breadcrumbs; - bool do_selective_canaries; - bool should_double_frame_size; - int random_seed; - int canary_value; - bool canary_value_inited; - - int double_threshold; - bool spri_validate; - - std::set<std::string> canary_functions; - - mitigation_policy detection_policy; - unsigned detection_exit_code; -}; - -extern PNOptions *pn_options; - -#endif diff --git a/builtin_xforms/p1transform/integertransformdriver.cpp b/builtin_xforms/p1transform/integertransformdriver.cpp deleted file mode 100644 index e1cf73517..000000000 --- a/builtin_xforms/p1transform/integertransformdriver.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <stdlib.h> -#include <fstream> -#include <irdb-core> -#include <getopt.h> -#include <libgen.h> - -#include "MEDS_AnnotationParser.hpp" -#include "transformutils.h" -#include "integertransform.hpp" -#include "integertransform32.hpp" -#include "integertransform64.hpp" -#include "pointercheck64.hpp" - -// current convention -#define BINARY_NAME "a.ncexe" -#define ANNOTATION_SUFFIX ".infoannot" -#define SHARED_OBJECTS_DIR "shared_objects" - -using namespace std; -using namespace libTransform; - -bool saturating_arithmetic = false; -bool path_manip_detected = false; // deprecated -bool instrument_idioms = false; -bool warning_only = false; -bool check_pointers = false; - -void usage() -{ - cerr << "Usage: integertransformdriver.exe <variant_id> <filtered_functions> <integer.warning.addresses> [--saturate] [--instrument-idioms] [--check-pointers] [--warning]"<<endl; -} - -int parse_args(int p_argc, char* p_argv[]) -{ - int option = 0; - char options[] = "s:i:w:c"; - struct option long_options[] = { - {"saturate", no_argument, NULL, 's'}, - {"instrument-idioms", no_argument, NULL, 'i'}, - {"warning", no_argument, NULL, 'w'}, - {"check-pointers", no_argument, NULL, 'c'}, - {NULL, no_argument, NULL, '\0'}, // end-of-array marker - }; - - while ((option = getopt_long( - p_argc, - p_argv, - options, - long_options, - NULL)) != -1) - { - switch (option) - { - case 's': - { - saturating_arithmetic = true; - printf("saturating arithmetic enabled\n"); - break; - } - case 'i': - { - printf("instrument idioms enabled\n"); - instrument_idioms = true; - break; - } - case 'w': - { - printf("warning only mode\n"); - warning_only = true; - break; - } - case 'c': - { - printf("check pointers mode\n"); - check_pointers = true; - break; - } - default: - return 1; - } - } - return 0; -} - -std::set<VirtualOffset> getInstructionWarnings(char *warningFilePath) -{ - std::set<VirtualOffset> warnings; - ifstream warningsFile; - - warningsFile.open(warningFilePath); - - if (warningsFile.is_open()) - { - while (!warningsFile.eof()) - { - string address; - getline(warningsFile, address); - - if (!address.empty()) - { - VirtualOffset vo(address); - warnings.insert(vo); - - cerr << "Detected warning address at: 0x" << hex << vo.getOffset() << endl; - } - } - } - - warningsFile.close(); - - cerr << "Detected a total of " << warnings.size() << " benign addresses" << endl; - return warnings; -} - -int main(int argc, char **argv) -{ - if(argc < 4) - { - usage(); - exit(1); - } - - string programName(argv[0]); - int variantID = atoi(argv[1]); - set<string> filteredFunctions = getFunctionList(argv[2]); - char *integerWarnings = argv[3]; - - parse_args(argc, argv); - - VariantID_t *pidp=NULL; - - /* setup the interface to the sql server */ - pqxxDB_t pqxx_interface; - BaseObj_t::setInterface(&pqxx_interface); - - pidp=new VariantID_t(variantID); - assert(pidp->isRegistered()==true); - - bool one_success = false; - for(set<File_t*>::iterator it=pidp->getFiles().begin(); - it!=pidp->getFiles().end(); - ++it) - { - File_t* this_file = *it; - FileIR_t *firp = new FileIR_t(*pidp, this_file); - char *fileBasename = basename((char*)this_file->getURL().c_str()); - - assert(firp && pidp); - - try - { - string annotationFilename; - // need to map filename to integer annotation file produced by STARS - // this should be retrieved from the IRDB but for now, we use files to store annotations - // convention from within the peasoup subdirectory is: - // a.ncexe.infoannot - // shared_objects/<shared-lib-filename>.infoannot - if (strcmp(fileBasename, BINARY_NAME) == 0) - annotationFilename = string(BINARY_NAME) + string(ANNOTATION_SUFFIX); - else - annotationFilename = string(SHARED_OBJECTS_DIR) + "/" + fileBasename + ANNOTATION_SUFFIX; - - cerr << "annotation file: " << annotationFilename << endl; - - // parse MEDS integer annotations - ifstream annotationFile(annotationFilename.c_str(), ifstream::in); - if (!annotationFile.is_open()) - { - cerr << "annotation file not found: " << annotationFilename.c_str() << endl; - continue; - } - - MEDS_AnnotationParser annotationParser(annotationFile); - - // this is now wrong as we're instrumenting shared libraries - // we need to display file IDs along with the PC to distinguish between various libs - std::set<VirtualOffset> warnings = getInstructionWarnings(integerWarnings); // keep track of instructions that should be instrumented as warnings (upon detection, print diagnostic & continue) - - MEDS_Annotations_t annotations = annotationParser.getAnnotations(); - - cout << "integer transform driver: found " << annotations.size() << " annotations" << endl; - - // do the transformation - - libTransform::IntegerTransform *intxform = NULL; - if(firp->getArchitectureBitWidth()==64) - { - if (check_pointers) - { - intxform = new PointerCheck64(pidp, firp, &annotations, &filteredFunctions, &warnings); - intxform->setInstrumentIdioms(true); - } - else - intxform = new IntegerTransform64(pidp, firp, &annotations, &filteredFunctions, &warnings); - } - else - { - intxform = new IntegerTransform32(pidp, firp, &annotations, &filteredFunctions, &warnings); - } - - intxform->setSaturatingArithmetic(saturating_arithmetic); - intxform->setPathManipulationDetected(path_manip_detected); - intxform->setInstrumentIdioms(instrument_idioms); - intxform->setWarningsOnly(warning_only); - - int exitcode = intxform->execute(); - - if (exitcode == 0) - { - one_success = true; - firp->writeToDB(); - intxform->logStats(); - delete firp; - } - } - catch (DatabaseError_t pnide) - { - cerr << programName << ": Unexpected database error: " << pnide << "file url: " << this_file->getURL() << endl; - } - catch (...) - { - cerr << programName << ": Unexpected error file url: " << this_file->getURL() << endl; - } - } // end file iterator - - // if any integer transforms for any files succeeded, we commit - if (one_success) - pqxx_interface.Commit(); - - return 0; -} diff --git a/builtin_xforms/p1transform/nulltransform.cpp b/builtin_xforms/p1transform/nulltransform.cpp deleted file mode 100644 index b1951aecd..000000000 --- a/builtin_xforms/p1transform/nulltransform.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <iostream> -#include "targ-config.h" - -#include "elfio/elfio.hpp" -#include "elfio/elfio_dump.hpp" - -#include "null_transform.h" - - -int main(int argc, char **argv) -{ - if (argc < 3) - { - std::cerr << "usage: " << argv[0] << " <elfFile> <annotationFile> [<spriFile>]" << std::endl; - return 1; - } - - std::cout << "Reading elf file:" << argv[1] << std::endl; - std::cout << "Reading MEDS annotation file:" << argv[2] << std::endl; - - NullTransform *nullTransform; - - if (argc == 3) - nullTransform = new NullTransform(argv[1], argv[2], (char*)"spri.out"); - else - nullTransform = new NullTransform(argv[1], argv[2], argv[3]); - - nullTransform->rewrite(); - - vector<wahoo::Function*> ncf = nullTransform->getNonCandidateFunctions(); - vector<wahoo::Function*> cf = nullTransform->getCandidateFunctions(); - vector<wahoo::Function*> af = nullTransform->getAllFunctions(); - - std::cout << "#functions: " << af.size() << std::endl; - std::cout << "#candidate functions: " << cf.size() << std::endl; - std::cout << "#non-candidate functions: " << ncf.size() << std::endl; -} diff --git a/builtin_xforms/p1transform/sample_meds_int.annot b/builtin_xforms/p1transform/sample_meds_int.annot deleted file mode 100644 index 745cf6d9b..000000000 --- a/builtin_xforms/p1transform/sample_meds_int.annot +++ /dev/null @@ -1,8 +0,0 @@ -80482bc 3 INSTR CHECK OVERFLOW UNSIGNED 32 EAX ZZ add eax, 1 -8048325 6 INSTR CHECK OVERFLOW SIGNED 16 [esp+2AH] ZZ add word ptr [esp+2Ah], 1 -804832b 6 INSTR CHECK OVERFLOW UNSIGNED 16 [esp+2CH] ZZ add word ptr [esp+2Ch], 1 -8048336 5 INSTR CHECK SIGNEDNESS SIGNED 16 AX ZZ mov [esp+28h], ax -80483db 5 INSTR CHECK UNDERFLOW SIGNED 32 EAX ZZ sub eax, 7FFFFFFFh -80483fd 3 INSTR CHECK UNDERFLOW SIGNED 32 EAX ZZ sub eax, 1 -8048492 5 INSTR CHECK TRUNCATION 32 EAX 16 AX ZZ mov [esp+26h], ax -8048492 5 INSTR CHECK SIGNEDNESS SIGNED 16 AX ZZ mov [esp+26h], ax diff --git a/builtin_xforms/p1transform/tests/test_buffer_overflow.c b/builtin_xforms/p1transform/tests/test_buffer_overflow.c deleted file mode 100644 index 39c151a88..000000000 --- a/builtin_xforms/p1transform/tests/test_buffer_overflow.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <stdio.h> -#include <string.h> - -#define BUFSIZE 32 - -void do_overflow(char *s) -{ - char tmp[BUFSIZE]; - strcpy(tmp, s); - printf("target string is: %s\n", tmp); -} - -int main(int argc, char **argv) -{ - if (argc > 1) - do_overflow(argv[1]); - else - printf("specify long string on command line as argument to overflow (bufsize=%d)\n", BUFSIZE); -} diff --git a/builtin_xforms/p1transform/tests/test_buffer_overflow.sh b/builtin_xforms/p1transform/tests/test_buffer_overflow.sh deleted file mode 100755 index d92d7328e..000000000 --- a/builtin_xforms/p1transform/tests/test_buffer_overflow.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -do_p1() -{ - if [[ -f $2 ]]; then - echo "Eliding rebuild of $2" - else - if [ -z "$3" ]; then - $PSZ $1 $2 --step p1transform=on - else - $PSZ $1 $2 --step p1transform=on --step-option p1transform:"$3" - fi - fi -} - -get_correct() -{ - ./test_buffer_overflow.exe > correct - ./test_buffer_overflow.exe abc >> correct -} - -test_functional() -{ - ./$1 > out - ./$1 abc >> out - - cmp out correct - if [ $? = 1 ]; then - fails=$(expr $fails + 1 ) - echo test failed $1 $2 $3 - echo "=== out ===" - cat out - echo "======" - else - passes=$(expr $passes + 1 ) - echo test passed. - fi -} - -test_detection() -{ - ./$1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - exitcode=$? - if [ $exitcode -eq $2 ]; then - passes=$(expr $passes + 1 ) - echo test passed. - else - fails=$(expr $fails + 1 ) - echo "test failed: does not detect overflow or wrong exit code: $1 (expected $2, got $exitcode)" - fi -} - -build() -{ - gcc -o test_buffer_overflow.exe test_buffer_overflow.c -fno-stack-protector -} - -build_with_stack_protector() -{ - gcc -o test_buffer_overflow.exe.sp test_buffer_overflow.c -} - - -protect() -{ - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.139 # new default is halt - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.188 "--detection_policy exit --detection_exit_code 188" - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.hlt "--detection_policy halt" - do_p1 ./test_buffer_overflow.exe.sp test_buffer_overflow.exe.sp.p1.189 "--detection_policy exit --detection_exit_code 189" -} - -clean() -{ - rm out 2>/dev/null - rm correct 2>/dev/null - rm -Rf test_buffer_overflow.exe* peasoup_exe* 2>/dev/null -} - -report () -{ - total=$(expr $passes + $fails) - echo "Passes: $passes / $total" - echo "Fails : $fails / $total" -} - -main() -{ - build - build_with_stack_protector - protect - get_correct - - echo "Test functionality" - test_functional test_buffer_overflow.exe # unprotected - should pass! - test_functional test_buffer_overflow.exe.p1.139 - test_functional test_buffer_overflow.exe.p1.188 - test_functional test_buffer_overflow.exe.p1.hlt - test_functional test_buffer_overflow.exe.sp.p1.189 - - echo "Test detection (segfaults, etc. expected) -- errors do not effect test results" - test_detection test_buffer_overflow.exe.p1.139 139 - test_detection test_buffer_overflow.exe.p1.188 188 - test_detection test_buffer_overflow.exe.p1.hlt 139 - - # verify P1 detection comes before gcc stack smashing protection - test_detection test_buffer_overflow.exe.sp.p1.189 189 - - report - - if [[ $1 == "-k" ]] ; then - echo "Skipping cleanup" - else - clean - fi -} - -passes=0 -fails=0 - -main $* diff --git a/builtin_xforms/p1transform/tests/test_spec-x32.sh b/builtin_xforms/p1transform/tests/test_spec-x32.sh deleted file mode 100755 index aadf8f616..000000000 --- a/builtin_xforms/p1transform/tests/test_spec-x32.sh +++ /dev/null @@ -1,280 +0,0 @@ -#!/bin/bash - -# the bad boys -#benchmarks=" -# 400.perlbench -# 403.gcc -# 445.gobmk -# 450.soplex -# 453.povray -# 458.sjeng -# 464.h264ref -# 465.tonto -# 471.omnetpp -# 481.wrf -# 482.sphinx3 -# 483.xalancbmk -# " - -# all -all_benchmarks="400.perlbench 401.bzip2 403.gcc 410.bwaves 416.gamess 429.mcf 433.milc 434.zeusmp 435.gromacs 436.cactusADM 437.leslie3d 444.namd 445.gobmk 450.soplex 453.povray 454.calculix 456.hmmer 458.sjeng 459.GemsFDTD 462.libquantum 464.h264ref 465.tonto 470.lbm 471.omnetpp 473.astar 481.wrf 482.sphinx3 483.xalancbmk" - -#all_benchmarks=" gromacs calculix sjeng h264ref omnetpp xalancbmk" - -number=1 -#input_size=test -input_size=ref - -setup() -{ - - if [ ! -d spec2006 ]; then - #svn co ^/spec2006/trunk spec2006 - git clone --depth 1 http://git.zephyr-software.com/allzp/spec2006.git spec2006 - fi - - if [[ ! -f /usr/bin/gfortran ]]; then - sudo apt-get install gfortran -y - fi - - cd spec2006/ - if [ ! -L bin ]; then - ln -s bin.power/ bin - fi - source shrc - bin/relocate -} - - -run_test() -{ - config_name=$1 - config=$2 - benchmarks="$3" - - # remember we ran this test. - global_config_names="$global_config_names $config_name" - - cd $SPEC - if [ ! -d result.$config_name ]; then - dropdb $PGDATABASE - createdb $PGDATABASE - $PEASOUP_HOME/tools/db/pdb_setup.sh - rm -Rf result/* - runspec --action scrub --config $config $benchmarks - - echo - echo "**************************************************************************" - echo "Starting test of $config_name" - echo "**************************************************************************" - echo - runspec --action validate --config $config -n $number $benchmarks -i $input_size - cp benchspec/CPU2006/*/exe/* result - mv result result.$config_name - for bench in $benchmarks - do - mv benchspec/CPU2006/$bench/run/build*/peasoup*/logs result.$config_name/$bench.log - done - fi - -} - -get_size_result() -{ - bench=$1 - if [ -e $bench ]; then - size=$(stat --printf="%s" $bench) - #echo -n "$size" - #LC_ALL= numfmt --grouping $size - #LC_ALL= printf "%'d" $size - #LC_NUMERIC=en_US printf "%'d" $size - #LC_NUMERIC=en_US printf "%'f" $size - #LC_NUMERIC=en_US printf "%'.f" $size - #LC_NUMERIC=en_US printf "%'10.10f" $size - #LC_NUMERIC=en_US /usr/bin/printf "%'d" $size - echo $size - else - echo -n "0" - fi -} - -get_result() -{ - bench=$1 - config=$2 - - results=$(cat $SPEC/result.$config/CPU2006.002.log 2> /dev/null |grep Success|grep $bench|grep ratio=|sed 's/.*ratio=//'|sed 's/,.*//') - - sum=0 - count=0 - for res in $results - do - sum=$(echo $sum + $res | bc) - count=$(echo $count + 1 | bc) - done - #echo sum=$sum - #echo count=$count - res=$(echo "scale=2; $sum / $count" | bc 2> /dev/null ) - - count=$(echo $res|wc -w) - - if [ $count = 1 ]; then - echo -n $res - else - echo -n "0" - fi - -} - - -get_raw_results() -{ - echo global_configs=$global_config_names - configs="$global_config_names" - get_raw_perf_results $configs - get_raw_size_results $configs - #get_raw_fde_results $configs -} - -get_raw_perf_results() -{ - configs="$*" - first_config=$1 - echo "--------------------------------------------------------------" - echo "Performance results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $benchmarks - do - echo -n "$bench " - for config in $* - do - get_result $bench $config - echo -n " " - done - echo - done -} - -get_raw_size_results() -{ - configs="$*" - first_config=$1 - - echo "--------------------------------------------------------------" - echo "Size results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - echo -n "$(basename $bench _base.amd64-m64-gcc42-nn) " - for config in $* - do - if [[ $config == "baseline" ]]; then - file="$SPEC/result.$config/$(basename $bench)" - cp $file /tmp/foo.exe - strip /tmp/foo.exe 2> /dev/null - file="/tmp/foo.exe" - else - file="$SPEC/result.$config/$(basename $bench)" - fi - res=$(get_size_result $file) - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -get_raw_fde_results() -{ - echo "--------------------------------------------------------------" - echo "FDE results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - #printf "%-20s" $(basename $bench _base.amd64-m64-gcc42-nn) - echo -n $(basename $bench _base.amd64-m64-gcc42-nn) - for config in $* - do - file="$SPEC/result.$config/$(basename $bench)" - res=$(readelf -w $file |grep FDE|wc -l ) - #if [[ $config == "baseline" ]]; then - #else - #fi - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -main() -{ - zipr_flags=" --backend zipr --step-option zipr:--add-sections --step-option zipr:true" - rida_flags=" $zipr_flags -c rida=on -s meds_static=off " - trace_flags=" --step-option zipr:--traceplacement:on --step-option zipr:true" - relax_flags=" --step-option zipr:--relax:on --step-option zipr:true --step-option zipr:--unpin:on --step-option zipr:false" - nounpin_flags=" --step-option zipr:--unpin:on --step-option zipr:false" - split_flags=" --step-option fill_in_indtargs:--split-eh-frame " - icall_flags=" --step-option fix_calls:--no-fix-icalls " - p1flags=" -c p1transform=on " - siflags=" -c p1transform=on -c initialize_stack=on" - ssflags=" -c stack_stamp=on " - nosflags=" -c non_overlapping_stack=on " - start_dir=$(pwd) - setup - - # baseline - run_test baseline $SPEC/config/ubuntu18.04lts-32bit.cfg "$all_benchmarks" - - # unmodified binary with heaprand preloaded - mkdir -p speclib/lib32 - mkdir -p speclib/lib64 - cp $DIEHARD_HOME/src/libdiehard-8k-x32.so speclib/lib32/libheaprand.so - cp $DIEHARD_HOME/src/libdiehard-8k-x64.so speclib/lib64/libheaprand.so - LD_LIBRARY_PATH=$PWD/speclib/lib32:$PWD/speclib/lib64 LD_PRELOAD=libheaprand.so run_test orig-hr $SPEC/config/ubuntu18.04lts-32bit.cfg "$all_benchmarks" - - # zipr only - PSOPTS="$zipr_flags " run_test zipr $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # rida - PSOPTS="$zipr_flags $ridaflags " run_test rida $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # zipr + p1 - PSOPTS="$zipr_flags $p1flags " run_test zipr-p1 $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # rida + p1 - PSOPTS="$rida_flags $p1flags " run_test rida-p1 $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # zipr+p1+si - PSOPTS="$zipr_flags $siflags " run_test zipr-p1-si $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # rida+p1+si - PSOPTS="$rida_flags $siflags " run_test rida-p1-si $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # zipr+ss - PSOPTS="$zipr_flags $ssflags " run_test zipr-ss $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # rida+ss - PSOPTS="$rida_flags $ssflags " run_test rida-ss $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # zipr+nos - PSOPTS="$zipr_flags $nosflags " run_test zipr-nos $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - # rida+nos - PSOPTS="$rida_flags $nosflags " run_test rida-nos $SPEC/config/ubuntu18.04lts-32bit-withps.cfg "$all_benchmarks" - - get_raw_results -} - -main "$@" - - - diff --git a/builtin_xforms/p1transform/tests/test_spec.sh b/builtin_xforms/p1transform/tests/test_spec.sh deleted file mode 100755 index aee2e9269..000000000 --- a/builtin_xforms/p1transform/tests/test_spec.sh +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/bash - -# the bad boys -#benchmarks=" -# 400.perlbench -# 403.gcc -# 445.gobmk -# 450.soplex -# 453.povray -# 458.sjeng -# 464.h264ref -# 465.tonto -# 471.omnetpp -# 481.wrf -# 482.sphinx3 -# 483.xalancbmk -# " - -# broken: 447.dealII - -cint_benchmarks="400.perlbench 401.bzip2 403.gcc 429.mcf 445.gobmk 456.hmmer 458.sjeng 462.libquantum 464.h264ref 471.omnetpp 473.astar 483.xalancbmk" - -c_cpp_benchmarks="$cint_benchmarks 433.milc 444.namd 450.soplex 453.povray 470.lbm 482.sphinx3" -fortran_benchmarks="410.bwaves 416.gamess 434.zeusmp 437.leslie3d 459.gemsFDTD 465.tonto" -mixed_c_fortran_benchnmarks="435.gromacs 436.cactusADM 454.calculix 481.wrf" - -cfp_benchmarks="$fortran_benchmakrs $mixed_c_fortran_benchmarks 433.milc 444.namd 450.soplex 453.povray 470.lbm 482.sphinx3" - -# all -#all_benchmarks="400.perlbench 401.bzip2 403.gcc 410.bwaves 416.gamess 429.mcf 433.milc 434.zeusmp 435.gromacs 436.cactusADM 437.leslie3d 444.namd 445.gobmk 450.soplex 453.povray 454.calculix 456.hmmer 458.sjeng 459.GemsFDTD 462.libquantum 464.h264ref 465.tonto 470.lbm 471.omnetpp 473.astar 481.wrf 482.sphinx3 483.xalancbmk" -#all_benchmarks=" 401.bzip2 " - -all_benchmarks=" $c_cpp_benchmarks " - -number=1 -#input_size=test -input_size=ref - -setup() -{ - - if [ ! -d spec2006 ]; then - #svn co ^/spec2006/trunk spec2006 - git clone --depth 1 git@git.zephyr-software.com:allzp/spec2006.git spec2006 - fi - - if [[ ! -f /usr/bin/gfortran ]]; then - sudo apt-get install gfortran -y - fi - - cd spec2006/ - if [ ! -L bin ]; then - ln -s bin.power/ bin - fi - source shrc - bin/relocate -} - - -run_test() -{ - config_name=$1 - config=$2 - benchmarks="$3" - global_config_list="$global_config_list $config_name" - cd $SPEC - if [ ! -d result.$config_name ]; then - dropdb $PGDATABASE - createdb $PGDATABASE - $PEASOUP_HOME/tools/db/pdb_setup.sh - rm -Rf result/* - runspec --action scrub --config $config $benchmarks - - echo - echo "**************************************************************************" - echo "Starting test of $config_name" - echo "**************************************************************************" - echo - runspec --action validate --config $config -n $number $benchmarks -i $input_size - cp benchspec/CPU2006/*/exe/* result - mv result result.$config_name - for bench in $benchmarks - do - mv benchspec/CPU2006/$bench/run/build*/peasoup*/logs result.$config_name/$bench.log - done - fi - -} - -get_size_result() -{ - bench=$1 - if [ -e $bench ]; then - size=$(stat --printf="%s" $bench) - #echo -n "$size" - #LC_ALL= numfmt --grouping $size - #LC_ALL= printf "%'d" $size - #LC_NUMERIC=en_US printf "%'d" $size - #LC_NUMERIC=en_US printf "%'f" $size - #LC_NUMERIC=en_US printf "%'.f" $size - #LC_NUMERIC=en_US printf "%'10.10f" $size - #LC_NUMERIC=en_US /usr/bin/printf "%'d" $size - echo $size - else - echo -n "0" - fi -} - -get_result() -{ - bench=$1 - config=$2 - - results=$(cat $SPEC/result.$config/CPU2006.002.log|grep Success|grep $bench|grep ratio=|sed 's/.*ratio=//'|sed 's/,.*//') - - sum=0 - count=0 - for res in $results - do - sum=$(echo $sum + $res | bc) - count=$(echo $count + 1 | bc) - done - #echo sum=$sum - #echo count=$count - res=$(echo "scale=2; $sum / $count" | bc 2> /dev/null ) - - count=$(echo $res|wc -w) - - if [ $count = 1 ]; then - echo -n $res - else - echo -n "0" - fi - -} - - -get_raw_results() -{ - local configs="$global_config_list" - get_raw_perf_results $configs - get_raw_size_results $configs - #get_raw_fde_results $configs -} - -get_raw_perf_results() -{ - configs=$* - first_config=$1 - echo "--------------------------------------------------------------" - echo "Performance results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $benchmarks - do - echo -n "$bench " - for config in $* - do - get_result $bench $config - echo -n " " - done - echo - done -} - -get_raw_size_results() -{ - echo "--------------------------------------------------------------" - echo "Size results are:" - echo "--------------------------------------------------------------" - configs=$* - first_config=$1 - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - echo -n "$(basename $bench _base.amd64-m64-gcc42-nn) " - for config in $* - do - if [[ $config == "baseline" ]]; then - file="$SPEC/result.$config/$(basename $bench)" - cp $file /tmp/foo.exe - strip /tmp/foo.exe 2> /dev/null - file="/tmp/foo.exe" - else - file="$SPEC/result.$config/$(basename $bench)" - fi - res=$(get_size_result $file) - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -get_raw_fde_results() -{ - echo "--------------------------------------------------------------" - echo "FDE results are:" - echo "--------------------------------------------------------------" - configs=$* - first_config=$1 - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - #printf "%-20s" $(basename $bench _base.amd64-m64-gcc42-nn) - echo -n $(basename $bench _base.amd64-m64-gcc42-nn) - for config in $* - do - file="$SPEC/result.$config/$(basename $bench)" - res=$(readelf -w $file |grep FDE|wc -l ) - #if [[ $config == "baseline" ]]; then - #else - #fi - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -main() -{ - zipr_flags=" --backend zipr --step-option zipr:--add-sections --step-option zipr:true" - rida_flags=" $zipr_flags -c rida=on -s meds_static=off " - trace_flags=" --step-option zipr:--traceplacement:on --step-option zipr:true" - relax_flags=" --step-option zipr:--relax:on --step-option zipr:true --step-option zipr:--unpin:on --step-option zipr:false" - nounpin_flags=" --step-option zipr:--unpin:on --step-option zipr:false" - split_flags=" --step-option fill_in_indtargs:--split-eh-frame " - icall_flags=" --step-option fix_calls:--no-fix-icalls " - p1flags=" -c p1transform=on " - siflags=" $p1flags -s initialize_stack=on " - ssflags=" -c stack_stamp=on " - mga_flags=" -c move_globals=on -o move_globals:--aggressive " - mgc_flags=" -c move_globals=on -o move_globals:--conservative " - - nosflags=" -c non_overlapping_stack=on " - start_dir=$(pwd) - setup - - # baseline - run_test baseline $SPEC/config/ubuntu14.04lts-64bit.cfg "$all_benchmarks" - - # unmodified binary with heaprand preloaded - if [[ ! -z $DIEHARD ]]; then - mkdir -p speclib/lib32 - mkdir -p speclib/lib64 - cp $DIEHARD_HOME/src/libdiehard-8k-x32.so speclib/lib32/libheaprand.so - cp $DIEHARD_HOME/src/libdiehard-8k-x64.so speclib/lib64/libheaprand.so - LD_LIBRARY_PATH=$PWD/speclib/lib32:$PWD/speclib/lib64 LD_PRELOAD=libheaprand.so run_test orig-hr $SPEC/config/ubuntu18.04lts-32bit.cfg "$all_benchmarks" - fi - - - # should be 100% success, tested by jdh on 4/11/18 as 100% success. - PSOPTS="$zipr_flags " run_test zipr $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags " run_test rida $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $p1flags " run_test rida-p1 $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $mga_flags " run_test rida-mga $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $mgc_flags " run_test rida-mgc $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - # two failures as of 4/11/18 -- cactusADM and povray - PSOPTS="$zipr_flags $p1flags " run_test zipr-p1 $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $p1flags " run_test rida-p1 $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - # try si - PSOPTS="$zipr_flags $siflags " run_test zipr-p1-si $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $siflags " run_test rida-p1-si $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - # try nos - PSOPTS="$zipr_flags $noslags " run_test zipr-nos $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $noslags " run_test rida-nos $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - # try ss - PSOPTS="$zipr_flags $sslags " run_test zipr-ss $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - PSOPTS="$rida_flags $sslags " run_test rida-ss $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - get_raw_results -} - -main "$@" - - - diff --git a/builtin_xforms/p1transform/tests/test_spec17.sh b/builtin_xforms/p1transform/tests/test_spec17.sh deleted file mode 100755 index 2a2cf7f8f..000000000 --- a/builtin_xforms/p1transform/tests/test_spec17.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/bin/bash - -# the bad boys - -run_size="ref" - -all_benchmarks=" -600.perlbench_s 602.gcc_s 603.bwaves_s 605.mcf_s 607.cactuBSSN_s 619.lbm_s 620.omnetpp_s 621.wrf_s 623.xalancbmk_s 625.x264_s 627.cam4_s 628.pop2_s 631.deepsjeng_s 638.imagick_s 641.leela_s 644.nab_s 648.exchange2_s 649.fotonik3d_s 654.roms_s 657.xz_s 996.specrand_fs 998.specrand_is -" - -#all_benchmarks=" -#500.perlbench_r -#" - - - -number=1 - -setup() -{ - - if [ ! -d spec2017 ]; then - #svn co ^/spec2017/trunk spec2017 - git clone --depth 1 http://git.zephyr-software.com/allzp/spec2017.git spec2017 - fi - - if [[ ! -f /usr/bin/gfortran ]]; then - sudo apt-get install gfortran gcc g++ -y - fi - - cd spec2017/ - source shrc -} - - -run_test() -{ - local config_name="$1" - local config="$2" - local benchmarks="$3" - - tests_that_ran="$tests_that_ran $config_name" - - cd $SPEC - if [ ! -d result.$config_name ]; then - bash -x $PEASOUP_UMBRELLA_DIR/postgres_reset.sh - rm -Rf result/* - runcpu --action scrub --config $config $benchmarks - - echo - echo "**************************************************************************" - echo "Starting test of $config_name" - echo "**************************************************************************" - echo - #runspec --action validate --config $config -n $number $benchmarks - runcpu --config $config --iterations $number --size $run_size --copies=8 --parallel_test_workload $run_size --noreportable $benchmarks - - cp benchspec/CPU/*/exe/* result - mv result result.$config_name - for bench in $benchmarks - do - mv benchspec/CPU/$bench/build/build*/peasoup*/logs result.$config_name/$bench.log - done - fi - -} - -get_size_result() -{ - bench=$1 - if [ -e $bench ]; then - size=$(stat --printf="%s" $bench) - #echo -n "$size" - #LC_ALL= numfmt --grouping $size - #LC_ALL= printf "%'d" $size - #LC_NUMERIC=en_US printf "%'d" $size - #LC_NUMERIC=en_US printf "%'f" $size - #LC_NUMERIC=en_US printf "%'.f" $size - #LC_NUMERIC=en_US printf "%'10.10f" $size - #LC_NUMERIC=en_US /usr/bin/printf "%'d" $size - echo $size - else - echo -n "0" - fi -} - -get_result() -{ - bench=$1 - config=$2 - - results=$(cat $SPEC/result.$config/CPU2017.002.log|grep Success|grep $bench|grep ratio=|sed 's/.*ratio=//'|sed 's/,.*//') - - sum=0 - count=0 - for res in $results - do - sum=$(echo $sum + $res | bc) - count=$(echo $count + 1 | bc) - done - #echo sum=$sum - #echo count=$count - res=$(echo "scale=2; $sum / $count" | bc 2> /dev/null ) - - count=$(echo $res|wc -w) - - if [ $count = 1 ]; then - echo -n $res - else - echo -n "0" - fi - -} - - -get_raw_results() -{ - get_raw_perf_results $tests_that_ran - get_raw_size_results $tests_that_ran - #get_raw_fde_results $tests_that_ran -} - -get_raw_perf_results() -{ - configs="$*" - first_config=$1 - - - echo "--------------------------------------------------------------" - echo "Performance results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $all_benchmarks - do - echo -n "$bench " - for config in $* - do - get_result $bench $config - echo -n " " - done - echo - done -} - -get_raw_size_results() -{ - echo "--------------------------------------------------------------" - echo "Size results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*mytest-m64 - do - echo -n "$(basename $bench _base.mytest-m64) " - for config in $* - do - if [[ $config == "baseline" ]]; then - file="$SPEC/result.$config/$(basename $bench)" - cp $file /tmp/foo.exe - strip /tmp/foo.exe - file="/tmp/foo.exe" - else - file="$SPEC/result.$config/$(basename $bench)" - fi - res=$(get_size_result $file) - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -get_raw_fde_results() -{ - echo "--------------------------------------------------------------" - echo "FDE results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*mytest-m64 - do - #printf "%-20s" $(basename $bench _base.amd64-m64-gcc42-nn) - echo -n $(basename $bench _base.amd64-m64-gcc42-nn) - for config in $* - do - file="$SPEC/result.$config/$(basename $bench)" - res=$(readelf -w $file |grep FDE|wc -l ) - #if [[ $config == "baseline" ]]; then - #else - #fi - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -main() -{ - local zipr_flags=" --backend zipr --step-option zipr:--add-sections --step-option zipr:true" - local trace_flags=" --step-option zipr:--traceplacement:on --step-option zipr:true" - local relax_flags=" --step-option zipr:--relax:on --step-option zipr:true --step-option zipr:--unpin:on --step-option zipr:false" - local nounpin_flags=" --step-option zipr:--unpin:on --step-option zipr:false" - local split_flags=" --step-option fill_in_indtargs:--split-eh-frame " - local icall_flags=" --step-option fix_calls:--no-fix-icalls " - local p1flags=" -c p1transform=on " - - # sets $SPEC - setup - - local nops_config=$SPEC/config/ubuntu14.cfg - local withps_config=$SPEC/config/ubuntu14_withps.cfg - - - # baseline - run_test baseline $SPEC/config/ubuntu14.cfg "$all_benchmarks" - - PSOPTS="$zipr_flags " run_test zipr $withps_config "$all_benchmarks" - PSOPTS="$zipr_flags $p1flags " run_test zipr-p1 $withps_config "$all_benchmarks" - - get_raw_results -} - -main "$@" - - - diff --git a/builtin_xforms/p1transform/transformutils.cpp b/builtin_xforms/p1transform/transformutils.cpp deleted file mode 100644 index bfab574de..000000000 --- a/builtin_xforms/p1transform/transformutils.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <iostream> -#include <fstream> -#include <string> - -#include "transformutils.h" - -using namespace std; - -set<string> getFunctionList(char *p_filename) -{ - set<string> functionList; - - ifstream candidateFile; - candidateFile.open(p_filename); - - if(candidateFile.is_open()) - { - while(!candidateFile.eof()) - { - string functionName; - getline(candidateFile, functionName); - - functionList.insert(functionName); - } - - candidateFile.close(); - } - - return functionList; -} - diff --git a/builtin_xforms/p1transform/transformutils.h b/builtin_xforms/p1transform/transformutils.h deleted file mode 100644 index 5143412f3..000000000 --- a/builtin_xforms/p1transform/transformutils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef _TRANSFORM_UTILS_ -#define _TRANSFORM_UTILS_ - -#include <string> -#include <set> - -extern std::set<std::string> getFunctionList(char *p_filename); - -#endif -- GitLab