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.
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,75 @@
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
+
23
+ require 'tempfile'
24
+
25
+ module Ronin
26
+ module Code
27
+ module ASM
28
+ #
29
+ # Represents Shellcode. Shellcode is like an Assembly {Program}, but
30
+ # assembles into raw machine code which can be injected into a process.
31
+ #
32
+ # ASM::Shellcode.new do
33
+ # xor eax, eax
34
+ # push eax
35
+ # push 0x68732f2f
36
+ # push 0x6e69622f
37
+ # mov ebx, esp
38
+ # push eax
39
+ # push ebx
40
+ # mov ecx, esp
41
+ # xor edx, edx
42
+ # mov al, 0xb
43
+ # int 0x80
44
+ # end
45
+ #
46
+ #
47
+ class Shellcode < Program
48
+
49
+ #
50
+ # Assembles the Shellcode.
51
+ #
52
+ # @param [String] output
53
+ # The optional output to write the shellcode to. If no `:output` is
54
+ # given a tempfile will be used.
55
+ #
56
+ # @param [Hash{Symbol => Object}] kwargs
57
+ # Additional keyword arguments for {Program#assemble}.
58
+ #
59
+ # @return [String]
60
+ # The raw object-code of the Shellcode.
61
+ #
62
+ # @see Program#assemble
63
+ #
64
+ def assemble(output: nil, **kwargs)
65
+ output ||= Tempfile.new(['ronin-shellcode', '.bin']).path
66
+
67
+ super(output, format: :bin, **kwargs)
68
+
69
+ return File.binread(output)
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,164 @@
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/syntax/common'
22
+
23
+ module Ronin
24
+ module Code
25
+ module ASM
26
+ module Syntax
27
+ #
28
+ # Handles emitting Assembly source code in ATT syntax.
29
+ #
30
+ class ATT < Common
31
+
32
+ # Data sizes and their instruction mnemonics
33
+ WIDTHS = {
34
+ 8 => 'q',
35
+ 4 => 'l',
36
+ 2 => 'w',
37
+ 1 => 'b',
38
+ nil => ''
39
+ }
40
+
41
+ #
42
+ # Emits a register.
43
+ #
44
+ # @param [Register] reg
45
+ # The register.
46
+ #
47
+ # @return [String]
48
+ # The register name.
49
+ #
50
+ def self.emit_register(reg)
51
+ "%#{reg.name}"
52
+ end
53
+
54
+ #
55
+ # Emits an immediate operand.
56
+ #
57
+ # @param [ImmediateOperand] op
58
+ # The operand.
59
+ #
60
+ # @return [String]
61
+ # The formatted immediate operand.
62
+ #
63
+ def self.emit_immediate_operand(op)
64
+ "$#{emit_integer(op.value)}"
65
+ end
66
+
67
+ #
68
+ # Emits a memory operand.
69
+ #
70
+ # @param [MemoryOperand] op
71
+ # The operand.
72
+ #
73
+ # @return [String]
74
+ # The formatted memory operand.
75
+ #
76
+ def self.emit_memory_operand(op)
77
+ asm = emit_register(op.base)
78
+
79
+ if op.index
80
+ asm << ',' << emit_register(op.index)
81
+ asm << ',' << op.scale.to_s if op.scale > 1
82
+ end
83
+
84
+ asm = "(#{asm})"
85
+ asm = emit_integer(op.offset) + asm if op.offset != 0
86
+
87
+ return asm
88
+ end
89
+
90
+ #
91
+ # Emits multiple operands.
92
+ #
93
+ # @param [Array<ImmediateOperand, MemoryOperand, Register, Symbol>] ops
94
+ # The Array of operands.
95
+ #
96
+ # @return [String]
97
+ # The formatted operands.
98
+ #
99
+ def self.emit_operands(ops)
100
+ if ops.length > 1
101
+ [*ops[1..-1], ops[0]].map { |op| emit_operand(op) }.join(",\t")
102
+ else
103
+ super(ops)
104
+ end
105
+ end
106
+
107
+ #
108
+ # Emits an instruction.
109
+ #
110
+ # @param [Instruction] ins
111
+ # The instruction.
112
+ #
113
+ # @return [String]
114
+ # The formatted instruction.
115
+ #
116
+ def self.emit_instruction(ins)
117
+ line = emit_keyword(ins.name)
118
+
119
+ unless ins.operands.empty?
120
+ unless (ins.operands.length == 1 && ins.width == 1)
121
+ line << WIDTHS[ins.width]
122
+ end
123
+
124
+ line << "\t" << emit_operands(ins.operands)
125
+ end
126
+
127
+ return line
128
+ end
129
+
130
+ #
131
+ # Emits a section name.
132
+ #
133
+ # @param [Symbol] name
134
+ # The section name.
135
+ #
136
+ # @return [String]
137
+ # The formatted section name.
138
+ #
139
+ # @since 0.2.0
140
+ #
141
+ def self.emit_section(name)
142
+ ".#{name}"
143
+ end
144
+
145
+ #
146
+ # Emits the program's prologue.
147
+ #
148
+ # @param [Program] program
149
+ # The program.
150
+ #
151
+ # @return [String]
152
+ # The formatted prologue.
153
+ #
154
+ # @since 0.2.0
155
+ #
156
+ def self.emit_prologue(program)
157
+ ".code#{BITS[program.arch]}"
158
+ end
159
+
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,241 @@
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/register'
22
+ require 'ronin/code/asm/immediate_operand'
23
+ require 'ronin/code/asm/memory_operand'
24
+
25
+ module Ronin
26
+ module Code
27
+ module ASM
28
+ module Syntax
29
+ #
30
+ # Abstract base-class for all Assembly Syntax classes.
31
+ #
32
+ class Common
33
+
34
+ # Bit sizes for various architectures
35
+ BITS = {
36
+ x86: 32,
37
+ amd64: 64,
38
+ }
39
+
40
+ #
41
+ # Emits a keyword.
42
+ #
43
+ # @param [Symbol] name
44
+ # Name of the keyword.
45
+ #
46
+ # @return [String]
47
+ # The formatted keyword.
48
+ #
49
+ def self.emit_keyword(name)
50
+ name.to_s
51
+ end
52
+
53
+ #
54
+ # Emits a register.
55
+ #
56
+ # @param [Register] reg
57
+ #
58
+ # @return [String]
59
+ # The formatted register.
60
+ #
61
+ # @abstract
62
+ #
63
+ def self.emit_register(reg)
64
+ end
65
+
66
+ #
67
+ # Emits an integer.
68
+ #
69
+ # @param [Integer] value
70
+ # The integer.
71
+ #
72
+ # @return [String]
73
+ # The formatted integer.
74
+ #
75
+ def self.emit_integer(value)
76
+ if value >= 0 then "0x%x" % value
77
+ else "-0x%x" % value.abs
78
+ end
79
+ end
80
+
81
+ #
82
+ # Emits a floating point number.
83
+ #
84
+ # @param [Float] value
85
+ # The number.
86
+ #
87
+ # @return [String]
88
+ # The formatted float.
89
+ #
90
+ # @abstract
91
+ #
92
+ def self.emit_float(value)
93
+ end
94
+
95
+ #
96
+ # Emits an immediate operand.
97
+ #
98
+ # @param [ImmediateOperand] op
99
+ # The immediate operand.
100
+ #
101
+ # @return [String]
102
+ # The formatted immediate operand.
103
+ #
104
+ # @abstract
105
+ #
106
+ def self.emit_immediate_operand(op)
107
+ end
108
+
109
+ #
110
+ # Emits an memory operand.
111
+ #
112
+ # @param [MemoryOperand] op
113
+ # The memory operand.
114
+ #
115
+ # @return [String]
116
+ # The formatted memory operand.
117
+ #
118
+ # @abstract
119
+ #
120
+ def self.emit_memory_operand(op)
121
+ end
122
+
123
+ #
124
+ # Emits an operand.
125
+ #
126
+ # @param [ImmediateOperand, MemoryOperand, Register, Symbol] op
127
+ # The operand.
128
+ #
129
+ # @return [String]
130
+ # The formatted operand.
131
+ #
132
+ def self.emit_operand(op)
133
+ case op
134
+ when ImmediateOperand then emit_immediate_operand(op)
135
+ when MemoryOperand then emit_memory_operand(op)
136
+ when Register then emit_register(op)
137
+ when Symbol then emit_keyword(op)
138
+ end
139
+ end
140
+
141
+ #
142
+ # Emits multiple operands.
143
+ #
144
+ # @param [Array<ImmediateOperand, MemoryOperand, Register, Symbol>] ops
145
+ # The Array of operands.
146
+ #
147
+ # @return [String]
148
+ # The formatted operands.
149
+ #
150
+ def self.emit_operands(ops)
151
+ ops.map { |op| emit_operand(op) }.join(",\t")
152
+ end
153
+
154
+ #
155
+ # Emits a label.
156
+ #
157
+ # @param [Symbol] name
158
+ # The name of the label.
159
+ #
160
+ # @return [String]
161
+ # The formatted label.
162
+ #
163
+ def self.emit_label(name)
164
+ "#{name}:"
165
+ end
166
+
167
+ #
168
+ # Emits an instruction.
169
+ #
170
+ # @param [Instruction] ins
171
+ # The instruction.
172
+ #
173
+ # @return [String]
174
+ # The formatted instruction.
175
+ #
176
+ # @abstract
177
+ #
178
+ def self.emit_instruction(ins)
179
+ end
180
+
181
+ #
182
+ # Emits a section name.
183
+ #
184
+ # @param [Symbol] name
185
+ # The section name.
186
+ #
187
+ # @return [String]
188
+ # The formatted section name.
189
+ #
190
+ # @since 0.2.0
191
+ #
192
+ def self.emit_section(name)
193
+ end
194
+
195
+ #
196
+ # Emits the program's prologue.
197
+ #
198
+ # @param [Program] program
199
+ # The program.
200
+ #
201
+ # @return [String]
202
+ # The formatted prologue.
203
+ #
204
+ # @since 0.2.0
205
+ #
206
+ def self.emit_prologue(program)
207
+ end
208
+
209
+ #
210
+ # Emits a program.
211
+ #
212
+ # @param [Program] program
213
+ # The program.
214
+ #
215
+ # @return [String]
216
+ # The formatted program.
217
+ #
218
+ def self.emit_program(program)
219
+ lines = [
220
+ emit_prologue(program),
221
+ emit_section(:text),
222
+ emit_label(:_start)
223
+ ].compact
224
+
225
+ program.instructions.each do |ins|
226
+ case ins
227
+ when Symbol then lines << emit_label(ins)
228
+ when Instruction then lines << "\t#{emit_instruction(ins)}"
229
+ end
230
+ end
231
+
232
+ lines << ''
233
+
234
+ return lines.join($/)
235
+ end
236
+
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,150 @@
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/syntax/common'
22
+
23
+ module Ronin
24
+ module Code
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
+ asm = "[#{asm}]"
89
+
90
+ unless op.width == op.base.width
91
+ asm = "#{WIDTHS[op.width]} #{asm}"
92
+ end
93
+
94
+ return asm
95
+ end
96
+
97
+ #
98
+ # Emits an instruction.
99
+ #
100
+ # @param [Instruction] ins
101
+ # The instruction.
102
+ #
103
+ # @return [String]
104
+ # The formatted instruction.
105
+ #
106
+ def self.emit_instruction(ins)
107
+ line = emit_keyword(ins.name)
108
+
109
+ unless ins.operands.empty?
110
+ line << "\t" << emit_operands(ins.operands)
111
+ end
112
+
113
+ return line
114
+ end
115
+
116
+ #
117
+ # Emits a section name.
118
+ #
119
+ # @param [Symbol] name
120
+ # The section name.
121
+ #
122
+ # @return [String]
123
+ # The formatted section name.
124
+ #
125
+ # @since 0.2.0
126
+ #
127
+ def self.emit_section(name)
128
+ "section .#{name}"
129
+ end
130
+
131
+ #
132
+ # Emits the program's prologue.
133
+ #
134
+ # @param [Program] program
135
+ # The program.
136
+ #
137
+ # @return [String]
138
+ # The formatted prologue.
139
+ #
140
+ # @since 0.2.0
141
+ #
142
+ def self.emit_prologue(program)
143
+ "BITS #{BITS[program.arch]}"
144
+ end
145
+
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,22 @@
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/syntax/att'
22
+ require 'ronin/code/asm/syntax/intel'
@@ -0,0 +1,28 @@
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
+ module Ronin
22
+ module Code
23
+ module ASM
24
+ # ronin-code-asm version
25
+ VERSION = '1.0.0.beta1'
26
+ end
27
+ end
28
+ end