# opt_local.rb extends the generic methods implemented in the coreopt # module with target-specific code patterns transformation class Flow # some helper regexp components # integer/label Intre = '(?:-|loc_|sub_|xref_)?[0-9][0-9a-fA-F]*h?' # GP register Reg = 'eax|ebx|ecx|edx|edi|esi|ebp' Peephole_patterns = [ # each pattern is an array of regexp on instruction ['call ' + Intre, 'pop ' + Reg], ['pushfd', 'popfd'], ] # ignore modifications to ecx that are not used within the flow #Semanticless_registers << 'ecx' undef peephole def peephole puts "\n * peephole *" if $VERBOSE return false if self.empty? work_in_progress = false # try to match every pattern against every instruction of the Flow Peephole_patterns.each { |pat| self.each_index{ |i| subFlow = nil if pat.length <= (self.length - i) subFlow = self[i, pat.length] if subFlow and pattern_match(pat, subFlow) # winner ! puts " [-] Match #{pat} at #{Expression[self[i].address]}" if $VERBOSE subFlow.each { |di| di.backtrace_binding = nil } case pat # here we list every pattern again, and apply the transformation we want when ['call ' + Intre, 'pop ' + Reg] pop = subFlow.last # pop eax -> mov eax pop.opcode = pop.instruction.cpu.opcode_list.find { |op| op.name == 'mov' } pop.instruction.opname = pop.opcode.name # append the address pushed by the call # mov eax, 0x2134 pop.instruction.args << Expression[subFlow.first.next_addr] pop.add_comment('call/pop') # remove the 'call' burn_di(subFlow.first) when ['pushfd', 'popfd'] burn_di(subFlow.first) burn_di(subFlow.last) else raise "Unsupported pattern: #{pat}" end work_in_progress = true end end } } # actually remove the instructions marked as unneeded purge_burnt! # return true if we did match something, # which means that the flow should be optimized once again work_in_progress end end