android_parser 2.5.1 → 2.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8360af54a4093e8cc95844b8b7419e3190aed92f5aa6c832f0fd4f7e8ccd2f53
4
- data.tar.gz: 1b8a9172fdf2b4f18c43cb0a342aa5244f7ad109cbfc8b8995d74d6de9fc34a9
3
+ metadata.gz: 5a455cf668b1e1fbae27b208a872c304ac7ff60987034c529aa93c676b3e4348
4
+ data.tar.gz: 5089aec3a63dec1766ae3c981442c2a6fa9500f1351d0e989552e84047309443
5
5
  SHA512:
6
- metadata.gz: 393956811a1cfcb6bd043cdc8c6494a1760a0558d6d12ce157ee9e08b67035499f702e15cf8d6baa7971572eb616c0de28ebc92003a4e9a32c18541eb82b7f7b
7
- data.tar.gz: a7998f5d5e71b889c083f6b1d73f4d277bd7aecd6c412a5d4b14dc10bccf1104472dffde03c2a2280071f88c846906f15c80991d73689f2dd957a46270ac3fbf
6
+ metadata.gz: b4e6104d2a29750902a79871b5a3e2750ea3ea3a8fdcde709870950ca93ddeaa2299f481c393be9556e21378a88c843afe8b9123b338c7a7e7c204a2800c6b99
7
+ data.tar.gz: 9474805fe13212f5193817cf0bc22b33163211232ec01cf4ad60b65eb4713992d701f3883f87241eb2d8b532d00397d6c641c167b19db4b8d71fc314bf87d352
@@ -0,0 +1,15 @@
1
+ name: Create Release
2
+ on:
3
+ push:
4
+ tags:
5
+ - "v*"
6
+
7
+ jobs:
8
+ create:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Create Release
12
+ uses: softprops/action-gh-release@v1
13
+ if: startsWith(github.ref, 'refs/tags/')
14
+ env:
15
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
data/Gemfile CHANGED
@@ -3,8 +3,7 @@ source 'http://rubygems.org'
3
3
  # Specify your gem's dependencies in android_parser.gemspec
4
4
  gemspec
5
5
 
6
- # group :development do
7
- # gem 'awesome_print'
8
- # gem 'debase'
9
- # gem 'ruby-debug-ide'
10
- # end
6
+ group :development do
7
+ gem 'awesome_print'
8
+ gem 'debug'
9
+ end
data/README.md CHANGED
@@ -55,7 +55,7 @@ icons.each do |name, data|
55
55
  end
56
56
  ```
57
57
 
58
- #### Extract signature and certificate information from Apk (since v0.7.0)
58
+ #### Extract v1 signature and certificate information from Apk (since v0.7.0)
59
59
 
60
60
  ```ruby
61
61
  apk = Android::Apk.new('sample.apk')
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'android_parser'
8
- spec.version = '2.5.1'
8
+ spec.version = '2.6.0'
9
9
  spec.authors = ['SecureBrain', 'icyleaf']
10
10
  spec.email = ['info@securebrain.co.jp', 'icyleaf.cn@gmail.com']
11
11
  spec.platform = Gem::Platform::RUBY
data/lib/android/apk.rb CHANGED
@@ -189,7 +189,7 @@ module Android
189
189
  # @return [nil] when label is not found
190
190
  # @deprecated move to {Android::Manifest#label}
191
191
  # @since 0.6.0
192
- def label(lang=nil)
192
+ def label(lang = nil)
193
193
  @manifest.label
194
194
  end
195
195
 
@@ -200,25 +200,63 @@ module Android
200
200
  @layouts ||= Layout.collect_layouts(self) # lazy parse
201
201
  end
202
202
 
203
- # apk's signature information
203
+ # apk's v1 signature information
204
204
  # @return [Hash{ String => OpenSSL::PKCS7 } ] key: sign file path, value: signature
205
205
  # @since 0.7.0
206
206
  def signs
