metasm 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (276) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.gitignore +3 -0
  5. data/.hgtags +3 -0
  6. data/Gemfile +3 -0
  7. data/INSTALL +61 -0
  8. data/LICENCE +458 -0
  9. data/README +29 -21
  10. data/Rakefile +10 -0
  11. data/TODO +10 -12
  12. data/doc/code_organisation.txt +3 -1
  13. data/doc/core/DynLdr.txt +247 -0
  14. data/doc/core/ExeFormat.txt +43 -0
  15. data/doc/core/Expression.txt +220 -0
  16. data/doc/core/GNUExports.txt +27 -0
  17. data/doc/core/Ia32.txt +236 -0
  18. data/doc/core/SerialStruct.txt +108 -0
  19. data/doc/core/VirtualString.txt +145 -0
  20. data/doc/core/WindowsExports.txt +61 -0
  21. data/doc/core/index.txt +1 -0
  22. data/doc/style.css +6 -3
  23. data/doc/usage/debugger.txt +327 -0
  24. data/doc/usage/index.txt +1 -0
  25. data/doc/use_cases.txt +2 -2
  26. data/metasm.gemspec +23 -0
  27. data/{lib/metasm.rb → metasm.rb} +15 -3
  28. data/{lib/metasm → metasm}/compile_c.rb +15 -9
  29. data/metasm/cpu/arc.rb +8 -0
  30. data/metasm/cpu/arc/decode.rb +404 -0
  31. data/metasm/cpu/arc/main.rb +191 -0
  32. data/metasm/cpu/arc/opcodes.rb +588 -0
  33. data/metasm/cpu/arm.rb +14 -0
  34. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  35. data/{lib/metasm → metasm/cpu}/arm/decode.rb +15 -18
  36. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  37. data/{lib/metasm → metasm/cpu}/arm/main.rb +3 -6
  38. data/metasm/cpu/arm/opcodes.rb +324 -0
  39. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  40. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  41. data/metasm/cpu/arm64.rb +15 -0
  42. data/metasm/cpu/arm64/debug.rb +38 -0
  43. data/metasm/cpu/arm64/decode.rb +285 -0
  44. data/metasm/cpu/arm64/encode.rb +41 -0
  45. data/metasm/cpu/arm64/main.rb +105 -0
  46. data/metasm/cpu/arm64/opcodes.rb +232 -0
  47. data/metasm/cpu/arm64/parse.rb +20 -0
  48. data/metasm/cpu/arm64/render.rb +95 -0
  49. data/{lib/metasm/mips/compile_c.rb → metasm/cpu/bpf.rb} +4 -2
  50. data/metasm/cpu/bpf/decode.rb +110 -0
  51. data/metasm/cpu/bpf/main.rb +60 -0
  52. data/metasm/cpu/bpf/opcodes.rb +81 -0
  53. data/metasm/cpu/bpf/render.rb +30 -0
  54. data/{lib/metasm/ppc.rb → metasm/cpu/cy16.rb} +2 -4
  55. data/metasm/cpu/cy16/decode.rb +247 -0
  56. data/metasm/cpu/cy16/main.rb +63 -0
  57. data/metasm/cpu/cy16/opcodes.rb +78 -0
  58. data/metasm/cpu/cy16/render.rb +30 -0
  59. data/metasm/cpu/dalvik.rb +11 -0
  60. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +34 -34
  61. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +71 -4
  62. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +21 -12
  63. data/{lib/metasm/mips.rb → metasm/cpu/ebpf.rb} +3 -4
  64. data/metasm/cpu/ebpf/debug.rb +61 -0
  65. data/metasm/cpu/ebpf/decode.rb +142 -0
  66. data/metasm/cpu/ebpf/main.rb +58 -0
  67. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  68. data/metasm/cpu/ebpf/render.rb +36 -0
  69. data/metasm/cpu/ia32.rb +17 -0
  70. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +23 -9
  71. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +44 -6
  72. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +342 -128
  73. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +75 -53
  74. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  75. data/{lib/metasm → metasm/cpu}/ia32/main.rb +66 -8
  76. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  77. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +55 -17
  78. data/{lib/metasm → metasm/cpu}/ia32/render.rb +32 -5
  79. data/metasm/cpu/mcs51.rb +8 -0
  80. data/metasm/cpu/mcs51/decode.rb +99 -0
  81. data/metasm/cpu/mcs51/main.rb +87 -0
  82. data/metasm/cpu/mcs51/opcodes.rb +120 -0
  83. data/metasm/cpu/mips.rb +14 -0
  84. data/metasm/cpu/mips/debug.rb +42 -0
  85. data/{lib/metasm → metasm/cpu}/mips/decode.rb +59 -38
  86. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  87. data/{lib/metasm → metasm/cpu}/mips/main.rb +13 -6
  88. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +87 -18
  89. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  90. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  91. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  92. data/metasm/cpu/msp430/decode.rb +243 -0
  93. data/metasm/cpu/msp430/main.rb +62 -0
  94. data/metasm/cpu/msp430/opcodes.rb +101 -0
  95. data/metasm/cpu/openrisc.rb +11 -0
  96. data/metasm/cpu/openrisc/debug.rb +106 -0
  97. data/metasm/cpu/openrisc/decode.rb +182 -0
  98. data/metasm/cpu/openrisc/decompile.rb +350 -0
  99. data/metasm/cpu/openrisc/main.rb +70 -0
  100. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  101. data/metasm/cpu/openrisc/render.rb +37 -0
  102. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  103. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  104. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  105. data/metasm/cpu/ppc.rb +11 -0
  106. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -37
  107. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  108. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  109. data/{lib/metasm → metasm/cpu}/ppc/main.rb +23 -18
  110. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -6
  111. data/metasm/cpu/ppc/parse.rb +55 -0
  112. data/metasm/cpu/python.rb +8 -0
  113. data/metasm/cpu/python/decode.rb +116 -0
  114. data/metasm/cpu/python/main.rb +36 -0
  115. data/metasm/cpu/python/opcodes.rb +180 -0
  116. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  117. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +50 -23
  118. data/{lib/metasm → metasm/cpu}/sh4/main.rb +38 -27
  119. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  120. data/metasm/cpu/st20.rb +9 -0
  121. data/metasm/cpu/st20/decode.rb +173 -0
  122. data/metasm/cpu/st20/decompile.rb +283 -0
  123. data/metasm/cpu/st20/main.rb +37 -0
  124. data/metasm/cpu/st20/opcodes.rb +140 -0
  125. data/{lib/metasm/arm.rb → metasm/cpu/webasm.rb} +4 -5
  126. data/metasm/cpu/webasm/debug.rb +31 -0
  127. data/metasm/cpu/webasm/decode.rb +321 -0
  128. data/metasm/cpu/webasm/decompile.rb +386 -0
  129. data/metasm/cpu/webasm/encode.rb +104 -0
  130. data/metasm/cpu/webasm/main.rb +81 -0
  131. data/metasm/cpu/webasm/opcodes.rb +214 -0
  132. data/metasm/cpu/x86_64.rb +15 -0
  133. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +40 -25
  134. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  135. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +58 -15
  136. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +59 -28
  137. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +18 -6
  138. data/metasm/cpu/x86_64/opcodes.rb +138 -0
  139. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +12 -4
  140. data/metasm/cpu/x86_64/render.rb +35 -0
  141. data/metasm/cpu/z80.rb +9 -0
  142. data/metasm/cpu/z80/decode.rb +286 -0
  143. data/metasm/cpu/z80/main.rb +67 -0
  144. data/metasm/cpu/z80/opcodes.rb +224 -0
  145. data/metasm/cpu/z80/render.rb +48 -0
  146. data/{lib/metasm/os/main.rb → metasm/debug.rb} +201 -407
  147. data/{lib/metasm → metasm}/decode.rb +104 -24
  148. data/{lib/metasm → metasm}/decompile.rb +804 -478
  149. data/{lib/metasm → metasm}/disassemble.rb +385 -170
  150. data/{lib/metasm → metasm}/disassemble_api.rb +684 -105
  151. data/{lib/metasm → metasm}/dynldr.rb +231 -138
  152. data/{lib/metasm → metasm}/encode.rb +20 -5
  153. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  154. data/{lib/metasm → metasm}/exe_format/autoexe.rb +3 -0
  155. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  156. data/{lib/metasm → metasm}/exe_format/coff.rb +35 -7
  157. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +70 -23
  158. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +24 -22
  159. data/{lib/metasm → metasm}/exe_format/dex.rb +26 -8
  160. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  161. data/{lib/metasm → metasm}/exe_format/elf.rb +108 -58
  162. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +202 -36
  163. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +126 -32
  164. data/metasm/exe_format/gb.rb +65 -0
  165. data/metasm/exe_format/javaclass.rb +424 -0
  166. data/{lib/metasm → metasm}/exe_format/macho.rb +218 -16
  167. data/{lib/metasm → metasm}/exe_format/main.rb +28 -3
  168. data/{lib/metasm → metasm}/exe_format/mz.rb +2 -0
  169. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  170. data/{lib/metasm → metasm}/exe_format/pe.rb +96 -11
  171. data/metasm/exe_format/pyc.rb +167 -0
  172. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  173. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  174. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  175. data/metasm/exe_format/swf.rb +205 -0
  176. data/metasm/exe_format/wasm.rb +402 -0
  177. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  178. data/metasm/exe_format/zip.rb +335 -0
  179. data/metasm/gui.rb +13 -0
  180. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  181. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  182. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +177 -114
  183. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  184. data/metasm/gui/dasm_graph.rb +1754 -0
  185. data/{lib/metasm → metasm}/gui/dasm_hex.rb +16 -12
  186. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  187. data/{lib/metasm → metasm}/gui/dasm_main.rb +360 -77
  188. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  189. data/{lib/metasm → metasm}/gui/debug.rb +109 -34
  190. data/{lib/metasm → metasm}/gui/gtk.rb +174 -44
  191. data/{lib/metasm → metasm}/gui/qt.rb +14 -4
  192. data/{lib/metasm → metasm}/gui/win32.rb +180 -43
  193. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  194. data/{lib/metasm → metasm}/main.rb +421 -286
  195. data/metasm/os/emulator.rb +175 -0
  196. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  197. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  198. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  199. data/metasm/os/main.rb +335 -0
  200. data/{lib/metasm → metasm}/os/windows.rb +151 -58
  201. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  202. data/{lib/metasm → metasm}/parse.rb +49 -36
  203. data/{lib/metasm → metasm}/parse_c.rb +405 -246
  204. data/{lib/metasm → metasm}/preprocessor.rb +71 -41
  205. data/{lib/metasm → metasm}/render.rb +14 -38
  206. data/misc/hexdump.rb +4 -3
  207. data/misc/lint.rb +58 -0
  208. data/misc/objdiff.rb +4 -1
  209. data/misc/objscan.rb +1 -1
  210. data/misc/openrisc-parser.rb +79 -0
  211. data/misc/txt2html.rb +9 -7
  212. data/samples/bindiff.rb +3 -4
  213. data/samples/dasm-plugins/bindiff.rb +15 -0
  214. data/samples/dasm-plugins/bookmark.rb +133 -0
  215. data/samples/dasm-plugins/c_constants.rb +57 -0
  216. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  217. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  218. data/samples/dasm-plugins/dasm_all.rb +70 -0
  219. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  220. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  221. data/samples/dasm-plugins/dump_text.rb +35 -0
  222. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  223. data/samples/dasm-plugins/findgadget.rb +75 -0
  224. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  225. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  226. data/samples/dasm-plugins/imm2off.rb +34 -0
  227. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  228. data/samples/dasm-plugins/patch_file.rb +95 -0
  229. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  230. data/samples/dasm-plugins/scanxrefs.rb +29 -0
  231. data/samples/dasm-plugins/selfmodify.rb +197 -0
  232. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  233. data/samples/dasmnavig.rb +1 -1
  234. data/samples/dbg-apihook.rb +24 -9
  235. data/samples/dbg-plugins/heapscan.rb +283 -0
  236. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  237. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  238. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  239. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  240. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  241. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  242. data/samples/dbg-plugins/trace_func.rb +214 -0
  243. data/samples/disassemble-gui.rb +48 -7
  244. data/samples/disassemble.rb +31 -6
  245. data/samples/dump_upx.rb +24 -12
  246. data/samples/dynamic_ruby.rb +35 -27
  247. data/samples/elfencode.rb +15 -0
  248. data/samples/emubios.rb +251 -0
  249. data/samples/emudbg.rb +127 -0
  250. data/samples/exeencode.rb +6 -5
  251. data/samples/factorize-headers-peimports.rb +1 -1
  252. data/samples/lindebug.rb +186 -391
  253. data/samples/metasm-shell.rb +68 -57
  254. data/samples/peldr.rb +2 -2
  255. data/tests/all.rb +1 -1
  256. data/tests/arc.rb +26 -0
  257. data/tests/dynldr.rb +22 -4
  258. data/tests/expression.rb +57 -0
  259. data/tests/graph_layout.rb +285 -0
  260. data/tests/ia32.rb +80 -26
  261. data/tests/mcs51.rb +27 -0
  262. data/tests/mips.rb +10 -3
  263. data/tests/preprocessor.rb +18 -0
  264. data/tests/x86_64.rb +66 -18
  265. metadata +465 -219
  266. metadata.gz.sig +2 -0
  267. data/lib/metasm/arm/opcodes.rb +0 -177
  268. data/lib/metasm/gui.rb +0 -23
  269. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  270. data/lib/metasm/ia32.rb +0 -14
  271. data/lib/metasm/ia32/opcodes.rb +0 -872
  272. data/lib/metasm/ppc/parse.rb +0 -52
  273. data/lib/metasm/x86_64.rb +0 -12
  274. data/lib/metasm/x86_64/opcodes.rb +0 -118
  275. data/samples/gdbclient.rb +0 -583
  276. data/samples/rubstop.rb +0 -399
