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,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