207
- signs = {}
208
- self.each_file do |path, data|
209
- # find META-INF/xxx.{RSA|DSA}
210
- next unless path =~ /^META-INF\// && data.unpack("CC") == [0x30, 0x82]
211
- signs[path] = OpenSSL::PKCS7.new(data)
212
- end
213
- signs
207
+ @signs ||= lambda {
208
+ signs = {}
209
+ self.each_file do |path, data|
210
+ # find META-INF/xxx.{RSA|DSA|EC}
211
+ next unless path =~ /^META-INF\// && data.unpack("CC") == [0x30, 0x82]
212
+
213
+ signs[path] = OpenSSL::PKCS7.new(data)
214
+ end
215
+ signs
216
+ }.call
214
217
  end
215
218
 
216
- # certificate info which is used for signing
219
+ # v1 certificate info which is used for signing
217
220
  # @return [Hash{String => OpenSSL::X509::Certificate }] key: sign file path, value: first certficate in the sign file
218
221
  # @since 0.7.0
219
222
  def certificates
220
- return Hash[self.signs.map{|path, sign| [path, sign.certificates.first] }]
223
+ @certificates ||= Hash[self.signs.map{|path, sign| [path, sign.certificates.first] }]
224
+ end
225
+
226
+ # detect if use kotlin language (may be third-party sdk or not)
227
+ # @return [Boolean]
228
+ # @since 2.6.0
229
+ def kotlin?
230
+ @kotlin ||= kotlin_file? || kotlin_classes?
221
231
  end
232
+
233
+ private
234
+
235
+ def kotlin_file?
236
+ KOTLIN_FILES.any? do |file|
237
+ begin
238
+ entry(file)
239
+ rescue
240
+ next
241
+ end
242
+ end
243
+ end
244
+
245
+ def kotlin_classes?
246
+ @dex.classes.any? do |class_info|
247
+ class_info.type.start_with?('kotlin.') ||
248
+ class_info.type.start_with?('kotlinx.')
249
+ end
250
+ end
251
+
252
+ KOTLIN_FILES = [
253
+ 'kotlin-tooling-metadata.json',
254
+ 'kotlin/kotlin.kotlin_builtins',
255
+ 'META-INF/kotlinx_coroutines_android.version',
256
+ 'META-INF/kotlinx_coroutines_core.version',
257
+ 'META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler',
258
+ 'META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory'
259
+ ].freeze
222
260
  end
223
261
  end
224
262
 
@@ -29,16 +29,32 @@ module Android
29
29
  # @return [DexObject::ClassDefItem]
30
30
  attr_reader :class_def
31
31
 
32
+ # return full namespace of class
33
+ #
34
+ # sample value like `Landroidx/activity/Cancellable;`
35
+ #
36
+ # @return [String] class name
32
37
  def name
33
- @dex.type_resolve(@class_def[:class_idx])
38
+ @name ||= @dex.type_resolve(@class_def[:class_idx])
34
39
  end
40
+
35
41
  def super_class
36
- if @class_def[:superclass_idx] != NO_INDEX
37
- @super_class = @dex.type_resolve(@class_def[:superclass_idx])
38
- else
39
- nil
40
- end
42
+ @super_class ||= if @class_def[:superclass_idx] != NO_INDEX
43
+ @dex.type_resolve(@class_def[:superclass_idx])
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ # Convert name to human readable string
50
+ #
51
+ # From `Landroidx/activity/Cancellable;` to `androidx.activity.Cancellable`
52
+ #
53
+ # @return [String] human readable name
54
+ def type
55
+ @type ||= name.gsub('/', '.')[1..-2]
41
56
  end
57
+
42
58
  # @param [Dex::ClassDefItem] class_def
43
59
  # @param [Dex] dex dex class instance
44
60
  def initialize(class_def, dex)
@@ -62,6 +78,7 @@ module Android
62
78
  end
63
79
 
64
80
  private
81
+
65
82
  def cls2info(arr, cls, idx_key)
66
83
  idx = 0
67
84
  ret = []
@@ -10,7 +10,7 @@ module Android
10
10
  # <activity>, <service>, <receiver> or <provider> element in <application> element of the manifest file.
11
11
  class Component
12
12
  # component types
13
- TYPES = ['activity', 'activity-alias', 'service', 'receiver', 'provider', 'application']
13
+ TYPES = ['activity', 'activity-alias', 'service', 'receiver', 'provider', 'application', 'queries']
14
14
 
15
15
  # the element is valid Component element or not
