Skip to content

Commit 5c5044a

Browse files
pbarry-r7dmohanty-r7
authored andcommitted
Stream audio data via channel (MS-2725).
1 parent dd7726b commit 5c5044a

File tree

4 files changed

+141
-83
lines changed

4 files changed

+141
-83
lines changed

lib/rex/post/meterpreter/channels/pools/audio.rb

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/post/meterpreter/channels/pool'
4+
require 'rex/post/meterpreter/extensions/stdapi/tlv'
5+
6+
module Rex
7+
module Post
8+
module Meterpreter
9+
module Channels
10+
module Pools
11+
12+
###
13+
#
14+
# StreamPool
15+
# ----------
16+
#
17+
# This class represents a channel that is associated with a
18+
# streaming pool that has no definite end-point. While this
19+
# may seem a paradox given the stream class of channels, it's
20+
# in fact dinstinct because streams automatically forward
21+
# traffic between the two ends of the channel whereas
22+
# stream pools are always requested data in a single direction.
23+
#
24+
###
25+
class AudioStreamPool < Rex::Post::Meterpreter::Channels::Pool
26+
27+
include Rex::IO::StreamAbstraction
28+
29+
##
30+
#
31+
# Constructor
32+
#
33+
##
34+
35+
# Initializes the file channel instance
36+
def initialize(client, cid, type, flags)
37+
super(client, cid, type, flags)
38+
39+
initialize_abstraction
40+
end
41+
42+
##
43+
#
44+
# Streaming pools don't support tell, seek, or eof.
45+
#
46+
##
47+
48+
#
49+
# This method returns the current offset into the pool.
50+
#
51+
def tell
52+
raise NotImplementedError
53+
end
54+
55+
#
56+
# This method seeks to an offset in the pool.
57+
#
58+
def seek
59+
raise NotImplementedError
60+
end
61+
62+
#
63+
# This method returns whether or not eof has been returned.
64+
#
65+
def eof
66+
return false
67+
end
68+
69+
#
70+
# Transfers data to the local half of the pool for reading.
71+
#
72+
def dio_write_handler(packet, data)
73+
rv = Rex::ThreadSafe.select(nil, [rsock], nil, 0.01)
74+
if(rv)
75+
rsock.write(data)
76+
return true
77+
else
78+
return false
79+
end
80+
end
81+
82+
#
83+
# Closes the local half of the pool stream.
84+
#
85+
def dio_close_handler(packet)
86+
rsock.close
87+
88+
return super(packet)
89+
end
90+
91+
#
92+
# Cleans up resources used by the channel.
93+
#
94+
def cleanup
95+
super
96+
97+
cleanup_abstraction
98+
end
99+
100+
end
101+
102+
end; end; end; end; end
103+

lib/rex/post/meterpreter/extensions/stdapi/mic/mic.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: binary -*-
22

33
require 'rex/post/meterpreter/channel'
4-
require 'rex/post/meterpreter/channels/pools/audio'
4+
require 'rex/post/meterpreter/channels/pools/audio_stream_pool'
55

66
module Rex
77
module Post
@@ -40,6 +40,15 @@ def mic_start
4040
request = Packet.create_request('audio_mic_start')
4141
request.add_tlv(TLV_TYPE_AUDIO_INTERFACE_NAME, 0)
4242
response = client.send_request(request)
43+
#channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID)
44+
# If we were creating a channel out of this
45+
46+
channel = Channel.create(client, 'audio_mic', Rex::Post::Meterpreter::Channels::Pools::AudioStreamPool, CHANNEL_FLAG_SYNCHRONOUS)
47+
48+
#if (channel_id != nil)
49+
# channel = Rex::Post::Meterpreter::Channels::Pools::StreamPool.new(client,
50+
# channel_id, "audio_mic", CHANNEL_FLAG_SYNCHRONOUS)
51+
#end
4352
end
4453

4554
def mic_get_frame(quality)

lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/mic.rb

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,29 @@ def cmd_mic_list
4949
end
5050
end
5151

