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
@@ -0,0 +1,17 @@
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
+ # fix autorequire warning
7
+ class Metasm::Ia32 < Metasm::CPU
8
+ end
9
+
10
+ require 'metasm/main'
11
+ require 'metasm/cpu/ia32/parse'
12
+ require 'metasm/cpu/ia32/encode'
13
+ require 'metasm/cpu/ia32/decode'
14
+ require 'metasm/cpu/ia32/render'
15
+ require 'metasm/cpu/ia32/compile_c'
16
+ require 'metasm/cpu/ia32/decompile'
17
+ require 'metasm/cpu/ia32/debug'
@@ -4,7 +4,7 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/ia32/parse'
7
+ require 'metasm/cpu/ia32/parse'
8
8
  require 'metasm/compile_c'
9
9
 
10
10
  module Metasm
@@ -527,7 +527,7 @@ class CCompiler < C::Compiler
527
527
  if expr.rexpr.type.specifier == :unsigned and r.sz == 64
528
528
  label = new_label('unsign_float')
529
529
  if m.sz == 64 and @cpusz < 64
530
- foo, m = get_composite_parts m
530
+ m = get_composite_parts(m)[1]
531
531
  end
532
532
  m2 = m
533
533
  m2 = make_volatile(m, expr.rexpr.type) if m.kind_of? ModRM
@@ -637,7 +637,7 @@ class CCompiler < C::Compiler
637
637
  # both sides are already cast to the same type by the precompiler
638
638
  # XXX expr.type.pointer?
639
639
  if expr.type.integral? and expr.type.name == :ptr and expr.lexpr.type.kind_of? C::BaseType and
640
- typesize[expr.lexpr.type.name] == typesize[:ptr]
640
+ typesize[expr.lexpr.type.name] == typesize[:ptr]
641
641
  expr.lexpr.type.name = :ptr
642
642
  end
643
643
  l = c_cexpr_inner(expr.lexpr)
@@ -711,6 +711,7 @@ class CCompiler < C::Compiler
711
711
  end
712
712
  when :-
713
713
  r = c_cexpr_inner(expr.rexpr)
714
+ r = resolve_address r if r.kind_of? Address
714
715
  if r.kind_of? Expression
715
716
  unuse l, r
716
717
  l = Address.new(l.modrm.dup)
@@ -1077,6 +1078,7 @@ class CCompiler < C::Compiler
1077
1078
  when 'add', 'sub', 'and', 'or', 'xor'
1078
1079
  r = make_volatile(r, type) if l.kind_of? ModRM and r.kind_of? ModRM
1079
1080
  unuse r
1081
+ r = Reg.new(r.val, l.sz) if r.kind_of?(Reg) and l.kind_of?(ModRM) and l.sz and l.sz != r.sz # add byte ptr [eax], bl
1080
1082
  instr op, l, r
1081
1083
  when 'shr', 'sar', 'shl'
1082
1084
  if r.kind_of? Expression
@@ -1509,10 +1511,6 @@ class CCompiler < C::Compiler
1509
1511
  #File.open('m-dbg-precomp.c', 'w') { |fd| fd.puts @parser }
1510
1512
  #File.open('m-dbg-src.asm', 'w') { |fd| fd.puts @source }
1511
1513
  end
1512
-
1513
- def check_reserved_name(var)
1514
- Reg.s_to_i[var.name] or super(var)
1515
- end
1516
1514
  end
1517
1515
 
1518
1516
  def new_ccompiler(parser, exe=ExeFormat.new)
@@ -4,7 +4,7 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/ia32/opcodes'
7
+ require 'metasm/cpu/ia32/opcodes'
8
8
 
9
9
  module Metasm
10
10
  class Ia32
@@ -18,7 +18,7 @@ class Ia32
18
18
  @dbg_register_flags ||= :eflags
19
19
  end
20
20
 
21
- def dbg_register_list
21
+ def dbg_register_list
22
22
  @dbg_register_list ||= [:eax, :ebx, :ecx, :edx, :esi, :edi, :ebp, :esp, :eip]
23
23
  end
24
24
 
@@ -46,10 +46,10 @@ class Ia32
46
46
  end
47
47
 
48
48
  def dbg_enable_singlestep(dbg)
49
- dbg_set_flag(dbg, :t)
49
+ dbg_set_flag(dbg, :t) if dbg_get_flag(dbg, :t) == 0
50
50
  end
51
51
  def dbg_disable_singlestep(dbg)
52
- dbg_unset_flag(dbg, :t)
52
+ dbg_unset_flag(dbg, :t) if dbg_get_flag(dbg, :t) != 0
53
53
  end
