ronin-asm 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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