metasm 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/Gemfile +3 -2
- data/metasm.gemspec +3 -2
- data/metasm.rb +4 -1
- data/metasm/compile_c.rb +2 -2
- data/metasm/cpu/arc/decode.rb +0 -21
- data/metasm/cpu/arc/main.rb +4 -4
- data/metasm/cpu/arm/decode.rb +1 -5
- data/metasm/cpu/arm/main.rb +3 -3
- data/metasm/cpu/arm64/decode.rb +2 -6
- data/metasm/cpu/arm64/main.rb +5 -5
- data/metasm/cpu/bpf/decode.rb +3 -35
- data/metasm/cpu/bpf/main.rb +5 -5
- data/metasm/cpu/bpf/render.rb +1 -12
- data/metasm/cpu/cy16/decode.rb +0 -6
- data/metasm/cpu/cy16/main.rb +3 -3
- data/metasm/cpu/cy16/render.rb +0 -11
- data/metasm/cpu/dalvik/decode.rb +4 -26
- data/metasm/cpu/dalvik/main.rb +20 -2
- data/metasm/cpu/dalvik/opcodes.rb +3 -2
- data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
- data/metasm/cpu/ebpf/debug.rb +61 -0
- data/metasm/cpu/ebpf/decode.rb +142 -0
- data/metasm/cpu/ebpf/main.rb +58 -0
- data/metasm/cpu/ebpf/opcodes.rb +97 -0
- data/metasm/cpu/ebpf/render.rb +36 -0
- data/metasm/cpu/ia32/debug.rb +39 -1
- data/metasm/cpu/ia32/decode.rb +111 -90
- data/metasm/cpu/ia32/decompile.rb +45 -37
- data/metasm/cpu/ia32/main.rb +10 -0
- data/metasm/cpu/ia32/parse.rb +6 -0
- data/metasm/cpu/mcs51/decode.rb +1 -1
- data/metasm/cpu/mcs51/main.rb +11 -0
- data/metasm/cpu/mips/decode.rb +8 -18
- data/metasm/cpu/mips/main.rb +3 -3
- data/metasm/cpu/mips/opcodes.rb +1 -1
- data/metasm/cpu/msp430/decode.rb +2 -6
- data/metasm/cpu/msp430/main.rb +3 -3
- data/metasm/cpu/openrisc.rb +11 -0
- data/metasm/cpu/openrisc/debug.rb +106 -0
- data/metasm/cpu/openrisc/decode.rb +182 -0
- data/metasm/cpu/openrisc/decompile.rb +350 -0
- data/metasm/cpu/openrisc/main.rb +70 -0
- data/metasm/cpu/openrisc/opcodes.rb +109 -0
- data/metasm/cpu/openrisc/render.rb +37 -0
- data/metasm/cpu/ppc/decode.rb +0 -25
- data/metasm/cpu/ppc/main.rb +6 -6
- data/metasm/cpu/ppc/opcodes.rb +3 -4
- data/metasm/cpu/python/decode.rb +0 -20
- data/metasm/cpu/python/main.rb +1 -1
- data/metasm/cpu/sh4/decode.rb +2 -6
- data/metasm/cpu/sh4/main.rb +25 -23
- data/metasm/cpu/st20/decode.rb +0 -7
- data/metasm/cpu/webasm.rb +11 -0
- data/metasm/cpu/webasm/debug.rb +31 -0
- data/metasm/cpu/webasm/decode.rb +321 -0
- data/metasm/cpu/webasm/decompile.rb +386 -0
- data/metasm/cpu/webasm/encode.rb +104 -0
- data/metasm/cpu/webasm/main.rb +81 -0
- data/metasm/cpu/webasm/opcodes.rb +214 -0
- data/metasm/cpu/x86_64/compile_c.rb +13 -9
- data/metasm/cpu/x86_64/parse.rb +1 -1
- data/metasm/cpu/z80/decode.rb +0 -27
- data/metasm/cpu/z80/main.rb +3 -3
- data/metasm/cpu/z80/render.rb +0 -11
- data/metasm/debug.rb +43 -8
- data/metasm/decode.rb +62 -14
- data/metasm/decompile.rb +793 -466
- data/metasm/disassemble.rb +188 -131
- data/metasm/disassemble_api.rb +30 -17
- data/metasm/dynldr.rb +2 -2
- data/metasm/encode.rb +8 -2
- data/metasm/exe_format/autoexe.rb +2 -0
- data/metasm/exe_format/coff.rb +21 -3
- data/metasm/exe_format/coff_decode.rb +12 -0
- data/metasm/exe_format/coff_encode.rb +6 -3
- data/metasm/exe_format/dex.rb +13 -3
- data/metasm/exe_format/elf.rb +12 -2
- data/metasm/exe_format/elf_decode.rb +59 -1
- data/metasm/exe_format/main.rb +2 -0
- data/metasm/exe_format/mz.rb +1 -0
- data/metasm/exe_format/pe.rb +25 -3
- data/metasm/exe_format/wasm.rb +402 -0
- data/metasm/gui/dasm_decomp.rb +171 -95
- data/metasm/gui/dasm_graph.rb +61 -2
- data/metasm/gui/dasm_hex.rb +2 -2
- data/metasm/gui/dasm_main.rb +45 -19
- data/metasm/gui/debug.rb +13 -4
- data/metasm/gui/gtk.rb +12 -4
- data/metasm/main.rb +108 -103
- data/metasm/os/emulator.rb +175 -0
- data/metasm/os/main.rb +11 -6
- data/metasm/parse.rb +23 -12
- data/metasm/parse_c.rb +189 -135
- data/metasm/preprocessor.rb +16 -1
- data/misc/openrisc-parser.rb +79 -0
- data/samples/dasm-plugins/scanxrefs.rb +6 -4
- data/samples/dasm-plugins/selfmodify.rb +8 -8
- data/samples/dbg-plugins/trace_func.rb +1 -1
- data/samples/disassemble-gui.rb +14 -3
- data/samples/emubios.rb +251 -0
- data/samples/emudbg.rb +127 -0
- data/samples/lindebug.rb +79 -78
- data/samples/metasm-shell.rb +8 -8
- data/tests/all.rb +1 -1
- data/tests/expression.rb +2 -0
- data/tests/graph_layout.rb +1 -1
- data/tests/ia32.rb +1 -0
- data/tests/mips.rb +1 -1
- data/tests/preprocessor.rb +18 -0
- metadata +124 -6
- metadata.gz.sig +0 -0
data/metasm/cpu/dalvik/decode.rb
CHANGED
|
@@ -106,6 +106,10 @@ class Dalvik
|
|
|
106
106
|
when :str16
|
|
107
107
|
val << edata.decode_imm(:u16, @endianness)
|
|
108
108
|
DexString.new(@dex, val.last)
|
|
109
|
+
when :str32
|
|
110
|
+
val << edata.decode_imm(:u16, @endianness)
|
|
111
|
+
val << edata.decode_imm(:u16, @endianness)
|
|
112
|
+
DexString.new(@dex, (val[-2] | (val[-1] << 16)))
|
|
109
113
|
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
|
|
110
114
|
end
|
|
111
115
|
}
|
|
@@ -126,10 +130,6 @@ class Dalvik
|
|
|
126
130
|
di
|
|
127
131
|
end
|
|
128
132
|
|
|
129
|
-
def backtrace_binding
|
|
130
|
-
@backtrace_binding ||= init_backtrace_binding
|
|
131
|
-
end
|
|
132
|
-
|
|
133
133
|
def init_backtrace_binding
|
|
134
134
|
@backtrace_binding ||= {}
|
|
135
135
|
sz = @size/8
|
|
@@ -149,28 +149,6 @@ class Dalvik
|
|
|
149
149
|
@backtrace_binding
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
def get_backtrace_binding(di)
|
|
153
|
-
a = di.instruction.args.map { |arg|
|
|
154
|
-
case arg
|
|
155
|
-
when Reg; arg.symbolic
|
|
156
|
-
else arg
|
|
157
|
-
end
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if binding = backtrace_binding[di.opcode.name]
|
|
161
|
-
binding[di, *a]
|
|
162
|
-
else
|
|
163
|
-
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
164
|
-
# assume nothing except the 1st arg is modified
|
|
165
|
-
case a[0]
|
|
166
|
-
when Indirection, Symbol; { a[0] => Expression::Unknown }
|
|
167
|
-
when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
|
|
168
|
-
else {}
|
|
169
|
-
end.update(:incomplete_binding => Expression[1])
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
end
|
|
173
|
-
|
|
174
152
|
def get_xrefs_x(dasm, di)
|
|
175
153
|
if di.opcode.props[:saveip]
|
|
176
154
|
m = di.instruction.args.first
|
data/metasm/cpu/dalvik/main.rb
CHANGED
|
@@ -14,7 +14,7 @@ class Dalvik < CPU
|
|
|
14
14
|
@i = i
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def symbolic
|
|
17
|
+
def symbolic(di=nil)
|
|
18
18
|
"r#@i".to_sym
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -35,9 +35,15 @@ class Dalvik < CPU
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def symbolic(di=nil)
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
def to_s
|
|
39
43
|
if @dex and m = @dex.methods[@midx]
|
|
40
|
-
@dex.types[m.classidx]
|
|
44
|
+
t = @dex.types[m.classidx]
|
|
45
|
+
t = t[1...-1] if t[0, 1] == 'L' and t[-1, 1] == ';'
|
|
46
|
+
t + '->' + @dex.strings[m.nameidx]
|
|
41
47
|
#dex.encoded.inv_export[@off]
|
|
42
48
|
else
|
|
43
49
|
"method_#@midx"
|
|
@@ -52,6 +58,10 @@ class Dalvik < CPU
|
|
|
52
58
|
@fidx = fidx
|
|
53
59
|
end
|
|
54
60
|
|
|
61
|
+
def symbolic(di=nil)
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
55
65
|
def to_s
|
|
56
66
|
if @dex and f = @dex.fields[@fidx]
|
|
57
67
|
@dex.types[f.classidx] + '->' + @dex.strings[f.nameidx]
|
|
@@ -68,6 +78,10 @@ class Dalvik < CPU
|
|
|
68
78
|
@tidx = tidx
|
|
69
79
|
end
|
|
70
80
|
|
|
81
|
+
def symbolic(di=nil)
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
71
85
|
def to_s
|
|
72
86
|
if @dex and f = @dex.types[@tidx]
|
|
73
87
|
f
|
|
@@ -84,6 +98,10 @@ class Dalvik < CPU
|
|
|
84
98
|
@sidx = sidx
|
|
85
99
|
end
|
|
86
100
|
|
|
101
|
+
def symbolic(di=nil)
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
|
|
87
105
|
def to_s
|
|
88
106
|
if @dex and f = @dex.strings[@sidx]
|
|
89
107
|
f.inspect
|
|
@@ -64,7 +64,7 @@ unused_fc unused_fd unused_fe unused_ff]
|
|
|
64
64
|
@valid_props[:canthrow] = true
|
|
65
65
|
[:i16, :i16_32hi, :i16_64hi, :i32, :iaa, :ib, :icc, :u16, :u32, :u64,
|
|
66
66
|
:r16, :ra, :raa, :rb, :rbb, :rcc, :rlist16, :rlist4, :rlist5,
|
|
67
|
-
:m16, :fld16, :typ16, :str16
|
|
67
|
+
:m16, :fld16, :typ16, :str16, :str32
|
|
68
68
|
].each { |a| @valid_args[a] = true }
|
|
69
69
|
@opcode_list = []
|
|
70
70
|
|
|
@@ -232,7 +232,8 @@ unused_fc unused_fd unused_fe unused_ff]
|
|
|
232
232
|
when :fmt22s, :fmt22t; op.args << :ra << :rb << :i16
|
|
233
233
|
when :fmt22c, :fmt22cs; op.args << :ra << :rb << :fld16
|
|
234
234
|
when :fmt30t; op.args << :i32
|
|
235
|
-
when :
|
|
235
|
+
when :fmt31c; op.args << :raa << :str32
|
|
236
|
+
when :fmt31t; op.args << :raa << :u32
|
|
236
237
|
when :fmt32x; op.args << :r16 << :r16
|
|
237
238
|
when :fmt31i; op.args << :raa << :i32
|
|
238
239
|
when :fmt35ca
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'metasm/cpu/ebpf/opcodes'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class EBPF
|
|
11
|
+
def dbg_register_pc
|
|
12
|
+
@dbg_register_pc ||= :pc
|
|
13
|
+
end
|
|
14
|
+
def dbg_register_sp
|
|
15
|
+
@dbg_register_sp ||= :r10
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dbg_register_list
|
|
19
|
+
@dbg_register_list ||= [:r0, :r1, :r2, :r3, :r4, :r5, :r6, :r7, :r8, :r9, :r10, :pc]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def dbg_flag_list
|
|
23
|
+
@dbg_flag_list ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dbg_register_size
|
|
27
|
+
@dbg_register_size ||= Hash.new(64)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def dbg_need_stepover(dbg, addr, di)
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
|
|
35
|
+
a = di.instruction.args.map { |aa| symbolic(aa) }
|
|
36
|
+
|
|
37
|
+
cond = case di.opcode.name
|
|
38
|
+
when 'jeq'; dbg_ctx.resolve(a[0]) == dbg_ctx.resolve(a[1])
|
|
39
|
+
when 'jgt'; dbg_ctx.resolve(a[0]) > dbg_ctx.resolve(a[1])
|
|
40
|
+
when 'jge'; dbg_ctx.resolve(a[0]) >= dbg_ctx.resolve(a[1])
|
|
41
|
+
when 'jset'; dbg_ctx.resolve(a[0]) & dbg_ctx.resolve(a[1]) > 0
|
|
42
|
+
when 'jne'; dbg_ctx.resolve(a[0]) != dbg_ctx.resolve(a[1])
|
|
43
|
+
when 'jsgt'; Expression.make_signed(dbg_ctx.resolve(a[0]), 64) > Expression.make_signed(dbg_ctx.resolve(a[1]), 64)
|
|
44
|
+
when 'jsge'; Expression.make_signed(dbg_ctx.resolve(a[0]), 64) >= Expression.make_signed(dbg_ctx.resolve(a[1]), 64)
|
|
45
|
+
else return super(di, fbd, pc_reg, dbg_ctx)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if cond
|
|
49
|
+
fbd[pc_reg] = a.last
|
|
50
|
+
else
|
|
51
|
+
fbd[pc_reg] = di.next_addr
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def dbg_enable_bp(dbg, bp)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dbg_disable_bp(dbg, bp)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'metasm/cpu/ebpf/opcodes'
|
|
8
|
+
require 'metasm/decode'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class EBPF
|
|
12
|
+
def build_bin_lookaside
|
|
13
|
+
opcode_list.inject({}) { |h, op| h.update op.bin => op }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# tries to find the opcode encoded at edata.ptr
|
|
17
|
+
def decode_findopcode(edata)
|
|
18
|
+
return if edata.ptr > edata.data.length-8
|
|
19
|
+
di = DecodedInstruction.new self
|
|
20
|
+
code_off = (@endianness == :little ? 0 : 7)
|
|
21
|
+
code = edata.data[edata.ptr+code_off, 1].unpack('C')[0]
|
|
22
|
+
return di if di.opcode = @bin_lookaside[code]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def decode_instr_op(edata, di)
|
|
26
|
+
op = di.opcode
|
|
27
|
+
di.instruction.opname = op.name
|
|
28
|
+
di.bin_length = 8
|
|
29
|
+
blob = edata.decode_imm(:u64, @endianness)
|
|
30
|
+
imm = (blob >> 32) & 0xffff_ffff
|
|
31
|
+
imm = Expression.make_signed(imm, 32)
|
|
32
|
+
off = (blob >> 16) & 0xffff
|
|
33
|
+
off = Expression.make_signed(off, 16)
|
|
34
|
+
src = (blob >> 12) & 0xf
|
|
35
|
+
dst = (blob >> 8) & 0xf
|
|
36
|
+
#code = blob & 0xff
|
|
37
|
+
|
|
38
|
+
if di.opcode.props[:imm64]
|
|
39
|
+
imm = (imm & 0xffff_ffff) | (edata.decode_imm(:u64, @endianness) & 0xffff_ffff_0000_0000) # next_imm << 32
|
|
40
|
+
di.bin_length += 8
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
op.args.each { |a|
|
|
44
|
+
di.instruction.args << case a
|
|
45
|
+
when :i; Expression[imm]
|
|
46
|
+
when :r0; Reg.new(0)
|
|
47
|
+
when :rs; Reg.new(src)
|
|
48
|
+
when :rd; Reg.new(dst)
|
|
49
|
+
when :off; Expression[off]
|
|
50
|
+
when :p_rs_o; Memref.new(Reg.new(src), Expression[off], op.props[:msz])
|
|
51
|
+
when :p_rd_o; Memref.new(Reg.new(dst), Expression[off], op.props[:msz])
|
|
52
|
+
when :p_pkt_i; Pktref.new(nil, Expression[imm], op.props[:msz])
|
|
53
|
+
when :p_pkt_rs_i; Pktref.new(Reg.new(src), Expression[imm], op.props[:msz])
|
|
54
|
+
else raise "unhandled arg #{a}"
|
|
55
|
+
end
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
di
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def decode_instr_interpret(di, addr)
|
|
62
|
+
if di.opcode.props[:setip]
|
|
63
|
+
delta = di.instruction.args[-1].reduce + 1
|
|
64
|
+
arg = Expression[addr, :+, 8*delta].reduce
|
|
65
|
+
di.instruction.args[-1] = Expression[arg]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
di
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# populate the @backtrace_binding hash with default values
|
|
72
|
+
def init_backtrace_binding
|
|
73
|
+
@backtrace_binding ||= {}
|
|
74
|
+
|
|
75
|
+
bswap = lambda { |val, nbytes|
|
|
76
|
+
case nbytes
|
|
77
|
+
when 1; val
|
|
78
|
+
when 2; Expression[[[val, :&, 0xff], :<<, 8], :|, [[val, :&, 0xff00], :>>, 8]]
|
|
79
|
+
when 4; Expression[[bswap[Expression[val, :&, 0xffff], 2], :<<, 16], :|, bswap[Expression[[val, :>>, 16], :&, 0xffff], 2]]
|
|
80
|
+
when 8; Expression[[bswap[Expression[val, :&, 0xffffffff], 4], :<<, 32], :|, bswap[Expression[[val, :>>, 32], :&, 0xffffffff], 4]]
|
|
81
|
+
end
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
|
85
|
+
binding = case op
|
|
86
|
+
|
|
87
|
+
when 'add'; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } }
|
|
88
|
+
when 'sub'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } }
|
|
89
|
+
when 'mul'; lambda { |di, a0, a1| { a0 => Expression[[a0, :*, a1], :&, 0xffff_ffff_ffff_ffff] } }
|
|
90
|
+
when 'div'; lambda { |di, a0, a1| { a0 => Expression[a0, :/, a1] } }
|
|
91
|
+
when 'or'; lambda { |di, a0, a1| { a0 => Expression[a0, :|, a1] } }
|
|
92
|
+
when 'and'; lambda { |di, a0, a1| { a0 => Expression[a0, :&, a1] } }
|
|
93
|
+
when 'shl'; lambda { |di, a0, a1| { a0 => Expression[[a0, :<<, a1], :&, 0xffff_ffff_ffff_ffff] } }
|
|
94
|
+
when 'shr'; lambda { |di, a0, a1| { a0 => Expression[a0, :>>, a1] } } # XXX sign
|
|
95
|
+
when 'neg'; lambda { |di, a0| { a0 => Expression[:-, a0] } }
|
|
96
|
+
when 'mod'; lambda { |di, a0, a1| { a0 => Expression[a0, :%, a1] } }
|
|
97
|
+
when 'xor'; lambda { |di, a0, a1| { a0 => Expression[a0, :^, a1] } }
|
|
98
|
+
when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
99
|
+
when 'sar'; lambda { |di, a0, a1| { a0 => Expression[a0, :>>, a1] } }
|
|
100
|
+
|
|
101
|
+
when 'add32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :+, a1], :&, 0xffff_ffff] } }
|
|
102
|
+
when 'sub32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :-, a1], :&, 0xffff_ffff] } }
|
|
103
|
+
when 'mul32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :*, a1], :&, 0xffff_ffff] } }
|
|
104
|
+
when 'div32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :/, a1], :&, 0xffff_ffff] } }
|
|
105
|
+
when 'or32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :|, a1], :&, 0xffff_ffff] } }
|
|
106
|
+
when 'and32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :&, a1], :&, 0xffff_ffff] } }
|
|
107
|
+
when 'shl32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :<<, a1], :&, 0xffff_ffff] } }
|
|
108
|
+
when 'shr32'; lambda { |di, a0, a1| { a0 => Expression[[[a0, :&, 0xffff_ffff], :>>, a1], :&, 0xffff_ffff] } } # XXX sign
|
|
109
|
+
when 'neg32'; lambda { |di, a0| { a0 => Expression[:-, [a0, :&, 0xffff_ffff]] } }
|
|
110
|
+
when 'mod32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :%, a1], :&, 0xffff_ffff] } }
|
|
111
|
+
when 'xor32'; lambda { |di, a0, a1| { a0 => Expression[[a0, :^, a1], :&, 0xffff_ffff] } }
|
|
112
|
+
when 'mov32'; lambda { |di, a0, a1| { a0 => Expression[a1, :&, 0xffff_ffff] } }
|
|
113
|
+
when 'sar32'; lambda { |di, a0, a1| { a0 => Expression[[[a0, :&, 0xffff_ffff], :>>, a1], :&, 0xffff_ffff] } }
|
|
114
|
+
|
|
115
|
+
when 'be', 'le'; lambda { |di, a0, a1|
|
|
116
|
+
if @endianness.to_s[0] == di.opcode.name[0]
|
|
117
|
+
{}
|
|
118
|
+
else
|
|
119
|
+
{ a1 => bswap[a1, Expression[a0].reduce] }
|
|
120
|
+
end
|
|
121
|
+
}
|
|
122
|
+
when /^ldind|^ldabs|^stind|^stabs/; lambda { |di, a0, a1|
|
|
123
|
+
if @endianness == :big
|
|
124
|
+
{ a0 => Expression[a1] }
|
|
125
|
+
else
|
|
126
|
+
{ a0 => bswap[a1, di.opcode.props[:msz]] }
|
|
127
|
+
end
|
|
128
|
+
}
|
|
129
|
+
when /^ld|^st/; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
130
|
+
when /^xadd/; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } } # XXX bswap ?
|
|
131
|
+
|
|
132
|
+
when 'call'; lambda { |di, *a| { :r0 => Expression::Unknown } }
|
|
133
|
+
|
|
134
|
+
when 'jmp', 'jeq', 'jgt', 'jge', 'jset', 'jne', 'jsgt', 'jsge'; lambda { |di, *a| { } }
|
|
135
|
+
end
|
|
136
|
+
@backtrace_binding[op] ||= binding if binding
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@backtrace_binding
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'metasm/main'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class EBPF < CPU
|
|
11
|
+
class Reg
|
|
12
|
+
attr_accessor :v
|
|
13
|
+
def initialize(v)
|
|
14
|
+
@v = v
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def symbolic(di=nil) ; "r#@v".to_sym ; end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Memref
|
|
21
|
+
attr_accessor :base, :offset, :msz
|
|
22
|
+
|
|
23
|
+
def initialize(base, offset, msz)
|
|
24
|
+
@base = base
|
|
25
|
+
@offset = offset
|
|
26
|
+
@msz = msz
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def symbolic(di=nil)
|
|
30
|
+
p = Expression[@base.symbolic] if base
|
|
31
|
+
p = Expression[p, :+, @offset] if offset
|
|
32
|
+
Indirection[p, @msz, (di.address if di)]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Pktref < Memref
|
|
37
|
+
def symbolic(di=nil)
|
|
38
|
+
p = Expression[:packet]
|
|
39
|
+
p = Expression[p, :+, @base.symbolic] if base
|
|
40
|
+
p = Expression[p, :+, @offset] if offset
|
|
41
|
+
Indirection[p, @msz, (di.address if di)]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize(family = :latest, endianness = :big)
|
|
46
|
+
super()
|
|
47
|
+
@endianness = endianness
|
|
48
|
+
@size = 64
|
|
49
|
+
@family = family
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def init_opcode_list
|
|
53
|
+
send("init_#@family")
|
|
54
|
+
@opcode_list
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
require 'metasm/cpu/ebpf/main'
|
|
7
|
+
|
|
8
|
+
module Metasm
|
|
9
|
+
|
|
10
|
+
# https://www.kernel.org/doc/Documentation/networking/filter.txt
|
|
11
|
+
class EBPF
|
|
12
|
+
def addop(name, bin, *args)
|
|
13
|
+
o = Opcode.new name, bin
|
|
14
|
+
args.each { |a|
|
|
15
|
+
o.args << a if @valid_args[a]
|
|
16
|
+
o.props.update a if a.kind_of?(::Hash)
|
|
17
|
+
}
|
|
18
|
+
@opcode_list << o
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def addop_alu(name, bin)
|
|
22
|
+
addop name, bin | 0x07, :rd, :i
|
|
23
|
+
addop name, bin | 0x0F, :rd, :rs
|
|
24
|
+
addop name+'32', bin | 0x04, :rd, :i
|
|
25
|
+
addop name+'32', bin | 0x0C, :rd, :rs
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def addop_sz32(name, bin, dst, src)
|
|
29
|
+
addop name + 'w', bin | 0x00, dst, src, :msz => 4
|
|
30
|
+
addop name + 'h', bin | 0x08, dst, src, :msz => 2
|
|
31
|
+
addop name + 'b', bin | 0x10, dst, src, :msz => 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def addop_sz64(name, bin, dst, src)
|
|
35
|
+
addop name + 'w', bin | 0x00, dst, src, :msz => 4
|
|
36
|
+
addop name + 'dw', bin | 0x18, dst, src, :msz => 8
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def addop_sz(name, bin, dst, src)
|
|
40
|
+
addop_sz32(name, bin, dst, src)
|
|
41
|
+
addop name + 'dw', bin | 0x18, dst, src, :msz => 8
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def addop_j(name, bin)
|
|
45
|
+
addop name, bin | 0x00, :rd, :i, :off, :setip => true
|
|
46
|
+
addop name, bin | 0x08, :rd, :rs, :off, :setip => true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def init_ebpf
|
|
50
|
+
@opcode_list = []
|
|
51
|
+
[:i, :rs, :rd, :off, :p_rs_o, :p_rd_o, :r0, :p_pkt_i, :p_pkt_rs_i].each { |a| @valid_args[a] = true }
|
|
52
|
+
|
|
53
|
+
# ALU
|
|
54
|
+
addop_alu 'add', 0x00
|
|
55
|
+
addop_alu 'sub', 0x10
|
|
56
|
+
addop_alu 'mul', 0x20
|
|
57
|
+
addop_alu 'div', 0x30
|
|
58
|
+
addop_alu 'or', 0x40
|
|
59
|
+
addop_alu 'and', 0x50
|
|
60
|
+
addop_alu 'shl', 0x60
|
|
61
|
+
addop_alu 'shr', 0x70
|
|
62
|
+
addop 'neg', 0x87, :rd
|
|
63
|
+
addop 'neg32', 0x84, :rd
|
|
64
|
+
addop_alu 'mod', 0x90
|
|
65
|
+
addop_alu 'xor', 0xa0
|
|
66
|
+
addop_alu 'mov', 0xb0
|
|
67
|
+
addop_alu 'sar', 0xc0
|
|
68
|
+
|
|
69
|
+
addop 'le', 0xd4, :i, :rd # native to little endian (short if i==16, word if i==32, quad if imm==64)
|
|
70
|
+
addop 'be', 0xdC, :i, :rd # native to big endian
|
|
71
|
+
|
|
72
|
+
# LD/ST
|
|
73
|
+
addop 'lddw', 0x18, :rd, :i, :imm64 => true # next insns serves only to store high 32bits of imm64
|
|
74
|
+
addop_sz32 'ldabs', 0x20, :r0, :p_pkt_i
|
|
75
|
+
addop_sz32 'ldind', 0x40, :r0, :p_pkt_rs_i
|
|
76
|
+
addop_sz 'ldx', 0x61, :rd, :p_rs_o
|
|
77
|
+
addop_sz 'st', 0x62, :p_rd_o, :i
|
|
78
|
+
addop_sz 'stx', 0x63, :p_rd_o, :rs
|
|
79
|
+
addop_sz64 'xadd', 0xC3, :p_rd_o, :rs
|
|
80
|
+
|
|
81
|
+
# BRANCH
|
|
82
|
+
addop 'jmp', 0x05, :off, :setip => true, :stopexec => true # 'ja'
|
|
83
|
+
addop_j 'jeq', 0x15
|
|
84
|
+
addop_j 'jgt', 0x25
|
|
85
|
+
addop_j 'jge', 0x35
|
|
86
|
+
addop_j 'jset', 0x45
|
|
87
|
+
addop_j 'jne', 0x55
|
|
88
|
+
addop_j 'jsgt', 0x65
|
|
89
|
+
addop_j 'jsge', 0x75
|
|
90
|
+
addop 'call', 0x85, :i # native call, doesn't interfere with bpf code flow
|
|
91
|
+
addop 'tailcall', 0x8D, :i, :stopexec => true # tail call: r2 is a map of bpf programs, r3 is an index, pass control to r2[r3] (no return)
|
|
92
|
+
addop 'exit', 0x95, :stopexec => true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
alias init_latest init_ebpf
|
|
96
|
+
end
|
|
97
|
+
end
|