Skip to content

Commit 7b33ff1

Browse files
committed
Land rapid7#3767, @jvazquez-r7's specs for Rex::Encoder::XDR
2 parents 3bffd24 + 3d03a8c commit 7b33ff1

File tree

2 files changed

+282
-2
lines changed

2 files changed

+282
-2
lines changed

lib/rex/encoder/xdr.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ def XDR.encode_int(int)
1616
end
1717

1818
def XDR.decode_int!(data)
19-
return data.slice!(0..3).unpack('N')[0] if data
20-
data = 0
19+
raise ArgumentError, 'XDR: No Integer data to decode' unless data
20+
raise ArgumentError, "XDR: Too little data to decode (#{data.size})" if data.size < 4
21+
return data.slice!(0..3).unpack('N')[0]
2122
end
2223

2324
def XDR.encode_lchar(char)

spec/lib/rex/encoder/xdr_spec.rb

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# -*- coding:binary -*-
2+
require 'spec_helper'
3+
4+
require 'rex/encoder/xdr'
5+
6+
describe Rex::Encoder::XDR do
7+
8+
describe ".encode_int" do
9+
subject(:encoded_int) { described_class.encode_int(int) }
10+
let(:int) { 0x41424344 }
11+
12+
it "returns an String" do
13+
is_expected.to be_kind_of(String)
14+
end
15+
16+
it "encodes big endian 32 bit usigned integer" do
17+
is_expected.to eq("\x41\x42\x43\x44")
18+
end
19+
end
20+
21+
describe ".decode_int!" do
22+
subject(:decoded_int) { described_class.decode_int!(data) }
23+
24+
context "when data is nil" do
25+
let(:data) { nil }
26+
it "raises an error" do
27+
expect { decoded_int }.to raise_error(ArgumentError)
28+
end
29+
end
30+
31+
context "when data is empty" do
32+
let(:data) { '' }
33+
34+
it "raises an error" do
35+
expect { decoded_int }.to raise_error(ArgumentError)
36+
end
37+
end
38+
39+
context "when data is 1-4 bytes length" do
40+
let(:data) { "\x41\x42\x43\x44" }
41+
42+
it "unpacks big endian 32bit unsigned int" do
43+
is_expected.to eq(0x41424344)
44+
end
45+
end
46+
47+
context "when data is bigger than 4 bytes" do
48+
let(:data) { "\x41\x42\x43\x44\x45" }
49+
50+
it "unpacks just one big endian 32bit unsigned int" do
51+
is_expected.to eq(0x41424344)
52+
end
53+
end
54+
end
55+
56+
describe ".encode_lchar" do
57+
subject(:encoded_lchar) { described_class.encode_lchar(char) }
58+
59+
context "when char & 0x80 == 0" do
60+
let(:char) { 0x80 }
61+
62+
it "encodes char byte as integer with sign extended" do
63+
is_expected.to eq("\xff\xff\xff\x80")
64+
end
65+
end
66+
67+
context "when char & 0x80 != 0" do
68+
let(:char) { 0x41 }
69+
70+
it "encodes char byte as integer" do
71+
is_expected.to eq("\x00\x00\x00\x41")
72+
end
73+
end
74+
end
75+
76+
describe ".decode_lchar!" do
77+
subject(:decoded_lchar) { described_class.decode_lchar!(data) }
78+
79+
context "when data's length is equal or greater than 4" do
80+
let(:data) { "\x41\x42\x43\x44" }
81+
82+
it "returns char code for last byte" do
83+
is_expected.to eq("D")
84+
end
85+
end
86+
87+
context "when data's length is less than 4" do
88+
let(:data) { "\x41" }
89+
90+
it "raises an error" do
91+
expect { decoded_lchar }.to raise_error(ArgumentError)
92+
end
93+
end
94+
end
95+
96+
describe ".encode_string" do
97+
subject(:encoded_string) { described_class.encode_string(str, max) }
98+
99+
context "when data is bigger than max" do
100+
let(:str) { "ABCDE" }
101+
let(:max) { 4 }
102+
103+
it "raises an error" do
104+
expect { encoded_string }.to raise_error(ArgumentError)
105+
end
106+
end
107+
108+
context "when data is shorter or equal to max" do
109+
let(:str) { "ABCDE" }
110+
let(:max) { 5 }
111+
112+
it "returns an String" do
113+
is_expected.to be_kind_of(String)
114+
end
115+
116+
it "prefix encoded length" do
117+
is_expected.to start_with("\x00\x00\x00\x05")
118+
end
119+
120+
it "returns the encoded string padded with zeros" do
121+
is_expected.to eq("\x00\x00\x00\x05ABCDE\x00\x00\x00")
122+
end
123+
end
124+
end
125+
126+
describe ".decode_string!" do
127+
subject(:decoded_string) { described_class.decode_string!(data) }
128+
129+
context "when encoded string length is 0" do
130+
let(:data) { "\x00\x00\x00\x00" }
131+
132+
it "returns empty string" do
133+
is_expected.to eq("")
134+
end
135+
end
136+
137+
context "when string contains padding" do
138+
let(:data) {"\x00\x00\x00\x03ABC00000"}
139+
140+
it "returns string without padding" do
141+
is_expected.to eq("ABC")
142+
end
143+
end
144+
145+
context "when fake length" do
146+
context "and no string" do
147+
let(:data) { "\x00\x00\x00\x03" }
148+
149+
it "returns empty string" do
150+
is_expected.to eq("")
151+
end
152+
end
153+
154+
context "longer than real string length" do
155+
let(:data) { "\x00\x00\x00\x08ABCD" }
156+
157+
it "returns available string" do
158+
is_expected.to eq("ABCD")
159+
end
160+
end
161+
end
162+
end
163+
164+
describe ".encode_varray" do
165+
subject(:encoded_varray) { described_class.encode_varray(arr, max) }
166+
167+
context "when arr length is bigger than max" do
168+
let(:arr) { [1, 2, 3] }
169+
let(:max) { 2 }
170+
it "raises an error" do
171+
expect { encoded_varray }.to raise_error(ArgumentError)
172+
end
173+
end
174+
175+
context "when arr length is minor or equal than max" do
176+
let(:arr) { [0x41414141, 0x42424242, 0x43434343] }
177+
let(:max) { 3 }
178+
179+
it "returns an String" do
180+
expect(described_class.encode_varray(arr, max) { |i| described_class.encode_int(i) }).to be_kind_of(String)
181+
end
182+
183+
it "prefixes encoded length" do
184+
expect(described_class.encode_varray(arr, max) { |i| described_class.encode_int(i) }).to start_with("\x00\x00\x00\x03")
185+
end
186+
187+
it "returns the encoded array" do
188+
expect(described_class.encode_varray(arr, max) { |i| described_class.encode_int(i) }).to eq("\x00\x00\x00\x03\x41\x41\x41\x41\x42\x42\x42\x42\x43\x43\x43\x43")
189+
end
190+
end
191+
end
192+
193+
describe ".decode_varray!" do
194+
subject(:decoded_varray) { described_class.decode_varray!(data) }
195+
196+
context "when encoded length is 0" do
197+
let(:data) { "\x00\x00\x00\x00" }
198+
199+
it "returns an empty array" do
200+
is_expected.to eq([])
201+
end
202+
end
203+
204+
context "when fake encoded length" do
205+
context "and no values" do
206+
let(:data) { "\x00\x00\x00\x02" }
207+
208+
it "raises an error" do
209+
expect { described_class.decode_varray!(data) { |s| described_class.decode_int!(s) } }.to raise_error(ArgumentError)
210+
end
211+
end
212+
213+
context "longer than available values" do
214+
let(:data) { "\x00\x00\x00\x02\x00\x00\x00\x41" }
215+
216+
it "raises an error" do
217+
expect { described_class.decode_varray!(data) { |s| described_class.decode_int!(s) } }.to raise_error(ArgumentError)
218+
end
219+
end
220+
end
221+
222+
context "when valid encoded data" do
223+
let(:data) { "\x00\x00\x00\x02\x41\x42\x43\x44\x00\x00\x00\x11"}
224+
it "retuns Array with decoded values" do
225+
expect(described_class.decode_varray!(data) { |s| described_class.decode_int!(s) }).to eq([0x41424344, 0x11])
226+
end
227+
end
228+
end
229+
230+
describe ".encode" do
231+
it "encodes integers" do
232+
expect(described_class.encode(1)).to eq("\x00\x00\x00\x01")
233+
end
234+
235+
it "encodes arrays" do
236+
expect(described_class.encode([0x41414141, 0x42424242])).to eq("\x00\x00\x00\x02\x41\x41\x41\x41\x42\x42\x42\x42")
237+
end
238+
239+
it "encodes strings" do
240+
expect(described_class.encode("ABCD")).to eq("\x00\x00\x00\x04\x41\x42\x43\x44")
241+
end
242+
243+
it "encodes mixed type of elements" do
244+
expect(described_class.encode(1, [0x41414141], "ABCD")).to eq("\x00\x00\x00\x01\x00\x00\x00\x01\x41\x41\x41\x41\x00\x00\x00\x04\x41\x42\x43\x44")
245+
end
246+
end
247+
248+
describe ".decode!" do
249+
250+
context "when no type arguments" do
251+
it "retuns empty Array" do
252+
expect(described_class.decode!("\x41\x41\x41\x41")).to eq([])
253+
end
254+
end
255+
256+
context "when not enough data" do
257+
it "retuns Array filled with nils" do
258+
expect(described_class.decode!("", Array)).to eq([nil])
259+
end
260+
end
261+
262+
it "decodes integers" do
263+
expect(described_class.decode!("\x41\x41\x41\x41", Integer)).to eq([0x41414141])
264+
end
265+
266+
it "decodes arrays" do
267+
expect(described_class.decode!("\x00\x00\x00\x01\x41\x41\x41\x41", [Integer])).to eq([[0x41414141]])
268+
end
269+
270+
it "decodes strings" do
271+
expect(described_class.decode!("\x00\x00\x00\x01\x41", String)).to eq(["A"])
272+
end
273+
274+
it "decodes mixed elements" do
275+
expect(described_class.decode!("\x41\x41\x41\x41\x00\x00\x00\x01\x41\x00\x00\x00\x00\x00\x00\x01\x42\x42\x42\x42", Integer, String, [Integer])).to eq([0x41414141, "A", [0x42424242]])
276+
end
277+
end
278+
279+
end

0 commit comments

Comments
 (0)