def _CSTtoREG_transitivity(reg, cst, env, n=1): """ Perform REG1 <- CST with REG1 <- REG2 <- CST """ ID = StrategyType.CSTtoREG_TRANSITIVITY ## Test for special cases # Test lmax if (env.getLmax() <= 0): return [] # Limit number of calls to ... elif (env.nbCalls(ID) >= 99): return [] # Check if the cst is in badBytes elif (not env.getConstraint().badBytes.verifyAddress(cst)): return [] # Check if previous call was already CSTtoREG_transitivity # Reason: we handle the transitivity with REGtoREG transitivity # so no need to do it also recursively with this one ;) elif (env.callsHistory()[-1] == ID): return [] # Set env env.addCall(ID) ############################# res = [] for inter in Arch.registers(): if (inter == reg or inter in env.getConstraint().getRegsNotModified() or inter == Arch.ipNum() or inter == Arch.spNum()): continue # Find reg <- inter inter_to_reg = _search(QueryType.REGtoREG, reg, (inter, 0), env, n) if (inter_to_reg): # We found ROPChains s.t reg <- inter # Now we want inter <- cst min_len = min([len(chain) for chain in inter_to_reg]) env.subLmax(min_len) env.addUnusableReg(reg) cst_to_inter = _search(QueryType.CSTtoREG, inter, cst, env, n / len(inter_to_reg) + 1) env.removeUnusableReg(reg) env.addLmax(min_len) for chain2 in inter_to_reg: for chain1 in cst_to_inter: if (len(chain1) + len(chain2) <= env.getLmax()): res.append(chain1.addChain(chain2, new=True)) # Did we get enough chains ? if (len(res) >= n): break ############################### # Restore env env.removeCall(ID) return res[:n]
def _MEMtoREG_transitivity(reg, arg2, env, n=1): """ Perform reg <- inter <- mem(arg2) """ ID = StrategyType.MEMtoREG_TRANSITIVITY ## Test for special cases # Test lmax if (env.getLmax() <= 0): return FailRecord(lmax=True) # Limit number of calls to ... elif (env.nbCalls(ID) >= 99): return FailRecord() # Check if previous call was already MEMtoREG_transitivity # Reason: we handle the transitivity with REGtoREG transitivity # so no need to do it also recursively with this one ;) elif (env.callsHistory()[-1] == ID): return FailRecord() # Set env env.addCall(ID) ########################### res = [] res_fail = FailRecord() for inter in Arch.registers(): if (inter == reg or inter in env.getConstraint().getRegsNotModified() or inter == Arch.ipNum() or inter == Arch.spNum()): continue # Find arg1 <- inter inter_to_reg = _search(QueryType.REGtoREG, reg, (inter, 0), env, n) if (inter_to_reg): min_len = min([len(chain) for chain in inter_to_reg]) # Try to find inter <- arg2 env.subLmax(min_len) env.addUnusableReg(reg) arg2_to_inter = _search(QueryType.MEMtoREG, inter, arg2, env, n) env.removeUnusableReg(reg) env.addLmax(min_len) if (not arg2_to_inter): res_fail.merge(arg2_to_inter) continue res += [chain1.addChain(chain2, new=True) for chain1 in arg2_to_inter \ for chain2 in inter_to_reg if len(chain1)+len(chain2) <= env.getLmax() ] else: res_fail.merge(inter_to_reg) # Did we get enough chains ? if (len(res) >= n): break ######################## # Restore env env.removeCall(ID) return res[:n] if res else res_fail
def _REGtoMEM_transitivity(arg1, arg2, env, n=1): """ reg <- arg2 mem(arg1) <- reg """ ID = StrategyType.REGtoMEM_TRANSITIVITY ## Test for special cases # Test lmax if (env.getLmax() <= 0): return FailRecord(lmax=True) # Limit number of calls to ... elif (env.nbCalls(ID) >= 99): return FailRecord() # Check if previous call was already REGtoMEM_transitivity # Reason: we handle the transitivity with REGtoREG transitivity # so no need to do it also recursively with this one ;) elif (env.callsHistory()[-1] == ID): return FailRecord() # Set env env.addCall(ID) ################################### res = [] res_fail = FailRecord() for inter in Arch.registers(): if (inter == arg2[0] or inter in env.getConstraint().getRegsNotModified() or inter == Arch.ipNum() or inter == Arch.spNum()): continue # Find inter <- arg2 arg2_to_inter = _search(QueryType.REGtoREG, inter, (arg2[0], arg2[1]), env, n) if (arg2_to_inter): len_min = min([len(chain) for chain in arg2_to_inter]) # Try to find mem(arg1) <- inter env.subLmax(len_min) env.addUnusableReg(arg2[0]) inter_to_mem = _search(QueryType.REGtoMEM, arg1, (inter, 0), env) env.removeUnusableReg(arg2[0]) env.addLmax(len_min) if (not inter_to_mem): res_fail.merge(inter_to_mem) continue res += [chain1.addChain(chain2, new=True) for chain1 in arg2_to_inter\ for chain2 in inter_to_mem if len(chain1)+len(chain2) <= env.getLmax()] if (len(res) >= n): break else: res_fail.merge(arg2_to_inter) ##################################### # Resotre env env.removeCall(ID) return res if res else res_fail
def init_impossible_REGtoREG(env): global INIT_LMAX, INIT_MAXDEPTH global baseAssertion # DEBUG #try: startTime = datetime.now() i = 0 impossible_count = 0 for reg1 in sorted(Arch.registers()): reg_name = Arch.r2n(reg1) if (len(reg_name) < 6): reg_name += " " * (6 - len(reg_name)) elif (len(reg_name) >= 6): reg_name = reg_name[:5] + "." for reg2 in Arch.registers(): i += 1 charging_bar(len(Arch.registers() * len(Arch.registers())), i, 30) if (reg2 == reg1 or reg2 == Arch.ipNum()): continue _search(QueryType.REGtoREG, reg1, (reg2, 0), env, n=1) if (env.checkImpossible_REGtoREG(reg1, reg2, 0)): impossible_count += 1 cTime = datetime.now() - startTime # Get how many impossible path we found impossible_rate = int(100 * (float(impossible_count) / float( (len(Arch.registers()) - 1) * len(Arch.registers())))) notify('Optimization rate : {}%'.format(impossible_rate)) notify("Computation time : " + str(cTime))
def init_impossible_REGtoREG(env): global INIT_LMAX, INIT_MAXDEPTH global baseAssertion try: startTime = datetime.now() i = 0 impossible_count = 0 for reg1 in sorted(Arch.registers()): reg_name = Arch.r2n(reg1) if (len(reg_name) < 6): reg_name += " " * (6 - len(reg_name)) elif (len(reg_name) >= 6): reg_name = reg_name[:5] + "." for reg2 in Arch.registers(): i += 1 charging_bar(len(Arch.registers() * len(Arch.registers())), i, 30) if (reg2 == reg1 or reg2 == Arch.ipNum()): continue _search(QueryType.REGtoREG, reg1, (reg2, 0), env, n=1) if (env.checkImpossible_REGtoREG(reg1, reg2, 0)): impossible_count += 1 cTime = datetime.now() - startTime # Get how many impossible path we found impossible_rate = int(100 * (float(impossible_count) / float( (len(Arch.registers()) - 1) * len(Arch.registers())))) notify('Optimization rate : {}%'.format(impossible_rate)) notify("Computation time : " + str(cTime)) except: print("\n") fatal("Exception caught, stopping Semantic Engine init process...\n") fatal("Search time might get very long !\n") env = SearchEnvironment(INIT_LMAX, Constraint(), baseAssertion, INIT_MAXDEPTH)
def initEngine(): global INIT_LMAX, INIT_MAXDEPTH global global_impossible_REGtoREG global baseAssertion # Init global variables baseAssertion = Assertion().add(\ RegsValidPtrRead([(Arch.spNum(),-5000, 10000)]), copy=False).add(\ RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]), copy=False).add(\ RegsNoOverlap([(Arch.spNum(), reg) for reg in Arch.registers()])) info(string_bold("Initializing Semantic Engine\n")) # Init helper for REGtoREG global_impossible_REGtoREG = SearchEnvironment(INIT_LMAX, Constraint(), baseAssertion, INIT_MAXDEPTH) init_impossible_REGtoREG(global_impossible_REGtoREG)
def _CSTtoMEM_write(arg1, cst, env, n=1): """ reg <- cst mem(arg2) <- reg """ ID = StrategyType.CSTtoMEM_WRITE ## Test for special cases # Test lmax if (env.getLmax() <= 0): return FailRecord(lmax=True) # Limit number of calls to ... elif (env.nbCalls(ID) >= 99): return FailRecord() # Set env env.addCall(ID) ###################################### res = [] res_fail addr_reg = arg1[0] addr_cst = arg1[1] # 1. First strategy (direct) # reg <- cst # mem(arg1) <- reg for reg in Arch.registers(): if (reg == Arch.ipNum() or reg == Arch.spNum() or reg == addr_reg): continue # Find reg <- cst constraint = env.getConstraint() env.setConstraint(constraint.add(RegsNotModified([addr_reg]))) env.subLmax(1) cst_to_reg_chains = _search(QueryType.CSTtoREG, reg, cst, env, n) env.addLmax(1) env.setConstraint(constraint) if (not cst_to_reg_chains): res_fail.merge(cst_to_reg_chains) continue # Search for mem(arg1) <- reg # We get all reg2,cst2 s.t mem(arg1) <- reg2+cst2 possible_mem_writes = DBPossibleMemWrites(addr_reg, addr_cst, env.getConstraint(), env.getAssertion(), n=1) # 1.A. Ideally we look for reg2=reg and cst2=0 (direct_writes) possible_mem_writes_reg = possible_mem_writes.get(reg) if (possible_mem_writes_reg): direct_writes = possible_mem_writes[reg].get(0, []) else: direct_writes = [] padding = constraint.getValidPadding(Arch.octets()) for write_gadget in direct_writes: for cst_to_reg_chain in cst_to_reg_chains: # Pad the gadgets write_chain = ROPChain([write_gadget]) for i in range(0, write_gadget.spInc - Arch.octets(), Arch.octets()): write_chain.addPadding(padding) full_chain = cst_to_reg_chain.addChain(write_chain, new=True) if (len(full_chain) <= env.getLmax()): res.append(full_chain) if (len(res) >= n): break if (len(res) >= n): break if (len(res) >= n): break # 1.B. Otherwise we try to adjust the cst2 # To be implemented # 2d Strategy: indirect # reg <- arg2 - cst # mem(arg1) <- reg + cst # TO IMPLEMENT IN ANOTHER FUNCTION ! ################### # Restore env env.removeCall(ID) return res if res else res_fail
def _REGtoREG_transitivity(arg1, arg2, env, n=1): """ Perform REG1 <- REG2+CST with REG1 <- REG3 <- REG2+CST """ ID = StrategyType.REGtoREG_TRANSITIVITY ## Test for special cases # Test lmax if (env.getLmax() <= 0): return FailRecord(lmax=True) # If reg1 <- reg1 + 0, return elif (arg1 == arg2[0] and arg2[1] == 0): return FailRecord() # Limit number of calls to REGtoREG transitivity elif (env.callsHistory()[-2:] == [ID, ID]): return FailRecord() # Set env env.addCall(ID) # Search res = [] res_fail = FailRecord() for inter_reg in Arch.registers(): if( inter_reg == arg1 or (inter_reg == arg2[0] and arg2[1]==0)\ or (env.checkImpossible_REGtoREG(arg1, inter_reg, 0))\ or (env.checkImpossible_REGtoREG(inter_reg, arg2[0], arg2[1]))\ or inter_reg == Arch.ipNum() or inter_reg == Arch.spNum() ): continue # Find reg1 <- inter_reg without using arg2 env.addUnusableReg(arg2[0]) env.subLmax(1) inter_to_arg1_list = _search(QueryType.REGtoREG, arg1, (inter_reg, 0), env, n) env.removeUnusableReg(arg2[0]) env.addLmax(1) if (not inter_to_arg1_list): res_fail.merge(inter_to_arg1_list) continue else: min_len_chain = min([len(chain) for chain in inter_to_arg1_list]) # Find inter_reg <- arg2 without using arg1 env.addUnusableReg(arg1) env.subLmax(min_len_chain) n2 = n / len(inter_to_arg1_list) if (n2 == 0): n2 = 1 arg2_to_inter_chains = _search(QueryType.REGtoREG, inter_reg, arg2, env, n2) if (not arg2_to_inter_chains): res_fail.merge(arg2_to_inter_chains) continue for arg2_to_inter in arg2_to_inter_chains: for inter_to_arg1 in inter_to_arg1_list: if (len(inter_to_arg1) + len(arg2_to_inter) <= env.getLmax()): res.append(arg2_to_inter.addChain(inter_to_arg1, new=True)) if (len(res) >= n): break if (len(res) >= n): break env.addLmax(min_len_chain) env.removeUnusableReg(arg1) if (len(res) >= n): break # Restore env env.removeCall(ID) return res if res else res_fail