rex 2.0.9 → 2.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|