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
@@ -18,19 +18,19 @@ class ELF
18
18
  case hdr.e_class
19
19
  when '32'; elf.bitsize = 32
20
20
  when '64', '64_icc'; elf.bitsize = 64
21
- else raise InvalidExeFormat, "E: ELF: unsupported class #{hdr.e_class}"
21
+ else puts "W: ELF: unsupported class #{hdr.e_class}, assuming 32bit"; elf.bitsize = 32
22
22
  end
23
23
 
24
24
  case hdr.data
25
25
  when 'LSB'; elf.endianness = :little
26
26
  when 'MSB'; elf.endianness = :big
27
- else raise InvalidExeFormat, "E: ELF: unsupported endianness #{hdr.data}"
27
+ else puts "W: ELF: unsupported endianness #{hdr.data}, assuming littleendian"; elf.endianness = :little
28
28
  end
29
29
 
30
30
  if hdr.i_version != 'CURRENT'
31
- raise InvalidExeFormat, "E: ELF: unsupported ELF version #{hdr.i_version}"
31
+ puts ":: ELF: unsupported ELF version #{hdr.i_version}"
32
32
  end
33
- }
33
+ }
34
34
  end
35
35
 
36
36
  class Symbol
@@ -66,7 +66,7 @@ class ELF
66
66
  # handles relocated LoadedELF
67
67
  def addr_to_fileoff(addr)
68
68
  la = module_address
69
- la = (la == 0 ? (@load_address ||= 0) : 0)
69
+ la = (la == 0 ? (@load_address ||= 0) : 0)
70
70
  addr_to_off(addr - la)
71
71
  end
72
72
 
@@ -75,7 +75,7 @@ class ELF
75
75
  def fileoff_to_addr(foff)
76
76
  if s = @segments.find { |s_| s_.type == 'LOAD' and s_.offset <= foff and s_.offset + s_.filesz > foff }
77
77
  la = module_address
78
- la = (la == 0 ? (@load_address ||= 0) : 0)
78
+ la = (la == 0 ? (@load_address ||= 0) : 0)
79
79
  s.vaddr + la + foff - s.offset
80
80
  end
81
81
  end
@@ -106,7 +106,7 @@ class ELF
106
106
  def decode_header(off = 0, decode_phdr=true, decode_shdr=true)
107
107
  @encoded.ptr = off
108
108
  @header.decode self
109
- raise InvalidExeFormat, "Invalid elf header size: #{@header.ehsize}" if Header.size(self) != @header.ehsize
109
+ raise InvalidExeFormat, "Invalid elf header size: #{@header.ehsize}" if Header.sizeof(self) != @header.ehsize
110
110
  if decode_phdr and @header.phoff != 0
111
111
  decode_program_header(@header.phoff+off)
112
112
  end
@@ -118,7 +118,7 @@ class ELF
118
118
  # decodes the section header
119
119
  # section names are read from shstrndx if possible
120
120
  def decode_section_header(off = @header.shoff)
121
- raise InvalidExeFormat, "Invalid elf section header size: #{@header.shentsize}" if Section.size(self) != @header.shentsize
121
+ raise InvalidExeFormat, "Invalid elf section header size: #{@header.shentsize}" if Section.sizeof(self) != @header.shentsize
122
122
  @encoded.add_export new_label('section_header'), off
123
123
  @encoded.ptr = off
124
124
  @sections = []
@@ -137,7 +137,7 @@ class ELF
137
137
  # decodes the program header table
138
138
  # marks the elf entrypoint as an export of +self.encoded+
139
139
  def decode_program_header(off = @header.phoff)
140
- raise InvalidExeFormat, "Invalid elf program header size: #{@header.phentsize}" if Segment.size(self) != @header.phentsize
140
+ raise InvalidExeFormat, "Invalid elf program header size: #{@header.phentsize}" if Segment.sizeof(self) != @header.phentsize
141
141
  @encoded.add_export new_label('program_header'), off
142
142
  @encoded.ptr = off
143
143
  @segments = []
@@ -224,7 +224,40 @@ class ELF
224
224
  # (gnu_hash(sym[N].name) & ~1) | (N == dynsymcount-1 || (gnu_hash(sym[N].name) % nbucket) != (gnu_hash(sym[N+1].name) % nbucket))
225
225
  # that's the hash, with its lower bit replaced by the bool [1 if i am the last sym having my hash as hash]
226
226
 
227
- return hsymcount+symndx if just_get_count
227
+ # we're going to decode the symbol table, and we just want to get the nr of symbols to read
228
+ if just_get_count
229
+ # index of highest hashed (exported) symbols
230
+ ns = hsymcount+symndx
231
+
232
+ # no way to get the number of non-exported symbols from what we have here
233
+ # so we'll decode all relocs and use the largest index we see..
234
+ rels = []
235
+ if @encoded.ptr = @tag['REL'] and @tag['RELENT'] == Relocation.sizeof(self)
236
+ p_end = @encoded.ptr + @tag['RELSZ']
237
+ while @encoded.ptr < p_end
238
+ rels << Relocation.decode(self)
239
+ end
240
+ end
241
+ if @encoded.ptr = @tag['RELA'] and @tag['RELAENT'] == RelocationAddend.sizeof(self)
242
+ p_end = @encoded.ptr + @tag['RELASZ']
243
+ while @encoded.ptr < p_end
244
+ rels << RelocationAddend.decode(self)
245
+ end
246
+ end
247
+ if @encoded.ptr = @tag['JMPREL'] and relcls = case @tag['PLTREL']
248
+ when 'REL'; Relocation
249
+ when 'RELA'; RelocationAddend
250
+ end
251
+ p_end = @encoded.ptr + @tag['PLTRELSZ']
252
+ while @encoded.ptr < p_end
253
+ rels << relcls.decode(self)
254
+ end
255
+ end
256
+ maxr = rels.map { |rel| rel.symbol }.grep(::Integer).max || -1
257
+
258
+ return [ns, maxr+1].max
259
+ end
260
+
228
261
 