54
54
 
55
55
  def dbg_enable_bp(dbg, bp)
@@ -113,7 +113,7 @@ class Ia32
113
113
  if dbg[:dr6] == 0 and dbg[:dr7] == 0
114
114
  dbg[:dr7] = 0x10000 # some OS (eg Windows) only return dr6 if dr7 != 0
115
115
  end
116
- dbg[:dr6] = 0
116
+ dbg[:dr6] = 0 if dbg[:dr6] & 0x400f != 0
117
117
  end
118
118
 
119
119
  def dbg_evt_bpx(dbg, b)
@@ -4,13 +4,13 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/ia32/opcodes'
7
+ require 'metasm/cpu/ia32/opcodes'
8
8
  require 'metasm/decode'
9
9
 
10
10
  module Metasm
11
11
  class Ia32
12
12
  class ModRM
13
- def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg)
13
+ def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg, h = {})
14
14
  m = (byte >> 6) & 3
15
15
  rm = byte & 7
16
16
 
@@ -28,7 +28,11 @@ class Ia32
28
28
  b = Reg.new(a, adsz)
29
29
  else
30
30
  s = 1
31
- i = Reg.new(a, adsz)
31
+ if h[:mrmvex]
32
+ i = SimdReg.new(a, h[:mrmvex])
33
+ else
34
+ i = Reg.new(a, adsz)
35
+ end
32
36
  end
33
37
 
34
38
  when :sib
@@ -37,7 +41,11 @@ class Ia32
37
41
  ii = ((sib >> 3) & 7)
38
42
  if ii != 4
39
43
  s = 1 << ((sib >> 6) & 3)
40
- i = Reg.new(ii, adsz)
44
+ if h[:mrmvex]
45
+ i = SimdReg.new(ii, h[:mrmvex])
46
+ else
47
+ i = Reg.new(ii, adsz)
48
+ end
41
49
  end
42
50
 
43
51
  bb = sib & 7
@@ -52,11 +60,12 @@ class Ia32
52
60
  end
53
61
  }
54
62
 
55
- if imm and imm.reduce.kind_of? Integer and imm.reduce < -0x10_0000
63
+ if imm and ir = imm.reduce and ir.kind_of?(Integer) and ir < 0 and (ir < -0x10_0000 or (!b and !i))
56
64
  # probably a base address -> unsigned
57
65
  imm = Expression[imm.reduce & ((1 << (adsz || 32)) - 1)]
58
66
  end
59
67
 
68
+ opsz = h[:argsz] if h[:argsz]
60
69
  new adsz, opsz, s, i, b, imm, seg
61
70
  end
62
71
  end
@@ -90,8 +99,7 @@ class Ia32
90
99
  msk = op.bin_mask[0]
91
100
 
92
101
  for i in b..(b | (255^msk))
93
- next if i & msk != b & msk
94
- lookaside[i] << op
102
+ lookaside[i] << op if i & msk == b & msk
95
103
  end
96
104
  }
97
105
  lookaside
@@ -117,8 +125,6 @@ class Ia32
117
125
  v = byte & 7
118
126
  end
119
127
  instr.prefix[:seg] = SegReg.new(v)
120
-
121
- instr.prefix[:jmphint] = ((byte & 0x10) == 0x10)
122
128
  else
123
129
  return false
124
130
  end
@@ -133,11 +139,10 @@ class Ia32
133
139
  while edata.ptr < edata.data.length
134
140
  pfx = di.instruction.prefix || {}
135
141
  byte = edata.data[edata.ptr]
136
- byte = byte.unpack('C').first if byte.kind_of? ::String # 1.9
142
+ byte = byte.unpack('C').first if byte.kind_of?(::String)
137
143
  return di if di.opcode = @bin_lookaside[byte].find { |op|
138
144
  # fetch the relevant bytes from edata
139
145
  bseq = edata.data[edata.ptr, op.bin.length].unpack('C*')
140
- di.opcode = op if op.props[:opsz] # needed by opsz(di)
141
146
 
142
147
  # check against full opcode mask
143
148
  op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) } and
@@ -147,12 +152,17 @@ class Ia32
147
152
  (fld = op.fields[:seg2A] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg2A] == 1) or
148
153
  (fld = op.fields[:seg3A] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg3A] < 4) or
149
154
  (fld = op.fields[:seg3A] || op.fields[:seg3] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg3] > 5) or
