[add]添加cordova完整性检验

This commit is contained in:
林文杰 2020-12-31 16:38:20 +08:00
commit 0ea70324cb
21 changed files with 1259 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2016 Davide Doronzo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

6
README.md Normal file
View File

@ -0,0 +1,6 @@
Cescit-Integrity Cordova Plugin
=============================
本插件基于cordova-plugin-antitampering有apk完整性检验res资源检验assert资源检验的功能。
Supports Android

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "cordova-plugin-cescit-integrity",
"version": "1.0.0",
"author": {
"name": "lwj"
},
"description": "本插件基于cordova-plugin-antitampering有apk完整性检验res资源检验assert资源检验的功能。",
"cordova": {
"id": "cordova-plugin-cescit-integrity",
"platforms": [
"android"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/CESCIT/cordova-plugin-cescit-integrity.git"
},
"keywords": [
"ecosystem:cordova",
"cordova-android"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC"
}

47
plugin.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-cescit-integrity"
version="1.0.0">
<name>cescit-integrity</name>
<description>基于cordova-plugin-antitampering的文件完整性检验 - Android</description>
<author>lwj</author>
<license>MIT</license>
<engines>
<engine name="cordova" version=">=5.4" />
</engines>
<js-module src="www/AntiTampering.js" name="AntiTampering">
<clobbers target="cordova.plugins.cescitIntegrity" />
</js-module>
<!-- <hook type="after_prepare" src="scripts/clear_hashes.js" /> -->
<!-- <hook type="before_run" src="scripts/clear_hashes.js" /> -->
<hook type="before_build" src="scripts/clear_hashes.js" />
<hook type="before_run" src="scripts/save_assets_hashes.js" />
<hook type="before_run" src="scripts/save_res_hashes.js" />
<hook type="before_build" src="scripts/save_assets_hashes.js" />
<hook type="before_build" src="scripts/save_res_hashes.js" />
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="CescitIntegrity">
<param name="android-package" value="com.cescit.integrity.CescitIntegrity"/>
<param name="onload" value="true" />
</feature>
</config-file>
<source-file src="src/android/com/cescit/integrity/Config.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/CescitIntegrity.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/AssetsIntegrity.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/ResIntegrity.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/ApkIntegrity.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/DebugDetection.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/TamperingException.java" target-dir="src/com/cescit/integrity" />
<source-file src="src/android/com/cescit/integrity/HttpUtil.java" target-dir="src/com/cescit/integrity" />
</platform>
</plugin>

30
scripts/clear_hashes.js Normal file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env node
var helpers = require('./helpers');
module.exports = function (context) {
var fs = require('fs');
var fileList = ['AssetsIntegrity', 'ResIntegrity', 'ApkIntegrity'];
process.stdout.write('[完整性检验] Clearing assets hash from previous build\n');
helpers.getPlatformsList(context).forEach(function (platform) {
fileList.forEach(fileName => {
var source = helpers.getFileMapContent(context, platform, fileName);
var content = source.content;
let regexp = ''
if(fileName == 'AssetsIntegrity') regexp = /hashList\s*=.+\s*new.*(\(\d+\)[^\w]*)\);/
else if(fileName == 'ResIntegrity') regexp = /hashList\s*=.+\s*new.*(\(\d+\)[^\w]*)\);/
else if(fileName == 'ApkIntegrity') regexp = /hashList\s*=.+\s*new.*(\(\d+\)[^\w]*)\);/
content = source.content.replace(/\s*put\("[^"]+",\s"[^"]{64}"\);/g, '')
.replace(regexp, function (match, group) {
return match.replace(group, '()\n ');
});
try {
fs.writeFileSync(source.path, content, 'utf-8');
} catch (e) {
helpers.exit('Unable to write java class source at path ' + source.path, e);
}
})
});
};

View File

@ -0,0 +1,4 @@
module.exports = function (msg, exception) {
process.stdout.write('\n[完整性检验] ERROR! ' + msg + '\n');
throw new Error(exception);
};

View File

@ -0,0 +1,32 @@
var helpers = require('./');
module.exports = function (platform, fileName) {
var path = require('path');
var fs = require('fs');
var cordovaUtil = this.requireCordovaModule('cordova-lib/src/cordova/util');
var projectRoot = cordovaUtil.isCordova();
var platformPath = path.join(projectRoot, 'platforms', platform);
var sourceFile;
var content;
if (platform === 'android') {
var fileBasename = fileName;
var filePath = 'com/cescit/integrity/' + fileBasename + '.java';
try {
sourceFile = path.join(platformPath, 'app/src/main/java', filePath);
content = fs.readFileSync(sourceFile, 'utf-8');
} catch (_e) {
try {
sourceFile = path.join(platformPath, 'src', filePath);
content = fs.readFileSync(sourceFile, 'utf-8');
} catch (e) {
helpers.exit('Unable to read java class source at path ' + sourceFile, e);
}
}
}
return {
content: content,
path: sourceFile
};
};

View File

@ -0,0 +1,5 @@
module.exports = function () {
return (this.opts.platforms || this.opts.cordova.platforms || []).filter(function (platform) {
return this.opts.plugin.pluginInfo.getPlatformsArray().indexOf(platform) > -1;
}, this);
};

26
scripts/helpers/index.js Normal file
View File

@ -0,0 +1,26 @@
/**
* Exit script with custom error log.
* @param {string} msg - Error message.
* @param {Error} exception
*/
exports.exit = require('./error_exit');
/**
* Get the real list of platforms affected by a running plugin hook.
* @param {Object} context - Cordova context.
*/
exports.getPlatformsList = invokeHelper.bind(null, './get_platforms_list');
/**
* Detect if the context process is running with verbose option.
* @param {Object} context - Cordova context.
*/
exports.isVerbose = invokeHelper.bind(null, './is_verbose');
exports.getFileMapContent = invokeHelper.bind(null, './getFileMapContent');
function invokeHelper (path) {
var helper = require(path);
var context = arguments[1];
return helper.apply(context, Array.prototype.splice.call(arguments, 2));
}

View File

@ -0,0 +1,4 @@
module.exports = function () {
return this.opts && this.opts.options && this.opts.options.verbose ||
typeof this.cmdLine === 'string' && this.cmdLine.indexOf(' -verbose') > -1;
};

View File

@ -0,0 +1,111 @@
#!/usr/bin/env node
var crypto = require('crypto');
var helpers = require('./helpers');
module.exports = function (context) {
var path = require('path');
var fs = require('fs');
var cordovaUtil = context.requireCordovaModule('cordova-lib/src/cordova/util');
var platforms = context.requireCordovaModule('cordova-lib/src/platforms/platforms');
var projectRoot = cordovaUtil.isCordova();
process.stdout.write('[完整性检验] Saving a hash for each platforms asset \n');
function getPlatformAssets (dir) {
var assetsList = [];
var list = fs.readdirSync(dir);
list.map(function (file) {
var filePath = path.join(dir, file);
if (fs.statSync(filePath).isDirectory()) {
var subDirList = getPlatformAssets(filePath);
assetsList = assetsList.concat(subDirList);
}
if (fs.statSync(filePath).isFile()) {
assetsList.push(filePath);
}
});
return assetsList;
}
helpers.getPlatformsList(context).forEach(function (platform) {
var platformPath = path.join(projectRoot, 'platforms', platform);
var platformApi = platforms.getPlatformApi(platform, platformPath);
var platformInfo = platformApi.getPlatformInfo();
var platformWww = platformInfo.locations.www;
var platformAssets = path.resolve(platformWww, '../') // assets文件夹
var source = helpers.getFileMapContent(context, platform, 'AssetsIntegrity');
var content = source.content;
var hashes = getPlatformAssets(platformAssets).map(function (file) {
var fileName = file.replace(/\\/g, '/');
fileName = fileName.replace(platformAssets.replace(/\\/g, '/') + '/', '');
var hash;
var hashHex;
hash = crypto.createHash('sha256');
try {
hash.update(fs.readFileSync(file), 'utf8');
} catch (e) {
helpers.exit('Unable to read file at path ' + file, e);
}
hashHex = hash.digest('hex');
if (helpers.isVerbose(context)) {
process.stdout.write('Hash: ' + hashHex + ' < ' + fileName + '\n');
}
return {
// file: Buffer.from(fileName).toString('base64'),
file: fileName,
hash: hashHex
};
});
if (platform === 'android') {
content = content.replace(/\s*put\("[^"]+",\s"[^"]{64}"\);/g, '')
.replace(/hashList\s*=.+\s*new.*(\(\d+\)[^\w]*)\);/, function (match, group) {
return match.replace(group, '()\n' + tab());
})
.replace(/hashList\s*=.+\s*new.*(\(.*\))/, function (match, group) {
var replace = match.replace(group, '(' + (hashes.length || '') + ')');
if (hashes.length) {
replace += ' {{\n' + tab();
hashes.forEach(function (h) {
replace += tab(2) + 'put("' + h.file + '", "' + h.hash + '");\n' + tab();
});
replace += tab() + '}}';
}
return replace;
});
try {
fs.writeFileSync(source.path, content, 'utf-8');
} catch (e) {
helpers.exit('Unable to write java class source at path ' + source.path, e);
}
}
if (platform === 'ios') {
content = content.replace(/hashList = (@{([^}]*)});/, function (a, b) {
var list = '@{\n' + tab();
hashes.forEach(function (h) {
list += tab() + '@"' + h.file + '": @"' + h.hash + '",\n' + tab();
});
list += '}';
return a.replace(b, list);
});
try {
fs.writeFileSync(source.path, content, 'utf-8');
} catch (e) {
helpers.exit('Unable to write obj-c source at path ' + source.path, e);
}
}
});
function tab (size) {
var str = '';
for (var i = 0; i < (size || 1); i++) {
str += ' ';
}
return str;
}
};

