metasm 1.0.5 → 1.0.6

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +3 -3
  4. data/Rakefile +1 -1
  5. data/cortex.yaml +17 -0
  6. data/metasm/cpu/arm64/decode.rb +87 -11
  7. data/metasm/cpu/arm64/decompile.rb +142 -0
  8. data/metasm/cpu/arm64/opcodes.rb +53 -23
  9. data/metasm/cpu/arm64.rb +1 -0
  10. data/metasm/cpu/dwarf/debug.rb +39 -0
  11. data/metasm/cpu/dwarf/decode.rb +124 -0
  12. data/metasm/cpu/dwarf/decompile.rb +212 -0
  13. data/metasm/cpu/dwarf/encode.rb +49 -0
  14. data/metasm/cpu/dwarf/main.rb +37 -0
  15. data/metasm/cpu/dwarf/opcodes.rb +107 -0
  16. data/metasm/cpu/dwarf.rb +11 -0
  17. data/metasm/cpu/ia32/debug.rb +8 -0
  18. data/metasm/cpu/ia32/decode.rb +25 -1
  19. data/metasm/cpu/ia32/decompile.rb +205 -342
  20. data/metasm/cpu/mips/decode.rb +1 -1
  21. data/metasm/cpu/ppc/decode.rb +1 -1
  22. data/metasm/cpu/sh4/decode.rb +1 -1
  23. data/metasm/cpu/x86_64/decompile.rb +68 -0
  24. data/metasm/cpu/x86_64.rb +1 -0
  25. data/metasm/decode.rb +14 -0
  26. data/metasm/decompile.rb +51 -27
  27. data/metasm/disassemble.rb +24 -15
  28. data/metasm/dynldr.rb +23 -4
  29. data/metasm/encode.rb +11 -0
  30. data/metasm/exe_format/coff_encode.rb +6 -7
  31. data/metasm/exe_format/elf.rb +60 -2
  32. data/metasm/exe_format/elf_decode.rb +201 -6
  33. data/metasm/exe_format/shellcode.rb +39 -0
  34. data/metasm/gui/dasm_decomp.rb +1 -0
  35. data/metasm/os/emulator.rb +7 -0
  36. data/metasm/parse_c.rb +1 -1
  37. data/metasm.gemspec +1 -2
  38. data/metasm.rb +1 -1
  39. data/samples/disassemble-gui.rb +27 -11
  40. data/samples/disassemble.rb +9 -12
  41. data/samples/emudbg.rb +1 -1
  42. data/samples/factorize-headers-elfimports.rb +4 -1
  43. data/samples/lindebug.rb +16 -2
  44. data/tests/shellcode.rb +111 -0
  45. metadata +19 -107
  46. checksums.yaml.gz.sig +0 -0
  47. data.tar.gz.sig +0 -3
  48. metadata.gz.sig +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e74fc20e6f9465f9bac4e96967e3537fd58304a4d962fbfa3d93b4516291ca99
4
- data.tar.gz: a818712400dc1be554245295e3f33f1f926d3c95e03b7f730fb034b0d2e2b78c
3
+ metadata.gz: 220a98d0282862014276d9667dcd41aa444270ba4b4019a5add42e0d58a4e9b2
4
+ data.tar.gz: 674c9502bd4724a7cba78e57fd0ae42099ee226d039843cbed3d3f11c40c9e55
5
5
  SHA512:
6
- metadata.gz: 4526e61a6ad9b55ce9376424018afd0979c688b281cae38de8050d18eff4475ca5d02c03a3e64db479a964542e347bbb10e36238a1c94ed9e7a9771519f04e11
7
- data.tar.gz: 864c9fcf111d806fc311d65062743d449a9a355d6b7b2bd5b44f0625a4d1c7fb6c86af4c1147dafd8c706f1a5659970c26e0911e953d4c82710ad2db3e5b025e
6
+ metadata.gz: 2357bb7357af85c8ace72fde57f8af490f6a2a64d10c086ba1037e96d88143a8089d0ce7266080c173932ac9de15a19041d70579aa1a3b9a0aab8954ae5565bc
7
+ data.tar.gz: a84f3952ffa0e0dcd44602b0b6826f1211d1930b63c8190afaadbe038c9017917f48a2f72bd35da0a4195e2409c663c2b3504b8ac6e017f6b825ae7586d10727
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/**
2
2
  doc/**/*.html
3
3
  metasm/dynldr-*.so
4
+ Gemfile.lock
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source 'https://rubygems.org' do
2
- gemspec
3
- end
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
data/Rakefile CHANGED
@@ -7,4 +7,4 @@ Rake::TestTask.new do |t|
7
7
  end
8
8
 
9
9
  task default: :test
