Add ACPP decoding capabilities
parent
2af82ac987
commit
7e4dd4e55b
|
@ -79,33 +79,84 @@ module ACPP
|
|||
attr_accessor :status
|
||||
|
||||
def initialize
|
||||
@message_checksum = 0
|
||||
@payload = ''
|
||||
@type = 0
|
||||
@status = 0
|
||||
@password = 'public'
|
||||
@password = ''
|
||||
end
|
||||
|
||||
def encode
|
||||
# Get this Message as a String
|
||||
#
|
||||
# @return [String] the string representation of this Message
|
||||
def to_s
|
||||
'acpp' + [
|
||||
1, # unknown1
|
||||
@message_checksum,
|
||||
Zlib::adler32(@payload),
|
||||
message_checksum,
|
||||
payload_checksum,
|
||||
@payload.size,
|
||||
0, 0, # unknown2
|
||||
@type,
|
||||
@status,
|
||||
0,0,0 # unknown3
|
||||
0, 0, 0 # unknown3
|
||||
].pack('NNNNN2NNN3') +
|
||||
Rex::Encoding::Xor::Generic.encode([@password].pack('a32'), XOR_KEY).first +
|
||||
Rex::Encoding::Xor::Generic.encode([@password].pack('a32').slice(0, 32), XOR_KEY).first +
|
||||
([0] * 12).pack('N12') + # unknown4
|
||||
payload
|
||||
end
|
||||
|
||||
def to_s
|
||||
@message_checksum = 0
|
||||
@message_checksum = Zlib::adler32(encode)
|
||||
encode
|
||||
# Compares this Message and another Message for equality
|
||||
#
|
||||
# @param other [Message] the Message to compare
|
||||
# @return [Boolean] true iff the two messages have equal String representations, false otherwise
|
||||
def ==(other)
|
||||
to_s == other.to_s
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# compute the 32-bit checksum of the payload
|
||||
def payload_checksum
|
||||
Zlib::adler32(@payload)
|
||||
end
|
||||
|
||||
# compute the 32-bit checksum of the entire message and payload
|
||||
def message_checksum
|
||||
Zlib::adler32(
|
||||
'acpp' + [
|
||||
1, # unknown1
|
||||
0, # message checksum is set to 0 during checksum calculation
|
||||
payload_checksum,
|
||||
@payload.size,
|
||||
0, 0, # unknown2
|
||||
@type,
|
||||
@status,
|
||||
0, 0, 0 # unknown3
|
||||
].pack('NNNNN2NNN3') +
|
||||
Rex::Encoding::Xor::Generic.encode([@password].pack('a32').slice(0, 32), XOR_KEY).first +
|
||||
([0] * 12).pack('N12') + # unknown4
|
||||
payload
|
||||
)
|
||||
end
|
||||
|
||||
def self.decode(data, validate_checksum = true)
|
||||
fail "Incorrect ACPP message size #{data.size}" unless data.size == 128
|
||||
fail 'Unexpected header' unless 'acpp' == data.slice!(0, 4)
|
||||
unknown1 = data.slice!(0, 4)
|
||||
read_message_checksum = data.slice!(0, 4).unpack('N').first
|
||||
read_payload_checksum = data.slice!(0, 4).unpack('N').first
|
||||
read_payload_size = data.slice!(0, 4).unpack('N').first
|
||||
unknown2 = data.slice!(0, 8)
|
||||
type = data.slice!(0, 4).unpack('N').first
|
||||
status = data.slice!(0, 4).unpack('N').first
|
||||
unknown3 = data.slice!(0, 12)
|
||||
password = Rex::Encoding::Xor::Generic.encode(data.slice!(0, 32), XOR_KEY).first.strip
|
||||
unknown4 = data.slice!(0, 48)
|
||||
m = self.new
|
||||
m.type = type
|
||||
m.password = password
|
||||
m.status = status
|
||||
m.payload = data
|
||||
m
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,18 +9,28 @@ describe Rex::Proto::ACPP::Message do
|
|||
described_class.new
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'constructs properly' do
|
||||
# public.bin has the contents of a message type 20, password public message
|
||||
# with a 612-byte retrieve payload that happens to be in a different packet
|
||||
let(:retrieve_public_bin) do
|
||||
IO.read(File.join(File.dirname(__FILE__), 'retrieve_public.bin'))
|
||||
end
|
||||
|
||||
let(:retrieve_public_message) do
|
||||
m = described_class.new
|
||||
m.password = 'public'
|
||||
m.type = 20
|
||||
m
|
||||
end
|
||||
|
||||
describe '#to_s' do
|
||||
it 'encodes properly' do
|
||||
expect(retrieve_public_bin).to eq(retrieve_public_message.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#encode' do
|
||||
it 'constructs properly' do
|
||||
message.password = 'public'
|
||||
message.type = 20
|
||||
|
||||
File.open("/tmp/f", "wb") { |f| f.print(message.to_s) }
|
||||
expect(IO.read(File.join(File.dirname(__FILE__), 'public.bin'))).to eq(message.to_s)
|
||||
describe '#decode' do
|
||||
it 'decodes properly' do
|
||||
expect(retrieve_public_message).to eq(described_class.decode(retrieve_public_bin))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue