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.
- data/.document +4 -0
- data/.gemtest +0 -0
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +674 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +19 -0
- data/README.md +142 -0
- data/Rakefile +44 -0
- data/data/ronin/asm/freebsd/amd64/syscalls.yml +415 -0
- data/data/ronin/asm/freebsd/x86/syscalls.yml +415 -0
- data/data/ronin/asm/linux/amd64/syscalls.yml +306 -0
- data/data/ronin/asm/linux/x86/syscalls.yml +339 -0
- data/data/ronin/gen/asm/source_file.s.erb +4 -0
- data/gemspec.yml +20 -0
- data/lib/ronin/asm.rb +25 -0
- data/lib/ronin/asm/archs.rb +23 -0
- data/lib/ronin/asm/archs/amd64.rb +99 -0
- data/lib/ronin/asm/archs/x86.rb +166 -0
- data/lib/ronin/asm/asm.rb +66 -0
- data/lib/ronin/asm/config.rb +39 -0
- data/lib/ronin/asm/immediate_operand.rb +76 -0
- data/lib/ronin/asm/instruction.rb +65 -0
- data/lib/ronin/asm/memory_operand.rb +109 -0
- data/lib/ronin/asm/os.rb +24 -0
- data/lib/ronin/asm/os/freebsd.rb +34 -0
- data/lib/ronin/asm/os/linux.rb +34 -0
- data/lib/ronin/asm/os/os.rb +40 -0
- data/lib/ronin/asm/program.rb +476 -0
- data/lib/ronin/asm/register.rb +110 -0
- data/lib/ronin/asm/shellcode.rb +70 -0
- data/lib/ronin/asm/syntax.rb +23 -0
- data/lib/ronin/asm/syntax/att.rb +136 -0
- data/lib/ronin/asm/syntax/common.rb +202 -0
- data/lib/ronin/asm/syntax/intel.rb +150 -0
- data/lib/ronin/asm/version.rb +27 -0
- data/ronin-asm.gemspec +61 -0
- data/spec/asm_spec.rb +8 -0
- data/spec/helpers/database.rb +7 -0
- data/spec/immediate_operand_spec.rb +77 -0
- data/spec/instruction_spec.rb +62 -0
- data/spec/memory_operand_spec.rb +80 -0
- data/spec/program_spec.rb +365 -0
- data/spec/register_spec.rb +110 -0
- data/spec/shellcode_spec.rb +34 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/syntax/att_spec.rb +171 -0
- data/spec/syntax/common_spec.rb +42 -0
- data/spec/syntax/intel_spec.rb +156 -0
- metadata +163 -0
@@ -0,0 +1,365 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/asm/program'
|
3
|
+
|
4
|
+
describe ASM::Program do
|
5
|
+
describe "#arch" do
|
6
|
+
it "should default to :x86" do
|
7
|
+
subject.arch.should == :x86
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when :arch => :x86" do
|
12
|
+
subject { described_class.new(:arch => :x86) }
|
13
|
+
|
14
|
+
its(:word_size) { should == 4 }
|
15
|
+
|
16
|
+
describe "#stask_base" do
|
17
|
+
it "should be ebp" do
|
18
|
+
subject.stack_base.name.should == :ebp
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#stask_pointer" do
|
23
|
+
it "should be esp" do
|
24
|
+
subject.stack_pointer.name.should == :esp
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#stack_push" do
|
29
|
+
let(:value) { 0xff }
|
30
|
+
|
31
|
+
before { subject.stack_push(value) }
|
32
|
+
|
33
|
+
it "should add a 'push' instruction with a value" do
|
34
|
+
subject.instructions[-1].name.should == :push
|
35
|
+
subject.instructions[-1].operands[0].value.should == value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#stack_pop" do
|
40
|
+
let(:register) { subject.register(:eax) }
|
41
|
+
|
42
|
+
before { subject.stack_pop(register) }
|
43
|
+
|
44
|
+
it "should add a 'pop' instruction with a register" do
|
45
|
+
subject.instructions[-1].name.should == :pop
|
46
|
+
subject.instructions[-1].operands[0].should == register
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#register_clear" do
|
51
|
+
let(:name) { :eax }
|
52
|
+
|
53
|
+
before { subject.register_clear(name) }
|
54
|
+
|
55
|
+
it "should add a 'xor' instruction with a registers" do
|
56
|
+
subject.instructions[-1].name.should == :xor
|
57
|
+
subject.instructions[-1].operands[0].name.should == name
|
58
|
+
subject.instructions[-1].operands[1].name.should == name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#register_set" do
|
63
|
+
let(:name) { :eax }
|
64
|
+
let(:value) { 0xff }
|
65
|
+
|
66
|
+
before { subject.register_set(value,name) }
|
67
|
+
|
68
|
+
it "should add a 'xor' instruction with a registers" do
|
69
|
+
subject.instructions[-1].name.should == :mov
|
70
|
+
subject.instructions[-1].operands[0].value.should == value
|
71
|
+
subject.instructions[-1].operands[1].name.should == name
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#register_save" do
|
76
|
+
let(:name) { :eax }
|
77
|
+
|
78
|
+
before { subject.register_save(name) }
|
79
|
+
|
80
|
+
it "should add a 'xor' instruction with a registers" do
|
81
|
+
subject.instructions[-1].name.should == :push
|
82
|
+
subject.instructions[-1].operands[0].name.should == name
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#register_save" do
|
87
|
+
let(:name) { :eax }
|
88
|
+
|
89
|
+
before { subject.register_load(name) }
|
90
|
+
|
91
|
+
it "should add a 'xor' instruction with a registers" do
|
92
|
+
subject.instructions[-1].name.should == :pop
|
93
|
+
subject.instructions[-1].operands[0].name.should == name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#interrupt" do
|
98
|
+
let(:number) { 0x0a }
|
99
|
+
|
100
|
+
before { subject.interrupt(number) }
|
101
|
+
|
102
|
+
it "should add an 'int' instruction with the interrupt number" do
|
103
|
+
subject.instructions[-1].name.should == :int
|
104
|
+
subject.instructions[-1].operands[0].value.should == number
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#syscall" do
|
109
|
+
before { subject.syscall }
|
110
|
+
|
111
|
+
it "should add an 'int 0x80' instruction" do
|
112
|
+
subject.instructions[-1].name.should == :int
|
113
|
+
subject.instructions[-1].operands[0].value.should == 0x80
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when :os => 'Linux'" do
|
118
|
+
subject { described_class.new(:arch => :x86, :os => 'Linux') }
|
119
|
+
|
120
|
+
its(:syscalls) { should_not be_empty }
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when :os => 'FreeBSD'" do
|
124
|
+
subject { described_class.new(:arch => :x86, :os => 'FreeBSD') }
|
125
|
+
|
126
|
+
its(:syscalls) { should_not be_empty }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when :arch => :amd64" do
|
131
|
+
subject { described_class.new(:arch => :amd64) }
|
132
|
+
|
133
|
+
its(:word_size) { should == 8 }
|
134
|
+
|
135
|
+
describe "#syscall" do
|
136
|
+
before { subject.syscall }
|
137
|
+
|
138
|
+
it "should add a 'syscall' instruction" do
|
139
|
+
subject.instructions[-1].name.should == :syscall
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "when :os => 'Linux'" do
|
144
|
+
subject { described_class.new(:arch => :amd64, :os => 'Linux') }
|
145
|
+
|
146
|
+
its(:syscalls) { should_not be_empty }
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when :os => 'FreeBSD'" do
|
150
|
+
subject { described_class.new(:arch => :amd64, :os => 'FreeBSD') }
|
151
|
+
|
152
|
+
its(:syscalls) { should_not be_empty }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#register?" do
|
157
|
+
it "should return true for existing registers" do
|
158
|
+
subject.register?(:eax).should be_true
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should return false for unknown registers" do
|
162
|
+
subject.register?(:foo).should be_false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#register" do
|
167
|
+
it "should return a Register" do
|
168
|
+
subject.register(:eax).should be_kind_of(ASM::Register)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should allocate the register" do
|
172
|
+
subject.register(:ebx)
|
173
|
+
|
174
|
+
subject.allocated_registers.should include(:ebx)
|
175
|
+
end
|
176
|
+
|
177
|
+
context "when given an unknown register name" do
|
178
|
+
it "should raise an ArgumentError" do
|
179
|
+
lambda {
|
180
|
+
subject.register(:foo)
|
181
|
+
}.should raise_error(ArgumentError)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#instruction" do
|
187
|
+
it "should return an Instruction" do
|
188
|
+
subject.instruction(:hlt).should be_kind_of(ASM::Instruction)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should append the new Instruction" do
|
192
|
+
subject.instruction(:push, 1)
|
193
|
+
|
194
|
+
subject.instructions.last.name.should == :push
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "#byte" do
|
199
|
+
it "should return a ImmedateOperand" do
|
200
|
+
subject.byte(1).should be_kind_of(ImmediateOperand)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should have width of 1" do
|
204
|
+
subject.byte(1).width.should == 1
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "#word" do
|
209
|
+
it "should return a ImmediateOperand" do
|
210
|
+
subject.word(1).should be_kind_of(ImmediateOperand)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should have width of 2" do
|
214
|
+
subject.word(1).width.should == 2
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "#dword" do
|
219
|
+
it "should return a ImmediateOperand" do
|
220
|
+
subject.dword(1).should be_kind_of(ImmediateOperand)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should have width of 4" do
|
224
|
+
subject.dword(1).width.should == 4
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#qword" do
|
229
|
+
it "should return a ImmediateOperand" do
|
230
|
+
subject.qword(1).should be_kind_of(ImmediateOperand)
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should have width of 8" do
|
234
|
+
subject.qword(1).width.should == 8
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#label" do
|
239
|
+
let(:name) { :_start }
|
240
|
+
|
241
|
+
it "should return the label name" do
|
242
|
+
label = subject.label(name) { }
|
243
|
+
|
244
|
+
label.should == name
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should add the label to the instructions" do
|
248
|
+
subject.label(name) { }
|
249
|
+
|
250
|
+
subject.instructions.last.should == name
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should accept a block" do
|
254
|
+
subject.label(name) { push 2 }
|
255
|
+
|
256
|
+
subject.instructions[-1].name.should == :push
|
257
|
+
subject.instructions[-2].should == name
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "#method_missing" do
|
262
|
+
context "when called without a block" do
|
263
|
+
it "should add a new instruction" do
|
264
|
+
subject.pop
|
265
|
+
|
266
|
+
subject.instructions[-1].name.should == :pop
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "when called with one argument and a block" do
|
271
|
+
it "should add a new label" do
|
272
|
+
subject._loop { mov eax, ebx }
|
273
|
+
|
274
|
+
subject.instructions[-2].should == :_loop
|
275
|
+
subject.instructions[-1].name.should == :mov
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
describe "#to_asm" do
|
281
|
+
subject do
|
282
|
+
described_class.new do
|
283
|
+
push eax
|
284
|
+
push ebx
|
285
|
+
push ecx
|
286
|
+
|
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
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should convert the program to ATT syntax" do
|
297
|
+
subject.to_asm.should == [
|
298
|
+
"_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",
|
308
|
+
""
|
309
|
+
].join($/)
|
310
|
+
end
|
311
|
+
|
312
|
+
context "when given :intel" do
|
313
|
+
it "should convert the program to Intel syntax" do
|
314
|
+
subject.to_asm(:intel).should == [
|
315
|
+
"_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]",
|
325
|
+
""
|
326
|
+
].join($/)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe "#assemble", :yasm => true do
|
332
|
+
subject do
|
333
|
+
described_class.new do
|
334
|
+
push eax
|
335
|
+
push ebx
|
336
|
+
push ecx
|
337
|
+
|
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
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
|
348
|
+
|
349
|
+
before { subject.assemble(output) }
|
350
|
+
|
351
|
+
it "should write to the output file" do
|
352
|
+
File.size(output).should > 0
|
353
|
+
end
|
354
|
+
|
355
|
+
context "with :syntax => :intel" do
|
356
|
+
let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
|
357
|
+
|
358
|
+
before { subject.assemble(output, :syntax => :intel) }
|
359
|
+
|
360
|
+
it "should write to the output file" do
|
361
|
+
File.size(output).should > 0
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ronin/asm/register'
|
4
|
+
|
5
|
+
describe Register do
|
6
|
+
let(:register) { described_class.new(:eax, 4) }
|
7
|
+
|
8
|
+
subject { register }
|
9
|
+
|
10
|
+
describe "#+" do
|
11
|
+
context "when given an MemoryOperand" do
|
12
|
+
let(:operand) { MemoryOperand.new(nil,10,register,2) }
|
13
|
+
|
14
|
+
subject { register + operand }
|
15
|
+
|
16
|
+
it { should be_kind_of(MemoryOperand) }
|
17
|
+
|
18
|
+
it "should set the base" do
|
19
|
+
subject.base.should == register
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should preserve the offset, index and scale" do
|
23
|
+
subject.offset.should == operand.offset
|
24
|
+
subject.index.should == operand.index
|
25
|
+
subject.scale.should == operand.scale
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when given a Register" do
|
30
|
+
subject { register + register }
|
31
|
+
|
32
|
+
it { should be_kind_of(MemoryOperand) }
|
33
|
+
|
34
|
+
it "should set the base" do
|
35
|
+
subject.base.should == register
|
36
|
+
end
|
37
|
+
|
38
|
+
its(:offset) { should == 0 }
|
39
|
+
|
40
|
+
it "should set the index" do
|
41
|
+
subject.index.should == register
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when given an Integer" do
|
46
|
+
let(:offset) { 10 }
|
47
|
+
|
48
|
+
subject { register + offset }
|
49
|
+
|
50
|
+
it { should be_kind_of(MemoryOperand) }
|
51
|
+
|
52
|
+
it "should set the base" do
|
53
|
+
subject.base.should == register
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should set the offset" do
|
57
|
+
subject.offset.should == offset
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "otherwise" do
|
62
|
+
it "should raise a TypeError" do
|
63
|
+
lambda {
|
64
|
+
register + Object.new
|
65
|
+
}.should raise_error(TypeError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#-" do
|
71
|
+
let(:offset) { 10 }
|
72
|
+
|
73
|
+
subject { register - offset }
|
74
|
+
|
75
|
+
it { should be_kind_of(MemoryOperand) }
|
76
|
+
|
77
|
+
it "should set the base" do
|
78
|
+
subject.base.should == register
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should set a negative offset" do
|
82
|
+
subject.offset.should == -offset
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#*" do
|
87
|
+
let(:scale) { 2 }
|
88
|
+
|
89
|
+
subject { register * scale }
|
90
|
+
|
91
|
+
it { should be_kind_of(MemoryOperand) }
|
92
|
+
|
93
|
+
its(:base) { should be_nil }
|
94
|
+
its(:offset) { should == 0 }
|
95
|
+
|
96
|
+
it "should set the index" do
|
97
|
+
subject.index.should == register
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should set the scale" do
|
101
|
+
subject.scale.should == scale
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#to_s" do
|
106
|
+
it "should return the register name" do
|
107
|
+
subject.to_s.should == subject.name.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|