415
scripts/save_res_hashes.js Normal file
View File

@ -0,0 +1,415 @@
#!/usr/bin/env node
var crypto = require('crypto');
var helpers = require('./helpers');
module.exports = function (context) {
var path = require('path');
var fs = require('fs');
var cordovaUtil = context.requireCordovaModule('cordova-lib/src/cordova/util');
var platforms = context.requireCordovaModule('cordova-lib/src/platforms/platforms');
var projectRoot = cordovaUtil.isCordova();
process.stdout.write('[完整性检验] Saving a hash for each platforms res \n');
function getHashList() {
let str = `
put("res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "d9cf644f86abcabfb29d7020e1f9bf51daf851ecb5b652eb60e668654cc68cd1")
put("res/drawable-mdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "6948c22791982b06d1d911fd6212ee29bf8a819196ec01f60f5ddcf852f5394f")
put("res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png", "d5c644b00ee79bd4f1fcb789ebbf89e79c0c6fea878dfbc4a8c64c3be34b5b03")
put("res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "6111c327f535aa76f4ceaa6b1f91c23252c3936f86e52100795594ae00e73b0f")
put("res/layout-v17/select_dialog_singlechoice_material.xml", "663a381007b438d9eeaa4f535323bc5a975e23bb2df0207b359545cb493d5347")
put("res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "dfe5008780f6427172ccb49cd0c2f5ccd0aaa3be3921b875362c9e65a08df76c")
put("res/drawable-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "500419896d42ee0818f210db317439df7458ad9f6f68f8b33690bd6f18c7d05a")
put("res/drawable-xxhdpi-v4/abc_list_divider_mtrl_alpha.9.png", "49903073ab23abfc11a55e1333eb2905c743e1b382006c27c15434fd76e0207c")
put("res/layout/zxing_capture.xml", "91c24841125766e60e238c2cc84eb50e98fd2accbdaa6bcfec4331e0f50cbf64")
put("res/drawable-ldrtl-xxxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "21b9bc9ca5bf09b7390dc9848395f81aca27dc6a44dd71f44a4718ee2698176a")
put("res/drawable-xxhdpi-v4/ic_action_remove.png", "a3bc9705eab4c61770b493dab577eb1cfc6d96e70c735a6cfd6da9b44028e728")
put("res/drawable-xxhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "178c653f6fdf2201b3eb6575839af350499f5c357a0fc2b7969a99824adf88f2")
put("res/drawable-xhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "8154b2e598f4cd681133db7634f89194ef4c7dd6d0f48eb48480f93234848400")
put("res/drawable-xxxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "323f7fbb7907c8df09c96bb41ae71ebc0b106a046ce4461510ad8f6424ed44a6")
put("res/layout/abc_action_bar_view_list_nav_layout.xml", "37d81d4b028ad5194a93fdbd2cb6f1b0e5b5317a2415e6d6534f7644a19a3a9b")
put("res/drawable/abc_list_selector_background_transition_holo_light.xml", "3553ef7b4d6984143bc4ee5bfd2556c1627cac4301c1800a1b7ae012c34905bc")
put("res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "540d0e23cd0c32a128c17bcee2982f1a47ef20ed1bf27fd0ee68db8ce1fabee4")
put("res/drawable-xxhdpi-v4/ic_action_next_item.png", "058f15a4afa192620e0bc8e4a7268f494a89495722337f889ed3109655a88d82")
put("res/color/abc_primary_text_disable_only_material_dark.xml", "b0eaa0e755bc2bf1d8cafe537920e0ceb507ac43f037806cbd2c4b9f92162cfe")
put("res/drawable-xxhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "b6e9825dcb2642d75a4ec0b4fbbec30c2fcd138c151290d3330682b588b3714f")
put("res/anim/abc_slide_in_bottom.xml", "18a752f91c63b61542bd743fab11657ccb0e11df795410c9cbb7b23b94651335")
put("res/drawable-mdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "089fd6dbea6ef15371447199ab8fef7f17d4acee7362f33692a565d4dafe1bdf")
put("res/layout/notification_template_part_chronometer.xml", "d51d12dbdbfa1db0238a35ba91610e628f35f95ded74eca929d243976ce46b36")
put("res/drawable-xhdpi-v4/abc_list_pressed_holo_light.9.png", "270ec2c94be001d62c967e5f5bebd180e24c48c10cfd7c108fd667378cfc95a9")
put("res/layout/abc_alert_dialog_button_bar_material.xml", "31ff21c6b8e73e150630521ab3d39fdc8b802731ec7cd9fd8792e044c470bba4")
put("res/drawable-ldrtl-mdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "40a015816f1754c099902ba322b2942d1f9fd91752615e160ad7dfd30a5abdec")
put("res/drawable-mdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "dfd5ae1cebc27420abc8ed8a789c3645caa665c1ea2a11577cb6468cb173f895")
put("res/drawable-land-mdpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "4eeb04eb02e6f07453e1d1972c5bea7be288c1100e508c4e106272360f8443d3")
put("res/layout/abc_action_menu_item_layout.xml", "5788c0d59e649fe9bfa1cc6b5d054695472fdc7734ce9e69dc023d421dc464ca")
put("res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_light.9.png", "51d83e107f732b13b915e32b185c78e4ad70fc6d0c23daa200f5ad710e7d4525")
put("res/drawable-xhdpi-v4/abc_list_pressed_holo_dark.9.png", "330791ec39b85952980ff0fa119f4360f6c68be646eae3fcc2e0129c485e017c")
put("res/drawable-mdpi-v4/ic_action_previous_item.png", "903b76da45e94a166cba5adcf1b0a07d24af13eb7b21252a8c7a06c8d81a7c83")
put("res/drawable-xxxhdpi-v4/abc_ic_clear_mtrl_alpha.png", "a7edc1182f345588539e644543e6f8ab4c4aec3b5919bd29becb93147622eb11")
put("res/drawable-mdpi-v4/abc_list_pressed_holo_dark.9.png", "50b3049da5275342546813eb61495d611bb82db21ef771846b9ca2b7d5c2d1fc")
put("res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "81fbbbc931441a4f6d64680a9d2f6c645c79209010a572f2ea0b732143039e73")
put("res/drawable-xxhdpi-v4/abc_list_pressed_holo_dark.9.png", "805839b77513ec41b4bf4b2e5ee12ed06138d319621eed15bb049d31165ce08b")
put("res/drawable/abc_list_selector_background_transition_holo_dark.xml", "2a67a427df005ed7b8d3aef7cdc131684ffa5d41d5a4734bffeeeaf1824f317c")
put("res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "0d1f5a3e36d02311640190fd768ee8d2607beba7a90b411be77a48a36427cb77")
put("res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "d19092254aa4133fba8b7795fb5db560ad5dcd16c6f79201bec31b0f1e9b608b")
put("res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "9be46560847b3596a1406bda8b7a8449477f3314206c9a19b53e6703653db4d7")
put("res/xml/config.xml", "e2a12496c7a21deeb3a7b5f9b595ab7bc83dda00a4207e04f03f09126df6ce1d")
put("res/layout/abc_search_dropdown_item_icons_2line.xml", "0853dd90f73c408322e623d532ae54fd3947618bb37f19d187efd568d2e0e571")
put("res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "7f537a60f30b3e56e0c091bae0747a3407fdcd9d648e6fa61ec6b44331a8bb0d")
put("res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png", "5ced2ab774853050255d7309e10b76217813d56f3f8ab8fb73ac3f635d90c676")
put("res/drawable/abc_cab_background_top_material.xml", "69b62b2562a9ac8df2efefb63c00c24dfc975e76c0b46561973a10642189394c")
put("res/layout-v17/abc_search_view.xml", "bfcc1746978149788fb7d4efbd4516464a7566583527b1edfdb0333b7fc7815c")
put("res/color-v11/abc_background_cache_hint_selector_material_dark.xml", "261c978a306f7388c522ca0af7edc0700b33d5eb83e08b9b9ddc513ab5c24d90")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "b3ca8774b4123d57482664a575a513369c7bda589ffca5c0b10a88b800c52235")
put("res/color/abc_primary_text_material_light.xml", "5859bc2fd64e2bba5f94a50a3bd586596bf3f6cd8945220d7e8c706c671484fa")
put("res/drawable-xhdpi-v4/abc_ic_go_search_api_mtrl_alpha.png", "c79caef928e8b856634a0ead1a31dad8f755ca02918ce3dbe26a2252e1300a96")
put("res/drawable-xhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "5c6a585c92347593e7344d8fd432487f9716fb6dec72ebd270ed9c8d5b597cb2")
put("res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "4ba313b3b8c9e8dd9536dc180d7ba6147b6954fa69a64e3bf38fc5dac5f1863f")
put("res/layout/abc_screen_simple_overlay_action_mode.xml", "3e8596db7c3f547bc578d0c246678282f8f1d92f3a328a72b52bac4ee1658cc5")
put("res/drawable-xhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png", "e689b9c84076ff5c339e2a3c6914321458d5c603a0596564e623442cc783e76c")
put("res/drawable-xhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "dd8dbab387958637a6b7d78c8d6cd88da4370b82c6f2767562b959e1db954b8e")
put("res/drawable-ldrtl-xxxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "753e4526bd3dd72cf154bb2dd6595e0bab1a002540aba793cb7f0e67dd8adfef")
put("res/drawable-xhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png", "31e46a844a40519da6b9168b7a631cbddf0137671c0cd25485c68a60a1f02fcb")
put("res/layout-v17/notification_template_big_media_narrow.xml", "1f037610ac5a05a48eb512aba265972637302c24706f2ea1e1b90d69280c1544")
put("res/drawable-ldrtl-xxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "8b21794e8bcfb520ee54d2c8162521fc74087d091a24ea3d22ffd1031a111fdb")
put("res/drawable-xxhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "966103c0bb0723292dfbc415653363cd4af2d874b7762a5c197a9a5aa1997330")
put("res/drawable-ldrtl-xxxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "3c287f4b4f894271811814a21408129444d0c79c51cd5729054d65c108b2098d")
put("res/color/abc_primary_text_disable_only_material_light.xml", "d233aef93574787c825c4f41b796ca667ab2d58e8769f1dc01ac611fbdbb4585")
put("res/drawable-xhdpi-v4/ic_action_remove.png", "548204063fbffed3d0458abad54a6a66eb09ea374eb6a9477c60bf199f70d281")
put("res/anim/abc_fade_in.xml", "aac9596dcef2ac796b74f2c2b4c149e9a66b004e864b37e82270752c66b1234d")
put("res/drawable-ldrtl-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "0df6d1fe57b9b28bac3a6a2b82941bcddab7e616a025201aacbe5e90c48c2068")
put("res/drawable-land-ldpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable-xhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "ed2b544497195069d55663bd91b5cbfa5c732b9d4d264ef201394d8ef59deb6e")
put("res/drawable/abc_seekbar_thumb_material.xml", "23aa9a856885c822bee0f578d1a2f17fe4c67e08281223a4669850b6a5e588ef")
put("res/anim/abc_fade_out.xml", "b13a8275d8ff8077b29b8413c6809ca3ff05fc16698ac2564ffc3b3325cf8302")
put("res/anim/abc_popup_exit.xml", "54702462887e035398f7a686b146e0c0660951f57faef59b7d4dbce21231aa6a")
put("res/drawable-hdpi-v4/ic_action_next_item.png", "8d802c3a172ebb13ea9fab6371cf2da9e03ce3cff2cd1fc924eec446a8f19cde")
put("res/color/abc_search_url_text.xml", "01a8d0346e9e0e932fac0dbe2f9329589109651e208905efe700518f2d756858")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "b78d97845a150185ff66371398582deddeccc81c4562b7ef987c3fd6c0a7631e")
put("res/drawable-xhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "0f5bd2f01b9689db08e4de977078e856427b126674afa8ebe7f0a9ff80aceea2")
put("res/drawable-xxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "6a42b5738417c10db0d053cdffbbd6667a94d614f449d47e6c435126da47c599")
put("res/drawable-xhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "4914c1f7b9f7185e0361aa4ea6bcc7b6e45a95d534b8f8299282ba45371734ed")
put("res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "e81784cdc8ac38373621e586d28d488d585ccf2d695759ed611d848d2bf04ca7")
put("res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "893e34d7adb3ad5d8ec6b443b0791ac1dd77b8e43496e43a1e2e1f6e5f0af975")
put("res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "b634d2fb563fb2c7053f3d2831074bac9a06bb53843394bcc4f900ed5fb655e7")
put("res/drawable-xxxhdpi-v4/abc_ic_search_api_mtrl_alpha.png", "e844c8feb07a35c300868ee6bdf72e112523a421933494586bf96015f2a4e4b8")
put("res/drawable-hdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "39aa138b792f6c1e1df99e0c1b748406b50aa6da3a864345f11bdedb3c0710a7")
put("res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "74a6c82d92bd4a42ba5a2a8f819c2dfee5fecfdf29a8539b920f0a239f27418f")
put("res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "e88c61d8f5bdbc2b21024a8f2fd69aae679d3ea4f77b4d6e66dc95a792ec6365")
put("res/layout-v21/abc_screen_toolbar.xml", "69892161f0b97e9ba9c06b00b91c0c725fd9289caac51ebdafee7f2455d72197")
put("res/drawable-hdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "9aca579e09ed6d8a1eb275b59248755f8a117c05b96178232d31d66ea327971c")
put("res/drawable-land-xhdpi-v4/screen.png", "0399d3e0e58cef3d3c47c892e9f1ffcfc43b96e937c67a891a42bdbdd7f9a23d")
put("res/mipmap-ldpi-v4/icon.png", "7a650c26e007c3f59977f98c292ba3625b6c977572e92e539c0f4e451cab5734")
put("res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "5080b07eb486ba05ede737b567eb2bb89d7b79a3edb5c2ca8141c6eba012b75d")
put("res/drawable-mdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "2be74c8cb7b5f25da58130799a22ca9435de80153a33a7dbbd3eaf9c8a96cb1d")
put("res/drawable-ldrtl-xxxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "160f6327240b59ec3534eefe0d4ea6dbd585e01d1357d870e910c5594016dc96")
put("res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "c7a19902a30c635c4708adc2e0c2911fbdb30fa8baf8878e96f44a8c9c012f65")
put("res/drawable-xxxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "1eb6da19924fabb0116fca45176fe1f4061708f5451e9844de332cb1e413e114")
put("res/drawable/abc_list_selector_holo_light.xml", "a3704ca7cc4c35254cc4719f675a8fa522935bd6f5bba1d0c94f6b3a091ed552")
put("res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "02ad0ea6ff5a560e947452c7d64f679afa2056b44f86ea3b707a1cb175c2ceb0")
put("res/drawable-mdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "dc02a2cc31bace5e8d4930f24af0e6f3de60ea3d991772c107a45f2af56bf957")
put("res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "18c6c39be0e5d67eed7006dd262f3e850f1d83aca242d836a208fb1f1e3638eb")
put("res/drawable-ldrtl-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "641ad19d3467a8e5c4d9714eb7581608de2843f19e9a902a4e9223be0661fb87")
put("res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png", "ad4d6c2d1a343d36781e16e81479c4a4cf75829d1ba2dce23443ed22f909540c")
put("res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "97caeaf819a086da7ff269296eda8b3899ccda2859820553772c2a9ed92b0c1d")
put("res/drawable-xhdpi-v4/abc_list_focused_holo.9.png", "671d27e5a4b42111174b888d57118e05075a556d703bd54f9335202d2a416791")
put("res/drawable-ldrtl-mdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "fe3e9afafacc6d85d8c92bdb5032d84652432d759570909847fa690b67efc137")
put("res/drawable-xhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "a3c71fec76e45cf16b5b6e508646217539fe6467c5e9fc27f9458b15c6df45fe")
put("res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "239d602c9c65f156fe024613207955ac8fbdd395ae6ec3efa51be98e3a4473f4")
put("res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "2ab0d18aa581997b2d36ac191151273995b212d3ac2e378ee2497e8aee81bfa6")
put("res/drawable-xxhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "4cdcafce259e3beb0cdcfccd969f6b18fdab421870934715cb4e0272230a36c8")
put("res/drawable-hdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "b769fc3384d88cbdcfdcfa316bc372a52b3e3976b87590bb2820e11edb9a00d9")
put("res/drawable-mdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "9f68c3256c42aae292504cb7ede8935e1f9c82bdb31eb0d2a55ca0c62ab810b6")
put("res/drawable-xxhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png", "c3402146e7228cb12772aad91fd071bcab4d668387a5da9b9a47bba8a5bfc7f6")
put("res/drawable-v21/abc_action_bar_item_background_material.xml", "8edbac0403d1abd530ee523971573d4c306a7a303f009f0b7f3befebab52e9db")
put("res/drawable-hdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png", "9ab4435bd62894ca412cd86419c477cd66b14a6b660f316c249a88066006d505")
put("res/xml/file_paths.xml", "e5a20dcc6765209234b2de6098cb99efa270649319199eb00453d1cecded9b6d")
put("res/layout/abc_dialog_title_material.xml", "b3393728c23229c6b0d9600f2240fc8616a925a0159628211f4a744361da9c2d")
put("res/layout/notification_template_part_time.xml", "e3fff5c2c216ebb732be9bbf9c214288548da591f9927752010790bce243223d")
put("res/drawable-xhdpi-v4/abc_ic_clear_mtrl_alpha.png", "287078c9586e942bd0d2a3d3e82db9d8d83f63bcf0d38e8ea148117418b313b7")
put("res/drawable-hdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "bcf9e688a1710c320c24f682ad26d12cd26b4b5e16e3a01a3ee690e486d57a95")
put("res/drawable-mdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "387c23e784744e75a3611ce17ed156f1c18852c6b025a94d16b13c0b10ac4410")
put("res/drawable-xxhdpi-v4/abc_ic_clear_mtrl_alpha.png", "93b3126fb85e3934cdef24c5f695c455688056171d14b462245fdc5febb10694")
put("res/drawable/abc_dialog_material_background_dark.xml", "cb9ce61156ab53d6344566fa385d7dfefd75af30c37cbddfbe9446515e5933cb")
put("res/drawable-port-xxhdpi-v4/screen.png", "ad1ac21edfdff36e6ca67afe850caa99d13e026c8fb09cf98d935ca493870ba0")
put("res/anim/abc_shrink_fade_out_from_bottom.xml", "e1192ab74c1bf01b33726f22ec05ed5329cb20079c5c77e5dad18f9692da96d0")
put("res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "cb93f48592ac219831b184b9e8d667edb48d13baca83b16fffef49dcc67b91f7")
put("res/drawable-xxhdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png", "68f02964d1eb0e1095cf76030bdb4ccc4d3bed858dd0819cbb2d6608b3c5e82f")
put("res/drawable/abc_dialog_material_background_light.xml", "ec2c6cd2099d681aa8423c6e6bcbb0a0b5c44fcdc56ac8b63cd724b287735003")
put("res/layout-v17/abc_alert_dialog_button_bar_material.xml", "ad4bedea15c039291e4f5668b3114ca8723ddb2da042568831b37815e6100c60")
put("res/drawable-hdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "774a7c9a0175ac0d1e3e87f296e62b6b1597aceea8486d94e4cebce3875b003e")
put("res/layout/select_dialog_multichoice_material.xml", "137466266c666166c43bc5b02fbbe986c6bfd7ada19b0fd6ab30b4b01050f5a6")
put("res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "00e20ad3da7eedc2389f24c48bab875075c6dcfc902c054cd0e89f9bee02f92a")
put("res/drawable-xxhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png", "2cf5ecdf6620a0e3a9f9ce3ce787e25cc05fdbe9c1d3c51dac2fe6f496074cab")
put("res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "ebcb76558e45a7f4c6692aa617173d40c41030034646510f0c76760e9b991d77")
put("res/drawable-xhdpi-v4/abc_popup_background_mtrl_mult.9.png", "fd1d8ff15f443fed99f64bb2de4c8e59148e7f45f0272c9388a624b3fdb5bf47")
put("res/drawable-xxhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "450bf8ea02097bc27ac7e21fa40fdc4e4ad521faf2e6bd1765711cd2c02c59b5")
put("res/layout/abc_action_mode_bar.xml", "26e44e7cff3de1aa7d927acff7aeb0a4cddb0f872a277710944c9a85c984269e")
put("res/anim/abc_popup_enter.xml", "414f580b4dc1f808c834f1d90dd2c7db9b7660e6465ec5420b70e55405fb9c9f")
put("res/drawable-hdpi-v4/abc_list_focused_holo.9.png", "a2f1a37af8e699320a2fadbe54eeaa6112d5a3522d57d682edf04fe97be3b47e")
put("res/layout/notification_media_action.xml", "3d27932335f2e4d9ee922909174332f6b0b40277705dd3f5df32deb5dcddd31b")
put("res/drawable-land-hdpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable-xhdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png", "4aa8bc81c7e08307255e73c16afedd2c97fd37a65dbdf2fdbbf9f9e37aff3758")
put("res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "afedf965914f9e0bb79f57f9083c4f44972f2e8c69f2645a9e12dfe648f22db5")
put("res/drawable-mdpi-v4/ic_action_remove.png", "fd5b864e446c631b5a41f5d40ff3e522c3073f8d651eb7fa1eb60b80cb42c85d")
put("res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "4bb4e2ec69ded3e748a26522b90a3d1318795687787374a05dc711f2925b4464")
put("res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png", "f0bc6f14305322192eb32eddcd3649025c712f8eec3cfcb5b298d7f4708073f5")
put("res/drawable-port-hdpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable/abc_item_background_holo_dark.xml", "6cc5a10d3387923b2ca66b5daa16b8524201f21ffac8236036b59c76a3e6ef44")
put("res/drawable-xxhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "f4812c6538630315d02cc3a182ba3fcfb85868a2aa98318ec5dd63677351f872")
put("res/drawable-mdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "66055f4b925daef0e5640a8e3075cd7b176a34da388085d52857d5c6f38ba632")
put("res/layout-v17/abc_alert_dialog_material.xml", "a198b24b9135e8a03d27d288ef4a9cf012b9a63c21f7ccf4da61de80dad7d62a")
put("res/drawable-ldrtl-xxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "ee0e3c601dbf603d7001b7ef4cbdb237a959734c9649dd211b0bf615b6ff4de1")
put("res/drawable-xxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "8c6e2a3c33890d72be345310e6e531778c25b9c9b143762c6c2bdee88f5fb0d0")
put("res/mipmap-mdpi-v4/icon.png", "7a650c26e007c3f59977f98c292ba3625b6c977572e92e539c0f4e451cab5734")
put("res/layout/abc_list_menu_item_checkbox.xml", "6b742ec907cd9ce87bbadfdc83b34e570a6ae1ec760364ddd17c3365e89066e8")
put("res/color/abc_secondary_text_material_dark.xml", "4e82e40e26ae5947329110f135b30ee5883d633689f3ab3f20ea0f68f1737efc")
put("res/layout-v17/abc_dialog_title_material.xml", "78fa8892acc354daa4b030b0d49767262f27b659960b81f92c1a3a129d19fa1a")
put("res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "52a0358e54439373ca39f99cd83cf3a7be73c257f07fae83edd83c9b4891895d")
put("res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "7442cda653acbacdf9aef256aa191e5ebb6071a1747312aec45e1db8252a3cfb")
put("res/drawable-port-xhdpi-v4/screen.png", "0399d3e0e58cef3d3c47c892e9f1ffcfc43b96e937c67a891a42bdbdd7f9a23d")
put("res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "f5ebab3a4b8712f651cd7e42a17a4d0577c3e3deb89e43123d6180c7f6d5137b")
put("res/layout/abc_search_view.xml", "d86ff6a808854f2071c1c9eba22b1d6a8b984319acf108070c3cec77d47f82e3")
put("res/drawable-mdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "1db8f8301b62f43b1f05faf082944e8be93eaa9b54669a406321e1b7ae9b05e8")
put("res/drawable-xxhdpi-v4/abc_popup_background_mtrl_mult.9.png", "4268b15d37eb27ec7ac1bb221a57000cede389fd34beaf75e268afb380901152")
put("res/drawable-mdpi-v4/abc_list_divider_mtrl_alpha.9.png", "0ef7b3d9f9d890a48e4fccc0db07315bd6fcca7049452e20a27a69bd22080415")
put("res/drawable-xxhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "9b6ad33830a9fa48796632fffd0a5386cce8ead83fa7265fb1a96bd44d479306")
put("res/layout/notification_template_media.xml", "208f7b22a6553723c1c60d971fd5fed0400ea1a180f265353a33d2a9bd5436ff")
put("res/drawable-mdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "5f997c46e51b3726b57a582f13663aedfeed55e4e61fcfe6dcf9999ead38f1d4")
put("res/drawable-hdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "44b4d2e07f32af386071fac95b80581e3c955b5e2281749d42774de9dfc87535")
put("res/drawable/abc_ratingbar_full_material.xml", "c323ab086275b807a25d041108bf3b1e73b1291bd276f3fbfbfe0f298766974e")
put("res/drawable-hdpi-v4/abc_ic_clear_mtrl_alpha.png", "e394bbb629366e5727227fdee2d3e3ad9bc5759950a8b358bbf5a4777ffe968d")
put("res/layout/notification_template_lines.xml", "0f6ca4f3efcbfd75584343039fe374222e89162ae1895413b76a930f4554d0df")
put("res/drawable-xhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "94b80df3ae6d8fbbb43ca98f062c7083ffbdf604715e1610a9a622f927a6fcdb")
put("res/layout/support_simple_spinner_dropdown_item.xml", "596b32eee9c6dc78af72f86bd82015d755778399ab4de6e9520706dd19bee4ef")
put("res/drawable-xhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "052762422b60e16802dd4dcdbc998f9c2ef911049e086592650faf895ec2bcd4")
put("res/drawable-ldrtl-xxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "ebd1e1432b6a54cc6161da7f69837e8fa45ed95eb196b421d693fffb040be7be")
put("res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "079843966864bf4099457cb72f1febe7c57bb5a70bf0f544a9169a078b7a5b01")
put("res/drawable-xxxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "4b787425a2b1eabb721cd99bd23ef235db80f41900a66028c2872fa068011078")
put("res/drawable-ldrtl-mdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "0f079710ca543c4c7042d0a463764c07ba6ba4bda26ec9b625c26485c98fc569")
put("res/drawable-xxhdpi-v4/abc_list_focused_holo.9.png", "8c6846f4105ef1c02107e842142e9ce60b08819296e9510b2d0c12cf4560c5e1")
put("res/drawable-xxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "d523fe7dc93908f07a61569bfc52f4be6e9c6033775d74394d18566832ccc408")
put("res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "0eedc51deea0c0f3f675a400d667eb476553b92cbd12683b6154e36306031c19")
put("res/layout/abc_select_dialog_material.xml", "15a1a201de1c2f663436eecee51b80545aa6f5f93811a45b324165a5e8716435")
put("res/anim/abc_slide_in_top.xml", "05cc140039277e0a2299e4d1650ee39f7d12ff5e09cecf84067c9f2f340ecd06")
put("res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png", "0ef7b3d9f9d890a48e4fccc0db07315bd6fcca7049452e20a27a69bd22080415")
put("res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png", "24e31720f77bc442bfd450d80747a99db2df3675a53447a291622006df52815a")
put("res/drawable-mdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "cacfc7acb35eb382effa1b8ee9881e1be435988bc98db9bf08199c3b6f8bca82")
put("res/layout-v17/notification_template_part_time.xml", "ee3fefac46bdfe73e01c2775944cd3cc2acab99d7c657efe20a3cc56a08a4805")
put("res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "71a2ba63a5d4e91f7c14324fa1c3eb9290b73cb7b3c7828018d05adb1cfaab45")
put("res/drawable-xhdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png", "e00c96c08036d89fc1fbe27df31257ce08ecaf2e06806786f3751ba7c970ff91")
put("res/color/abc_primary_text_material_dark.xml", "116a77ff0f38762bc4c47fcd4e4157490dc970625415ddebc2dfeb9aa17970f5")
put("res/drawable-xhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "2ae7387b4db93f8ecbc01d288b752d41373ce7b7d808969fca1e3b2e9d049219")
put("res/drawable-mdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "c618fafa6107721f6b07922ab06ed1922074412c7963dfcc9e34e1db93daacd5")
put("res/layout-v17/notification_template_part_chronometer.xml", "5e800e8032e365bd2f4f2964bbd3f2ec2ea443201ca06c47590bb346e72929cd")
put("res/drawable-xxxhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "add9abce47185fdac6290fa13cc9cbf46cf4148c7dbf4f3147f0e7b821ca223f")
put("res/drawable-ldrtl-hdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "8945707810ae4c8b568981bdcb74fcc92998ea09045f18649d587ea75ed8b985")
put("res/color-v11/abc_background_cache_hint_selector_material_light.xml", "ebf2196624ef10188cd1a0935b5426b2fdf8232a362277a57d09c4a1f2c507da")
put("res/drawable-mdpi-v4/abc_popup_background_mtrl_mult.9.png", "9e96a642ab9139cca3fb822ce199c711443087b5a7463e0c7fed012d9a773285")
put("res/layout/abc_popup_menu_item_layout.xml", "88986f7cc025876a7093ff01e98f0df8a8f452a43bc1b6438b089d4d2036cea6")
put("res/drawable-xxhdpi-v4/abc_ic_search_api_mtrl_alpha.png", "269f388a6a672af16e49203bce389020f51da34b43e7117e954c3cc0ab96c840")
put("res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "523733ec9c1ed308943cfb03770d64909c02ea6e866d535d389f9ae663a4c78f")
put("res/layout/abc_expanded_menu_layout.xml", "9d026182191a5c46211ba40fd2abf85483bfec033e28d21895195aa27b5aea0c")
put("res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "8dd453207afc153e8f1712fb630568e05cf2697fa22ca1789e53c247de2cb960")
put("res/drawable-xhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "3c93dc6550e031dec53f2c1646b46fe52e6c574a7b5eddd33d029100363df916")
put("res/xml/provider_paths.xml", "2e4306b5c4d5603f5db9c29b176c253e9420b46be253daac581c4c98f1aa108b")
put("res/drawable/abc_textfield_search_material.xml", "820b5412de01a1488720d18aacbeceadd07a0288a2d13dd3af3d977590a6ff9d")
put("res/drawable-xhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "c6a403e2ee84f5ba230fc1acaa5c6b87b9defab26f7b679696ac885b7dfe4a21")
put("res/drawable-xxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "bb54f3ff22d6e6bcaaaeef3e9b0765137485f924a8b7888e7dc2b9b826832913")
put("res/mipmap-xxhdpi-v4/icon.png", "7a650c26e007c3f59977f98c292ba3625b6c977572e92e539c0f4e451cab5734")
put("res/layout/abc_screen_toolbar.xml", "f1670f2cd6c6dcb86f3c50b0e840a0195322cdbcd460e46828806ca1cd918ba0")
put("res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "9dc401d6dcb691b4904d007d4c57be4af0b38a2b103fafca5812ac02b6f0e0cd")
put("res/drawable/abc_btn_borderless_material.xml", "0822257cdc5124d811dfb13ae57f242e4ae550abce462250231c0befa29e082a")
put("res/layout/abc_alert_dialog_material.xml", "3825181f8cffc231f4fa7fcfc3078eae492f19d39c202de2bcd21c537a59d7ac")
put("res/drawable-v23/abc_control_background_material.xml", "3ce4a969a079c570bb634572d111be190443a90f0fa754e0f99e645dc6c25a82")
put("res/color-v23/abc_color_highlight_material.xml", "b476ac65ddf4fcc665d5d9225365a6bcb613b186649a6490232aa4c458fa7c55")
put("res/drawable-xxhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "2310172cf1c75ca08b63baa38d29b6a145da35e9bd23ac0b78d2571f00d9d88a")
put("res/drawable-v21/abc_btn_colored_material.xml", "ede942fcb0f3325b45ed32e0c76ab0c760229d2a4201455c245e04fd8d6ff01a")
put("res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "20f88839f937925401106c71e57f7e4a24636dbb5ed714ae702bac11c05a0fe7")
put("res/drawable-mdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png", "5c621922ae954f1c7b17a2c81e82caf8e26c3c8f7bb1f494536e12996298befe")
put("res/drawable-xxhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "a8252f52638c80df119db031626198a4a8d4b32ee618e96c3a36b9b946e26894")
put("res/drawable/abc_list_selector_holo_dark.xml", "c0a8c5fa064df16c8130e6c1b89c407ca3e6907a77138f9354fd7f279a309cb5")
put("res/drawable-mdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png", "91bc27962779745e35aa681dc7a74fd5e829f090e59d0ff9557bab37e2ca2d40")
put("res/drawable-mdpi-v4/abc_list_longpressed_holo.9.png", "dbc0af61f440bb3f5382b8ea3fa578659f76c7a6aef620a68afc43a909f2e0e5")
put("res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "0eed99d0a5e36a468b557605e6ccea495c029f3569844a45f4b5d8dadd77d4a7")
put("res/layout-v17/notification_template_big_media.xml", "1eac34b2099c68d22e45f05253ad6d357dde52b57765cc6bf787fcb12e03265b")
put("res/drawable-xxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "75c6f650f790493b89c50d6a3bc46bcecc677291a1ac1513b067cb4dd73aafa6")
put("res/drawable/abc_tab_indicator_material.xml", "8663108d80dc207cc2d9e2e89dfe75ac1b68f0b804546874f8363a7fa797a90f")
put("res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "6002eb56783b956b5f91e6ddffaf36cc867402a01a225e627b4c25c8d21a4e23")
put("res/drawable-mdpi-v4/ic_action_next_item.png", "c01422fff1e45b864e7cc9b807a83d80868dac2bd0113e138385076b1a6fbf6d")
put("res/drawable-xhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "624af94ddb9b168bf22243043429772bede14c779e771dba98c6cc9ba597c4c3")
put("res/drawable-xhdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "3d7bbf47c8ac2b75977a579ca1aa2c12be8494f916450e971cf172bbc8a1f311")
put("res/drawable-xxhdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png", "7d230ee7f0709fe3016a360538d493f0a3b565337e576dccb1e798985fc473d9")
put("res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_light.9.png", "550e8f5f4a6004c0ff14c681b20ae675c6943e5ee299da36939f790fa8818fe0")
put("res/layout-v17/select_dialog_multichoice_material.xml", "b8dd03f6cdaddda24427698c320c9fe7fbdeda4e360a67f901cc99f6b676b0b2")
put("res/drawable-xhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "247152ba9b093d65d697d071cc7e986ac7e64c4ec95cf42c40b6f054ef9bb661")
put("res/layout/abc_action_bar_up_container.xml", "0903525f885f6aba13a17daf5be0355c455689dac8839418dc57908c8c7008a4")
put("res/drawable/abc_spinner_textfield_background_material.xml", "a875de881d4296c070560ae4208bb00810874ec9252e5569ddad3c50e5e580a7")
put("res/drawable-hdpi-v4/abc_ic_go_search_api_mtrl_alpha.png", "8eefaa5bbcce1a47294ada4eca76c92dec81913de9ab2d4cd09c1bf9fa10990f")
put("res/drawable-hdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png", "180a880eb2c603e1e1c903a2cd9cdbf8afa6fc2fe0bf6618d2f9b57b637832ac")
put("res/drawable-xhdpi-v4/ic_action_previous_item.png", "1dc3b456866e6c9a612ef9eec0b900394bae784c84af4e9dbdadd07d02cd394d")
put("res/layout/abc_activity_chooser_view_list_item.xml", "0c45295e533ffa94b98572b6b782872524cc25f3021d43646b62af4e66f3391e")
put("res/drawable-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "b948c74fe67d905b365ad3dc96a6ee416c9927dcadf3c555b5b2359540100b18")
put("res/drawable-mdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "9c05e26f9e74ce6d54e1e9e3d0fc1d6e7353ce7515e1195843fc627ad734156b")
put("res/drawable-xhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "7fb735d88839bff8190cdcadd7896326365456c85561d098d1d9ab98bf291838")
put("res/drawable-xxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "a55f232779d32baeea6c7ed6c84c6e985d3288c6d244e29cc8856d9d0334f32c")
put("res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "ffb431a4128e5aac93bf838154e272768a6dd51ab36a61517c95d53700daa0b9")
put("res/layout/abc_action_bar_title_item.xml", "9203c3aee1dc30c22c3909a126c087f20507a27e0e27c09d0f86de2303b0a64c")
put("res/drawable-port-mdpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable/abc_btn_check_material.xml", "12e9ca66114da2c67fc8f8ea38b4f28de73155154c2d15f9e7cc9a0fb4e2a4e6")
put("res/layout/notification_media_cancel_action.xml", "109cddab44f02e57fac23430d5ecd17a54fac1f5fad5444887cb2c68be84fb80")
put("res/drawable-ldrtl-mdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "3a283a4f4cc377084337680f3d3c693259902fc8793f5395afdfeaa0bf9ca105")
put("res/drawable-ldrtl-xhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "3cc16a0cc86ab8c137f9355a5577927a95caba18565b657d815b76461de3962e")
put("res/drawable-mdpi-v4/abc_ic_go_search_api_mtrl_alpha.png", "acf23a1bc642062f1f93f94247463c4077cd00d48521c3609268dff657c488ac")
put("res/drawable-xxhdpi-v4/ic_action_previous_item.png", "0f18602b3446953de962a1a8d412db3532d2ef180ec0bc8b3d33fd35e8cbb5cc")
put("res/raw/zxing_beep.ogg", "9bd6f5856d9162d4a41c016976edc4bfc2dfbbff9d98f05a362a50fa678dd5bc")
put("res/drawable-port-ldpi-v4/screen.png", "bc34a82eb2bd4abc1fd24a5fc0a7d1afda50ac1783327d50f610647f2b25f770")
put("res/drawable-mdpi-v4/abc_ic_clear_mtrl_alpha.png", "c550947a9eab1396c706ba97a39b3e4ce51c91329a5e597f6d6647bfece68fed")
put("res/drawable-xxhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "05b76fbf46593122597b8b4e2fd2358fa0734a9fbc2d24f5198ee2a72e77a9e9")
put("res/drawable-xxhdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "025d8a1155d2ce4769e307a89ff7ec6c175280df90ec51a8c61cea4551992cef")
put("res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "53340b0b0f529b26db6af632a0112708233bf312448c5b89a1357b2cd70b3f42")
put("res/anim/abc_slide_out_bottom.xml", "e33c8ff0e038ba561eac7101963096094d58b5f1a748c1067bad5290328148df")
put("res/drawable-hdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png", "e80e3db92ba1b47e32b7279a00778aac3c68150f88a4158941096adea34561bb")
put("res/drawable-xhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png", "cac329555c22a8b70581bc59c12c1c3e19c86748dd5a9e2c1251de16ee579170")
put("res/drawable-hdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "ea50d85209d909ecd07013b992929444b7f51fd22da25a6be2936631ad1d28c4")
put("res/layout-v17/notification_template_lines.xml", "cb5c99d9244a9d994903ce2c3e12c346be80c8661f87845cdd609ed377a13b5c")
put("res/drawable-mdpi-v4/abc_switch_track_mtrl_alpha.9.png", "7b73c914c459938dc3257fa1151c736609eb37bb437ee42071b81eb4860bdc04")
put("res/drawable/abc_edit_text_material.xml", "3ee45694043973b0dd0f43c29cae923c63f053af6cab0d5b501162153f7f84a5")
put("res/drawable-ldrtl-xhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "5d01a80f82b4c5874f20d78183037fb55504c6c3384458ad29b4535bdb951cac")
put("res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_015.png", "d33c0277bfd52f3b32daac3c30a420d7fc0a7214addb30dfe3b44dfead940b11")
put("res/drawable/abc_btn_radio_material.xml", "206c4cd4d38f53ee940c2ed149cdb5d7483dda1d89bcdb7d2b68adb5d6392846")
put("res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "915cfe2e2a1f9f2ad498669b0b1c6ec4a26735b7e690c4fd6b8339aa1747e5d7")
put("res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "c0e4c8fdbf4fef50f8a7033e529c3ef8da2c994b3567d4e9d89cfa099e7ac15b")
put("res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "2fa524cda78d7ebd66164a896a042277b7a56b8658fb318fc700a114cb04f7b2")
put("res/drawable-xhdpi-v4/abc_ic_search_api_mtrl_alpha.png", "0bdd69dcc421f49c9feb0baa908694baa968464dce0f09b55a8a8add3724e996")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "1c515bd153b3f9d1eb1bb53c2dcb0c168ed3cf0763986ef1652cd39aa3a0bbc2")
put("res/layout/notification_template_big_media.xml", "5195d15e19b8bab1fb9fc2973708cb3968f25f066758b854801b3ff7674b32bf")
put("res/drawable-xxhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "bfa384ba37a3e1024b738e0a82a7890f012f1a3291307135f7c819d0c9c3d425")
put("res/drawable-ldrtl-xhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "e89ed0715d5e67ab55ddcb3f2a56b41ac50d2e6a3b9216fea4d8ee23693c8f64")
put("res/drawable-ldrtl-xxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "173404ec34c97c2142f4955ac0950606649b195fab48df5e8f33560cbd9c5654")
put("res/drawable-xxhdpi-v4/abc_ic_go_search_api_mtrl_alpha.png", "9b699740ec1aa941bf4af584ae2fc2a3a37f3036769736b8885e1a682330c248")
put("res/drawable-xxhdpi-v4/abc_list_longpressed_holo.9.png", "44c29766b2d88b78a71393b3e3a771ca7eef5f552630c6074f33d6291241d0b9")
put("res/drawable-mdpi-v4/abc_list_selector_disabled_holo_light.9.png", "ae964252406ac9465a442ad66c9fe077e8d16391de4ece7ead6128b97f954362")
put("res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png", "e71502ac4d35951d0e063ef8b76885e27846a2dc0cdc616959d2a513f4852a2d")
put("res/anim/abc_grow_fade_in_from_bottom.xml", "a5fbceaa55ddc0aaed2077543b1f32ab7dd4b1de32a8775cac4e65ba09ed04a9")
put("res/drawable-land-xxhdpi-v4/screen.png", "ad1ac21edfdff36e6ca67afe850caa99d13e026c8fb09cf98d935ca493870ba0")
put("res/drawable-mdpi-v4/abc_ic_search_api_mtrl_alpha.png", "7ad683f3e730c98b12ae85edc0f9b2a61476f1dcf3df411721924d919ae98f5b")
put("res/drawable/abc_cab_background_internal_bg.xml", "ec7dc93f92559eb10d1d91fa944e746e95c3c7f03bbffab87ff22c1b3b002f49")
put("res/drawable-mdpi-v4/abc_list_pressed_holo_light.9.png", "35c56471c6414f33645a376c0d1a8a126f4cdc728f2344d08bccd3828e810e2e")
put("res/drawable/abc_item_background_holo_light.xml", "daf638c66b3fe5f24b5c7038193ca6e0a462663eeec720462d61cb4c61fbbf2c")
put("res/color/switch_thumb_material_dark.xml", "2c505932939633d0a61684d98161bde0a05b8c32e967114031335ee96387a76d")
put("res/drawable-ldrtl-xhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "fe21f096ab18f8947a27624ae952e86be4ff8d645ae714b653d398f64f8e39ee")
put("res/layout/abc_screen_content_include.xml", "bfdb030a0c978bb66333ac0dc6c4748caf3d856835f7370aaa8e06ec3269534c")
put("res/drawable-xxxhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png", "9e81ace23f53713fff9f07794897def554cf72df8bcc0e78e3ca2e1184e75e5b")
put("res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png", "5eca0280bd38a6887b6e41765cf5da573133874625001eb90156eaeb35fbe088")
put("res/drawable-mdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "16a04f086d374b00ba759124c4a372de58cb1b4eb070db121ca747073fef4745")
put("res/drawable/abc_seekbar_track_material.xml", "a209cb89db7acaf32a22ad77209ceccdd2a1c8a401c9d5e0df99961468338f50")
put("res/mipmap-hdpi-v4/icon.png", "7a650c26e007c3f59977f98c292ba3625b6c977572e92e539c0f4e451cab5734")
put("res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "40ae459db3548ac42fb949d69ecd5d3c452866db0fcf4d1b1081dd676a9431ec")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png", "2c3122e4c041da2a88b5e513d2891edd20ff7dc1216708e2d3b7b14678d08232")
put("res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png", "2c770f581a2ca530edeb27812f9153ca16a7b79f5245e02d6911b534a4c80c5e")
put("res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "4a494c652ef9019cc723afcb39de29a523e72e7b648739900fd786161cd47bf8")
put("res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_000.png", "055d5f87b1bbb6677096bc7eb7eace57e40216cb97f2b2b926d26c1263f9abce")
put("res/layout/select_dialog_singlechoice_material.xml", "7f7d5e80a17d35312f1ab8e84da3c0d1a6a1213dbc71ecdbb1e1507f00c2ad07")
put("res/drawable-hdpi-v4/ic_action_previous_item.png", "d326359f839c3c87dc22c9c133fcf8a6789eec76f6276300d0e045a5354feb36")
put("res/layout/select_dialog_item_material.xml", "16482ac145fdbda41d7eb9fba7020475dd6c96b2e11d70d2bab7c0a8bef0a286")
put("res/drawable-xhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "236db6dffdfccab00c623ed956723f19660cacbc9d9e2daa0ecd91e4afc40d2b")
put("res/drawable-xxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "cf8755669eda61de90624c9e21cbce526ca313ca206d7563f5a6066b1876abce")
put("res/drawable-ldrtl-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "de207ef50c941d5a22eb48586346228ff5b98c6f0540d6731af06658aeb8ecb7")
put("res/drawable-mdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "b1e9c8ff1b5662b3a5c7bab6b223ff14b68fe14e2d097ffc3ccdc3d5859eac88")
put("res/drawable-xhdpi-v4/abc_list_longpressed_holo.9.png", "727d78fec3f903a271c0476a50e8c064d28b32f7829b016ae0a07da53b83b281")
put("res/layout-v17/notification_template_media.xml", "8bb61dab2c80af12d33d99e23df5c9b604d76294ff0ddb4ffa3c9d880ad2bd35")
put("res/drawable-xxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "54b757ced1278d78846c070ae2802ca65f88c17657236e4fd72e46e23a2c9a22")
put("res/layout/abc_action_mode_close_item_material.xml", "0b5cff6338e6ce6fd63b8f24846558e269ac39f9e1f70cf6b8e45c1ec67cc260")
put("res/drawable-mdpi-v4/abc_list_focused_holo.9.png", "8436624220fba246ae816a3aab379dfd7ff2a484284ab24c3af4989778705bb3")
put("res/drawable-xhdpi-v4/ic_action_next_item.png", "9c57cd4759313169898d4f4b69a96bd963c3b2257532d5ed43275b502ca98e64")
put("res/drawable/abc_text_cursor_material.xml", "14e09849019f466a6780ffb38bfffdee36c21519c7627f1fdb17224b60e09f6b")
put("res/drawable-mdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "1df76313283b0046c002e9792e35b1f4087ef98e79bb757aededc9d27bd54897")
put("res/drawable-mdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png", "4ad77975a92c859163b4f39ba17d01e3bde2d03f1fc2177d113401fa84a67c73")
put("res/drawable-xhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "395c5e56806478d86eb4fae5570163962bc6845971dad92ea29356690511ec56")
put("res/layout/abc_list_menu_item_layout.xml", "af7dd160067d2397d998be2399dac8f8fe69b9890825896ffbbd447dc44caba0")
put("res/color/abc_secondary_text_material_light.xml", "47407173ce8bc17e8d19577230c43f62e9d5f38cae3d23ebaa92f785e0c4932b")
put("res/color/switch_thumb_material_light.xml", "45177bbc0542c30e514408dd4b23c83a17a84a5e594989c0e094c159a39cb721")
put("res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png", "7e12fcbd0c61e037cd1cafe510c307b4074d156adac0022d91f3dcdcae692818")
put("res/drawable-xxxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "307cc34bbb3a22f5ad82decd369e14404d467655097cbbce7b03f6aac0f82264")
put("res/drawable-mdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png", "da7b78e6af0d3a21b965cec54ce80c54271a0206d1da3787673f9cf504dbe3a4")
put("res/drawable-mdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "aa44c927eb4e9a886438f3b6083c948d8cf67c52b3e5fe034b9720648f5fa78e")
put("res/drawable/abc_btn_colored_material.xml", "363cf11a26c4c89772b73bf267da6a7b3229e0831b8eff5998076b12011f5603")
put("res/anim/abc_slide_out_top.xml", "2f5ba7fce4651ca8fcf598e8bb6df46b4d32912606c5d20a39de9b0554971105")
put("res/layout/abc_list_menu_item_radio.xml", "af7c4fa541f9e90b6ec8d6f8971c1d404cfabb86610bd9054de2b2dd211b33e6")
put("res/drawable-xhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "b15c567058a56d15661e044bb4f8408512d87a79d11779ec8d7189dbb30eaefb")
put("res/layout/abc_activity_chooser_view.xml", "dd991ccd05f4240d13c6ad9b685debe84f6801d454b5edd0689a4cc9f1fb27e2")
put("res/layout/abc_screen_simple.xml", "b444aa5a73a22ebaa8745ac91729180ef54ce675138dd8bf3f75a649b0fb140d")
put("res/layout/zxing_barcode_scanner.xml", "b52f5db8970b2d92e3e5c352741dbb4385df7f0d7270db648842e05950b8e92f")
put("res/drawable-mdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "cf2d1096edd99c09a185d330a8a202a35b0d21ec1305df4ae7d359bcf0179b4d")
put("res/drawable-mdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "36e3737c04ce9ff9322ea71c2908a36ae532437d0b899f70e4ff33f20f810ba8")
put("res/drawable/abc_btn_default_mtrl_shape.xml", "f0f21a53cce548fa7d611f1cded76fbc15b100bee7857ef1e6b073138057dd82")
put("res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "27c227cad79fa831621558b8ad808e28c939fb6dbdfa040ae57136b4b50f19d4")
put("res/mipmap-xhdpi-v4/icon.png", "7a650c26e007c3f59977f98c292ba3625b6c977572e92e539c0f4e451cab5734")
put("res/drawable-hdpi-v4/abc_ic_search_api_mtrl_alpha.png", "4bf6cadfd829c96627a3cc6bdb894ee48edf7567b341aee4a4c38917e65f7fcd")
put("res/drawable/abc_switch_thumb_material.xml", "652d8486916207186bc3bf5155d0d9b437f473c5c58ed793932098bd6f22a207")
put("res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "43ccf1f0a5e9e9ed9a6df33e1b3d378d49dbc8dc60d83b1cdb985e5e48f52497")
put("res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "076be4630bb4f4ba10579cba1b3900e3f3f2286cafcbc15892d97fa4b45a27ce")
put("res/layout/abc_action_menu_layout.xml", "78e8b182c9982b18cc3bf705e95511e4ef4554b1f15c91d4c443b62587547f97")
put("res/layout/notification_template_big_media_narrow.xml", "edc0530f0084410597bedd5623e0cf8e0f1d0f2180ee3377e85ebc3ce7966968")
put("res/drawable-hdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png", "b6ed0b4f4e4f64989a78969a49ddf9eb7c2f56a9473691c080d8fc10154f8d73")
put("res/drawable-hdpi-v4/ic_action_remove.png", "8ed4fff301384afff335f560209a5216bcf90946f26421eca413aadb07a01d6c")
put("res/layout/abc_list_menu_item_icon.xml", "69c2869ea56579b9d02e761d4cf817870b080e9229a32dd4f30ab59255e2fc95")
put("res/drawable-mdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "7d15a2bdf032c5ae801f762f92104a30d247a83529ac91c2a5900a7b17307f8b")
put("res/drawable-xhdpi-v4/abc_list_divider_mtrl_alpha.9.png", "0ef7b3d9f9d890a48e4fccc0db07315bd6fcca7049452e20a27a69bd22080415")
`
let arr = str.split(/\n/ig).filter(v => v.trim())
let arr2 = arr.map(v => {
// console.log(v)
v = v.trim().replace(/\s*put\(/, '').replace(/\)$/, '')
vArr = v.split(', ')
return { file: vArr[0].replace(/\"/ig, ''), hash: vArr[1].replace(/\"/ig, '') }
})
return arr2
}
helpers.getPlatformsList(context).forEach(function (platform) {
var platformPath = path.join(projectRoot, 'platforms', platform);
var platformApi = platforms.getPlatformApi(platform, platformPath);
var platformInfo = platformApi.getPlatformInfo();
var platformRes = platformInfo.locations.res;
var source = helpers.getFileMapContent(context, platform, 'ResIntegrity');
var content = source.content;
hashes = getHashList()
if (platform === 'android') {
content = content.replace(/\s*put\("[^"]+",\s"[^"]{64}"\);/g, '')
.replace(/hashList\s*=.+\s*new.*(\(\d+\)[^\w]*)\);/, function (match, group) {
return match.replace(group, '()\n' + tab());
})
.replace(/hashList\s*=.+\s*new.*(\(.*\))/, function (match, group) {
var replace = match.replace(group, '(' + (hashes.length || '') + ')');
if (hashes.length) {
replace += ' {{\n' + tab();
hashes.forEach(function (h) {
replace += tab(2) + 'put("' + h.file + '", "' + h.hash + '");\n' + tab();
});
replace += tab() + '}}';
}
return replace;
});
// console.log(content)
try {
fs.writeFileSync(source.path, content, 'utf-8');
} catch (e) {
helpers.exit('Unable to write java class source at path ' + source.path, e);
}
}
});
function tab(size) {
var str = '';
for (var i = 0; i < (size || 1); i++) {
str += ' ';
}
return str;
}
};

View File

@ -0,0 +1,92 @@
package com.cescit.integrity;
import org.json.JSONObject;
import android.content.Context;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.nio.charset.StandardCharsets;
// apk完整性检验
class ApkIntegrity {
private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256";
private static final String ASSETS_BASE_PATH = "";
// Collections.unmodifiableMap 使得返回的内容只能只读访问
private static final Map<String, String> hashList = Collections.unmodifiableMap(
new HashMap<String, String>()
);
public static JSONObject check(Context context) throws Exception {
JSONObject result = new JSONObject();
Map<String, String> nowHashList = getHashMap(context);
String ret = HttpUtil.getHttpRequestData((String) Config.getConfig("APK_HASH_URL"));
JSONObject obj = new JSONObject(ret);
String upHash = obj.getString("apk");
String nowHash = nowHashList.get("apk");
if (!upHash.equals(nowHash)) {
throw new Exception("Content of APK has been tampered");
}
result.put("res conunt", hashList.size());
return result;
}
// 获取文件对应的hash值
public static Map getHashMap(Context context) throws Exception{
File file = new File(context.getPackageCodePath());
InputStream fis = new FileInputStream(file);
String fileHash = getFileHash(fis);
// res资源路径文件hash键值对
Map<String, String> nowHashList = new HashMap<String,String>();
nowHashList.put("apk", fileHash);
return nowHashList;
}
// 获取Res文件对应的hash值构造的String
public static String getHashString(Context context) throws Exception{
Map<String, String> nowHashList = getHashMap(context);
String str = "";
// 遍历对比文件hash
for (Map.Entry<String, String> entry : nowHashList.entrySet()) {
String fileName = entry.getKey();
String presetHash = entry.getValue();
if (!presetHash.equals("")) {
str += "put(\"" + fileName + "\", \"" + presetHash + "\");";
}
}
// 用默认字符编码解码字符串
byte[] bs = str.getBytes();
str = new String(bs, StandardCharsets.UTF_8);
return str;
}
private static String getFileHash(InputStream file) throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = file.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
MessageDigest digest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
byte[] hashBytes = digest.digest(buffer.toByteArray());
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hashBytes.length; i++) {
if ((0xff & hashBytes[i]) < 0x10) {
hexString.append("0");
}
hexString.append(Integer.toHexString(0xFF & hashBytes[i]));
}
// Log.d("AntiTampering", String(hexString));
return new String(hexString);
}
}

