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.
Files changed (51) hide show
  1. data/.document +4 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +1 -0
  6. data/COPYING.txt +674 -0
  7. data/ChangeLog.md +10 -0
  8. data/Gemfile +19 -0
  9. data/README.md +142 -0
  10. data/Rakefile +44 -0
  11. data/data/ronin/asm/freebsd/amd64/syscalls.yml +415 -0
  12. data/data/ronin/asm/freebsd/x86/syscalls.yml +415 -0
  13. data/data/ronin/asm/linux/amd64/syscalls.yml +306 -0
  14. data/data/ronin/asm/linux/x86/syscalls.yml +339 -0
  15. data/data/ronin/gen/asm/source_file.s.erb +4 -0
  16. data/gemspec.yml +20 -0
  17. data/lib/ronin/asm.rb +25 -0
  18. data/lib/ronin/asm/archs.rb +23 -0
  19. data/lib/ronin/asm/archs/amd64.rb +99 -0
  20. data/lib/ronin/asm/archs/x86.rb +166 -0
  21. data/lib/ronin/asm/asm.rb +66 -0
  22. data/lib/ronin/asm/config.rb +39 -0
  23. data/lib/ronin/asm/immediate_operand.rb +76 -0
  24. data/lib/ronin/asm/instruction.rb +65 -0
  25. data/lib/ronin/asm/memory_operand.rb +109 -0
  26. data/lib/ronin/asm/os.rb +24 -0
  27. data/lib/ronin/asm/os/freebsd.rb +34 -0
  28. data/lib/ronin/asm/os/linux.rb +34 -0
  29. data/lib/ronin/asm/os/os.rb +40 -0
  30. data/lib/ronin/asm/program.rb +476 -0
  31. data/lib/ronin/asm/register.rb +110 -0
  32. data/lib/ronin/asm/shellcode.rb +70 -0
  33. data/lib/ronin/asm/syntax.rb +23 -0
  34. data/lib/ronin/asm/syntax/att.rb +136 -0
  35. data/lib/ronin/asm/syntax/common.rb +202 -0
  36. data/lib/ronin/asm/syntax/intel.rb +150 -0
  37. data/lib/ronin/asm/version.rb +27 -0
  38. data/ronin-asm.gemspec +61 -0
  39. data/spec/asm_spec.rb +8 -0
  40. data/spec/helpers/database.rb +7 -0
  41. data/spec/immediate_operand_spec.rb +77 -0
  42. data/spec/instruction_spec.rb +62 -0
  43. data/spec/memory_operand_spec.rb +80 -0
  44. data/spec/program_spec.rb +365 -0
  45. data/spec/register_spec.rb +110 -0
  46. data/spec/shellcode_spec.rb +34 -0
  47. data/spec/spec_helper.rb +10 -0
  48. data/spec/syntax/att_spec.rb +171 -0
  49. data/spec/syntax/common_spec.rb +42 -0
  50. data/spec/syntax/intel_spec.rb +156 -0
  51. 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
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'ronin/asm/version'
3
+
4
+ describe ASM do
5
+ it "should have a version" do
6
+ subject.const_defined?('VERSION').should == true
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ require 'ronin/database'
2
+
3
+ require 'spec_helper'
4
+
5
+ module Helpers
6
+ Database.setup(ENV['DATABASE'] || 'sqlite3::memory:')
7
+ end
@@ -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