@@ -4,7 +4,7 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/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)
@@ -66,9 +66,11 @@ class Ia32
66
66
  end
67
67
  end
68
68
 
69
+ DBG_BPX = "\xcc"
70
+ DBG_BPX.force_encoding('BINARY') if DBG_BPX.respond_to?(:force_encoding)
69
71
  def dbg_enable_bpx(dbg, bp)
70
72
  bp.internal[:previous] ||= dbg.memory[bp.address, 1]
71
- dbg.memory[bp.address, 1] = "\xcc"
73
+ dbg.memory[bp.address, 1] = DBG_BPX
72
74
  end
73
75
 
74
76
  def dbg_disable_bpx(dbg, bp)
@@ -113,7 +115,7 @@ class Ia32
113
115
  if dbg[:dr6] == 0 and dbg[:dr7] == 0
114
116
  dbg[:dr7] = 0x10000 # some OS (eg Windows) only return dr6 if dr7 != 0
115
117
  end
116
- dbg[:dr6] = 0
118
+ dbg[:dr6] = 0 if dbg[:dr6] & 0x400f != 0
117
119
  end
118
120
 
119
121
  def dbg_evt_bpx(dbg, b)
@@ -189,5 +191,41 @@ class Ia32
189
191
  def dbg_func_arg_set(dbg, argnr, arg)