150
- (fld = op.fields[:modrmA] and (bseq[fld[0]] >> fld[1]) & 0xC0 == 0xC0) or
151
- (sz = op.props[:opsz] and opsz(di) != sz) or
155
+ (op.props[:modrmA] and fld = op.fields[:modrm] and (bseq[fld[0]] >> fld[1]) & 0xC0 == 0xC0) or
156
+ (op.props[:modrmR] and fld = op.fields[:modrm] and (bseq[fld[0]] >> fld[1]) & 0xC0 != 0xC0) or
157
+ (fld = op.fields[:vex_vvvv] and @size != 64 and (bseq[fld[0]] >> fld[1]) & @fields_mask[:vex_vvvv] < 8) or
158
+ (sz = op.props[:opsz] and opsz(di, op) != sz) or
159
+ (sz = op.props[:adsz] and adsz(di, op) != sz) or
152
160
  (ndpfx = op.props[:needpfx] and not pfx[:list].to_a.include? ndpfx) or
161
+ (pfx[:adsz] and op.props[:adsz] and op.props[:adsz] == @size) or
153
162
  # return non-ambiguous opcode (eg push.i16 in 32bit mode) / sync with addop_post in opcode.rb
154
- (pfx[:opsz] and (op.args == [:i] or op.args == [:farptr] or op.name[0, 3] == 'ret') and not op.props[:opsz]) or
155
- (pfx[:adsz] and op.props[:adsz] and op.props[:adsz] == @size)
163
+ (pfx[:opsz] and not op.props[:opsz] and (op.args == [:i] or op.args == [:farptr] or op.name == 'ret')) or
164
+ (pfx[:adsz] and not op.props[:adsz] and (op.props[:strop] or op.props[:stropz] or op.args.include?(:mrm_imm) or op.args.include?(:modrm) or op.name =~ /loop|xlat/)) or
165
+ (op.name == 'nop' and op.bin[0] == 0x90 and di.instruction.prefix and di.instruction.prefix[:rex_b])
156
166
  )
157
167
  }
158
168
 
@@ -174,19 +184,21 @@ class Ia32
174
184
  when 0xF2, 0xF3; pfx.delete :rep
175
185
  end
176
186
 
187
+ if op.props[:setip] and not op.props[:stopexec] and pfx[:seg]
188
+ case pfx.delete(:seg).val
189
+ when 1; pfx[:jmphint] = 'hintnojmp'
190
+ when 3; pfx[:jmphint] = 'hintjmp'
191
+ end
192
+ end
193
+
177
194
  field_val = lambda { |f|
178
195
  if fld = op.fields[f]
179
196
  (bseq[fld[0]] >> fld[1]) & @fields_mask[f]
180
197
  end
181
198
  }
182
199
 
183
- opsz = opsz(di)
184
-
185
- if pfx[:adsz]
186
- adsz = 48 - @size
187
- else
188
- adsz = @size
189
- end
200
+ opsz = op.props[:argsz] || opsz(di)
201
+ adsz = (pfx[:adsz] ? 48 - @size : @size)
190
202
 
191
203
  mmxsz = ((op.props[:xmmx] && pfx[:opsz]) ? 128 : 64)
192
204
  op.args.each { |a|
@@ -199,15 +211,23 @@ class Ia32
199
211
  when :regfp; FpReg.new field_val[a]
200
212
  when :regmmx; SimdReg.new field_val[a], mmxsz
201
213
  when :regxmm; SimdReg.new field_val[a], 128
214
+ when :regymm; SimdReg.new field_val[a], 256
202
215
 
203
216
  when :farptr; Farptr.decode edata, @endianness, opsz
204
217
  when :i8, :u8, :u16; Expression[edata.decode_imm(a, @endianness)]
205
218
  when :i; Expression[edata.decode_imm("#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym, @endianness)]
206
219
 
207
- when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx[:seg]
208
- when :modrm, :modrmA; ModRM.decode edata, field_val[a], @endianness, adsz, opsz, pfx[:seg]
209
- when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx[:seg], SimdReg
210
- when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx[:seg], SimdReg
220
+ when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx.delete(:seg)
221
+ when :modrm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, opsz, pfx.delete(:seg)
222
+ when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz]
223
+ when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]
224
+ when :modrmymm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 256, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]
225
+
226
+ when :vexvreg; Reg.new((field_val[:vex_vvvv] ^ 0xf), opsz)
227
+ when :vexvxmm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 128)
228
+ when :vexvymm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 256)
229
+ when :i4xmm; SimdReg.new((edata.decode_imm(:u8, @endianness) >> 4) & 7, 128)
230
+ when :i4ymm; SimdReg.new((edata.decode_imm(:u8, @endianness) >> 4) & 7, 256)
211
231
 
212
232
  when :imm_val1; Expression[1]
213
233
  when :imm_val3; Expression[3]
