rex 2.0.9 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rex/exploitation/cmdstager/bourne.rb +14 -8
- data/lib/rex/exploitation/cmdstager/echo.rb +3 -3
- data/lib/rex/exploitation/js/memory.rb +1 -1
- data/lib/rex/java/serialization/model/contents.rb +1 -1
- data/lib/rex/mime/message.rb +1 -1
- data/lib/rex/parser/acunetix_nokogiri.rb +2 -0
- data/lib/rex/parser/appscan_nokogiri.rb +1 -1
- data/lib/rex/parser/burp_issue_nokogiri.rb +139 -0
- data/lib/rex/parser/burp_session_nokogiri.rb +1 -1
- data/lib/rex/parser/fs/bitlocker.rb +233 -0
- data/lib/rex/parser/fusionvm_nokogiri.rb +2 -2
- data/lib/rex/parser/ini.rb +1 -8
- data/lib/rex/parser/nokogiri_doc_mixin.rb +5 -0
- data/lib/rex/payloads/meterpreter/config.rb +23 -4
- data/lib/rex/post/meterpreter/channel.rb +8 -3
- data/lib/rex/post/meterpreter/client.rb +1 -0
- data/lib/rex/post/meterpreter/client_core.rb +2 -2
- data/lib/rex/post/meterpreter/extensions/android/android.rb +86 -1
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +29 -0
- data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +75 -89
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +8 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +10 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +7 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +10 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +8 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +1 -1
- data/lib/rex/post/meterpreter/packet.rb +38 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +101 -108
- data/lib/rex/post/meterpreter/packet_parser.rb +14 -6
- data/lib/rex/post/meterpreter/packet_response_waiter.rb +42 -21
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +54 -4
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +39 -13
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +8 -0
- data/lib/rex/proto/adb.rb +7 -0
- data/lib/rex/proto/adb/client.rb +39 -0
- data/lib/rex/proto/adb/message.rb +164 -0
- data/lib/rex/proto/dcerpc/svcctl/packet.rb +9 -9
- data/lib/rex/proto/http/client_request.rb +2 -1
- data/lib/rex/proto/http/response.rb +1 -1
- data/lib/rex/proto/kademlia/bootstrap_response.rb +2 -2
- data/lib/rex/proto/ntp/modes.rb +17 -0
- data/lib/rex/text.rb +12 -0
- data/lib/rex/zip/blocks.rb +1 -1
- data/lib/rex/zip/entry.rb +1 -1
- data/rex.gemspec +28 -1
- metadata +106 -3
@@ -12,6 +12,11 @@ module Meterpreter
|
|
12
12
|
###
|
13
13
|
class PacketParser
|
14
14
|
|
15
|
+
# 4 byte xor
|
16
|
+
# 4 byte length
|
17
|
+
# 4 byte type
|
18
|
+
HEADER_SIZE = 12
|
19
|
+
|
15
20
|
#
|
16
21
|
# Initializes the packet parser context with an optional cipher.
|
17
22
|
#
|
@@ -26,7 +31,7 @@ class PacketParser
|
|
26
31
|
#
|
27
32
|
def reset
|
28
33
|
self.raw = ''
|
29
|
-
self.hdr_length_left =
|
34
|
+
self.hdr_length_left = HEADER_SIZE
|
30
35
|
self.payload_length_left = 0
|
31
36
|
end
|
32
37
|
|
@@ -34,6 +39,9 @@ class PacketParser
|
|
34
39
|
# Reads data from the wire and parse as much of the packet as possible.
|
35
40
|
#
|
36
41
|
def recv(sock)
|
42
|
+
# Create a typeless packet
|
43
|
+
packet = Packet.new(0)
|
44
|
+
|
37
45
|
if (self.hdr_length_left > 0)
|
38
46
|
buf = sock.read(self.hdr_length_left)
|
39
47
|
|
@@ -49,7 +57,10 @@ class PacketParser
|
|
49
57
|
# payload length left to the number of bytes
|
50
58
|
# specified in the length
|
51
59
|
if (self.hdr_length_left == 0)
|
52
|
-
|
60
|
+
xor_key = raw[0, 4].unpack('N')[0]
|
61
|
+
length_bytes = packet.xor_bytes(xor_key, raw[4, 4])
|
62
|
+
# header size doesn't include the xor key, which is always tacked on the front
|
63
|
+
self.payload_length_left = length_bytes.unpack("N")[0] - (HEADER_SIZE - 4)
|
53
64
|
end
|
54
65
|
elsif (self.payload_length_left > 0)
|
55
66
|
buf = sock.read(self.payload_length_left)
|
@@ -67,14 +78,11 @@ class PacketParser
|
|
67
78
|
if ((self.hdr_length_left == 0) &&
|
68
79
|
(self.payload_length_left == 0))
|
69
80
|
|
70
|
-
# Create a typeless packet
|
71
|
-
packet = Packet.new(0)
|
72
|
-
|
73
81
|
# TODO: cipher decryption
|
74
82
|
if (cipher)
|
75
83
|
end
|
76
84
|
|
77
|
-
#
|
85
|
+
# Deserialize the packet from the raw buffer
|
78
86
|
packet.from_r(self.raw)
|
79
87
|
|
80
88
|
# Reset our state
|
@@ -15,6 +15,30 @@ module Meterpreter
|
|
15
15
|
###
|
16
16
|
class PacketResponseWaiter
|
17
17
|
|
18
|
+
# Arbitrary argument to {#completion_routine}
|
19
|
+
#
|
20
|
+
# @return [Object,nil]
|
21
|
+
attr_accessor :completion_param
|
22
|
+
|
23
|
+
# A callback to be called when this waiter is notified of a packet's
|
24
|
+
# arrival. If not nil, this will be called with the response packet as first
|
25
|
+
# parameter and {#completion_param} as the second.
|
26
|
+
#
|
27
|
+
# @return [Proc,nil]
|
28
|
+
attr_accessor :completion_routine
|
29
|
+
|
30
|
+
# @return [ConditionVariable]
|
31
|
+
attr_accessor :cond
|
32
|
+
|
33
|
+
# @return [Mutex]
|
34
|
+
attr_accessor :mutex
|
35
|
+
|
36
|
+
# @return [Packet]
|
37
|
+
attr_accessor :response
|
38
|
+
|
39
|
+
# @return [Fixnum] request ID to wait for
|
40
|
+
attr_accessor :rid
|
41
|
+
|
18
42
|
#
|
19
43
|
# Initializes a response waiter instance for the supplied request
|
20
44
|
# identifier.
|
@@ -27,7 +51,8 @@ class PacketResponseWaiter
|
|
27
51
|
self.completion_routine = completion_routine
|
28
52
|
self.completion_param = completion_param
|
29
53
|
else
|
30
|
-
self.
|
54
|
+
self.mutex = Mutex.new
|
55
|
+
self.cond = ConditionVariable.new
|
31
56
|
end
|
32
57
|
end
|
33
58
|
|
@@ -42,41 +67,37 @@ class PacketResponseWaiter
|
|
42
67
|
#
|
43
68
|
# Notifies the waiter that the supplied response packet has arrived.
|
44
69
|
#
|
70
|
+
# @param response [Packet]
|
71
|
+
# @return [void]
|
45
72
|
def notify(response)
|
46
|
-
self.response = response
|
47
|
-
|
48
73
|
if (self.completion_routine)
|
74
|
+
self.response = response
|
49
75
|
self.completion_routine.call(response, self.completion_param)
|
50
76
|
else
|
51
|
-
self.
|
77
|
+
self.mutex.synchronize do
|
78
|
+
self.response = response
|
79
|
+
self.cond.signal
|
80
|
+
end
|
52
81
|
end
|
53
82
|
end
|
54
83
|
|
55
84
|
#
|
56
|
-
#
|
57
|
-
# If the interval is -1 we can wait forever.
|
85
|
+
# Wait for a given time interval for the response packet to arrive.
|
58
86
|
#
|
87
|
+
# @param interval [Fixnum,nil] number of seconds to wait, or nil to wait
|
88
|
+
# forever
|
89
|
+
# @return [Packet,nil] the response, or nil if the interval elapsed before
|
90
|
+
# receiving one
|
59
91
|
def wait(interval)
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
else
|
65
|
-
begin
|
66
|
-
Timeout.timeout(interval) {
|
67
|
-
while(not self.done)
|
68
|
-
::IO.select(nil, nil, nil, 0.1)
|
69
|
-
end
|
70
|
-
}
|
71
|
-
rescue Timeout::Error
|
72
|
-
self.response = nil
|
92
|
+
interval = nil if interval and interval == -1
|
93
|
+
self.mutex.synchronize do
|
94
|
+
if self.response.nil?
|
95
|
+
self.cond.wait(self.mutex, interval)
|
73
96
|
end
|
74
97
|
end
|
75
98
|
return self.response
|
76
99
|
end
|
77
100
|
|
78
|
-
attr_accessor :rid, :done, :response # :nodoc:
|
79
|
-
attr_accessor :completion_routine, :completion_param # :nodoc:
|
80
101
|
end
|
81
102
|
|
82
103
|
end; end; end
|
@@ -29,7 +29,9 @@ class Console::CommandDispatcher::Android
|
|
29
29
|
'device_shutdown' => 'Shutdown device',
|
30
30
|
'send_sms' => 'Sends SMS from target session',
|
31
31
|
'wlan_geolocate' => 'Get current lat-long using WLAN information',
|
32
|
-
'interval_collect' => 'Manage interval collection capabilities'
|
32
|
+
'interval_collect' => 'Manage interval collection capabilities',
|
33
|
+
'activity_start' => 'Start an Android activity from a Uri string',
|
34
|
+
'set_audio_mode' => 'Set Ringer Mode'
|
33
35
|
}
|
34
36
|
|
35
37
|
reqs = {
|
@@ -41,7 +43,9 @@ class Console::CommandDispatcher::Android
|
|
41
43
|
'device_shutdown' => ['device_shutdown'],
|
42
44
|
'send_sms' => ['send_sms'],
|
43
45
|
'wlan_geolocate' => ['wlan_geolocate'],
|
44
|
-
'interval_collect' => ['interval_collect']
|
46
|
+
'interval_collect' => ['interval_collect'],
|
47
|
+
'activity_start' => ['activity_start'],
|
48
|
+
'set_audio_mode' => ['set_audio_mode']
|
45
49
|
}
|
46
50
|
|
47
51
|
# Ensure any requirements of the command are met
|
@@ -151,6 +155,36 @@ class Console::CommandDispatcher::Android
|
|
151
155
|
end
|
152
156
|
end
|
153
157
|
|
158
|
+
def cmd_set_audio_mode(*args)
|
159
|
+
help = false
|
160
|
+
mode = 1
|
161
|
+
set_audio_mode_opts = Rex::Parser::Arguments.new(
|
162
|
+
'-h' => [ false, "Help Banner" ],
|
163
|
+
'-m' => [ true, "Set Mode - (0 - Off, 1 - Normal, 2 - Max) (Default: '#{mode}')"]
|
164
|
+
)
|
165
|
+
|
166
|
+
set_audio_mode_opts.parse(args) do |opt, _idx, val|
|
167
|
+
case opt
|
168
|
+
when '-h'
|
169
|
+
help = true
|
170
|
+
when '-m'
|
171
|
+
mode = val.to_i
|
172
|
+
else
|
173
|
+
help = true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
if help || mode < 0 || mode > 2
|
178
|
+
print_line('Usage: set_audio_mode [options]')
|
179
|
+
print_line('Set Ringer mode.')
|
180
|
+
print_line(set_audio_mode_opts.usage)
|
181
|
+
return
|
182
|
+
end
|
183
|
+
|
184
|
+
client.android.set_audio_mode(mode)
|
185
|
+
print_status("Ringer mode was changed to #{mode}!")
|
186
|
+
end
|
187
|
+
|
154
188
|
def cmd_dump_sms(*args)
|
155
189
|
path = "sms_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
|
156
190
|
dump_sms_opts = Rex::Parser::Arguments.new(
|
@@ -457,7 +491,7 @@ class Console::CommandDispatcher::Android
|
|
457
491
|
end
|
458
492
|
end
|
459
493
|
|
460
|
-
if dest.
|
494
|
+
if dest.to_s.empty? || body.to_s.empty?
|
461
495
|
print_error("You must enter both a destination address -d and the SMS text body -t")
|
462
496
|
print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."')
|
463
497
|
print_line(send_sms_opts.usage)
|
@@ -509,7 +543,7 @@ class Console::CommandDispatcher::Android
|
|
509
543
|
wlan_list << [mac, ssid, ss.to_s]
|
510
544
|
end
|
511
545
|
|
512
|
-
if wlan_list.
|
546
|
+
if wlan_list.to_s.empty?
|
513
547
|
print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.")
|
514
548
|
return
|
515
549
|
end
|
@@ -528,6 +562,22 @@ class Console::CommandDispatcher::Android
|
|
528
562
|
end
|
529
563
|
end
|
530
564
|
|
565
|
+
def cmd_activity_start(*args)
|
566
|
+
if (args.length < 1)
|
567
|
+
print_line("Usage: activity_start <uri>\n")
|
568
|
+
print_line("Start an Android activity from a uri")
|
569
|
+
return
|
570
|
+
end
|
571
|
+
|
572
|
+
uri = args[0]
|
573
|
+
result = client.android.activity_start(uri)
|
574
|
+
if result.nil?
|
575
|
+
print_status("Intent started")
|
576
|
+
else
|
577
|
+
print_error("Error: #{result}")
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
531
581
|
#
|
532
582
|
# Name for this dispatcher
|
533
583
|
#
|
@@ -816,16 +816,18 @@ class Console::CommandDispatcher::Core
|
|
816
816
|
end
|
817
817
|
|
818
818
|
@@migrate_opts = Rex::Parser::Arguments.new(
|
819
|
-
'-
|
820
|
-
'-
|
821
|
-
'-
|
819
|
+
'-P' => [true, 'PID to migrate to.'],
|
820
|
+
'-N' => [true, 'Process name to migrate to.'],
|
821
|
+
'-p' => [true, 'Writable path - Linux only (eg. /tmp).'],
|
822
|
+
'-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'],
|
823
|
+
'-h' => [false, 'Help menu.']
|
822
824
|
)
|
823
825
|
|
824
826
|
def cmd_migrate_help
|
825
827
|
if client.platform =~ /linux/
|
826
|
-
print_line('Usage: migrate <pid> [-p writable_path] [-t timeout]')
|
828
|
+
print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-p writable_path] [-t timeout]')
|
827
829
|
else
|
828
|
-
print_line('Usage: migrate <pid> [-t timeout]')
|
830
|
+
print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-t timeout]')
|
829
831
|
end
|
830
832
|
print_line
|
831
833
|
print_line('Migrates the server instance to another process.')
|
@@ -840,29 +842,53 @@ class Console::CommandDispatcher::Core
|
|
840
842
|
# platforms a path for the unix domain socket used for IPC.
|
841
843
|
# @return [void]
|
842
844
|
def cmd_migrate(*args)
|
843
|
-
if args.length == 0 || args.
|
845
|
+
if args.length == 0 || args.any? { |arg| %w(-h --pid --name).include? arg }
|
844
846
|
cmd_migrate_help
|
845
847
|
return true
|
846
848
|
end
|
847
849
|
|
848
|
-
pid =
|
849
|
-
if pid == 0
|
850
|
-
print_error('A process ID must be specified, not a process name')
|
851
|
-
return
|
852
|
-
end
|
853
|
-
|
850
|
+
pid = nil
|
854
851
|
writable_dir = nil
|
855
852
|
opts = {
|
856
853
|
timeout: nil
|
857
854
|
}
|
858
855
|
|
859
|
-
@@
|
856
|
+
@@migrate_opts.parse(args) do |opt, idx, val|
|
860
857
|
case opt
|
861
858
|
when '-t'
|
862
859
|
opts[:timeout] = val.to_i
|
863
860
|
when '-p'
|
864
861
|
writable_dir = val
|
862
|
+
when '-P'
|
863
|
+
unless val =~ /^\d+$/
|
864
|
+
print_error("Not a PID: #{val}")
|
865
|
+
return
|
866
|
+
end
|
867
|
+
pid = val.to_i
|
868
|
+
when '-N'
|
869
|
+
if val.to_s.empty?
|
870
|
+
print_error("No process name provided")
|
871
|
+
return
|
872
|
+
end
|
873
|
+
# this will migrate to the first process with a matching name
|
874
|
+
unless (process = client.sys.process.processes.find { |p| p['name'] == val })
|
875
|
+
print_error("Could not find process name #{val}")
|
876
|
+
return
|
877
|
+
end
|
878
|
+
pid = process['pid']
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
unless pid
|
883
|
+
unless (pid = args.first)
|
884
|
+
print_error('A process ID or name argument must be provided')
|
885
|
+
return
|
886
|
+
end
|
887
|
+
unless pid =~ /^\d+$/
|
888
|
+
print_error("Not a PID: #{pid}")
|
889
|
+
return
|
865
890
|
end
|
891
|
+
pid = pid.to_i
|
866
892
|
end
|
867
893
|
|
868
894
|
begin
|
@@ -52,6 +52,7 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|
52
52
|
'cat' => 'Read the contents of a file to the screen',
|
53
53
|
'cd' => 'Change directory',
|
54
54
|
'del' => 'Delete the specified file',
|
55
|
+
'dir' => 'List files (alias for ls)',
|
55
56
|
'download' => 'Download a file or directory',
|
56
57
|
'edit' => 'Edit a file',
|
57
58
|
'getlwd' => 'Print local working directory',
|
@@ -73,6 +74,7 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|
73
74
|
'cat' => [],
|
74
75
|
'cd' => ['stdapi_fs_chdir'],
|
75
76
|
'del' => ['stdapi_fs_rm'],
|
77
|
+
'dir' => ['stdapi_fs_stat', 'stdapi_fs_ls'],
|
76
78
|
'download' => [],
|
77
79
|
'edit' => [],
|
78
80
|
'getlwd' => [],
|
@@ -598,6 +600,12 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|
598
600
|
return true
|
599
601
|
end
|
600
602
|
|
603
|
+
#
|
604
|
+
# Alias the ls command to dir, for those of us who have windows muscle-memory
|
605
|
+
#
|
606
|
+
alias cmd_dir cmd_ls
|
607
|
+
|
608
|
+
|
601
609
|
#
|
602
610
|
# Make one or more directory.
|
603
611
|
#
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
##
|
4
|
+
# ADB protocol support
|
5
|
+
##
|
6
|
+
|
7
|
+
require 'rex/proto/adb/message'
|
8
|
+
|
9
|
+
module Rex
|
10
|
+
module Proto
|
11
|
+
module ADB
|
12
|
+
|
13
|
+
class Client
|
14
|
+
|
15
|
+
def initialize(sock, opts = {})
|
16
|
+
@sock = sock
|
17
|
+
@opts = opts
|
18
|
+
@local_id_counter = 0x0a
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect
|
22
|
+
ADB::Message::Connect.new.send_recv(@sock)
|
23
|
+
end
|
24
|
+
|
25
|
+
def exec_cmd(cmd)
|
26
|
+
local_id = @local_id_counter += 1
|
27
|
+
response = ADB::Message::Open.new(local_id, "shell:"+cmd).send_recv(@sock)
|
28
|
+
ADB::Message::Close.new(local_id, response.arg0).send_recv(@sock)
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_message
|
32
|
+
ADB::Message.read(@sock)
|
33
|
+
end
|
34
|
+
|
35
|
+
end # Client
|
36
|
+
|
37
|
+
end # ADB
|
38
|
+
end # Proto
|
39
|
+
end # Rex
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
##
|
4
|
+
# ADB protocol support
|
5
|
+
##
|
6
|
+
|
7
|
+
module Rex
|
8
|
+
module Proto
|
9
|
+
module ADB
|
10
|
+
|
11
|
+
# A Message for the ADB protocol. For documentation see:
|
12
|
+
# https://android.googlesource.com/platform/system/core/+/master/adb/protocol.txt
|
13
|
+
class Message
|
14
|
+
|
15
|
+
WORD_WIDTH = 4 # bytes
|
16
|
+
WORD_PACK = 'L<'
|
17
|
+
|
18
|
+
attr_accessor :command
|
19
|
+
attr_accessor :arg0
|
20
|
+
attr_accessor :arg1
|
21
|
+
attr_accessor :data
|
22
|
+
|
23
|
+
def initialize(arg0, arg1, data)
|
24
|
+
self.command = self.class::COMMAND if defined?(self.class::COMMAND)
|
25
|
+
self.arg0 = arg0
|
26
|
+
self.arg1 = arg1
|
27
|
+
self.data = data + "\0"
|
28
|
+
end
|
29
|
+
|
30
|
+
def data_check
|
31
|
+
# this check is implemented in adb/transport.cpp, in the send_packet method.
|
32
|
+
# it is not crc32 as the docs make it appear, it is just a 32bit sum.
|
33
|
+
data.bytes.inject(&:+) & 0xffffffff
|
34
|
+
end
|
35
|
+
|
36
|
+
def magic
|
37
|
+
command_word ^ 0xffffffff
|
38
|
+
end
|
39
|
+
|
40
|
+
def command_word
|
41
|
+
command.unpack(WORD_PACK)[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_recv(socket)
|
45
|
+
socket.print self.serialize
|
46
|
+
Message.read socket
|
47
|
+
end
|
48
|
+
|
49
|
+
def serialize
|
50
|
+
[
|
51
|
+
command_word,
|
52
|
+
arg0,
|
53
|
+
arg1,
|
54
|
+
data.bytes.length,
|
55
|
+
data_check,
|
56
|
+
magic
|
57
|
+
].pack(WORD_PACK+'*') + data
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
[
|
62
|
+
"command=#{command}",
|
63
|
+
"arg0=0x#{arg0.to_s(16)}",
|
64
|
+
"arg1=0x#{arg1.to_s(16)}",
|
65
|
+
"data=#{data}"
|
66
|
+
].join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.read(socket)
|
70
|
+
header = socket.recvfrom(6 * WORD_WIDTH)[0]
|
71
|
+
command = header[0, WORD_WIDTH]
|
72
|
+
arg0 = header[WORD_WIDTH, WORD_WIDTH].unpack(WORD_PACK)[0]
|
73
|
+
arg1 = header[WORD_WIDTH*2, WORD_WIDTH].unpack(WORD_PACK)[0]
|
74
|
+
payload_len = header[WORD_WIDTH*3, WORD_WIDTH].unpack(WORD_PACK)[0]
|
75
|
+
payload = socket.recvfrom(payload_len)[0]
|
76
|
+
|
77
|
+
klass = MESSAGE_TYPES.find { |klass| klass::COMMAND == command }
|
78
|
+
if klass.nil?
|
79
|
+
raise "Invalid adb command: #{command}"
|
80
|
+
end
|
81
|
+
|
82
|
+
message = klass.allocate
|
83
|
+
message.command = command
|
84
|
+
message.arg0 = arg0
|
85
|
+
message.arg1 = arg1
|
86
|
+
message.data = payload
|
87
|
+
message
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Subclasses inside Message:: namespace for specific message types
|
92
|
+
#
|
93
|
+
|
94
|
+
class Connect < Message
|
95
|
+
COMMAND = "CNXN"
|
96
|
+
DEFAULT_VERSION = 0x01000000
|
97
|
+
DEFAULT_MAXDATA = 4096
|
98
|
+
DEFAULT_IDENTITY = "host::"
|
99
|
+
|
100
|
+
def initialize(version=DEFAULT_VERSION,
|
101
|
+
maxdata=DEFAULT_MAXDATA,
|
102
|
+
system_identity_string=DEFAULT_IDENTITY)
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Auth < Message
|
108
|
+
COMMAND = "AUTH"
|
109
|
+
TYPE_TOKEN = 1
|
110
|
+
TYPE_SIGNATURE = 2
|
111
|
+
|
112
|
+
def initialize(type, data)
|
113
|
+
super(type, 0, data)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class Open < Message
|
118
|
+
COMMAND = "OPEN"
|
119
|
+
|
120
|
+
def initialize(local_id, destination)
|
121
|
+
super(local_id, 0, destination)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Ready < Message
|
126
|
+
COMMAND = "OKAY"
|
127
|
+
|
128
|
+
def initialize(local_id, remote_id)
|
129
|
+
super(local_id, remote_id, "")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Write < Message
|
134
|
+
COMMAND = "WRTE"
|
135
|
+
|
136
|
+
def initialize(local_id, remote_id, data)
|
137
|
+
super
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class Close < Message
|
142
|
+
COMMAND = "CLSE"
|
143
|
+
|
144
|
+
def initialize(local_id, remote_id)
|
145
|
+
super(local_id, remote_id, "")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Sync < Message
|
150
|
+
COMMAND = "SYNC"
|
151
|
+
|
152
|
+
def initialize(online, sequence)
|
153
|
+
super(online, sequence, "")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Avoid a dependency on Rails's nice Class#subclasses
|
158
|
+
MESSAGE_TYPES = [Connect, Auth, Open, Ready, Write, Close, Sync]
|
159
|
+
|
160
|
+
end # Message
|
161
|
+
|
162
|
+
end # ADB
|
163
|
+
end # Proto
|
164
|
+
end # Rex
|