metasm 1.0.3 → 1.0.4

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 (114) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +3 -2
  5. data/metasm.gemspec +3 -2
  6. data/metasm.rb +4 -1
  7. data/metasm/compile_c.rb +2 -2
  8. data/metasm/cpu/arc/decode.rb +0 -21
  9. data/metasm/cpu/arc/main.rb +4 -4
  10. data/metasm/cpu/arm/decode.rb +1 -5
  11. data/metasm/cpu/arm/main.rb +3 -3
  12. data/metasm/cpu/arm64/decode.rb +2 -6
  13. data/metasm/cpu/arm64/main.rb +5 -5
  14. data/metasm/cpu/bpf/decode.rb +3 -35
  15. data/metasm/cpu/bpf/main.rb +5 -5
  16. data/metasm/cpu/bpf/render.rb +1 -12
  17. data/metasm/cpu/cy16/decode.rb +0 -6
  18. data/metasm/cpu/cy16/main.rb +3 -3
  19. data/metasm/cpu/cy16/render.rb +0 -11
  20. data/metasm/cpu/dalvik/decode.rb +4 -26
  21. data/metasm/cpu/dalvik/main.rb +20 -2
  22. data/metasm/cpu/dalvik/opcodes.rb +3 -2
  23. data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
  24. data/metasm/cpu/ebpf/debug.rb +61 -0
  25. data/metasm/cpu/ebpf/decode.rb +142 -0
  26. data/metasm/cpu/ebpf/main.rb +58 -0
  27. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  28. data/metasm/cpu/ebpf/render.rb +36 -0
  29. data/metasm/cpu/ia32/debug.rb +39 -1
  30. data/metasm/cpu/ia32/decode.rb +111 -90
  31. data/metasm/cpu/ia32/decompile.rb +45 -37
  32. data/metasm/cpu/ia32/main.rb +10 -0
  33. data/metasm/cpu/ia32/parse.rb +6 -0
  34. data/metasm/cpu/mcs51/decode.rb +1 -1
  35. data/metasm/cpu/mcs51/main.rb +11 -0
  36. data/metasm/cpu/mips/decode.rb +8 -18
  37. data/metasm/cpu/mips/main.rb +3 -3
  38. data/metasm/cpu/mips/opcodes.rb +1 -1
  39. data/metasm/cpu/msp430/decode.rb +2 -6
  40. data/metasm/cpu/msp430/main.rb +3 -3
  41. data/metasm/cpu/openrisc.rb +11 -0
  42. data/metasm/cpu/openrisc/debug.rb +106 -0
  43. data/metasm/cpu/openrisc/decode.rb +182 -0
  44. data/metasm/cpu/openrisc/decompile.rb +350 -0
  45. data/metasm/cpu/openrisc/main.rb +70 -0
  46. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  47. data/metasm/cpu/openrisc/render.rb +37 -0
  48. data/metasm/cpu/ppc/decode.rb +0 -25
  49. data/metasm/cpu/ppc/main.rb +6 -6
  50. data/metasm/cpu/ppc/opcodes.rb +3 -4
  51. data/metasm/cpu/python/decode.rb +0 -20
  52. data/metasm/cpu/python/main.rb +1 -1
  53. data/metasm/cpu/sh4/decode.rb +2 -6
  54. data/metasm/cpu/sh4/main.rb +25 -23
  55. data/metasm/cpu/st20/decode.rb +0 -7
  56. data/metasm/cpu/webasm.rb +11 -0
  57. data/metasm/cpu/webasm/debug.rb +31 -0
  58. data/metasm/cpu/webasm/decode.rb +321 -0
  59. data/metasm/cpu/webasm/decompile.rb +386 -0
  60. data/metasm/cpu/webasm/encode.rb +104 -0
  61. data/metasm/cpu/webasm/main.rb +81 -0
  62. data/metasm/cpu/webasm/opcodes.rb +214 -0
  63. data/metasm/cpu/x86_64/compile_c.rb +13 -9
  64. data/metasm/cpu/x86_64/parse.rb +1 -1
  65. data/metasm/cpu/z80/decode.rb +0 -27
  66. data/metasm/cpu/z80/main.rb +3 -3
  67. data/metasm/cpu/z80/render.rb +0 -11
  68. data/metasm/debug.rb +43 -8
  69. data/metasm/decode.rb +62 -14
  70. data/metasm/decompile.rb +793 -466
  71. data/metasm/disassemble.rb +188 -131
  72. data/metasm/disassemble_api.rb +30 -17
  73. data/metasm/dynldr.rb +2 -2
  74. data/metasm/encode.rb +8 -2
  75. data/metasm/exe_format/autoexe.rb +2 -0
  76. data/metasm/exe_format/coff.rb +21 -3
  77. data/metasm/exe_format/coff_decode.rb +12 -0
  78. data/metasm/exe_format/coff_encode.rb +6 -3
  79. data/metasm/exe_format/dex.rb +13 -3
  80. data/metasm/exe_format/elf.rb +12 -2
  81. data/metasm/exe_format/elf_decode.rb +59 -1
  82. data/metasm/exe_format/main.rb +2 -0
  83. data/metasm/exe_format/mz.rb +1 -0
  84. data/metasm/exe_format/pe.rb +25 -3
  85. data/metasm/exe_format/wasm.rb +402 -0
  86. data/metasm/gui/dasm_decomp.rb +171 -95
  87. data/metasm/gui/dasm_graph.rb +61 -2
  88. data/metasm/gui/dasm_hex.rb +2 -2
  89. data/metasm/gui/dasm_main.rb +45 -19
  90. data/metasm/gui/debug.rb +13 -4
  91. data/metasm/gui/gtk.rb +12 -4
  92. data/metasm/main.rb +108 -103
  93. data/metasm/os/emulator.rb +175 -0
  94. data/metasm/os/main.rb +11 -6
  95. data/metasm/parse.rb +23 -12
  96. data/metasm/parse_c.rb +189 -135
  97. data/metasm/preprocessor.rb +16 -1
  98. data/misc/openrisc-parser.rb +79 -0
  99. data/samples/dasm-plugins/scanxrefs.rb +6 -4
  100. data/samples/dasm-plugins/selfmodify.rb +8 -8
  101. data/samples/dbg-plugins/trace_func.rb +1 -1
  102. data/samples/disassemble-gui.rb +14 -3
  103. data/samples/emubios.rb +251 -0
  104. data/samples/emudbg.rb +127 -0
  105. data/samples/lindebug.rb +79 -78
  106. data/samples/metasm-shell.rb +8 -8
  107. data/tests/all.rb +1 -1
  108. data/tests/expression.rb +2 -0
  109. data/tests/graph_layout.rb +1 -1
  110. data/tests/ia32.rb +1 -0
  111. data/tests/mips.rb +1 -1
  112. data/tests/preprocessor.rb +18 -0
  113. metadata +124 -6
  114. metadata.gz.sig +0 -0
