ronin-code-asm 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +31 -0
  5. data/.gitignore +11 -0
  6. data/.mailmap +1 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.yardopts +1 -0
  10. data/COPYING.txt +165 -0
  11. data/ChangeLog.md +44 -0
  12. data/Gemfile +25 -0
  13. data/README.md +166 -0
  14. data/Rakefile +39 -0
  15. data/data/os/freebsd/amd64/syscalls.yml +415 -0
  16. data/data/os/freebsd/x86/syscalls.yml +415 -0
  17. data/data/os/linux/amd64/syscalls.yml +306 -0
  18. data/data/os/linux/x86/syscalls.yml +339 -0
  19. data/gemspec.yml +26 -0
  20. data/lib/ronin/code/asm/archs/amd64.rb +100 -0
  21. data/lib/ronin/code/asm/archs/x86.rb +170 -0
  22. data/lib/ronin/code/asm/archs.rb +22 -0
  23. data/lib/ronin/code/asm/config.rb +33 -0
  24. data/lib/ronin/code/asm/immediate_operand.rb +84 -0
  25. data/lib/ronin/code/asm/instruction.rb +66 -0
  26. data/lib/ronin/code/asm/memory_operand.rb +119 -0
  27. data/lib/ronin/code/asm/os/freebsd.rb +35 -0
  28. data/lib/ronin/code/asm/os/linux.rb +35 -0
  29. data/lib/ronin/code/asm/os/os.rb +47 -0
  30. data/lib/ronin/code/asm/os.rb +57 -0
  31. data/lib/ronin/code/asm/program.rb +509 -0
  32. data/lib/ronin/code/asm/register.rb +111 -0
  33. data/lib/ronin/code/asm/shellcode.rb +75 -0
  34. data/lib/ronin/code/asm/syntax/att.rb +164 -0
  35. data/lib/ronin/code/asm/syntax/common.rb +241 -0
  36. data/lib/ronin/code/asm/syntax/intel.rb +150 -0
  37. data/lib/ronin/code/asm/syntax.rb +22 -0
  38. data/lib/ronin/code/asm/version.rb +28 -0
  39. data/lib/ronin/code/asm.rb +68 -0
  40. data/ronin-code-asm.gemspec +62 -0
  41. data/spec/asm_spec.rb +14 -0
  42. data/spec/config_spec.rb +10 -0
  43. data/spec/immediate_operand_spec.rb +79 -0
  44. data/spec/instruction_spec.rb +62 -0
  45. data/spec/memory_operand_spec.rb +80 -0
  46. data/spec/os_spec.rb +68 -0
  47. data/spec/program_spec.rb +439 -0
  48. data/spec/register_spec.rb +112 -0
  49. data/spec/shellcode_spec.rb +58 -0
  50. data/spec/spec_helper.rb +7 -0
  51. data/spec/syntax/att_spec.rb +181 -0
  52. data/spec/syntax/common_spec.rb +42 -0
  53. data/spec/syntax/intel_spec.rb +174 -0
  54. metadata +143 -0
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ronin/code/asm/syntax/att'
4
+ require 'ronin/code/asm/register'
5
+ require 'ronin/code/asm/immediate_operand'
6
+ require 'ronin/code/asm/memory_operand'
7
+ require 'ronin/code/asm/instruction'
8
+ require 'ronin/code/asm/program'
9
+
10
+ describe Ronin::Code::ASM::Syntax::ATT do
11
+ subject { described_class }
12
+
13
+ describe "emit_register" do
14
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
15
+
16
+ it "must prepend a '%' to the register name" do
17
+ expect(subject.emit_register(register)).to eq("%eax")
18
+ end
19
+ end
20
+
21
+ describe "emit_immediate_operand" do
22
+ let(:operand) { Ronin::Code::ASM::ImmediateOperand.new(255, 1) }
23
+
24
+ it "must prepend a '$' to the immediate" do
25
+ expect(subject.emit_immediate_operand(operand)).to eq("$0xff")
26
+ end
27
+ end
28
+
29
+ describe "emit_memory_operand" do
30
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
31
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
32
+
33
+ it "must enclose the memory in parenthesis" do
34
+ expect(subject.emit_memory_operand(operand)).to eq("(%eax)")
35
+ end
36
+
37
+ context "with an offset" do
38
+ let(:offset) { 255 }
39
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,offset) }
40
+
41
+ it "must prepend the offset as an integer" do
42
+ expect(subject.emit_memory_operand(operand)).to eq("0xff(%eax)")
43
+ end
44
+
45
+ context "when 0" do
46
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0) }
47
+
48
+ it "must omit the offset" do
49
+ expect(subject.emit_memory_operand(operand)).to eq("(%eax)")
50
+ end
51
+ end
52
+ end
53
+
54
+ context "with an index" do
55
+ let(:index) { Ronin::Code::ASM::Register.new(:esi, 4) }
56
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index) }
57
+
58
+ it "must include the index argument" do
59
+ expect(subject.emit_memory_operand(operand)).to eq("(%eax,%esi)")
60
+ end
61
+
62
+ context "with a scale" do
63
+ let(:scale) { 4 }
64
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index,scale) }
65
+
66
+ it "must prepend the scale argument as a decimal" do
67
+ expect(subject.emit_memory_operand(operand)).to eq("(%eax,%esi,#{scale})")
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "emit_instruction" do
74
+ context "with no operands" do
75
+ let(:instruction) { Ronin::Code::ASM::Instruction.new(:ret, []) }
76
+
77
+ it "must emit the instruction name" do
78
+ expect(subject.emit_instruction(instruction)).to eq('ret')
79
+ end
80
+ end
81
+
82
+ context "with one operand" do
83
+ context "with width of 1" do
84
+ let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0x80, 1) }
85
+ let(:instruction) { Ronin::Code::ASM::Instruction.new(:int, [immediate]) }
86
+
87
+ it "must not append a size specifier to the instruction name" do
88
+ expect(subject.emit_instruction(instruction)).to eq("int\t$0x80")
89
+ end
90
+ end
91
+ end
92
+
93
+ context "with multiple operands" do
94
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
95
+ let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0xff, 1) }
96
+ let(:instruction) { Ronin::Code::ASM::Instruction.new(:mov, [register, immediate]) }
97
+
98
+ it "must add a size specifier to the instruction name" do
99
+ expect(subject.emit_instruction(instruction)).to match(/^movl/)
100
+ end
101
+
102
+ it "must emit the operands" do
103
+ expect(subject.emit_instruction(instruction)).to eq("movl\t$0xff,\t%eax")
104
+ end
105
+ end
106
+ end
107
+
108
+ describe "emit_section" do
109
+ it "must emit the section name" do
110
+ expect(subject.emit_section(:text)).to eq(".text")
111
+ end
112
+ end
113
+
114
+ describe "emit_program" do
115
+ let(:program) do
116
+ Ronin::Code::ASM::Program.new do
117
+ mov eax, 0xff
118
+ ret
119
+ end
120
+ end
121
+
122
+ it "must output the _start label and the program" do
123
+ asm = subject.emit_program(program)
124
+
125
+ expect(asm).to eq([
126
+ ".code32",
127
+ ".text",
128
+ "_start:",
129
+ "\tmovl\t$0xff,\t%eax",
130
+ "\tret",
131
+ ""
132
+ ].join($/))
133
+ end
134
+
135
+ context "when emitting labels" do
136
+ let(:program) do
137
+ Ronin::Code::ASM::Program.new do
138
+ mov eax, 0
139
+
140
+ _loop do
141
+ inc eax
142
+ cmp eax, 10
143
+ jl :_loop
144
+ end
145
+
146
+ ret
147
+ end
148
+ end
149
+
150
+ it "must emit both labels and instructions" do
151
+ expect(subject.emit_program(program)).to eq([
152
+ ".code32",
153
+ ".text",
154
+ "_start:",
155
+ "\tmovl\t$0x0,\t%eax",
156
+ "_loop:",
157
+ "\tincl\t%eax",
158
+ "\tcmpl\t$0xa,\t%eax",
159
+ "\tjl\t_loop",
160
+ "\tret",
161
+ ""
162
+ ].join($/))
163
+ end
164
+ end
165
+
166
+ context "when the program arch is :amd64" do
167
+ let(:program) do
168
+ Ronin::Code::ASM::Program.new(arch: :amd64) do
169
+ push rax
170
+ push rbx
171
+ mov 0xff, rax
172
+ ret
173
+ end
174
+ end
175
+
176
+ it "must include start with the '.code64' directive" do
177
+ expect(subject.emit_program(program)).to match(/^\.code64$/)
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ronin/code/asm/syntax/common'
4
+
5
+ describe Ronin::Code::ASM::Syntax::Common do
6
+ subject { described_class }
7
+
8
+ describe "emit_keyword" do
9
+ let(:name) { :_start }
10
+
11
+ it "must convert a keyword to a String" do
12
+ expect(subject.emit_keyword(name)).to eq(name.to_s)
13
+ end
14
+ end
15
+
16
+ describe "emit_integer" do
17
+ let(:integer) { 255 }
18
+ let(:hexadecimal) { "0xff" }
19
+
20
+ it "must convert it into a hexadecimal value" do
21
+ expect(subject.emit_integer(integer)).to eq(hexadecimal)
22
+ end
23
+
24
+ context "when given a negative number" do
25
+ let(:negative) { -255 }
26
+ let(:hexadecimal) { "-0xff" }
27
+
28
+ it "must convert it into a hexadecimal value" do
29
+ expect(subject.emit_integer(negative)).to eq(hexadecimal)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "emit_label" do
35
+ let(:name) { :_start }
36
+ let(:label) { '_start:' }
37
+
38
+ it "must append a ':' to the name" do
39
+ expect(subject.emit_label(name)).to eq(label)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ronin/code/asm/syntax/intel'
4
+ require 'ronin/code/asm/register'
5
+ require 'ronin/code/asm/immediate_operand'
6
+ require 'ronin/code/asm/memory_operand'
7
+ require 'ronin/code/asm/instruction'
8
+ require 'ronin/code/asm/program'
9
+
10
+ describe Ronin::Code::ASM::Syntax::Intel do
11
+ subject { described_class }
12
+
13
+ describe "emit_register" do
14
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
15
+
16
+ it "must return the register name" do
17
+ expect(subject.emit_register(register)).to eq("eax")
18
+ end
19
+ end
20
+
21
+ describe "emit_immediate_operand" do
22
+ let(:operand) { Ronin::Code::ASM::ImmediateOperand.new(255, 1) }
23
+
24
+ it "must prepend a size specifier" do
25
+ expect(subject.emit_immediate_operand(operand)).to eq("BYTE 0xff")
26
+ end
27
+ end
28
+
29
+ describe "emit_memory_operand" do
30
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
31
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
32
+
33
+ it "must enclose the memory in brackets" do
34
+ expect(subject.emit_memory_operand(operand)).to eq("[eax]")
35
+ end
36
+
37
+ context "when operand width does not match the base width" do
38
+ before { operand.width = 2 }
39
+
40
+ it "must specify the width" do
41
+ expect(subject.emit_memory_operand(operand)).to eq("WORD [eax]")
42
+ end
43
+ end
44
+
45
+ context "with an offset" do
46
+ let(:offset) { 255 }
47
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,offset) }
48
+
49
+ it "must add the offset to the base" do
50
+ expect(subject.emit_memory_operand(operand)).to eq("[eax+0xff]")
51
+ end
52
+
53
+ context "when 0" do
54
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0) }
55
+
56
+ it "must omit the offset" do
57
+ expect(subject.emit_memory_operand(operand)).to eq("[eax]")
58
+ end
59
+ end
60
+ end
61
+
62
+ context "with an index" do
63
+ let(:index) { Ronin::Code::ASM::Register.new(:esi, 4) }
64
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index) }
65
+
66
+ it "must add the index to the base" do
67
+ expect(subject.emit_memory_operand(operand)).to eq("[eax+esi]")
68
+ end
69
+
70
+ context "with a scale" do
71
+ let(:scale) { 4 }
72
+ let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index,scale) }
73
+
74
+ it "must multiple the index by the scale" do
75
+ expect(subject.emit_memory_operand(operand)).to eq("[eax+esi*0x4]")
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "emit_instruction" do
82
+ context "with no operands" do
83
+ let(:instruction) { Ronin::Code::ASM::Instruction.new(:ret, []) }
84
+
85
+ it "must emit the instruction name" do
86
+ expect(subject.emit_instruction(instruction)).to eq('ret')
87
+ end
88
+ end
89
+
90
+ context "with multiple operands" do
91
+ let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
92
+ let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0xff, 1) }
93
+ let(:instruction) { Ronin::Code::ASM::Instruction.new(:mov, [register, immediate]) }
94
+
95
+ it "must emit the operands" do
96
+ expect(subject.emit_instruction(instruction)).to eq("mov\teax,\tBYTE 0xff")
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "emit_section" do
102
+ it "must emit the section name" do
103
+ expect(subject.emit_section(:text)).to eq("section .text")
104
+ end
105
+ end
106
+
107
+ describe "emit_program" do
108
+ let(:program) do
109
+ Ronin::Code::ASM::Program.new do
110
+ mov eax, 0xff
111
+ ret
112
+ end
113
+ end
114
+
115
+ it "must output the _start label and the program" do
116
+ asm = subject.emit_program(program)
117
+
118
+ expect(asm).to eq([
119
+ "BITS 32",
120
+ "section .text",
121
+ "_start:",
122
+ "\tmov\teax,\tBYTE 0xff",
123
+ "\tret",
124
+ ""
125
+ ].join($/))
126
+ end
127
+
128
+ context "when emitting labels" do
129
+ let(:program) do
130
+ Ronin::Code::ASM::Program.new do
131
+ mov eax, 0
132
+
133
+ _loop do
134
+ inc eax
135
+ cmp eax, 10
136
+ jl :_loop
137
+ end
138
+
139
+ ret
140
+ end
141
+ end
142
+
143
+ it "must emit both labels and instructions" do
144
+ expect(subject.emit_program(program)).to eq([
145
+ "BITS 32",
146
+ "section .text",
147
+ "_start:",
148
+ "\tmov\teax,\tBYTE 0x0",
149
+ "_loop:",
150
+ "\tinc\teax",
151
+ "\tcmp\teax,\tBYTE 0xa",
152
+ "\tjl\t_loop",
153
+ "\tret",
154
+ ""
155
+ ].join($/))
156
+ end
157
+ end
158
+
159
+ context "when the program arch is :amd64" do
160
+ let(:program) do
161
+ Ronin::Code::ASM::Program.new(arch: :amd64) do
162
+ push rax
163
+ push rbx
164
+ mov rax, 0xff
165
+ ret
166
+ end
167
+ end
168
+
169
+ it "must include start with the '.code64' directive" do
170
+ expect(subject.emit_program(program)).to match(/^BITS 64$/)
171
+ end
172
+ end
173
+ end
174
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ronin-code-asm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-yasm
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: ronin-code-asm is a Ruby DSL for crafting Assembly programs and shellcode.
42
+ email: postmodern.mod3@gmail.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files:
46
+ - COPYING.txt
47
+ - ChangeLog.md
48
+ - README.md
49
+ files:
50
+ - ".document"
51
+ - ".editorconfig"
52
+ - ".github/workflows/ruby.yml"
53
+ - ".gitignore"
54
+ - ".mailmap"
55
+ - ".rspec"
56
+ - ".ruby-version"
57
+ - ".yardopts"
58
+ - COPYING.txt
59
+ - ChangeLog.md
60
+ - Gemfile
61
+ - README.md
62
+ - Rakefile
63
+ - data/os/freebsd/amd64/syscalls.yml
64
+ - data/os/freebsd/x86/syscalls.yml
65
+ - data/os/linux/amd64/syscalls.yml
66
+ - data/os/linux/x86/syscalls.yml
67
+ - gemspec.yml
68
+ - lib/ronin/code/asm.rb
69
+ - lib/ronin/code/asm/archs.rb
70
+ - lib/ronin/code/asm/archs/amd64.rb
71
+ - lib/ronin/code/asm/archs/x86.rb
72
+ - lib/ronin/code/asm/config.rb
73
+ - lib/ronin/code/asm/immediate_operand.rb
74
+ - lib/ronin/code/asm/instruction.rb
75
+ - lib/ronin/code/asm/memory_operand.rb
76
+ - lib/ronin/code/asm/os.rb
77
+ - lib/ronin/code/asm/os/freebsd.rb
78
+ - lib/ronin/code/asm/os/linux.rb
79
+ - lib/ronin/code/asm/os/os.rb
80
+ - lib/ronin/code/asm/program.rb
81
+ - lib/ronin/code/asm/register.rb
82
+ - lib/ronin/code/asm/shellcode.rb
83
+ - lib/ronin/code/asm/syntax.rb
84
+ - lib/ronin/code/asm/syntax/att.rb
85
+ - lib/ronin/code/asm/syntax/common.rb
86
+ - lib/ronin/code/asm/syntax/intel.rb
87
+ - lib/ronin/code/asm/version.rb
88
+ - ronin-code-asm.gemspec
89
+ - spec/asm_spec.rb
90
+ - spec/config_spec.rb
91
+ - spec/immediate_operand_spec.rb
92
+ - spec/instruction_spec.rb
93
+ - spec/memory_operand_spec.rb
94
+ - spec/os_spec.rb
95
+ - spec/program_spec.rb
96
+ - spec/register_spec.rb
97
+ - spec/shellcode_spec.rb
98
+ - spec/spec_helper.rb
99
+ - spec/syntax/att_spec.rb
100
+ - spec/syntax/common_spec.rb
101
+ - spec/syntax/intel_spec.rb
102
+ homepage: https://github.com/ronin-rb/ronin-code-asm#readme
103
+ licenses:
104
+ - LGPL-3.0
105
+ metadata:
106
+ documentation_uri: https://ronin-rb.dev/docs/ronin-code-asm/frames
107
+ source_code_uri: https://github.com/ronin-rb/ronin-code-asm
108
+ bug_tracker_uri: https://github.com/ronin-rb/ronin-code-asm/issues
109
+ changelog_uri: https://github.com/ronin-rb/ronin-code-asm/blob/master/ChangeLog.md
110
+ rubygems_mfa_required: 'true'
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: 3.0.0
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements:
126
+ - yasm >= 0.6.0
127
+ rubygems_version: 3.3.26
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: A Ruby DSL for crafting Assembly programs and Shellcode.
131
+ test_files:
132
+ - spec/asm_spec.rb
133
+ - spec/config_spec.rb
134
+ - spec/immediate_operand_spec.rb
135
+ - spec/instruction_spec.rb
136
+ - spec/memory_operand_spec.rb
137
+ - spec/os_spec.rb
138
+ - spec/program_spec.rb
139
+ - spec/register_spec.rb
140
+ - spec/shellcode_spec.rb
141
+ - spec/syntax/att_spec.rb
142
+ - spec/syntax/common_spec.rb
143
+ - spec/syntax/intel_spec.rb