ronin-code-asm 1.0.0.beta1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -0
- data/.yardopts +1 -1
- data/README.md +2 -1
- data/gemspec.yml +2 -2
- data/lib/ronin/code/asm/archs/amd64.rb +2 -2
- data/lib/ronin/code/asm/archs/x86.rb +2 -2
- data/lib/ronin/code/asm/archs.rb +1 -1
- data/lib/ronin/code/asm/config.rb +1 -1
- data/lib/ronin/code/asm/immediate_operand.rb +1 -1
- data/lib/ronin/code/asm/instruction.rb +1 -1
- data/lib/ronin/code/asm/memory_operand.rb +1 -1
- data/lib/ronin/code/asm/os/freebsd.rb +1 -1
- data/lib/ronin/code/asm/os/linux.rb +1 -1
- data/lib/ronin/code/asm/os/os.rb +1 -1
- data/lib/ronin/code/asm/os.rb +1 -1
- data/lib/ronin/code/asm/program.rb +6 -6
- data/lib/ronin/code/asm/register.rb +2 -2
- data/lib/ronin/code/asm/shellcode.rb +1 -1
- data/lib/ronin/code/asm/syntax/att.rb +1 -1
- data/lib/ronin/code/asm/syntax/common.rb +1 -1
- data/lib/ronin/code/asm/syntax/intel.rb +1 -1
- data/lib/ronin/code/asm/syntax.rb +1 -1
- data/lib/ronin/code/asm/version.rb +2 -2
- data/lib/ronin/code/asm.rb +1 -1
- data/ronin-code-asm.gemspec +2 -1
- metadata +5 -30
- data/spec/asm_spec.rb +0 -14
- data/spec/config_spec.rb +0 -10
- data/spec/immediate_operand_spec.rb +0 -79
- data/spec/instruction_spec.rb +0 -62
- data/spec/memory_operand_spec.rb +0 -80
- data/spec/os_spec.rb +0 -68
- data/spec/program_spec.rb +0 -439
- data/spec/register_spec.rb +0 -112
- data/spec/shellcode_spec.rb +0 -58
- data/spec/spec_helper.rb +0 -7
- data/spec/syntax/att_spec.rb +0 -181
- data/spec/syntax/common_spec.rb +0 -42
- data/spec/syntax/intel_spec.rb +0 -174
data/spec/shellcode_spec.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# encoding: US-ASCII
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'ronin/code/asm/shellcode'
|
5
|
-
|
6
|
-
describe Ronin::Code::ASM::Shellcode do
|
7
|
-
describe "#assemble", integration: true do
|
8
|
-
subject do
|
9
|
-
described_class.new do
|
10
|
-
xor eax, eax
|
11
|
-
push eax
|
12
|
-
push 0x68732f2f
|
13
|
-
push 0x6e69622f
|
14
|
-
mov ebx, esp
|
15
|
-
push eax
|
16
|
-
push ebx
|
17
|
-
mov ecx, esp
|
18
|
-
xor edx, edx
|
19
|
-
mov al, 0xb
|
20
|
-
int 0x80
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
let(:shellcode) { "1\xC0Ph//shh/bin\x89\xE3PS\x89\xE11\xD2\xB0\v\xCD\x80" }
|
25
|
-
|
26
|
-
it "must assemble down to raw machine code" do
|
27
|
-
expect(subject.assemble).to eq(shellcode)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "must return an ASCII-8bit encoded String" do
|
31
|
-
expect(subject.assemble.encoding).to eq(Encoding::ASCII_8BIT)
|
32
|
-
end
|
33
|
-
|
34
|
-
context "with :output" do
|
35
|
-
let(:output) do
|
36
|
-
Tempfile.new(['ronin-shellcode-custom-path', '.bin']).path
|
37
|
-
end
|
38
|
-
|
39
|
-
it "must write to the custom path" do
|
40
|
-
expect(subject.assemble(output: output)).to eq(shellcode)
|
41
|
-
|
42
|
-
File.binread(output)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "with :syntax is :intel" do
|
47
|
-
it "assemble down to raw machine code" do
|
48
|
-
expect(subject.assemble(syntax: :intel)).to eq(shellcode)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "with :syntax is :att" do
|
53
|
-
it "assemble down to raw machine code" do
|
54
|
-
expect(subject.assemble(syntax: :att)).to eq(shellcode)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/spec/spec_helper.rb
DELETED
data/spec/syntax/att_spec.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'ronin/code/asm/syntax/att'
|
4
|
-
require 'ronin/code/asm/register'
|
5
|
-
require 'ronin/code/asm/immediate_operand'
|
6
|
-
require 'ronin/code/asm/memory_operand'
|
7
|
-
require 'ronin/code/asm/instruction'
|
8
|
-
require 'ronin/code/asm/program'
|
9
|
-
|
10
|
-
describe Ronin::Code::ASM::Syntax::ATT do
|
11
|
-
subject { described_class }
|
12
|
-
|
13
|
-
describe "emit_register" do
|
14
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
15
|
-
|
16
|
-
it "must prepend a '%' to the register name" do
|
17
|
-
expect(subject.emit_register(register)).to eq("%eax")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "emit_immediate_operand" do
|
22
|
-
let(:operand) { Ronin::Code::ASM::ImmediateOperand.new(255, 1) }
|
23
|
-
|
24
|
-
it "must prepend a '$' to the immediate" do
|
25
|
-
expect(subject.emit_immediate_operand(operand)).to eq("$0xff")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "emit_memory_operand" do
|
30
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
31
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
|
32
|
-
|
33
|
-
it "must enclose the memory in parenthesis" do
|
34
|
-
expect(subject.emit_memory_operand(operand)).to eq("(%eax)")
|
35
|
-
end
|
36
|
-
|
37
|
-
context "with an offset" do
|
38
|
-
let(:offset) { 255 }
|
39
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,offset) }
|
40
|
-
|
41
|
-
it "must prepend the offset as an integer" do
|
42
|
-
expect(subject.emit_memory_operand(operand)).to eq("0xff(%eax)")
|
43
|
-
end
|
44
|
-
|
45
|
-
context "when 0" do
|
46
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0) }
|
47
|
-
|
48
|
-
it "must omit the offset" do
|
49
|
-
expect(subject.emit_memory_operand(operand)).to eq("(%eax)")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "with an index" do
|
55
|
-
let(:index) { Ronin::Code::ASM::Register.new(:esi, 4) }
|
56
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index) }
|
57
|
-
|
58
|
-
it "must include the index argument" do
|
59
|
-
expect(subject.emit_memory_operand(operand)).to eq("(%eax,%esi)")
|
60
|
-
end
|
61
|
-
|
62
|
-
context "with a scale" do
|
63
|
-
let(:scale) { 4 }
|
64
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index,scale) }
|
65
|
-
|
66
|
-
it "must prepend the scale argument as a decimal" do
|
67
|
-
expect(subject.emit_memory_operand(operand)).to eq("(%eax,%esi,#{scale})")
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe "emit_instruction" do
|
74
|
-
context "with no operands" do
|
75
|
-
let(:instruction) { Ronin::Code::ASM::Instruction.new(:ret, []) }
|
76
|
-
|
77
|
-
it "must emit the instruction name" do
|
78
|
-
expect(subject.emit_instruction(instruction)).to eq('ret')
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "with one operand" do
|
83
|
-
context "with width of 1" do
|
84
|
-
let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0x80, 1) }
|
85
|
-
let(:instruction) { Ronin::Code::ASM::Instruction.new(:int, [immediate]) }
|
86
|
-
|
87
|
-
it "must not append a size specifier to the instruction name" do
|
88
|
-
expect(subject.emit_instruction(instruction)).to eq("int\t$0x80")
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context "with multiple operands" do
|
94
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
95
|
-
let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0xff, 1) }
|
96
|
-
let(:instruction) { Ronin::Code::ASM::Instruction.new(:mov, [register, immediate]) }
|
97
|
-
|
98
|
-
it "must add a size specifier to the instruction name" do
|
99
|
-
expect(subject.emit_instruction(instruction)).to match(/^movl/)
|
100
|
-
end
|
101
|
-
|
102
|
-
it "must emit the operands" do
|
103
|
-
expect(subject.emit_instruction(instruction)).to eq("movl\t$0xff,\t%eax")
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "emit_section" do
|
109
|
-
it "must emit the section name" do
|
110
|
-
expect(subject.emit_section(:text)).to eq(".text")
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
describe "emit_program" do
|
115
|
-
let(:program) do
|
116
|
-
Ronin::Code::ASM::Program.new do
|
117
|
-
mov eax, 0xff
|
118
|
-
ret
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
it "must output the _start label and the program" do
|
123
|
-
asm = subject.emit_program(program)
|
124
|
-
|
125
|
-
expect(asm).to eq([
|
126
|
-
".code32",
|
127
|
-
".text",
|
128
|
-
"_start:",
|
129
|
-
"\tmovl\t$0xff,\t%eax",
|
130
|
-
"\tret",
|
131
|
-
""
|
132
|
-
].join($/))
|
133
|
-
end
|
134
|
-
|
135
|
-
context "when emitting labels" do
|
136
|
-
let(:program) do
|
137
|
-
Ronin::Code::ASM::Program.new do
|
138
|
-
mov eax, 0
|
139
|
-
|
140
|
-
_loop do
|
141
|
-
inc eax
|
142
|
-
cmp eax, 10
|
143
|
-
jl :_loop
|
144
|
-
end
|
145
|
-
|
146
|
-
ret
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
it "must emit both labels and instructions" do
|
151
|
-
expect(subject.emit_program(program)).to eq([
|
152
|
-
".code32",
|
153
|
-
".text",
|
154
|
-
"_start:",
|
155
|
-
"\tmovl\t$0x0,\t%eax",
|
156
|
-
"_loop:",
|
157
|
-
"\tincl\t%eax",
|
158
|
-
"\tcmpl\t$0xa,\t%eax",
|
159
|
-
"\tjl\t_loop",
|
160
|
-
"\tret",
|
161
|
-
""
|
162
|
-
].join($/))
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context "when the program arch is :amd64" do
|
167
|
-
let(:program) do
|
168
|
-
Ronin::Code::ASM::Program.new(arch: :amd64) do
|
169
|
-
push rax
|
170
|
-
push rbx
|
171
|
-
mov 0xff, rax
|
172
|
-
ret
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
it "must include start with the '.code64' directive" do
|
177
|
-
expect(subject.emit_program(program)).to match(/^\.code64$/)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
data/spec/syntax/common_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'ronin/code/asm/syntax/common'
|
4
|
-
|
5
|
-
describe Ronin::Code::ASM::Syntax::Common do
|
6
|
-
subject { described_class }
|
7
|
-
|
8
|
-
describe "emit_keyword" do
|
9
|
-
let(:name) { :_start }
|
10
|
-
|
11
|
-
it "must convert a keyword to a String" do
|
12
|
-
expect(subject.emit_keyword(name)).to eq(name.to_s)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "emit_integer" do
|
17
|
-
let(:integer) { 255 }
|
18
|
-
let(:hexadecimal) { "0xff" }
|
19
|
-
|
20
|
-
it "must convert it into a hexadecimal value" do
|
21
|
-
expect(subject.emit_integer(integer)).to eq(hexadecimal)
|
22
|
-
end
|
23
|
-
|
24
|
-
context "when given a negative number" do
|
25
|
-
let(:negative) { -255 }
|
26
|
-
let(:hexadecimal) { "-0xff" }
|
27
|
-
|
28
|
-
it "must convert it into a hexadecimal value" do
|
29
|
-
expect(subject.emit_integer(negative)).to eq(hexadecimal)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe "emit_label" do
|
35
|
-
let(:name) { :_start }
|
36
|
-
let(:label) { '_start:' }
|
37
|
-
|
38
|
-
it "must append a ':' to the name" do
|
39
|
-
expect(subject.emit_label(name)).to eq(label)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/spec/syntax/intel_spec.rb
DELETED
@@ -1,174 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'ronin/code/asm/syntax/intel'
|
4
|
-
require 'ronin/code/asm/register'
|
5
|
-
require 'ronin/code/asm/immediate_operand'
|
6
|
-
require 'ronin/code/asm/memory_operand'
|
7
|
-
require 'ronin/code/asm/instruction'
|
8
|
-
require 'ronin/code/asm/program'
|
9
|
-
|
10
|
-
describe Ronin::Code::ASM::Syntax::Intel do
|
11
|
-
subject { described_class }
|
12
|
-
|
13
|
-
describe "emit_register" do
|
14
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
15
|
-
|
16
|
-
it "must return the register name" do
|
17
|
-
expect(subject.emit_register(register)).to eq("eax")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "emit_immediate_operand" do
|
22
|
-
let(:operand) { Ronin::Code::ASM::ImmediateOperand.new(255, 1) }
|
23
|
-
|
24
|
-
it "must prepend a size specifier" do
|
25
|
-
expect(subject.emit_immediate_operand(operand)).to eq("BYTE 0xff")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "emit_memory_operand" do
|
30
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
31
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
|
32
|
-
|
33
|
-
it "must enclose the memory in brackets" do
|
34
|
-
expect(subject.emit_memory_operand(operand)).to eq("[eax]")
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when operand width does not match the base width" do
|
38
|
-
before { operand.width = 2 }
|
39
|
-
|
40
|
-
it "must specify the width" do
|
41
|
-
expect(subject.emit_memory_operand(operand)).to eq("WORD [eax]")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "with an offset" do
|
46
|
-
let(:offset) { 255 }
|
47
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,offset) }
|
48
|
-
|
49
|
-
it "must add the offset to the base" do
|
50
|
-
expect(subject.emit_memory_operand(operand)).to eq("[eax+0xff]")
|
51
|
-
end
|
52
|
-
|
53
|
-
context "when 0" do
|
54
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0) }
|
55
|
-
|
56
|
-
it "must omit the offset" do
|
57
|
-
expect(subject.emit_memory_operand(operand)).to eq("[eax]")
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "with an index" do
|
63
|
-
let(:index) { Ronin::Code::ASM::Register.new(:esi, 4) }
|
64
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index) }
|
65
|
-
|
66
|
-
it "must add the index to the base" do
|
67
|
-
expect(subject.emit_memory_operand(operand)).to eq("[eax+esi]")
|
68
|
-
end
|
69
|
-
|
70
|
-
context "with a scale" do
|
71
|
-
let(:scale) { 4 }
|
72
|
-
let(:operand) { Ronin::Code::ASM::MemoryOperand.new(register,0,index,scale) }
|
73
|
-
|
74
|
-
it "must multiple the index by the scale" do
|
75
|
-
expect(subject.emit_memory_operand(operand)).to eq("[eax+esi*0x4]")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "emit_instruction" do
|
82
|
-
context "with no operands" do
|
83
|
-
let(:instruction) { Ronin::Code::ASM::Instruction.new(:ret, []) }
|
84
|
-
|
85
|
-
it "must emit the instruction name" do
|
86
|
-
expect(subject.emit_instruction(instruction)).to eq('ret')
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context "with multiple operands" do
|
91
|
-
let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
|
92
|
-
let(:immediate) { Ronin::Code::ASM::ImmediateOperand.new(0xff, 1) }
|
93
|
-
let(:instruction) { Ronin::Code::ASM::Instruction.new(:mov, [register, immediate]) }
|
94
|
-
|
95
|
-
it "must emit the operands" do
|
96
|
-
expect(subject.emit_instruction(instruction)).to eq("mov\teax,\tBYTE 0xff")
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe "emit_section" do
|
102
|
-
it "must emit the section name" do
|
103
|
-
expect(subject.emit_section(:text)).to eq("section .text")
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe "emit_program" do
|
108
|
-
let(:program) do
|
109
|
-
Ronin::Code::ASM::Program.new do
|
110
|
-
mov eax, 0xff
|
111
|
-
ret
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
it "must output the _start label and the program" do
|
116
|
-
asm = subject.emit_program(program)
|
117
|
-
|
118
|
-
expect(asm).to eq([
|
119
|
-
"BITS 32",
|
120
|
-
"section .text",
|
121
|
-
"_start:",
|
122
|
-
"\tmov\teax,\tBYTE 0xff",
|
123
|
-
"\tret",
|
124
|
-
""
|
125
|
-
].join($/))
|
126
|
-
end
|
127
|
-
|
128
|
-
context "when emitting labels" do
|
129
|
-
let(:program) do
|
130
|
-
Ronin::Code::ASM::Program.new do
|
131
|
-
mov eax, 0
|
132
|
-
|
133
|
-
_loop do
|
134
|
-
inc eax
|
135
|
-
cmp eax, 10
|
136
|
-
jl :_loop
|
137
|
-
end
|
138
|
-
|
139
|
-
ret
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
it "must emit both labels and instructions" do
|
144
|
-
expect(subject.emit_program(program)).to eq([
|
145
|
-
"BITS 32",
|
146
|
-
"section .text",
|
147
|
-
"_start:",
|
148
|
-
"\tmov\teax,\tBYTE 0x0",
|
149
|
-
"_loop:",
|
150
|
-
"\tinc\teax",
|
151
|
-
"\tcmp\teax,\tBYTE 0xa",
|
152
|
-
"\tjl\t_loop",
|
153
|
-
"\tret",
|
154
|
-
""
|
155
|
-
].join($/))
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
context "when the program arch is :amd64" do
|
160
|
-
let(:program) do
|
161
|
-
Ronin::Code::ASM::Program.new(arch: :amd64) do
|
162
|
-
push rax
|
163
|
-
push rbx
|
164
|
-
mov rax, 0xff
|
165
|
-
ret
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
it "must include start with the '.code64' directive" do
|
170
|
-
expect(subject.emit_program(program)).to match(/^BITS 64$/)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|