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
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_xrefs_x(dasm, di) click to toggle source
# File metasm/cpu/bpf/decode.rb, line 100
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 78
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_latest()
Alias for: init_bpf
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