@@ -130,11 +130,6 @@ class DecodedInstruction
130
130
  end
131
131
  end
132
132
 
133
- class CPU
134
- # compat alias, for scripts using older version of metasm
135
- def get_backtrace_binding(di) backtrace_binding(di) end
136
- end
137
-
138
133
  class Disassembler
139
134
  # access the default value for @@backtrace_maxblocks for newly created Disassemblers
140
135
  def self.backtrace_maxblocks ; @@backtrace_maxblocks ; end
@@ -210,8 +205,8 @@ class Disassembler
210
205
  alias instructionblocks each_instructionblock
211
206
 
212
207
  # return a backtrace_binding reversed (akin to code emulation) (but not really)
213
- def get_fwdemu_binding(di, pc=nil)
214
- @cpu.get_fwdemu_binding(di, pc)
208
+ def get_fwdemu_binding(di, pc=nil, dbg_ctx=nil)
209
+ @cpu.get_fwdemu_binding(di, pc, dbg_ctx)
215
210
  end
216
211
 
217
212
  # reads len raw bytes from the mmaped address space
@@ -276,7 +271,7 @@ class Disassembler
276
271
  if b = block_at(from_addr)
277
272
  b.add_to_normal(addr)
278
273
  end
279
- @addrs_todo << [addr, from_addr]
274
+ @addrs_todo << { :addr => addr, :from => from_addr }
280
275
  disassemble
281
276
  end