@@ -221,6 +241,8 @@ class Ia32
221
241
 
222
242
  di.bin_length += edata.ptr - before_ptr
223
243
 
244
+ return false if edata.ptr > edata.length
245
+
224
246
  if op.name == 'movsx' or op.name == 'movzx'
225
247
  if di.opcode.props[:argsz] == 8
226
248
  di.instruction.args[1].sz = 8
@@ -232,9 +254,10 @@ class Ia32
232
254
  else
233
255
  di.instruction.args[0].sz = @size
234
256
  end
257
+ elsif op.name == 'crc32'
258
+ di.instruction.args[0].sz = 32
235
259
  end
236
260
 
237
- pfx.delete :seg
238
261
  case pfx.delete(:rep)
239
262
  when :nz
240
263
  if di.opcode.props[:strop]
@@ -257,7 +280,7 @@ class Ia32
257
280
  # adds the eip delta to the offset +off+ of the instruction (may be an Expression) + its bin_length
258
281
  # do not call twice on the same di !
259
282
  def decode_instr_interpret(di, addr)
260
- if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.instruction.opname[0, 3] != 'ret'
283
+ if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.instruction.opname !~ /^i?ret/
261
284
  delta = di.instruction.args.last.reduce
262
285
  arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
263
286
  di.instruction.args[-1] = Expression[arg]
@@ -306,11 +329,16 @@ class Ia32
306
329
  end
307
330
  def backtrace_binding=(b) @backtrace_binding = b end
308
331
 
309
- def opsz(di)
310
- ret = @size
311
- ret = di.opcode.props[:argsz] if di and di.opcode.props[:argsz]
312
- ret = 48 - ret if di and not di.opcode.props[:argsz] and di.instruction.prefix and di.instruction.prefix[:opsz]
313
- ret
332
+ def opsz(di, op=nil)
333
+ if di and di.instruction.prefix and di.instruction.prefix[:opsz] and (op || di.opcode).props[:needpfx] != 0x66; 48-@size
334
+ else @size
335
+ end
336
+ end
337
+
338
+ def adsz(di, op=nil)
339
+ if di and di.instruction.prefix and di.instruction.prefix[:adsz] and (op || di.opcode).props[:needpfx] != 0x67; 48-@size
340
+ else @size
341
+ end
314
342
  end
315
343
 
316
344
  # populate the @backtrace_binding hash with default values
@@ -318,15 +346,37 @@ class Ia32
318
346
  @backtrace_binding ||= {}
319
347
 
320
348
  eax, ecx, edx, ebx, esp, ebp, esi, edi = register_symbols
349
+ ebx = ebx
321
350
 
322
351
  mask = lambda { |di| (1 << opsz(di))-1 } # 32bits => 0xffff_ffff
323
352
  sign = lambda { |v, di| Expression[[[v, :&, mask[di]], :>>, opsz(di)-1], :'!=', 0] }
324
353
 
325
354
  opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
326
355
  binding = case op
327
- when 'mov', 'movsx', 'movzx', 'movsxd', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
356
+ when 'mov', 'movzx', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
357
+ when 'movsx', 'movsxd'
358
+ lambda { |di, a0, a1|
359
+ sz1 = di.instruction.args[1].sz
360
+ sign1 = Expression[[a1, :>>, sz1-1], :&, 1]
361
+ { a0 => Expression[[a1, :|, [sign1, :*, (-1 << sz1)]], :&, mask[di]] }
362
+ }
328
363
  when 'lea'; lambda { |di, a0, a1| { a0 => a1.target } }
329
- when 'xchg'; lambda { |di, a0, a1| { a0 => Expression[a1], a1 => Expression[a0] } }
364
+ when 'xchg'; lambda { |di, a0, a1|
365
+ # specialcase xchg al, ah (conflict on eax not handled in get_backtrace_binding)
366
+ if a0.kind_of?(Expression) and a1.kind_of?(Expression) and
367
+ a0.op == :& and a0.rexpr == 255 and
368
+ a1.op == :& and a1.rexpr == 255 and
369
+ ((a0.lexpr.kind_of?(Expression) and a0.lexpr.lexpr == a1.lexpr and a0.lexpr.op == :>> and a0.lexpr.rexpr == 8) or
370
+ (a1.lexpr.kind_of?(Expression) and a1.lexpr.lexpr == a0.lexpr and a1.lexpr.op == :>> and a1.lexpr.rexpr == 8))
371
+ tgreg = a0.lexpr.kind_of?(Expression) ? a1.lexpr : a0.lexpr
372
+ invmask = (@size == 64 ? 0xffff_ffff_ffff_0000 : 0xffff_0000)
373
+ { tgreg => Expression[[tgreg, :&, invmask], :|,
374
+ [[[tgreg, :>>, 8], :&, 0x00ff], :|,
375
+ [[tgreg, :<<, 8], :&, 0xff00]]] }
376
+ else
377
+ { a0 => Expression[a1], a1 => Expression[a0] }
378
+ end
379
+ }
330
380
  when 'add', 'sub', 'or', 'xor', 'and', 'pxor', 'adc', 'sbb'
