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,24 @@
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/os/os'
23
+ require 'ronin/asm/os/freebsd'
24
+ require 'ronin/asm/os/linux'
@@ -0,0 +1,34 @@
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/config'
23
+
24
+ module Ronin
25
+ module ASM
26
+ module OS
27
+ #
28
+ # Contains FreeBSD specific helper methods.
29
+ #
30
+ module FreeBSD
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
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/config'
23
+
24
+ module Ronin
25
+ module ASM
26
+ module OS
27
+ #
28
+ # Contains Linux specific helper methods.
29
+ #
30
+ module Linux
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
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/config'
23
+
24
+ module Ronin
25
+ module ASM
26
+ module OS
27
+ #
28
+ # Collection of all known syscalls, grouped by OS and Arch.
29
+ #
30
+ # @return [Hash{Symbol => Hash{Symbol => Hash{Symbol => Integer}}}]
31
+ # Syscall names and numbers, organized by OS then Arch.
32
+ #
33
+ SYSCALLS = Hash.new do |hash,os|
34
+ hash[os] = Hash.new do |subhash,arch|
35
+ subhash[arch] = Config.load_yaml_file(File.join(Config::DATA_DIR,os.to_s.downcase,arch.to_s,'syscalls.yml'))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,476 @@
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/archs'
23
+ require 'ronin/asm/os'
24
+ require 'ronin/asm/register'
25
+ require 'ronin/asm/instruction'
26
+ require 'ronin/asm/immediate_operand'
27
+ require 'ronin/asm/syntax'
28
+
29
+ require 'tempfile'
30
+ require 'yasm/program'
31
+
32
+ module Ronin
33
+ module ASM
34
+ #
35
+ # Represents a full Assembly program.
36
+ #
37
+ class Program
38
+
39
+ # Supported Assembly Syntaxs
40
+ SYNTAX = {
41
+ :att => Syntax::ATT,
42
+ :intel => Syntax::Intel
43
+ }
44
+
45
+ # The Assembly Parsers
46
+ PARSERS = {
47
+ :att => :gas,
48
+ :intel => :nasm
49
+ }
50
+
51
+ # The targeted architecture
52
+ attr_reader :arch
53
+
54
+ # The targeted Operating System
55
+ attr_reader :os
56
+
57
+ # The default word size
58
+ attr_reader :word_size
59
+
60
+ # The registers available to the program
61
+ #
62
+ # @return [Hash{Symbol => Register}]
63
+ # The names and registers.
64
+ attr_reader :registers
65
+
66
+ # The syscalls available to the program
67
+ #
68
+ # @return [Hash{Symbol => Integer}]
69
+ # The syscall names and numbers.
70
+ attr_reader :syscalls
71
+
72
+ # The registers used by the program
73
+ attr_reader :allocated_registers
74
+
75
+ # The instructions of the program
76
+ attr_reader :instructions
77
+
78
+ #
79
+ # Initializes a new Assembly Program.
80
+ #
81
+ # @param [Hash] options
82
+ # Additional options.
83
+ #
84
+ # @option options [String, Symbol] :arch (:x86)
85
+ # The Architecture to target.
86
+ #
87
+ # @option options [String, Symbol] :os
88
+ # The Operating System to target.
89
+ #
90
+ # @option options [Hash{Symbol => Object}] :define
91
+ # Constants to define in the program.
92
+ #
93
+ # @yield []
94
+ # The given block will be evaluated within the program.
95
+ #
96
+ # @example
97
+ # Program.new(:arch => :amd64) do
98
+ # push rax
99
+ # push rbx
100
+ #
101
+ # mov rsp, rax
102
+ # mov rax[8], rbx
103
+ # end
104
+ #
105
+ def initialize(options={},&block)
106
+ @arch = options.fetch(:arch,:x86).to_sym
107
+
108
+ arch = Archs.const_get(@arch.to_s.upcase)
109
+
110
+ @word_size = arch::WORD_SIZE
111
+ @registers = arch::REGISTERS
112
+
113
+ extend Archs.const_get(@arch.to_s.upcase)
114
+
115
+ @syscalls = {}
116
+
117
+ if options.has_key?(:os)
118
+ @os = options[:os].to_s
119
+ @syscalls = OS::SYSCALLS[@os][@arch]
120
+
121
+ extend OS.const_get(@os)
122
+ end
123
+
124
+ if options[:define]
125
+ options[:define].each do |name,value|
126
+ instance_variable_set("@#{name}",value)
127
+ end
128
+ end
129
+
130
+ @allocated_registers = []
131
+ @instructions = []
132
+
133
+ instance_eval(&block) if block
134
+ end
135
+
136
+ #
137
+ # Determines if a register exists.
138
+ #
139
+ # @param [Symbol] name
140
+ # The name of the register.
141
+ #
142
+ # @return [Boolean]
143
+ # Specifies whether the register exists.
144
+ #
145
+ def register?(name)
146
+ @registers.has_key?(name.to_sym)
147
+ end
148
+
149
+ #
150
+ # Accesses a register.
151
+ #
152
+ # @param [String, Symbol] name
153
+ # The name of the register.
154
+ #
155
+ # @return [Register]
156
+ # The register.
157
+ #
158
+ # @raise [ArgumentError]
159
+ # The register could not be found.
160
+ #
161
+ def register(name)
162
+ name = name.to_sym
163
+
164
+ unless register?(name)
165
+ raise(ArgumentError,"unknown register: #{name}")
166
+ end
167
+
168
+ unless @allocated_registers.include?(name)
169
+ # mark the register as being used, when it was first accessed
170
+ @allocated_registers << name
171
+ end
172
+
173
+ return @registers[name]
174
+ end
175
+
176
+ #
177
+ # Adds a new instruction to the program.
178
+ #
179
+ # @param [String, Symbol] name
180
+ #
181
+ # @param [Array] operands
182
+ #
183
+ # @return [Instruction]
184
+ # The newly created instruction.
185
+ #
186
+ def instruction(name,*operands)
187
+ insn = Instruction.new(name.to_sym,operands)
188
+
189
+ @instructions << insn
190
+ return insn
191
+ end
192
+
193
+ #
194
+ # Creates an operand of size 1 (byte).
195
+ #
196
+ # @param [Integer] number
197
+ # The value of the operand.
198
+ #
199
+ # @return [ImmediateOperand]
200
+ # The new operand value.
201
+ #
202
+ def byte(number)
203
+ ImmediateOperand.new(number,1)
204
+ end
205
+
206
+ #
207
+ # Creates a operand of size 2 (bytes).
208
+ #
209
+ # @param [Integer] number
210
+ # The value of the operand.
211
+ #
212
+ # @return [ImmediateOperand]
213
+ # The new operand value.
214
+ #
215
+ def word(number)
216
+ ImmediateOperand.new(number,2)
217
+ end
218
+
219
+ #
220
+ # Creates a operand of size 4 (bytes).
221
+ #
222
+ # @param [Integer] number
223
+ # The value of the operand.
224
+ #
225
+ # @return [ImmediateOperand]
226
+ # The new operand value.
227
+ #
228
+ def dword(number)
229
+ ImmediateOperand.new(number,4)
230
+ end
231
+
232
+ #
233
+ # Creates a operand of size 8 (bytes).
234
+ #
235
+ # @param [Integer] number
236
+ # The value of the operand.
237
+ #
238
+ # @return [ImmediateOperand]
239
+ # The new operand.
240
+ #
241
+ def qword(number)
242
+ ImmediateOperand.new(number,8)
243
+ end
244
+
245
+ #
246
+ # Adds a label to the program.
247
+ #
248
+ # @param [Symbol, String] name
249
+ # The name of the label.
250
+ #
251
+ # @yield []
252
+ # The given block will be evaluated after the label has been
253
+ # added.
254
+ #
255
+ # @return [Symbol]
256
+ # The label name.
257
+ #
258
+ def label(name,&block)
259
+ name = name.to_sym
260
+
261
+ @instructions << name
262
+ instance_eval(&block)
263
+ return name
264
+ end
265
+
266
+ #
267
+ # Generic method for generating the instruction for causing an interrupt.
268
+ #
269
+ # @param [Integer] number
270
+ # The interrupt number to call.
271
+ #
272
+ # @abstract
273
+ #
274
+ def interrupt(number)
275
+ end
276
+
277
+ #
278
+ # Generic method for generating the instruction for invoking a syscall.
279
+ #
280
+ # @abstract
281
+ #
282
+ def syscall
283
+ end
284
+
285
+ #
286
+ # Generic method for pushing onto the stack.
287
+ #
288
+ # @param [Register, Integer] value
289
+ # The value to push.
290
+ #
291
+ # @abstract
292
+ #
293
+ def stack_push(value)
294
+ end
295
+
296
+ #
297
+ # Generic method for popping off the stack.
298
+ #
299
+ # @param [Symbol] name
300
+ # The name of the reigster.
301
+ #
302
+ # @abstract
303
+ #
304
+ def stack_pop(name)
305
+ end
306
+
307
+ #
308
+ # Generic method for clearing a register.
309
+ #
310
+ # @param [Symbol] name
311
+ # The name of the reigster.
312
+ #
313
+ # @abstract
314
+ #
315
+ def register_clear(name)
316
+ end
317
+
318
+ #
319
+ # Generic method for setting a register.
320
+ #
321
+ # @param [Register, Immediate, Integer] value
322
+ # The new value for the register.
323
+ #
324
+ # @param [Symbol] name
325
+ # The name of the reigster.
326
+ #
327
+ # @abstract
328
+ #
329
+ def register_set(value,name)
330
+ end
331
+
332
+ #
333
+ # Generic method for saving a register.
334
+ #
335
+ # @param [Symbol] name
336
+ # The name of the reigster.
337
+ #
338
+ # @abstract
339
+ #
340
+ def register_save(name)
341
+ end
342
+
343
+ #
344
+ # Generic method for loading a register.
345
+ #
346
+ # @param [Symbol] name
347
+ # The name of the reigster.
348
+ #
349
+ # @abstract
350
+ #
351
+ def register_load(name)
352
+ end
353
+
354
+ #
355
+ # Defines a critical region, where the specified Registers
356
+ # should be saved and then reloaded.
357
+ #
358
+ # @param [Array<Symbol>] regs
359
+ # The registers to save and reload.
360
+ #
361
+ # @yield []
362
+ # The given block will be evaluated after the registers
363
+ # have been saved.
364
+ #
365
+ def critical(*regs,&block)
366
+ regs.each { |name| register_save(name) }
367
+
368
+ instance_eval(&block)
369
+
370
+ regs.reverse_each { |name| register_load(name) }
371
+ end
372
+
373
+ #
374
+ # Evaluates code within the Program.
375
+ #
376
+ # @yield []
377
+ # The code to evaluate.
378
+ #
379
+ def eval(&block)
380
+ instance_eval(&block)
381
+ end
382
+
383
+ #
384
+ # Converts the program to Assembly Source Code.
385
+ #
386
+ # @param [Symbol] syntax
387
+ # The syntax to compile the program to.
388
+ #
389
+ def to_asm(syntax=:att)
390
+ SYNTAX[syntax].emit_program(self)
391
+ end
392
+
393
+ #
394
+ # Assembles the program.
395
+ #
396
+ # @param [String] output
397
+ # The path for the assembled program.
398
+ #
399
+ # @param [Hash] options
400
+ # Additional options.
401
+ #
402
+ # @option options [Symbol, String] :syntax (:att)
403
+ # The syntax to compile the program to.
404
+ #
405
+ # @option options [Symbol] :format (:bin)
406
+ # The format of the assembled executable. May be one of:
407
+ #
408
+ # * `:dbg` - Trace of all info passed to object format module.
409
+ # * `:bin` - Flat format binary.
410
+ # * `:dosexe` - DOS .EXE format binary.
411
+ # * `:elf` - ELF.
412
+ # * `:elf32` - ELF (32-bit).
413
+ # * `:elf64` - ELF (64-bit).
414
+ # * `:coff` - COFF (DJGPP).
415
+ # * `:macho` - Mac OS X ABI Mach-O File Format.
416
+ # * `:macho32` - Mac OS X ABI Mach-O File Format (32-bit).
417
+ # * `:macho64` - Mac OS X ABI Mach-O File Format (64-bit).
418
+ # * `:rdf` - Relocatable Dynamic Object File Format (RDOFF) v2.0.
419
+ # * `:win32` - Win32.
420
+ # * `:win64` / `:x64` - Win64.
421
+ # * `:xdf` - Extended Dynamic Object.
422
+ #
423
+ # @return [String]
424
+ # The path to the assembled program.
425
+ #
426
+ def assemble(output,options={})
427
+ syntax = options.fetch(:syntax,:att)
428
+ format = options.fetch(:format,:bin)
429
+ parser = PARSERS[syntax]
430
+
431
+ source = Tempfile.new(['ronin-asm', '.s'])
432
+ source.write(to_asm(syntax))
433
+ source.close
434
+
435
+ YASM::Program.assemble(
436
+ :file => source.path,
437
+ :parser => PARSERS[syntax],
438
+ :target => @arch,
439
+ :output_format => format,
440
+ :output => output
441
+ )
442
+
443
+ return output
444
+ end
445
+
446
+ protected
447
+
448
+ # undefine the syscall method, so method_missing handles it
449
+ undef syscall
450
+
451
+ #
452
+ # Allows adding unknown instructions to the program.
453
+ #
454
+ # @param [Symbol] name
455
+ # The name of the instruction.
456
+ #
457
+ # @param [Array] arguments
458
+ # Additional operands.
459
+ #
460
+ def method_missing(name,*arguments,&block)
461
+ if (block && arguments.empty?)
462
+ label(name,&block)
463
+ elsif block.nil?
464
+ if (arguments.empty? && register?(name))
465
+ register(name)
466
+ else
467
+ instruction(name,*arguments)
468
+ end
469
+ else
470
+ super(name,*arguments,&block)
471
+ end
472
+ end
473
+
474
+ end
475
+ end
476
+ end