282
277
 
@@ -286,6 +281,12 @@ class Disassembler
286
281
  e.inv_export[e.ptr] if e
287
282
  end
288
283
 
284
+ # return the array of all labels associated to an addr
285
+ def get_all_labels_at(addr)
286
+ addr = normalize(addr)
287
+ label_alias[addr].to_a
288
+ end
289
+
289
290
  # sets the label for the specified address
290
291
  # returns nil if the address is not mapped
291
292
  # memcheck is passed to get_section_at to validate that the address is mapped
@@ -295,6 +296,7 @@ class Disassembler
295
296
  e, b = get_section_at(addr, memcheck)
296
297
  if not e
297
298
  elsif not l = e.inv_export[e.ptr] or (!overwrite and l != name)
299
+ split_block(addr)
298
300
  l = @program.new_label(name)
299
301
  e.add_export l, e.ptr
300
302
  @label_alias_cache = nil
@@ -683,7 +685,7 @@ class Disassembler
683
685
  # give something equivalent to the code accessible from the (list of) entrypoints given
684
686
  # from the @decoded dasm graph
685
687
  # assume all jump targets have a matching label in @prog_binding
686
- # may add inconditionnal jumps in the listing to preserve the code flow
688
+ # may add inconditional jumps in the listing to preserve the code flow
687
689
  def flatten_graph(entry, include_subfunc=true)
688
690
  ret = []
689
691
  entry = [entry] if not entry.kind_of? Array
@@ -691,11 +693,16 @@ class Disassembler
691
693
  done = []
692
694
  inv_binding = @prog_binding.invert
693
695
  while addr = todo.pop
694
- next if done.include? addr or not di_at(addr)
696
+ next if done.include?(addr)
695
697
  done << addr
696
- b = @decoded[addr].block
697
698
 
698
699
  ret << Label.new(inv_binding[addr]) if inv_binding[addr]
700
+ if not di_at(addr)
701
+ ret << @cpu.instr_jump_stop
702
+ next
703
+ end
704
+
705
+ b = @decoded[addr].block
699
706
  ret.concat b.list.map { |di| di.instruction }
700
707
 