190
192
  dbg.memory_write_int(Expression[:esp, :+, 4*(argnr+1)], arg)
191
193
  end
194
+
195
+ def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
196
+ a = di.instruction.args.map { |aa| symbolic(aa) }
197
+
198
+ cond = case di.opcode.name
199
+ when 'jz', 'je'; dbg_ctx.get_flag(:z)
200
+ when 'jnz', 'jne'; !dbg_ctx.get_flag(:z)
201
+ when 'jo'; dbg_ctx.get_flag(:o)
202
+ when 'jno'; !dbg_ctx.get_flag(:o)
203
+ when 'js'; dbg_ctx.get_flag(:s)
204
+ when 'jns'; !dbg_ctx.get_flag(:s)
205
+ when 'jc', 'jb', 'jnae'; dbg_ctx.get_flag(:c)
206
+ when 'jnc', 'jnb', 'jae'; !dbg_ctx.get_flag(:c)
207
+ when 'jbe', 'jna'; dbg_ctx.get_flag(:c) or dbg_ctx.get_flag(:z)
208
+ when 'jnbe', 'ja'; !dbg_ctx.get_flag(:c) and !dbg_ctx.get_flag(:z)
209
+ when 'jl', 'jnge'; dbg_ctx.get_flag(:s) != dbg_ctx.get_flag(:o)
210
+ when 'jnl', 'jge'; dbg_ctx.get_flag(:s) == dbg_ctx.get_flag(:o)
211
+ when 'jle', 'jng'; dbg_ctx.get_flag(:z) or dbg_ctx.get_flag(:s) != dbg_ctx.get_flag(:o)
212
+ when 'jnle', 'jg'; !dbg_ctx.get_flag(:z) and dbg_ctx.get_flag(:s) == dbg_ctx.get_flag(:o)
213
+ when 'jp', 'jpe'; dbg_ctx.get_flag(:p)
214
+ when 'jnp', 'jpo'; !dbg_ctx.get_flag(:p)
215
+ when 'loop'; dbg_ctx[dbg_register_list[2]] != 0
216
+ when 'loopz', 'loope'; dbg_ctx[dbg_register_list[2]] != 0 and dbg_ctx.get_flag(:z)
217
+ when 'loopnz', 'loopne'; dbg_ctx[dbg_register_list[2]] != 0 and !dbg_ctx.get_flag(:z)
218
+ when 'jcxz', 'jecxz', 'jrcxz'
219
+ mask = {?c => 0xffff, ?e => 0xffff_ffff, ?r => -1}[di.opcode.name[1]]
220
+ dbg_ctx[dbg_register_list[2]] & mask == 0
221
+ else return super(di, fbd, pc_reg, dbg_ctx)
222
+ end
223
+
224
+ if cond
225
+ fbd[pc_reg] = a.last
226
+ else
227
+ fbd[pc_reg] = di.next_addr
228
+ end
229
+ end
192
230
  end
193
231
  end
@@ -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|
@@ -194,19 +206,28 @@ class Ia32
194
206
  when :reg; Reg.new field_val[a], opsz
195
207
  when :eeec; CtrlReg.new field_val[a]
196
208
  when :eeed; DbgReg.new field_val[a]
209
+ when :eeet; TstReg.new field_val[a]
197
210
  when :seg2, :seg2A, :seg3, :seg3A; SegReg.new field_val[a]
198
211
  when :regfp; FpReg.new field_val[a]
199
212
  when :regmmx; SimdReg.new field_val[a], mmxsz
200
213
  when :regxmm; SimdReg.new field_val[a], 128
214
+ when :regymm; SimdReg.new field_val[a], 256
201
215
 
202
216
  when :farptr; Farptr.decode edata, @endianness, opsz
203
217
  when :i8, :u8, :u16; Expression[edata.decode_imm(a, @endianness)]
