metasm 1.0.2 → 1.0.3

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 (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