metasm 1.0.1 → 1.0.2

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