ronin-asm 0.1.0 → 0.2.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 (41) hide show
  1. data/.ruby-version +1 -0
  2. data/.travis.yml +12 -0
  3. data/ChangeLog.md +32 -6
  4. data/Gemfile +2 -2
  5. data/README.md +30 -22
  6. data/Rakefile +5 -4
  7. data/gemspec.yml +1 -0
  8. data/lib/ronin/asm.rb +1 -1
  9. data/lib/ronin/asm/archs.rb +1 -1
  10. data/lib/ronin/asm/archs/amd64.rb +53 -53
  11. data/lib/ronin/asm/archs/x86.rb +48 -48
  12. data/lib/ronin/asm/asm.rb +1 -1
  13. data/lib/ronin/asm/config.rb +1 -1
  14. data/lib/ronin/asm/immediate_operand.rb +18 -11
  15. data/lib/ronin/asm/instruction.rb +1 -1
  16. data/lib/ronin/asm/memory_operand.rb +22 -16
  17. data/lib/ronin/asm/os.rb +1 -1
  18. data/lib/ronin/asm/os/freebsd.rb +1 -1
  19. data/lib/ronin/asm/os/linux.rb +1 -1
  20. data/lib/ronin/asm/os/os.rb +1 -1
  21. data/lib/ronin/asm/program.rb +60 -33
  22. data/lib/ronin/asm/register.rb +1 -1
  23. data/lib/ronin/asm/shellcode.rb +2 -2
  24. data/lib/ronin/asm/syntax.rb +1 -1
  25. data/lib/ronin/asm/syntax/att.rb +39 -12
  26. data/lib/ronin/asm/syntax/common.rb +40 -2
  27. data/lib/ronin/asm/syntax/intel.rb +27 -28
  28. data/lib/ronin/asm/version.rb +2 -2
  29. data/spec/{asm_spec.rb → asm/asm_spec.rb} +0 -0
  30. data/spec/{immediate_operand_spec.rb → asm/immediate_operand_spec.rb} +2 -0
  31. data/spec/{instruction_spec.rb → asm/instruction_spec.rb} +0 -0
  32. data/spec/{memory_operand_spec.rb → asm/memory_operand_spec.rb} +0 -0
  33. data/spec/{program_spec.rb → asm/program_spec.rb} +106 -50
  34. data/spec/{register_spec.rb → asm/register_spec.rb} +0 -0
  35. data/spec/{shellcode_spec.rb → asm/shellcode_spec.rb} +15 -7
  36. data/spec/{syntax → asm/syntax}/att_spec.rb +15 -5
  37. data/spec/{syntax → asm/syntax}/common_spec.rb +0 -0
  38. data/spec/{syntax → asm/syntax}/intel_spec.rb +24 -6
  39. metadata +16 -16
  40. data/.gemtest +0 -0
  41. data/spec/helpers/database.rb +0 -7
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # Ronin ASM - A Ruby DSL for crafting Assembly programs and Shellcode.
3
3
  #
4
- # Copyright (c) 2007-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2007-2013 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of Ronin ASM.
7
7
  #
@@ -31,6 +31,12 @@ module Ronin
31
31
  #
32
32
  class Common
33
33
 
34
+ # Bit sizes for various architectures
35
+ BITS = {
36
+ x86: 32,
37
+ amd64: 64,
38
+ }
39
+
34
40
  #
35
41
  # Emits a keyword.
36
42
  #
@@ -172,6 +178,34 @@ module Ronin
172
178
  def self.emit_instruction(ins)
173
179
  end
174
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
+
175
209
  #
176
210
  # Emits a program.
177
211
  #
@@ -182,7 +216,11 @@ module Ronin
182
216
  # The formatted program.
183
217
  #
184
218
  def self.emit_program(program)
185
- lines = [emit_label(:_start)]
219
+ lines = [
220
+ emit_prologue(program),
221
+ emit_section(:text),
222
+ emit_label(:_start)
223
+ ].compact
186
224
 
187
225
  program.instructions.each do |ins|
188
226
  case ins
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # Ronin ASM - A Ruby DSL for crafting Assembly programs and Shellcode.
3
3
  #
4
- # Copyright (c) 2007-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2007-2013 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of Ronin ASM.
7
7
  #
@@ -85,24 +85,13 @@ module Ronin
85
85
  asm << sign << emit_integer(op.offset)
86
86
  end
87
87
 
88
- return "[#{asm}]"
89
- end
88
+ asm = "[#{asm}]"
90
89
 
91
- #
92
- # Emits multiple operands.
93
- #
94
- # @param [Array<ImmediateOperand, MemoryOperand, Register, Symbol>] ops
95
- # The Array of operands.
96
- #
97
- # @return [String]
98
- # The formatted operands.
99
- #
100
- def self.emit_operands(ops)
101
- if ops.length > 1
102
- [ops[-1], *ops[0..-2]].map { |op| emit_operand(op) }.join(",\t")
103
- else
104
- super(ops)
90
+ unless op.width == op.base.width
91
+ asm = "#{WIDTHS[op.width]} #{asm}"
105
92
  end