10
-
10
+ task spec: :test
data/cortex.yaml ADDED
@@ -0,0 +1,17 @@
1
+ ---
2
+ info:
3
+ title: Metasm
4
+ description: This is a mirror of the mercurial repository for metasm
5
+ x-cortex-git:
6
+ github:
7
+ alias: r7org
8
+ repository: rapid7/metasm
9
+ x-cortex-tag: metasm
10
+ x-cortex-type: service
11
+ x-cortex-domain-parents:
12
+ - tag: metasploit
13
+ x-cortex-groups:
14
+ - exposure:external-ship
15
+ openapi: 3.0.1
16
+ servers:
17
+ - url: "/"
@@ -47,11 +47,6 @@ class ARM64
47
47
  }
48
48
  end
49
49
 
50
- def disassembler_default_func
51
- df = DecodedFunction.new
52
- df
53
- end
54
-
55
50
  def decode_instr_op(edata, di)
56
51
  op = di.opcode
57
52
  di.instruction.opname = op.name
@@ -96,7 +91,6 @@ class ARM64
96
91
  mode = [ :uxtb, :uxth, :uxtw, :uxtx, :sxtb, :sxth, :sxtw, :sxtx ][x]
97
92
  RegShift.new r, mode, shift
98
93
  end
99
- when :i16_5; Expression[field_val[a]]
100
94
  when :il18_5;
101
95
  v = field_val[a]
102
96
  s = (v >> 16) & 3
@@ -146,7 +140,12 @@ class ARM64
146
140
  Memref.new(r, nil, nil, Expression[o*mem_sz], mem_sz, op.props[:mem_incr])
147
141
  when :cond_12
148
142
  RegCC.new OP_CC[field_val[a]]
149
- else raise SyntaxError, "Internal error: invalid argument #{a.inspect} in #{op.name}"
143
+ else
144
+ if @fields_shift[a]
145
+ Expression[field_val[a]]
146
+ else
147
+ raise SyntaxError, "Internal error: invalid argument #{a.inspect} in #{op.name}"
148
+ end
150
149
  end
151
150
  }
152
151
 
@@ -173,7 +172,13 @@ class ARM64
173
172
  when 'mov', 'adr', 'adrp'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
174
173
  when 'movz'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
175
174
  when 'movn'; lambda { |di, a0, a1| { a0 => Expression[:~, a1] } }
176
- #when 'movk'; lambda { |di, a0, a1| a1 + lsl replace target bits of a0, other unchanged
175
+ when 'movk'; lambda { |di, a0, a1|
176
+ # set a 16bit word of the target reg, dont touch the others
177
+ if a1.kind_of?(Expression) and a1.op == :<< and a1.rexpr.kind_of?(::Integer)
178
+ { a0 => Expression[[a0, :&, (((1<<64)-1) - (0xffff << a1.rexpr))], :|, a1] }
179
+ else
180
+ { a0 => Expression[a0, :|, a1] } # shouldn't happen, but should be fine with standard code
181
+ end }
177
182
  when 'and', 'ands', 'orr', 'or', 'eor', 'xor'
178
183
  bin_op = { 'and' => :&, 'ands' => :&, 'orr' => :|,
179
184
  'or' => :|, 'eor' => :^, 'xor' => :^ }[op]
@@ -257,12 +262,31 @@ class ARM64
257
262
  end
258
263
  end
259
264
 
265
+ def decode_cc_to_expr(cc)
266
+ case cc
267
+ when 'eq'; Expression[:eflag_z]
268
+ when 'ne'; Expression[:'!', :eflag_z]
269
+ when 'cs'; Expression[:eflag_c] # carry set
270
+ when 'cc'; Expression[:'!', :eflag_c] # carry clear
271
+ when 'mi'; Expression[:eflag_n] # minus
272
+ when 'pl'; Expression[:'!', :eflag_n] # plus
273
+ when 'vs'; Expression[:eflag_v] # oVerflow set
274
+ when 'vc'; Expression[:'!', :eflag_v] # overflow clear
275
+ when 'hi'; Expression[:eflag_c, :&, [:'!', :eflag_z]] # unsigned higher
276
+ when 'ls'; Expression[:eflag_z, :|, [:'!', :eflag_c]] # unsigned lower or same
277
+ when 'ge'; Expression[:eflag_n, :'==', :eflag_v]
278
+ when 'lt'; Expression[:eflag_n, :'!=', :eflag_v]
279
+ when 'gt'; Expression[[:eflag_n, :'==', :eflag_v], :&, [:'!', :eflag_z]]
280
+ when 'le'; Expression[[:eflag_n, :'!=', :eflag_v], :|, :eflag_z]
281
+ end
282
+ end
283
+
260
284
  def get_xrefs_x(dasm, di)