52+
def audio_file_wave_header(sample_rate_hz, num_channels, bits_per_sample, data_size)
53+
subchunk1_size = 16
54+
chunk_size = 4 + (8 + subchunk1_size) + (8 + data_size)
55+
byte_rate = sample_rate_hz * num_channels * bits_per_sample / 8
56+
block_align = num_channels * bits_per_sample / 8
57+
58+
[
59+
BinData::Int32be.new(0x52494646), # ChunkID: "RIFF"
60+
BinData::Int32le.new(chunk_size), # ChunkSize
61+
BinData::Int32be.new(0x57415645), # Format: "WAVE"
62+
BinData::Int32be.new(0x666d7420), # SubChunk1ID: "fmt "
63+
BinData::Int32le.new(16), # SubChunk1Size
64+
BinData::Int16le.new(1), # AudioFormat
65+
BinData::Int16le.new(num_channels), # NumChannels
66+
BinData::Int32le.new(sample_rate_hz), # SampleRate
67+
BinData::Int32le.new(byte_rate), # ByteRate
68+
BinData::Int16le.new(block_align), # BlockAlign
69+
BinData::Int16le.new(bits_per_sample), # BitsPerSample
70+
BinData::Int32be.new(0x64617461), # SubChunk2ID: "data"
71+
BinData::Int32le.new(data_size) # SubChunk2Size
72+
]
73+
end
74+
5275
def cmd_mic_start(start_delay=4096)
5376
print_status("Streaming mic audio channel...")
5477

@@ -66,39 +89,20 @@ def cmd_mic_start(start_delay=4096)
6689
print_status("Streaming...")
6790

6891
begin
69-
client.mic.mic_start
92+
channel = client.mic.mic_start
7093
mic_started = true
7194
::Timeout.timeout(duration) do
7295
::File.open(stream_path, 'wb') do |outfd|
73-
numchannels = 1
74-
sampleratehz = 11025
75-
bitspersample = 16
76-
datasize = 2000000000
77-
subchunk1size = 16
78-
chunksize = 4 + (8 + subchunk1size) + (8 + datasize)
79-
byterate = sampleratehz * numchannels * bitspersample / 8
80-
blockalign = numchannels * bitspersample / 8
81-
82-
BinData::Int32be.new(0x52494646).write(outfd) # ChunkID: "RIFF"
83-
BinData::Int32le.new(chunksize).write(outfd) # ChunkSize
84-
BinData::Int32be.new(0x57415645).write(outfd) # Format: "WAVE"
85-
BinData::Int32be.new(0x666d7420).write(outfd) # SubChunk1ID: "fmt "
86-
BinData::Int32le.new(16).write(outfd) # SubChunk1Size
87-
BinData::Int16le.new(1).write(outfd) # AudioFormat
88-
BinData::Int16le.new(numchannels).write(outfd) # NumChannels
89-
BinData::Int32le.new(sampleratehz).write(outfd) # SampleRate
90-
BinData::Int32le.new(byterate).write(outfd) # ByteRate
91-
BinData::Int16le.new(blockalign).write(outfd) # BlockAlign
92-
BinData::Int16le.new(bitspersample).write(outfd) # BitsPerSample
93-
BinData::Int32be.new(0x64617461).write(outfd) # SubChunk2ID: "data"
94-
BinData::Int32le.new(datasize).write(outfd) # SubChunk2Size
96+
audio_file_wave_header(11025, 1, 16, 2000000000).each { |e| e.write(outfd) }
9597
end
9698
stream_index = 0
9799
while client do
98100
if stream_index == start_delay
99101
cmd_listen(stream_path)
100102
end
101-
data = client.mic.mic_get_frame(quality)
103+
Rex::sleep(0.5)
104+
#data = client.mic.mic_get_frame(quality)
105+
data = channel.read(65536)
102106
if data
103107
::File.open(stream_path, 'a') do |f|
104108
f.write(data)

0 commit comments

Comments
 (0)