├── .github └── workflows │ └── tests.yml ├── .gitignore ├── BEMENTIONED.md ├── LICENSE.md ├── Makefile ├── README.md ├── composer.json ├── examples ├── ApkActivities.php ├── ApkClasses.php ├── ApkExtractor.php ├── ApkInfo.php ├── ApkResource.php ├── EBHS.apk ├── PrintManifestXml.php ├── autoload.php └── rsa.php ├── lib └── ApkParser │ ├── Activity.php │ ├── AndroidPlatform.php │ ├── Application.php │ ├── Archive.php │ ├── Config.php │ ├── Dex │ └── dedexer.jar │ ├── Exceptions │ ├── ApkException.php │ ├── FileNotFoundException.php │ ├── StreamNotFoundException.php │ └── XmlParserException.php │ ├── IntentFilter.php │ ├── Manifest.php │ ├── ManifestXmlElement.php │ ├── Parser.php │ ├── ResourcesParser.php │ ├── SeekableStream.php │ ├── Stream.php │ ├── Utils.php │ ├── Xml.php │ ├── XmlParser.php │ └── lang │ └── en.permissions.json ├── phpunit.xml └── test ├── ManifestTest.php ├── ParserTest.php ├── XmlParserTest.php └── resources ├── EBHS.apk ├── ebhs.png ├── invalid.xml └── meta.xml /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | php-version: 10 | - '8.0' 11 | - '8.1' 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: "Setup PHP" 19 | uses: "shivammathur/setup-php@v2" 20 | with: 21 | php-version: "${{ matrix.php-version }}" 22 | 23 | - name: Get composer cache directory 24 | id: composer-cache 25 | run: | 26 | echo "::set-output name=dir::$(composer config cache-files-dir)" 27 | - uses: actions/cache@v2 28 | with: 29 | path: ${{ steps.composer-cache.outputs.dir }} 30 | key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }} 31 | restore-keys: | 32 | ${{ runner.os }}-${{ matrix.php-version }}-composer- 33 | 34 | - name: Install dependencies 35 | run: composer install 36 | 37 | - name: Run tests 38 | run: composer tests 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### IntelliJ ### 2 | *.ipr 3 | *.iws 4 | *.iml 5 | .idea/ 6 | out/ 7 | 8 | ### Composer ### 9 | composer.phar 10 | composer.lock 11 | vendor/ 12 | 13 | # Mac OS 14 | .DS_Store 15 | examples/extract_folder 16 | 17 | # PHPUnit 18 | .phpunit.result.cache 19 | .php-cs-fixer.cache -------------------------------------------------------------------------------- /BEMENTIONED.md: -------------------------------------------------------------------------------- 1 | # How To Be Mentioned 2 | 3 | As php-apk-parser developers, we support and love all open source lovers. You are always welcome to use and develop any 4 | of our projects. If you are an open source user / lover / supporter please mention this on your project to help spread 5 | the word. You need at least a public "Open source credits" page to be mentioned on apk-parser page as a apk-parser user. 6 | If you have such a page, please open a pull request with an edit to README.md, and in the body of the pull request 7 | include a link to your open source credits page. 8 | 9 | Since it's an individual project, for sure you can be mentioned just with a donation too :) 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | For PHP Apk Parser 4 | https://github.com/tufanbarisyildirim/php-apk-parser 5 | 6 | Copyright (c) 2012 - 2020 Tufan Baris Yildirim 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PHP = php 2 | COMPOSER = composer 3 | M = $(shell printf "\033[34;1m>>\033[0m") 4 | 5 | .PHONY: test 6 | test: 7 | $(info $(M) runing tests...) 8 | $(COMPOSER) tests 9 | 10 | .PHONY: lint 11 | lint: 12 | $(info $(M) runing cs fixer...) 13 | $(COMPOSER) cs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Apk Parser](http://tufanbarisyildirim.github.io/php-apk-parser/) 2 | 3 | This package can extract application package files in APK format used by devices running on Android OS. It can open an 4 | APK file and extract the contained manifest file to parse it and retrieve the meta-information it contains like the 5 | application name, description, device feature access permission it requires, etc.. The class can also extract the whole 6 | files contained in the APK file to a given directory. 7 | 8 | ### Requirements 9 | 10 | PHP 8.0+ 11 | PHP 7.3+ is in [2.x.x](https://github.com/tufanbarisyildirim/php-apk-parser/tree/v2.x.x) branch 12 | 13 | ### Installation 14 | 15 | - Install [composer](http://getcomposer.org/download/) 16 | - Run the following command in the folder where `composer.json` is: `composer require tufanbarisyildirim/php-apk-parser` 17 | 18 | ## Testing 19 | 20 | Tests are powered by PHPUnit. You have several options. 21 | 22 | - Run `phpunit` if PHPUnit is installed globally. 23 | - Install dependencies (requires [Composer](https://getcomposer.org/download)). Run `php composer.phar --dev install` 24 | or `composer --dev install`. Then `bin/vendor/phpunit` to run version installed by Composer. This ensures that you are 25 | running a version compatible with the test suite. 26 | 27 | ## Contributing 28 | 29 | Fork the repo, make your changes, add your name to developers, and create a pull request with a comment that describe 30 | your changes. That's all! 31 | [Thanks to all contributers](https://github.com/tufanbarisyildirim/php-apk-parser/graphs/contributors) 32 | 33 | ## Thanks 34 | 35 | Thanks JetBrains for the free open source license 36 | 37 | 38 | Jetbrains 39 | 40 | 41 | ### License 42 | 43 | Apk Parser is [MIT licensed](./LICENSE.md). 44 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tufanbarisyildirim/php-apk-parser", 3 | "type": "library", 4 | "description": "Read basic info about an application from .apk file.", 5 | "keywords": [ 6 | "apk", 7 | "parser", 8 | "android" 9 | ], 10 | "homepage": "https://github.com/tufanbarisyildirim/php-apk-parser", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Tufan Baris YILDIRIM", 15 | "email": "tufanbarisyildirim@gmail.com", 16 | "homepage": "https://tufanbarisyildirim.com", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=8.0", 22 | "ext-simplexml": "*", 23 | "ext-json": "*", 24 | "ext-libxml": "*", 25 | "ext-mbstring": "*", 26 | "ext-zip": "*" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^8.5", 30 | "friendsofphp/php-cs-fixer": "^3.1" 31 | }, 32 | "repositories": [ 33 | { 34 | "type": "vcs", 35 | "url": "https://github.com/tufanbarisyildirim/php-apk-parser.git" 36 | } 37 | ], 38 | "autoload": { 39 | "psr-0": { 40 | "ApkParser": "lib" 41 | } 42 | }, 43 | "scripts": { 44 | "tests": "@php phpunit --configuration=phpunit.xml", 45 | "cs": "PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix ." 46 | }, 47 | "minimum-stability": "dev" 48 | } 49 | -------------------------------------------------------------------------------- /examples/ApkActivities.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | include 'autoload.php'; 13 | 14 | $apk = new ApkParser\Parser('EBHS.apk'); 15 | 16 | echo '
';
17 | foreach ($apk->getManifest()->getApplication()->getActivityNameList() as $activityName) {
18 |     echo $activityName . PHP_EOL;
19 | }
20 | 


--------------------------------------------------------------------------------
/examples/ApkClasses.php:
--------------------------------------------------------------------------------
 1 | 
 6 |  *
 7 |  * For the full copyright and license information, please view the LICENSE
 8 |  * file that was distributed with this source code.
 9 |  */
10 | 
11 | include 'autoload.php';
12 | 
13 | $apk = new ApkParser\Parser('EBHS.apk');
14 | 
15 | echo '
';
16 | foreach ($apk->getClasses() as $className) {
17 |     echo $className . PHP_EOL;
18 | }
19 | 


--------------------------------------------------------------------------------
/examples/ApkExtractor.php:
--------------------------------------------------------------------------------
 1 | 
 6 |  *
 7 |  * For the full copyright and license information, please view the LICENSE
 8 |  * file that was distributed with this source code.
 9 |  */
10 | 
11 | include 'autoload.php';
12 | 
13 | $apk = new \ApkParser\Parser('EBHS.apk');
14 | $extractFolder = 'extract_folder';
15 | 
16 | if (is_dir($extractFolder) || mkdir($extractFolder)) {
17 |     $apk->extractTo($extractFolder);
18 | }
19 | 


--------------------------------------------------------------------------------
/examples/ApkInfo.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | include 'autoload.php';
13 | $apk = new \ApkParser\Parser('EBHS.apk');
14 | 
15 | $manifest = $apk->getManifest();
16 | $permissions = $manifest->getPermissions();
17 | 
18 | echo '
';
19 | echo "Package Name      : " . $manifest->getPackageName() . "" . PHP_EOL;
20 | echo "Version           : " . $manifest->getVersionName() . " (" . $manifest->getVersionCode() . ")" . PHP_EOL;
21 | echo "Min Sdk Level     : " . $manifest->getMinSdkLevel() . "" . PHP_EOL;
22 | echo "Min Sdk Platform  : " . $manifest->getMinSdk()->platform . "" . PHP_EOL;
23 | echo "Target Sdk Level     : " . $manifest->getTargetSdkLevel() . "" . PHP_EOL;
24 | echo "Target Sdk Platform  : " . $manifest->getTargetSdk()->platform . "" . PHP_EOL;
25 | echo PHP_EOL;
26 | echo "------------- Permssions List -------------" . PHP_EOL;
27 | 
28 | // find max length to print more pretty.
29 | $perm_keys = array_keys($permissions);
30 | $perm_key_lengths = array_map(
31 |     function ($perm) {
32 |         return strlen($perm);
33 |     },
34 |     $perm_keys
35 | );
36 | $max_length = max($perm_key_lengths);
37 | 
38 | foreach ($permissions as $perm => $detail) {
39 |     echo str_pad($perm, $max_length + 4, ' ') . "=> " . $detail['description'] . " " . PHP_EOL;
40 |     echo str_pad(
41 |         '',
42 |         $max_length - 5,
43 |         ' '
44 |     ) . ' cost    =>  ' . ($detail['flags']['cost'] ? 'true' : 'false') . " " . PHP_EOL;
45 |     echo str_pad(
46 |         '',
47 |         $max_length - 5,
48 |         ' '
49 |     ) . ' warning =>  ' . ($detail['flags']['warning'] ? 'true' : 'false') . " " . PHP_EOL;
50 |     echo str_pad(
51 |         '',
52 |         $max_length - 5,
53 |         ' '
54 |     ) . ' danger  =>  ' . ($detail['flags']['danger'] ? 'true' : 'false') . " " . PHP_EOL;
55 | }
56 | 
57 | 
58 | echo PHP_EOL;
59 | echo "------------- Activities  -------------" . PHP_EOL;
60 | foreach ($apk->getManifest()->getApplication()->activities as $activity) {
61 |     echo $activity->name . ($activity->isLauncher ? ' (Launcher)' : null) . PHP_EOL;
62 | }
63 | 
64 | echo PHP_EOL;
65 | echo "------------- All Classes List -------------" . PHP_EOL;
66 | foreach ($apk->getClasses() as $className) {
67 |     echo $className . PHP_EOL;
68 | }
69 | 


