metasm 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. 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? 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 :i16, :i24, :i8_12, :i8_r; arg.kind_of? Expression
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; :i16
45
+ when :mem_rn_i12; :i12
39
46
  end
40
- arg.kind_of? Memref and parse_arg_valid?(op, os, arg.offset)
41
- when :reglist; arg.kind_of? RegList
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? Expression and not off.kind_of? Reg
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}"]
@@ -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