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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/doc/code_organisation.txt +1 -1
- data/metasm.gemspec +1 -1
- data/metasm.rb +2 -1
- data/metasm/cpu/arc/decode.rb +3 -3
- data/metasm/cpu/arm/decode.rb +2 -2
- data/metasm/cpu/ia32/compile_c.rb +18 -2
- data/metasm/cpu/ia32/decode.rb +9 -4
- data/metasm/cpu/ia32/decompile.rb +22 -8
- data/metasm/cpu/ia32/opcodes.rb +5 -5
- data/metasm/cpu/mcs51.rb +8 -0
- data/metasm/cpu/mcs51/decode.rb +99 -0
- data/metasm/cpu/mcs51/main.rb +76 -0
- data/metasm/cpu/mcs51/opcodes.rb +120 -0
- data/metasm/cpu/mips/decode.rb +5 -4
- data/metasm/cpu/st20.rb +9 -0
- data/metasm/cpu/st20/decode.rb +180 -0
- data/metasm/cpu/st20/decompile.rb +283 -0
- data/metasm/cpu/st20/main.rb +37 -0
- data/metasm/cpu/st20/opcodes.rb +140 -0
- data/metasm/cpu/x86_64/encode.rb +4 -2
- data/metasm/cpu/x86_64/opcodes.rb +4 -2
- data/metasm/decode.rb +16 -15
- data/metasm/decompile.rb +1 -1
- data/metasm/disassemble.rb +3 -1
- data/metasm/disassemble_api.rb +3 -1
- data/metasm/dynldr.rb +9 -3
- data/metasm/encode.rb +2 -2
- data/metasm/exe_format/coff.rb +3 -1
- data/metasm/exe_format/coff_decode.rb +5 -3
- data/metasm/exe_format/elf.rb +4 -0
- data/metasm/exe_format/elf_decode.rb +1 -2
- data/metasm/exe_format/elf_encode.rb +4 -1
- data/metasm/exe_format/macho.rb +20 -6
- data/metasm/exe_format/pe.rb +1 -1
- data/metasm/exe_format/serialstruct.rb +1 -1
- data/metasm/gui.rb +1 -1
- data/metasm/gui/dasm_hex.rb +2 -2
- data/metasm/gui/dasm_main.rb +8 -8
- data/metasm/gui/debug.rb +4 -4
- data/metasm/gui/gtk.rb +1 -1
- data/metasm/gui/qt.rb +2 -2
- data/metasm/gui/win32.rb +1 -1
- data/metasm/main.rb +11 -6
- data/metasm/os/windows.rb +26 -23
- data/misc/hexdump.rb +2 -2
- data/misc/objdiff.rb +4 -1
- data/misc/objscan.rb +1 -1
- data/samples/dasm-plugins/bindiff.rb +1 -1
- data/samples/dasm-plugins/scanxrefs.rb +2 -1
- data/samples/dynamic_ruby.rb +24 -25
- data/samples/elfencode.rb +15 -0
- data/samples/exeencode.rb +2 -2
- data/samples/metasm-shell.rb +67 -55
- data/tests/mcs51.rb +27 -0
- metadata +13 -2
data/misc/objdiff.rb
CHANGED
@@ -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 = (
|
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
|
data/misc/objscan.rb
CHANGED
@@ -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("
|
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)&
|
15
|
+
ans << (s_addr + off) if (r + off+4 + s_addr) & msk == target or r == target
|
15
16
|
}
|
16
17
|
}
|
17
18
|
ans
|
data/samples/dynamic_ruby.rb
CHANGED
@@ -452,8 +452,8 @@ EOS
|
|
452
452
|
end
|
453
453
|
|
454
454
|
# compile a case/when
|
455
|
-
# create a real C switch() for
|
456
|
-
# XXX will get the wrong order for "case x; when 1; when
|
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?
|
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?(
|
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?
|
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?(
|
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?
|
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
|
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
|
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
|
-
|
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
|
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"));
|
data/samples/elfencode.rb
CHANGED
@@ -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
|
data/samples/exeencode.rb
CHANGED
@@ -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.
|
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.
|
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}"
|
data/samples/metasm-shell.rb
CHANGED
@@ -18,73 +18,85 @@
|
|
18
18
|
# > exit
|
19
19
|
|
20
20
|
require 'metasm'
|
21
|
+
require 'readline'
|
21
22
|
|
22
23
|
class String
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
66
|
-
|
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
|
-
|
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
|
-
|
101
|
+
asm
|
90
102
|
end
|
data/tests/mcs51.rb
ADDED
@@ -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
|