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
@@ -271,7 +271,16 @@ class Expression
271
271
  def encode(type, endianness, backtrace=nil)
272
272
  case val = reduce
273
273
  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)})
274
+ else
275
+ str = case INT_SIZE[type]
276
+ when 8; "\0"
277
+ when 16; "\0\0"
278
+ when 32; "\0\0\0\0"
279
+ when 64; "\0\0\0\0\0\0\0\0"
280
+ else [0].pack('C')*(INT_SIZE[type]/8)
281
+ end
282
+ str = str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
283
+ EncodedData.new(str, :reloc => {0 => Relocation.new(self, type, endianness, backtrace)})
275
284
  end
276
285
  end
277
286
 
@@ -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
@@ -58,6 +58,7 @@ register_signature("\xca\xfe\xba\xbe") { UniversalBinary }
58
58
  register_signature("dex\n") { DEX }
59
59
  register_signature("dey\n") { DEY }
60
60
  register_signature("\xfa\x70\x0e\x1f") { FatELF }
61
+ register_signature("\x50\x4b\x03\x04") { ZIP }
61
62
  register_signature('Metasm.dasm') { Disassembler }
62
63
 
63
64
  # 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
@@ -81,7 +81,7 @@ class COFF < ExeFormat
81
81
  11 => 'UNION_MEMBER', 12 => 'UNION_TAG', 13 => 'TYPEDEF', 14 => 'UNDEF_STATIC',
82
82
  15 => 'ENUM_TAG', 16 => 'ENUM_MEMBER', 17 => 'REG_PARAM', 18 => 'BIT_FIELD',
83
83
  100 => 'BLOCK', 101 => 'FUNCTION', 102 => 'END_STRUCT',
84
- 103 => 'FILE', 104 => 'SECTION', 105 => 'WEAK_EXT',
84
+ 103 => 'FILE', 104 => 'SECTION', 105 => 'WEAK_EXT',
85
85
  }
86
86
 
87
87
  DEBUG_TYPE = { 0 => 'UNKNOWN', 1 => 'COFF', 2 => 'CODEVIEW', 3 => 'FPO', 4 => 'MISC',
@@ -140,7 +140,7 @@ class COFF < ExeFormat
140
140
  bytes :link_ver_maj, :link_ver_min
141
141
  words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code
142
142
  # 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)
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 }, lambda { |exe, hdr| exe.bitsize != 64 ? 4 : 0 }, 0)
144
144
  # NT-specific fields
145
145
  xword :image_base
146
146
  words :sect_align, :file_align
@@ -264,7 +264,7 @@ class COFF < ExeFormat
264
264
 
265
265
  class TLSDirectory < SerialStruct
266
266
  xwords :start_va, :end_va, :index_addr, :callback_p
267
- words :zerofill_sz, :characteristics
267
+ words :zerofill_sz, :characteristics
268
268
 
269
269
  attr_accessor :callbacks
270
270
  end
@@ -413,6 +413,11 @@ class COFF < ExeFormat
413
413
  end
414
414
 
415
415
  def shortname; 'coff'; end
416
+
417
+ def sizeof_byte ; 1 ; end
418
+ def sizeof_half ; 2 ; end
419
+ def sizeof_word ; 4 ; end
420
+ def sizeof_xword ; @bitsize == 32 ? 4 : 8 ; end
416
421
  end
417
422
 
418
423
  # the COFF archive file format
@@ -448,6 +453,9 @@ class COFFArchive < ExeFormat
448
453
  def member(name)
449
454
  @members.find { |m| m.name == name }
450
455
  end
456
+
457
+ def sizeof_half ; 2 ; end
458
+ def sizeof_word ; 4 ; end
451
459
  end
452
460
  end
453
461
 
@@ -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 = {}
@@ -171,17 +173,17 @@ class COFF
171
173
  end
172
174
 
173
175
  class ResourceDirectory
174
- def decode(coff, edata = coff.curencoded, startptr = edata.ptr)
176
+ def decode(coff, edata = coff.curencoded, startptr = edata.ptr, maxdepth=3)
175
177
  super(coff, edata)
176
178
 
177
179
  @entries = []
178
180
 
179
181
  nrnames = @nr_names if $DEBUG
