Class: Rex::RopBuilder::RopCollect

Inherits:
RopBase
  • Object
show all
Defined in:
lib/rex/ropbuilder/rop.rb

Instance Method Summary collapse

Methods inherited from RopBase

#import, #print_msg, #to_csv

Constructor Details

#initialize(file = "") ⇒ RopCollect


91
92
93
94
95
96
97
98
99
100
# File 'lib/rex/ropbuilder/rop.rb', line 91

def initialize(file="")
  @stdio = Rex::Ui::Text::Output::Stdio.new
  @file = file if not file.empty?
  @bin = Metasm::AutoExe.decode_file(file) if not file.empty?
  @disassembler = @bin.disassembler if not @bin.nil?
  if @disassembler
    @disassembler.cpu = Metasm::Ia32.new('386_common')
  end
  super()
end

Instance Method Details

#collect(depth, pattern) ⇒ Object


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/rex/ropbuilder/rop.rb', line 102

def collect(depth, pattern)
  matches = []
  gadgets = []

  # find matches by scanning for the pattern
  matches = @disassembler.pattern_scan(pattern)
  if @bin.kind_of?(Metasm::PE)
    @bin.sections.each do |section|
      next if section.characteristics.include? 'MEM_EXECUTE'
      # delete matches if the address is outside the virtual address space
      matches.delete_if do |ea|
        va = section.virtaddr + @bin.optheader.image_base
        ea >= va and ea < va + section.virtsize
      end
    end
  elsif @bin.kind_of?(Metasm::ELF)
    @bin.segments.each do |seg|
      next if seg.flags.include? 'X'
      matches.delete_if do |ea|
        ea >= seg.vaddr and ea < seg.vaddr + seg.memsz
      end
    end
  elsif @bin.kind_of?(Metasm::MachO)
    @bin.segments.each do |seg|
      next if seg.initprot.include? 'EXECUTE'
      matches.delete_if do |ea|
        ea >= seg.virtaddr and ea < seg.virtaddr + seg.filesize
      end
    end
  end

  gadgets = process_gadgets(matches, depth)
  gadgets.each do |gadget|
    @gadgets << gadget
  end
  gadgets
end

#color_pattern(gadget, disasm, addrs, p) ⇒ Object


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rex/ropbuilder/rop.rb', line 165

def color_pattern(gadget, disasm, addrs, p)
  idx = disasm.index(p)
  if idx.nil?
    print_msg(gadget[:disasm])
    return
  end

  disasm = disasm.insert(idx, "%bld%grn")

  asm = ""
  cnt = 0
  colors = false
  disasm.each_line do |line|
    # if we find this then we are in the matching area
    if line.index(/\%bld\%grn/)
      colors = true
    end
    asm << "%clr" + addrs[cnt] + "\t"

    # color the remaining parts of the gadget
    if colors and line.index("%bld%grn").nil?
      asm << "%bld%grn" + line
    else
      asm << line
    end

    cnt += 1
  end
  asm << "%clr\n"
  print_msg(asm)
end

#pattern_search(pattern) ⇒ Object


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rex/ropbuilder/rop.rb', line 140

def pattern_search(pattern)
  p = Regexp.new("(" + pattern + ")")
  matches = []

  @gadgets.each do |gadget|
    disasm = ""
    addrs = []

    gadget[:disasm].each_line do |line|
      addr, asm = line.split("\t", 2)
      addrs << addr
      disasm << asm
    end

    if gadget[:raw] =~ p or gadget[:disasm] =~ p or disasm =~ p
      matches << {:gadget => gadget, :disasm => disasm, :addrs => addrs}
    end
  end
  matches.each do |match|
    @stdio.print_status("gadget with address: %bld%cya#{match[:gadget][:address]}%clr matched")
    color_pattern(match[:gadget], match[:disasm], match[:addrs], p)
  end
  matches
end

#process_gadgets(rets, num) ⇒ Object


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/rex/ropbuilder/rop.rb', line 197

def process_gadgets(rets, num)
  ret     = {}
  gadgets = []
  tmp     = []
  rets.each do |ea|
    insn = @disassembler.disassemble_instruction(ea)
    next if not insn

    xtra = insn.bin_length

    num.downto(0) do |x|
      addr = ea - x

      # get the disassembled instruction at this address
      di = @disassembler.disassemble_instruction(addr)

      # skip invalid instructions
      next if not di
      next if di.opcode.props[:setip]
      next if di.opcode.props[:stopexec]

      # get raw bytes
      buf = @disassembler.read_raw_data(addr, x + xtra)


      # make sure disassembling forward leads to our instruction
      next if not ends_with_addr(buf, addr, ea)

      dasm = ""
      while addr <= ea
        di = @disassembler.disassemble_instruction(addr)
        dasm << ("0x%08x:\t" % addr) + di.instruction.to_s + "\n"
        addr = addr + di.bin_length
      end

      if not tmp.include?(ea)
        tmp << ea
      else
        next
      end

      # otherwise, we create a new tailchunk and add it to the list
      ret = {:file => @file, :address => ("0x%08x" % (ea - x)), :raw => buf, :disasm => dasm}
      gadgets << ret
    end
  end
  gadgets
end