metasm 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
@@ -4,7 +4,7 @@
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
5
5
|
|
6
6
|
|
7
|
-
require 'metasm/arm/opcodes'
|
7
|
+
require 'metasm/cpu/arm/opcodes'
|
8
8
|
require 'metasm/parse'
|
9
9
|
|
10
10
|
module Metasm
|
@@ -26,24 +26,32 @@ class ARM
|
|
26
26
|
|
27
27
|
def parse_arg_valid?(op, sym, arg)
|
28
28
|
case sym
|
29
|
-
when :rd, :rs, :rn, :rm; arg.kind_of?
|
30
|
-
when :rm_rs; arg.kind_of?
|
31
|
-
when :rm_is; arg.kind_of?
|
32
|
-
when :
|
29
|
+
when :rd, :rs, :rn, :rm; arg.kind_of?(Reg) and arg.shift == 0 and (arg.updated ? op.props[:baseincr] : !op.props[:baseincr])
|
30
|
+
when :rm_rs; arg.kind_of?(Reg) and arg.shift.kind_of?(Reg)
|
31
|
+
when :rm_is; arg.kind_of?(Reg) and arg.shift.kind_of?(Integer)
|
32
|
+
when :i12, :i24, :i8_12; arg.kind_of?(Expression)
|
33
|
+
when :i8_r
|
34
|
+
if arg.kind_of?(Expression)
|
35
|
+
b = arg.reduce
|
36
|
+
!b.kind_of?(Integer) or (0..15).find {
|
37
|
+
b = ((b << 2) & 0xffff_ffff) | ((b >> 30) & 3)
|
38
|
+
b < 0x100 }
|
39
|
+
end
|
33
40
|
when :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12
|
34
41
|
os = case sym
|
35
42
|
when :mem_rn_rm; :rm
|
36
43
|
when :mem_rn_i8_12; :i8_12
|
37
44
|
when :mem_rn_rms; :rm_rs
|
38
|
-
when :mem_rn_i12; :
|
45
|
+
when :mem_rn_i12; :i12
|
39
46
|
end
|
40
|
-
arg.kind_of?
|
41
|
-
when :reglist; arg.kind_of?
|
47
|
+
arg.kind_of?(Memref) and parse_arg_valid?(op, os, arg.offset)
|
48
|
+
when :reglist; arg.kind_of?(RegList)
|
42
49
|
end
|
43
50
|
# TODO check flags on reglist, check int values
|
44
51
|
end
|
45
52
|
|
46
53
|
def parse_argument(lexer)
|
54
|
+
raise lexer, "unexpected EOS" if not lexer.nexttok
|
47
55
|
if Reg.s_to_i[lexer.nexttok.raw]
|
48
56
|
arg = Reg.new Reg.s_to_i[lexer.readtok.raw]
|
49
57
|
lexer.skip_space
|
@@ -62,22 +70,24 @@ class ARM
|
|
62
70
|
when '!'
|
63
71
|
lexer.readtok
|
64
72
|
arg.updated = true
|
65
|
-
end
|
73
|
+
end if lexer.nexttok
|
66
74
|
elsif lexer.nexttok.raw == '{'
|
67
75
|
lexer.readtok
|
68
76
|
arg = RegList.new
|
69
77
|
loop do
|
70
|
-
raise "unterminated reglist" if lexer.eos?
|
71
78
|
lexer.skip_space
|
79
|
+
raise "unterminated reglist" if lexer.eos?
|
72
80
|
if Reg.s_to_i[lexer.nexttok.raw]
|
73
81
|
arg.list << Reg.new(Reg.s_to_i[lexer.readtok.raw])
|
74
82
|
lexer.skip_space
|
83
|
+
raise "unterminated reglist" if lexer.eos?
|
75
84
|
end
|
76
85
|
case lexer.nexttok.raw
|
77
86
|
when ','; lexer.readtok
|
78
87
|
when '-'
|
79
88
|
lexer.readtok
|
80
89
|
lexer.skip_space
|
90
|
+
raise "unterminated reglist" if lexer.eos?
|
81
91
|
if not r = Reg.s_to_i[lexer.nexttok.raw]
|
82
92
|
raise lexer, "reglist parse error: invalid range"
|
83
93
|
end
|
@@ -95,20 +105,22 @@ class ARM
|
|
95
105
|
end
|
96
106
|
elsif lexer.nexttok.raw == '['
|
97
107
|
lexer.readtok
|
108
|
+
raise "unexpected EOS" if lexer.eos?
|
98
109
|
if not base = Reg.s_to_i[lexer.nexttok.raw]
|
99
110
|
raise lexer, 'invalid mem base (reg expected)'
|
100
111
|
end
|
101
112
|
base = Reg.new Reg.s_to_i[lexer.readtok.raw]
|
113
|
+
raise "unexpected EOS" if lexer.eos?
|
102
114
|
if lexer.nexttok.raw == ']'
|
103
115
|
lexer.readtok
|
104
|
-
closed = true
|
116
|
+
#closed = true
|
105
117
|
end
|
106
|
-
if lexer.nexttok.raw != ','
|
118
|
+
if !lexer.nexttok or lexer.nexttok.raw != ','
|
107
119
|
raise lexer, 'mem off expected'
|
108
120
|
end
|
109
121
|
lexer.readtok
|
110
122
|
off = parse_argument(lexer)
|
111
|
-
if not off.kind_of?
|
123
|
+
if not off.kind_of?(Expression) and not off.kind_of?(Reg)
|
112
124
|
raise lexer, 'invalid mem off (reg/imm expected)'
|
113
125
|
end
|
114
126
|
case lexer.nexttok and lexer.nexttok.raw
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
5
5
|
|
6
6
|
require 'metasm/render'
|
7
|
-
require 'metasm/arm/opcodes'
|
7
|
+
require 'metasm/cpu/arm/opcodes'
|
8
8
|
|
9
9
|
module Metasm
|
10
10
|
class ARM
|
@@ -19,7 +19,7 @@ class ARM
|
|
19
19
|
["#{r} RRX"]
|
20
20
|
else
|
21
21
|
case s = @shift
|
22
|
-
when Integer; s = Expression[s]
|
22
|
+
when Integer; s = Expression[s == 0 ? 32 : s] # lsl and ror already accounted for
|
23
23
|
when Reg; s = self.class.i_to_s[s.i]
|
24
24
|
end
|
25
25
|
["#{r} #{@stype.to_s.upcase} #{s}"]
|
data/metasm/cpu/arm64.rb
ADDED
@@ -0,0 +1,15 @@
|
|
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
|
+
class Metasm::ARM64 < Metasm::CPU
|
7
|
+
end
|
8
|
+
Metasm::AArch64 = Metasm::ARM64
|
9
|
+
|
10
|
+
require 'metasm/main'
|
11
|
+
require 'metasm/cpu/arm64/parse'
|
12
|
+
require 'metasm/cpu/arm64/encode'
|
13
|
+
require 'metasm/cpu/arm64/decode'
|
14
|
+
require 'metasm/cpu/arm64/render'
|
15
|
+
require 'metasm/cpu/arm64/debug'
|
@@ -0,0 +1,38 @@
|
|
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/opcodes'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM64
|
11
|
+
def dbg_register_pc
|
12
|
+
@dbg_register_pc ||= :pc
|
13
|
+
end
|
14
|
+
def dbg_register_flags
|
15
|
+
@dbg_register_flags ||= :flags
|
16
|
+
end
|
17
|
+
|
18
|
+
def dbg_register_list
|
19
|
+
@dbg_register_list ||= Reg::Sym.sort.transpose[1] - [:xzr]
|
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
|
+
di and di.opcode.props[:saveip]
|
32
|
+
end
|
33
|
+
|
34
|
+
def dbg_end_stepout(dbg, addr, di)
|
35
|
+
di and di.opcode.name == 'foobar'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,289 @@
|
|
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/arm64/opcodes'
|
7
|
+
require 'metasm/decode'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM64
|
11
|
+
# create the bin_mask for a given opcode
|
12
|
+
def build_opcode_bin_mask(op)
|
13
|
+
# bit = 0 if can be mutated by an field value, 1 if fixed by opcode
|
14
|
+
op.bin_mask = 0
|
15
|
+
op.fields.each { |k, (m, s)|
|
16
|
+
op.bin_mask |= m << s
|
17
|
+
}
|
18
|
+
op.bin_mask = 0xffffffff ^ op.bin_mask
|
19
|
+
end
|
20
|
+
|
21
|
+
# create the lookaside hash from the first byte of the opcode
|
22
|
+
def build_bin_lookaside
|
23
|
+
lookaside = Array.new(256) { [] }
|
24
|
+
|
25
|
+
opcode_list.each { |op|
|
26
|
+
build_opcode_bin_mask op
|
27
|
+
|
28
|
+
b = (op.bin >> 24) & 0xff
|
29
|
+
msk = (op.bin_mask >> 24) & 0xff
|
30
|
+
b &= msk
|
31
|
+
|
32
|
+
for i in b..(b | (255^msk))
|
33
|
+
lookaside[i] << op if i & msk == b
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
lookaside
|
38
|
+
end
|
39
|
+
|
40
|
+
def decode_findopcode(edata)
|
41
|
+
return if edata.ptr+4 > edata.length
|
42
|
+
di = DecodedInstruction.new(self)
|
43
|
+
val = edata.decode_imm(:u32, @endianness)
|
44
|
+
di.raw_data = val
|
45
|
+
di if di.opcode = @bin_lookaside[(val >> 24) & 0xff].find { |op|
|
46
|
+
(op.bin & op.bin_mask) == (val & op.bin_mask)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def disassembler_default_func
|
51
|
+
df = DecodedFunction.new
|
52
|
+
df
|
53
|
+
end
|
54
|
+
|
55
|
+
def decode_instr_op(edata, di)
|
56
|
+
op = di.opcode
|
57
|
+
di.instruction.opname = op.name
|
58
|
+
val = di.raw_data
|
59
|
+
|
60
|
+
field_val = lambda { |f|
|
61
|
+
(val >> @fields_shift[f]) & @fields_mask[f]
|
62
|
+
}
|
63
|
+
|
64
|
+
op.args.each { |a|
|
65
|
+
di.instruction.args << case a
|
66
|
+
when :rn, :rt, :rt2, :rm
|
67
|
+
nr = field_val[a]
|
68
|
+
nr = 32 if nr == 31 and op.props[:r_z]
|
69
|
+
Reg.new nr, (op.props[:r_32] ? 32 : 64)
|
70
|
+
when :rm_lsl_i6, :rm_lsr_i6, :rm_asr_i6, :rm_lsl_i5, :rm_lsr_i5, :rm_asr_i5
|
71
|
+
nr = field_val[:rm]
|
72
|
+
nr = 32 if nr == 31 and op.props[:r_z]
|
73
|
+
r = Reg.new nr, (op.props[:r_32] ? 32 : 64)
|
74
|
+
shift = field_val[:i6_10]
|
75
|
+
mode = { :rm_lsl_i6 => :lsl, :rm_lsl_i5 => :lsl,
|
76
|
+
:rm_lsr_i6 => :lsr, :rm_lsr_i5 => :lsr,
|
77
|
+
:rm_asr_i6 => :asr, :rm_asr_i5 => :asr }[a]
|
78
|
+
RegShift.new r, mode, shift
|
79
|
+
when :m_rm_extend, :rm_extend_i3
|
80
|
+
nr = field_val[:rm]
|
81
|
+
nr = 32 if nr == 31
|
82
|
+
x = field_val[:regextend_13]
|
83
|
+
case a
|
84
|
+
when :m_rm_extend
|
85
|
+
shift = 0 # field_val[:i1_12] -- bug in arm doc ?
|
86
|
+
mode = [ :resv000, :resv001, :uxtw, :lsl, :resv100, :resv101, :sxtw, :sxtx ][x]
|
87
|
+
rm = RegShift.new Reg.new(nr, 64), mode, shift
|
88
|
+
|
89
|
+
rn = Reg.new field_val[:rn], 64
|
90
|
+
|
91
|
+
mem_sz = op.props[:mem_sz] || (op.props[:r_32] ? 4 : 8)
|
92
|
+
Memref.new(rn, rm, 1, nil, mem_sz)
|
93
|
+
when :rm_extend_i3
|
94
|
+
r = Reg.new nr, (op.props[:r_32] ? 32 : 64)
|
95
|
+
shift = field_val[:i3_10]
|
96
|
+
mode = [ :uxtb, :uxth, :uxtw, :uxtx, :sxtb, :sxth, :sxtw, :sxtx ][x]
|
97
|
+
RegShift.new r, mode, shift
|
98
|
+
end
|
99
|
+
when :i16_5; Expression[field_val[a]]
|
100
|
+
when :il18_5;
|
101
|
+
v = field_val[a]
|
102
|
+
s = (v >> 16) & 3
|
103
|
+
v = v & 0xffff
|
104
|
+
Expression[v, :<<, (16*s)]
|
105
|
+
when :i19_5; Expression[Expression.make_signed(field_val[a], 19) << 2]
|
106
|
+
when :i26_0; Expression[Expression.make_signed(field_val[a], 26) << 2]
|
107
|
+
when :i12_10_s1
|
108
|
+
f = field_val[a]
|
109
|
+
f = (f & 0xfff) << 12 if (f >> 12) & 1 == 1
|
110
|
+
Expression[f]
|
111
|
+
when :i19_5_2_29
|
112
|
+
Expression.make_signed((field_val[:i19_5] << 2) | field_val[:i2_29], 21)
|
113
|
+
when :bitmask, :bitmask_imm
|
114
|
+
n = field_val[:bitmask_n]
|
115
|
+
s = field_val[:bitmask_s]
|
116
|
+
r = field_val[:bitmask_r]
|
117
|
+
# highestsetbit stuff
|
118
|
+
levels = ((n << 6) | (s ^ 0x3f)) >> 1
|
119
|
+
levels = levels | (levels >> 1)
|
120
|
+
levels = levels | (levels >> 2)
|
121
|
+
levels = levels | (levels >> 4)
|
122
|
+
esize = levels + 1
|
123
|
+
s &= levels
|
124
|
+
r &= levels
|
125
|
+
welem = (1 << (s+1)) - 1
|
126
|
+
# ROR(welem, r)
|
127
|
+
wmask = ((welem >> (r % esize)) | (welem << (esize - (r % esize))))
|
128
|
+
wmask &= (1 << esize) - 1
|
129
|
+
# duplicate(wmask, sz)
|
130
|
+
while esize < 64
|
131
|
+
wmask |= wmask << esize
|
132
|
+
esize *= 2
|
133
|
+
end
|
134
|
+
wmask &= (1 << di.instruction.args[0].sz) - 1
|
135
|
+
Expression[wmask]
|
136
|
+
|
137
|
+
when :m_rn_s9, :m_rn_u12, :m_rn_s7
|
138
|
+
r = Reg.new(field_val[:rn], 64)
|
139
|
+
o = case a
|
140
|
+
when :m_rn_s9; Expression.make_signed(field_val[:s9_12], 9)
|
141
|
+
when :m_rn_s7; Expression.make_signed(field_val[:s7_15], 7)
|
142
|
+
when :m_rn_u12; field_val[:u12_10]
|
143
|
+
else raise SyntaxError, "Internal error #{a.inspect} in #{op.name}"
|
144
|
+
end
|
145
|
+
mem_sz = op.props[:mem_sz] || (op.props[:r_32] ? 4 : 8)
|
146
|
+
Memref.new(r, nil, nil, Expression[o*mem_sz], mem_sz, op.props[:mem_incr])
|
147
|
+
when :cond_12
|
148
|
+
RegCC.new OP_CC[field_val[a]]
|
149
|
+
else raise SyntaxError, "Internal error: invalid argument #{a.inspect} in #{op.name}"
|
150
|
+
end
|
151
|
+
}
|
152
|
+
|
153
|
+
di.bin_length = 4
|
154
|
+
di
|
155
|
+
end
|
156
|
+
|
157
|
+
def decode_instr_interpret(di, addr)
|
158
|
+
if di.opcode.props[:setip] and di.instruction.args.last.kind_of?(Expression)
|
159
|
+
di.instruction.args[-1] = Expression[Expression[addr, :+, di.instruction.args[-1]].reduce]
|
160
|
+
elsif di.opcode.props[:pcrel]
|
161
|
+
di.instruction.args[-1] = Expression[Expression[addr, :+, di.instruction.args[-1]].reduce]
|
162
|
+
elsif di.opcode.props[:pcrel_page]
|
163
|
+
di.instruction.args[-1] = Expression[Expression[[addr, :&, ~0xfff], :+, [di.instruction.args[-1], :<<, 12]].reduce]
|
164
|
+
end
|
165
|
+
di
|
166
|
+
end
|
167
|
+
|
168
|
+
def backtrace_binding
|
169
|
+
@backtrace_binding ||= init_backtrace_binding
|
170
|
+
end
|
171
|
+
|
172
|
+
def init_backtrace_binding
|
173
|
+
@backtrace_binding ||= {}
|
174
|
+
|
175
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
176
|
+
binding = case op
|
177
|
+
when 'mov', 'adr', 'adrp'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
178
|
+
when 'movz'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
179
|
+
when 'movn'; lambda { |di, a0, a1| { a0 => Expression[:~, a1] } }
|
180
|
+
#when 'movk'; lambda { |di, a0, a1| a1 + lsl replace target bits of a0, other unchanged
|
181
|
+
when 'and', 'ands', 'orr', 'or', 'eor', 'xor'
|
182
|
+
bin_op = { 'and' => :&, 'ands' => :&, 'orr' => :|,
|
183
|
+
'or' => :|, 'eor' => :^, 'xor' => :^ }[op]
|
184
|
+
lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, a2 ] } }
|
185
|
+
when 'orn', 'eorn', 'bic', 'bics', 'andn'
|
186
|
+
bin_op = { 'orn' => :|, 'eorn' => :^, 'andn' => :&, 'bic' => :&, 'bics' => :& }[op]
|
187
|
+
lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, [ :~, a2 ] ] } }
|
188
|
+
when 'add', 'adds', 'sub', 'subs'
|
189
|
+
bin_op = { 'add' => :+, 'adds' => :+, 'sub' => :-, 'subs' => :- }[op]
|
190
|
+
lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, a2 ] } }
|
191
|
+
when 'ldr', 'ldrb', 'ldrsw'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
192
|
+
when 'str', 'strb', 'strsw'; lambda { |di, a0, a1| { a1 => Expression[a0] } }
|
193
|
+
when 'stp'; lambda { |di, a0, a1, a2| ptr = a2.target
|
194
|
+
{ Indirection[ptr, 8] => Expression[a0], Indirection[Expression[ptr, :+, 8].reduce, 8] => Expression[a1] } }
|
195
|
+
when 'ldp'; lambda { |di, a0, a1, a2| ptr = a2.target
|
196
|
+
{ a0 => Indirection[ptr, 8], a1 => Indirection[Expression[ptr, :+, 8].reduce, 8] } }
|
197
|
+
when 'ret'; lambda { |di, *a| { } }
|
198
|
+
when 'bl', 'blr'; lambda { |di, *a| { :x30 => Expression[di.next_addr] } }
|
199
|
+
when 'cbz', 'cbnz', 'cmp', /^b/; lambda { |di, *a| {} }
|
200
|
+
end
|
201
|
+
|
202
|
+
# pre/post-increment memref done in def get_backtrace_binding(di)
|
203
|
+
|
204
|
+
@backtrace_binding[op] ||= binding
|
205
|
+
}
|
206
|
+
|
207
|
+
@backtrace_binding
|
208
|
+
end
|
209
|
+
|
210
|
+
def get_backtrace_binding(di)
|
211
|
+
a = di.instruction.args.map { |arg|
|
212
|
+
case arg
|
213
|
+
when Reg, RegShift, RegCC; arg.symbolic
|
214
|
+
when Memref; arg.symbolic(di.address)
|
215
|
+
else arg
|
216
|
+
end
|
217
|
+
}
|
218
|
+
|
219
|
+
if binding = backtrace_binding[di.opcode.name]
|
220
|
+
bd = binding[di, *a] || {}
|
221
|
+
|
222
|
+
# handle pre-increment / post-increment memrefs
|
223
|
+
di.instruction.args.grep(Memref).each { |m|
|
224
|
+
next unless r = m.base and r.kind_of?(Reg)
|
225
|
+
case m.incr
|
226
|
+
when :pre
|
227
|
+
# for di "str x1, [sp+10]!" ; bt_bind should be { sp += 10, [sp] = x1 } but memref.symbolic returns [sp+10]
|
228
|
+
# eg: str x30, [sp-20]! ; ldr x30, [sp], 20 ; ret should backtrace as x30 -> [sp] -!> x30
|
229
|
+
rs = r.symbolic
|
230
|
+
bd.dup.each_key { |k|
|
231
|
+
if k.kind_of?(Indirection)
|
232
|
+
bd[Indirection[k.target.bind(rs => Expression[rs, :-, m.offset]).reduce, k.len, k.origin]] = bd.delete(k)
|
233
|
+
end
|
234
|
+
}
|
235
|
+
bd[rs] ||= Expression[rs, :+, m.offset]
|
236
|
+
when :post
|
237
|
+
bd[r.symbolic] ||= Expression[r.symbolic, :+, m.offset]
|
238
|
+
end
|
239
|
+
}
|
240
|
+
|
241
|
+
# handle subregisters (x30 -> w30)
|
242
|
+
bd.keys.grep(Expression).each { |e|
|
243
|
+
# must be Expression[reg, :&, 0xffff_ffff]
|
244
|
+
if e.op == :& and e.rexpr == 0xffff_ffff
|
245
|
+
reg = e.lexpr
|
246
|
+
next if not reg.kind_of? Symbol
|
247
|
+
val = bd.delete e
|
248
|
+
bd[reg] = Expression[[reg, :&, 0xffff_ffff_0000_0000], :|, [val, :&, 0xffff_ffff]]
|
249
|
+
end
|
250
|
+
}
|
251
|
+
|
252
|
+
bd
|
253
|
+
else
|
254
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
255
|
+
# assume nothing except the 1st arg is modified
|
256
|
+
case a[0]
|
257
|
+
when Indirection, Symbol; { a[0] => Expression::Unknown }
|
258
|
+
when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
|
259
|
+
else {}
|
260
|
+
end.update(:incomplete_binding => Expression[1])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def get_xrefs_x(dasm, di)
|
265
|
+
if di.opcode.props[:setip]
|
266
|
+
tg = di.instruction.args.last
|
267
|
+
case tg
|
268
|
+
when nil
|
269
|
+
raise 'internal error: no jmp target' if di.opcode.name != 'ret'
|
270
|
+
tg = :x30
|
271
|
+
when Expression
|
272
|
+
else tg = tg.symbolic
|
273
|
+
end
|
274
|
+
[tg]
|
275
|
+
else
|
276
|
+
# TODO ldr pc, ..
|
277
|
+
[]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def backtrace_is_function_return(expr, di=nil)
|
282
|
+
expr.reduce_rec == :x30
|
283
|
+
end
|
284
|
+
|
285
|
+
def backtrace_is_stack_address(expr)
|
286
|
+
Expression[expr].expr_externals.include? :sp
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|