metasm 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -5,7 +5,5 @@
5
5
 
6
6
 
7
7
  require 'metasm/main'
8
- require 'metasm/ppc/parse'
9
- require 'metasm/ppc/encode'
10
- require 'metasm/ppc/decode'
11
- require 'metasm/ppc/decompile'
8
+ require 'metasm/cpu/bpf/decode'
9
+ require 'metasm/cpu/bpf/render'
@@ -0,0 +1,142 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/cpu/bpf/opcodes'
8
+ require 'metasm/decode'
9
+
10
+ module Metasm
11
+ class BPF
12
+ def build_bin_lookaside
13
+ opcode_list.inject({}) { |h, op| h.update op.bin => op }
14
+ end
15
+
16
+ # tries to find the opcode encoded at edata.ptr
17
+ def decode_findopcode(edata)
18
+ return if edata.ptr > edata.data.length-8
19
+ di = DecodedInstruction.new self
20
+ code = edata.data[edata.ptr, 2].unpack('v')[0]
21
+ return di if di.opcode = @bin_lookaside[code]
22
+ end
23
+
24
+ def decode_instr_op(edata, di)
25
+ op = di.opcode
26
+ di.instruction.opname = op.name
27
+ di.bin_length = 8
28
+ code, jt, jf, k = edata.read(8).unpack('vCCV')
29
+
30
+ op.args.each { |a|
31
+ di.instruction.args << case a
32
+ when :k; Expression[k]
33
+ when :x; Reg.new(:x)
34
+ when :a; Reg.new(:a)
35
+ when :len; Reg.new(:len)
36
+ when :p_k; PktRef.new(nil, Expression[k], op.props[:msz])
37
+ when :p_xk; PktRef.new(Reg.new(:x), Expression[k], op.props[:msz])
38
+ when :m_k; MemRef.new(nil, Expression[4*k], 4)
39
+ when :jt; Expression[jt]
40
+ when :jf; Expression[jf]
41
+ else raise "unhandled arg #{a}"
42
+ end
43
+ }
44
+
45
+ # je a, x, 0, 12 -> jne a, x, 12
46
+ # je a, x, 12, 0 -> je a, x, 12
47
+ if op.args[2] == :jt and di.instruction.args[2] == Expression[0]
48
+ di.opcode = op.dup
49
+ di.opcode.props.delete :stopexec
50
+ di.instruction.opname = { 'jg' => 'jle', 'jge' => 'jl', 'je' => 'jne', 'jtest' => 'jntest' }[di.instruction.opname]
51
+ di.instruction.args.delete_at(2)
52
+ elsif op.args[3] == :jf and di.instruction.args[3] == Expression[0]
53
+ di.opcode = op.dup
54
+ di.opcode.props.delete :stopexec
55
+ di.instruction.args.delete_at(3)
56
+ end
57
+
58
+ di
59
+ end
60
+
61
+ def decode_instr_interpret(di, addr)
62
+ if di.opcode.props[:setip]
63
+ delta = di.instruction.args[-1].reduce + 1
64
+ arg = Expression[addr, :+, 8*delta].reduce
65
+ di.instruction.args[-1] = Expression[arg]
66
+
67
+ if di.instruction.args.length == 4
68
+ delta = di.instruction.args[2].reduce + 1
69
+ arg = Expression[addr, :+, 8*delta].reduce
70
+ di.instruction.args[2] = Expression[arg]
71
+ end
72
+ end
73
+
74
+ di
75
+ end
76
+
77
+ # hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
78
+ def backtrace_binding
79
+ @backtrace_binding ||= init_backtrace_binding
80
+ end
81
+ def backtrace_binding=(b) @backtrace_binding = b end
82
+
83
+ # populate the @backtrace_binding hash with default values
84
+ def init_backtrace_binding
85
+ @backtrace_binding ||= {}
86
+
87
+ opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
88
+ binding = case op
89
+ when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
90
+ when 'add'; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } }
91
+ when 'sub'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } }
92
+ when 'mul'; lambda { |di, a0, a1| { a0 => Expression[a0, :*, a1] } }
93
+ when 'div'; lambda { |di, a0, a1| { a0 => Expression[a0, :/, a1] } }
94
+ when 'shl'; lambda { |di, a0, a1| { a0 => Expression[a0, :<<, a1] } }
95
+ when 'shr'; lambda { |di, a0, a1| { a0 => Expression[a0, :>>, a1] } }
96
+ when 'neg'; lambda { |di, a0| { a0 => Expression[:-, a0] } }
97
+ when 'msh'; lambda { |di, a0, a1| { a0 => Expression[[a1, :&, 0xf], :<<, 2] } }
98
+ when 'jmp', 'jg', 'jge', 'je', 'jtest', 'ret'; lambda { |di, *a| { } }
99
+ end
100
+ @backtrace_binding[op] ||= binding if binding
101
+ }
102
+
103
+ @backtrace_binding
104
+ end
105
+
106
+ def get_backtrace_binding(di)
107
+ a = di.instruction.args.map { |arg|
108
+ case arg
109
+ when PktRef, MemRef, Reg; arg.symbolic(di)
110
+ else arg
111
+ end
112
+ }
113
+
114
+ if binding = backtrace_binding[di.opcode.name]
115
+ binding[di, *a]
116
+ else
117
+ puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
118
+ {:incomplete_binding => Expression[1]}
119
+ end
120
+ end
121
+
122
+ def get_xrefs_x(dasm, di)
123
+ return [] if not di.opcode.props[:setip]
124
+
125
+ if di.instruction.args.length == 4
126
+ di.instruction.args[-2, 2]
127
+ else
128
+ di.instruction.args[-1, 1]
129
+ end
130
+ end
131
+
132
+ # updates an instruction's argument replacing an expression with another (eg label renamed)
133
+ def replace_instr_arg_immediate(i, old, new)
134
+ i.args.map! { |a|
135
+ case a
136
+ when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
137
+ else a
138
+ end
139
+ }
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,60 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/main'
8
+
9
+ module Metasm
10
+ class BPF < CPU
11
+ class Reg
12
+ attr_accessor :v
13
+ def initialize(v)
14
+ @v = v
15
+ end
16
+
17
+ def symbolic(orig=nil) ; @v ; end
18
+ end
19
+
20
+ class MemRef
21
+ attr_accessor :base, :offset, :msz
22
+
23
+ def memtype
24
+ :mem
25
+ end
26
+
27
+ def initialize(base, offset, msz)
28
+ @base = base
29
+ @offset = offset
30
+ @msz = msz
31
+ end
32
+
33
+ def symbolic(orig)
34
+ p = Expression[memtype]
35
+ p = Expression[p, :+, @base.symbolic] if base
36
+ p = Expression[p, :+, @offset] if offset
37
+ Indirection[p, @msz, orig]
38
+ end
39
+ end
40
+
41
+ class PktRef < MemRef
42
+ def memtype
43
+ :pkt
44
+ end
45
+ end
46
+
47
+ def initialize(family = :latest)
48
+ super()
49
+ @endianness = :big
50
+ @size = 32
51
+ @family = family
52
+ end
53
+
54
+ def init_opcode_list
55
+ send("init_#@family")
56
+ @opcode_list
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,81 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'metasm/cpu/bpf/main'
7
+
8
+ module Metasm
9
+
10
+ class BPF
11
+ def addop(name, bin, *args)
12
+ o = Opcode.new name, bin
13
+ args.each { |a|
14
+ o.args << a if @valid_args[a]
15
+ o.props.update a if a.kind_of?(::Hash)
16
+ }
17
+ @opcode_list << o
18
+ end
19
+
20
+ def addop_ldx(bin, src)
21
+ addop 'mov', bin | 0x00, :a, src
22
+ addop 'mov', bin | 0x01, :x, src
23
+ end
24
+
25
+ def addop_ldsz(bin, src)
26
+ addop 'mov', bin | 0x00, :a, src, :msz => 4
27
+ addop 'mov', bin | 0x08, :a, src, :msz => 2
28
+ addop 'mov', bin | 0x10, :a, src, :msz => 1
29
+ end
30
+
31
+ def addop_alu(name, bin)
32
+ addop name, bin | 0x04, :a, :k
33
+ addop name, bin | 0x0C, :a, :x
34
+ end
35
+
36
+ def addop_j(name, bin)
37
+ addop name, bin | 0x05 | 0x00, :a, :k, :jt, :jf, :setip => true, :stopexec => true
38
+ addop name, bin | 0x05 | 0x08, :a, :x, :jt, :jf, :setip => true, :stopexec => true
39
+ end
40
+
41
+ def init_bpf
42
+ @opcode_list = []
43
+ [:a, :k, :x, :len, :m_k, :p_k, :p_xk, :jt, :jf].each { |a| @valid_args[a] = true }
44
+
45
+ # LD/ST
46
+ addop_ldx 0x00, :k
47
+ addop_ldsz 0x20, :p_k
48
+ addop_ldsz 0x40, :p_xk
49
+ addop_ldx 0x60, :m_k
50
+ addop_ldx 0x80, :len
51
+ addop 'msh', 0xB1, :x, :p_k, :msz => 1
52
+ addop 'mov', 0x02, :m_k, :a
53
+ addop 'mov', 0x03, :m_k, :x
54
+
55
+ # ALU
56
+ addop_alu 'add', 0x00
57
+ addop_alu 'sub', 0x10
58
+ addop_alu 'mul', 0x20
59
+ addop_alu 'div', 0x30
60
+ addop_alu 'or', 0x40
61
+ addop_alu 'and', 0x50
62
+ addop_alu 'shl', 0x60
63
+ addop_alu 'shr', 0x70
64
+ addop 'neg', 0x84, :a
65
+
66
+ # JMP
67
+ addop 'jmp', 0x05, :k, :setip => true, :stopexec => true
68
+ addop_j 'je', 0x10
69
+ addop_j 'jg', 0x20
70
+ addop_j 'jge', 0x30
71
+ addop_j 'jtest',0x40
72
+ addop 'ret', 0x06, :k, :stopexec => true
73
+ addop 'ret', 0x16, :a, :stopexec => true
74
+
75
+ addop 'mov', 0x07, :x, :a
76
+ addop 'mov', 0x87, :a, :x
77
+ end
78
+
79
+ alias init_latest init_bpf
80
+ end
81
+ end
@@ -0,0 +1,41 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/cpu/bpf/opcodes'
8
+ require 'metasm/render'
9
+
10
+ module Metasm
11
+ class BPF
12
+ class Reg
13
+ include Renderable
14
+ def render ; [@v.to_s] end
15
+ end
16
+ class MemRef
17
+ include Renderable
18
+ def render
19
+ r = []
20
+ r << memtype
21
+ r << [nil, ' byte ', ' word ', nil, ' dword '][@msz]
22
+ r << '['
23
+ r << @base if @base
24
+ r << '+' if @base and @offset
25
+ r << @offset if @offset
26
+ r << ']'
27
+ end
28
+ end
29
+
30
+ def render_instruction(i)
31
+ r = []
32
+ r << i.opname
33
+ if not i.args.empty?
34
+ r << ' '
35
+ i.args.each { |a_| r << a_ << ', ' }
36
+ r.pop
37
+ end
38
+ r
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/main'
8
+ require 'metasm/cpu/cy16/decode'
9
+ require 'metasm/cpu/cy16/render'
@@ -0,0 +1,253 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/cpu/cy16/opcodes'
8
+ require 'metasm/decode'
9
+
10
+ module Metasm
11
+ class CY16
12
+ def build_opcode_bin_mask(op)
13
+ # bit = 0 if can be mutated by an field value, 1 if fixed by opcode
14
+ op.bin_mask = 0
15
+ op.fields.each { |f, off|
16
+ op.bin_mask |= (@fields_mask[f] << off)
17
+ }
18
+ op.bin_mask ^= 0xffff
19
+ end
20
+
21
+ def build_bin_lookaside
22
+ # sets up a hash byte value => list of opcodes that may match
23
+ # opcode.bin_mask is built here
24
+ lookaside = Array.new(256) { [] }
25
+ opcode_list.each { |op|
26
+ build_opcode_bin_mask op
27
+ b = (op.bin >> 8) & 0xff
28
+ msk = (op.bin_mask >> 8) & 0xff
29
+ for i in b..(b | (255^msk))
30
+ lookaside[i] << op if i & msk == b & msk
31
+ end
32
+ }
33
+ lookaside
34
+ end
35
+
36
+ def decode_findopcode(edata)
37
+ di = DecodedInstruction.new self
38
+ return if edata.ptr+2 > edata.length
39
+ bin = edata.decode_imm(:u16, @endianness)
40
+ edata.ptr -= 2
41
+ return di if di.opcode = @bin_lookaside[(bin >> 8) & 0xff].find { |op|
42
+ bin & op.bin_mask == op.bin & op.bin_mask
43
+ }
44
+ end
45
+
46
+
47
+ def decode_instr_op_r(val, edata)
48
+ bw = ((val & 0b1000) > 0 ? 1 : 2)
49
+ case val & 0b11_0000
50
+ when 0b00_0000
51
+ Reg.new(val)
52
+ when 0b01_0000
53
+ if val == 0b01_1111
54
+ Expression[edata.decode_imm(:u16, @endianness)]
55
+ else
56
+ Memref.new(Reg.new(8+(val&7)), nil, bw)
57
+ end
58
+ when 0b10_0000
59
+ if val & 7 == 7
60
+ Memref.new(nil, edata.decode_imm(:u16, @endianness), bw)
61
+ else
62
+ Memref.new(Reg.new(8+(val&7)), nil, bw, true)
63
+ end
64
+ when 0b11_0000
65
+ Memref.new(Reg.new(8+(val&7)), edata.decode_imm(:u16, @endianness), bw)
66
+ end
67
+
68
+ end
69
+
70
+ def decode_instr_op(edata, di)
71
+ before_ptr = edata.ptr
72
+ op = di.opcode
73
+ di.instruction.opname = op.name
74
+ bin = edata.decode_imm(:u16, @endianness)
75
+
76
+ field_val = lambda { |f|
77
+ if off = op.fields[f]
78
+ (bin >> off) & @fields_mask[f]
79
+ end
80
+ }
81
+
82
+ op.args.each { |a|
83
+ di.instruction.args << case a
84
+ when :rs, :rd; decode_instr_op_r(field_val[a], edata)
85
+ when :o7; Expression[2*Expression.make_signed(field_val[a], 7)]
86
+ when :x7; Expression[field_val[a]]
87
+ when :u3; Expression[field_val[a]+1]
88
+ else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
89
+ end
90
+ }
91
+
92
+ di.instruction.args.reverse!
93
+
94
+ di.bin_length += edata.ptr - before_ptr
95
+
96
+ di
97
+ rescue InvalidRD
98
+ end
99
+
100
+ def decode_instr_interpret(di, addr)
101
+ if di.opcode.props[:setip] and di.opcode.args.last == :o7
102
+ delta = di.instruction.args.last.reduce
103
+ arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
104
+ di.instruction.args[-1] = Expression[arg]
105
+ end
106
+
107
+ di
108
+ end
109
+
110
+ # hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
111
+ def backtrace_binding
112
+ @backtrace_binding ||= init_backtrace_binding
113
+ end
114
+ def backtrace_binding=(b) @backtrace_binding = b end
115
+
116
+ # populate the @backtrace_binding hash with default values
117
+ def init_backtrace_binding
118
+ @backtrace_binding ||= {}
119
+
120
+ mask = 0xffff
121
+
122
+ opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
123
+ binding = case op
124
+ when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
125
+ when 'add', 'adc', 'sub', 'sbc', 'and', 'xor', 'or', 'addi', 'subi'
126
+ lambda { |di, a0, a1|
127
+ e_op = { 'add' => :+, 'adc' => :+, 'sub' => :-, 'sbc' => :-, 'and' => :&,
128
+ 'xor' => :^, 'or' => :|, 'addi' => :+, 'subi' => :- }[op]
129
+ ret = Expression[a0, e_op, a1]
130
+ ret = Expression[ret, e_op, :flag_c] if op == 'adc' or op == 'sbb'
131
+ # optimises eax ^ eax => 0
132
+ # avoid hiding memory accesses (to not hide possible fault)
133
+ ret = Expression[ret.reduce] if not a0.kind_of? Indirection
134
+ { a0 => ret }
135
+ }
136
+ when 'cmp', 'test'; lambda { |di, *a| {} }
137
+ when 'not'; lambda { |di, a0| { a0 => Expression[a0, :^, mask] } }
138
+ when 'call'
139
+ lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
140
+ Indirection[:sp, 2, di.address] => Expression[di.next_addr] }
141
+ }
142
+ when 'ret'; lambda { |di, *a| { :sp => Expression[:sp, :+, 2] } }
143
+ # TODO callCC, retCC ...
144
+ when /^j/; lambda { |di, *a| {} }
145
+ end
146
+
147
+ # TODO flags ?
148
+
149
+ @backtrace_binding[op] ||= binding if binding
150
+ }
151
+ @backtrace_binding
152
+ end
153
+
154
+ def get_backtrace_binding(di)
155
+ a = di.instruction.args.map { |arg|
156
+ case arg
157
+ when Memref, Reg; arg.symbolic(di)
158
+ else arg
159
+ end
160
+ }
161
+
162
+ if binding = backtrace_binding[di.opcode.basename]
163
+ bd = {}
164
+ di.instruction.args.each { |aa| bd[aa.base.symbolic] = Expression[aa.base.symbolic, :+, aa.sz] if aa.kind_of?(Memref) and aa.autoincr }
165
+ bd.update binding[di, *a]
166
+ else
167
+ puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
168
+ # assume nothing except the 1st arg is modified
169
+ case a[0]
170
+ when Indirection, Symbol; { a[0] => Expression::Unknown }
171
+ when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
172
+ else {}
173
+ end.update(:incomplete_binding => Expression[1])
174
+ end
175
+ end
176
+
177
+ # patch a forward binding from the backtrace binding
178
+ def fix_fwdemu_binding(di, fbd)
179
+ case di.opcode.name
180
+ when 'call'; fbd[Indirection[[:sp, :-, 2], 2]] = fbd.delete(Indirection[:sp, 2])
181
+ end
182
+ fbd
183
+ end
184
+
185
+ def get_xrefs_x(dasm, di)
186
+ return [] if not di.opcode.props[:setip]
187
+
188
+ return [Indirection[:sp, 2, di.address]] if di.opcode.name =~ /^r/
189
+
190
+ case tg = di.instruction.args.first
191
+ when Memref; [Expression[tg.symbolic(di)]]
192
+ when Reg; [Expression[tg.symbolic(di)]]
193
+ when Expression, ::Integer; [Expression[tg]]
194
+ else
195
+ puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
196
+ []
197
+ end
198
+ end
199
+
200
+ # checks if expr is a valid return expression matching the :saveip instruction
201
+ def backtrace_is_function_return(expr, di=nil)
202
+ expr = Expression[expr].reduce_rec
203
+ expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp]
204
+ end
205
+
206
+ # updates the function backtrace_binding
207
+ # if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand)
208
+ def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
209
+ b = f.backtrace_binding
210
+
211
+ bt_val = lambda { |r|
212
+ next if not retaddrlist
213
+ b[r] = Expression::Unknown
214
+ bt = []
215
+ retaddrlist.each { |retaddr|
216
+ bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true,
217
+ :snapshot_addr => faddr, :origin => retaddr)
218
+ }
219
+ if bt.length != 1
220
+ b[r] = Expression::Unknown
221
+ else
222
+ b[r] = bt.first
223
+ end
224
+ }
225
+
226
+ if not wantregs.empty?
227
+ wantregs.each(&bt_val)
228
+ else
229
+ bt_val[:sp]
230
+ end
231
+
232
+ b
233
+ end
234
+
235
+ # returns true if the expression is an address on the stack
236
+ def backtrace_is_stack_address(expr)
237
+ Expression[expr].expr_externals.include?(:sp)
238
+ end
239
+
240
+ # updates an instruction's argument replacing an expression with another (eg label renamed)
241
+ def replace_instr_arg_immediate(i, old, new)
242
+ i.args.map! { |a|
243
+ case a
244
+ when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
245
+ when Memref
246
+ a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset
247
+ a
248
+ else a
249
+ end
250
+ }
251
+ end
252
+ end
253
+ end