class Metasm::BPF
Public Class Methods
new(family = :latest)
click to toggle source
Calls superclass method
# File metasm/cpu/bpf/main.rb, line 47 def initialize(family = :latest) super() @endianness = :big @size = 32 @family = family end
Public Instance Methods
addop(name, bin, *args)
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 11 def addop(name, bin, *args) o = Opcode.new name, bin args.each { |a| o.args << a if @valid_args[a] o.props.update a if a.kind_of?(::Hash) } @opcode_list << o end
addop_alu(name, bin)
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 31 def addop_alu(name, bin) addop name, bin | 0x04, :a, :k addop name, bin | 0x0C, :a, :x end
addop_j(name, bin)
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 36 def addop_j(name, bin) addop name, bin | 0x05 | 0x00, :a, :k, :jt, :jf, :setip => true, :stopexec => true addop name, bin | 0x05 | 0x08, :a, :x, :jt, :jf, :setip => true, :stopexec => true end
addop_ldsz(bin, src)
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 25 def addop_ldsz(bin, src) addop 'mov', bin | 0x00, :a, src, :msz => 4 addop 'mov', bin | 0x08, :a, src, :msz => 2 addop 'mov', bin | 0x10, :a, src, :msz => 1 end
addop_ldx(bin, src)
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 20 def addop_ldx(bin, src) addop 'mov', bin | 0x00, :a, src addop 'mov', bin | 0x01, :x, src end
backtrace_binding()
click to toggle source
hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
# File metasm/cpu/bpf/decode.rb, line 78 def backtrace_binding @backtrace_binding ||= init_backtrace_binding end
backtrace_binding=(b)
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 81 def backtrace_binding=(b) @backtrace_binding = b end
build_bin_lookaside()
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 12 def build_bin_lookaside opcode_list.inject({}) { |h, op| h.update op.bin => op } end
decode_findopcode(edata)
click to toggle source
tries to find the opcode encoded at edata.ptr
# File metasm/cpu/bpf/decode.rb, line 17 def decode_findopcode(edata) return if edata.ptr > edata.data.length-8 di = DecodedInstruction.new self code = edata.data[edata.ptr, 2].unpack('v')[0] return di if di.opcode = @bin_lookaside[code] end
decode_instr_interpret(di, addr)
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 61 def decode_instr_interpret(di, addr) if di.opcode.props[:setip] delta = di.instruction.args[-1].reduce + 1 arg = Expression[addr, :+, 8*delta].reduce di.instruction.args[-1] = Expression[arg] if di.instruction.args.length == 4 delta = di.instruction.args[2].reduce + 1 arg = Expression[addr, :+, 8*delta].reduce di.instruction.args[2] = Expression[arg] end end di end
decode_instr_op(edata, di)
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 24 def decode_instr_op(edata, di) op = di.opcode di.instruction.opname = op.name di.bin_length = 8 code, jt, jf, k = edata.read(8).unpack('vCCV') op.args.each { |a| di.instruction.args << case a when :k; Expression[k] when :x; Reg.new(:x) when :a; Reg.new(:a) when :len; Reg.new(:len) when :p_k; PktRef.new(nil, Expression[k], op.props[:msz]) when :p_xk; PktRef.new(Reg.new(:x), Expression[k], op.props[:msz]) when :m_k; MemRef.new(nil, Expression[4*k], 4) when :jt; Expression[jt] when :jf; Expression[jf] else raise "unhandled arg #{a}" end } # je a, x, 0, 12 -> jne a, x, 12 # je a, x, 12, 0 -> je a, x, 12 if op.args[2] == :jt and di.instruction.args[2] == Expression[0] di.opcode = op.dup di.opcode.props.delete :stopexec di.instruction.opname = { 'jg' => 'jle', 'jge' => 'jl', 'je' => 'jne', 'jtest' => 'jntest' }[di.instruction.opname] di.instruction.args.delete_at(2) elsif op.args[3] == :jf and di.instruction.args[3] == Expression[0] di.opcode = op.dup di.opcode.props.delete :stopexec di.instruction.args.delete_at(3) end di end
get_backtrace_binding(di)
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 106 def get_backtrace_binding(di) a = di.instruction.args.map { |arg| case arg when PktRef, MemRef, Reg; arg.symbolic(di) else arg end } if binding = backtrace_binding[di.opcode.name] binding[di, *a] else puts "unhandled instruction to backtrace: #{di}" if $VERBOSE {:incomplete_binding => Expression[1]} end end
get_xrefs_x(dasm, di)
click to toggle source
# File metasm/cpu/bpf/decode.rb, line 122 def get_xrefs_x(dasm, di) return [] if not di.opcode.props[:setip] if di.instruction.args.length == 4 di.instruction.args[-2, 2] else di.instruction.args[-1, 1] end end
init_backtrace_binding()
click to toggle source
populate the @backtrace_binding hash with default values
# File metasm/cpu/bpf/decode.rb, line 84 def init_backtrace_binding @backtrace_binding ||= {} opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op| binding = case op when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } } when 'add'; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } } when 'sub'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } } when 'mul'; lambda { |di, a0, a1| { a0 => Expression[a0, :*, a1] } } when 'div'; lambda { |di, a0, a1| { a0 => Expression[a0, :/, a1] } } when 'shl'; lambda { |di, a0, a1| { a0 => Expression[a0, :<<, a1] } } when 'shr'; lambda { |di, a0, a1| { a0 => Expression[a0, :>>, a1] } } when 'neg'; lambda { |di, a0| { a0 => Expression[:-, a0] } } when 'msh'; lambda { |di, a0, a1| { a0 => Expression[[a1, :&, 0xf], :<<, 2] } } when 'jmp', 'jg', 'jge', 'je', 'jtest', 'ret'; lambda { |di, *a| { } } end @backtrace_binding[op] ||= binding if binding } @backtrace_binding end
init_bpf()
click to toggle source
# File metasm/cpu/bpf/opcodes.rb, line 41 def init_bpf @opcode_list = [] [:a, :k, :x, :len, :m_k, :p_k, :p_xk, :jt, :jf].each { |a| @valid_args[a] = true } # LD/ST addop_ldx 0x00, :k addop_ldsz 0x20, :p_k addop_ldsz 0x40, :p_xk addop_ldx 0x60, :m_k addop_ldx 0x80, :len addop 'msh', 0xB1, :x, :p_k, :msz => 1 addop 'mov', 0x02, :m_k, :a addop 'mov', 0x03, :m_k, :x # ALU addop_alu 'add', 0x00 addop_alu 'sub', 0x10 addop_alu 'mul', 0x20 addop_alu 'div', 0x30 addop_alu 'or', 0x40 addop_alu 'and', 0x50 addop_alu 'shl', 0x60 addop_alu 'shr', 0x70 addop 'neg', 0x84, :a # JMP addop 'jmp', 0x05, :k, :setip => true, :stopexec => true addop_j 'je', 0x10 addop_j 'jg', 0x20 addop_j 'jge', 0x30 addop_j 'jtest',0x40 addop 'ret', 0x06, :k, :stopexec => true addop 'ret', 0x16, :a, :stopexec => true addop 'mov', 0x07, :x, :a addop 'mov', 0x87, :a, :x end
Also aliased as: init_latest
init_opcode_list()
click to toggle source
# File metasm/cpu/bpf/main.rb, line 54 def init_opcode_list send("init_#@family") @opcode_list end
render_instruction(i)
click to toggle source
# File metasm/cpu/bpf/render.rb, line 30 def render_instruction(i) r = [] r << i.opname if not i.args.empty? r << ' ' i.args.each { |a_| r << a_ << ', ' } r.pop end r end
replace_instr_arg_immediate(i, old, new)
click to toggle source
updates an instruction's argument replacing an expression with another (eg label renamed)
# File metasm/cpu/bpf/decode.rb, line 133 def replace_instr_arg_immediate(i, old, new) i.args.map! { |a| case a when Expression; a == old ? new : Expression[a.bind(old => new).reduce] else a end } end