204
218
  when :i; Expression[edata.decode_imm("#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym, @endianness)]
205
219
 
206
- when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx[:seg]
207
- when :modrm, :modrmA; ModRM.decode edata, field_val[a], @endianness, adsz, opsz, pfx[:seg]
208
- when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx[:seg], SimdReg
209
- 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)
210
231
 
211
232
  when :imm_val1; Expression[1]
212
233
  when :imm_val3; Expression[3]
@@ -220,6 +241,8 @@ class Ia32
220
241
 
221
242
  di.bin_length += edata.ptr - before_ptr
222
243
 
244
+ return false if edata.ptr > edata.length
245
+
223
246
  if op.name == 'movsx' or op.name == 'movzx'
224
247
  if di.opcode.props[:argsz] == 8
225
248
  di.instruction.args[1].sz = 8
@@ -231,9 +254,10 @@ class Ia32
231
254
  else
232
255
  di.instruction.args[0].sz = @size
233
256
  end
257
+ elsif op.name == 'crc32'
258
+ di.instruction.args[0].sz = 32
234
259
  end
235
260
 
236
- pfx.delete :seg
237
261
  case pfx.delete(:rep)
238
262
  when :nz
239
263
  if di.opcode.props[:strop]
@@ -256,7 +280,7 @@ class Ia32
256
280
  # adds the eip delta to the offset +off+ of the instruction (may be an Expression) + its bin_length
257
281
  # do not call twice on the same di !
258
282
  def decode_instr_interpret(di, addr)
259
- 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/
260
284
  delta = di.instruction.args.last.reduce
261
285
  arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
262
286
  di.instruction.args[-1] = Expression[arg]
@@ -299,17 +323,16 @@ class Ia32
299
323
  end
300
324
  end
301
325
 
302
- # hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
303
- def backtrace_binding
304
- @backtrace_binding ||= init_backtrace_binding
326
+ def opsz(di, op=nil)
327
+ if di and di.instruction.prefix and di.instruction.prefix[:opsz] and (op || di.opcode).props[:needpfx] != 0x66; 48-@size
328
+ else @size
329
+ end
305
330
  end
306
- def backtrace_binding=(b) @backtrace_binding = b end
307
331
 
308
- def opsz(di)
309
- ret = @size
310
- ret = di.opcode.props[:argsz] if di and di.opcode.props[:argsz]
311
- ret = 48 - ret if di and not di.opcode.props[:argsz] and di.instruction.prefix and di.instruction.prefix[:opsz]
312
- ret
332
+ def adsz(di, op=nil)
333
+ if di and di.instruction.prefix and di.instruction.prefix[:adsz] and (op || di.opcode).props[:needpfx] != 0x67; 48-@size
334
+ else @size
335
+ end
313
336
  end
314
337
 
315
338
  # populate the @backtrace_binding hash with default values
@@ -317,15 +340,37 @@ class Ia32
317
340
  @backtrace_binding ||= {}
318
341
 
319
342
  eax, ecx, edx, ebx, esp, ebp, esi, edi = register_symbols
343
+ ebx = ebx
320
344
 
321
345
  mask = lambda { |di| (1 << opsz(di))-1 } # 32bits => 0xffff_ffff
322
346
  sign = lambda { |v, di| Expression[[[v, :&, mask[di]], :>>, opsz(di)-1], :'!=', 0] }
323
347
 
324
348
  opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
325
349
  binding = case op
326
- when 'mov', 'movsx', 'movzx', 'movsxd', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
350
+ when 'mov', 'movzx', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
351
+ when 'movsx', 'movsxd'
352
+ lambda { |di, a0, a1|
353
+ sz1 = di.instruction.args[1].sz
354
+ sign1 = Expression[[a1, :>>, sz1-1], :&, 1]
355
+ { a0 => Expression[[a1, :|, [sign1, :*, (-1 << sz1)]], :&, mask[di]] }
356
+ }
327
357
  when 'lea'; lambda { |di, a0, a1| { a0 => a1.target } }
328
- when 'xchg'; lambda { |di, a0, a1| { a0 => Expression[a1], a1 => Expression[a0] } }
358
+ when 'xchg'; lambda { |di, a0, a1|
359
+ # specialcase xchg al, ah (conflict on eax not handled in get_backtrace_binding)
360
+ if a0.kind_of?(Expression) and a1.kind_of?(Expression) and
361
+ a0.op == :& and a0.rexpr == 255 and
362
+ a1.op == :& and a1.rexpr == 255 and
363
+ ((a0.lexpr.kind_of?(Expression) and a0.lexpr.lexpr == a1.lexpr and a0.lexpr.op == :>> and a0.lexpr.rexpr == 8) or
364
+ (a1.lexpr.kind_of?(Expression) and a1.lexpr.lexpr == a0.lexpr and a1.lexpr.op == :>> and a1.lexpr.rexpr == 8))
365
+ tgreg = a0.lexpr.kind_of?(Expression) ? a1.lexpr : a0.lexpr
366
+ invmask = (@size == 64 ? 0xffff_ffff_ffff_0000 : 0xffff_0000)
367
+ { tgreg => Expression[[tgreg, :&, invmask], :|,
368
+ [[[tgreg, :>>, 8], :&, 0x00ff], :|,
369
+ [[tgreg, :<<, 8], :&, 0xff00]]] }
370
+ else
371
+ { a0 => Expression[a1], a1 => Expression[a0] }
372
+ end
373
+ }
329
374
  when 'add', 'sub', 'or', 'xor', 'and', 'pxor', 'adc', 'sbb'
330
375
  lambda { |di, a0, a1|
331
376
  e_op = { 'add' => :+, 'sub' => :-, 'or' => :|, 'and' => :&, 'xor' => :^, 'pxor' => :^, 'adc' => :+, 'sbb' => :- }[op]
@@ -345,13 +390,28 @@ class Ia32
345
390
  lambda { |di, a0, a1|
346
391
  e_op = (op[2] == ?r ? :>> : :<<)
347
392
  inv_op = {:<< => :>>, :>> => :<< }[e_op]
348
- sz = [a1, :%, opsz(di)]
349
- isz = [[opsz(di), :-, a1], :%, opsz(di)]
393
+ operandsize = di.instruction.args[0].sz
394
+ operandmask = (1 << operandsize) - 1
395
+ sz = [a1, :%, operandsize]
396
+ isz = [[operandsize, :-, a1], :%, operandsize]
350
397
  # ror a, b => (a >> b) | (a << (32-b))
351
- { a0 => Expression[[[a0, e_op, sz], :|, [a0, inv_op, isz]], :&, mask[di]] }
398
+ { a0 => Expression[[[[a0, :&, operandmask], e_op, sz], :|, [[a0, :&, operandmask], inv_op, isz]], :&, operandmask] }
352
399
  }
353
- when 'sar', 'shl', 'sal'; lambda { |di, a0, a1| { a0 => Expression[a0, (op[-1] == ?r ? :>> : :<<), [a1, :%, [opsz(di), 32].max]] } }
400
+ when 'shl', 'sal'; lambda { |di, a0, a1| { a0 => Expression[a0, (op[-1] == ?r ? :>> : :<<), [a1, :%, [opsz(di), 32].max]] } }
401
+ when 'sar'; lambda { |di, a0, a1|
402
+ sz = [opsz(di), 32].max
403
+ a1 = [a1, :%, sz]
404
+ { a0 => Expression[[a0, :>>, a1], :|,
405
+ [[[mask[di], :*, sign[a0, di]], :<<, [sz, :-, a1]], :&, mask[di]]] } }
354
406
  when 'shr'; lambda { |di, a0, a1| { a0 => Expression[[a0, :&, mask[di]], :>>, [a1, :%, opsz(di)]] } }
407
+ when 'shrd'
408
+ lambda { |di, a0, a1, a2|
409
+ { a0 => Expression[[a0, :>>, [a2, :%, opsz(di)]], :|, [a1, :<<, [[opsz(di), :-, a2], :%, opsz(di)]]] }
410
+ }
411
+ when 'shld'
412
+ lambda { |di, a0, a1, a2|
413
+ { a0 => Expression[[a0, :<<, [a2, :%, opsz(di)]], :|, [a1, :>>, [[opsz(di), :-, a2], :%, opsz(di)]]] }
414
+ }
355
415
  when 'cwd', 'cdq', 'cqo'; lambda { |di| { Expression[edx, :&, mask[di]] => Expression[mask[di], :*, sign[eax, di]] } }
356
416
  when 'cbw', 'cwde', 'cdqe'; lambda { |di|
357
417
  o2 = opsz(di)/2 ; m2 = (1 << o2) - 1
@@ -362,7 +422,7 @@ class Ia32
362
422
  when 'pop'
363
423
  lambda { |di, a0| { esp => Expression[esp, :+, opsz(di)/8],
364
424
  a0 => Indirection[esp, opsz(di)/8, di.address] } }
365
- when 'pushfd'
425
+ when 'pushfd', 'pushf', 'pushfq'
366
426
  # TODO Unknown per bit
367
427
  lambda { |di|
368
428
  efl = Expression[0x202]
@@ -372,12 +432,12 @@ class Ia32
372
432
  bts[7, :eflag_s]
373
433
  bts[11, :eflag_o]
374
434
  { esp => Expression[esp, :-, opsz(di)/8], Indirection[esp, opsz(di)/8, di.address] => efl }
375
- }
376
- when 'popfd'
435
+ }
436
+ when 'popfd', 'popf', 'popfq'
377
437
  lambda { |di| bt = lambda { |pos| Expression[[Indirection[esp, opsz(di)/8, di.address], :>>, pos], :&, 1] }
378
438
  { esp => Expression[esp, :+, opsz(di)/8], :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7], :eflag_o => bt[11] } }
379
439
  when 'sahf'
380
- lambda { |di| bt = lambda { |pos| Expression[[eax, :>>, pos], :&, 1] }
440
+ lambda { |di| bt = lambda { |pos| Expression[[eax, :>>, 8+pos], :&, 1] }
381
441
  { :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7] } }
382
442
  when 'lahf'
383
443
  lambda { |di|
@@ -386,7 +446,7 @@ class Ia32
386
446
  bts[0, :eflag_c] #bts[2, :eflag_p] #bts[4, :eflag_a]
387
447
  bts[6, :eflag_z]
388
448
  bts[7, :eflag_s]
389
- { eax => efl }
449
+ { Expression[[eax, :>>, 8], :&, 0xff] => efl }
390
450
  }
391
451
  when 'pushad'
392
452
  lambda { |di|
@@ -411,9 +471,25 @@ class Ia32
411
471
  ret
412
472
  }
413
473
  when 'call'
414
- lambda { |di, a0| { esp => Expression[esp, :-, opsz(di)/8],
415
- Indirection[esp, opsz(di)/8, di.address] => Expression[di.next_addr] } }
474
+ lambda { |di, a0|
475
+ sz = opsz(di)/8
476
+ if a0.kind_of? Farptr
477
+ { esp => Expression[esp, :-, 2*sz],
478
+ Indirection[esp, sz, di.address] => Expression[di.next_addr],
479
+ Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown }
480
+ else
481
+ { esp => Expression[esp, :-, sz],
482
+ Indirection[esp, sz, di.address] => Expression[di.next_addr] }
483
+ end
484
+ }
485
+ when 'callf'
486
+ lambda { |di, a0|
487
+ sz = opsz(di)/8
488
+ { esp => Expression[esp, :-, 2*sz],
489
+ Indirection[esp, sz, di.address] => Expression[di.next_addr],
490
+ Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown } }
416
491
  when 'ret'; lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/8, :+, a[0] || 0]] } }
