ronin-code-asm 1.0.0.beta1
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 +7 -0
- data/.document +4 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +11 -0
- data/.mailmap +1 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +44 -0
- data/Gemfile +25 -0
- data/README.md +166 -0
- data/Rakefile +39 -0
- data/data/os/freebsd/amd64/syscalls.yml +415 -0
- data/data/os/freebsd/x86/syscalls.yml +415 -0
- data/data/os/linux/amd64/syscalls.yml +306 -0
- data/data/os/linux/x86/syscalls.yml +339 -0
- data/gemspec.yml +26 -0
- data/lib/ronin/code/asm/archs/amd64.rb +100 -0
- data/lib/ronin/code/asm/archs/x86.rb +170 -0
- data/lib/ronin/code/asm/archs.rb +22 -0
- data/lib/ronin/code/asm/config.rb +33 -0
- data/lib/ronin/code/asm/immediate_operand.rb +84 -0
- data/lib/ronin/code/asm/instruction.rb +66 -0
- data/lib/ronin/code/asm/memory_operand.rb +119 -0
- data/lib/ronin/code/asm/os/freebsd.rb +35 -0
- data/lib/ronin/code/asm/os/linux.rb +35 -0
- data/lib/ronin/code/asm/os/os.rb +47 -0
- data/lib/ronin/code/asm/os.rb +57 -0
- data/lib/ronin/code/asm/program.rb +509 -0
- data/lib/ronin/code/asm/register.rb +111 -0
- data/lib/ronin/code/asm/shellcode.rb +75 -0
- data/lib/ronin/code/asm/syntax/att.rb +164 -0
- data/lib/ronin/code/asm/syntax/common.rb +241 -0
- data/lib/ronin/code/asm/syntax/intel.rb +150 -0
- data/lib/ronin/code/asm/syntax.rb +22 -0
- data/lib/ronin/code/asm/version.rb +28 -0
- data/lib/ronin/code/asm.rb +68 -0
- data/ronin-code-asm.gemspec +62 -0
- data/spec/asm_spec.rb +14 -0
- data/spec/config_spec.rb +10 -0
- data/spec/immediate_operand_spec.rb +79 -0
- data/spec/instruction_spec.rb +62 -0
- data/spec/memory_operand_spec.rb +80 -0
- data/spec/os_spec.rb +68 -0
- data/spec/program_spec.rb +439 -0
- data/spec/register_spec.rb +112 -0
- data/spec/shellcode_spec.rb +58 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/syntax/att_spec.rb +181 -0
- data/spec/syntax/common_spec.rb +42 -0
- data/spec/syntax/intel_spec.rb +174 -0
- metadata +143 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-code-asm - A Ruby DSL for crafting Assembly programs and shellcode.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-code-asm is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-code-asm is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-code-asm. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/code/asm/program'
|
22
|
+
require 'ronin/code/asm/shellcode'
|
23
|
+
require 'ronin/code/asm/version'
|
24
|
+
|
25
|
+
module Ronin
|
26
|
+
module Code
|
27
|
+
module ASM
|
28
|
+
#
|
29
|
+
# Creates a new Assembly Program.
|
30
|
+
#
|
31
|
+
# @param [Hash{Symbol => Object}] kwargs
|
32
|
+
# Additional keyword arguments for {Program#initialize}.
|
33
|
+
#
|
34
|
+
# @option kwargs [String, Symbol] :arch (:x86)
|
35
|
+
# The architecture of the Program.
|
36
|
+
#
|
37
|
+
# @option kwargs [Hash{Symbol => Object}] :variables
|
38
|
+
# Variables to set in the program.
|
39
|
+
#
|
40
|
+
# @yield []
|
41
|
+
# The given block will be evaluated within the program.
|
42
|
+
#
|
43
|
+
# @return [Program]
|
44
|
+
# The new Assembly Program.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# ASM.new do
|
48
|
+
# mov 1, eax
|
49
|
+
# mov 1, ebx
|
50
|
+
# mov 2, ecx
|
51
|
+
#
|
52
|
+
# _loop do
|
53
|
+
# push ecx
|
54
|
+
# imul ebx, ecx
|
55
|
+
# pop ebx
|
56
|
+
#
|
57
|
+
# inc eax
|
58
|
+
# cmp ebx, 10
|
59
|
+
# jl :_loop
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
def ASM.new(**kwargs,&block)
|
64
|
+
Program.new(**kwargs,&block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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/code/asm/version'
|
14
|
+
Ronin::Code::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
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
24
|
+
|
25
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
26
|
+
|
27
|
+
gem.files = `git ls-files`.split($/)
|
28
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
29
|
+
gem.files += Array(gemspec['generated_files'])
|
30
|
+
|
31
|
+
gem.executables = gemspec.fetch('executables') do
|
32
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
33
|
+
end
|
34
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
35
|
+
|
36
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
37
|
+
gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
|
38
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
39
|
+
|
40
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
41
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
42
|
+
})
|
43
|
+
|
44
|
+
gem.requirements = gemspec['requirements']
|
45
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
46
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
47
|
+
gem.post_install_message = gemspec['post_install_message']
|
48
|
+
|
49
|
+
split = lambda { |string| string.split(/,\s*/) }
|
50
|
+
|
51
|
+
if gemspec['dependencies']
|
52
|
+
gemspec['dependencies'].each do |name,versions|
|
53
|
+
gem.add_dependency(name,split[versions])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if gemspec['development_dependencies']
|
58
|
+
gemspec['development_dependencies'].each do |name,versions|
|
59
|
+
gem.add_development_dependency(name,split[versions])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/asm_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/code/asm'
|
3
|
+
|
4
|
+
describe Ronin::Code::ASM do
|
5
|
+
it "must have a version" do
|
6
|
+
expect(subject.const_defined?('VERSION')).to eq(true)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
it "must return a new Ronin::Code::ASM::Program" do
|
11
|
+
expect(subject.new(arch: :x86)).to be_kind_of(Ronin::Code::ASM::Program)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/code/asm/immediate_operand'
|
4
|
+
|
5
|
+
describe Ronin::Code::ASM::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 "must set the width" do
|
15
|
+
expect(subject.width).to eq(width)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#width" do
|
21
|
+
describe "default width for" do
|
22
|
+
context "0x100000000 .. 0xffffffffffffffff" do
|
23
|
+
subject { described_class.new(0xffffffffffffffff).width }
|
24
|
+
|
25
|
+
it { expect(subject).to be == 8 }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "-0x800000000 .. -0x7fffffffffffffff" do
|
29
|
+
subject { described_class.new(-0x7fffffffffffffff).width }
|
30
|
+
|
31
|
+
it { expect(subject).to be == 8 }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "0x10000 .. 0xffffffff" do
|
35
|
+
subject { described_class.new(0xffffffff).width }
|
36
|
+
|
37
|
+
it { expect(subject).to be == 4 }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "-0x80000 .. -0x7fffffff" do
|
41
|
+
subject { described_class.new(-0x7fffffff).width }
|
42
|
+
|
43
|
+
it { expect(subject).to be == 4 }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "0x100 .. 0xffff" do
|
47
|
+
subject { described_class.new(0xffff).width }
|
48
|
+
|
49
|
+
it { expect(subject).to be == 2 }
|
50
|
+
end
|
51
|
+
|
52
|
+
context "-0x80 .. -0x7fff" do
|
53
|
+
subject { described_class.new(-0x7fff).width }
|
54
|
+
|
55
|
+
it { expect(subject).to be == 2 }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "0x0 .. 0xff" do
|
59
|
+
subject { described_class.new(0xff).width }
|
60
|
+
|
61
|
+
it { expect(subject).to be == 1 }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "0x0 .. -0x7f" do
|
65
|
+
subject { described_class.new(-0x7f).width }
|
66
|
+
|
67
|
+
it { expect(subject).to be == 1 }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#to_i" do
|
73
|
+
subject { described_class.new(value) }
|
74
|
+
|
75
|
+
it "must return the value" do
|
76
|
+
expect(subject.to_i).to eq(value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/code/asm/instruction'
|
4
|
+
require 'ronin/code/asm/register'
|
5
|
+
require 'ronin/code/asm/immediate_operand'
|
6
|
+
require 'ronin/code/asm/memory_operand'
|
7
|
+
|
8
|
+
describe Ronin::Code::ASM::Instruction do
|
9
|
+
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
10
|
+
let(:immediate) { Ronin::Code::ASM::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 "must set the name" do
|
19
|
+
expect(subject.name).to eq(:mov)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "must set the operands" do
|
23
|
+
expect(subject.operands).to eq(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 "must wrap the operand to in a Ronin::Code::ASM::ImmediateOperand" do
|
32
|
+
expect(subject.operands[0]).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
|
33
|
+
expect(subject.operands[0].value).to eq(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 "must wrap the operand to in a Ronin::Code::ASM::ImmediateOperand" do
|
41
|
+
expect(subject.operands[0]).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
|
42
|
+
expect(subject.operands[0].value).to eq(0)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#width" do
|
48
|
+
subject { described_class.new(:mov, [immediate, register]) }
|
49
|
+
|
50
|
+
it "must return the maximum width of the operands" do
|
51
|
+
expect(subject.width).to eq(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 "must ignore them" do
|
58
|
+
expect(subject.width).to eq(register.width)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/code/asm/memory_operand'
|
4
|
+
require 'ronin/code/asm/register'
|
5
|
+
|
6
|
+
describe Ronin::Code::ASM::MemoryOperand do
|
7
|
+
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
it { expect(subject.base).to be_nil }
|
11
|
+
it { expect(subject.offset).to eq(0) }
|
12
|
+
it { expect(subject.index).to be_nil }
|
13
|
+
it { expect(subject.scale).to eq(1) }
|
14
|
+
|
15
|
+
it "must only accept nil and a Register for base" do
|
16
|
+
expect {
|
17
|
+
described_class.new(Object.new)
|
18
|
+
}.to raise_error(TypeError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must only accept Integers for offset" do
|
22
|
+
expect {
|
23
|
+
described_class.new(register,2.0)
|
24
|
+
}.to raise_error(TypeError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must only accept nil and a Register for index" do
|
28
|
+
expect {
|
29
|
+
described_class.new(register,0,Object.new)
|
30
|
+
}.to raise_error(TypeError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must only accept Integers for offset" do
|
34
|
+
expect {
|
35
|
+
described_class.new(register,0,nil,2.0)
|
36
|
+
}.to 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 "must add to offset" do
|
47
|
+
expect(subject.offset).to eq(8)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must not change base, index or scale" do
|
51
|
+
expect(subject.base).to eq(operand.base)
|
52
|
+
expect(subject.index).to eq(operand.index)
|
53
|
+
expect(subject.scale).to eq(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 "must subtract from offset" do
|
63
|
+
expect(subject.offset).to eq(2)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "must not change base, index or scale" do
|
67
|
+
expect(subject.base).to eq(operand.base)
|
68
|
+
expect(subject.index).to eq(operand.index)
|
69
|
+
expect(subject.scale).to eq(operand.scale)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#width" do
|
74
|
+
subject { described_class.new(register,10) }
|
75
|
+
|
76
|
+
it "must return the width of base" do
|
77
|
+
expect(subject.width).to eq(register.width)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/spec/os_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/code/asm/os'
|
3
|
+
|
4
|
+
describe Ronin::Code::ASM::OS do
|
5
|
+
describe "SYSCALLS" do
|
6
|
+
subject { described_class::SYSCALLS }
|
7
|
+
|
8
|
+
let(:data_dir) { Ronin::Code::ASM::Config::DATA_DIR }
|
9
|
+
|
10
|
+
it { expect(subject).to be_kind_of(Hash) }
|
11
|
+
|
12
|
+
it "must load syscalls for :freebsd and :amd64" do
|
13
|
+
expect(subject[:freebsd][:amd64]).to eq(
|
14
|
+
YAML.load_file(
|
15
|
+
File.join(data_dir,'os','freebsd','amd64','syscalls.yml')
|
16
|
+
)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must load syscalls for :freebsd and :x86" do
|
21
|
+
expect(subject[:freebsd][:amd64]).to eq(
|
22
|
+
YAML.load_file(
|
23
|
+
File.join(data_dir,'os','freebsd','x86','syscalls.yml')
|
24
|
+
)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "must load syscalls for :linux and :amd64" do
|
29
|
+
expect(subject[:linux][:amd64]).to eq(
|
30
|
+
YAML.load_file(
|
31
|
+
File.join(data_dir,'os','linux','amd64','syscalls.yml')
|
32
|
+
)
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "must load syscalls for :linux and :x86" do
|
37
|
+
expect(subject[:linux][:x86]).to eq(
|
38
|
+
YAML.load_file(
|
39
|
+
File.join(data_dir,'os','linux','x86','syscalls.yml')
|
40
|
+
)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".[]" do
|
46
|
+
context "when given :linux" do
|
47
|
+
it "must return #{described_class}::Linux" do
|
48
|
+
expect(subject[:linux]).to be(described_class::Linux)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when given :freebsd" do
|
53
|
+
it "must return #{described_class}::FreeBSD" do
|
54
|
+
expect(subject[:freebsd]).to be(described_class::FreeBSD)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when given an unknown Symbol" do
|
59
|
+
let(:name) { :foo }
|
60
|
+
|
61
|
+
it do
|
62
|
+
expect {
|
63
|
+
subject[name]
|
64
|
+
}.to raise_error(ArgumentError,"unknown OS name: #{name.inspect}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|