93
+
94
+ return asm
106
95
  end
107
96
 
108
97
  #
@@ -125,23 +114,33 @@ module Ronin
125
114
  end
126
115
 
127
116
  #
128
- # Emits a program.
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.
129
133
  #
130
134
  # @param [Program] program
131
135
  # The program.
132
136
  #
133
137
  # @return [String]
134
- # The formatted program.
138
+ # The formatted prologue.
135
139
  #
136
- def self.emit_program(program)
137
- asm = super(program)
138
-
139
- # prepend the `BITS 64` directive for YASM
140
- if program.arch == :amd64
141
- asm = ["BITS 64", '', asm].join($/)
142
- end
143
-
144
- return asm
140
+ # @since 0.2.0
141
+ #
142
+ def self.emit_prologue(program)
143
+ "BITS #{BITS[program.arch]}"
145
144
  end
146
145
 
147
146
  end
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # Ronin ASM - A Ruby DSL for crafting Assembly programs and Shellcode.
3
3
  #
4
- # Copyright (c) 2007-2012 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ # Copyright (c) 2007-2013 Hal Brodigan (postmodern.mod3 at gmail.com)
5
5
  #
6
6
  # This file is part of Ronin ASM.
7
7
  #
@@ -22,6 +22,6 @@
22
22
  module Ronin
23
23
  module ASM
24
24
  # ronin-asm version
25
- VERSION = '0.1.0'
25
+ VERSION = '0.2.0'
26
26
  end
27
27
  end
File without changes
@@ -15,7 +15,9 @@ describe ImmediateOperand do
15
15
  subject.width.should == width
16
16
  end
17
17
  end
18
+ end
18
19
 
20
+ describe "#width" do
19
21
  describe "default width for" do
20
22
  context "0x100000000 .. 0xffffffffffffffff" do
21
23
  subject { described_class.new(0xffffffffffffffff).width }
@@ -8,8 +8,8 @@ describe ASM::Program do
8
8
  end
9
9
  end
10
10
 
11
- context "when :arch => :x86" do
12
- subject { described_class.new(:arch => :x86) }
11
+ context "when :arch is :x86" do
12
+ subject { described_class.new(arch: :x86) }
13
13
 
14
14
  its(:word_size) { should == 4 }
15
15
 
@@ -63,7 +63,7 @@ describe ASM::Program do
63
63
  let(:name) { :eax }
64
64
  let(:value) { 0xff }
65
65
 
66
- before { subject.register_set(value,name) }
66
+ before { subject.register_set(name,value) }
67
67
 
68
68
  it "should add a 'xor' instruction with a registers" do
69
69
  subject.instructions[-1].name.should == :mov
@@ -114,21 +114,21 @@ describe ASM::Program do
114
114
  end
115
115
  end
116
116
 
117
- context "when :os => 'Linux'" do
118
- subject { described_class.new(:arch => :x86, :os => 'Linux') }
117
+ context "when :os is 'Linux'" do
118
+ subject { described_class.new(arch: :x86, os: 'Linux') }
119
119
 
120
120
  its(:syscalls) { should_not be_empty }
121
121
  end
122
122
 
123
- context "when :os => 'FreeBSD'" do
124
- subject { described_class.new(:arch => :x86, :os => 'FreeBSD') }
123
+ context "when :os is 'FreeBSD'" do
124
+ subject { described_class.new(arch: :x86, os: 'FreeBSD') }
125
125
 
126
126
  its(:syscalls) { should_not be_empty }
127
127
  end
128
128
  end
129
129
 
130
- context "when :arch => :amd64" do
131
- subject { described_class.new(:arch => :amd64) }
130
+ context "when :arch is :amd64" do
131
+ subject { described_class.new(arch: :amd64) }
132
132
 
133
133
  its(:word_size) { should == 8 }
134
134
 
@@ -140,14 +140,14 @@ describe ASM::Program do
140
140
  end
141
141
  end
142
142
 
143
- context "when :os => 'Linux'" do
144
- subject { described_class.new(:arch => :amd64, :os => 'Linux') }
143
+ context "when :os is 'Linux'" do
144
+ subject { described_class.new(arch: :amd64, os: 'Linux') }
145
145
 
146
146
  its(:syscalls) { should_not be_empty }
147
147
  end
148
148
 
149
- context "when :os => 'FreeBSD'" do
150
- subject { described_class.new(:arch => :amd64, :os => 'FreeBSD') }
149
+ context "when :os is 'FreeBSD'" do
150
+ subject { described_class.new(arch: :amd64, os: 'FreeBSD') }
151
151
 