701
708
  b.each_to_otherfunc(self) { |to|
@@ -709,8 +716,8 @@ class Disassembler
709
716
 
710
717
  if not di = b.list[-1-@cpu.delay_slot] or not di.opcode.props[:stopexec] or di.opcode.props[:saveip]
711
718
  to = b.list.last.next_addr
712
- if todo.include? to
713
- if done.include? to or not di_at(to)
719
+ if todo.include?(to) and di_at(to)
720
+ if done.include?(to)
714
721
  if not to_l = inv_binding[to]
715
722
  to_l = auto_label_at(to, 'loc')
716
723
  if done.include? to and idx = ret.index(@decoded[to].block.list.first.instruction)
@@ -721,6 +728,8 @@ class Disassembler
721
728
  else
722
729
  todo << to # ensure it's next in the listing
723
730
  end
731
+ else
732
+ ret << @cpu.instr_jump_stop
724
733
  end
725
734
  end
726
735
  end
@@ -977,7 +986,7 @@ class Disassembler
977
986
  end
978
987
 
979
988
  # loads a map file (addr => symbol)
980
- # off is an optionnal offset to add to every address found (for eg rebased binaries)
989
+ # off is an optional offset to add to every address found (for eg rebased binaries)
981
990
  # understands:
982
991
  # standard map files (eg linux-kernel.map: <addr> <type> <name>, e.g. 'c01001ba t setup_idt')
983
992
  # ida map files (<sectionidx>:<sectionoffset> <name>)
@@ -996,7 +1005,7 @@ class Disassembler
996
1005
  # we do not have section load order, let's just hope that the addresses are sorted (and sortable..)
997
1006
  # could check the 1st part of the file, with section sizes, but it is not very convenient
998
1007
  # the regexp is so that we skip the 1st part with section descriptions
999
- # in the file, section 1 is the 1st section ; we have an additionnal section (exe header) which fixes the 0-index
1008
+ # in the file, section 1 is the 1st section ; we have an additional section (exe header) which fixes the 0-index
1000
1009
  # XXX this is PE-specific, TODO fix it for ELF (ida references sections, we reference segments...)
1001
1010
  addr = sks[$1.to_i(16)] + $2.to_i(16) + off
1002
1011
  set_label_at(addr, $3, false, !seen[addr])
@@ -1137,7 +1146,11 @@ class Disassembler
1137
1146
  addr = Expression.parse(pp).reduce
1138
1147
  len = Expression.parse(pp).reduce
1139
1148
  edata = EncodedData.new(data.unpack('m*').first, :virtsize => len)
1140
- add_section(addr, edata)
1149
+ # check for an existing section, eg from binarypath
1150
+ existing_section = get_section_at(addr)
1151
+ if not existing_section or existing_section[0].data.to_str != edata.data.to_str
1152
+ add_section(addr, edata)
1153
+ end
1141
1154
  when 'map'
1142
1155
  load_map data
1143
1156
  when 'decoded'
@@ -1741,7 +1754,7 @@ class Disassembler
1741
1754
  end
1742
1755
 
1743
1756
  # same as load_plugin, but hides the @gui attribute while loading, preventing the plugin do popup stuff
1744
- # this is useful when you want to load a plugin from another plugin to enhance the plugin's functionnality
1757
+ # this is useful when you want to load a plugin from another plugin to enhance the plugin's functionality
1745
1758
  # XXX this also prevents setting up kbd_callbacks etc..
1746
1759
  def load_plugin_nogui(plugin_filename)
1747
1760
  oldgui = gui
@@ -5,7 +5,7 @@
5
5
 
6
6
  # This sample creates the dynldr.so ruby shared object that allows interaction with
7
7
  # native libraries
8
- # x86 only for now
8
+ # x86/x64 only for now
9
9
 
10
10
  module Metasm
11
11
  class DynLdr
@@ -1229,7 +1229,7 @@ EOS
1229
1229
  cp.alloc_c_struct(structname, values)
1230
1230
  end
1231
1231
 
1232
- # return a C::AllocCStruct mapped over the string (with optionnal offset)
1232
+ # return a C::AllocCStruct mapped over the string (with optional offset)
1233
1233
  # str may be an EncodedData
1234
1234
  def self.decode_c_struct(structname, str, off=0)
1235
1235
  str = str.data if str.kind_of? EncodedData
@@ -214,8 +214,14 @@ class ExeFormat
214
214
 
215
215
  raise EncodeError, "cannot find candidate in #{elem.inspect}, immediate too big #{wantsize.inspect} #{target_bounds.inspect}" if acceptable.empty?
216
216
 
217
- # keep the shortest
218
- acceptable.sort_by { |edata| edata.virtsize }.first
217
+ # keep the shortest, use a hack make sort consistent in all cases
218
+ # see https://8thlight.com/blog/will-warner/2013/03/26/stable-sorting-in-ruby.html
219
+ n = 0
220
+ mod_map = acceptable.map { |edata| n += 1 ; [[edata.virtsize, n], edata] }
221
+ interm_sort = mod_map.sort { |left, right| left[0] <=> right[0] }
222
+ mod_sort_result = interm_sort.collect { |edata| edata[1] }
223
+ result = mod_sort_result.first
224
+ result
219
225
  else
220
226
  elem
221
227
  end
@@ -37,6 +37,7 @@ end
37
37
 
38
38
  # register a new binary file signature
39
39
  def self.register_signature(sig, exe=nil, &b)
40
+ sig.force_encoding('binary') if sig.respond_to?(:force_encoding)
40
41
  (@signatures ||= []) << [sig, exe || b]
41
42
  end
42
43
 
@@ -59,6 +60,7 @@ register_signature("dex\n") { DEX }
59
60
  register_signature("dey\n") { DEY }
60
61
  register_signature("\xfa\x70\x0e\x1f") { FatELF }
61
62
  register_signature("\x50\x4b\x03\x04") { ZIP }
63
+ register_signature("\0asm") { WasmFile }
62
64
  register_signature('Metasm.dasm') { Disassembler }
63
65
 
64
66
  # replacement for AutoExe where #load defaults to a Shellcode of the specified CPU
@@ -213,7 +213,7 @@ class COFF < ExeFormat
213
213
  end
214
214
 
215
215
  # tree-like structure, holds all misc data the program might need (icons, cursors, version information)
216
- # conventionnally structured in a 3-level depth structure:
216
+ # conventionally structured in a 3-level depth structure:
217
217
  # I resource type (icon/cursor/etc, see +TYPES+)
218
218
  # II resource id (icon n1, icon 'toto', ...)
219
219
  # III language-specific version (icon n1 en, icon n1 en-dvorak...)
@@ -230,6 +230,12 @@ class COFF < ExeFormat
230
230
  end
231
231
  end
232
232
 
233
+ # unwind info
234
+ class ExceptionEntry < SerialStruct
235
+ # function start RVA, function end RVA, UNWIND_INFO RVA
236
+ words :func, :func_end, :unwind
237
+ end
238
+
233
239
  # array of relocations to apply to an executable file
234
240
  # when it is loaded at an address that is not its preferred_base_address
235
241
  class RelocationTable < SerialStruct
@@ -258,9 +264,20 @@ class COFF < ExeFormat
258
264
  end
259
265
 
260
266
  class RSDS < SerialStruct
261
- mem :guid, 16
267
+ word :guid_03
268
+ halfs :guid_45, :guid_67
269
+ bytes :guid_8, :guid_9, :guid_a, :guid_b, :guid_c, :guid_d, :guid_e, :guid_f
262
270
  word :age
263
271
  strz :pdbfilename
272
+
273
+ def guid
274
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % [guid_03, guid_45, guid_67, guid_8, guid_9, guid_a, guid_b, guid_c, guid_d, guid_e, guid_f]
275
+ end
276
+
277
+ # http path to pdb (compressed)
278
+ def msdl_url
279
+ "http://msdl.microsoft.com/download/symbols/#{pdbfilename}/#{guid.delete("-")}#{age}/#{pdbfilename.chop}_"
280
+ end
264
281
  end
265
282
  end
266
283
 
@@ -396,7 +413,8 @@ class COFF < ExeFormat
396
413
  end
397
414
 
398
415
  attr_accessor :header, :optheader, :directory, :sections, :endianness, :symbols, :bitsize,
399
- :export, :imports, :resource, :certificates, :relocations, :debug, :tls, :loadconfig, :delayimports, :com_header
416
+ :export, :imports, :resource, :exception_table, :certificates,
417
+ :relocations, :debug, :tls, :loadconfig, :delayimports, :com_header
400
418
 
401
419
  # boolean, set to true to have #decode() ignore the base_relocs directory
402
420
  attr_accessor :nodecode_relocs
@@ -639,6 +639,17 @@ class COFF
639
639
  resource.decode_version(self, lang)
640
640
  end
641
641
 
642
+ # decode the exception table, holding the start and end of every function in the binary (x64)
643
+ # includes a pointer to the UNWIND_INFO structure for exception handling
644
+ def decode_exception_table
645
+ if et = @directory['exception_table'] and sect_at_rva(et[0])
646
+ @exception_table = []
647
+ (et[1]/12).times {
648
+ @exception_table << ExceptionEntry.decode(self)
649
+ }
650
+ end
651
+ end
652
+
642
653
  # decodes certificate table
643
654
  def decode_certificates
644
655
  if ct = @directory['certificate_table']
@@ -782,6 +793,7 @@ class COFF
782
793
  decode_exports
783
794
  decode_imports
784
795
  decode_resources
796
+ decode_exception_table
785
797
  decode_certificates
786
798
  decode_debug
787
799
  decode_tls
@@ -172,6 +172,7 @@ class COFF
172
172
  @iat_p ||= Expression[coff.label_at(edata['iat'].last, 0, 'iat'), :-, coff.label_at(coff.encoded, 0)]
173
173
  edata['idata'] << super(coff)
174
174
 
175
+ @libname.force_encoding('BINARY') if @libname.respond_to?(:force_encoding)
175
176
  edata['nametable'] << @libname << 0
176
177
 
177
178
  ord_mask = 1 << (coff.bitsize - 1)
@@ -182,6 +183,7 @@ class COFF
182
183
  else
183
184
  edata['nametable'].align 2
184
185
  ptr = coff.encode_xword(rva_end['nametable'])
186
+ i.name.force_encoding('BINARY') if i.name.respond_to?(:force_encoding)
185
187
  edata['nametable'] << coff.encode_half(i.hint || 0) << i.name << 0
186
188
  end
187
189
  edata['ilt'] << ptr
@@ -510,8 +512,8 @@ class COFF
510
512
 
511
513
  s.encoded.reloc.each { |off, rel|
512
514
  # check that the relocation looks like "program_start + integer" when bound using the fake binding
513
- # XXX allow :i32 etc
514
- if rel.endianness == @endianness and [:u32, :a32, :u64, :a64].include?(rel.type) and
515
+ # TODO relocate refs to IAT (eg plt)
516
+ if rel.endianness == @endianness and [:i32, :u32, :a32, :i64, :u64, :a64].include?(rel.type) and
515
517
  rel.target.bind(binding).reduce.kind_of?(Expression) and
516
518
  Expression[rel.target, :-, startaddr].bind(binding).reduce.kind_of?(::Integer)
517
519
  # winner !
@@ -519,7 +521,7 @@ class COFF
519
521
  # build relocation
520
522
  r = RelocationTable::Relocation.new
521
523
  r.offset = off & 0xfff
522
- r.type = { :u32 => 'HIGHLOW', :u64 => 'DIR64', :a32 => 'HIGHLOW', :a64 => 'DIR64' }[rel.type]
524
+ r.type = { '32' => 'HIGHLOW', '64' => 'DIR64' }[rel.type.to_s[1, 2]]
523
525
 
524
526
  # check if we need to start a new relocation table
525
527
  if rt.base_addr and (rt.base_addr & ~0xfff) != (off & ~0xfff)
@@ -626,6 +628,7 @@ class COFF
626
628
  end
627
629
  end
628
630
  s.rawaddr = nil if s.rawaddr.kind_of?(::Integer) # XXX allow to force rawaddr ?
631
+ s.name.force_encoding('BINARY') if s.name.respond_to?(:force_encoding)
629
632
  s_table << s.encode(self)
630
633
  }
631
634
 
@@ -331,17 +331,27 @@ class DEX < ExeFormat
331
331
  def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
332
332
  def sizeof_u2 ; 2 ; end
333
333
  def sizeof_u4 ; 4 ; end
334
+ def encode_uleb(val, signed=false)
335
+ v = val
336
+ out = EncodedData.new
337
+ while v > 0x7f or v < -0x40 or (signed and v > 0x3f)
338
+ out << Expression[0x80 | (v&0x7f)].encode(:u8, @endianness)
339
+ v >>= 7
340
+ end
341
+ out << Expression[v & 0x7f].encode(:u8, @endianness)
342
+ end
334
343
  def decode_uleb(ed = @encoded, signed=false)
335
344
  v = s = 0
336
- while s < 5*7
345
+ while s < 10*7
337
346
  b = ed.read(1).unpack('C').first.to_i
338
347
  v |= (b & 0x7f) << s
339
- break if (b&0x80) == 0
340
348
  s += 7
349
+ break if (b&0x80) == 0
341
350
  end
342
351
  v = Expression.make_signed(v, s) if signed
343
352
  v
344
353
  end
354
+ def encode_sleb(val) encode_uleb(val, true) end
345
355
  def decode_sleb(ed = @encoded) decode_uleb(ed, true) end
346
356
  attr_accessor :header, :strings, :types, :protos, :fields, :methods, :classes
347
357
 
@@ -425,7 +435,7 @@ class DEX < ExeFormat
425
435
  next if not c.data
426
436
  (c.data.direct_methods + c.data.virtual_methods).each { |m|
427
437
  n = @types[c.classidx] + '->' + m.name
428
- dasm.comment[m.codeoff+m.code.insns_off] = [n]
438
+ dasm.add_comment m.codeoff+m.code.insns_off, n
429
439
  }
430
440
  }
