metasm 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile +1 -0
  4. data/doc/code_organisation.txt +1 -1
  5. data/metasm.gemspec +1 -1
  6. data/metasm.rb +2 -1
  7. data/metasm/cpu/arc/decode.rb +3 -3
  8. data/metasm/cpu/arm/decode.rb +2 -2
  9. data/metasm/cpu/ia32/compile_c.rb +18 -2
  10. data/metasm/cpu/ia32/decode.rb +9 -4
  11. data/metasm/cpu/ia32/decompile.rb +22 -8
  12. data/metasm/cpu/ia32/opcodes.rb +5 -5
  13. data/metasm/cpu/mcs51.rb +8 -0
  14. data/metasm/cpu/mcs51/decode.rb +99 -0
  15. data/metasm/cpu/mcs51/main.rb +76 -0
  16. data/metasm/cpu/mcs51/opcodes.rb +120 -0
  17. data/metasm/cpu/mips/decode.rb +5 -4
  18. data/metasm/cpu/st20.rb +9 -0
  19. data/metasm/cpu/st20/decode.rb +180 -0
  20. data/metasm/cpu/st20/decompile.rb +283 -0
  21. data/metasm/cpu/st20/main.rb +37 -0
  22. data/metasm/cpu/st20/opcodes.rb +140 -0
  23. data/metasm/cpu/x86_64/encode.rb +4 -2
  24. data/metasm/cpu/x86_64/opcodes.rb +4 -2
  25. data/metasm/decode.rb +16 -15
  26. data/metasm/decompile.rb +1 -1
  27. data/metasm/disassemble.rb +3 -1
  28. data/metasm/disassemble_api.rb +3 -1
  29. data/metasm/dynldr.rb +9 -3
  30. data/metasm/encode.rb +2 -2
  31. data/metasm/exe_format/coff.rb +3 -1
  32. data/metasm/exe_format/coff_decode.rb +5 -3
  33. data/metasm/exe_format/elf.rb +4 -0
  34. data/metasm/exe_format/elf_decode.rb +1 -2
  35. data/metasm/exe_format/elf_encode.rb +4 -1
  36. data/metasm/exe_format/macho.rb +20 -6
  37. data/metasm/exe_format/pe.rb +1 -1
  38. data/metasm/exe_format/serialstruct.rb +1 -1
  39. data/metasm/gui.rb +1 -1
  40. data/metasm/gui/dasm_hex.rb +2 -2
  41. data/metasm/gui/dasm_main.rb +8 -8
  42. data/metasm/gui/debug.rb +4 -4
  43. data/metasm/gui/gtk.rb +1 -1
  44. data/metasm/gui/qt.rb +2 -2
  45. data/metasm/gui/win32.rb +1 -1
  46. data/metasm/main.rb +11 -6
  47. data/metasm/os/windows.rb +26 -23
  48. data/misc/hexdump.rb +2 -2
  49. data/misc/objdiff.rb +4 -1
  50. data/misc/objscan.rb +1 -1
  51. data/samples/dasm-plugins/bindiff.rb +1 -1
  52. data/samples/dasm-plugins/scanxrefs.rb +2 -1
  53. data/samples/dynamic_ruby.rb +24 -25
  54. data/samples/elfencode.rb +15 -0
  55. data/samples/exeencode.rb +2 -2
  56. data/samples/metasm-shell.rb +67 -55
  57. data/tests/mcs51.rb +27 -0
  58. metadata +13 -2
@@ -22,7 +22,10 @@ def Object.diff(o1, o2)
22
22
  h["[#{k.inspect}]"] = d if not d.empty?
23
23
  }
24
24
  else
