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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +3 -3
- data/Rakefile +1 -1
- data/cortex.yaml +17 -0
- data/metasm/cpu/arm64/decode.rb +87 -11
- data/metasm/cpu/arm64/decompile.rb +142 -0
- data/metasm/cpu/arm64/opcodes.rb +53 -23
- data/metasm/cpu/arm64.rb +1 -0
- data/metasm/cpu/dwarf/debug.rb +39 -0
- data/metasm/cpu/dwarf/decode.rb +124 -0
- data/metasm/cpu/dwarf/decompile.rb +212 -0
- data/metasm/cpu/dwarf/encode.rb +49 -0
- data/metasm/cpu/dwarf/main.rb +37 -0
- data/metasm/cpu/dwarf/opcodes.rb +107 -0
- data/metasm/cpu/dwarf.rb +11 -0
- data/metasm/cpu/ia32/debug.rb +8 -0
- data/metasm/cpu/ia32/decode.rb +25 -1
- data/metasm/cpu/ia32/decompile.rb +205 -342
- data/metasm/cpu/mips/decode.rb +1 -1
- data/metasm/cpu/ppc/decode.rb +1 -1
- data/metasm/cpu/sh4/decode.rb +1 -1
- data/metasm/cpu/x86_64/decompile.rb +68 -0
- data/metasm/cpu/x86_64.rb +1 -0
- data/metasm/decode.rb +14 -0
- data/metasm/decompile.rb +51 -27
- data/metasm/disassemble.rb +24 -15
- data/metasm/dynldr.rb +23 -4
- data/metasm/encode.rb +11 -0
- data/metasm/exe_format/coff_encode.rb +6 -7
- data/metasm/exe_format/elf.rb +60 -2
- data/metasm/exe_format/elf_decode.rb +201 -6
- data/metasm/exe_format/shellcode.rb +39 -0
- data/metasm/gui/dasm_decomp.rb +1 -0
- data/metasm/os/emulator.rb +7 -0
- data/metasm/parse_c.rb +1 -1
- data/metasm.gemspec +1 -2
- data/metasm.rb +1 -1
- data/samples/disassemble-gui.rb +27 -11
- data/samples/disassemble.rb +9 -12
- data/samples/emudbg.rb +1 -1
- data/samples/factorize-headers-elfimports.rb +4 -1
- data/samples/lindebug.rb +16 -2
- data/tests/shellcode.rb +111 -0
- metadata +19 -107
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -3
- metadata.gz.sig +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 220a98d0282862014276d9667dcd41aa444270ba4b4019a5add42e0d58a4e9b2
|
|
4
|
+
data.tar.gz: 674c9502bd4724a7cba78e57fd0ae42099ee226d039843cbed3d3f11c40c9e55
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2357bb7357af85c8ace72fde57f8af490f6a2a64d10c086ba1037e96d88143a8089d0ce7266080c173932ac9de15a19041d70579aa1a3b9a0aab8954ae5565bc
|
|
7
|
+
data.tar.gz: a84f3952ffa0e0dcd44602b0b6826f1211d1930b63c8190afaadbe038c9017917f48a2f72bd35da0a4195e2409c663c2b3504b8ac6e017f6b825ae7586d10727
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
source 'https://rubygems.org'
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
gemspec
|
|
3
|
+
|
data/Rakefile
CHANGED
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: "/"
|
data/metasm/cpu/arm64/decode.rb
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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?
|
|
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
|
data/metasm/cpu/arm64/opcodes.rb
CHANGED
|
@@ -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, :
|
|
38
|
-
addop n, bin | (0b01 << 22), :rt, :rn, :
|
|
39
|
-
addop n, bin | (0b10 << 22), :rt, :rn, :
|
|
40
|
-
addop n, bin | (0b00 << 22) | (1 << 31), :rt, :rn, :
|
|
41
|
-
addop n, bin | (0b01 << 22) | (1 << 31), :rt, :rn, :
|
|
42
|
-
addop n, bin | (0b10 << 22) | (1 << 31), :rt, :rn, :
|
|
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',
|
|
198
|
-
addop_s31 'add',
|
|
199
|
-
addop_s31 'adds',
|
|
200
|
-
addop_s31 'sub',
|
|
201
|
-
addop_s31 'subs',
|
|
202
|
-
|
|
203
|
-
addop_s31 'movn',
|
|
204
|
-
addop_s31 'mov',
|
|
205
|
-
addop_s31 'movz',
|
|
206
|
-
addop_s31 'movk',
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
addop_store '
|
|
210
|
-
addop_store '
|
|
211
|
-
addop_store '
|
|
212
|
-
addop_store '
|
|
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
|
@@ -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
|