331
381
  lambda { |di, a0, a1|
332
382
  e_op = { 'add' => :+, 'sub' => :-, 'or' => :|, 'and' => :&, 'xor' => :^, 'pxor' => :^, 'adc' => :+, 'sbb' => :- }[op]
@@ -346,13 +396,23 @@ class Ia32
346
396
  lambda { |di, a0, a1|
347
397
  e_op = (op[2] == ?r ? :>> : :<<)
348
398
  inv_op = {:<< => :>>, :>> => :<< }[e_op]
349
- sz = [a1, :%, opsz(di)]
350
- isz = [[opsz(di), :-, a1], :%, opsz(di)]
399
+ operandsize = di.instruction.args[0].sz
400
+ operandmask = (1 << operandsize) - 1
401
+ sz = [a1, :%, operandsize]
402
+ isz = [[operandsize, :-, a1], :%, operandsize]
351
403
  # ror a, b => (a >> b) | (a << (32-b))
352
- { a0 => Expression[[[a0, e_op, sz], :|, [a0, inv_op, isz]], :&, mask[di]] }
404
+ { a0 => Expression[[[[a0, :&, operandmask], e_op, sz], :|, [[a0, :&, operandmask], inv_op, isz]], :&, operandmask] }
353
405
  }
354
406
  when 'sar', 'shl', 'sal'; lambda { |di, a0, a1| { a0 => Expression[a0, (op[-1] == ?r ? :>> : :<<), [a1, :%, [opsz(di), 32].max]] } }
355
407
  when 'shr'; lambda { |di, a0, a1| { a0 => Expression[[a0, :&, mask[di]], :>>, [a1, :%, opsz(di)]] } }
408
+ when 'shrd'
409
+ lambda { |di, a0, a1, a2|
410
+ { a0 => Expression[[a0, :>>, [a2, :%, opsz(di)]], :|, [a1, :<<, [[opsz(di), :-, a2], :%, opsz(di)]]] }
411
+ }
412
+ when 'shld'
413
+ lambda { |di, a0, a1, a2|
414
+ { a0 => Expression[[a0, :<<, [a2, :%, opsz(di)]], :|, [a1, :>>, [[opsz(di), :-, a2], :%, opsz(di)]]] }
415
+ }
356
416
  when 'cwd', 'cdq', 'cqo'; lambda { |di| { Expression[edx, :&, mask[di]] => Expression[mask[di], :*, sign[eax, di]] } }
357
417
  when 'cbw', 'cwde', 'cdqe'; lambda { |di|
358
418
  o2 = opsz(di)/2 ; m2 = (1 << o2) - 1
@@ -363,7 +423,7 @@ class Ia32
363
423
  when 'pop'
364
424
  lambda { |di, a0| { esp => Expression[esp, :+, opsz(di)/8],
365
425
  a0 => Indirection[esp, opsz(di)/8, di.address] } }
366
- when 'pushfd'
426
+ when 'pushfd', 'pushf'
367
427
  # TODO Unknown per bit
368
428
  lambda { |di|
369
429
  efl = Expression[0x202]
@@ -373,8 +433,8 @@ class Ia32
373
433
  bts[7, :eflag_s]
374
434
  bts[11, :eflag_o]
375
435
  { esp => Expression[esp, :-, opsz(di)/8], Indirection[esp, opsz(di)/8, di.address] => efl }
376
- }
377
- when 'popfd'
436
+ }
437
+ when 'popfd', 'popf'
378
438
  lambda { |di| bt = lambda { |pos| Expression[[Indirection[esp, opsz(di)/8, di.address], :>>, pos], :&, 1] }
379
439
  { esp => Expression[esp, :+, opsz(di)/8], :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7], :eflag_o => bt[11] } }
380
440
  when 'sahf'
@@ -412,9 +472,25 @@ class Ia32
412
472
  ret
413
473
  }
414
474
  when 'call'