261
285
  if di.opcode.props[:setip]
262
286
  tg = di.instruction.args.last
263
287
  case tg
264
288
  when nil
265
- raise 'internal error: no jmp target' if di.opcode.name != 'ret'
289
+ raise "internal error: no jmp target for #{di}" if di.opcode.name != 'ret' and di.opcode.name != 'eret'
266
290
  tg = :x30
267
291
  when Expression
268
292
  else tg = tg.symbolic(di)
@@ -274,12 +298,64 @@ class ARM64
274
298
  end
275
299
  end
276
300
 
301
+ # returns a DecodedFunction from a parsed C function prototype
302
+ def decode_c_function_prototype(cp, sym, orig=nil)
303
+ sym = cp.toplevel.symbol[sym] if sym.kind_of?(::String)
304
+ df = DecodedFunction.new
305
+ orig ||= Expression[sym.name]
306
+
307
+ new_bt = lambda { |expr, rlen|
308
+ df.backtracked_for << BacktraceTrace.new(expr, orig, expr, rlen ? :r : :x, rlen)
309
+ }
310
+
311
+ # return instr emulation
312
+ if sym.has_attribute 'noreturn' or sym.has_attribute '__noreturn__'
313
+ df.noreturn = true
314
+ else
315
+ new_bt[:x30, nil]
316
+ end
317
+
318
+ [*0..18].each { |r|
319
+ # dirty regs according to ABI
320
+ df.backtrace_binding.update "x#{r}".to_sym => Expression::Unknown
321
+ }
322
+
323
+ # scan args for function pointers
324
+ reg_args = [:x0, :x1, :x2, :x3, :x4, :x5, :x6, :x7]
325
+ sym.type.args.to_a.zip(reg_args).each { |a, ra|
326
+ break if not a or not ra
327
+ if a.type.untypedef.kind_of?(C::Pointer)
328
+ pt = a.type.untypedef.type.untypedef
329
+ if pt.kind_of?(C::Function)
330
+ new_bt[ra, nil]
331
+ df.backtracked_for.last.detached = true
332
+ elsif pt.kind_of?(C::Struct)
333
+ new_bt[ra, cp.typesize[:ptr]]
334
+ else
335
+ new_bt[ra, cp.sizeof(nil, pt)]
336
+ end
337
+ end
338
+ }
339
+
340
+ df
341
+ end
342
+
343
+ def disassembler_default_func
344
+ df = DecodedFunction.new
345
+ df.backtrace_binding = { :sp => Expression[:sp] }
346
+ (0..30).each { |r|
347
+ df.backtrace_binding["x#{r}".to_sym] = (r <= 18 ? Expression::Unknown : Expression["x#{r}".to_sym])
348
+ }
349
+ df.backtracked_for = [BacktraceTrace.new(Expression[:x30], :default, Expression[:x30], :x)]
350
+ df
351
+ end
352
+
277
353
  def backtrace_is_function_return(expr, di=nil)
278
- expr.reduce_rec == :x30
354
+ Expression[expr].reduce_rec == :x30
279
355
  end
280
356
 
281
357
  def backtrace_is_stack_address(expr)
282
- Expression[expr].expr_externals.include? :sp
358
+ Expression[expr].expr_externals.include?(:sp)
283
359
  end
284
360
  end
285
361
  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/arm64/main'