229
262
  # TODO
230
263
  end
@@ -332,8 +365,7 @@ class ELF
332
365
  # marks a symbol as @encoded.export (from s.value, using segments or sections)
333
366
  def decode_symbol_export(s)
334
367
  if s.name and s.shndx != 'UNDEF' and %w[NOTYPE OBJECT FUNC].include?(s.type)
335
- if @header.type == 'REL'
336
- sec = @sections[s.shndx]
368
+ if @header.type == 'REL' and s.shndx.kind_of?(::Integer) and sec = @sections[s.shndx]
337
369
  o = sec.offset + s.value
338
370
  elsif not o = addr_to_off(s.value)
339
371
  # allow to point to end of segment
@@ -359,7 +391,7 @@ class ELF
359
391
  def decode_segments_symbols
360
392
  return unless @tag['STRTAB'] and @tag['STRSZ'] and @tag['SYMTAB'] and (@tag['HASH'] or @tag['GNU_HASH'])
361
393
 
362
- raise "E: ELF: unsupported symbol entry size: #{@tag['SYMENT']}" if @tag['SYMENT'] != Symbol.size(self)
394
+ raise "E: ELF: unsupported symbol entry size: #{@tag['SYMENT']}" if @tag['SYMENT'] != Symbol.sizeof(self)
363
395
 
364
396
  # find number of symbols
365
397
  if @tag['HASH']
@@ -394,14 +426,16 @@ class ELF
394
426
  @encoded.ptr = sec.offset
395
427
  syms = []
396
428
  raise 'Invalid symbol table' if sec.size > @encoded.length
397
- (sec.size / Symbol.size(self)).times { syms << Symbol.decode(self, strtab) }
429
+ (sec.size / Symbol.sizeof(self)).times { syms << Symbol.decode(self, strtab) }
398
430
  alreadysegs = true if @header.type == 'DYN' or @header.type == 'EXEC'
