Land #4095, specs for Rex::OLE
commit
135faeee29
|
@ -96,7 +96,7 @@ class DirEntry
|
|||
return de
|
||||
end
|
||||
@children.each { |cde|
|
||||
ret = find_by_sid(cde, sid)
|
||||
ret = find_by_sid(sid, cde)
|
||||
if (ret)
|
||||
return ret
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'spec_helper'
|
|||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::CLSID do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
let(:sample_clsid) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" }
|
||||
|
||||
|
@ -35,7 +38,6 @@ describe Rex::OLE::CLSID do
|
|||
|
||||
describe "#to_s" do
|
||||
it "returns printable clsid" do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
expect(clsid.to_s).to eq('33221100-5544-7766-8899-aabbccddeeff')
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
|
||||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::DIFAT do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
let(:storage) do
|
||||
Rex::OLE::Storage.new
|
||||
end
|
||||
|
||||
subject(:difat) do
|
||||
described_class.new(storage)
|
||||
end
|
||||
|
||||
describe ".new" do
|
||||
it "returns a Rex::OLE::DIFAT instance" do
|
||||
expect(described_class.new(storage)).to be_a(Rex::OLE::DIFAT)
|
||||
end
|
||||
|
||||
it "initializes @stg" do
|
||||
expect(difat.instance_variable_get(:@stg)).to eq(storage)
|
||||
end
|
||||
|
||||
it "initializes @entries" do
|
||||
expect(difat.instance_variable_get(:@entries)).to be_an(Array)
|
||||
end
|
||||
|
||||
it "initializes @entries as empty array" do
|
||||
expect(difat.instance_variable_get(:@entries)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[]=" do
|
||||
context "when the entry doesn't exist" do
|
||||
it "sets an element in the @entries array" do
|
||||
difat[0] = 1
|
||||
expect(difat.instance_variable_get(:@entries)[0]).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the entry exists" do
|
||||
it "replaces the element in the @entries array" do
|
||||
difat[0] = 1
|
||||
difat[0] = 2
|
||||
expect(difat.instance_variable_get(:@entries)[0]).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[]" do
|
||||
context "when the entry doesn't exist" do
|
||||
it "returns nil" do
|
||||
expect(difat[3]).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the entry exists" do
|
||||
it "returns the entry value" do
|
||||
difat[3] = 31
|
||||
expect(difat[3]).to eq(31)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "#+" do
|
||||
context "when @entries is empty" do
|
||||
it "sets the @entries values" do
|
||||
difat + [1, 2]
|
||||
expect(difat.instance_variable_get(:@entries)).to eq([1, 2])
|
||||
end
|
||||
end
|
||||
|
||||
context "when @entries isn't empty" do
|
||||
it "concatenates the array to @entries" do
|
||||
difat[2] = 0
|
||||
difat + [1, 2]
|
||||
expect(difat.instance_variable_get(:@entries)).to eq([nil, nil, 0, 1, 2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#<<" do
|
||||
it "concatenates the element to the @entries array" do
|
||||
difat[0] = 1
|
||||
difat << 3
|
||||
expect(difat.instance_variable_get(:@entries)).to eq([1, 3])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#length" do
|
||||
subject(:difat_length) do
|
||||
difat.length
|
||||
end
|
||||
|
||||
context "when @entries is empty" do
|
||||
it "returns 0" do
|
||||
is_expected.to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "when @entries isn't empty" do
|
||||
it "returns the @entries length" do
|
||||
difat[0] = 1
|
||||
difat[1] = 2
|
||||
is_expected.to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#slice!" do
|
||||
context "when @entries is empty" do
|
||||
it "returns empty array" do
|
||||
expect(difat.slice!(0, 1)).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context "when start is out of range" do
|
||||
it "returns nil" do
|
||||
difat[0] = 1
|
||||
expect(difat.slice!(10, 1)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "when stop is 0" do
|
||||
it "returns empty array" do
|
||||
difat[0] = 1
|
||||
expect(difat.slice!(0, 0)).to eq([])
|
||||
end
|
||||
|
||||
it "doesn't delete nothing" do
|
||||
difat[0] = 1
|
||||
difat.slice!(0, 0)
|
||||
expect(difat[0]).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context "when @entries is long enough" do
|
||||
it "returns the deleted elements" do
|
||||
difat + [1, 2]
|
||||
expect(difat.slice!(0, 1)).to eq([1])
|
||||
end
|
||||
|
||||
it "deletes the elements in the range" do
|
||||
difat + [1, 2]
|
||||
difat.slice!(0, 1)
|
||||
expect(difat.instance_variable_get(:@entries)).to eq([2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#reset" do
|
||||
it "resets the @entries array" do
|
||||
difat[0] = 1
|
||||
difat.reset
|
||||
expect(difat.length).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#each" do
|
||||
it "calls the block for every @entries element" do
|
||||
difat + [1, 2, 3]
|
||||
res = 0
|
||||
difat.each { |elem| res += elem}
|
||||
expect(res).to eq(1 + 2 + 3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject(:difat_string) do
|
||||
difat.to_s
|
||||
end
|
||||
|
||||
it "returns an String" do
|
||||
is_expected.to be_an(String)
|
||||
end
|
||||
|
||||
it "starts with {" do
|
||||
is_expected.to start_with('{')
|
||||
end
|
||||
|
||||
it "ends with }" do
|
||||
is_expected.to end_with('}')
|
||||
end
|
||||
|
||||
it "contains @entries values" do
|
||||
difat + [Rex::OLE::SECT_FAT, 1, 2, 3, Rex::OLE::SECT_DIF, Rex::OLE::SECT_FREE, Rex::OLE::SECT_END]
|
||||
is_expected.to match(/FAT, 0x1, 0x2, 0x3, DIF, FREE, END/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#read" do
|
||||
context "when difat is empty" do
|
||||
it "returns nil" do
|
||||
expect(difat.read).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#write" do
|
||||
context "when entries is empty" do
|
||||
it "returns 0" do
|
||||
expect(difat.write).to eq(0)
|
||||
end
|
||||
|
||||
it "fills the first 109 FAT sectors in the storage header" do
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
expect(storage.header._sectFat.length).to eq(109)
|
||||
end
|
||||
|
||||
it "fills the first 109 FAT sectors in the storage header with SECT_FREE" do
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
storage.header._sectFat.each { |s|
|
||||
expect(s).to eq(Rex::OLE::SECT_FREE)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "when entries length is less than 109" do
|
||||
let(:entries) { [1] * 20 }
|
||||
|
||||
it "returns the number of entries" do
|
||||
difat + entries
|
||||
expect(difat.write).to eq(20)
|
||||
end
|
||||
|
||||
it "fills the first 109 FAT sectors in the storage header" do
|
||||
difat + entries
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
expect(storage.header._sectFat.length).to eq(109)
|
||||
end
|
||||
|
||||
it "fills the first FAT sectors with the entries" do
|
||||
difat + entries
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
(0..entries.length - 1).each { |i|
|
||||
expect(storage.header._sectFat[i]).to eq(1)
|
||||
}
|
||||
end
|
||||
|
||||
it "fills the remaining FAT sectors with FREE sectors" do
|
||||
difat + entries
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
(entries.length..109 - 1).each { |i|
|
||||
expect(storage.header._sectFat[i]).to eq(Rex::OLE::SECT_FREE)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "when entries length is 109" do
|
||||
let(:entries) { [1] * 109 }
|
||||
|
||||
it "returns the number of entries" do
|
||||
difat + entries
|
||||
expect(difat.write).to eq(109)
|
||||
end
|
||||
|
||||
it "fills the first 109 FAT sectors in the storage header" do
|
||||
difat + entries
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
expect(storage.header._sectFat.length).to eq(109)
|
||||
end
|
||||
|
||||
it "fills the first 109 FAT sectors with the entries" do
|
||||
difat + entries
|
||||
difat.write
|
||||
storage = difat.instance_variable_get(:@stg)
|
||||
(0..storage.header._sectFat.length - 1).each { |i|
|
||||
expect(storage.header._sectFat[i]).to eq(1)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "when entries length is greater than 109" do
|
||||
let(:entries) { [1] * 110 }
|
||||
|
||||
it "raises a RuntimeError" do
|
||||
difat + entries
|
||||
expect { difat.write }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,401 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
|
||||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::DirEntry do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
let(:storage) do
|
||||
Rex::OLE::Storage.new
|
||||
end
|
||||
|
||||
subject(:dir_entry) do
|
||||
described_class.new(storage)
|
||||
end
|
||||
|
||||
describe ".new" do
|
||||
it "returns a Rex::OLE::DirEntry instance" do
|
||||
expect(described_class.new(storage)).to be_a(Rex::OLE::DirEntry)
|
||||
end
|
||||
|
||||
it { expect(dir_entry.instance_variable_get(:@stg)).to eq(storage) }
|
||||
it { expect(dir_entry.sid).to eq(0) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_ab)).to eq('Root Entry') }
|
||||
it { expect(dir_entry.instance_variable_get(:@_cb)).to be_nil }
|
||||
it { expect(dir_entry.instance_variable_get(:@_mse)).to eq(Rex::OLE::STGTY_ROOT) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_bflags)).to eq(0) }
|
||||
it { expect(dir_entry._sidLeftSib).to eq(Rex::OLE::SECT_FREE) }
|
||||
it { expect(dir_entry._sidRightSib).to eq(Rex::OLE::SECT_FREE) }
|
||||
it { expect(dir_entry._sidChild).to eq(Rex::OLE::SECT_FREE) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_clsId)).to be_a(Rex::OLE::CLSID) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_dwUserFlags)).to eq(0) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_ctime)).to eq("\x00" * 8) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_mtime)).to eq("\x00" * 8) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_END) }
|
||||
it { expect(dir_entry.instance_variable_get(:@_ulSize)).to eq(0) }
|
||||
it { expect(dir_entry.instance_variable_get(:@children)).to be_an(Array) }
|
||||
it { expect(dir_entry.instance_variable_get(:@children)).to be_empty }
|
||||
end
|
||||
|
||||
describe "#length" do
|
||||
it "returns _ulSize" do
|
||||
dir_entry.instance_variable_set(:@_ulSize, 28)
|
||||
expect(dir_entry.length).to eq(28)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#<<" do
|
||||
it "increments the children array" do
|
||||
dir_entry << 1
|
||||
children = dir_entry.instance_variable_get(:@children)
|
||||
expect(children.length).to eq(1)
|
||||
end
|
||||
|
||||
it "appends to the children array" do
|
||||
dir_entry << 1
|
||||
children = dir_entry.instance_variable_get(:@children)
|
||||
expect(children).to eq([1])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#each" do
|
||||
it "calls the block for every children element" do
|
||||
dir_entry << 1
|
||||
dir_entry << 2
|
||||
dir_entry << 3
|
||||
res = 0
|
||||
dir_entry.each { |elem| res += elem}
|
||||
expect(res).to eq(1 + 2 + 3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#type" do
|
||||
it "returns the _mse field" do
|
||||
expect(dir_entry.type).to eq(Rex::OLE::STGTY_ROOT)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#type=" do
|
||||
it "modifies the _mse field" do
|
||||
dir_entry.type = 3838
|
||||
expect(dir_entry.instance_variable_get(:@_mse)).to eq(3838)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#name" do
|
||||
it "returns the _ab field" do
|
||||
expect(dir_entry.name).to eq('Root Entry')
|
||||
end
|
||||
end
|
||||
|
||||
describe "#name=" do
|
||||
it "modifies the _ab field" do
|
||||
dir_entry.name = 'test'
|
||||
expect(dir_entry.instance_variable_get(:@_ab)).to eq('test')
|
||||
end
|
||||
end
|
||||
|
||||
describe "#start_sector" do
|
||||
it "returns the _sectStart field" do
|
||||
expect(dir_entry.start_sector).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#start_sector=" do
|
||||
it "modifies the _sectStart field" do
|
||||
dir_entry.start_sector = Rex::OLE::SECT_FREE
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_stream_by_name_and_type" do
|
||||
context "when any children matches the search criteria" do
|
||||
it "returns nil" do
|
||||
expect(dir_entry.find_stream_by_name_and_type('name', Rex::OLE::STGTY_ROOT)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when one children matches the search criteria" do
|
||||
let(:stream) { Rex::OLE::Stream.new(storage) }
|
||||
let(:name) { 'name' }
|
||||
let(:type) { Rex::OLE::STGTY_ROOT }
|
||||
it "returns the matching stream" do
|
||||
stream.name = name
|
||||
stream.type = type
|
||||
dir_entry << stream
|
||||
expect(dir_entry.find_stream_by_name_and_type(name, type)).to eq(stream)
|
||||
end
|
||||
end
|
||||
|
||||
context "when several children matches the search criteria" do
|
||||
let(:stream) { Rex::OLE::Stream.new(storage) }
|
||||
let(:stream_two) { Rex::OLE::Stream.new(storage) }
|
||||
let(:name) { 'name' }
|
||||
let(:type) { Rex::OLE::STGTY_ROOT }
|
||||
let(:sid) { 2 }
|
||||
it "returns the first matching stream" do
|
||||
stream.name = name
|
||||
stream.type = type
|
||||
dir_entry << stream
|
||||
|
||||
stream_two.name = name
|
||||
stream_two.type = type
|
||||
stream_two.sid = sid
|
||||
dir_entry << stream_two
|
||||
expect(dir_entry.find_stream_by_name_and_type(name, type)).to eq(stream)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_by_sid" do
|
||||
let(:stream) { Rex::OLE::Stream.new(storage) }
|
||||
let(:another_stream) { Rex::OLE::Stream.new(storage) }
|
||||
|
||||
context "when self match the criteria" do
|
||||
it "returns self" do
|
||||
expect(dir_entry.find_by_sid(0, dir_entry)).to eq(dir_entry)
|
||||
end
|
||||
end
|
||||
|
||||
context "when self and a children stream match the criteria" do
|
||||
it "returns self" do
|
||||
stream.sid = 0
|
||||
dir_entry << stream
|
||||
expect(dir_entry.find_by_sid(0, dir_entry)).to eq(dir_entry)
|
||||
end
|
||||
end
|
||||
|
||||
context "when only one children stream match the criteria" do
|
||||
it "returns the child stream" do
|
||||
stream.sid = 20
|
||||
dir_entry << stream
|
||||
expect(dir_entry.find_by_sid(20, dir_entry)).to eq(stream)
|
||||
end
|
||||
end
|
||||
|
||||
context "when several children stream match the criteria" do
|
||||
it "returns the first child" do
|
||||
stream.sid = 20
|
||||
stream.name = 'stream'
|
||||
dir_entry << stream
|
||||
another_stream.sid = 20
|
||||
another_stream.name = 'another'
|
||||
dir_entry << another_stream
|
||||
expect(dir_entry.find_by_sid(20, dir_entry)).to eq(stream)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#from_s" do
|
||||
let(:valid_direntry) do
|
||||
"\x52\x00\x6f\x00\x6f\x00\x74\x00\x20\x00\x45\x00\x6e\x00\x74\x00\x72\x00\x79\x00\x00\x00" + # name (_ab)
|
||||
("\x00" * 42) + # padding
|
||||
"\x16\x00" + # _cb
|
||||
"\x05" + # _mse
|
||||
"\x00" + #_bflags
|
||||
"\xff\xff\xff\xff" + # _sidLeftSib
|
||||
"\xff\xff\xff\xff" + # _sidRightSib
|
||||
"\xff\xff\xff\xff" + # _sidChild
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # clsid
|
||||
"\x00\x00\x00\x00" + # _dwUserFlags
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _ctime
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _metime
|
||||
"\xfe\xff\xff\xff" + # _sectStart
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" # _ulSize
|
||||
end
|
||||
|
||||
let(:invalid_name_length)do
|
||||
"\x52\x00\x6f\x00\x6f\x00\x74\x00\x20\x00\x45\x00\x6e\x00\x74\x00\x72\x00\x79\x00\x00\x00" + # name (_ab)
|
||||
("\x00" * 42) + # padding
|
||||
"\x41\x00" + # _cb (invalid, major than 0x40)
|
||||
"\x05" + # _mse
|
||||
"\x00" + #_bflags
|
||||
"\xff\xff\xff\xff" + # _sidLeftSib
|
||||
"\xff\xff\xff\xff" + # _sidRightSib
|
||||
"\xff\xff\xff\xff" + # _sidChild
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # clsid
|
||||
"\x00\x00\x00\x00" + # _dwUserFlags
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _ctime
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _metime
|
||||
"\xfe\xff\xff\xff" + # _sectStart
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" # _ulSize
|
||||
end
|
||||
|
||||
let(:mismatch_length) do
|
||||
"\x52\x00\x6f\x00\x6f\x00\x74\x00\x20\x00\x45\x00\x6e\x00\x74\x00\x72\x00\x79\x00\x00\x00" + # name (_ab)
|
||||
("\x00" * 42) + # padding
|
||||
"\x13\x00" + # _cb (invalid length, shorter than real name length)
|
||||
"\x05" + # _mse
|
||||
"\x00" + #_bflags
|
||||
"\xff\xff\xff\xff" + # _sidLeftSib
|
||||
"\xff\xff\xff\xff" + # _sidRightSib
|
||||
"\xff\xff\xff\xff" + # _sidChild
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # clsid
|
||||
"\x00\x00\x00\x00" + # _dwUserFlags
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _ctime
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + # _metime
|
||||
"\xfe\xff\xff\xff" + # _sectStart
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00" # _ulSize
|
||||
end
|
||||
|
||||
let(:sid) { 0 }
|
||||
|
||||
context "when name length major than 64" do
|
||||
it "raises RuntimeError" do
|
||||
expect { dir_entry.from_s(sid, invalid_name_length) }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when name length doesn't match real length" do
|
||||
it "raises RuntimeError" do
|
||||
expect { dir_entry.from_s(sid, mismatch_length) }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when valid buf" do
|
||||
it "uses argument sid" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.sid).to eq(sid)
|
||||
end
|
||||
|
||||
it "parses _ab from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_ab)).to eq('Root Entry')
|
||||
end
|
||||
|
||||
it "parses _cb from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_cb)).to eq(22)
|
||||
end
|
||||
|
||||
it "parses _mse from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_mse)).to eq(Rex::OLE::STGTY_ROOT)
|
||||
end
|
||||
|
||||
it "parses _bflags from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_bflags)).to eq(0)
|
||||
end
|
||||
|
||||
it "parses _sidLeftSib from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry._sidLeftSib).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
|
||||
it "parses _sidRightSib from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry._sidRightSib).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
|
||||
it "parses _sidChild from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry._sidChild).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
|
||||
it "parses _clsId from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_clsId)).to be_a(Rex::OLE::CLSID)
|
||||
end
|
||||
|
||||
it "parses _dwUserFlags from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_dwUserFlags)).to eq(0)
|
||||
end
|
||||
|
||||
it "parses _ctime from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_ctime)).to eq("\x00" * 8)
|
||||
end
|
||||
|
||||
it "parses _mtime from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_mtime)).to eq("\x00" * 8)
|
||||
end
|
||||
|
||||
it "parses _sectStart from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
|
||||
it "parses _ulSize from buf" do
|
||||
dir_entry.from_s(sid, valid_direntry)
|
||||
expect(dir_entry.instance_variable_get(:@_ulSize)).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#pack" do
|
||||
it "returns an string" do
|
||||
expect(dir_entry.pack).to be_an(String)
|
||||
end
|
||||
|
||||
it "includes the unicode dir entry name" do
|
||||
expect(dir_entry.pack).to match(/R\x00o\x00o\x00t\x00 \x00E\x00n\x00t\x00r\x00y\x00/)
|
||||
end
|
||||
|
||||
context "when _sectStart is undefined" do
|
||||
it "sets _sectStart to SECT_END" do
|
||||
dir_entry.instance_variable_set(:@_sectStart, nil)
|
||||
dir_entry.pack
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
end
|
||||
|
||||
context "when _sectStart is defined" do
|
||||
it "doesn't modify _sectStart value" do
|
||||
dir_entry.instance_variable_set(:@_sectStart, Rex::OLE::SECT_FREE)
|
||||
dir_entry.pack
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
end
|
||||
|
||||
it "sets _cb as the unicode length of the name" do
|
||||
dir_entry.pack
|
||||
expect(dir_entry.instance_variable_get(:@_cb)).to eq("Root Entry\x00".length * 2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
it "returns an string" do
|
||||
expect(dir_entry.to_s).to be_an(String)
|
||||
end
|
||||
|
||||
it "starts with {" do
|
||||
expect(dir_entry.to_s).to start_with('{')
|
||||
end
|
||||
|
||||
it "ends with }" do
|
||||
expect(dir_entry.to_s).to end_with('}')
|
||||
end
|
||||
|
||||
it "contains the entry name" do
|
||||
expect(dir_entry.to_s).to match(/Root Entry/)
|
||||
end
|
||||
|
||||
context "when _sectStart is undefined" do
|
||||
it "sets _sectStart to SECT_END" do
|
||||
dir_entry.instance_variable_set(:@_sectStart, nil)
|
||||
dir_entry.to_s
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
end
|
||||
|
||||
context "when _sectStart is defined" do
|
||||
it "doesn't modify _sectStart value" do
|
||||
dir_entry.instance_variable_set(:@_sectStart, Rex::OLE::SECT_FREE)
|
||||
dir_entry.to_s
|
||||
expect(dir_entry.instance_variable_get(:@_sectStart)).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
end
|
||||
|
||||
it "sets _cb as the unicode length of the name" do
|
||||
dir_entry.to_s
|
||||
expect(dir_entry.instance_variable_get(:@_cb)).to eq("Root Entry\x00".length * 2)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,355 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
|
||||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::Header do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
subject(:header) do
|
||||
described_class.new
|
||||
end
|
||||
|
||||
describe ".new" do
|
||||
it "returns a Rex::OLE::Header instance" do
|
||||
expect(described_class.new).to be_a(Rex::OLE::Header)
|
||||
end
|
||||
|
||||
it { expect(header.instance_variable_get(:@_abSig)).to eq(Rex::OLE::SIG) }
|
||||
it { expect(header.instance_variable_get(:@_clid)).to be_a(Rex::OLE::CLSID) }
|
||||
it { expect(header.instance_variable_get(:@_uByteOrder)).to eq(Rex::OLE::LITTLE_ENDIAN) }
|
||||
it { expect(header.instance_variable_get(:@_uMinorVersion)).to eq(0x3e) }
|
||||
it { expect(header._uMajorVersion).to eq(0x03) }
|
||||
it { expect(header.instance_variable_get(:@_uSectorShift)).to eq(9) }
|
||||
it { expect(header._uMiniSectorShift).to eq(6) }
|
||||
it { expect(header.instance_variable_get(:@_csectDir)).to be_nil }
|
||||
it { expect(header._csectFat).to be_nil }
|
||||
it { expect(header._sectDirStart).to be_nil }
|
||||
it { expect(header.instance_variable_get(:@_signature)).to eq(0) }
|
||||
it { expect(header._ulMiniSectorCutoff).to eq(0x1000) }
|
||||
it { expect(header._sectMiniFatStart).to eq(Rex::OLE::SECT_END) }
|
||||
it { expect(header._csectMiniFat).to eq(0) }
|
||||
it { expect(header._sectDifStart).to eq(Rex::OLE::SECT_END) }
|
||||
it { expect(header._csectDif).to eq(0) }
|
||||
it { expect(header._sectFat).to be_an(Array) }
|
||||
it { expect(header.instance_variable_get(:@_sectFat)).to be_empty }
|
||||
it { expect(header.sector_size).to eq(1 << 9) }
|
||||
it { expect(header.mini_sector_size).to eq(1 << 6) }
|
||||
it { expect(header.idx_per_sect).to eq((1 << 9) / 4) }
|
||||
end
|
||||
|
||||
describe "#set_defaults" do
|
||||
it "sets OLECF signature" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_abSig)).to eq(Rex::OLE::SIG)
|
||||
end
|
||||
|
||||
it "setup a class identifier (guid)" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_clid)).to be_a(Rex::OLE::CLSID)
|
||||
end
|
||||
|
||||
it "sets byte order identifier as little endian" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_uByteOrder)).to eq(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
it "sets the minor version to 0x3e" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_uMinorVersion)).to eq(0x3e)
|
||||
end
|
||||
|
||||
it "sets the major version to 0x3" do
|
||||
header.set_defaults
|
||||
expect(header._uMajorVersion).to eq(0x03)
|
||||
end
|
||||
|
||||
it "sets the size of sectors to 9" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_uSectorShift)).to eq(9)
|
||||
end
|
||||
|
||||
it "sets the size of mini-sectors to 6" do
|
||||
header.set_defaults
|
||||
expect(header._uMiniSectorShift).to eq(6)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the directory chain to nil" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_csectDir)).to be_nil
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the FAT chain to nil" do
|
||||
header.set_defaults
|
||||
expect(header._csectFat).to be_nil
|
||||
end
|
||||
|
||||
it "sets first sector in the directory chain to nil" do
|
||||
header.set_defaults
|
||||
expect(header._sectDirStart).to be_nil
|
||||
end
|
||||
|
||||
it "sets the signature used for transactioning to zero" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_signature)).to eq(0)
|
||||
end
|
||||
|
||||
it "sets the maximum size of mini-streams to 4096" do
|
||||
header.set_defaults
|
||||
expect(header._ulMiniSectorCutoff).to eq(0x1000)
|
||||
end
|
||||
|
||||
it "sets the first sector in the mini-FAT chain to end of chain" do
|
||||
header.set_defaults
|
||||
expect(header._sectMiniFatStart).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the mini-FAT chain to 0" do
|
||||
header.set_defaults
|
||||
expect(header._csectMiniFat).to eq(0)
|
||||
end
|
||||
|
||||
it "sets the first sector in the DIF chain to end of chain" do
|
||||
header.set_defaults
|
||||
expect(header._sectDifStart).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the DIF chain to 0" do
|
||||
header.set_defaults
|
||||
expect(header._csectDif).to eq(0)
|
||||
end
|
||||
|
||||
it "creates an array for the sectors of the first 109 FAT sectors" do
|
||||
header.set_defaults
|
||||
expect(header._sectFat).to be_an(Array)
|
||||
end
|
||||
|
||||
it "creates an empty array for the FAT sectors" do
|
||||
header.set_defaults
|
||||
expect(header.instance_variable_get(:@_sectFat)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject(:header_string) { header.to_s }
|
||||
|
||||
it "returns an String" do
|
||||
expect(header_string).to be_an(String)
|
||||
end
|
||||
|
||||
it "starts with {" do
|
||||
expect(header_string).to start_with('{')
|
||||
end
|
||||
|
||||
it "ends with {" do
|
||||
expect(header_string).to end_with('}')
|
||||
end
|
||||
|
||||
it "includes the OLECF signature" do
|
||||
expect(header_string).to match(/_abSig => "\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1"/)
|
||||
end
|
||||
|
||||
it "includes the class identifier value" do
|
||||
expect(header_string).to match(/_clid => 00000000-0000-0000-0000-000000000000/)
|
||||
end
|
||||
|
||||
it "includes the minor version value" do
|
||||
expect(header_string).to match(/_uMinorVersion => 0x003e/)
|
||||
end
|
||||
|
||||
it "includes the major version value" do
|
||||
expect(header_string).to match(/_uMajorVersion => 0x0003/)
|
||||
end
|
||||
|
||||
it "includes the byte order identifier value" do
|
||||
expect(header_string).to match(/_uByteOrder => 0xfffe/)
|
||||
end
|
||||
|
||||
it "includes the size of sectors value" do
|
||||
expect(header_string).to match(/_uSectorShift => 0x0009/)
|
||||
end
|
||||
|
||||
it "includes the size of mini-sectors value" do
|
||||
expect(header_string).to match(/_uMiniSectorShift => 0x0006/)
|
||||
end
|
||||
|
||||
it "includes the number of sectors in the directory chain" do
|
||||
expect(header_string).to match(/_csectDir => UNALLOCATED/)
|
||||
end
|
||||
|
||||
it "includes the number of sectors in the FAT chain" do
|
||||
expect(header_string).to match(/_csectFat => UNALLOCATED/)
|
||||
end
|
||||
|
||||
it "includes the first sector in the directory chain" do
|
||||
expect(header_string).to match(/_sectDirStart => UNALLOCATED/)
|
||||
end
|
||||
|
||||
it "includes the signature used for transactioning" do
|
||||
expect(header_string).to match(/_signature => 0x00000000/)
|
||||
end
|
||||
|
||||
it "includes the maximum size of mini-streams" do
|
||||
expect(header_string).to match(/_uMiniSectorCutoff => 0x00001000/)
|
||||
end
|
||||
|
||||
it "includes the first sector in the mini-FAT chain value" do
|
||||
expect(header_string).to match(/_sectMiniFatStart => 0xfffffffe/)
|
||||
end
|
||||
|
||||
it "includes the number of sectors in the mini-FAT chain" do
|
||||
expect(header_string).to match(/_csectMiniFat => 0x00000000/)
|
||||
end
|
||||
|
||||
it "includes the first sector in the DIF chain value" do
|
||||
expect(header_string).to match(/_sectDifStart => 0xfffffffe/)
|
||||
end
|
||||
|
||||
it "includes the number of sectors in the DIF chain" do
|
||||
expect(header_string).to match(/_csectDif => 0x00000000/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#read" do
|
||||
context "when reading empty header" do
|
||||
let(:empty_fd) do
|
||||
s = ''
|
||||
StringIO.new(s, 'rb')
|
||||
end
|
||||
|
||||
it "raises NoMethodError" do
|
||||
expect { header.read(empty_fd) }.to raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "when reading header with invalid signature" do
|
||||
let(:incorrect_fd) do
|
||||
s = 'A' * Rex::OLE::HDR_SZ
|
||||
StringIO.new(s, 'rb')
|
||||
end
|
||||
|
||||
it "raises RuntimeError" do
|
||||
expect { header.read(incorrect_fd) }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when reading header with valid signature" do
|
||||
let(:correct_fd) do
|
||||
hdr = ""
|
||||
hdr << Rex::OLE::SIG
|
||||
hdr << 'A' * 16 # @_clid
|
||||
hdr << 'BB' # @_uMinorVersion
|
||||
hdr << 'CC' # @_uMajorVersion
|
||||
hdr << "\xfe\xff" # @_uByteOrder
|
||||
hdr << 'EE' # @_uSectorShift
|
||||
hdr << 'FF' # @_uMiniSectorShift
|
||||
hdr << '123456' # padding
|
||||
hdr << 'GGGG' # @_csectDir
|
||||
hdr << 'HHHH' # @_csectFat
|
||||
hdr << 'IIII' # @_sectDirStart
|
||||
hdr << 'JJJJ' # @_signature
|
||||
hdr << 'KKKK' # @_ulMiniSectorCutoff
|
||||
hdr << 'LLLL' # @_sectMiniFatStart
|
||||
hdr << 'MMMM' # @_csectMiniFat
|
||||
hdr << 'NNNN' # @_sectDifStart
|
||||
hdr << 'OOOO' # @_csectDif
|
||||
hdr << 'P' * 109 * 4 # @_sectFat
|
||||
|
||||
StringIO.new(hdr, 'rb')
|
||||
end
|
||||
|
||||
it "sets clsid from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_clid).to_s).to eq("41414141-4141-4141-4141-414141414141")
|
||||
end
|
||||
|
||||
it "sets minor version from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_uMinorVersion)).to eq(0x4242)
|
||||
end
|
||||
|
||||
it "sets major version from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._uMajorVersion).to eq(0x4343)
|
||||
end
|
||||
|
||||
it "sets byte order from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_uByteOrder)).to eq(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
it "sets the size of sectors from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_uSectorShift)).to eq(0x4545)
|
||||
end
|
||||
|
||||
it "sets the size of mini-sectors from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._uMiniSectorShift).to eq(0x4646)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the directory chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_csectDir)).to eq(0x47474747)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the FAT chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._csectFat).to eq(0x48484848)
|
||||
end
|
||||
|
||||
it "sets the first sector in the directory chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._sectDirStart).to eq(0x49494949)
|
||||
end
|
||||
|
||||
it "sets the signature used for transactioning from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header.instance_variable_get(:@_signature)).to eq(0x4a4a4a4a)
|
||||
end
|
||||
|
||||
it "sets the maximum size of mini-streams from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._ulMiniSectorCutoff).to eq(0x4b4b4b4b)
|
||||
end
|
||||
|
||||
it "sets the first sector in the mini-FAT chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._sectMiniFatStart).to eq(0x4c4c4c4c)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the mini-FAT chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._csectMiniFat).to eq(0x4d4d4d4d)
|
||||
end
|
||||
|
||||
it "sets the first sector in the DIF chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._sectDifStart).to eq(0x4e4e4e4e)
|
||||
end
|
||||
|
||||
it "sets the number of sectors in the DIF chain from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._csectDif).to eq(0x4f4f4f4f)
|
||||
end
|
||||
|
||||
it "creates an array for the FAT sectors from input" do
|
||||
header.read(correct_fd)
|
||||
expect(header._sectFat.length).to eq(109)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#write" do
|
||||
context "when default header" do
|
||||
it "writes 76 bytes" do
|
||||
fd = StringIO.new('', 'wb')
|
||||
header.write(fd)
|
||||
expect(fd.string.length).to eq(76)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,98 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
|
||||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::MiniFAT do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
let(:storage) do
|
||||
Rex::OLE::Storage.new
|
||||
end
|
||||
|
||||
subject(:minifat) do
|
||||
described_class.new(storage)
|
||||
end
|
||||
|
||||
describe "#allocate_sector" do
|
||||
context "when entries is empty" do
|
||||
it "returns index 0" do
|
||||
expect(minifat.allocate_sector).to eq(0)
|
||||
end
|
||||
|
||||
it "allocates idx_per_sect entries" do
|
||||
minifat.allocate_sector
|
||||
storage = minifat.instance_variable_get(:@stg)
|
||||
expect(minifat.length).to eq(storage.header.idx_per_sect)
|
||||
end
|
||||
|
||||
it "marks the first entry as SECT_END" do
|
||||
minifat.allocate_sector
|
||||
expect(minifat[0]).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
|
||||
it "marks the remaining entries as SECT_FREE" do
|
||||
minifat.allocate_sector
|
||||
storage = minifat.instance_variable_get(:@stg)
|
||||
(1..storage.header.idx_per_sect - 1).each do |i|
|
||||
expect(minifat[i]).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when entries include a free sector" do
|
||||
it "returns the free sector index entry" do
|
||||
minifat + [1, 2, Rex::OLE::SECT_FREE]
|
||||
expect(minifat.allocate_sector).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context "when entries don't include a free sector" do
|
||||
it "returns index of a new entry" do
|
||||
minifat + [1, 2, 3]
|
||||
expect(minifat.allocate_sector).to eq(3)
|
||||
end
|
||||
|
||||
it "allocates idx_per_sect entries" do
|
||||
minifat + [1, 2, 3]
|
||||
minifat.allocate_sector
|
||||
storage = minifat.instance_variable_get(:@stg)
|
||||
expect(minifat.length).to eq(storage.header.idx_per_sect + 3)
|
||||
end
|
||||
|
||||
it "marks the first entry as SECT_END" do
|
||||
minifat + [1, 2, 3]
|
||||
minifat.allocate_sector
|
||||
expect(minifat[3]).to eq(Rex::OLE::SECT_END)
|
||||
end
|
||||
|
||||
it "marks the remaining entries as SECT_FREE" do
|
||||
minifat + [1, 2, 3]
|
||||
minifat.allocate_sector
|
||||
storage = minifat.instance_variable_get(:@stg)
|
||||
(4..3 + storage.header.idx_per_sect - 1).each do |i|
|
||||
expect(minifat[i]).to eq(Rex::OLE::SECT_FREE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#read" do
|
||||
context "when the MiniFAT in the storage is empty" do
|
||||
it "returns zero" do
|
||||
expect(minifat.read).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#write" do
|
||||
context "when entries is empty" do
|
||||
it "returns nil" do
|
||||
expect(minifat.write).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -4,6 +4,9 @@ require 'spec_helper'
|
|||
require 'rex/ole'
|
||||
|
||||
describe Rex::OLE::Util do
|
||||
before(:each) do
|
||||
Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN)
|
||||
end
|
||||
|
||||
describe ".Hexify32array" do
|
||||
subject(:hex_array) { described_class.Hexify32array(arr) }
|
||||
|
|
Loading…
Reference in New Issue