class OneGadget::Gadget::Gadget

Information of a gadget.

Attributes

base[RW]

@return [Integer] Base address of libc. Default: 0.

constraints[R]

@return [Array<String>] The constraints need for this gadget.

effect[R]

@return [String] The final result of this gadget.

offset[R]

@return [Integer] The gadget’s address offset.

Public Class Methods

new(offset, **options) click to toggle source

Initialize method of {Gadget} instance. @param [Integer] offset The relative address offset of this gadget. @option options [Array<String>] :constraints

The constraints need for this gadget. Defaults to +[]+.

@example

OneGadget::Gadget::Gadget.new(0x12345, constraints: ['rax == 0'])
# File lib/one_gadget/gadget.rb, line 27
def initialize(offset, **options)
  @base = 0
  @offset = offset
  @constraints = options[:constraints] || []
  @effect = options[:effect]
end

Public Instance Methods

inspect() click to toggle source

Show gadget in a pretty way.

# File lib/one_gadget/gadget.rb, line 35
def inspect
  str = OneGadget::Helper.hex(value)
  str += effect ? " #{effect}\n" : "\n"
  unless constraints.empty?
    str += "#{OneGadget::Helper.colorize('constraints')}:\n  "
    str += merge_constraints.join("\n  ")
  end
  str.gsub!(/0x[\da-f]+/) { |s| OneGadget::Helper.colorize(s, sev: :integer) }
  OneGadget::ABI.all.each do |reg|
    str.gsub!(/([^\w])(#{reg})([^\w])/, "\\1#{OneGadget::Helper.colorize('\2', sev: :reg)}\\3")
  end
  "#{str}\n"
end
score() click to toggle source

@return [Float]

The success probability of the constraints.
# File lib/one_gadget/gadget.rb, line 57
def score
  @score ||= constraints.reduce(1.0) { |s, c| s * calculate_score(c) }
end
value() click to toggle source

@return [Integer]

Returns +base+ plus +offset+.
# File lib/one_gadget/gadget.rb, line 51
def value
  base + offset
end

Private Instance Methods

calculate_null_score(identity) click to toggle source
# File lib/one_gadget/gadget.rb, line 87
def calculate_null_score(identity)
  # remove <CAST>
  identity.sub!(/^\([s|u]\d+\)/, '')
  # Thank God we are already able to parse this
  lmda = OneGadget::Emulators::Lambda.parse(identity)
  # rax == 0 is easy; rax + 0x10 == 0 is damn hard.
  return lmda.immi.zero? ? 0.9 : 0.1 if lmda.deref_count.zero?

  # [sp+xx] == NULL is easy.
  base = OneGadget::ABI.stack_register?(lmda.obj) ? 0 : 1
  0.9**(lmda.deref_count + base)
end
merge_constraints() click to toggle source
# File lib/one_gadget/gadget.rb, line 100
def merge_constraints
  key = 'writable: '
  w_cons, normal = constraints.partition { |c| c.start_with?(key) }
  return normal if w_cons.empty?

  w_cons.map! { |c| c[key.size..-1] }
  ["address#{w_cons.size > 1 ? 'es' : ''} #{w_cons.join(', ')} #{w_cons.size > 1 ? 'are' : 'is'} writable"] +
    normal
end