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.
Files changed (51) hide show
  1. data/.document +4 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +1 -0
  6. data/COPYING.txt +674 -0
  7. data/ChangeLog.md +10 -0
  8. data/Gemfile +19 -0
  9. data/README.md +142 -0
  10. data/Rakefile +44 -0
  11. data/data/ronin/asm/freebsd/amd64/syscalls.yml +415 -0
  12. data/data/ronin/asm/freebsd/x86/syscalls.yml +415 -0
  13. data/data/ronin/asm/linux/amd64/syscalls.yml +306 -0
  14. data/data/ronin/asm/linux/x86/syscalls.yml +339 -0
  15. data/data/ronin/gen/asm/source_file.s.erb +4 -0
  16. data/gemspec.yml +20 -0
  17. data/lib/ronin/asm.rb +25 -0
  18. data/lib/ronin/asm/archs.rb +23 -0
  19. data/lib/ronin/asm/archs/amd64.rb +99 -0
  20. data/lib/ronin/asm/archs/x86.rb +166 -0
  21. data/lib/ronin/asm/asm.rb +66 -0
  22. data/lib/ronin/asm/config.rb +39 -0
  23. data/lib/ronin/asm/immediate_operand.rb +76 -0
  24. data/lib/ronin/asm/instruction.rb +65 -0
  25. data/lib/ronin/asm/memory_operand.rb +109 -0
  26. data/lib/ronin/asm/os.rb +24 -0
  27. data/lib/ronin/asm/os/freebsd.rb +34 -0
  28. data/lib/ronin/asm/os/linux.rb +34 -0
  29. data/lib/ronin/asm/os/os.rb +40 -0
  30. data/lib/ronin/asm/program.rb +476 -0
  31. data/lib/ronin/asm/register.rb +110 -0
  32. data/lib/ronin/asm/shellcode.rb +70 -0
  33. data/lib/ronin/asm/syntax.rb +23 -0
  34. data/lib/ronin/asm/syntax/att.rb +136 -0
  35. data/lib/ronin/asm/syntax/common.rb +202 -0
  36. data/lib/ronin/asm/syntax/intel.rb +150 -0
  37. data/lib/ronin/asm/version.rb +27 -0
  38. data/ronin-asm.gemspec +61 -0
  39. data/spec/asm_spec.rb +8 -0
  40. data/spec/helpers/database.rb +7 -0
  41. data/spec/immediate_operand_spec.rb +77 -0
  42. data/spec/instruction_spec.rb +62 -0
  43. data/spec/memory_operand_spec.rb +80 -0
  44. data/spec/program_spec.rb +365 -0
  45. data/spec/register_spec.rb +110 -0
  46. data/spec/shellcode_spec.rb +34 -0
  47. data/spec/spec_helper.rb +10 -0
  48. data/spec/syntax/att_spec.rb +171 -0
  49. data/spec/syntax/common_spec.rb +42 -0
  50. data/spec/syntax/intel_spec.rb +156 -0
  51. 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