16
16
  # @param [REXML::Element] elem xml element
@@ -322,6 +322,99 @@ module Android
322
322
  end
323
323
  end
324
324
 
325
+ # <intent>, <service>, <receiver> or <provider> element in <application> element of the manifest file.
326
+ class QueriesComponent
327
+ # component types
328
+ TYPES = ['package', 'intent', 'provider']
329
+
330
+ # @return [String] type string in TYPES
331
+ attr_reader :type
332
+ # @return [Manifest::Queries::Package]
333
+ attr_reader :packages
334
+ # @return [Array<Manifest::Queries::Intent>]
335
+ attr_reader :intents
336
+ # @return [Array<Manifest::Queries::Provider>]
337
+ attr_reader :providers
338
+ # @return [REXML::Element]
339
+ attr_reader :elem
340
+
341
+ # @param [REXML::Element] elem target element
342
+ # @raise [ArgumentError] when elem is invalid.
343
+ def initialize(elem)
344
+ raise ArgumentError unless Component.valid?(elem)
345
+
346
+ @elem = elem
347
+ @type = elem.name
348
+ @packages = parse_packages
349
+ @intents = parse_intents
350
+ @providers = parse_providers
351
+ end
352
+
353
+ private
354
+
355
+ def parse_packages
356
+ packages = []
357
+ return packages if @elem.elements['package'].nil?
358
+
359
+ @elem.each_element('package') do |package|
360
+ packages << Android::Manifest::Queries::Package.new(package)
361
+ end
362
+
363
+ packages
364
+ end
365
+
366
+ def parse_intents
367
+ intents = []
368
+ return intents if @elem.elements['intent'].nil?
369
+
370
+ @elem.each_element('intent') do |intent|
371
+ next if intent&.elements&.empty?
372
+ next unless Android::Manifest::Queries::Intent.valid?(intent)
373
+
374
+ intent = Android::Manifest::Queries::Intent.new(intent)
375
+ intents << intent unless intent.empty?
376
+ end
377
+
378
+ intents
379
+ end
380
+
381
+ def parse_providers
382
+ providers = []
383
+ return providers if @elem.elements['provider'].nil?
384
+
385
+ @elem.each_element('provider') do |provider|
386
+ providers << Android::Manifest::Queries::Provider.new(provider)
387
+ end
388
+
389
+ providers
390
+ end
391
+ end
392
+
393
+ class Queries < QueriesComponent
394
+ class Intent < Android::Manifest::IntentFilter; end
395
+ class Provider < Android::Manifest::Provider
396
+ def authorities
397
+ @authorities ||= @elem.attributes['authorities']
398
+ end
399
+ end
400
+
401
+ class Package
402
+ # @return [String] action name of queries
403
+ attr_reader :name
404
+ # @return [String] action type of intent-filter
405
+ attr_reader :type
406
+
407
+ def initialize(elem)
408
+ @type = 'package'
409
+ @name = elem.attributes['name']
410
+ end
411
+ end
412
+
413
+ def self.valid?(elem)
414
+ elem&.name == 'queries'
415
+ end
416
+ end
417
+
325
418
  #################################
326
419
  # Manifest class definitions
327
420
  #################################
@@ -370,6 +463,13 @@ module Android
370
463
  components
371
464
  end
372
465
 
466
+ # Returns the manifest's queries element or nil, if there isn't any.
467
+ # @return [Android::Manifest::Queries] the manifest's application element
468
+ def queries
469
+ element = @doc.elements['/manifest/queries']
470
+ Queries.new(element) if Queries.valid?(element)
471
+ end
472
+
373
473
  # @return [Array<Android::Manifest::Activity&ActivityAlias>] all activities in the apk
374
474
  # @note return empty array when the manifest include no activities
375
475
  def activities
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: android_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SecureBrain
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-09 00:00:00.000000000 Z
12
+ date: 2023-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubyzip
@@ -139,6 +139,7 @@ extra_rdoc_files: []
139
139
  files:
140
140
  - ".github/dependabot.yml"
141
141
  - ".github/workflows/ci.yml"
142
+ - ".github/workflows/create_release.yml"
142
143
  - ".gitignore"
143
144
  - ".rspec"
144
145
  - CHANGELOG.md