View File

@ -0,0 +1,87 @@
package com.cescit.integrity;
import android.content.res.AssetManager;
import android.util.Base64;
import android.app.Activity;
import android.content.Context;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
class AssetsIntegrity {
private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256";
private static final String ASSETS_BASE_PATH = "";
private static final Map<String, String> hashList = Collections.unmodifiableMap(
new HashMap<String, String>()
);
public static JSONObject check(Context context) throws Exception {
AssetManager assets = context.getAssets();
for (Map.Entry<String, String> entry : hashList.entrySet()) {
// byte[] fileNameDecode = Base64.decode(entry.getKey(), 0);
// String fileName = new String(fileNameDecode, StandardCharsets.UTF_8);
// Log.d("AntiTampering", fileName + " -> " + entry.getValue());
String filePath = entry.getKey();
InputStream file = assets.open(filePath);
String hash = getFileHash(file);
if (entry.getValue() == null || !entry.getValue().equals(hash)) {
throw new Exception("Content of " + filePath + " has been tampered");
}
}
JSONObject result = new JSONObject();
result.put("count", hashList.size());
return result;
}
// 获取Res文件对应的hash值构造的String
public static String getHashString(Context context) throws Exception{
AssetManager assets = context.getAssets();
String str = "";
// 遍历对比文件hash
for (Map.Entry<String, String> entry : hashList.entrySet()) {
String fileName = entry.getKey();
String presetHash = entry.getValue();
if (!presetHash.equals("")) {
str += "put(\"" + fileName + "\", \"" + presetHash + "\");";
}
}
// 用默认字符编码解码字符串
byte[] bs = str.getBytes();
str = new String(bs, StandardCharsets.UTF_8);
return str;
}
private static String getFileHash(InputStream file) throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = file.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
MessageDigest digest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
byte[] hashBytes = digest.digest(buffer.toByteArray());
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hashBytes.length; i++) {
if ((0xff & hashBytes[i]) < 0x10) {
hexString.append("0");
}
hexString.append(Integer.toHexString(0xFF & hashBytes[i]));
}
// Log.d("AntiTampering", String(hexString));
return new String(hexString);
}
}