8
+
9
+ module Metasm
10
+ class ARM64
11
+ def abi_funcall
12
+ @abi_funcall ||= { :changed => (0..18).map { |r| "x#{r}".to_sym } }
13
+ end
14
+
15
+ def decompile_makestackvars(dasm, funcstart, blocks)
16
+ oldbd = {}
17
+ oldbd[funcstart] = dasm.address_binding[funcstart]
18
+ dasm.address_binding[funcstart] = { :sp => Expression[:frameptr] }
19
+ blocks.each { |block|
20
+ oldbd[block.address] = dasm.address_binding[block.address]
21
+ stkoff = dasm.backtrace(:sp, block.address, :snapshot_addr => funcstart)
22
+ dasm.address_binding[block.address] = { :sp => Expression[:frameptr, :+, stkoff[0]-:frameptr] }
23
+ yield block
24
+ }
25
+ oldbd.each { |a, b| b ? dasm.address_binding[a] = b : dasm.address_binding.delete(a) }
26
+ end
27
+
28
+ def decompile_func_finddeps_di(dcmp, func, di, a, w)
29
+ end
30
+
31
+ def decompile_func_finddeps(dcmp, blocks, func)
32
+ {}
33
+ end
34
+
35
+ def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
36
+ scope = func.initializer
37
+ func.type.args.each { |a| scope.symbol[a.name] = a }
38
+ stmts = scope.statements
39
+
40
+ di_addr = nil
41
+
42
+ # Expr => CExpr
43
+ ce = lambda { |*e|
44
+ c_expr = dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope)
45
+ dcmp.walk_ce(c_expr) { |ee| ee.with_misc :di_addr => di_addr } if di_addr
46
+ c_expr
47
+ }
48
+
49
+ blocks_toclean = myblocks.dup
50
+ until myblocks.empty?
51
+ b, to = myblocks.shift
52
+ if l = dcmp.dasm.get_label_at(b)
53
+ stmts << C::Label.new(l)
54
+ end
55
+
56
+ # go !
57
+ di_list = dcmp.dasm.decoded[b].block.list.dup
58
+ di_list.each { |di|
59
+ di_addr = di.address
60
+ # TODO jz/jnz
61
+ if di.opcode.props[:setip] and not di.opcode.props[:stopexec]
62
+ case di.opcode.name
63
+ when 'cbz'
64
+ cc = Expression[di.instruction.args.first.symbolic, :==, 0]
65
+ when 'cbnz'
66
+ cc = Expression[di.instruction.args.first.symbolic, :!=, 0]
67
+ when /^b(.*)/
68
+ cc = decode_cc_to_expr($1)
69
+ end
70
+ n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
71
+ bd = get_fwdemu_binding(di)
72
+ stmts << C::If.new(ce[cc], C::Goto.new(n).with_misc(:di_addr => di.address)).with_misc(:di_addr => di.address)
73
+ to.delete dcmp.dasm.normalize(n)
74
+ elsif di.opcode.name == 'ret'
75
+ ret = ce[:x0]
76
+ stmts << C::Return.new(ret).with_misc(:di_addr => di.address)
77
+ elsif di.opcode.name == 'bl'
78
+ n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
79
+ args = []
80
+ if f = dcmp.c_parser.toplevel.symbol[n] and f.type.kind_of?(C::Function) and f.type.args
81
+ f.type.args.each_with_index { |a, i| args << ce["x#{i}".to_sym] }
82
+ end
83
+
84
+ if not n.kind_of?(::String) or (f and not f.type.kind_of?(C::Function))
85
+ # indirect funcall
86
+ fptr = ce[n]
87
+ proto = C::Function.new(C::BaseType.new(:__int64))
88
+ proto = f.type if f and f.type.kind_of? C::Function
89
+ f = C::CExpression[[fptr], C::Pointer.new(proto)]
90
+ elsif not f
91
+ # internal functions are predeclared, so this one is extern
92
+ f = C::Variable.new
93
+ f.name = n
94
+ f.type = C::Function.new(C::BaseType.new(:__int64))
95
+ if dcmp.recurse > 0
96
+ dcmp.c_parser.toplevel.symbol[n] = f
97
+ dcmp.c_parser.toplevel.statements << C::Declaration.new(f)
98
+ end
99
+ end
100
+ e = C::CExpression[f, :funcall, args].with_misc(:di_addr => di_addr)
101
+ e = C::CExpression[ce[:x0], :'=', e, f.type.type].with_misc(:di_addr => di_addr) if f.type.type != C::BaseType.new(:void)
102
+ stmts << e
103
+ else
104
+ bd = get_fwdemu_binding(di)
105
+ if di.backtrace_binding[:incomplete_binding]
106
+ stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil).with_misc(:di_addr => di.address)
107
+ else
108
+ bd.each { |k, v|
109
+ e = ce[k, :'=', v]
110
+ stmts << e #if not e.kind_of?(C::Variable) # [:eflag_s, :=, :unknown].reduce
111
+ }
112
+ end
113
+ end
114
+ di_addr = nil
115
+ }
116
+
117
+ case to.length
118
+ when 0
119
+ if not myblocks.empty? and not stmts.last.kind_of?(C::Return)
120
+ puts " block #{Expression[b]} has no to and don't end in ret"
121
+ end
122
+ when 1
123
+ if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0])
124
+ stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto'))
125
+ end
126
+ else
127
+ puts " block #{Expression[b]} with multiple to"
128
+ end
129
+ end
130
+
131
+ # cleanup di.bt_binding (we set :frameptr etc in those, this may confuse the dasm)
132
+ blocks_toclean.each { |b_, to_|
133
+ dcmp.dasm.decoded[b_].block.list.each { |di|
134
+ di.backtrace_binding = nil
135
+ }
136
+ }
137
+ end
138
+
139
+ def decompile_check_abi(dcmp, entry, func)
140
+ end
141
+ end
142
+ end
@@ -34,12 +34,12 @@ class ARM64
34
34
  end
35
35
 
36
36
  def addop_data_shifted(n, bin, *args)
