metasm 1.0.1 → 1.0.2

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