View File

@ -0,0 +1,98 @@
package com.cescit.integrity;
import android.app.Activity;
import android.content.Context;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
public class CescitIntegrity extends CordovaPlugin {
private Activity activity;
private Context context;
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
activity = cordova.getActivity();
context = activity.getApplicationContext();
checkAndStopExecution();
super.initialize(cordova, webView);
}
private void checkAndStopExecution() {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run () {
try {
String ret = HttpUtil.getHttpRequestData((String) Config.getConfig("APK_HASH_URL"));
JSONObject obj = new JSONObject(ret);
if(obj.getBoolean("ApkIntegrity")) {
ApkIntegrity.check(context);
}
if(obj.getBoolean("ResIntegrity")) {
ResIntegrity.check(context);
}
if(obj.getBoolean("AssetsIntegrity")) {
AssetsIntegrity.check(context);
}
} catch (final Exception e) {
e.printStackTrace();
throw new TamperingException("Anti-Tampering check failed");
}
}
});
}
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
if ("verify".equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run () {
PluginResult result;
try {
// DebugDetection.check(activity.getPackageName());
JSONObject response = new JSONObject();
response.put("assets", AssetsIntegrity.check(context));
response.put("res", ResIntegrity.check(context));
response.put("apk", ApkIntegrity.check(context));
result = new PluginResult(PluginResult.Status.OK, response);
} catch (Exception e) {
result = new PluginResult(PluginResult.Status.ERROR, e.toString());
}
callbackContext.sendPluginResult(result);
}
});
return true;
}
if ("getList".equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run () {
PluginResult result;
try {
JSONObject response = new JSONObject();
response.put("assets", AssetsIntegrity.getHashString(context));
response.put("res", ResIntegrity.getHashString(context));
response.put("apk", ApkIntegrity.getHashString(context));
result = new PluginResult(PluginResult.Status.OK, response);
} catch (Exception e) {
result = new PluginResult(PluginResult.Status.ERROR, e.toString());
}
callbackContext.sendPluginResult(result);
}
});
return true;
}
return false;
}
}