415
- lambda { |di, a0| { esp => Expression[esp, :-, opsz(di)/8],
416
- Indirection[esp, opsz(di)/8, di.address] => Expression[di.next_addr] } }
475
+ lambda { |di, a0|
476
+ sz = opsz(di)/8
477
+ if a0.kind_of? Farptr
478
+ { esp => Expression[esp, :-, 2*sz],
479
+ Indirection[esp, sz, di.address] => Expression[di.next_addr],
480
+ Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown }
481
+ else
482
+ { esp => Expression[esp, :-, sz],
483
+ Indirection[esp, sz, di.address] => Expression[di.next_addr] }
484
+ end
485
+ }
486
+ when 'callf'
487
+ lambda { |di, a0|
488
+ sz = opsz(di)/8
489
+ { esp => Expression[esp, :-, 2*sz],
490
+ Indirection[esp, sz, di.address] => Expression[di.next_addr],
491
+ Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown } }
417
492
  when 'ret'; lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/8, :+, a[0] || 0]] } }
493
+ when 'retf';lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/4, :+, a[0] || 0]] } }
418
494
  when 'loop', 'loopz', 'loopnz'; lambda { |di, a0| { ecx => Expression[ecx, :-, 1] } }
419
495
  when 'enter'
420
496
  lambda { |di, a0, a1|
@@ -427,7 +503,7 @@ class Ia32
427
503
  (1..depth).each { |i|
428
504
  b[Indirection[[esp, :+, a0.reduce+i*sz], sz, di.address]] =
429
505
  b[Indirection[[ebp, :-, i*sz], sz, di.address]] =
430
- Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
506
+ Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
431
507
  }
432
508
  b
433
509
  }
@@ -435,21 +511,46 @@ class Ia32
435
511
  when 'aaa'; lambda { |di| { eax => Expression::Unknown, :incomplete_binding => Expression[1] } }
436
512
  when 'imul'
437
513
  lambda { |di, *a|
438
- # 1 operand form == same as 'mul' (ax:dx stuff)
439
- next { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } if not a[1]
514
+ if not a[1]
515
+ # 1 operand from: store result in edx:eax
516
+ bd = {}
517
+ m = mask[di]
518
+ s = opsz(di)
519
+ e = Expression[Expression.make_signed(Expression[a[0], :&, m], s), :*, Expression.make_signed(Expression[eax, :&, m], s)]
520
+ if s == 8
521
+ bd[Expression[eax, :&, 0xffff]] = e
522
+ else
523
+ bd[Expression[eax, :&, m]] = Expression[e, :&, m]
524
+ bd[Expression[edx, :&, m]] = Expression[[e, :>>, opsz(di)], :&, m]
525
+ end
526
+ # XXX eflags?
527
+ next bd
528
+ end
440
529
 
441
530
  if a[2]; e = Expression[a[1], :*, a[2]]
442
531
  else e = Expression[[a[0], :*, a[1]], :&, (1 << (di.instruction.args.first.sz || opsz(di))) - 1]
443
532
  end
444
533
  { a[0] => e }
445
534
  }