431
441
  dasm.function[:default] = @cpu.disassembler_default_func
@@ -78,7 +78,8 @@ class ELF < ExeFormat
78
78
  'MIPS' => {1 => 'NOREORDER', 2 => 'PIC', 4 => 'CPIC',
79
79
  8 => 'XGOT', 0x10 => '64BIT_WHIRL', 0x20 => 'ABI2',
80
80
  0x40 => 'ABI_ON32', 0x80 => 'OPTIONSFIRST',
81
- 0x100 => '32BITMODE'}
81
+ 0x100 => '32BITMODE'},
82
+ 'OPENRISC' => { 1 => 'NODELAY' },
82
83
  }
83
84
 
84
85
  DYNAMIC_TAG = { 0 => 'NULL', 1 => 'NEEDED', 2 => 'PLTRELSZ', 3 =>
@@ -391,7 +392,16 @@ class ELF < ExeFormat
391
392
  11 => '32S', 12 => '16', 13 => 'PC16', 14 => '8',
392
393
  15 => 'PC8', 16 => 'DTPMOD64', 17 => 'DTPOFF64',
393
394
  18 => 'TPOFF64', 19 => 'TLSGD', 20 => 'TLSLD',
394
- 21 => 'DTPOFF32', 22 => 'GOTTPOFF', 23 => 'TPOFF32' }
395
+ 21 => 'DTPOFF32', 22 => 'GOTTPOFF', 23 => 'TPOFF32' },
396
+ 'OPENRISC' => { 0 => 'NONE', 1 => '32', 2 => '16', 3 => '8',
397
+ 4 => 'LO_16_IN_INSN', 5 => 'HI_16_IN_INSN', 6 => 'INSN_REL_26', 7 => 'GNU_VTENTRY',
398
+ 8 => 'GNU_VTINHERIT', 9 => '32_PCREL', 10 => '16_PCREL', 11 => '8_PCREL',
399
+ 12 => 'GOTPC_HI16', 13 => 'GOTPC_LO16', 14 => 'GOT15', 15 => 'PLT26',
400
+ 16 => 'GOTOFF_HI16', 17 => 'GOTOFF_LO16', 18 => 'COPY', 19 => 'GLOB_DAT',
401
+ 20 => 'JMP_SLOT', 21 => 'RELATIVE', 22 => 'TLS_GD_HI16', 23 => 'TLS_GD_LO16',
402
+ 24 => 'TLS_LDM_HI16', 25 => 'TLS_LDM_LO16', 26 => 'TLS_LDO_HI16', 27 => 'TLS_LDO_LO16',
403
+ 28 => 'TLS_IE_HI16', 29 => 'TLS_IE_LO16', 30 => 'TLS_LE_HI16', 31 => 'TLS_LE_LO16',
404
+ 32 => 'TLS_TPOFF', 33 => 'TLS_DTPOFF', 34 => 'TLS_DTPMOD' },
395
405
  }
