pwn 0.5.510 → 0.5.512
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/Gemfile +8 -8
- data/README.md +3 -3
- data/bin/pwn_gqrx_scanner +58 -83
- data/{build_pwn_gem.sh → build_gem.sh} +1 -1
- data/{git_commit_test_reinit_gem.sh → git_commit.sh} +4 -4
- data/lib/pwn/sdr/decoder/gsm.rb +24 -35
- data/lib/pwn/sdr/frequency_allocation.rb +81 -100
- data/lib/pwn/sdr/gqrx.rb +287 -119
- data/lib/pwn/version.rb +1 -1
- data/packer/provisioners/pwn.sh +1 -1
- data/third_party/pwn_rdoc.jsonl +5 -3
- data/{update_pwn.sh → upgrade_pwn.sh} +1 -1
- data/upgrade_ruby.sh +2 -2
- data/vagrant/provisioners/pwn.sh +1 -1
- metadata +23 -23
- /data/{reinstall_pwn_gemset.sh → reinstall_gemset.sh} +0 -0
- /data/{find_latest_gem_versions_per_Gemfile.sh → upgrade_Gemfile_gems.sh} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e7b1030cb5ce3e024a16630a46f404f8919da6d799e385133be3be4da8286e9
|
|
4
|
+
data.tar.gz: e19976ea7a052f608f9b17e50e76e06e070926146749bed674a30e39f91dccce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69ce103c6b63b5691adb551adb86540373671f15455a2614d94230f7530c80f8d24b2e46503c52852208e428d015d86185b64df1cd8fcf29e18c75e7b9103287
|
|
7
|
+
data.tar.gz: 99d2a4f9b47e9f2e3226c81539854a102b22b3956d36be70dbd75c62b5d0bd09c36563589e590d2796cec9ddef9b68736fb2649bb1d2320d666bac844f97524a
|
data/Gemfile
CHANGED
|
@@ -20,7 +20,7 @@ gem 'base32', '0.3.4'
|
|
|
20
20
|
gem 'bitcoin-ruby', '0.0.20'
|
|
21
21
|
gem 'brakeman', '7.1.1'
|
|
22
22
|
gem 'bson', '5.2.0'
|
|
23
|
-
gem 'bundler', '>=4.0.
|
|
23
|
+
gem 'bundler', '>=4.0.2'
|
|
24
24
|
gem 'bundler-audit', '>=0.9.3'
|
|
25
25
|
gem 'bunny', '2.24.0'
|
|
26
26
|
gem 'colorize', '1.1.0'
|
|
@@ -44,12 +44,12 @@ gem 'jenkins_api_client2', '1.9.0'
|
|
|
44
44
|
gem 'js-beautify', '0.1.8'
|
|
45
45
|
gem 'json', '>=2.13.2'
|
|
46
46
|
gem 'jsonpath', '1.1.5'
|
|
47
|
-
gem 'json_schemer', '2.
|
|
47
|
+
gem 'json_schemer', '2.5.0'
|
|
48
48
|
gem 'jwt', '3.1.2'
|
|
49
49
|
gem 'libusb', '0.7.2'
|
|
50
50
|
gem 'luhn', '3.0.0'
|
|
51
51
|
gem 'mail', '2.9.0'
|
|
52
|
-
gem 'meshtastic', '0.0.
|
|
52
|
+
gem 'meshtastic', '0.0.149'
|
|
53
53
|
gem 'metasm', '1.0.5'
|
|
54
54
|
gem 'mongo', '2.22.0'
|
|
55
55
|
gem 'msfrpc-client', '1.1.2'
|
|
@@ -73,14 +73,14 @@ gem 'pry-doc', '1.6.0'
|
|
|
73
73
|
gem 'rake', '13.3.1'
|
|
74
74
|
gem 'rb-readline', '0.5.5'
|
|
75
75
|
gem 'rbvmomi2', '3.8.0'
|
|
76
|
-
gem 'rdoc', '6.
|
|
76
|
+
gem 'rdoc', '6.17.0'
|
|
77
77
|
gem 'rest-client', '2.1.0'
|
|
78
78
|
gem 'rex', '2.0.13'
|
|
79
79
|
gem 'rmagick', '6.1.4'
|
|
80
80
|
gem 'rqrcode', '3.1.1'
|
|
81
81
|
gem 'rspec', '3.13.2'
|
|
82
82
|
gem 'rtesseract', '3.1.4'
|
|
83
|
-
gem 'rubocop', '1.
|
|
83
|
+
gem 'rubocop', '1.82.0'
|
|
84
84
|
gem 'rubocop-rake', '0.7.1'
|
|
85
85
|
gem 'rubocop-rspec', '3.8.0'
|
|
86
86
|
gem 'ruby-audio', '1.6.1'
|
|
@@ -88,8 +88,8 @@ gem 'ruby-nmap', '1.0.3'
|
|
|
88
88
|
gem 'ruby-saml', '1.18.1'
|
|
89
89
|
gem 'rvm', '1.11.3.9'
|
|
90
90
|
gem 'savon', '2.15.1'
|
|
91
|
-
gem 'selenium-devtools', '0.
|
|
92
|
-
gem 'selenium-webdriver', '4.
|
|
91
|
+
gem 'selenium-devtools', '0.143.0'
|
|
92
|
+
gem 'selenium-webdriver', '4.39.0'
|
|
93
93
|
gem 'slack-ruby-client', '3.1.0'
|
|
94
94
|
gem 'socksify', '1.8.1'
|
|
95
95
|
gem 'spreadsheet', '1.3.4'
|
|
@@ -104,4 +104,4 @@ gem 'webrick', '1.9.2'
|
|
|
104
104
|
gem 'whois', '6.0.3'
|
|
105
105
|
gem 'whois-parser', '2.0.0'
|
|
106
106
|
gem 'wicked_pdf', '2.8.2'
|
|
107
|
-
gem 'yard', '0.9.
|
|
107
|
+
gem 'yard', '0.9.38'
|
data/README.md
CHANGED
|
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
|
37
37
|
$ ./install.sh
|
|
38
38
|
$ ./install.sh ruby-gem
|
|
39
39
|
$ pwn
|
|
40
|
-
pwn[v0.5.
|
|
40
|
+
pwn[v0.5.512]:001 >>> PWN.help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.7@pwn
|
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
|
53
53
|
$ gem install --verbose pwn
|
|
54
54
|
$ pwn
|
|
55
|
-
pwn[v0.5.
|
|
55
|
+
pwn[v0.5.512]:001 >>> PWN.help
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.7@pwn
|
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
|
64
64
|
$ pwn
|
|
65
|
-
pwn[v0.5.
|
|
65
|
+
pwn[v0.5.512]:001 >>> PWN.help
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
data/bin/pwn_gqrx_scanner
CHANGED
|
@@ -13,12 +13,12 @@ PWN::Driver::Parser.new do |options|
|
|
|
13
13
|
opts[:list_scan_profiles] = l
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
options.on('-
|
|
17
|
-
opts[:
|
|
16
|
+
options.on('-sFREQ', '--start-freq=FREQ', '<Required if "--assume-profile" is Nil - Frequency to Start Scanning (e.g. 800.000.000 == 800 mHz>') do |s|
|
|
17
|
+
opts[:start_freq] = s
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
options.on('-
|
|
21
|
-
opts[:
|
|
20
|
+
options.on('-tFREQ', '--target-freq=FREQ', '<Required if "--assume-profile" is Nil - Frequency to Conclude Scanning (e.g. 900.000.000 == 900 mHz>') do |e|
|
|
21
|
+
opts[:target_freq] = e
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
options.on('-hHOST', '--host=HOST', '<Optional - GQRX Host (Defaults to 127.0.0.1)>') do |h|
|
|
@@ -29,7 +29,7 @@ PWN::Driver::Parser.new do |options|
|
|
|
29
29
|
opts[:port] = p
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
options.on('-AFLOAT', '--audio-gain=FLOAT', '<Optional - Set audio gain -80.0 to 50.0 (Defaults to
|
|
32
|
+
options.on('-AFLOAT', '--audio-gain=FLOAT', '<Optional - Set audio gain -80.0 to 50.0 (Defaults to 9.0)>') do |a|
|
|
33
33
|
opts[:audio_gain_db] = a
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -37,6 +37,10 @@ PWN::Driver::Parser.new do |options|
|
|
|
37
37
|
opts[:bandwidth] = b
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
options.on('-OLAP', '--overlap-protection', '<Optional - Enable Overlap Protection to prevent false positives when scanning (Defaults to false)>') do |o|
|
|
41
|
+
opts[:overlap_protection] = o
|
|
42
|
+
end
|
|
43
|
+
|
|
40
44
|
options.on('-DMODE', '--demodulator-mode=MODE', '<Optional - Set Demodulator Mode OFF | RAW | AM | FM | WFM | WFM_ST | WFM_ST_OIRT | LSB | USB | CW | CWL | CWU (Defaults to WFM_ST)>') do |d|
|
|
41
45
|
opts[:demodulator_mode] = d
|
|
42
46
|
end
|
|
@@ -45,44 +49,58 @@ PWN::Driver::Parser.new do |options|
|
|
|
45
49
|
opts[:precision] = p
|
|
46
50
|
end
|
|
47
51
|
|
|
48
|
-
options.on('-SFLOAT', '--strength-lock=FLOAT', '<Optional - Strength to lock onto frequency (Defaults to -
|
|
52
|
+
options.on('-SFLOAT', '--strength-lock=FLOAT', '<Optional - Strength to lock onto frequency (Defaults to -70.0)>') do |s|
|
|
49
53
|
opts[:strength_lock] = s
|
|
50
54
|
end
|
|
51
55
|
|
|
52
|
-
options.on('-LFLOAT', '--lock-freq-duration=FLOAT', '<Optional - Duration to lock onto Freqency when Strength < --strength-lock value (Defaults to 0.
|
|
56
|
+
options.on('-LFLOAT', '--lock-freq-duration=FLOAT', '<Optional - Duration to lock onto Freqency when Strength < --strength-lock value (Defaults to 0.04)>') do |l|
|
|
53
57
|
opts[:lock_freq_duration] = l
|
|
54
58
|
end
|
|
55
59
|
|
|
56
|
-
options.on('-QFLOAT', '--squelch=FLOAT', '<Optional - Squelch Threshold -150.0 to 0 (Defaults to -
|
|
60
|
+
options.on('-QFLOAT', '--squelch=FLOAT', '<Optional - Squelch Threshold -150.0 to 0 (Defaults to --strength-lock - 3)>') do |q|
|
|
57
61
|
opts[:squelch] = q
|
|
58
62
|
end
|
|
59
63
|
|
|
60
|
-
options.on('-RFLOAT', '--rf-gain=FLOAT', '<Optional - RF Gain 0.0-16.0(Defaults to
|
|
64
|
+
options.on('-RFLOAT', '--rf-gain=FLOAT', '<Optional - RF Gain 0.0-16.0(Defaults to 0.0)>') do |r|
|
|
61
65
|
opts[:rf_gain] = r
|
|
62
66
|
end
|
|
63
67
|
|
|
64
|
-
options.on('-IFLOAT', '--intermediate-gain=FLOAT', '<Optional - Intermediate Gain 0.0-40.0 (Defaults to
|
|
68
|
+
options.on('-IFLOAT', '--intermediate-gain=FLOAT', '<Optional - Intermediate Gain 0.0-40.0 (Defaults to 32.0)>') do |i|
|
|
65
69
|
opts[:intermediate_gain] = i
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
options.on('-BFLOAT', '--basedband-gain=FLOAT', '<Optional - Baseband Gain 0.0-62.0 (Defaults to 10.0)>') do |b|
|
|
69
73
|
opts[:baseband_gain] = b
|
|
70
74
|
end
|
|
75
|
+
|
|
76
|
+
options.on('-LFILE', '--scan-log=FILE', '<Optional - Path to log scan results to (Defaults to /tmp/pwn_sdr_gqrx_scan_<start_freq>-<target_freq>_<timestamp>.json)>') do |l|
|
|
77
|
+
opts[:scan_log] = l
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
options.on('-LOC', '--location', '<Optional - Location string to include in AI analysis (e.g. "New York, NY", 90210, GPS coords, etc.)>') do |l|
|
|
81
|
+
opts[:location] = l
|
|
82
|
+
end
|
|
71
83
|
end.parse!
|
|
72
84
|
|
|
73
85
|
begin
|
|
74
86
|
pwn_provider = 'ruby-gem'
|
|
75
87
|
pwn_provider = ENV.fetch('PWN_PROVIDER') if ENV.keys.any? { |s| s == 'PWN_PROVIDER' }
|
|
76
88
|
|
|
89
|
+
profiles_available = PWN::SDR::FrequencyAllocation.profiles
|
|
90
|
+
|
|
77
91
|
list_scan_profiles = opts[:list_scan_profiles]
|
|
78
92
|
if list_scan_profiles
|
|
79
|
-
profiles_available = PWN::SDR::GQRX.list_scan_profiles
|
|
80
93
|
puts JSON.pretty_generate(profiles_available)
|
|
81
94
|
exit 0
|
|
82
95
|
end
|
|
83
96
|
|
|
84
97
|
profile = opts[:profile]
|
|
85
|
-
opts
|
|
98
|
+
opts.merge!(profiles_available[profile.to_sym]) unless profile.nil?
|
|
99
|
+
|
|
100
|
+
start_freq = opts[:start_freq]
|
|
101
|
+
start_freq = start_freq.to_s.delete('.') unless start_freq.nil?
|
|
102
|
+
start_freq = start_freq.to_i
|
|
103
|
+
raise 'ERROR: Invalid start frequency.' if !start_freq.nil? && start_freq.zero?
|
|
86
104
|
|
|
87
105
|
target_freq = opts[:target_freq]
|
|
88
106
|
target_freq = target_freq.to_s.delete('.') unless target_freq.nil?
|
|
@@ -95,96 +113,53 @@ begin
|
|
|
95
113
|
puts "Connecting to GQRX at #{host}:#{port}..."
|
|
96
114
|
gqrx_sock = PWN::SDR::GQRX.connect(target: host, port: port)
|
|
97
115
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if start_freq.zero?
|
|
102
|
-
start_freq = PWN::SDR::GQRX.gqrx_cmd(
|
|
103
|
-
gqrx_sock: gqrx_sock, cmd: 'f',
|
|
104
|
-
resp_ok: 'RPRT 0'
|
|
105
|
-
).to_i
|
|
106
|
-
end
|
|
116
|
+
demodulator_mode = opts[:demodulator_mode]
|
|
117
|
+
bandwidth = opts[:bandwidth]
|
|
118
|
+
overlap_protection = opts[:overlap_protection]
|
|
107
119
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# demodulator_mode.upcase! if opts[:demodulator_mode]
|
|
111
|
-
demodulator_modes = %i[OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWU]
|
|
112
|
-
raise "ERROR: Invalid demodulator mode: #{demodulator_mode}" unless demodulator_modes.include?(demodulator_mode)
|
|
120
|
+
audio_gain_db = opts[:audio_gain_db]
|
|
121
|
+
audio_gain_db = audio_gain_db.to_f unless audio_gain_db.nil?
|
|
113
122
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
puts "Setting demodulator mode to #{demodulator_mode} and bandwidth to #{bandwidth}..."
|
|
117
|
-
bandwidth = bandwidth.to_s.delete('.').to_i unless bandwidth.nil?
|
|
118
|
-
demod_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
119
|
-
gqrx_sock: gqrx_sock,
|
|
120
|
-
cmd: "M #{demodulator_mode} #{bandwidth}",
|
|
121
|
-
resp_ok: 'RPRT 0'
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
audio_gain_db = opts[:audio_gain_db] ||= 1.0
|
|
125
|
-
audio_gain_db = audio_gain_db.to_f
|
|
126
|
-
audio_gain_db_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
127
|
-
gqrx_sock: gqrx_sock,
|
|
128
|
-
cmd: "L AF #{audio_gain_db}",
|
|
129
|
-
resp_ok: 'RPRT 0'
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
squelch = opts[:squelch] ||= -63.0
|
|
133
|
-
squelch = squelch.to_f
|
|
134
|
-
squelch_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
135
|
-
gqrx_sock: gqrx_sock,
|
|
136
|
-
cmd: "L SQL #{squelch}",
|
|
137
|
-
resp_ok: 'RPRT 0'
|
|
138
|
-
)
|
|
123
|
+
squelch = opts[:squelch]
|
|
124
|
+
squelch = squelch.to_f unless squelch.nil?
|
|
139
125
|
|
|
140
126
|
precision = opts[:precision] ||= 5
|
|
141
127
|
precision = precision.to_i
|
|
142
128
|
raise "ERROR: Invalid precision: #{precision}" unless (1..12).include?(precision)
|
|
143
129
|
|
|
144
|
-
lock_freq_duration = opts[:lock_freq_duration]
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
strength_lock = opts[:strength_lock] ||= -60.0
|
|
148
|
-
strength_lock = strength_lock.to_f
|
|
130
|
+
lock_freq_duration = opts[:lock_freq_duration]
|
|
131
|
+
strength_lock = opts[:strength_lock]
|
|
132
|
+
strength_lock = strength_lock.to_f unless strength_lock.nil?
|
|
149
133
|
|
|
150
|
-
rf_gain = opts[:rf_gain]
|
|
151
|
-
rf_gain = rf_gain.to_f
|
|
152
|
-
rf_gain_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
153
|
-
gqrx_sock: gqrx_sock,
|
|
154
|
-
cmd: "L RF_GAIN #{rf_gain}",
|
|
155
|
-
resp_ok: 'RPRT 0'
|
|
156
|
-
)
|
|
134
|
+
rf_gain = opts[:rf_gain]
|
|
135
|
+
rf_gain = rf_gain.to_f unless rf_gain.nil?
|
|
157
136
|
|
|
158
|
-
intermediate_gain = opts[:intermediate_gain]
|
|
159
|
-
intermediate_gain = intermediate_gain.to_f
|
|
160
|
-
intermediate_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
161
|
-
gqrx_sock: gqrx_sock,
|
|
162
|
-
cmd: "L IF_GAIN #{intermediate_gain}",
|
|
163
|
-
resp_ok: 'RPRT 0'
|
|
164
|
-
)
|
|
137
|
+
intermediate_gain = opts[:intermediate_gain]
|
|
138
|
+
intermediate_gain = intermediate_gain.to_f unless intermediate_gain.nil?
|
|
165
139
|
|
|
166
|
-
baseband_gain = opts[:baseband_gain]
|
|
167
|
-
baseband_gain = baseband_gain.to_f
|
|
168
|
-
baseband_resp = PWN::SDR::GQRX.gqrx_cmd(
|
|
169
|
-
gqrx_sock: gqrx_sock,
|
|
170
|
-
cmd: "L BB_GAIN #{baseband_gain}",
|
|
171
|
-
resp_ok: 'RPRT 0'
|
|
172
|
-
)
|
|
140
|
+
baseband_gain = opts[:baseband_gain]
|
|
141
|
+
baseband_gain = baseband_gain.to_f unless baseband_gain.nil?
|
|
173
142
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
puts "*** Scanning from #{s_freq_pretty} to #{t_freq_pretty}\n\n\n"
|
|
143
|
+
scan_log = opts[:scan_log]
|
|
144
|
+
location = opts[:location]
|
|
177
145
|
|
|
178
146
|
PWN::SDR::GQRX.scan_range(
|
|
179
147
|
gqrx_sock: gqrx_sock,
|
|
180
|
-
demodulator_mode: demodulator_mode,
|
|
181
|
-
bandwidth: bandwidth,
|
|
182
148
|
start_freq: start_freq,
|
|
183
149
|
target_freq: target_freq,
|
|
150
|
+
demodulator_mode: demodulator_mode,
|
|
151
|
+
bandwidth: bandwidth,
|
|
152
|
+
overlap_protection: overlap_protection,
|
|
184
153
|
precision: precision,
|
|
185
154
|
lock_freq_duration: lock_freq_duration,
|
|
186
155
|
strength_lock: strength_lock,
|
|
187
|
-
squelch: squelch
|
|
156
|
+
squelch: squelch,
|
|
157
|
+
audio_gain_db: audio_gain_db,
|
|
158
|
+
rf_gain: rf_gain,
|
|
159
|
+
intermediate_gain: intermediate_gain,
|
|
160
|
+
baseband_gain: baseband_gain,
|
|
161
|
+
scan_log: scan_log,
|
|
162
|
+
location: location
|
|
188
163
|
)
|
|
189
164
|
puts 'Scan Complete.'
|
|
190
165
|
rescue StandardError => e
|
|
@@ -18,7 +18,7 @@ rvmsudo gem update --system
|
|
|
18
18
|
|
|
19
19
|
if [[ $old_ruby_version == $new_ruby_version ]]; then
|
|
20
20
|
export rvmsudo_secure_path=1
|
|
21
|
-
rvmsudo /bin/bash --login -c "cd ${pwn_root} && ./
|
|
21
|
+
rvmsudo /bin/bash --login -c "cd ${pwn_root} && ./reinstall_gemset.sh"
|
|
22
22
|
cd /tmp && cd $pwn_root
|
|
23
23
|
rvmsudo rake
|
|
24
24
|
rvmsudo rake install
|
|
@@ -11,9 +11,9 @@ if (( $# == 3 )); then
|
|
|
11
11
|
git pull
|
|
12
12
|
git add . --all
|
|
13
13
|
echo 'Updating Gems to Latest Versions in Gemfile...'
|
|
14
|
-
./
|
|
14
|
+
./upgrade_Gemfile_gems.sh
|
|
15
15
|
if [[ $? -ne 0 ]]; then
|
|
16
|
-
echo 'ERROR:
|
|
16
|
+
echo 'ERROR: upgrade_Gemfile_gems.sh failed!'
|
|
17
17
|
exit 1
|
|
18
18
|
fi
|
|
19
19
|
|
|
@@ -34,9 +34,9 @@ if (( $# == 3 )); then
|
|
|
34
34
|
fi
|
|
35
35
|
|
|
36
36
|
git commit -a -S --author="${1} <${2}>" -m "${3}"
|
|
37
|
-
./
|
|
37
|
+
./upgrade_pwn.sh
|
|
38
38
|
if [[ $? -ne 0 ]]; then
|
|
39
|
-
echo 'ERROR:
|
|
39
|
+
echo 'ERROR: upgrade_pwn.sh failed!'
|
|
40
40
|
exit 1
|
|
41
41
|
fi
|
|
42
42
|
|
data/lib/pwn/sdr/decoder/gsm.rb
CHANGED
|
@@ -15,15 +15,13 @@ module PWN
|
|
|
15
15
|
|
|
16
16
|
# Starts the live decoding thread.
|
|
17
17
|
def self.start(opts = {})
|
|
18
|
-
|
|
19
|
-
raise ':ERROR: :
|
|
18
|
+
freq_obj = opts[:freq_obj]
|
|
19
|
+
raise ':ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
gqrx_obj[:decoder_stop_flag] ||= [false]
|
|
21
|
+
gqrx_sock = freq_obj[:gqrx_sock]
|
|
22
|
+
freq = freq_obj[:freq]
|
|
23
|
+
bandwidth = freq_obj[:bandwidth].to_i
|
|
24
|
+
record_path = freq_obj[:record_path]
|
|
27
25
|
|
|
28
26
|
sleep 0.1 until File.exist?(record_path)
|
|
29
27
|
|
|
@@ -32,12 +30,10 @@ module PWN
|
|
|
32
30
|
|
|
33
31
|
bytes_read = HEADER_SIZE
|
|
34
32
|
|
|
35
|
-
puts "GSM Decoder started for
|
|
33
|
+
puts "GSM Decoder started for freq: #{freq}, bandwidth: #{bandwidth}"
|
|
36
34
|
|
|
37
35
|
Thread.new do
|
|
38
36
|
loop do
|
|
39
|
-
break if gqrx_obj[:decoder_stop_flag][0]
|
|
40
|
-
|
|
41
37
|
current_size = File.size(record_path)
|
|
42
38
|
if current_size > bytes_read
|
|
43
39
|
new_bytes = current_size - bytes_read
|
|
@@ -46,8 +42,8 @@ module PWN
|
|
|
46
42
|
data = File.binread(record_path, new_bytes, bytes_read)
|
|
47
43
|
process_chunk(
|
|
48
44
|
data: data,
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
bandwidth: bandwidth,
|
|
46
|
+
freq: freq
|
|
51
47
|
)
|
|
52
48
|
bytes_read = current_size
|
|
53
49
|
end
|
|
@@ -63,12 +59,11 @@ module PWN
|
|
|
63
59
|
|
|
64
60
|
# Stops the decoding thread.
|
|
65
61
|
def self.stop(opts = {})
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
raise ':ERROR: :thread and :gqrx_obj are required' unless thread && gqrx_obj.is_a?(Hash)
|
|
62
|
+
freq_obj = opts[:freq_obj]
|
|
63
|
+
raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
decoder_thread = freq_obj[:decoder_thread]
|
|
66
|
+
decoder_thread.kill if decoder_thread.is_a?(Thread)
|
|
72
67
|
end
|
|
73
68
|
|
|
74
69
|
class << self
|
|
@@ -76,9 +71,9 @@ module PWN
|
|
|
76
71
|
|
|
77
72
|
def process_chunk(opts = {})
|
|
78
73
|
data = opts[:data]
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
raise ':ERROR: :data, :
|
|
74
|
+
bandwidth = opts[:bandwidth]
|
|
75
|
+
freq = opts[:freq]
|
|
76
|
+
raise ':ERROR: :data, :bandwidth, and :freq are required' unless data && bandwidth && freq
|
|
82
77
|
|
|
83
78
|
samples = data.unpack('f< *')
|
|
84
79
|
return if samples.length.odd? # Skip incomplete
|
|
@@ -88,7 +83,7 @@ module PWN
|
|
|
88
83
|
complex_samples << Complex(samples[i], samples[i + 1])
|
|
89
84
|
end
|
|
90
85
|
|
|
91
|
-
window_size = [(
|
|
86
|
+
window_size = [(bandwidth * BURST_DURATION_SEC).round, complex_samples.length].min
|
|
92
87
|
return if window_size <= 0
|
|
93
88
|
|
|
94
89
|
# Simplified power on sliding windows
|
|
@@ -112,10 +107,10 @@ module PWN
|
|
|
112
107
|
return unless burst_start >= 0 && burst_start + 148 <= bits.length
|
|
113
108
|
|
|
114
109
|
data_bits = extract_data_bits(bits, burst_start)
|
|
115
|
-
puts "Burst synchronized at offset #{sync_offset} for #{
|
|
110
|
+
puts "Burst synchronized at offset #{sync_offset} for #{freq} Hz (power: #{max_power.round(4)})"
|
|
116
111
|
decode_imsi(
|
|
117
112
|
data_bits: data_bits,
|
|
118
|
-
|
|
113
|
+
freq: freq
|
|
119
114
|
)
|
|
120
115
|
end
|
|
121
116
|
|
|
@@ -159,8 +154,8 @@ module PWN
|
|
|
159
154
|
|
|
160
155
|
def decode_imsi(opts = {})
|
|
161
156
|
data_bits = opts[:data_bits]
|
|
162
|
-
|
|
163
|
-
raise ':ERROR: :data_bits and :
|
|
157
|
+
freq = opts[:freq]
|
|
158
|
+
raise ':ERROR: :data_bits and :freq are required' unless data_bits && freq
|
|
164
159
|
|
|
165
160
|
# Simplified "IMSI extraction": Interpret first ~60 bits as packed digits (4 bits per digit, BCD-like).
|
|
166
161
|
# In reality: Deinterleave (over bursts), Viterbi decode convolutional code (polys G0=10011b, G1=11011b),
|
|
@@ -180,7 +175,7 @@ module PWN
|
|
|
180
175
|
msin = imsi_digits[6, 9].join
|
|
181
176
|
imsi = "#{mcc.ljust(3, '0')}#{mnc.ljust(3, '0')}#{msin.ljust(9, '0')}"
|
|
182
177
|
|
|
183
|
-
puts "Decoded IMSI: #{imsi} at #{
|
|
178
|
+
puts "Decoded IMSI: #{imsi} at #{freq} Hz"
|
|
184
179
|
# TODO: Integrate full L3 parser (e.g., from ruby-gsm gem or custom).
|
|
185
180
|
end
|
|
186
181
|
|
|
@@ -208,18 +203,12 @@ module PWN
|
|
|
208
203
|
public_class_method def self.help
|
|
209
204
|
puts "USAGE:
|
|
210
205
|
gsm_decoder_thread = PWN::SDR::Decoder::GSM.start(
|
|
211
|
-
|
|
212
|
-
record_path: 'path/to/record.wav',
|
|
213
|
-
frequency: 935_000_000, # Frequency in Hz
|
|
214
|
-
bandwidth: 200_000, # Sample rate in Hz
|
|
215
|
-
gqrx_sock: gqrx_socket_object
|
|
216
|
-
}
|
|
206
|
+
freq_obj: 'required - freq_obj returned from PWN::SDR::Receiver::GQRX.init_freq method'
|
|
217
207
|
)
|
|
218
208
|
|
|
219
209
|
# To stop the decoder thread:
|
|
220
210
|
PWN::SDR::Decoder::GSM.stop(
|
|
221
|
-
|
|
222
|
-
gqrx_obj: gqrx_object_used_to_start_decoder
|
|
211
|
+
freq_obj: 'required - freq_obj returned from PWN::SDR::Receiver::GQRX.init_freq method'
|
|
223
212
|
)
|
|
224
213
|
|
|
225
214
|
#{self}.authors
|