431
+ alreadysyms = @symbols.inject({}) { |h, s| h.update s.name => true } if alreadysegs
399
432
  syms.each { |s|
400
433
  if alreadysegs
401
434
  # if we already decoded the symbols from the DYNAMIC segment,
402
435
  # ignore dups and imports from this section
403
436
  next if s.shndx == 'UNDEF'
404
- next if @symbols.find { |ss| ss.name == s.name }
437
+ next if alreadysyms[s.name]
438
+ alreadysyms[s.name] = true
405
439
  end
406
440
  @symbols << s
407
441
  decode_symbol_export(s)
@@ -445,7 +479,7 @@ class ELF
445
479
  def decode_segments_relocs
446
480
  @relocations.clear
447
481
  if @encoded.ptr = @tag['REL']
448
- raise "E: ELF: unsupported rel entry size #{@tag['RELENT']}" if @tag['RELENT'] != Relocation.size(self)
482
+ raise "E: ELF: unsupported rel entry size #{@tag['RELENT']}" if @tag['RELENT'] != Relocation.sizeof(self)
449
483
  p_end = @encoded.ptr + @tag['RELSZ']
450
484
  while @encoded.ptr < p_end
451
485
  @relocations << Relocation.decode(self)
@@ -453,7 +487,7 @@ class ELF
453
487
  end
454
488
 
455
489
  if @encoded.ptr = @tag['RELA']
456
- raise "E: ELF: unsupported rela entry size #{@tag['RELAENT'].inspect}" if @tag['RELAENT'] != RelocationAddend.size(self)
490
+ raise "E: ELF: unsupported rela entry size #{@tag['RELAENT'].inspect}" if @tag['RELAENT'] != RelocationAddend.sizeof(self)
457
491
  p_end = @encoded.ptr + @tag['RELASZ']
458
492
  while @encoded.ptr < p_end
459
493
  @relocations << RelocationAddend.decode(self)
@@ -509,10 +543,28 @@ class ELF
509
543
  end
510
544
  end
511
545
 
546
+ # returns the target of a relocation using reloc.symbol
547
+ # may create new labels if the relocation targets a section
548
+ def reloc_target(reloc)
549
+ target = 0
550
+ if reloc.symbol.kind_of?(Symbol)
551
+ if reloc.symbol.type == 'SECTION'
552
+ s = @sections[reloc.symbol.shndx]
553
+ if not target = @encoded.inv_export[s.offset]
554
+ target = new_label(s.name)
555
+ @encoded.add_export(target, s.offset)
556
+ end
557
+ elsif reloc.symbol.name
558
+ target = reloc.symbol.name
559
+ end
560
+ end
561
+ target
562
+ end
563
+
512
564
  # returns the Metasm::Relocation that should be applied for reloc
513
565
  # self.encoded.ptr must point to the location that will be relocated (for implicit addends)
514
566
  def arch_decode_segments_reloc_386(reloc)
515
- if reloc.symbol and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
567
+ if reloc.symbol.kind_of?(Symbol) and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
516
568
  s = @sections.find { |s_| s_.name and s_.offset <= @encoded.ptr and s_.offset + s_.size > @encoded.ptr }
517
569
  @encoded.add_export(new_label("#{s.name}_#{n}"), @encoded.ptr, true)
518
570
  end
@@ -541,15 +593,14 @@ class ELF
541
593
  when 'GLOB_DAT', 'JMP_SLOT', '32', 'PC32', 'TLS_TPOFF', 'TLS_TPOFF32'
542
594
  # XXX use versionned version
543
595
  # lazy jmp_slot ?
544
- target = 0
545
- target = reloc.symbol.name if reloc.symbol.kind_of?(Symbol) and reloc.symbol.name
596
+ target = reloc_target(reloc)
546
597
  target = Expression[target, :-, reloc.offset] if reloc.type == 'PC32'
547
598
  target = Expression[target, :+, addend] if addend and addend != 0
548
599
  target = Expression[target, :+, 'tlsoffset'] if reloc.type == 'TLS_TPOFF'
549
600
  target = Expression[:-, [target, :+, 'tlsoffset']] if reloc.type == 'TLS_TPOFF32'
550
601
  when 'COPY'
551
602
  # mark the address pointed as a copy of the relocation target
552
- if not reloc.symbol or not name = reloc.symbol.name
603
+ if not reloc.symbol.kind_of?(Symbol) or not name = reloc.symbol.name
553
604
  puts "W: Elf: symbol to COPY has no name: #{reloc.inspect}" if $VERBOSE
554
605
  name = ''
555
606
  end
@@ -567,24 +618,40 @@ class ELF
567
618
  # returns the Metasm::Relocation that should be applied for reloc
568
619
  # self.encoded.ptr must point to the location that will be relocated (for implicit addends)
569
620
  def arch_decode_segments_reloc_mips(reloc)
570
- if reloc.symbol and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
621
+ if reloc.symbol.kind_of?(Symbol) and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
571
622
  s = @sections.find { |s_| s_.name and s_.offset <= @encoded.ptr and s_.offset + s_.size > @encoded.ptr }
572
623
  @encoded.add_export(new_label("#{s.name}_#{n}"), @encoded.ptr, true)
573
624
  end
574
625
 
626
+ original_word = decode_word
627
+
575
628
  # decode addend if needed
576
629
  case reloc.type
577
630
  when 'NONE' # no addend
578
- else addend = reloc.addend || decode_sword
631
+ else addend = reloc.addend || Expression.make_signed(original_word, 32)
579
632
  end
580
633
 
581
634
  case reloc.type
582
635
  when 'NONE'
583
636
  when '32', 'REL32'
584
- target = 0
585
- target = reloc.symbol.name if reloc.symbol.kind_of?(Symbol) and reloc.symbol.name
637
+ target = reloc_target(reloc)
586
638
  target = Expression[target, :-, reloc.offset] if reloc.type == 'REL32'
587
639
  target = Expression[target, :+, addend] if addend and addend != 0
640
+ when '26'
641
+ target = reloc_target(reloc)
642
+ addend &= 0x3ff_ffff
643
+ target = Expression[target, :+, [addend, :<<, 2]] if addend and addend != 0
644
+ target = Expression[[original_word, :&, 0xfc0_0000], :|, [[target, :&, 0x3ff_ffff], :>>, 2]]
645
+ when 'HI16'
646
+ target = reloc_target(reloc)
647
+ addend &= 0xffff
648
+ target = Expression[target, :+, [addend, :<<, 16]] if addend and addend != 0
649
+ target = Expression[[original_word, :&, 0xffff_0000], :|, [[target, :>>, 16], :&, 0xffff]]
650
+ when 'LO16'
651
+ target = reloc_target(reloc)
652
+ addend &= 0xffff
653
+ target = Expression[target, :+, addend] if addend and addend != 0
654
+ target = Expression[[original_word, :&, 0xffff_0000], :|, [target, :&, 0xffff]]
588
655
  else
589
656
  puts "W: Elf: unhandled MIPS reloc #{reloc.inspect}" if $VERBOSE
590
657
  target = nil
@@ -596,7 +663,7 @@ class ELF
596
663
  # returns the Metasm::Relocation that should be applied for reloc
597
664
  # self.encoded.ptr must point to the location that will be relocated (for implicit addends)
598
665
  def arch_decode_segments_reloc_x86_64(reloc)
599
- if reloc.symbol and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
666
+ if reloc.symbol.kind_of?(Symbol) and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
600
667
  s = @sections.find { |s_| s_.name and s_.offset <= @encoded.ptr and s_.offset + s_.size > @encoded.ptr }
601
668
  @encoded.add_export(new_label("#{s.name}_#{n}"), @encoded.ptr, true)
602
669
  end
@@ -627,14 +694,13 @@ class ELF
627
694
  when 'GLOB_DAT', 'JMP_SLOT', '64', 'PC64', '32', 'PC32'
628
695
  # XXX use versionned version
629
696
  # lazy jmp_slot ?
630
- target = 0
631
- target = reloc.symbol.name if reloc.symbol.kind_of?(Symbol) and reloc.symbol.name
697
+ target = reloc_target(reloc)
632
698
  target = Expression[target, :-, reloc.offset] if reloc.type == 'PC64' or reloc.type == 'PC32'
633
699
  target = Expression[target, :+, addend] if addend and addend != 0
634
700
  sz = :u32 if reloc.type == '32' or reloc.type == 'PC32'
635
701
  when 'COPY'
636
702
  # mark the address pointed as a copy of the relocation target
637
- if not reloc.symbol or not name = reloc.symbol.name
703
+ if not reloc.symbol.kind_of?(Symbol) or not name = reloc.symbol.name
638
704
  puts "W: Elf: symbol to COPY has no name: #{reloc.inspect}" if $VERBOSE
639
705
  name = ''
640
706
  end
@@ -649,6 +715,79 @@ class ELF
649
715
  Metasm::Relocation.new(Expression[target], sz, @endianness) if target
650
716
  end
651
717
 
718
+ def arch_decode_segments_reloc_sh(reloc)
719
+ if reloc.symbol.kind_of?(Symbol) and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
720
+ s = @sections.find { |s_| s_.name and s_.offset <= @encoded.ptr and s_.offset + s_.size > @encoded.ptr }
721
+ @encoded.add_export(new_label("#{s.name}_#{n}"), @encoded.ptr, true)
722
+ end
723
+
724
+ original_word = decode_word
725
+
726
+ # decode addend if needed
727
+ case reloc.type
728
+ when 'NONE' # no addend
729
+ else addend = reloc.addend || Expression.make_signed(original_word, 32)
730
+ end
731
+
732
+ case reloc.type
733
+ when 'NONE'
734
+ when 'GLOB_DAT', 'JMP_SLOT'
735
+ target = reloc_target(reloc)
736
+ target = Expression[target, :+, addend] if addend and addend != 0
737
+ else
738
+ puts "W: Elf: unhandled SH reloc #{reloc.inspect}" if $VERBOSE
739
+ target = nil
740
+ end
741
+
742
+ Metasm::Relocation.new(Expression[target], :u32, @endianness) if target
743
+ end
744
+
745
+ def arch_decode_segments_reloc_openrisc(reloc)
746
+ if reloc.symbol.kind_of?(Symbol) and n = reloc.symbol.name and reloc.symbol.shndx == 'UNDEF' and @sections and
747
+ s = @sections.find { |s_| s_.name and s_.offset <= @encoded.ptr and s_.offset + s_.size > @encoded.ptr }
748
+ @encoded.add_export(new_label("#{s.name}_#{n}"), @encoded.ptr, true)
749
+ end
750
+
751
+ original_word = decode_word
752
+
753
+ # decode addend if needed
754
+ case reloc.type
755
+ when 'NONE' # no addend
756
+ else addend = reloc.addend || Expression.make_signed(original_word, 32)
757
+ end
758
+
759
+ case reloc.type
760
+ when 'NONE'
761
+ when '32', '32_PCREL'
762
+ target = reloc_target(reloc)
763
+ target = Expression[target, :-, reloc.offset] if reloc.type == '32_PCREL'
764
+ target = Expression[target, :+, addend] if addend and addend != 0
765
+ when 'INSN_REL_26'
766
+ target = reloc_target(reloc)
767
+ addend &= 0x3ff_ffff
768
+ target = Expression[target, :+, [addend, :<<, 2]] if addend and addend != 0
769
+ target = Expression[[original_word, :&, 0xfc0_0000], :|, [[target, :&, 0x3ff_ffff], :>>, 2]]
770
+ when 'HI_16_IN_INSN'
771
+ target = reloc_target(reloc)
772
+ addend &= 0xffff
773
+ target = Expression[target, :+, [addend, :<<, 16]] if addend and addend != 0
774
+ target = Expression[[original_word, :&, 0xffff_0000], :|, [[target, :>>, 16], :&, 0xffff]]
775
+ when 'LO_16_IN_INSN'
776
+ target = reloc_target(reloc)
777
+ addend &= 0xffff
778
+ target = Expression[target, :+, addend] if addend and addend != 0
779
+ target = Expression[[original_word, :&, 0xffff_0000], :|, [target, :&, 0xffff]]
780
+ when 'JMP_SLOT'
781
+ target = reloc_target(reloc)
782
+ target = Expression[target, :+, addend] if addend and addend != 0
783
+ else
784
+ puts "W: Elf: unhandled MIPS reloc #{reloc.inspect}" if $VERBOSE
785
+ target = nil
786
+ end
787
+
788
+ Metasm::Relocation.new(Expression[target], :u32, @endianness) if target
789
+ end
790
+
652
791
  class DwarfDebug
653
792
  # decode a DWARF2 'compilation unit'
654
793
  def decode(elf, info, abbrev, str)
@@ -749,12 +888,13 @@ class ELF
749
888
  end
750
889
 
751
890
  # decodes the ELF dynamic tags, interpret them, and decodes symbols and relocs
752
- def decode_segments_dynamic
891
+ def decode_segments_dynamic(decode_relocs=true)
753
892
  return if not dynamic = @segments.find { |s| s.type == 'DYNAMIC' }
754
893
  @encoded.ptr = add_label('dynamic_tags', dynamic.vaddr)
755
894
  decode_tags
756
895
  decode_segments_tags_interpret
757
896
  decode_segments_symbols
897
+ return if not decode_relocs
758
898
  decode_segments_relocs
759
899
  decode_segments_relocs_interpret
760
900
  end
@@ -783,6 +923,7 @@ class ELF
783
923
 
784
924
  # decodes sections, interprets symbols/relocs, fills sections.encoded
785
925
  def decode_sections
926
+ @symbols.clear # the NULL symbol is explicit in the symbol table
786
927
  decode_sections_symbols
787
928
  decode_sections_relocs
788
929
  @sections.each { |s|
@@ -804,7 +945,7 @@ class ELF
804
945
  end
805
946
 
806
947
  def decode_exports
807
- decode_segments_dynamic
948
+ decode_segments_dynamic(false)
808
949
  end
809
950
 
810
951
  # decodes the elf header, and depending on the elf type, decode segments or sections
@@ -819,12 +960,14 @@ class ELF
819
960
 
820
961
  def each_section
821
962
  @segments.each { |s| yield s.encoded, s.vaddr if s.type == 'LOAD' }
822
- return if @header.type != 'REL'
963
+ return if @header.type != 'REL'
823
964
  @sections.each { |s|
824
965
  next if not s.encoded
825
- l = new_label(s.name)
826
- s.encoded.add_export l, 0
827
- yield s.encoded, l
966
+ if not l = s.encoded.inv_export[0] or l != s.name.tr('^a-zA-Z0-9_', '_')
967
+ l = new_label(s.name)
968
+ s.encoded.add_export l, 0
969
+ end
970
+ yield s.encoded, l
828
971
  }
829
972
  end
830
973
 
@@ -833,9 +976,14 @@ class ELF
833
976
  case @header.machine
834
977
  when 'X86_64'; X86_64.new
835
978
  when '386'; Ia32.new
836
- when 'MIPS'; MIPS.new @endianness
979
+ when 'MIPS'; (@header.flags.include?('32BITMODE') ? MIPS64 : MIPS).new(@endianness)
837
980
  when 'PPC'; PPC.new
838
981
  when 'ARM'; ARM.new
982
+ when 'AARCH64'; AArch64.new
983
+ when 'SH'; Sh4.new
984
+ when 'ARC_COMPACT'; ARC.new
985
+ when 'MSP430'; MSP430.new
986
+ when 'OPENRISC'; OpenRisc.new(:latest, @endianness, (@header.flags.include?('NODELAY') ? 0 : 1))
839
987
  else raise "unsupported cpu #{@header.machine}"
840
988
  end
841
989
  end
@@ -912,6 +1060,24 @@ EOC
912
1060
  (d.address_binding[s.value] ||= {})[:$t9] ||= Expression[s.value]
913
1061
  }
914
1062
  d.function[:default] = @cpu.disassembler_default_func
1063
+ when 'sh4'
1064
+ noret = DecodedFunction.new
1065
+ noret.noreturn = true
1066
+ %w[__stack_chk_fail abort exit].each { |fn|
1067
+ d.function[Expression[fn]] = noret
1068
+ }
1069
+ d.function[:default] = @cpu.disassembler_default_func
1070
+ when 'openrisc'
1071
+ old_cp = d.c_parser
1072
+ d.c_parser = nil
1073
+ d.parse_c <<EOC
1074
+ void __libc_start_main(void(*)(), int, char**, void(*)(), void(*)()) __attribute__((noreturn));
1075
+ void __attribute__((noreturn)) exit(int);
1076
+ EOC
1077
+ d.function[Expression['__libc_start_main']] = @cpu.decode_c_function_prototype(d.c_parser, '__libc_start_main')
1078
+ d.function[Expression['exit']] = @cpu.decode_c_function_prototype(d.c_parser, 'exit')
1079
+ d.c_parser = old_cp
1080
+ d.function[:default] = @cpu.disassembler_default_func
915
1081
  end
916
1082
  d
917
1083
  end
@@ -11,7 +11,7 @@ module Metasm
11
11
  class ELF
12
12
  class Header
13
13
  def set_default_values elf
14
- @magic ||= "\x7fELF"
14
+ @magic ||= ELF::MAGIC
15
15
  @e_class ||= elf.bitsize.to_s
16
16
  @data ||= (elf.endianness == :big ? 'MSB' : 'LSB')
17
17
  @version ||= 'CURRENT'
@@ -20,10 +20,10 @@ class ELF
20
20
  @phoff ||= elf.segments.empty? ? 0 : elf.new_label('phdr')
21
21
  @shoff ||= elf.sections.length <= 1 ? 0 : elf.new_label('shdr')
22
22
  @flags ||= []
23
- @ehsize ||= Header.size(elf)
24
- @phentsize ||= Segment.size(elf)
23
+ @ehsize ||= Header.sizeof(elf)
24
+ @phentsize ||= Segment.sizeof(elf)
25
25
  @phnum ||= elf.segments.length
26
- @shentsize ||= Section.size(elf)
26
+ @shentsize ||= Section.sizeof(elf)
27
27
  @shnum ||= elf.sections.length
28
28
 
29
29
  super(elf)
@@ -47,8 +47,8 @@ class ELF
47
47
  # defines the @name_p field from @name and elf.section[elf.header.shstrndx]
48
48
  # creates .shstrtab if needed
49
49
  def make_name_p elf
50
- return 0 if not name or @name == ''
51
- if elf.header.shstrndx.to_i == 0
50
+ return 0 if not name or @name == '' or elf.header.shnum == 0
51
+ if elf.header.shstrndx.to_i == 0 or not elf.sections[elf.header.shstrndx]
52
52
  sn = Section.new
53
53
  sn.name = '.shstrtab'
54
54
  sn.type = 'STRTAB'
@@ -62,6 +62,7 @@ class ELF
62
62
  return if name_p and sne.data[@name_p, @name.length+1] == @name+0.chr
63
63
  return if @name_p = sne.data.index(@name+0.chr)
64
64
  @name_p = sne.virtsize
65
+ @name.force_encoding('BINARY') if name.respond_to?(:force_encoding)
65
66
  sne << @name << 0
66
67
  end
67
68
  end
@@ -92,6 +93,7 @@ class ELF
92
93
  return if name_p and s[@name_p, @name.length+1] == @name+0.chr
93
94
  return if @name_p = s.index(@name+0.chr)
94
95
  @name_p = strtab.length
96
+ @name.force_encoding('BINARY') if name.respond_to?(:force_encoding)
95
97
  strtab << @name << 0
96
98
  end
97
99
  end
@@ -140,6 +142,9 @@ class ELF
140
142
  srank = rank[s]
141
143
  nexts = @sections.find { |sec| rank[sec] > srank } # find section with rank superior
142
144
  nexts = nexts ? @sections.index(nexts) : -1 # if none, last
145
+ if @header.shstrndx.to_i != 0 and nexts != -1 and @header.shstrndx >= nexts
146
+ @header.shstrndx += 1
147
+ end
143
148
  @sections.insert(nexts, s) # insert section
144
149
  end
145
150
 
@@ -196,6 +201,8 @@ class ELF
196
201
 
197
202
  # encodes the symbol dynamic hash table in the .hash section, updates the HASH tag
198
203
  def encode_hash
204
+ return if @symbols.length <= 1
205
+
199
206
  if not hash = @sections.find { |s| s.type == 'HASH' }
200
207
  hash = Section.new
201
208
  hash.name = '.hash'
@@ -236,11 +243,13 @@ class ELF
236
243
  # encodes the symbol table
237
244
  # should have a stable self.sections array (only append allowed after this step)
238
245
  def encode_segments_symbols(strtab)
246
+ return if @symbols.length <= 1
247
+
239
248
  if not dynsym = @sections.find { |s| s.type == 'DYNSYM' }
240
249
  dynsym = Section.new
241
250
  dynsym.name = '.dynsym'
242
251
  dynsym.type = 'DYNSYM'
243
- dynsym.entsize = Symbol.size(self)
252
+ dynsym.entsize = Symbol.sizeof(self)
244
253
  dynsym.addralign = 4
245
254
  dynsym.flags = ['ALLOC']
246
255
  dynsym.info = @symbols[1..-1].find_all { |s| s.bind == 'LOCAL' }.length + 1
@@ -251,7 +260,7 @@ class ELF
251
260
  @symbols.each { |s| dynsym.encoded << s.encode(self, strtab.encoded) } # needs all section indexes, as will be in the final section header
252
261
 
253
262
  @tag['SYMTAB'] = label_at(dynsym.encoded, 0)
254
- @tag['SYMENT'] = Symbol.size(self)
263
+ @tag['SYMENT'] = Symbol.sizeof(self)
255
264
 
256
265
  encode_check_section_size dynsym
257
266
 
@@ -261,7 +270,7 @@ class ELF
261
270
  # encodes the relocation tables
262
271
  # needs a complete self.symbols array
263
272
  def encode_segments_relocs
264
- return if not @relocations
273
+ return if not @relocations or @relocations.empty?
265
274
 
266
275
  arch_preencode_reloc_func = "arch_#{@header.machine.downcase}_preencode_reloc"
267
276
  send arch_preencode_reloc_func if respond_to? arch_preencode_reloc_func
@@ -287,7 +296,7 @@ class ELF
287
296
  @tag['JMPREL'] = label_at(relplt.encoded, 0)
288
297
  @tag['PLTRELSZ'] = relplt.encoded.virtsize
289
298
  @tag['PLTREL'] = relplt.type = stype
290
- @tag[stype + 'ENT'] = relplt.entsize = relplt.addralign = (stype == 'REL' ? Relocation.size(self) : RelocationAddend.size(self))
299
+ @tag[stype + 'ENT'] = relplt.entsize = relplt.addralign = (stype == 'REL' ? Relocation.sizeof(self) : RelocationAddend.sizeof(self))
291
300
  encode_check_section_size relplt
292
301
  end
293
302
 
@@ -305,13 +314,13 @@ class ELF
305
314
  rel.name = '.rel.dyn'
306
315
  rel.type = 'REL'
307
316
  rel.flags = ['ALLOC']
308
- rel.entsize = rel.addralign = Relocation.size(self)
317
+ rel.entsize = rel.addralign = Relocation.sizeof(self)
309
318
  encode_add_section rel
310
319
  end
311
320
  rel.encoded = EncodedData.new
312
321
  list.each { |r| rel.encoded << r.encode(self) }
313
322
  @tag['REL'] = label_at(rel.encoded, 0)
314
- @tag['RELENT'] = Relocation.size(self)
323
+ @tag['RELENT'] = Relocation.sizeof(self)
315
324
  @tag['RELSZ'] = rel.encoded.virtsize
316
325
  encode_check_section_size rel
317
326
  end
@@ -323,13 +332,13 @@ class ELF
323
332
  rela.name = '.rela.dyn'
324
333
  rela.type = 'RELA'
325
334
  rela.flags = ['ALLOC']
326
- rela.entsize = rela.addralign = RelocationAddend.size(self)
335
+ rela.entsize = rela.addralign = RelocationAddend.sizeof(self)
327
336
  encode_add_section rela
328
337
  end
329
338
  rela.encoded = EncodedData.new
330
339
  list.each { |r| rela.encoded << r.encode(self) }
331
340
  @tag['RELA'] = label_at(rela.encoded, 0)
332
- @tag['RELAENT'] = RelocationAddend.size(self)
341
+ @tag['RELAENT'] = RelocationAddend.sizeof(self)
333
342
  @tag['RELASZ'] = rela.encoded.virtsize
334
343
  encode_check_section_size rela
335
344
  end
@@ -337,6 +346,8 @@ class ELF
337
346
 
338
347
  # creates the .plt/.got from the @relocations
339
348
  def arch_386_preencode_reloc
349
+ return if @relocations.empty?
350
+
340
351
  # if .got.plt does not exist, the dynamic loader segfaults
341
352
  if not gotplt = @sections.find { |s| s.type == 'PROGBITS' and s.name == '.got.plt' }
342
353
  gotplt = Section.new
@@ -358,7 +369,7 @@ class ELF
358
369
  when 'PC32'
359
370
  next if not r.symbol
360
371
 
361
- if r.symbol.type != 'FUNC'
372
+ if r.symbol.type != 'FUNC'
362
373
  # external data xref: generate a GOT entry
363
374
  # XXX reuse .got.plt ?
364
375
  if not got ||= @sections.find { |s| s.type == 'PROGBITS' and s.name == '.got' }
@@ -385,7 +396,7 @@ class ELF
385
396
  else
386
397
  @relocations.delete r
387
398
  end
388
-
399
+
389
400
  # prevoffset is label_section_start + int_section_offset
390
401
  target_s = @sections.find { |s| s.encoded and s.encoded.export[prevoffset.lexpr] == 0 }
391
402
  rel = target_s.encoded.reloc[prevoffset.rexpr]
@@ -411,12 +422,12 @@ class ELF
411
422
  #
412
423
  # [.got.plt header]
413
424
  # dd _DYNAMIC
414
- # dd 0 # rewritten to GOTPLT? by ld-linux
425
+ # dd 0 # rewritten to GOTPLT? by ld-linux
415
426
  # dd 0 # rewritten to dlresolve_inplace by ld-linux
416
427
  #
417
428
  # [.got.plt + func_got_offset]
418
429
  # dd some_func_got_default # lazily rewritten to the real addr of some_func by jmp dlresolve_inplace
419
- # # base_relocated ?
430
+ # # base_relocated ?
420
431
 
421
432
  # in the PIC case, _dlresolve imposes us to use the ebx register (which may not be saved by the calling function..)
422
433
  # also geteip trashes eax, which may interfere with regparm(3)
@@ -448,7 +459,7 @@ class ELF
448
459
  plt.encoded << shellcode["jmp [#{base} + #{gotplt.encoded.length}]"]
449
460
  plt.encoded.add_export r.symbol.name+'_plt_default', plt.encoded.length
450
461
  reloffset = @relocations.find_all { |rr| rr.type == 'JMP_SLOT' }.length
451
- reloffset *= Relocation.size(self) if @bitsize == 32
462
+ reloffset *= Relocation.sizeof(self) if @bitsize == 32
452
463
  plt.encoded << shellcode["push #{reloffset}\njmp metasm_plt_start"]
453
464
 
454
465
  # transform the reloc PC32 => JMP_SLOT
@@ -510,6 +521,7 @@ class ELF
510
521
  add_str = lambda { |n|
511
522
  if n and n != '' and not ret = strtab.encoded.data.index(n + 0.chr)
512
523
  ret = strtab.encoded.virtsize
524
+ n.force_encoding('BINARY') if n.respond_to?(:force_encoding)
513
525
  strtab.encoded << n << 0
514
526
  end
515
527
  ret || 0
@@ -531,7 +543,7 @@ class ELF
531
543
 
532
544
  # fill these later, but create the base relocs now
533
545
  arch_create_reloc_func = "arch_#{@header.machine.downcase}_create_reloc"
534
- next if not respond_to?(arch_create_reloc_func)
546
+ next if not respond_to?(arch_create_reloc_func)
535
547
  curaddr = label_at(@encoded, 0, 'elf_start')
536
548
  fkbind = {}
537
549
  @sections.each { |s|
@@ -557,6 +569,9 @@ class ELF
557
569
 
558
570
  encode_check_section_size strtab
559
571
 
572
+ # rm unused tag (shrink .nointerp binaries by allowing to skip the section entirely)
573
+ @tag.delete('STRTAB') if strtab.encoded.length == 1
574
+
560
575
  # XXX any order needed ?
561
576
  @tag.keys.each { |k|
562
577
  case k
@@ -581,7 +596,7 @@ class ELF
581
596
  encode_tag[k, @tag[k]]
582
597
  end
583
598
  }
584
- encode_tag['NULL', @tag['NULL'] || 0]
599
+ encode_tag['NULL', @tag['NULL'] || 0] unless @tag.empty?
585
600
 
586
601
  encode_check_section_size dynamic
587
602
  end
@@ -598,17 +613,13 @@ class ELF
598
613
  @sections.each { |s|
599
614
  next if not s.encoded
600
615
  s.encoded.reloc.each_value { |r|
601
- t = Expression[r.target.reduce]
602
- if t.op == :+ and t.rexpr.kind_of? Expression and t.rexpr.op == :- and not t.rexpr.lexpr and
603
- t.rexpr.rexpr.kind_of?(::String) and t.lexpr.kind_of?(::String)
604
- symname = t.lexpr
605
- else
606
- symname = t.reduce_rec
607
- end
608
- next if not dll = autoexports[symname]
616
+ et = r.target.externals
617
+ extern = et.find_all { |name| autoexports[name] }
618
+ next if extern.length != 1
619
+ symname = extern.first
609
620
  if not @symbols.find { |sym| sym.name == symname }
610
621
  @tag['NEEDED'] ||= []
611
- @tag['NEEDED'] |= [dll]
622
+ @tag['NEEDED'] |= [autoexports[symname]]
612
623
  sym = Symbol.new
613
624
  sym.shndx = 'UNDEF'
614
625
  sym.type = 'FUNC'
@@ -737,6 +748,55 @@ class ELF
737
748
  @relocations << r
738
749
  end
739
750
 
751
+ def arch_mips_create_reloc(section, off, binding, rel=nil)
752
+ rel ||= section.encoded.reloc[off]
753
+ startaddr = label_at(@encoded, 0)
754
+ r = Relocation.new
755
+ r.offset = Expression[label_at(section.encoded, 0, 'sect_start'), :+, off]
756
+ if Expression[rel.target, :-, startaddr].bind(binding).reduce.kind_of?(::Integer)
757
+ # this location is relative to the base load address of the ELF
758
+ r.type = 'REL32'
759
+ else
760
+ et = rel.target.externals
761
+ extern = et.find_all { |name| not binding[name] }
762
+ if extern.length != 1
763
+ puts "ELF: mips_create_reloc: ignoring reloc #{rel.target} in #{section.name}: #{extern.inspect} unknown" if $VERBOSE
764
+ return
765
+ end
766
+ if not sym = @symbols.find { |s| s.name == extern.first }
767
+ puts "ELF: mips_create_reloc: ignoring reloc #{rel.target} in #{section.name}: undefined symbol #{extern.first}" if $VERBOSE
768
+ return
769
+ end
770
+ r.symbol = sym
771
+ if Expression[rel.target, :-, sym.name].bind(binding).reduce.kind_of?(::Integer)
772
+ rel.target = Expression[rel.target, :-, sym.name]
773
+ r.type = '32'
774
+ elsif Expression[rel.target, :&, 0xffff0000].reduce.kind_of?(::Integer)
775
+ lo = Expression[rel.target, :&, 0xffff].reduce
776
+ lo = lo.lexpr if lo.kind_of?(Expression) and lo.op == :& and lo.rexpr == 0xffff
777
+ if lo.kind_of?(Expression) and lo.op == :>> and lo.rexpr == 16
778
+ r.type = 'HI16'
779
+ rel.target = Expression[rel.target, :&, 0xffff0000]
780
+ # XXX offset ?
781
+ elsif lo.kind_of?(String) or (lo.kind_of(Expression) and lo.op == :+)
782
+ r.type = 'LO16'
783
+ rel.target = Expression[rel.target, :&, 0xffff0000]
784
+ # XXX offset ?
785
+ else
786
+ puts "ELF: mips_create_reloc: ignoring reloc #{lo}: cannot find matching 16 reloc type" if $VERBOSE
787
+ return
788
+ end
789
+ #elsif Expression[rel.target, :+, label_at(section.encoded, 0)].bind(section.encoded.binding).reduce.kind_of? ::Integer
790
+ # rel.target = Expression[[rel.target, :+, label_at(section.encoded, 0)], :+, off]
791
+ # r.type = 'PC32'
792
+ else
793
+ puts "ELF: mips_create_reloc: ignoring reloc #{sym.name} + #{rel.target}: cannot find matching standard reloc type" if $VERBOSE
794
+ return
795
+ end
796
+ end
797
+ @relocations << r
798
+ end
799
+
740
800
  # resets the fields of the elf headers that should be recalculated, eg phdr offset
741
801
  def invalidate_header
742
802
  @header.shoff = @header.shnum = nil
@@ -817,9 +877,13 @@ class ELF
817
877
  end
818
878
 
819
879
  if @header.type == 'REL'
820
- raise 'ET_REL encoding not supported atm, come back later'
880
+ encode_rel
881
+ else
882
+ encode_elf
821
883
  end
884
+ end
822
885
 
886
+ def encode_elf
823
887
  @encoded = EncodedData.new
824
888
  if @header.type != 'EXEC' or @segments.find { |i| i.type == 'INTERP' }
825
889
  # create a .dynamic section unless we are an ET_EXEC with .nointerp
@@ -870,7 +934,7 @@ class ELF
870
934
  end
871
935
 
872
936
  # add dynamic segment
873
- if ds = @sections.find { |sec| sec.type == 'DYNAMIC' }
937
+ if ds = @sections.find { |sec| sec.type == 'DYNAMIC' } and ds.encoded.length > 1
874
938
  ds.set_default_values self
875
939
  seg = Segment.new
876
940
  seg.type = 'DYNAMIC'
@@ -979,6 +1043,36 @@ class ELF
979
1043
  @encoded.data
980
1044
  end
981
1045
 
1046
+ def encode_rel
1047
+ @encoded = EncodedData.new
1048
+ automagic_symbols
1049
+ create_relocations
1050
+
1051
+ @header.phoff = @header.phnum = @header.phentsize = 0
1052
+ @header.entry = 0
1053
+ @sections.each { |sec| sec.addr = 0 }
1054
+ st = @sections.inject(EncodedData.new) { |edata, sec| edata << sec.encode(self) }
1055
+
1056
+ binding = {}
1057
+ @encoded << @header.encode(self)
1058
+ @encoded.align 8
1059
+
1060
+ binding[@header.shoff] = @encoded.length
1061
+ @encoded << st
1062
+ @encoded.align 8
1063
+
1064
+ @sections.each { |sec|
1065
+ next if not sec.encoded
1066
+ binding[sec.offset] = @encoded.length
1067
+ sec.encoded.fixup sec.encoded.binding
1068
+ @encoded << sec.encoded
1069
+ @encoded.align 8
1070
+ }
1071
+
1072
+ @encoded.fixup! binding
1073
+ @encoded.data
1074
+ end
1075
+
982
1076
  def parse_init
983
1077
  # allow the user to specify a section, falls back to .text if none specified
984
1078
  if not defined? @cursource or not @cursource