-
Notifications
You must be signed in to change notification settings - Fork 81
/
Copy pathmetasm-shell.rb
102 lines (90 loc) · 2.91 KB
/
metasm-shell.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env ruby
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2009 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
# modifies the standard ruby class String to add #asm_decode and #asm_encode methods
# they will respectively disassemble binary data / assemble asm source
# the default CPU is x86 32bits, change it using eg String.cpu = Metasm::MIPS.new(:big) (mips bigendian)
#
# it also defines the toplevel 'asm' method, that will start an interactive
# assembler shell (type in assembly statements, they are shown assembled in binary escaped form)
#
# eg:
# ruby metasm-shell
# > nop ; nop
# "\x90\x90"
# > exit
require 'metasm'
require 'readline'
class String
@@cpu = Metasm::Ia32.new
class << self
def cpu() @@cpu end
def cpu=(c)
c = Metasm.const_get(c).new if c.kind_of? String
@@cpu=c
end
end
# encodes the current string as a Shellcode, returns the resulting EncodedData
def asm_encode_edata
Metasm::Shellcode.assemble(@@cpu, self).encode.encoded
end
# encodes the current string as a Shellcode, returns the resulting binary String
# outputs warnings on unresolved relocations
def asm_encode
ed = asm_encode_edata
if not ed.reloc.empty?
puts 'W: encoded string has unresolved relocations: ' + ed.reloc.map { |o, r| r.target.inspect }.join(', ')
end
ed.fill
ed.data
end
# decodes the current string as a Shellcode, with specified base address
# returns the resulting Disassembler
def asm_decode_blocks(base_addr=0, eip=base_addr)
sc = Metasm::Shellcode.decode(self, @@cpu)
sc.base_addr = base_addr
sc.disassemble(eip)
end
# decodes the current string as a Shellcode, with specified base address
# returns the asm source equivallent
def asm_decode(base_addr=0, eip=base_addr)
asm_decode_blocks(base_addr, eip).to_s
end
end
# get in interactive assembler mode
def asm
puts "[+] Metasm assembly shell"
puts "type help for usage..\n\n"
Readline.completion_proc = lambda { |line| %w[help exit quit].find_all { |w| line.downcase == w[0, line.length] } }
Readline.completion_append_character = ' '
while line = Readline.readline('asm> ', true)
case line
when /^help(\W|$)/
puts "",
"Type in opcodes to see their binary form",
"You can use ';' to type multi-line stuff",
"e.g. 'nop nop' will display \"\\x90\\x90\"",
"",
"exit/quit Quit the console",
"help Show this screen",
""
when /^(quit|exit)(\W|$)/
break
else
begin
data = line.gsub(';', "\n")
next if data.strip.empty?
e_data = data.asm_encode
puts '"' + e_data.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'
rescue Metasm::Exception => e
puts "Error: #{e.class} #{e.message}"
end
end
end
puts
end
if __FILE__ == $0
asm
end