37
- addop n, bin | (0b00 << 22), :rt, :rn, :rm_lsl_i6, :r_32, *args
38
- addop n, bin | (0b01 << 22), :rt, :rn, :rm_lsr_i6, :r_32, *args
39
- addop n, bin | (0b10 << 22), :rt, :rn, :rm_asr_i6, :r_32, *args
40
- addop n, bin | (0b00 << 22) | (1 << 31), :rt, :rn, :rm_lsl_i5, *args
41
- addop n, bin | (0b01 << 22) | (1 << 31), :rt, :rn, :rm_lsr_i5, *args
42
- addop n, bin | (0b10 << 22) | (1 << 31), :rt, :rn, :rm_asr_i5, *args
37
+ addop n, bin | (0b00 << 22), :rt, :rn, :rm_lsl_i5, :r_32, *args
38
+ addop n, bin | (0b01 << 22), :rt, :rn, :rm_lsr_i5, :r_32, *args
39
+ addop n, bin | (0b10 << 22), :rt, :rn, :rm_asr_i5, :r_32, *args
40
+ addop n, bin | (0b00 << 22) | (1 << 31), :rt, :rn, :rm_lsl_i6, *args
41
+ addop n, bin | (0b01 << 22) | (1 << 31), :rt, :rn, :rm_lsr_i6, *args
42
+ addop n, bin | (0b10 << 22) | (1 << 31), :rt, :rn, :rm_asr_i6, *args
43
43
  end
44
44
 
45
45
  def addop_data_imm(n, bin, *args)
@@ -78,7 +78,7 @@ class ARM64
78
78
  OP_CC = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al al2]
79
79
  def addop_cc(n, bin, *args)
80
80
  OP_CC.each_with_index { |e, i|
81
- args << :stopexec if e == 'al' and args.include?(:setip)
81
+ args << :stopexec if e[0, 2] == 'al' and args.include?(:setip)
82
82
  addop n+e, bin | i, *args
83
83
  }
84
84
  end
@@ -103,6 +103,7 @@ class ARM64
103
103
  :m_rm_extend, :rm_extend_i3,
104
104
  :i14_5, :i16_5, :il18_5, :i19_5, :i26_0, :i12_10_s1,
105
105
  :i19_5_2_29,
106
+ :crn, :crm, :i3_16, :i3_5, :i7_5, :i15_5,
106
107
  :m_rn_s7, :m_rn_s9, :m_rn_u12,
107
108
  :bitmask, :bitmask_imm, :cond_12,
108
109
  ].each { |p| @valid_args[p] = true }
@@ -118,6 +119,7 @@ class ARM64
118
119
  :i19_5_2_29 => 0x60ffffe0, :cond_12 => 0xf,
119
120
  :bitmask_n => 1, :bitmask_s => 0x3f, :bitmask_r => 0x3f,
120
121
  :regextend_13 => 7, :i1_12 => 1, :i3_10 => 7,
122
+ :crn => 0xf, :crm => 0xf, :i3_16 => 7, :i3_5 => 7, :i7_5 => 0x7f, :i15_5 => 0x7fff,
121
123
  :m_rn_s7 => ((0x7f << 10) | 0x1f),
122
124
  :m_rn_s9 => ((0x1ff << 7) | 0x1f),
123
125
  :m_rn_u12 => ((0xfff << 5) | 0x1f)
@@ -133,6 +135,7 @@ class ARM64
133
135
  :i19_5_2_29 => 0, :cond_12 => 12,
134
136
  :bitmask_n => 22, :bitmask_s => 10, :bitmask_r => 16,
135
137
  :regextend_13 => 13, :i1_12 => 12, :i3_10 => 10,
138
+ :crn => 12, :crm => 8, :i3_16 => 16, :i3_5 => 5, :i7_5 => 5, :i15_5 => 5,
136
139
  :m_rn_s7 => 5, :m_rn_s9 => 5, :m_rn_u12 => 5
137
140
 
138
141
  addop 'adr', 1 << 28, :rt, :i19_5_2_29, :pcrel
@@ -183,6 +186,31 @@ class ARM64
183
186
  addop 'dcps2', (0b11010100 << 24) | (0b101 << 21) | (0b00010), :i16_5, :stopexec
184
187
  addop 'dcps3', (0b11010100 << 24) | (0b101 << 21) | (0b00011), :i16_5, :stopexec
185
188
 
