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
@@ -5,19 +5,27 @@
5
5
 
6
6
 
7
7
  require 'metasm/main'
8
- require 'metasm/ia32'
8
+ require 'metasm/cpu/ia32'
9
9
 
10
10
  module Metasm
11
11
 
12
12
  # The x86_64, 64-bit extension of the x86 CPU (x64, em64t, amd64...)
13
13
  class X86_64 < Ia32
14
14
  # FpReg, SegReg, Farptr unchanged
15
- # XXX ST(15) ?
16
15
 
17
- # Simd extended to 16 regs, xmm only (mmx gone with 80387)
16
+ # XMM extended to 16 regs, YMM
18
17
  class SimdReg < Ia32::SimdReg
19
- double_map 64 => (0..15).map { |n| "mm#{n}" },
20
- 128 => (0..15).map { |n| "xmm#{n}" }
18
+ double_map 64 => (0..7).map { |n| "mm#{n}" },
19
+ 128 => (0..15).map { |n| "xmm#{n}" },
20
+ 256 => (0..15).map { |n| "ymm#{n}" }
21
+
22
+ def val_enc
23
+ @val & 7
24
+ end
25
+
26
+ def val_rex
27
+ @val >> 3
28
+ end
21
29
  end
22
30
 
23
31
  # general purpose registers, all sizes
@@ -125,7 +133,7 @@ class X86_64 < Ia32
125
133
 
126
134
  def str_to_reg(str)
127
135
  # X86_64::Reg != Ia32::Reg
128
- Reg.from_str(str) if Reg.s_to_i.has_key? str
136
+ Reg.s_to_i.has_key?(str) ? Reg.from_str(str) : SimdReg.s_to_i.has_key?(str) ? SimdReg.from_str(str) : nil
129
137
  end
130
138
 
131
139
  def shortname