View File

@ -0,0 +1,20 @@
package com.cescit.integrity;
import java.util.HashMap;
import java.util.Map;
class Config {
private static final String APK_HASH_URL = "http://webf.cewater.com.cn/apk-hash/jm.json";
// 获取配置
public static <T> T getConfig(String key) throws Exception{
// res资源路径文件hash键值对
Map<String, T> config = new HashMap<String,T>();
config.put("APK_HASH_URL", (T) APK_HASH_URL);
T result = null;
for(String configKey : config.keySet()){
result = config.get(configKey);
}
return (T) result;
}
}

View File

@ -0,0 +1,28 @@
package com.cescit.integrity;
import android.os.Debug;
import java.lang.reflect.Field;
class DebugDetection {
public static void check(String packageName) throws Exception {
if (hasDebuggerAttached()) {
throw new Exception("Debugger attached");
} else if (getDebugField(packageName)) {
throw new Exception("App running in Debug mode");
}
}
private static Boolean getDebugField(String packageName) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> buildConfigClass = Class.forName(packageName.concat(".BuildConfig"));
Field debugField = buildConfigClass.getField("DEBUG");
return debugField.getBoolean(null);
}
private static Boolean hasDebuggerAttached() {
return Debug.isDebuggerConnected() || Debug.waitingForDebugger();
}
}