189
+ # MSR (immediate)
190
+ addop 'msr_sp', (0b1101010100 << 22) | (0b0000000100 << 12) | (0b10111111), :crm
191
+ addop 'msr_daif_set', (0b1101010100 << 22) | (0b0000110100 << 12) | (0b11011111), :crm
192
+ addop 'msr_daif_clr', (0b1101010100 << 22) | (0b0000110100 << 12) | (0b11111111), :crm
193
+
194
+ # HINT
195
+ addop 'nop', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000000011111)
196
+ addop 'sevl', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000000111111)
197
+ addop 'sev', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000001011111)
198
+ addop 'wfe', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000001111111)
199
+ addop 'wfi', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000010011111)
200
+ addop 'yield', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000010111111)
201
+ addop 'nop', (0b1101010100 << 22) | (0b0000110010 << 12) | (0b000000011111), :i7_5
202
+
203
+ addop 'clrex', (0b1101010100 << 22) | (0b0000110011 << 12) | (0b01011111), :crm # arg ignored
204
+ addop 'dsb', (0b1101010100 << 22) | (0b0000110011 << 12) | (0b10011111), :crm
205
+ addop 'dmb', (0b1101010100 << 22) | (0b0000110011 << 12) | (0b10111111), :crm
206
+ addop 'isb', (0b1101010100 << 22) | (0b0000110011 << 12) | (0b11011111), :crm
207
+
208
+ addop 'sys', (0b1101010100 << 22) | (0b001 << 19), :i3_16, :crn, :crm, :i3_5, :rt
209
+ addop 'sysl', (0b1101010100 << 22) | (0b101 << 19), :i3_16, :crn, :crm, :i3_5, :rt
210
+
211
+ addop 'msr', (0b1101010100 << 22) | (0b01 << 20), :i15_5, :rt # i15 = MSR number
212
+ addop 'mrs', (0b1101010100 << 22) | (0b11 << 20), :i15_5, :rt
213
+
186
214
  addop_s31 'tbz', (0b0110110 << 24), :rt, :i14_5
187
215
 
188
216
  addop 'b', (0b000101 << 26), :i26_0, :setip, :stopexec
@@ -194,22 +222,23 @@ class ARM64
194
222
  addop 'eret',(0b1101011 << 25) | (0b0100 << 21) | (0b11111 << 16) | (0b11111 << 5), :setip, :stopexec
195
223
  addop 'drps',(0b1101011 << 25) | (0b0101 << 21) | (0b11111 << 16) | (0b11111 << 5), :setip, :stopexec
196
224
 
197
- addop_s31 'mov', (0b0010001 << 24), :rt, :rn # alias for add rt, rn, 0
198
- addop_s31 'add', (0b0010001 << 24), :rt, :rn, :i12_10_s1
199
- addop_s31 'adds', (0b0110001 << 24), :rt, :rn, :i12_10_s1
200
- addop_s31 'sub', (0b1010001 << 24), :rt, :rn, :i12_10_s1
201
- addop_s31 'subs', (0b1110001 << 24), :rt, :rn, :i12_10_s1
202
-
203
- addop_s31 'movn', (0b00100101 << 23), :rt, :il18_5
204
- addop_s31 'mov', (0b10100101 << 23), :rt, :i16_5 # alias movz rt, i16 LSL 0
205
- addop_s31 'movz', (0b10100101 << 23), :rt, :il18_5
206
- addop_s31 'movk', (0b11100101 << 23), :rt, :il18_5
207
-
208
- addop_store 'str', (0b10_111_0_00_00 << 22)
209
- addop_store 'ldr', (0b10_111_0_00_01 << 22)
210
- addop_store 'ldrsw', (0b10_111_0_00_10 << 22)
211
- addop_store 'strb', (0b00_111_0_00_00 << 22)
212
- addop_store 'ldrb', (0b00_111_0_00_01 << 22)
225
+ addop_s31 'mov', 0b0010001 << 24, :rt, :rn # alias for add rt, rn, 0
226
+ addop_s31 'add', 0b0010001 << 24, :rt, :rn, :i12_10_s1
227
+ addop_s31 'adds', 0b0110001 << 24, :rt, :rn, :i12_10_s1
228
+ addop_s31 'sub', 0b1010001 << 24, :rt, :rn, :i12_10_s1
229
+ addop_s31 'subs', 0b1110001 << 24, :rt, :rn, :i12_10_s1
230
+
231
+ addop_s31 'movn', 0b00100101 << 23, :rt, :il18_5
232
+ addop_s31 'mov', 0b10100101 << 23, :rt, :i16_5 # alias movz rt, i16 LSL 0
233
+ addop_s31 'movz', 0b10100101 << 23, :rt, :il18_5
234
+ addop_s31 'movk', 0b11100101 << 23, :rt, :il18_5
235
+
236
+ addop_s30 'ldr', 0b00011000 << 24 , :rt, :i19_5
237
+ addop_store 'str', 0b10_111_0_00_00 << 22
238
+ addop_store 'ldr', 0b10_111_0_00_01 << 22
239
+ addop_store 'ldrsw', 0b10_111_0_00_10 << 22
240
+ addop_store 'strb', 0b00_111_0_00_00 << 22
241
+ addop_store 'ldrb', 0b00_111_0_00_01 << 22
213
242
  addop_s31 'stp', 0b00_101_0_001_0 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :post
