metasm 1.0.1 → 1.0.2

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 (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