396
406
 
397
407
  DEFAULT_INTERP = '/lib/ld-linux.so.2'
@@ -742,6 +742,52 @@ class ELF
742
742
  Metasm::Relocation.new(Expression[target], :u32, @endianness) if target
743
743
  end
744
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
+
745
791
  class DwarfDebug
746
792
  # decode a DWARF2 'compilation unit'
747
793
  def decode(elf, info, abbrev, str)
@@ -930,13 +976,14 @@ class ELF
930
976
  case @header.machine
931
977
  when 'X86_64'; X86_64.new
932
978
  when '386'; Ia32.new
933
- when 'MIPS'; (@header.flags.include?('32BITMODE') ? MIPS64 : MIPS).new @endianness
979
+ when 'MIPS'; (@header.flags.include?('32BITMODE') ? MIPS64 : MIPS).new(@endianness)
934
980
  when 'PPC'; PPC.new
935
981
  when 'ARM'; ARM.new
936
982
  when 'AARCH64'; AArch64.new
937
983
  when 'SH'; Sh4.new
938
984
  when 'ARC_COMPACT'; ARC.new
939
985
  when 'MSP430'; MSP430.new
986
+ when 'OPENRISC'; OpenRisc.new(:latest, @endianness, (@header.flags.include?('NODELAY') ? 0 : 1))
940
987
  else raise "unsupported cpu #{@header.machine}"
941
988
  end
942
989
  end
@@ -1020,6 +1067,17 @@ EOC
1020
1067
  d.function[Expression[fn]] = noret
1021
1068
  }
1022
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
1023
1081
  end
1024
1082
  d
1025
1083
  end