214
243
  addop_s31 'stp', 0b00_101_0_011_0 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :pre
215
244
  addop_s31 'stp', 0b00_101_0_010_0 << 22, :rt, :rt2, :m_rn_s7
@@ -222,6 +251,7 @@ class ARM64
222
251
  addop_s31 'csinv', (0b1011010100 << 21) | (0b00 << 10), :rt, :rn, :rm, :cond_12, :r_z
223
252
  addop_s31 'csneg', (0b1011010100 << 21) | (0b01 << 10), :rt, :rn, :rm, :cond_12, :r_z
224
253
 
254
+ # TODO fix :bitmask decoding
225
255
  addop_bitfield 'sbfm', 0b00_100110 << 23
226
256
  addop_bitfield 'bfm', 0b01_100110 << 23
227
257
  addop_bitfield 'ubfm', 0b10_100110 << 23
data/metasm/cpu/arm64.rb CHANGED
@@ -13,3 +13,4 @@ require 'metasm/cpu/arm64/encode'
13
13
  require 'metasm/cpu/arm64/decode'
14
14
  require 'metasm/cpu/arm64/render'
15
15
  require 'metasm/cpu/arm64/debug'
16
+ require 'metasm/cpu/arm64/decompile'
@@ -0,0 +1,39 @@
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/dwarf/opcodes'
8
+
9
+ module Metasm
10
+ class Dwarf
11
+ def dbg_register_list
12
+ @dbg_register_list ||= [:r0, :r1, :r2, :r3, :opstack, :pc]
13
+ end
14
+
15
+ def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
16
+ case di.opcode.name
17
+ when 'bra'
18
+ if dbg_ctx.resolve(Indirection[:opstack, @size/8]) != 0
19
+ fbd[pc_reg] = di.instruction.args[0]
20
+ else
21
+ fbd[pc_reg] = di.next_addr
22
+ end
23
+ else return super(di, fbd, pc_reg, dbg_ctx)
24
+ end
25
+ end
26
+
27
+ def dbg_end_stepout(dbg, addr, di)
28
+ true
29
+ end
30
+
31
+ def initialize_emudbg(dbg)
32
+ stack = EncodedData.new("\x00" * 0x1000)
33
+ stack_addr = 0x10000
34
+ stack_addr += 0x10000 while dbg.disassembler.get_section_at(stack_addr)
35
+ dbg.disassembler.add_section(stack, stack_addr)
36
+ dbg.set_reg_value(:opstack, stack_addr)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,124 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2010 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'metasm/cpu/dwarf/opcodes'
7
+ require 'metasm/decode'
8
+
9
+ module Metasm
10
+ class Dwarf
11
+ def build_bin_lookaside
12
+ lookaside = (0..0xff).inject({}) { |h, i| h.update i => [] }
13
+ opcode_list.each { |op|
14
+ lookaside[op.bin] << op
15
+ }
16
+ lookaside
17
+ end
18
+
19
+ def decode_findopcode(edata)
20
+ di = DecodedInstruction.new(self)
21
+ val = edata.get_byte
22
+ di if di.opcode = bin_lookaside[val].first
23
+ end
24
+
25
+ def decode_instr_op(edata, di)
26
+ before_ptr = edata.ptr
27
+ op = di.opcode
28
+ di.instruction.opname = op.name
29
+
30
+ op.args.each { |a|
31
+ di.instruction.args << case a
32
+ when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64; Expression[edata.decode_imm(a, @endianness)]
33
+ when :addr; Expression[edata.decode_imm("u#@size".to_sym, @endianness)]
34
+ when :uleb; Expression[edata.decode_leb(false)]
35
+ when :sleb; Expression[edata.decode_leb(true)]
36
+ when :imm; Expression[op.props[:imm]]
37
+ when :reg; di.instruction.args[0] = Reg.new(di.instruction.args[0].reduce) ; next
38
+ when :gnu; len = edata.get_byte; len = @size/8 if len == 0 ; Expression[edata.decode_imm("u#{len*8}", @endianness)]
39
+ else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
40
+ end
41
+ }
42
+
43
+ di.bin_length = 1 + edata.ptr - before_ptr
44
+ di
45
+ end
46
+
47
+ def decode_instr_interpret(di, addr)
48
+ if di.opcode.props[:setip]
49
+ delta = di.instruction.args.first.reduce
50
+ di.instruction.args[0] = Expression[addr + delta + di.bin_length]
51
+ end
52
+ di
53
+ end
54
+
55
+ def init_backtrace_binding
56
+ @backtrace_binding ||= {}
57
+
58
+ sz = @size/8
59
+ opstack = lambda { |off| Indirection[Expression[:opstack, :-, off*sz].reduce, sz] }
60
+ push_opstack = lambda { |val| { :opstack => Expression[:opstack, :+, sz], opstack[0] => Expression[val] } }
61
+ push_op2 = lambda { |op| { :opstack => Expression[:opstack, :-, sz],
62
+ opstack[0] => Expression[[opstack[1], op, opstack[0]], :&, (1<<@size)-1] } }
63
+
64
+ opcode_list.map { |ol| ol.name }.uniq.each { |opname|
65
+ @backtrace_binding[opname] ||= case opname
66
+ when 'addr', 'lit'; lambda { |di, a1| push_opstack[a1] }
67
+ when 'dup'; lambda { |di| push_opstack[opstack[0]] }
68
+ when 'drop'; lambda { |di| { :opstack => Expression[:opstack, :-, sz] } }
69
+ when 'over'; lambda { |di| push_opstack[opstack[1]] }
70
+ when 'pick'; lambda { |di, a1| push_opstack[opstack[a1.reduce]] } # 0 => dup
71
+ when 'swap'; lambda { |di| { opstack[0] => Expression[opstack[1]], opstack[1] => Expression[opstack[0]] } }
72
+ # backtrace order
73
+ when 'rot'; lambda { |di| { opstack[0] => Expression[opstack[2]], opstack[1] => Expression[opstack[0]], opstack[2] => Expression[opstack[1]] } }
74
+ #when 'xderef';
75
+ when 'deref'; lambda { |di| { opstack[0] => Expression[Indirection[opstack[0], sz]] } }
76
+ when 'abs'; lambda { |di| { opstack[0] => Expression[opstack[0], :-, [[[opstack[0], :>>, sz-1], :&, 1], :*, [2, :*, opstack[0]]]] } }
77
+ when 'neg'; lambda { |di| { opstack[0] => Expression[:-, opstack[0]] } }
78
+ when 'not'; lambda { |di| { opstack[0] => Expression[:~, opstack[0]] } }
79
+ when 'add_u'; lambda { |di, a1| { opstack[0] => Expression[opstack[0], :+, a1] } }
80
+ when 'deref_size'; lambda { |di, a1| { opstack[0] => Expression[Indirection[opstack[0], a1.reduce]] } }
81
+ when 'and', 'div', 'sub', 'mod', 'mul', 'or', 'add', 'shl', 'shr', 'shra', 'xor', 'eq', 'ge', 'gt', 'le', 'lt', 'ne'
82
+ o = { 'and' => :&, 'div' => :/, 'sub' => :-, 'mod' => :%, 'mul' => :*, 'or' => :|,
83
+ 'add' => :+, 'shl' => :<<, 'shr' => :>>, 'shra' => :>>, 'xor' => :^,
84
+ 'eq' => :'==', 'ne' => :'!=', 'le' => :'<=', 'lt' => :<, 'ge' => :'>=', 'gt' => :> }[opname]
85
+ lambda { |di| push_op2[o] }
86
+ when 'reg'; lambda { |di, a1| push_opstack[a1] }
87
+ when 'breg'; lambda { |di, a1, a2| push_opstack[Expression[a1, :+, a2]] }
88
+ when 'bra'; lambda { |di, a| { :opstack => Expression[:opstack, :-, sz] } }
89
+ when 'skip'; lambda { |di, a| {} }
90
+ when 'nop'; lambda { |di| {} }
91
+ end
92
+ }
93
+
94
+ @backtrace_binding
95
+ end
96
+
97
+ def get_backtrace_binding(di)
98
+ if binding = backtrace_binding[di.opcode.name]
99
+ a = di.instruction.args.map { |arg| symbolic(arg, di) }
100
+ binding[di, *a] || {}
101
+ else
102
+ puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
103
+ {:incomplete_binding => Expression[1]}
104
+ end
105
+ end
106
+
107
+ # TODO real forwardbind/backwardbind
108
+ #def fix_fwdemu_binding(di, fbd)
109
+ #end
110
+
111
+ def get_xrefs_x(dasm, di)
112
+ return [] if not di.opcode.props[:setip]
113
+ [di.instruction.args.first]
114
+ end
115
+
116
+ def backtrace_is_function_return(expr, di=nil)
117
+ false
118
+ end
119
+
120
+ def backtrace_is_stack_address(expr)
121
+ Expression[expr].expr_externals.include?(:opstack)
122
+ end
123
+ end
124
+ end