View File

@ -0,0 +1,58 @@
package com.cescit.integrity;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpUtil {
public static String getHttpRequestData(String urlPath) {
// 首先抓取异常并处理
String returnString = "";
try{
// 代码实现以GET请求方式为主,POST跳过
/** 1 GET方式请求数据 start*/
// 1 创建URL对象,接收用户传递访问地址对象链接
URL url = new URL(urlPath);
// 2 打开用户传递URL参数地址
HttpURLConnection connect = (HttpURLConnection) url.openConnection();
// 3 设置HTTP请求的一些参数信息
connect.setRequestMethod("GET"); // 参数必须大写
connect.connect();
// 4 获取URL请求到的数据并创建数据流接收
InputStream isString = connect.getInputStream();
// 5 构建一个字符流缓冲对象,承载URL读取到的数据
BufferedReader isRead = new BufferedReader(new InputStreamReader(isString));
// 6 输出打印获取到的文件流
String str = "";
while ((str = isRead.readLine()) != null) {
str = new String(str.getBytes(),"UTF-8"); //解决中文乱码问题
// System.out.println("文件解析打印:");
// System.out.println(str);
returnString += str;
}
// 7 关闭流
isString.close();
connect.disconnect();
// 8 JSON转List对象
// do somthings
}catch(Exception e){
e.printStackTrace();
}
return returnString;
}
}