152
152
  its(:syscalls) { should_not be_empty }
153
153
  end
@@ -203,6 +203,19 @@ describe ASM::Program do
203
203
  it "should have width of 1" do
204
204
  subject.byte(1).width.should == 1
205
205
  end
206
+
207
+ context "when given a MemoryOperand" do
208
+ let(:register) { Register.new(:eax, 4) }
209
+ let(:memory_operand) { MemoryOperand.new(register) }
210
+
211
+ it "should return a MemoryOperand" do
212
+ subject.byte(memory_operand).should be_kind_of(MemoryOperand)
213
+ end
214
+
215
+ it "should have a width of 1" do
216
+ subject.byte(memory_operand).width.should == 1
217
+ end
218
+ end
206
219
  end
207
220
 
208
221
  describe "#word" do
@@ -213,6 +226,19 @@ describe ASM::Program do
213
226
  it "should have width of 2" do
214
227
  subject.word(1).width.should == 2
215
228
  end
229
+
230
+ context "when given a MemoryOperand" do
231
+ let(:register) { Register.new(:eax, 4) }
232
+ let(:memory_operand) { MemoryOperand.new(register) }
233
+
234
+ it "should return a MemoryOperand" do
235
+ subject.word(memory_operand).should be_kind_of(MemoryOperand)
236
+ end
237
+
238
+ it "should have a width of 2" do
239
+ subject.word(memory_operand).width.should == 2
240
+ end
241
+ end
216
242
  end
217
243
 
218
244
  describe "#dword" do
@@ -223,6 +249,19 @@ describe ASM::Program do
223
249
  it "should have width of 4" do
224
250
  subject.dword(1).width.should == 4
225
251
  end
252
+
253
+ context "when given a MemoryOperand" do
254
+ let(:register) { Register.new(:eax, 4) }
255
+ let(:memory_operand) { MemoryOperand.new(register) }
256
+
257
+ it "should return a MemoryOperand" do
258
+ subject.dword(memory_operand).should be_kind_of(MemoryOperand)
259
+ end
260
+
261
+ it "should have a width of 4" do
262
+ subject.dword(memory_operand).width.should == 4
263
+ end
264
+ end
226
265
  end
227
266
 
228
267
  describe "#qword" do
@@ -233,6 +272,19 @@ describe ASM::Program do
233
272
  it "should have width of 8" do
234
273
  subject.qword(1).width.should == 8
235
274
  end
275
+
276
+ context "when given a MemoryOperand" do
277
+ let(:register) { Register.new(:eax, 4) }
278
+ let(:memory_operand) { MemoryOperand.new(register) }
279
+
280
+ it "should return a MemoryOperand" do
281
+ subject.qword(memory_operand).should be_kind_of(MemoryOperand)
282
+ end
283
+
284
+ it "should have a width of 8" do
285
+ subject.qword(memory_operand).width.should == 8
286
+ end
287
+ end
236
288
  end
237
289
 
238
290
  describe "#label" do
@@ -284,63 +336,67 @@ describe ASM::Program do
284
336
  push ebx
285
337
  push ecx
286
338
 
287
- mov eax, ebx
288
- mov eax+0, ebx
289
- mov eax+4, ebx
290
- mov eax+esi, ebx
291
- mov eax+(esi*4), ebx
292
- mov eax+(esi*4)+10, ebx
339
+ mov ebx, eax
340
+ mov ebx, eax+0
341
+ mov ebx, eax+4
342
+ mov ebx, eax+esi
343
+ mov ebx, eax+(esi*4)
344
+ mov ebx, eax+(esi*4)+10
293
345
  end
294
346
  end
295
347
 
296
- it "should convert the program to ATT syntax" do
348
+ it "should convert the program to Intel syntax" do
297
349
  subject.to_asm.should == [
350
+ "BITS 32",
351
+ "section .text",
298
352
  "_start:",
299
- "\tpushl\t%eax",
300
- "\tpushl\t%ebx",
301
- "\tpushl\t%ecx",
302
- "\tmovl\t%eax,\t%ebx",
303
- "\tmovl\t(%eax),\t%ebx",
304
- "\tmovl\t0x4(%eax),\t%ebx",
305
- "\tmovl\t(%eax,%esi),\t%ebx",
306
- "\tmovl\t(%eax,%esi,4),\t%ebx",
307
- "\tmovl\t0xa(%eax,%esi,4),\t%ebx",
353
+ "\tpush\teax",
354
+ "\tpush\tebx",
355
+ "\tpush\tecx",
356
+ "\tmov\tebx,\teax",
357
+ "\tmov\tebx,\t[eax]",
358
+ "\tmov\tebx,\t[eax+0x4]",
359
+ "\tmov\tebx,\t[eax+esi]",
360
+ "\tmov\tebx,\t[eax+esi*0x4]",
361
+ "\tmov\tebx,\t[eax+esi*0x4+0xa]",
308
362
  ""
309
363
  ].join($/)
