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
@@ -42,7 +42,7 @@ class ExeFormat
42
42
  edata
43
43
  end
44
44
 
45
- # chose among multiple possible sub-EncodedData
45
+ # choose among multiple possible sub-EncodedData
46
46
  # assumes all ambiguous edata have the equivallent relocations in the same order
47
47
  def assemble_resolve(ary)
48
48
  startlabel = new_label('section_start')
@@ -167,7 +167,7 @@ class ExeFormat
167
167
  # for linear expressions of internal variables (ie differences of labels from the ary):
168
168
  # - calc target numeric bounds, and reject relocs not accepting worst case value
169
169
  # - else reject all but largest place available
170
- # then chose the shortest overall EData left
170
+ # then choose the shortest overall EData left
171
171
  ary.map! { |elem|
172
172
  case elem
173
173
  when Array
@@ -214,8 +214,14 @@ class ExeFormat
214
214
 
215
215
  raise EncodeError, "cannot find candidate in #{elem.inspect}, immediate too big #{wantsize.inspect} #{target_bounds.inspect}" if acceptable.empty?
216
216
 
217
- # keep the shortest
218
- acceptable.sort_by { |edata| edata.virtsize }.first
217
+ # keep the shortest, use a hack make sort consistent in all cases
218
+ # see https://8thlight.com/blog/will-warner/2013/03/26/stable-sorting-in-ruby.html
219
+ n = 0
220
+ mod_map = acceptable.map { |edata| n += 1 ; [[edata.virtsize, n], edata] }
221
+ interm_sort = mod_map.sort { |left, right| left[0] <=> right[0] }
222
+ mod_sort_result = interm_sort.collect { |edata| edata[1] }
223
+ result = mod_sort_result.first
224
+ result
219
225
  else
220
226
  elem
221
227
  end
@@ -271,7 +277,16 @@ class Expression
271
277
  def encode(type, endianness, backtrace=nil)
272
278
  case val = reduce
273
279
  when Integer; EncodedData.new Expression.encode_imm(val, type, endianness, backtrace)
274
- else EncodedData.new([0].pack('C')*(INT_SIZE[type]/8), :reloc => {0 => Relocation.new(self, type, endianness, backtrace)})
280
+ else
281
+ str = case INT_SIZE[type]
282
+ when 8; "\0"
283
+ when 16; "\0\0"
284
+ when 32; "\0\0\0\0"
285
+ when 64; "\0\0\0\0\0\0\0\0"
286
+ else [0].pack('C')*(INT_SIZE[type]/8)
287
+ end
288
+ str = str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
289
+ EncodedData.new(str, :reloc => {0 => Relocation.new(self, type, endianness, backtrace)})
275
290
  end
276
291
  end
277
292
 
@@ -58,7 +58,7 @@ class AOut < ExeFormat
58
58
  class Relocation < SerialStruct
59
59
  word :address
60
60
  bitfield :word, 0 => :symbolnum, 24 => :pcrel, 25 => :length,
61
- 27 => :extern, 28 => :baserel, 29 => :jmptable, 30 => :relative, 31 => :rtcopy
61
+ 27 => :extern, 28 => :baserel, 29 => :jmptable, 30 => :relative, 31 => :rtcopy
62
62
  fld_enum :length, 0 => 1, 1 => 2, 2 => 4, 3 => 8
63
63
  fld_default :length, 4
64
64
  end
@@ -68,7 +68,7 @@ class AOut < ExeFormat
68
68
  bitfield :byte, 0 => :extern, 1 => :type, 5 => :stab
69
69
  byte :other
70
70
  half :desc
71
- word :value
71
+ word :value
72
72
  attr_accessor :name
73
73
 
74
74
  def decode(aout, strings=nil)
@@ -93,6 +93,9 @@ class AOut < ExeFormat
93
93
  def encode_byte(w) Expression[w].encode(:u8 , @endianness) end
94
94
  def encode_half(w) Expression[w].encode(:u16, @endianness) end
95
95
  def encode_word(w) Expression[w].encode(:u32, @endianness) end
96
+ def sizeof_byte ; 1 ; end
97
+ def sizeof_half ; 2 ; end
98
+ def sizeof_word ; 4 ; end
96
99
 
97
100
  def initialize(cpu = nil)
98
101
  @endianness = cpu ? cpu.endianness : :little
@@ -119,11 +122,11 @@ class AOut < ExeFormat
119
122
 
120
123
  @data = EncodedData.new << @encoded.read(@header.data)
121
124
 
122
- textrel = @encoded.read @header.trsz
123
- datarel = @encoded.read @header.drsz
124
- syms = @encoded.read @header.syms
125
- strings = @encoded.read
126
125
  # TODO
126
+ #textrel = @encoded.read @header.trsz
127
+ #datarel = @encoded.read @header.drsz
128
+ #syms = @encoded.read @header.syms
129
+ #strings = @encoded.read
127
130
  end
128
131
 
129
132
  def encode
@@ -37,6 +37,7 @@ end
37
37
 
38
38
  # register a new binary file signature
39
39
  def self.register_signature(sig, exe=nil, &b)
40
+ sig.force_encoding('binary') if sig.respond_to?(:force_encoding)
40
41
  (@signatures ||= []) << [sig, exe || b]
41
42
  end
42
43
 
@@ -58,6 +59,8 @@ register_signature("\xca\xfe\xba\xbe") { UniversalBinary }
58
59
  register_signature("dex\n") { DEX }
59
60
  register_signature("dey\n") { DEY }
60
61
  register_signature("\xfa\x70\x0e\x1f") { FatELF }
62
+ register_signature("\x50\x4b\x03\x04") { ZIP }
63
+ register_signature("\0asm") { WasmFile }
61
64
  register_signature('Metasm.dasm') { Disassembler }
62
65
 
63
66
  # replacement for AutoExe where #load defaults to a Shellcode of the specified CPU
@@ -9,6 +9,7 @@ require 'metasm/decode'
9
9
 
10
10
  module Metasm
11
11
  # BFLT is the binary flat format used by the uClinux
12
+ # from examining a v4 binary, it looks like the header is discarded and the file is mapped from 0x40 to memory address 0 (wrt relocations)
12
13
  class Bflt < ExeFormat
13
14
  MAGIC = 'bFLT'
14
15
  FLAGS = { 1 => 'RAM', 2 => 'GOTPIC', 4 => 'GZIP' }
@@ -29,13 +30,20 @@ class Bflt < ExeFormat
29
30
  when MAGIC
30
31
  else raise InvalidExeFormat, "Bad bFLT signature #@magic"
31
32
  end
33
+
34
+ if @rev >= 0x01000000 and (@rev & 0x00f0ffff) == 0
35
+ puts "Bflt: probable wrong endianness, retrying" if $VERBOSE
36
+ exe.endianness = { :big => :little, :little => :big }[exe.endianness]
37
+ exe.encoded.ptr -= 4*16
38
+ super(exe)
39
+ end
32
40
  end
33
41
 
34
42
  def set_default_values(exe)
35
43
  @magic ||= MAGIC
36
44
  @rev ||= 4
37
45
  @entry ||= 0x40
38
- @data_start ||= @entry + exe.text.length if exe.text
46
+ @data_start ||= 0x40 + exe.text.length if exe.text
39
47
  @data_end ||= @data_start + exe.data.data.length if exe.data
40
48
  @bss_end ||= @data_start + exe.data.length if exe.data
41
49
  @stack_size ||= 0x1000
@@ -49,7 +57,9 @@ class Bflt < ExeFormat
49
57
 
50
58
  def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
51
59
  def encode_word(w) Expression[w].encode(:u32, @endianness) end
60
+ def sizeof_word ; 4 ; end
52
61
 
62
+ attr_accessor :endianness
53
63
  def initialize(cpu = nil)
54
64
  @endianness = cpu ? cpu.endianness : :little
55
65
  @header = Header.new
@@ -61,17 +71,17 @@ class Bflt < ExeFormat
61
71
  def decode_header
62
72
  @encoded.ptr = 0
63
73
  @header.decode(self)
74
+ @encoded.add_export(new_label('entrypoint'), @header.entry)
64
75
  end
65
76
 
66
77
  def decode
67
78
  decode_header
68
79
 
69
- @encoded.ptr = @header.entry
70
- @text = EncodedData.new << @encoded.read(@header.data_start - @header.entry)
71
- @data = EncodedData.new << @encoded.read(@header.data_end - @header.data_start)
72
- @data.virtsize += (@header.bss_end - @header.data_end)
80
+ @text = @encoded[0x40...@header.data_start]
81
+ @data = @encoded[@header.data_start...@header.data_end]
82
+ @data.virtsize += @header.bss_end - @header.data_end
73
83
 
74
- if @header.flags.include? 'GZIP'
84
+ if @header.flags.include?('GZIP')
75
85
  # TODO gzip
76
86
  raise 'bFLT decoder: gzip format not supported'
77
87
  end
@@ -79,7 +89,7 @@ class Bflt < ExeFormat
79
89
  @reloc = []
80
90
  @encoded.ptr = @header.reloc_start
81
91
  @header.reloc_count.times { @reloc << decode_word }
82
- if @header.version == 2
92
+ if @header.rev == 2
83
93
  @reloc.map! { |r| r & 0x3fff_ffff }
84
94
  end
85
95
 
@@ -87,32 +97,29 @@ class Bflt < ExeFormat
87
97
  end
88
98
 
89
99
  def decode_interpret_relocs
100
+ textsz = @header.data_start-0x40
90
101
  @reloc.each { |r|
91
102
  # where the reloc is
92
- if r >= @header.entry and r < @header.data_start
103
+ if r < textsz
93
104
  section = @text
94
- base = @header.entry
95
- elsif r >= @header.data_start and r < @header.data_end
96
- section = @data
97
- base = @header.data_start
105
+ off = section.ptr = r
98
106
  else
99
- puts "out of bounds reloc at #{Expression[r]}" if $VERBOSE
100
- next
107
+ section = @data
108
+ off = section.ptr = r-textsz
101
109
  end
102
110
 
103
111
  # what it points to
104
- section.ptr = r-base
105
112
  target = decode_word(section)
106
- if target >= @header.entry and target < @header.data_start
107
- target = label_at(@text, target - @header.entry, "xref_#{Expression[target]}")
108
- elsif target >= @header.data_start and target < @header.bss_end
109
- target = label_at(@data, target - @header.data_start, "xref_#{Expression[target]}")
113
+ if target < textsz
114
+ target = label_at(@text, target, "xref_#{Expression[target]}")
115
+ elsif target < @header.bss_end-0x40
116
+ target = label_at(@data, target-textsz, "xref_#{Expression[target]}")
110
117
  else
111
- puts "out of bounds reloc target at #{Expression[r]}" if $VERBOSE
118
+ puts "out of bounds reloc target #{Expression[target]} at #{Expression[r]}" if $VERBOSE
112
119
  next
113
120
  end
114
121
 
115
- @text.reloc[r-base] = Relocation.new(Expression[target], :u32, @endianness)
122
+ section.reloc[off] = Relocation.new(Expression[target], :u32, @endianness)
116
123
  }
117
124
  end
118
125
 
@@ -127,8 +134,8 @@ class Bflt < ExeFormat
127
134
 
128
135
  @encoded = EncodedData.new
129
136
  @encoded << @header.encode(self)
130
-
131
- binding = @text.binding(@header.entry).merge(@data.binding(@header.data_start))
137
+
138
+ binding = @text.binding(0x40).merge(@data.binding(@header.data_start))
132
139
  @encoded << @text << @data.data
133
140
  @encoded.fixup! binding
134
141
  @encoded.reloc.clear
@@ -143,7 +150,7 @@ class Bflt < ExeFormat
143
150
  mapaddr = new_label('mapaddr')
144
151
  binding = @text.binding(mapaddr).merge(@data.binding(mapaddr))
145
152
  [@text, @data].each { |section|
146
- base = @header.entry || 0x40
153
+ base = 0x40 # XXX maybe 0 ?
147
154
  base = @header.data_start || base+@text.length if section == @data
148
155
  section.reloc.each { |o, r|
149
156
  if r.endianness == @endianness and [:u32, :a32, :i32].include? r.type and
@@ -167,7 +174,16 @@ class Bflt < ExeFormat
167
174
  case instr.raw.downcase
168
175
  when '.text'; @cursource = @textsrc
169
176
  when '.data'; @cursource = @datasrc
170
- # entrypoint is the 1st byte of .text
177
+ when '.entrypoint'
178
+ # ".entrypoint <somelabel/expression>" or ".entrypoint" (here)
179
+ @lexer.skip_space
180
+ if tok = @lexer.nexttok and tok.type == :string
181
+ raise instr if not entrypoint = Expression.parse(@lexer)
182
+ else
183
+ entrypoint = new_label('entrypoint')
184
+ @cursource << Label.new(entrypoint, instr.backtrace.dup)
185
+ end
186
+ @header.entry = entrypoint
171
187
  else super(instr)
172
188
  end
173
189
  end
@@ -181,9 +197,23 @@ class Bflt < ExeFormat
181
197
  self
182
198
  end
183
199
 
200
+ def get_default_entrypoints
201
+ ['entrypoint']
202
+ end
203
+
184
204
  def each_section
185
- yield @text, @header.entry
186
- yield @data, @header.data_start
205
+ yield @text, 0
206
+ yield @data, @header.data_start - @header.entry
207
+ end
208
+
209
+ def section_info
210
+ [['.text', 0, @text.length, 'rx'],
211
+ ['.data', @header.data_addr-0x40, @data.data.length, 'rw'],
212
+ ['.bss', @header.data_end-0x40, @data.length-@data.data.length, 'rw']]
213
+ end
214
+
215
+ def module_symbols
216
+ ['entrypoint', @header.entry-0x40]
187
217
  end
188
218
  end
189
219
  end
@@ -46,9 +46,11 @@ class COFF < ExeFormat
46
46
  }
47
47
 
48
48
  DLL_CHARACTERISTIC_BITS = {
49
+ 0x20 => 'HIGH_ENTROPY_VA',
49
50
  0x40 => 'DYNAMIC_BASE', 0x80 => 'FORCE_INTEGRITY', 0x100 => 'NX_COMPAT',
50
51
  0x200 => 'NO_ISOLATION', 0x400 => 'NO_SEH', 0x800 => 'NO_BIND',
51
- 0x2000 => 'WDM_DRIVER', 0x8000 => 'TERMINAL_SERVER_AWARE'
52
+ 0x1000 => 'APPCONTAINER', 0x2000 => 'WDM_DRIVER',
53
+ 0x4000 => 'GUARD_CF', 0x8000 => 'TERMINAL_SERVER_AWARE'
52
54
  }
53
55
 
54
56
  BASE_RELOCATION_TYPE = { 0 => 'ABSOLUTE', 1 => 'HIGH', 2 => 'LOW', 3 => 'HIGHLOW',
@@ -81,7 +83,7 @@ class COFF < ExeFormat
81
83
  11 => 'UNION_MEMBER', 12 => 'UNION_TAG', 13 => 'TYPEDEF', 14 => 'UNDEF_STATIC',
82
84
  15 => 'ENUM_TAG', 16 => 'ENUM_MEMBER', 17 => 'REG_PARAM', 18 => 'BIT_FIELD',
83
85
  100 => 'BLOCK', 101 => 'FUNCTION', 102 => 'END_STRUCT',
84
- 103 => 'FILE', 104 => 'SECTION', 105 => 'WEAK_EXT',
86
+ 103 => 'FILE', 104 => 'SECTION', 105 => 'WEAK_EXT',
85
87
  }
86
88
 
87
89
  DEBUG_TYPE = { 0 => 'UNKNOWN', 1 => 'COFF', 2 => 'CODEVIEW', 3 => 'FPO', 4 => 'MISC',
@@ -140,7 +142,7 @@ class COFF < ExeFormat
140
142
  bytes :link_ver_maj, :link_ver_min
141
143
  words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code
142
144
  # base_of_data does not exist in 64-bit
143
- new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, 0)
145
+ new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, lambda { |exe, hdr| exe.bitsize != 64 ? 4 : 0 }, 0)
144
146
  # NT-specific fields
145
147
  xword :image_base
146
148
  words :sect_align, :file_align
@@ -211,7 +213,7 @@ class COFF < ExeFormat
211
213
  end
212
214
 
213
215
  # tree-like structure, holds all misc data the program might need (icons, cursors, version information)
214
- # conventionnally structured in a 3-level depth structure:
216
+ # conventionally structured in a 3-level depth structure:
215
217
  # I resource type (icon/cursor/etc, see +TYPES+)
216
218
  # II resource id (icon n1, icon 'toto', ...)
217
219
  # III language-specific version (icon n1 en, icon n1 en-dvorak...)
@@ -228,6 +230,12 @@ class COFF < ExeFormat
228
230
  end
229
231
  end
230
232
 
233
+ # unwind info
234
+ class ExceptionEntry < SerialStruct
235
+ # function start RVA, function end RVA, UNWIND_INFO RVA
236
+ words :func, :func_end, :unwind
237
+ end
238
+
231
239
  # array of relocations to apply to an executable file
232
240
  # when it is loaded at an address that is not its preferred_base_address
233
241
  class RelocationTable < SerialStruct
@@ -256,15 +264,26 @@ class COFF < ExeFormat
256
264
  end
257
265
 
258
266
  class RSDS < SerialStruct
259
- mem :guid, 16
267
+ word :guid_03
268
+ halfs :guid_45, :guid_67
269
+ bytes :guid_8, :guid_9, :guid_a, :guid_b, :guid_c, :guid_d, :guid_e, :guid_f
260
270
  word :age
261
271
  strz :pdbfilename
272
+
273
+ def guid
274
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % [guid_03, guid_45, guid_67, guid_8, guid_9, guid_a, guid_b, guid_c, guid_d, guid_e, guid_f]
275
+ end
276
+
277
+ # http path to pdb (compressed)
278
+ def msdl_url
279
+ "http://msdl.microsoft.com/download/symbols/#{pdbfilename}/#{guid.delete("-")}#{age}/#{pdbfilename.chop}_"
280
+ end
262
281
  end
263
282
  end
264
283
 
265
284
  class TLSDirectory < SerialStruct
266
285
  xwords :start_va, :end_va, :index_addr, :callback_p
267
- words :zerofill_sz, :characteristics
286
+ words :zerofill_sz, :characteristics
268
287
 
269
288
  attr_accessor :callbacks
270
289
  end
@@ -394,7 +413,8 @@ class COFF < ExeFormat
394
413
  end
395
414
 
396
415
  attr_accessor :header, :optheader, :directory, :sections, :endianness, :symbols, :bitsize,
397
- :export, :imports, :resource, :certificates, :relocations, :debug, :tls, :loadconfig, :delayimports, :com_header
416
+ :export, :imports, :resource, :exception_table, :certificates,
417
+ :relocations, :debug, :tls, :loadconfig, :delayimports, :com_header
398
418
 
399
419
  # boolean, set to true to have #decode() ignore the base_relocs directory
400
420
  attr_accessor :nodecode_relocs
@@ -413,6 +433,11 @@ class COFF < ExeFormat
413
433
  end
414
434
 
415
435
  def shortname; 'coff'; end
436
+
437
+ def sizeof_byte ; 1 ; end
438
+ def sizeof_half ; 2 ; end
439
+ def sizeof_word ; 4 ; end
440
+ def sizeof_xword ; @bitsize == 32 ? 4 : 8 ; end
416
441
  end
417
442
 
418
443
  # the COFF archive file format
@@ -448,6 +473,9 @@ class COFFArchive < ExeFormat
448
473
  def member(name)
449
474
  @members.find { |m| m.name == name }
450
475
  end
476
+
477
+ def sizeof_half ; 2 ; end
478
+ def sizeof_word ; 4 ; end
451
479
  end
452
480
  end
453
481
 
@@ -17,13 +17,15 @@ class COFF
17
17
  # decodes a COFF optional header from coff.cursection
18
18
  # also decodes directories in coff.directory
19
19
  def decode(coff)
20
- return set_default_values(coff) if coff.header.size_opthdr == 0
20
+ return set_default_values(coff) if coff.header.size_opthdr == 0 and not coff.header.characteristics.include?('EXECUTABLE_IMAGE')
21
+ off = coff.curencoded.ptr
21
22
  super(coff)
23
+ nrva = (coff.header.size_opthdr - (coff.curencoded.ptr - off)) / 8
24
+ nrva = @numrva if nrva < 0
22
25
 
23
- nrva = @numrva
24
- if @numrva > DIRECTORIES.length
25
- puts "W: COFF: Invalid directories count #{@numrva}" if $VERBOSE
26
- nrva = DIRECTORIES.length
26
+ if nrva > DIRECTORIES.length or nrva != @numrva
27
+ puts "W: COFF: Weird directories count #{@numrva}" if $VERBOSE
28
+ nrva = DIRECTORIES.length if nrva > DIRECTORIES.length
27
29
  end
28
30
 
29
31
  coff.directory = {}
@@ -64,7 +66,7 @@ class COFF
64
66
  class RelocObj
65
67
  def decode(coff)
66
68
  super(coff)
67
- @sym = coff.symbols[@symidx]
69
+ @sym = coff.symbols[@symidx] if coff.symbols
68
70
  end
69
71
  end
70
72
 
@@ -87,7 +89,7 @@ class COFF
87
89
  addr = addrs[i]
88
90
  if addr >= coff.directory['export_table'][0] and addr < coff.directory['export_table'][0] + coff.directory['export_table'][1] and coff.sect_at_rva(addr)
89
91
  name = coff.decode_strz
90
- e.forwarder_lib, name = name.split('.', 2)
92
+ e.forwarder_lib, name = name.split('.', 2) if name.index('.')
91
93
  if name[0] == ?#
92
94
  e.forwarder_ordinal = name[1..-1].to_i
93
95
  else
@@ -109,6 +111,7 @@ class COFF
109
111
  end
110
112
  if namep and ords
111
113
  namep.zip(ords).each { |np, oi|
114
+ next if not @exports[oi]
112
115
  @exports[oi].name_p = np
113
116
  if coff.sect_at_rva(np)
114
117
  @exports[oi].name = coff.decode_strz
@@ -171,17 +174,17 @@ class COFF
171
174
  end
172
175
 
173
176
  class ResourceDirectory
174
- def decode(coff, edata = coff.curencoded, startptr = edata.ptr)
177
+ def decode(coff, edata = coff.curencoded, startptr = edata.ptr, maxdepth=3)
175
178
  super(coff, edata)
176
179
 
177
180
  @entries = []
178
181
 
179
182
  nrnames = @nr_names if $DEBUG
180
183
  (@nr_names+@nr_id).times {
181
- e = Entry.new
184
+ e = Entry.new
182
185
 
183
- e_id = coff.decode_word(edata)
184
- e_ptr = coff.decode_word(edata)
186
+ e_id = coff.decode_word(edata)
187
+ e_ptr = coff.decode_word(edata)
185
188
 
186
189
  if not e_id.kind_of? Integer or not e_ptr.kind_of? Integer
187
190
  puts 'W: COFF: relocs in the rsrc directory?' if $VERBOSE
@@ -213,10 +216,12 @@ class COFF
213
216
  e.subdir_p = e_ptr & 0x7fff_ffff
214
217
  if startptr + e.subdir_p >= edata.length
215
218
  puts 'W: COFF: invalid resource structure: directory too far' if $VERBOSE
216
- else
219
+ elsif maxdepth > 0
217
220
  edata.ptr = startptr + e.subdir_p
218
221
  e.subdir = ResourceDirectory.new
219
- e.subdir.decode coff, edata, startptr
222
+ e.subdir.decode coff, edata, startptr, maxdepth-1
223
+ else
224
+ puts 'W: COFF: recursive resource section' if $VERBOSE
220
225
  end
221
226
  else
222
227
  e.dataentry_p = e_ptr
@@ -244,7 +249,8 @@ class COFF
244
249
 
245
250
  decode_tllv = lambda { |ed, state|
246
251
  sptr = ed.ptr
247
- len, vlen, type = coff.decode_half(ed), coff.decode_half(ed), coff.decode_half(ed)
252
+ len, vlen = coff.decode_half(ed), coff.decode_half(ed)
253
+ coff.decode_half(ed) # type
248
254
  tagname = ''
249
255
  while c = coff.decode_half(ed) and c != 0
250
256
  tagname << (c&255)
@@ -273,7 +279,7 @@ class COFF
273
279
  when :str
274
280
  val = ed.read(vlen*2).unpack('v*')
275
281
  val.pop if val[-1] == 0
276
- val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
282
+ val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
277
283
  vers[tagname] = val
278
284
  when :var
279
285
  val = ed.read(vlen).unpack('V*')
@@ -424,10 +430,9 @@ class COFF
424
430
  # may return self when rva points to the coff header
425
431
  # returns nil if none match, 0 never matches
426
432
  def sect_at_rva(rva)
427
- return if not rva or rva <= 0
433
+ return if not rva or not rva.kind_of?(::Integer) or rva <= 0
428
434
  if sections and not @sections.empty?
429
- valign = lambda { |l| EncodedData.align_size(l, @optheader.sect_align) }
430
- if s = @sections.find { |s_| s_.virtaddr <= rva and s_.virtaddr + valign[s_.virtsize] > rva }
435
+ if s = @sections.find { |s_| s_.virtaddr <= rva and s_.virtaddr + EncodedData.align_size((s_.virtsize == 0 ? s_.rawsize : s_.virtsize), @optheader.sect_align) > rva }
431
436
  s.encoded.ptr = rva - s.virtaddr
432
437
  @cursection = s
433
438
  elsif rva < @sections.map { |s_| s_.virtaddr }.min
@@ -479,7 +484,7 @@ class COFF
479
484
  end
480
485
 
481
486
  def each_section
482
- if @header.size_opthdr == 0
487
+ if @header.size_opthdr == 0 and not @header.characteristics.include?('EXECUTABLE_IMAGE')
483
488
  @sections.each { |s|
484
489
  next if not s.encoded
485
490
  l = new_label(s.name)
@@ -490,7 +495,9 @@ class COFF
490
495
  end
491
496
  base = @optheader.image_base
492
497
  base = 0 if not base.kind_of? Integer
493
- yield @encoded[0, @optheader.headers_size], base
498
+ sz = @optheader.headers_size
499
+ sz = EncodedData.align_size(@optheader.image_size, 4096) if @sections.empty?
500
+ yield @encoded[0, sz], base
494
501
  @sections.each { |s| yield s.encoded, base + s.virtaddr }
495
502
  end
496
503
 
@@ -545,6 +552,7 @@ class COFF
545
552
  s.relocnr.times { s.relocs << RelocObj.decode(self) }
546
553
  new_label 'pcrel'
547
554
  s.relocs.each { |r|
555
+ next if not r.sym
548
556
  case r.type
549
557
  when 'DIR32'
550
558
  s.encoded.reloc[r.va] = Metasm::Relocation.new(Expression[r.sym.name], :u32, @endianness)
@@ -566,8 +574,10 @@ class COFF
566
574
  # decodes a section content (allows simpler LoadedPE override)
567
575
  def decode_section_body(s)
568
576
  raw = EncodedData.align_size(s.rawsize, @optheader.file_align)
569
- virt = EncodedData.align_size(s.virtsize, @optheader.sect_align)
577
+ virt = s.virtsize
570
578
  virt = raw = s.rawsize if @header.size_opthdr == 0
579
+ virt = raw if virt == 0
580
+ virt = EncodedData.align_size(virt, @optheader.sect_align)
571
581
  s.encoded = @encoded[s.rawaddr, [raw, virt].min] || EncodedData.new
572
582
  s.encoded.virtsize = virt
573
583
  end
@@ -629,13 +639,29 @@ class COFF
629
639
  resource.decode_version(self, lang)
630
640
  end
631
641
 
642
+ # decode the exception table, holding the start and end of every function in the binary (x64)
643
+ # includes a pointer to the UNWIND_INFO structure for exception handling
644
+ def decode_exception_table
645
+ if et = @directory['exception_table'] and sect_at_rva(et[0])
646
+ @exception_table = []
647
+ (et[1]/12).times {
648
+ @exception_table << ExceptionEntry.decode(self)
649
+ }
650
+ end
651
+ end
652
+
632
653
  # decodes certificate table
633
654
  def decode_certificates
634
655
  if ct = @directory['certificate_table']
635
656
  @certificates = []
636
657
  @cursection = self
658
+ if ct[0] > @encoded.length or ct[1] > @encoded.length - ct[0]
659
+ puts "W: COFF: invalid certificate_table #{'0x%X+0x%0X' % ct}" if $VERBOSE
660
+ ct = [ct[0], 1]
661
+ end
637
662
  @encoded.ptr = ct[0]
638
663
  off_end = ct[0]+ct[1]
664
+ off_end = @encoded.length if off_end > @encoded.length
639
665
  while @encoded.ptr < off_end
640
666
  certlen = decode_word
641
667
  certrev = decode_half
@@ -704,6 +730,25 @@ class COFF
704
730
  end
705
731
  end
706
732
 
733
+ def decode_reloc_amd64(r)
734
+ case r.type
735
+ when 'ABSOLUTE'
736
+ when 'HIGHLOW'
737
+ addr = decode_word
738
+ if s = sect_at_va(addr)
739
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
740
+ Metasm::Relocation.new(Expression[label], :u32, @endianness)
741
+ end
742
+ when 'DIR64'
743
+ addr = decode_xword
744
+ if s = sect_at_va(addr)
745
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
746
+ Metasm::Relocation.new(Expression[label], :u64, @endianness)
747
+ end
748
+ else puts "W: COFF: Unsupported amd64 relocation #{r.inspect}" if $VERBOSE
749
+ end
750
+ end
751
+
707
752
  def decode_debug
708
753
  if dd = @directory['debug'] and sect_at_rva(dd[0])
709
754
  @debug = []
@@ -719,11 +764,11 @@ class COFF
719
764
  def decode_tls
720
765
  if @directory['tls_table'] and sect_at_rva(@directory['tls_table'][0])
721
766
  @tls = TLSDirectory.decode(self)
722
- if s = sect_at_va(@tls.callback_p)
767
+ if s = sect_at_va(@tls.callback_p)
723
768
  s.encoded.add_export 'tls_callback_table'
724
769
  @tls.callbacks.each_with_index { |cb, i|
725
770
  @tls.callbacks[i] = curencoded.add_export "tls_callback_#{i}" if sect_at_rva(cb)
726
- }
771
+ }
727
772
  end
728
773
  end
729
774
  end
@@ -748,6 +793,7 @@ class COFF
748
793
  decode_exports
749
794
  decode_imports
750
795
  decode_resources
796
+ decode_exception_table
751
797
  decode_certificates
752
798
  decode_debug
753
799
  decode_tls
@@ -815,6 +861,7 @@ class COFFArchive
815
861
  ar.encoded.ptr += 1 if @size & 1 == 1
816
862
  end
817
863
 
864
+ # TODO XXX are those actually used ?
818
865
  def decode_half ; @encoded.decode_imm(:u16, :big) end
819
866
  def decode_word ; @encoded.decode_imm(:u32, :big) end
820
867