446
- when 'mul', 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
535
+ when 'mul'
536
+ lambda { |di, *a|
537
+ m = mask[di]
538
+ e = Expression[a, :*, [eax, :&, m]]
539
+ if opsz(di) == 8
540
+ { Expression[eax, :&, 0xffff] => e }
541
+ else
542
+ { Expression[eax, :&, m] => Expression[e, :&, m],
543
+ Expression[edx, :&, m] => Expression[[e, :>>, opsz(di)], :&, m] }
544
+ end
545
+ }
546
+ when 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
447
547
  when 'rdtsc'; lambda { |di| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
448
- when /^(stos|movs|lods|scas|cmps)[bwd]$/
449
- lambda { |di|
450
- op =~ /^(stos|movs|lods|scas|cmps)([bwd])$/
548
+ when /^(stos|movs|lods|scas|cmps)[bwdq]$/
549
+ lambda { |di, *a|
550
+ next {:incomplete_binding => 1} if di.opcode.args.include?(:regxmm) # XXX movsd xmm0, xmm1...
551
+ op =~ /^(stos|movs|lods|scas|cmps)([bwdq])$/
451
552
  e_op = $1
452
- sz = { 'b' => 1, 'w' => 2, 'd' => 4 }[$2]
553
+ sz = { 'b' => 1, 'w' => 2, 'd' => 4, 'q' => 8 }[$2]
453
554
  eax_ = Reg.new(0, 8*sz).symbolic
454
555
  dir = :+
455
556
  if di.block and (di.block.list.find { |ddi| ddi.opcode.name == 'std' } rescue nil)
@@ -477,7 +578,7 @@ class Ia32
477
578
  end
478
579
  when 'scas'
479
580
  case pfx[:rep]
480
- when nil; { edi => Expression[edi, dir, sz] }
581
+ when nil; { edi => Expression[edi, dir, sz], :eflag_z => Expression[pedi, :==, Expression[eax, :&, (1 << (sz*8))-1]] }
481
582
  else { edi => Expression::Unknown, ecx => Expression::Unknown }
482
583
  end
483
584
  when 'cmps'
@@ -506,7 +607,7 @@ class Ia32
506
607
  ret
507
608
  }
508
609
  when 'fstenv', 'fnstenv'
509
- lambda { |di, a0|
610
+ lambda { |di, a0|
510
611
  # stores the address of the last non-control fpu instr run
511
612
  lastfpuinstr = di.block.list[0...di.block.list.index(di)].reverse.find { |pdi|
512
613
  case pdi.opcode.name
@@ -535,7 +636,8 @@ class Ia32
535
636
  a0 => Expression[a0, :^, [1, :<<, [a1, :%, opsz(di)]]] } }
536
637
  when 'bswap'
537
638
  lambda { |di, a0|
538
- if opsz(di) == 64
639
+ case opsz(di)
640
+ when 64
539
641
  { a0 => Expression[
540
642
  [[[[a0, :&, 0xff000000_00000000], :>>, 56], :|,
541
643
  [[a0, :&, 0x00ff0000_00000000], :>>, 40]], :|,
@@ -545,12 +647,15 @@ class Ia32
545
647
  [[a0, :&, 0x00000000_00ff0000], :<<, 24]], :|,
546
648
  [[[a0, :&, 0x00000000_0000ff00], :<<, 40], :|,
547
649
  [[a0, :&, 0x00000000_000000ff], :<<, 56]]]] }
548
- else # XXX opsz != 32 => undef
650
+ when 32
549
651
  { a0 => Expression[
550
652
  [[[a0, :&, 0xff000000], :>>, 24], :|,
551
653
  [[a0, :&, 0x00ff0000], :>>, 8]], :|,
552
654
  [[[a0, :&, 0x0000ff00], :<<, 8], :|,
553
655
  [[a0, :&, 0x000000ff], :<<, 24]]] }
656
+ when 16
657
+ # bswap ax => mov ax, 0
658
+ { a0 => 0 }
554
659
  end
555
660
  }
556
661
  when 'nop', 'pause', 'wait', 'cmp', 'test'; lambda { |di, *a| {} }
@@ -602,7 +707,11 @@ class Ia32
602
707
  when 'imul', 'mul', 'idiv', 'div', /^(scas|cmps)[bwdq]$/
603
708
  lambda { |di, *a|
604
709
  ret = (binding ? binding[di, *a] : {})
605
- ret[:eflag_z] = ret[:eflag_s] = ret[:eflag_c] = ret[:eflag_o] = Expression::Unknown # :incomplete_binding ?
710
+ ret[:eflag_z] ||= Expression::Unknown
711
+ ret[:eflag_s] ||= Expression::Unknown
712
+ ret[:eflag_c] ||= Expression::Unknown
713
+ ret[:eflag_o] ||= Expression::Unknown
714
+ # :incomplete_binding ?
606
715
  ret
607
716
  }
608
717
  end
@@ -675,6 +784,30 @@ class Ia32
675
784
  end
676
785
  end
677
786
 
787
+ # patch a forward binding from the backtrace binding
788
+ # fixes fwdemu for push/pop/call/ret
789
+ def fix_fwdemu_binding(di, fbd)
790
+ if di.instruction.args.grep(ModRM).find { |m| m.seg and m.symbolic(di).target.lexpr =~ /^segment_base_/ }
791
+ fbd = fbd.dup
792
+ fbd[:incomplete_binding] = Expression[1]
793
+ end
794
+
795
+ case di.opcode.name
796
+ when 'push', 'call'
797
+ fbd = fbd.dup
798
+ sz = opsz(di)/8
799
+ esp = register_symbols[4]
800
+ if i = fbd.delete(Indirection[esp, sz])
801
+ fbd[Indirection[[esp, :-, sz], sz]] = i
802
+ end
803
+ when 'pop', 'ret' # nothing to do
804
+ when /^(push|pop|call|ret|enter|leave|stos|movs|lods|scas|cmps)/
805
+ fbd = fbd.dup
806
+ fbd[:incomplete_binding] = Expression[1] # TODO
807
+ end
808
+ fbd
809
+ end
810
+
678
811
  def get_xrefs_x(dasm, di)
679
812
  return [] if not di.opcode.props[:setip]
680
813
 
@@ -683,8 +816,8 @@ class Ia32
683
816
  when 'ret'; return [Indirection[register_symbols[4], sz/8, di.address]]
684
817
  when 'jmp', 'call'
685
818
  a = di.instruction.args.first
686
- if dasm and a.kind_of?(ModRM) and a.imm and a.s == sz/8 and not a.b and dasm.get_section_at(a.imm)
687
- return get_xrefs_x_jmptable(dasm, di, a, sz)
819
+ if dasm and a.kind_of?(ModRM) and a.imm and (a.s == sz/8 or a.s == 4) and not a.b and dasm.get_section_at(a.imm)
820
+ return get_xrefs_x_jmptable(dasm, di, a, a.s*8)
688
821
  end
689
822
  end
690
823
 
@@ -724,6 +857,19 @@ class Ia32
724
857
  }
725
858
  l = dasm.auto_label_at(mrm.imm, 'jmp_table', 'xref')
726
859
  replace_instr_arg_immediate(di.instruction, mrm.imm, Expression[l])
860
+ # add 'case 1' comments
861
+ cases = {}
862
+ ret.each_with_index { |ind, idx|
863
+ idx -= 1 # ret[0] = symbolic
864
+ next if idx < 0
865
+ a = dasm.backtrace(ind, di.address)
866
+ if a.length == 1 and a[0].kind_of?(Expression) and addr = a[0].reduce and addr.kind_of?(::Integer)
867
+ (cases[addr] ||= []) << idx
868
+ end
869
+ }
870
+ cases.each { |addr, list|
871
+ dasm.add_comment(addr, "case #{list.join(', ')}:")
872
+ }
727
873
  return ret
728
874
  end
729
875
 
@@ -735,7 +881,7 @@ class Ia32
735
881
  s = dasm.get_section_at(mrm.imm)
736
882
  v = 0
737
883
  end
738
- loop do
884
+ while s[0].ptr < s[0].length
739
885
  ptr = dasm.normalize s[0].decode_imm("u#{sz}".to_sym, @endianness)
740
886
  diff = Expression[ptr, :-, di.address].reduce
741
887
  if (diff.kind_of? ::Integer and diff.abs < 4096) or (di.opcode.basename == 'call' and ptr != 0 and dasm.get_section_at(ptr))
@@ -1164,5 +1310,46 @@ class Ia32
1164
1310
 
1165
1311
  binding
1166
1312
  end
1313
+
1314
+ # trace the stack pointer register across a function, rename occurences of esp+XX to esp+var_XX
1315
+ def name_local_vars(dasm, funcaddr)
1316
+ esp = register_symbols[4]
1317
+ func = dasm.function[funcaddr]
1318
+ subs = []
1319
+ dasm.trace_function_register(funcaddr, esp => 0) { |di, r, off, trace|
1320
+ next if r.to_s =~ /flag/
1321
+ if di.opcode.name == 'call' and tf = di.block.to_normal.find { |t| dasm.function[t] and dasm.function[t].localvars }
1322
+ subs << [trace[esp], dasm.function[tf].localvars]
1323
+ end
1324
+ di.instruction.args.grep(ModRM).each { |mrm|
1325
+ b = mrm.b || (mrm.i if mrm.s == 1)
1326
+ # its a modrm => b is read, so ignore r/off (not yet applied), use trace only
1327
+ stackoff = trace[b.symbolic] if b
1328
+ next if not stackoff
1329
+ imm = mrm.imm || Expression[0]
1330
+ frameoff = imm + stackoff
1331
+ if frameoff.kind_of?(::Integer)
1332
+ # XXX register args ? non-ABI standard register args ? (eg optimized x64)
1333
+ str = 'var_%X' % (-frameoff)
1334
+ str = 'arg_%X' % (frameoff-@size/8) if frameoff > 0
1335
+ str = func.get_localvar_stackoff(frameoff, di, str) if func
1336
+ imm = imm.expr if imm.kind_of?(ExpressionString)
1337
+ mrm.imm = ExpressionString.new(imm, str, :stackvar)
1338
+ end
1339
+ }
1340
+ off = off.reduce if off.kind_of?(Expression)
1341
+ next unless off.kind_of?(Integer)
1342
+ off
1343
+ }
1344
+ # if subfunctions are called at a fixed stack offset, rename var_3c -> subarg_0
1345
+ if func and func.localvars and not subs.empty? and subs.all? { |sb| sb[0] == subs.first[0] }
1346
+ func.localvars.each { |varoff, varname|
1347
+ subargnames = subs.map { |o, sb| sb[varoff-o+@size/8] }.compact
1348
+ if subargnames.uniq.length == 1
1349
+ varname.replace 'sub'+subargnames[0]
1350
+ end
1351
+ }
1352
+ end
1353
+ end
1167
1354
  end
1168
1355
  end