310
364
  end
311
365
 
312
- context "when given :intel" do
313
- it "should convert the program to Intel syntax" do
314
- subject.to_asm(:intel).should == [
366
+ context "when given :att" do
367
+ it "should convert the program to ATT syntax" do
368
+ subject.to_asm(:att).should == [
369
+ ".code32",
370
+ ".text",
315
371
  "_start:",
316
- "\tpush\teax",
317
- "\tpush\tebx",
318
- "\tpush\tecx",
319
- "\tmov\tebx,\teax",
320
- "\tmov\tebx,\t[eax]",
321
- "\tmov\tebx,\t[eax+0x4]",
322
- "\tmov\tebx,\t[eax+esi]",
323
- "\tmov\tebx,\t[eax+esi*0x4]",
324
- "\tmov\tebx,\t[eax+esi*0x4+0xa]",
372
+ "\tpushl\t%eax",
373
+ "\tpushl\t%ebx",
374
+ "\tpushl\t%ecx",
375
+ "\tmovl\t%eax,\t%ebx",
376
+ "\tmovl\t(%eax),\t%ebx",
377
+ "\tmovl\t0x4(%eax),\t%ebx",
378
+ "\tmovl\t(%eax,%esi),\t%ebx",
379
+ "\tmovl\t(%eax,%esi,4),\t%ebx",
380
+ "\tmovl\t0xa(%eax,%esi,4),\t%ebx",
325
381
  ""
326
382
  ].join($/)
327
383
  end
328
384
  end
329
385
  end
330
386
 
331
- describe "#assemble", :yasm => true do
387
+ describe "#assemble", integration: true do
332
388
  subject do
333
389
  described_class.new do
334
390
  push eax
335
391
  push ebx
336
392
  push ecx
337
393
 
338
- mov eax, ebx
339
- mov eax+0, ebx
340
- mov eax+4, ebx
341
- mov eax+esi, ebx
342
- mov eax+(esi*4), ebx
343
- mov eax+(esi*4)+10, ebx
394
+ mov ebx, eax
395
+ mov ebx, eax+0
396
+ mov ebx, eax+4
397
+ mov ebx, eax+esi
398
+ mov ebx, eax+(esi*4)
399
+ mov ebx, eax+(esi*4)+10
344
400
  end
345
401
  end
346
402
 
@@ -352,10 +408,10 @@ describe ASM::Program do
352
408
  File.size(output).should > 0
353
409
  end
354
410
 
355
- context "with :syntax => :intel" do
411
+ context "with :syntax is :intel" do
356
412
  let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
357
413
 
358
- before { subject.assemble(output, :syntax => :intel) }
414
+ before { subject.assemble(output, syntax: :intel) }
359
415
 
360
416
  it "should write to the output file" do
361
417
  File.size(output).should > 0
@@ -1,33 +1,41 @@
1
+ # encoding: US-ASCII
2
+
1
3
  require 'spec_helper'
2
4
  require 'ronin/asm/shellcode'
3
5
 
4
6
  describe ASM::Shellcode do
5
- describe "#assemble", :yasm => true do
7
+ describe "#assemble", integration: true do
6
8
  subject do
7
9
  described_class.new do
8
10
  xor eax, eax
9
11
  push eax
10
12
  push 0x68732f2f
11
13
  push 0x6e69622f
12
- mov esp, ebx
14
+ mov ebx, esp
13
15
  push eax
14
16
  push ebx
15
- mov esp, ecx
17
+ mov ecx, esp
16
18
  xor edx, edx
17
- mov 0xb, al
19
+ mov al, 0xb
18
20
  int 0x80
19
21
  end
20
22
  end
21
23
 
22
- let(:shellcode) { "f1\xC0fPfh//shfh/binf\x89\xE3fPfSf\x89\xE1f1\xD2\xB0\v\xCD\x80" }
24
+ let(:shellcode) { "1\xC0Ph//shh/bin\x89\xE3PS\x89\xE11\xD2\xB0\v\xCD\x80" }
23
25
 
24
26
  it "assemble down to raw machine code" do
25
27
  subject.assemble.should == shellcode
26
28
  end
27
29
 
28
- context "with :syntax => :intel" do
30
+ context "with :syntax is :intel" do
31
+ it "assemble down to raw machine code" do
32
+ subject.assemble(syntax: :intel).should == shellcode
33
+ end
34
+ end
35
+
36
+ context "with :syntax is :att" do
29
37
  it "assemble down to raw machine code" do
30
- subject.assemble(:syntax => :intel).should == shellcode
38
+ subject.assemble(syntax: :att).should == shellcode
31
39
  end
32
40
  end
33
41
  end