@@ -0,0 +1,136 @@
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/x86_64/main'
8
+ require 'metasm/cpu/ia32/opcodes'
9
+
10
+ module Metasm
11
+ class X86_64
12
+ def init_cpu_constants
13
+ super()
14
+ [:i32, :u32, :i64, :u64].each { |a| @valid_args[a] = true }
15
+ end
16
+
17
+ def init_386_common_only
18
+ super()
19
+ # :imm64 => accept a real int64 as :i argument
20
+ # :auto64 => ignore rex_w, always 64-bit op
21
+ # :op32no64 => if write to a 32-bit reg, dont zero the top 32-bits of dest
22
+ [:imm64, :auto64, :op32no64].each { |a| @valid_props[a] = true }
23
+ @opcode_list.delete_if { |o| o.bin[0].to_i & 0xf0 == 0x40 } # now REX prefix
24
+ @opcode_list.each { |o|
25
+ o.props[:imm64] = true if o.bin == [0xB8] # mov reg, <true imm64>
26
+ o.props[:auto64] = true if o.name =~ /^(j.*|loop.*|call|enter|leave|push|pop|ret)$/
27
+ }
28
+ addop 'movsxd', [0x63], :mrm
29
+ addop('cdqe', [0x98]) { |o| o.props[:opsz] = 64 }
30
+ addop('cqo', [0x99]) { |o| o.props[:opsz] = 64 }
31
+ end
32
+
33
+ # all x86_64 cpu understand <= sse2 instrs
34
+ def init_x8664_only
35
+ init_386_common_only
36
+ init_386_only
37
+ init_387_only
38
+ init_486_only
39
+ init_pentium_only
40
+ init_p6_only
41
+ init_sse_only
42
+ init_sse2_only
43
+
44
+ @opcode_list.delete_if { |o|
45
+ o.args.include?(:seg2) or
46
+ o.args.include?(:seg2A) or
47
+ o.args.include?(:farptr) or
48
+ %w[aaa aad aam aas bound daa das into jcxz jecxz
49
+ lds les loadall arpl pusha pushad popa
50
+ popad].include?(o.name.split('.')[0])
51
+ # split needed for lds.a32
52
+ }
53
+
54
+ @opcode_list.each { |o|
55
+ o.props[:auto64] = true if o.name =~ /^(enter|leave|[sl]gdt|[sl]idt|[sl]ldt|[sl]tr|push|pop|syscall)$/
56
+ }
57
+
58
+ addop('cmpxchg16b', [0x0F, 0xC7], 1) { |o| o.props[:opsz] = 64 ; o.props[:argsz] = 128 }
59
+ addop('iretq', [0xCF], nil, :stopexec, :setip) { |o| o.props[:opsz] = 64 } ; opcode_list.unshift opcode_list.pop
60
+ addop 'swapgs', [0x0F, 0x01, 0xF8]
61
+
62
+ addop('movq', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args = [:regmmx, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 }
63
+ addop('movq', [0x0F, 0x6E], :mrmxmm, {:d => [1, 4]}) { |o| o.args = [:regxmm, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 }
64
+ addop('jecxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 32 }
65
+ addop('jrcxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 64 }
66
+ end
67
+
68
+ def init_sse3
69
+ init_x8664_only
70
+ init_sse3_only
71
+ end
72
+
73
+ def init_sse41_only
74
+ super()
75
+ addop('pextrq', [0x0F, 0x3A, 0x16], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 }
76
+ addop('pinsrq', [0x0F, 0x3A, 0x22], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 }
77
+ end
78
+
79
+ def init_avx_only
80
+ super()
81
+ addop('rdfsbase', [0x0F, 0xAE], 0, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
82
+ addop('rdgsbase', [0x0F, 0xAE], 1, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
83
+ addop('wrfsbase', [0x0F, 0xAE], 2, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
84
+ addop('wrgsbase', [0x0F, 0xAE], 3, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
85
+ end
86
+
87
+ def addop_macrostr(name, bin, type)
88
+ super(name, bin, type)
89
+ bin = bin.dup
90
+ bin[0] |= 1
91
+ addop(name+'q', bin) { |o| o.props[:opsz] = 64 ; o.props[type] = true }
92
+ end
93
+
94
+ def addop_macroret(name, bin, *args)
95
+ addop(name + '.i64', bin, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 64 }
96
+ super(name, bin, *args)
97
+ end
98
+
99
+ def addop_post(op)
100
+ if op.fields[:d] or op.fields[:w] or op.fields[:s] or op.args.first == :regfp0
101
+ return super(op)
102
+ end
103
+
104
+ if op.props[:needpfx]
105
+ @opcode_list.unshift op
106
+ else
107
+ @opcode_list << op
108
+ end
109
+
110
+ if op.args == [:i] or op.name == 'ret'
111
+ # define opsz-override version for ambiguous opcodes
112
+ op16 = op.dup
113
+ op16.name << '.i16'
114
+ op16.props[:opsz] = 16
115
+ @opcode_list << op16
116
+ # push call ret jz can't 32bit
117
+ op64 = op.dup
118
+ op64.name << '.i64'
119
+ op64.props[:opsz] = 64
120
+ @opcode_list << op64
121
+ elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
122
+ op.args.include? :modrm or op.name =~ /loop|xlat/
123
+ # define adsz-override version for ambiguous opcodes (movsq)
124
+ # XXX loop pfx 67 = rip+ecx, 66/rex ignored
125
+ op32 = op.dup
126
+ op32.name << '.a32'
127
+ op32.props[:adsz] = 32
128
+ @opcode_list << op32
129
+ op64 = op.dup
130
+ op64.name << '.a64'
131
+ op64.props[:adsz] = 64
132
+ @opcode_list << op64
133
+ end
134
+ end
135
+ end
136
+ end
@@ -4,8 +4,8 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/x86_64/opcodes'
8
- require 'metasm/x86_64/encode'
7
+ require 'metasm/cpu/x86_64/opcodes'
8
+ require 'metasm/cpu/x86_64/encode'
9
9
  require 'metasm/parse'
10
10
 
11
11
  module Metasm
@@ -52,6 +52,8 @@ class X86_64
52
52
  return if arg.kind_of? ModRM and ((arg.b and arg.b.val == 16 and arg.i) or (arg.i and arg.i.val == 16 and (arg.b or arg.s != 1)))
53
53
  return if arg.kind_of? Reg and arg.sz >= 32 and arg.val == 16 # eip/rip only in modrm
54
54
  return if o.props[:auto64] and arg.respond_to? :sz and arg.sz == 32
55
+ # vex c4/c5
56
+ return if o.fields[:vex_r] and not o.fields[:vex_b] and (spec == :modrm or spec == :modrmxmm or spec == :modrmymm) and (((arg.kind_of?(SimdReg) or arg.kind_of?(Reg)) and arg.val >= 8) or (arg.kind_of?(ModRM) and ((arg.b and arg.b.val >= 8) or (arg.i and arg.i.val >= 8))))
55
57
  if o.name == 'movsxd'
56
58
  return if not arg.kind_of? Reg and not arg.kind_of? ModRM
57
59
  arg.sz ||= 32
@@ -62,7 +64,13 @@ class X86_64
62
64
  return arg.sz == 32
63
65
  end
64
66
  end
67
+ return if o.name == 'xchg' and spec == :reg and o.args.include?(:reg_eax) and arg.kind_of?(Reg) and arg.sz == 32 and arg.val == 0
68
+
65
69
  super(o, spec, arg)
66
70
  end
71
+
72
+ def check_reserved_name(name)
73
+ Reg.s_to_i[name]
74
+ end
67
75
  end
68
76
  end
@@ -0,0 +1,35 @@
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/x86_64/opcodes'
8
+ require 'metasm/render'
9
+
10
+ module Metasm
11
+ class X86_64
12
+ def gui_hilight_word_regexp_init
13
+ ret = {}
14
+
15
+ %w[a b c d].each { |r|
16
+ ret["#{r}l"] = "[re]?#{r}x|#{r}l"
17
+ ret["#{r}h"] = "[re]?#{r}x|#{r}h"
18
+ ret["#{r}x"] = ret["e#{r}x"] = ret["r#{r}x"] = "[re]?#{r}x|#{r}[hl]"
19
+ }
20
+
21
+ %w[sp bp si di].each { |r|
22
+ ret["#{r}l"] = ret[r] = ret["e#{r}"] = ret["r#{r}"] = "[re]?#{r}|#{r}l"
23
+ }
24
+
25
+ (8..15).each { |i|
26
+ r = "r#{i}"
27
+ ret[r+'b'] = ret[r+'w'] = ret[r+'d'] = ret[r] = "#{r}[bwd]?"
28
+ }
29
+
30
+ ret['eip'] = ret['rip'] = '[re]ip'
31
+
32
+ ret
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
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/main'
8
+ require 'metasm/cpu/z80/decode'
9
+ require 'metasm/cpu/z80/render'
@@ -0,0 +1,313 @@
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/z80/opcodes'
8
+ require 'metasm/decode'
9
+
10
+ module Metasm
11
+ class Z80
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 = Array.new(op.bin.length, 0)
15
+ op.fields.each { |f, (oct, off)|
16
+ op.bin_mask[oct] |= (@fields_mask[f] << off)
17
+ }
18
+ op.bin_mask.map! { |v| 255 ^ v }
19
+ end
20
+
21
+ def build_bin_lookaside
22
+ # sets up a hash byte value => list of opcodes that may match
23
+ # opcode.bin_mask is built here
24
+ lookaside = Array.new(256) { [] }
25
+ opcode_list.each { |op|
26
+ build_opcode_bin_mask op
27
+ b = op.bin[0]
28
+ msk = op.bin_mask[0]
29
+ next @unknown_opcode = op if not b
30
+ for i in b..(b | (255^msk))
31
+ lookaside[i] << op if i & msk == b & msk
32
+ end
33
+ }
34
+ lookaside
35
+ end
36
+
37
+ def decode_prefix(instr, byte)
38
+ case byte
39
+ when 0xDD; instr.prefix = 0xDD
40
+ when 0xFD; instr.prefix = 0xFD
41
+ # implicit 'else return false'
42
+ end
43
+ end
44
+
45
+ # tries to find the opcode encoded at edata.ptr
46
+ # if no match, tries to match a prefix (update di.instruction.prefix)
47
+ # on match, edata.ptr points to the first byte of the opcode (after prefixes)
48
+ def decode_findopcode(edata)
49
+ di = DecodedInstruction.new self
50
+ while edata.ptr < edata.data.length
51
+ byte = edata.data[edata.ptr]
52
+ byte = byte.unpack('C').first if byte.kind_of?(::String)
53
+ return di if di.opcode = @bin_lookaside[byte].find { |op|
54
+ # fetch the relevant bytes from edata
55
+ bseq = edata.data[edata.ptr, op.bin.length].unpack('C*')
56
+ # check against full opcode mask
57
+ op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) }
58
+ }
59
+
60
+ if decode_prefix(di.instruction, edata.get_byte)
61
+ nb = edata.data[edata.ptr]
62
+ nb = nb.unpack('C').first if nb.kind_of?(::String)
63
+ case nb
64
+ when 0xCB
65
+ # DD CB <disp8> <opcode_pfxCB> [<args>]
66
+ di.instruction.prefix |= edata.get_byte << 8
67
+ di.bin_length += 2
68
+ opc = edata.data[edata.ptr+1]
69
+ opc = opc.unpack('C').first if opc.kind_of?(::String)
70
+ bseq = [0xCB, opc]
71
+ # XXX in decode_instr_op, byte[0] is the immediate displacement instead of cb
72
+ return di if di.opcode = @bin_lookaside[nb].find { |op|
73
+ op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) }
74
+ }
75
+ when 0xED
76
+ di.instruction.prefix = nil
77
+ end
78
+ else
79
+ di.opcode = @unknown_opcode
80
+ return di
81
+ end
82
+ di.bin_length += 1
83
+ end
84
+ end
85
+
86
+
87
+ def decode_instr_op(edata, di)
88
+ before_ptr = edata.ptr
89
+ op = di.opcode
90
+ di.instruction.opname = op.name
91
+ bseq = edata.read(op.bin.length).unpack('C*') # decode_findopcode ensures that data >= op.length
92
+ pfx = di.instruction.prefix
93
+
94
+ field_val = lambda { |f|
95
+ if fld = op.fields[f]
96
+ (bseq[fld[0]] >> fld[1]) & @fields_mask[f]
97
+ end
98
+ }
99
+
100
+ op.args.each { |a|
101
+ di.instruction.args << case a
102
+ when :i8, :u8, :i16, :u16; Expression[edata.decode_imm(a, @endianness)]
103
+ when :iy; Expression[field_val[a]]
104
+ when :iy8; Expression[field_val[a]*8]
105
+
106
+ when :rp
107
+ v = field_val[a]
108
+ Reg.new(16, v)
109
+ when :rp2
110
+ v = field_val[a]
111
+ v = 4 if v == 3
112
+ Reg.new(16, v)
113
+ when :ry, :rz
114
+ v = field_val[a]
115
+ if v == 6
116
+ Memref.new(Reg.from_str('HL'), nil, 1)
117
+ else
118
+ Reg.new(8, v)
119
+ end
120
+
121
+ when :r_a; Reg.from_str('A')
122
+ when :r_af; Reg.from_str('AF')
123
+ when :r_hl; Reg.from_str('HL')
124
+ when :r_de; Reg.from_str('DE')
125
+ when :r_sp; Reg.from_str('SP')
126
+ when :r_i; Reg.from_str('I')
127
+
128
+ when :m16; Memref.new(nil, edata.decode_imm(:u16, @endianness), nil)
129
+ when :m_bc; Memref.new(Reg.from_str('BC'), nil, 1)
130
+ when :m_de; Memref.new(Reg.from_str('DE'), nil, 1)
131
+ when :m_sp; Memref.new(Reg.from_str('SP'), nil, 2)
132
+ when :m_hl; Memref.new(Reg.from_str('HL'), nil, 1)
133
+ when :mf8; Memref.new(nil, 0xff00 + edata.decode_imm(:u8, @endianness), 1)
134
+ when :mfc; Memref.new(Reg.from_str('C'), 0xff00, 1)
135
+
136
+ else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
137
+ end
138
+ }
139
+
140
+ case pfx
141
+ when 0xDD
142
+ when 0xFD
143
+ when 0xCBDD
144
+ when 0xCBFD
145
+ end
146
+
147
+ di.bin_length += edata.ptr - before_ptr
148
+
149
+ return if edata.ptr > edata.length
150
+
151
+ di
152
+ end
153
+
154
+ # hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
155
+ def backtrace_binding
156
+ @backtrace_binding ||= init_backtrace_binding
157
+ end
158
+ def backtrace_binding=(b) @backtrace_binding = b end
159
+
160
+ # populate the @backtrace_binding hash with default values
161
+ def init_backtrace_binding
162
+ @backtrace_binding ||= {}
163
+
164
+ mask = 0xffff
165
+
166
+ opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
167
+ binding = case op
168
+ when 'ld'; lambda { |di, a0, a1, *aa| a2 = aa[0] ; a2 ? { a0 => Expression[a1, :+, a2] } : { a0 => Expression[a1] } }
169
+ when 'ldi'; lambda { |di, a0, a1| hl = (a0 == :a ? a1 : a0) ; { a0 => Expression[a1], hl => Expression[hl, :+, 1] } }
170
+ when 'ldd'; lambda { |di, a0, a1| hl = (a0 == :a ? a1 : a0) ; { a0 => Expression[a1], hl => Expression[hl, :-, 1] } }
171
+ when 'add', 'adc', 'sub', 'sbc', 'and', 'xor', 'or'
172
+ lambda { |di, a0, a1|
173
+ e_op = { 'add' => :+, 'adc' => :+, 'sub' => :-, 'sbc' => :-, 'and' => :&, 'xor' => :^, 'or' => :| }[op]
174
+ ret = Expression[a0, e_op, a1]
175
+ ret = Expression[ret, e_op, :flag_c] if op == 'adc' or op == 'sbc'
176
+ ret = Expression[ret.reduce] if not a0.kind_of? Indirection
177
+ { a0 => ret }
178
+ }
179
+ when 'cp', 'cmp'; lambda { |di, *a| {} }
180
+ when 'inc'; lambda { |di, a0| { a0 => Expression[a0, :+, 1] } }
181
+ when 'dec'; lambda { |di, a0| { a0 => Expression[a0, :-, 1] } }
182
+ when 'not'; lambda { |di, a0| { a0 => Expression[a0, :^, mask] } }
183
+ when 'push'
184
+ lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
185
+ Indirection[:sp, 2, di.address] => Expression[a0] } }
186
+ when 'pop'
187
+ lambda { |di, a0| { :sp => Expression[:sp, :+, 2],
188
+ a0 => Indirection[:sp, 2, di.address] } }
189
+ when 'call'
190
+ lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
191
+ Indirection[:sp, 2, di.address] => Expression[di.next_addr] }
192
+ }
193
+ when 'ret', 'reti'; lambda { |di, *a| { :sp => Expression[:sp, :+, 2] } }
194
+ # TODO callCC, retCC ...
195
+ when 'bswap'
196
+ lambda { |di, a0| { a0 => Expression[
197
+ [[a0, :&, 0xff00], :>>, 8], :|,
198
+ [[a0, :&, 0x00ff], :<<, 8]] } }
199
+ when 'nop', /^j/; lambda { |di, *a| {} }
200
+ end
201
+
202
+ # TODO flags ?
203
+
204
+ @backtrace_binding[op] ||= binding if binding
205
+ }
206
+ @backtrace_binding
207
+ end
208
+
209
+ def get_backtrace_binding(di)
210
+ a = di.instruction.args.map { |arg|
211
+ case arg
212
+ when Memref, Reg; arg.symbolic(di)
213
+ else arg
214
+ end
215
+ }
216
+
217
+ if binding = backtrace_binding[di.opcode.basename]
218
+ binding[di, *a]
219
+ else
220
+ puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
221
+ # assume nothing except the 1st arg is modified
222
+ case a[0]
223
+ when Indirection, Symbol; { a[0] => Expression::Unknown }
224
+ when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
225
+ else {}
226
+ end.update(:incomplete_binding => Expression[1])
227
+ end
228
+ end
229
+
230
+ # patch a forward binding from the backtrace binding
231
+ def fix_fwdemu_binding(di, fbd)
232
+ case di.opcode.name
233
+ when 'push', 'call'; fbd[Indirection[[:sp, :-, 2], 2]] = fbd.delete(Indirection[:sp, 2])
234
+ end
235
+ fbd
236
+ end
237
+
238
+ def get_xrefs_x(dasm, di)
239
+ return [] if not di.opcode.props[:setip]
240
+
241
+ case di.opcode.basename
242
+ when 'ret', 'reti'
243
+ return [Indirection[:sp, 2, di.address]]
244
+ when /^jr|^djnz/
245
+ # jmp/call are absolute addrs, only jr/djnz are relative
246
+ # also, the asm source should display the relative offset
247
+ return [Expression[[di.address, :+, di.bin_length], :+, di.instruction.args.first]]
248
+ end
249
+
250
+ case tg = di.instruction.args.first
251
+ when Memref; [Expression[tg.symbolic(di)]]
252
+ when Reg; [Expression[tg.symbolic(di)]]
253
+ when Expression, ::Integer; [Expression[tg]]
254
+ else
255
+ puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
256
+ []
257
+ end
258
+ end
259
+
260
+ # checks if expr is a valid return expression matching the :saveip instruction
261
+ def backtrace_is_function_return(expr, di=nil)
262
+ expr = Expression[expr].reduce_rec
263
+ expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp]
264
+ end
265
+
266
+ # updates the function backtrace_binding
267
+ # if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand)
268
+ def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
269
+ b = f.backtrace_binding
270
+
271
+ bt_val = lambda { |r|
272
+ next if not retaddrlist
273
+ b[r] = Expression::Unknown
274
+ bt = []
275
+ retaddrlist.each { |retaddr|
276
+ bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true,
277
+ :snapshot_addr => faddr, :origin => retaddr)
278
+ }
279
+ if bt.length != 1
280
+ b[r] = Expression::Unknown
281
+ else
282
+ b[r] = bt.first
283
+ end
284
+ }
285
+
286
+ if not wantregs.empty?
287
+ wantregs.each(&bt_val)
288
+ else
289
+ bt_val[:sp]
290
+ end
291
+
292
+ b
293
+ end
294
+
295
+ # returns true if the expression is an address on the stack
296
+ def backtrace_is_stack_address(expr)
297
+ Expression[expr].expr_externals.include?(:sp)
298
+ end
299
+
300
+ # updates an instruction's argument replacing an expression with another (eg label renamed)
301
+ def replace_instr_arg_immediate(i, old, new)
302
+ i.args.map! { |a|
303
+ case a
304
+ when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
305
+ when Memref
306
+ a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset
307
+ a
308
+ else a
309
+ end
310
+ }
311
+ end
312
+ end
313
+ end