180
182
  (@nr_names+@nr_id).times {
181
- e = Entry.new
183
+ e = Entry.new
182
184
 
183
- e_id = coff.decode_word(edata)
184
- e_ptr = coff.decode_word(edata)
185
+ e_id = coff.decode_word(edata)
186
+ e_ptr = coff.decode_word(edata)
185
187
 
186
188
  if not e_id.kind_of? Integer or not e_ptr.kind_of? Integer
187
189
  puts 'W: COFF: relocs in the rsrc directory?' if $VERBOSE
@@ -213,10 +215,12 @@ class COFF
213
215
  e.subdir_p = e_ptr & 0x7fff_ffff
214
216
  if startptr + e.subdir_p >= edata.length
215
217
  puts 'W: COFF: invalid resource structure: directory too far' if $VERBOSE
216
- else
218
+ elsif maxdepth > 0
217
219
  edata.ptr = startptr + e.subdir_p
218
220
  e.subdir = ResourceDirectory.new
219
- e.subdir.decode coff, edata, startptr
221
+ e.subdir.decode coff, edata, startptr, maxdepth-1
222
+ else
223
+ puts 'W: COFF: recursive resource section' if $VERBOSE
220
224
  end
221
225
  else
222
226
  e.dataentry_p = e_ptr
@@ -244,7 +248,8 @@ class COFF
244
248
 
245
249
  decode_tllv = lambda { |ed, state|
246
250
  sptr = ed.ptr
247
- len, vlen, type = coff.decode_half(ed), coff.decode_half(ed), coff.decode_half(ed)
251
+ len, vlen = coff.decode_half(ed), coff.decode_half(ed)
252
+ coff.decode_half(ed) # type
248
253
  tagname = ''
249
254
  while c = coff.decode_half(ed) and c != 0
250
255
  tagname << (c&255)
@@ -273,7 +278,7 @@ class COFF
273
278
  when :str
274
279
  val = ed.read(vlen*2).unpack('v*')
275
280
  val.pop if val[-1] == 0
276
- val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
281
+ val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
277
282
  vers[tagname] = val
278
283
  when :var
279
284
  val = ed.read(vlen).unpack('V*')
@@ -426,8 +431,7 @@ class COFF
426
431
  def sect_at_rva(rva)
427
432
  return if not rva or rva <= 0
428
433
  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 }
434
+ 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
435
  s.encoded.ptr = rva - s.virtaddr
432
436
  @cursection = s
433
437
  elsif rva < @sections.map { |s_| s_.virtaddr }.min
@@ -479,7 +483,7 @@ class COFF
479
483
  end
480
484
 
481
485
  def each_section
482
- if @header.size_opthdr == 0
486
+ if @header.size_opthdr == 0 and not @header.characteristics.include?('EXECUTABLE_IMAGE')
483
487
  @sections.each { |s|
484
488
  next if not s.encoded
485
489
  l = new_label(s.name)
@@ -490,7 +494,9 @@ class COFF
490
494
  end
491
495
  base = @optheader.image_base
492
496
  base = 0 if not base.kind_of? Integer
493
- yield @encoded[0, @optheader.headers_size], base
497
+ sz = @optheader.headers_size
498
+ sz = EncodedData.align_size(@optheader.image_size, 4096) if @sections.empty?
499
+ yield @encoded[0, sz], base
494
500
  @sections.each { |s| yield s.encoded, base + s.virtaddr }
495
501
  end
496
502
 
@@ -566,8 +572,10 @@ class COFF
566
572
  # decodes a section content (allows simpler LoadedPE override)
567
573
  def decode_section_body(s)
568
574
  raw = EncodedData.align_size(s.rawsize, @optheader.file_align)
569
- virt = EncodedData.align_size(s.virtsize, @optheader.sect_align)
575
+ virt = s.virtsize
570
576
  virt = raw = s.rawsize if @header.size_opthdr == 0
577
+ virt = raw if virt == 0
578
+ virt = EncodedData.align_size(virt, @optheader.sect_align)
571
579
  s.encoded = @encoded[s.rawaddr, [raw, virt].min] || EncodedData.new
572
580
  s.encoded.virtsize = virt
573
581
  end
@@ -634,8 +642,13 @@ class COFF
634
642
  if ct = @directory['certificate_table']
635
643
  @certificates = []
636
644
  @cursection = self
645
+ if ct[0] > @encoded.length or ct[1] > @encoded.length - ct[0]
646
+ puts "W: COFF: invalid certificate_table #{'0x%X+0x%0X' % ct}" if $VERBOSE
647
+ ct = [ct[0], 1]
648
+ end
637
649
  @encoded.ptr = ct[0]
638
650
  off_end = ct[0]+ct[1]
651
+ off_end = @encoded.length if off_end > @encoded.length
639
652
  while @encoded.ptr < off_end
640
653
  certlen = decode_word
641
654
  certrev = decode_half
@@ -704,6 +717,25 @@ class COFF
704
717
  end
705
718
  end
706
719
 
720
+ def decode_reloc_amd64(r)
721
+ case r.type
722
+ when 'ABSOLUTE'
723
+ when 'HIGHLOW'
724
+ addr = decode_word
725
+ if s = sect_at_va(addr)
726
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
727
+ Metasm::Relocation.new(Expression[label], :u32, @endianness)
728
+ end
729
+ when 'DIR64'
730
+ addr = decode_xword
731
+ if s = sect_at_va(addr)
732
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
733
+ Metasm::Relocation.new(Expression[label], :u64, @endianness)
734
+ end
735
+ else puts "W: COFF: Unsupported amd64 relocation #{r.inspect}" if $VERBOSE
736
+ end
737
+ end
738
+
707
739
  def decode_debug
708
740
  if dd = @directory['debug'] and sect_at_rva(dd[0])
709
741
  @debug = []
@@ -719,11 +751,11 @@ class COFF
719
751
  def decode_tls
720
752
  if @directory['tls_table'] and sect_at_rva(@directory['tls_table'][0])
721
753
  @tls = TLSDirectory.decode(self)
722
- if s = sect_at_va(@tls.callback_p)
754
+ if s = sect_at_va(@tls.callback_p)
723
755
  s.encoded.add_export 'tls_callback_table'
724
756
  @tls.callbacks.each_with_index { |cb, i|
725
757
  @tls.callbacks[i] = curencoded.add_export "tls_callback_#{i}" if sect_at_rva(cb)
726
- }
758
+ }
727
759
  end
728
760
  end
729
761
  end
@@ -815,6 +847,7 @@ class COFFArchive
815
847
  ar.encoded.ptr += 1 if @size & 1 == 1
816
848
  end
817
849
 
850
+ # TODO XXX are those actually used ?
818
851
  def decode_half ; @encoded.decode_imm(:u16, :big) end
819
852
  def decode_word ; @encoded.decode_imm(:u32, :big) end
820
853