--------------------------------------------------------------------------------
/examples/ApkResource.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | include 'autoload.php';
13 | $apk = new \ApkParser\Parser('vitrinova.apk', ['manifest_only' => false]);
14 | $resourceId = $apk->getManifest()->getApplication()->getIcon();
15 | $resources = $apk->getResources($resourceId);
16 | 
17 | $labelResourceId = $apk->getManifest()->getApplication()->getLabel();
18 | $appLabel = $apk->getResources($labelResourceId);
19 | echo $appLabel[0];
20 | 
21 | header('Content-type: text/html');
22 | echo $appLabel[0] . '
'; 23 | foreach ($resources as $resource) { 24 | echo ''; 25 | } 26 | -------------------------------------------------------------------------------- /examples/EBHS.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tufanbarisyildirim/php-apk-parser/d482e460d540a16565fa9d1d70bb4c2292821c7c/examples/EBHS.apk -------------------------------------------------------------------------------- /examples/PrintManifestXml.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | include 'autoload.php'; 12 | 13 | $apk = new ApkParser\Parser('EBHS.apk'); 14 | 15 | header("Content-Type:text/xml;Charset=UTF-8"); 16 | echo $apk->getManifest()->getXmlString(); 17 | -------------------------------------------------------------------------------- /examples/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | // Test purpose 13 | require_once __DIR__ . '/../vendor/autoload.php'; 14 | 15 | //spl_autoload_register(function ($className) { 16 | // Fix for OSX and *nix 17 | // $className = str_replace('\\', DIRECTORY_SEPARATOR, $className); 18 | // include(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . $className . ".php"); 19 | //}); 20 | -------------------------------------------------------------------------------- /examples/rsa.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Activity 14 | { 15 | public $label; 16 | public $name; 17 | 18 | /** 19 | * @var \ApkParser\IntentFilter[] $filters 20 | */ 21 | public $filters = array(); 22 | 23 | 24 | public $isLauncher = false; 25 | 26 | 27 | /** 28 | * @param ManifestXmlElement $actXml 29 | */ 30 | public function __construct(ManifestXmlElement $actXml) 31 | { 32 | $actArray = get_object_vars($actXml); 33 | $attrs = $actArray['@attributes']; 34 | $this->setName(isset($attrs['name']) ? $attrs['name'] : null); 35 | $this->setLabel(isset($attrs['label']) ? $attrs['label'] : null); 36 | 37 | if (isset($actArray['intent-filter'])) { 38 | if (!is_array($actArray['intent-filter'])) { 39 | $actArray['intent-filter'] = array($actArray['intent-filter']); 40 | } 41 | 42 | foreach ($actArray['intent-filter'] as $filterXml) { 43 | $this->filters[] = new IntentFilter($filterXml); 44 | } 45 | } 46 | 47 | foreach ($this->filters as $filter) { 48 | if (($filter->actions != null && in_array('MAIN', $filter->actions)) && 49 | ($filter->categories != null && in_array('LAUNCHER', $filter->categories)) 50 | ) { 51 | $this->isLauncher = true; 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * @return mixed 58 | */ 59 | public function getLabel() 60 | { 61 | return $this->label; 62 | } 63 | 64 | /** 65 | * @param $label 66 | */ 67 | public function setLabel($label) 68 | { 69 | $this->label = $label; 70 | } 71 | 72 | /** 73 | * @return mixed 74 | */ 75 | public function getName() 76 | { 77 | return $this->name; 78 | } 79 | 80 | /** 81 | * @param $name 82 | */ 83 | public function setName($name) 84 | { 85 | $this->name = $name; 86 | } 87 | 88 | /** 89 | * @return IntentFilter[] 90 | */ 91 | public function getFilters() 92 | { 93 | return $this->filters; // we may need an intent-filter class 94 | } 95 | 96 | /** 97 | * @param array $filters 98 | */ 99 | public function setFilters(array $filters) 100 | { 101 | $this->filters = $filters; 102 | } 103 | 104 | /** 105 | * @return boolean 106 | */ 107 | public function isLauncher() 108 | { 109 | return $this->isLauncher; 110 | } 111 | 112 | /** 113 | * @param boolean $isLauncher 114 | */ 115 | public function setIsLauncher($isLauncher) 116 | { 117 | $this->isLauncher = $isLauncher; 118 | } 119 | 120 | /** 121 | * @return boolean 122 | */ 123 | public function isIsLauncher() 124 | { 125 | return $this->isLauncher; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/ApkParser/AndroidPlatform.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | 14 | // Android Api Version Codes 15 | define('ANDROID_API_BASE', 1); 16 | define('ANDROID_API_BASE_1_1', 2); 17 | define('ANDROID_API_CUPCAKE', 3); 18 | define('ANDROID_API_DONUT', 4); 19 | define('ANDROID_API_ECLAIR', 5); 20 | define('ANDROID_API_ECLAIR_0_1', 6); 21 | define('ANDROID_API_ECLAIR_MR1', 7); 22 | define('ANDROID_API_FROYO', 8); 23 | define('ANDROID_API_GINGERBREAD', 9); 24 | define('ANDROID_API_GINGERBREAD_MR1', 10); 25 | define('ANDROID_API_HONEYCOMB', 11); 26 | define('ANDROID_API_HONEYCOMB_MR1', 12); 27 | define('ANDROID_API_HONEYCOMB_MR2', 13); 28 | define('ANDROID_API_ICE_CREAM_SANDWICH', 14); 29 | define('ANDROID_API_ICE_CREAM_SANDWICH_MR1', 15); 30 | define('ANDROID_API_ICE_JELLY_BEAN', 16); 31 | define('ANDROID_API_ICE_JELLY_BEAN_MR1', 17); 32 | define('ANDROID_API_ICE_JELLY_BEAN_MR2', 18); 33 | define('ANDROID_API_KITKAT', 19); 34 | define('ANDROID_API_KITKAT_WATCH', 20); 35 | define('ANDROID_API_LOLLIPOP', 21); 36 | define('ANDROID_API_LOLLIPOP_MR1', 22); 37 | define('ANDROID_API_M', 23); 38 | define('ANDROID_API_NOUGAT', 24); 39 | define('ANDROID_API_NOUGAT_MR1', 25); 40 | define('ANDROID_API_OREO', 26); 41 | define('ANDROID_API_OREO_MR1', 27); 42 | define('ANDROID_API_PIE', 28); 43 | define('ANDROID_API_Q', 29); 44 | define('ANDROID_API_R', 30); 45 | define('ANDROID_API_S', 31); 46 | define('ANDROID_API_S_12L', 32); 47 | define('ANDROID_API_TIRAMISU', 33); 48 | define('ANDROID_API_UPSIDE_DOWN_CAKE', 34); 49 | 50 | 51 | /** 52 | * 53 | * @property $level 54 | * @property $versions array 55 | * @property $url string 56 | * @property $platform 57 | */ 58 | class AndroidPlatform 59 | { 60 | private static $platforms = array( 61 | /** 62 | * @link http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels 63 | * @link http://developer.android.com/about/dashboards/index.html 64 | */ 65 | 0 => array('versions' => array('Undefined'), 'url' => 'Undefined'), 66 | ANDROID_API_BASE => array('versions' => array('1.0'), 'url' => 'http://developer.android.com/reference/android/os/Build.VERSION_CODES.html#BASE'), 67 | ANDROID_API_BASE_1_1 => array('versions' => array('1.1'), 'url' => 'http://developer.android.com/about/versions/android-1.1.html'), 68 | ANDROID_API_CUPCAKE => array('versions' => array('1.5'), 'url' => 'http://developer.android.com/about/versions/android-1.5.html'), 69 | ANDROID_API_DONUT => array('versions' => array('1.6'), 'url' => 'http://developer.android.com/about/versions/android-1.6.html'), 70 | ANDROID_API_ECLAIR => array('versions' => array('2.0'), 'url' => 'http://developer.android.com/about/versions/android-2.0.html'), 71 | ANDROID_API_ECLAIR_0_1 => array('versions' => array('2.0.1'), 'url' => 'http://developer.android.com/about/versions/android-2.0.1.html'), 72 | ANDROID_API_ECLAIR_MR1 => array('versions' => array('2.1.x'), 'url' => 'http://developer.android.com/about/versions/android-2.1.html'), 73 | ANDROID_API_FROYO => array('versions' => array('2.2.x'), 'url' => 'http://developer.android.com/about/versions/android-2.2.html'), 74 | ANDROID_API_GINGERBREAD => array('versions' => array('2.3', '2.3.1', '2.3.2'), 'url' => 'http://developer.android.com/about/versions/android-2.3.html'), 75 | ANDROID_API_GINGERBREAD_MR1 => array('versions' => array('2.3.3', '2.3.4'), 'url' => 'http://developer.android.com/about/versions/android-2.3.3.html'), 76 | ANDROID_API_HONEYCOMB => array('versions' => array('3.0.x'), 'url' => 'http://developer.android.com/about/versions/android-3.0.html'), 77 | ANDROID_API_HONEYCOMB_MR1 => array('versions' => array('3.1.x'), 'url' => 'http://developer.android.com/about/versions/android-3.1.html'), 78 | ANDROID_API_HONEYCOMB_MR2 => array('versions' => array('3.2'), 'url' => 'http://developer.android.com/about/versions/android-3.2.html'), 79 | ANDROID_API_ICE_CREAM_SANDWICH => array('versions' => array('4.0', '4.0.1', '4.0.2'), 'url' => 'http://developer.android.com/about/versions/android-4.0.html'), 80 | ANDROID_API_ICE_CREAM_SANDWICH_MR1 => array('versions' => array('4.0.3', '4.0.4'), 'url' => 'http://developer.android.com/about/versions/android-4.0.3.html'), 81 | ANDROID_API_ICE_JELLY_BEAN => array('versions' => array('4.1', '4.1.1'), 'url' => 'http://developer.android.com/about/versions/android-4.1.html'), 82 | ANDROID_API_ICE_JELLY_BEAN_MR1 => array('versions' => array('4.2', '4.2.2'), 'url' => 'http://developer.android.com/about/versions/android-4.2.html'), 83 | ANDROID_API_ICE_JELLY_BEAN_MR2 => array('versions' => array('4.3'), 'url' => 'http://developer.android.com/about/versions/android-4.3.html'), 84 | ANDROID_API_KITKAT => array('versions' => array('4.4'), 'url' => 'http://developer.android.com/about/versions/android-4.4.html'), 85 | ANDROID_API_KITKAT_WATCH => array('versions' => array('4.4W'), 'url' => 'http://developer.android.com/training/building-wearables.html'), 86 | ANDROID_API_LOLLIPOP => array('versions' => array('5.0'), 'url' => 'http://developer.android.com/about/versions/android-5.0.html'), 87 | ANDROID_API_LOLLIPOP_MR1 => array('versions' => array('5.1'), 'url' => 'http://developer.android.com/about/versions/android-5.1.html'), 88 | ANDROID_API_M => array('versions' => array('6.0'), 'url' => 'http://developer.android.com/sdk/api_diff/23/changes.html'), 89 | ANDROID_API_NOUGAT => array('versions' => array('7.0'), 'url' => 'https://developer.android.com/about/versions/nougat/android-7.0'), 90 | ANDROID_API_NOUGAT_MR1 => array('versions' => array('7.1'), 'url' => 'https://developer.android.com/about/versions/nougat/android-7.1'), 91 | ANDROID_API_OREO => array('versions' => array('8.0'), 'url' => 'https://developer.android.com/about/versions/oreo/android-8.0'), 92 | ANDROID_API_OREO_MR1 => array('versions' => array('8.1'), 'url' => 'https://developer.android.com/about/versions/oreo/android-8.1'), 93 | ANDROID_API_PIE => array('versions' => array('9.0'), 'url' => 'https://developer.android.com/about/versions/pie/android-9.0'), 94 | ANDROID_API_Q => array('versions' => array('10.0'), 'url' => 'https://developer.android.com/about/versions/10/features'), 95 | ANDROID_API_R => array('versions' => array('11.0'), 'url' => 'https://developer.android.com/about/versions/11/features'), 96 | ANDROID_API_S => array('versions' => array('12.0'), 'url' => 'https://developer.android.com/about/versions/12/features'), 97 | ANDROID_API_S_12L => array('versions' => array('12.0'), 'url' => 'https://developer.android.com/about/versions/12/features'), 98 | ANDROID_API_TIRAMISU => array('versions' => array('13.0'), 'url' => 'https://developer.android.com/about/versions/13/features'), 99 | ANDROID_API_UPSIDE_DOWN_CAKE => array('versions' => array('14.0'), 'url' => 'https://developer.android.com/about/versions/14/features') 100 | ); 101 | 102 | public $level = null; 103 | 104 | /** 105 | * use a constant with ANDROID_API prefix like ANDROID_API_JELLY_BEAN 106 | * 107 | * @param mixed $apiLevel 108 | * @throws \Exception 109 | */ 110 | 111 | public function __construct($apiLevel) 112 | { 113 | if (!isset(self::$platforms[$apiLevel])) { 114 | throw new \Exception("Unknown Api Level: " . $apiLevel); 115 | } 116 | 117 | $this->setLevel($apiLevel); 118 | } 119 | 120 | public static function fromVersion($v) 121 | { 122 | foreach (self::$platforms as $apiLevel => $p) { 123 | if (in_array($v, $p['versions'])) { 124 | return new self($apiLevel); 125 | } 126 | } 127 | 128 | return null; 129 | } 130 | 131 | public function __get($var) 132 | { 133 | switch ($var) { 134 | case 'platform': 135 | return 'Android ' . implode(',', self::$platforms[$this->level]['versions']); 136 | break; 137 | default: 138 | return self::$platforms[$this->level][$var]; 139 | break; 140 | } 141 | } 142 | 143 | /** 144 | * @return mixed|null 145 | */ 146 | public function getLevel() 147 | { 148 | return $this->level; 149 | } 150 | 151 | /** 152 | * @param mixed|null $level 153 | */ 154 | public function setLevel($level) 155 | { 156 | $this->level = $level; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /lib/ApkParser/Application.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Application 14 | { 15 | /** 16 | * @var \ApkParser\Activity[] 17 | */ 18 | public $activities = array(); 19 | 20 | /** 21 | * @var ManifestXmlElement 22 | */ 23 | private $application; 24 | 25 | public function __construct(ManifestXmlElement $application) 26 | { 27 | $this->application = $application; 28 | 29 | foreach ($application->activity as $actXml) { 30 | $this->activities[] = new Activity($actXml); 31 | } 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getIcon() 38 | { 39 | return $this->getAttr('icon'); 40 | } 41 | 42 | /** 43 | * @param $attrName 44 | * @return string 45 | */ 46 | public function getAttr($attrName) 47 | { 48 | $attr = get_object_vars($this->application); 49 | return isset($attr['@attributes']) && isset($attr['@attributes'][$attrName]) ? (string)$attr['@attributes'][$attrName] : null; 50 | } 51 | 52 | /** 53 | * @return string 54 | */ 55 | public function getLabel() 56 | { 57 | return $this->getAttr('label'); 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getActivityHash() 64 | { 65 | return md5(implode('', $this->getActivityNameList())); 66 | } 67 | 68 | /** 69 | * @return array 70 | */ 71 | public function getActivityNameList() 72 | { 73 | $names = array(); 74 | 75 | foreach ($this->activities as $act) { 76 | $names[] = trim($act->getName(), '.'); 77 | } 78 | 79 | return $names; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/ApkParser/Archive.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Archive extends \ZipArchive 14 | { 15 | /** 16 | * @var string 17 | */ 18 | private $filePath; 19 | 20 | /** 21 | * @var string 22 | */ 23 | private $fileName; 24 | 25 | 26 | /** 27 | * @param bool|string $file 28 | * @throws \Exception 29 | */ 30 | public function __construct(string|bool $file = false) 31 | { 32 | if ($file && is_file($file)) { 33 | $this->open($file); 34 | $this->fileName = basename($this->filePath = $file); 35 | } else { 36 | throw new \Exception($file . " not a regular file"); 37 | } 38 | } 39 | 40 | /** 41 | * Get a file from apk Archive by name. 42 | * 43 | * @param string $name 44 | * @param int|null $length 45 | * @param int|null $flags 46 | * @return string|false 47 | * @throws \Exception 48 | */ 49 | public function getFromName(string $name, int $length = null, int $flags = null): string|false 50 | { 51 | if (strtolower(substr($name, -4)) == '.xml') { 52 | $xmlParser = new XmlParser(new Stream($this->getStream($name))); 53 | return $xmlParser->getXmlString(); 54 | } else { 55 | return parent::getFromName($name, $length, $flags); 56 | } 57 | } 58 | 59 | /** 60 | * Returns an ApkStream which contains AndroidManifest.xml 61 | * @return Stream 62 | */ 63 | public function getManifestStream(): Stream 64 | { 65 | return new Stream($this->getStream('AndroidManifest.xml')); 66 | } 67 | 68 | /** 69 | * @return SeekableStream 70 | */ 71 | public function getResourcesStream(): SeekableStream 72 | { 73 | return new SeekableStream($this->getStream('resources.arsc')); 74 | } 75 | 76 | /** 77 | * Returns an \ApkParser\Stream instance which contains classes.dex file 78 | * @returns Stream 79 | * @throws \Exception 80 | */ 81 | public function getClassesDexStream(): Stream 82 | { 83 | return new Stream($this->getStream('classes.dex')); 84 | } 85 | 86 | /** 87 | * Apk file path. 88 | * @return bool|string 89 | */ 90 | public function getApkPath(): bool|string 91 | { 92 | return $this->filePath; 93 | } 94 | 95 | /** 96 | * Apk file name 97 | * @return string 98 | */ 99 | public function getApkName(): string 100 | { 101 | return $this->fileName; 102 | } 103 | 104 | 105 | /** 106 | * @param string $pathto 107 | * @param array|string|null $files 108 | * @return bool 109 | * @throws \Exception 110 | */ 111 | public function extractTo(string $pathto, array|string|null $files = null): bool 112 | { 113 | if ($extResult = parent::extractTo($pathto, $files)) { 114 | $xmlFiles = Utils::globRecursive($pathto . '/*.xml'); 115 | 116 | foreach ($xmlFiles as $xmlFile) { 117 | if ($xmlFile == ($pathto . "/AndroidManifest.xml")) { 118 | XmlParser::decompressFile($xmlFile); 119 | } 120 | } 121 | } 122 | 123 | return $extResult; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/ApkParser/Config.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace ApkParser; 12 | 13 | /** 14 | * Class Config 15 | * @package ApkParser 16 | * @property $tmp_path string 17 | * @property $jar_path string 18 | * @property $manifest_only boolean 19 | */ 20 | class Config 21 | { 22 | /** 23 | * @var array 24 | */ 25 | private $config; 26 | 27 | /** 28 | * @param array $config 29 | */ 30 | public function __construct(array $config = []) 31 | { 32 | $this->config = array_merge( 33 | [ 34 | 'tmp_path' => sys_get_temp_dir(), 35 | 'jar_path' => __DIR__ . '/Dex/dedexer.jar', 36 | 'manifest_only' => true 37 | ], 38 | $config 39 | ); 40 | } 41 | 42 | /** 43 | * @param $key 44 | * @return mixed 45 | */ 46 | public function get($key) 47 | { 48 | return $this->config[$key]; 49 | } 50 | 51 | /** 52 | * @param $key 53 | * @return mixed 54 | */ 55 | public function __get($key) 56 | { 57 | return $this->config[$key]; 58 | } 59 | 60 | /** 61 | * @param $name 62 | * @param $value 63 | * @return mixed 64 | * @internal param $key 65 | */ 66 | public function __set($name, $value) 67 | { 68 | return $this->config[$name] = $value; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/ApkParser/Dex/dedexer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tufanbarisyildirim/php-apk-parser/d482e460d540a16565fa9d1d70bb4c2292821c7c/lib/ApkParser/Dex/dedexer.jar -------------------------------------------------------------------------------- /lib/ApkParser/Exceptions/ApkException.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class ApkException extends \Exception 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /lib/ApkParser/Exceptions/FileNotFoundException.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class FileNotFoundException extends ApkException 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /lib/ApkParser/Exceptions/StreamNotFoundException.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class StreamNotFoundException extends ApkException 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /lib/ApkParser/Exceptions/XmlParserException.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class XmlParserException extends ApkException 14 | { 15 | /** 16 | * @var \LibXMLError[] 17 | */ 18 | private $xmlErrors; 19 | 20 | /** 21 | * XmlParserException constructor. 22 | * @param $xmlstr 23 | */ 24 | public function __construct($xmlstr) 25 | { 26 | $this->xmlErrors = libxml_get_errors(); 27 | $xml = explode("\n", $xmlstr); 28 | $message = ""; 29 | foreach ($this->xmlErrors as $error) { 30 | $message .= $this->display_xml_error($error, $xml); 31 | } 32 | 33 | libxml_clear_errors(); 34 | 35 | parent::__construct($message); 36 | } 37 | 38 | /** 39 | * Borrowed from http://php.net/manual/en/function.libxml-get-errors.php 40 | * 41 | * @param \LibXMLError $error 42 | * @param string $xml 43 | * @return string 44 | */ 45 | private function display_xml_error(\LibXMLError $error, $xml) 46 | { 47 | $return = $xml[$error->line - 1] . "\n"; 48 | $return .= str_repeat('-', $error->column) . "^\n"; 49 | 50 | switch ($error->level) { 51 | case LIBXML_ERR_WARNING: 52 | $return .= "Warning $error->code: "; 53 | break; 54 | case LIBXML_ERR_ERROR: 55 | $return .= "Error $error->code: "; 56 | break; 57 | case LIBXML_ERR_FATAL: 58 | $return .= "Fatal Error $error->code: "; 59 | break; 60 | } 61 | 62 | $return .= trim($error->message) . 63 | "\n Line: $error->line" . 64 | "\n Column: $error->column"; 65 | 66 | if ($error->file) { 67 | $return .= "\n File: $error->file"; 68 | } 69 | 70 | return "$return\n"; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/ApkParser/IntentFilter.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class IntentFilter 14 | { 15 | public $actions = array(); 16 | public $categories = array(); 17 | 18 | 19 | /** 20 | * @param ManifestXmlElement $filterXml 21 | */ 22 | public function __construct(ManifestXmlElement $filterXml) 23 | { 24 | $filterArray = get_object_vars($filterXml); 25 | 26 | 27 | if (isset($filterArray['action'])) { 28 | if (!is_array($filterArray['action'])) { 29 | $filterArray['action'] = array($filterArray['action']); 30 | } 31 | 32 | foreach ($filterArray['action'] as $act) { 33 | $actionElement = get_object_vars($act); 34 | $actionNameSections = explode('.', $actionElement['@attributes']['name']); 35 | $this->actions[] = end($actionNameSections); 36 | } 37 | } 38 | 39 | if (isset($filterArray['category'])) { 40 | if (!is_array($filterArray['category'])) { 41 | $filterArray['category'] = array($filterArray['category']); 42 | } 43 | 44 | 45 | foreach ($filterArray['category'] as $cat) { 46 | $categoryElement = get_object_vars($cat); 47 | $categoryNameSections = explode('.', $categoryElement['@attributes']['name']); 48 | $this->categories[] = end($categoryNameSections); 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * @return mixed 55 | */ 56 | public function getActions() 57 | { 58 | return $this->actions; 59 | } 60 | 61 | /** 62 | * @param mixed $actions 63 | */ 64 | public function setActions($actions) 65 | { 66 | $this->actions = $actions; 67 | } 68 | 69 | /** 70 | * @return mixed 71 | */ 72 | public function getCategories() 73 | { 74 | return $this->categories; 75 | } 76 | 77 | /** 78 | * @param mixed $categories 79 | */ 80 | public function setCategories($categories) 81 | { 82 | $this->categories = $categories; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/ApkParser/Manifest.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Manifest extends Xml 14 | { 15 | /** 16 | * Android Permissions list 17 | * @see http://developer.android.com/reference/android/Manifest.permission.html 18 | * 19 | * @todo: Move to {lang}_perms.php file, for easy translations. 20 | * @var mixed 21 | */ 22 | public static $permissions = array( 23 | 'ACCESS_CHECKIN_PROPERTIES' => 'Allows read/write access to the "properties" table in the checkin database, to change values that get uploaded.', 24 | 'ACCESS_COARSE_LOCATION' => 'Allows an app to access approximate location derived from network location sources such as cell towers and Wi-Fi.', 25 | 'ACCESS_FINE_LOCATION' => 'Allows an app to access precise location from location sources such as GPS, cell towers, and Wi-Fi.', 26 | 'ACCESS_LOCATION_EXTRA_COMMANDS' => 'Allows an application to access extra location provider commands.', 27 | 'ACCESS_MOCK_LOCATION' => 'Allows an application to create mock location providers for testing.', 28 | 'ACCESS_NETWORK_STATE' => 'Allows applications to access information about networks.', 29 | 'ACCESS_NOTIFICATION_POLICY' => 'Marker permission for applications that wish to access notification policy.', 30 | 'ACCESS_SURFACE_FLINGER' => 'Allows an application to use SurfaceFlinger\'s low level features.', 31 | 'ACCESS_WIFI_STATE' => 'Allows applications to access information about Wi-Fi networks', 32 | 'ACCOUNT_MANAGER' => 'Allows applications to call into AccountAuthenticators.', 33 | 'ADD_VOICEMAIL' => 'Allows an application to add voicemails into the system.', 34 | 'AUTHENTICATE_ACCOUNTS' => 'Allows an application to act as an AccountAuthenticator for the AccountManager.', 35 | 'BATTERY_STATS' => 'Allows an application to collect battery statistics.', 36 | 'BIND_ACCESSIBILITY_SERVICE' => 'Must be required by an AccessibilityService,to ensure that only the system can bind to it.', 37 | 'BIND_APPWIDGET' => 'Allows an application to tell the AppWidget service which application can access AppWidget\'s data.', 38 | 'BIND_CARRIER_MESSAGING_SERVICE' => 'The system process that is allowed to bind to services in carrier apps will have this permission. Carrier apps should use this permission to protect their services that only the system is allowed to bind to.', 39 | 'BIND_CARRIER_SERVICES' => 'The system process that is allowed to bind to services in carrier apps will have this permission. Carrier apps should use this permission to protect their services that only the system is allowed to bind to.', 40 | 'BIND_CHOOSER_TARGET_SERVICE' => 'Must be required by a ChooserTargetService, to ensure that only the system can bind to it.', 41 | 'BIND_DEVICE_ADMIN' => 'Must be required by device administration receiver, to ensure that only the system can interact with it.', 42 | 'BIND_DREAM_SERVICE' => 'Must be required by an DreamService, to ensure that only the system can bind to it.', 43 | 'BIND_INCALL_SERVICE' => 'Must be required by a InCallService, to ensure that only the system can bind to it.', 44 | 'BIND_INPUT_METHOD' => 'Must be required by an InputMethodService, to ensure that only the system can bind to it.', 45 | 'BIND_MIDI_DEVICE_SERVICE' => 'Must be required by an MidiDeviceService, to ensure that only the system can bind to it.', 46 | 'BIND_NFC_SERVICE' => 'Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it.', 47 | 'BIND_NOTIFICATION_LISTENER_SERVICE' => 'Must be required by an NotificationListenerService, to ensure that only the system can bind to it.', 48 | 'BIND_PRINT_SERVICE' => 'Must be required by a PrintService, to ensure that only the system can bind to it.', 49 | 'BIND_REMOTEVIEWS' => 'Must be required by a RemoteViewsService, to ensure that only the system can bind to it.', 50 | 'BIND_TELECOM_CONNECTION_SERVICE' => 'Must be required by a ConnectionService, to ensure that only the system can bind to it.', 51 | 'BIND_TEXT_SERVICE' => 'Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it.', 52 | 'BIND_TV_INPUT' => 'Must be required by a TvInputService to ensure that only the system can bind to it.', 53 | 'BIND_VOICE_INTERACTION' => 'Must be required by a VoiceInteractionService, to ensure that only the system can bind to it.', 54 | 'BIND_VPN_SERVICE' => 'Must be required by a VpnService, to ensure that only the system can bind to it.', 55 | 'BIND_WALLPAPER' => 'Must be required by a WallpaperService, to ensure that only the system can bind to it.', 56 | 'BLUETOOTH' => 'Allows applications to connect to paired bluetooth devices.', 57 | 'BLUETOOTH_ADMIN' => 'Allows applications to discover and pair bluetooth devices.', 58 | 'BLUETOOTH_PRIVILEGED' => 'Allows applications to pair bluetooth devices without user interaction.', 59 | 'BODY_SENSORS' => 'Allows an application to access data from sensors that the user uses to measure what is happening inside his/her body, such as heart rate.', 60 | 'BRICK' => 'Required to be able to disable the device (very dangerous!).', 61 | 'BROADCAST_PACKAGE_REMOVED' => 'Allows an application to broadcast a notification that an application package has been removed.', 62 | 'BROADCAST_SMS' => 'Allows an application to broadcast an SMS receipt notification.', 63 | 'BROADCAST_STICKY' => 'Allows an application to broadcast sticky intents.', 64 | 'BROADCAST_WAP_PUSH' => 'Allows an application to broadcast a WAP PUSH receipt notification.', 65 | 'CALL_PHONE' => 'Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call being placed.', 66 | 'CALL_PRIVILEGED' => 'Allows an application to call any phone number, including emergency numbers, without going through the Dialer user interface for the user to confirm the call being placed.', 67 | 'CAMERA' => 'Required to be able to access the camera device.', 68 | 'CAPTURE_AUDIO_OUTPUT' => 'Allows an application to capture audio output.', 69 | 'CAPTURE_SECURE_VIDEO_OUTPUT' => 'Allows an application to capture secure video output.', 70 | 'CAPTURE_VIDEO_OUTPUT' => 'Allows an application to capture video output.', 71 | 'CHANGE_COMPONENT_ENABLED_STATE' => 'Allows an application to change whether an application component (other than its own) is enabled or not.', 72 | 'CHANGE_CONFIGURATION' => 'Allows an application to modify the current configuration, such as locale.', 73 | 'CHANGE_NETWORK_STATE' => 'Allows applications to change network connectivity state.', 74 | 'CHANGE_WIFI_MULTICAST_STATE' => 'Allows applications to enter Wi-Fi Multicast mode.', 75 | 'CHANGE_WIFI_STATE' => 'Allows applications to change Wi-Fi connectivity state.', 76 | 'CLEAR_APP_CACHE' => 'Allows an application to clear the caches of all installed applications on the device.', 77 | 'CLEAR_APP_USER_DATA' => 'Allows an application to clear user data.', 78 | 'CONTROL_LOCATION_UPDATES' => 'Allows enabling/disabling location update notifications from the radio.', 79 | 'DELETE_CACHE_FILES' => 'Allows an application to delete cache files.', 80 | 'DELETE_PACKAGES' => 'Allows an application to delete packages.', 81 | 'DEVICE_POWER' => 'Allows low-level access to power management.', 82 | 'DIAGNOSTIC' => 'Allows applications to RW to diagnostic resources.', 83 | 'DISABLE_KEYGUARD' => 'Allows applications to disable the keyguard.', 84 | 'DUMP' => 'Allows an application to retrieve state dump information from system services.', 85 | 'EXPAND_STATUS_BAR' => 'Allows an application to expand or collapse the status bar.', 86 | 'FACTORY_TEST' => 'Run as a manufacturer test application, running as the root user.', 87 | 'FLASHLIGHT' => 'Allows access to the flashlight.', 88 | 'FORCE_BACK' => 'Allows an application to force a BACK operation on whatever is the top activity.', 89 | 'GET_ACCOUNTS' => 'Allows access to the list of accounts in the Accounts Service.', 90 | 'GET_ACCOUNTS_PRIVILEGED' => 'Allows access to the list of accounts in the Accounts Service.', 91 | 'GET_PACKAGE_SIZE' => 'Allows an application to find out the space used by any package.', 92 | 'GET_TASKS' => 'Allows an application to get information about the currently or recently running tasks.', 93 | 'GET_TOP_ACTIVITY_INFO' => 'Allows an application to retrieve private information about the current top activity, such as any assist context it can provide.', 94 | 'GLOBAL_SEARCH' => 'This permission can be used on content providers to allow the global search system to access their data.', 95 | 'HARDWARE_TEST' => 'Allows access to hardware peripherals.', 96 | 'INJECT_EVENTS' => 'Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window.', 97 | 'INSTALL_LOCATION_PROVIDER' => 'Allows an application to install a location provider into the Location Manager.', 98 | 'INSTALL_PACKAGES' => 'Allows an application to install packages.', 99 | 'INSTALL_SHORTCUT' => 'Allows an application to install a shortcut in Launcher.', 100 | 'INTERNAL_SYSTEM_WINDOW' => 'Allows an application to open windows that are for use by parts of the system user interface.', 101 | 'INTERNET' => 'Allows applications to open network sockets.', 102 | 'KILL_BACKGROUND_PROCESSES' => 'Allows an application to call killBackgroundProcesses(String).', 103 | 'LOCATION_HARDWARE' => 'Allows an application to use location features in hardware, such as the geofencing api.', 104 | 'MANAGE_ACCOUNTS' => 'Allows an application to manage the list of accounts in the AccountManager.', 105 | 'MANAGE_APP_TOKENS' => 'Allows an application to manage (create, destroy, Z-order) application tokens in the window manager.', 106 | 'MANAGE_DOCUMENTS' => 'Allows an application to manage access to documents, usually as part of a document picker.', 107 | 'MASTER_CLEAR' => 'Not for use by third-party applications.', 108 | 'MEDIA_CONTENT_CONTROL' => 'Allows an application to know what content is playing and control its playback.', 109 | 'MODIFY_AUDIO_SETTINGS' => 'Allows an application to modify global audio setting.s.', 110 | 'MODIFY_PHONE_STATE' => 'Allows modification of the telephony state - power on, mmi, etc.', 111 | 'MOUNT_FORMAT_FILESYSTEMS' => 'Allows formatting file systems for removable storage.', 112 | 'MOUNT_UNMOUNT_FILESYSTEMS' => 'Allows mounting and unmounting file systems for removable storage.', 113 | 'NFC' => 'Allows applications to perform I/O operations over NFC.', 114 | 'PACKAGE_USAGE_STATS' => 'Allows an application to collect component usage statistics.', 115 | 'PERSISTENT_ACTIVITY' => 'This constant was deprecated in API level 9. This functionality will be removed in the future; please do not use. Allow an application to make its activities persistent.', 116 | 'PROCESS_OUTGOING_CALLS' => 'Allows an application to monitor, modify, or abort outgoing calls.', 117 | 'READ_CALENDAR' => 'Allows an application to read the user\'s calendar data.', 118 | 'READ_CALL_LOG' => 'Allows an application to read the user\'s call log.', 119 | 'READ_CONTACTS' => 'Allows an application to read the user\'s contacts data.', 120 | 'READ_EXTERNAL_STORAGE' => 'Allows an application to read from external storage.', 121 | 'READ_FRAME_BUFFER' => 'Allows an application to take screen shots and more generally get access to the frame buffer data.', 122 | 'READ_HISTORY_BOOKMARKS' => 'Allows an application to read (but not write) the user\'s browsing history and bookmarks.', 123 | 'READ_INPUT_STATE' => 'This constant was deprecated in API level 16. The API that used this permission has been removed.', 124 | 'READ_LOGS' => 'Allows an application to read the low-level system log files.', 125 | 'READ_PHONE_STATE' => 'Allows read only access to phone state.', 126 | 'READ_PROFILE' => 'Allows an application to read the user\'s personal profile data.', 127 | 'READ_SMS' => 'Allows an application to read SMS messages.', 128 | 'READ_SOCIAL_STREAM' => 'Allows an application to read from the user\'s social stream.', 129 | 'READ_SYNC_SETTINGS' => 'Allows applications to read the sync settings.', 130 | 'READ_SYNC_STATS' => 'Allows applications to read the sync stats.', 131 | 'READ_USER_DICTIONARY' => 'Allows an application to read the user dictionary.', 132 | 'READ_VOICEMAIL' => 'Allows an application to read voicemails in the system.', 133 | 'REBOOT' => 'Required to be able to reboot the device.', 134 | 'RECEIVE_BOOT_COMPLETED' => 'Allows an application to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting.', 135 | 'RECEIVE_MMS' => 'Allows an application to monitor incoming MMS messages, to record or perform processing on them.', 136 | 'RECEIVE_SMS' => 'Allows an application to monitor incoming SMS messages, to record or perform processing on them.', 137 | 'RECEIVE_WAP_PUSH' => 'Allows an application to monitor incoming WAP push messages.', 138 | 'RECORD_AUDIO' => 'Allows an application to record audio.', 139 | 'REORDER_TASKS' => 'Allows an application to change the Z-order of tasks', 140 | 'REQUEST_IGNORE_BATTERY_OPTIMIZATIONS' => 'Permission an application must hold in order to use ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. This is a normal permission: an app requesting it will always be granted the permission, without the user needing to approve or see it', 141 | 'REQUEST_INSTALL_PACKAGES' => 'Allows an application to request installing packages. Apps targeting APIs greater than 25 must hold this permission in order to use ACTION_INSTALL_PACKAGE', 142 | 'RESTART_PACKAGES' => 'This constant was deprecated in API level 8. The restartPackage(String) API is no longer supported.', 143 | 'SEND_RESPOND_VIA_MESSAGE' => 'Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls.', 144 | 'SEND_SMS' => 'Allows an application to send SMS messages.', 145 | 'SET_ACTIVITY_WATCHER' => 'Allows an application to watch and control how activities are started globally in the system.', 146 | 'SET_ALARM' => 'Allows an application to broadcast an Intent to set an alarm for the user.', 147 | 'SET_ALWAYS_FINISH' => 'Allows an application to control whether activities are immediately finished when put in the background.', 148 | 'SET_ANIMATION_SCALE' => 'Modify the global animation scaling factor.', 149 | 'SET_DEBUG_APP' => 'Configure an application for debugging.', 150 | 'SET_ORIENTATION' => 'Allows low-level access to setting the orientation (actually rotation) of the screen.', 151 | 'SET_POINTER_SPEED' => 'Allows low-level access to setting the pointer speed.', 152 | 'SET_PREFERRED_APPLICATIONS' => 'This constant was deprecated in API level 7. No longer useful, see addPackageToPreferred(String) for details.', 153 | 'SET_PROCESS_LIMIT' => 'Allows an application to set the maximum number of (not needed) application processes that can be running.', 154 | 'SET_TIME' => 'Allows applications to set the system time.', 155 | 'SET_TIME_ZONE' => 'Allows applications to set the system time zone.', 156 | 'SET_WALLPAPER' => 'Allows applications to set the wallpaper.', 157 | 'SET_WALLPAPER_HINTS' => 'Allows applications to set the wallpaper hints.', 158 | 'SIGNAL_PERSISTENT_PROCESSES' => 'Allow an application to request that a signal be sent to all persistent processes.', 159 | 'STATUS_BAR' => 'Allows an application to open, close, or disable the status bar and its icons.', 160 | 'SUBSCRIBED_FEEDS_READ' => 'Allows an application to allow access the subscribed feeds ContentProvider.', 161 | 'SUBSCRIBED_FEEDS_WRITE' => '', 162 | 'SYSTEM_ALERT_WINDOW' => 'Allows an application to open windows using the type TYPE_SYSTEM_ALERT, shown on top of all other applications.', 163 | 'TRANSMIT_IR' => 'Allows using the device\'s IR transmitter, if available.', 164 | 'UNINSTALL_SHORTCUT' => 'Allows an application to uninstall a shortcut in Launche.r', 165 | 'UPDATE_DEVICE_STATS' => 'Allows an application to update device statistics.', 166 | 'USE_CREDENTIALS' => 'Allows an application to request authtokens from the AccountManager.', 167 | 'USE_FINGERPRINT' => 'Allows an app to use fingerprint hardware.', 168 | 'USE_SIP' => 'Allows an application to use SIP service.', 169 | 'VIBRATE' => 'Allows access to the vibrator.', 170 | 'WAKE_LOCK' => 'Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming.', 171 | 'WRITE_APN_SETTINGS' => 'Allows applications to write the apn settings.', 172 | 'WRITE_CALENDAR' => 'Allows an application to write (but not read) the user\'s calendar data.', 173 | 'WRITE_CALL_LOG' => 'Allows an application to write (but not read) the user\'s contacts data.', 174 | 'WRITE_CONTACTS' => 'Allows an application to write (but not read) the user\'s contacts data.', 175 | 'WRITE_EXTERNAL_STORAGE' => 'Allows an application to write to external storage.', 176 | 'WRITE_GSERVICES' => 'Allows an application to modify the Google service map.', 177 | 'WRITE_HISTORY_BOOKMARKS' => 'Allows an application to write (but not read) the user\'s browsing history and bookmarks.', 178 | 'WRITE_PROFILE' => 'Allows an application to write (but not read) the user\'s personal profile data.', 179 | 'WRITE_SECURE_SETTINGS' => 'Allows an application to read or write the secure system settings.', 180 | 'WRITE_SETTINGS' => 'Allows an application to read or write the system settings.', 181 | 'WRITE_SMS' => 'Allows an application to write SMS messages.', 182 | 'WRITE_SOCIAL_STREAM' => 'Allows an application to write (but not read) the user\'s social stream data.', 183 | 'WRITE_SYNC_SETTINGS' => 'Allows applications to write the sync settings.', 184 | 'WRITE_USER_DICTIONARY' => 'Allows an application to write to the user dictionary.', 185 | 'WRITE_VOICEMAIL' => 'Allows an application to modify and remove existing voicemails in the system.' 186 | ); 187 | public static $permission_flags = array( 188 | 'ACCESS_CHECKIN_PROPERTIES' => 189 | array( 190 | 'cost' => false, 191 | 'warning' => false, 192 | 'danger' => false, 193 | ), 194 | 'ACCESS_COARSE_LOCATION' => 195 | array( 196 | 'cost' => false, 197 | 'warning' => true, 198 | 'danger' => false, 199 | ), 200 | 'ACCESS_FINE_LOCATION' => 201 | array( 202 | 'cost' => false, 203 | 'warning' => true, 204 | 'danger' => false, 205 | ), 206 | 'ACCESS_LOCATION_EXTRA_COMMANDS' => 207 | array( 208 | 'cost' => false, 209 | 'warning' => false, 210 | 'danger' => false, 211 | ), 212 | 'ACCESS_MOCK_LOCATION' => 213 | array( 214 | 'cost' => false, 215 | 'warning' => false, 216 | 'danger' => false, 217 | ), 218 | 'ACCESS_NETWORK_STATE' => 219 | array( 220 | 'cost' => false, 221 | 'warning' => false, 222 | 'danger' => false, 223 | ), 224 | 'ACCESS_SURFACE_FLINGER' => 225 | array( 226 | 'cost' => false, 227 | 'warning' => false, 228 | 'danger' => false, 229 | ), 230 | 'ACCESS_WIFI_STATE' => 231 | array( 232 | 'cost' => false, 233 | 'warning' => false, 234 | 'danger' => false, 235 | ), 236 | 'ACCOUNT_MANAGER' => 237 | array( 238 | 'cost' => false, 239 | 'warning' => false, 240 | 'danger' => false, 241 | ), 242 | 'ADD_VOICEMAIL' => 243 | array( 244 | 'cost' => false, 245 | 'warning' => true, 246 | 'danger' => true, 247 | ), 248 | 'AUTHENTICATE_ACCOUNTS' => 249 | array( 250 | 'cost' => false, 251 | 'warning' => true, 252 | 'danger' => true, 253 | ), 254 | 'BATTERY_STATS' => 255 | array( 256 | 'cost' => false, 257 | 'warning' => false, 258 | 'danger' => false, 259 | ), 260 | 'BIND_ACCESSIBILITY_SERVICE' => 261 | array( 262 | 'cost' => false, 263 | 'warning' => false, 264 | 'danger' => false, 265 | ), 266 | 'BIND_APPWIDGET' => 267 | array( 268 | 'cost' => false, 269 | 'warning' => false, 270 | 'danger' => false, 271 | ), 272 | 'BIND_DEVICE_ADMIN' => 273 | array( 274 | 'cost' => false, 275 | 'warning' => false, 276 | 'danger' => false, 277 | ), 278 | 'BIND_DREAM_SERVICE' => 279 | array( 280 | 'cost' => false, 281 | 'warning' => false, 282 | 'danger' => false, 283 | ), 284 | 'BIND_INPUT_METHOD' => 285 | array( 286 | 'cost' => false, 287 | 'warning' => false, 288 | 'danger' => false, 289 | ), 290 | 'BIND_NFC_SERVICE' => 291 | array( 292 | 'cost' => false, 293 | 'warning' => false, 294 | 'danger' => false, 295 | ), 296 | 'BIND_NOTIFICATION_LISTENER_SERVICE' => 297 | array( 298 | 'cost' => false, 299 | 'warning' => false, 300 | 'danger' => false, 301 | ), 302 | 'BIND_PRINT_SERVICE' => 303 | array( 304 | 'cost' => false, 305 | 'warning' => false, 306 | 'danger' => false, 307 | ), 308 | 'BIND_REMOTEVIEWS' => 309 | array( 310 | 'cost' => false, 311 | 'warning' => false, 312 | 'danger' => false, 313 | ), 314 | 'BIND_TEXT_SERVICE' => 315 | array( 316 | 'cost' => false, 317 | 'warning' => false, 318 | 'danger' => false, 319 | ), 320 | 'BIND_TV_INPUT' => 321 | array( 322 | 'cost' => false, 323 | 'warning' => false, 324 | 'danger' => false, 325 | ), 326 | 'BIND_VOICE_INTERACTION' => 327 | array( 328 | 'cost' => false, 329 | 'warning' => false, 330 | 'danger' => false, 331 | ), 332 | 'BIND_VPN_SERVICE' => 333 | array( 334 | 'cost' => false, 335 | 'warning' => false, 336 | 'danger' => false, 337 | ), 338 | 'BIND_WALLPAPER' => 339 | array( 340 | 'cost' => false, 341 | 'warning' => false, 342 | 'danger' => false, 343 | ), 344 | 'BLUETOOTH' => 345 | array( 346 | 'cost' => false, 347 | 'warning' => true, 348 | 'danger' => false, 349 | ), 350 | 'BLUETOOTH_ADMIN' => 351 | array( 352 | 'cost' => false, 353 | 'warning' => true, 354 | 'danger' => false, 355 | ), 356 | 'BLUETOOTH_PRIVILEGED' => 357 | array( 358 | 'cost' => false, 359 | 'warning' => true, 360 | 'danger' => false, 361 | ), 362 | 'BODY_SENSORS' => 363 | array( 364 | 'cost' => false, 365 | 'warning' => true, 366 | 'danger' => true, 367 | ), 368 | 'BRICK' => 369 | array( 370 | 'cost' => false, 371 | 'warning' => true, 372 | 'danger' => true, 373 | ), 374 | 'BROADCAST_PACKAGE_REMOVED' => 375 | array( 376 | 'cost' => false, 377 | 'warning' => false, 378 | 'danger' => false, 379 | ), 380 | 'BROADCAST_SMS' => 381 | array( 382 | 'cost' => false, 383 | 'warning' => false, 384 | 'danger' => false, 385 | ), 386 | 'BROADCAST_STICKY' => 387 | array( 388 | 'cost' => false, 389 | 'warning' => false, 390 | 'danger' => false, 391 | ), 392 | 'BROADCAST_WAP_PUSH' => 393 | array( 394 | 'cost' => false, 395 | 'warning' => false, 396 | 'danger' => false, 397 | ), 398 | 'CALL_PHONE' => 399 | array( 400 | 'cost' => true, 401 | 'warning' => true, 402 | 'danger' => false, 403 | ), 404 | 'CALL_PRIVILEGED' => 405 | array( 406 | 'cost' => true, 407 | 'warning' => true, 408 | 'danger' => true, 409 | ), 410 | 'CAMERA' => 411 | array( 412 | 'cost' => false, 413 | 'warning' => false, 414 | 'danger' => false, 415 | ), 416 | 'CAPTURE_AUDIO_OUTPUT' => 417 | array( 418 | 'cost' => false, 419 | 'warning' => false, 420 | 'danger' => false, 421 | ), 422 | 'CAPTURE_SECURE_VIDEO_OUTPUT' => 423 | array( 424 | 'cost' => false, 425 | 'warning' => false, 426 | 'danger' => false, 427 | ), 428 | 'CAPTURE_VIDEO_OUTPUT' => 429 | array( 430 | 'cost' => false, 431 | 'warning' => false, 432 | 'danger' => false, 433 | ), 434 | 'CHANGE_COMPONENT_ENABLED_STATE' => 435 | array( 436 | 'cost' => false, 437 | 'warning' => false, 438 | 'danger' => false, 439 | ), 440 | 'CHANGE_CONFIGURATION' => 441 | array( 442 | 'cost' => false, 443 | 'warning' => false, 444 | 'danger' => false, 445 | ), 446 | 'CHANGE_NETWORK_STATE' => 447 | array( 448 | 'cost' => false, 449 | 'warning' => false, 450 | 'danger' => false, 451 | ), 452 | 'CHANGE_WIFI_MULTICAST_STATE' => 453 | array( 454 | 'cost' => false, 455 | 'warning' => false, 456 | 'danger' => false, 457 | ), 458 | 'CHANGE_WIFI_STATE' => 459 | array( 460 | 'cost' => false, 461 | 'warning' => false, 462 | 'danger' => false, 463 | ), 464 | 'CLEAR_APP_CACHE' => 465 | array( 466 | 'cost' => false, 467 | 'warning' => false, 468 | 'danger' => false, 469 | ), 470 | 'CLEAR_APP_USER_DATA' => 471 | array( 472 | 'cost' => false, 473 | 'warning' => false, 474 | 'danger' => false, 475 | ), 476 | 'CONTROL_LOCATION_UPDATES' => 477 | array( 478 | 'cost' => false, 479 | 'warning' => false, 480 | 'danger' => false, 481 | ), 482 | 'DELETE_CACHE_FILES' => 483 | array( 484 | 'cost' => false, 485 | 'warning' => false, 486 | 'danger' => false, 487 | ), 488 | 'DELETE_PACKAGES' => 489 | array( 490 | 'cost' => false, 491 | 'warning' => false, 492 | 'danger' => false, 493 | ), 494 | 'DEVICE_POWER' => 495 | array( 496 | 'cost' => false, 497 | 'warning' => false, 498 | 'danger' => false, 499 | ), 500 | 'DIAGNOSTIC' => 501 | array( 502 | 'cost' => false, 503 | 'warning' => false, 504 | 'danger' => false, 505 | ), 506 | 'DISABLE_KEYGUARD' => 507 | array( 508 | 'cost' => false, 509 | 'warning' => false, 510 | 'danger' => false, 511 | ), 512 | 'DUMP' => 513 | array( 514 | 'cost' => false, 515 | 'warning' => false, 516 | 'danger' => false, 517 | ), 518 | 'EXPAND_STATUS_BAR' => 519 | array( 520 | 'cost' => false, 521 | 'warning' => false, 522 | 'danger' => false, 523 | ), 524 | 'FACTORY_TEST' => 525 | array( 526 | 'cost' => false, 527 | 'warning' => false, 528 | 'danger' => false, 529 | ), 530 | 'FLASHLIGHT' => 531 | array( 532 | 'cost' => false, 533 | 'warning' => false, 534 | 'danger' => false, 535 | ), 536 | 'FORCE_BACK' => 537 | array( 538 | 'cost' => false, 539 | 'warning' => false, 540 | 'danger' => false, 541 | ), 542 | 'GET_ACCOUNTS' => 543 | array( 544 | 'cost' => false, 545 | 'warning' => false, 546 | 'danger' => false, 547 | ), 548 | 'GET_PACKAGE_SIZE' => 549 | array( 550 | 'cost' => false, 551 | 'warning' => false, 552 | 'danger' => false, 553 | ), 554 | 'GET_TASKS' => 555 | array( 556 | 'cost' => false, 557 | 'warning' => false, 558 | 'danger' => false, 559 | ), 560 | 'GET_TOP_ACTIVITY_INFO' => 561 | array( 562 | 'cost' => false, 563 | 'warning' => false, 564 | 'danger' => false, 565 | ), 566 | 'GLOBAL_SEARCH' => 567 | array( 568 | 'cost' => false, 569 | 'warning' => false, 570 | 'danger' => false, 571 | ), 572 | 'HARDWARE_TEST' => 573 | array( 574 | 'cost' => false, 575 | 'warning' => false, 576 | 'danger' => false, 577 | ), 578 | 'INJECT_EVENTS' => 579 | array( 580 | 'cost' => false, 581 | 'warning' => false, 582 | 'danger' => false, 583 | ), 584 | 'INSTALL_LOCATION_PROVIDER' => 585 | array( 586 | 'cost' => false, 587 | 'warning' => false, 588 | 'danger' => false, 589 | ), 590 | 'INSTALL_PACKAGES' => 591 | array( 592 | 'cost' => false, 593 | 'warning' => true, 594 | 'danger' => true, 595 | ), 596 | 'INSTALL_SHORTCUT' => 597 | array( 598 | 'cost' => false, 599 | 'warning' => true, 600 | 'danger' => true, 601 | ), 602 | 'INTERNAL_SYSTEM_WINDOW' => 603 | array( 604 | 'cost' => false, 605 | 'warning' => false, 606 | 'danger' => false, 607 | ), 608 | 'INTERNET' => 609 | array( 610 | 'cost' => false, 611 | 'warning' => false, 612 | 'danger' => false, 613 | ), 614 | 'KILL_BACKGROUND_PROCESSES' => 615 | array( 616 | 'cost' => false, 617 | 'warning' => false, 618 | 'danger' => true, 619 | ), 620 | 'LOCATION_HARDWARE' => 621 | array( 622 | 'cost' => false, 623 | 'warning' => true, 624 | 'danger' => false, 625 | ), 626 | 'MANAGE_ACCOUNTS' => 627 | array( 628 | 'cost' => false, 629 | 'warning' => false, 630 | 'danger' => false, 631 | ), 632 | 'MANAGE_APP_TOKENS' => 633 | array( 634 | 'cost' => false, 635 | 'warning' => false, 636 | 'danger' => false, 637 | ), 638 | 'MANAGE_DOCUMENTS' => 639 | array( 640 | 'cost' => false, 641 | 'warning' => false, 642 | 'danger' => false, 643 | ), 644 | 'MASTER_CLEAR' => 645 | array( 646 | 'cost' => false, 647 | 'warning' => false, 648 | 'danger' => true, 649 | ), 650 | 'MEDIA_CONTENT_CONTROL' => 651 | array( 652 | 'cost' => false, 653 | 'warning' => false, 654 | 'danger' => false, 655 | ), 656 | 'MODIFY_AUDIO_SETTINGS' => 657 | array( 658 | 'cost' => false, 659 | 'warning' => false, 660 | 'danger' => false, 661 | ), 662 | 'MODIFY_PHONE_STATE' => 663 | array( 664 | 'cost' => false, 665 | 'warning' => false, 666 | 'danger' => false, 667 | ), 668 | 'MOUNT_FORMAT_FILESYSTEMS' => 669 | array( 670 | 'cost' => false, 671 | 'warning' => false, 672 | 'danger' => false, 673 | ), 674 | 'MOUNT_UNMOUNT_FILESYSTEMS' => 675 | array( 676 | 'cost' => false, 677 | 'warning' => false, 678 | 'danger' => false, 679 | ), 680 | 'NFC' => 681 | array( 682 | 'cost' => false, 683 | 'warning' => false, 684 | 'danger' => false, 685 | ), 686 | 'PERSISTENT_ACTIVITY' => 687 | array( 688 | 'cost' => false, 689 | 'warning' => true, 690 | 'danger' => true, 691 | ), 692 | 'PROCESS_OUTGOING_CALLS' => 693 | array( 694 | 'cost' => false, 695 | 'warning' => false, 696 | 'danger' => false, 697 | ), 698 | 'READ_CALENDAR' => 699 | array( 700 | 'cost' => false, 701 | 'warning' => false, 702 | 'danger' => false, 703 | ), 704 | 'READ_CALL_LOG' => 705 | array( 706 | 'cost' => false, 707 | 'warning' => false, 708 | 'danger' => false, 709 | ), 710 | 'READ_CONTACTS' => 711 | array( 712 | 'cost' => false, 713 | 'warning' => false, 714 | 'danger' => false, 715 | ), 716 | 'READ_EXTERNAL_STORAGE' => 717 | array( 718 | 'cost' => false, 719 | 'warning' => false, 720 | 'danger' => false, 721 | ), 722 | 'READ_FRAME_BUFFER' => 723 | array( 724 | 'cost' => false, 725 | 'warning' => false, 726 | 'danger' => false, 727 | ), 728 | 'READ_HISTORY_BOOKMARKS' => 729 | array( 730 | 'cost' => false, 731 | 'warning' => false, 732 | 'danger' => false, 733 | ), 734 | 'READ_INPUT_STATE' => 735 | array( 736 | 'cost' => false, 737 | 'warning' => false, 738 | 'danger' => true, 739 | ), 740 | 'READ_LOGS' => 741 | array( 742 | 'cost' => false, 743 | 'warning' => false, 744 | 'danger' => false, 745 | ), 746 | 'READ_PHONE_STATE' => 747 | array( 748 | 'cost' => false, 749 | 'warning' => false, 750 | 'danger' => false, 751 | ), 752 | 'READ_PROFILE' => 753 | array( 754 | 'cost' => false, 755 | 'warning' => false, 756 | 'danger' => false, 757 | ), 758 | 'READ_SMS' => 759 | array( 760 | 'cost' => false, 761 | 'warning' => false, 762 | 'danger' => false, 763 | ), 764 | 'READ_SOCIAL_STREAM' => 765 | array( 766 | 'cost' => false, 767 | 'warning' => false, 768 | 'danger' => false, 769 | ), 770 | 'READ_SYNC_SETTINGS' => 771 | array( 772 | 'cost' => false, 773 | 'warning' => false, 774 | 'danger' => false, 775 | ), 776 | 'READ_SYNC_STATS' => 777 | array( 778 | 'cost' => false, 779 | 'warning' => false, 780 | 'danger' => false, 781 | ), 782 | 'READ_USER_DICTIONARY' => 783 | array( 784 | 'cost' => false, 785 | 'warning' => false, 786 | 'danger' => false, 787 | ), 788 | 'READ_VOICEMAIL' => 789 | array( 790 | 'cost' => false, 791 | 'warning' => false, 792 | 'danger' => false, 793 | ), 794 | 'REBOOT' => 795 | array( 796 | 'cost' => false, 797 | 'warning' => true, 798 | 'danger' => true, 799 | ), 800 | 'RECEIVE_BOOT_COMPLETED' => 801 | array( 802 | 'cost' => false, 803 | 'warning' => false, 804 | 'danger' => false, 805 | ), 806 | 'RECEIVE_MMS' => 807 | array( 808 | 'cost' => false, 809 | 'warning' => true, 810 | 'danger' => false, 811 | ), 812 | 'RECEIVE_SMS' => 813 | array( 814 | 'cost' => false, 815 | 'warning' => true, 816 | 'danger' => false, 817 | ), 818 | 'RECEIVE_WAP_PUSH' => 819 | array( 820 | 'cost' => false, 821 | 'warning' => true, 822 | 'danger' => false, 823 | ), 824 | 'RECORD_AUDIO' => 825 | array( 826 | 'cost' => false, 827 | 'warning' => true, 828 | 'danger' => false, 829 | ), 830 | 'REORDER_TASKS' => 831 | array( 832 | 'cost' => false, 833 | 'warning' => true, 834 | 'danger' => false, 835 | ), 836 | 'RESTART_PACKAGES' => 837 | array( 838 | 'cost' => false, 839 | 'warning' => true, 840 | 'danger' => true, 841 | ), 842 | 'SEND_RESPOND_VIA_MESSAGE' => 843 | array( 844 | 'cost' => false, 845 | 'warning' => true, 846 | 'danger' => true, 847 | ), 848 | 'SEND_SMS' => 849 | array( 850 | 'cost' => true, 851 | 'warning' => true, 852 | 'danger' => false, 853 | ), 854 | 'SET_ACTIVITY_WATCHER' => 855 | array( 856 | 'cost' => false, 857 | 'warning' => false, 858 | 'danger' => true, 859 | ), 860 | 'SET_ALARM' => 861 | array( 862 | 'cost' => false, 863 | 'warning' => true, 864 | 'danger' => false, 865 | ), 866 | 'SET_ALWAYS_FINISH' => 867 | array( 868 | 'cost' => false, 869 | 'warning' => true, 870 | 'danger' => true, 871 | ), 872 | 'SET_ANIMATION_SCALE' => 873 | array( 874 | 'cost' => false, 875 | 'warning' => true, 876 | 'danger' => true, 877 | ), 878 | 'SET_DEBUG_APP' => 879 | array( 880 | 'cost' => false, 881 | 'warning' => true, 882 | 'danger' => true, 883 | ), 884 | 'SET_ORIENTATION' => 885 | array( 886 | 'cost' => false, 887 | 'warning' => true, 888 | 'danger' => true, 889 | ), 890 | 'SET_POINTER_SPEED' => 891 | array( 892 | 'cost' => false, 893 | 'warning' => true, 894 | 'danger' => true, 895 | ), 896 | 'SET_PREFERRED_APPLICATIONS' => 897 | array( 898 | 'cost' => false, 899 | 'warning' => false, 900 | 'danger' => true, 901 | ), 902 | 'SET_PROCESS_LIMIT' => 903 | array( 904 | 'cost' => false, 905 | 'warning' => false, 906 | 'danger' => false, 907 | ), 908 | 'SET_TIME' => 909 | array( 910 | 'cost' => false, 911 | 'warning' => false, 912 | 'danger' => false, 913 | ), 914 | 'SET_TIME_ZONE' => 915 | array( 916 | 'cost' => false, 917 | 'warning' => false, 918 | 'danger' => false, 919 | ), 920 | 'SET_WALLPAPER' => 921 | array( 922 | 'cost' => false, 923 | 'warning' => false, 924 | 'danger' => false, 925 | ), 926 | 'SET_WALLPAPER_HINTS' => 927 | array( 928 | 'cost' => false, 929 | 'warning' => false, 930 | 'danger' => false, 931 | ), 932 | 'SIGNAL_PERSISTENT_PROCESSES' => 933 | array( 934 | 'cost' => false, 935 | 'warning' => false, 936 | 'danger' => false, 937 | ), 938 | 'STATUS_BAR' => 939 | array( 940 | 'cost' => false, 941 | 'warning' => false, 942 | 'danger' => false, 943 | ), 944 | 'SUBSCRIBED_FEEDS_READ' => 945 | array( 946 | 'cost' => false, 947 | 'warning' => false, 948 | 'danger' => false, 949 | ), 950 | 'SUBSCRIBED_FEEDS_WRITE' => 951 | array( 952 | 'cost' => false, 953 | 'warning' => false, 954 | 'danger' => false, 955 | ), 956 | 'SYSTEM_ALERT_WINDOW' => 957 | array( 958 | 'cost' => false, 959 | 'warning' => false, 960 | 'danger' => false, 961 | ), 962 | 'TRANSMIT_IR' => 963 | array( 964 | 'cost' => false, 965 | 'warning' => false, 966 | 'danger' => false, 967 | ), 968 | 'UNINSTALL_SHORTCUT' => 969 | array( 970 | 'cost' => false, 971 | 'warning' => true, 972 | 'danger' => false, 973 | ), 974 | 'UPDATE_DEVICE_STATS' => 975 | array( 976 | 'cost' => false, 977 | 'warning' => false, 978 | 'danger' => false, 979 | ), 980 | 'USE_CREDENTIALS' => 981 | array( 982 | 'cost' => false, 983 | 'warning' => false, 984 | 'danger' => false, 985 | ), 986 | 'USE_FINGERPRINT' => 987 | array( 988 | 'cost' => false, 989 | 'warning' => false, 990 | 'danger' => false, 991 | ), 992 | 'USE_SIP' => 993 | array( 994 | 'cost' => false, 995 | 'warning' => false, 996 | 'danger' => false, 997 | ), 998 | 'VIBRATE' => 999 | array( 1000 | 'cost' => false, 1001 | 'warning' => false, 1002 | 'danger' => false, 1003 | ), 1004 | 'WAKE_LOCK' => 1005 | array( 1006 | 'cost' => false, 1007 | 'warning' => true, 1008 | 'danger' => false, 1009 | ), 1010 | 'WRITE_APN_SETTINGS' => 1011 | array( 1012 | 'cost' => false, 1013 | 'warning' => false, 1014 | 'danger' => true, 1015 | ), 1016 | 'WRITE_CALENDAR' => 1017 | array( 1018 | 'cost' => false, 1019 | 'warning' => true, 1020 | 'danger' => false, 1021 | ), 1022 | 'WRITE_CALL_LOG' => 1023 | array( 1024 | 'cost' => false, 1025 | 'warning' => false, 1026 | 'danger' => true, 1027 | ), 1028 | 'WRITE_CONTACTS' => 1029 | array( 1030 | 'cost' => false, 1031 | 'warning' => false, 1032 | 'danger' => true, 1033 | ), 1034 | 'WRITE_EXTERNAL_STORAGE' => 1035 | array( 1036 | 'cost' => false, 1037 | 'warning' => false, 1038 | 'danger' => false, 1039 | ), 1040 | 'WRITE_GSERVICES' => 1041 | array( 1042 | 'cost' => false, 1043 | 'warning' => false, 1044 | 'danger' => true, 1045 | ), 1046 | 'WRITE_HISTORY_BOOKMARKS' => 1047 | array( 1048 | 'cost' => false, 1049 | 'warning' => false, 1050 | 'danger' => true, 1051 | ), 1052 | 'WRITE_PROFILE' => 1053 | array( 1054 | 'cost' => false, 1055 | 'warning' => false, 1056 | 'danger' => true, 1057 | ), 1058 | 'WRITE_SECURE_SETTINGS' => 1059 | array( 1060 | 'cost' => false, 1061 | 'warning' => true, 1062 | 'danger' => false, 1063 | ), 1064 | 'WRITE_SETTINGS' => 1065 | array( 1066 | 'cost' => false, 1067 | 'warning' => true, 1068 | 'danger' => false, 1069 | ), 1070 | 'WRITE_SMS' => 1071 | array( 1072 | 'cost' => false, 1073 | 'warning' => true, 1074 | 'danger' => false, 1075 | ), 1076 | 'WRITE_SOCIAL_STREAM' => 1077 | array( 1078 | 'cost' => false, 1079 | 'warning' => true, 1080 | 'danger' => false, 1081 | ), 1082 | 'WRITE_SYNC_SETTINGS' => 1083 | array( 1084 | 'cost' => false, 1085 | 'warning' => false, 1086 | 'danger' => false, 1087 | ), 1088 | 'WRITE_USER_DICTIONARY' => 1089 | array( 1090 | 'cost' => false, 1091 | 'warning' => false, 1092 | 'danger' => false, 1093 | ), 1094 | 'WRITE_VOICEMAIL' => 1095 | array( 1096 | 'cost' => false, 1097 | 'warning' => false, 1098 | 'danger' => false, 1099 | ), 1100 | ); 1101 | private $xmlParser; 1102 | private $attrs = null; 1103 | private $meta = null; 1104 | 1105 | /** 1106 | * @param XmlParser $xmlParser 1107 | */ 1108 | public function __construct(XmlParser $xmlParser) 1109 | { 1110 | $this->xmlParser = $xmlParser; 1111 | } 1112 | 1113 | /** 1114 | * @return Application 1115 | * @throws Exceptions\XmlParserException 1116 | */ 1117 | public function getApplication() 1118 | { 1119 | return $this->getXmlObject()->getApplication(); 1120 | } 1121 | 1122 | /** 1123 | * get SimleXmlElement created from AndroidManifest.xml 1124 | * 1125 | * @param mixed $className 1126 | * @return ManifestXmlElement|\SimpleXMLElement 1127 | * @throws Exceptions\XmlParserException 1128 | */ 1129 | public function getXmlObject($className = '\ApkParser\ManifestXmlElement') 1130 | { 1131 | return $this->xmlParser->getXmlObject($className); 1132 | } 1133 | 1134 | /** 1135 | * Get Application Permissions 1136 | * @param string $lang 1137 | * @return array 1138 | * @throws Exceptions\XmlParserException 1139 | */ 1140 | public function getPermissions($lang = 'en') 1141 | { 1142 | return $this->getXmlObject()->getPermissions($lang); 1143 | } 1144 | 1145 | /** 1146 | * Get Application Permissions 1147 | * @return array 1148 | * @throws Exceptions\XmlParserException 1149 | */ 1150 | public function getPermissionsRaw() 1151 | { 1152 | return $this->getXmlObject()->getPermissionsRaw(); 1153 | } 1154 | 1155 | /** 1156 | * Android Package Name 1157 | * @return string 1158 | * @throws \Exception 1159 | */ 1160 | public function getPackageName() 1161 | { 1162 | return $this->getAttribute('package'); 1163 | } 1164 | 1165 | /** 1166 | * @param $attributeName 1167 | * @return mixed 1168 | * @throws \Exception 1169 | */ 1170 | private function getAttribute($attributeName) 1171 | { 1172 | if ($this->attrs === null) { 1173 | $xmlObj = $this->getXmlObject(); 1174 | $vars = get_object_vars($xmlObj->attributes()); 1175 | $this->attrs = $vars['@attributes']; 1176 | } 1177 | 1178 | if (!isset($this->attrs[$attributeName])) { 1179 | throw new \Exception("Attribute not found : " . $attributeName); 1180 | } 1181 | 1182 | return $this->attrs[$attributeName]; 1183 | } 1184 | 1185 | /** 1186 | * Application Version Name 1187 | * @return string 1188 | * @throws \Exception 1189 | */ 1190 | public function getVersionName() 1191 | { 1192 | return $this->getAttribute('versionName'); 1193 | } 1194 | 1195 | /** 1196 | * Application Version Code 1197 | * @return mixed 1198 | * @throws \Exception 1199 | */ 1200 | public function getVersionCode() 1201 | { 1202 | return hexdec($this->getAttribute('versionCode')); 1203 | } 1204 | 1205 | /** 1206 | * @return bool 1207 | * @throws \Exception 1208 | */ 1209 | public function isDebuggable() 1210 | { 1211 | return (bool)$this->getAttribute('debuggable'); 1212 | } 1213 | 1214 | /** 1215 | * @param $name 1216 | * @return mixed 1217 | * @throws Exceptions\XmlParserException 1218 | */ 1219 | public function getMetaData($name) 1220 | { 1221 | if ($this->meta === null) { 1222 | $xmlObj = $this->getXmlObject(); 1223 | $nodes = $xmlObj->xpath('//meta-data'); 1224 | $this->meta = array(); 1225 | 1226 | foreach ($nodes as $node) { 1227 | $nodeAttrs = get_object_vars($node->attributes()); 1228 | $nodeName = $nodeAttrs['@attributes']['name']; 1229 | if (array_key_exists('value', $nodeAttrs['@attributes'])) { 1230 | $this->meta[$nodeName] = $nodeAttrs['@attributes']['value']; 1231 | } elseif (array_key_exists('resource', $nodeAttrs['@attributes'])) { 1232 | $this->meta[$nodeName] = $nodeAttrs['@attributes']['resource']; 1233 | } 1234 | } 1235 | } 1236 | return $this->meta[$name]; 1237 | } 1238 | 1239 | /** 1240 | * More Information About The minimum API Level required for the application to run. 1241 | * @return AndroidPlatform 1242 | * @throws \Exception 1243 | */ 1244 | public function getMinSdk() 1245 | { 1246 | return new AndroidPlatform($this->getMinSdkLevel()); 1247 | } 1248 | 1249 | /** 1250 | * The minimum API Level required for the application to run. 1251 | * @return int 1252 | * @throws Exceptions\XmlParserException 1253 | */ 1254 | public function getMinSdkLevel() 1255 | { 1256 | $xmlObj = $this->getXmlObject(); 1257 | $usesSdk = get_object_vars($xmlObj->{'uses-sdk'}); 1258 | if (isset($usesSdk['@attributes']) && isset($usesSdk['@attributes']['minSdkVersion'])) { 1259 | return hexdec($usesSdk['@attributes']['minSdkVersion']); 1260 | } 1261 | return null; 1262 | } 1263 | 1264 | /** 1265 | * More Information About The target API Level required for the application to run. 1266 | * @return AndroidPlatform 1267 | * @throws \Exception 1268 | */ 1269 | public function getTargetSdk() 1270 | { 1271 | if ($this->getTargetSdkLevel()) { 1272 | return new AndroidPlatform($this->getTargetSdkLevel()); 1273 | } 1274 | return null; 1275 | } 1276 | 1277 | /** 1278 | * The target API Level required for the application to run. 1279 | * @return float|int 1280 | * @throws Exceptions\XmlParserException 1281 | */ 1282 | public function getTargetSdkLevel() 1283 | { 1284 | $xmlObj = $this->getXmlObject(); 1285 | $usesSdk = get_object_vars($xmlObj->{'uses-sdk'}); 1286 | if (isset($usesSdk['@attributes']) && isset($usesSdk['@attributes']['targetSdkVersion'])) { 1287 | return hexdec($usesSdk['@attributes']['targetSdkVersion']); 1288 | } 1289 | return null; 1290 | } 1291 | 1292 | /** 1293 | * Basically string casting method. 1294 | * @throws \Exception 1295 | */ 1296 | public function __toString() 1297 | { 1298 | return $this->getXmlString(); 1299 | } 1300 | 1301 | /** 1302 | * Returns ManifestXml as a String. 1303 | * @return string 1304 | * @throws \Exception 1305 | */ 1306 | public function getXmlString() 1307 | { 1308 | return $this->xmlParser->getXmlString(); 1309 | } 1310 | } 1311 | -------------------------------------------------------------------------------- /lib/ApkParser/ManifestXmlElement.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | * @property mixed application 13 | */ 14 | class ManifestXmlElement extends \SimpleXMLElement 15 | { 16 | /** 17 | * @return array 18 | */ 19 | public function getPermissions($lang = 'en') 20 | { 21 | /** 22 | * @var \ApkParser\ManifestXmlElement 23 | */ 24 | $permsArray = $this->{'uses-permission'}; 25 | $permissions = json_decode(file_get_contents(__DIR__ . "/lang/{$lang}.permissions.json"), true); 26 | $perms = array(); 27 | foreach ($permsArray as $perm) { 28 | $permAttr = get_object_vars($perm); 29 | $objNotationArray = explode('.', $permAttr['@attributes']['name']); 30 | $permName = trim(end($objNotationArray)); 31 | $perms[$permName] = array( 32 | 'description' => isset($permissions[$permName]) ? $permissions[$permName]['desc'] : null, 33 | 34 | 'flags' => isset($permissions[$permName]) ? 35 | $permissions[$permName]['flags'] 36 | : array( 37 | 'cost' => false, 38 | 'warning' => false, 39 | 'danger' => false, 40 | ) 41 | ); 42 | } 43 | return $perms; 44 | } 45 | 46 | /** 47 | * @return array 48 | */ 49 | public function getPermissionsRaw() 50 | { 51 | /** 52 | * @var \ApkParser\ManifestXmlElement 53 | */ 54 | $permsArray = $this->{'uses-permission'}; 55 | $perms = array(); 56 | foreach ($permsArray as $perm) { 57 | $permAttr = get_object_vars($perm); 58 | $perms[] = $permAttr['@attributes']['name']; 59 | } 60 | return $perms; 61 | } 62 | 63 | 64 | /** 65 | * @return Application 66 | */ 67 | public function getApplication() 68 | { 69 | return new Application($this->application); 70 | } 71 | 72 | /** 73 | * @param $attributeName 74 | * @return null 75 | */ 76 | public function getAttribute($attributeName) 77 | { 78 | $attrs = get_object_vars($this); 79 | return isset($attrs['@attributes'][$attributeName]) ? $attrs['@attributes'][$attributeName] : null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/ApkParser/Parser.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Parser 14 | { 15 | private $apk; 16 | private $manifest; 17 | /** 18 | * @var ResourcesParser|null 19 | */ 20 | private $resources; 21 | private $config; 22 | 23 | /** 24 | * @param $apkFile 25 | * @param array $config 26 | * @throws \Exception 27 | */ 28 | public function __construct($apkFile, array $config = []) 29 | { 30 | $this->config = new Config($config); 31 | $this->apk = new Archive($apkFile); 32 | $this->manifest = new Manifest(new XmlParser($this->apk->getManifestStream())); 33 | 34 | if (!$this->config->manifest_only) { 35 | $this->resources = new ResourcesParser($this->apk->getResourcesStream()); 36 | } else { 37 | $this->resources = null; 38 | } 39 | } 40 | 41 | /** 42 | * Get Manifest Object 43 | * @return \ApkParser\Manifest 44 | */ 45 | public function getManifest() 46 | { 47 | return $this->manifest; 48 | } 49 | 50 | /** 51 | * Get the apk. Zip handler. 52 | * - Extract all(or sp. entries) files, 53 | * - add file, 54 | * - recompress 55 | * - and other ZipArchive features. 56 | * 57 | * @return \ApkParser\Archive 58 | */ 59 | public function getApkArchive() 60 | { 61 | return $this->apk; 62 | } 63 | 64 | /** 65 | * @param $key 66 | * @return bool|mixed 67 | */ 68 | public function getResources($key) 69 | { 70 | return is_null($this->resources) ? false : $this->resources->getResources($key); 71 | } 72 | 73 | /** 74 | * Get all resources as an array 75 | */ 76 | public function getAllResources() 77 | { 78 | return is_null($this->resources) ? [] : $this->resources->getAllResources(); 79 | } 80 | 81 | /** 82 | * @param $name 83 | * @return resource 84 | */ 85 | public function getStream($name) 86 | { 87 | return $this->apk->getStream($name); 88 | } 89 | 90 | /** 91 | * Extract apk content directly 92 | * 93 | * @param mixed $destination 94 | * @param array $entries 95 | * @return bool 96 | */ 97 | public function extractTo($destination, $entries = null) 98 | { 99 | return $this->apk->extractTo($destination, $entries); 100 | } 101 | 102 | /** 103 | * @return array 104 | * @throws \Exception 105 | */ 106 | public function getClasses() 107 | { 108 | $dexStream = $this->apk->getClassesDexStream(); 109 | $apkName = $this->apk->getApkName(); 110 | 111 | $cache_folder = $this->config->tmp_path . '/' . str_replace('.', '_', $apkName) . '/'; 112 | 113 | // No folder means no cached data. 114 | if (!is_dir($cache_folder)) { 115 | mkdir($cache_folder, 0755, true); 116 | } 117 | 118 | $dex_file = $cache_folder . '/classes.dex'; 119 | $dexStream->save($dex_file); 120 | 121 | // run shell command to extract dalvik compiled codes to the cache folder. 122 | // Template : java -jar dedexer.jar -d {destination_folder} {source_dex_file} 123 | $command = "java -jar {$this->config->jar_path} -d {$cache_folder} {$dex_file}"; 124 | $returns = shell_exec($command); 125 | 126 | if (!$returns) { //TODO : check if it not contains any error. $returns will always contain some output. 127 | throw new \Exception("Couldn't decompile .dex file"); 128 | } 129 | 130 | $file_list = Utils::globRecursive($cache_folder . '*.ddx'); 131 | 132 | //Make classnames more readable. 133 | foreach ($file_list as &$file) { 134 | $file = str_replace($cache_folder, '', $file); 135 | $file = str_replace('/', '.', $file); 136 | $file = str_replace('.ddx', '', $file); 137 | $file = trim($file, '.'); 138 | } 139 | 140 | 141 | return $file_list; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /lib/ApkParser/ResourcesParser.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class ResourcesParser 14 | { 15 | public const RES_STRING_POOL_TYPE = 0x0001; 16 | public const RES_TABLE_TYPE = 0x0002; 17 | public const RES_TABLE_PACKAGE_TYPE = 0x0200; 18 | public const RES_TABLE_TYPE_TYPE = 0x0201; 19 | public const RES_TABLE_TYPE_SPEC_TYPE = 0x0202; 20 | // The 'data' holds a ResTable_ref, a reference to another resource table entry. 21 | public const TYPE_REFERENCE = 0x01; 22 | // The 'data' holds an index into the containing resource table's global value string pool. 23 | public const TYPE_STRING = 0x03; 24 | public const FLAG_COMPLEX = 0x0001; 25 | 26 | /** 27 | * @var SeekableStream 28 | */ 29 | private $stream; 30 | 31 | private $valueStringPool; 32 | private $typeStringPool; 33 | private $keyStringPool; 34 | 35 | private $packageId = 0; 36 | private $resources = array(); 37 | 38 | /** 39 | * @param SeekableStream $stream 40 | * @throws \Exception 41 | */ 42 | public function __construct(SeekableStream $stream) 43 | { 44 | $this->stream = $stream; 45 | $this->decompress(); 46 | } 47 | 48 | /** 49 | * @throws \Exception 50 | */ 51 | private function decompress() 52 | { 53 | $type = $this->stream->readInt16LE(); 54 | $this->stream->readInt16LE(); // headerSize 55 | $size = $this->stream->readInt32LE(); 56 | $packagesCount = $this->stream->readInt32LE(); 57 | 58 | if ($type != self::RES_TABLE_TYPE) { 59 | throw new \Exception('No RES_TABLE_TYPE found'); 60 | } 61 | if ($size != $this->stream->size()) { 62 | throw new \Exception('The buffer size not matches to the resource table size'); 63 | } 64 | 65 | $realStringsCount = 0; 66 | $realPackagesCount = 0; 67 | while (true) { 68 | $pos = $this->stream->position(); 69 | $chunkType = $this->stream->readInt16LE(); 70 | $this->stream->readInt16LE(); // headerSize 71 | $chunkSize = $this->stream->readInt32LE(); 72 | if ($chunkType == self::RES_STRING_POOL_TYPE) { 73 | // Only the first string pool is processed. 74 | if ($realStringsCount == 0) { 75 | $this->stream->seek($pos); 76 | $this->valueStringPool = $this->processStringPool($this->stream->copyBytes($chunkSize)); 77 | } 78 | $realStringsCount++; 79 | } else { 80 | if ($chunkType == self::RES_TABLE_PACKAGE_TYPE) { 81 | $this->stream->seek($pos); 82 | $this->processPackage($this->stream->copyBytes($chunkSize)); 83 | $realPackagesCount++; 84 | } else { 85 | throw new \Exception('Unsupported Type'); 86 | } 87 | } 88 | 89 | $this->stream->seek($pos + $chunkSize); 90 | if ($this->stream->position() == $size) { 91 | break; 92 | } 93 | } 94 | if ($realStringsCount != 1) { 95 | throw new \Exception('More than 1 string pool found!'); 96 | } 97 | if ($realPackagesCount != $packagesCount) { 98 | throw new \Exception('Real package count not equals the declared count.'); 99 | } 100 | } 101 | 102 | /** 103 | * @param SeekableStream $data 104 | * @return array 105 | */ 106 | private function processStringPool(SeekableStream $data) 107 | { 108 | $data->readInt16LE(); // type 109 | $data->readInt16LE(); // headerSize 110 | $data->readInt32LE(); // size 111 | $stringsCount = $data->readInt32LE(); 112 | $data->readInt32LE(); // stylesCount 113 | $flags = $data->readInt32LE(); 114 | $stringsStart = $data->readInt32LE(); 115 | $data->readInt32LE(); // stylesStart 116 | 117 | $offsets = array(); 118 | for ($i = 0; $i < $stringsCount; $i++) { 119 | $offsets[$i] = $data->readInt32LE(); 120 | } 121 | $isUtf8 = ($flags & 256) != 0; 122 | 123 | $strings = array(); 124 | for ($i = 0; $i < $stringsCount; $i++) { 125 | $lastPosition = $data->position(); 126 | $pos = $stringsStart + $offsets[$i]; 127 | $data->seek($pos); 128 | $len = $data->position(); 129 | $data->seek($lastPosition); 130 | if ($len < 0) { 131 | $data->readInt16LE(); // extendShort 132 | } 133 | $pos += 2; 134 | 135 | $strings[$i] = ''; 136 | if ($isUtf8) { 137 | $length = 0; 138 | $data->seek($pos); 139 | while ($data->readByte() != 0) { 140 | $length++; 141 | } 142 | if ($length > 0) { 143 | $data->seek($pos); 144 | $strings[$i] = $data->read($length); 145 | } else { 146 | $strings[$i] = ''; 147 | } 148 | } else { 149 | $data->seek($pos); 150 | while (($c = $data->read()) != 0) { 151 | $strings[$i] .= $c; 152 | $pos += 2; 153 | } 154 | } 155 | // echo 'Parsed value: ', $strings[$i], PHP_EOL; 156 | } 157 | return $strings; 158 | } 159 | 160 | /** 161 | * @param SeekableStream $data 162 | * @throws \Exception 163 | */ 164 | private function processPackage(SeekableStream $data) 165 | { 166 | $data->readInt16LE(); // type 167 | $headerSize = $data->readInt16LE(); 168 | $data->readInt32LE(); // size 169 | 170 | $this->packageId = $data->readInt32LE(); 171 | $packageName = $data->read(256); 172 | // echo 'Package name: ', $packageName, PHP_EOL; 173 | 174 | $typeStringsStart = $data->readInt32LE(); 175 | $data->readInt32LE(); // lastPublicType 176 | $keyStringsStart = $data->readInt32LE(); 177 | $data->readInt32LE(); // lastPublicKey 178 | 179 | if ($typeStringsStart != $headerSize) { 180 | throw new \Exception('TypeStrings must immediately follow the package structure header.'); 181 | } 182 | 183 | // echo 'Type strings', PHP_EOL; 184 | $data->seek($typeStringsStart); 185 | $this->typeStringPool = $this->processStringPool($data->copyBytes($data->size() - $data->position())); 186 | 187 | // echo 'Key strings', PHP_EOL; 188 | $data->seek($keyStringsStart); 189 | $data->readInt16LE(); // key_type 190 | $data->readInt16LE(); // key_headerSize 191 | $keySize = $data->readInt32LE(); 192 | 193 | $data->seek($keyStringsStart); 194 | $this->keyStringPool = $this->processStringPool($data->copyBytes($data->size() - $data->position())); 195 | 196 | $data->seek($keyStringsStart + $keySize); 197 | 198 | // Iterate through all chunks 199 | while (true) { 200 | $pos = $data->position(); 201 | $chunkType = $data->readInt16LE(); 202 | $data->readInt16LE(); // headerSize 203 | $chunkSize = $data->readInt32LE(); 204 | if ($chunkType == self::RES_TABLE_TYPE_SPEC_TYPE) { 205 | $data->seek($pos); 206 | $this->processTypeSpec($data->copyBytes($chunkSize)); 207 | } else { 208 | if ($chunkType == self::RES_TABLE_TYPE_TYPE) { 209 | $data->seek($pos); 210 | $this->processType($data->copyBytes($chunkSize)); 211 | } 212 | } 213 | 214 | $data->seek($pos + $chunkSize); 215 | if ($data->position() == $data->size()) { 216 | break; 217 | } 218 | } 219 | } 220 | 221 | /** 222 | * @param SeekableStream $data 223 | */ 224 | private function processTypeSpec(SeekableStream $data) 225 | { 226 | $data->readInt16LE(); // type 227 | $data->readInt16LE(); // headerSize 228 | $data->readInt32LE(); // size 229 | $id = $data->readByte(); 230 | $data->readByte(); // res0 231 | $data->readInt16LE(); // res1 232 | $entriesCount = $data->readInt32LE(); 233 | 234 | // echo 'Processing type spec ' . $this->typeStringPool[$id - 1], PHP_EOL; 235 | $flags = array(); 236 | for ($i = 0; $i < $entriesCount; ++$i) { 237 | $flags[$i] = $data->readInt32LE(); 238 | } 239 | } 240 | 241 | /** 242 | * @param SeekableStream $data 243 | * @throws \Exception 244 | */ 245 | private function processType(SeekableStream $data) 246 | { 247 | $data->readInt16LE(); // type 248 | $headerSize = $data->readInt16LE(); 249 | $data->readInt32LE(); // size 250 | $id = $data->readByte(); 251 | $data->readByte(); // res0 252 | $data->readInt16LE(); // res1 253 | $entriesCount = $data->readInt32LE(); 254 | $entriesStart = $data->readInt32LE(); 255 | $config_size = $data->readInt32LE(); // config_size 256 | 257 | if ($headerSize + $entriesCount * 4 != $entriesStart) { 258 | throw new \Exception('HeaderSize, entriesCount and entriesStart are not valid.'); 259 | } 260 | 261 | // Skip the header data 262 | $data->seek($headerSize - $config_size); 263 | // Process config data TODO 未完成 264 | $config = $this->processConfig($data->copyBytes($config_size)); 265 | 266 | // Skip the config data 267 | // $data->seek($headerSize); 268 | 269 | // Start to get entry indices 270 | $entryIndices = array(); 271 | for ($i = 0; $i < $entriesCount; ++$i) { 272 | $entryIndices[$i] = $data->readInt32LE(); 273 | } 274 | 275 | // Get entries 276 | for ($i = 0; $i < $entriesCount; ++$i) { 277 | if ($entryIndices[$i] == -1) { 278 | continue; 279 | } 280 | 281 | $resourceId = ($this->packageId << 24) | ($id << 16) | $i; 282 | 283 | $data->readInt16LE(); // entry_size 284 | $entryFlag = $data->readInt16LE(); 285 | $entryKey = $data->readInt32LE(); 286 | 287 | $resourceIdString = '0x' . dechex($resourceId); 288 | $entryKeyString = $this->keyStringPool[$entryKey]; 289 | // echo 'Entry ' . $resourceIdString . ', key: ' . $entryKeyString; 290 | 291 | // Get the value (simple) or map (complex) 292 | if (($entryFlag & self::FLAG_COMPLEX) == 0) { 293 | // echo ', simple value type'; 294 | // Simple case 295 | $data->readInt16LE(); // value_size 296 | $data->readByte(); // value_res0 297 | $valueDataType = $data->readByte(); 298 | $valueData = $data->readInt32LE(); 299 | 300 | if ($valueDataType == self::TYPE_STRING) { 301 | $value = $this->valueStringPool[$valueData]; 302 | $this->putResource($resourceIdString, $value); 303 | // echo ', data: ' . $value; 304 | } else { 305 | if ($valueDataType == self::TYPE_REFERENCE) { 306 | $referenceIdString = '0x' . dechex($valueData); 307 | $this->putReferenceResource($resourceIdString, $referenceIdString); 308 | // echo ', reference: ' . $referenceIdString; 309 | } else { 310 | $this->putResource($resourceIdString, $valueData); 311 | // echo ', data: ' . $valueData; 312 | } 313 | } 314 | // echo PHP_EOL; 315 | } else { 316 | // echo ', complex value, not printed.', PHP_EOL; 317 | $data->readInt32LE(); // entry_parent 318 | $entryCount = $data->readInt32LE(); 319 | for ($j = 0; $j < $entryCount; ++$j) { 320 | $data->readInt32LE(); // ref_name 321 | $data->readInt16LE(); // value_size 322 | $data->readByte(); // value_res0 323 | $data->readByte(); // value_data_type 324 | $data->readInt32LE(); // value_data 325 | } 326 | } 327 | } 328 | } 329 | 330 | /** 331 | * @param SeekableStream $bytes 332 | * @return array 333 | */ 334 | private function processConfig($bytes) 335 | { 336 | $size = $bytes->size(); 337 | 338 | // 12 339 | $config['size'] = $bytes->readInt32LE(); 340 | $config['mcc'] = $bytes->readInt16LE(); 341 | $config['mnc'] = $bytes->readInt16LE(); 342 | $bytes->backSeek(-4); 343 | $config['imsi'] = $bytes->readInt32LE(); 344 | 345 | // 8 346 | $config['language'] = $bytes->read(2); 347 | $config['country'] = $bytes->read(2); 348 | $bytes->backSeek(-4); 349 | $config['locale'] = $bytes->read(4); 350 | 351 | // 8 352 | $config['orientation'] = $bytes->readByte(); 353 | $config['touchscreen'] = $bytes->readByte(); 354 | $config['density'] = $bytes->readInt16LE(); 355 | $bytes->backSeek(-4); 356 | $config['screenType'] = $bytes->readInt32LE(); 357 | 358 | // 8 359 | $config['keyboard'] = $bytes->readByte(); 360 | $config['navigation'] = $bytes->readByte(); 361 | $config['inputFlags'] = $bytes->readByte(); 362 | $config['inputPad0'] = $bytes->readByte(); 363 | $bytes->backSeek(-4); 364 | $config['input'] = $bytes->readInt32LE(); 365 | 366 | if ($size > 36) { 367 | // 8 368 | $config['screenWidth'] = $bytes->readInt16LE(); 369 | $config['screenHeight'] = $bytes->readInt16LE(); 370 | $bytes->backSeek(-4); 371 | $config['screenSize'] = $bytes->readInt32LE(); 372 | 373 | // 8 374 | $config['sdVersion'] = $bytes->readInt16LE(); 375 | $config['minorVersion'] = $bytes->readInt16LE(); 376 | $bytes->backSeek(-4); 377 | $config['version'] = $bytes->readInt32LE(); 378 | 379 | // 8 380 | $config['screenLayout'] = $bytes->readByte(); 381 | $config['uiMode'] = $bytes->readByte(); 382 | $config['smallestScreenWidthDp'] = $bytes->readInt16LE(); 383 | $bytes->backSeek(-4); 384 | $config['screenConfig'] = $bytes->readInt32LE(); 385 | 386 | // 10 387 | $config['screenWidthDp'] = $bytes->readByte(); 388 | $config['screenHeightDp'] = $bytes->readByte(); 389 | $bytes->backSeek(-4); 390 | $config['screenSizeDp'] = $bytes->readInt32LE(); 391 | 392 | // 4 393 | $config['localeScript'] = $bytes->readInt32LE(); 394 | 395 | // 8 396 | $config['localeVariant'] = $bytes->read(8); 397 | } 398 | 399 | return $config; 400 | } 401 | 402 | /** 403 | * @param $resourceId 404 | * @param $value 405 | */ 406 | private function putResource($resourceId, $value) 407 | { 408 | $key = strtolower($resourceId); 409 | if (array_key_exists($key, $this->resources) === false) { 410 | $this->resources[$key] = array(); 411 | } 412 | $this->resources[$key][] = $value; 413 | } 414 | 415 | /** 416 | * @param $resourceId 417 | * @param $valueData 418 | */ 419 | private function putReferenceResource($resourceId, $valueData) 420 | { 421 | $key = strtolower($resourceId); 422 | if (array_key_exists($key, $this->resources)) { 423 | $values = $this->resources[$key]; 424 | foreach ($values as $value) { 425 | $this->putResource($valueData, $value); 426 | } 427 | } 428 | } 429 | 430 | /** 431 | * @param $key 432 | * @return mixed 433 | */ 434 | public function getResources($key) 435 | { 436 | $key = strtolower($key); 437 | if (array_key_exists($key, $this->resources)) { 438 | return $this->resources[$key]; 439 | } 440 | 441 | return false; 442 | } 443 | 444 | /** 445 | * All resources 446 | */ 447 | public function getAllResources() 448 | { 449 | return $this->resources; 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /lib/ApkParser/SeekableStream.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class SeekableStream 14 | { 15 | public const LITTLE_ENDIAN_ORDER = 1; 16 | public const BIG_ENDIAN_ORDER = 2; 17 | /** 18 | * The endianess of the current machine. 19 | * 20 | * @var integer 21 | */ 22 | private static $endianess = 0; 23 | private $stream; 24 | private $size = 0; 25 | 26 | public function __construct($stream = null) 27 | { 28 | if (is_null($stream) || is_resource($stream) === false) { 29 | throw new \InvalidArgumentException('Stream must be a resource'); 30 | } 31 | $meta = stream_get_meta_data($stream); 32 | if ($meta['seekable'] === false) { 33 | $this->stream = self::toMemoryStream($stream); 34 | } else { 35 | $this->stream = $stream; 36 | } 37 | rewind($this->stream); 38 | fseek($this->stream, 0, SEEK_END); 39 | $this->size = ftell($this->stream); 40 | rewind($this->stream); 41 | } 42 | 43 | /** 44 | * @param $stream 45 | * @param int $length 46 | * @return resource 47 | */ 48 | private static function toMemoryStream($stream, $length = 0) 49 | { 50 | $size = 0; 51 | $memoryStream = \fopen('php://memory', 'wb+'); 52 | 53 | while (!\feof($stream)) { 54 | $buf = \fread($stream, 128); 55 | $bufSize = \strlen($buf); 56 | $size += $bufSize; 57 | 58 | if ($length > 0 && $size >= $length) { 59 | $over = $size - $length; 60 | \fputs($memoryStream, \substr($buf, 0, $bufSize - $over)); 61 | 62 | if ($over > 0) { 63 | \fseek($stream, -$over, SEEK_CUR); 64 | } 65 | break; 66 | } 67 | \fputs($memoryStream, $buf); 68 | } 69 | return $memoryStream; 70 | } 71 | 72 | /** 73 | * @param $length 74 | * @return SeekableStream 75 | */ 76 | public function copyBytes($length) 77 | { 78 | return new self(self::toMemoryStream($this->stream, $length)); 79 | } 80 | 81 | public function seek($offset) 82 | { 83 | fseek($this->stream, $offset); 84 | } 85 | 86 | public function backSeek($offset) 87 | { 88 | fseek($this->stream, $offset, SEEK_CUR); 89 | } 90 | 91 | /** 92 | * Check if we have reached the end of the stream 93 | * 94 | * @return bool 95 | */ 96 | public function eof() 97 | { 98 | return feof($this->stream); 99 | } 100 | 101 | /** 102 | * Obtain the current position in the stream 103 | * 104 | * @return int 105 | */ 106 | public function position() 107 | { 108 | return ftell($this->stream); 109 | } 110 | 111 | /** 112 | * @return int 113 | */ 114 | public function size() 115 | { 116 | return $this->size; 117 | } 118 | 119 | /** 120 | * @return int 121 | */ 122 | public function readByte() 123 | { 124 | return ord($this->read(1)); 125 | } 126 | 127 | /** 128 | * Obtain a number of bytes from the string 129 | * 130 | * @param int $length 131 | * @return string 132 | * @throws \RuntimeException 133 | */ 134 | public function read($length = 1) 135 | { 136 | // Protect against 0 byte reads when an EOF 137 | if ($length < 0) { 138 | throw new \RuntimeException('Length cannot be negative'); 139 | } 140 | if ($length == 0) { 141 | return ''; 142 | } 143 | 144 | $bytes = fread($this->stream, $length); 145 | if (false === $bytes || strlen($bytes) != $length) { 146 | throw new \RuntimeException('Failed to read ' . $length . ' bytes'); 147 | } 148 | return $bytes; 149 | } 150 | 151 | /** 152 | * Reads 2 bytes from the stream and returns little-endian ordered binary 153 | * data as signed 16-bit integer. 154 | * 155 | * @return integer 156 | */ 157 | public function readInt16LE() 158 | { 159 | if (self::isBigEndian()) { 160 | return self::unpackInt16(strrev($this->read(2))); 161 | } else { 162 | return self::unpackInt16($this->read(2)); 163 | } 164 | } 165 | 166 | /** 167 | * Returns whether the current machine endian order is big endian. 168 | * @return boolean 169 | */ 170 | private static function isBigEndian() 171 | { 172 | return self::getEndianess() == self::BIG_ENDIAN_ORDER; 173 | } 174 | 175 | /** 176 | * Returns the current machine endian order. 177 | * @return integer 178 | */ 179 | private static function getEndianess() 180 | { 181 | if (self::$endianess === 0) { 182 | self::$endianess = self::unpackInt32( 183 | "\x01\x00\x00\x00" 184 | ) == 1 ? self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; 185 | } 186 | return self::$endianess; 187 | } 188 | 189 | /** 190 | * Returns machine-endian ordered binary data as signed 32-bit integer. 191 | * 192 | * @param string $value The binary data string. 193 | * @return integer 194 | */ 195 | private static function unpackInt32($value) 196 | { 197 | list(, $int) = unpack('l*', $value); 198 | return $int; 199 | } 200 | 201 | /** 202 | * Returns machine endian ordered binary data as signed 16-bit integer. 203 | * 204 | * @param string $value The binary data string. 205 | * @return integer 206 | */ 207 | private static function unpackInt16($value) 208 | { 209 | list(, $int) = unpack('s*', $value); 210 | return $int; 211 | } 212 | 213 | /** 214 | * Reads 4 bytes from the stream and returns little-endian ordered binary 215 | * data as signed 32-bit integer. 216 | * 217 | * @return integer 218 | */ 219 | public function readInt32LE() 220 | { 221 | if (self::isBigEndian()) { 222 | return self::unpackInt32(strrev($this->read(4))); 223 | } else { 224 | return self::unpackInt32($this->read(4)); 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /lib/ApkParser/Stream.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Stream 14 | { 15 | /** 16 | * file strem, like "fopen" 17 | * 18 | * @var resource 19 | */ 20 | private $stream; 21 | 22 | /** 23 | * @param resource $stream File stream. 24 | * @return \ApkParser\Stream 25 | * @throws \Exception 26 | */ 27 | public function __construct($stream) 28 | { 29 | if (!is_resource($stream)) { 30 | // TODO : the resource type must be a regular file stream resource. 31 | throw new \Exception("Invalid stream"); 32 | } 33 | 34 | $this->stream = $stream; 35 | } 36 | 37 | /** 38 | * Jump to the index! 39 | * @param int $offset 40 | */ 41 | public function seek($offset) 42 | { 43 | fseek($this->stream, $offset); 44 | } 45 | 46 | /** 47 | * fetch the remaining byte into an array 48 | * 49 | * @param mixed $count Byte length. 50 | * @return array 51 | */ 52 | public function getByteArray($count = null) 53 | { 54 | $bytes = array(); 55 | 56 | while (!$this->feof() && ($count === null || count($bytes) < $count)) { 57 | $bytes[] = $this->readByte(); 58 | } 59 | 60 | return $bytes; 61 | } 62 | 63 | /** 64 | * check if end of filestream 65 | */ 66 | public function feof() 67 | { 68 | return feof($this->stream); 69 | } 70 | 71 | /** 72 | * Read the next byte 73 | * @return int 74 | */ 75 | public function readByte() 76 | { 77 | return ord($this->read()); 78 | } 79 | 80 | /** 81 | * Read the next character from stream. 82 | * 83 | * @param mixed $length 84 | * @return string 85 | */ 86 | public function read($length = 1) 87 | { 88 | return fread($this->stream, $length); 89 | } 90 | 91 | /** 92 | * Write a byte to the stream 93 | * 94 | * @param mixed $byte 95 | */ 96 | public function writeByte($byte) 97 | { 98 | $this->write(chr($byte)); 99 | } 100 | 101 | /** 102 | * Write a string to the stream 103 | * 104 | * @param mixed $str 105 | */ 106 | public function write($str) 107 | { 108 | fwrite($this->stream, $str); 109 | } 110 | 111 | /** 112 | * Write the stream to the given destionation directly without using extra memory like storing in an array etc. 113 | * 114 | * @param mixed $destination file path. 115 | * @throws \Exception 116 | */ 117 | public function save($destination) 118 | { 119 | $destination = new Stream(is_resource($destination) ? $destination : fopen($destination, 'w+')); 120 | while (!$this->feof()) { 121 | $destination->write($this->read()); 122 | } 123 | 124 | if (!is_resource($destination)) { // close the file if we opened it otwhise dont touch. 125 | $destination->close(); 126 | } 127 | } 128 | 129 | /** 130 | * Close the stream 131 | */ 132 | public function close() 133 | { 134 | fclose($this->stream); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /lib/ApkParser/Utils.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | class Utils 14 | { 15 | /** 16 | * @param $pattern 17 | * @param int $flags 18 | * @return array 19 | */ 20 | public static function globRecursive($pattern, $flags = 0) 21 | { 22 | $files = glob($pattern, $flags); 23 | 24 | foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { 25 | $files = array_merge($files, self::globRecursive($dir . '/' . basename($pattern), $flags)); 26 | } 27 | 28 | return $files; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/ApkParser/Xml.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | abstract class Xml 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /lib/ApkParser/lang/en.permissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "ACCESS_CHECKIN_PROPERTIES": { 3 | "desc": "Allows read\/write access to the \"properties\" table in the checkin database, to change values that get uploaded.", 4 | "flags": { 5 | "cost": false, 6 | "warning": false, 7 | "danger": false 8 | } 9 | }, 10 | "ACCESS_COARSE_LOCATION": { 11 | "desc": "Allows an app to access approximate location derived from network location sources such as cell towers and Wi-Fi.", 12 | "flags": { 13 | "cost": false, 14 | "warning": true, 15 | "danger": false 16 | } 17 | }, 18 | "ACCESS_FINE_LOCATION": { 19 | "desc": "Allows an app to access precise location from location sources such as GPS, cell towers, and Wi-Fi.", 20 | "flags": { 21 | "cost": false, 22 | "warning": true, 23 | "danger": false 24 | } 25 | }, 26 | "ACCESS_LOCATION_EXTRA_COMMANDS": { 27 | "desc": "Allows an application to access extra location provider commands", 28 | "flags": { 29 | "cost": false, 30 | "warning": false, 31 | "danger": false 32 | } 33 | }, 34 | "ACCESS_MOCK_LOCATION": { 35 | "desc": "Allows an application to create mock location providers for testing", 36 | "flags": { 37 | "cost": false, 38 | "warning": false, 39 | "danger": false 40 | } 41 | }, 42 | "ACCESS_NETWORK_STATE": { 43 | "desc": "Allows applications to access information about networks", 44 | "flags": { 45 | "cost": false, 46 | "warning": false, 47 | "danger": false 48 | } 49 | }, 50 | "ACCESS_SURFACE_FLINGER": { 51 | "desc": "Allows an application to use SurfaceFlinger's low level features.", 52 | "flags": { 53 | "cost": false, 54 | "warning": false, 55 | "danger": false 56 | } 57 | }, 58 | "ACCESS_WIFI_STATE": { 59 | "desc": "Allows applications to access information about Wi-Fi networks", 60 | "flags": { 61 | "cost": false, 62 | "warning": false, 63 | "danger": false 64 | } 65 | }, 66 | "ACCOUNT_MANAGER": { 67 | "desc": "Allows applications to call into AccountAuthenticators.", 68 | "flags": { 69 | "cost": false, 70 | "warning": false, 71 | "danger": false 72 | } 73 | }, 74 | "ADD_VOICEMAIL": { 75 | "desc": "Allows an application to add voicemails into the system.", 76 | "flags": { 77 | "cost": false, 78 | "warning": true, 79 | "danger": true 80 | } 81 | }, 82 | "AUTHENTICATE_ACCOUNTS": { 83 | "desc": "Allows an application to act as an AccountAuthenticator for the AccountManager", 84 | "flags": { 85 | "cost": false, 86 | "warning": true, 87 | "danger": true 88 | } 89 | }, 90 | "BATTERY_STATS": { 91 | "desc": "Allows an application to collect battery statistics", 92 | "flags": { 93 | "cost": false, 94 | "warning": false, 95 | "danger": false 96 | } 97 | }, 98 | "BIND_ACCESSIBILITY_SERVICE": { 99 | "desc": "Must be required by an AccessibilityService,to ensure that only the system can bind to it.", 100 | "flags": { 101 | "cost": false, 102 | "warning": false, 103 | "danger": false 104 | } 105 | }, 106 | "BIND_APPWIDGET": { 107 | "desc": "Allows an application to tell the AppWidget service which application can access AppWidget's data.", 108 | "flags": { 109 | "cost": false, 110 | "warning": false, 111 | "danger": false 112 | } 113 | }, 114 | "BIND_DEVICE_ADMIN": { 115 | "desc": "Must be required by device administration receiver, to ensure that only the system can interact with it.", 116 | "flags": { 117 | "cost": false, 118 | "warning": false, 119 | "danger": false 120 | } 121 | }, 122 | "BIND_INPUT_METHOD": { 123 | "desc": "Must be required by an InputMethodService, to ensure that only the system can bind to it.", 124 | "flags": { 125 | "cost": false, 126 | "warning": false, 127 | "danger": false 128 | } 129 | }, 130 | "BIND_NFC_SERVICE": { 131 | "desc": "Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it.", 132 | "flags": { 133 | "cost": false, 134 | "warning": false, 135 | "danger": false 136 | } 137 | }, 138 | "BIND_NOTIFICATION_LISTENER_SERVICE": { 139 | "desc": "Must be required by an NotificationListenerService, to ensure that only the system can bind to it.", 140 | "flags": { 141 | "cost": false, 142 | "warning": false, 143 | "danger": false 144 | } 145 | }, 146 | "BIND_PRINT_SERVICE": { 147 | "desc": "Must be required by a PrintService, to ensure that only the system can bind to it.", 148 | "flags": { 149 | "cost": false, 150 | "warning": false, 151 | "danger": false 152 | } 153 | }, 154 | "BIND_REMOTEVIEWS": { 155 | "desc": "Must be required by a RemoteViewsService, to ensure that only the system can bind to it.", 156 | "flags": { 157 | "cost": false, 158 | "warning": false, 159 | "danger": false 160 | } 161 | }, 162 | "BIND_TEXT_SERVICE": { 163 | "desc": "Must be required by a TextService (e.g.", 164 | "flags": { 165 | "cost": false, 166 | "warning": false, 167 | "danger": false 168 | } 169 | }, 170 | "BIND_VPN_SERVICE": { 171 | "desc": "Must be required by a VpnService, to ensure that only the system can bind to it.", 172 | "flags": { 173 | "cost": false, 174 | "warning": false, 175 | "danger": false 176 | } 177 | }, 178 | "BIND_WALLPAPER": { 179 | "desc": "Must be required by a WallpaperService, to ensure that only the system can bind to it.", 180 | "flags": { 181 | "cost": false, 182 | "warning": false, 183 | "danger": false 184 | } 185 | }, 186 | "BLUETOOTH": { 187 | "desc": "Allows applications to connect to paired bluetooth devices", 188 | "flags": { 189 | "cost": false, 190 | "warning": true, 191 | "danger": false 192 | } 193 | }, 194 | "BLUETOOTH_ADMIN": { 195 | "desc": "Allows applications to discover and pair bluetooth devices ", 196 | "flags": { 197 | "cost": false, 198 | "warning": true, 199 | "danger": false 200 | } 201 | }, 202 | "BLUETOOTH_PRIVILEGED": { 203 | "desc": "Allows applications to pair bluetooth devices without user interaction.", 204 | "flags": { 205 | "cost": false, 206 | "warning": true, 207 | "danger": false 208 | } 209 | }, 210 | "BRICK": { 211 | "desc": "Required to be able to disable the device (very dangerous!).", 212 | "flags": { 213 | "cost": false, 214 | "warning": true, 215 | "danger": true 216 | } 217 | }, 218 | "BROADCAST_PACKAGE_REMOVED": { 219 | "desc": "Allows an application to broadcast a notification that an application package has been removed.", 220 | "flags": { 221 | "cost": false, 222 | "warning": false, 223 | "danger": false 224 | } 225 | }, 226 | "BROADCAST_SMS": { 227 | "desc": "Allows an application to broadcast an SMS receipt notification.", 228 | "flags": { 229 | "cost": false, 230 | "warning": false, 231 | "danger": false 232 | } 233 | }, 234 | "BROADCAST_STICKY": { 235 | "desc": "Allows an application to broadcast sticky intents.", 236 | "flags": { 237 | "cost": false, 238 | "warning": false, 239 | "danger": false 240 | } 241 | }, 242 | "BROADCAST_WAP_PUSH": { 243 | "desc": "Allows an application to broadcast a WAP PUSH receipt notification.", 244 | "flags": { 245 | "cost": false, 246 | "warning": false, 247 | "danger": false 248 | } 249 | }, 250 | "CALL_PHONE": { 251 | "desc": "Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call being placed.", 252 | "flags": { 253 | "cost": true, 254 | "warning": true, 255 | "danger": false 256 | } 257 | }, 258 | "CALL_PRIVILEGED": { 259 | "desc": "Allows an application to call any phone number, including emergency numbers, without going through the Dialer user interface for the user to confirm the call being placed.", 260 | "flags": { 261 | "cost": true, 262 | "warning": true, 263 | "danger": true 264 | } 265 | }, 266 | "CAMERA": { 267 | "desc": "Required to be able to access the camera device.", 268 | "flags": { 269 | "cost": false, 270 | "warning": false, 271 | "danger": false 272 | } 273 | }, 274 | "CAPTURE_AUDIO_OUTPUT": { 275 | "desc": "Allows an application to capture audio output.", 276 | "flags": { 277 | "cost": false, 278 | "warning": false, 279 | "danger": false 280 | } 281 | }, 282 | "CAPTURE_SECURE_VIDEO_OUTPUT": { 283 | "desc": "Allows an application to capture secure video output.", 284 | "flags": { 285 | "cost": false, 286 | "warning": false, 287 | "danger": false 288 | } 289 | }, 290 | "CAPTURE_VIDEO_OUTPUT": { 291 | "desc": "Allows an application to capture video output.", 292 | "flags": { 293 | "cost": false, 294 | "warning": false, 295 | "danger": false 296 | } 297 | }, 298 | "CHANGE_COMPONENT_ENABLED_STATE": { 299 | "desc": "Allows an application to change whether an application component (other than its own) is enabled or not.", 300 | "flags": { 301 | "cost": false, 302 | "warning": false, 303 | "danger": false 304 | } 305 | }, 306 | "CHANGE_CONFIGURATION": { 307 | "desc": "Allows an application to modify the current configuration, such as locale.", 308 | "flags": { 309 | "cost": false, 310 | "warning": false, 311 | "danger": false 312 | } 313 | }, 314 | "CHANGE_NETWORK_STATE": { 315 | "desc": "Allows applications to change network connectivity state", 316 | "flags": { 317 | "cost": false, 318 | "warning": false, 319 | "danger": false 320 | } 321 | }, 322 | "CHANGE_WIFI_MULTICAST_STATE": { 323 | "desc": "Allows applications to enter Wi-Fi Multicast mode", 324 | "flags": { 325 | "cost": false, 326 | "warning": false, 327 | "danger": false 328 | } 329 | }, 330 | "CHANGE_WIFI_STATE": { 331 | "desc": "Allows applications to change Wi-Fi connectivity state", 332 | "flags": { 333 | "cost": false, 334 | "warning": false, 335 | "danger": false 336 | } 337 | }, 338 | "CLEAR_APP_CACHE": { 339 | "desc": "Allows an application to clear the caches of all installed applications on the device.", 340 | "flags": { 341 | "cost": false, 342 | "warning": false, 343 | "danger": false 344 | } 345 | }, 346 | "CLEAR_APP_USER_DATA": { 347 | "desc": "Allows an application to clear user data.", 348 | "flags": { 349 | "cost": false, 350 | "warning": false, 351 | "danger": false 352 | } 353 | }, 354 | "CONTROL_LOCATION_UPDATES": { 355 | "desc": "Allows enabling\/disabling location update notifications from the radio.", 356 | "flags": { 357 | "cost": false, 358 | "warning": false, 359 | "danger": false 360 | } 361 | }, 362 | "DELETE_CACHE_FILES": { 363 | "desc": "Allows an application to delete cache files.", 364 | "flags": { 365 | "cost": false, 366 | "warning": false, 367 | "danger": false 368 | } 369 | }, 370 | "DELETE_PACKAGES": { 371 | "desc": "Allows an application to delete packages.", 372 | "flags": { 373 | "cost": false, 374 | "warning": false, 375 | "danger": false 376 | } 377 | }, 378 | "DEVICE_POWER": { 379 | "desc": "Allows low-level access to power management.", 380 | "flags": { 381 | "cost": false, 382 | "warning": false, 383 | "danger": false 384 | } 385 | }, 386 | "DIAGNOSTIC": { 387 | "desc": "Allows applications to RW to diagnostic resources.", 388 | "flags": { 389 | "cost": false, 390 | "warning": false, 391 | "danger": false 392 | } 393 | }, 394 | "DISABLE_KEYGUARD": { 395 | "desc": "Allows applications to disable the keyguard", 396 | "flags": { 397 | "cost": false, 398 | "warning": false, 399 | "danger": false 400 | } 401 | }, 402 | "DUMP": { 403 | "desc": "Allows an application to retrieve state dump information from system services.", 404 | "flags": { 405 | "cost": false, 406 | "warning": false, 407 | "danger": false 408 | } 409 | }, 410 | "EXPAND_STATUS_BAR": { 411 | "desc": "Allows an application to expand or collapse the status bar.", 412 | "flags": { 413 | "cost": false, 414 | "warning": false, 415 | "danger": false 416 | } 417 | }, 418 | "FACTORY_TEST": { 419 | "desc": "Run as a manufacturer test application, running as the root user.", 420 | "flags": { 421 | "cost": false, 422 | "warning": false, 423 | "danger": false 424 | } 425 | }, 426 | "FLASHLIGHT": { 427 | "desc": "Allows access to the flashlight", 428 | "flags": { 429 | "cost": false, 430 | "warning": false, 431 | "danger": false 432 | } 433 | }, 434 | "FORCE_BACK": { 435 | "desc": "Allows an application to force a BACK operation on whatever is the top activity.", 436 | "flags": { 437 | "cost": false, 438 | "warning": false, 439 | "danger": false 440 | } 441 | }, 442 | "GET_ACCOUNTS": { 443 | "desc": "Allows access to the list of accounts in the Accounts Service", 444 | "flags": { 445 | "cost": false, 446 | "warning": false, 447 | "danger": false 448 | } 449 | }, 450 | "GET_PACKAGE_SIZE": { 451 | "desc": "Allows an application to find out the space used by any package.", 452 | "flags": { 453 | "cost": false, 454 | "warning": false, 455 | "danger": false 456 | } 457 | }, 458 | "GET_TASKS": { 459 | "desc": "Allows an application to get information about the currently or recently running tasks.", 460 | "flags": { 461 | "cost": false, 462 | "warning": false, 463 | "danger": false 464 | } 465 | }, 466 | "GET_TOP_ACTIVITY_INFO": { 467 | "desc": "Allows an application to retrieve private information about the current top activity, such as any assist context it can provide.", 468 | "flags": { 469 | "cost": false, 470 | "warning": false, 471 | "danger": false 472 | } 473 | }, 474 | "GLOBAL_SEARCH": { 475 | "desc": "This permission can be used on content providers to allow the global search system to access their data.", 476 | "flags": { 477 | "cost": false, 478 | "warning": false, 479 | "danger": false 480 | } 481 | }, 482 | "HARDWARE_TEST": { 483 | "desc": "Allows access to hardware peripherals.", 484 | "flags": { 485 | "cost": false, 486 | "warning": false, 487 | "danger": false 488 | } 489 | }, 490 | "INJECT_EVENTS": { 491 | "desc": "Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window.", 492 | "flags": { 493 | "cost": false, 494 | "warning": false, 495 | "danger": false 496 | } 497 | }, 498 | "INSTALL_LOCATION_PROVIDER": { 499 | "desc": "Allows an application to install a location provider into the Location Manager.", 500 | "flags": { 501 | "cost": false, 502 | "warning": false, 503 | "danger": false 504 | } 505 | }, 506 | "INSTALL_PACKAGES": { 507 | "desc": "Allows an application to install packages.", 508 | "flags": { 509 | "cost": false, 510 | "warning": true, 511 | "danger": true 512 | } 513 | }, 514 | "INSTALL_SHORTCUT": { 515 | "desc": "Allows an application to install a shortcut in Launcher", 516 | "flags": { 517 | "cost": false, 518 | "warning": true, 519 | "danger": true 520 | } 521 | }, 522 | "INTERNAL_SYSTEM_WINDOW": { 523 | "desc": "Allows an application to open windows that are for use by parts of the system user interface.", 524 | "flags": { 525 | "cost": false, 526 | "warning": false, 527 | "danger": false 528 | } 529 | }, 530 | "INTERNET": { 531 | "desc": "Allows applications to open network sockets.", 532 | "flags": { 533 | "cost": false, 534 | "warning": false, 535 | "danger": false 536 | } 537 | }, 538 | "KILL_BACKGROUND_PROCESSES": { 539 | "desc": "Allows an application to call killBackgroundProcesses(String).", 540 | "flags": { 541 | "cost": false, 542 | "warning": false, 543 | "danger": true 544 | } 545 | }, 546 | "LOCATION_HARDWARE": { 547 | "desc": "Allows an application to use location features in hardware, such as the geofencing api.", 548 | "flags": { 549 | "cost": false, 550 | "warning": true, 551 | "danger": false 552 | } 553 | }, 554 | "MANAGE_ACCOUNTS": { 555 | "desc": "Allows an application to manage the list of accounts in the AccountManager", 556 | "flags": { 557 | "cost": false, 558 | "warning": false, 559 | "danger": false 560 | } 561 | }, 562 | "MANAGE_APP_TOKENS": { 563 | "desc": "Allows an application to manage (create, destroy, Z-order) application tokens in the window manager.", 564 | "flags": { 565 | "cost": false, 566 | "warning": false, 567 | "danger": false 568 | } 569 | }, 570 | "MANAGE_DOCUMENTS": { 571 | "desc": "Allows an application to manage access to documents, usually as part of a document picker.", 572 | "flags": { 573 | "cost": false, 574 | "warning": false, 575 | "danger": false 576 | } 577 | }, 578 | "MASTER_CLEAR": { 579 | "desc": "Not for use by third-party applications.", 580 | "flags": { 581 | "cost": false, 582 | "warning": false, 583 | "danger": true 584 | } 585 | }, 586 | "MEDIA_CONTENT_CONTROL": { 587 | "desc": "Allows an application to know what content is playing and control its playback.", 588 | "flags": { 589 | "cost": false, 590 | "warning": false, 591 | "danger": false 592 | } 593 | }, 594 | "MODIFY_AUDIO_SETTINGS": { 595 | "desc": "Allows an application to modify global audio settings", 596 | "flags": { 597 | "cost": false, 598 | "warning": false, 599 | "danger": false 600 | } 601 | }, 602 | "MODIFY_PHONE_STATE": { 603 | "desc": "Allows modification of the telephony state - power on, mmi, etc.", 604 | "flags": { 605 | "cost": false, 606 | "warning": false, 607 | "danger": false 608 | } 609 | }, 610 | "MOUNT_FORMAT_FILESYSTEMS": { 611 | "desc": "Allows formatting file systems for removable storage.", 612 | "flags": { 613 | "cost": false, 614 | "warning": false, 615 | "danger": false 616 | } 617 | }, 618 | "MOUNT_UNMOUNT_FILESYSTEMS": { 619 | "desc": "Allows mounting and unmounting file systems for removable storage.", 620 | "flags": { 621 | "cost": false, 622 | "warning": false, 623 | "danger": false 624 | } 625 | }, 626 | "NFC": { 627 | "desc": "Allows applications to perform I\/O operations over NFC", 628 | "flags": { 629 | "cost": false, 630 | "warning": false, 631 | "danger": false 632 | } 633 | }, 634 | "PERSISTENT_ACTIVITY": { 635 | "desc": "This constant was deprecated in API level 9. This functionality will be removed in the future; please do not use. Allow an application to make its activities persistent.", 636 | "flags": { 637 | "cost": false, 638 | "warning": true, 639 | "danger": true 640 | } 641 | }, 642 | "PROCESS_OUTGOING_CALLS": { 643 | "desc": "Allows an application to monitor, modify, or abort outgoing calls.", 644 | "flags": { 645 | "cost": false, 646 | "warning": false, 647 | "danger": false 648 | } 649 | }, 650 | "READ_CALENDAR": { 651 | "desc": "Allows an application to read the user's calendar data.", 652 | "flags": { 653 | "cost": false, 654 | "warning": false, 655 | "danger": false 656 | } 657 | }, 658 | "READ_CALL_LOG": { 659 | "desc": "Allows an application to read the user's call log.", 660 | "flags": { 661 | "cost": false, 662 | "warning": false, 663 | "danger": false 664 | } 665 | }, 666 | "READ_CONTACTS": { 667 | "desc": "Allows an application to read the user's contacts data.", 668 | "flags": { 669 | "cost": false, 670 | "warning": false, 671 | "danger": false 672 | } 673 | }, 674 | "READ_EXTERNAL_STORAGE": { 675 | "desc": "Allows an application to read from external storage.", 676 | "flags": { 677 | "cost": false, 678 | "warning": false, 679 | "danger": false 680 | } 681 | }, 682 | "READ_FRAME_BUFFER": { 683 | "desc": "Allows an application to take screen shots and more generally get access to the frame buffer data.", 684 | "flags": { 685 | "cost": false, 686 | "warning": false, 687 | "danger": false 688 | } 689 | }, 690 | "READ_HISTORY_BOOKMARKS": { 691 | "desc": "Allows an application to read (but not write) the user's browsing history and bookmarks.", 692 | "flags": { 693 | "cost": false, 694 | "warning": false, 695 | "danger": false 696 | } 697 | }, 698 | "READ_INPUT_STATE": { 699 | "desc": "This constant was deprecated in API level 16. The API that used this permission has been removed.", 700 | "flags": { 701 | "cost": false, 702 | "warning": false, 703 | "danger": true 704 | } 705 | }, 706 | "READ_LOGS": { 707 | "desc": "Allows an application to read the low-level system log files.", 708 | "flags": { 709 | "cost": false, 710 | "warning": false, 711 | "danger": false 712 | } 713 | }, 714 | "READ_PHONE_STATE": { 715 | "desc": "Allows read only access to phone state.", 716 | "flags": { 717 | "cost": false, 718 | "warning": false, 719 | "danger": false 720 | } 721 | }, 722 | "READ_PROFILE": { 723 | "desc": "Allows an application to read the user's personal profile data.", 724 | "flags": { 725 | "cost": false, 726 | "warning": false, 727 | "danger": false 728 | } 729 | }, 730 | "READ_SMS": { 731 | "desc": "Allows an application to read SMS messages.", 732 | "flags": { 733 | "cost": false, 734 | "warning": false, 735 | "danger": false 736 | } 737 | }, 738 | "READ_SOCIAL_STREAM": { 739 | "desc": "Allows an application to read from the user's social stream.", 740 | "flags": { 741 | "cost": false, 742 | "warning": false, 743 | "danger": false 744 | } 745 | }, 746 | "READ_SYNC_SETTINGS": { 747 | "desc": "Allows applications to read the sync settings", 748 | "flags": { 749 | "cost": false, 750 | "warning": false, 751 | "danger": false 752 | } 753 | }, 754 | "READ_SYNC_STATS": { 755 | "desc": "Allows applications to read the sync stats", 756 | "flags": { 757 | "cost": false, 758 | "warning": false, 759 | "danger": false 760 | } 761 | }, 762 | "READ_USER_DICTIONARY": { 763 | "desc": "Allows an application to read the user dictionary.", 764 | "flags": { 765 | "cost": false, 766 | "warning": false, 767 | "danger": false 768 | } 769 | }, 770 | "REBOOT": { 771 | "desc": "Required to be able to reboot the device.", 772 | "flags": { 773 | "cost": false, 774 | "warning": true, 775 | "danger": true 776 | } 777 | }, 778 | "RECEIVE_BOOT_COMPLETED": { 779 | "desc": "Allows an application to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting.", 780 | "flags": { 781 | "cost": false, 782 | "warning": false, 783 | "danger": false 784 | } 785 | }, 786 | "RECEIVE_MMS": { 787 | "desc": "Allows an application to monitor incoming MMS messages, to record or perform processing on them.", 788 | "flags": { 789 | "cost": false, 790 | "warning": true, 791 | "danger": false 792 | } 793 | }, 794 | "RECEIVE_SMS": { 795 | "desc": "Allows an application to monitor incoming SMS messages, to record or perform processing on them.", 796 | "flags": { 797 | "cost": false, 798 | "warning": true, 799 | "danger": false 800 | } 801 | }, 802 | "RECEIVE_WAP_PUSH": { 803 | "desc": "Allows an application to monitor incoming WAP push messages.", 804 | "flags": { 805 | "cost": false, 806 | "warning": true, 807 | "danger": false 808 | } 809 | }, 810 | "RECORD_AUDIO": { 811 | "desc": "Allows an application to record audio", 812 | "flags": { 813 | "cost": false, 814 | "warning": true, 815 | "danger": false 816 | } 817 | }, 818 | "REORDER_TASKS": { 819 | "desc": "Allows an application to change the Z-order of tasks", 820 | "flags": { 821 | "cost": false, 822 | "warning": true, 823 | "danger": false 824 | } 825 | }, 826 | "RESTART_PACKAGES": { 827 | "desc": "This constant was deprecated in API level 8. The restartPackage(String) API is no longer supported.", 828 | "flags": { 829 | "cost": false, 830 | "warning": true, 831 | "danger": true 832 | } 833 | }, 834 | "SEND_RESPOND_VIA_MESSAGE": { 835 | "desc": "Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls.", 836 | "flags": { 837 | "cost": false, 838 | "warning": true, 839 | "danger": true 840 | } 841 | }, 842 | "SEND_SMS": { 843 | "desc": "Allows an application to send SMS messages.", 844 | "flags": { 845 | "cost": true, 846 | "warning": true, 847 | "danger": false 848 | } 849 | }, 850 | "SET_ACTIVITY_WATCHER": { 851 | "desc": "Allows an application to watch and control how activities are started globally in the system.", 852 | "flags": { 853 | "cost": false, 854 | "warning": false, 855 | "danger": true 856 | } 857 | }, 858 | "SET_ALARM": { 859 | "desc": "Allows an application to broadcast an Intent to set an alarm for the user.", 860 | "flags": { 861 | "cost": false, 862 | "warning": true, 863 | "danger": false 864 | } 865 | }, 866 | "SET_ALWAYS_FINISH": { 867 | "desc": "Allows an application to control whether activities are immediately finished when put in the background.", 868 | "flags": { 869 | "cost": false, 870 | "warning": true, 871 | "danger": true 872 | } 873 | }, 874 | "SET_ANIMATION_SCALE": { 875 | "desc": "Modify the global animation scaling factor.", 876 | "flags": { 877 | "cost": false, 878 | "warning": true, 879 | "danger": true 880 | } 881 | }, 882 | "SET_DEBUG_APP": { 883 | "desc": "Configure an application for debugging.", 884 | "flags": { 885 | "cost": false, 886 | "warning": true, 887 | "danger": true 888 | } 889 | }, 890 | "SET_ORIENTATION": { 891 | "desc": "Allows low-level access to setting the orientation (actually rotation) of the screen.", 892 | "flags": { 893 | "cost": false, 894 | "warning": true, 895 | "danger": true 896 | } 897 | }, 898 | "SET_POINTER_SPEED": { 899 | "desc": "Allows low-level access to setting the pointer speed.", 900 | "flags": { 901 | "cost": false, 902 | "warning": true, 903 | "danger": true 904 | } 905 | }, 906 | "SET_PREFERRED_APPLICATIONS": { 907 | "desc": "This constant was deprecated in API level 7. No longer useful, see addPackageToPreferred(String) for details.", 908 | "flags": { 909 | "cost": false, 910 | "warning": false, 911 | "danger": true 912 | } 913 | }, 914 | "SET_PROCESS_LIMIT": { 915 | "desc": "Allows an application to set the maximum number of (not needed) application processes that can be running.", 916 | "flags": { 917 | "cost": false, 918 | "warning": false, 919 | "danger": false 920 | } 921 | }, 922 | "SET_TIME": { 923 | "desc": "Allows applications to set the system time.", 924 | "flags": { 925 | "cost": false, 926 | "warning": false, 927 | "danger": false 928 | } 929 | }, 930 | "SET_TIME_ZONE": { 931 | "desc": "Allows applications to set the system time zone ", 932 | "flags": { 933 | "cost": false, 934 | "warning": false, 935 | "danger": false 936 | } 937 | }, 938 | "SET_WALLPAPER": { 939 | "desc": "Allows applications to set the wallpaper", 940 | "flags": { 941 | "cost": false, 942 | "warning": false, 943 | "danger": false 944 | } 945 | }, 946 | "SET_WALLPAPER_HINTS": { 947 | "desc": "Allows applications to set the wallpaper hints", 948 | "flags": { 949 | "cost": false, 950 | "warning": false, 951 | "danger": false 952 | } 953 | }, 954 | "SIGNAL_PERSISTENT_PROCESSES": { 955 | "desc": "Allow an application to request that a signal be sent to all persistent processes.", 956 | "flags": { 957 | "cost": false, 958 | "warning": false, 959 | "danger": false 960 | } 961 | }, 962 | "STATUS_BAR": { 963 | "desc": "Allows an application to open, close, or disable the status bar and its icons.", 964 | "flags": { 965 | "cost": false, 966 | "warning": false, 967 | "danger": false 968 | } 969 | }, 970 | "SUBSCRIBED_FEEDS_READ": { 971 | "desc": "Allows an application to allow access the subscribed feeds ContentProvider.", 972 | "flags": { 973 | "cost": false, 974 | "warning": false, 975 | "danger": false 976 | } 977 | }, 978 | "SUBSCRIBED_FEEDS_WRITE": { 979 | "desc": "", 980 | "flags": { 981 | "cost": false, 982 | "warning": false, 983 | "danger": false 984 | } 985 | }, 986 | "SYSTEM_ALERT_WINDOW": { 987 | "desc": "Allows an application to open windows using the type TYPE_SYSTEM_ALERT, shown on top of all other applications.", 988 | "flags": { 989 | "cost": false, 990 | "warning": false, 991 | "danger": false 992 | } 993 | }, 994 | "TRANSMIT_IR": { 995 | "desc": "Allows using the device's IR transmitter, if available", 996 | "flags": { 997 | "cost": false, 998 | "warning": false, 999 | "danger": false 1000 | } 1001 | }, 1002 | "UNINSTALL_SHORTCUT": { 1003 | "desc": "Allows an application to uninstall a shortcut in Launcher", 1004 | "flags": { 1005 | "cost": false, 1006 | "warning": true, 1007 | "danger": false 1008 | } 1009 | }, 1010 | "UPDATE_DEVICE_STATS": { 1011 | "desc": "Allows an application to update device statistics.", 1012 | "flags": { 1013 | "cost": false, 1014 | "warning": false, 1015 | "danger": false 1016 | } 1017 | }, 1018 | "USE_CREDENTIALS": { 1019 | "desc": "Allows an application to request authtokens from the AccountManager", 1020 | "flags": { 1021 | "cost": false, 1022 | "warning": false, 1023 | "danger": false 1024 | } 1025 | }, 1026 | "USE_SIP": { 1027 | "desc": "Allows an application to use SIP service", 1028 | "flags": { 1029 | "cost": false, 1030 | "warning": false, 1031 | "danger": false 1032 | } 1033 | }, 1034 | "VIBRATE": { 1035 | "desc": "Allows access to the vibrator", 1036 | "flags": { 1037 | "cost": false, 1038 | "warning": false, 1039 | "danger": false 1040 | } 1041 | }, 1042 | "WAKE_LOCK": { 1043 | "desc": "Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming", 1044 | "flags": { 1045 | "cost": false, 1046 | "warning": true, 1047 | "danger": false 1048 | } 1049 | }, 1050 | "WRITE_APN_SETTINGS": { 1051 | "desc": "Allows applications to write the apn settings.", 1052 | "flags": { 1053 | "cost": false, 1054 | "warning": false, 1055 | "danger": true 1056 | } 1057 | }, 1058 | "WRITE_CALENDAR": { 1059 | "desc": "Allows an application to write (but not read) the user's calendar data.", 1060 | "flags": { 1061 | "cost": false, 1062 | "warning": true, 1063 | "danger": false 1064 | } 1065 | }, 1066 | "WRITE_CALL_LOG": { 1067 | "desc": "Allows an application to write (but not read) the user's contacts data.", 1068 | "flags": { 1069 | "cost": false, 1070 | "warning": false, 1071 | "danger": true 1072 | } 1073 | }, 1074 | "WRITE_CONTACTS": { 1075 | "desc": "Allows an application to write (but not read) the user's contacts data.", 1076 | "flags": { 1077 | "cost": false, 1078 | "warning": false, 1079 | "danger": true 1080 | } 1081 | }, 1082 | "WRITE_EXTERNAL_STORAGE": { 1083 | "desc": "Allows an application to write to external storage.", 1084 | "flags": { 1085 | "cost": false, 1086 | "warning": false, 1087 | "danger": false 1088 | } 1089 | }, 1090 | "WRITE_GSERVICES": { 1091 | "desc": "Allows an application to modify the Google service map.", 1092 | "flags": { 1093 | "cost": false, 1094 | "warning": false, 1095 | "danger": true 1096 | } 1097 | }, 1098 | "WRITE_HISTORY_BOOKMARKS": { 1099 | "desc": "Allows an application to write (but not read) the user's browsing history and bookmarks.", 1100 | "flags": { 1101 | "cost": false, 1102 | "warning": false, 1103 | "danger": true 1104 | } 1105 | }, 1106 | "WRITE_PROFILE": { 1107 | "desc": "Allows an application to write (but not read) the user's personal profile data.", 1108 | "flags": { 1109 | "cost": false, 1110 | "warning": false, 1111 | "danger": true 1112 | } 1113 | }, 1114 | "WRITE_SECURE_SETTINGS": { 1115 | "desc": "Allows an application to read or write the secure system settings.", 1116 | "flags": { 1117 | "cost": false, 1118 | "warning": true, 1119 | "danger": false 1120 | } 1121 | }, 1122 | "WRITE_SETTINGS": { 1123 | "desc": "Allows an application to read or write the system settings.", 1124 | "flags": { 1125 | "cost": false, 1126 | "warning": true, 1127 | "danger": false 1128 | } 1129 | }, 1130 | "WRITE_SMS": { 1131 | "desc": "Allows an application to write SMS messages.", 1132 | "flags": { 1133 | "cost": false, 1134 | "warning": true, 1135 | "danger": false 1136 | } 1137 | }, 1138 | "WRITE_SOCIAL_STREAM": { 1139 | "desc": "Allows an application to write (but not read) the user's social stream data.", 1140 | "flags": { 1141 | "cost": false, 1142 | "warning": true, 1143 | "danger": false 1144 | } 1145 | }, 1146 | "WRITE_SYNC_SETTINGS": { 1147 | "desc": "Allows applications to write the sync settings", 1148 | "flags": { 1149 | "cost": false, 1150 | "warning": false, 1151 | "danger": false 1152 | } 1153 | }, 1154 | "WRITE_USER_DICTIONARY": { 1155 | "desc": "Allows an application to write to the user dictionary.", 1156 | "flags": { 1157 | "cost": false, 1158 | "warning": false, 1159 | "danger": false 1160 | } 1161 | } 1162 | } -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | 15 | ./test/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/ManifestTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('ApkParser\XmlParser') 17 | ->disableOriginalConstructor() 18 | ->setMethods(array('getXmlString')) 19 | ->getMock(); 20 | 21 | $file = __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'meta.xml'; 22 | $mock->expects($this->once())->method('getXmlString')->will($this->returnValue(file_get_contents($file))); 23 | 24 | $manifest = new \ApkParser\Manifest($mock); 25 | 26 | $this->assertEquals('0x7f0c0012', $manifest->getMetaData('com.google.android.gms.version')); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/ParserTest.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | use ApkParser\Parser; 12 | 13 | class ParserTest extends \PHPUnit\Framework\TestCase 14 | { 15 | /** 16 | * @var ApkParser\Parser 17 | */ 18 | private $subject; 19 | 20 | /** 21 | * @throws \PHPUnit\Framework\ExpectationFailedException 22 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 23 | */ 24 | public function testSanity() 25 | { 26 | $this->assertTrue(true); 27 | } 28 | 29 | /** 30 | * @throws \ApkParser\Exceptions\XmlParserException 31 | * @throws \PHPUnit\Framework\ExpectationFailedException 32 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 33 | */ 34 | public function testPermissions() 35 | { 36 | $permissions = $this->subject->getManifest()->getPermissions(); 37 | 38 | $this->assertCount(4, $permissions); 39 | $this->assertArrayHasKey('INTERNET', $permissions, "INTERNET permission not found!"); 40 | $this->assertArrayHasKey('CAMERA', $permissions, "CAMERA permission not found!"); 41 | $this->assertArrayHasKey('BLUETOOTH', $permissions, "BLUETOOTH permission not found!"); 42 | $this->assertArrayHasKey('BLUETOOTH_ADMIN', $permissions, "BLUETOOTH_ADMIN permission not found!"); 43 | } 44 | 45 | /** 46 | * @throws \ApkParser\Exceptions\XmlParserException 47 | * @throws \PHPUnit\Framework\ExpectationFailedException 48 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 49 | */ 50 | public function testApplication() 51 | { 52 | $application = $this->subject->getManifest()->getApplication(); 53 | 54 | $this->assertInstanceOf('ApkParser\Application', $application); 55 | $this->assertEquals($application->getIcon(), '0x7f020001'); 56 | $this->assertEquals($application->getLabel(), '0x7f050001'); 57 | } 58 | 59 | /** 60 | * @throws \ApkParser\Exceptions\XmlParserException 61 | * @throws \PHPUnit\Framework\ExpectationFailedException 62 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 63 | */ 64 | public function testIconResources() 65 | { 66 | $application = $this->subject->getManifest()->getApplication(); 67 | $resources = $this->subject->getResources($application->getIcon()); 68 | 69 | $expected = ['res/drawable-ldpi/ebhs.png', 'res/drawable-mdpi/ebhs.png', 'res/drawable-hdpi/ebhs.png']; 70 | $this->assertEquals($resources, $expected); 71 | } 72 | 73 | public function testGetMissingResources() 74 | { 75 | $this->assertFalse($this->subject->getResources('missing')); 76 | } 77 | 78 | /** 79 | * @throws \PHPUnit\Framework\ExpectationFailedException 80 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 81 | */ 82 | public function testIconStream() 83 | { 84 | $stream = $this->subject->getStream('res/drawable-hdpi/ebhs.png'); 85 | $icon = stream_get_contents($stream); 86 | $file = __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'ebhs.png'; 87 | $expected = file_get_contents($file); 88 | 89 | $this->assertIsResource($stream); 90 | $this->assertEquals(base64_encode($icon), base64_encode($expected)); 91 | } 92 | 93 | /** 94 | * @throws \ApkParser\Exceptions\XmlParserException 95 | * @throws \PHPUnit\Framework\ExpectationFailedException 96 | * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException 97 | */ 98 | public function testLabelResources() 99 | { 100 | $application = $this->subject->getManifest()->getApplication(); 101 | $resources = $this->subject->getResources($application->getLabel()); 102 | 103 | $expected = ['EBHS']; 104 | $this->assertEquals($resources, $expected); 105 | } 106 | 107 | /** 108 | * @throws Exception 109 | */ 110 | protected function setUp(): void 111 | { 112 | $file = __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'EBHS.apk'; 113 | $this->subject = new Parser($file, ['manifest_only' => false]); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /test/XmlParserTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('ApkParser\XmlParser') 11 | ->disableOriginalConstructor() 12 | ->setMethods(array('getXmlString')) 13 | ->getMock(); 14 | 15 | $file = __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'invalid.xml'; 16 | $mock->expects($this->once())->method('getXmlString')->will($this->returnValue(file_get_contents($file))); 17 | 18 | $this->expectException(\ApkParser\Exceptions\XmlParserException::class); 19 | 20 | $mock->getXmlObject(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/resources/EBHS.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tufanbarisyildirim/php-apk-parser/d482e460d540a16565fa9d1d70bb4c2292821c7c/test/resources/EBHS.apk -------------------------------------------------------------------------------- /test/resources/ebhs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tufanbarisyildirim/php-apk-parser/d482e460d540a16565fa9d1d70bb4c2292821c7c/test/resources/ebhs.png -------------------------------------------------------------------------------- /test/resources/invalid.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 64 | 65 | 66 | 67 | 68 | 70 | 71 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 87 | 88 | 90 | 91 | 92 | 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /test/resources/meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 72 | 73 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | 89 | 90 | 91 | 92 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 173 | 174 | 175 | 176 | --------------------------------------------------------------------------------