ronin-asm 0.1.0
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.
- data/.document +4 -0
- data/.gemtest +0 -0
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +674 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +19 -0
- data/README.md +142 -0
- data/Rakefile +44 -0
- data/data/ronin/asm/freebsd/amd64/syscalls.yml +415 -0
- data/data/ronin/asm/freebsd/x86/syscalls.yml +415 -0
- data/data/ronin/asm/linux/amd64/syscalls.yml +306 -0
- data/data/ronin/asm/linux/x86/syscalls.yml +339 -0
- data/data/ronin/gen/asm/source_file.s.erb +4 -0
- data/gemspec.yml +20 -0
- data/lib/ronin/asm.rb +25 -0
- data/lib/ronin/asm/archs.rb +23 -0
- data/lib/ronin/asm/archs/amd64.rb +99 -0
- data/lib/ronin/asm/archs/x86.rb +166 -0
- data/lib/ronin/asm/asm.rb +66 -0
- data/lib/ronin/asm/config.rb +39 -0
- data/lib/ronin/asm/immediate_operand.rb +76 -0
- data/lib/ronin/asm/instruction.rb +65 -0
- data/lib/ronin/asm/memory_operand.rb +109 -0
- data/lib/ronin/asm/os.rb +24 -0
- data/lib/ronin/asm/os/freebsd.rb +34 -0
- data/lib/ronin/asm/os/linux.rb +34 -0
- data/lib/ronin/asm/os/os.rb +40 -0
- data/lib/ronin/asm/program.rb +476 -0
- data/lib/ronin/asm/register.rb +110 -0
- data/lib/ronin/asm/shellcode.rb +70 -0
- data/lib/ronin/asm/syntax.rb +23 -0
- data/lib/ronin/asm/syntax/att.rb +136 -0
- data/lib/ronin/asm/syntax/common.rb +202 -0
- data/lib/ronin/asm/syntax/intel.rb +150 -0
- data/lib/ronin/asm/version.rb +27 -0
- data/ronin-asm.gemspec +61 -0
- data/spec/asm_spec.rb +8 -0
- data/spec/helpers/database.rb +7 -0
- data/spec/immediate_operand_spec.rb +77 -0
- data/spec/instruction_spec.rb +62 -0
- data/spec/memory_operand_spec.rb +80 -0
- data/spec/program_spec.rb +365 -0
- data/spec/register_spec.rb +110 -0
- data/spec/shellcode_spec.rb +34 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/syntax/att_spec.rb +171 -0
- data/spec/syntax/common_spec.rb +42 -0
- data/spec/syntax/intel_spec.rb +156 -0
- metadata +163 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
#
|
2
|
+
# Ronin ASM - A Ruby DSL for crafting Assembly programs and Shellcode.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2007-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This file is part of Ronin ASM.
|
7
|
+
#
|
8
|
+
# Ronin is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Ronin is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Ronin. If not, see <http://www.gnu.org/licenses/>
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'ronin/asm/syntax/common'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module ASM
|
26
|
+
module Syntax
|
27
|
+
class Intel < Common
|
28
|
+
|
29
|
+
# Data sizes and their identifiers
|
30
|
+
WIDTHS = {
|
31
|
+
1 => 'BYTE',
|
32
|
+
2 => 'WORD',
|
33
|
+
4 => 'DWORD',
|
34
|
+
8 => 'QWORD'
|
35
|
+
}
|
36
|
+
|
37
|
+
#
|
38
|
+
# Emits a register.
|
39
|
+
#
|
40
|
+
# @param [Register] reg
|
41
|
+
# The register.
|
42
|
+
#
|
43
|
+
# @return [String]
|
44
|
+
# The register name.
|
45
|
+
#
|
46
|
+
def self.emit_register(reg)
|
47
|
+
reg.name.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Emits an immediate operand.
|
52
|
+
#
|
53
|
+
# @param [ImmediateOperand] op
|
54
|
+
# The operand.
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
# The formatted immediate operand.
|
58
|
+
#
|
59
|
+
def self.emit_immediate_operand(op)
|
60
|
+
"#{WIDTHS[op.width]} #{emit_integer(op.value)}"
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Emits a memory operand.
|
65
|
+
#
|
66
|
+
# @param [MemoryOperand] op
|
67
|
+
# The operand.
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
# The formatted memory operand.
|
71
|
+
#
|
72
|
+
def self.emit_memory_operand(op)
|
73
|
+
asm = emit_register(op.base)
|
74
|
+
|
75
|
+
if op.index
|
76
|
+
asm << '+' << emit_register(op.index)
|
77
|
+
asm << '*' << emit_integer(op.scale) if op.scale > 1
|
78
|
+
end
|
79
|
+
|
80
|
+
if op.offset != 0
|
81
|
+
sign = if op.offset >= 0 then '+'
|
82
|
+
else '-'
|
83
|
+
end
|
84
|
+
|
85
|
+
asm << sign << emit_integer(op.offset)
|
86
|
+
end
|
87
|
+
|
88
|
+
return "[#{asm}]"
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Emits multiple operands.
|
93
|
+
#
|
94
|
+
# @param [Array<ImmediateOperand, MemoryOperand, Register, Symbol>] ops
|
95
|
+
# The Array of operands.
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
# The formatted operands.
|
99
|
+
#
|
100
|
+
def self.emit_operands(ops)
|
101
|
+
if ops.length > 1
|
102
|
+
[ops[-1], *ops[0..-2]].map { |op| emit_operand(op) }.join(",\t")
|
103
|
+
else
|
104
|
+
super(ops)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Emits an instruction.
|
110
|
+
#
|
111
|
+
# @param [Instruction] ins
|
112
|
+
# The instruction.
|
113
|
+
#
|
114
|
+
# @return [String]
|
115
|
+
# The formatted instruction.
|
116
|
+
#
|
117
|
+
def self.emit_instruction(ins)
|
118
|
+
line = emit_keyword(ins.name)
|
119
|
+
|
120
|
+
unless ins.operands.empty?
|
121
|
+
line << "\t" << emit_operands(ins.operands)
|
122
|
+
end
|
123
|
+
|
124
|
+
return line
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Emits a program.
|
129
|
+
#
|
130
|
+
# @param [Program] program
|
131
|
+
# The program.
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
# The formatted program.
|
135
|
+
#
|
136
|
+
def self.emit_program(program)
|
137
|
+
asm = super(program)
|
138
|
+
|
139
|
+
# prepend the `BITS 64` directive for YASM
|
140
|
+
if program.arch == :amd64
|
141
|
+
asm = ["BITS 64", '', asm].join($/)
|
142
|
+
end
|
143
|
+
|
144
|
+
return asm
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Ronin ASM - A Ruby DSL for crafting Assembly programs and Shellcode.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2007-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This file is part of Ronin ASM.
|
7
|
+
#
|
8
|
+
# Ronin Asm is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Ronin Asm is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Ronin Asm. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#
|
21
|
+
|
22
|
+
module Ronin
|
23
|
+
module ASM
|
24
|
+
# ronin-asm version
|
25
|
+
VERSION = '0.1.0'
|
26
|
+
end
|
27
|
+
end
|
data/ronin-asm.gemspec
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'ronin/asm/version'
|
14
|
+
Ronin::ASM::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
|
24
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
25
|
+
|
26
|
+
gem.files = `git ls-files`.split($/)
|
27
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
28
|
+
gem.files += Array(gemspec['generated_files'])
|
29
|
+
|
30
|
+
gem.executables = gemspec.fetch('executables') do
|
31
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
32
|
+
end
|
33
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
34
|
+
|
35
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
36
|
+
gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
|
37
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
38
|
+
|
39
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
40
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
41
|
+
})
|
42
|
+
|
43
|
+
gem.requirements = gemspec['requirements']
|
44
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
45
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
46
|
+
gem.post_install_message = gemspec['post_install_message']
|
47
|
+
|
48
|
+
split = lambda { |string| string.split(/,\s*/) }
|
49
|
+
|
50
|
+
if gemspec['dependencies']
|
51
|
+
gemspec['dependencies'].each do |name,versions|
|
52
|
+
gem.add_dependency(name,split[versions])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if gemspec['development_dependencies']
|
57
|
+
gemspec['development_dependencies'].each do |name,versions|
|
58
|
+
gem.add_development_dependency(name,split[versions])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/asm_spec.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/asm/immediate_operand'
|
4
|
+
|
5
|
+
describe ImmediateOperand do
|
6
|
+
let(:value) { 0xff }
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
context "with a width" do
|
10
|
+
let(:width) { 2 }
|
11
|
+
|
12
|
+
subject { described_class.new(value,width) }
|
13
|
+
|
14
|
+
it "should set the width" do
|
15
|
+
subject.width.should == width
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "default width for" do
|
20
|
+
context "0x100000000 .. 0xffffffffffffffff" do
|
21
|
+
subject { described_class.new(0xffffffffffffffff).width }
|
22
|
+
|
23
|
+
it { should == 8 }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "-0x800000000 .. -0x7fffffffffffffff" do
|
27
|
+
subject { described_class.new(-0x7fffffffffffffff).width }
|
28
|
+
|
29
|
+
it { should == 8 }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "0x10000 .. 0xffffffff" do
|
33
|
+
subject { described_class.new(0xffffffff).width }
|
34
|
+
|
35
|
+
it { should == 4 }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "-0x80000 .. -0x7fffffff" do
|
39
|
+
subject { described_class.new(-0x7fffffff).width }
|
40
|
+
|
41
|
+
it { should == 4 }
|
42
|
+
end
|
43
|
+
|
44
|
+
context "0x100 .. 0xffff" do
|
45
|
+
subject { described_class.new(0xffff).width }
|
46
|
+
|
47
|
+
it { should == 2 }
|
48
|
+
end
|
49
|
+
|
50
|
+
context "-0x80 .. -0x7fff" do
|
51
|
+
subject { described_class.new(-0x7fff).width }
|
52
|
+
|
53
|
+
it { should == 2 }
|
54
|
+
end
|
55
|
+
|
56
|
+
context "0x0 .. 0xff" do
|
57
|
+
subject { described_class.new(0xff).width }
|
58
|
+
|
59
|
+
it { should == 1 }
|
60
|
+
end
|
61
|
+
|
62
|
+
context "0x0 .. -0x7f" do
|
63
|
+
subject { described_class.new(-0x7f).width }
|
64
|
+
|
65
|
+
it { should == 1 }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#to_i" do
|
71
|
+
subject { described_class.new(value) }
|
72
|
+
|
73
|
+
it "should return the value" do
|
74
|
+
subject.to_i.should == value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/asm/instruction'
|
4
|
+
require 'ronin/asm/register'
|
5
|
+
require 'ronin/asm/immediate_operand'
|
6
|
+
require 'ronin/asm/memory_operand'
|
7
|
+
|
8
|
+
describe Instruction do
|
9
|
+
let(:register) { Register.new(:eax, 4) }
|
10
|
+
let(:immediate) { ImmediateOperand.new(0xff, 1) }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
let(:name) { :mov }
|
14
|
+
let(:operands) { [immediate, register] }
|
15
|
+
|
16
|
+
subject { described_class.new(name,operands) }
|
17
|
+
|
18
|
+
it "should set the name" do
|
19
|
+
subject.name.should == :mov
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set the operands" do
|
23
|
+
subject.operands.should == operands
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when given an Integer operand" do
|
27
|
+
let(:integer) { 0xff }
|
28
|
+
|
29
|
+
subject { described_class.new(name, [integer, register]) }
|
30
|
+
|
31
|
+
it "should wrap the operand to in a ImmediateOperand" do
|
32
|
+
subject.operands[0].should be_kind_of(ImmediateOperand)
|
33
|
+
subject.operands[0].value.should == integer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when given a nil operand" do
|
38
|
+
subject { described_class.new(name, [nil, register]) }
|
39
|
+
|
40
|
+
it "should wrap the operand to in a ImmediateOperand" do
|
41
|
+
subject.operands[0].should be_kind_of(ImmediateOperand)
|
42
|
+
subject.operands[0].value.should == 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#width" do
|
48
|
+
subject { described_class.new(:mov, [immediate, register]) }
|
49
|
+
|
50
|
+
it "should return the maximum width of the operands" do
|
51
|
+
subject.width.should == register.width
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when one of the operands does not define #width" do
|
55
|
+
subject { described_class.new(:mov, [:label, register]) }
|
56
|
+
|
57
|
+
it "should ignore them" do
|
58
|
+
subject.width.should == register.width
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/asm/memory_operand'
|
4
|
+
require 'ronin/asm/register'
|
5
|
+
|
6
|
+
describe MemoryOperand do
|
7
|
+
let(:register) { Register.new(:eax, 4) }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
its(:base) { should be_nil }
|
11
|
+
its(:offset) { should == 0 }
|
12
|
+
its(:index) { should be_nil }
|
13
|
+
its(:scale) { should == 1 }
|
14
|
+
|
15
|
+
it "should only accept nil and a Register for base" do
|
16
|
+
lambda {
|
17
|
+
described_class.new(Object.new)
|
18
|
+
}.should raise_error(TypeError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should only accept Integers for offset" do
|
22
|
+
lambda {
|
23
|
+
described_class.new(register,2.0)
|
24
|
+
}.should raise_error(TypeError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should only accept nil and a Register for index" do
|
28
|
+
lambda {
|
29
|
+
described_class.new(register,0,Object.new)
|
30
|
+
}.should raise_error(TypeError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should only accept Integers for offset" do
|
34
|
+
lambda {
|
35
|
+
described_class.new(register,0,nil,2.0)
|
36
|
+
}.should raise_error(TypeError)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#+" do
|
42
|
+
let(:operand) { described_class.new(register,4,register,2) }
|
43
|
+
|
44
|
+
subject { operand + 4 }
|
45
|
+
|
46
|
+
it "should add to offset" do
|
47
|
+
subject.offset.should == 8
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not change base, index or scale" do
|
51
|
+
subject.base.should == operand.base
|
52
|
+
subject.index.should == operand.index
|
53
|
+
subject.scale.should == operand.scale
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#-" do
|
58
|
+
let(:operand) { described_class.new(register,4,register,2) }
|
59
|
+
|
60
|
+
subject { operand - 2 }
|
61
|
+
|
62
|
+
it "should subtract from offset" do
|
63
|
+
subject.offset.should == 2
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not change base, index or scale" do
|
67
|
+
subject.base.should == operand.base
|
68
|
+
subject.index.should == operand.index
|
69
|
+
subject.scale.should == operand.scale
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#width" do
|
74
|
+
subject { described_class.new(register,10) }
|
75
|
+
|
76
|
+
it "should return the width of base" do
|
77
|
+
subject.width.should == register.width
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|