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