492
+ when 'retf';lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/4, :+, a[0] || 0]] } }
417
493
  when 'loop', 'loopz', 'loopnz'; lambda { |di, a0| { ecx => Expression[ecx, :-, 1] } }
418
494
  when 'enter'
419
495
  lambda { |di, a0, a1|
@@ -426,7 +502,7 @@ class Ia32
426
502
  (1..depth).each { |i|
427
503
  b[Indirection[[esp, :+, a0.reduce+i*sz], sz, di.address]] =
428
504
  b[Indirection[[ebp, :-, i*sz], sz, di.address]] =
429
- Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
505
+ Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
430
506
  }
431
507
  b
432
508
  }
@@ -434,22 +510,47 @@ class Ia32
434
510
  when 'aaa'; lambda { |di| { eax => Expression::Unknown, :incomplete_binding => Expression[1] } }
435
511
  when 'imul'
436
512
  lambda { |di, *a|
437
- # 1 operand form == same as 'mul' (ax:dx stuff)
438
- next { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } if not a[1]
513
+ if not a[1]
514
+ # 1 operand from: store result in edx:eax
515
+ bd = {}
516
+ m = mask[di]
517
+ s = opsz(di)
518
+ e = Expression[Expression.make_signed(Expression[a[0], :&, m], s), :*, Expression.make_signed(Expression[eax, :&, m], s)]
519
+ if s == 8
520
+ bd[Expression[eax, :&, 0xffff]] = e
521
+ else
522
+ bd[Expression[eax, :&, m]] = Expression[e, :&, m]
523
+ bd[Expression[edx, :&, m]] = Expression[[e, :>>, opsz(di)], :&, m]
524
+ end
525
+ # XXX eflags?
526
+ next bd
527
+ end
439
528
 
440
529
  if a[2]; e = Expression[a[1], :*, a[2]]
441
530
  else e = Expression[[a[0], :*, a[1]], :&, (1 << (di.instruction.args.first.sz || opsz(di))) - 1]
442
531
  end
443
532
  { a[0] => e }
444
533
  }