25
- a = (@@diff_accessor_cache ||= {})[o1.class] ||= (im = o1.class.public_instance_methods.grep(/^[a-z]/) ; (im & im.map { |m| m + '=' }).map { |m| m.chop }.find_all { |m| o1.instance_variable_get('@'+m) })
25
+ a = ($diff_accessor_cache ||= {})[o1.class] ||= (
26
+ im = o1.class.public_instance_methods.map { |m| m.to_s }.grep(/^[a-z]/)
27
+ (im & im.map { |m| m+'=' }).map { |m| m.chop }.find_all { |m| o1.instance_variable_get('@'+m) }
28
+ )
26
29
  if a.empty?
27
30
  return o1 == o2 ? h : [o1, o2]
28
31
  end
@@ -26,7 +26,7 @@ class Object
26
26
  end
27
27
  scan_iter { |v, p|
28
28
  case v
29
- when Fixnum, Symbol; next
29
+ when Integer, Symbol; next
30
30
  end
31
31
  p = path+p
32
32
  if done[v.object_id]
@@ -8,7 +8,7 @@
8
8
 
9
9
  require File.join(Metasm::Metasmdir, 'samples', 'bindiff.rb')
10
10
 
11
- Gui::DasmWindow.new("bindiff target").promptopen("chose bindiff target") { |w|
11
+ Gui::DasmWindow.new("bindiff target").promptopen("choose bindiff target") { |w|
12
12
  w.title = "#{w.widget.dasm.program.filename} - metasm bindiff"
13
13
  @bindiff_win = BinDiffWindow.new(self, w.widget.dasm)
14
14
  }
@@ -7,11 +7,12 @@
7
7
  # metasm dasm plugin: scan for xrefs to the target address, incl. relative offsets (eg near call/jmp)
8
8
  def scanxrefs(target)
9
9
  ans = []
10
+ msk = (1 << cpu.size) - 1
10
11
  sections.sort.each { |s_addr, edata|
11
12
  raw = edata.data.to_str
12
13
  (0..raw.length-4).each { |off|
13
14
  r = raw[off, 4].unpack('V').first
14
- ans << (s_addr + off) if (r + off+4 + s_addr)&0xffffffff == target or r == target
15
+ ans << (s_addr + off) if (r + off+4 + s_addr) & msk == target or r == target
15
16
  }
16
17
  }
17
18
  ans
@@ -452,8 +452,8 @@ EOS
452
452
  end
453
453
 
454
454
  # compile a case/when
455
- # create a real C switch() for Fixnums, and put the others === in the default case
456
- # XXX will get the wrong order for "case x; when 1; when Fixnum; when 3;" ...
455
+ # create a real C switch() for Integers, and put the others === in the default case
456
+ # XXX will get the wrong order for "case x; when 1; when Integer; when 3;" ...
457
457
  def compile_case(ast, scope, want_value)
458
458
  # this generates
459
459
  # var = stuff_to_test()
@@ -472,7 +472,7 @@ EOS
472
472
  # else {
473
473
  # default();
474
474
  # }
475
- #
475
+ #
476
476
  if want_value == true
477
477
  ret = get_new_tmp_var('case', want_value)
478
478
  want_value = ret
@@ -498,7 +498,7 @@ EOS
498
498
  raise Fail if cs[1][0] != :array
499
499
 
500
500
  # numeric case, add a case to body_int
501
- if cs[1][1..-1].all? { |cd| cd[0] == :lit and (cd[1].kind_of? Fixnum or cd[1].kind_of? Range) }
501
+ if cs[1][1..-1].all? { |cd| cd[0] == :lit and (cd[1].kind_of? Integer or cd[1].kind_of? Range) }
502
502
  cs[1][1..-1].each { |cd|
503
503
  if cd[1].kind_of? Range
504
504
  b = cd[1].begin
@@ -520,7 +520,7 @@ EOS
520
520
  else
521
521
  cnd = nil
522
522
  cs[1][1..-1].each { |cd|
523
- if (cd[0] == :lit and (cd[1].kind_of?(Fixnum) or cd[1].kind_of?(Symbol))) or
523
+ if (cd[0] == :lit and (cd[1].kind_of?(Integer) or cd[1].kind_of?(Symbol))) or
524
524
  [:nil, :true, :false].include?(cd[0])
525
525
  # true C equality
526
526
  cd = C::CExpression[var, :==, ast_to_c(cd, scope)]
@@ -541,7 +541,7 @@ EOS
541
541
  cb = C::Block.new(scope)
542
542
  v = ast_to_c(cs[2], cb, want_value)
543
543
  cb.statements << C::CExpression[ret, :'=', v] if want_value and v != ret
544
-
544
+
545
545
  fu = C::If.new(cnd, cb, nil)
546
546
 
547
547
  if body_other
@@ -659,7 +659,7 @@ EOS
659
659
  end
660
660
 
661
661
  # retrieve the current class, from self->klass
662
- # XXX will segfault with self.kind_of? Fixnum/true/false/nil/sym
662
+ # XXX will segfault with self.kind_of? Integer/true/false/nil/sym
663
663
  def rb_selfclass
664
664
  rb_cast_pvalue(rb_self, 1)
665
665
  end
@@ -810,7 +810,7 @@ EOS
810
810
  # if want_value is a C::Variable, the statements should try to populate this var instead of some random tmp var
811
811
  # eg to simplify :if encoding unless we have 'foo = if 42;..'
812
812
  def ast_to_c(ast, scope, want_value = true)
813
- ret =
813
+ ret =
814
814
  case ast.to_a[0]
815
815
  when :block
816
816
  if ast[1]
@@ -1085,13 +1085,13 @@ EOS
1085
1085
  case ast[1][0]
1086
1086
  when :ivar
1087
1087
  fcall('rb_ivar_defined', rb_self, rb_intern(ast[1][1]))
1088
- else
1088
+ else
1089
1089
  raise Fail, "unsupported #{ast.inspect}"
1090
1090
  end
1091
1091
  when :masgn
1092
1092
  # parallel assignment: put everything in an Array, then pop everything back?
1093
1093
  rb_masgn(ast, scope, want_value)
1094
-
1094
+
1095
1095
  when :evstr
1096
1096
  fcall('rb_obj_as_string', ast_to_c(ast[1], scope))
1097
1097
  when :dot2, :dot3
@@ -1138,7 +1138,7 @@ EOS
1138
1138
  args = ast[3][1..-1] if ast[3] and ast[3][0] == :array
1139
1139
  arg0 = args[0] if args and args[0]
1140
1140
 
1141
- if arg0 and arg0[0] == :lit and arg0[1].kind_of?(Fixnum) and %w[== > < >= <= + -].include?(op)
1141
+ if arg0 and arg0[0] == :lit and arg0[1].kind_of?(Integer) and %w[== > < >= <= + -].include?(op)
1142
1142
  # TODO or @optim_hint[ast[1]] == 'fixnum'
1143
1143
  # optimize 'x==42', 'x+42', 'x-42'
1144
1144
  o2 = arg0[1]
@@ -1146,7 +1146,7 @@ EOS
1146
1146
  # need o2 >= 0 for overflow detection
1147
1147
  op = {'+' => '-', '-' => '+'}[op]
1148
1148
  o2 = -o2
1149
- return if not o2.kind_of? Fixnum # -0x40000000
1149
+ return if not o2.kind_of? Integer # -0x40000000
1150
1150
  end
1151
1151
 
1152
1152
  int_v = o2.object_id
@@ -1159,11 +1159,11 @@ EOS
1159
1159
 
1160
1160
  case op
1161
1161
  when '=='
1162
- # XXX assume == only return true for full equality: if not Fixnum, then always false
1162
+ # XXX assume == only return true for full equality: if not Integer, then always false
1163
1163
  # which breaks 1.0 == 1 and maybe others, but its ok
1164
1164
  scope.statements << C::If.new(ce[recv, :'==', [int_v]], ce[tmp, :'=', rb_true], ce[tmp, :'=', rb_false])
1165
1165
  when '>', '<', '>=', '<='
1166
- # do the actual comparison on signed >>1 if both Fixnum
1166
+ # do the actual comparison on signed >>1 if both Integer
1167
1167
  t = C::If.new(
1168
1168
  ce[[[[recv], int], :>>, [1]], op.to_sym, [[[int_v], int], :>>, [1]]],
1169
1169
  ce[tmp, :'=', rb_true],
@@ -1194,7 +1194,7 @@ EOS
1194
1194
  end
1195
1195
  end
1196
1196
  tmp
1197
-
1197
+
1198
1198
  # Symbol#==
1199
1199
  elsif arg0 and arg0[0] == :lit and arg0[1].kind_of? Symbol and op == '=='
1200
1200
  s_v = ast_to_c(arg0, scope)
@@ -1244,13 +1244,13 @@ EOS
1244
1244
 
1245
1245
  ar = C::Block.new(scope)
1246
1246
  ar.statements << ce[idx, :'=', [[[arg], int], :>>, [1]]]
1247
- ar.statements << C::If.new(ce[idx, :<, [0]], ce[idx, :'=', [idx, :+, rb_ary_len(recv)]], nil)
1247
+ ar.statements << C::If.new(ce[idx, :<, [0]], ce[idx, :'=', [idx, :+, rb_ary_len(recv)]], nil)
1248
1248
  ar.statements << C::If.new(ce[[idx, :<, [0]], :'||', [idx, :>=, [[rb_ary_len(recv)], int]]],
1249
1249
  ce[tmp, :'=', rb_nil],
1250
1250
  ce[tmp, :'=', rb_ary_ptr(recv, idx)])
1251
1251
  st = C::Block.new(scope)
1252
1252
  st.statements << ce[idx, :'=', [[[arg], int], :>>, [1]]]
1253
- st.statements << C::If.new(ce[idx, :<, [0]], ce[idx, :'=', [idx, :+, rb_str_len(recv)]], nil)
1253
+ st.statements << C::If.new(ce[idx, :<, [0]], ce[idx, :'=', [idx, :+, rb_str_len(recv)]], nil)
1254
1254
  st.statements << C::If.new(ce[[idx, :<, [0]], :'||', [idx, :>=, [[rb_str_len(recv)], int]]],
1255
1255
  ce[tmp, :'=', rb_nil],
1256
1256
  ce[tmp, :'=', [[[[rb_str_ptr(recv, idx), :&, [0xff]], :<<, [1]], :|, [1]], value]])
@@ -1304,8 +1304,7 @@ EOS
1304
1304
  when 'Symbol'
1305
1305
  tmp = get_new_tmp_var('kindof', want_value)
1306
1306
  ce[[ast_to_c(ast[1], scope, tmp), :'&', [0xf]], :'==', [0xe]]
1307
- #when 'Numeric', 'Integer'
1308
- when 'Fixnum'
1307
+ when 'Integer'
1309
1308
  tmp = get_new_tmp_var('kindof', want_value)
1310
1309
  ce[ast_to_c(ast[1], scope, tmp), :'&', [0x1]]
1311
1310
  when 'Array'
@@ -1503,7 +1502,7 @@ puts "shortcut may be incorrect for #{ast.inspect}" if arg0[0] == :const
1503
1502
  elsif b_recv[0] == :call and not b_recv[3] and b_recv[2] == 'times'
1504
1503
  limit = get_new_tmp_var('limit')
1505
1504
  recv = ast_to_c(b_recv[1], scope, limit)
1506
- scope.statements << C::If.new(C::CExpression[:'!', [recv, :&, 1]], rb_raise('only Fixnum#times handled'), nil)
1505
+ scope.statements << C::If.new(C::CExpression[:'!', [recv, :&, 1]], rb_raise('only Integer#times handled'), nil)
1507
1506
  if want_value
1508
1507
  scope.statements << C::CExpression[@iter_break, :'=', recv]
1509
1508
  end
@@ -1553,7 +1552,7 @@ puts "shortcut may be incorrect for #{ast.inspect}" if arg0[0] == :const
1553
1552
  body.statements << C::CExpression[dvar(b_args[1]), :'=', [rb_ary_ptr(ary), :'[]', [cntr]]]
1554
1553
  end
1555
1554
  # same as #each up to this point (except default retval), now add a 'if (body_value) break ary[cntr];'
1556
- # XXX 'find { next true }'
1555
+ # XXX 'find { next true }'
1557
1556
 
1558
1557
  found = ast_to_c(b_body, body)
1559
1558
  t = C::Block.new(body)
@@ -1580,7 +1579,7 @@ puts "shortcut may be incorrect for #{ast.inspect}" if arg0[0] == :const
1580
1579
  body.statements << C::CExpression[dvar(b_args[1]), :'=', [rb_ary_ptr(ary), :'[]', [cntr]]]
1581
1580
  end
1582
1581
  # same as #each up to this point (except default retval), now add a '@iter_break << body_value'
1583
- # XXX 'next' unhandled
1582
+ # XXX 'next' unhandled
1584
1583
 
1585
1584
  val = ast_to_c(b_body, body)
1586
1585
  body.statements << fcall('rb_ary_push', @iter_break, val)
@@ -1642,7 +1641,7 @@ static void do_init_once(void) {
1642
1641
  // rb_define_method(const_Lol, "method", method, 2);
1643
1642
  }
1644
1643
 
1645
- int Init_compiledruby(void) __attribute__((export)) {
1644
+ int Init_compiledruby(void) __attribute__((export)) {
1646
1645
  // use a separate func to avoid having to append statements before the 'return'
1647
1646
  do_init_once();
1648
1647
  return 0;
@@ -1664,7 +1663,7 @@ EOS
1664
1663
  @compiled_func_cache[[klass, method.to_s, singleton]] = @cur_cfunc
1665
1664
 
1666
1665
  cls = rb_const(nil, klass)
1667
-
1666
+
1668
1667
  init.statements << fcall("rb_define#{'_singleton' if singleton}_method", cls, method.to_s, @cur_cfunc, method_arity)
1669
1668
 
1670
1669
  mname
@@ -1699,7 +1698,7 @@ EOS
1699
1698
  @cp.toplevel.symbol[n] || declare_newtopvar(n, fcall('rb_intern', sym.to_s), C::BaseType.new(:int, :unsigned))
1700
1699
  end
1701
1700
 
1702
- # rb_const 'FOO', Bar::Baz ==>
1701
+ # rb_const 'FOO', Bar::Baz ==>
1703
1702
  # const_Bar = rb_const_get(rb_cObject, rb_intern("Bar"));
1704
1703
  # const_Bar_Baz = rb_const_get(const_Bar, rb_intern("Baz"));
1705
1704
  # const_Bar_Baz_FOO = rb_const_get(const_Bar_Baz, rb_intern("FOO"));
@@ -14,12 +14,27 @@ __END__
14
14
  // .nointerp // to disable the dynamic section, eg for stuff with int80 only
15
15
  .text
16
16
  .entrypoint
17
+ #if defined __i386__
17
18
  push bla
18
19
  push fmt
19
20
  call printf
21
+
20
22
  push 0
21
23
  call exit
22
24
 
25
+ #elif defined __amd64__
26
+ lea rsi, [rip+bla-$_]
27
+ lea rdi, [rip+fmt-$_]
28
+ xor rax, rax
29
+ call printf
30
+
31
+ mov rdi, 0
32
+ call exit
33
+
34
+ #else
35
+ unsupported architecture!
36
+ #endif
37
+
23
38
  .data
24
39
  bla db "world", 0
25
40
  fmt db "Hello, %s !\n", 0
@@ -94,7 +94,7 @@ if $opts[:to_string]
94
94
  end
95
95
 
96
96
  if of = $opts[:outfilename]
97
- abort "Error: target file #{of.inspect} exists !" if File.exists?(of) and $opts[:nooverwrite_outfile]
97
+ abort "Error: target file #{of.inspect} exists !" if File.exist?(of) and $opts[:nooverwrite_outfile]
98
98
  File.open(of, 'w') { |fd| fd.puts str }
99
99
  puts "saved to file #{of.inspect}"
100
100
  else
@@ -102,7 +102,7 @@ if $opts[:to_string]
102
102
  end
103
103
  else
104
104
  of = $opts[:outfilename] ||= 'a.out'
105
- abort "Error: target file #{of.inspect} exists !" if File.exists?(of) and $opts[:nooverwrite_outfile]
105
+ abort "Error: target file #{of.inspect} exists !" if File.exist?(of) and $opts[:nooverwrite_outfile]
106
106
  Metasm::DynLdr.compile_binary_module_hack(exe) if $opts[:dldrhack]
107
107
  exe.encode_file(of, $opts[:exetype])
108
108
  puts "saved to file #{of.inspect}"
@@ -18,73 +18,85 @@
18
18
  # > exit
19
19
 
20
20
  require 'metasm'
21
+ require 'readline'
21
22
 
22
23
  class String
23
- @@cpu = Metasm::Ia32.new
24
- class << self
25
- def cpu() @@cpu end
26
- def cpu=(c)
27
- c = Metasm.const_get(c).new if c.kind_of? String
28
- @@cpu=c
29
- end
30
- end
24
+ @@cpu = Metasm::Ia32.new
25
+ class << self
26
+ def cpu() @@cpu end
27
+ def cpu=(c)
28
+ c = Metasm.const_get(c).new if c.kind_of? String
29
+ @@cpu=c
30
+ end
31
+ end
31
32
 
32
- # encodes the current string as a Shellcode, returns the resulting EncodedData
33
- def encode_edata
34
- Metasm::Shellcode.assemble(@@cpu, self).encode.encoded
35
- end
33
+ # encodes the current string as a Shellcode, returns the resulting EncodedData
34
+ def encode_edata
35
+ Metasm::Shellcode.assemble(@@cpu, self).encode.encoded
36
+ end
36
37
 
37
- # encodes the current string as a Shellcode, returns the resulting binary String
38
- # outputs warnings on unresolved relocations
39
- def encode
40
- ed = encode_edata
41
- if not ed.reloc.empty?
42
- puts 'W: encoded string has unresolved relocations: ' + ed.reloc.map { |o, r| r.target.inspect }.join(', ')
43
- end
44
- ed.fill
45
- ed.data
46
- end
38
+ # encodes the current string as a Shellcode, returns the resulting binary String
39
+ # outputs warnings on unresolved relocations
40
+ def encode
41
+ ed = encode_edata
42
+ if not ed.reloc.empty?
43
+ puts 'W: encoded string has unresolved relocations: ' + ed.reloc.map { |o, r| r.target.inspect }.join(', ')
44
+ end
45
+ ed.fill
46
+ ed.data
47
+ end
47
48
 
48
- # decodes the current string as a Shellcode, with specified base address
49
- # returns the resulting Disassembler
50
- def decode_blocks(base_addr=0, eip=base_addr)
51
- sc = Metasm::Shellcode.decode(self, @@cpu)
52
- sc.base_addr = base_addr
53
- sc.disassemble(eip)
54
- end
49
+ # decodes the current string as a Shellcode, with specified base address
50
+ # returns the resulting Disassembler
51
+ def decode_blocks(base_addr=0, eip=base_addr)
52
+ sc = Metasm::Shellcode.decode(self, @@cpu)
53
+ sc.base_addr = base_addr
54
+ sc.disassemble(eip)
55
+ end
55
56
 
56
- # decodes the current string as a Shellcode, with specified base address
57
- # returns the asm source equivallent
58
- def decode(base_addr=0, eip=base_addr)
59
- decode_blocks(base_addr, eip).to_s
60
- end
57
+ # decodes the current string as a Shellcode, with specified base address
58
+ # returns the asm source equivallent
59
+ def decode(base_addr=0, eip=base_addr)
60
+ decode_blocks(base_addr, eip).to_s
61
+ end
61
62
  end
62
63
 
63
64
  # get in interactive assembler mode
64
65
  def asm
65
- puts 'type "exit" or "quit" to quit', 'use ";" for newline', ''
66
- while (print "asm> " ; $stdout.flush ; l = gets)
67
- break if %w[quit exit].include? l.chomp
68
- if l.chomp == 'help'
69
- puts "Metasm assembly shell: type in opcodes to see their binary form",
70
- "You can use ';' to type multi-line stuff",
71
- "e.g. 'nop nop' will display \"\\x90\\x90\""
72
- next
73
- end
74
-
75
- begin
76
- data = l.gsub(';', "\n")
77
- next if data.strip.empty?
78
- data = data.encode
79
- puts '"' + data.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'
80
- rescue Metasm::Exception => e
81
- puts "Error: #{e.class} #{e.message}"
82
- end
83
- end
66
+ puts "[+] Metasm assembly shell"
67
+ puts "type help for usage..\n\n"
84
68
 
85
- puts
69
+ Readline.completion_proc = lambda { |line| %w[help exit quit].find_all { |w| line.downcase == w[0, line.length] } }
70
+ Readline.completion_append_character = ' '
71
+
72
+ while line = Readline.readline('asm> ', true)
73
+ case line
74
+ when /^help(\W|$)/
75
+ puts "",
76
+ "Type in opcodes to see their binary form",
77
+ "You can use ';' to type multi-line stuff",
78
+ "e.g. 'nop nop' will display \"\\x90\\x90\"",
79
+ "",
80
+ "exit/quit Quit the console",
81
+ "help Show this screen",
82
+ ""
83
+ when /^(quit|exit)(\W|$)/
84
+ break
85
+ else
86
+ begin
87
+ data = line.gsub(';', "\n")
88
+ next if data.strip.empty?
89
+ e_data = data.encode
90
+ puts '"' + e_data.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'
91
+ rescue Metasm::Exception => e
92
+ puts "Error: #{e.class} #{e.message}"
93
+ end
94
+ end
95
+ end
96
+
97
+ puts
86
98
  end
87
99
 
88
100
  if __FILE__ == $0
89
- asm
101
+ asm
90
102
  end
@@ -0,0 +1,27 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2015 Google
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'test/unit'
7
+ require 'metasm'
8
+
9
+
10
+ class TestMCS51 < Test::Unit::TestCase
11
+ def test_mcs51_dec
12
+ hex_stream = "\x09\x00\x1F" # inc; nop; dec
13
+ hex_stream += "\x58\xF9\xEC\x32\x36\xc4\xa5\x24\x02\x45\x03"
14
+ hex_stream += "\x84\xa4\xc5\xa5\x70\xfe"
15
+ hex_stream += "\xba\x04\x08"
16
+ hex_stream += "\xc0\x04"
17
+ hex_stream += "\x11\x23"
18
+ hex_stream += "\xa1\x88"
19
+ hex_stream += "\x62\x88"
20
+ hex_stream += "\x53\x79\x66"
21
+ hex_stream += "\x02\x12\x34"
22
+
23
+ dasm = Metasm::Shellcode.disassemble(Metasm::MCS51.new, hex_stream)
24
+ #puts dasm
25
+ assert_equal(23, dasm.decoded.length)
26
+ end
27
+ end