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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +3 -2
  5. data/metasm.gemspec +3 -2
  6. data/metasm.rb +4 -1
  7. data/metasm/compile_c.rb +2 -2
  8. data/metasm/cpu/arc/decode.rb +0 -21
  9. data/metasm/cpu/arc/main.rb +4 -4
  10. data/metasm/cpu/arm/decode.rb +1 -5
  11. data/metasm/cpu/arm/main.rb +3 -3
  12. data/metasm/cpu/arm64/decode.rb +2 -6
  13. data/metasm/cpu/arm64/main.rb +5 -5
  14. data/metasm/cpu/bpf/decode.rb +3 -35
  15. data/metasm/cpu/bpf/main.rb +5 -5
  16. data/metasm/cpu/bpf/render.rb +1 -12
  17. data/metasm/cpu/cy16/decode.rb +0 -6
  18. data/metasm/cpu/cy16/main.rb +3 -3
  19. data/metasm/cpu/cy16/render.rb +0 -11
  20. data/metasm/cpu/dalvik/decode.rb +4 -26
  21. data/metasm/cpu/dalvik/main.rb +20 -2
  22. data/metasm/cpu/dalvik/opcodes.rb +3 -2
  23. data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
  24. data/metasm/cpu/ebpf/debug.rb +61 -0
  25. data/metasm/cpu/ebpf/decode.rb +142 -0
  26. data/metasm/cpu/ebpf/main.rb +58 -0
  27. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  28. data/metasm/cpu/ebpf/render.rb +36 -0
  29. data/metasm/cpu/ia32/debug.rb +39 -1
  30. data/metasm/cpu/ia32/decode.rb +111 -90
  31. data/metasm/cpu/ia32/decompile.rb +45 -37
  32. data/metasm/cpu/ia32/main.rb +10 -0
  33. data/metasm/cpu/ia32/parse.rb +6 -0
  34. data/metasm/cpu/mcs51/decode.rb +1 -1
  35. data/metasm/cpu/mcs51/main.rb +11 -0
  36. data/metasm/cpu/mips/decode.rb +8 -18
  37. data/metasm/cpu/mips/main.rb +3 -3
  38. data/metasm/cpu/mips/opcodes.rb +1 -1
  39. data/metasm/cpu/msp430/decode.rb +2 -6
  40. data/metasm/cpu/msp430/main.rb +3 -3
  41. data/metasm/cpu/openrisc.rb +11 -0
  42. data/metasm/cpu/openrisc/debug.rb +106 -0
  43. data/metasm/cpu/openrisc/decode.rb +182 -0
  44. data/metasm/cpu/openrisc/decompile.rb +350 -0
  45. data/metasm/cpu/openrisc/main.rb +70 -0
  46. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  47. data/metasm/cpu/openrisc/render.rb +37 -0
  48. data/metasm/cpu/ppc/decode.rb +0 -25
  49. data/metasm/cpu/ppc/main.rb +6 -6
  50. data/metasm/cpu/ppc/opcodes.rb +3 -4
  51. data/metasm/cpu/python/decode.rb +0 -20
  52. data/metasm/cpu/python/main.rb +1 -1
  53. data/metasm/cpu/sh4/decode.rb +2 -6
  54. data/metasm/cpu/sh4/main.rb +25 -23
  55. data/metasm/cpu/st20/decode.rb +0 -7
  56. data/metasm/cpu/webasm.rb +11 -0
  57. data/metasm/cpu/webasm/debug.rb +31 -0
  58. data/metasm/cpu/webasm/decode.rb +321 -0
  59. data/metasm/cpu/webasm/decompile.rb +386 -0
  60. data/metasm/cpu/webasm/encode.rb +104 -0
  61. data/metasm/cpu/webasm/main.rb +81 -0
  62. data/metasm/cpu/webasm/opcodes.rb +214 -0
  63. data/metasm/cpu/x86_64/compile_c.rb +13 -9
  64. data/metasm/cpu/x86_64/parse.rb +1 -1
  65. data/metasm/cpu/z80/decode.rb +0 -27
  66. data/metasm/cpu/z80/main.rb +3 -3
  67. data/metasm/cpu/z80/render.rb +0 -11
  68. data/metasm/debug.rb +43 -8
  69. data/metasm/decode.rb +62 -14
  70. data/metasm/decompile.rb +793 -466
  71. data/metasm/disassemble.rb +188 -131
  72. data/metasm/disassemble_api.rb +30 -17
  73. data/metasm/dynldr.rb +2 -2
  74. data/metasm/encode.rb +8 -2
  75. data/metasm/exe_format/autoexe.rb +2 -0
  76. data/metasm/exe_format/coff.rb +21 -3
  77. data/metasm/exe_format/coff_decode.rb +12 -0
  78. data/metasm/exe_format/coff_encode.rb +6 -3
  79. data/metasm/exe_format/dex.rb +13 -3
  80. data/metasm/exe_format/elf.rb +12 -2
  81. data/metasm/exe_format/elf_decode.rb +59 -1
  82. data/metasm/exe_format/main.rb +2 -0
  83. data/metasm/exe_format/mz.rb +1 -0
  84. data/metasm/exe_format/pe.rb +25 -3
  85. data/metasm/exe_format/wasm.rb +402 -0
  86. data/metasm/gui/dasm_decomp.rb +171 -95
  87. data/metasm/gui/dasm_graph.rb +61 -2
  88. data/metasm/gui/dasm_hex.rb +2 -2
  89. data/metasm/gui/dasm_main.rb +45 -19
  90. data/metasm/gui/debug.rb +13 -4
  91. data/metasm/gui/gtk.rb +12 -4
  92. data/metasm/main.rb +108 -103
  93. data/metasm/os/emulator.rb +175 -0
  94. data/metasm/os/main.rb +11 -6
  95. data/metasm/parse.rb +23 -12
  96. data/metasm/parse_c.rb +189 -135
  97. data/metasm/preprocessor.rb +16 -1
  98. data/misc/openrisc-parser.rb +79 -0
  99. data/samples/dasm-plugins/scanxrefs.rb +6 -4
  100. data/samples/dasm-plugins/selfmodify.rb +8 -8
  101. data/samples/dbg-plugins/trace_func.rb +1 -1
  102. data/samples/disassemble-gui.rb +14 -3
  103. data/samples/emubios.rb +251 -0
  104. data/samples/emudbg.rb +127 -0
  105. data/samples/lindebug.rb +79 -78
  106. data/samples/metasm-shell.rb +8 -8
  107. data/tests/all.rb +1 -1
  108. data/tests/expression.rb +2 -0
  109. data/tests/graph_layout.rb +1 -1
  110. data/tests/ia32.rb +1 -0
  111. data/tests/mips.rb +1 -1
  112. data/tests/preprocessor.rb +18 -0
  113. metadata +124 -6
  114. metadata.gz.sig +0 -0
@@ -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
@@ -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] + '->' + @dex.strings[m.nameidx]
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 :fmt31t, :fmt31c; op.args << :raa << :u32
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
@@ -3,5 +3,8 @@
3
3
  #
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
- require 'metasm/cpu/mips/parse'
7
- require 'metasm/compile_c'
6
+
7
+ require 'metasm/main'
8
+ require 'metasm/cpu/ebpf/decode'
9
+ require 'metasm/cpu/ebpf/render'
10
+ require 'metasm/cpu/ebpf/debug'
@@ -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