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.
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/ChangeLog.md +32 -6
- data/Gemfile +2 -2
- data/README.md +30 -22
- data/Rakefile +5 -4
- data/gemspec.yml +1 -0
- data/lib/ronin/asm.rb +1 -1
- data/lib/ronin/asm/archs.rb +1 -1
- data/lib/ronin/asm/archs/amd64.rb +53 -53
- data/lib/ronin/asm/archs/x86.rb +48 -48
- data/lib/ronin/asm/asm.rb +1 -1
- data/lib/ronin/asm/config.rb +1 -1
- data/lib/ronin/asm/immediate_operand.rb +18 -11
- data/lib/ronin/asm/instruction.rb +1 -1
- data/lib/ronin/asm/memory_operand.rb +22 -16
- data/lib/ronin/asm/os.rb +1 -1
- data/lib/ronin/asm/os/freebsd.rb +1 -1
- data/lib/ronin/asm/os/linux.rb +1 -1
- data/lib/ronin/asm/os/os.rb +1 -1
- data/lib/ronin/asm/program.rb +60 -33
- data/lib/ronin/asm/register.rb +1 -1
- data/lib/ronin/asm/shellcode.rb +2 -2
- data/lib/ronin/asm/syntax.rb +1 -1
- data/lib/ronin/asm/syntax/att.rb +39 -12
- data/lib/ronin/asm/syntax/common.rb +40 -2
- data/lib/ronin/asm/syntax/intel.rb +27 -28
- data/lib/ronin/asm/version.rb +2 -2
- data/spec/{asm_spec.rb → asm/asm_spec.rb} +0 -0
- data/spec/{immediate_operand_spec.rb → asm/immediate_operand_spec.rb} +2 -0
- data/spec/{instruction_spec.rb → asm/instruction_spec.rb} +0 -0
- data/spec/{memory_operand_spec.rb → asm/memory_operand_spec.rb} +0 -0
- data/spec/{program_spec.rb → asm/program_spec.rb} +106 -50
- data/spec/{register_spec.rb → asm/register_spec.rb} +0 -0
- data/spec/{shellcode_spec.rb → asm/shellcode_spec.rb} +15 -7
- data/spec/{syntax → asm/syntax}/att_spec.rb +15 -5
- data/spec/{syntax → asm/syntax}/common_spec.rb +0 -0
- data/spec/{syntax → asm/syntax}/intel_spec.rb +24 -6
- metadata +16 -16
- data/.gemtest +0 -0
- 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-
|
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 = [
|
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-
|
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
|
-
|
89
|
-
end
|
88
|
+
asm = "[#{asm}]"
|
90
89
|
|
91
|
-
|
92
|
-
|
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
|
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
|
138
|
+
# The formatted prologue.
|
135
139
|
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
#
|
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
|
data/lib/ronin/asm/version.rb
CHANGED
@@ -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-
|
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.
|
25
|
+
VERSION = '0.2.0'
|
26
26
|
end
|
27
27
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -8,8 +8,8 @@ describe ASM::Program do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
context "when :arch
|
12
|
-
subject { described_class.new(:
|
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
|
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
|
118
|
-
subject { described_class.new(:
|
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
|
124
|
-
subject { described_class.new(:
|
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
|
131
|
-
subject { described_class.new(:
|
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
|
144
|
-
subject { described_class.new(:
|
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
|
150
|
-
subject { described_class.new(:
|
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
|
288
|
-
mov eax+0
|
289
|
-
mov eax+4
|
290
|
-
mov eax+esi
|
291
|
-
mov eax+(esi*4)
|
292
|
-
mov eax+(esi*4)+10
|
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
|
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
|
-
"\
|
300
|
-
"\
|
301
|
-
"\
|
302
|
-
"\
|
303
|
-
"\
|
304
|
-
"\
|
305
|
-
"\
|
306
|
-
"\
|
307
|
-
"\
|
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 :
|
313
|
-
it "should convert the program to
|
314
|
-
subject.to_asm(:
|
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
|
-
"\
|
317
|
-
"\
|
318
|
-
"\
|
319
|
-
"\
|
320
|
-
"\
|
321
|
-
"\
|
322
|
-
"\
|
323
|
-
"\
|
324
|
-
"\
|
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", :
|
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
|
339
|
-
mov eax+0
|
340
|
-
mov eax+4
|
341
|
-
mov eax+esi
|
342
|
-
mov eax+(esi*4)
|
343
|
-
mov eax+(esi*4)+10
|
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
|
411
|
+
context "with :syntax is :intel" do
|
356
412
|
let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
|
357
413
|
|
358
|
-
before { subject.assemble(output, :
|
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
|
File without changes
|
@@ -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", :
|
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
|
14
|
+
mov ebx, esp
|
13
15
|
push eax
|
14
16
|
push ebx
|
15
|
-
mov
|
17
|
+
mov ecx, esp
|
16
18
|
xor edx, edx
|
17
|
-
mov 0xb
|
19
|
+
mov al, 0xb
|
18
20
|
int 0x80
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
let(:shellcode) { "
|
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
|
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(:
|
38
|
+
subject.assemble(syntax: :att).should == shellcode
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|