445
- when 'mul', 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
534
+ when 'mul'
535
+ lambda { |di, *a|
536
+ m = mask[di]
537
+ e = Expression[a, :*, [eax, :&, m]]
538
+ if opsz(di) == 8
539
+ { Expression[eax, :&, 0xffff] => e }
540
+ else
541
+ { Expression[eax, :&, m] => Expression[e, :&, m],
542
+ Expression[edx, :&, m] => Expression[[e, :>>, opsz(di)], :&, m] }
543
+ end
544
+ }
545
+ when 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
446
546
  when 'rdtsc'; lambda { |di| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
447
- when /^(stos|movs|lods|scas|cmps)[bwd]$/
448
- lambda { |di|
449
- op =~ /^(stos|movs|lods|scas|cmps)([bwd])$/
547
+ when /^(stos|movs|lods|scas|cmps)[bwdq]$/
548
+ lambda { |di, *a|
549
+ next {:incomplete_binding => 1} if di.opcode.args.include?(:regxmm) # XXX movsd xmm0, xmm1...
550
+ op =~ /^(stos|movs|lods|scas|cmps)([bwdq])$/
450
551
  e_op = $1
451
- sz = { 'b' => 1, 'w' => 2, 'd' => 4 }[$2]
452
- eax_ = Reg.new(0, 8*sz).symbolic
552
+ sz = { 'b' => 1, 'w' => 2, 'd' => 4, 'q' => 8 }[$2]
553
+ eax_ = self.class::Reg.new(0, 8*sz).symbolic
453
554
  dir = :+
454
555
  if di.block and (di.block.list.find { |ddi| ddi.opcode.name == 'std' } rescue nil)
455
556
  dir = :-
@@ -476,7 +577,7 @@ class Ia32
476
577
  end
477
578
  when 'scas'
478
579
  case pfx[:rep]
479
- when nil; { edi => Expression[edi, dir, sz] }
580
+ when nil; { edi => Expression[edi, dir, sz], :eflag_z => Expression[pedi, :==, Expression[eax, :&, (1 << (sz*8))-1]] }
480
581
  else { edi => Expression::Unknown, ecx => Expression::Unknown }
481
582
  end
482
583
  when 'cmps'
@@ -505,7 +606,7 @@ class Ia32
505
606
  ret
506
607
  }
507
608
  when 'fstenv', 'fnstenv'
508
- lambda { |di, a0|
609
+ lambda { |di, a0|
509
610
  # stores the address of the last non-control fpu instr run
510
611
  lastfpuinstr = di.block.list[0...di.block.list.index(di)].reverse.find { |pdi|
511
612
  case pdi.opcode.name
@@ -534,7 +635,8 @@ class Ia32
534
635
  a0 => Expression[a0, :^, [1, :<<, [a1, :%, opsz(di)]]] } }
535
636
  when 'bswap'
536
637
  lambda { |di, a0|
537
- if opsz(di) == 64
638
+ case opsz(di)
639
+ when 64
538
640
  { a0 => Expression[
539
641
  [[[[a0, :&, 0xff000000_00000000], :>>, 56], :|,
540
642
  [[a0, :&, 0x00ff0000_00000000], :>>, 40]], :|,
@@ -544,14 +646,35 @@ class Ia32
544
646
  [[a0, :&, 0x00000000_00ff0000], :<<, 24]], :|,
545
647
  [[[a0, :&, 0x00000000_0000ff00], :<<, 40], :|,
546
648
  [[a0, :&, 0x00000000_000000ff], :<<, 56]]]] }
547
- else # XXX opsz != 32 => undef
649
+ when 32
548
650
  { a0 => Expression[
549
651
  [[[a0, :&, 0xff000000], :>>, 24], :|,
550
652
  [[a0, :&, 0x00ff0000], :>>, 8]], :|,
551
653
  [[[a0, :&, 0x0000ff00], :<<, 8], :|,
552
654
  [[a0, :&, 0x000000ff], :<<, 24]]] }
655
+ when 16
656
+ # bswap ax => mov ax, 0
657
+ { a0 => 0 }
553
658
  end
554
659
  }
660
+ when 'movdqa', 'movdqu', 'movaps', 'movups'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
661
+ when 'cmpxchg'; lambda { |di, a0, a1| # eax == a0 ? a0 <= a1, zf <= 1 : eax <= a0, zf <= 0
662
+ eax_ = self.class::Reg.new(0, opsz(di)).symbolic
663
+ cmp = Expression[eax_, :==, a0]
664
+ { :eflag_z => cmp,
665
+ eax_ => Expression[[cmp, :*, eax_], :|, [[1, :-, cmp], :*, a0]],
666
+ a0 => Expression[[cmp, :*, a1], :|, [[1, :-, cmp], :*, a0]] } }
667
+ when 'cmpxchg8b', 'cmpxchg16b'; lambda { |di, a0| # edx:eax == mem ? mem <= ecx:ebx, zf <= 1 : edx:eax <= mem, zf <= 0
668
+ sz = (di.opcode.name =~ /8b/ ? 32 : 64)
669
+ eax_ = self.class::Reg.new(0, sz).symbolic
670
+ ecx_ = self.class::Reg.new(1, sz).symbolic
671
+ edx_ = self.class::Reg.new(2, sz).symbolic
672
+ ebx_ = self.class::Reg.new(3, sz).symbolic
673
+ cmp = Expression[[[edx_, :<<, sz], :|, eax_], :==, a0]
674
+ { :eflag_z => cmp,
675
+ eax_ => Expression[[cmp, :*, eax_], :|, [[1, :-, cmp], :*, [a0, :&, (1 << sz) - 1]]],
676
+ edx_ => Expression[[cmp, :*, edx_], :|, [[1, :-, cmp], :*, [a0, :>>, sz]]],
677
+ a0 => Expression[[cmp, :*, [[ecx_, :<<, sz], :|, ebx_]], :|, [[1, :-, cmp], :*, a0]] } }
555
678
  when 'nop', 'pause', 'wait', 'cmp', 'test'; lambda { |di, *a| {} }
556
679
  end
557
680
 
@@ -579,7 +702,7 @@ class Ia32
579
702
  end
580
703
  ret
581
704
  }
582
- when 'inc', 'dec', 'neg', 'shl', 'shr', 'sar', 'ror', 'rol', 'rcr', 'rcl', 'shld', 'shrd'
705
+ when 'inc', 'dec', 'neg', 'shl', 'shr', 'sal', 'sar', 'ror', 'rol', 'rcr', 'rcl', 'shld', 'shrd'
583
706
  lambda { |di, a0, *a|
584
707
  ret = (binding ? binding[di, a0, *a] : {})
585
708
  res = ret[a0] || Expression::Unknown
@@ -588,6 +711,8 @@ class Ia32
588
711
  case op
589
712
  when 'neg'; ret[:eflag_c] = Expression[[res, :&, mask[di]], :'!=', 0]
590
713
  when 'inc', 'dec' # don't touch carry flag
714
+ when 'shr', 'sar', 'shrd'; ret[:eflag_c] = Expression[[a0, :>>, [a[0], :-, 1]], :&, 1] # XXX shr 0 => no touch flag
715
+ when 'shl', 'sal', 'shld'; ret[:eflag_c] = Expression[[a0, :>>, [di.instruction.args[0].sz, :-, a[0]]], :&, 1]
591
716
  else ret[:eflag_c] = Expression::Unknown # :incomplete_binding ?
592
717
  end
593
718
  ret[:eflag_o] = case op
@@ -601,7 +726,11 @@ class Ia32
601
726
  when 'imul', 'mul', 'idiv', 'div', /^(scas|cmps)[bwdq]$/
602
727
  lambda { |di, *a|
603
728
  ret = (binding ? binding[di, *a] : {})
604
- ret[:eflag_z] = ret[:eflag_s] = ret[:eflag_c] = ret[:eflag_o] = Expression::Unknown # :incomplete_binding ?
729
+ ret[:eflag_z] ||= Expression::Unknown
730
+ ret[:eflag_s] ||= Expression::Unknown
731
+ ret[:eflag_c] ||= Expression::Unknown
732
+ ret[:eflag_o] ||= Expression::Unknown
733
+ # :incomplete_binding ?
605
734
  ret
606
735
  }
607
736
  end
@@ -611,8 +740,8 @@ class Ia32
611
740
  @backtrace_binding
612
741
  end
613
742
 
614
- # returns the condition (bool Expression) under which a conditionnal jump is taken
615
- # returns nil if not a conditionnal jump
743
+ # returns the condition (bool Expression) under which a conditional jump is taken
744
+ # returns nil if not a conditional jump
616
745
  # backtrace for the condition must include the jump itself (eg loop -> ecx--)
617
746
  def get_jump_condition(di)
618
747
  ecx = register_symbols[1]
@@ -627,12 +756,7 @@ class Ia32
627
756
  end
628
757
 
629
758
  def get_backtrace_binding(di)
630
- a = di.instruction.args.map { |arg|
631
- case arg
632
- when ModRM, Reg, SimdReg; arg.symbolic(di)
633
- else arg
634
- end
635
- }
759
+ a = di.instruction.args.map { |arg| symbolic(arg, di) }
636
760
 
637
761
  if binding = backtrace_binding[di.opcode.basename]
638
762
  bd = binding[di, *a]
@@ -674,6 +798,40 @@ class Ia32
674
798
  end
675
799
  end
676
800
 
801
+ # patch a forward binding from the backtrace binding
802
+ # fixes fwdemu for push/pop/call/ret
803
+ def fix_fwdemu_binding(di, fbd)
804
+ if di.instruction.args.grep(ModRM).find { |m| m.seg and m.symbolic(di).target.lexpr =~ /^segment_base_/ }
805
+ fbd = fbd.dup
806
+ fbd[:incomplete_binding] = Expression[1]
807
+ end
808
+
809
+ case di.opcode.name
810
+ when /^push/, 'call'
811
+ ori = fbd
812
+ fbd = {}
813
+ sz = opsz(di)/8
814
+ esp = register_symbols[4]
815
+ if ori[esp] and ori[Indirection[esp, sz]]
816
+ ori.each { |k, v|
817
+ if k.kind_of?(Indirection)
818
+ fbd[k.bind(esp => ori[esp]).reduce_rec] = v
819
+ else
820
+ fbd[k] = v
821
+ end
822
+ }
823
+ else
824
+ fbd = ori.dup
825
+ fbd[:incomplete_binding] = Expression[1] # TODO
826
+ end
827
+ when /^pop/, 'ret' # nothing to do
828
+ when /^(push|pop|call|ret|enter|leave|stos|movs|lods|scas|cmps)/
829
+ fbd = fbd.dup
830
+ fbd[:incomplete_binding] = Expression[1] # TODO
831
+ end
832
+ fbd
833
+ end
834
+
677
835
  def get_xrefs_x(dasm, di)
678
836
  return [] if not di.opcode.props[:setip]
679
837
 
@@ -681,9 +839,8 @@ class Ia32
681
839
  case di.opcode.basename
682
840
  when 'ret'; return [Indirection[register_symbols[4], sz/8, di.address]]
683
841
  when 'jmp', 'call'
684
- a = di.instruction.args.first
685
- 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)
686
- return get_xrefs_x_jmptable(dasm, di, a, sz)
842
+ if dasm and not di.instruction.args.first.kind_of?(Expression) and switch_table = get_xrefs_x_jmptable(dasm, di)
843
+ return switch_table
687
844
  end
688
845
  end
689
846
 
@@ -695,57 +852,57 @@ class Ia32
695
852
  when Expression, ::Integer; [Expression[tg]]
696
853
  when Farptr; tg.seg.reduce < 0x30 ? [tg.addr] : [Expression[[tg.seg, :*, 0x10], :+, tg.addr]]
697
854
  else
698
- puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
855
+ puts "unhandled setip at #{Expression[di.address]} #{di.instruction}" if $DEBUG
699
856
  []
700
857
  end
701
858
  end
702
859
 
703
- # we detected a jmp table (jmp [base+4*idx])
704
- # try to return an accurate dest list
705
- def get_xrefs_x_jmptable(dasm, di, mrm, sz)
706
- # include the symbolic dest for backtrack stuff
707
- ret = [Expression[mrm.symbolic(di)]]
708
- i = mrm.i
709
- if di.block.list.length == 2 and di.block.list[0].opcode.name =~ /^mov/ and a0 = di.block.list[0].instruction.args[0] and
710
- a0.respond_to? :symbolic and a0.symbolic == i.symbolic
711
- i = di.block.list[0].instruction.args[1]
712
- end
713
- pb = di.block.from_normal.to_a
714
- if pb.length == 1 and pdi = dasm.decoded[pb[0]] and pdi.opcode.name =~ /^jn?be?/ and ppdi = pdi.block.list[-2] and ppdi.opcode.name == 'cmp' and
715
- ppdi.instruction.args[0].symbolic == i.symbolic and lim = Expression[ppdi.instruction.args[1]].reduce and lim.kind_of? Integer
716
- # cmp eax, 42 ; jbe switch ; switch: jmp [base+4*eax]
717
- s = dasm.get_section_at(mrm.imm)
718
- lim += 1 if pdi.opcode.name[-1] == ?e
719
- lim.times { |v|
720
- dasm.add_xref(s[1]+s[0].ptr, Xref.new(:r, di.address, sz/8))
721
- ret << Indirection[[mrm.imm, :+, v*sz/8], sz/8, di.address]
722
- s[0].read(sz/8)
860
+ # indirect call, try to match a switch table pattern (eg jmp [base+4*idx])
861
+ # return a list of target addresses if found, nil otherwise
862
+ def get_xrefs_x_jmptable(dasm, di)
863
+ puts "search jmptable for #{Expression[di.address]} #{di.instruction}" if $DEBUG
864
+ arg0 = di.instruction.args.first.symbolic(di)
865
+
866
+ bt_log = []
867
+ dasm.backtrace(arg0, di.address, :maxdepth => 3, :log => bt_log)
868
+
869
+ expr = nil
870
+ index = nil
871
+ index_max = nil
872
+
873
+ bt_log.each { |btl|
874
+ next if btl[0] != :up
875
+ last = dasm.di_at(btl[4])
876
+ break if not last or last.block.to_normal.length > 2
877
+ next if last.block.to_normal.length != 2
878
+ # search cmp eax, 42 ; ja too_big ; jmp [base+4*eax]
879
+ # XXX 256 cases switch => no cmp...
880
+ prelast = last.block.list.reverse.find { |pl| pl.opcode.name == 'cmp' }
881
+ break unless prelast and cmp_value = prelast.instruction.args.last and cmp_value.kind_of?(Expression) and cmp_value.reduce.kind_of?(::Integer)
882
+ cmp_value = cmp_value.reduce % (1 << prelast.instruction.args.first.sz) # cmp al, -12h ; jnbe => -12h is unsigned 0eeh
883
+ index = prelast.instruction.args.first.symbolic(prelast)
884
+ index = index.externals.first if index.kind_of?(Expression) # cmp bl, 13 => ebx
885
+ expr = Expression[btl[1], :&, ((1 << @size) - 1)] # XXX without the mask, additions may overflow (this breaks elsewhere too, need Expr32)
886
+ (expr.externals.grep(Symbol) - [index]).uniq.each { |r|
887
+ rv = dasm.backtrace(r, prelast.address, :maxdepth => 3)
888
+ expr = expr.bind(r => rv[0]) if rv.length == 1
723
889
  }
724
- l = dasm.auto_label_at(mrm.imm, 'jmp_table', 'xref')
725
- replace_instr_arg_immediate(di.instruction, mrm.imm, Expression[l])
726
- return ret
727
- end
728
-
729
- puts "unrecognized jmp table pattern, using wild guess for #{di}" if $VERBOSE
730
- di.add_comment 'wildguess'
731
- if s = dasm.get_section_at(mrm.imm - 3*sz/8)
732
- v = -3
733
- else
734
- s = dasm.get_section_at(mrm.imm)
735
- v = 0
736
- end
737
- loop do
738
- ptr = dasm.normalize s[0].decode_imm("u#{sz}".to_sym, @endianness)
739
- diff = Expression[ptr, :-, di.address].reduce
740
- if (diff.kind_of? ::Integer and diff.abs < 4096) or (di.opcode.basename == 'call' and ptr != 0 and dasm.get_section_at(ptr))
741
- dasm.add_xref(s[1]+s[0].ptr-sz/8, Xref.new(:r, di.address, sz/8))
742
- ret << Indirection[[mrm.imm, :+, v*sz/8], sz/8, di.address]
743
- elsif v > 0
744
- break
890
+ cmp_value = prelast.instruction.args.last.reduce % (1 << prelast.instruction.args.first.sz)
891
+ case last.opcode.name
892
+ when 'jae', 'jb', 'jnae', 'jnb'; index_max = cmp_value-1
893
+ when 'ja', 'jbe', 'jna', 'jnbe'; index_max = cmp_value
894
+ else; expr = nil
745
895
  end
746
- v += 1
896
+ break
897
+ }
898
+
899
+ if expr and expr.externals.grep(Symbol).uniq == [index]
900
+ # yay !
901
+ # include the symbolic dest for backtrace stuff
902
+ puts "found jmptable for #{Expression[di.address]} #{di.instruction} (#{index_max+1} entries)" if $VERBOSE
903
+ # TODO add labels / tables / xrefs etc
904
+ [Expression[arg0]] + (0..index_max).map { |i| expr.bind(index => i) }
747
905
  end
748
- ret
749
906
  end
750
907
 
751
908
  # checks if expr is a valid return expression matching the :saveip instruction
@@ -1087,11 +1244,15 @@ class Ia32
1087
1244
  # the binding will not include memory access from subfunctions
1088
1245
  # entry should be an entrypoint of the disassembler if finish is nil
1089
1246
  # the code sequence must have only one end, with no to_normal
1090
- def code_binding(dasm, entry, finish=nil)
1247
+ # options:
1248
+ # :include_flags => include EFLAGS in the returned binding
1249
+ def code_binding(dasm, entry, finish=nil, nargs={})
1250
+ include_flags = nargs.delete :include_flags
1251
+
1091
1252
  entry = dasm.normalize(entry)
1092
1253
  finish = dasm.normalize(finish) if finish
1093
1254
  lastdi = nil
1094
- binding = {}
1255
+ bd = {}
1095
1256
  bt = lambda { |from, expr, inc_start|
1096
1257
  ret = dasm.backtrace(Expression[expr], from, :snapshot_addr => entry, :include_start => inc_start)
1097
1258
  ret.length == 1 ? ret.first : Expression::Unknown
@@ -1116,7 +1277,7 @@ class Ia32
1116
1277
  get_xrefs_w(dasm, di).each { |waddr, len|
1117
1278
  # we want the ptr expressed with reg values at entry
1118
1279
  ptr = bt[a, waddr, false]
1119
- binding[Indirection[ptr, len, a]] = bt[a, Indirection[waddr, len, a], true]
1280
+ bd[Indirection[ptr, len, a]] = bt[a, Indirection[waddr, len, a], true]
1120
1281
  }
1121
1282
  false
1122
1283
  end
@@ -1139,13 +1300,13 @@ class Ia32
1139
1300
  if lastdi.opcode.props[:setip]
1140
1301
  e = get_xrefs_x(dasm, lastdi)
1141
1302
  raise 'bad code_binding ending' if e.to_a.length != 1 or not lastdi.opcode.props[:stopexec]
1142
- binding[:ip] = bt[lastdi.address, e.first, false]
1303
+ bd[:ip] = bt[lastdi.address, e.first, false]
1143
1304
  elsif not lastdi.opcode.props[:stopexec]
1144
- binding[:ip] = lastdi.next_addr
1305
+ bd[:ip] = lastdi.next_addr
1145
1306
  end
1146
1307
  end
1147
1308
  end
1148
- binding.delete_if { |k, v| Expression[k] == Expression[v] }
1309
+ bd.delete_if { |k, v| Expression[k] == Expression[v] }
1149
1310
 
1150
1311
  # add register binding
1151
1312
  raise "no code_binding end" if not lastdi and not finish
@@ -1158,10 +1319,63 @@ class Ia32
1158
1319
  mask = 0xffff_ffff # dont use 1<<@size, because 16bit code may use e.g. edi (through opszoverride)
1159
1320
  mask = 0xffff_ffff_ffff_ffff if @size == 64
1160
1321
  val = Expression[val, :&, mask].reduce
1161
- binding[reg] = Expression[val]
1322
+ bd[reg] = Expression[val]
1162
1323
  }
1163
1324
 
1164
- binding
1325
+ # add EFLAGS binding
1326
+ if include_flags
1327
+ [:eflag_z, :eflag_s, :eflag_c, :eflag_o].each { |eflag|
1328
+ val =
1329
+ if lastdi; bt[lastdi.address, eflag, true]
1330
+ else bt[finish, eflag, false]
1331
+ end
1332
+ next if val == Expression[eflag]
1333
+ bd[eflag] = Expression[val.reduce]
1334
+ }
1335
+ end
1336
+
1337
+ bd
1338
+ end
1339
+
1340
+ # trace the stack pointer register across a function, rename occurences of esp+XX to esp+var_XX
1341
+ def name_local_vars(dasm, funcaddr)
1342
+ esp = register_symbols[4]
1343
+ func = dasm.function[funcaddr]
1344
+ subs = []
1345
+ dasm.trace_function_register(funcaddr, esp => 0) { |di, r, off, trace|
1346
+ next if r.to_s =~ /flag/
1347
+ if di.opcode.name == 'call' and tf = di.block.to_normal.find { |t| dasm.function[t] and dasm.function[t].localvars }
1348
+ subs << [trace[esp], dasm.function[tf].localvars]
1349
+ end
1350
+ di.instruction.args.grep(ModRM).each { |mrm|
1351
+ b = mrm.b || (mrm.i if mrm.s == 1)
1352
+ # its a modrm => b is read, so ignore r/off (not yet applied), use trace only
1353
+ stackoff = trace[b.symbolic] if b
1354
+ next if not stackoff
1355
+ imm = mrm.imm || Expression[0]
1356
+ frameoff = imm + stackoff
1357
+ if frameoff.kind_of?(::Integer)
1358
+ # XXX register args ? non-ABI standard register args ? (eg optimized x64)
1359
+ str = 'var_%X' % (-frameoff)
1360
+ str = 'arg_%X' % (frameoff-@size/8) if frameoff > 0
1361
+ str = func.get_localvar_stackoff(frameoff, di, str) if func
1362
+ imm = imm.expr if imm.kind_of?(ExpressionString)
1363
+ mrm.imm = ExpressionString.new(imm, str, :stackvar)
1364
+ end
1365
+ }
1366
+ off = off.reduce if off.kind_of?(Expression)
1367
+ next unless off.kind_of?(Integer)
1368
+ off
1369
+ }
1370
+ # if subfunctions are called at a fixed stack offset, rename var_3c -> subarg_0
1371
+ if func and func.localvars and not subs.empty? and subs.all? { |sb| sb[0] == subs.first[0] }
1372
+ func.localvars.each { |varoff, varname|
1373
+ subargnames = subs.map { |o, sb| sb[varoff-o+@size/8] }.compact
1374
+ if subargnames.uniq.length == 1
1375
+ varname.replace 'sub'+subargnames[0]
1376
+ end
1377
+ }
1378
+ end
1165
1379
  end
1166
1380
  end
1167
1381
  end