metasm 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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