View File

@ -0,0 +1,118 @@
package com.cescit.integrity;
import org.json.JSONObject;
import android.content.Context;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.regex.*;
import java.nio.charset.StandardCharsets;
// apk res资源完整性检验
class ResIntegrity {
private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256";
private static final String ASSETS_BASE_PATH = "";
// Collections.unmodifiableMap 使得返回的内容只能只读访问
private static final Map<String, String> hashList = Collections.unmodifiableMap(
new HashMap<String, String>()
);
public static JSONObject check(Context context) throws Exception {
JSONObject result = new JSONObject();
Map<String, String> resHashList = getResHashMap(context);
// 遍历对比文件hash
for (Map.Entry<String, String> entry : hashList.entrySet()) {
// byte[] fileNameDecode = Base64.decode(entry.getKey(), 0);
// String fileName = new String(fileNameDecode, StandardCharsets.UTF_8);
String fileName = entry.getKey();
String presetHash = entry.getValue();
String filePath = ASSETS_BASE_PATH.concat(fileName);
String nowHash = resHashList.get(filePath);
if (presetHash == null || !presetHash.equals(nowHash)) {
throw new Exception("Content of " + filePath + " has been tampered");
}
}
result.put("res conunt", hashList.size());
return result;
}
// 获取Res文件对应的hash值
public static Map getResHashMap(Context context) throws Exception{
File file = new File(context.getPackageCodePath());
ZipFile zf = new ZipFile(file);
// res资源路径文件键值对
Map<String, ZipEntry> resList = new HashMap<String,ZipEntry>();
// res资源路径文件hash键值对
Map<String, String> resHashList = new HashMap<String,String>();
// 提取出apk里的res文件资源
Enumeration<?> entries = zf.entries();
while(entries.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) entries.nextElement();
String pattern = "^res\\/.*";
boolean isMatch = Pattern.matches(pattern, zipEntry.getName());
if(isMatch) {
resList.put(zipEntry.getName(), zipEntry);
}
}
// 获取文件hash
for (Map.Entry<String, ZipEntry> resListItem : resList.entrySet()) {
String key = resListItem.getKey();
ZipEntry fileEntry = resListItem.getValue();
InputStream fileSteam= zf.getInputStream(fileEntry);
String fileHash = getFileHash(fileSteam);
resHashList.put(key, fileHash);
}
return resHashList;
}
// 获取Res文件对应的hash值构造的String
public static String getHashString(Context context) throws Exception{
Map<String, String> resHashList = getResHashMap(context);
String str = "";
// 遍历对比文件hash
for (Map.Entry<String, String> entry : resHashList.entrySet()) {
String fileName = entry.getKey();
String presetHash = entry.getValue();
if (!presetHash.equals("")) {
str += "put(\"" + fileName + "\", \"" + presetHash + "\");";
}
}
// 用默认字符编码解码字符串
byte[] bs = str.getBytes();
str = new String(bs, StandardCharsets.UTF_8);
return str;
}
private static String getFileHash(InputStream file) throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = file.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
MessageDigest digest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
byte[] hashBytes = digest.digest(buffer.toByteArray());
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hashBytes.length; i++) {
if ((0xff & hashBytes[i]) < 0x10) {
hexString.append("0");
}
hexString.append(Integer.toHexString(0xFF & hashBytes[i]));
}
// Log.d("AntiTampering", String(hexString));
return new String(hexString);
}
}

View File

@ -0,0 +1,9 @@
package com.cescit.integrity;
class TamperingException extends SecurityException {
public TamperingException(String message) {
super(message);
}
}

22
www/AntiTampering.js Normal file
View File

@ -0,0 +1,22 @@
var exec = require('cordova/exec');
function AntiTampering () {}
AntiTampering.prototype.verify = function (successCallback, errorCallback) {
exec(successCallback,
errorCallback,
'CescitIntegrity',
'verify',
[]);
};
AntiTampering.prototype.getList = function (successCallback, errorCallback) {
exec(successCallback,
errorCallback,
'CescitIntegrity',
'getList',
[]);
};
module.exports = new AntiTampering();