commit d4770c4b4b1cc42fbe118d0e543ae33abdf27fba Author: Lircyn Date: Sun Jul 6 22:26:02 2014 +0200 Fix a bug with invoke-super/range Split variables to separate each definition (not exactly SSA, but sort of) diff --git a/.hgsub b/.hgsub new file mode 100644 index 00000000..a7426353 --- /dev/null +++ b/.hgsub @@ -0,0 +1 @@ +elsim = https://code.google.com/p/elsim/ diff --git a/.hgsubstate b/.hgsubstate new file mode 100644 index 00000000..0aea2785 --- /dev/null +++ b/.hgsubstate @@ -0,0 +1 @@ +ceadaf0d341fb0cc3c46fbafcd474a6f2c3ed320 elsim diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..e494ae85 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,27 @@ +1.9: + - fix AXML bugs + - add ARSC support + - add sublimetext plugin + - remove useless dependencies (networkx, pygments) + - improve decompiler + - fix various bugs for python2.6 + - add a tool (androdis) to disasm a dex file at a specific offset + +1.6: + - fix doc + - add auto analysis + - comunity + +1.5.1: + DAD: + - Propagatation pass has been updated + - Switches with fallthrough are handled + Core: + - fix and add the zipmodule python + - fix bugs in search of packages + - fix bugs in show_* + - fix bug in ganalysis.py + +1.5: stable release + + diff --git a/LICENCE-2.0 b/LICENCE-2.0 new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/LICENCE-2.0 @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..cfc92436 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CD = cd +RM = rm -f + + +.SILENT: + +all : LIBS + +LIBS : +# cd androguard/core/bytecodes/libdvm && make + cd elsim && make + +clean : +# cd androguard/core/bytecodes/libdvm && make clean + cd elsim && make clean diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..3b9fd67f --- /dev/null +++ b/README.txt @@ -0,0 +1,113 @@ +########################################################################## +################################# Androguard ############################# +########################################################################## +################### http://code.google.com/p/androguard ################## +######################## dev (at) androguard.re ########################## +########################################################################## + +1 -] About + +Androguard (Android Guard) is primarily a tool written in full python to +play with : + - DEX, ODEX + - APK + - Android's binary xml + +2 -] Usage + +You need to follow the following information to install dependencies +for androguard : + http://code.google.com/p/androguard/wiki/Installation + +You must go to the website to see more example : + http://code.google.com/p/androguard/wiki/Usage + +2.1 --] API + +2.1.1 --] Instructions + +http://code.google.com/p/androguard/wiki/Instructions + +2.2 --] Demos + +see the source codes in the directory 'demos' + +2.3 --] Tools + +http://code.google.com/p/androguard/wiki/Usage + +2.4 --] Disassembler + +http://code.google.com/p/androguard/wiki/Disassembler + +2.5 --] Analysis + +http://code.google.com/p/androguard/wiki/Analysis + +2.6 --] Visualization + +http://code.google.com/p/androguard/wiki/Visualization + +2.7 --] Similarities, Diffing, plagiarism/rip-off indicator + +http://code.google.com/p/androguard/wiki/Similarity +http://code.google.com/p/androguard/wiki/DetectingApplications + +2.8 --] Open Source database of android malwares + +http://code.google.com/p/androguard/wiki/DatabaseAndroidMalwares + +2.9 --] Decompiler + +2.10 --] Reverse + +http://code.google.com/p/androguard/wiki/RE + +3 -] Roadmap/Issues +http://code.google.com/p/androguard/wiki/RoadMap +http://code.google.com/p/androguard/issues/list + +4 -] Authors: Androguard Team + +Androguard + tools: Anthony Desnos +DAD (DAD is A Decompiler): Geoffroy Gueguen + +5 -] Contributors + +Craig Smith : 64 bits patch + magic tricks + +6 -] Licenses + +6.1 --] Androguard + +Copyright (C) 2012, Anthony Desnos +All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS-IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +6.2 -] DAD + +Copyright (C) 2012, Geoffroy Gueguen +All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS-IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/ag-st/Default (Linux).sublime-keymap b/ag-st/Default (Linux).sublime-keymap new file mode 100755 index 00000000..fad4f326 --- /dev/null +++ b/ag-st/Default (Linux).sublime-keymap @@ -0,0 +1,22 @@ +[ + { + "keys": ["ctrl+f5"], + "command": "ag" + }, + { + "keys": ["f5"], + "command": "ag_tr" + }, + { + "keys": ["ctrl+f6"], + "command": "ag_ref_from" + }, + { + "keys": ["ctrl+f7"], + "command": "ag_ref_to" + }, + { + "keys": ["ctrl+f8"], + "command": "ag_reset" + } +] diff --git a/ag-st/Default (OSX).sublime-keymap b/ag-st/Default (OSX).sublime-keymap new file mode 100755 index 00000000..fad4f326 --- /dev/null +++ b/ag-st/Default (OSX).sublime-keymap @@ -0,0 +1,22 @@ +[ + { + "keys": ["ctrl+f5"], + "command": "ag" + }, + { + "keys": ["f5"], + "command": "ag_tr" + }, + { + "keys": ["ctrl+f6"], + "command": "ag_ref_from" + }, + { + "keys": ["ctrl+f7"], + "command": "ag_ref_to" + }, + { + "keys": ["ctrl+f8"], + "command": "ag_reset" + } +] diff --git a/ag-st/Default (Windows).sublime-keymap b/ag-st/Default (Windows).sublime-keymap new file mode 100755 index 00000000..fad4f326 --- /dev/null +++ b/ag-st/Default (Windows).sublime-keymap @@ -0,0 +1,22 @@ +[ + { + "keys": ["ctrl+f5"], + "command": "ag" + }, + { + "keys": ["f5"], + "command": "ag_tr" + }, + { + "keys": ["ctrl+f6"], + "command": "ag_ref_from" + }, + { + "keys": ["ctrl+f7"], + "command": "ag_ref_to" + }, + { + "keys": ["ctrl+f8"], + "command": "ag_reset" + } +] diff --git a/ag-st/Default.sublime-commands b/ag-st/Default.sublime-commands new file mode 100755 index 00000000..fad4f326 --- /dev/null +++ b/ag-st/Default.sublime-commands @@ -0,0 +1,22 @@ +[ + { + "keys": ["ctrl+f5"], + "command": "ag" + }, + { + "keys": ["f5"], + "command": "ag_tr" + }, + { + "keys": ["ctrl+f6"], + "command": "ag_ref_from" + }, + { + "keys": ["ctrl+f7"], + "command": "ag_ref_to" + }, + { + "keys": ["ctrl+f8"], + "command": "ag_reset" + } +] diff --git a/ag-st/Default.sublime-mousemap b/ag-st/Default.sublime-mousemap new file mode 100644 index 00000000..5b8c27b0 --- /dev/null +++ b/ag-st/Default.sublime-mousemap @@ -0,0 +1,8 @@ +[ + { + "button": "button1", "count": 2, + "press_command": "drag_select", + "press_args": {"by": "words"}, + "command": "ag_double_click" + } +] \ No newline at end of file diff --git a/ag-st/Main.sublime-menu b/ag-st/Main.sublime-menu new file mode 100644 index 00000000..335beab1 --- /dev/null +++ b/ag-st/Main.sublime-menu @@ -0,0 +1,31 @@ +[ + { + + "id": "tools", + "caption": "Tools", + "children": + [ + { + "id": "packages", + "caption": "Packages", + "children": + [ + { + "id": "androguard", + "caption": "Androguard", + "children": + [ + { + "caption": "View Strings", + "command": "ag_strings" + }, + { + "caption": "-" + } + ] + } + ] + } + ] + } +] diff --git a/ag-st/ag.JSON-tmLanguage b/ag-st/ag.JSON-tmLanguage new file mode 100644 index 00000000..31f034ac --- /dev/null +++ b/ag-st/ag.JSON-tmLanguage @@ -0,0 +1,32 @@ +{ "name": "Dalvik Classes (Androguard)", + "scopeName": "source.ag", + "fileTypes": [""], + "patterns": [ + { + "match": "^([\\w\\d\\_\/\\$]+)", + "name": "storage.package", + "comment": "package" + }, + { + "match": "^(\\s*[\\w\\d\\_\/\\$]+)(\\s*)(extends)(\\s*)(.)*", + "name": "storage.class", + "comment": "current class" + }, + { + "match": "^(\\s*(method\\:))(\\s*)((\\)|(\\))(.)+", + "name": "support", + "comment": "init/clinit method" + }, + { + "match": "^(\\s*(method\\:))(.)+", + "name": "support.function.classicmethod", + "comment": "method" + }, + { + "match": "^(\\s*(field\\:))(.)+", + "name": "variable", + "comment": "field" + } + ], + "uuid": "75ba8e42-b55b-4823-b4aa-e4e407da9c8d" +} \ No newline at end of file diff --git a/ag-st/ag.py b/ag-st/ag.py new file mode 100644 index 00000000..84a6cc0e --- /dev/null +++ b/ag-st/ag.py @@ -0,0 +1,772 @@ +# This file is part of Androguard. +# +# Copyright (C) 2013, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + + +import sublime +import sublime_plugin + +import os +import threading +import hashlib + + +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis import analysis +from androguard.core.analysis import ganalysis +from androguard.decompiler import decompiler +from androguard.core import androconf + +AG_DEX_VIEW = {} +AG_APK_VIEW = {} + +AG_DEX_VIEW_LINK = {} +AG_REVERT_METHODS = {} +AG_REVERT_FIELDS = {} +AG_SC = {} +AG_METHOD_ID = {} +AG_FIELD_ID = {} +AG_CLASS_ID = {} +AG_AXML_ID = {} +AG_ARSC_ID = {} + + +AG_METHODS_LINE = {} +AG_FIELDS_LINE = {} +AG_CLASSES_LINE = {} + +FILENAMES = {} + + +def get_setting(key, default=None): + return sublime.load_settings("ag.sublime-settings").get(key, default) + + +def is_setting(key): + return sublime.load_settings("ag.sublime-settings").has(key) + + +def get_bytecodes_class(dex_object, ana_object, class_obj): + i_buffer = "" + + for i in class_obj.get_methods(): + i_buffer += dvm.get_bytecodes_method(dex_object, ana_object, i) + + return i_buffer + + +def get_field_info(field): + i_buffer = "" + + i_buffer += "# %s->%s %s [access_flags=%s]\n#\n" % (field.get_class_name(), field.get_name(), field.get_descriptor(), field.get_access_flags_string()) + + init_value = field.get_init_value() + if init_value != None: + i_buffer += repr(str(init_value.get_value())) + + return i_buffer + + +def get_axml_info(apk_object): + i_buffer = "PERMISSIONS:\n" + details_permissions = apk_object.get_details_permissions() + for i in details_permissions: + i_buffer += "\t%s %s\n" % (i, details_permissions[i]) + i_buffer += "\nMAIN ACTIVITY: %s\n" % apk_object.get_main_activity() + + i_buffer += "\nACTIVITIES:\n" + for i in apk_object.get_activities(): + i_buffer += "\t%s\n" % (i) + + i_buffer += "\nSERVICES:\n" + for i in apk_object.get_services(): + i_buffer += "\t%s\n" % (i) + + i_buffer += "\nRECEIVERS:\n" + for i in apk_object.get_receivers(): + i_buffer += "\t%s\n" % (i) + + i_buffer += "\nPROVIDERS:\n" + for i in apk_object.get_providers(): + i_buffer += "\t%s\n" % (i) + + return i_buffer + + +def get_sourcecode_method(dex_object, ana_object, method): + return method.get_source() + + +class MethodView: + def __init__(self, orig_id, method): + self.view = sublime.active_window().new_file() + self.dex_object, self.ana_object = AG_DEX_VIEW[orig_id] + AG_DEX_VIEW_LINK[self.view.id()] = orig_id + AG_REVERT_METHODS[method] = self.view + + self.view.set_name("%s-%s-%s.mag" % (method.get_class_name(), method.get_name(), method.get_descriptor())) + self.view.set_syntax_file("Packages/ag-st/agbytecodes.tmLanguage") + + self.view.set_scratch(True) + edit = self.view.begin_edit() + + i_buffer = dvm.get_bytecodes_method(self.dex_object, self.ana_object, method) + AG_METHOD_ID[self.view.id()] = method + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.sel().clear() + + if self.view.id() not in AG_SC: + AG_SC[self.view.id()] = False + + +class FieldView: + def __init__(self, orig_id, field): + self.view = sublime.active_window().new_file() + self.dex_object, self.ana_object = AG_DEX_VIEW[orig_id] + AG_DEX_VIEW_LINK[self.view.id()] = orig_id + AG_REVERT_FIELDS[field] = self.view + + self.view.set_name("%s-%s-%s.fag" % (field.get_class_name(), field.get_name(), field.get_descriptor())) + self.view.set_syntax_file("Packages/ag-st/agbytecodes.tmLanguage") + + self.view.set_scratch(True) + edit = self.view.begin_edit() + + i_buffer = get_field_info(field) + AG_FIELD_ID[self.view.id()] = field + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.sel().clear() + + +class ClassView: + def __init__(self, orig_id, class_obj): + self.view = sublime.active_window().new_file() + self.dex_object, self.ana_object = AG_DEX_VIEW[orig_id] + AG_DEX_VIEW_LINK[self.view.id()] = orig_id + + self.view.set_name("%s.cag" % (class_obj.get_name())) + self.view.set_syntax_file("Packages/ag-st/agbytecodes.tmLanguage") + + self.view.set_scratch(True) + edit = self.view.begin_edit() + + i_buffer = get_bytecodes_class(self.dex_object, self.ana_object, class_obj) + + AG_CLASS_ID[self.view.id()] = class_obj + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.sel().clear() + + if self.view.id() not in AG_SC: + AG_SC[self.view.id()] = False + + +class AgDoubleClick(sublime_plugin.TextCommand): + def extract_bb(self, raw, position): + raw_list = raw.split(" ") + idx = 0 + for i in raw_list: + begin = idx + end = idx + len(i) + + if position >= begin and position <= end: + if ":" in i: + return i.split(":")[-1] + return i + idx += len(i) + return None + + def run(self, edit): + if self.view.id() in AG_METHOD_ID and self.view.id() in AG_SC: + if not AG_SC[self.view.id()]: + for sel in self.view.sel(): + if self.view.scope_name(sel.begin()) == 'source.agbt markup.list ': + scope_region = self.view.extract_scope(sel.begin()) + + scope_value = self.view.substr(scope_region) + + bb_selected = self.extract_bb(scope_value, sel.begin() - scope_region.begin()) + region_bb = self.view.find("^(%s)" % bb_selected, 0) + self.view.run_command("goto_line", {"line": self.view.rowcol(region_bb.end())[0] + 1}) + + if self.view.id() in AG_DEX_VIEW: + current_view_id = self.view.id() + datas = [] + try: + for sel in self.view.sel(): + x, y = self.view.rowcol(sel.begin()) + datas.append(x) + except AttributeError: + pass + + dex_object, ana_object = AG_DEX_VIEW[self.view.id()] + + for x in datas: + if x in AG_METHODS_LINE[current_view_id]: + MethodView(self.view.id(), AG_METHODS_LINE[current_view_id][x]) + elif x in AG_FIELDS_LINE[current_view_id]: + FieldView(self.view.id(), AG_FIELDS_LINE[current_view_id][x]) + elif x in AG_CLASSES_LINE[current_view_id]: + ClassView(self.view.id(), AG_CLASSES_LINE[current_view_id][x]) + + elif self.view.id() in AG_APK_VIEW: + apk_object = AG_APK_VIEW[self.view.id()] + + datas = [] + try: + for sel in self.view.sel(): + datas.append(self.view.substr(self.view.line(sel))) + except AttributeError: + pass + + filename = FILENAMES[self.view.id()] + for x in datas: + if x == "classes.dex": + at = AnalyseDexThread(sublime.active_window().new_file(), filename + "-classes", apk_object.get_dex()) + at.run() + elif x == "AndroidManifest.xml": + at = AnalyseAXMLThread(sublime.active_window().new_file(), filename + "-AndroidManifest", apk_object) + at.run() + elif x == "resources.arsc": + at = AnalyseARSCThread(sublime.active_window().new_file(), filename + "-resources", apk_object.get_file(x)) + at.run() + elif ".xml" in x: + at = AnalyseAXMLSimpleThread(sublime.active_window().new_file(), filename + "-%s" + x, apk_object.get_file(x)) + at.run() + else: + new_view = sublime.active_window().new_file() + new_view.set_name("%s-%s" % (filename, x)) + new_view.set_syntax_file("Packages/Text/Plain text.tmLanguage") + + new_view.set_scratch(True) + edit = new_view.begin_edit() + new_view.sel().clear() + + i_buffer = apk_object.get_file(x).decode('utf-8', 'replace') + + new_view.replace(edit, sublime.Region(0, new_view.size()), i_buffer) + new_view.end_edit(edit) + new_view.set_read_only(True) + + +class ThreadProgress(): + def __init__(self, thread, message, success_message): + self.thread = thread + self.message = message + self.success_message = success_message + self.addend = 1 + self.size = 8 + sublime.set_timeout(lambda: self.run(0), 100) + + def run(self, i): + if not self.thread.is_alive(): + if hasattr(self.thread, 'result') and not self.thread.result: + sublime.status_message('') + return + sublime.status_message(self.success_message) + return + + before = i % self.size + after = (self.size - 1) - before + sublime.status_message('%s [%s=%s]' % \ + (self.message, ' ' * before, ' ' * after)) + if not after: + self.addend = -1 + if not before: + self.addend = 1 + i += self.addend + sublime.set_timeout(lambda: self.run(i), 100) + + +class AnalyseAXMLThread: + def __init__(self, view, filename, apk_object): + self.view = view + self.apk_object = apk_object + self.filename = filename + #threading.Thread.__init__(self) + + def run(self): + self.view.set_name("%s.uaxml" % (self.filename)) + + self.view.set_scratch(True) + edit = self.view.begin_edit() + self.view.sel().clear() + #self.view.set_syntax_file("Packages/ag-st/agapk.tmLanguage") + + i_buffer = get_axml_info(self.apk_object) + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.set_read_only(True) + + AG_AXML_ID[self.view.id()] = self.apk_object + + if self.view.id() not in AG_SC: + AG_SC[self.view.id()] = False + + +class AnalyseAXMLSimpleThread: + def __init__(self, view, filename, raw_object): + self.view = view + self.raw_object = raw_object + self.filename = filename + #threading.Thread.__init__(self) + + def run(self): + self.view.set_name("%s.uaxml" % (self.filename)) + + self.view.set_scratch(True) + edit = self.view.begin_edit() + self.view.sel().clear() + self.view.set_syntax_file("Packages/XML/XML.tmLanguage") + + ap = apk.AXMLPrinter(self.raw_object) + i_buffer = ap.get_xml() + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.set_read_only(True) + + +class AnalyseARSCThread: + def __init__(self, view, filename, raw_object): + self.view = view + self.raw_object = raw_object + self.filename = filename + #threading.Thread.__init__(self) + + def run(self): + self.view.set_name("%s.uarsc" % (self.filename)) + + self.view.set_scratch(True) + edit = self.view.begin_edit() + self.view.sel().clear() + #self.view.set_syntax_file("Packages/ag-st/agapk.tmLanguage") + + arscobj = apk.ARSCParser(self.raw_object) + i_buffer = apk.get_arsc_info(arscobj) + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.set_read_only(True) + + AG_ARSC_ID[self.view.id()] = arscobj + + if self.view.id() not in AG_SC: + AG_SC[self.view.id()] = False + + +class AnalyseAPKThread: + def __init__(self, view, filename, raw): + self.view = view + self.raw = raw + self.filename = filename + #threading.Thread.__init__(self) + + def run(self): + apk_object = apk.APK(self.raw, raw=True) + self.view.set_name("%s.uapk" % (self.filename)) + + self.view.set_scratch(True) + edit = self.view.begin_edit() + self.view.sel().clear() + self.view.set_syntax_file("Packages/ag-st/agapk.tmLanguage") + + i_buffer = "" +# files_list = apk_object.get_files_types() +# for i in files_list: +# i_buffer += "%s: %s" % (i, files_list[i]) + + for i in sorted(apk_object.get_files()): + i_buffer += "%s\n" % i + + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + self.view.set_read_only(True) + AG_APK_VIEW[self.view.id()] = apk_object + FILENAMES[self.view.id()] = hashlib.sha1(apk_object.get_raw()).hexdigest() + + +class AnalyseDexThread: # (threading.Thread): + def __init__(self, view, filename, raw): + self.view = view + self.raw = raw + self.filename = filename + #threading.Thread.__init__(self) + + def run(self): + if androconf.is_android_raw(self.raw) == "DEY": + dex_object = dvm.DalvikOdexVMFormat(self.raw) + else: + dex_object = dvm.DalvikVMFormat(self.raw) + + ana_object = analysis.uVMAnalysis(dex_object) + gvm_object = ganalysis.GVMAnalysis(ana_object, None) + + dex_object.set_vmanalysis(ana_object) + dex_object.set_gvmanalysis(gvm_object) + + for i in androconf.CONF: + if is_setting(i): + androconf.CONF[i] = get_setting(i) + + decompiler_option = get_setting("DEFAULT_DECOMPILER", "dad") + + if decompiler_option == "dex2jad": + dex_object.set_decompiler(decompiler.DecompilerDex2Jad( + dex_object, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_JAD"], + androconf.CONF["BIN_JAD"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler_option == "ded": + dex_object.set_decompiler(decompiler.DecompilerDed( + dex_object, + androconf.CONF["PATH_DED"], + androconf.CONF["BIN_DED"], + androconf.CONF["TMP_DIRECTORY"])) + else: + dex_object.set_decompiler(decompiler.DecompilerDAD(dex_object, ana_object)) + + dex_object.create_xref() + dex_object.create_dref() + + self.view.set_name("%s.ag" % (self.filename)) + + self.view.set_scratch(True) + edit = self.view.begin_edit() + self.view.sel().clear() + self.view.set_syntax_file("Packages/ag-st/ag.tmLanguage") + + by_package = {} + for current_class in dex_object.get_classes(): + name = current_class.get_name() + + try: + by_package[os.path.dirname(name)].append(current_class) + except KeyError: + by_package[os.path.dirname(name)] = [] + by_package[os.path.dirname(name)].append(current_class) + + b_buffer = "" + line = 0 + + AG_METHODS_LINE[self.view.id()] = {} + AG_CLASSES_LINE[self.view.id()] = {} + AG_FIELDS_LINE[self.view.id()] = {} + for key in sorted(by_package.iterkeys()): + b_buffer += "%s\n" % key + line += 1 + + for c_class in sorted(by_package[key], key=lambda k: k.get_name()): + b_buffer += "\t%s extends %s\n" % (c_class.get_name()[1:-1], c_class.get_superclassname()[1:-1]) + AG_CLASSES_LINE[self.view.id()][line] = c_class + line += 1 + + for j in c_class.get_methods(): + b_buffer += "\t\tmethod: %s %s [%s] size:%d\n" % (j.get_name(), j.get_descriptor(), j.get_access_flags_string(), j.get_length()) + AG_METHODS_LINE[self.view.id()][line] = j + line += 1 + + b_buffer += "\n" + line += 1 + + for j in c_class.get_fields(): + b_buffer += "\t\tfield: %s %s [%s %s]" % (j.get_name(), j.get_descriptor(), j.get_access_flags_string(), dvm.get_type(j.get_descriptor())) + + init_value = j.get_init_value() + if init_value != None: + b_buffer += " (%s)" % repr(str(init_value.get_value())) + b_buffer += "\n" + + AG_FIELDS_LINE[self.view.id()][line] = j + line += 1 + + b_buffer += "\n" + line += 1 + + l = dex_object.print_classes_hierarchy() + h_buffer = "" + for i in l: + h_buffer += i + "\n" + + b_buffer += h_buffer + + self.view.replace(edit, sublime.Region(0, self.view.size()), b_buffer) + self.view.end_edit(edit) + self.view.set_read_only(True) + AG_DEX_VIEW[self.view.id()] = (dex_object, ana_object) + FILENAMES[self.view.id()] = hashlib.sha1(dex_object.get_buff()).hexdigest() + + +class AgCommand(sublime_plugin.WindowCommand): + def run(self): + self.view = self.window.active_view() + + filename = self.view.file_name() + + ret = androconf.is_android(filename) + if ret == "APK": + at = AnalyseAPKThread(self.window.new_file(), filename, open(filename, "rb").read()) + at.run() + elif ret == "DEX" or ret == "DEY": + at = AnalyseDexThread(self.window.new_file(), filename, open(filename, "rb").read()) + at.run() + elif ret == "AXML": + at = AnalyseAXMLSimpleThread(self.window.new_file(), filename, open(filename, "rb").read()) + at.run() + elif ret == "ARSC": + at = AnalyseARSCThread(self.window.new_file(), filename, open(filename, "rb").read()) + at.run() + + #thread = AnalyseThread(self.window.new_file(), filename, open(filename, "rb").read()) + #thread.start() + #ThreadProgress(thread, + # "Analysing app ...", + # "Finished !") + + +def get_strings_info(dex_object, ana_object): + i_buffer = "" + + for i in dex_object.get_strings(): + i_buffer += repr(i) + "\n" + if ana_object != None: + ref = ana_object.tainted_variables.get_string(i) + if ref != None: + for path in ref.get_paths(): + access, idx = path[0] + m_idx = path[1] + method = dex_object.get_cm_method(m_idx) + i_buffer += "\t\t%s %x %s->%s %s\n" % (access, idx, method[0], method[1], method[2][0] + method[2][1]) + + return i_buffer + + +class AgStrings(sublime_plugin.WindowCommand): + def run(self): + self.view = self.window.active_view() + if self.view.id() in AG_DEX_VIEW: + dex_object, ana_object = AG_DEX_VIEW[self.view.id()] + + view = sublime.active_window().new_file() + + filename = FILENAMES[self.view.id()] + view.set_name("%s.strings" % filename) + + view.set_scratch(True) + edit = view.begin_edit() + + i_buffer = get_strings_info(dex_object, ana_object) + + view.replace(edit, sublime.Region(0, view.size()), i_buffer) + view.end_edit(edit) + view.sel().clear() + + +class AgTrCommand(sublime_plugin.WindowCommand): + def run(self): + self.view = self.window.active_view() + + if self.view.id() in AG_METHOD_ID: + dex_object, ana_object = AG_DEX_VIEW[AG_DEX_VIEW_LINK[self.view.id()]] + + self.view.sel().clear() + if not AG_SC[self.view.id()]: + self.view.set_syntax_file("Packages/Java/Java.tmLanguage") + i_buffer = get_sourcecode_method(dex_object, ana_object, AG_METHOD_ID[self.view.id()]) + else: + self.view.set_syntax_file("Packages/ag-st/agbytecodes.tmLanguage") + i_buffer = dvm.get_bytecodes_method(dex_object, ana_object, AG_METHOD_ID[self.view.id()]) + + self.view.set_read_only(False) + edit = self.view.begin_edit() + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + AG_SC[self.view.id()] = not AG_SC[self.view.id()] + + elif self.view.id() in AG_CLASS_ID: + dex_object, ana_object = AG_DEX_VIEW[AG_DEX_VIEW_LINK[self.view.id()]] + + self.view.sel().clear() + + if not AG_SC[self.view.id()]: + self.view.set_syntax_file("Packages/Java/Java.tmLanguage") + i_buffer = AG_CLASS_ID[self.view.id()].get_source() + else: + self.view.set_syntax_file("Packages/ag-st/agbytecodes.tmLanguage") + i_buffer = get_bytecodes_class(dex_object, ana_object, AG_CLASS_ID[self.view.id()]) + + self.view.set_read_only(False) + edit = self.view.begin_edit() + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + + AG_SC[self.view.id()] = not AG_SC[self.view.id()] + + elif self.view.id() in AG_AXML_ID: + apk_object = AG_AXML_ID[self.view.id()] + + self.view.sel().clear() + + if not AG_SC[self.view.id()]: + i_buffer = apk_object.get_android_manifest_xml().toprettyxml() + self.view.set_syntax_file("Packages/XML/XML.tmLanguage") + else: + i_buffer = get_axml_info(apk_object) + + self.view.set_read_only(False) + edit = self.view.begin_edit() + self.view.replace(edit, sublime.Region(0, self.view.size()), i_buffer) + self.view.end_edit(edit) + + AG_SC[self.view.id()] = not AG_SC[self.view.id()] + + +class AgRefFromCommand(sublime_plugin.WindowCommand): + def set_ref(self, value): + if value == -1: + return + + if self.view.id() in AG_METHOD_ID: + self.set_ref_method(value, 0) + elif self.view.id() in AG_FIELD_ID: + self.set_ref_method(value, 1) + + def set_ref_method(self, value, action): + if action == 0: + method = AG_METHOD_ID[self.view.id()] + x_method = method.XREFfrom.items[value][0] + else: + field = AG_FIELD_ID[self.view.id()] + x_method = field.DREFr.items[value][0] + + if x_method in AG_REVERT_METHODS: + if self.window.get_view_index(AG_REVERT_METHODS[x_method])[0] != -1: + self.window.focus_view(AG_REVERT_METHODS[x_method]) + else: + del AG_REVERT_METHODS[x_method] + MethodView(AG_DEX_VIEW_LINK[self.view.id()], x_method) + else: + MethodView(AG_DEX_VIEW_LINK[self.view.id()], x_method) + + def run(self): + self.option_list = [] + + self.view = self.window.active_view() + if self.view.id() in AG_METHOD_ID: + method = AG_METHOD_ID[self.view.id()] + for i in method.XREFfrom.items: + x_method = i[0] + self.option_list.append("%s %s %s" % (x_method.get_class_name(), x_method.get_name(), x_method.get_descriptor())) + elif self.view.id() in AG_FIELD_ID: + field = AG_FIELD_ID[self.view.id()] + for i in field.DREFr.items: + x_method = i[0] + self.option_list.append("%s %s %s" % (x_method.get_class_name(), x_method.get_name(), x_method.get_descriptor())) + + self.window.show_quick_panel(self.option_list, self.set_ref) + + +class AgRefToCommand(sublime_plugin.WindowCommand): + def set_ref(self, value): + if value == -1: + return + + if self.view.id() in AG_METHOD_ID: + self.set_ref_method(value, 0) + elif self.view.id() in AG_FIELD_ID: + self.set_ref_method(value, 1) + + def set_ref_method(self, value, action): + if action == 0: + method = AG_METHOD_ID[self.view.id()] + x_method = method.XREFto.items[value][0] + else: + field = AG_FIELD_ID[self.view.id()] + x_method = field.DREFw.items[value][0] + + if x_method in AG_REVERT_METHODS: + if self.window.get_view_index(AG_REVERT_METHODS[x_method])[0] != -1: + self.window.focus_view(AG_REVERT_METHODS[x_method]) + else: + del AG_REVERT_METHODS[x_method] + MethodView(AG_DEX_VIEW_LINK[self.view.id()], x_method) + else: + MethodView(AG_DEX_VIEW_LINK[self.view.id()], x_method) + + def run(self): + self.option_list = [] + + self.view = self.window.active_view() + if self.view.id() in AG_METHOD_ID: + method = AG_METHOD_ID[self.view.id()] + for i in method.XREFto.items: + x_method = i[0] + self.option_list.append("%s %s %s" % (x_method.get_class_name(), x_method.get_name(), x_method.get_descriptor())) + elif self.view.id() in AG_FIELD_ID: + field = AG_FIELD_ID[self.view.id()] + for i in field.DREFw.items: + x_method = i[0] + self.option_list.append("%s %s %s" % (x_method.get_class_name(), x_method.get_name(), x_method.get_descriptor())) + + self.window.show_quick_panel(self.option_list, self.set_ref) + + +class AgReset(sublime_plugin.WindowCommand): + def run(self): + self.view = self.window.active_view() + + global AG_DEX_VIEW + global AG_APK_VIEW + global AG_DEX_VIEW_LINK + global AG_REVERT_METHODS + global AG_REVERT_FIELDS + global AG_SC + global AG_METHOD_ID + global AG_FIELD_ID + global AG_CLASS_ID + global AG_METHODS_LINE + global AG_FIELDS_LINE + global AG_CLASSES_LINE + global AG_AXML_ID + global AG_ARSC_ID + + AG_DEX_VIEW = {} + AG_APK_VIEW = {} + + AG_DEX_VIEW_LINK = {} + AG_REVERT_METHODS = {} + AG_REVERT_FIELDS = {} + AG_SC = {} + AG_METHOD_ID = {} + AG_FIELD_ID = {} + AG_CLASS_ID = {} + AG_AXML_ID = {} + AG_ARSC_ID = {} + + AG_METHODS_LINE = {} + AG_FIELDS_LINE = {} + AG_CLASSES_LINE = {} + + print "Reset Androguard Plugin" diff --git a/ag-st/ag.tmLanguage b/ag-st/ag.tmLanguage new file mode 100644 index 00000000..2f805280 --- /dev/null +++ b/ag-st/ag.tmLanguage @@ -0,0 +1,59 @@ + + + + + fileTypes + + + + name + Dalvik Classes (Androguard) + patterns + + + comment + package + match + ^([\w\d\_/\$]+) + name + storage.package + + + comment + current class + match + ^(\s*[\w\d\_/\$]+)(\s*)(extends)(\s*)(.)* + name + storage.class + + + comment + init/clinit method + match + ^(\s*(method\:))(\s*)((\<init\>)|(\<clinit\>))(.)+ + name + support + + + comment + method + match + ^(\s*(method\:))(.)+ + name + support.function.classicmethod + + + comment + field + match + ^(\s*(field\:))(.)+ + name + variable + + + scopeName + source.ag + uuid + 75ba8e42-b55b-4823-b4aa-e4e407da9c8d + + diff --git a/ag-st/agapk.JSON-tmLanguage b/ag-st/agapk.JSON-tmLanguage new file mode 100644 index 00000000..befb6b47 --- /dev/null +++ b/ag-st/agapk.JSON-tmLanguage @@ -0,0 +1,17 @@ +{ "name": "APK (Androguard)", + "scopeName": "source.uapk", + "fileTypes": [""], + "patterns": [ + { + "match": "^((classes\\.dex)|(AndroidManifest\\.xml)|(resources\\.arsc))", + "name": "keyword.resources", + "captures": { + "1": { "name": "keyword.classes" }, + "2": { "name": "keyword.androidmanifest" }, + "3": { "name": "keyword.resources" } + }, + "comment": "resources.arsc" + } + ], + "uuid": "75ba8e42-b55b-4823-b4aa-e4e407da9d8c" +} \ No newline at end of file diff --git a/ag-st/agapk.tmLanguage b/ag-st/agapk.tmLanguage new file mode 100644 index 00000000..bd63a929 --- /dev/null +++ b/ag-st/agapk.tmLanguage @@ -0,0 +1,45 @@ + + + + + fileTypes + + + + name + APK (Androguard) + patterns + + + captures + + 1 + + name + keyword.classes + + 2 + + name + keyword.androidmanifest + + 3 + + name + keyword.resources + + + comment + resources.arsc + match + ^((classes\.dex)|(AndroidManifest\.xml)|(resources\.arsc)) + name + keyword.resources + + + scopeName + source.uapk + uuid + 75ba8e42-b55b-4823-b4aa-e4e407da9d8c + + diff --git a/ag-st/agbytecodes.JSON-tmLanguage b/ag-st/agbytecodes.JSON-tmLanguage new file mode 100644 index 00000000..754d37c3 --- /dev/null +++ b/ag-st/agbytecodes.JSON-tmLanguage @@ -0,0 +1,62 @@ +{ "name": "Dalvik Bytecodes (Androguard)", + "scopeName": "source.agbt", + "fileTypes": [""], + "patterns": [ + { + "match": "\\s*(#).*$\\n?", + "name": "comment", + "comment": "comment" + }, + { + "match": "^([\\w\\d\\-\\<\\>\\_]+)(@)([\\w\\d]+)(\\s*)(:)", + "name": "markup.bold", + "comment": "bb name" + }, + { + "match": "(\\-|\\+)([\\d+a-z]+)", + "name": "storage.int", + "comment": "hexa value" + }, + { + "match": ",\\s(\\d*)", + "name": "storage.int", + "captures": { + "1": { "name": "storage.int" } + }, + "comment": "int value" + }, + { + "match": "^(\\s+\\d*\\s+)", + "name": "markup.italic", + "comment": "decimal value" + }, + { + "match": "(\\[)([\\w\\d\\-\\s@\\<\\>\\_\\:])+(\\])", + "name": "markup.list", + "comment": "next bbs list" + }, + { + "match": "(\\()([\\d\\-a-z]+)(\\))(\\s+)([a-z\\-\/0-9]+)([0-9]*)(\\s+)", + "name": "keyword.control", + "captures": { + "2": { "name": "support.constant" }, + "3": { "name": "keyword.control.instruction" } + }, + "comment": "hexa + instruction" + }, + { + "match": "(v\\d+)", + "name": "variable", + "comment": "register" + }, + { "name": "string.quoted.single", + "begin": "(\\')", + "end": "(\\')" + }, + { "name": "string.quoted.double", + "begin": "(\")", + "end": "(\")" + } + ], + "uuid": "75ba8e42-b55b-4823-b4aa-e4e407da9c8e" +} \ No newline at end of file diff --git a/ag-st/agbytecodes.tmLanguage b/ag-st/agbytecodes.tmLanguage new file mode 100644 index 00000000..749134bc --- /dev/null +++ b/ag-st/agbytecodes.tmLanguage @@ -0,0 +1,120 @@ + + + + + fileTypes + + + + name + Dalvik Bytecodes (Androguard) + patterns + + + comment + comment + match + \s*(#).*$\n? + name + comment + + + comment + bb name + match + ^([\w\d\-\<\>\_]+)(@)([\w\d]+)(\s*)(:) + name + markup.bold + + + comment + hexa value + match + (\-|\+)([\d+a-z]+) + name + storage.int + + + captures + + 1 + + name + storage.int + + + comment + int value + match + ,\s(\d*) + name + storage.int + + + comment + decimal value + match + ^(\s+\d*\s+) + name + markup.italic + + + comment + next bbs list + match + (\[)([\w\d\-\s@\<\>\_\:])+(\]) + name + markup.list + + + captures + + 2 + + name + support.constant + + 3 + + name + keyword.control.instruction + + + comment + hexa + instruction + match + (\()([\d\-a-z]+)(\))(\s+)([a-z\-/0-9]+)([0-9]*)(\s+) + name + keyword.control + + + comment + register + match + (v\d+) + name + variable.smali + + + begin + (\') + end + (\') + name + string.quoted.single + + + begin + (") + end + (") + name + string.quoted.double + + + scopeName + source.agbt + uuid + 75ba8e42-b55b-4823-b4aa-e4e407da9c8e + + diff --git a/androapkinfo.py b/androapkinfo.py new file mode 100755 index 00000000..0bb18993 --- /dev/null +++ b/androapkinfo.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os + +from optparse import OptionParser + +from androguard.core import androconf +from androguard.core.bytecodes import apk +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename (APK)', 'nargs' : 1 } +option_1 = { 'name' : ('-d', '--directory'), 'help' : 'directory : use this directory', 'nargs' : 1 } +option_2 = { 'name' : ('-t', '--tag'), 'help' : 'display tags', 'action' : 'count' } +option_3 = { 'name' : ('-v', '--version'), 'help' : 'version', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3] + +def display_dvm_info(apk): + vm = dvm.DalvikVMFormat(apk.get_dex()) + vmx = analysis.uVMAnalysis(vm) + + print "Native code:", analysis.is_native_code(vmx) + print "Dynamic code:", analysis.is_dyn_code(vmx) + print "Reflection code:", analysis.is_reflection_code(vmx) + print "Ascii Obfuscation:", analysis.is_ascii_obfuscation(vm) + + for i in vmx.get_methods(): + i.create_tags() + if not i.tags.empty(): + print i.method.get_class_name(), i.method.get_name(), i.tags + +def main(options, arguments) : + if options.input != None : + ret_type = androconf.is_android( options.input ) + + print os.path.basename(options.input), ":" + if ret_type == "APK" : + try : + a = apk.APK(options.input, zipmodule=2) + if a.is_valid_APK() : + a.show() + display_dvm_info( a ) + else : + print "INVALID" + except Exception, e : + print "ERROR", e + import traceback + traceback.print_exc() + + elif options.directory != None : + for root, dirs, files in os.walk( options.directory, followlinks=True ) : + if files != [] : + for f in files : + real_filename = root + if real_filename[-1] != "/" : + real_filename += "/" + real_filename += f + + ret_type = androconf.is_android( real_filename ) + if ret_type == "APK" : + print os.path.basename( real_filename ), ":" + try : + a = apk.APK( real_filename ) + if a.is_valid_APK() : + a.show() + display_dvm_info( a ) + else : + print "INVALID APK" + raise("ooos") + except Exception, e : + print "ERROR", e + raise("ooos") + + elif options.version != None : + print "Androapkinfo version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androarsc.py b/androarsc.py new file mode 100755 index 00000000..6a2fca87 --- /dev/null +++ b/androarsc.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys +from optparse import OptionParser +from xml.dom import minidom +import codecs + +from androguard.core import androconf +from androguard.core.bytecodes import apk + + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'filename input (APK or android resources(arsc))', 'nargs' : 1 } +option_1 = { 'name' : ('-p', '--package'), 'help' : 'select the package (optional)', 'nargs' : 1 } +option_2 = { 'name' : ('-l', '--locale'), 'help' : 'select the locale (optional)', 'nargs' : 1 } +option_3 = { 'name' : ('-t', '--type'), 'help' : 'select the type (string, interger, public, ...)', 'nargs' : 1 } +option_4 = { 'name' : ('-o', '--output'), 'help' : 'filename output', 'nargs' : 1 } +option_5 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } +options = [option_0, option_1, option_2, option_3, option_4, option_5] + + +def main(options, arguments): + if options.input != None: + buff = "" + + arscobj = None + ret_type = androconf.is_android(options.input) + if ret_type == "APK": + a = apk.APK(options.input) + arscobj = a.get_android_resources() + elif ret_type == "ARSC": + arscobj = apk.ARSCParser(open(options.input, "rb").read()) + else: + print "Unknown file type" + return + + if not options.package and not options.type and not options.locale: + buff = "" + for package in arscobj.get_packages_names(): + buff += package + "\n" + for locale in arscobj.get_locales(package): + buff += "\t" + repr(locale) + "\n" + for ttype in arscobj.get_types(package, locale): + buff += "\t\t" + ttype + "\n" + + else: + package = options.package or arscobj.get_packages_names()[0] + ttype = options.type or "public" + locale = options.locale or '\x00\x00' + + buff = minidom.parseString(getattr(arscobj, "get_" + ttype + "_resources")(package, locale)).toprettyxml() + + if options.output != None: + fd = codecs.open(options.output, "w", "utf-8") + fd.write(buff) + fd.close() + else: + print buff + + elif options.version != None: + print "Androarsc version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__": + parser = OptionParser() + for option in options: + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androauto.py b/androauto.py new file mode 100755 index 00000000..de72023b --- /dev/null +++ b/androauto.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys + +from optparse import OptionParser +from androguard.core.analysis import auto +from androguard.core.androconf import set_debug + +option_0 = {'name': ('-d', '--directory'), 'help': 'directory input', 'nargs': 1} +option_1 = {'name': ('-v', '--verbose'), 'help': 'add debug', 'action': 'count'} +options = [option_0, option_1] + + +class AndroLog: + def __init__(self, id_file, filename): + self.id_file = id_file + + +def main(options, arguments): + if options.verbose: + set_debug() + + if options.directory: + settings = { + "my": auto.DirectoryAndroAnalysis(options.directory), + "log": AndroLog, + "max_fetcher": 3, + } + + aa = auto.AndroAuto(settings) + aa.go() + +if __name__ == "__main__": + parser = OptionParser() + for option in options: + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androaxml.py b/androaxml.py new file mode 100755 index 00000000..aff35061 --- /dev/null +++ b/androaxml.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys +from optparse import OptionParser +from xml.dom import minidom +import codecs + +from androguard.core import androconf +from androguard.core.bytecodes import apk + + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'filename input (APK or android\'s binary xml)', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--output'), 'help' : 'filename output of the xml', 'nargs' : 1 } +option_2 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } +options = [option_0, option_1, option_2] + + +def main(options, arguments) : + if options.input != None : + buff = "" + + ret_type = androconf.is_android(options.input) + if ret_type == "APK": + a = apk.APK(options.input) + buff = a.get_android_manifest_xml().toprettyxml(encoding="utf-8") + elif ".xml" in options.input: + ap = apk.AXMLPrinter(open(options.input, "rb").read()) + buff = minidom.parseString(ap.get_buff()).toprettyxml(encoding="utf-8") + else: + print "Unknown file type" + return + + if options.output != None : + fd = codecs.open(options.output, "w", "utf-8") + fd.write( buff ) + fd.close() + else : + print buff + + elif options.version != None : + print "Androaxml version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androcsign.py b/androcsign.py new file mode 100755 index 00000000..267ac849 --- /dev/null +++ b/androcsign.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys + +from androguard.core import androconf + +sys.path.append("./elsim/") +from elsim.elsign import dalvik_elsign + +from optparse import OptionParser + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename', 'nargs' : 1 } +option_1 = { 'name' : ('-r', '--remove'), 'help' : 'remote the signature', 'nargs' : 1 } +option_2 = { 'name' : ('-o', '--output'), 'help' : 'output database', 'nargs' : 1 } +option_3 = { 'name' : ('-l', '--list'), 'help' : 'list signatures in database', 'nargs' : 1 } +option_4 = { 'name' : ('-c', '--check'), 'help' : 'check signatures in database', 'nargs' : 1 } +option_5 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4, option_5] + +def main(options, arguments) : + s = dalvik_elsign.CSignature(pcs=dalvik_elsign.PublicCSignature) + if options.input != None : + ret = s.add_file( open( options.input, "rb" ).read() ) + if ret != None and options.output != None : + s.add_indb( ret, options.output ) + + elif options.list != None : + s.list_indb( options.list ) + + elif options.remove != None : + s.remove_indb( options.remove, options.output ) + + elif options.check != None : + s.check_db( options.check ) + + elif options.version != None : + print "Androcsign version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androdd.py b/androdd.py new file mode 100755 index 00000000..de3d6a62 --- /dev/null +++ b/androdd.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012/2013, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import shutil +import sys +import os +import re + +from optparse import OptionParser + +from androguard.core.androgen import Androguard +from androguard.core import androconf +from androguard.core.analysis import analysis +from androguard.core.bytecodes import dvm +from androguard.core.bytecode import method2dot, method2format +from androguard.decompiler import decompiler + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--output'), 'help' : 'base directory to output all files', 'nargs' : 1 } +option_2 = { 'name' : ('-d', '--decompiler'), 'help' : 'choose a decompiler', 'nargs' : 1 } +option_3 = { 'name' : ('-j', '--jar'), 'help' : 'output jar file', 'action' : 'count' } + +option_4 = { 'name' : ('-f', '--format'), 'help' : 'write the method in specific format (png, ...)', 'nargs' : 1 } + +option_5 = { 'name' : ('-l', '--limit'), 'help' : 'limit analysis to specific methods/classes by using a regexp', 'nargs' : 1} +option_6 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4, option_5, option_6] + + +def valid_class_name(class_name): + if class_name[-1] == ";": + return class_name[1:-1] + return class_name + + +def create_directory(class_name, output): + output_name = output + if output_name[-1] != "/": + output_name = output_name + "/" + + pathdir = output_name + class_name + try: + if not os.path.exists(pathdir): + os.makedirs(pathdir) + except OSError: + # FIXME + pass + + +def export_apps_to_format(filename, a, output, methods_filter=None, jar=None, decompiler_type=None, format=None): + print "Dump information %s in %s" % (filename, output) + + if not os.path.exists(output): + print "Create directory %s" % output + os.makedirs(output) + else: + print "Clean directory %s" % output + androconf.rrmdir(output) + os.makedirs(output) + + methods_filter_expr = None + if methods_filter: + methods_filter_expr = re.compile(methods_filter) + + output_name = output + if output_name[-1] != "/": + output_name = output_name + "/" + + dump_classes = [] + for vm in a.get_vms(): + print "Analysis ...", + sys.stdout.flush() + vmx = analysis.VMAnalysis(vm) + print "End" + + print "Decompilation ...", + sys.stdout.flush() + + if not decompiler_type: + vm.set_decompiler(decompiler.DecompilerDAD(vm, vmx)) + elif decompiler_type == "dex2jad": + vm.set_decompiler(decompiler.DecompilerDex2Jad(vm, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_JAD"], + androconf.CONF["BIN_JAD"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler_type == "dex2winejad": + vm.set_decompiler(decompiler.DecompilerDex2WineJad(vm, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_JAD"], + androconf.CONF["BIN_WINEJAD"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler_type == "ded": + vm.set_decompiler(decompiler.DecompilerDed(vm, + androconf.CONF["PATH_DED"], + androconf.CONF["BIN_DED"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler_type == "dex2fernflower": + vm.set_decompiler(decompiler.DecompilerDex2Fernflower(vm, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_FERNFLOWER"], + androconf.CONF["BIN_FERNFLOWER"], + androconf.CONF["OPTIONS_FERNFLOWER"], + androconf.CONF["TMP_DIRECTORY"])) + else: + raise("invalid decompiler !") + print "End" + + if options.jar: + print "jar ...", + filenamejar = decompiler.Dex2Jar(vm, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["TMP_DIRECTORY"]).get_jar() + shutil.move(filenamejar, output + "classes.jar") + print "End" + + for method in vm.get_methods(): + if methods_filter_expr: + msig = "%s%s%s" % (method.get_class_name(), + method.get_name(), + method.get_descriptor()) + if not methods_filter_expr.search(msig): + continue + + filename_class = valid_class_name(method.get_class_name()) + create_directory(filename_class, output) + + print "Dump %s %s %s ..." % (method.get_class_name(), + method.get_name(), + method.get_descriptor()), + + filename_class = output_name + filename_class + if filename_class[-1] != "/": + filename_class = filename_class + "/" + + descriptor = method.get_descriptor() + descriptor = descriptor.replace(";", "") + descriptor = descriptor.replace(" ", "") + descriptor = descriptor.replace("(", "-") + descriptor = descriptor.replace(")", "-") + descriptor = descriptor.replace("/", "_") + + filename = filename_class + method.get_name() + descriptor + if len(method.get_name() + descriptor) > 250: + all_identical_name_methods = vm.get_methods_descriptor(method.get_class_name(), method.get_name()) + pos = 0 + for i in all_identical_name_methods: + if i.get_descriptor() == method.get_descriptor(): + break + pos += 1 + + filename = filename_class + method.get_name() + "_%d" % pos + + buff = method2dot(vmx.get_method(method)) + + if format: + print "%s ..." % format, + method2format(filename + "." + format, format, None, buff) + + if method.get_class_name() not in dump_classes: + print "source codes ...", + current_class = vm.get_class(method.get_class_name()) + current_filename_class = valid_class_name(current_class.get_name()) + create_directory(filename_class, output) + + current_filename_class = output_name + current_filename_class + ".java" + fd = open(current_filename_class, "w") + fd.write(current_class.get_source()) + fd.close() + + dump_classes.append(method.get_class_name()) + + print "bytecodes ...", + bytecode_buff = dvm.get_bytecodes_method(vm, vmx, method) + fd = open(filename + ".ag", "w") + fd.write(bytecode_buff) + fd.close() + + print + + +def main(options, arguments): + if options.input != None and options.output != None: + a = Androguard([options.input]) + export_apps_to_format(options.input, a, options.output, options.limit, options.jar, options.decompiler, options.format) + elif options.version != None: + print "Androdd version %s" % androconf.ANDROGUARD_VERSION + else: + print "Please, specify an input file and an output directory" + +if __name__ == "__main__": + parser = OptionParser() + for option in options: + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androdiff.py b/androdiff.py new file mode 100755 index 00000000..56306cc4 --- /dev/null +++ b/androdiff.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys + +from optparse import OptionParser + +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis import analysis +from androguard.core import androconf + +sys.path.append("./elsim") +from elsim import elsim +from elsim.elsim_dalvik import ProxyDalvik, FILTERS_DALVIK_SIM, ProxyDalvikMethod, FILTERS_DALVIK_BB +from elsim.elsim_dalvik import ProxyDalvikBasicBlock, FILTERS_DALVIK_DIFF_BB +from elsim.elsim_dalvik import DiffDalvikMethod + + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use these filenames', 'nargs' : 2 } +option_1 = { 'name' : ('-t', '--threshold'), 'help' : 'define the threshold', 'nargs' : 1 } +option_2 = { 'name' : ('-c', '--compressor'), 'help' : 'define the compressor', 'nargs' : 1 } +option_3 = { 'name' : ('-d', '--display'), 'help' : 'display the file in human readable format', 'action' : 'count' } +#option_4 = { 'name' : ('-e', '--exclude'), 'help' : 'exclude specific blocks (0 : orig, 1 : diff, 2 : new)', 'nargs' : 1 } +option_5 = { 'name' : ('-e', '--exclude'), 'help' : 'exclude specific class name (python regexp)', 'nargs' : 1 } +option_6 = { 'name' : ('-s', '--size'), 'help' : 'exclude specific method below the specific size', 'nargs' : 1 } +option_7 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_5, option_6, option_7] + +def main(options, arguments) : + details = False + if options.display != None : + details = True + + if options.input != None : + ret_type = androconf.is_android( options.input[0] ) + if ret_type == "APK" : + a = apk.APK( options.input[0] ) + d1 = dvm.DalvikVMFormat( a.get_dex() ) + elif ret_type == "DEX" : + d1 = dvm.DalvikVMFormat( open(options.input[0], "rb").read() ) + + dx1 = analysis.VMAnalysis( d1 ) + + ret_type = androconf.is_android( options.input[1] ) + if ret_type == "APK" : + a = apk.APK( options.input[1] ) + d2 = dvm.DalvikVMFormat( a.get_dex() ) + elif ret_type == "DEX" : + d2 = dvm.DalvikVMFormat( open(options.input[1], "rb").read() ) + + dx2 = analysis.VMAnalysis( d2 ) + + print d1, dx1, d2, dx2 + sys.stdout.flush() + + threshold = None + if options.threshold != None : + threshold = float(options.threshold) + + FS = FILTERS_DALVIK_SIM + FS[elsim.FILTER_SKIPPED_METH].set_regexp( options.exclude ) + FS[elsim.FILTER_SKIPPED_METH].set_size( options.size ) + el = elsim.Elsim( ProxyDalvik(d1, dx1), ProxyDalvik(d2, dx2), FS, threshold, options.compressor ) + el.show() + + e1 = elsim.split_elements( el, el.get_similar_elements() ) + for i in e1 : + j = e1[ i ] + elb = elsim.Elsim( ProxyDalvikMethod(i), ProxyDalvikMethod(j), FILTERS_DALVIK_BB, threshold, options.compressor ) + #elb.show() + + eld = elsim.Eldiff( ProxyDalvikBasicBlock(elb), FILTERS_DALVIK_DIFF_BB ) + #eld.show() + + ddm = DiffDalvikMethod( i, j, elb, eld ) + ddm.show() + + print "NEW METHODS" + enew = el.get_new_elements() + for i in enew : + el.show_element( i, False ) + + print "DELETED METHODS" + edel = el.get_deleted_elements() + for i in edel : + el.show_element( i ) + + elif options.version != None : + print "Androdiff version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androdis.py b/androdis.py new file mode 100755 index 00000000..0227d2d3 --- /dev/null +++ b/androdis.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Axelle Apvrille +# Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys +import os +from optparse import OptionParser +from androguard.core import androconf +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes.apk import * + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename (DEX/ODEX)', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--offset'), 'help' : 'offset to disassemble', 'nargs' : 1 } +option_2 = { 'name' : ('-s', '--size'), 'help' : 'size', 'nargs' : 1 } + +options = [option_0, option_1, option_2] + + +def disassemble(dex, offset, size): + d = dvm.auto(dex) + if d != None: + nb = 0 + idx = offset + for i in d.disassemble(offset, size): + print "%-8d(%08x)" % (nb, idx), + i.show(idx) + print + + idx += i.get_length() + nb += 1 + + +def main(options, arguments): + if options.input and options.offset and options.size: + offset = int(options.offset, 0) + size = int(options.size, 0) + disassemble(options.input, offset, size) + + +if __name__ == "__main__": + parser = OptionParser() + for option in options: + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androdump.py b/androdump.py new file mode 100755 index 00000000..60d3f0f4 --- /dev/null +++ b/androdump.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os, cmd, threading, re, atexit + +from optparse import OptionParser + +import androguard, androconf, jvm + +# External Libraries + +# python-ptrace : http://bitbucket.org/haypo/python-ptrace/ +from ptrace import PtraceError +from ptrace.tools import locateProgram +from ptrace.debugger import ProcessExit, DebuggerError, PtraceDebugger, ProcessExit, ProcessSignal, NewProcessEvent, ProcessExecution +from ptrace.debugger.memory_mapping import readProcessMappings +#################### + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'pid', 'nargs' : 1 } + +option_1 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1] + +MAGIC_PATTERN = "\xca\xfe\xba\xbe" + +class AndroPreDump : + def __init__(self, input) : + self.data = [] + + self.pid = int(input) + self.debugger = PtraceDebugger() + self.process = self.debugger.addProcess(self.pid, is_attached=False) + atexit.register(self.debugger.quit) + + Header = False + Code = False + + self.procmaps = readProcessMappings(self.process) + for pm in self.procmaps: + if pm.permissions.find("w") != -1 and pm.pathname == None : + +# if Code == False and Header == True : +# data = self.process.readBytes(pm.start, pm.end-pm.start) +# idx = data.find("SourceFile") +# if idx != -1 : +# print "CODE", pm +# self.data.append( (pm, data, idx) ) +# Code = True + + if Header == False : + data = self.process.readBytes(pm.start, pm.end-pm.start) + idx = data.find(MAGIC_PATTERN) + if idx != -1 : + print "HEADER", pm + self.data.append( (pm, data) ) + Header = True + + self.dumpMemory( "java_dump_memory" ) +# self.dumpFiles( "java_files" ) + + def write(self, idx, buff) : + self.process.writeBytes( idx, buff ) + + def getFilesBuffer(self) : + for i in self.data : + d = i[1] + x = d.find(MAGIC_PATTERN) + idx = x + while x != -1 : + yield i[0].start + idx, d[x:] + d = d[x+len(MAGIC_PATTERN):] + + idx += len(MAGIC_PATTERN) + x = d.find(MAGIC_PATTERN) + idx += x + + def dumpMemory(self, base_filename) : + for i in self.data : + fd = open(base_filename + "-" + "0x%x-0x%x" % (i[0].start, i[0].end), "w") + fd.write( i[1] ) + fd.close() + + def dumpFiles(self, base_filename) : + for i in self.data : + fd = open(base_filename + "-" + "0x%x-0x%x" % (i[0].start + i[2], i[0].end), "w") + fd.write( i[1][i[2]:] ) + fd.close() + +class AndroDump : + def __init__(self, adp) : + self.__adp = adp + + for i in self.__adp.getFilesBuffer() : + try : + print "0x%x :" % (i[0]) + j = jvm.JVMFormat( i[1] ) + + for method in j.get_methods() : + print "\t -->", method.get_class_name(), method.get_name(), method.get_descriptor() + +# if (method.get_class_name() == "Test2" and method.get_name() == "main") : +# print "patch" + +# code = method.get_code() + #code.remplace_at( 51, [ "bipush", 20 ] ) +# code.show() + +# print "\t\t-> %x" % (len(j.save())) + +# self.__adp.write( i[0], j.save() ) + except Exception, e : + print e + +def main(options, arguments) : + if options.input != None : + apd = AndroPreDump( options.input ) + AndroDump( apd ) + + elif options.version != None : + print "Androdump version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androgexf.py b/androgexf.py new file mode 100755 index 00000000..67117bef --- /dev/null +++ b/androgexf.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +from xml.sax.saxutils import escape, unescape +import sys, hashlib, os +from optparse import OptionParser + +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis import analysis, ganalysis +from androguard.core import androconf + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'filename input (dex, apk)', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--output'), 'help' : 'filename output of the gexf', 'nargs' : 1 } + +options = [option_0, option_1] + +def main(options, arguments) : + if options.input != None and options.output != None : + ret_type = androconf.is_android( options.input ) + + vm = None + a = None + if ret_type == "APK" : + a = apk.APK( options.input ) + if a.is_valid_APK() : + vm = dvm.DalvikVMFormat( a.get_dex() ) + else : + print "INVALID APK" + elif ret_type == "DEX" : + try : + vm = dvm.DalvikVMFormat( open(options.input, "rb").read() ) + except Exception, e : + print "INVALID DEX", e + + vmx = analysis.VMAnalysis( vm ) + gvmx = ganalysis.GVMAnalysis( vmx, a ) + + b = gvmx.export_to_gexf() + androconf.save_to_disk( b, options.output ) + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androguard/__init__.py b/androguard/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/__init__.py b/androguard/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/analysis/__init__.py b/androguard/core/analysis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/analysis/analysis.py b/androguard/core/analysis/analysis.py new file mode 100644 index 00000000..51ecab1d --- /dev/null +++ b/androguard/core/analysis/analysis.py @@ -0,0 +1,2550 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re, random, string, cPickle + +from androguard.core.androconf import error, warning, debug, is_ascii_problem +from androguard.core.bytecodes import jvm, dvm +from androguard.core.bytecodes.api_permissions import DVM_PERMISSIONS_BY_PERMISSION, DVM_PERMISSIONS_BY_ELEMENT + +class ContextField : + def __init__(self, mode) : + self.mode = mode + self.details = [] + + def set_details(self, details) : + for i in details : + self.details.append( i ) + +class ContextMethod : + def __init__(self) : + self.details = [] + + def set_details(self, details) : + for i in details : + self.details.append( i ) + +class ExternalFM : + def __init__(self, class_name, name, descriptor) : + self.class_name = class_name + self.name = name + self.descriptor = descriptor + + def get_class_name(self) : + return self.class_name + + def get_name(self) : + return self.name + + def get_descriptor(self) : + return self.descriptor + +class ToString : + def __init__(self, tab) : + self.__tab = tab + self.__re_tab = {} + + for i in self.__tab : + self.__re_tab[i] = [] + for j in self.__tab[i] : + self.__re_tab[i].append( re.compile( j ) ) + + self.__string = "" + + def push(self, name) : + for i in self.__tab : + for j in self.__re_tab[i] : + if j.match(name) != None : + if len(self.__string) > 0 : + if i == 'O' and self.__string[-1] == 'O' : + continue + self.__string += i + + def get_string(self) : + return self.__string + +class BreakBlock(object) : + def __init__(self, _vm, idx) : + self._vm = _vm + self._start = idx + self._end = self._start + + self._ins = [] + + self._ops = [] + + self._fields = {} + self._methods = {} + + + def get_ops(self) : + return self._ops + + def get_fields(self) : + return self._fields + + def get_methods(self) : + return self._methods + + def push(self, ins) : + self._ins.append(ins) + self._end += ins.get_length() + + def get_start(self) : + return self._start + + def get_end(self) : + return self._end + + def show(self) : + for i in self._ins : + print "\t\t", + i.show(0) + +##### JVM ###### +FIELDS = { + "getfield" : "R", + "getstatic" : "R", + "putfield" : "W", + "putstatic" : "W", + } + +METHODS = [ "invokestatic", "invokevirtual", "invokespecial" ] + +JVM_TOSTRING = { "O" : jvm.MATH_JVM_OPCODES.keys(), + "I" : jvm.INVOKE_JVM_OPCODES, + "G" : jvm.FIELD_READ_JVM_OPCODES, + "P" : jvm.FIELD_WRITE_JVM_OPCODES, + } + +BREAK_JVM_OPCODES_RE = [] +for i in jvm.BREAK_JVM_OPCODES : + BREAK_JVM_OPCODES_RE.append( re.compile( i ) ) + +class Stack : + def __init__(self) : + self.__elems = [] + + def gets(self) : + return self.__elems + + def push(self, elem) : + self.__elems.append( elem ) + + def get(self) : + return self.__elems[-1] + + def pop(self) : + return self.__elems.pop(-1) + + def nil(self) : + return len(self.__elems) == 0 + + def insert_stack(self, idx, elems) : + if elems != self.__elems : + for i in elems : + self.__elems.insert(idx, i) + idx += 1 + + def show(self) : + nb = 0 + + if len(self.__elems) == 0 : + print "\t--> nil" + + for i in self.__elems : + print "\t-->", nb, ": ", i + nb += 1 + +class StackTraces : + def __init__(self) : + self.__elems = [] + + def save(self, idx, i_idx, ins, stack_pickle, msg_pickle) : + self.__elems.append( (idx, i_idx, ins, stack_pickle, msg_pickle) ) + + def get(self) : + for i in self.__elems : + yield (i[0], i[1], i[2], cPickle.loads( i[3] ), cPickle.loads( i[4] ) ) + + def show(self) : + for i in self.__elems : + print i[0], i[1], i[2].get_name() + + cPickle.loads( i[3] ).show() + print "\t", cPickle.loads( i[4] ) + +def push_objectref(_vm, ins, special, stack, res, ret_v) : + value = "OBJ_REF_@_%s" % str(special) + stack.push( value ) + +def push_objectref_l(_vm, ins, special, stack, res, ret_v) : + stack.push( "VARIABLE_LOCAL_%d" % special ) + +def push_objectref_l_i(_vm, ins, special, stack, res, ret_v) : + stack.push( "VARIABLE_LOCAL_%d" % ins.get_operands() ) + +def pop_objectref(_vm, ins, special, stack, res, ret_v) : + ret_v.add_return( stack.pop() ) + +def multi_pop_objectref_i(_vm, ins, special, stack, res, ret_v) : + for i in range(0, ins.get_operands()[1]) : + stack.pop() + +def push_objectres(_vm, ins, special, stack, res, ret_v) : + value = "" + + if special[0] == 1 : + value += special[1] + "(" + str( res.pop() ) + ") " + else : + for i in range(0, special[0]) : + value += str( res.pop() ) + special[1] + + value = value[:-1] + + stack.push( value ) + +def push_integer_i(_vm, ins, special, stack, res, ret_v) : + value = ins.get_operands() + stack.push( value ) + +def push_integer_d(_vm, ins, special, stack, res, ret_v) : + stack.push( special ) + +def push_float_d(_vm, ins, special, stack, res, ret_v) : + stack.push( special ) + +def putfield(_vm, ins, special, stack, res, ret_v) : + ret_v.add_return( stack.pop() ) + +def putstatic(_vm, ins, special, stack, res, ret_v) : + stack.pop() + +def getfield(_vm, ins, special, stack, res, ret_v) : + ret_v.add_return( stack.pop() ) + stack.push( "FIELD" ) + +def getstatic(_vm, ins, special, stack, res, ret_v) : + stack.push( "FIELD_STATIC" ) + +def new(_vm, ins, special, stack, res, ret_v) : + stack.push( "NEW_OBJ" ) + +def dup(_vm, ins, special, stack, res, ret_v) : + l = [] + + for i in range(0, special+1) : + l.append( stack.pop() ) + l.reverse() + + l.insert( 0, l[-1] ) + for i in l : + stack.push( i ) + +def dup2(_vm, ins, special, stack, res, ret_v) : + l = [] + + for i in range(0, special+1) : + l.append( stack.pop() ) + l.reverse() + + l.insert( 0, l[-1] ) + l.insert( 1, l[-2] ) + for i in l : + stack.push( i ) + +#FIXME +def ldc(_vm, ins, special, stack, res, ret_v) : + #print ins.get_name(), ins.get_operands(), special + stack.push( "STRING" ) + +def invoke(_vm, ins, special, stack, res, ret_v) : + desc = ins.get_operands()[-1] + param = desc[1:desc.find(")")] + ret = desc[desc.find(")")+1:] + +# print "DESC --->", param, calc_nb( param ), ret, calc_nb( ret ) + + for i in range(0, calc_nb( param )) : + stack.pop() + + # objectref : static or not + for i in range(0, special) : + stack.pop() + + for i in range(0, calc_nb( ret )): + stack.push( "E" ) + +def set_arrayref(_vm, ins, special, stack, res, ret_v) : + ret_v.add_msg( "SET VALUE %s %s @ ARRAY REF %s %s" % (special, str(stack.pop()), str(stack.pop()), str(stack.pop())) ) + +def set_objectref(_vm, ins, special, stack, res, ret_v) : + ret_v.add_msg( "SET OBJECT REF %d --> %s" % (special, str(stack.pop())) ) + +def set_objectref_i(_vm, ins, special, stack, res, ret_v) : + ret_v.add_msg( "SET OBJECT REF %d --> %s" % (ins.get_operands(), str(stack.pop())) ) + +def swap(_vm, ins, special, stack, res, ret_v) : + l = stack.pop() + l2 = stack.pop() + + stack.push(l2) + stack.push(l) + +def calc_nb(info) : + if info == "" or info == "V" : + return 0 + + if ";" in info : + n = 0 + for i in info.split(";") : + if i != "" : + n += 1 + return n + else : + return len(info) - info.count('[') + +INSTRUCTIONS_ACTIONS = { + "aaload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "aastore" : [ { set_arrayref : None } ], + "aconst_null" : [ { push_objectref : "null" } ], + "aload" : [ { push_objectref_l_i : None } ], + "aload_0" : [ { push_objectref_l : 0 } ], + "aload_1" : [ { push_objectref_l : 1 } ], + "aload_2" : [ { push_objectref_l : 2 } ], + "aload_3" : [ { push_objectref_l : 3 } ], + "anewarray" : [ { pop_objectref : None }, { push_objectref : [ 1, "ANEWARRAY" ] } ], + "areturn" : [ { pop_objectref : None } ], + "arraylength" : [ { pop_objectref : None }, { push_objectres : [ 1, 'LENGTH' ] } ], + "astore" : [ { set_objectref_i : None } ], + "astore_0" : [ { set_objectref : 0 } ], + "astore_1" : [ { set_objectref : 1 } ], + "astore_2" : [ { set_objectref : 2 } ], + "astore_3" : [ { set_objectref : 3 } ], + "athrow" : [ { pop_objectref : None }, { push_objectres : [ 1, "throw" ] } ], + "baload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "bastore" : [ { set_arrayref : "byte" } ], + "bipush" : [ { push_integer_i : None } ], + "caload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "castore" : [ { set_arrayref : "char" } ], + "checkcast" : [ { pop_objectref : None }, { push_objectres : [ 1, "checkcast" ] } ], + "d2f" : [ { pop_objectref : None }, { push_objectres : [ 1, 'float' ] } ], + "d2i" : [ { pop_objectref : None }, { push_objectres : [ 1, 'integer' ] } ], + "d2l" : [ { pop_objectref : None }, { push_objectres : [ 1, 'long' ] } ], + "dadd" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '+' ] } ], + "daload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "dastore" : [ { set_arrayref : "double" } ], + "dcmpg" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "dcmpl" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "dconst_0" : [ { push_float_d : 0.0 } ], + "dconst_1" : [ { push_float_d : 1.0 } ], + "ddiv" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '&' ] } ], + "dload" : [ { push_objectref_l_i : None } ], + "dload_0" : [ { push_objectref_l : 0 } ], + "dload_1" : [ { push_objectref_l : 1 } ], + "dload_2" : [ { push_objectref_l : 2 } ], + "dload_3" : [ { push_objectref_l : 3 } ], + "dmul" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '*' ] } ], + "dneg" : [ { pop_objectref : None }, { push_objectres : [ 1, '-' ] } ], + "drem" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, 'rem' ] } ], + "dreturn" : [ { pop_objectref : None } ], + "dstore" : [ { set_objectref_i : None } ], + "dstore_0" : [ { set_objectref : 0 } ], + "dstore_1" : [ { set_objectref : 1 } ], + "dstore_2" : [ { set_objectref : 2 } ], + "dstore_3" : [ { set_objectref : 3 } ], + "dsub" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '-' ] } ], + "dup" : [ { dup : 0 } ], + "dup_x1" : [ { dup : 1 } ], + "dup_x2" : [ { dup : 2 } ], + "dup2" : [ { dup2 : 0 } ], + "dup2_x1" : [ { dup2 : 1 } ], + "dup2_x2" : [ { dup2 : 2 } ], + "f2d" : [ { pop_objectref : None }, { push_objectres : [ 1, 'double' ] } ], + "f2i" : [ { pop_objectref : None }, { push_objectres : [ 1, 'integer' ] } ], + "f2l" : [ { pop_objectref : None }, { push_objectres : [ 1, 'long' ] } ], + "fadd" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '+' ] } ], + "faload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "fastore" : [ { set_arrayref : "float" } ], + "fcmpg" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "fcmpl" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "fconst_0" : [ { push_float_d : 0.0 } ], + "fconst_1" : [ { push_float_d : 1.0 } ], + "fconst_2" : [ { push_float_d : 2.0 } ], + "fdiv" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '&' ] } ], + "fload" : [ { push_objectref_l_i : None } ], + "fload_0" : [ { push_objectref_l : 0 } ], + "fload_1" : [ { push_objectref_l : 1 } ], + "fload_2" : [ { push_objectref_l : 2 } ], + "fload_3" : [ { push_objectref_l : 3 } ], + "fmul" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '*' ] } ], + "fneg" : [ { pop_objectref : None }, { push_objectres : [ 1, '-' ] } ], + "freturn" : [ { pop_objectref : None } ], + "fstore" : [ { set_objectref_i : None } ], + "fstore_0" : [ { set_objectref : 0 } ], + "fstore_1" : [ { set_objectref : 1 } ], + "fstore_2" : [ { set_objectref : 2 } ], + "fstore_3" : [ { set_objectref : 3 } ], + "fsub" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '-' ] } ], + "getfield" : [ { getfield : None } ], + "getstatic" : [ { getstatic : None } ], + "goto" : [ {} ], + "goto_w" : [ {} ], + "i2b" : [ { pop_objectref : None }, { push_objectres : [ 1, 'byte' ] } ], + "i2c" : [ { pop_objectref : None }, { push_objectres : [ 1, 'char' ] } ], + "i2d" : [ { pop_objectref : None }, { push_objectres : [ 1, 'double' ] } ], + "i2f" : [ { pop_objectref : None }, { push_objectres : [ 1, 'float' ] } ], + "i2l" : [ { pop_objectref : None }, { push_objectres : [ 1, 'long' ] } ], + "i2s" : [ { pop_objectref : None }, { push_objectres : [ 1, 'string' ] } ], + "iadd" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '+' ] } ], + "iaload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "iand" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '&' ] } ], + "iastore" : [ { set_arrayref : "int" } ], + "iconst_m1" : [ { push_integer_d : -1 } ], + "iconst_0" : [ { push_integer_d : 0 } ], + "iconst_1" : [ { push_integer_d : 1 } ], + "iconst_2" : [ { push_integer_d : 2 } ], + "iconst_3" : [ { push_integer_d : 3 } ], + "iconst_4" : [ { push_integer_d : 4 } ], + "iconst_5" : [ { push_integer_d : 5 } ], + "idiv" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '/' ] } ], + "if_acmpeq" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_acmpne" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmpeq" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmpne" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmplt" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmpge" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmpgt" : [ { pop_objectref : None }, { pop_objectref : None } ], + "if_icmple" : [ { pop_objectref : None }, { pop_objectref : None } ], + "ifeq" : [ { pop_objectref : None } ], + "ifne" : [ { pop_objectref : None } ], + "iflt" : [ { pop_objectref : None } ], + "ifge" : [ { pop_objectref : None } ], + "ifgt" : [ { pop_objectref : None } ], + "ifle" : [ { pop_objectref : None } ], + "ifnonnull" : [ { pop_objectref : None } ], + "ifnull" : [ { pop_objectref : None } ], + "iinc" : [ {} ], + "iload" : [ { push_objectref_l_i : None } ], + "iload_1" : [ { push_objectref_l : 1 } ], + "iload_2" : [ { push_objectref_l : 2 } ], + "iload_3" : [ { push_objectref_l : 3 } ], + "imul" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '*' ] } ], + "ineg" : [ { pop_objectref : None }, { push_objectres : [ 1, '-' ] } ], + "instanceof" : [ { pop_objectref : None }, { push_objectres : [ 1, 'instanceof' ] } ], + "invokeinterface" : [ { invoke : 1 } ], + "invokespecial" : [ { invoke : 1 } ], + "invokestatic" : [ { invoke : 0 } ], + "invokevirtual": [ { invoke : 1 } ], + "ior" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '|' ] } ], + "irem" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, 'REM' ] } ], + "ireturn" : [ { pop_objectref : None } ], + "ishl" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '<<' ] } ], + "ishr" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '>>' ] } ], + "istore" : [ { set_objectref_i : None } ], + "istore_0" : [ { set_objectref : 0 } ], + "istore_1" : [ { set_objectref : 1 } ], + "istore_2" : [ { set_objectref : 2 } ], + "istore_3" : [ { set_objectref : 3 } ], + "isub" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '-' ] } ], + "iushr" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '>>' ] } ], + "ixor" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '^' ] } ], + "jsr" : [ { push_integer_i : None } ], + "jsr_w" : [ { push_integer_i : None } ], + "l2d" : [ { pop_objectref : None }, { push_objectres : [ 1, 'double' ] } ], + "l2f" : [ { pop_objectref : None }, { push_objectres : [ 1, 'float' ] } ], + "l2i" : [ { pop_objectref : None }, { push_objectres : [ 1, 'integer' ] } ], + "ladd" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '+' ] } ], + "laload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "land" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '&' ] } ], + "lastore" : [ { set_arrayref : "long" } ], + "lcmp" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "lconst_0" : [ { push_float_d : 0.0 } ], + "lconst_1" : [ { push_float_d : 1.0 } ], + "ldc" : [ { ldc : None } ], + "ldc_w" : [ { ldc : None } ], + "ldc2_w" : [ { ldc : None } ], + "ldiv" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '/' ] } ], + "lload" : [ { push_objectref_l_i : None } ], + "lload_0" : [ { push_objectref_l : 0 } ], + "lload_1" : [ { push_objectref_l : 1 } ], + "lload_2" : [ { push_objectref_l : 2 } ], + "lload_3" : [ { push_objectref_l : 3 } ], + "lmul" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '*' ] } ], + "lneg" : [ { pop_objectref : None }, { push_objectres : [ 1, '-' ] } ], + "lookupswitch" : [ { pop_objectref : None } ], + "lor" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '|' ] } ], + "lrem" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, 'REM' ] } ], + "lreturn" : [ { pop_objectref : None } ], + "lshl" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '<<' ] } ], + "lshr" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '>>' ] } ], + "lstore" : [ { set_objectref_i : None } ], + "lstore_0" : [ { set_objectref : 0 } ], + "lstore_1" : [ { set_objectref : 1 } ], + "lstore_2" : [ { set_objectref : 2 } ], + "lstore_3" : [ { set_objectref : 3 } ], + "lsub" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '-' ] } ], + "lushr" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '>>' ] } ], + "lxor" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectres : [ 2, '^' ] } ], + "monitorenter" : [ { pop_objectref : None } ], + "monitorexit" : [ { pop_objectref : None } ], + "multianewarray" : [ { multi_pop_objectref_i : None }, { push_objectref : 0 } ], + "new" : [ { new : None } ], + "newarray" : [ { pop_objectref : None }, { push_objectref : [ 1, "NEWARRAY" ] } ], + "nop" : [ {} ], + "pop" : [ { pop_objectref : None } ], + "pop2" : [ { pop_objectref : None }, { pop_objectref : None } ], + "putfield" : [ { putfield : None }, { pop_objectref : None } ], + "putstatic" : [ { putstatic : None } ], + "ret" : [ {} ], + "return" : [ {} ], + "saload" : [ { pop_objectref : None }, { pop_objectref : None }, { push_objectref : 0 } ], + "sastore" : [ { set_arrayref : "short" } ], + "sipush" : [ { push_integer_i : None } ], + "swap" : [ { swap : None } ], + "tableswitch" : [ { pop_objectref : None } ], + "wide" : [ {} ], +} + + +class ReturnValues : + def __init__(self) : + self.__elems = [] + self.__msgs = [] + + def add_msg(self, e) : + self.__msgs.append( e ) + + def add_return(self, e) : + self.__elems.append( e ) + + def get_msg(self) : + return self.__msgs + + def get_return(self) : + return self.__elems + +class ExternalMethod : + def __init__(self, class_name, name, descriptor) : + self.__class_name = class_name + self.__name = name + self.__descriptor = descriptor + + def get_name(self) : + return "M@[%s][%s]-[%s]" % (self.__class_name, self.__name, self.__descriptor) + + def set_fathers(self, f) : + pass + +class JVMBasicBlock : + def __init__(self, start, vm, method, context) : + self.__vm = vm + self.method = method + self.context = context + + self.__stack = Stack() + self.stack_traces = StackTraces() + + self.ins = [] + + self.fathers = [] + self.childs = [] + + self.start = start + self.end = self.start + + self.break_blocks = [] + + self.free_blocks_offsets = [] + + self.name = "%s-BB@0x%x" % (self.method.get_name(), self.start) + + def get_stack(self) : + return self.__stack.gets() + + def get_method(self) : + return self.method + + def get_name(self) : + return self.name + + def get_start(self) : + return self.start + + def get_end(self) : + return self.end + + def get_last(self) : + return self.ins[-1] + + def push(self, i) : + self.ins.append( i ) + self.end += i.get_length() + + def set_fathers(self, f) : + self.fathers.append( f ) + + def set_childs(self, values) : +# print self, self.start, self.end, values, self.ins[-1].get_name() + if values == [] : + next_block = self.context.get_basic_block( self.end + 1 ) + if next_block != None : + self.childs.append( ( self.end - self.ins[-1].get_length(), self.end, next_block ) ) + else : + for i in values : + #print i, self.context.get_basic_block( i ) + if i != -1 : + self.childs.append( ( self.end - self.ins[-1].get_length(), i, self.context.get_basic_block( i ) ) ) + + for c in self.childs : + if c[2] != None : + c[2].set_fathers( ( c[1], c[0], self ) ) + + def prev_free_block_offset(self, idx=0) : + last = -1 + + #print "IDX", idx, self.free_blocks_offsets + + if self.free_blocks_offsets == [] : + return -1 + + for i in self.free_blocks_offsets : + if i <= idx : + last = i + else : + return last + + return last + + def random_free_block_offset(self) : + return self.free_blocks_offsets[ random.randint(0, len(self.free_blocks_offsets) - 1) ] + + def next_free_block_offset(self, idx=0) : + #print idx, self.__free_blocks_offsets + for i in self.free_blocks_offsets : + if i > idx : + return i + return -1 + + def get_random_free_block_offset(self) : + return self.free_blocks_offsets[ random.randint(0, len(self.free_blocks_offsets) - 1) ] + + def get_random_break_block(self) : + return self.break_blocks[ random.randint(0, len(self.break_blocks) - 1) ] + + def get_break_block(self, idx) : + for i in self.break_blocks : + if idx >= i.get_start() and idx <= i.get_end() : + return i + return None + + def analyze_break_blocks(self) : + idx = self.get_start() + + current_break = JVMBreakBlock( self.__vm, idx ) + self.break_blocks.append(current_break) + for i in self.ins : + name = i.get_name() + + ##################### Break Block ######################## + match = False + for j in BREAK_JVM_OPCODES_RE : + if j.match(name) != None : + match = True + break + + current_break.push( i ) + if match == True : + current_break.analyze() + current_break = JVMBreakBlock( self.__vm, current_break.get_end() ) + + self.break_blocks.append( current_break ) + ######################################################### + + idx += i.get_length() + + def analyze(self) : + idx = 0 + for i in self.ins : + ################### TAINTED LOCAL VARIABLES ################### + if "load" in i.get_name() or "store" in i.get_name() : + action = i.get_name() + + access_flag = [ "R", "load" ] + if "store" in action : + access_flag = [ "W", "store" ] + + if "_" in action : + name = i.get_name().split(access_flag[1]) + value = name[1][-1] + else : + value = i.get_operands() + + variable_name = "%s-%s" % (i.get_name()[0], value) + + self.context.get_tainted_variables().add( variable_name, TAINTED_LOCAL_VARIABLE, self.method ) + self.context.get_tainted_variables().push_info( TAINTED_LOCAL_VARIABLE, variable_name, (access_flag[0], idx, self, self.method) ) + ######################################################### + + ################### TAINTED FIELDS ################### + elif i.get_name() in FIELDS : + o = i.get_operands() + desc = getattr(self.__vm, "get_field_descriptor")(o[0], o[1], o[2]) + + # It's an external + #if desc == None : + # desc = ExternalFM( o[0], o[1], o[2] ) + +# print "RES", res, "-->", desc.get_name() + self.context.get_tainted_variables().push_info( TAINTED_FIELD, [o[0], o[1], o[2]], (FIELDS[ i.get_name() ][0], idx, self, self.method) ) + ######################################################### + + ################### TAINTED PACKAGES ################### + elif "new" in i.get_name() or "invoke" in i.get_name() or "getstatic" in i.get_name() : + if "new" in i.get_name() : + self.context.get_tainted_packages().push_info( i.get_operands(), (TAINTED_PACKAGE_CREATE, idx, self, self.method) ) + else : + self.context.get_tainted_packages().push_info( i.get_operands()[0], (TAINTED_PACKAGE_CALL, idx, self, self.method, i.get_operands()[1], i.get_operands()[2]) ) + ######################################################### + + ################### TAINTED INTEGERS ################### + if "ldc" == i.get_name() : + o = i.get_operands() + + if o[0] == "CONSTANT_Integer" : + self.context.get_tainted_integers().push_info( i, (o[1], idx, self, self.method) ) + + elif "sipush" in i.get_name() : + self.context.get_tainted_integers().push_info( i, (i.get_operands(), idx, self, self.method) ) + + elif "bipush" in i.get_name() : + self.context.get_tainted_integers().push_info( i, (i.get_operands(), idx, self, self.method) ) + + ######################################################### + + idx += i.get_length() + + def set_exception(self, exception_analysis) : + pass + + # FIXME : create a recursive function to follow the cfg, because it does not work with obfuscator + def analyze_code(self) : + self.analyze_break_blocks() + + #print "ANALYZE CODE -->", self.name + d = {} + for i in self.fathers : + # print "\t FATHER ->", i[2].get_name(), i[2].get_stack(), i[0], i[1] + d[ i[0] ] = i[2] + + self.free_blocks_offsets.append( self.get_start() ) + + idx = 0 + for i in self.ins : +# print i.get_name(), self.start + idx, idx +# i.show(idx) + + if self.start + idx in d : + self.__stack.insert_stack( 0, d[ self.start + idx ].get_stack() ) + + ret_v = ReturnValues() + + res = [] + try : + #print i.get_name(), i.get_name() in INSTRUCTIONS_ACTIONS + + if INSTRUCTIONS_ACTIONS[ i.get_name() ] == [] : + print "[[[[ %s is not yet implemented ]]]]" % i.get_name() + raise("ooops") + + i_idx = 0 + for actions in INSTRUCTIONS_ACTIONS[ i.get_name() ] : + for action in actions : + action( self.__vm, i, actions[action], self.__stack, res, ret_v ) + for val in ret_v.get_return() : + res.append( val ) + + #self.__stack.show() + self.stack_traces.save( idx, i_idx, i, cPickle.dumps( self.__stack ), cPickle.dumps( ret_v.get_msg() ) ) + i_idx += 1 + + except KeyError : + print "[[[[ %s is not in INSTRUCTIONS_ACTIONS ]]]]" % i.get_name() + except IndexError : + print "[[[[ Analysis failed in %s-%s-%s ]]]]" % (self.method.get_class_name(), self.method.get_name(), self.method.get_descriptor()) + + idx += i.get_length() + + if self.__stack.nil() == True and i != self.ins[-1] : + self.free_blocks_offsets.append( idx + self.get_start() ) + + def show(self) : + print "\t@", self.name + + idx = 0 + nb = 0 + for i in self.ins : + print "\t\t", nb, idx, + i.show(nb) + nb += 1 + idx += i.get_length() + + print "" + print "\t\tFree blocks offsets --->", self.free_blocks_offsets + print "\t\tBreakBlocks --->", len(self.break_blocks) + + print "\t\tF --->", ', '.join( i[2].get_name() for i in self.fathers ) + print "\t\tC --->", ', '.join( i[2].get_name() for i in self.childs ) + + self.stack_traces.show() + + def get_ins(self) : + return self.ins + +class JVMBreakBlock(BreakBlock) : + def __init__(self, _vm, idx) : + super(JVMBreakBlock, self).__init__(_vm, idx) + + self.__info = { + "F" : [ "get_field_descriptor", self._fields, ContextField ], + "M" : [ "get_method_descriptor", self._methods, ContextMethod ], + } + + + def get_free(self) : + if self._ins == [] : + return False + + if "store" in self._ins[-1].get_name() : + return True + elif "putfield" in self._ins[-1].get_name() : + return True + + return False + + def analyze(self) : + ctt = [] + + stack = Stack() + for i in self._ins : + v = self.trans(i) + if v != None : + ctt.append( v ) + + t = "" + + for mre in jvm.MATH_JVM_RE : + if mre[0].match( i.get_name() ) : + self._ops.append( mre[1] ) + break + + # Woot it's a field ! + if i.get_name() in FIELDS : + t = "F" + elif i.get_name() in METHODS : + t = "M" + + if t != "" : + o = i.get_operands() + desc = getattr(self._vm, self.__info[t][0])(o[0], o[1], o[2]) + + # It's an external + if desc == None : + desc = ExternalFM( o[0], o[1], o[2] ) + + if desc not in self.__info[t][1] : + self.__info[t][1][desc] = [] + + if t == "F" : + self.__info[t][1][desc].append( self.__info[t][2]( FIELDS[ i.get_name() ][0] ) ) + +# print "RES", res, "-->", desc.get_name() +# self.__tf.push_info( desc, [ FIELDS[ i.get_name() ][0], res ] ) + elif t == "M" : + self.__info[t][1][desc].append( self.__info[t][2]() ) + + for i in self._fields : + for k in self._fields[i] : + k.set_details( ctt ) + + for i in self._methods : + for k in self._methods[i] : + k.set_details( ctt ) + + def trans(self, i) : + v = i.get_name()[0:2] + if v == "il" or v == "ic" or v == "ia" or v == "si" or v == "bi" : + return "I" + + if v == "ba" : + return "B" + + if v == "if" : + return "IF" + + if v == "ir" : + return "RET" + + if "and" in i.get_name() : + return "&" + + if "add" in i.get_name() : + return "+" + + if "sub" in i.get_name() : + return "-" + + if "xor" in i.get_name() : + return "^" + + if "ldc" in i.get_name() : + return "I" + + if "invokevirtual" in i.get_name() : + return "M" + i.get_operands()[2] + + if "getfield" in i.get_name() : + return "F" + i.get_operands()[2] + + +DVM_FIELDS_ACCESS = { + "iget" : "R", + "iget-wide" : "R", + "iget-object" : "R", + "iget-boolean" : "R", + "iget-byte" : "R", + "iget-char" : "R", + "iget-short" : "R", + + "iput" : "W", + "iput-wide" : "W", + "iput-object" : "W", + "iput-boolean" : "W", + "iput-byte" : "W", + "iput-char" : "W", + "iput-short" : "W", + + "sget" : "R", + "sget-wide" : "R", + "sget-object" : "R", + "sget-boolean" : "R", + "sget-byte" : "R", + "sget-char" : "R", + "sget-short" : "R", + + "sput" : "W", + "sput-wide" : "W", + "sput-object" : "W", + "sput-boolean" : "W", + "sput-byte" : "W", + "sput-char" : "W", + "sput-short" : "W", + } + + +class DVMBasicBlock: + """ + A simple basic block of a dalvik method + """ + def __init__(self, start, vm, method, context): + self.__vm = vm + self.method = method + self.context = context + + self.last_length = 0 + self.nb_instructions = 0 + + self.fathers = [] + self.childs = [] + + self.start = start + self.end = self.start + + self.special_ins = {} + + self.name = "%s-BB@0x%x" % (self.method.get_name(), self.start) + self.exception_analysis = None + + self.tainted_variables = self.context.get_tainted_variables() + self.tainted_packages = self.context.get_tainted_packages() + + self.notes = [] + + def get_notes(self): + return self.notes + + def set_notes(self, value): + self.notes = [value] + + def add_note(self, note): + self.notes.append(note) + + def clear_notes(self): + self.notes = [] + + def get_instructions(self): + """ + Get all instructions from a basic block. + + :rtype: Return all instructions in the current basic block + """ + tmp_ins = [] + idx = 0 + for i in self.method.get_instructions(): + if idx >= self.start and idx < self.end: + tmp_ins.append(i) + + idx += i.get_length() + return tmp_ins + + def get_nb_instructions(self): + return self.nb_instructions + + def get_method(self): + return self.method + + def get_name(self): + return "%s-BB@0x%x" % (self.method.get_name(), self.start) + + def get_start(self): + return self.start + + def get_end(self): + return self.end + + def get_last(self): + return self.get_instructions()[-1] + + def get_next(self): + """ + Get next basic blocks + + :rtype: a list of the next basic blocks + """ + return self.childs + + def get_prev(self): + """ + Get previous basic blocks + + :rtype: a list of the previous basic blocks + """ + return self.fathers + + def set_fathers(self, f): + self.fathers.append(f) + + def get_last_length(self): + return self.last_length + + def set_childs(self, values): + #print self, self.start, self.end, values + if values == [] : + next_block = self.context.get_basic_block( self.end + 1 ) + if next_block != None : + self.childs.append( ( self.end - self.get_last_length(), self.end, next_block ) ) + else : + for i in values : + if i != -1 : + next_block = self.context.get_basic_block( i ) + if next_block != None : + self.childs.append( ( self.end - self.get_last_length(), i, next_block) ) + + for c in self.childs : + if c[2] != None : + c[2].set_fathers( ( c[1], c[0], self ) ) + + def push(self, i): + try: + self.nb_instructions += 1 + idx = self.end + self.last_length = i.get_length() + self.end += self.last_length + + op_value = i.get_op_value() + + # field access + if (op_value >= 0x52 and op_value <= 0x6d): + desc = self.__vm.get_cm_field(i.get_ref_kind()) + if self.tainted_variables != None: + self.tainted_variables.push_info(TAINTED_FIELD, desc, DVM_FIELDS_ACCESS[i.get_name()][0], idx, self.method) + + # invoke + elif (op_value >= 0x6e and op_value <= 0x72) or (op_value >= 0x74 and op_value <= 0x78): + idx_meth = i.get_ref_kind() + method_info = self.__vm.get_cm_method(idx_meth) + if self.tainted_packages != None: + self.tainted_packages.push_info(method_info[0], TAINTED_PACKAGE_CALL, idx, self.method, idx_meth) + + # new_instance + elif op_value == 0x22: + idx_type = i.get_ref_kind() + type_info = self.__vm.get_cm_type(idx_type) + if self.tainted_packages != None: + self.tainted_packages.push_info(type_info, TAINTED_PACKAGE_CREATE, idx, self.method, None) + + # const-string + elif (op_value >= 0x1a and op_value <= 0x1b): + string_name = self.__vm.get_cm_string(i.get_ref_kind()) + if self.tainted_variables != None: + self.tainted_variables.push_info(TAINTED_STRING, string_name, "R", idx, self.method) + + elif op_value == 0x26 or (op_value >= 0x2b and op_value <= 0x2c): + code = self.method.get_code().get_bc() + self.special_ins[idx] = code.get_ins_off(idx + i.get_ref_off() * 2) + except: + pass + + def get_special_ins(self, idx): + """ + Return the associated instruction to a specific instruction (for example a packed/sparse switch) + + :param idx: the index of the instruction + + :rtype: None or an Instruction + """ + try: + return self.special_ins[idx] + except: + return None + + def get_exception_analysis(self): + return self.exception_analysis + + def set_exception_analysis(self, exception_analysis): + self.exception_analysis = exception_analysis + +TAINTED_LOCAL_VARIABLE = 0 +TAINTED_FIELD = 1 +TAINTED_STRING = 2 + +class PathVar : + def __init__(self, access, idx, dst_idx, info_obj) : + self.access_flag = access + self.idx = idx + self.dst_idx = dst_idx + self.info_obj = info_obj + + def get_var_info(self) : + return self.info_obj.get_info() + + def get_access_flag(self) : + return self.access_flag + + def get_dst(self, cm) : + method = cm.get_method_ref( self.dst_idx ) + return method.get_class_name(), method.get_name(), method.get_descriptor() + + def get_idx(self) : + return self.idx + +class TaintedVariable : + def __init__(self, var, _type) : + self.var = var + self.type = _type + + self.paths = {} + self.__cache = [] + + def get_type(self) : + return self.type + + def get_info(self) : + if self.type == TAINTED_FIELD : + return [ self.var[0], self.var[2], self.var[1] ] + return self.var + + def push(self, access, idx, ref) : + m_idx = ref.get_method_idx() + + if m_idx not in self.paths : + self.paths[ m_idx ] = [] + + self.paths[ m_idx ].append( (access, idx) ) + + def get_paths_access(self, mode) : + for i in self.paths : + for j in self.paths[ i ] : + for k, v in self.paths[ i ][ j ] : + if k in mode : + yield i, j, k, v + + def get_paths(self) : + if self.__cache != [] : + return self.__cache + + for i in self.paths : + for j in self.paths[ i ] : + self.__cache.append( [j, i] ) + #yield j, i + return self.__cache + + def get_paths_length(self) : + return len(self.paths) + + def show_paths(self, vm) : + show_PathVariable( vm, self.get_paths() ) + +class TaintedVariables : + def __init__(self, _vm) : + self.__vm = _vm + self.__vars = { + TAINTED_LOCAL_VARIABLE : {}, + TAINTED_FIELD : {}, + TAINTED_STRING : {}, + } + + self.__cache_field_by_method = {} + self.__cache_string_by_method = {} + + # functions to get particulars elements + def get_string(self, s) : + try : + return self.__vars[ TAINTED_STRING ][ s ] + except KeyError : + return None + + def get_field(self, class_name, name, descriptor) : + key = class_name + descriptor + name + + try : + return self.__vars[ TAINTED_FIELD ] [ key ] + except KeyError : + return None + + def toPathVariable(self, obj) : + z = [] + for i in obj.get_paths() : + access, idx = i[0] + m_idx = i[1] + + z.append( PathVar(access, idx, m_idx, obj ) ) + return z + + # permission functions + def get_permissions_method(self, method) : + permissions = [] + + for f, f1 in self.get_fields() : + data = "%s-%s-%s" % (f1[0], f1[1], f1[2]) + if data in DVM_PERMISSIONS_BY_ELEMENT : + for path in f.get_paths() : + access, idx = path[0] + m_idx = path[1] + if m_idx == method.get_idx() : + if DVM_PERMISSIONS_BY_ELEMENT[ data ] not in permissions : + permissions.append( DVM_PERMISSIONS_BY_ELEMENT[ data ] ) + + return permissions + + def get_permissions(self, permissions_needed) : + """ + @param permissions_needed : a list of restricted permissions to get ([] returns all permissions) + + @rtype : a dictionnary of permissions' paths + """ + permissions = {} + + pn = permissions_needed + if permissions_needed == [] : + pn = DVM_PERMISSIONS_BY_PERMISSION.keys() + + for f, f1 in self.get_fields() : + data = "%s-%s-%s" % (f.var[0], f.var[2], f.var[1]) + + if data in DVM_PERMISSIONS_BY_ELEMENT : + if DVM_PERMISSIONS_BY_ELEMENT[ data ] in pn : + try : + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ].extend( self.toPathVariable( f ) ) + except KeyError : + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ] = [] + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ].extend( self.toPathVariable( f ) ) + + return permissions + + # global functions + + def get_strings(self) : + for i in self.__vars[ TAINTED_STRING ] : + yield self.__vars[ TAINTED_STRING ][ i ], i + + def get_fields(self) : + for i in self.__vars[ TAINTED_FIELD ] : + yield self.__vars[ TAINTED_FIELD ][ i ], i + + # specifics functions + def get_strings_by_method(self, method) : + z = {} + + try : + for i in self.__cache_string_by_method[ method.get_method_idx() ] : + z[ i ] = [] + for j in i.get_paths() : + if method.get_method_idx() == j[1] : + z[i].append( j[0] ) + + return z + except : + return z + + + def get_fields_by_method(self, method) : + z = {} + + try : + for i in self.__cache_field_by_method[ method.get_method_idx() ] : + z[ i ] = [] + for j in i.get_paths() : + if method.get_method_idx() == j[1] : + z[i].append( j[0] ) + return z + except : + return z + + def add(self, var, _type, _method=None) : + if _type == TAINTED_FIELD : + key = var[0] + var[1] + var[2] + if key not in self.__vars[ TAINTED_FIELD ] : + self.__vars[ TAINTED_FIELD ][ key ] = TaintedVariable( var, _type ) + elif _type == TAINTED_STRING : + if var not in self.__vars[ TAINTED_STRING ] : + self.__vars[ TAINTED_STRING ][ var ] = TaintedVariable( var, _type ) + elif _type == TAINTED_LOCAL_VARIABLE : + if _method not in self.__vars[ TAINTED_LOCAL_VARIABLE ] : + self.__vars[ TAINTED_LOCAL_VARIABLE ][ _method ] = {} + + if var not in self.__vars[ TAINTED_LOCAL_VARIABLE ][ _method ] : + self.__vars[ TAINTED_LOCAL_VARIABLE ][ _method ][ var ] = TaintedVariable( var, _type ) + + def push_info(self, _type, var, access, idx, ref) : + if _type == TAINTED_FIELD : + self.add( var, _type ) + key = var[0] + var[1] + var[2] + self.__vars[ _type ][ key ].push( access, idx, ref ) + + method_idx = ref.get_method_idx() + if method_idx not in self.__cache_field_by_method : + self.__cache_field_by_method[ method_idx ] = set() + + self.__cache_field_by_method[ method_idx ].add( self.__vars[ TAINTED_FIELD ][ key ] ) + + + elif _type == TAINTED_STRING : + self.add( var, _type ) + self.__vars[ _type ][ var ].push( access, idx, ref ) + + method_idx = ref.get_method_idx() + + if method_idx not in self.__cache_string_by_method : + self.__cache_string_by_method[ method_idx ] = set() + + self.__cache_string_by_method[ method_idx ].add( self.__vars[ TAINTED_STRING ][ var ] ) + +TAINTED_PACKAGE_CREATE = 0 +TAINTED_PACKAGE_CALL = 1 + +TAINTED_PACKAGE = { + TAINTED_PACKAGE_CREATE : "C", + TAINTED_PACKAGE_CALL : "M" +} +def show_Path(vm, path): + cm = vm.get_class_manager() + + if isinstance(path, PathVar): + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( cm ) + info_var = path.get_var_info() + print "%s %s (0x%x) ---> %s->%s%s" % (path.get_access_flag(), + info_var, + path.get_idx(), + dst_class_name, + dst_method_name, + dst_descriptor) + else : + if path.get_access_flag() == TAINTED_PACKAGE_CALL : + src_class_name, src_method_name, src_descriptor = path.get_src( cm ) + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( cm ) + + print "%d %s->%s%s (0x%x) ---> %s->%s%s" % (path.get_access_flag(), + src_class_name, + src_method_name, + src_descriptor, + path.get_idx(), + dst_class_name, + dst_method_name, + dst_descriptor) + else : + src_class_name, src_method_name, src_descriptor = path.get_src( cm ) + print "%d %s->%s%s (0x%x)" % (path.get_access_flag(), + src_class_name, + src_method_name, + src_descriptor, + path.get_idx()) + +def get_Path(vm, path): + x = {} + cm = vm.get_class_manager() + + if isinstance(path, PathVar): + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( cm ) + info_var = path.get_var_info() + x["src"] = "%s" % info_var + x["dst"] = "%s %s %s" % (dst_class_name, dst_method_name, dst_descriptor) + x["idx"] = path.get_idx() + + else : + if path.get_access_flag() == TAINTED_PACKAGE_CALL : + src_class_name, src_method_name, src_descriptor = path.get_src( cm ) + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( cm ) + + x["src"] = "%s %s %s" % (src_class_name, src_method_name, src_descriptor) + x["dst"] = "%s %s %s" % (dst_class_name, dst_method_name, dst_descriptor) + else : + src_class_name, src_method_name, src_descriptor = path.get_src( cm ) + x["src"] = "%s %s %s" % (src_class_name, src_method_name, src_descriptor) + + x["idx"] = path.get_idx() + + return x + + +def show_Paths(vm, paths) : + """ + Show paths of packages + :param paths: a list of :class:`PathP` objects + """ + for path in paths : + show_Path( vm, path ) + + +def show_PathVariable(vm, paths): + for path in paths: + access, idx = path[0] + m_idx = path[1] + method = vm.get_cm_method(m_idx) + print "%s %x %s->%s %s" % (access, idx, method[0], method[1], method[2][0] + method[2][1]) + + +class PathP: + def __init__(self, access, idx, src_idx, dst_idx): + self.access_flag = access + self.idx = idx + self.src_idx = src_idx + self.dst_idx = dst_idx + + def get_access_flag(self): + return self.access_flag + + def get_dst(self, cm): + method = cm.get_method_ref(self.dst_idx) + return method.get_class_name(), method.get_name(), method.get_descriptor() + + def get_src(self, cm): + method = cm.get_method_ref(self.src_idx) + return method.get_class_name(), method.get_name(), method.get_descriptor() + + def get_idx(self): + return self.idx + + def get_src_idx(self): + return self.src_idx + + def get_dst_idx(self): + return self.dst_idx + + +class TaintedPackage: + def __init__(self, vm, name): + self.vm = vm + self.name = name + self.paths = {TAINTED_PACKAGE_CREATE : [], TAINTED_PACKAGE_CALL : []} + + def get_name(self) : + return self.name + + def gets(self) : + return self.paths + + def push(self, access, idx, src_idx, dst_idx) : + p = PathP( access, idx, src_idx, dst_idx ) + self.paths[ access ].append( p ) + return p + + def get_objects_paths(self) : + return self.paths[ TAINTED_PACKAGE_CREATE ] + + def search_method(self, name, descriptor) : + """ + @param name : a regexp for the name of the method + @param descriptor : a regexp for the descriptor of the method + + @rtype : a list of called paths + """ + l = [] + m_name = re.compile(name) + m_descriptor = re.compile(descriptor) + + for path in self.paths[ TAINTED_PACKAGE_CALL ] : + _, dst_name, dst_descriptor = path.get_dst(self.vm.get_class_manager()) + + if m_name.match( dst_name ) != None and m_descriptor.match( dst_descriptor ) != None : + l.append( path ) + return l + + def get_method(self, name, descriptor) : + l = [] + for path in self.paths[ TAINTED_PACKAGE_CALL ] : + if path.get_name() == name and path.get_descriptor() == descriptor : + l.append( path ) + return l + + def get_paths(self) : + for i in self.paths : + for j in self.paths[ i ] : + yield j + + def get_paths_length(self) : + x = 0 + for i in self.paths : + x += len(self.paths[ i ]) + return x + + def get_methods(self): + return [path for path in self.paths[TAINTED_PACKAGE_CALL]] + + def get_new(self): + return [path for path in self.paths[TAINTED_PACKAGE_CREATE]] + + def show(self) : + cm = self.vm.get_class_manager() + print self.get_name() + for _type in self.paths: + print "\t -->", _type + if _type == TAINTED_PACKAGE_CALL: + for path in self.paths[_type]: + print "\t\t => %s <-- %x in %s" % (path.get_dst(cm), path.get_idx(), path.get_src(cm)) + else: + for path in self.paths[_type]: + print "\t\t => %x in %s" % (path.get_idx(), path.get_src(cm)) + +def show_Permissions(dx) : + """ + Show where permissions are used in a specific application + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + """ + p = dx.get_permissions( [] ) + + for i in p : + print i, ":" + for j in p[i] : + show_Path( dx.get_vm(), j ) + +def show_DynCode(dx) : + """ + Show where dynamic code is used + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + """ + paths = dx.get_tainted_packages().search_methods( "Ldalvik/system/DexClassLoader;", ".", ".") + show_Paths( dx.get_vm(), paths ) + + +def show_NativeMethods(dx): + """ + Show the native methods + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + """ + d = dx.get_vm() + for i in d.get_methods() : + if i.get_access_flags() & 0x100 : + print i.get_class_name(), i.get_name(), i.get_descriptor() + + +def show_ReflectionCode(dx): + """ + Show the reflection code + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + """ + paths = dx.get_tainted_packages().search_methods("Ljava/lang/reflect/Method;", ".", ".") + show_Paths(dx.get_vm(), paths) + + +def is_crypto_code(dx): + """ + Crypto code is present ? + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + :rtype: boolean + """ + if dx.get_tainted_packages().search_methods("Ljavax/crypto/.", + ".", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/security/spec/.", + ".", + "."): + return True + + return False + + +def is_dyn_code(dx): + """ + Dalvik Dynamic code loading is present ? + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + :rtype: boolean + """ + if dx.get_tainted_packages().search_methods("Ldalvik/system/DexClassLoader;", + ".", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/security/ClassLoader;", + "defineClass", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/security/SecureClassLoader;", + "defineClass", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/net/URLClassLoader;", + ".", + "."): + return True + + return False + + +def is_reflection_code(dx): + """ + Reflection is present ? + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + :rtype: boolean + """ + if dx.get_tainted_packages().search_methods("Ljava/lang/reflect/Method;", + ".", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/lang/reflect/Field;", + ".", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/lang/Class;", + "forName", + "."): + return True + + return False + + +def is_native_code(dx): + """ + Native code is present ? + :param dx : the analysis virtual machine + :type dx: a :class:`VMAnalysis` object + :rtype: boolean + """ + if dx.get_tainted_packages().search_methods("Ljava/lang/System;", + "load.", + "."): + return True + + if dx.get_tainted_packages().search_methods("Ljava/lang/Runtime;", + "load.", + "."): + return True + + return False + + +class TaintedPackages : + def __init__(self, _vm) : + self.__vm = _vm + self.__packages = {} + self.__methods = {} + + def _add_pkg(self, name) : + if name not in self.__packages : + self.__packages[ name ] = TaintedPackage( self.__vm, name ) + + #self.context.get_tainted_packages().push_info( method_info[0], TAINTED_PACKAGE_CALL, idx, self, self.method, method_info[1], method_info[2][0] + method_info[2][1] ) + def push_info(self, class_name, access, idx, method, idx_method) : + self._add_pkg( class_name ) + p = self.__packages[ class_name ].push( access, idx, method.get_method_idx(), idx_method ) + + try : + self.__methods[ method ][ class_name ].append( p ) + except : + try : + self.__methods[ method ][ class_name ] = [] + except : + self.__methods[ method ] = {} + self.__methods[ method ][ class_name ] = [] + + self.__methods[ method ][ class_name ].append( p ) + + def get_packages_by_method(self, method): + try: + return self.__methods[method] + except KeyError: + return {} + + def get_package(self, name): + return self.__packages[name] + + def get_packages_by_bb(self, bb): + """ + :rtype: return a list of packaged used in a basic block + """ + l = [] + for i in self.__packages : + paths = self.__packages[i].gets() + for j in paths : + for k in paths[j] : + if k.get_bb() == bb : + l.append( (i, k.get_access_flag(), k.get_idx(), k.get_method()) ) + + return l + + def get_packages(self): + for i in self.__packages: + yield self.__packages[i], i + + def get_internal_packages_from_package(self, package): + classes = self.__vm.get_classes_names() + l = [] + for m, _ in self.get_packages(): + paths = m.get_methods() + for j in paths: + src_class_name, _, _ = j.get_src(self.__vm.get_class_manager()) + dst_class_name, _, _ = j.get_dst(self.__vm.get_class_manager()) + + if src_class_name == package and dst_class_name in classes: + l.append(j) + return l + + def get_internal_packages(self): + """ + :rtype: return a list of the internal packages called in the application + """ + classes = self.__vm.get_classes_names() + l = [] + for m, _ in self.get_packages(): + paths = m.get_methods() + for j in paths: + if j.get_access_flag() == TAINTED_PACKAGE_CALL: + dst_class_name, _, _ = j.get_dst(self.__vm.get_class_manager()) + if dst_class_name in classes and m.get_name() in classes: + l.append(j) + return l + + def get_internal_new_packages(self): + """ + :rtype: return a list of the internal packages created in the application + """ + classes = self.__vm.get_classes_names() + l = {} + for m, _ in self.get_packages(): + paths = m.get_new() + for j in paths: + src_class_name, _, _ = j.get_src(self.__vm.get_class_manager()) + if src_class_name in classes and m.get_name() in classes: + if j.get_access_flag() == TAINTED_PACKAGE_CREATE: + try: + l[m.get_name()].append(j) + except: + l[m.get_name()] = [] + l[m.get_name()].append(j) + return l + + def get_external_packages(self): + """ + :rtype: return a list of the external packages called in the application + """ + classes = self.__vm.get_classes_names() + l = [] + for m, _ in self.get_packages(): + paths = m.get_methods() + for j in paths: + src_class_name, _, _ = j.get_src(self.__vm.get_class_manager()) + dst_class_name, _, _ = j.get_dst(self.__vm.get_class_manager()) + if src_class_name in classes and dst_class_name not in classes: + if j.get_access_flag() == TAINTED_PACKAGE_CALL: + l.append(j) + return l + + def search_packages(self, package_name): + """ + :param package_name: a regexp for the name of the package + + :rtype: a list of called packages' paths + """ + ex = re.compile(package_name) + + l = [] + for m, _ in self.get_packages(): + if ex.search(m.get_name()) != None: + l.extend(m.get_methods()) + return l + + def search_unique_packages(self, package_name) : + """ + :param package_name: a regexp for the name of the package + """ + ex = re.compile( package_name ) + + l = [] + d = {} + for m, _ in self.get_packages() : + if ex.match( m.get_info() ) != None : + for path in m.get_methods() : + try : + d[ path.get_class_name() + path.get_name() + path.get_descriptor() ] += 1 + except KeyError : + d[ path.get_class_name() + path.get_name() + path.get_descriptor() ] = 0 + l.append( [ path.get_class_name(), path.get_name(), path.get_descriptor() ] ) + return l, d + + def search_methods(self, class_name, name, descriptor, re_expr=True) : + """ + @param class_name : a regexp for the class name of the method (the package) + @param name : a regexp for the name of the method + @param descriptor : a regexp for the descriptor of the method + + @rtype : a list of called methods' paths + """ + l = [] + if re_expr == True : + ex = re.compile( class_name ) + + for m, _ in self.get_packages() : + if ex.search( m.get_name() ) != None : + l.extend( m.search_method( name, descriptor ) ) + + return l + + def search_objects(self, class_name) : + """ + @param class_name : a regexp for the class name + + @rtype : a list of created objects' paths + """ + ex = re.compile( class_name ) + l = [] + + for m, _ in self.get_packages() : + if ex.search( m.get_name() ) != None : + l.extend( m.get_objects_paths() ) + + return l + + def search_crypto_packages(self) : + """ + @rtype : a list of called crypto packages + """ + return self.search_packages( "Ljavax/crypto/" ) + + def search_telephony_packages(self) : + """ + @rtype : a list of called telephony packages + """ + return self.search_packages( "Landroid/telephony/" ) + + def search_net_packages(self) : + """ + @rtype : a list of called net packages + """ + return self.search_packages( "Landroid/net/" ) + + def get_method(self, class_name, name, descriptor) : + try : + return self.__packages[ class_name ].get_method( name, descriptor ) + except KeyError : + return [] + + def get_permissions_method(self, method) : + permissions = [] + + for m, _ in self.get_packages() : + paths = m.get_methods() + for j in paths : + if j.get_method() == method : + if j.get_access_flag() == TAINTED_PACKAGE_CALL : + tmp = j.get_descriptor() + tmp = tmp[ : tmp.rfind(")") + 1 ] + data = "%s-%s-%s" % (m.get_info(), j.get_name(), tmp) + if data in DVM_PERMISSIONS_BY_ELEMENT : + if DVM_PERMISSIONS_BY_ELEMENT[ data ] not in permissions : + permissions.append( DVM_PERMISSIONS_BY_ELEMENT[ data ] ) + return permissions + + def get_permissions(self, permissions_needed) : + """ + @param permissions_needed : a list of restricted permissions to get ([] returns all permissions) + @rtype : a dictionnary of permissions' paths + """ + permissions = {} + + pn = permissions_needed + if permissions_needed == [] : + pn = DVM_PERMISSIONS_BY_PERMISSION.keys() + + classes = self.__vm.get_classes_names() + + for m, _ in self.get_packages() : + paths = m.get_methods() + for j in paths : + src_class_name, src_method_name, src_descriptor = j.get_src( self.__vm.get_class_manager() ) + dst_class_name, dst_method_name, dst_descriptor = j.get_dst( self.__vm.get_class_manager() ) + if src_class_name in classes and m.get_name() not in classes : + if j.get_access_flag() == TAINTED_PACKAGE_CALL : + tmp = dst_descriptor + tmp = tmp[ : tmp.rfind(")") + 1 ] + + #data = "%s-%s-%s" % (m.get_info(), j.get_name(), j.get_descriptor()) + data = "%s-%s-%s" % (m.get_name(), dst_method_name, tmp) + + if data in DVM_PERMISSIONS_BY_ELEMENT : + if DVM_PERMISSIONS_BY_ELEMENT[ data ] in pn : + try : + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ].append( j ) + except KeyError : + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ] = [] + permissions[ DVM_PERMISSIONS_BY_ELEMENT[ data ] ].append( j ) + + return permissions + +class Enum(object): + def __init__(self, names): + self.names = names + for value, name in enumerate(self.names): + setattr(self, name.upper(), value) + + def tuples(self): + return tuple(enumerate(self.names)) + +TAG_ANDROID = Enum([ 'ANDROID', 'TELEPHONY', 'SMS', 'SMSMESSAGE', 'ACCESSIBILITYSERVICE', 'ACCOUNTS', + 'ANIMATION', 'APP', 'BLUETOOTH', 'CONTENT', 'DATABASE', 'DEBUG', 'DRM', 'GESTURE', + 'GRAPHICS', 'HARDWARE', 'INPUTMETHODSERVICE', 'LOCATION', 'MEDIA', 'MTP', + 'NET', 'NFC', 'OPENGL', 'OS', 'PREFERENCE', 'PROVIDER', 'RENDERSCRIPT', + 'SAX', 'SECURITY', 'SERVICE', 'SPEECH', 'SUPPORT', 'TEST', 'TEXT', 'UTIL', + 'VIEW', 'WEBKIT', 'WIDGET', 'DALVIK_BYTECODE', 'DALVIK_SYSTEM', 'JAVA_REFLECTION']) + +TAG_REVERSE_ANDROID = dict((i[0], i[1]) for i in TAG_ANDROID.tuples()) + +TAGS_ANDROID = { TAG_ANDROID.ANDROID : [ 0, "Landroid" ], + TAG_ANDROID.TELEPHONY : [ 0, "Landroid/telephony"], + TAG_ANDROID.SMS : [ 0, "Landroid/telephony/SmsManager"], + TAG_ANDROID.SMSMESSAGE : [ 0, "Landroid/telephony/SmsMessage"], + TAG_ANDROID.DEBUG : [ 0, "Landroid/os/Debug"], + TAG_ANDROID.ACCESSIBILITYSERVICE : [ 0, "Landroid/accessibilityservice" ], + TAG_ANDROID.ACCOUNTS : [ 0, "Landroid/accounts" ], + TAG_ANDROID.ANIMATION : [ 0, "Landroid/animation" ], + TAG_ANDROID.APP : [ 0, "Landroid/app" ], + TAG_ANDROID.BLUETOOTH : [ 0, "Landroid/bluetooth" ], + TAG_ANDROID.CONTENT : [ 0, "Landroid/content" ], + TAG_ANDROID.DATABASE : [ 0, "Landroid/database" ], + TAG_ANDROID.DRM : [ 0, "Landroid/drm" ], + TAG_ANDROID.GESTURE : [ 0, "Landroid/gesture" ], + TAG_ANDROID.GRAPHICS : [ 0, "Landroid/graphics" ], + TAG_ANDROID.HARDWARE : [ 0, "Landroid/hardware" ], + TAG_ANDROID.INPUTMETHODSERVICE : [ 0, "Landroid/inputmethodservice" ], + TAG_ANDROID.LOCATION : [ 0, "Landroid/location" ], + TAG_ANDROID.MEDIA : [ 0, "Landroid/media" ], + TAG_ANDROID.MTP : [ 0, "Landroid/mtp" ], + TAG_ANDROID.NET : [ 0, "Landroid/net" ], + TAG_ANDROID.NFC : [ 0, "Landroid/nfc" ], + TAG_ANDROID.OPENGL : [ 0, "Landroid/opengl" ], + TAG_ANDROID.OS : [ 0, "Landroid/os" ], + TAG_ANDROID.PREFERENCE : [ 0, "Landroid/preference" ], + TAG_ANDROID.PROVIDER : [ 0, "Landroid/provider" ], + TAG_ANDROID.RENDERSCRIPT : [ 0, "Landroid/renderscript" ], + TAG_ANDROID.SAX : [ 0, "Landroid/sax" ], + TAG_ANDROID.SECURITY : [ 0, "Landroid/security" ], + TAG_ANDROID.SERVICE : [ 0, "Landroid/service" ], + TAG_ANDROID.SPEECH : [ 0, "Landroid/speech" ], + TAG_ANDROID.SUPPORT : [ 0, "Landroid/support" ], + TAG_ANDROID.TEST : [ 0, "Landroid/test" ], + TAG_ANDROID.TEXT : [ 0, "Landroid/text" ], + TAG_ANDROID.UTIL : [ 0, "Landroid/util" ], + TAG_ANDROID.VIEW : [ 0, "Landroid/view" ], + TAG_ANDROID.WEBKIT : [ 0, "Landroid/webkit" ], + TAG_ANDROID.WIDGET : [ 0, "Landroid/widget" ], + TAG_ANDROID.DALVIK_BYTECODE : [ 0, "Ldalvik/bytecode" ], + TAG_ANDROID.DALVIK_SYSTEM : [ 0, "Ldalvik/system" ], + + TAG_ANDROID.JAVA_REFLECTION : [ 0, "Ljava/lang/reflect"], +} + +class Tags : + """ + Handle specific tags + + :param patterns: + :params reverse: + """ + def __init__(self, patterns=TAGS_ANDROID, reverse=TAG_REVERSE_ANDROID) : + self.tags = set() + + self.patterns = patterns + self.reverse = TAG_REVERSE_ANDROID + + for i in self.patterns : + self.patterns[i][1] = re.compile(self.patterns[i][1]) + + def emit(self, method) : + for i in self.patterns : + if self.patterns[i][0] == 0 : + if self.patterns[i][1].search( method.get_class() ) != None : + self.tags.add( i ) + + def emit_by_classname(self, classname) : + for i in self.patterns : + if self.patterns[i][0] == 0 : + if self.patterns[i][1].search( classname ) != None : + self.tags.add( i ) + + def get_list(self): + return [ self.reverse[ i ] for i in self.tags ] + + def __contains__(self, key) : + return key in self.tags + + def __str__(self) : + return str([ self.reverse[ i ] for i in self.tags ]) + + + def empty(self) : + return self.tags == set() + + +class BasicBlocks: + """ + This class represents all basic blocks of a method + """ + def __init__(self, _vm, tv): + self.__vm = _vm + self.tainted = tv + + self.bb = [] + + def push(self, bb): + self.bb.append(bb) + + def pop(self, idx): + return self.bb.pop(idx) + + def get_basic_block(self, idx): + for i in self.bb: + if idx >= i.get_start() and idx < i.get_end(): + return i + return None + + def get_tainted_integers(self): + try: + return self.tainted.get_tainted_integers() + except: + return None + + def get_tainted_packages(self): + try: + return self.tainted.get_tainted_packages() + except: + return None + + def get_tainted_variables(self): + try: + return self.tainted.get_tainted_variables() + except: + return None + + def get(self): + """ + :rtype: return each basic block (:class:`DVMBasicBlock` object) + """ + for i in self.bb: + yield i + + def gets(self): + """ + :rtype: a list of basic blocks (:class:`DVMBasicBlock` objects) + """ + return self.bb + + def get_basic_block_pos(self, idx): + return self.bb[idx] + + +class ExceptionAnalysis: + def __init__(self, exception, bb): + self.start = exception[0] + self.end = exception[1] + + self.exceptions = exception[2:] + + for i in self.exceptions: + i.append(bb.get_basic_block(i[1])) + + def show_buff(self): + buff = "%x:%x\n" % (self.start, self.end) + + for i in self.exceptions: + if i[2] == None: + buff += "\t(%s -> %x %s)\n" % (i[0], i[1], i[2]) + else: + buff += "\t(%s -> %x %s)\n" % (i[0], i[1], i[2].get_name()) + + return buff[:-1] + + def get(self): + d = {"start": self.start, "end": self.end, "list": []} + + for i in self.exceptions: + d["list"].append({"name": i[0], "idx": i[1], "bb": i[2].get_name()}) + + return d + + +class Exceptions: + def __init__(self, _vm) : + self.__vm = _vm + self.exceptions = [] + + def add(self, exceptions, basic_blocks) : + for i in exceptions : + self.exceptions.append( ExceptionAnalysis( i, basic_blocks ) ) + + def get_exception(self, addr_start, addr_end) : + for i in self.exceptions : +# print hex(i.start), hex(i.end), hex(addr_start), hex(addr_end), i.start >= addr_start and i.end <= addr_end, addr_end <= i.end and addr_start >= i.start + if i.start >= addr_start and i.end <= addr_end : + return i + + elif addr_end <= i.end and addr_start >= i.start : + return i + + return None + + def gets(self) : + return self.exceptions + + def get(self) : + for i in self.exceptions : + yield i + +#BO = { "BasicOPCODES" : jvm.BRANCH2_JVM_OPCODES, "BasicClass" : JVMBasicBlock, "Dnext" : jvm.determineNext, "Dexception" : jvm.determineException } +BO = { "BasicOPCODES" : dvm.BRANCH_DVM_OPCODES, "BasicClass" : DVMBasicBlock, "Dnext" : dvm.determineNext, "Dexception" : dvm.determineException } + +BO["BasicOPCODES_H"] = [] +for i in BO["BasicOPCODES"] : + BO["BasicOPCODES_H"].append( re.compile( i ) ) + + +class MethodAnalysis: + """ + This class analyses in details a method of a class/dex file + + :param vm: the object which represent the dex file + :param method: the original method + :param tv: a virtual object to get access to tainted information + :type vm: a :class:`DalvikVMFormat` object + :type method: a :class:`EncodedMethod` object + """ + def __init__(self, vm, method, tv): + self.__vm = vm + self.method = method + + self.tainted = tv + + self.basic_blocks = BasicBlocks(self.__vm, self.tainted) + self.exceptions = Exceptions(self.__vm) + + code = self.method.get_code() + if code == None: + return + + current_basic = BO["BasicClass"](0, self.__vm, self.method, self.basic_blocks) + self.basic_blocks.push(current_basic) + + ########################################################## + + bc = code.get_bc() + l = [] + h = {} + idx = 0 + + debug("Parsing instructions") + instructions = [i for i in bc.get_instructions()] + for i in instructions: + for j in BO["BasicOPCODES_H"]: + if j.match(i.get_name()) != None: + v = BO["Dnext"](i, idx, self.method) + h[ idx ] = v + l.extend(v) + break + + idx += i.get_length() + + debug("Parsing exceptions") + excepts = BO["Dexception"]( self.__vm, self.method ) + for i in excepts: + l.extend( [i[0]] ) + for handler in i[2:] : + l.append( handler[1] ) + + debug("Creating basic blocks") + idx = 0 + for i in instructions: + # index is a destination + if idx in l: + if current_basic.get_nb_instructions() != 0: + current_basic = BO["BasicClass"](current_basic.get_end(), self.__vm, self.method, self.basic_blocks) + self.basic_blocks.push(current_basic) + + current_basic.push(i) + + # index is a branch instruction + if idx in h: + current_basic = BO["BasicClass"]( current_basic.get_end(), self.__vm, self.method, self.basic_blocks ) + self.basic_blocks.push( current_basic ) + + idx += i.get_length() + + if current_basic.get_nb_instructions() == 0: + self.basic_blocks.pop(-1) + + debug("Settings basic blocks childs") + + for i in self.basic_blocks.get(): + try : + i.set_childs( h[ i.end - i.get_last_length() ] ) + except KeyError : + i.set_childs( [] ) + + debug("Creating exceptions") + + # Create exceptions + self.exceptions.add(excepts, self.basic_blocks) + + for i in self.basic_blocks.get(): + # setup exception by basic block + i.set_exception_analysis(self.exceptions.get_exception( i.start, i.end - 1 )) + + del instructions + del h, l + + def get_basic_blocks(self): + """ + :rtype: a :class:`BasicBlocks` object + """ + return self.basic_blocks + + def get_length(self) : + """ + :rtype: an integer which is the length of the code + """ + return self.get_code().get_length() + + def get_vm(self) : + return self.__vm + + def get_method(self) : + return self.method + + def get_local_variables(self) : + return self.tainted.get_tainted_variables().get_local_variables( self.method ) + + def show(self) : + print "METHOD", self.method.get_class_name(), self.method.get_name(), self.method.get_descriptor() + + for i in self.basic_blocks.get() : + print "\t", i + i.show() + print "" + + def show_methods(self) : + print "\t #METHODS :" + for i in self.__bb : + methods = i.get_methods() + for method in methods : + print "\t\t-->", method.get_class_name(), method.get_name(), method.get_descriptor() + for context in methods[method] : + print "\t\t\t |---|", context.details + + def create_tags(self) : + """ + Create the tags for the method + """ + self.tags = Tags() + for i in self.tainted.get_tainted_packages().get_packages_by_method( self.method ) : + self.tags.emit_by_classname( i ) + + def get_tags(self) : + """ + Return the tags of the method + + :rtype: a :class:`Tags` object + """ + return self.tags + +SIGNATURE_L0_0 = "L0_0" +SIGNATURE_L0_1 = "L0_1" +SIGNATURE_L0_2 = "L0_2" +SIGNATURE_L0_3 = "L0_3" +SIGNATURE_L0_4 = "L0_4" +SIGNATURE_L0_5 = "L0_5" +SIGNATURE_L0_6 = "L0_6" +SIGNATURE_L0_0_L1 = "L0_0:L1" +SIGNATURE_L0_1_L1 = "L0_1:L1" +SIGNATURE_L0_2_L1 = "L0_2:L1" +SIGNATURE_L0_3_L1 = "L0_3:L1" +SIGNATURE_L0_4_L1 = "L0_4:L1" +SIGNATURE_L0_5_L1 = "L0_5:L1" +SIGNATURE_L0_0_L2 = "L0_0:L2" +SIGNATURE_L0_0_L3 = "L0_0:L3" +SIGNATURE_HEX = "hex" +SIGNATURE_SEQUENCE_BB = "sequencebb" + +SIGNATURES = { + SIGNATURE_L0_0 : { "type" : 0 }, + SIGNATURE_L0_1 : { "type" : 1 }, + SIGNATURE_L0_2 : { "type" : 2, "arguments" : ["Landroid"] }, + SIGNATURE_L0_3 : { "type" : 2, "arguments" : ["Ljava"] }, + SIGNATURE_L0_4 : { "type" : 2, "arguments" : ["Landroid", "Ljava"] }, + SIGNATURE_L0_5 : { "type" : 3, "arguments" : ["Landroid"] }, + SIGNATURE_L0_6 : { "type" : 3, "arguments" : ["Ljava"] }, + SIGNATURE_SEQUENCE_BB : {}, + SIGNATURE_HEX : {}, + } + +from sign import Signature + + +class VMAnalysis: + """ + This class analyses a dex file + + :param _vm: the object which represent the dex file + :type _vm: a :class:`DalvikVMFormat` object + + :Example: + VMAnalysis( DalvikVMFormat( open("toto.dex", "r").read() ) ) + """ + def __init__(self, _vm) : + self.__vm = _vm + + self.tainted_variables = TaintedVariables( self.__vm ) + self.tainted_packages = TaintedPackages( self.__vm ) + + self.tainted = { "variables" : self.tainted_variables, + "packages" : self.tainted_packages, + } + + self.signature = None + + for i in self.__vm.get_all_fields() : + self.tainted_variables.add( [ i.get_class_name(), i.get_descriptor(), i.get_name() ], TAINTED_FIELD ) + + self.methods = [] + self.hmethods = {} + self.__nmethods = {} + for i in self.__vm.get_methods() : + x = MethodAnalysis( self.__vm, i, self ) + self.methods.append( x ) + self.hmethods[ i ] = x + self.__nmethods[ i.get_name() ] = x + + def get_vm(self) : + return self.__vm + + def get_method(self, method) : + """ + Return an analysis method + + :param method: a classical method object + :type method: an :class:`EncodedMethod` object + + :rtype: a :class:`MethodAnalysis` object + """ + return self.hmethods[ method ] + + def get_methods(self) : + """ + Return each analysis method + + :rtype: a :class:`MethodAnalysis` object + """ + for i in self.hmethods : + yield self.hmethods[i] + + def get_method_signature(self, method, grammar_type="", options={}, predef_sign="") : + """ + Return a specific signature for a specific method + + :param method: a reference to method from a vm class + :type method: a :class:`EncodedMethod` object + + :param grammar_type: the type of the signature (optional) + :type grammar_type: string + + :param options: the options of the signature (optional) + :param options: dict + + :param predef_sign: used a predefined signature (optional) + :type predef_sign: string + + :rtype: a :class:`Sign` object + """ + if self.signature == None : + self.signature = Signature( self ) + + if predef_sign != "" : + g = "" + o = {} + + for i in predef_sign.split(":") : + if "_" in i : + g += "L0:" + o[ "L0" ] = SIGNATURES[ i ] + else : + g += i + g += ":" + + return self.signature.get_method( self.get_method( method ), g[:-1], o ) + else : + return self.signature.get_method( self.get_method( method ), grammar_type, options ) + + def get_permissions(self, permissions_needed) : + """ + Return the permissions used + + :param permissions_needed: a list of restricted permissions to get ([] returns all permissions) + :type permissions_needed: list + + :rtype: a dictionnary of permissions paths + """ + permissions = {} + + permissions.update( self.get_tainted_packages().get_permissions( permissions_needed ) ) + permissions.update( self.get_tainted_variables().get_permissions( permissions_needed ) ) + + return permissions + + def get_permissions_method(self, method) : + permissions_f = self.get_tainted_packages().get_permissions_method( method ) + permissions_v = self.get_tainted_variables().get_permissions_method( method ) + + return list( set( permissions_f + permissions_v ) ) + + def get_tainted_variables(self) : + """ + Return the tainted variables + + :rtype: a :class:`TaintedVariables` object + """ + return self.tainted_variables + + def get_tainted_packages(self) : + """ + Return the tainted packages + + :rtype: a :class:`TaintedPackages` object + """ + return self.tainted_packages + + def get_tainted_fields(self) : + return self.get_tainted_variables().get_fields() + + def get_tainted_field(self, class_name, name, descriptor) : + """ + Return a specific tainted field + + :param class_name: the name of the class + :param name: the name of the field + :param descriptor: the descriptor of the field + :type class_name: string + :type name: string + :type descriptor: string + + :rtype: a :class:`TaintedVariable` object + """ + return self.get_tainted_variables().get_field( class_name, name, descriptor ) + +class uVMAnalysis(VMAnalysis) : + """ + This class analyses a dex file but on the fly (quicker !) + + :param _vm: the object which represent the dex file + :type _vm: a :class:`DalvikVMFormat` object + + :Example: + uVMAnalysis( DalvikVMFormat( open("toto.dex", "r").read() ) ) + """ + def __init__(self, vm) : + self.vm = vm + self.tainted_variables = TaintedVariables( self.vm ) + self.tainted_packages = TaintedPackages( self.vm ) + + self.tainted = { "variables" : self.tainted_variables, + "packages" : self.tainted_packages, + } + + self.signature = None + self.resolve = False + + def get_methods(self) : + self.resolve = True + for i in self.vm.get_methods(): + yield MethodAnalysis(self.vm, i, self) + + def get_method(self, method) : + return MethodAnalysis( self.vm, method, None ) + + def get_vm(self) : + return self.vm + + def _resolve(self) : + if self.resolve == False : + for i in self.get_methods(): + pass + + def get_tainted_packages(self) : + self._resolve() + return self.tainted_packages + + def get_tainted_variables(self) : + self._resolve() + return self.tainted_variables + + +def is_ascii_obfuscation(vm): + for classe in vm.get_classes(): + if is_ascii_problem(classe.get_name()): + return True + for method in classe.get_methods(): + if is_ascii_problem(method.get_name()): + return True + return False diff --git a/androguard/core/analysis/auto.py b/androguard/core/analysis/auto.py new file mode 100644 index 00000000..8590fdf7 --- /dev/null +++ b/androguard/core/analysis/auto.py @@ -0,0 +1,358 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import Queue +import threading +import time +import zlib + +from androguard.core import androconf +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis import analysis +from androguard.core.androconf import debug + + +class AndroAuto(object): + """ + The main class which analyse automatically android apps by calling methods + from a specific object + :param settings: the settings of the analysis + :type settings: dict + """ + def __init__(self, settings): + self.settings = settings + + def dump(self): + """ + Dump the analysis + """ + self.settings["my"].dump() + + def dump_file(self, filename): + """ + Dump the analysis in a filename + """ + self.settings["my"].dump_file(filename) + + def go(self): + """ + Launch the analysis + """ + myandro = self.settings["my"] + + def worker(idx, q): + debug("Running worker-%d" % idx) + + while True: + a, d, dx, axmlobj, arscobj = None, None, None, None, None + try: + filename, fileraw = q.get() + id_file = zlib.adler32(fileraw) + + debug("(worker-%d) get %s %d" % (idx, filename, id_file)) + + log = self.settings["log"](id_file, filename) + + is_analysis_dex, is_analysis_adex = True, True + debug("(worker-%d) filtering file %d" % (idx, id_file)) + filter_file_ret, filter_file_type = myandro.filter_file(log, fileraw) + if filter_file_ret: + debug("(worker-%d) analysis %s" % (id_file, filter_file_type)) + + if filter_file_type == "APK": + a = myandro.create_apk(log, fileraw) + is_analysis_dex = myandro.analysis_apk(log, a) + fileraw = a.get_dex() + filter_file_type = androconf.is_android_raw(fileraw) + + elif filter_file_type == "AXML": + axmlobj = myandro.create_axml(log, fileraw) + myandro.analysis_axml(log, axmlobj) + + elif filter_file_type == "ARSC": + arscobj = myandro.create_arsc(log, fileraw) + myandro.analysis_arsc(log, arscobj) + + if is_analysis_dex and filter_file_type == "DEX": + d = myandro.create_dex(log, fileraw) + is_analysis_adex = myandro.analysis_dex(log, d) + + elif is_analysis_dex and filter_file_type == "DEY": + d = myandro.create_dey(log, fileraw) + is_analysis_adex = myandro.analysis_dey(log, d) + + if is_analysis_adex and d: + dx = myandro.create_adex(log, d) + myandro.analysis_adex(log, dx) + + myandro.analysis_app(log, a, d, dx) + + myandro.finish(log) + except Exception, why: + myandro.crash(log, why) + myandro.finish(log) + + del a, d, dx, axmlobj, arscobj + q.task_done() + + q = Queue.Queue(self.settings["max_fetcher"]) + for i in range(self.settings["max_fetcher"]): + t = threading.Thread(target=worker, args=[i, q]) + t.daemon = True + t.start() + + terminated = True + while terminated: + terminated = myandro.fetcher(q) + + try: + if terminated: + time.sleep(10) + except KeyboardInterrupt: + terminated = False + + q.join() + + +class DefaultAndroAnalysis(object): + """ + This class can be used as a template in order to analyse apps + """ + def fetcher(self, q): + """ + This method is called to fetch a new app in order to analyse it. The queue + must be fill with the following format: (filename, raw) + + :param q: the Queue to put new app + """ + pass + + def filter_file(self, log, fileraw): + """ + This method is called in order to filer a specific app + + :param log: an object which corresponds to a unique app + :param fileraw: the raw app (a string) + + :rtype: a set with 2 elements, the return value (boolean) if it is necessary to + continue the analysis and the file type + """ + file_type = androconf.is_android_raw(fileraw) + if file_type == "APK" or file_type == "DEX" or file_type == "DEY" or file_type == "AXML" or file_type == "ARSC": + if file_type == "APK": + if androconf.is_valid_android_raw(fileraw): + return (True, "APK") + else: + return (True, file_type) + return (False, None) + + def create_axml(self, log, fileraw): + """ + This method is called in order to create a new AXML object + + :param log: an object which corresponds to a unique app + :param fileraw: the raw axml (a string) + + :rtype: an :class:`APK` object + """ + return apk.AXMLPrinter(fileraw) + + def create_arsc(self, log, fileraw): + """ + This method is called in order to create a new ARSC object + + :param log: an object which corresponds to a unique app + :param fileraw: the raw arsc (a string) + + :rtype: an :class:`APK` object + """ + return apk.ARSCParser(fileraw) + + def create_apk(self, log, fileraw): + """ + This method is called in order to create a new APK object + + :param log: an object which corresponds to a unique app + :param fileraw: the raw apk (a string) + + :rtype: an :class:`APK` object + """ + return apk.APK(fileraw, raw=True, zipmodule=2) + + def create_dex(self, log, dexraw): + """ + This method is called in order to create a DalvikVMFormat object + + :param log: an object which corresponds to a unique app + :param dexraw: the raw classes.dex (a string) + + :rtype: a :class:`DalvikVMFormat` object + """ + return dvm.DalvikVMFormat(dexraw) + + def create_dey(self, log, deyraw): + """ + This method is called in order to create a DalvikOdexVMFormat object + + :param log: an object which corresponds to a unique app + :param dexraw: the raw odex file (a string) + + :rtype: a :class:`DalvikOdexVMFormat` object + """ + return dvm.DalvikOdexVMFormat(deyraw) + + def create_adex(self, log, dexobj): + """ + This method is called in order to create a VMAnalysis object + + :param log: an object which corresponds to a unique app + :param dexobj: a :class:`DalvikVMFormat` object + + :rytpe: a :class:`VMAnalysis` object + """ + return analysis.uVMAnalysis(dexobj) + + def analysis_axml(self, log, axmlobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param axmlobj: a :class:`AXMLPrinter` object + + :rtype: a boolean + """ + return True + + def analysis_arsc(self, log, arscobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param arscobj: a :class:`ARSCParser` object + + :rtype: a boolean + """ + return True + + def analysis_apk(self, log, apkobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param apkobj: a :class:`APK` object + + :rtype: a boolean + """ + return True + + def analysis_dex(self, log, dexobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param dexobj: a :class:`DalvikVMFormat` object + + :rtype: a boolean + """ + return True + + def analysis_dey(self, log, deyobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param deyobj: a :class:`DalvikOdexVMFormat` object + + :rtype: a boolean + """ + return True + + def analysis_adex(self, log, adexobj): + """ + This method is called in order to know if the analysis must continue + + :param log: an object which corresponds to a unique app + :param adexobj: a :class:`VMAnalysis` object + + :rtype: a boolean + """ + return True + + def analysis_app(self, log, apkobj, dexobj, adexobj): + """ + This method is called if you wish to analyse the final app + + :param log: an object which corresponds to a unique app + :param apkobj: a :class:`APK` object + :param dexobj: a :class:`DalvikVMFormat` object + :param adexobj: a :class:`VMAnalysis` object + """ + pass + + def finish(self, log): + """ + This method is called before the end of the analysis + + :param log: an object which corresponds to a unique app + """ + pass + + def crash(self, log, why): + """ + This method is called if a crash appends + + :param log: an object which corresponds to a unique app + :param why: the string exception + """ + pass + + def dump(self): + """ + This method is called to dump the result + + :param log: an object which corresponds to a unique app + """ + pass + + def dump_file(self, filename): + """ + This method is called to dump the result in a file + + :param log: an object which corresponds to a unique app + :param filename: the filename to dump the result + """ + pass + + +class DirectoryAndroAnalysis(DefaultAndroAnalysis): + """ + A simple class example to analyse a directory + """ + def __init__(self, directory): + self.directory = directory + + def fetcher(self, q): + for root, dirs, files in os.walk(self.directory, followlinks=True): + if files != []: + for f in files: + real_filename = root + if real_filename[-1] != "/": + real_filename += "/" + real_filename += f + q.put((real_filename, open(real_filename, "rb").read())) + return False diff --git a/androguard/core/analysis/ganalysis.py b/androguard/core/analysis/ganalysis.py new file mode 100644 index 00000000..9376d242 --- /dev/null +++ b/androguard/core/analysis/ganalysis.py @@ -0,0 +1,3488 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from xml.sax.saxutils import escape + +from androguard.core import bytecode +from androguard.core.bytecodes.dvm_permissions import DVM_PERMISSIONS +from androguard.core.analysis.risk import PERMISSIONS_RISK, INTERNET_RISK, PRIVACY_RISK, PHONE_RISK, SMS_RISK, MONEY_RISK +from androguard.core.analysis.analysis import PathVar, TAINTED_PACKAGE_CREATE + + +"""Base class for undirected graphs. + +The Graph class allows any hashable object as a node +and can associate key/value attribute pairs with each undirected edge. + +Self-loops are allowed but multiple edges are not (see MultiGraph). + +For directed graphs see DiGraph and MultiDiGraph. +""" +# Copyright (C) 2004-2011 by +# Aric Hagberg +# Dan Schult +# Pieter Swart +# All rights reserved. +# BSD license. +from copy import deepcopy + +__author__ = """\n""".join(['Aric Hagberg (hagberg@lanl.gov)', + 'Pieter Swart (swart@lanl.gov)', + 'Dan Schult(dschult@colgate.edu)']) + + +class Graph(object): + """ + Base class for undirected graphs. + + A Graph stores nodes and edges with optional data, or attributes. + + Graphs hold undirected edges. Self loops are allowed but multiple + (parallel) edges are not. + + Nodes can be arbitrary (hashable) Python objects with optional + key/value attributes. + + Edges are represented as links between nodes with optional + key/value attributes. + + Parameters + ---------- + data : input graph + Data to initialize graph. If data=None (default) an empty + graph is created. The data can be an edge list, or any + NetworkX graph object. If the corresponding optional Python + packages are installed the data can also be a NumPy matrix + or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to graph as key=value pairs. + + See Also + -------- + DiGraph + MultiGraph + MultiDiGraph + + Examples + -------- + Create an empty graph structure (a "null graph") with no nodes and + no edges. + + >>> G = nx.Graph() + + G can be grown in several ways. + + **Nodes:** + + Add one node at a time: + + >>> G.add_node(1) + + Add the nodes from any container (a list, dict, set or + even the lines from a file or the nodes from another graph). + + >>> G.add_nodes_from([2,3]) + >>> G.add_nodes_from(range(100,110)) + >>> H=nx.Graph() + >>> H.add_path([0,1,2,3,4,5,6,7,8,9]) + >>> G.add_nodes_from(H) + + In addition to strings and integers any hashable Python object + (except None) can represent a node, e.g. a customized node object, + or even another Graph. + + >>> G.add_node(H) + + **Edges:** + + G can also be grown by adding edges. + + Add one edge, + + >>> G.add_edge(1, 2) + + a list of edges, + + >>> G.add_edges_from([(1,2),(1,3)]) + + or a collection of edges, + + >>> G.add_edges_from(H.edges()) + + If some edges connect nodes not yet in the graph, the nodes + are added automatically. There are no errors when adding + nodes or edges that already exist. + + **Attributes:** + + Each graph, node, and edge can hold key/value attribute pairs + in an associated attribute dictionary (the keys must be hashable). + By default these are empty, but can be added or changed using + add_edge, add_node or direct manipulation of the attribute + dictionaries named graph, node and edge respectively. + + >>> G = nx.Graph(day="Friday") + >>> G.graph + {'day': 'Friday'} + + Add node attributes using add_node(), add_nodes_from() or G.node + + >>> G.add_node(1, time='5pm') + >>> G.add_nodes_from([3], time='2pm') + >>> G.node[1] + {'time': '5pm'} + >>> G.node[1]['room'] = 714 + >>> del G.node[1]['room'] # remove attribute + >>> G.nodes(data=True) + [(1, {'time': '5pm'}), (3, {'time': '2pm'})] + + Warning: adding a node to G.node does not add it to the graph. + + Add edge attributes using add_edge(), add_edges_from(), subscript + notation, or G.edge. + + >>> G.add_edge(1, 2, weight=4.7 ) + >>> G.add_edges_from([(3,4),(4,5)], color='red') + >>> G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})]) + >>> G[1][2]['weight'] = 4.7 + >>> G.edge[1][2]['weight'] = 4 + + **Shortcuts:** + + Many common graph features allow python syntax to speed reporting. + + >>> 1 in G # check if node in graph + True + >>> [n for n in G if n<3] # iterate through nodes + [1, 2] + >>> len(G) # number of nodes in graph + 5 + >>> G[1] # adjacency dict keyed by neighbor to edge attributes + ... # Note: you should not change this dict manually! + {2: {'color': 'blue', 'weight': 4}} + + The fastest way to traverse all edges of a graph is via + adjacency_iter(), but the edges() method is often more convenient. + + >>> for n,nbrsdict in G.adjacency_iter(): + ... for nbr,eattr in nbrsdict.items(): + ... if 'weight' in eattr: + ... (n,nbr,eattr['weight']) + (1, 2, 4) + (2, 1, 4) + (2, 3, 8) + (3, 2, 8) + >>> [ (u,v,edata['weight']) for u,v,edata in G.edges(data=True) if 'weight' in edata ] + [(1, 2, 4), (2, 3, 8)] + + **Reporting:** + + Simple graph information is obtained using methods. + Iterator versions of many reporting methods exist for efficiency. + Methods exist for reporting nodes(), edges(), neighbors() and degree() + as well as the number of nodes and edges. + + For details on these and other miscellaneous methods, see below. + """ + def __init__(self, data=None, **attr): + """Initialize a graph with edges, name, graph attributes. + + Parameters + ---------- + data : input graph + Data to initialize graph. If data=None (default) an empty + graph is created. The data can be an edge list, or any + NetworkX graph object. If the corresponding optional Python + packages are installed the data can also be a NumPy matrix + or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. + name : string, optional (default='') + An optional name for the graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to graph as key=value pairs. + + See Also + -------- + convert + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G = nx.Graph(name='my graph') + >>> e = [(1,2),(2,3),(3,4)] # list of edges + >>> G = nx.Graph(e) + + Arbitrary graph attribute pairs (key=value) may be assigned + + >>> G=nx.Graph(e, day="Friday") + >>> G.graph + {'day': 'Friday'} + + """ + self.graph = {} # dictionary for graph attributes + self.node = {} # empty node dict (created before convert) + self.adj = {} # empty adjacency dict + # attempt to load graph with data + if data is not None: + convert.to_networkx_graph(data,create_using=self) + # load graph attributes (must be after convert) + self.graph.update(attr) + self.edge = self.adj + + @property + def name(self): + return self.graph.get('name','') + @name.setter + def name(self, s): + self.graph['name']=s + + def __str__(self): + """Return the graph name. + + Returns + ------- + name : string + The name of the graph. + + Examples + -------- + >>> G = nx.Graph(name='foo') + >>> str(G) + 'foo' + """ + return self.name + + def __iter__(self): + """Iterate over the nodes. Use the expression 'for n in G'. + + Returns + ------- + niter : iterator + An iterator over all nodes in the graph. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + """ + return iter(self.node) + + def __contains__(self,n): + """Return True if n is a node, False otherwise. Use the expression + 'n in G'. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> 1 in G + True + """ + try: + return n in self.node + except TypeError: + return False + + def __len__(self): + """Return the number of nodes. Use the expression 'len(G)'. + + Returns + ------- + nnodes : int + The number of nodes in the graph. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> len(G) + 4 + + """ + return len(self.node) + + def __getitem__(self, n): + """Return a dict of neighbors of node n. Use the expression 'G[n]'. + + Parameters + ---------- + n : node + A node in the graph. + + Returns + ------- + adj_dict : dictionary + The adjacency dictionary for nodes connected to n. + + Notes + ----- + G[n] is similar to G.neighbors(n) but the internal data dictionary + is returned instead of a list. + + Assigning G[n] will corrupt the internal graph data structure. + Use G[n] for reading data only. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G[0] + {1: {}} + """ + return self.adj[n] + + + def add_node(self, n, attr_dict=None, **attr): + """Add a single node n and update node attributes. + + Parameters + ---------- + n : node + A node can be any hashable Python object except None. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of node attributes. Key/value pairs will + update existing data associated with the node. + attr : keyword arguments, optional + Set or change attributes using key=value. + + See Also + -------- + add_nodes_from + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_node(1) + >>> G.add_node('Hello') + >>> K3 = nx.Graph([(0,1),(1,2),(2,0)]) + >>> G.add_node(K3) + >>> G.number_of_nodes() + 3 + + Use keywords set/change node attributes: + + >>> G.add_node(1,size=10) + >>> G.add_node(3,weight=0.4,UTM=('13S',382871,3972649)) + + Notes + ----- + A hashable object is one that can be used as a key in a Python + dictionary. This includes strings, numbers, tuples of strings + and numbers, etc. + + On many platforms hashable items also include mutables such as + NetworkX Graphs, though one should be careful that the hash + doesn't change on mutables. + """ + # set up attribute dict + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dictionary.") + if n not in self.node: + self.adj[n] = {} + self.node[n] = attr_dict + else: # update attr even if node already exists + self.node[n].update(attr_dict) + + + def add_nodes_from(self, nodes, **attr): + """Add multiple nodes. + + Parameters + ---------- + nodes : iterable container + A container of nodes (list, dict, set, etc.). + OR + A container of (node, attribute dict) tuples. + Node attributes are updated using the attribute dict. + attr : keyword arguments, optional (default= no attributes) + Update attributes for all nodes in nodes. + Node attributes specified in nodes as a tuple + take precedence over attributes specified generally. + + See Also + -------- + add_node + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_nodes_from('Hello') + >>> K3 = nx.Graph([(0,1),(1,2),(2,0)]) + >>> G.add_nodes_from(K3) + >>> sorted(G.nodes(),key=str) + [0, 1, 2, 'H', 'e', 'l', 'o'] + + Use keywords to update specific node attributes for every node. + + >>> G.add_nodes_from([1,2], size=10) + >>> G.add_nodes_from([3,4], weight=0.4) + + Use (node, attrdict) tuples to update attributes for specific + nodes. + + >>> G.add_nodes_from([(1,dict(size=11)), (2,{'color':'blue'})]) + >>> G.node[1]['size'] + 11 + >>> H = nx.Graph() + >>> H.add_nodes_from(G.nodes(data=True)) + >>> H.node[1]['size'] + 11 + + """ + for n in nodes: + try: + newnode=n not in self.node + except TypeError: + nn,ndict = n + if nn not in self.node: + self.adj[nn] = {} + newdict = attr.copy() + newdict.update(ndict) + self.node[nn] = newdict + else: + olddict = self.node[nn] + olddict.update(attr) + olddict.update(ndict) + continue + if newnode: + self.adj[n] = {} + self.node[n] = attr.copy() + else: + self.node[n].update(attr) + + def remove_node(self,n): + """Remove node n. + + Removes the node n and all adjacent edges. + Attempting to remove a non-existent node will raise an exception. + + Parameters + ---------- + n : node + A node in the graph + + Raises + ------- + NetworkXError + If n is not in the graph. + + See Also + -------- + remove_nodes_from + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> G.edges() + [(0, 1), (1, 2)] + >>> G.remove_node(1) + >>> G.edges() + [] + + """ + adj = self.adj + try: + nbrs = list(adj[n].keys()) # keys handles self-loops (allow mutation later) + del self.node[n] + except KeyError: # NetworkXError if n not in self + raise NetworkXError("The node %s is not in the graph."%(n,)) + for u in nbrs: + del adj[u][n] # remove all edges n-u in graph + del adj[n] # now remove node + + + def remove_nodes_from(self, nodes): + """Remove multiple nodes. + + Parameters + ---------- + nodes : iterable container + A container of nodes (list, dict, set, etc.). If a node + in the container is not in the graph it is silently + ignored. + + See Also + -------- + remove_node + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> e = G.nodes() + >>> e + [0, 1, 2] + >>> G.remove_nodes_from(e) + >>> G.nodes() + [] + + """ + adj = self.adj + for n in nodes: + try: + del self.node[n] + for u in list(adj[n].keys()): # keys() handles self-loops + del adj[u][n] #(allows mutation of dict in loop) + del adj[n] + except KeyError: + pass + + + def nodes_iter(self, data=False): + """Return an iterator over the nodes. + + Parameters + ---------- + data : boolean, optional (default=False) + If False the iterator returns nodes. If True + return a two-tuple of node and node data dictionary + + Returns + ------- + niter : iterator + An iterator over nodes. If data=True the iterator gives + two-tuples containing (node, node data, dictionary) + + Notes + ----- + If the node data is not required it is simpler and equivalent + to use the expression 'for n in G'. + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + + >>> [d for n,d in G.nodes_iter(data=True)] + [{}, {}, {}] + """ + if data: + return iter(self.node.items()) + return iter(self.node) + + def nodes(self, data=False): + """Return a list of the nodes in the graph. + + Parameters + ---------- + data : boolean, optional (default=False) + If False return a list of nodes. If True return a + two-tuple of node and node data dictionary + + Returns + ------- + nlist : list + A list of nodes. If data=True a list of two-tuples containing + (node, node data dictionary). + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> G.nodes() + [0, 1, 2] + >>> G.add_node(1, time='5pm') + >>> G.nodes(data=True) + [(0, {}), (1, {'time': '5pm'}), (2, {})] + """ + return list(self.nodes_iter(data=data)) + + def number_of_nodes(self): + """Return the number of nodes in the graph. + + Returns + ------- + nnodes : int + The number of nodes in the graph. + + See Also + -------- + order, __len__ which are identical + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> len(G) + 3 + """ + return len(self.node) + + def order(self): + """Return the number of nodes in the graph. + + Returns + ------- + nnodes : int + The number of nodes in the graph. + + See Also + -------- + number_of_nodes, __len__ which are identical + + """ + return len(self.node) + + def has_node(self, n): + """Return True if the graph contains the node n. + + Parameters + ---------- + n : node + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> G.has_node(0) + True + + It is more readable and simpler to use + + >>> 0 in G + True + + """ + try: + return n in self.node + except TypeError: + return False + + def add_edge(self, u, v, attr_dict=None, **attr): + """Add an edge between u and v. + + The nodes u and v will be automatically added if they are + not already in the graph. + + Edge attributes can be specified with keywords or by providing + a dictionary with key/value pairs. See examples below. + + Parameters + ---------- + u,v : nodes + Nodes can be, for example, strings or numbers. + Nodes must be hashable (and not None) Python objects. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of edge attributes. Key/value pairs will + update existing data associated with the edge. + attr : keyword arguments, optional + Edge data (or labels or objects) can be assigned using + keyword arguments. + + See Also + -------- + add_edges_from : add a collection of edges + + Notes + ----- + Adding an edge that already exists updates the edge data. + + Many NetworkX algorithms designed for weighted graphs use as + the edge weight a numerical value assigned to a keyword + which by default is 'weight'. + + Examples + -------- + The following all add the edge e=(1,2) to graph G: + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> e = (1,2) + >>> G.add_edge(1, 2) # explicit two-node form + >>> G.add_edge(*e) # single edge as tuple of two nodes + >>> G.add_edges_from( [(1,2)] ) # add edges from iterable container + + Associate data to edges using keywords: + + >>> G.add_edge(1, 2, weight=3) + >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) + """ + # set up attribute dictionary + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dictionary.") + # add nodes + if u not in self.node: + self.adj[u] = {} + self.node[u] = {} + if v not in self.node: + self.adj[v] = {} + self.node[v] = {} + # add the edge + datadict=self.adj[u].get(v,{}) + datadict.update(attr_dict) + self.adj[u][v] = datadict + self.adj[v][u] = datadict + + + def add_edges_from(self, ebunch, attr_dict=None, **attr): + """Add all the edges in ebunch. + + Parameters + ---------- + ebunch : container of edges + Each edge given in the container will be added to the + graph. The edges must be given as as 2-tuples (u,v) or + 3-tuples (u,v,d) where d is a dictionary containing edge + data. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of edge attributes. Key/value pairs will + update existing data associated with each edge. + attr : keyword arguments, optional + Edge data (or labels or objects) can be assigned using + keyword arguments. + + + See Also + -------- + add_edge : add a single edge + add_weighted_edges_from : convenient way to add weighted edges + + Notes + ----- + Adding the same edge twice has no effect but any edge data + will be updated when each duplicate edge is added. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edges_from([(0,1),(1,2)]) # using a list of edge tuples + >>> e = zip(range(0,3),range(1,4)) + >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 + + Associate data to edges + + >>> G.add_edges_from([(1,2),(2,3)], weight=3) + >>> G.add_edges_from([(3,4),(1,4)], label='WN2898') + """ + # set up attribute dict + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dictionary.") + # process ebunch + for e in ebunch: + ne=len(e) + if ne==3: + u,v,dd = e + elif ne==2: + u,v = e + dd = {} + else: + raise NetworkXError(\ + "Edge tuple %s must be a 2-tuple or 3-tuple."%(e,)) + if u not in self.node: + self.adj[u] = {} + self.node[u] = {} + if v not in self.node: + self.adj[v] = {} + self.node[v] = {} + datadict=self.adj[u].get(v,{}) + datadict.update(attr_dict) + datadict.update(dd) + self.adj[u][v] = datadict + self.adj[v][u] = datadict + + + def add_weighted_edges_from(self, ebunch, weight='weight', **attr): + """Add all the edges in ebunch as weighted edges with specified + weights. + + Parameters + ---------- + ebunch : container of edges + Each edge given in the list or container will be added + to the graph. The edges must be given as 3-tuples (u,v,w) + where w is a number. + weight : string, optional (default= 'weight') + The attribute name for the edge weights to be added. + attr : keyword arguments, optional (default= no attributes) + Edge attributes to add/update for all edges. + + See Also + -------- + add_edge : add a single edge + add_edges_from : add multiple edges + + Notes + ----- + Adding the same edge twice for Graph/DiGraph simply updates + the edge data. For MultiGraph/MultiDiGraph, duplicate edges + are stored. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_weighted_edges_from([(0,1,3.0),(1,2,7.5)]) + """ + self.add_edges_from(((u,v,{weight:d}) for u,v,d in ebunch),**attr) + + def remove_edge(self, u, v): + """Remove the edge between u and v. + + Parameters + ---------- + u,v: nodes + Remove the edge between nodes u and v. + + Raises + ------ + NetworkXError + If there is not an edge between u and v. + + See Also + -------- + remove_edges_from : remove a collection of edges + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.remove_edge(0,1) + >>> e = (1,2) + >>> G.remove_edge(*e) # unpacks e from an edge tuple + >>> e = (2,3,{'weight':7}) # an edge with attribute data + >>> G.remove_edge(*e[:2]) # select first part of edge tuple + """ + try: + del self.adj[u][v] + if u != v: # self-loop needs only one entry removed + del self.adj[v][u] + except KeyError: + raise NetworkXError("The edge %s-%s is not in the graph"%(u,v)) + + + + def remove_edges_from(self, ebunch): + """Remove all edges specified in ebunch. + + Parameters + ---------- + ebunch: list or container of edge tuples + Each edge given in the list or container will be removed + from the graph. The edges can be: + + - 2-tuples (u,v) edge between u and v. + - 3-tuples (u,v,k) where k is ignored. + + See Also + -------- + remove_edge : remove a single edge + + Notes + ----- + Will fail silently if an edge in ebunch is not in the graph. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> ebunch=[(1,2),(2,3)] + >>> G.remove_edges_from(ebunch) + """ + adj=self.adj + for e in ebunch: + u,v = e[:2] # ignore edge data if present + if u in adj and v in adj[u]: + del adj[u][v] + if u != v: # self loop needs only one entry removed + del adj[v][u] + + + def has_edge(self, u, v): + """Return True if the edge (u,v) is in the graph. + + Parameters + ---------- + u,v : nodes + Nodes can be, for example, strings or numbers. + Nodes must be hashable (and not None) Python objects. + + Returns + ------- + edge_ind : bool + True if edge is in the graph, False otherwise. + + Examples + -------- + Can be called either using two nodes u,v or edge tuple (u,v) + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.has_edge(0,1) # using two nodes + True + >>> e = (0,1) + >>> G.has_edge(*e) # e is a 2-tuple (u,v) + True + >>> e = (0,1,{'weight':7}) + >>> G.has_edge(*e[:2]) # e is a 3-tuple (u,v,data_dictionary) + True + + The following syntax are all equivalent: + + >>> G.has_edge(0,1) + True + >>> 1 in G[0] # though this gives KeyError if 0 not in G + True + + """ + try: + return v in self.adj[u] + except KeyError: + return False + + + def neighbors(self, n): + """Return a list of the nodes connected to the node n. + + Parameters + ---------- + n : node + A node in the graph + + Returns + ------- + nlist : list + A list of nodes that are adjacent to n. + + Raises + ------ + NetworkXError + If the node n is not in the graph. + + Notes + ----- + It is usually more convenient (and faster) to access the + adjacency dictionary as G[n]: + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edge('a','b',weight=7) + >>> G['a'] + {'b': {'weight': 7}} + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.neighbors(0) + [1] + + """ + try: + return list(self.adj[n]) + except KeyError: + raise NetworkXError("The node %s is not in the graph."%(n,)) + + def neighbors_iter(self, n): + """Return an iterator over all neighbors of node n. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> [n for n in G.neighbors_iter(0)] + [1] + + Notes + ----- + It is faster to use the idiom "in G[0]", e.g. + + >>> G = nx.path_graph(4) + >>> [n for n in G[0]] + [1] + """ + try: + return iter(self.adj[n]) + except KeyError: + raise NetworkXError("The node %s is not in the graph."%(n,)) + + def edges(self, nbunch=None, data=False): + """Return a list of edges. + + Edges are returned as tuples with optional data + in the order (node, neighbor, data). + + Parameters + ---------- + nbunch : iterable container, optional (default= all nodes) + A container of nodes. The container will be iterated + through once. + data : bool, optional (default=False) + Return two tuples (u,v) (False) or three-tuples (u,v,data) (True). + + Returns + -------- + edge_list: list of edge tuples + Edges that are adjacent to any node in nbunch, or a list + of all edges if nbunch is not specified. + + See Also + -------- + edges_iter : return an iterator over the edges + + Notes + ----- + Nodes in nbunch that are not in the graph will be (quietly) ignored. + For directed graphs this returns the out-edges. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.edges() + [(0, 1), (1, 2), (2, 3)] + >>> G.edges(data=True) # default edge data is {} (empty dictionary) + [(0, 1, {}), (1, 2, {}), (2, 3, {})] + >>> G.edges([0,3]) + [(0, 1), (3, 2)] + >>> G.edges(0) + [(0, 1)] + + """ + return list(self.edges_iter(nbunch, data)) + + def edges_iter(self, nbunch=None, data=False): + """Return an iterator over the edges. + + Edges are returned as tuples with optional data + in the order (node, neighbor, data). + + Parameters + ---------- + nbunch : iterable container, optional (default= all nodes) + A container of nodes. The container will be iterated + through once. + data : bool, optional (default=False) + If True, return edge attribute dict in 3-tuple (u,v,data). + + Returns + ------- + edge_iter : iterator + An iterator of (u,v) or (u,v,d) tuples of edges. + + See Also + -------- + edges : return a list of edges + + Notes + ----- + Nodes in nbunch that are not in the graph will be (quietly) ignored. + For directed graphs this returns the out-edges. + + Examples + -------- + >>> G = nx.Graph() # or MultiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> [e for e in G.edges_iter()] + [(0, 1), (1, 2), (2, 3)] + >>> list(G.edges_iter(data=True)) # default data is {} (empty dict) + [(0, 1, {}), (1, 2, {}), (2, 3, {})] + >>> list(G.edges_iter([0,3])) + [(0, 1), (3, 2)] + >>> list(G.edges_iter(0)) + [(0, 1)] + + """ + seen={} # helper dict to keep track of multiply stored edges + if nbunch is None: + nodes_nbrs = self.adj.items() + else: + nodes_nbrs=((n,self.adj[n]) for n in self.nbunch_iter(nbunch)) + if data: + for n,nbrs in nodes_nbrs: + for nbr,data in nbrs.items(): + if nbr not in seen: + yield (n,nbr,data) + seen[n]=1 + else: + for n,nbrs in nodes_nbrs: + for nbr in nbrs: + if nbr not in seen: + yield (n,nbr) + seen[n] = 1 + del seen + + + def get_edge_data(self, u, v, default=None): + """Return the attribute dictionary associated with edge (u,v). + + Parameters + ---------- + u,v : nodes + default: any Python object (default=None) + Value to return if the edge (u,v) is not found. + + Returns + ------- + edge_dict : dictionary + The edge attribute dictionary. + + Notes + ----- + It is faster to use G[u][v]. + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G[0][1] + {} + + Warning: Assigning G[u][v] corrupts the graph data structure. + But it is safe to assign attributes to that dictionary, + + >>> G[0][1]['weight'] = 7 + >>> G[0][1]['weight'] + 7 + >>> G[1][0]['weight'] + 7 + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.get_edge_data(0,1) # default edge data is {} + {} + >>> e = (0,1) + >>> G.get_edge_data(*e) # tuple form + {} + >>> G.get_edge_data('a','b',default=0) # edge not in graph, return 0 + 0 + """ + try: + return self.adj[u][v] + except KeyError: + return default + + def adjacency_list(self): + """Return an adjacency list representation of the graph. + + The output adjacency list is in the order of G.nodes(). + For directed graphs, only outgoing adjacencies are included. + + Returns + ------- + adj_list : lists of lists + The adjacency structure of the graph as a list of lists. + + See Also + -------- + adjacency_iter + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.adjacency_list() # in order given by G.nodes() + [[1], [0, 2], [1, 3], [2]] + + """ + return list(map(list,iter(self.adj.values()))) + + def adjacency_iter(self): + """Return an iterator of (node, adjacency dict) tuples for all nodes. + + This is the fastest way to look at every edge. + For directed graphs, only outgoing adjacencies are included. + + Returns + ------- + adj_iter : iterator + An iterator of (node, adjacency dictionary) for all nodes in + the graph. + + See Also + -------- + adjacency_list + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> [(n,nbrdict) for n,nbrdict in G.adjacency_iter()] + [(0, {1: {}}), (1, {0: {}, 2: {}}), (2, {1: {}, 3: {}}), (3, {2: {}})] + + """ + return iter(self.adj.items()) + + def degree(self, nbunch=None, weight=None): + """Return the degree of a node or nodes. + + The node degree is the number of edges adjacent to that node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd : dictionary, or number + A dictionary with nodes as keys and degree as values or + a number if a single node is specified. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.degree(0) + 1 + >>> G.degree([0,1]) + {0: 1, 1: 2} + >>> list(G.degree([0,1]).values()) + [1, 2] + + """ + if nbunch in self: # return a single node + return next(self.degree_iter(nbunch,weight))[1] + else: # return a dict + return dict(self.degree_iter(nbunch,weight)) + + def degree_iter(self, nbunch=None, weight=None): + """Return an iterator for (node, degree). + + The node degree is the number of edges adjacent to the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd_iter : an iterator + The iterator returns two-tuples of (node, degree). + + See Also + -------- + degree + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> list(G.degree_iter(0)) # node 0 with degree 1 + [(0, 1)] + >>> list(G.degree_iter([0,1])) + [(0, 1), (1, 2)] + + """ + if nbunch is None: + nodes_nbrs = self.adj.items() + else: + nodes_nbrs=((n,self.adj[n]) for n in self.nbunch_iter(nbunch)) + + if weight is None: + for n,nbrs in nodes_nbrs: + yield (n,len(nbrs)+(n in nbrs)) # return tuple (n,degree) + else: + # edge weighted graph - degree is sum of nbr edge weights + for n,nbrs in nodes_nbrs: + yield (n, sum((nbrs[nbr].get(weight,1) for nbr in nbrs)) + + (n in nbrs and nbrs[n].get(weight,1))) + + + def clear(self): + """Remove all nodes and edges from the graph. + + This also removes the name, and all graph, node, and edge attributes. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.clear() + >>> G.nodes() + [] + >>> G.edges() + [] + + """ + self.name = '' + self.adj.clear() + self.node.clear() + self.graph.clear() + + def copy(self): + """Return a copy of the graph. + + Returns + ------- + G : Graph + A copy of the graph. + + See Also + -------- + to_directed: return a directed copy of the graph. + + Notes + ----- + This makes a complete copy of the graph including all of the + node or edge attributes. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> H = G.copy() + + """ + return deepcopy(self) + + def is_multigraph(self): + """Return True if graph is a multigraph, False otherwise.""" + return False + + + def is_directed(self): + """Return True if graph is directed, False otherwise.""" + return False + + def to_directed(self): + """Return a directed representation of the graph. + + Returns + ------- + G : DiGraph + A directed graph with the same name, same nodes, and with + each edge (u,v,data) replaced by two directed edges + (u,v,data) and (v,u,data). + + Notes + ----- + This returns a "deepcopy" of the edge, node, and + graph attributes which attempts to completely copy + all of the data and references. + + This is in contrast to the similar D=DiGraph(G) which returns a + shallow copy of the data. + + See the Python copy module for more information on shallow + and deep copies, http://docs.python.org/library/copy.html. + + Examples + -------- + >>> G = nx.Graph() # or MultiGraph, etc + >>> G.add_path([0,1]) + >>> H = G.to_directed() + >>> H.edges() + [(0, 1), (1, 0)] + + If already directed, return a (deep) copy + + >>> G = nx.DiGraph() # or MultiDiGraph, etc + >>> G.add_path([0,1]) + >>> H = G.to_directed() + >>> H.edges() + [(0, 1)] + """ + from networkx import DiGraph + G=DiGraph() + G.name=self.name + G.add_nodes_from(self) + G.add_edges_from( ((u,v,deepcopy(data)) + for u,nbrs in self.adjacency_iter() + for v,data in nbrs.items()) ) + G.graph=deepcopy(self.graph) + G.node=deepcopy(self.node) + return G + + def to_undirected(self): + """Return an undirected copy of the graph. + + Returns + ------- + G : Graph/MultiGraph + A deepcopy of the graph. + + See Also + -------- + copy, add_edge, add_edges_from + + Notes + ----- + This returns a "deepcopy" of the edge, node, and + graph attributes which attempts to completely copy + all of the data and references. + + This is in contrast to the similar G=DiGraph(D) which returns a + shallow copy of the data. + + See the Python copy module for more information on shallow + and deep copies, http://docs.python.org/library/copy.html. + + Examples + -------- + >>> G = nx.Graph() # or MultiGraph, etc + >>> G.add_path([0,1]) + >>> H = G.to_directed() + >>> H.edges() + [(0, 1), (1, 0)] + >>> G2 = H.to_undirected() + >>> G2.edges() + [(0, 1)] + """ + return deepcopy(self) + + def subgraph(self, nbunch): + """Return the subgraph induced on nodes in nbunch. + + The induced subgraph of the graph contains the nodes in nbunch + and the edges between those nodes. + + Parameters + ---------- + nbunch : list, iterable + A container of nodes which will be iterated through once. + + Returns + ------- + G : Graph + A subgraph of the graph with the same edge attributes. + + Notes + ----- + The graph, edge or node attributes just point to the original graph. + So changes to the node or edge structure will not be reflected in + the original graph while changes to the attributes will. + + To create a subgraph with its own copy of the edge/node attributes use: + nx.Graph(G.subgraph(nbunch)) + + If edge attributes are containers, a deep copy can be obtained using: + G.subgraph(nbunch).copy() + + For an inplace reduction of a graph to a subgraph you can remove nodes: + G.remove_nodes_from([ n in G if n not in set(nbunch)]) + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> H = G.subgraph([0,1,2]) + >>> H.edges() + [(0, 1), (1, 2)] + """ + bunch =self.nbunch_iter(nbunch) + # create new graph and copy subgraph into it + H = self.__class__() + # copy node and attribute dictionaries + for n in bunch: + H.node[n]=self.node[n] + # namespace shortcuts for speed + H_adj=H.adj + self_adj=self.adj + # add nodes and edges (undirected method) + for n in H.node: + Hnbrs={} + H_adj[n]=Hnbrs + for nbr,d in self_adj[n].items(): + if nbr in H_adj: + # add both representations of edge: n-nbr and nbr-n + Hnbrs[nbr]=d + H_adj[nbr][n]=d + H.graph=self.graph + return H + + + def nodes_with_selfloops(self): + """Return a list of nodes with self loops. + + A node with a self loop has an edge with both ends adjacent + to that node. + + Returns + ------- + nodelist : list + A list of nodes with self loops. + + See Also + -------- + selfloop_edges, number_of_selfloops + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edge(1,1) + >>> G.add_edge(1,2) + >>> G.nodes_with_selfloops() + [1] + """ + return [ n for n,nbrs in self.adj.items() if n in nbrs ] + + def selfloop_edges(self, data=False): + """Return a list of selfloop edges. + + A selfloop edge has the same node at both ends. + + Parameters + ----------- + data : bool, optional (default=False) + Return selfloop edges as two tuples (u,v) (data=False) + or three-tuples (u,v,data) (data=True) + + Returns + ------- + edgelist : list of edge tuples + A list of all selfloop edges. + + See Also + -------- + nodes_with_selfloops, number_of_selfloops + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edge(1,1) + >>> G.add_edge(1,2) + >>> G.selfloop_edges() + [(1, 1)] + >>> G.selfloop_edges(data=True) + [(1, 1, {})] + """ + if data: + return [ (n,n,nbrs[n]) + for n,nbrs in self.adj.items() if n in nbrs ] + else: + return [ (n,n) + for n,nbrs in self.adj.items() if n in nbrs ] + + + def number_of_selfloops(self): + """Return the number of selfloop edges. + + A selfloop edge has the same node at both ends. + + Returns + ------- + nloops : int + The number of selfloops. + + See Also + -------- + nodes_with_selfloops, selfloop_edges + + Examples + -------- + >>> G=nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edge(1,1) + >>> G.add_edge(1,2) + >>> G.number_of_selfloops() + 1 + """ + return len(self.selfloop_edges()) + + + def size(self, weight=None): + """Return the number of edges. + + Parameters + ---------- + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + + Returns + ------- + nedges : int + The number of edges of sum of edge weights in the graph. + + See Also + -------- + number_of_edges + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.size() + 3 + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edge('a','b',weight=2) + >>> G.add_edge('b','c',weight=4) + >>> G.size() + 2 + >>> G.size(weight='weight') + 6.0 + """ + s=sum(self.degree(weight=weight).values())/2 + if weight is None: + return int(s) + else: + return float(s) + + def number_of_edges(self, u=None, v=None): + """Return the number of edges between two nodes. + + Parameters + ---------- + u,v : nodes, optional (default=all edges) + If u and v are specified, return the number of edges between + u and v. Otherwise return the total number of all edges. + + Returns + ------- + nedges : int + The number of edges in the graph. If nodes u and v are specified + return the number of edges between those nodes. + + See Also + -------- + size + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.number_of_edges() + 3 + >>> G.number_of_edges(0,1) + 1 + >>> e = (0,1) + >>> G.number_of_edges(*e) + 1 + """ + if u is None: return int(self.size()) + if v in self.adj[u]: + return 1 + else: + return 0 + + + def add_star(self, nodes, **attr): + """Add a star. + + The first node in nodes is the middle of the star. It is connected + to all other nodes. + + Parameters + ---------- + nodes : iterable container + A container of nodes. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to every edge in star. + + See Also + -------- + add_path, add_cycle + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_star([0,1,2,3]) + >>> G.add_star([10,11,12],weight=2) + + """ + nlist = list(nodes) + v=nlist[0] + edges=((v,n) for n in nlist[1:]) + self.add_edges_from(edges, **attr) + + def add_path(self, nodes, **attr): + """Add a path. + + Parameters + ---------- + nodes : iterable container + A container of nodes. A path will be constructed from + the nodes (in order) and added to the graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to every edge in path. + + See Also + -------- + add_star, add_cycle + + Examples + -------- + >>> G=nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.add_path([10,11,12],weight=7) + + """ + nlist = list(nodes) + edges=zip(nlist[:-1],nlist[1:]) + self.add_edges_from(edges, **attr) + + def add_cycle(self, nodes, **attr): + """Add a cycle. + + Parameters + ---------- + nodes: iterable container + A container of nodes. A cycle will be constructed from + the nodes (in order) and added to the graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to every edge in cycle. + + See Also + -------- + add_path, add_star + + Examples + -------- + >>> G=nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_cycle([0,1,2,3]) + >>> G.add_cycle([10,11,12],weight=7) + + """ + nlist = list(nodes) + edges=zip(nlist,nlist[1:]+[nlist[0]]) + self.add_edges_from(edges, **attr) + + + def nbunch_iter(self, nbunch=None): + """Return an iterator of nodes contained in nbunch that are + also in the graph. + + The nodes in nbunch are checked for membership in the graph + and if not are silently ignored. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + Returns + ------- + niter : iterator + An iterator over nodes in nbunch that are also in the graph. + If nbunch is None, iterate over all nodes in the graph. + + Raises + ------ + NetworkXError + If nbunch is not a node or or sequence of nodes. + If a node in nbunch is not hashable. + + See Also + -------- + Graph.__iter__ + + Notes + ----- + When nbunch is an iterator, the returned iterator yields values + directly from nbunch, becoming exhausted when nbunch is exhausted. + + To test whether nbunch is a single node, one can use + "if nbunch in self:", even after processing with this routine. + + If nbunch is not a node or a (possibly empty) sequence/iterator + or None, a NetworkXError is raised. Also, if any object in + nbunch is not hashable, a NetworkXError is raised. + """ + if nbunch is None: # include all nodes via iterator + bunch=iter(self.adj.keys()) + elif nbunch in self: # if nbunch is a single node + bunch=iter([nbunch]) + else: # if nbunch is a sequence of nodes + def bunch_iter(nlist,adj): + try: + for n in nlist: + if n in adj: + yield n + except TypeError as e: + message=e.args[0] + import sys + sys.stdout.write(message) + # capture error for non-sequence/iterator nbunch. + if 'iter' in message: + raise NetworkXError(\ + "nbunch is not a node or a sequence of nodes.") + # capture error for unhashable node. + elif 'hashable' in message: + raise NetworkXError(\ + "Node %s in the sequence nbunch is not a valid node."%n) + else: + raise + bunch=bunch_iter(nbunch,self.adj) + return bunch + +"""Base class for directed graphs.""" +# Copyright (C) 2004-2011 by +# Aric Hagberg +# Dan Schult +# Pieter Swart +# All rights reserved. +# BSD license. +from copy import deepcopy + + +class DiGraph(Graph): + """ + Base class for directed graphs. + + A DiGraph stores nodes and edges with optional data, or attributes. + + DiGraphs hold directed edges. Self loops are allowed but multiple + (parallel) edges are not. + + Nodes can be arbitrary (hashable) Python objects with optional + key/value attributes. + + Edges are represented as links between nodes with optional + key/value attributes. + + Parameters + ---------- + data : input graph + Data to initialize graph. If data=None (default) an empty + graph is created. The data can be an edge list, or any + NetworkX graph object. If the corresponding optional Python + packages are installed the data can also be a NumPy matrix + or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to graph as key=value pairs. + + See Also + -------- + Graph + MultiGraph + MultiDiGraph + + Examples + -------- + Create an empty graph structure (a "null graph") with no nodes and + no edges. + + >>> G = nx.DiGraph() + + G can be grown in several ways. + + **Nodes:** + + Add one node at a time: + + >>> G.add_node(1) + + Add the nodes from any container (a list, dict, set or + even the lines from a file or the nodes from another graph). + + >>> G.add_nodes_from([2,3]) + >>> G.add_nodes_from(range(100,110)) + >>> H=nx.Graph() + >>> H.add_path([0,1,2,3,4,5,6,7,8,9]) + >>> G.add_nodes_from(H) + + In addition to strings and integers any hashable Python object + (except None) can represent a node, e.g. a customized node object, + or even another Graph. + + >>> G.add_node(H) + + **Edges:** + + G can also be grown by adding edges. + + Add one edge, + + >>> G.add_edge(1, 2) + + a list of edges, + + >>> G.add_edges_from([(1,2),(1,3)]) + + or a collection of edges, + + >>> G.add_edges_from(H.edges()) + + If some edges connect nodes not yet in the graph, the nodes + are added automatically. There are no errors when adding + nodes or edges that already exist. + + **Attributes:** + + Each graph, node, and edge can hold key/value attribute pairs + in an associated attribute dictionary (the keys must be hashable). + By default these are empty, but can be added or changed using + add_edge, add_node or direct manipulation of the attribute + dictionaries named graph, node and edge respectively. + + >>> G = nx.DiGraph(day="Friday") + >>> G.graph + {'day': 'Friday'} + + Add node attributes using add_node(), add_nodes_from() or G.node + + >>> G.add_node(1, time='5pm') + >>> G.add_nodes_from([3], time='2pm') + >>> G.node[1] + {'time': '5pm'} + >>> G.node[1]['room'] = 714 + >>> del G.node[1]['room'] # remove attribute + >>> G.nodes(data=True) + [(1, {'time': '5pm'}), (3, {'time': '2pm'})] + + Warning: adding a node to G.node does not add it to the graph. + + Add edge attributes using add_edge(), add_edges_from(), subscript + notation, or G.edge. + + >>> G.add_edge(1, 2, weight=4.7 ) + >>> G.add_edges_from([(3,4),(4,5)], color='red') + >>> G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})]) + >>> G[1][2]['weight'] = 4.7 + >>> G.edge[1][2]['weight'] = 4 + + **Shortcuts:** + + Many common graph features allow python syntax to speed reporting. + + >>> 1 in G # check if node in graph + True + >>> [n for n in G if n<3] # iterate through nodes + [1, 2] + >>> len(G) # number of nodes in graph + 5 + >>> G[1] # adjacency dict keyed by neighbor to edge attributes + ... # Note: you should not change this dict manually! + {2: {'color': 'blue', 'weight': 4}} + + The fastest way to traverse all edges of a graph is via + adjacency_iter(), but the edges() method is often more convenient. + + >>> for n,nbrsdict in G.adjacency_iter(): + ... for nbr,eattr in nbrsdict.items(): + ... if 'weight' in eattr: + ... (n,nbr,eattr['weight']) + (1, 2, 4) + (2, 3, 8) + >>> [ (u,v,edata['weight']) for u,v,edata in G.edges(data=True) if 'weight' in edata ] + [(1, 2, 4), (2, 3, 8)] + + **Reporting:** + + Simple graph information is obtained using methods. + Iterator versions of many reporting methods exist for efficiency. + Methods exist for reporting nodes(), edges(), neighbors() and degree() + as well as the number of nodes and edges. + + For details on these and other miscellaneous methods, see below. + """ + def __init__(self, data=None, **attr): + """Initialize a graph with edges, name, graph attributes. + + Parameters + ---------- + data : input graph + Data to initialize graph. If data=None (default) an empty + graph is created. The data can be an edge list, or any + NetworkX graph object. If the corresponding optional Python + packages are installed the data can also be a NumPy matrix + or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. + name : string, optional (default='') + An optional name for the graph. + attr : keyword arguments, optional (default= no attributes) + Attributes to add to graph as key=value pairs. + + See Also + -------- + convert + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G = nx.Graph(name='my graph') + >>> e = [(1,2),(2,3),(3,4)] # list of edges + >>> G = nx.Graph(e) + + Arbitrary graph attribute pairs (key=value) may be assigned + + >>> G=nx.Graph(e, day="Friday") + >>> G.graph + {'day': 'Friday'} + + """ + self.graph = {} # dictionary for graph attributes + self.node = {} # dictionary for node attributes + # We store two adjacency lists: + # the predecessors of node n are stored in the dict self.pred + # the successors of node n are stored in the dict self.succ=self.adj + self.adj = {} # empty adjacency dictionary + self.pred = {} # predecessor + self.succ = self.adj # successor + + # attempt to load graph with data + if data is not None: + convert.to_networkx_graph(data,create_using=self) + # load graph attributes (must be after convert) + self.graph.update(attr) + self.edge=self.adj + + + def add_node(self, n, attr_dict=None, **attr): + """Add a single node n and update node attributes. + + Parameters + ---------- + n : node + A node can be any hashable Python object except None. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of node attributes. Key/value pairs will + update existing data associated with the node. + attr : keyword arguments, optional + Set or change attributes using key=value. + + See Also + -------- + add_nodes_from + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_node(1) + >>> G.add_node('Hello') + >>> K3 = nx.Graph([(0,1),(1,2),(2,0)]) + >>> G.add_node(K3) + >>> G.number_of_nodes() + 3 + + Use keywords set/change node attributes: + + >>> G.add_node(1,size=10) + >>> G.add_node(3,weight=0.4,UTM=('13S',382871,3972649)) + + Notes + ----- + A hashable object is one that can be used as a key in a Python + dictionary. This includes strings, numbers, tuples of strings + and numbers, etc. + + On many platforms hashable items also include mutables such as + NetworkX Graphs, though one should be careful that the hash + doesn't change on mutables. + """ + # set up attribute dict + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dictionary.") + if n not in self.succ: + self.succ[n] = {} + self.pred[n] = {} + self.node[n] = attr_dict + else: # update attr even if node already exists + self.node[n].update(attr_dict) + + + def add_nodes_from(self, nodes, **attr): + """Add multiple nodes. + + Parameters + ---------- + nodes : iterable container + A container of nodes (list, dict, set, etc.). + OR + A container of (node, attribute dict) tuples. + Node attributes are updated using the attribute dict. + attr : keyword arguments, optional (default= no attributes) + Update attributes for all nodes in nodes. + Node attributes specified in nodes as a tuple + take precedence over attributes specified generally. + + See Also + -------- + add_node + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_nodes_from('Hello') + >>> K3 = nx.Graph([(0,1),(1,2),(2,0)]) + >>> G.add_nodes_from(K3) + >>> sorted(G.nodes(),key=str) + [0, 1, 2, 'H', 'e', 'l', 'o'] + + Use keywords to update specific node attributes for every node. + + >>> G.add_nodes_from([1,2], size=10) + >>> G.add_nodes_from([3,4], weight=0.4) + + Use (node, attrdict) tuples to update attributes for specific + nodes. + + >>> G.add_nodes_from([(1,dict(size=11)), (2,{'color':'blue'})]) + >>> G.node[1]['size'] + 11 + >>> H = nx.Graph() + >>> H.add_nodes_from(G.nodes(data=True)) + >>> H.node[1]['size'] + 11 + + """ + for n in nodes: + try: + newnode=n not in self.succ + except TypeError: + nn,ndict = n + if nn not in self.succ: + self.succ[nn] = {} + self.pred[nn] = {} + newdict = attr.copy() + newdict.update(ndict) + self.node[nn] = newdict + else: + olddict = self.node[nn] + olddict.update(attr) + olddict.update(ndict) + continue + if newnode: + self.succ[n] = {} + self.pred[n] = {} + self.node[n] = attr.copy() + else: + self.node[n].update(attr) + + def remove_node(self, n): + """Remove node n. + + Removes the node n and all adjacent edges. + Attempting to remove a non-existent node will raise an exception. + + Parameters + ---------- + n : node + A node in the graph + + Raises + ------- + NetworkXError + If n is not in the graph. + + See Also + -------- + remove_nodes_from + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> G.edges() + [(0, 1), (1, 2)] + >>> G.remove_node(1) + >>> G.edges() + [] + + """ + try: + nbrs=self.succ[n] + del self.node[n] + except KeyError: # NetworkXError if n not in self + raise NetworkXError("The node %s is not in the digraph."%(n,)) + for u in nbrs: + del self.pred[u][n] # remove all edges n-u in digraph + del self.succ[n] # remove node from succ + for u in self.pred[n]: + del self.succ[u][n] # remove all edges n-u in digraph + del self.pred[n] # remove node from pred + + + def remove_nodes_from(self, nbunch): + """Remove multiple nodes. + + Parameters + ---------- + nodes : iterable container + A container of nodes (list, dict, set, etc.). If a node + in the container is not in the graph it is silently + ignored. + + See Also + -------- + remove_node + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2]) + >>> e = G.nodes() + >>> e + [0, 1, 2] + >>> G.remove_nodes_from(e) + >>> G.nodes() + [] + + """ + for n in nbunch: + try: + succs=self.succ[n] + del self.node[n] + for u in succs: + del self.pred[u][n] # remove all edges n-u in digraph + del self.succ[n] # now remove node + for u in self.pred[n]: + del self.succ[u][n] # remove all edges n-u in digraph + del self.pred[n] # now remove node + except KeyError: + pass # silent failure on remove + + + def add_edge(self, u, v, attr_dict=None, **attr): + """Add an edge between u and v. + + The nodes u and v will be automatically added if they are + not already in the graph. + + Edge attributes can be specified with keywords or by providing + a dictionary with key/value pairs. See examples below. + + Parameters + ---------- + u,v : nodes + Nodes can be, for example, strings or numbers. + Nodes must be hashable (and not None) Python objects. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of edge attributes. Key/value pairs will + update existing data associated with the edge. + attr : keyword arguments, optional + Edge data (or labels or objects) can be assigned using + keyword arguments. + + See Also + -------- + add_edges_from : add a collection of edges + + Notes + ----- + Adding an edge that already exists updates the edge data. + + Many NetworkX algorithms designed for weighted graphs use as + the edge weight a numerical value assigned to a keyword + which by default is 'weight'. + + Examples + -------- + The following all add the edge e=(1,2) to graph G: + + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> e = (1,2) + >>> G.add_edge(1, 2) # explicit two-node form + >>> G.add_edge(*e) # single edge as tuple of two nodes + >>> G.add_edges_from( [(1,2)] ) # add edges from iterable container + + Associate data to edges using keywords: + + >>> G.add_edge(1, 2, weight=3) + >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) + """ + # set up attribute dict + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dictionary.") + # add nodes + if u not in self.succ: + self.succ[u]={} + self.pred[u]={} + self.node[u] = {} + if v not in self.succ: + self.succ[v]={} + self.pred[v]={} + self.node[v] = {} + # add the edge + datadict=self.adj[u].get(v,{}) + datadict.update(attr_dict) + self.succ[u][v]=datadict + self.pred[v][u]=datadict + + def add_edges_from(self, ebunch, attr_dict=None, **attr): + """Add all the edges in ebunch. + + Parameters + ---------- + ebunch : container of edges + Each edge given in the container will be added to the + graph. The edges must be given as as 2-tuples (u,v) or + 3-tuples (u,v,d) where d is a dictionary containing edge + data. + attr_dict : dictionary, optional (default= no attributes) + Dictionary of edge attributes. Key/value pairs will + update existing data associated with each edge. + attr : keyword arguments, optional + Edge data (or labels or objects) can be assigned using + keyword arguments. + + + See Also + -------- + add_edge : add a single edge + add_weighted_edges_from : convenient way to add weighted edges + + Notes + ----- + Adding the same edge twice has no effect but any edge data + will be updated when each duplicate edge is added. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_edges_from([(0,1),(1,2)]) # using a list of edge tuples + >>> e = zip(range(0,3),range(1,4)) + >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 + + Associate data to edges + + >>> G.add_edges_from([(1,2),(2,3)], weight=3) + >>> G.add_edges_from([(3,4),(1,4)], label='WN2898') + """ + # set up attribute dict + if attr_dict is None: + attr_dict=attr + else: + try: + attr_dict.update(attr) + except AttributeError: + raise NetworkXError(\ + "The attr_dict argument must be a dict.") + # process ebunch + for e in ebunch: + ne = len(e) + if ne==3: + u,v,dd = e + assert hasattr(dd,"update") + elif ne==2: + u,v = e + dd = {} + else: + raise NetworkXError(\ + "Edge tuple %s must be a 2-tuple or 3-tuple."%(e,)) + if u not in self.succ: + self.succ[u] = {} + self.pred[u] = {} + self.node[u] = {} + if v not in self.succ: + self.succ[v] = {} + self.pred[v] = {} + self.node[v] = {} + datadict=self.adj[u].get(v,{}) + datadict.update(attr_dict) + datadict.update(dd) + self.succ[u][v] = datadict + self.pred[v][u] = datadict + + + def remove_edge(self, u, v): + """Remove the edge between u and v. + + Parameters + ---------- + u,v: nodes + Remove the edge between nodes u and v. + + Raises + ------ + NetworkXError + If there is not an edge between u and v. + + See Also + -------- + remove_edges_from : remove a collection of edges + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.remove_edge(0,1) + >>> e = (1,2) + >>> G.remove_edge(*e) # unpacks e from an edge tuple + >>> e = (2,3,{'weight':7}) # an edge with attribute data + >>> G.remove_edge(*e[:2]) # select first part of edge tuple + """ + try: + del self.succ[u][v] + del self.pred[v][u] + except KeyError: + raise NetworkXError("The edge %s-%s not in graph."%(u,v)) + + + def remove_edges_from(self, ebunch): + """Remove all edges specified in ebunch. + + Parameters + ---------- + ebunch: list or container of edge tuples + Each edge given in the list or container will be removed + from the graph. The edges can be: + + - 2-tuples (u,v) edge between u and v. + - 3-tuples (u,v,k) where k is ignored. + + See Also + -------- + remove_edge : remove a single edge + + Notes + ----- + Will fail silently if an edge in ebunch is not in the graph. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> ebunch=[(1,2),(2,3)] + >>> G.remove_edges_from(ebunch) + """ + for e in ebunch: + (u,v)=e[:2] # ignore edge data + if u in self.succ and v in self.succ[u]: + del self.succ[u][v] + del self.pred[v][u] + + + def has_successor(self, u, v): + """Return True if node u has successor v. + + This is true if graph has the edge u->v. + """ + return (u in self.succ and v in self.succ[u]) + + def has_predecessor(self, u, v): + """Return True if node u has predecessor v. + + This is true if graph has the edge u<-v. + """ + return (u in self.pred and v in self.pred[u]) + + def successors_iter(self,n): + """Return an iterator over successor nodes of n. + + neighbors_iter() and successors_iter() are the same. + """ + try: + return iter(self.succ[n]) + except KeyError: + raise NetworkXError("The node %s is not in the digraph."%(n,)) + + def predecessors_iter(self,n): + """Return an iterator over predecessor nodes of n.""" + try: + return iter(self.pred[n]) + except KeyError: + raise NetworkXError("The node %s is not in the digraph."%(n,)) + + def successors(self, n): + """Return a list of successor nodes of n. + + neighbors() and successors() are the same function. + """ + return list(self.successors_iter(n)) + + def predecessors(self, n): + """Return a list of predecessor nodes of n.""" + return list(self.predecessors_iter(n)) + + + # digraph definitions + neighbors = successors + neighbors_iter = successors_iter + + def edges_iter(self, nbunch=None, data=False): + """Return an iterator over the edges. + + Edges are returned as tuples with optional data + in the order (node, neighbor, data). + + Parameters + ---------- + nbunch : iterable container, optional (default= all nodes) + A container of nodes. The container will be iterated + through once. + data : bool, optional (default=False) + If True, return edge attribute dict in 3-tuple (u,v,data). + + Returns + ------- + edge_iter : iterator + An iterator of (u,v) or (u,v,d) tuples of edges. + + See Also + -------- + edges : return a list of edges + + Notes + ----- + Nodes in nbunch that are not in the graph will be (quietly) ignored. + For directed graphs this returns the out-edges. + + Examples + -------- + >>> G = nx.DiGraph() # or MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> [e for e in G.edges_iter()] + [(0, 1), (1, 2), (2, 3)] + >>> list(G.edges_iter(data=True)) # default data is {} (empty dict) + [(0, 1, {}), (1, 2, {}), (2, 3, {})] + >>> list(G.edges_iter([0,2])) + [(0, 1), (2, 3)] + >>> list(G.edges_iter(0)) + [(0, 1)] + + """ + if nbunch is None: + nodes_nbrs=self.adj.items() + else: + nodes_nbrs=((n,self.adj[n]) for n in self.nbunch_iter(nbunch)) + if data: + for n,nbrs in nodes_nbrs: + for nbr,data in nbrs.items(): + yield (n,nbr,data) + else: + for n,nbrs in nodes_nbrs: + for nbr in nbrs: + yield (n,nbr) + + # alias out_edges to edges + out_edges_iter=edges_iter + out_edges=Graph.edges + + def in_edges_iter(self, nbunch=None, data=False): + """Return an iterator over the incoming edges. + + Parameters + ---------- + nbunch : iterable container, optional (default= all nodes) + A container of nodes. The container will be iterated + through once. + data : bool, optional (default=False) + If True, return edge attribute dict in 3-tuple (u,v,data). + + Returns + ------- + in_edge_iter : iterator + An iterator of (u,v) or (u,v,d) tuples of incoming edges. + + See Also + -------- + edges_iter : return an iterator of edges + """ + if nbunch is None: + nodes_nbrs=self.pred.items() + else: + nodes_nbrs=((n,self.pred[n]) for n in self.nbunch_iter(nbunch)) + if data: + for n,nbrs in nodes_nbrs: + for nbr,data in nbrs.items(): + yield (nbr,n,data) + else: + for n,nbrs in nodes_nbrs: + for nbr in nbrs: + yield (nbr,n) + + def in_edges(self, nbunch=None, data=False): + """Return a list of the incoming edges. + + See Also + -------- + edges : return a list of edges + """ + return list(self.in_edges_iter(nbunch, data)) + + def degree_iter(self, nbunch=None, weight=None): + """Return an iterator for (node, degree). + + The node degree is the number of edges adjacent to the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd_iter : an iterator + The iterator returns two-tuples of (node, degree). + + See Also + -------- + degree, in_degree, out_degree, in_degree_iter, out_degree_iter + + Examples + -------- + >>> G = nx.DiGraph() # or MultiDiGraph + >>> G.add_path([0,1,2,3]) + >>> list(G.degree_iter(0)) # node 0 with degree 1 + [(0, 1)] + >>> list(G.degree_iter([0,1])) + [(0, 1), (1, 2)] + + """ + if nbunch is None: + nodes_nbrs=zip(iter(self.succ.items()),iter(self.pred.items())) + else: + nodes_nbrs=zip( + ((n,self.succ[n]) for n in self.nbunch_iter(nbunch)), + ((n,self.pred[n]) for n in self.nbunch_iter(nbunch))) + + if weight is None: + for (n,succ),(n2,pred) in nodes_nbrs: + yield (n,len(succ)+len(pred)) + else: + # edge weighted graph - degree is sum of edge weights + for (n,succ),(n2,pred) in nodes_nbrs: + yield (n, + sum((succ[nbr].get(weight,1) for nbr in succ))+ + sum((pred[nbr].get(weight,1) for nbr in pred))) + + + def in_degree_iter(self, nbunch=None, weight=None): + """Return an iterator for (node, in-degree). + + The node in-degree is the number of edges pointing in to the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd_iter : an iterator + The iterator returns two-tuples of (node, in-degree). + + See Also + -------- + degree, in_degree, out_degree, out_degree_iter + + Examples + -------- + >>> G = nx.DiGraph() + >>> G.add_path([0,1,2,3]) + >>> list(G.in_degree_iter(0)) # node 0 with degree 0 + [(0, 0)] + >>> list(G.in_degree_iter([0,1])) + [(0, 0), (1, 1)] + + """ + if nbunch is None: + nodes_nbrs=self.pred.items() + else: + nodes_nbrs=((n,self.pred[n]) for n in self.nbunch_iter(nbunch)) + + if weight is None: + for n,nbrs in nodes_nbrs: + yield (n,len(nbrs)) + else: + # edge weighted graph - degree is sum of edge weights + for n,nbrs in nodes_nbrs: + yield (n, sum(data.get(weight,1) for data in nbrs.values())) + + + def out_degree_iter(self, nbunch=None, weight=None): + """Return an iterator for (node, out-degree). + + The node out-degree is the number of edges pointing out of the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd_iter : an iterator + The iterator returns two-tuples of (node, out-degree). + + See Also + -------- + degree, in_degree, out_degree, in_degree_iter + + Examples + -------- + >>> G = nx.DiGraph() + >>> G.add_path([0,1,2,3]) + >>> list(G.out_degree_iter(0)) # node 0 with degree 1 + [(0, 1)] + >>> list(G.out_degree_iter([0,1])) + [(0, 1), (1, 1)] + + """ + if nbunch is None: + nodes_nbrs=self.succ.items() + else: + nodes_nbrs=((n,self.succ[n]) for n in self.nbunch_iter(nbunch)) + + if weight is None: + for n,nbrs in nodes_nbrs: + yield (n,len(nbrs)) + else: + # edge weighted graph - degree is sum of edge weights + for n,nbrs in nodes_nbrs: + yield (n, sum(data.get(weight,1) for data in nbrs.values())) + + + def in_degree(self, nbunch=None, weight=None): + """Return the in-degree of a node or nodes. + + The node in-degree is the number of edges pointing in to the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd : dictionary, or number + A dictionary with nodes as keys and in-degree as values or + a number if a single node is specified. + + See Also + -------- + degree, out_degree, in_degree_iter + + Examples + -------- + >>> G = nx.DiGraph() # or MultiDiGraph + >>> G.add_path([0,1,2,3]) + >>> G.in_degree(0) + 0 + >>> G.in_degree([0,1]) + {0: 0, 1: 1} + >>> list(G.in_degree([0,1]).values()) + [0, 1] + """ + if nbunch in self: # return a single node + return next(self.in_degree_iter(nbunch,weight))[1] + else: # return a dict + return dict(self.in_degree_iter(nbunch,weight)) + + def out_degree(self, nbunch=None, weight=None): + """Return the out-degree of a node or nodes. + + The node out-degree is the number of edges pointing out of the node. + + Parameters + ---------- + nbunch : iterable container, optional (default=all nodes) + A container of nodes. The container will be iterated + through once. + + weight : string or None, optional (default=None) + The edge attribute that holds the numerical value used + as a weight. If None, then each edge has weight 1. + The degree is the sum of the edge weights adjacent to the node. + + Returns + ------- + nd : dictionary, or number + A dictionary with nodes as keys and out-degree as values or + a number if a single node is specified. + + Examples + -------- + >>> G = nx.DiGraph() # or MultiDiGraph + >>> G.add_path([0,1,2,3]) + >>> G.out_degree(0) + 1 + >>> G.out_degree([0,1]) + {0: 1, 1: 1} + >>> list(G.out_degree([0,1]).values()) + [1, 1] + + + """ + if nbunch in self: # return a single node + return next(self.out_degree_iter(nbunch,weight))[1] + else: # return a dict + return dict(self.out_degree_iter(nbunch,weight)) + + def clear(self): + """Remove all nodes and edges from the graph. + + This also removes the name, and all graph, node, and edge attributes. + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> G.clear() + >>> G.nodes() + [] + >>> G.edges() + [] + + """ + self.succ.clear() + self.pred.clear() + self.node.clear() + self.graph.clear() + + + def is_multigraph(self): + """Return True if graph is a multigraph, False otherwise.""" + return False + + + def is_directed(self): + """Return True if graph is directed, False otherwise.""" + return True + + def to_directed(self): + """Return a directed copy of the graph. + + Returns + ------- + G : DiGraph + A deepcopy of the graph. + + Notes + ----- + This returns a "deepcopy" of the edge, node, and + graph attributes which attempts to completely copy + all of the data and references. + + This is in contrast to the similar D=DiGraph(G) which returns a + shallow copy of the data. + + See the Python copy module for more information on shallow + and deep copies, http://docs.python.org/library/copy.html. + + Examples + -------- + >>> G = nx.Graph() # or MultiGraph, etc + >>> G.add_path([0,1]) + >>> H = G.to_directed() + >>> H.edges() + [(0, 1), (1, 0)] + + If already directed, return a (deep) copy + + >>> G = nx.DiGraph() # or MultiDiGraph, etc + >>> G.add_path([0,1]) + >>> H = G.to_directed() + >>> H.edges() + [(0, 1)] + """ + return deepcopy(self) + + def to_undirected(self, reciprocal=False): + """Return an undirected representation of the digraph. + + Parameters + ---------- + reciprocal : bool (optional) + If True only keep edges that appear in both directions + in the original digraph. + + Returns + ------- + G : Graph + An undirected graph with the same name and nodes and + with edge (u,v,data) if either (u,v,data) or (v,u,data) + is in the digraph. If both edges exist in digraph and + their edge data is different, only one edge is created + with an arbitrary choice of which edge data to use. + You must check and correct for this manually if desired. + + Notes + ----- + If edges in both directions (u,v) and (v,u) exist in the + graph, attributes for the new undirected edge will be a combination of + the attributes of the directed edges. The edge data is updated + in the (arbitrary) order that the edges are encountered. For + more customized control of the edge attributes use add_edge(). + + This returns a "deepcopy" of the edge, node, and + graph attributes which attempts to completely copy + all of the data and references. + + This is in contrast to the similar G=DiGraph(D) which returns a + shallow copy of the data. + + See the Python copy module for more information on shallow + and deep copies, http://docs.python.org/library/copy.html. + """ + H=Graph() + H.name=self.name + H.add_nodes_from(self) + if reciprocal is True: + H.add_edges_from( (u,v,deepcopy(d)) + for u,nbrs in self.adjacency_iter() + for v,d in nbrs.items() + if v in self.pred[u]) + else: + H.add_edges_from( (u,v,deepcopy(d)) + for u,nbrs in self.adjacency_iter() + for v,d in nbrs.items() ) + H.graph=deepcopy(self.graph) + H.node=deepcopy(self.node) + return H + + + def reverse(self, copy=True): + """Return the reverse of the graph. + + The reverse is a graph with the same nodes and edges + but with the directions of the edges reversed. + + Parameters + ---------- + copy : bool optional (default=True) + If True, return a new DiGraph holding the reversed edges. + If False, reverse the reverse graph is created using + the original graph (this changes the original graph). + """ + if copy: + H = self.__class__(name="Reverse of (%s)"%self.name) + H.add_nodes_from(self) + H.add_edges_from( (v,u,deepcopy(d)) for u,v,d + in self.edges(data=True) ) + H.graph=deepcopy(self.graph) + H.node=deepcopy(self.node) + else: + self.pred,self.succ=self.succ,self.pred + self.adj=self.succ + H=self + return H + + + def subgraph(self, nbunch): + """Return the subgraph induced on nodes in nbunch. + + The induced subgraph of the graph contains the nodes in nbunch + and the edges between those nodes. + + Parameters + ---------- + nbunch : list, iterable + A container of nodes which will be iterated through once. + + Returns + ------- + G : Graph + A subgraph of the graph with the same edge attributes. + + Notes + ----- + The graph, edge or node attributes just point to the original graph. + So changes to the node or edge structure will not be reflected in + the original graph while changes to the attributes will. + + To create a subgraph with its own copy of the edge/node attributes use: + nx.Graph(G.subgraph(nbunch)) + + If edge attributes are containers, a deep copy can be obtained using: + G.subgraph(nbunch).copy() + + For an inplace reduction of a graph to a subgraph you can remove nodes: + G.remove_nodes_from([ n in G if n not in set(nbunch)]) + + Examples + -------- + >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc + >>> G.add_path([0,1,2,3]) + >>> H = G.subgraph([0,1,2]) + >>> H.edges() + [(0, 1), (1, 2)] + """ + bunch = self.nbunch_iter(nbunch) + # create new graph and copy subgraph into it + H = self.__class__() + # copy node and attribute dictionaries + for n in bunch: + H.node[n]=self.node[n] + # namespace shortcuts for speed + H_succ=H.succ + H_pred=H.pred + self_succ=self.succ + # add nodes + for n in H: + H_succ[n]={} + H_pred[n]={} + # add edges + for u in H_succ: + Hnbrs=H_succ[u] + for v,datadict in self_succ[u].items(): + if v in H_succ: + # add both representations of edge: u-v and v-u + Hnbrs[v]=datadict + H_pred[v][u]=datadict + H.graph=self.graph + return H + + +DEFAULT_RISKS = { + INTERNET_RISK : ( "INTERNET_RISK", (195, 255, 0) ), + PRIVACY_RISK : ( "PRIVACY_RISK", (255, 255, 51) ), + PHONE_RISK : ( "PHONE_RISK", ( 255, 216, 0 ) ), + SMS_RISK : ( "SMS_RISK", ( 255, 93, 0 ) ), + MONEY_RISK : ( "MONEY_RISK", ( 255, 0, 0 ) ), +} + +DEXCLASSLOADER_COLOR = (0, 0, 0) +ACTIVITY_COLOR = (51, 255, 51) +SERVICE_COLOR = (0, 204, 204) +RECEIVER_COLOR = (204, 51, 204) + +ID_ATTRIBUTES = { + "type" : 0, + "class_name" : 1, + "method_name" : 2, + "descriptor" : 3, + "permissions" : 4, + "permissions_level" : 5, + "dynamic_code" : 6, +} + + +class GVMAnalysis: + def __init__(self, vmx, apk): + self.vmx = vmx + self.vm = self.vmx.get_vm() + + self.nodes = {} + self.nodes_id = {} + self.entry_nodes = [] + self.G = DiGraph() + self.GI = DiGraph() + + for j in self.vmx.get_tainted_packages().get_internal_packages(): + src_class_name, src_method_name, src_descriptor = j.get_src(self.vm.get_class_manager()) + dst_class_name, dst_method_name, dst_descriptor = j.get_dst(self.vm.get_class_manager()) + + n1 = self._get_node(src_class_name, src_method_name, src_descriptor) + n2 = self._get_node(dst_class_name, dst_method_name, dst_descriptor) + + self.G.add_edge(n1.id, n2.id) + n1.add_edge(n2, j) + + internal_new_packages = self.vmx.tainted_packages.get_internal_new_packages() + for j in internal_new_packages: + for path in internal_new_packages[j]: + src_class_name, src_method_name, src_descriptor = path.get_src(self.vm.get_class_manager()) + + n1 = self._get_node(src_class_name, src_method_name, src_descriptor) + n2 = self._get_node(j, "", "") + self.GI.add_edge(n2.id, n1.id) + n1.add_edge(n2, path) + + if apk != None: + for i in apk.get_activities() : + j = bytecode.FormatClassToJava(i) + n1 = self._get_exist_node( j, "onCreate", "(Landroid/os/Bundle;)V" ) + if n1 != None : + n1.set_attributes( { "type" : "activity" } ) + n1.set_attributes( { "color" : ACTIVITY_COLOR } ) + n2 = self._get_new_node_from( n1, "ACTIVITY" ) + n2.set_attributes( { "color" : ACTIVITY_COLOR } ) + self.G.add_edge( n2.id, n1.id ) + self.entry_nodes.append( n1.id ) + for i in apk.get_services() : + j = bytecode.FormatClassToJava(i) + n1 = self._get_exist_node( j, "onCreate", "()V" ) + if n1 != None : + n1.set_attributes( { "type" : "service" } ) + n1.set_attributes( { "color" : SERVICE_COLOR } ) + n2 = self._get_new_node_from( n1, "SERVICE" ) + n2.set_attributes( { "color" : SERVICE_COLOR } ) + self.G.add_edge( n2.id, n1.id ) + self.entry_nodes.append( n1.id ) + for i in apk.get_receivers() : + j = bytecode.FormatClassToJava(i) + n1 = self._get_exist_node( j, "onReceive", "(Landroid/content/Context; Landroid/content/Intent;)V" ) + if n1 != None : + n1.set_attributes( { "type" : "receiver" } ) + n1.set_attributes( { "color" : RECEIVER_COLOR } ) + n2 = self._get_new_node_from( n1, "RECEIVER" ) + n2.set_attributes( { "color" : RECEIVER_COLOR } ) + self.G.add_edge( n2.id, n1.id ) + self.entry_nodes.append( n1.id ) + + # Specific Java/Android library + for c in self.vm.get_classes(): + #if c.get_superclassname() == "Landroid/app/Service;" : + # n1 = self._get_node( c.get_name(), "", "()V" ) + # n2 = self._get_node( c.get_name(), "onCreate", "()V" ) + + # self.G.add_edge( n1.id, n2.id ) + if c.get_superclassname() == "Ljava/lang/Thread;" or c.get_superclassname() == "Ljava/util/TimerTask;" : + for i in self.vm.get_method("run") : + if i.get_class_name() == c.get_name() : + n1 = self._get_node( i.get_class_name(), i.get_name(), i.get_descriptor() ) + n2 = self._get_node( i.get_class_name(), "start", i.get_descriptor() ) + + # link from start to run + self.G.add_edge( n2.id, n1.id ) + n2.add_edge( n1, {} ) + + # link from init to start + for init in self.vm.get_method("") : + if init.get_class_name() == c.get_name() : + n3 = self._get_node( init.get_class_name(), "", init.get_descriptor() ) + #n3 = self._get_node( i.get_class_name(), "", i.get_descriptor() ) + self.G.add_edge( n3.id, n2.id ) + n3.add_edge( n2, {} ) + + #elif c.get_superclassname() == "Landroid/os/AsyncTask;" : + # for i in self.vm.get_method("doInBackground") : + # if i.get_class_name() == c.get_name() : + # n1 = self._get_node( i.get_class_name(), i.get_name(), i.get_descriptor() ) + # n2 = self._get_exist_node( i.get_class_name(), "execute", i.get_descriptor() ) + # print n1, n2, i.get_descriptor() + #for j in self.vm.get_method("doInBackground") : + # n2 = self._get_exist_node( i.get_class_name(), j.get_name(), j.get_descriptor() ) + # print n1, n2 + # n2 = self._get_node( i.get_class_name(), " + # raise("ooo") + + #for j in self.vmx.tainted_packages.get_internal_new_packages() : + # print "\t %s %s %s %x ---> %s %s %s" % (j.get_method().get_class_name(), j.get_method().get_name(), j.get_method().get_descriptor(), \ + # j.get_bb().start + j.get_idx(), \ + # j.get_class_name(), j.get_name(), j.get_descriptor()) + + list_permissions = self.vmx.get_permissions([]) + for x in list_permissions: + for j in list_permissions[x]: + if isinstance(j, PathVar): + continue + + src_class_name, src_method_name, src_descriptor = j.get_src( self.vm.get_class_manager() ) + dst_class_name, dst_method_name, dst_descriptor = j.get_dst( self.vm.get_class_manager() ) + n1 = self._get_exist_node( dst_class_name, dst_method_name, dst_descriptor ) + + if n1 == None : + continue + + n1.set_attributes( { "permissions" : 1 } ) + n1.set_attributes( { "permissions_level" : DVM_PERMISSIONS[ "MANIFEST_PERMISSION" ][ x ][0] } ) + n1.set_attributes( { "permissions_details" : x } ) + + try : + for tmp_perm in PERMISSIONS_RISK[ x ] : + if tmp_perm in DEFAULT_RISKS : + n2 = self._get_new_node( dst_class_name, + dst_method_name, + dst_descriptor + " " + DEFAULT_RISKS[ tmp_perm ][0], + DEFAULT_RISKS[ tmp_perm ][0] ) + n2.set_attributes( { "color" : DEFAULT_RISKS[ tmp_perm ][1] } ) + self.G.add_edge( n2.id, n1.id ) + + n1.add_risk( DEFAULT_RISKS[ tmp_perm ][0] ) + n1.add_api( x, src_class_name + "-" + src_method_name + "-" + src_descriptor ) + except KeyError : + pass + + # Tag DexClassLoader + for m, _ in self.vmx.get_tainted_packages().get_packages() : + if m.get_name() == "Ldalvik/system/DexClassLoader;" : + for path in m.get_paths() : + if path.get_access_flag() == TAINTED_PACKAGE_CREATE : + src_class_name, src_method_name, src_descriptor = path.get_src( self.vm.get_class_manager() ) + n1 = self._get_exist_node( src_class_name, src_method_name, src_descriptor ) + n2 = self._get_new_node( dst_class_name, dst_method_name, dst_descriptor + " " + "DEXCLASSLOADER", + "DEXCLASSLOADER" ) + + n1.set_attributes( { "dynamic_code" : "true" } ) + n2.set_attributes( { "color" : DEXCLASSLOADER_COLOR } ) + self.G.add_edge( n2.id, n1.id ) + + n1.add_risk( "DEXCLASSLOADER" ) + + def _get_exist_node(self, class_name, method_name, descriptor) : + key = "%s %s %s" % (class_name, method_name, descriptor) + try : + return self.nodes[ key ] + except KeyError : + return None + + def _get_node(self, class_name, method_name, descriptor): + if method_name == "" and descriptor == "": + key = class_name + else: + key = "%s %s %s" % (class_name, method_name, descriptor) + if key not in self.nodes: + self.nodes[key] = NodeF(len(self.nodes), class_name, method_name, descriptor) + self.nodes_id[self.nodes[key].id] = self.nodes[key] + + return self.nodes[key] + + def _get_new_node_from(self, n, label) : + return self._get_new_node( n.class_name, n.method_name, n.descriptor + label, label ) + + def _get_new_node(self, class_name, method_name, descriptor, label) : + key = "%s %s %s" % (class_name, method_name, descriptor) + if key not in self.nodes : + self.nodes[ key ] = NodeF( len(self.nodes), class_name, method_name, descriptor, label, False ) + self.nodes_id[ self.nodes[ key ].id ] = self.nodes[ key ] + + return self.nodes[ key ] + + def set_new_attributes(self, cm) : + for i in self.G.nodes() : + n1 = self.nodes_id[ i ] + m1 = self.vm.get_method_descriptor( n1.class_name, n1.method_name, n1.descriptor ) + + H = cm( self.vmx, m1 ) + + n1.set_attributes( H ) + + def export_to_gexf(self) : + buff = "\n" + buff += "\n" + buff += "\n" + + buff += "\n" + buff += "\n" % ID_ATTRIBUTES[ "type"] + buff += "\n" % ID_ATTRIBUTES[ "class_name"] + buff += "\n" % ID_ATTRIBUTES[ "method_name"] + buff += "\n" % ID_ATTRIBUTES[ "descriptor"] + + + buff += "\n" % ID_ATTRIBUTES[ "permissions"] + buff += "\n" % ID_ATTRIBUTES[ "permissions_level"] + + buff += "\n" % ID_ATTRIBUTES[ "dynamic_code"] + buff += "\n" + + buff += "\n" + for node in self.G.nodes() : + buff += "\n" % (node, escape(self.nodes_id[ node ].label)) + buff += self.nodes_id[ node ].get_attributes_gexf() + buff += "\n" + buff += "\n" + + + buff += "\n" + nb = 0 + for edge in self.G.edges() : + buff += "\n" % (nb, edge[0], edge[1]) + nb += 1 + buff += "\n" + + + buff += "\n" + buff += "\n" + + return buff + + def export_to_gml(self) : + buff = "\n" + buff += "\n" + + buff += "\n" + buff += "\n" + + buff += "\n" + + for node in self.G.nodes() : + buff += "\n" % (node) + #fd.write( "\n" % (node, escape(self.nodes_id[ node ].label)) ) + buff += self.nodes_id[ node ].get_attributes_gml() + buff += "\n" + + nb = 0 + for edge in self.G.edges() : + buff += "\n" % (nb, edge[0], edge[1]) + nb += 1 + + buff += "\n" + buff += "\n" + + return buff + +DEFAULT_NODE_TYPE = "normal" +DEFAULT_NODE_PERM = 0 +DEFAULT_NODE_PERM_LEVEL = -1 + +PERMISSIONS_LEVEL = { + "dangerous" : 3, + "signatureOrSystem" : 2, + "signature" : 1, + "normal" : 0, +} + +COLOR_PERMISSIONS_LEVEL = { + "dangerous" : (255, 0, 0), + "signatureOrSystem" : (255, 63, 63), + "signature" : (255, 132, 132), + "normal" : (255, 181, 181), +} + + +class NodeF: + def __init__(self, id, class_name, method_name, descriptor, label=None, real=True): + self.class_name = class_name + self.method_name = method_name + self.descriptor = descriptor + + self.id = id + self.real = real + self.risks = [] + self.api = {} + self.edges = {} + + if label == None: + self.label = "%s %s %s" % (class_name, method_name, descriptor) + else: + self.label = label + + self.attributes = {"type": DEFAULT_NODE_TYPE, + "color": None, + "permissions": DEFAULT_NODE_PERM, + "permissions_level": DEFAULT_NODE_PERM_LEVEL, + "permissions_details": set(), + "dynamic_code": "false", + } + + def add_edge(self, n, idx): + try: + self.edges[n].append(idx) + except KeyError: + self.edges[n] = [] + self.edges[n].append(idx) + + def get_attributes_gexf(self): + buff = "" + + if self.attributes[ "color" ] != None : + buff += "\n" % (self.attributes[ "color" ][0], self.attributes[ "color" ][1], self.attributes[ "color" ][2]) + + buff += "\n" + buff += "\n" % (ID_ATTRIBUTES["class_name"], escape(self.class_name)) + buff += "\n" % (ID_ATTRIBUTES["method_name"], escape(self.method_name)) + buff += "\n" % (ID_ATTRIBUTES["descriptor"], escape(self.descriptor)) + + + if self.attributes[ "type" ] != DEFAULT_NODE_TYPE : + buff += "\n" % (ID_ATTRIBUTES["type"], self.attributes[ "type" ]) + if self.attributes[ "permissions" ] != DEFAULT_NODE_PERM : + buff += "\n" % (ID_ATTRIBUTES["permissions"], self.attributes[ "permissions" ]) + buff += "\n" % (ID_ATTRIBUTES["permissions_level"], self.attributes[ "permissions_level_name" ]) + + + buff += "\n" % (ID_ATTRIBUTES["dynamic_code"], self.attributes[ "dynamic_code" ]) + + buff += "\n" + + return buff + + def get_attributes_gml(self) : + buff = "" + + buff += "\n" + buff += "\n" + + height = 10 + width = max(len(self.class_name), len(self.method_name)) + width = max(width, len(self.descriptor)) + + buff += "\n" % (16 * height, 8 * width) + if self.attributes[ "color" ] != None : + buff += "\n" % (self.attributes[ "color" ][0], self.attributes[ "color" ][1], self.attributes[ "color" ][2]) + + buff += "\n" + + label = self.class_name + "\n" + self.method_name + "\n" + self.descriptor + buff += escape(label) + + buff += "\n" + buff += "\n" + buff += "\n" + + return buff + + def get_attributes(self) : + return self.attributes + + def get_attribute(self, name) : + return self.attributes[ name ] + + def set_attributes(self, values) : + for i in values : + if i == "permissions" : + self.attributes[ "permissions" ] += values[i] + elif i == "permissions_level" : + if values[i] > self.attributes[ "permissions_level" ] : + self.attributes[ "permissions_level" ] = PERMISSIONS_LEVEL[ values[i] ] + self.attributes[ "permissions_level_name" ] = values[i] + self.attributes[ "color" ] = COLOR_PERMISSIONS_LEVEL[ values[i] ] + elif i == "permissions_details" : + self.attributes[ i ].add( values[i] ) + else : + self.attributes[ i ] = values[i] + + def add_risk(self, risk) : + if risk not in self.risks : + self.risks.append( risk ) + + def add_api(self, perm, api) : + if perm not in self.api : + self.api[ perm ] = [] + + if api not in self.api[ perm ] : + self.api[ perm ].append( api ) diff --git a/androguard/core/analysis/risk.py b/androguard/core/analysis/risk.py new file mode 100644 index 00000000..156eaa8f --- /dev/null +++ b/androguard/core/analysis/risk.py @@ -0,0 +1,1047 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# risks from classes.dex : + # API <-> Permissions + # method X is more dangerous than another one + # const-string -> apk-tool + # v0 <- X + # v1 <- Y + + # v10 <- X + # v11 <- Y + + # CALL( v0, v1 ) + # obfuscated names + +GENERAL_RISK = 0 +DANGEROUS_RISK = 1 +SIGNATURE_SYSTEM_RISK = 2 +SIGNATURE_RISK = 3 +NORMAL_RISK = 4 + +MONEY_RISK = 5 +SMS_RISK = 6 +PHONE_RISK = 7 +INTERNET_RISK = 8 +PRIVACY_RISK = 9 +DYNAMIC_RISK = 10 + +BINARY_RISK = 11 +EXPLOIT_RISK = 12 + +RISK_VALUES = { + DANGEROUS_RISK : 5, + SIGNATURE_SYSTEM_RISK : 10, + SIGNATURE_RISK : 10, + NORMAL_RISK : 0, + + MONEY_RISK : 5, + SMS_RISK : 5, + PHONE_RISK : 5, + INTERNET_RISK : 2, + PRIVACY_RISK : 5, + DYNAMIC_RISK : 5, + + BINARY_RISK : 10, + EXPLOIT_RISK : 15, +} + +GENERAL_PERMISSIONS_RISK = { + "dangerous" : DANGEROUS_RISK, + "signatureOrSystem" : SIGNATURE_SYSTEM_RISK, + "signatureOrSystemOrDevelopment" : SIGNATURE_SYSTEM_RISK, + "signature" : SIGNATURE_RISK, + "normal" : NORMAL_RISK, +} + +PERMISSIONS_RISK = { + "SEND_SMS" : [ MONEY_RISK, SMS_RISK ], + + "RECEIVE_SMS" : [ SMS_RISK ], + "READ_SMS" : [ SMS_RISK ], + "WRITE_SMS" : [ SMS_RISK ], + "RECEIVE_SMS" : [ SMS_RISK ], + "RECEIVE_MMS" : [ SMS_RISK ], + + "PHONE_CALL" : [ MONEY_RISK ], + "PROCESS_OUTGOING_CALLS" : [ MONEY_RISK ], + "CALL_PRIVILEGED" : [ MONEY_RISK ], + + + "INTERNET" : [ MONEY_RISK, INTERNET_RISK ], + + "READ_PHONE_STATE" : [ PRIVACY_RISK ], + "READ_CONTACTS" : [ PRIVACY_RISK ], + "READ_HISTORY_BOOKMARKS" : [ PRIVACY_RISK ], + "ACCESS_FINE_LOCATION" : [ PRIVACY_RISK ], + "ACCESS_COARSE_LOCATION" : [ PRIVACY_RISK ], +} + +LOW_RISK = "low" +AVERAGE_RISK = "average" +HIGH_RISK = "high" +UNACCEPTABLE_RISK = "unacceptable" + +NULL_MALWARE_RISK = "null" +AVERAGE_MALWARE_RISK = "average" +HIGH_MALWARE_RISK = "high" +UNACCEPTABLE_MALWARE_RISK = "unacceptable" + +from androguard.core.androconf import error, warning, debug, set_debug, get_debug +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis + +from androguard.core.bytecodes.dvm_permissions import DVM_PERMISSIONS +import re, copy + +def add_system_rule(system, rule_name, rule) : + system.rules[ rule_name ] = rule + +def create_system_risk() : + try : + import fuzzy + except ImportError : + error("please install pyfuzzy to use this module !") + + import fuzzy.System + import fuzzy.InputVariable + import fuzzy.fuzzify.Plain + import fuzzy.OutputVariable + import fuzzy.defuzzify.COGS + import fuzzy.defuzzify.COG + import fuzzy.defuzzify.MaxRight + import fuzzy.defuzzify.MaxLeft + import fuzzy.defuzzify.LM + import fuzzy.set.Polygon + import fuzzy.set.Singleton + import fuzzy.set.Triangle + import fuzzy.Adjective + import fuzzy.operator.Input + import fuzzy.operator.Compound + import fuzzy.norm.Min + import fuzzy.norm.Max + import fuzzy.Rule + import fuzzy.defuzzify.Dict + + system = fuzzy.System.System() + + input_Dangerous_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Money_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Privacy_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Binary_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Internet_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Dynamic_Risk = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + + # Input variables + + # Dangerous Risk + system.variables["input_Dangerous_Risk"] = input_Dangerous_Risk + input_Dangerous_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (8.0, 1.0), (12.0, 0.0)]) ) + input_Dangerous_Risk.adjectives[AVERAGE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(8.0, 0.0), (50.0, 1.0), (60.0, 0.0)]) ) + input_Dangerous_Risk.adjectives[HIGH_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(50.0, 0.0), (85.0, 1.0), (95.0, 0.0)]) ) + input_Dangerous_Risk.adjectives[UNACCEPTABLE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(85.0, 0.0), (100.0, 1.0)]) ) + + # Money Risk + system.variables["input_Money_Risk"] = input_Money_Risk + input_Money_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (3.0, 0.0)]) ) + input_Money_Risk.adjectives[UNACCEPTABLE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(4.0, 0.0), (5.0, 1.0), (30.0, 1.0)]) ) + + # Privacy Risk + system.variables["input_Privacy_Risk"] = input_Privacy_Risk + input_Privacy_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (6.0, 1.0), (10.0, 0.0)]) ) + input_Privacy_Risk.adjectives[HIGH_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(6.0, 0.0), (10.0, 1.0), (20.0, 0.0)]) ) + input_Privacy_Risk.adjectives[UNACCEPTABLE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(15.0, 0.0), (20.0, 1.0), (30.0, 1.0)]) ) + + # Binary Risk + system.variables["input_Binary_Risk"] = input_Binary_Risk + input_Binary_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (6.0, 1.0), (10.0, 0.0)]) ) + input_Binary_Risk.adjectives[AVERAGE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(6.0, 0.0), (10.0, 1.0), (15.0, 0.0)]) ) + input_Binary_Risk.adjectives[HIGH_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(10.0, 0.0), (20.0, 1.0), (24.0, 0.0)]) ) + input_Binary_Risk.adjectives[UNACCEPTABLE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(23.0, 0.0), (30.0, 1.0), (40.0, 1.0)]) ) + + # Internet Risk + system.variables["input_Internet_Risk"] = input_Internet_Risk + #input_Internet_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (1.0, 1.0)]) ) + input_Internet_Risk.adjectives[HIGH_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(1.0, 0.0), (5.0, 1.0), (30.0, 1.0)]) ) + + # Dynamic Risk + system.variables["input_Dynamic_Risk"] = input_Dynamic_Risk + input_Dynamic_Risk.adjectives[LOW_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (3.0, 0.0)])) + input_Dynamic_Risk.adjectives[UNACCEPTABLE_RISK] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(4.0, 0.0), (5.0, 1.0), (50.0, 1.0)]) ) + + # Output variables + output_malware_risk = fuzzy.OutputVariable.OutputVariable( + defuzzify=fuzzy.defuzzify.COGS.COGS(), + description="malware risk", + min=0.0,max=100.0, + ) + + #output_malware_risk = fuzzy.OutputVariable.OutputVariable(defuzzify=fuzzy.defuzzify.Dict.Dict()) + + output_malware_risk.adjectives[NULL_MALWARE_RISK] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(0.0)) + output_malware_risk.adjectives[AVERAGE_MALWARE_RISK] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(30.0)) + output_malware_risk.adjectives[HIGH_MALWARE_RISK] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(60.0)) + output_malware_risk.adjectives[UNACCEPTABLE_MALWARE_RISK] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(100.0)) + + system.variables["output_malware_risk"] = output_malware_risk + + # Rules + #RULE 0: DYNAMIC + add_system_rule(system, "r0", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[NULL_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Dynamic_Risk"].adjectives[LOW_RISK] ) + ) + ) + + add_system_rule(system, "r0a", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[UNACCEPTABLE_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Dynamic_Risk"].adjectives[UNACCEPTABLE_RISK] ) + ) + ) + + + #RULE 1: MONEY + add_system_rule(system, "r1", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[NULL_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Money_Risk"].adjectives[LOW_RISK] ) + ) + ) + + add_system_rule(system, "r1a", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[UNACCEPTABLE_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Money_Risk"].adjectives[UNACCEPTABLE_RISK] ) + ) + ) + + #RULE 3 : BINARY + add_system_rule(system, "r3", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[AVERAGE_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Binary_Risk"].adjectives[AVERAGE_RISK] ) + ) + ) + + add_system_rule(system, "r3a", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[HIGH_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Binary_Risk"].adjectives[HIGH_RISK] ) + ) + ) + + add_system_rule(system, "r3b", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[UNACCEPTABLE_MALWARE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Binary_Risk"].adjectives[UNACCEPTABLE_RISK] ) + ) + ) + + # PRIVACY + INTERNET + add_system_rule(system, "r5", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[HIGH_MALWARE_RISK]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Privacy_Risk"].adjectives[LOW_RISK] ), + fuzzy.operator.Input.Input( system.variables["input_Internet_Risk"].adjectives[HIGH_RISK] ) ) + ) + ) + add_system_rule(system, "r5a", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[UNACCEPTABLE_MALWARE_RISK]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Privacy_Risk"].adjectives[HIGH_RISK] ), + fuzzy.operator.Input.Input( system.variables["input_Internet_Risk"].adjectives[HIGH_RISK] ) ) + ) + ) + + add_system_rule(system, "r6", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[HIGH_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Dangerous_Risk"].adjectives[HIGH_RISK] ) + ) + ) + + add_system_rule(system, "r6a", fuzzy.Rule.Rule( + adjective=[system.variables["output_malware_risk"].adjectives[UNACCEPTABLE_RISK]], + operator=fuzzy.operator.Input.Input( system.variables["input_Dangerous_Risk"].adjectives[UNACCEPTABLE_RISK] ) + ) + ) + + + return system + + +PERFECT_SCORE = "perfect" +HIGH_SCORE = "high" +AVERAGE_SCORE = "average" +LOW_SCORE = "low" +NULL_METHOD_SCORE = "null" +AVERAGE_METHOD_SCORE = "average" +HIGH_METHOD_SCORE = "high" +PERFECT_METHOD_SCORE = "perfect" + +def create_system_method_score() : + try : + import fuzzy + except ImportError : + error("please install pyfuzzy to use this module !") + + import fuzzy.System + import fuzzy.InputVariable + import fuzzy.fuzzify.Plain + import fuzzy.OutputVariable + import fuzzy.defuzzify.COGS + import fuzzy.set.Polygon + import fuzzy.set.Singleton + import fuzzy.set.Triangle + import fuzzy.Adjective + import fuzzy.operator.Input + import fuzzy.operator.Compound + import fuzzy.norm.Min + import fuzzy.norm.Max + import fuzzy.Rule + + system = fuzzy.System.System() + + input_Length_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Match_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_AndroidEntropy_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_JavaEntropy_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Permissions_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Similarity_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + + # Input variables + + # Length + system.variables["input_Length_MS"] = input_Length_MS + input_Length_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (50.0, 1.0), (100.0, 0.0)]) ) + input_Length_MS.adjectives[AVERAGE_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(50.0, 0.0), (100.0, 1.0), (150.0, 1.0), (300.0, 0.0)]) ) + input_Length_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(150.0, 0.0), (200.0, 1.0), (300.0, 1.0), (400.0, 0.0)]) ) + input_Length_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(350.0, 0.0), (400.0, 1.0), (500.0, 1.0)]) ) + + # Match + system.variables["input_Match_MS"] = input_Match_MS + input_Match_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (20.0, 1.0), (50.0, 0.0)]) ) + input_Match_MS.adjectives[AVERAGE_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(40.0, 0.0), (45.0, 1.0), (60.0, 1.0), (80.0, 0.0)]) ) + input_Match_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(75.0, 0.0), (90.0, 1.0), (98.0, 1.0), (99.0, 0.0)]) ) + input_Match_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(98.0, 0.0), (100.0, 1.0)]) ) + #input_Match_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Singleton.Singleton( 100.0 ) ) + + # Android Entropy + system.variables["input_AndroidEntropy_MS"] = input_AndroidEntropy_MS + input_AndroidEntropy_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (4.0, 0.0)]) ) + input_AndroidEntropy_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (30.0, 1.0)]) ) + + # Java Entropy + system.variables["input_JavaEntropy_MS"] = input_JavaEntropy_MS + input_JavaEntropy_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (4.0, 0.0)]) ) + input_JavaEntropy_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (30.0, 1.0)]) ) + + # Permissions + system.variables["input_Permissions_MS"] = input_Permissions_MS + input_Permissions_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (3.0, 1.0), (4.0, 0.0)]) ) + input_Permissions_MS.adjectives[AVERAGE_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (8.0, 1.0), (9.0, 0.0)]) ) + input_Permissions_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(8.0, 0.0), (10.0, 1.0), (12.0, 1.0), (13.0, 0.0)]) ) + input_Permissions_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(12.0, 0.0), (13.0, 1.0), (20.0, 1.0)]) ) + + # Similarity Match + system.variables["input_Similarity_MS"] = input_Similarity_MS + input_Similarity_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (0.1, 1.0), (0.3, 0.0)]) ) + input_Similarity_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.3, 0.0), (0.35, 1.0), (0.4, 1.0)]) ) + + + # Output variables + output_method_score = fuzzy.OutputVariable.OutputVariable( + defuzzify=fuzzy.defuzzify.COGS.COGS(), + description="method score", + min=0.0,max=100.0, + ) + output_method_score.adjectives[NULL_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(0.0)) + output_method_score.adjectives[AVERAGE_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(50.0)) + output_method_score.adjectives[HIGH_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(80.0)) + output_method_score.adjectives[PERFECT_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(100.0)) + + system.variables["output_method_score"] = output_method_score + + add_system_rule(system, "android entropy null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_AndroidEntropy_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "java entropy null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_JavaEntropy_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "permissions null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "permissions average", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[AVERAGE_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[AVERAGE_SCORE] )) + ) + + add_system_rule(system, "permissions high", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[HIGH_SCORE] )) + ) + + add_system_rule(system, "permissions perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[PERFECT_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[PERFECT_SCORE] )) + ) + + add_system_rule(system, "similarity low", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Similarity_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "length match perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[PERFECT_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_Match_MS"].adjectives[PERFECT_SCORE] ) ) + ) + ) + + add_system_rule(system, "length match null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[LOW_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_Match_MS"].adjectives[PERFECT_SCORE] ) ) + ) + ) + + add_system_rule(system, "length AndroidEntropy perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_AndroidEntropy_MS"].adjectives[HIGH_SCORE] ) ) + ) + ) + + add_system_rule(system, "length JavaEntropy perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_JavaEntropy_MS"].adjectives[HIGH_SCORE] ) ) + ) + ) + + + add_system_rule(system, "length similarity perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[PERFECT_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_Similarity_MS"].adjectives[HIGH_SCORE] ), + ) + ) + ) + + add_system_rule(system, "length similarity average", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[AVERAGE_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_Similarity_MS"].adjectives[HIGH_SCORE] ), + ) + ) + ) + + return system + +def create_system_method_one_score() : + try : + import fuzzy + except ImportError : + error("please install pyfuzzy to use this module !") + + import fuzzy.System + import fuzzy.InputVariable + import fuzzy.fuzzify.Plain + import fuzzy.OutputVariable + import fuzzy.defuzzify.COGS + import fuzzy.set.Polygon + import fuzzy.set.Singleton + import fuzzy.set.Triangle + import fuzzy.Adjective + import fuzzy.operator.Input + import fuzzy.operator.Compound + import fuzzy.norm.Min + import fuzzy.norm.Max + import fuzzy.Rule + + system = fuzzy.System.System() + + input_Length_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_AndroidEntropy_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_JavaEntropy_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + input_Permissions_MS = fuzzy.InputVariable.InputVariable(fuzzify=fuzzy.fuzzify.Plain.Plain()) + + # Input variables + + # Length + system.variables["input_Length_MS"] = input_Length_MS + input_Length_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (50.0, 1.0), (100.0, 0.0)]) ) + input_Length_MS.adjectives[AVERAGE_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(50.0, 0.0), (100.0, 1.0), (150.0, 1.0), (300.0, 0.0)]) ) + input_Length_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(150.0, 0.0), (200.0, 1.0), (300.0, 1.0), (400.0, 0.0)]) ) + input_Length_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(350.0, 0.0), (400.0, 1.0), (500.0, 1.0)]) ) + + # Android Entropy + system.variables["input_AndroidEntropy_MS"] = input_AndroidEntropy_MS + input_AndroidEntropy_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (4.0, 0.0)]) ) + input_AndroidEntropy_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (30.0, 1.0)]) ) + + # Java Entropy + system.variables["input_JavaEntropy_MS"] = input_JavaEntropy_MS + input_JavaEntropy_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (2.0, 1.0), (4.0, 0.0)]) ) + input_JavaEntropy_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (30.0, 1.0)]) ) + + # Permissions + system.variables["input_Permissions_MS"] = input_Permissions_MS + input_Permissions_MS.adjectives[LOW_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(0.0, 1.0), (3.0, 1.0), (4.0, 0.0)]) ) + input_Permissions_MS.adjectives[AVERAGE_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(3.0, 0.0), (4.0, 1.0), (8.0, 1.0), (9.0, 0.0)]) ) + input_Permissions_MS.adjectives[HIGH_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(8.0, 0.0), (10.0, 1.0), (12.0, 1.0), (13.0, 0.0)]) ) + input_Permissions_MS.adjectives[PERFECT_SCORE] = fuzzy.Adjective.Adjective( fuzzy.set.Polygon.Polygon([(12.0, 0.0), (13.0, 1.0), (20.0, 1.0)]) ) + + # Output variables + output_method_score = fuzzy.OutputVariable.OutputVariable( + defuzzify=fuzzy.defuzzify.COGS.COGS(), + description="method one score", + min=0.0,max=100.0, + ) + output_method_score.adjectives[NULL_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(0.0)) + output_method_score.adjectives[AVERAGE_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(50.0)) + output_method_score.adjectives[HIGH_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(80.0)) + output_method_score.adjectives[PERFECT_METHOD_SCORE] = fuzzy.Adjective.Adjective(fuzzy.set.Singleton.Singleton(100.0)) + + system.variables["output_method_one_score"] = output_method_score + + add_system_rule(system, "android entropy null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_AndroidEntropy_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "java entropy null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_JavaEntropy_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "permissions null", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[NULL_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[LOW_SCORE] )) + ) + + add_system_rule(system, "permissions average", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[AVERAGE_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[AVERAGE_SCORE] )) + ) + + add_system_rule(system, "permissions high", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[HIGH_SCORE] )) + ) + + add_system_rule(system, "permissions perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[PERFECT_METHOD_SCORE]], + operator=fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[PERFECT_SCORE] )) + ) + + + add_system_rule(system, "length permissions perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[PERFECT_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_Permissions_MS"].adjectives[PERFECT_SCORE] ) ) + ) + ) + + add_system_rule(system, "length AndroidEntropy perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_AndroidEntropy_MS"].adjectives[HIGH_SCORE] ) ) + ) + ) + + add_system_rule(system, "length JavaEntropy perfect", fuzzy.Rule.Rule( + adjective=[system.variables["output_method_one_score"].adjectives[HIGH_METHOD_SCORE]], + operator=fuzzy.operator.Compound.Compound( + fuzzy.norm.Min.Min(), + fuzzy.operator.Input.Input( system.variables["input_Length_MS"].adjectives[PERFECT_SCORE] ), + fuzzy.operator.Input.Input( system.variables["input_JavaEntropy_MS"].adjectives[HIGH_SCORE] ) ) + ) + ) + + return system + +def export_system(system, directory) : + from fuzzy.doc.plot.gnuplot import doc + + d = doc.Doc(directory) + d.createDoc(system) + + import fuzzy.doc.structure.dot.dot + import subprocess + for name,rule in system.rules.items(): + cmd = "dot -T png -o '%s/fuzzy-Rule %s.png'" % (directory,name) + f = subprocess.Popen(cmd, shell=True, bufsize=32768, stdin=subprocess.PIPE).stdin + fuzzy.doc.structure.dot.dot.print_header(f,"XXX") + fuzzy.doc.structure.dot.dot.print_dot(rule,f,system,"") + fuzzy.doc.structure.dot.dot.print_footer(f) + cmd = "dot -T png -o '%s/fuzzy-System.png'" % directory + f = subprocess.Popen(cmd, shell=True, bufsize=32768, stdin=subprocess.PIPE).stdin + fuzzy.doc.structure.dot.dot.printDot(system,f) + + d.overscan=0 + in_vars = [name for name,var in system.variables.items() if isinstance(var,fuzzy.InputVariable.InputVariable)] + out_vars = [name for name,var in system.variables.items() if isinstance(var,fuzzy.OutputVariable.OutputVariable)] + + if len(in_vars) == 2 and not ( + isinstance(system.variables[in_vars[0]].fuzzify,fuzzy.fuzzify.Dict.Dict) + or + isinstance(system.variables[in_vars[1]].fuzzify,fuzzy.fuzzify.Dict.Dict) + ): + for out_var in out_vars: + args = [] + if isinstance(system.variables[out_var].defuzzify,fuzzy.defuzzify.Dict.Dict): + for adj in system.variables[out_var].adjectives: + d.create3DPlot_adjective(system, in_vars[0], in_vars[1], out_var, adj, {}) + else: + d.create3DPlot(system, in_vars[0], in_vars[1], out_var, {}) + +class RiskIndicator : + def __init__(self) : + self.risk_analysis_obj = [] + + def add_risk_analysis(self, obj) : + self.risk_analysis_obj.append( obj ) + + def with_apk(self, apk_file) : + if apk_file.is_valid_APK() : + d = dvm.DalvikVMFormat( apk_file.get_dex() ) + dx = analysis.uVMAnalysis( d ) + + return self.with_apk_direct(apk_file, d, dx) + return {} + + def with_apk_direct(self, apk_file, d, dx) : + res = {} + for i in self.risk_analysis_obj : + res[ i.get_name() ] = i.with_apk( apk_file, d, dx ) + return res + + def with_dex(self, dex_file) : + """ + @param dex_file : a buffer + + @rtype : return the risk of the dex file (from 0.0 to 100.0) + """ + d = dvm.DalvikVMFormat( dex_file ) + dx = analysis.uVMAnalysis( d ) + + return self.with_dex_direct(d, dx) + + def with_dex_direct(self, d, dx) : + res = {} + for i in self.risk_analysis_obj : + res[ i.get_name() ] = i.with_dex( d, dx ) + return res + +class FuzzyRisk : + """ + Calculate the risk to install a specific android application by using : + Permissions : + - dangerous + - signatureOrSystem + - signature + - normal + + - money + - internet + - sms + - call + - privacy + + API : + - DexClassLoader + + Files : + - binary file + - shared library + + note : pyfuzzy without fcl support (don't install antlr) + """ + def __init__(self) : + self.system = create_system_risk() +# export_system( SYSTEM, "./output" ) + + self.system_method_risk = create_system_method_one_score() + + def get_name(self) : + return "FuzzyRisk" + + def with_apk(self, apk_file, d, dx) : + """ + @param apk_file : an L{APK} object + + @rtype : return the risk of the apk file (from 0.0 to 100.0) + """ + risks = { DANGEROUS_RISK : 0.0, + MONEY_RISK : 0.0, + PRIVACY_RISK : 0.0, + INTERNET_RISK : 0.0, + BINARY_RISK : 0.0, + DYNAMIC_RISK : 0.0, + } + + self.__eval_risk_perm( apk_file.get_details_permissions(), risks ) + + self.__eval_risk_dyn( dx, risks ) + self.__eval_risk_bin( apk_file.get_files_types(), risks ) + + val = self.__eval_risks( risks ) + + return val + + def with_dex(self, vm, vmx) : + risks = { DANGEROUS_RISK : 0.0, + MONEY_RISK : 0.0, + PRIVACY_RISK : 0.0, + INTERNET_RISK : 0.0, + BINARY_RISK : 0.0, + DYNAMIC_RISK : 0.0, + } + + + d = {} + for i in vmx.get_permissions( [] ) : + d[ i ] = DVM_PERMISSIONS["MANIFEST_PERMISSION"][i] + self.__eval_risk_perm( d, risks ) + self.__eval_risk_dyn( vmx, risks ) + + val = self.__eval_risks( risks ) + + return val + + def test(self) : + ########################## + score_order_sign = {} + + + import sys + sys.path.append("./elsim") + from elsim.elsign.libelsign import libelsign + for method in vm.get_methods() : + if method.get_length() < 80 : + continue + + score_order_sign[ method ] = self.get_method_score( method.get_length(), + libelsign.entropy( vmx.get_method_signature(method, "L4", { "L4" : { "arguments" : ["Landroid"] } } ).get_string() ), + libelsign.entropy( vmx.get_method_signature(method, "L4", { "L4" : { "arguments" : ["Ljava"] } } ).get_string() ), + map(lambda perm : (perm, DVM_PERMISSIONS["MANIFEST_PERMISSION"][ perm ]), vmx.get_permissions_method( method )), + ) + + + for v in sorted(score_order_sign, key=lambda x : score_order_sign[x], reverse=True) : + print v.get_name(), v.get_class_name(), v.get_descriptor(), v.get_length(), score_order_sign[ v ] + + ########################## + + return val, score_order_sign + + def __eval_risk_perm(self, list_details_permissions, risks) : + for i in list_details_permissions : + permission = i + if permission.find(".") != -1 : + permission = permission.split(".")[-1] +# print permission, GENERAL_PERMISSIONS_RISK[ list_details_permissions[ i ][0] ] + + risk_type = GENERAL_PERMISSIONS_RISK[ list_details_permissions[ i ][0] ] + + risks[ DANGEROUS_RISK ] += RISK_VALUES [ risk_type ] + + try : + for j in PERMISSIONS_RISK[ permission ] : + risks[ j ] += RISK_VALUES[ j ] + except KeyError : + pass + + def __eval_risk_dyn(self, vmx, risks) : + for m, _ in vmx.tainted_packages.get_packages() : + if m.get_name() == "Ldalvik/system/DexClassLoader;" : + for path in m.get_paths() : + if path.get_access_flag() == analysis.TAINTED_PACKAGE_CREATE : + risks[ DYNAMIC_RISK ] = RISK_VALUES[ DYNAMIC_RISK ] + return + + def __eval_risk_bin(self, list_details_files, risks) : + for i in list_details_files : + if "ELF" in list_details_files[ i ] : + # shared library + if "shared" in list_details_files[ i ] : + risks[ BINARY_RISK ] += RISK_VALUES [ BINARY_RISK ] + # binary + else : + risks[ BINARY_RISK ] += RISK_VALUES [ EXPLOIT_RISK ] + + def __eval_risks(self, risks) : + output_values = {"output_malware_risk" : 0.0} + input_val = {} + input_val['input_Dangerous_Risk'] = risks[ DANGEROUS_RISK ] + input_val['input_Money_Risk'] = risks[ MONEY_RISK ] + input_val['input_Privacy_Risk'] = risks[ PRIVACY_RISK ] + input_val['input_Binary_Risk'] = risks[ BINARY_RISK ] + input_val['input_Internet_Risk'] = risks[ INTERNET_RISK ] + input_val['input_Dynamic_Risk'] = risks[ DYNAMIC_RISK ] + + #print input_val, + + self.system.calculate(input=input_val, output = output_values) + + val = output_values[ "output_malware_risk" ] + return { "VALUE" : val } + + def get_method_score(self, length, android_entropy, java_entropy, permissions) : + val_permissions = 0 + for i in permissions : + val_permissions += RISK_VALUES[ GENERAL_PERMISSIONS_RISK[ i[1][0] ] ] + + try : + for j in PERMISSIONS_RISK[ i[0] ] : + val_permissions += RISK_VALUES[ j ] + except KeyError : + pass + + print length, android_entropy, java_entropy, val_permissions + + output_values = {"output_method_one_score" : 0.0} + input_val = {} + input_val['input_Length_MS'] = length + input_val['input_AndroidEntropy_MS'] = android_entropy + input_val['input_JavaEntropy_MS'] = java_entropy + input_val['input_Permissions_MS'] = val_permissions + + self.system_method_risk.calculate(input=input_val, output = output_values) + score = output_values[ "output_method_one_score" ] + + return score + + def simulate(self, risks) : + return self.__eval_risks( risks ) + +class RedFlags : + # APK + # BINARY + # shared library + # executable + # dex + # apk + # jar + # shell script + # Perm + # SMS + # Call + # Money + # Internet + # Privacy + # Normal + # Dangerous + # Signature + # System + # DEX + # Obfuscation + def __init__(self) : + self.flags = { "APK" : { + "SHARED LIBRARIES" : 0, # presence of shared libraries (ELF) + "EXECUTABLE" : 0, # presence of executables (ELF) + "DEX" : 0, # presence of dex files + "APK" : 0, # presence of APK files + "ZIP" : 0, # presence of zip files + "SHELL_SCRIPT" : 0, # presence of shell scripts + }, + "PERM" : { + "SMS" : 0, # presence of permissions which can manipulate sms + "CALL" : 0, # presence of permissions which can perform a call + "GPS" : 0, # presence of permissions which can manipulate your location + "MONEY" : 0, # presence of permissions which can result to a payement + "INTERNET" : 0, # presence of permissions which can access to internet + "PRIVACY" : 0, # presence of permissions which can access to private information + "NORMAL" : 0, # "The default value. A lower-risk permission that gives requesting applications access to isolated application-level features, with minimal risk to other applications, the system, or the user" + "DANGEROUS" : 0, # "A higher-risk permission that would give a requesting application access to private user data or control over the device that can negatively impact the user" + "SIGNATURE" : 0, # "A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission" + "SIGNATUREORSYSTEM" : 0, # "A permission that the system grants only to applications that are in the Android system image or that are signed with the same certificates as those in the system image" + }, + "DEX" : { + "REFLECTION" : 0, # presence of the reflection API + "NATIVE" : 0, # presence of loading a shared library + "DYNAMIC" : 0, # presence of loading dynamically a new dex file + "CRYPTO" : 0, # presence of crypto functions + }, + #"OBFUSCATION" : { # presence of obfuscation techniques + #} + } + + self.flags_dex = { "DEX" : self.flags["DEX"] } + + def get_name(self) : + return "RedFlags" + + def with_apk(self, apk_file, d, dx) : + flags = copy.deepcopy( self.flags ) + + self.analyze_apk( apk_file, flags["APK"] ) + self.analyze_axml( apk_file, flags["PERM"] ) + self.analyze_dex( d, dx, flags["DEX"] ) + + return flags + + def with_dex(self, d, dx) : + flags = self.flags_dex.copy() + + self.analyze_dex( d, dx, flags["DEX"] ) + + return flags + + def analyze_apk(self, a, flags) : + elf_executable = [ re.compile("ELF.+executable.+"), "EXECUTABLE" ] + lib_elf = [ re.compile("ELF.+shared object"), "SHARED LIBRARIES" ] + apk_file = [ re.compile("Android application package file"), "APK" ] + dex_file = [ re.compile("Dalvik dex file version 035"), "DEX", re.compile("^classes.dex$") ] + script_file = [ re.compile("script text executable"), "SHELL_SCRIPT" ] + zip_file = [ re.compile("^Zip archive data.+"), "ZIP" ] + + regexp = [ elf_executable, lib_elf, apk_file, dex_file, script_file, zip_file ] + + files_types = a.get_files_types() + for i in files_types : + for j in regexp : + if j[0].search( files_types[i] ) != None : + if len(j) < 3 : + flags[j[1]] += 1 + else : + if j[2].search( i ) == None : + flags[j[1]] += 1 + + def analyze_axml(self, a, flags) : + perms = { + "SEND_SMS" : [ "MONEY", "SMS" ], + "SEND_SMS_NO_CONFIRMATION" : [ "MONEY", "SMS"], + "READ_SMS" : [ "SMS", "PRIVACY" ], + "WRITE_SMS" : [ "MONEY", "SMS" ], + "RECEIVE_SMS" : [ "SMS", "PRIVACY" ], + "RECEIVE_MMS" : [ "SMS", "PRIVACY" ], + + "PHONE_CALL" : [ "MONEY", "CALL" ], + "PROCESS_OUTGOING_CALLS" : [ "MONEY", "CALL" ], + "CALL_PRIVILEGED" : [ "MONEY", "CALL" ], + + "INTERNET" : [ "INTERNET" ], + + "READ_PHONE_STATE" : [ "PRIVACY" ], + + "READ_CONTACTS" : [ "PRIVACY" ], + "WRITE_CONTACTS" : [ "PRIVACY" ], + + "READ_HISTORY_BOOKMARKS" : [ "PRIVACY" ], + "WRITE_HISTORY_BOOKMARKS" : [ "PRIVACY" ], + + "READ_PROFILE" : [ "PRIVACY" ], + "WRITE_PROFILE" : [ "PRIVACY" ], + + "READ_SOCIAL_STREAM" : [ "PRIVACY" ], + "WRITE_SOCIAL_STREAM" : [ "PRIVACY" ], + + "READ_CALENDAR" : [ "PRIVACY" ], + "WRITE_CALENDAR" : [ "PRIVACY" ], + + "READ_USER_DICTIONARY" : [ "PRIVACY" ], + "WRITE_USER_DICTIONARY" : [ "PRIVACY" ], + + "SET_ALARM" : [ "PRIVACY" ], + + "ADD_VOICEMAIL" : [ "PRIVACY" ], + + "GET_ACCOUNTS" : [ "PRIVACY" ], + "MANAGE_ACCOUNTS" : [ "PRIVACY" ], + + "RECORD_AUDIO" : [ "PRIVACY" ], + "CAMERA" : [ "PRIVACY" ], + + + "ACCESS_FINE_LOCATION" : [ "PRIVACY", "GPS" ], + "ACCESS_COARSE_LOCATION" : [ "PRIVACY", "GPS" ], + "ACCESS_LOCATION_EXTRA_COMMANS" : [ "GPS"], + "INSTALL_LOCATION_PROVIDER" : [ "GPS" ], + } + + for i in a.get_permissions() : + perm = i.split(".")[-1] + + try : + flags[ DVM_PERMISSIONS["MANIFEST_PERMISSION"][perm][0].upper() ] += 1 + + for j in perms : + if j == perm : + for k in perms[j] : + flags[k] += 1 + except : + debug("Unknown permission %s" % perm) + + def analyze_dex(self, d, dx, flags) : + flags["REFLECTION"] = int( analysis.is_reflection_code(dx) ) + flags["NATIVE"] = int( analysis.is_native_code(dx) ) + flags["DYNAMIC"] = int( analysis.is_dyn_code(dx) ) + flags["CRYPTO"] = int( analysis.is_crypto_code(dx) ) + +class MethodScore : + def __init__(self, length, matches, android_entropy, java_entropy, permissions, similarity_matches) : + self.system = create_system_method_score() + #export_system( self.system, "./output" ) + + + val_permissions = 0 + for i in permissions : + val_permissions += RISK_VALUES[ GENERAL_PERMISSIONS_RISK[ i[1][0] ] ] + + try : + for j in PERMISSIONS_RISK[ i[0] ] : + val_permissions += RISK_VALUES[ j ] + except KeyError : + pass + + print length, matches, android_entropy, java_entropy, similarity_matches, val_permissions + + output_values = {"output_method_score" : 0.0} + input_val = {} + input_val['input_Length_MS'] = length + input_val['input_Match_MS'] = matches + input_val['input_AndroidEntropy_MS'] = android_entropy + input_val['input_JavaEntropy_MS'] = java_entropy + input_val['input_Permissions_MS'] = val_permissions + input_val['input_Similarity_MS'] = similarity_matches + + self.system.calculate(input=input_val, output = output_values) + self.score = output_values[ "output_method_score" ] + + def get_score(self) : + return self.score diff --git a/androguard/core/analysis/sign.py b/androguard/core/analysis/sign.py new file mode 100644 index 00000000..f47f3aa7 --- /dev/null +++ b/androguard/core/analysis/sign.py @@ -0,0 +1,376 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from androguard.core.analysis.analysis import TAINTED_PACKAGE_CREATE, TAINTED_PACKAGE_CALL +from androguard.core.bytecodes import dvm + +TAINTED_PACKAGE_INTERNAL_CALL = 2 +FIELD_ACCESS = { "R" : 0, "W" : 1 } +PACKAGE_ACCESS = { TAINTED_PACKAGE_CREATE : 0, TAINTED_PACKAGE_CALL : 1, TAINTED_PACKAGE_INTERNAL_CALL : 2 } + +class Sign : + def __init__(self) : + self.levels = {} + self.hlevels = [] + + def add(self, level, value) : + self.levels[ level ] = value + self.hlevels.append( level ) + + def get_level(self, l) : + return self.levels[ "L%d" % l ] + + def get_string(self) : + buff = "" + for i in self.hlevels : + buff += self.levels[ i ] + return buff + + def get_list(self) : + return self.levels[ "sequencebb" ] + +class Signature : + def __init__(self, vmx) : + self.vmx = vmx + self.tainted_packages = self.vmx.get_tainted_packages() + self.tainted_variables = self.vmx.get_tainted_variables() + + self._cached_signatures = {} + self._cached_fields = {} + self._cached_packages = {} + self._global_cached = {} + + self.levels = { + # Classical method signature with basic blocks, strings, fields, packages + "L0" : { + 0 : ( "_get_strings_a", "_get_fields_a", "_get_packages_a" ), + 1 : ( "_get_strings_pa", "_get_fields_a", "_get_packages_a" ), + 2 : ( "_get_strings_a", "_get_fields_a", "_get_packages_pa_1" ), + 3 : ( "_get_strings_a", "_get_fields_a", "_get_packages_pa_2" ), + }, + + # strings + "L1" : [ "_get_strings_a1" ], + + # exceptions + "L2" : [ "_get_exceptions" ], + + # fill array data + "L3" : [ "_get_fill_array_data" ], + } + + self.classes_names = None + self._init_caches() + + def _get_method_info(self, m) : + m1 = m.get_method() + return "%s-%s-%s" % (m1.get_class_name(), m1.get_name(), m1.get_descriptor()) + + + def _get_sequence_bb(self, analysis_method) : + l = [] + + for i in analysis_method.basic_blocks.get() : + buff = "" + instructions = [j for j in i.get_instructions()] + if len(instructions) > 5 : + for ins in instructions : + buff += ins.get_name() + if buff != "" : + l.append( buff ) + + return l + + def _get_hex(self, analysis_method) : + code = analysis_method.get_method().get_code() + if code == None : + return "" + + buff = "" + for i in code.get_bc().get_instructions() : + buff += dvm.clean_name_instruction( i ) + buff += dvm.static_operand_instruction( i ) + + return buff + + def _get_bb(self, analysis_method, functions, options) : + bbs = [] + for b in analysis_method.basic_blocks.get() : + l = [] + l.append( (b.start, "B") ) + l.append( (b.start, "[") ) + + internal = [] + + op_value = b.get_last().get_op_value() + + # return + if op_value >= 0x0e and op_value <= 0x11 : + internal.append( (b.end-1, "R") ) + + # if + elif op_value >= 0x32 and op_value <= 0x3d : + internal.append( (b.end-1, "I") ) + + # goto + elif op_value >= 0x28 and op_value <= 0x2a : + internal.append( (b.end-1, "G") ) + + # sparse or packed switch + elif op_value >= 0x2b and op_value <= 0x2c : + internal.append( (b.end-1, "G") ) + + + for f in functions : + try : + internal.extend( getattr( self, f )( analysis_method, options ) ) + except TypeError : + internal.extend( getattr( self, f )( analysis_method ) ) + + internal.sort() + + for i in internal : + if i[0] >= b.start and i[0] < b.end : + l.append( i ) + + del internal + + l.append( (b.end, "]") ) + + bbs.append( ''.join(i[1] for i in l) ) + return bbs + + def _init_caches(self) : + if self._cached_fields == {} : + for f_t, f in self.tainted_variables.get_fields() : + self._cached_fields[ f ] = f_t.get_paths_length() + n = 0 + for f in sorted( self._cached_fields ) : + self._cached_fields[ f ] = n + n += 1 + + if self._cached_packages == {} : + for m_t, m in self.tainted_packages.get_packages() : + self._cached_packages[ m ] = m_t.get_paths_length() + n = 0 + for m in sorted( self._cached_packages ) : + self._cached_packages[ m ] = n + n += 1 + + def _get_fill_array_data(self, analysis_method) : + buff = "" + for b in analysis_method.basic_blocks.get() : + for i in b.get_instructions() : + if i.get_name() == "FILL-ARRAY-DATA" : + buff_tmp = i.get_operands() + for j in range(0, len(buff_tmp)) : + buff += "\\x%02x" % ord( buff_tmp[j] ) + return buff + + def _get_exceptions(self, analysis_method) : + buff = "" + + method = analysis_method.get_method() + code = method.get_code() + if code == None or code.get_tries_size() <= 0 : + return buff + + handler_catch_list = code.get_handlers() + + for handler_catch in handler_catch_list.get_list() : + for handler in handler_catch.get_handlers() : + buff += analysis_method.get_vm().get_cm_type( handler.get_type_idx() ) + return buff + + def _get_strings_a1(self, analysis_method) : + buff = "" + + strings_method = self.tainted_variables.get_strings_by_method( analysis_method.get_method() ) + for s in strings_method : + for path in strings_method[s] : + buff += s.replace('\n', ' ') + return buff + + def _get_strings_pa(self, analysis_method) : + l = [] + + strings_method = self.tainted_variables.get_strings_by_method( analysis_method.get_method() ) + for s in strings_method : + for path in strings_method[s] : + l.append( ( path[1], "S%d" % len(s) ) ) + return l + + + def _get_strings_a(self, analysis_method) : + key = "SA-%s" % self._get_method_info(analysis_method) + if key in self._global_cached : + return self._global_cached[ key ] + + l = [] + + strings_method = self.tainted_variables.get_strings_by_method( analysis_method.get_method() ) + for s in strings_method : + for path in strings_method[s] : + l.append( ( path[1], "S") ) + + self._global_cached[ key ] = l + return l + + def _get_fields_a(self, analysis_method) : + key = "FA-%s" % self._get_method_info(analysis_method) + if key in self._global_cached : + return self._global_cached[ key ] + + fields_method = self.tainted_variables.get_fields_by_method( analysis_method.get_method() ) + l = [] + + for f in fields_method : + for path in fields_method[ f ] : + l.append( (path[1], "F%d" % FIELD_ACCESS[ path[0] ]) ) + + self._global_cached[ key ] = l + return l + + def _get_packages_a(self, analysis_method) : + packages_method = self.tainted_packages.get_packages_by_method( analysis_method.get_method() ) + l = [] + + for m in packages_method : + for path in packages_method[ m ] : + l.append( (path.get_idx(), "P%s" % (PACKAGE_ACCESS[ path.get_access_flag() ]) ) ) + return l + + def _get_packages(self, analysis_method, include_packages) : + l = self._get_packages_pa_1( analysis_method, include_packages ) + return "".join([ i[1] for i in l ]) + + def _get_packages_pa_1(self, analysis_method, include_packages) : + key = "PA1-%s-%s" % (self._get_method_info(analysis_method), include_packages) + if key in self._global_cached : + return self._global_cached[ key ] + + packages_method = self.tainted_packages.get_packages_by_method( analysis_method.get_method() ) + if self.classes_names == None : + self.classes_names = analysis_method.get_vm().get_classes_names() + + l = [] + + + for m in packages_method : + for path in packages_method[ m ] : + present = False + for i in include_packages : + if m.find(i) == 0 : + present = True + break + + if path.get_access_flag() == 1 : + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( analysis_method.get_vm().get_class_manager() ) + + if dst_class_name in self.classes_names : + l.append( (path.get_idx(), "P%s" % (PACKAGE_ACCESS[ 2 ]) ) ) + else : + if present == True : + l.append( (path.get_idx(), "P%s{%s%s%s}" % (PACKAGE_ACCESS[ path.get_access_flag() ], dst_class_name, dst_method_name, dst_descriptor ) ) ) + else : + l.append( (path.get_idx(), "P%s" % (PACKAGE_ACCESS[ path.get_access_flag() ]) ) ) + else : + if present == True : + l.append( (path.get_idx(), "P%s{%s}" % (PACKAGE_ACCESS[ path.get_access_flag() ], m) ) ) + else : + l.append( (path.get_idx(), "P%s" % (PACKAGE_ACCESS[ path.get_access_flag() ]) ) ) + + self._global_cached[ key ] = l + return l + + def _get_packages_pa_2(self, analysis_method, include_packages) : + packages_method = self.tainted_packages.get_packages_by_method( analysis_method.get_method() ) + + l = [] + + for m in packages_method : + for path in packages_method[ m ] : + present = False + for i in include_packages : + if m.find(i) == 0 : + present = True + break + + if present == True : + l.append( (path.get_idx(), "P%s" % (PACKAGE_ACCESS[ path.get_access_flag() ]) ) ) + continue + + if path.get_access_flag() == 1 : + dst_class_name, dst_method_name, dst_descriptor = path.get_dst( analysis_method.get_vm().get_class_manager() ) + l.append( (path.get_idx(), "P%s{%s%s%s}" % (PACKAGE_ACCESS[ path.get_access_flag() ], dst_class_name, dst_method_name, dst_descriptor ) ) ) + else : + l.append( (path.get_idx(), "P%s{%s}" % (PACKAGE_ACCESS[ path.get_access_flag() ], m) ) ) + + return l + + def get_method(self, analysis_method, signature_type, signature_arguments={}) : + key = "%s-%s-%s" % (self._get_method_info(analysis_method), signature_type, signature_arguments) + + if key in self._cached_signatures : + return self._cached_signatures[ key ] + + s = Sign() + + #print signature_type, signature_arguments + for i in signature_type.split(":") : + # print i, signature_arguments[ i ] + if i == "L0" : + _type = self.levels[ i ][ signature_arguments[ i ][ "type" ] ] + try : + _arguments = signature_arguments[ i ][ "arguments" ] + except KeyError : + _arguments = [] + + value = self._get_bb( analysis_method, _type, _arguments ) + s.add( i, ''.join(z for z in value) ) + + elif i == "L4" : + try : + _arguments = signature_arguments[ i ][ "arguments" ] + except KeyError : + _arguments = [] + + value = self._get_packages( analysis_method, _arguments ) + s.add( i , value ) + + elif i == "hex" : + value = self._get_hex( analysis_method ) + s.add( i, value ) + + elif i == "sequencebb" : + _type = ('_get_strings_a', '_get_fields_a', '_get_packages_pa_1') + _arguments = ['Landroid', 'Ljava'] + + #value = self._get_bb( analysis_method, _type, _arguments ) + #s.add( i, value ) + + value = self._get_sequence_bb( analysis_method ) + s.add( i, value ) + + else : + for f in self.levels[ i ] : + value = getattr( self, f )( analysis_method ) + s.add( i, value ) + + self._cached_signatures[ key ] = s + return s diff --git a/androguard/core/androconf.py b/androguard/core/androconf.py new file mode 100644 index 00000000..c810dfad --- /dev/null +++ b/androguard/core/androconf.py @@ -0,0 +1,359 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import logging +import types +import random +import string + +ANDROGUARD_VERSION = "2.0" + + +def is_ascii_problem(s): + try: + s.decode("ascii") + return False + except UnicodeDecodeError: + return True + + +class Color: + Normal = "\033[0m" + Black = "\033[30m" + Red = "\033[31m" + Green = "\033[32m" + Yellow = "\033[33m" + Blue = "\033[34m" + Purple = "\033[35m" + Cyan = "\033[36m" + Grey = "\033[37m" + Bold = "\033[1m" + +CONF = { + "BIN_DED": "ded.sh", + "PATH_DED": "./decompiler/ded/", + "PATH_DEX2JAR": "./decompiler/dex2jar/", + "BIN_DEX2JAR": "dex2jar.sh", + "PATH_JAD": "./decompiler/jad/", + "BIN_JAD": "jad", + "BIN_WINEJAD": "jad.exe", + "PATH_FERNFLOWER": "./decompiler/fernflower/", + "BIN_FERNFLOWER": "fernflower.jar", + "OPTIONS_FERNFLOWER": {"dgs": '1', "asc": '1'}, + "PRETTY_SHOW": 1, + + "TMP_DIRECTORY": "/tmp/", + + # Full python or mix python/c++ (native) + #"ENGINE" : "automatic", + "ENGINE": "python", + + "RECODE_ASCII_STRING": False, + "RECODE_ASCII_STRING_METH": None, + + "DEOBFUSCATED_STRING": True, +# "DEOBFUSCATED_STRING_METH" : get_deobfuscated_string, + + "PATH_JARSIGNER": "jarsigner", + + "COLORS": { + "OFFSET": Color.Yellow, + "OFFSET_ADDR": Color.Green, + "INSTRUCTION_NAME": Color.Yellow, + "BRANCH_FALSE": Color.Red, + "BRANCH_TRUE": Color.Green, + "BRANCH": Color.Blue, + "EXCEPTION": Color.Cyan, + "BB": Color.Purple, + "NOTE": Color.Red, + "NORMAL": Color.Normal, + + "OUTPUT": { + "normal": Color.Normal, + "registers": Color.Normal, + "literal": Color.Green, + "offset": Color.Purple, + "raw": Color.Red, + "string": Color.Red, + "meth": Color.Cyan, + "type": Color.Blue, + "field": Color.Green, + } + }, + + "PRINT_FCT": sys.stdout.write, + "LAZY_ANALYSIS": False, + "MAGIC_PATH_FILE": None, +} + + +def default_colors(obj): + CONF["COLORS"]["OFFSET"] = obj.Yellow + CONF["COLORS"]["OFFSET_ADDR"] = obj.Green + CONF["COLORS"]["INSTRUCTION_NAME"] = obj.Yellow + CONF["COLORS"]["BRANCH_FALSE"] = obj.Red + CONF["COLORS"]["BRANCH_TRUE"] = obj.Green + CONF["COLORS"]["BRANCH"] = obj.Blue + CONF["COLORS"]["EXCEPTION"] = obj.Cyan + CONF["COLORS"]["BB"] = obj.Purple + CONF["COLORS"]["NOTE"] = obj.Red + CONF["COLORS"]["NORMAL"] = obj.Normal + + CONF["COLORS"]["OUTPUT"]["normal"] = obj.Normal + CONF["COLORS"]["OUTPUT"]["registers"] = obj.Normal + CONF["COLORS"]["OUTPUT"]["literal"] = obj.Green + CONF["COLORS"]["OUTPUT"]["offset"] = obj.Purple + CONF["COLORS"]["OUTPUT"]["raw"] = obj.Red + CONF["COLORS"]["OUTPUT"]["string"] = obj.Red + CONF["COLORS"]["OUTPUT"]["meth"] = obj.Cyan + CONF["COLORS"]["OUTPUT"]["type"] = obj.Blue + CONF["COLORS"]["OUTPUT"]["field"] = obj.Green + + +def disable_colors(): + """ Disable colors from the output (color = normal)""" + for i in CONF["COLORS"]: + if isinstance(CONF["COLORS"][i], dict): + for j in CONF["COLORS"][i]: + CONF["COLORS"][i][j] = Color.normal + else: + CONF["COLORS"][i] = Color.normal + + +def remove_colors(): + """ Remove colors from the output (no escape sequences)""" + for i in CONF["COLORS"]: + if isinstance(CONF["COLORS"][i], dict): + for j in CONF["COLORS"][i]: + CONF["COLORS"][i][j] = "" + else: + CONF["COLORS"][i] = "" + + +def enable_colors(colors): + for i in colors: + CONF["COLORS"][i] = colors[i] + + +def save_colors(): + c = {} + for i in CONF["COLORS"]: + if isinstance(CONF["COLORS"][i], dict): + c[i] = {} + for j in CONF["COLORS"][i]: + c[i][j] = CONF["COLORS"][i][j] + else: + c[i] = CONF["COLORS"][i] + return c + + +def long2int(l): + if l > 0x7fffffff: + l = (0x7fffffff & l) - 0x80000000 + return l + + +def long2str(l): + """Convert an integer to a string.""" + if type(l) not in (types.IntType, types.LongType): + raise ValueError, 'the input must be an integer' + + if l < 0: + raise ValueError, 'the input must be greater than 0' + s = '' + while l: + s = s + chr(l & 255L) + l >>= 8 + + return s + +def str2long(s): + """Convert a string to a long integer.""" + if type(s) not in (types.StringType, types.UnicodeType): + raise ValueError, 'the input must be a string' + + l = 0L + for i in s: + l <<= 8 + l |= ord(i) + + return l + +def random_string() : + return random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] ) + +def is_android(filename) : + """Return the type of the file + + @param filename : the filename + @rtype : "APK", "DEX", "ELF", None + """ + if not filename: + return None + + fd = open( filename, "r") + val = None + + f_bytes = fd.read(7) + + val = is_android_raw( f_bytes ) + + fd.close() + return val + +def is_android_raw(raw): + val = None + f_bytes = raw[:7] + + if f_bytes[0:2] == "PK": + val = "APK" + elif f_bytes[0:3] == "dex": + val = "DEX" + elif f_bytes[0:3] == "dey": + val = "DEY" + elif f_bytes[0:7] == "\x7fELF\x01\x01\x01": + val = "ELF" + elif f_bytes[0:4] == "\x03\x00\x08\x00": + val = "AXML" + elif f_bytes[0:4] == "\x02\x00\x0C\x00": + val = "ARSC" + + return val + +def is_valid_android_raw(raw) : + return raw.find("classes.dex") != -1 + +# from scapy +log_andro = logging.getLogger("andro") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) +log_andro.addHandler(console_handler) +log_runtime = logging.getLogger("andro.runtime") # logs at runtime +log_interactive = logging.getLogger("andro.interactive") # logs in interactive functions +log_loading = logging.getLogger("andro.loading") # logs when loading andro + +def set_lazy() : + CONF["LAZY_ANALYSIS"] = True + +def set_debug() : + log_andro.setLevel( logging.DEBUG ) + +def set_info() : + log_andro.setLevel(logging.INFO) + +def get_debug() : + return log_andro.getEffectiveLevel() == logging.DEBUG + +def warning(x): + log_runtime.warning(x) + import traceback + traceback.print_exc() + +def error(x) : + log_runtime.error(x) + raise() + +def debug(x): + log_runtime.debug(x) + +def info(x): + log_runtime.info(x) + +def set_options(key, value) : + CONF[ key ] = value + +def save_to_disk(buff, output) : + fd = open(output, "w") + fd.write(buff) + fd.close() + +def rrmdir( directory ): + for root, dirs, files in os.walk(directory, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + os.rmdir( directory ) + + +def make_color_tuple( color ): + """ + turn something like "#000000" into 0,0,0 + or "#FFFFFF into "255,255,255" + """ + R = color[1:3] + G = color[3:5] + B = color[5:7] + + R = int(R, 16) + G = int(G, 16) + B = int(B, 16) + + return R,G,B + +def interpolate_tuple( startcolor, goalcolor, steps ): + """ + Take two RGB color sets and mix them over a specified number of steps. Return the list + """ + # white + + R = startcolor[0] + G = startcolor[1] + B = startcolor[2] + + targetR = goalcolor[0] + targetG = goalcolor[1] + targetB = goalcolor[2] + + DiffR = targetR - R + DiffG = targetG - G + DiffB = targetB - B + + buffer = [] + + for i in range(0, steps +1): + iR = R + (DiffR * i / steps) + iG = G + (DiffG * i / steps) + iB = B + (DiffB * i / steps) + + hR = string.replace(hex(iR), "0x", "") + hG = string.replace(hex(iG), "0x", "") + hB = string.replace(hex(iB), "0x", "") + + if len(hR) == 1: + hR = "0" + hR + if len(hB) == 1: + hB = "0" + hB + + if len(hG) == 1: + hG = "0" + hG + + color = string.upper("#"+hR+hG+hB) + buffer.append(color) + + return buffer + +def color_range( startcolor, goalcolor, steps ): + """ + wrapper for interpolate_tuple that accepts colors as html ("#CCCCC" and such) + """ + start_tuple = make_color_tuple(startcolor) + goal_tuple = make_color_tuple(goalcolor) + + return interpolate_tuple(start_tuple, goal_tuple, steps) diff --git a/androguard/core/androgen.py b/androguard/core/androgen.py new file mode 100644 index 00000000..437a849e --- /dev/null +++ b/androguard/core/androgen.py @@ -0,0 +1,264 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from androguard.core import androconf +from androguard.core.bytecodes import jvm +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.analysis import analysis +from androguard.core.analysis import ganalysis + +class BC : + def __init__(self, bc) : + self.__bc = bc + + def get_vm(self) : + return self.__bc + + def get_analysis(self) : + return self.__a + + def analyze(self) : + self.__a = analysis.uVMAnalysis( self.__bc ) + self.__bc.set_vmanalysis( self.__a ) + + self.__g = ganalysis.GVMAnalysis( self.__a, None ) + + self.__bc.set_gvmanalysis( self.__g ) + + self.__bc.create_xref() + self.__bc.create_dref() + + def _get(self, val, name) : + l = [] + r = getattr(self.__bc, val)(name) + for i in r : + l.append( i ) + return l + + def _gets(self, val) : + l = [] + r = getattr(self.__bc, val)() + for i in r : + l.append( i ) + return l + + def gets(self, name) : + return self._gets("get_" + name) + + def get(self, val, name) : + return self._get("get_" + val, name) + + def insert_direct_method(self, name, method) : + return self.__bc.insert_direct_method(name, method) + + def insert_craft_method(self, name, proto, codes) : + return self.__bc.insert_craft_method( name, proto, codes) + + def show(self) : + self.__bc.show() + + def pretty_show(self) : + self.__bc.pretty_show() + + def save(self) : + return self.__bc.save() + + def __getattr__(self, value) : + return getattr(self.__bc, value) + +class Androguard: + """Androguard is the main object to abstract and manage differents formats + + @param files : a list of filenames (filename must be terminated by .class or .dex) + @param raw : specify if the filename is in fact a raw buffer (default : False) #FIXME + """ + def __init__(self, files, raw=False) : + self.__files = files + + self.__orig_raw = {} + for i in self.__files : + self.__orig_raw[ i ] = open(i, "rb").read() + + self.__bc = [] + self._analyze() + + def _iterFlatten(self, root): + if isinstance(root, (list, tuple)): + for element in root : + for e in self._iterFlatten(element) : + yield e + else: + yield root + + def _analyze(self) : + for i in self.__files : + ret_type = androconf.is_android( i ) + if ret_type == "APK" : + x = apk.APK( i ) + bc = dvm.DalvikVMFormat( x.get_dex() ) + elif ret_type == "DEX" : + bc = dvm.DalvikVMFormat( open(i, "rb").read() ) + elif ret_type == "DEY" : + bc = dvm.DalvikOdexVMFormat( open(i, "rb").read() ) + elif ret_type == "ELF" : + from androguard.core.binaries import elf + bc = elf.ELF( open(i, "rb").read() ) + else : + raise( "Unknown format" ) + + if isinstance(bc, list) : + for j in bc : + self.__bc.append( (j[0], BC( jvm.JVMFormat(j[1]) ) ) ) + else : + self.__bc.append( (i, BC( bc )) ) + + def ianalyze(self) : + for i in self.get_bc() : + i[1].analyze() + + def get_class(self, class_name) : + for _, bc in self.__bc : + if bc.get_class(class_name) == True : + return bc + return None + + def get_raw(self) : + """Return raw format of all file""" + l = [] + for _, bc in self.__bc : + l.append( bc._get_raw() ) + return l + + def get_orig_raw(self) : + return self.__orig_raw + + def get_method_descriptor(self, class_name, method_name, descriptor) : + """ + Return the specific method + + @param class_name : the class name of the method + @param method_name : the name of the method + @param descriptor : the descriptor of the method + """ + for file_name, bc in self.__bc : + x = bc.get_method_descriptor( class_name, method_name, descriptor ) + if x != None : + return x, bc + return None, None + + def get_field_descriptor(self, class_name, field_name, descriptor) : + """ + Return the specific field + + @param class_name : the class name of the field + @param field_name : the name of the field + @param descriptor : the descriptor of the field + """ + for file_name, bc in self.__bc : + x = bc.get_field_descriptor( class_name, field_name, descriptor ) + if x != None : + return x, bc + return None, None + + def get(self, name, val) : + """ + Return the specific value for all files + + @param name : + @param val : + """ + if name == "file" : + for file_name, bc in self.__bc : + if file_name == val : + return bc + + return None + else : + l = [] + for file_name, bc in self.__bc : + l.append( bc.get( name, val ) ) + + return list( self._iterFlatten(l) ) + + def gets(self, name) : + """ + Return the specific value for all files + + @param name : + """ + l = [] + for file_name, bc in self.__bc : + l.append( bc.gets( name ) ) + + return list( self._iterFlatten(l) ) + + def get_vms(self) : + return [ i[1].get_vm() for i in self.__bc ] + + def get_bc(self) : + return self.__bc + + def show(self) : + """ + Display all files + """ + for _, bc in self.__bc : + bc.show() + + def pretty_show(self) : + """ + Display all files + """ + for _, bc in self.__bc : + bc.pretty_show() + +class AndroguardS : + """AndroguardS is the main object to abstract and manage differents formats but only per filename. In fact this class is just a wrapper to the main class Androguard + + @param filename : the filename to use (filename must be terminated by .class or .dex) + @param raw : specify if the filename is a raw buffer (default : False) + """ + def __init__(self, filename, raw=False) : + self.__filename = filename + self.__orig_a = Androguard( [ filename ], raw ) + self.__a = self.__orig_a.get( "file", filename ) + + def get_orig_raw(self) : + return self.__orig_a.get_orig_raw()[ self.__filename ] + + def get_vm(self) : + """ + This method returns the VMFormat which correspond to the file + + @rtype: L{jvm.JVMFormat} or L{dvm.DalvikVMFormat} + """ + return self.__a.get_vm() + + def save(self) : + """ + Return the original format (with the modifications) into raw format + + @rtype: string + """ + return self.__a.save() + + def __getattr__(self, value) : + try : + return getattr(self.__orig_a, value) + except AttributeError : + return getattr(self.__a, value) diff --git a/androguard/core/binaries/__init__.py b/androguard/core/binaries/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/binaries/elf.py b/androguard/core/binaries/elf.py new file mode 100644 index 00000000..bd0201ab --- /dev/null +++ b/androguard/core/binaries/elf.py @@ -0,0 +1,101 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from elfesteem import * +from miasm.tools.pe_helper import * +from miasm.core import asmbloc +from miasm.arch import arm_arch +from miasm.core import bin_stream + + +from androguard.core import bytecode +from androguard.core.androconf import CONF, debug + +def disasm_at_addr(in_str, ad_to_dis, symbol_pool) : + kargs = {} + all_bloc = asmbloc.dis_bloc_all(arm_arch.arm_mn, in_str, ad_to_dis, set(), + symbol_pool=symbol_pool, + dontdis_retcall = False, + follow_call = False, + **kargs) + for i in all_bloc : + bytecode._PrintDefault("%s\n" % i.label) + for j in i.lines : + bytecode._PrintDefault("\t %s\n" % j) + bytecode._PrintDefault("\n") + +class Function : + def __init__(self, cm, name, info) : + self.cm = cm + self.name = name + self.info = info + + def show(self) : + bytecode._PrintSubBanner("Function") + bytecode._PrintDefault("name=%s addr=0x%x\n" % (self.name, self.info.value)) + + self.cm.disasm_at_addr( self.info.value ) + +class ClassManager : + def __init__(self, in_str, symbol_pool) : + self.in_str = in_str + self.symbol_pool = symbol_pool + + def disasm_at_addr(self, ad_to_dis) : + disasm_at_addr( self.in_str, ad_to_dis, self.symbol_pool ) + +class ELF : + def __init__(self, buff) : + self.E = elf_init.ELF( buff ) + + self.in_str = bin_stream.bin_stream(self.E.virt) + self.symbol_pool = None + self.functions = [] + + self.create_symbol_pool() + + self.CM = ClassManager( self.in_str, self.symbol_pool ) + + self.create_functions() + + def create_symbol_pool(self) : + dll_dyn_funcs = get_import_address_elf(self.E) + self.symbol_pool = asmbloc.asm_symbol_pool() + for (n,f), ads in dll_dyn_funcs.items() : + for ad in ads : + l = self.symbol_pool.getby_name_create("%s_%s"%(n, f)) + l.offset = ad + self.symbol_pool.s_offset[l.offset] = l + + def show(self) : + for i in self.get_functions(): + i.show() + + def get_functions(self) : + return self.functions + + def create_functions(self) : + try : + for k, v in self.E.sh.symtab.symbols.items(): + if v.size != 0 : + self.functions.append( Function(self.CM, k, v) ) + except AttributeError : + pass + + for k, v in self.E.sh.dynsym.symbols.items() : + if v.size != 0 : + self.functions.append( Function(self.CM, k, v) ) diff --git a/androguard/core/binaries/idapipe.py b/androguard/core/binaries/idapipe.py new file mode 100644 index 00000000..faf1d075 --- /dev/null +++ b/androguard/core/binaries/idapipe.py @@ -0,0 +1,211 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from subprocess import Popen, PIPE, STDOUT + +import os, sys +import xmlrpclib + +import cPickle + +class _Method : + def __init__(self, proxy, name) : + self.proxy = proxy + self.name = name + + def __call__(self, *args): + #print "CALL", self.name, args + z = getattr( self.proxy, self.name, None ) + #print "SEND", repr(cPickle.dumps( args ) ) + + try : + if len(args) == 1 : + ret = z( cPickle.dumps( args[0] ) ) + else : + ret = z( cPickle.dumps( args ) ) + #print "RECEIVE", repr(ret) + return cPickle.loads( ret ) + except xmlrpclib.ProtocolError : + return [] + +class MyXMLRPC : + def __init__(self, proxy) : + self.proxy = proxy + + def __getattr__(self, name) : + return _Method(self.proxy, name) + +class BasicBlock : + def __init__(self, ins) : + self.ins = ins + + def show(self) : + for i in self.ins : + print i + +class Function : + def __init__(self, name, start_ea, instructions, information) : + #print name, start_ea + + self.name = name + self.start_ea = start_ea + self.information = information + self.basic_blocks = [] + self.instructions = instructions + + r = {} + idx = 0 + for i in instructions : + r[ i[0] ] = idx + idx += 1 + + for i in information[0] : + try : + start = r[i[0]] + end = r[i[1]] + 1 + self.basic_blocks.append( BasicBlock( instructions[start:end] ) ) + except KeyError : + pass + + def get_instructions(self) : + return [ i for i in self.instructions ] + +def run_ida(idapath, wrapper_init_path, binpath) : + os.environ["TVHEADLESS"] = "1" + pid = os.fork() + if pid == 0: + wrapper_path = "-S" + wrapper_init_path + l = [ idapath, "-A", wrapper_path, binpath ] + print l + compile = Popen(l, stdout=open('/dev/null', 'w'), stderr=STDOUT) + stdout, stderr = compile.communicate() +# print stdout, stderr + sys.exit(0) + +class IDAPipe : + def __init__(self, idapath, binpath, wrapper_init_path) : + self.idapath = idapath + self.binpath = binpath + + self.proxy = None + + run_ida(self.idapath, self.binpath, wrapper_init_path) + + while 1 : + try : + self.proxy = xmlrpclib.ServerProxy("http://localhost:9000/") + self.proxy.is_connected() + break + except : + pass + + #print self.proxy + self.proxy = MyXMLRPC( self.proxy ) + + def quit(self) : + try : + self.proxy.quit() + except : + pass + + def _build_functions(self, functions) : + F = {} + + for i in functions : + F[ i ] = Function( functions[i][0], i, functions[i][1:-1], functions[i][-1] ) + + return F + + def get_quick_functions(self) : + functions = self.get_raw() + return self._build_functions( functions ) + + def get_raw(self) : + return self.proxy.get_raw() + + def get_nb_functions(self) : + return len(self.proxy.Functions()) + + def get_functions(self) : + for function_ea in self.proxy.Functions() : + self.get_function_addr( function_ea ) + + def get_function_name(self, name) : + function_ea = self.proxy.get_function( name ) + self.get_function_addr( function_ea ) + + def get_function_addr(self, function_ea) : + if function_ea == -1 : + return + + f_start = function_ea + f_end = self.proxy.GetFunctionAttr(function_ea, 4) #FUNCATTR_END) + + edges = set() + boundaries = set((f_start,)) + + for head in self.proxy.Heads(f_start, f_end) : + if self.proxy.isCode( self.proxy.GetFlags( head ) ) : + refs = self.proxy.CodeRefsFrom(head, 0) + refs = set(filter(lambda x: x>=f_start and x<=f_end, refs)) + + #print head, f_end, refs, self.proxy.GetMnem(head), self.proxy.GetOpnd(head, 0), self.proxy.GetOpnd(head, 1) + + if refs : + next_head = self.proxy.NextHead(head, f_end) + if self.proxy.isFlow(self.proxy.GetFlags(next_head)): + refs.add(next_head) + + # Update the boundaries found so far. + boundaries.update(refs) + + # For each of the references found, and edge is + # created. + for r in refs: + # If the flow could also come from the address + # previous to the destination of the branching + # an edge is created. + if self.proxy.isFlow(self.proxy.GetFlags(r)): + edges.add((self.proxy.PrevHead(r, f_start), r)) + edges.add((head, r)) + + + #print edges, boundaries + # Let's build the list of (startEA, startEA) couples + # for each basic block + sorted_boundaries = sorted(boundaries, reverse = True) + end_addr = self.proxy.PrevHead(f_end, f_start) + bb_addr = [] + for begin_addr in sorted_boundaries: + bb_addr.append((begin_addr, end_addr)) + # search the next end_addr which could be + # farther than just the previous head + # if data are interlaced in the code + # WARNING: it assumes it won't epicly fail ;) + end_addr = self.proxy.PrevHead(begin_addr, f_start) + while not self.proxy.isCode(self.proxy.GetFlags(end_addr)): + end_addr = self.proxy.PrevHead(end_addr, f_start) + # And finally return the result + bb_addr.reverse() + #print bb_addr, sorted(edges) + +def display_function(f) : + print f, f.name, f.information + + for i in f.basic_blocks : + print i + i.show() diff --git a/androguard/core/binaries/idawrapper.py b/androguard/core/binaries/idawrapper.py new file mode 100644 index 00000000..4134bbc0 --- /dev/null +++ b/androguard/core/binaries/idawrapper.py @@ -0,0 +1,161 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from idaapi import * +from idautils import * +from idc import * + +from SimpleXMLRPCServer import SimpleXMLRPCServer +import cPickle + +def is_connected() : + return True + +def wrapper_get_raw(oops) : + F = {} + for function_ea in Functions() : + + F[ function_ea ] = [] + + f_start = function_ea + f_end = GetFunctionAttr(function_ea, FUNCATTR_END) + + edges = set() + boundaries = set((f_start,)) + + F[ function_ea ].append( GetFunctionName(function_ea) ) + + for head in Heads(f_start, f_end) : + if isCode( GetFlags( head ) ) : + F[ function_ea ].append( (head, GetMnem(head), GetOpnd(head, 0), GetOpnd(head, 1), GetOpnd(head, 2)) ) + + refs = CodeRefsFrom(head, 0) + refs = set(filter(lambda x: x>=f_start and x<=f_end, refs)) + + if refs : + next_head = NextHead(head, f_end) + if isFlow(GetFlags(next_head)): + refs.add(next_head) + + # Update the boundaries found so far. + boundaries.update(refs) + + # For each of the references found, and edge is + # created. + for r in refs: + # If the flow could also come from the address + # previous to the destination of the branching + # an edge is created. + if isFlow(GetFlags(r)): + edges.add((PrevHead(r, f_start), r)) + edges.add((head, r)) + + #print edges, boundaries + # Let's build the list of (startEA, startEA) couples + # for each basic block + sorted_boundaries = sorted(boundaries, reverse = True) + end_addr = PrevHead(f_end, f_start) + bb_addr = [] + for begin_addr in sorted_boundaries: + bb_addr.append((begin_addr, end_addr)) + # search the next end_addr which could be + # farther than just the previous head + # if data are interlaced in the code + # WARNING: it assumes it won't epicly fail ;) + end_addr = PrevHead(begin_addr, f_start) + while not isCode(GetFlags(end_addr)): + end_addr = PrevHead(end_addr, f_start) + # And finally return the result + bb_addr.reverse() + F[ function_ea ].append( (bb_addr, sorted(edges)) ) + + return cPickle.dumps( F ) + +def wrapper_Heads(oops) : + start, end = cPickle.loads(oops) + return cPickle.dumps( [ x for x in Heads( start, end ) ] ) + +def wrapper_Functions(oops) : + return cPickle.dumps( [ x for x in Functions() ] ) + +def wrapper_get_function(oops) : + name = cPickle.loads(oops) + for function_ea in Functions() : + if GetFunctionName(function_ea) == name : + return cPickle.dumps( function_ea ) + return cPickle.dumps( -1 ) + +def wrapper_quit(oops) : + qexit(0) + +class IDAWrapper : + def _dispatch(self, x, params) : + #fd = open("toto.txt", "w") + #fd.write( x + "\n" ) + #fd.write( str(type(params[0])) + "\n" ) + #fd.close() + + params = cPickle.loads( *params ) + if isinstance(params, tuple) == False : + params = (params,) + + import types + import idautils + import idc + + #[getattr(idautils, a, None) for a in dir(idautils) if isinstance(getattr(idautils, a, None) , types.FunctionType)] + for a in dir(idautils) : + #fd.write( "\t" + a + "\n" ) + if a == x : + z = getattr(idautils, a, None) + ret = z( *params ) + if type(ret).__name__=='generator' : + return cPickle.dumps( [ i for i in ret ] ) + return cPickle.dumps( ret ) + + for a in dir(idc) : + #fd.write( "\t" + a + "\n" ) + if a == x : + z = getattr(idc, a, None) + ret = z( *params ) + if type(ret).__name__=='generator' : + return cPickle.dumps( [ i for i in ret ] ) + return cPickle.dumps( ret ) + + return cPickle.dumps( [] ) + +def main() : + autoWait() + ea = ScreenEA() + + server = SimpleXMLRPCServer(("localhost", 9000)) + server.register_function(is_connected, "is_connected") + + server.register_function(wrapper_get_raw, "get_raw") + server.register_function(wrapper_get_function, "get_function") + server.register_function(wrapper_Heads, "Heads") + server.register_function(wrapper_Functions, "Functions") + + server.register_instance(IDAWrapper()) + + server.register_function(wrapper_quit, "quit") + server.serve_forever() + + qexit(0) + +main() diff --git a/androguard/core/bytecode.py b/androguard/core/bytecode.py new file mode 100644 index 00000000..9e45bf82 --- /dev/null +++ b/androguard/core/bytecode.py @@ -0,0 +1,765 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012/2013, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hashlib +from xml.sax.saxutils import escape +from struct import unpack, pack +import textwrap + +import json +from androconf import warning, error, CONF, enable_colors, remove_colors, save_colors, color_range + + +def disable_print_colors(): + colors = save_colors() + remove_colors() + return colors + + +def enable_print_colors(colors): + enable_colors(colors) + + +# Handle exit message +def Exit( msg ): + warning("Error : " + msg) + raise("oops") + +def Warning( msg ): + warning(msg) + +def _PrintBanner() : + print_fct = CONF["PRINT_FCT"] + print_fct("*" * 75 + "\n") + +def _PrintSubBanner(title=None) : + print_fct = CONF["PRINT_FCT"] + if title == None : + print_fct("#" * 20 + "\n") + else : + print_fct("#" * 10 + " " + title + "\n") + +def _PrintNote(note, tab=0) : + print_fct = CONF["PRINT_FCT"] + note_color = CONF["COLORS"]["NOTE"] + normal_color = CONF["COLORS"]["NORMAL"] + print_fct("\t" * tab + "%s# %s%s" % (note_color, note, normal_color) + "\n") + +# Print arg into a correct format +def _Print(name, arg) : + buff = name + " " + + if type(arg).__name__ == 'int' : + buff += "0x%x" % arg + elif type(arg).__name__ == 'long' : + buff += "0x%x" % arg + elif type(arg).__name__ == 'str' : + buff += "%s" % arg + elif isinstance(arg, SV) : + buff += "0x%x" % arg.get_value() + elif isinstance(arg, SVs) : + buff += arg.get_value().__str__() + + print buff + + +def PrettyShowEx(exceptions): + if len(exceptions) > 0: + CONF["PRINT_FCT"]("Exceptions:\n") + for i in exceptions: + CONF["PRINT_FCT"]("\t%s%s%s\n" % (CONF["COLORS"]["EXCEPTION"], i.show_buff(), CONF["COLORS"]["NORMAL"])) + + +def _PrintXRef(tag, items): + print_fct = CONF["PRINT_FCT"] + for i in items: + print_fct("%s: %s %s %s %s\n" % (tag, i[0].get_class_name(), i[0].get_name(), i[0].get_descriptor(), ' '.join("%x" % j.get_idx() for j in i[1]))) + + +def _PrintDRef(tag, items): + print_fct = CONF["PRINT_FCT"] + for i in items: + print_fct("%s: %s %s %s %s\n" % (tag, i[0].get_class_name(), i[0].get_name(), i[0].get_descriptor(), ' '.join("%x" % j for j in i[1]))) + + +def _PrintDefault(msg): + print_fct = CONF["PRINT_FCT"] + print_fct(msg) + + +def PrettyShow(m_a, basic_blocks, notes={}): + idx = 0 + nb = 0 + + offset_color = CONF["COLORS"]["OFFSET"] + offset_addr_color = CONF["COLORS"]["OFFSET_ADDR"] + instruction_name_color = CONF["COLORS"]["INSTRUCTION_NAME"] + branch_false_color = CONF["COLORS"]["BRANCH_FALSE"] + branch_true_color = CONF["COLORS"]["BRANCH_TRUE"] + branch_color = CONF["COLORS"]["BRANCH"] + exception_color = CONF["COLORS"]["EXCEPTION"] + bb_color = CONF["COLORS"]["BB"] + normal_color = CONF["COLORS"]["NORMAL"] + print_fct = CONF["PRINT_FCT"] + + colors = CONF["COLORS"]["OUTPUT"] + + for i in basic_blocks: + print_fct("%s%s%s : \n" % (bb_color, i.get_name(), normal_color)) + instructions = i.get_instructions() + for ins in instructions: + if nb in notes: + for note in notes[nb]: + _PrintNote(note, 1) + + print_fct("\t%s%-3d%s(%s%08x%s) " % (offset_color, nb, normal_color, offset_addr_color, idx, normal_color)) + print_fct("%s%-20s%s" % (instruction_name_color, ins.get_name(), normal_color)) + + operands = ins.get_operands() + print_fct("%s" % ", ".join(m_a.get_vm().colorize_operands(operands, colors))) + + op_value = ins.get_op_value() + if ins == instructions[-1] and i.childs: + print_fct(" ") + + # packed/sparse-switch + if (op_value == 0x2b or op_value == 0x2c) and len(i.childs) > 1: + values = i.get_special_ins(idx).get_values() + print_fct("%s[ D:%s%s " % (branch_false_color, i.childs[0][2].get_name(), branch_color)) + print_fct(' '.join("%d:%s" % (values[j], i.childs[j + 1][2].get_name()) for j in range(0, len(i.childs) - 1)) + " ]%s" % normal_color) + else: + if len(i.childs) == 2: + print_fct("%s[ %s%s " % (branch_false_color, i.childs[0][2].get_name(), branch_true_color)) + print_fct(' '.join("%s" % c[2].get_name() for c in i.childs[1:]) + " ]%s" % normal_color) + else: + print_fct("%s[ " % branch_color + ' '.join("%s" % c[2].get_name() for c in i.childs) + " ]%s" % normal_color) + + idx += ins.get_length() + nb += 1 + + print_fct("\n") + + if i.get_exception_analysis(): + print_fct("\t%s%s%s\n" % (exception_color, i.exception_analysis.show_buff(), normal_color)) + + print_fct("\n") + + +def method2dot(mx, colors={}): + """ + Export analysis method to dot format + + @param mx : MethodAnalysis object + @param colors : MethodAnalysis object + + @rtype : dot format buffer (it is a subgraph (dict)) + """ + + colors = colors or {"true_branch": "green", + "false_branch": "red", + "default_branch": "purple", + "jump_branch": "blue", + "bg_idx": "lightgray", + "idx": "blue", + "bg_start_idx": "yellow", + "bg_instruction": "lightgray", + "instruction_name": "black", + "instructions_operands": "yellow", + + "raw": "red", + "string": "red", + "literal": "green", + "offset": "#4000FF", + "method": "#DF3A01", + "field": "#088A08", + "type": "#0000FF", + + "registers_range": ("#999933", "#6666FF") + } + + node_tpl = "\nstruct_%s [label=<\n\n%s
>];\n" + label_tpl = " %x %s %s \n" + link_tpl = "\n" + + edges_html = "" + blocks_html = "" + + method = mx.get_method() + sha256 = hashlib.sha256("%s%s%s" % (mx.get_method().get_class_name(), mx.get_method().get_name(), mx.get_method().get_descriptor())).hexdigest() + + registers = {} + if method.get_code(): + for DVMBasicMethodBlock in mx.basic_blocks.gets(): + for DVMBasicMethodBlockInstruction in DVMBasicMethodBlock.get_instructions(): + operands = DVMBasicMethodBlockInstruction.get_operands(0) + for register in operands: + if register[0] == 0: + if register[1] not in registers: + registers[register[1]] = 0 + registers[register[1]] += 1 +# for i in range(method.get_code().get_registers_size()): +# registers[i] = 0 + + if registers: + registers_colors = color_range(colors["registers_range"][0], + colors["registers_range"][1], + len(registers)) + for i in registers: + registers[i] = registers_colors.pop(0) + + new_links = [] + + for DVMBasicMethodBlock in mx.basic_blocks.gets(): + ins_idx = DVMBasicMethodBlock.start + block_id = hashlib.md5(sha256 + DVMBasicMethodBlock.get_name()).hexdigest() + + content = link_tpl % 'header' + + for DVMBasicMethodBlockInstruction in DVMBasicMethodBlock.get_instructions(): + if DVMBasicMethodBlockInstruction.get_op_value() == 0x2b or DVMBasicMethodBlockInstruction.get_op_value() == 0x2c: + new_links.append((DVMBasicMethodBlock, ins_idx, DVMBasicMethodBlockInstruction.get_ref_off() * 2 + ins_idx)) + elif DVMBasicMethodBlockInstruction.get_op_value() == 0x26: + new_links.append((DVMBasicMethodBlock, ins_idx, DVMBasicMethodBlockInstruction.get_ref_off() * 2 + ins_idx)) + + operands = DVMBasicMethodBlockInstruction.get_operands(ins_idx) + output = ", ".join(mx.get_vm().get_operand_html(i, registers, colors, escape, textwrap.wrap) for i in operands) + + formatted_operands = DVMBasicMethodBlockInstruction.get_formatted_operands() + if formatted_operands: + output += " ; %s" % str(formatted_operands) + + bg_idx = colors["bg_idx"] + if ins_idx == 0 and "bg_start_idx" in colors: + bg_idx = colors["bg_start_idx"] + + content += label_tpl % (bg_idx, + colors["idx"], + ins_idx, + colors["bg_instruction"], + colors["instruction_name"], + DVMBasicMethodBlockInstruction.get_name(), + output) + + ins_idx += DVMBasicMethodBlockInstruction.get_length() + last_instru = DVMBasicMethodBlockInstruction + + # all blocks from one method parsed + # updating dot HTML content + content += link_tpl % 'tail' + blocks_html += node_tpl % (block_id, content) + + # Block edges color treatment (conditional branchs colors) + val = colors["true_branch"] + if len(DVMBasicMethodBlock.childs) > 1: + val = colors["false_branch"] + elif len(DVMBasicMethodBlock.childs) == 1: + val = colors["jump_branch"] + + values = None + if (last_instru.get_op_value() == 0x2b or last_instru.get_op_value() == 0x2c) and len(DVMBasicMethodBlock.childs) > 1: + val = colors["default_branch"] + values = ["default"] + values.extend(DVMBasicMethodBlock.get_special_ins(ins_idx - last_instru.get_length()).get_values()) + + # updating dot edges + for DVMBasicMethodBlockChild in DVMBasicMethodBlock.childs: + label_edge = "" + + if values: + label_edge = values.pop(0) + + child_id = hashlib.md5(sha256 + DVMBasicMethodBlockChild[-1].get_name()).hexdigest() + edges_html += "struct_%s:tail -> struct_%s:header [color=\"%s\", label=\"%s\"];\n" % (block_id, child_id, val, label_edge) + # color switch + if val == colors["false_branch"]: + val = colors["true_branch"] + elif val == colors["default_branch"]: + val = colors["true_branch"] + + exception_analysis = DVMBasicMethodBlock.get_exception_analysis() + if exception_analysis: + for exception_elem in exception_analysis.exceptions: + exception_block = exception_elem[-1] + if exception_block: + exception_id = hashlib.md5(sha256 + exception_block.get_name()).hexdigest() + edges_html += "struct_%s:tail -> struct_%s:header [color=\"%s\", label=\"%s\"];\n" % (block_id, exception_id, "black", exception_elem[0]) + + for link in new_links: + DVMBasicMethodBlock = link[0] + DVMBasicMethodBlockChild = mx.basic_blocks.get_basic_block(link[2]) + + if DVMBasicMethodBlockChild: + block_id = hashlib.md5(sha256 + DVMBasicMethodBlock.get_name()).hexdigest() + child_id = hashlib.md5(sha256 + DVMBasicMethodBlockChild.get_name()).hexdigest() + + edges_html += "struct_%s:tail -> struct_%s:header [color=\"%s\", label=\"data(0x%x) to @0x%x\", style=\"dashed\"];\n" % (block_id, child_id, "yellow", link[1], link[2]) + + method_label = method.get_class_name() + "." + method.get_name() + "->" + method.get_descriptor() + + method_information = method.get_information() + if method_information: + method_label += "\\nLocal registers v%d ... v%d" % (method_information["registers"][0], method_information["registers"][1]) + if "params" in method_information: + for register, rtype in method_information["params"]: + method_label += "\\nparam v%d = %s" % (register, rtype) + method_label += "\\nreturn = %s" % (method_information["return"]) + + return {'name': method_label, + 'nodes': blocks_html, + 'edges': edges_html} + + +def method2format(output, _format="png", mx=None, raw=None): + """ + Export method to a specific file format + + @param output : output filename + @param _format : format type (png, jpg ...) (default : png) + @param mx : specify the MethodAnalysis object + @param raw : use directly a dot raw buffer if None + """ + try: + import pydot + except ImportError: + error("module pydot not found") + + buff = "digraph {\n" + buff += "graph [rankdir=TB]\n" + buff += "node [shape=plaintext]\n" + + if raw: + data = raw + else: + data = method2dot(mx) + + # subgraphs cluster + buff += "subgraph cluster_" + hashlib.md5(output).hexdigest() + " {\nlabel=\"%s\"\n" % data['name'] + buff += data['nodes'] + buff += "}\n" + + # subgraphs edges + buff += data['edges'] + buff += "}\n" + + d = pydot.graph_from_dot_data(buff) + if d: + getattr(d, "write_" + _format.lower())(output) + + +def method2png(output, mx, raw=False): + """ + Export method to a png file format + + :param output: output filename + :type output: string + :param mx: specify the MethodAnalysis object + :type mx: :class:`MethodAnalysis` object + :param raw: use directly a dot raw buffer + :type raw: string + """ + buff = raw + if raw == False: + buff = method2dot(mx) + + method2format(output, "png", mx, buff) + + +def method2jpg(output, mx, raw=False): + """ + Export method to a jpg file format + + :param output: output filename + :type output: string + :param mx: specify the MethodAnalysis object + :type mx: :class:`MethodAnalysis` object + :param raw: use directly a dot raw buffer (optional) + :type raw: string + """ + buff = raw + if raw == False: + buff = method2dot(mx) + + method2format(output, "jpg", mx, buff) + + +def vm2json(vm): + d = {} + d["name"] = "root" + d["children"] = [] + + for _class in vm.get_classes(): + c_class = {} + c_class["name"] = _class.get_name() + c_class["children"] = [] + + for method in _class.get_methods(): + c_method = {} + c_method["name"] = method.get_name() + c_method["children"] = [] + + c_class["children"].append(c_method) + + d["children"].append(c_class) + + return json.dumps(d) + + +class TmpBlock: + def __init__(self, name): + self.name = name + + def get_name(self): + return self.name + + +def method2json(mx, directed_graph=False): + if directed_graph: + return method2json_direct(mx) + return method2json_undirect(mx) + + +def method2json_undirect(mx): + d = {} + reports = [] + d["reports"] = reports + + for DVMBasicMethodBlock in mx.basic_blocks.gets(): + cblock = {} + + cblock["BasicBlockId"] = DVMBasicMethodBlock.get_name() + cblock["registers"] = mx.get_method().get_code().get_registers_size() + cblock["instructions"] = [] + + ins_idx = DVMBasicMethodBlock.start + for DVMBasicMethodBlockInstruction in DVMBasicMethodBlock.get_instructions(): + c_ins = {} + c_ins["idx"] = ins_idx + c_ins["name"] = DVMBasicMethodBlockInstruction.get_name() + c_ins["operands"] = DVMBasicMethodBlockInstruction.get_operands(ins_idx) + + cblock["instructions"].append(c_ins) + ins_idx += DVMBasicMethodBlockInstruction.get_length() + + cblock["Edge"] = [] + for DVMBasicMethodBlockChild in DVMBasicMethodBlock.childs: + cblock["Edge"].append(DVMBasicMethodBlockChild[-1].get_name()) + + reports.append(cblock) + + return json.dumps(d) + + +def method2json_direct(mx): + d = {} + reports = [] + d["reports"] = reports + + hooks = {} + + l = [] + for DVMBasicMethodBlock in mx.basic_blocks.gets(): + for index, DVMBasicMethodBlockChild in enumerate(DVMBasicMethodBlock.childs): + if DVMBasicMethodBlock.get_name() == DVMBasicMethodBlockChild[-1].get_name(): + + preblock = TmpBlock(DVMBasicMethodBlock.get_name() + "-pre") + + cnblock = {} + cnblock["BasicBlockId"] = DVMBasicMethodBlock.get_name() + "-pre" + cnblock["start"] = DVMBasicMethodBlock.start + cnblock["notes"] = [] + + cnblock["Edge"] = [DVMBasicMethodBlock.get_name()] + cnblock["registers"] = 0 + cnblock["instructions"] = [] + cnblock["info_bb"] = 0 + + l.append(cnblock) + + for parent in DVMBasicMethodBlock.fathers: + hooks[parent[-1].get_name()] = [] + hooks[parent[-1].get_name()].append(preblock) + + for idx, child in enumerate(parent[-1].childs): + if child[-1].get_name() == DVMBasicMethodBlock.get_name(): + hooks[parent[-1].get_name()].append(child[-1]) + + for DVMBasicMethodBlock in mx.basic_blocks.gets(): + cblock = {} + + cblock["BasicBlockId"] = DVMBasicMethodBlock.get_name() + cblock["start"] = DVMBasicMethodBlock.start + cblock["notes"] = DVMBasicMethodBlock.get_notes() + + cblock["registers"] = mx.get_method().get_code().get_registers_size() + cblock["instructions"] = [] + + ins_idx = DVMBasicMethodBlock.start + last_instru = None + for DVMBasicMethodBlockInstruction in DVMBasicMethodBlock.get_instructions(): + c_ins = {} + c_ins["idx"] = ins_idx + c_ins["name"] = DVMBasicMethodBlockInstruction.get_name() + c_ins["operands"] = DVMBasicMethodBlockInstruction.get_operands(ins_idx) + + c_ins["formatted_operands"] = DVMBasicMethodBlockInstruction.get_formatted_operands() + + cblock["instructions"].append(c_ins) + + if (DVMBasicMethodBlockInstruction.get_op_value() == 0x2b or DVMBasicMethodBlockInstruction.get_op_value() == 0x2c): + values = DVMBasicMethodBlock.get_special_ins(ins_idx) + cblock["info_next"] = values.get_values() + + ins_idx += DVMBasicMethodBlockInstruction.get_length() + last_instru = DVMBasicMethodBlockInstruction + + cblock["info_bb"] = 0 + if DVMBasicMethodBlock.childs: + if len(DVMBasicMethodBlock.childs) > 1: + cblock["info_bb"] = 1 + + if (last_instru.get_op_value() == 0x2b or last_instru.get_op_value() == 0x2c): + cblock["info_bb"] = 2 + + cblock["Edge"] = [] + for DVMBasicMethodBlockChild in DVMBasicMethodBlock.childs: + ok = False + if DVMBasicMethodBlock.get_name() in hooks: + if DVMBasicMethodBlockChild[-1] in hooks[DVMBasicMethodBlock.get_name()]: + ok = True + cblock["Edge"].append(hooks[DVMBasicMethodBlock.get_name()][0].get_name()) + + if not ok: + cblock["Edge"].append(DVMBasicMethodBlockChild[-1].get_name()) + + exception_analysis = DVMBasicMethodBlock.get_exception_analysis() + if exception_analysis: + cblock["Exceptions"] = exception_analysis.get() + + reports.append(cblock) + + reports.extend(l) + + return json.dumps(d) + + +class SV: + def __init__(self, size, buff): + self.__size = size + self.__value = unpack(self.__size, buff)[0] + + def _get(self): + return pack(self.__size, self.__value) + + def __str__(self) : + return "0x%x" % self.__value + + def __int__(self) : + return self.__value + + def get_value_buff(self) : + return self._get() + + def get_value(self) : + return self.__value + + def set_value(self, attr) : + self.__value = attr + +class SVs : + def __init__(self, size, ntuple, buff) : + self.__size = size + + self.__value = ntuple._make( unpack( self.__size, buff ) ) + + def _get(self) : + l = [] + for i in self.__value._fields : + l.append( getattr( self.__value, i ) ) + return pack( self.__size, *l) + + def _export(self) : + return [ x for x in self.__value._fields ] + + def get_value_buff(self) : + return self._get() + + def get_value(self) : + return self.__value + + def set_value(self, attr) : + self.__value = self.__value._replace( **attr ) + + def __str__(self) : + return self.__value.__str__() + +def object_to_str(obj) : + if isinstance(obj, str) : + return obj + elif isinstance(obj, bool) : + return "" + elif isinstance(obj, int) : + return pack("", "") + i = i.replace("$", "_") + + return i + +def FormatDescriptorToPython(input) : + i = input.replace("/", "_") + i = i.replace(";", "") + i = i.replace("[", "") + i = i.replace("(", "") + i = i.replace(")", "") + i = i.replace(" ", "") + i = i.replace("$", "") + + return i + +class Node: + def __init__(self, n, s): + self.id = n + self.title = s + self.children = [] diff --git a/androguard/core/bytecodes/__init__.py b/androguard/core/bytecodes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/bytecodes/api_permissions.py b/androguard/core/bytecodes/api_permissions.py new file mode 100644 index 00000000..d4a7f598 --- /dev/null +++ b/androguard/core/bytecodes/api_permissions.py @@ -0,0 +1,4379 @@ +DVM_PERMISSIONS_BY_PERMISSION = { +"BIND_DEVICE_ADMIN" : { + "Landroid/app/admin/DeviceAdminReceiver;" : [ + ("C", "ACTION_DEVICE_ADMIN_ENABLED", "Ljava/lang/String;"), + ], + "Landroid/app/admin/DevicePolicyManager;" : [ + ("F", "getRemoveWarning", "(Landroid/content/ComponentName; Landroid/os/RemoteCallback;)"), + ("F", "reportFailedPasswordAttempt", "()"), + ("F", "reportSuccessfulPasswordAttempt", "()"), + ("F", "setActiveAdmin", "(Landroid/content/ComponentName;)"), + ("F", "setActivePasswordState", "(I I)"), + ], + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;" : [ + ("F", "getRemoveWarning", "(Landroid/content/ComponentName; Landroid/os/RemoteCallback;)"), + ("F", "reportFailedPasswordAttempt", "()"), + ("F", "reportSuccessfulPasswordAttempt", "()"), + ("F", "setActiveAdmin", "(Landroid/content/ComponentName;)"), + ("F", "setActivePasswordState", "(I I)"), + ], +}, +"READ_SYNC_SETTINGS" : { + "Landroid/app/ContextImpl$ApplicationContentResolver;" : [ + ("F", "getIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getMasterSyncAutomatically", "()"), + ("F", "getPeriodicSyncs", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/ContentService;" : [ + ("F", "getIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getMasterSyncAutomatically", "()"), + ("F", "getPeriodicSyncs", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/ContentResolver;" : [ + ("F", "getIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getMasterSyncAutomatically", "()"), + ("F", "getPeriodicSyncs", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/IContentService$Stub$Proxy;" : [ + ("F", "getIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getMasterSyncAutomatically", "()"), + ("F", "getPeriodicSyncs", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "getSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], +}, +"FACTORY_TEST" : { + "Landroid/content/pm/ApplicationInfo;" : [ + ("C", "FLAG_FACTORY_TEST", "I"), + ("C", "flags", "I"), + ], + "Landroid/content/Intent;" : [ + ("C", "IntentResolution", "Ljava/lang/String;"), + ("C", "ACTION_FACTORY_TEST", "Ljava/lang/String;"), + ], +}, +"SET_ALWAYS_FINISH" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "setAlwaysFinish", "(B)"), + ], +}, +"READ_CALENDAR" : { + "Landroid/provider/Calendar$CalendarAlerts;" : [ + ("F", "alarmExists", "(Landroid/content/ContentResolver; J J J)"), + ("F", "findNextAlarmTime", "(Landroid/content/ContentResolver; J)"), + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)"), + ], + "Landroid/provider/Calendar$Calendars;" : [ + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/provider/Calendar$Events;" : [ + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)"), + ], + "Landroid/provider/Calendar$Instances;" : [ + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; J J Ljava/lang/String; Ljava/lang/String;)"), + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; J J)"), + ], + "Landroid/provider/Calendar$EventDays;" : [ + ("F", "query", "(Landroid/content/ContentResolver; I I)"), + ], +}, +"ACCESS_DRM" : { + "Landroid/provider/DrmStore;" : [ + ("F", "enforceAccessDrmPermission", "(Landroid/content/Context;)"), + ], +}, +"CHANGE_CONFIGURATION" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "updateConfiguration", "(Landroid/content/res/Configuration;)"), + ], +}, +"SET_ACTIVITY_WATCHER" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "profileControl", "(Ljava/lang/String; B Ljava/lang/String; Landroid/os/ParcelFileDescriptor;)"), + ("F", "setActivityController", "(Landroid/app/IActivityController;)"), + ], +}, +"GET_PACKAGE_SIZE" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "getPackageSizeInfo", "(Ljava/lang/String; LIPackageStatsObserver;)"), + ("F", "getPackageSizeInfo", "(Ljava/lang/String; Landroid/content/pm/IPackageStatsObserver;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "getPackageSizeInfo", "(Ljava/lang/String; Landroid/content/pm/IPackageStatsObserver;)"), + ], +}, +"CONTROL_LOCATION_UPDATES" : { + "Landroid/telephony/TelephonyManager;" : [ + ("F", "disableLocationUpdates", "()"), + ("F", "enableLocationUpdates", "()"), + ], + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;" : [ + ("F", "disableLocationUpdates", "()"), + ("F", "enableLocationUpdates", "()"), + ], +}, +"CLEAR_APP_CACHE" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "freeStorage", "(J LIntentSender;)"), + ("F", "freeStorageAndNotify", "(J LIPackageDataObserver;)"), + ("F", "freeStorage", "(J Landroid/content/IntentSender;)"), + ("F", "freeStorageAndNotify", "(J Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "freeStorage", "(J Landroid/content/IntentSender;)"), + ("F", "freeStorageAndNotify", "(J Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "freeStorage", "(J Landroid/content/IntentSender;)"), + ("F", "freeStorageAndNotify", "(J Landroid/content/pm/IPackageDataObserver;)"), + ], +}, +"BIND_INPUT_METHOD" : { + "Landroid/view/inputmethod/InputMethod;" : [ + ("C", "SERVICE_INTERFACE", "Ljava/lang/String;"), + ], +}, +"SIGNAL_PERSISTENT_PROCESSES" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "signalPersistentProcesses", "(I)"), + ], +}, +"BATTERY_STATS" : { + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;" : [ + ("F", "getAwakeTimeBattery", "()"), + ("F", "getAwakeTimePlugged", "()"), + ("F", "getStatistics", "()"), + ], +}, +"AUTHENTICATE_ACCOUNTS" : { + "Landroid/accounts/AccountManager;" : [ + ("F", "addAccountExplicitly", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getPassword", "(Landroid/accounts/Account;)"), + ("F", "getUserData", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "peekAuthToken", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setPassword", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setUserData", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "addAccountExplicitly", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getPassword", "(Landroid/accounts/Account;)"), + ("F", "getUserData", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "peekAuthToken", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setPassword", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setUserData", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/accounts/AccountManagerService;" : [ + ("F", "addAccount", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "checkAuthenticateAccountsPermission", "(Landroid/accounts/Account;)"), + ("F", "getPassword", "(Landroid/accounts/Account;)"), + ("F", "getUserData", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "peekAuthToken", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setPassword", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setUserData", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/accounts/IAccountManager$Stub$Proxy;" : [ + ("F", "addAccount", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getPassword", "(Landroid/accounts/Account;)"), + ("F", "getUserData", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "peekAuthToken", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setPassword", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "setUserData", "(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)"), + ], +}, +"CHANGE_BACKGROUND_DATA_SETTING" : { + "Landroid/net/IConnectivityManager$Stub$Proxy;" : [ + ("F", "setBackgroundDataSetting", "(B)"), + ], + "Landroid/net/ConnectivityManager;" : [ + ("F", "setBackgroundDataSetting", "(B)"), + ], +}, +"RESTART_PACKAGES" : { + "Landroid/app/ActivityManagerNative;" : [ + ("F", "killBackgroundProcesses", "(Ljava/lang/String;)"), + ("F", "restartPackage", "(Ljava/lang/String;)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "killBackgroundProcesses", "(Ljava/lang/String;)"), + ("F", "restartPackage", "(Ljava/lang/String;)"), + ], +}, +"CALL_PRIVILEGED" : { + "Landroid/telephony/TelephonyManager;" : [ + ("F", "getCompleteVoiceMailNumber", "()"), + ], + "Landroid/telephony/PhoneNumberUtils;" : [ + ("F", "getNumberFromIntent", "(Landroid/content/Intent; Landroid/content/Context;)"), + ], +}, +"SET_WALLPAPER_COMPONENT" : { + "Landroid/app/IWallpaperManager$Stub$Proxy;" : [ + ("F", "setWallpaperComponent", "(Landroid/content/ComponentName;)"), + ], +}, +"DISABLE_KEYGUARD" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "disableKeyguard", "(Landroid/os/IBinder; Ljava/lang/String;)"), + ("F", "exitKeyguardSecurely", "(Landroid/view/IOnKeyguardExitResult;)"), + ("F", "reenableKeyguard", "(Landroid/os/IBinder;)"), + ], + "Landroid/app/KeyguardManager;" : [ + ("F", "exitKeyguardSecurely", "(Landroid/app/KeyguardManager$OnKeyguardExitResult;)"), + ], + "Landroid/app/KeyguardManager$KeyguardLock;" : [ + ("F", "disableKeyguard", "()"), + ("F", "reenableKeyguard", "()"), + ], +}, +"DELETE_PACKAGES" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "deletePackage", "(Ljava/lang/String; LIPackageDeleteObserver; I)"), + ("F", "deletePackage", "(Ljava/lang/String; LIPackageDeleteObserver; I)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "deletePackage", "(Ljava/lang/String; LIPackageDeleteObserver; I)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "deletePackage", "(Ljava/lang/String; Landroid/content/pm/IPackageDeleteObserver; I)"), + ], +}, +"CHANGE_COMPONENT_ENABLED_STATE" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "setApplicationEnabledSetting", "(Ljava/lang/String; I I)"), + ("F", "setComponentEnabledSetting", "(LComponentName; I I)"), + ("F", "setApplicationEnabledSetting", "(Ljava/lang/String; I I)"), + ("F", "setComponentEnabledSetting", "(Landroid/content/ComponentName; I I)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "setApplicationEnabledSetting", "(Ljava/lang/String; I I)"), + ("F", "setComponentEnabledSetting", "(Landroid/content/ComponentName; I I)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "setApplicationEnabledSetting", "(Ljava/lang/String; I I)"), + ("F", "setComponentEnabledSetting", "(Landroid/content/ComponentName; I I)"), + ], +}, +"ASEC_ACCESS" : { + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "getSecureContainerList", "()"), + ("F", "getSecureContainerPath", "(Ljava/lang/String;)"), + ("F", "isSecureContainerMounted", "(Ljava/lang/String;)"), + ], +}, +"UPDATE_DEVICE_STATS " : { + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;" : [ + ("F", "noteLaunchTime", "(LComponentName;)"), + ], +}, +"RECORD_AUDIO" : { + "Landroid/net/sip/SipAudioCall;" : [ + ("F", "startAudio", "()"), + ], + "Landroid/media/MediaRecorder;" : [ + ("F", "setAudioSource", "(I)"), + ], + "Landroid/speech/SpeechRecognizer;" : [ + ("F", "cancel", "()"), + ("F", "handleCancelMessage", "()"), + ("F", "handleStartListening", "(Landroid/content/Intent;)"), + ("F", "handleStopMessage", "()"), + ("F", "startListening", "(Landroid/content/Intent;)"), + ("F", "stopListening", "()"), + ], + "Landroid/media/AudioRecord;" : [ + ("F", "", "(I I I I I)"), + ], +}, +"ACCESS_MOCK_LOCATION" : { + "Landroid/location/LocationManager;" : [ + ("F", "addTestProvider", "(Ljava/lang/String; B B B B B B B I I)"), + ("F", "clearTestProviderEnabled", "(Ljava/lang/String;)"), + ("F", "clearTestProviderLocation", "(Ljava/lang/String;)"), + ("F", "clearTestProviderStatus", "(Ljava/lang/String;)"), + ("F", "removeTestProvider", "(Ljava/lang/String;)"), + ("F", "setTestProviderEnabled", "(Ljava/lang/String; B)"), + ("F", "setTestProviderLocation", "(Ljava/lang/String; Landroid/location/Location;)"), + ("F", "setTestProviderStatus", "(Ljava/lang/String; I Landroid/os/Bundle; J)"), + ("F", "addTestProvider", "(Ljava/lang/String; B B B B B B B I I)"), + ("F", "clearTestProviderEnabled", "(Ljava/lang/String;)"), + ("F", "clearTestProviderLocation", "(Ljava/lang/String;)"), + ("F", "clearTestProviderStatus", "(Ljava/lang/String;)"), + ("F", "removeTestProvider", "(Ljava/lang/String;)"), + ("F", "setTestProviderEnabled", "(Ljava/lang/String; B)"), + ("F", "setTestProviderLocation", "(Ljava/lang/String; Landroid/location/Location;)"), + ("F", "setTestProviderStatus", "(Ljava/lang/String; I Landroid/os/Bundle; J)"), + ], + "Landroid/location/ILocationManager$Stub$Proxy;" : [ + ("F", "addTestProvider", "(Ljava/lang/String; B B B B B B B I I)"), + ("F", "clearTestProviderEnabled", "(Ljava/lang/String;)"), + ("F", "clearTestProviderLocation", "(Ljava/lang/String;)"), + ("F", "clearTestProviderStatus", "(Ljava/lang/String;)"), + ("F", "removeTestProvider", "(Ljava/lang/String;)"), + ("F", "setTestProviderEnabled", "(Ljava/lang/String; B)"), + ("F", "setTestProviderLocation", "(Ljava/lang/String; Landroid/location/Location;)"), + ("F", "setTestProviderStatus", "(Ljava/lang/String; I Landroid/os/Bundle; J)"), + ], +}, +"VIBRATE" : { + "Landroid/media/AudioManager;" : [ + ("C", "EXTRA_RINGER_MODE", "Ljava/lang/String;"), + ("C", "EXTRA_VIBRATE_SETTING", "Ljava/lang/String;"), + ("C", "EXTRA_VIBRATE_TYPE", "Ljava/lang/String;"), + ("C", "FLAG_REMOVE_SOUND_AND_VIBRATE", "I"), + ("C", "FLAG_VIBRATE", "I"), + ("C", "RINGER_MODE_VIBRATE", "I"), + ("C", "VIBRATE_SETTING_CHANGED_ACTION", "Ljava/lang/String;"), + ("C", "VIBRATE_SETTING_OFF", "I"), + ("C", "VIBRATE_SETTING_ON", "I"), + ("C", "VIBRATE_SETTING_ONLY_SILENT", "I"), + ("C", "VIBRATE_TYPE_NOTIFICATION", "I"), + ("C", "VIBRATE_TYPE_RINGER", "I"), + ("F", "getRingerMode", "()"), + ("F", "getVibrateSetting", "(I)"), + ("F", "setRingerMode", "(I)"), + ("F", "setVibrateSetting", "(I I)"), + ("F", "shouldVibrate", "(I)"), + ], + "Landroid/os/Vibrator;" : [ + ("F", "cancel", "()"), + ("F", "vibrate", "([L; I)"), + ("F", "vibrate", "(J)"), + ], + "Landroid/provider/Settings/System;" : [ + ("C", "VIBRATE_ON", "Ljava/lang/String;"), + ], + "Landroid/app/NotificationManager;" : [ + ("F", "notify", "(I Landroid/app/Notification;)"), + ("F", "notify", "(Ljava/lang/String; I Landroid/app/Notification;)"), + ], + "Landroid/app/Notification/Builder;" : [ + ("F", "setDefaults", "(I)"), + ], + "Landroid/os/IVibratorService$Stub$Proxy;" : [ + ("F", "cancelVibrate", "(Landroid/os/IBinder;)"), + ("F", "vibrate", "(J Landroid/os/IBinder;)"), + ("F", "vibratePattern", "([L; I Landroid/os/IBinder;)"), + ], + "Landroid/app/Notification;" : [ + ("C", "DEFAULT_VIBRATE", "I"), + ("C", "defaults", "I"), + ], +}, +"ASEC_CREATE" : { + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "createSecureContainer", "(Ljava/lang/String; I Ljava/lang/String; Ljava/lang/String; I)"), + ("F", "finalizeSecureContainer", "(Ljava/lang/String;)"), + ], +}, +"WRITE_SECURE_SETTINGS" : { + "Landroid/bluetooth/BluetoothAdapter;" : [ + ("F", "setScanMode", "(I I)"), + ("F", "setScanMode", "(I)"), + ], + "Landroid/server/BluetoothService;" : [ + ("F", "setScanMode", "(I I)"), + ], + "Landroid/os/IPowerManager$Stub$Proxy;" : [ + ("F", "setMaximumScreenOffTimeount", "(I)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "setInstallLocation", "(I)"), + ], + "Landroid/bluetooth/IBluetooth$Stub$Proxy;" : [ + ("F", "setScanMode", "(I I)"), + ], +}, +"SET_ORIENTATION" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "setRotation", "(I B I)"), + ], +}, +"PACKAGE_USAGE_STATS" : { + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;" : [ + ("F", "getAllPkgUsageStats", "()"), + ("F", "getPkgUsageStats", "(LComponentName;)"), + ], +}, +"FLASHLIGHT" : { + "Landroid/os/IHardwareService$Stub$Proxy;" : [ + ("F", "setFlashlightEnabled", "(B)"), + ], +}, +"GLOBAL_SEARCH" : { + "Landroid/app/SearchManager;" : [ + ("C", "EXTRA_SELECT_QUERY", "Ljava/lang/String;"), + ("C", "INTENT_ACTION_GLOBAL_SEARCH", "Ljava/lang/String;"), + ], + "Landroid/server/search/Searchables;" : [ + ("F", "buildSearchableList", "()"), + ("F", "findGlobalSearchActivity", "()"), + ], +}, +"CHANGE_WIFI_STATE" : { + "Landroid/net/wifi/IWifiManager$Stub$Proxy;" : [ + ("F", "addOrUpdateNetwork", "(Landroid/net/wifi/WifiConfiguration;)"), + ("F", "disableNetwork", "(I)"), + ("F", "disconnect", "()"), + ("F", "enableNetwork", "(I B)"), + ("F", "pingSupplicant", "()"), + ("F", "reassociate", "()"), + ("F", "reconnect", "()"), + ("F", "removeNetwork", "(I)"), + ("F", "saveConfiguration", "()"), + ("F", "setNumAllowedChannels", "(I B)"), + ("F", "setWifiApEnabled", "(Landroid/net/wifi/WifiConfiguration; B)"), + ("F", "setWifiEnabled", "(B)"), + ("F", "startScan", "(B)"), + ], + "Landroid/net/wifi/WifiManager;" : [ + ("F", "addNetwork", "(Landroid/net/wifi/WifiConfiguration;)"), + ("F", "addOrUpdateNetwork", "(Landroid/net/wifi/WifiConfiguration;)"), + ("F", "disableNetwork", "(I)"), + ("F", "disconnect", "()"), + ("F", "enableNetwork", "(I B)"), + ("F", "pingSupplicant", "()"), + ("F", "reassociate", "()"), + ("F", "reconnect", "()"), + ("F", "removeNetwork", "(I)"), + ("F", "saveConfiguration", "()"), + ("F", "setNumAllowedChannels", "(I B)"), + ("F", "setWifiApEnabled", "(Landroid/net/wifi/WifiConfiguration; B)"), + ("F", "setWifiEnabled", "(B)"), + ("F", "startScan", "()"), + ("F", "startScanActive", "()"), + ], +}, +"BROADCAST_STICKY" : { + "Landroid/app/ExpandableListActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/accessibilityservice/AccessibilityService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/accounts/GrantCredentialsPermissionActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/backup/BackupAgent;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/service/wallpaper/WallpaperService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/backup/BackupAgentHelper;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/accounts/AccountAuthenticatorActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "unbroadcastIntent", "(Landroid/app/IApplicationThread; Landroid/content/Intent;)"), + ], + "Landroid/app/ActivityGroup;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/content/ContextWrapper;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/Activity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/ContextImpl;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/AliasActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/content/Context;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/service/urlrenderer/UrlRendererService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/FullBackupAgent;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/TabActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/view/ContextThemeWrapper;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/speech/RecognitionService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/IntentService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/inputmethodservice/AbstractInputMethodService;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/Application;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/ListActivity;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/app/Service;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/content/MutableContextWrapper;" : [ + ("F", "removeStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyBroadcast", "(Landroid/content/Intent;)"), + ("F", "sendStickyOrderedBroadcast", "(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)"), + ], +}, +"FORCE_STOP_PACKAGES" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "forceStopPackage", "(Ljava/lang/String;)"), + ], + "Landroid/app/ActivityManagerNative;" : [ + ("F", "forceStopPackage", "(Ljava/lang/String;)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "forceStopPackage", "(Ljava/lang/String;)"), + ], +}, +"KILL_BACKGROUND_PROCESSES" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "killBackgroundProcesses", "(Ljava/lang/String;)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "killBackgroundProcesses", "(Ljava/lang/String;)"), + ], +}, +"SET_TIME_ZONE" : { + "Landroid/app/AlarmManager;" : [ + ("F", "setTimeZone", "(Ljava/lang/String;)"), + ("F", "setTimeZone", "(Ljava/lang/String;)"), + ], + "Landroid/app/IAlarmManager$Stub$Proxy;" : [ + ("F", "setTimeZone", "(Ljava/lang/String;)"), + ], +}, +"BLUETOOTH_ADMIN" : { + "Landroid/server/BluetoothA2dpService;" : [ + ("F", "connectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "resumeSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "setSinkPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ("F", "setSinkPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ("F", "suspendSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/bluetooth/BluetoothPbap;" : [ + ("F", "disconnect", "()"), + ], + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;" : [ + ("F", "connectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "resumeSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "setSinkPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ("F", "suspendSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/bluetooth/BluetoothAdapter;" : [ + ("F", "cancelDiscovery", "()"), + ("F", "disable", "()"), + ("F", "enable", "()"), + ("F", "setName", "(Ljava/lang/String;)"), + ("F", "startDiscovery", "()"), + ("F", "cancelDiscovery", "()"), + ("F", "disable", "()"), + ("F", "enable", "()"), + ("F", "setDiscoverableTimeout", "(I)"), + ("F", "setName", "(Ljava/lang/String;)"), + ("F", "startDiscovery", "()"), + ], + "Landroid/server/BluetoothService;" : [ + ("F", "cancelBondProcess", "(Ljava/lang/String;)"), + ("F", "cancelDiscovery", "()"), + ("F", "cancelPairingUserInput", "(Ljava/lang/String;)"), + ("F", "createBond", "(Ljava/lang/String;)"), + ("F", "disable", "()"), + ("F", "disable", "(B)"), + ("F", "enable", "()"), + ("F", "enable", "(B)"), + ("F", "removeBond", "(Ljava/lang/String;)"), + ("F", "setDiscoverableTimeout", "(I)"), + ("F", "setName", "(Ljava/lang/String;)"), + ("F", "setPairingConfirmation", "(Ljava/lang/String; B)"), + ("F", "setPasskey", "(Ljava/lang/String; I)"), + ("F", "setPin", "(Ljava/lang/String; [L;)"), + ("F", "setTrust", "(Ljava/lang/String; B)"), + ("F", "startDiscovery", "()"), + ], + "Landroid/bluetooth/BluetoothHeadset;" : [ + ("F", "connectHeadset", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnectHeadset", "()"), + ("F", "setPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ], + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;" : [ + ("F", "connectHeadset", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnectHeadset", "()"), + ("F", "setPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ], + "Landroid/bluetooth/BluetoothDevice;" : [ + ("F", "cancelBondProcess", "()"), + ("F", "cancelPairingUserInput", "()"), + ("F", "createBond", "()"), + ("F", "removeBond", "()"), + ("F", "setPairingConfirmation", "(B)"), + ("F", "setPasskey", "(I)"), + ("F", "setPin", "([L;)"), + ], + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;" : [ + ("F", "connect", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnect", "()"), + ], + "Landroid/bluetooth/BluetoothA2dp;" : [ + ("F", "connectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "disconnectSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "resumeSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "setSinkPriority", "(Landroid/bluetooth/BluetoothDevice; I)"), + ("F", "suspendSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/bluetooth/IBluetooth$Stub$Proxy;" : [ + ("F", "cancelBondProcess", "(Ljava/lang/String;)"), + ("F", "cancelDiscovery", "()"), + ("F", "cancelPairingUserInput", "(Ljava/lang/String;)"), + ("F", "createBond", "(Ljava/lang/String;)"), + ("F", "disable", "(B)"), + ("F", "enable", "()"), + ("F", "removeBond", "(Ljava/lang/String;)"), + ("F", "setDiscoverableTimeout", "(I)"), + ("F", "setName", "(Ljava/lang/String;)"), + ("F", "setPairingConfirmation", "(Ljava/lang/String; B)"), + ("F", "setPasskey", "(Ljava/lang/String; I)"), + ("F", "setPin", "(Ljava/lang/String; [L;)"), + ("F", "setTrust", "(Ljava/lang/String; B)"), + ("F", "startDiscovery", "()"), + ], +}, +"INJECT_EVENTS" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "injectKeyEvent", "(Landroid/view/KeyEvent; B)"), + ("F", "injectPointerEvent", "(Landroid/view/MotionEvent; B)"), + ("F", "injectTrackballEvent", "(Landroid/view/MotionEvent; B)"), + ], + "Landroid/app/Instrumentation;" : [ + ("F", "invokeContextMenuAction", "(Landroid/app/Activity; I I)"), + ("F", "sendCharacterSync", "(I)"), + ("F", "sendKeyDownUpSync", "(I)"), + ("F", "sendKeySync", "(Landroid/view/KeyEvent;)"), + ("F", "sendPointerSync", "(Landroid/view/MotionEvent;)"), + ("F", "sendStringSync", "(Ljava/lang/String;)"), + ("F", "sendTrackballEventSync", "(Landroid/view/MotionEvent;)"), + ], +}, +"CAMERA" : { + "Landroid/hardware/Camera/ErrorCallback;" : [ + ("F", "onError", "(I Landroid/hardware/Camera;)"), + ], + "Landroid/media/MediaRecorder;" : [ + ("F", "setVideoSource", "(I)"), + ], + "Landroid/view/KeyEvent;" : [ + ("C", "KEYCODE_CAMERA", "I"), + ], + "Landroid/bluetooth/BluetoothClass/Device;" : [ + ("C", "AUDIO_VIDEO_VIDEO_CAMERA", "I"), + ], + "Landroid/provider/MediaStore;" : [ + ("C", "INTENT_ACTION_STILL_IMAGE_CAMERA", "Ljava/lang/String;"), + ("C", "INTENT_ACTION_VIDEO_CAMERA", "Ljava/lang/String;"), + ], + "Landroid/hardware/Camera/CameraInfo;" : [ + ("C", "CAMERA_FACING_BACK", "I"), + ("C", "CAMERA_FACING_FRONT", "I"), + ("C", "facing", "I"), + ], + "Landroid/provider/ContactsContract/StatusColumns;" : [ + ("C", "CAPABILITY_HAS_CAMERA", "I"), + ], + "Landroid/hardware/Camera/Parameters;" : [ + ("F", "setRotation", "(I)"), + ], + "Landroid/media/MediaRecorder/VideoSource;" : [ + ("C", "CAMERA", "I"), + ], + "Landroid/content/Intent;" : [ + ("C", "IntentResolution", "Ljava/lang/String;"), + ("C", "ACTION_CAMERA_BUTTON", "Ljava/lang/String;"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("C", "FEATURE_CAMERA", "Ljava/lang/String;"), + ("C", "FEATURE_CAMERA_AUTOFOCUS", "Ljava/lang/String;"), + ("C", "FEATURE_CAMERA_FLASH", "Ljava/lang/String;"), + ("C", "FEATURE_CAMERA_FRONT", "Ljava/lang/String;"), + ], + "Landroid/hardware/Camera;" : [ + ("C", "CAMERA_ERROR_SERVER_DIED", "I"), + ("C", "CAMERA_ERROR_UNKNOWN", "I"), + ("F", "setDisplayOrientation", "(I)"), + ("F", "native_setup", "(Ljava/lang/Object;)"), + ("F", "open", "()"), + ], +}, +"SET_WALLPAPER" : { + "Landroid/app/Activity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/ExpandableListActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/accessibilityservice/AccessibilityService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/accounts/GrantCredentialsPermissionActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/backup/BackupAgent;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/service/wallpaper/WallpaperService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/backup/BackupAgentHelper;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/accounts/AccountAuthenticatorActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/IWallpaperManager$Stub$Proxy;" : [ + ("F", "setWallpaper", "(Ljava/lang/String;)"), + ], + "Landroid/app/ActivityGroup;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/content/ContextWrapper;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/WallpaperManager;" : [ + ("F", "setBitmap", "(Landroid/graphics/Bitmap;)"), + ("F", "clear", "()"), + ("F", "setBitmap", "(Landroid/graphics/Bitmap;)"), + ("F", "setResource", "(I)"), + ("F", "setStream", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/ContextImpl;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/AliasActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/content/Context;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/service/urlrenderer/UrlRendererService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/FullBackupAgent;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/TabActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/view/ContextThemeWrapper;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/speech/RecognitionService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/IntentService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/inputmethodservice/AbstractInputMethodService;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/Application;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/ListActivity;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/app/Service;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], + "Landroid/content/MutableContextWrapper;" : [ + ("F", "clearWallpaper", "()"), + ("F", "setWallpaper", "(Landroid/graphics/Bitmap;)"), + ("F", "setWallpaper", "(Ljava/io/InputStream;)"), + ], +}, +"WAKE_LOCK" : { + "Landroid/net/wifi/IWifiManager$Stub$Proxy;" : [ + ("F", "acquireWifiLock", "(Landroid/os/IBinder; I Ljava/lang/String;)"), + ("F", "releaseWifiLock", "(Landroid/os/IBinder;)"), + ], + "Landroid/bluetooth/HeadsetBase;" : [ + ("F", "acquireWakeLock", "()"), + ("F", "finalize", "()"), + ("F", "handleInput", "(Ljava/lang/String;)"), + ("F", "releaseWakeLock", "()"), + ], + "Landroid/os/PowerManager$WakeLock;" : [ + ("F", "acquire", "()"), + ("F", "acquire", "(J)"), + ("F", "release", "()"), + ("F", "release", "(I)"), + ], + "Landroid/media/MediaPlayer;" : [ + ("F", "setWakeMode", "(Landroid/content/Context; I)"), + ("F", "start", "()"), + ("F", "stayAwake", "(B)"), + ("F", "stop", "()"), + ], + "Landroid/bluetooth/ScoSocket;" : [ + ("F", "acquireWakeLock", "()"), + ("F", "close", "()"), + ("F", "finalize", "()"), + ("F", "releaseWakeLock", "()"), + ("F", "releaseWakeLockNow", "()"), + ], + "Landroid/media/AsyncPlayer;" : [ + ("F", "acquireWakeLock", "()"), + ("F", "enqueueLocked", "(Landroid/media/AsyncPlayer$Command;)"), + ("F", "play", "(Landroid/content/Context; Landroid/net/Uri; B I)"), + ("F", "releaseWakeLock", "()"), + ("F", "stop", "()"), + ], + "Landroid/net/wifi/WifiManager$WifiLock;" : [ + ("F", "acquire", "()"), + ("F", "finalize", "()"), + ("F", "release", "()"), + ], + "Landroid/os/IPowerManager$Stub$Proxy;" : [ + ("F", "acquireWakeLock", "(I Landroid/os/IBinder; Ljava/lang/String;)"), + ("F", "releaseWakeLock", "(Landroid/os/IBinder; I)"), + ], + "Landroid/net/sip/SipAudioCall;" : [ + ("F", "startAudio", "()"), + ], + "Landroid/os/PowerManager;" : [ + ("C", "ACQUIRE_CAUSES_WAKEUP", "I"), + ("C", "FULL_WAKE_LOCK", "I"), + ("C", "ON_AFTER_RELEASE", "I"), + ("C", "PARTIAL_WAKE_LOCK", "I"), + ("C", "SCREEN_BRIGHT_WAKE_LOCK", "I"), + ("C", "SCREEN_DIM_WAKE_LOCK", "I"), + ("F", "newWakeLock", "(I Ljava/lang/String;)"), + ], +}, +"MANAGE_ACCOUNTS" : { + "Landroid/accounts/AccountManager;" : [ + ("F", "addAccount", "(Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "clearPassword", "(Landroid/accounts/Account;)"), + ("F", "confirmCredentials", "(Landroid/accounts/Account; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "editProperties", "(Ljava/lang/String; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "getAuthTokenByFeatures", "(Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Landroid/app/Activity; Landroid/os/Bundle; Landroid/os/Bundle; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "invalidateAuthToken", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "removeAccount", "(Landroid/accounts/Account; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "updateCredentials", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "addAccount", "(Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "clearPassword", "(Landroid/accounts/Account;)"), + ("F", "confirmCredentials", "(Landroid/accounts/Account; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "editProperties", "(Ljava/lang/String; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "invalidateAuthToken", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "removeAccount", "(Landroid/accounts/Account; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "updateCredentials", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ], + "Landroid/accounts/AccountManagerService;" : [ + ("F", "addAcount", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; B Landroid/os/Bundle;)"), + ("F", "checkManageAccountsOrUseCredentialsPermissions", "()"), + ("F", "checkManageAccountsPermission", "()"), + ("F", "clearPassword", "(Landroid/accounts/Account;)"), + ("F", "confirmCredentials", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Landroid/os/Bundle; B)"), + ("F", "editProperties", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; B)"), + ("F", "invalidateAuthToken", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "removeAccount", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account;)"), + ("F", "updateCredentials", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B Landroid/os/Bundle;)"), + ], + "Landroid/accounts/IAccountManager$Stub$Proxy;" : [ + ("F", "addAcount", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; B Landroid/os/Bundle;)"), + ("F", "clearPassword", "(Landroid/accounts/Account;)"), + ("F", "confirmCredentials", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Landroid/os/Bundle; B)"), + ("F", "editProperties", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; B)"), + ("F", "invalidateAuthToken", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "removeAccount", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account;)"), + ("F", "updateCredentials", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B Landroid/os/Bundle;)"), + ], +}, +"WRITE_CALENDAR" : { + "Landroid/provider/Calendar$CalendarAlerts;" : [ + ("F", "insert", "(Landroid/content/ContentResolver; J J J J I)"), + ], + "Landroid/provider/Calendar$Calendars;" : [ + ("F", "delete", "(Landroid/content/ContentResolver; Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ("F", "deleteCalendarsForAccount", "(Landroid/content/ContentResolver; Landroid/accounts/Account;)"), + ], +}, +"BIND_APPWIDGET" : { + "Landroid/appwidget/AppWidgetManager;" : [ + ("F", "bindAppWidgetId", "(I Landroid/content/ComponentName;)"), + ], + "Lcom/android/internal/appwidget/IAppWidgetService$Stub$Proxy;" : [ + ("F", "bindAppWidgetId", "(I LComponentName;)"), + ], +}, +"ASEC_MOUNT_UNMOUNT" : { + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "mountSecureContainer", "(Ljava/lang/String; Ljava/lang/String; I)"), + ("F", "unmountSecureContainer", "(Ljava/lang/String; B)"), + ], +}, +"SET_PREFERRED_APPLICATIONS" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "addPreferredActivity", "(LIntentFilter; I [LComponentName; LComponentName;)"), + ("F", "clearPackagePreferredActivities", "(Ljava/lang/String;)"), + ("F", "replacePreferredActivity", "(LIntentFilter; I [LComponentName; LComponentName;)"), + ("F", "addPreferredActivity", "(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)"), + ("F", "clearPackagePreferredActivities", "(Ljava/lang/String;)"), + ("F", "replacePreferredActivity", "(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "addPreferredActivity", "(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)"), + ("F", "clearPackagePreferredActivities", "(Ljava/lang/String;)"), + ("F", "replacePreferredActivity", "(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "addPreferredActivity", "(Landroid/content/IntentFilter; I [L[Landroid/content/ComponentNam; Landroid/content/ComponentName;)"), + ("F", "clearPackagePreferredActivities", "(Ljava/lang/String;)"), + ("F", "replacePreferredActivity", "(Landroid/content/IntentFilter; I [L[Landroid/content/ComponentNam; Landroid/content/ComponentName;)"), + ], +}, +"NFC" : { + "Landroid/inputmethodservice/InputMethodService;" : [ + ("C", "SoftInputView", "I"), + ("C", "CandidatesView", "I"), + ("C", "FullscreenMode", "I"), + ("C", "GeneratingText", "I"), + ], + "Landroid/nfc/tech/NfcA;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "get", "(Landroid/nfc/Tag;)"), + ("F", "transceive", "([B)"), + ], + "Landroid/nfc/tech/NfcB;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "get", "(Landroid/nfc/Tag;)"), + ("F", "transceive", "([B)"), + ], + "Landroid/nfc/NfcAdapter;" : [ + ("C", "ACTION_TECH_DISCOVERED", "Ljava/lang/String;"), + ("F", "disableForegroundDispatch", "(Landroid/app/Activity;)"), + ("F", "disableForegroundNdefPush", "(Landroid/app/Activity;)"), + ("F", "enableForegroundDispatch", "(Landroid/app/Activity; Landroid/app/PendingIntent; [Landroid/content/IntentFilter; [[Ljava/lang/String[];)"), + ("F", "enableForegroundNdefPush", "(Landroid/app/Activity; Landroid/nfc/NdefMessage;)"), + ("F", "getDefaultAdapter", "()"), + ("F", "getDefaultAdapter", "(Landroid/content/Context;)"), + ("F", "isEnabled", "()"), + ], + "Landroid/nfc/tech/NfcF;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "get", "(Landroid/nfc/Tag;)"), + ("F", "transceive", "([B)"), + ], + "Landroid/nfc/tech/NdefFormatable;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "format", "(Landroid/nfc/NdefMessage;)"), + ("F", "formatReadOnly", "(Landroid/nfc/NdefMessage;)"), + ], + "Landroid/app/Activity;" : [ + ("C", "Fragments", "I"), + ("C", "ActivityLifecycle", "I"), + ("C", "ConfigurationChanges", "I"), + ("C", "StartingActivities", "I"), + ("C", "SavingPersistentState", "I"), + ("C", "Permissions", "I"), + ("C", "ProcessLifecycle", "I"), + ], + "Landroid/nfc/tech/MifareClassic;" : [ + ("C", "KEY_NFC_FORUM", "[B"), + ("F", "authenticateSectorWithKeyA", "(I [B)"), + ("F", "authenticateSectorWithKeyB", "(I [B)"), + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "decrement", "(I I)"), + ("F", "increment", "(I I)"), + ("F", "readBlock", "(I)"), + ("F", "restore", "(I)"), + ("F", "transceive", "([B)"), + ("F", "transfer", "(I)"), + ("F", "writeBlock", "(I [B)"), + ], + "Landroid/nfc/Tag;" : [ + ("F", "getTechList", "()"), + ], + "Landroid/app/Service;" : [ + ("C", "WhatIsAService", "I"), + ("C", "ServiceLifecycle", "I"), + ("C", "Permissions", "I"), + ("C", "ProcessLifecycle", "I"), + ("C", "LocalServiceSample", "I"), + ("C", "RemoteMessengerServiceSample", "I"), + ], + "Landroid/nfc/NfcManager;" : [ + ("F", "getDefaultAdapter", "()"), + ], + "Landroid/nfc/tech/MifareUltralight;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "readPages", "(I)"), + ("F", "transceive", "([B)"), + ("F", "writePage", "(I [B)"), + ], + "Landroid/nfc/tech/NfcV;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "get", "(Landroid/nfc/Tag;)"), + ("F", "transceive", "([B)"), + ], + "Landroid/nfc/tech/TagTechnology;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ], + "Landroid/preference/PreferenceActivity;" : [ + ("C", "SampleCode", "Ljava/lang/String;"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("C", "FEATURE_NFC", "Ljava/lang/String;"), + ], + "Landroid/content/Context;" : [ + ("C", "NFC_SERVICE", "Ljava/lang/String;"), + ], + "Landroid/nfc/tech/Ndef;" : [ + ("C", "NFC_FORUM_TYPE_1", "Ljava/lang/String;"), + ("C", "NFC_FORUM_TYPE_2", "Ljava/lang/String;"), + ("C", "NFC_FORUM_TYPE_3", "Ljava/lang/String;"), + ("C", "NFC_FORUM_TYPE_4", "Ljava/lang/String;"), + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "getType", "()"), + ("F", "isWritable", "()"), + ("F", "makeReadOnly", "()"), + ("F", "writeNdefMessage", "(Landroid/nfc/NdefMessage;)"), + ], + "Landroid/nfc/tech/IsoDep;" : [ + ("F", "close", "()"), + ("F", "connect", "()"), + ("F", "setTimeout", "(I)"), + ("F", "transceive", "([B)"), + ], +}, +"CALL_PHONE" : { + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;" : [ + ("F", "call", "(Ljava/lang/String;)"), + ("F", "endCall", "()"), + ], +}, +"INTERNET" : { + "Lcom/android/http/multipart/FilePart;" : [ + ("F", "sendData", "(Ljava/io/OutputStream;)"), + ("F", "sendDispositionHeader", "(Ljava/io/OutputStream;)"), + ], + "Ljava/net/HttpURLConnection;" : [ + ("F", "", "(Ljava/net/URL;)"), + ("F", "connect", "()"), + ], + "Landroid/webkit/WebSettings;" : [ + ("F", "setBlockNetworkLoads", "(B)"), + ("F", "verifyNetworkAccess", "()"), + ], + "Lorg/apache/http/impl/client/DefaultHttpClient;" : [ + ("F", "", "()"), + ("F", "", "(Lorg/apache/http/params/HttpParams;)"), + ("F", "", "(Lorg/apache/http/conn/ClientConnectionManager; Lorg/apache/http/params/HttpParams;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)"), + ], + "Lorg/apache/http/impl/client/HttpClient;" : [ + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)"), + ("F", "execute", "(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest;)"), + ("F", "execute", "(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)"), + ], + "Lcom/android/http/multipart/Part;" : [ + ("F", "send", "(Ljava/io/OutputStream;)"), + ("F", "sendParts", "(Ljava/io/OutputStream; [Lcom/android/http/multipart/Part;)"), + ("F", "sendParts", "(Ljava/io/OutputStream; [Lcom/android/http/multipart/Part; [B)"), + ("F", "sendStart", "(Ljava/io/OutputStream;)"), + ("F", "sendTransferEncodingHeader", "(Ljava/io/OutputStream;)"), + ], + "Landroid/drm/DrmErrorEvent;" : [ + ("C", "TYPE_NO_INTERNET_CONNECTION", "I"), + ], + "Landroid/webkit/WebViewCore;" : [ + ("F", "", "(Landroid/content/Context; Landroid/webkit/WebView; Landroid/webkit/CallbackProxy; Ljava/util/Map;)"), + ], + "Ljava/net/URLConnection;" : [ + ("F", "connect", "()"), + ("F", "getInputStream", "()"), + ], + "Landroid/app/Activity;" : [ + ("F", "setContentView", "(I)"), + ], + "Ljava/net/MulticastSocket;" : [ + ("F", "", "()"), + ("F", "", "(I)"), + ("F", "", "(Ljava/net/SocketAddress;)"), + ], + "Lcom/android/http/multipart/StringPart;" : [ + ("F", "sendData", "(Ljava/io/OuputStream;)"), + ], + "Ljava/net/URL;" : [ + ("F", "getContent", "([Ljava/lang/Class;)"), + ("F", "getContent", "()"), + ("F", "openConnection", "(Ljava/net/Proxy;)"), + ("F", "openConnection", "()"), + ("F", "openStream", "()"), + ], + "Ljava/net/DatagramSocket;" : [ + ("F", "", "()"), + ("F", "", "(I)"), + ("F", "", "(I Ljava/net/InetAddress;)"), + ("F", "", "(Ljava/net/SocketAddress;)"), + ], + "Ljava/net/ServerSocket;" : [ + ("F", "", "()"), + ("F", "", "(I)"), + ("F", "", "(I I)"), + ("F", "", "(I I Ljava/net/InetAddress;)"), + ("F", "bind", "(Ljava/net/SocketAddress;)"), + ("F", "bind", "(Ljava/net/SocketAddress; I)"), + ], + "Ljava/net/Socket;" : [ + ("F", "", "()"), + ("F", "", "(Ljava/lang/String; I)"), + ("F", "", "(Ljava/lang/String; I Ljava/net/InetAddress; I)"), + ("F", "", "(Ljava/lang/String; I B)"), + ("F", "", "(Ljava/net/InetAddress; I)"), + ("F", "", "(Ljava/net/InetAddress; I Ljava/net/InetAddress; I)"), + ("F", "", "(Ljava/net/InetAddress; I B)"), + ], + "Landroid/webkit/WebView;" : [ + ("F", "", "(Landroid/content/Context; Landroid/util/AttributeSet; I)"), + ("F", "", "(Landroid/content/Context; Landroid/util/AttributeSet;)"), + ("F", "", "(Landroid/content/Context;)"), + ], + "Ljava/net/NetworkInterface;" : [ + ("F", "", "()"), + ("F", "", "(Ljava/lang/String; I Ljava/net/InetAddress;)"), + ], +}, +"ACCESS_FINE_LOCATION" : { + "Landroid/webkit/WebChromeClient;" : [ + ("F", "onGeolocationPermissionsShowPrompt", "(Ljava/lang/String; Landroid/webkit/GeolocationPermissions/Callback;)"), + ], + "Landroid/location/LocationManager;" : [ + ("C", "GPS_PROVIDER", "Ljava/lang/String;"), + ("C", "NETWORK_PROVIDER", "Ljava/lang/String;"), + ("C", "PASSIVE_PROVIDER", "Ljava/lang/String;"), + ("F", "addGpsStatusListener", "(Landroid/location/GpsStatus/Listener;)"), + ("F", "addNmeaListener", "(Landroid/location/GpsStatus/NmeaListener;)"), + ("F", "_requestLocationUpdates", "(Ljava/lang/String; J F Landroid/app/PendingIntent;)"), + ("F", "_requestLocationUpdates", "(Ljava/lang/String; J F Landroid/location/LocationListener; Landroid/os/Looper;)"), + ("F", "addGpsStatusListener", "(Landroid/location/GpsStatus$Listener;)"), + ("F", "addNmeaListener", "(Landroid/location/GpsStatus$NmeaListener;)"), + ("F", "addProximityAlert", "(D D F J Landroid/app/PendingIntent;)"), + ("F", "best", "(Ljava/util/List;)"), + ("F", "getBestProvider", "(Landroid/location/Criteria; B)"), + ("F", "getLastKnownLocation", "(Ljava/lang/String;)"), + ("F", "getProvider", "(Ljava/lang/String;)"), + ("F", "getProviders", "(Landroid/location/Criteria; B)"), + ("F", "getProviders", "(B)"), + ("F", "isProviderEnabled", "(Ljava/lang/String;)"), + ("F", "requestLocationUpdates", "(Ljava/lang/String; J F Landroid/app/PendingIntent;)"), + ("F", "requestLocationUpdates", "(Ljava/lang/String; J F Landroid/location/LocationListener; Landroid/os/Looper;)"), + ("F", "requestLocationUpdates", "(Ljava/lang/String; J F Landroid/location/LocationListener;)"), + ("F", "sendExtraCommand", "(Ljava/lang/String; Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/webkit/GeolocationService;" : [ + ("F", "registerForLocationUpdates", "()"), + ("F", "setEnableGps", "(B)"), + ("F", "start", "()"), + ], + "Landroid/telephony/TelephonyManager;" : [ + ("F", "getCellLocation", "()"), + ("F", "getCellLocation", "()"), + ("F", "getNeighboringCellInfo", "()"), + ], + "Landroid/location/ILocationManager$Stub$Proxy;" : [ + ("F", "addGpsStatusListener", "(Landroid/location/IGpsStatusListener;)"), + ("F", "addProximityAlert", "(D D F J Landroid/app/PendingIntent;)"), + ("F", "getLastKnownLocation", "(Ljava/lang/String;)"), + ("F", "getProviderInfo", "(Ljava/lang/String;)"), + ("F", "getProviders", "(B)"), + ("F", "isProviderEnabled", "(Ljava/lang/String;)"), + ("F", "requestLocationUpdates", "(Ljava/lang/String; J F Landroid/location/ILocationListener;)"), + ("F", "requestLocationUpdatesPI", "(Ljava/lang/String; J F Landroid/app/PendingIntent;)"), + ("F", "sendExtraCommand", "(Ljava/lang/String; Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;" : [ + ("F", "getCellLocation", "()"), + ("F", "getNeighboringCellInfo", "()"), + ], + "Landroid/webkit/GeolocationPermissions$Callback;" : [ + ("F", "invok", "()"), + ], +}, +"READ_SMS" : { + "Landroid/provider/Telephony$Sms$Inbox;" : [ + ("F", "addMessage", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B)"), + ], + "Landroid/provider/Telephony$Threads;" : [ + ("F", "getOrCreateThreadId", "(Landroid/content/Context; Ljava/lang/String;)"), + ("F", "getOrCreateThreadId", "(Landroid/content/Context; Ljava/util/Set;)"), + ], + "Landroid/provider/Telephony$Mms;" : [ + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)"), + ], + "Landroid/provider/Telephony$Sms$Draft;" : [ + ("F", "addMessage", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long;)"), + ], + "Landroid/provider/Telephony$Sms$Sent;" : [ + ("F", "addMessage", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long;)"), + ], + "Landroid/provider/Telephony$Sms;" : [ + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "query", "(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)"), + ], +}, +"ACCESS_SURFACE_FLINGER" : { + "Landroid/view/SurfaceSession;" : [ + ("F", "", "()"), + ], + "Landroid/view/Surface;" : [ + ("F", "closeTransaction", "()"), + ("F", "freezeDisplay", "(I)"), + ("F", "setOrientation", "(I I I)"), + ("F", "setOrientation", "(I I)"), + ("F", "unfreezeDisplay", "(I)"), + ], +}, +"REORDER_TASKS" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "moveTaskBackwards", "(I)"), + ("F", "moveTaskToBack", "(I)"), + ("F", "moveTaskToFront", "(I)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "moveTaskToFront", "(I I)"), + ], +}, +"MODIFY_AUDIO_SETTINGS" : { + "Landroid/net/sip/SipAudioCall;" : [ + ("F", "setSpeakerMode", "(B)"), + ], + "Landroid/server/BluetoothA2dpService;" : [ + ("F", "checkSinkSuspendState", "(I)"), + ("F", "handleSinkStateChange", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "onBluetoothDisable", "()"), + ("F", "onBluetoothEnable", "()"), + ], + "Landroid/media/IAudioService$Stub$Proxy;" : [ + ("F", "setBluetoothScoOn", "(B)"), + ("F", "setMode", "(I Landroid/os/IBinder;)"), + ("F", "setSpeakerphoneOn", "(B)"), + ("F", "startBluetoothSco", "(Landroid/os/IBinder;)"), + ("F", "stopBluetoothSco", "(Landroid/os/IBinder;)"), + ], + "Landroid/media/AudioService;" : [ + ("F", "setBluetoothScoOn", "(B)"), + ("F", "setMode", "(I Landroid/os/IBinder;)"), + ("F", "setSpeakerphoneOn", "(B)"), + ("F", "startBluetoothSco", "(Landroid/os/IBinder;)"), + ("F", "stopBluetoothSco", "(Landroid/os/IBinder;)"), + ], + "Landroid/media/AudioManager;" : [ + ("F", "startBluetoothSco", "()"), + ("F", "stopBluetoothSco", "()"), + ("F", "isBluetoothA2dpOn", "()"), + ("F", "isWiredHeadsetOn", "()"), + ("F", "setBluetoothScoOn", "(B)"), + ("F", "setMicrophoneMute", "(B)"), + ("F", "setMode", "(I)"), + ("F", "setParameter", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setParameters", "(Ljava/lang/String;)"), + ("F", "setSpeakerphoneOn", "(B)"), + ("F", "startBluetoothSco", "()"), + ("F", "stopBluetoothSco", "()"), + ], +}, +"READ_PHONE_STATE" : { + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;" : [ + ("F", "getDeviceId", "()"), + ("F", "getDeviceSvn", "()"), + ("F", "getIccSerialNumber", "()"), + ("F", "getLine1AlphaTag", "()"), + ("F", "getLine1Number", "()"), + ("F", "getSubscriberId", "()"), + ("F", "getVoiceMailAlphaTag", "()"), + ("F", "getVoiceMailNumber", "()"), + ], + "Landroid/telephony/PhoneStateListener;" : [ + ("C", "LISTEN_CALL_FORWARDING_INDICATOR", "I"), + ("C", "LISTEN_CALL_STATE", "I"), + ("C", "LISTEN_DATA_ACTIVITY", "I"), + ("C", "LISTEN_MESSAGE_WAITING_INDICATOR", "I"), + ("C", "LISTEN_SIGNAL_STRENGTH", "I"), + ], + "Landroid/accounts/AccountManagerService$SimWatcher;" : [ + ("F", "onReceive", "(Landroid/content/Context; Landroid/content/Intent;)"), + ], + "Lcom/android/internal/telephony/CallerInfo;" : [ + ("F", "markAsVoiceMail", "()"), + ], + "Landroid/os/Build/VERSION_CODES;" : [ + ("C", "DONUT", "I"), + ], + "Landroid/telephony/TelephonyManager;" : [ + ("C", "ACTION_PHONE_STATE_CHANGED", "Ljava/lang/String;"), + ("F", "getDeviceId", "()"), + ("F", "getDeviceSoftwareVersion", "()"), + ("F", "getLine1Number", "()"), + ("F", "getSimSerialNumber", "()"), + ("F", "getSubscriberId", "()"), + ("F", "getVoiceMailAlphaTag", "()"), + ("F", "getVoiceMailNumber", "()"), + ("F", "getDeviceId", "()"), + ("F", "getDeviceSoftwareVersion", "()"), + ("F", "getLine1AlphaTag", "()"), + ("F", "getLine1Number", "()"), + ("F", "getSimSerialNumber", "()"), + ("F", "getSubscriberId", "()"), + ("F", "getVoiceMailAlphaTag", "()"), + ("F", "getVoiceMailNumber", "()"), + ("F", "listen", "(Landroid/telephony/PhoneStateListener; I)"), + ], + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;" : [ + ("F", "listen", "(Ljava/lang/String; Lcom/android/internal/telephony/IPhoneStateListener; I B)"), + ], + "Landroid/telephony/PhoneNumberUtils;" : [ + ("F", "isVoiceMailNumber", "(Ljava/lang/String;)"), + ], + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;" : [ + ("F", "isSimPinEnabled", "()"), + ], +}, +"WRITE_SETTINGS" : { + "Landroid/media/RingtoneManager;" : [ + ("F", "setActualDefaultRingtoneUri", "(Landroid/content/Context; I Landroid/net/Uri;)"), + ], + "Landroid/os/IPowerManager$Stub$Proxy;" : [ + ("F", "setStayOnSetting", "(I)"), + ], + "Landroid/server/BluetoothService;" : [ + ("F", "persistBluetoothOnSetting", "(B)"), + ], + "Landroid/provider/Settings$Secure;" : [ + ("F", "putFloat", "(Landroid/content/ContentResolver; Ljava/lang/String; F)"), + ("F", "putInt", "(Landroid/content/ContentResolver; Ljava/lang/String; I)"), + ("F", "putLong", "(Landroid/content/ContentResolver; Ljava/lang/String; J)"), + ("F", "putString", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setLocationProviderEnabled", "(Landroid/content/ContentResolver; Ljava/lang/String; B)"), + ], + "Landroid/provider/Settings$Bookmarks;" : [ + ("F", "add", "(Landroid/content/ContentResolver; Landroid/content/Intent; Ljava/lang/String; Ljava/lang/String; C I)"), + ("F", "getIntentForShortcut", "(Landroid/content/ContentResolver; C)"), + ], + "Landroid/os/IMountService$Stub$Proxy;" : [ + ("F", "setAutoStartUm", "()"), + ("F", "setPlayNotificationSound", "()"), + ], + "Landroid/provider/Settings$System;" : [ + ("F", "putConfiguration", "(Landroid/content/ContentResolver; Landroid/content/res/Configuration;)"), + ("F", "putFloat", "(Landroid/content/ContentResolver; Ljava/lang/String; F)"), + ("F", "putInt", "(Landroid/content/ContentResolver; Ljava/lang/String; I)"), + ("F", "putLong", "(Landroid/content/ContentResolver; Ljava/lang/String; J)"), + ("F", "putString", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setShowGTalkServiceStatus", "(Landroid/content/ContentResolver; B)"), + ], +}, +"BIND_WALLPAPER" : { + "Landroid/service/wallpaper/WallpaperService;" : [ + ("C", "SERVICE_INTERFACE", "Ljava/lang/String;"), + ], + "Lcom/android/server/WallpaperManagerService;" : [ + ("F", "bindWallpaperComponentLocked", "(Landroid/content/ComponentName;)"), + ], +}, +"DUMP" : { + "Landroid/content/ContentService;" : [ + ("F", "dump", "(Ljava/io/FileDescriptor; Ljava/io/PrintWriter; [L[Ljava/lang/Strin;)"), + ], + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "isViewServerRunning", "()"), + ("F", "startViewServer", "(I)"), + ("F", "stopViewServer", "()"), + ], + "Landroid/os/Debug;" : [ + ("F", "dumpService", "(Ljava/lang/String; Ljava/io/FileDescriptor; [Ljava/lang/String;)"), + ], + "Landroid/os/IBinder;" : [ + ("C", "DUMP_TRANSACTION", "I"), + ], + "Lcom/android/server/WallpaperManagerService;" : [ + ("F", "dump", "(Ljava/io/FileDescriptor; Ljava/io/PrintWriter; [L[Ljava/lang/Stri;)"), + ], +}, +"USE_CREDENTIALS" : { + "Landroid/accounts/AccountManager;" : [ + ("F", "blockingGetAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ("F", "getAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "getAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; B Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "invalidateAuthToken", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "blockingGetAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ("F", "getAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "getAuthToken", "(Landroid/accounts/Account; Ljava/lang/String; B Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ], + "Landroid/accounts/AccountManagerService;" : [ + ("F", "getAuthToken", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B B Landroid/os/Bundle;)"), + ], + "Landroid/accounts/IAccountManager$Stub$Proxy;" : [ + ("F", "getAuthToken", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B B Landroid/os/Bundle;)"), + ], +}, +"UPDATE_DEVICE_STATS" : { + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;" : [ + ("F", "notePauseComponent", "(LComponentName;)"), + ("F", "noteResumeComponent", "(LComponentName;)"), + ], + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;" : [ + ("F", "noteFullWifiLockAcquired", "(I)"), + ("F", "noteFullWifiLockReleased", "(I)"), + ("F", "noteInputEvent", "()"), + ("F", "notePhoneDataConnectionState", "(I B)"), + ("F", "notePhoneOff", "()"), + ("F", "notePhoneOn", "()"), + ("F", "notePhoneSignalStrength", "(LSignalStrength;)"), + ("F", "notePhoneState", "(I)"), + ("F", "noteScanWifiLockAcquired", "(I)"), + ("F", "noteScanWifiLockReleased", "(I)"), + ("F", "noteScreenBrightness", "(I)"), + ("F", "noteScreenOff", "()"), + ("F", "noteScreenOn", "()"), + ("F", "noteStartGps", "(I)"), + ("F", "noteStartSensor", "(I I)"), + ("F", "noteStartWakelock", "(I Ljava/lang/String; I)"), + ("F", "noteStopGps", "(I)"), + ("F", "noteStopSensor", "(I I)"), + ("F", "noteStopWakelock", "(I Ljava/lang/String; I)"), + ("F", "noteUserActivity", "(I I)"), + ("F", "noteWifiMulticastDisabled", "(I)"), + ("F", "noteWifiMulticastEnabled", "(I)"), + ("F", "noteWifiOff", "(I)"), + ("F", "noteWifiOn", "(I)"), + ("F", "noteWifiRunning", "()"), + ("F", "noteWifiStopped", "()"), + ("F", "recordCurrentLevel", "(I)"), + ("F", "setOnBattery", "(B I)"), + ], +}, +"SEND_SMS" : { + "Landroid/telephony/gsm/SmsManager;" : [ + ("F", "getDefault", "()"), + ("F", "sendDataMessage", "(Ljava/lang/String; Ljava/lang/String; S [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendDataMessage", "(Ljava/lang/String; Ljava/lang/String; S [L; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendMultipartTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/util/ArrayList; Ljava/util/ArrayList; Ljava/util/ArrayList;)"), + ("F", "sendTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ], + "Landroid/telephony/SmsManager;" : [ + ("F", "getDefault", "()"), + ("F", "sendDataMessage", "(Ljava/lang/String; Ljava/lang/String; S [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendDataMessage", "(Ljava/lang/String; Ljava/lang/String; S [L; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendMultipartTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/util/ArrayList; Ljava/util/ArrayList; Ljava/util/ArrayList;)"), + ("F", "sendTextMessage", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ], + "Lcom/android/internal/telephony/ISms$Stub$Proxy;" : [ + ("F", "sendData", "(Ljava/lang/String; Ljava/lang/String; I [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ("F", "sendMultipartText", "(Ljava/lang/String; Ljava/lang/String; Ljava/util/List; Ljava/util/List; Ljava/util/List;)"), + ("F", "sendText", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)"), + ], +}, +"WRITE_USER_DICTIONARY" : { + "Landroid/provider/UserDictionary$Words;" : [ + ("F", "addWord", "(Landroid/content/Context; Ljava/lang/String; I I)"), + ], +}, +"ACCESS_COARSE_LOCATION" : { + "Landroid/telephony/TelephonyManager;" : [ + ("F", "getCellLocation", "()"), + ], + "Landroid/telephony/PhoneStateListener;" : [ + ("C", "LISTEN_CELL_LOCATION", "I"), + ], + "Landroid/location/LocationManager;" : [ + ("C", "NETWORK_PROVIDER", "Ljava/lang/String;"), + ], +}, +"ASEC_RENAME" : { + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "renameSecureContainer", "(Ljava/lang/String; Ljava/lang/String;)"), + ], +}, +"SYSTEM_ALERT_WINDOW" : { + "Landroid/view/IWindowSession$Stub$Proxy;" : [ + ("F", "add", "(Landroid/view/IWindow; Landroid/view/WindowManager$LayoutParams; I Landroid/graphics/Rect;)"), + ], +}, +"CHANGE_WIFI_MULTICAST_STATE" : { + "Landroid/net/wifi/IWifiManager$Stub$Proxy;" : [ + ("F", "acquireMulticastLock", "(Landroid/os/IBinder; Ljava/lang/String;)"), + ("F", "initializeMulticastFiltering", "()"), + ("F", "releaseMulticastLock", "()"), + ], + "Landroid/net/wifi/WifiManager$MulticastLock;" : [ + ("F", "acquire", "()"), + ("F", "finalize", "()"), + ("F", "release", "()"), + ], + "Landroid/net/wifi/WifiManager;" : [ + ("F", "initializeMulticastFiltering", "()"), + ], +}, +"RECEIVE_BOOT_COMPLETED" : { + "Landroid/content/Intent;" : [ + ("C", "ACTION_BOOT_COMPLETED", "Ljava/lang/String;"), + ], +}, +"SET_ALARM" : { + "Landroid/provider/AlarmClock;" : [ + ("C", "ACTION_SET_ALARM", "Ljava/lang/String;"), + ("C", "EXTRA_HOUR", "Ljava/lang/String;"), + ("C", "EXTRA_MESSAGE", "Ljava/lang/String;"), + ("C", "EXTRA_MINUTES", "Ljava/lang/String;"), + ("C", "EXTRA_SKIP_UI", "Ljava/lang/String;"), + ], +}, +"WRITE_CONTACTS" : { + "Lcom/android/internal/telephony/IccPhoneBookInterfaceManager$Stub$Proxy;" : [ + ("F", "updateAdnRecordsInEfByIndex", "(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "updateAdnRecordsInEfBySearch", "(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/provider/Contacts$People;" : [ + ("F", "addToGroup", "(Landroid/content/ContentResolver; J J)"), + ], + "Landroid/provider/ContactsContract$Contacts;" : [ + ("F", "markAsContacted", "(Landroid/content/ContentResolver; J)"), + ], + "Landroid/provider/Contacts$Settings;" : [ + ("F", "setSetting", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;" : [ + ("F", "updateAdnRecordsInEfByIndex", "(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "updateAdnRecordsInEfBySearch", "(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/provider/CallLog$Calls;" : [ + ("F", "removeExpiredEntries", "(Landroid/content/Context;)"), + ], + "Landroid/pim/vcard/VCardEntryCommitter;" : [ + ("F", "onEntryCreated", "(Landroid/pim/vcard/VCardEntry;)"), + ], + "Landroid/pim/vcard/VCardEntryHandler;" : [ + ("F", "onEntryCreated", "(Landroid/pim/vcard/VCardEntry;)"), + ], + "Landroid/pim/vcard/VCardEntry;" : [ + ("F", "pushIntoContentResolver", "(Landroid/content/ContentResolver;)"), + ], +}, +"PROCESS_OUTGOING_CALLS" : { + "Landroid/content/Intent;" : [ + ("C", "ACTION_NEW_OUTGOING_CALL", "Ljava/lang/String;"), + ], +}, +"EXPAND_STATUS_BAR" : { + "Landroid/app/StatusBarManager;" : [ + ("F", "collapse", "()"), + ("F", "expand", "()"), + ("F", "toggle", "()"), + ], + "Landroid/app/IStatusBar$Stub$Proxy;" : [ + ("F", "activate", "()"), + ("F", "deactivate", "()"), + ("F", "toggle", "()"), + ], +}, +"MODIFY_PHONE_STATE" : { + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;" : [ + ("F", "answerRingingCall", "()"), + ("F", "cancelMissedCallsNotification", "()"), + ("F", "disableApnType", "(Ljava/lang/String;)"), + ("F", "disableDataConnectivity", "()"), + ("F", "enableApnType", "(Ljava/lang/String;)"), + ("F", "enableDataConnectivity", "()"), + ("F", "handlePinMmi", "(Ljava/lang/String;)"), + ("F", "setRadio", "(B)"), + ("F", "silenceRinger", "()"), + ("F", "supplyPin", "(Ljava/lang/String;)"), + ("F", "toggleRadioOnOff", "()"), + ], + "Landroid/net/MobileDataStateTracker;" : [ + ("F", "reconnect", "()"), + ("F", "setRadio", "(B)"), + ("F", "teardown", "()"), + ], + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;" : [ + ("F", "notifyCallForwardingChanged", "(B)"), + ("F", "notifyCallState", "(I Ljava/lang/String;)"), + ("F", "notifyCellLocation", "(Landroid/os/Bundle;)"), + ("F", "notifyDataActivity", "(I)"), + ("F", "notifyDataConnection", "(I B Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Ljava/lang/String; I)"), + ("F", "notifyDataConnectionFailed", "(Ljava/lang/String;)"), + ("F", "notifyMessageWaitingChanged", "(B)"), + ("F", "notifyServiceState", "(Landroid/telephony/ServiceState;)"), + ("F", "notifySignalStrength", "(Landroid/telephony/SignalStrength;)"), + ], +}, +"MOUNT_FORMAT_FILESYSTEMS" : { + "Landroid/os/IMountService$Stub$Proxy;" : [ + ("F", "formatMedi", "()"), + ], + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "formatVolume", "(Ljava/lang/String;)"), + ], +}, +"ACCESS_DOWNLOAD_MANAGER" : { + "Landroid/net/Downloads$DownloadBase;" : [ + ("F", "startDownloadByUri", "(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/net/Downloads$ByUri;" : [ + ("F", "getCurrentOtaDownloads", "(Landroid/content/Context; Ljava/lang/String;)"), + ("F", "getProgressCursor", "(Landroid/content/Context; J)"), + ("F", "getStatus", "(Landroid/content/Context; Ljava/lang/String; J)"), + ("F", "removeAllDownloadsByPackage", "(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "startDownloadByUri", "(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/net/Downloads$ById;" : [ + ("F", "deleteDownload", "(Landroid/content/Context; J)"), + ("F", "getMimeTypeForId", "(Landroid/content/Context; J)"), + ("F", "getStatus", "(Landroid/content/Context; J)"), + ("F", "openDownload", "(Landroid/content/Context; J Ljava/lang/String;)"), + ("F", "openDownloadStream", "(Landroid/content/Context; J)"), + ("F", "startDownloadByUri", "(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ], +}, +"READ_INPUT_STATE" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "getDPadKeycodeState", "(I)"), + ("F", "getDPadScancodeState", "(I)"), + ("F", "getKeycodeState", "(I)"), + ("F", "getKeycodeStateForDevice", "(I I)"), + ("F", "getScancodeState", "(I)"), + ("F", "getScancodeStateForDevice", "(I I)"), + ("F", "getSwitchState", "(I)"), + ("F", "getSwitchStateForDevice", "(I I)"), + ("F", "getTrackballKeycodeState", "(I)"), + ("F", "getTrackballScancodeState", "(I)"), + ], +}, +"READ_SYNC_STATS" : { + "Landroid/app/ContextImpl$ApplicationContentResolver;" : [ + ("F", "getCurrentSync", "()"), + ("F", "getSyncStatus", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncActive", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncPending", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/ContentService;" : [ + ("F", "getCurrentSync", "()"), + ("F", "getSyncStatus", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncActive", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncPending", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/ContentResolver;" : [ + ("F", "getCurrentSync", "()"), + ("F", "getSyncStatus", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncActive", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncPending", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], + "Landroid/content/IContentService$Stub$Proxy;" : [ + ("F", "getCurrentSync", "()"), + ("F", "getSyncStatus", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncActive", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ("F", "isSyncPending", "(Landroid/accounts/Account; Ljava/lang/String;)"), + ], +}, +"SET_TIME" : { + "Landroid/app/AlarmManager;" : [ + ("F", "setTime", "(J)"), + ("F", "setTimeZone", "(Ljava/lang/String;)"), + ("F", "setTime", "(J)"), + ], + "Landroid/app/IAlarmManager$Stub$Proxy;" : [ + ("F", "setTime", "(J)"), + ], +}, +"CHANGE_WIMAX_STATE" : { + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;" : [ + ("F", "setWimaxEnable", "()"), + ], +}, +"MOUNT_UNMOUNT_FILESYSTEMS" : { + "Landroid/os/IMountService$Stub$Proxy;" : [ + ("F", "mountMedi", "()"), + ("F", "unmountMedi", "()"), + ], + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "getStorageUsers", "(Ljava/lang/String;)"), + ("F", "mountVolume", "(Ljava/lang/String;)"), + ("F", "setUsbMassStorageEnabled", "(B)"), + ("F", "unmountVolume", "(Ljava/lang/String; B)"), + ], + "Landroid/os/storage/StorageManager;" : [ + ("F", "disableUsbMassStorage", "()"), + ("F", "enableUsbMassStorage", "()"), + ], +}, +"MOVE_PACKAGE" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "movePackage", "(Ljava/lang/String; LIPackageMoveObserver; I)"), + ("F", "movePackage", "(Ljava/lang/String; LIPackageMoveObserver; I)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "movePackage", "(Ljava/lang/String; LIPackageMoveObserver; I)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "movePackage", "(Ljava/lang/String; Landroid/content/pm/IPackageMoveObserver; I)"), + ], +}, +"ACCESS_WIMAX_STATE" : { + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;" : [ + ("F", "getConnectionInf", "()"), + ("F", "getWimaxStat", "()"), + ("F", "isBackoffStat", "()"), + ("F", "isWimaxEnable", "()"), + ], +}, +"ACCESS_WIFI_STATE" : { + "Landroid/net/sip/SipAudioCall;" : [ + ("F", "startAudio", "()"), + ], + "Landroid/net/wifi/IWifiManager$Stub$Proxy;" : [ + ("F", "getConfiguredNetworks", "()"), + ("F", "getConnectionInfo", "()"), + ("F", "getDhcpInfo", "()"), + ("F", "getNumAllowedChannels", "()"), + ("F", "getScanResults", "()"), + ("F", "getValidChannelCounts", "()"), + ("F", "getWifiApEnabledState", "()"), + ("F", "getWifiEnabledState", "()"), + ("F", "isMulticastEnabled", "()"), + ], + "Landroid/net/wifi/WifiManager;" : [ + ("F", "getConfiguredNetworks", "()"), + ("F", "getConnectionInfo", "()"), + ("F", "getDhcpInfo", "()"), + ("F", "getNumAllowedChannels", "()"), + ("F", "getScanResults", "()"), + ("F", "getValidChannelCounts", "()"), + ("F", "getWifiApState", "()"), + ("F", "getWifiState", "()"), + ("F", "isMulticastEnabled", "()"), + ("F", "isWifiApEnabled", "()"), + ("F", "isWifiEnabled", "()"), + ], +}, +"READ_HISTORY_BOOKMARKS" : { + "Landroid/webkit/WebIconDatabase;" : [ + ("F", "bulkRequestIconForPageUrl", "(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase$IconListener;)"), + ], + "Landroid/provider/Browser;" : [ + ("C", "BOOKMARKS_URI", "Landroid/net/Uri;"), + ("C", "SEARCHES_URI", "Landroid/net/Uri;"), + ("F", "addSearchUrl", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "canClearHistory", "(Landroid/content/ContentResolver;)"), + ("F", "getAllBookmarks", "(Landroid/content/ContentResolver;)"), + ("F", "getAllVisitedUrls", "(Landroid/content/ContentResolver;)"), + ("F", "requestAllIcons", "(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase/IconListener;)"), + ("F", "truncateHistory", "(Landroid/content/ContentResolver;)"), + ("F", "updateVisitedHistory", "(Landroid/content/ContentResolver; Ljava/lang/String; B)"), + ("F", "addSearchUrl", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "canClearHistory", "(Landroid/content/ContentResolver;)"), + ("F", "clearHistory", "(Landroid/content/ContentResolver;)"), + ("F", "deleteFromHistory", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "deleteHistoryTimeFrame", "(Landroid/content/ContentResolver; J J)"), + ("F", "deleteHistoryWhere", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "getAllBookmarks", "(Landroid/content/ContentResolver;)"), + ("F", "getAllVisitedUrls", "(Landroid/content/ContentResolver;)"), + ("F", "getVisitedHistory", "(Landroid/content/ContentResolver;)"), + ("F", "getVisitedLike", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "requestAllIcons", "(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase$IconListener;)"), + ("F", "truncateHistory", "(Landroid/content/ContentResolver;)"), + ("F", "updateVisitedHistory", "(Landroid/content/ContentResolver; Ljava/lang/String; B)"), + ], +}, +"ASEC_DESTROY" : { + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "destroySecureContainer", "(Ljava/lang/String; B)"), + ], +}, +"ACCESS_NETWORK_STATE" : { + "Landroid/net/ThrottleManager;" : [ + ("F", "getByteCount", "(Ljava/lang/String; I I I)"), + ("F", "getCliffLevel", "(Ljava/lang/String; I)"), + ("F", "getCliffThreshold", "(Ljava/lang/String; I)"), + ("F", "getHelpUri", "()"), + ("F", "getPeriodStartTime", "(Ljava/lang/String;)"), + ("F", "getResetTime", "(Ljava/lang/String;)"), + ], + "Landroid/net/NetworkInfo;" : [ + ("F", "isConnectedOrConnecting", "()"), + ], + "Landroid/os/INetworkManagementService$Stub$Proxy;" : [ + ("F", "getDnsForwarders", "()"), + ("F", "getInterfaceRxCounter", "(Ljava/lang/String;)"), + ("F", "getInterfaceRxThrottle", "(Ljava/lang/String;)"), + ("F", "getInterfaceTxCounter", "(Ljava/lang/String;)"), + ("F", "getInterfaceTxThrottle", "(Ljava/lang/String;)"), + ("F", "getIpForwardingEnabled", "()"), + ("F", "isTetheringStarted", "()"), + ("F", "isUsbRNDISStarted", "()"), + ("F", "listInterfaces", "()"), + ("F", "listTetheredInterfaces", "()"), + ("F", "listTtys", "()"), + ], + "Landroid/net/IConnectivityManager$Stub$Proxy;" : [ + ("F", "getActiveNetworkInfo", "()"), + ("F", "getAllNetworkInfo", "()"), + ("F", "getLastTetherError", "(Ljava/lang/String;)"), + ("F", "getMobileDataEnabled", "()"), + ("F", "getNetworkInfo", "(I)"), + ("F", "getNetworkPreference", "()"), + ("F", "getTetherableIfaces", "()"), + ("F", "getTetherableUsbRegexs", "()"), + ("F", "getTetherableWifiRegexs", "()"), + ("F", "getTetheredIfaces", "()"), + ("F", "getTetheringErroredIfaces", "()"), + ("F", "isTetheringSupported", "()"), + ("F", "startUsingNetworkFeature", "(I Ljava/lang/String; Landroid/os/IBinder;)"), + ], + "Landroid/net/IThrottleManager$Stub$Proxy;" : [ + ("F", "getByteCount", "(Ljava/lang/String; I I I)"), + ("F", "getCliffLevel", "(Ljava/lang/String; I)"), + ("F", "getCliffThreshold", "(Ljava/lang/String; I)"), + ("F", "getHelpUri", "()"), + ("F", "getPeriodStartTime", "(Ljava/lang/String;)"), + ("F", "getResetTime", "(Ljava/lang/String;)"), + ("F", "getThrottle", "(Ljava/lang/String;)"), + ], + "Landroid/net/ConnectivityManager;" : [ + ("F", "getActiveNetworkInfo", "()"), + ("F", "getAllNetworkInfo", "()"), + ("F", "getLastTetherError", "(Ljava/lang/String;)"), + ("F", "getMobileDataEnabled", "()"), + ("F", "getNetworkInfo", "(I)"), + ("F", "getNetworkPreference", "()"), + ("F", "getTetherableIfaces", "()"), + ("F", "getTetherableUsbRegexs", "()"), + ("F", "getTetherableWifiRegexs", "()"), + ("F", "getTetheredIfaces", "()"), + ("F", "getTetheringErroredIfaces", "()"), + ("F", "isTetheringSupported", "()"), + ], + "Landroid/net/http/RequestQueue;" : [ + ("F", "enablePlatformNotifications", "()"), + ("F", "setProxyConfig", "()"), + ], +}, +"GET_TASKS" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "getRecentTasks", "(I I)"), + ("F", "getTasks", "(I I Landroid/app/IThumbnailReceiver;)"), + ], + "Landroid/app/ActivityManagerNative;" : [ + ("F", "getRecentTasks", "(I I)"), + ("F", "getRunningTasks", "(I)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "getRecentTasks", "(I I)"), + ("F", "getRunningTasks", "(I)"), + ("F", "getRecentTasks", "(I I)"), + ("F", "getRunningTasks", "(I)"), + ], +}, +"STATUS_BAR" : { + "Landroid/view/View/OnSystemUiVisibilityChangeListener;" : [ + ("F", "onSystemUiVisibilityChange", "(I)"), + ], + "Landroid/view/View;" : [ + ("C", "STATUS_BAR_HIDDEN", "I"), + ("C", "STATUS_BAR_VISIBLE", "I"), + ], + "Landroid/app/StatusBarManager;" : [ + ("F", "addIcon", "(Ljava/lang/String; I I)"), + ("F", "disable", "(I)"), + ("F", "removeIcon", "(Landroid/os/IBinder;)"), + ("F", "updateIcon", "(Landroid/os/IBinder; Ljava/lang/String; I I)"), + ], + "Landroid/view/WindowManager/LayoutParams;" : [ + ("C", "TYPE_STATUS_BAR", "I"), + ("C", "TYPE_STATUS_BAR_PANEL", "I"), + ("C", "systemUiVisibility", "I"), + ("C", "type", "I"), + ], + "Landroid/app/IStatusBar$Stub$Proxy;" : [ + ("F", "addIcon", "(Ljava/lang/String; Ljava/lang/String; I I)"), + ("F", "disable", "(I Landroid/os/IBinder; Ljava/lang/String;)"), + ("F", "removeIcon", "(Landroid/os/IBinder;)"), + ("F", "updateIcon", "(Landroid/os/IBinder; Ljava/lang/String; Ljava/lang/String; I I)"), + ], +}, +"SHUTDOWN" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "shutdown", "(I)"), + ], + "Landroid/os/IMountService$Stub$Proxy;" : [ + ("F", "shutdow", "()"), + ], + "Landroid/os/storage/IMountService$Stub$Proxy;" : [ + ("F", "shutdown", "(Landroid/os/storage/IMountShutdownObserver;)"), + ], + "Landroid/os/INetworkManagementService$Stub$Proxy;" : [ + ("F", "shutdown", "()"), + ], +}, +"READ_LOGS" : { + "Landroid/os/DropBoxManager;" : [ + ("C", "ACTION_DROPBOX_ENTRY_ADDED", "Ljava/lang/String;"), + ("F", "getNextEntry", "(Ljava/lang/String; J)"), + ("F", "getNextEntry", "(Ljava/lang/String; J)"), + ], + "Lcom/android/internal/os/IDropBoxManagerService$Stub$Proxy;" : [ + ("F", "getNextEntry", "(Ljava/lang/String; J)"), + ], + "Ljava/lang/Runtime;" : [ + ("F", "exec", "(Ljava/lang/String;)"), + ("F", "exec", "([Ljava/lang/String;)"), + ("F", "exec", "([Ljava/lang/String; [Ljava/lang/String;)"), + ("F", "exec", "([Ljava/lang/String; [Ljava/lang/String; Ljava/io/File;)"), + ("F", "exec", "(Ljava/lang/String; [Ljava/lang/String;)"), + ("F", "exec", "(Ljava/lang/String; [Ljava/lang/String; Ljava/io/File;)"), + ], +}, +"BLUETOOTH" : { + "Landroid/os/Process;" : [ + ("C", "BLUETOOTH_GID", "I"), + ], + "Landroid/bluetooth/BluetoothA2dp;" : [ + ("C", "ACTION_CONNECTION_STATE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_PLAYING_STATE_CHANGED", "Ljava/lang/String;"), + ("F", "getConnectedDevices", "()"), + ("F", "getConnectionState", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getDevicesMatchingConnectionStates", "([I)"), + ("F", "isA2dpPlaying", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getConnectedSinks", "()"), + ("F", "getNonDisconnectedSinks", "()"), + ("F", "getSinkPriority", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getSinkState", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "isSinkConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/media/AudioManager;" : [ + ("C", "ROUTE_BLUETOOTH", "I"), + ("C", "ROUTE_BLUETOOTH_A2DP", "I"), + ("C", "ROUTE_BLUETOOTH_SCO", "I"), + ], + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;" : [ + ("F", "getConnectedSinks", "()"), + ("F", "getNonDisconnectedSinks", "()"), + ("F", "getSinkPriority", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getSinkState", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/bluetooth/BluetoothSocket;" : [ + ("F", "connect", "()"), + ], + "Landroid/bluetooth/BluetoothPbap;" : [ + ("F", "getClient", "()"), + ("F", "getState", "()"), + ("F", "isConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/provider/Settings/System;" : [ + ("C", "AIRPLANE_MODE_RADIOS", "Ljava/lang/String;"), + ("C", "BLUETOOTH_DISCOVERABILITY", "Ljava/lang/String;"), + ("C", "BLUETOOTH_DISCOVERABILITY_TIMEOUT", "Ljava/lang/String;"), + ("C", "BLUETOOTH_ON", "Ljava/lang/String;"), + ("C", "RADIO_BLUETOOTH", "Ljava/lang/String;"), + ("C", "VOLUME_BLUETOOTH_SCO", "Ljava/lang/String;"), + ], + "Landroid/provider/Settings;" : [ + ("C", "ACTION_BLUETOOTH_SETTINGS", "Ljava/lang/String;"), + ], + "Landroid/bluetooth/IBluetooth$Stub$Proxy;" : [ + ("F", "addRfcommServiceRecord", "(Ljava/lang/String; Landroid/os/ParcelUuid; I Landroid/os/IBinder;)"), + ("F", "fetchRemoteUuids", "(Ljava/lang/String; Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetoothCallback;)"), + ("F", "getAddress", "()"), + ("F", "getBluetoothState", "()"), + ("F", "getBondState", "(Ljava/lang/String;)"), + ("F", "getDiscoverableTimeout", "()"), + ("F", "getName", "()"), + ("F", "getRemoteClass", "(Ljava/lang/String;)"), + ("F", "getRemoteName", "(Ljava/lang/String;)"), + ("F", "getRemoteServiceChannel", "(Ljava/lang/String; Landroid/os/ParcelUuid;)"), + ("F", "getRemoteUuids", "(Ljava/lang/String;)"), + ("F", "getScanMode", "()"), + ("F", "getTrustState", "(Ljava/lang/String;)"), + ("F", "isDiscovering", "()"), + ("F", "isEnabled", "()"), + ("F", "listBonds", "()"), + ("F", "removeServiceRecord", "(I)"), + ], + "Landroid/bluetooth/BluetoothAdapter;" : [ + ("C", "ACTION_CONNECTION_STATE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_DISCOVERY_FINISHED", "Ljava/lang/String;"), + ("C", "ACTION_DISCOVERY_STARTED", "Ljava/lang/String;"), + ("C", "ACTION_LOCAL_NAME_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_REQUEST_DISCOVERABLE", "Ljava/lang/String;"), + ("C", "ACTION_REQUEST_ENABLE", "Ljava/lang/String;"), + ("C", "ACTION_SCAN_MODE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_STATE_CHANGED", "Ljava/lang/String;"), + ("F", "cancelDiscovery", "()"), + ("F", "disable", "()"), + ("F", "enable", "()"), + ("F", "getAddress", "()"), + ("F", "getBondedDevices", "()"), + ("F", "getName", "()"), + ("F", "getScanMode", "()"), + ("F", "getState", "()"), + ("F", "isDiscovering", "()"), + ("F", "isEnabled", "()"), + ("F", "listenUsingInsecureRfcommWithServiceRecord", "(Ljava/lang/String; Ljava/util/UUID;)"), + ("F", "listenUsingRfcommWithServiceRecord", "(Ljava/lang/String; Ljava/util/UUID;)"), + ("F", "setName", "(Ljava/lang/String;)"), + ("F", "startDiscovery", "()"), + ("F", "getAddress", "()"), + ("F", "getBondedDevices", "()"), + ("F", "getDiscoverableTimeout", "()"), + ("F", "getName", "()"), + ("F", "getScanMode", "()"), + ("F", "getState", "()"), + ("F", "isDiscovering", "()"), + ("F", "isEnabled", "()"), + ("F", "listenUsingRfcommWithServiceRecord", "(Ljava/lang/String; Ljava/util/UUID;)"), + ], + "Landroid/bluetooth/BluetoothProfile;" : [ + ("F", "getConnectedDevices", "()"), + ("F", "getConnectionState", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getDevicesMatchingConnectionStates", "([I)"), + ], + "Landroid/bluetooth/BluetoothHeadset;" : [ + ("C", "ACTION_AUDIO_STATE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_CONNECTION_STATE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_VENDOR_SPECIFIC_HEADSET_EVENT", "Ljava/lang/String;"), + ("F", "getConnectedDevices", "()"), + ("F", "getConnectionState", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getDevicesMatchingConnectionStates", "([I)"), + ("F", "isAudioConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "startVoiceRecognition", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "stopVoiceRecognition", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getBatteryUsageHint", "()"), + ("F", "getCurrentHeadset", "()"), + ("F", "getPriority", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getState", "()"), + ("F", "isConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "startVoiceRecognition", "()"), + ("F", "stopVoiceRecognition", "()"), + ], + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;" : [ + ("F", "getBatteryUsageHint", "()"), + ("F", "getCurrentHeadset", "()"), + ("F", "getPriority", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getState", "()"), + ("F", "isConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "startVoiceRecognition", "()"), + ("F", "stopVoiceRecognition", "()"), + ], + "Landroid/bluetooth/BluetoothDevice;" : [ + ("C", "ACTION_ACL_CONNECTED", "Ljava/lang/String;"), + ("C", "ACTION_ACL_DISCONNECTED", "Ljava/lang/String;"), + ("C", "ACTION_ACL_DISCONNECT_REQUESTED", "Ljava/lang/String;"), + ("C", "ACTION_BOND_STATE_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_CLASS_CHANGED", "Ljava/lang/String;"), + ("C", "ACTION_FOUND", "Ljava/lang/String;"), + ("C", "ACTION_NAME_CHANGED", "Ljava/lang/String;"), + ("F", "createInsecureRfcommSocketToServiceRecord", "(Ljava/util/UUID;)"), + ("F", "createRfcommSocketToServiceRecord", "(Ljava/util/UUID;)"), + ("F", "getBluetoothClass", "()"), + ("F", "getBondState", "()"), + ("F", "getName", "()"), + ("F", "createRfcommSocketToServiceRecord", "(Ljava/util/UUID;)"), + ("F", "fetchUuidsWithSdp", "()"), + ("F", "getBondState", "()"), + ("F", "getName", "()"), + ("F", "getServiceChannel", "(Landroid/os/ParcelUuid;)"), + ("F", "getUuids", "()"), + ], + "Landroid/server/BluetoothA2dpService;" : [ + ("F", "", "(Landroid/content/Context; Landroid/server/BluetoothService;)"), + ("F", "addAudioSink", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getConnectedSinks", "()"), + ("F", "getNonDisconnectedSinks", "()"), + ("F", "getSinkPriority", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "getSinkState", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "isSinkDevice", "(Landroid/bluetooth/BluetoothDevice;)"), + ("F", "lookupSinksMatchingStates", "([I)"), + ("F", "onConnectSinkResult", "(Ljava/lang/String; B)"), + ("F", "onSinkPropertyChanged", "(Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ], + "Landroid/provider/Settings/Secure;" : [ + ("C", "BLUETOOTH_ON", "Ljava/lang/String;"), + ], + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;" : [ + ("F", "getClient", "()"), + ("F", "getState", "()"), + ("F", "isConnected", "(Landroid/bluetooth/BluetoothDevice;)"), + ], + "Landroid/server/BluetoothService;" : [ + ("F", "addRemoteDeviceProperties", "(Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ("F", "addRfcommServiceRecord", "(Ljava/lang/String; Landroid/os/ParcelUuid; I Landroid/os/IBinder;)"), + ("F", "fetchRemoteUuids", "(Ljava/lang/String; Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetoothCallback;)"), + ("F", "getAddress", "()"), + ("F", "getAddressFromObjectPath", "(Ljava/lang/String;)"), + ("F", "getAllProperties", "()"), + ("F", "getBluetoothState", "()"), + ("F", "getBondState", "(Ljava/lang/String;)"), + ("F", "getDiscoverableTimeout", "()"), + ("F", "getName", "()"), + ("F", "getObjectPathFromAddress", "(Ljava/lang/String;)"), + ("F", "getProperty", "(Ljava/lang/String;)"), + ("F", "getPropertyInternal", "(Ljava/lang/String;)"), + ("F", "getRemoteClass", "(Ljava/lang/String;)"), + ("F", "getRemoteName", "(Ljava/lang/String;)"), + ("F", "getRemoteServiceChannel", "(Ljava/lang/String; Landroid/os/ParcelUuid;)"), + ("F", "getRemoteUuids", "(Ljava/lang/String;)"), + ("F", "getScanMode", "()"), + ("F", "getTrustState", "(Ljava/lang/String;)"), + ("F", "isDiscovering", "()"), + ("F", "isEnabled", "()"), + ("F", "listBonds", "()"), + ("F", "removeServiceRecord", "(I)"), + ("F", "sendUuidIntent", "(Ljava/lang/String;)"), + ("F", "setLinkTimeout", "(Ljava/lang/String; I)"), + ("F", "setPropertyBoolean", "(Ljava/lang/String; B)"), + ("F", "setPropertyInteger", "(Ljava/lang/String; I)"), + ("F", "setPropertyString", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "updateDeviceServiceChannelCache", "(Ljava/lang/String;)"), + ("F", "updateRemoteDevicePropertiesCache", "(Ljava/lang/String;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("C", "FEATURE_BLUETOOTH", "Ljava/lang/String;"), + ], + "Landroid/bluetooth/BluetoothAssignedNumbers;" : [ + ("C", "BLUETOOTH_SIG", "I"), + ], +}, +"CLEAR_APP_USER_DATA" : { + "Landroid/app/ActivityManagerNative;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; LIPackageDataObserver;)"), + ("F", "clearApplicationUserData", "(Ljava/lang/String; LIPackageDataObserver;)"), + ], + "Landroid/app/ActivityManager;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; LIPackageDataObserver;)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "clearApplicationUserData", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], +}, +"WRITE_SMS" : { + "Landroid/provider/Telephony$Sms;" : [ + ("F", "addMessageToUri", "(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B B J)"), + ("F", "addMessageToUri", "(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B B)"), + ("F", "moveMessageToFolder", "(Landroid/content/Context; Landroid/net/Uri; I I)"), + ], + "Landroid/provider/Telephony$Sms$Outbox;" : [ + ("F", "addMessage", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B J)"), + ], + "Landroid/provider/Telephony$Sms$Draft;" : [ + ("F", "saveMessage", "(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String;)"), + ], +}, +"SET_PROCESS_LIMIT" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "setProcessForeground", "(Landroid/os/IBinder; I B)"), + ("F", "setProcessLimit", "(I)"), + ], +}, +"DEVICE_POWER" : { + "Landroid/os/PowerManager;" : [ + ("F", "goToSleep", "(J)"), + ("F", "setBacklightBrightness", "(I)"), + ], + "Landroid/os/IPowerManager$Stub$Proxy;" : [ + ("F", "clearUserActivityTimeout", "(J J)"), + ("F", "goToSleep", "(J)"), + ("F", "goToSleepWithReason", "(J I)"), + ("F", "preventScreenOn", "(B)"), + ("F", "setAttentionLight", "(B I)"), + ("F", "setBacklightBrightness", "(I)"), + ("F", "setPokeLock", "(I Landroid/os/IBinder; Ljava/lang/String;)"), + ("F", "userActivityWithForce", "(J B B)"), + ], +}, +"PERSISTENT_ACTIVITY" : { + "Landroid/app/ExpandableListActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/accounts/GrantCredentialsPermissionActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/app/Activity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/app/ListActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/app/AliasActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/accounts/AccountAuthenticatorActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "setPersistent", "(Landroid/os/IBinder; B)"), + ], + "Landroid/app/TabActivity;" : [ + ("F", "setPersistent", "(B)"), + ], + "Landroid/app/ActivityGroup;" : [ + ("F", "setPersistent", "(B)"), + ], +}, +"MANAGE_APP_TOKENS" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "addAppToken", "(I Landroid/view/IApplicationToken; I I B)"), + ("F", "addWindowToken", "(Landroid/os/IBinder; I)"), + ("F", "executeAppTransition", "()"), + ("F", "moveAppToken", "(I Landroid/os/IBinder;)"), + ("F", "moveAppTokensToBottom", "(Ljava/util/List;)"), + ("F", "moveAppTokensToTop", "(Ljava/util/List;)"), + ("F", "pauseKeyDispatching", "(Landroid/os/IBinder;)"), + ("F", "prepareAppTransition", "(I)"), + ("F", "removeAppToken", "(Landroid/os/IBinder;)"), + ("F", "removeWindowToken", "(Landroid/os/IBinder;)"), + ("F", "resumeKeyDispatching", "(Landroid/os/IBinder;)"), + ("F", "setAppGroupId", "(Landroid/os/IBinder; I)"), + ("F", "setAppOrientation", "(Landroid/view/IApplicationToken; I)"), + ("F", "setAppStartingWindow", "(Landroid/os/IBinder; Ljava/lang/String; I Ljava/lang/CharSequence; I I Landroid/os/IBinder; B)"), + ("F", "setAppVisibility", "(Landroid/os/IBinder; B)"), + ("F", "setAppWillBeHidden", "(Landroid/os/IBinder;)"), + ("F", "setEventDispatching", "(B)"), + ("F", "setFocusedApp", "(Landroid/os/IBinder; B)"), + ("F", "setNewConfiguration", "(Landroid/content/res/Configuration;)"), + ("F", "startAppFreezingScreen", "(Landroid/os/IBinder; I)"), + ("F", "stopAppFreezingScreen", "(Landroid/os/IBinder; B)"), + ("F", "updateOrientationFromAppTokens", "(Landroid/content/res/Configuration; Landroid/os/IBinder;)"), + ], +}, +"WRITE_HISTORY_BOOKMARKS" : { + "Landroid/provider/Browser;" : [ + ("C", "BOOKMARKS_URI", "Landroid/net/Uri;"), + ("C", "SEARCHES_URI", "Landroid/net/Uri;"), + ("F", "addSearchUrl", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "clearHistory", "(Landroid/content/ContentResolver;)"), + ("F", "clearSearches", "(Landroid/content/ContentResolver;)"), + ("F", "deleteFromHistory", "(Landroid/content/ContentResolver; Ljava/lang/String;)"), + ("F", "deleteHistoryTimeFrame", "(Landroid/content/ContentResolver; J J)"), + ("F", "truncateHistory", "(Landroid/content/ContentResolver;)"), + ("F", "updateVisitedHistory", "(Landroid/content/ContentResolver; Ljava/lang/String; B)"), + ("F", "clearSearches", "(Landroid/content/ContentResolver;)"), + ], +}, +"FORCE_BACK" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "unhandledBack", "(I)"), + ], +}, +"CHANGE_NETWORK_STATE" : { + "Landroid/net/IConnectivityManager$Stub$Proxy;" : [ + ("F", "requestRouteToHost", "(I I)"), + ("F", "setMobileDataEnabled", "(B)"), + ("F", "setNetworkPreference", "(I)"), + ("F", "setRadio", "(I B)"), + ("F", "setRadios", "(B)"), + ("F", "stopUsingNetworkFeature", "(I Ljava/lang/String;)"), + ("F", "tether", "(Ljava/lang/String;)"), + ("F", "untether", "(Ljava/lang/String;)"), + ], + "Landroid/net/ConnectivityManager;" : [ + ("F", "requestRouteToHost", "(I I)"), + ("F", "setMobileDataEnabled", "(B)"), + ("F", "setNetworkPreference", "(I)"), + ("F", "setRadio", "(I B)"), + ("F", "setRadios", "(B)"), + ("F", "startUsingNetworkFeature", "(I Ljava/lang/String;)"), + ("F", "stopUsingNetworkFeature", "(I Ljava/lang/String;)"), + ("F", "tether", "(Ljava/lang/String;)"), + ("F", "untether", "(Ljava/lang/String;)"), + ], + "Landroid/os/INetworkManagementService$Stub$Proxy;" : [ + ("F", "attachPppd", "(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "detachPppd", "(Ljava/lang/String;)"), + ("F", "disableNat", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "enableNat", "(Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setAccessPoint", "(Landroid/net/wifi/WifiConfiguration; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "setInterfaceThrottle", "(Ljava/lang/String; I I)"), + ("F", "setIpForwardingEnabled", "(B)"), + ("F", "startAccessPoint", "(Landroid/net/wifi/WifiConfiguration; Ljava/lang/String; Ljava/lang/String;)"), + ("F", "startUsbRNDIS", "()"), + ("F", "stopAccessPoint", "()"), + ("F", "stopTethering", "()"), + ("F", "stopUsbRNDIS", "()"), + ("F", "tetherInterface", "(Ljava/lang/String;)"), + ("F", "unregisterObserver", "(Landroid/net/INetworkManagementEventObserver;)"), + ("F", "untetherInterface", "(Ljava/lang/String;)"), + ], +}, +"WRITE_SYNC_SETTINGS" : { + "Landroid/app/ContextImpl$ApplicationContentResolver;" : [ + ("F", "addPeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)"), + ("F", "removePeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "setIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String; I)"), + ("F", "setMasterSyncAutomatically", "(B)"), + ("F", "setSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ], + "Landroid/content/ContentService;" : [ + ("F", "addPeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)"), + ("F", "removePeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "setIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String; I)"), + ("F", "setMasterSyncAutomatically", "(B)"), + ("F", "setSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ], + "Landroid/content/ContentResolver;" : [ + ("F", "addPeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)"), + ("F", "removePeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "setIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String; I)"), + ("F", "setMasterSyncAutomatically", "(B)"), + ("F", "setSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ], + "Landroid/content/IContentService$Stub$Proxy;" : [ + ("F", "addPeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)"), + ("F", "removePeriodicSync", "(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "setIsSyncable", "(Landroid/accounts/Account; Ljava/lang/String; I)"), + ("F", "setMasterSyncAutomatically", "(B)"), + ("F", "setSyncAutomatically", "(Landroid/accounts/Account; Ljava/lang/String; B)"), + ], +}, +"ACCOUNT_MANAGER" : { + "Landroid/accounts/AccountManager;" : [ + ("C", "KEY_ACCOUNT_MANAGER_RESPONSE", "Ljava/lang/String;"), + ], + "Landroid/accounts/AbstractAccountAuthenticator;" : [ + ("F", "checkBinderPermission", "()"), + ("F", "confirmCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)"), + ("F", "editProperties", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "getAccountRemovalAllowed", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)"), + ("F", "getAuthToken", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getAuthTokenLabel", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "hasFeatures", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)"), + ("F", "updateCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "addAccount", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)"), + ], + "Landroid/accounts/AbstractAccountAuthenticator$Transport;" : [ + ("F", "addAccount", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)"), + ("F", "confirmCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)"), + ("F", "editProperties", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "getAccountRemovalAllowed", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)"), + ("F", "getAuthToken", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getAuthTokenLabel", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "hasFeatures", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)"), + ("F", "updateCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ], + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;" : [ + ("F", "addAccount", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)"), + ("F", "confirmCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)"), + ("F", "editProperties", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "getAccountRemovalAllowed", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)"), + ("F", "getAuthToken", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ("F", "getAuthTokenLabel", "(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)"), + ("F", "hasFeatures", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)"), + ("F", "updateCredentials", "(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)"), + ], +}, +"SET_ANIMATION_SCALE" : { + "Landroid/view/IWindowManager$Stub$Proxy;" : [ + ("F", "setAnimationScale", "(I F)"), + ("F", "setAnimationScales", "([L;)"), + ], +}, +"GET_ACCOUNTS" : { + "Landroid/accounts/AccountManager;" : [ + ("F", "getAccounts", "()"), + ("F", "getAccountsByType", "(Ljava/lang/String;)"), + ("F", "getAccountsByTypeAndFeatures", "(Ljava/lang/String; [Ljava/lang/String; [Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "addOnAccountsUpdatedListener", "(Landroid/accounts/OnAccountsUpdateListener; Landroid/os/Handler; B)"), + ("F", "getAccounts", "()"), + ("F", "getAccountsByType", "(Ljava/lang/String;)"), + ("F", "getAccountsByTypeAndFeatures", "(Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "getAuthTokenByFeatures", "(Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/app/Activity; Landroid/os/Bundle; Landroid/os/Bundle; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ("F", "hasFeatures", "(Landroid/accounts/Account; [L[Ljava/lang/Strin; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)"), + ], + "Landroid/content/ContentService;" : [ + ("F", "", "(Landroid/content/Context; B)"), + ("F", "main", "(Landroid/content/Context; B)"), + ], + "Landroid/accounts/AccountManager$GetAuthTokenByTypeAndFeaturesTask;" : [ + ("F", "doWork", "()"), + ("F", "start", "()"), + ], + "Landroid/accounts/AccountManager$AmsTask;" : [ + ("F", "doWork", "()"), + ("F", "start", "()"), + ], + "Landroid/accounts/IAccountManager$Stub$Proxy;" : [ + ("F", "getAccounts", "(Ljava/lang/String;)"), + ("F", "getAccountsByFeatures", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ("F", "hasFeatures", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)"), + ], + "Landroid/accounts/AccountManagerService;" : [ + ("F", "checkReadAccountsPermission", "()"), + ("F", "getAccounts", "(Ljava/lang/String;)"), + ("F", "getAccountsByFeatures", "(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ("F", "hasFeatures", "(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)"), + ], +}, +"RECEIVE_SMS" : { + "Landroid/telephony/gsm/SmsManager;" : [ + ("F", "copyMessageToSim", "([L; [L; I)"), + ("F", "deleteMessageFromSim", "(I)"), + ("F", "getAllMessagesFromSim", "()"), + ("F", "updateMessageOnSim", "(I I [L;)"), + ], + "Landroid/telephony/SmsManager;" : [ + ("F", "copyMessageToIcc", "([L; [L; I)"), + ("F", "deleteMessageFromIcc", "(I)"), + ("F", "getAllMessagesFromIcc", "()"), + ("F", "updateMessageOnIcc", "(I I [L;)"), + ], + "Lcom/android/internal/telephony/ISms$Stub$Proxy;" : [ + ("F", "copyMessageToIccEf", "(I [B [B)"), + ("F", "getAllMessagesFromIccEf", "()"), + ("F", "updateMessageOnIccEf", "(I I [B)"), + ], +}, +"STOP_APP_SWITCHES" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "resumeAppSwitches", "()"), + ("F", "stopAppSwitches", "()"), + ], +}, +"DELETE_CACHE_FILES" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "deleteApplicationCacheFiles", "(Ljava/lang/String; LIPackageDataObserver;)"), + ("F", "deleteApplicationCacheFiles", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "deleteApplicationCacheFiles", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "deleteApplicationCacheFiles", "(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)"), + ], +}, +"WRITE_EXTERNAL_STORAGE" : { + "Landroid/os/Build/VERSION_CODES;" : [ + ("C", "DONUT", "I"), + ], + "Landroid/app/DownloadManager/Request;" : [ + ("F", "setDestinationUri", "(Landroid/net/Uri;)"), + ], +}, +"REBOOT" : { + "Landroid/os/RecoverySystem;" : [ + ("F", "installPackage", "(Landroid/content/Context; Ljava/io/File;)"), + ("F", "rebootWipeUserData", "(Landroid/content/Context;)"), + ("F", "bootCommand", "(Landroid/content/Context; Ljava/lang/String;)"), + ("F", "installPackage", "(Landroid/content/Context; Ljava/io/File;)"), + ("F", "rebootWipeUserData", "(Landroid/content/Context;)"), + ], + "Landroid/content/Intent;" : [ + ("C", "IntentResolution", "Ljava/lang/String;"), + ("C", "ACTION_REBOOT", "Ljava/lang/String;"), + ], + "Landroid/os/PowerManager;" : [ + ("F", "reboot", "(Ljava/lang/String;)"), + ("F", "reboot", "(Ljava/lang/String;)"), + ], + "Landroid/os/IPowerManager$Stub$Proxy;" : [ + ("F", "crash", "(Ljava/lang/String;)"), + ("F", "reboot", "(Ljava/lang/String;)"), + ], +}, +"INSTALL_PACKAGES" : { + "Landroid/app/ContextImpl$ApplicationPackageManager;" : [ + ("F", "installPackage", "(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)"), + ("F", "installPackage", "(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)"), + ], + "Landroid/content/pm/PackageManager;" : [ + ("F", "installPackage", "(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)"), + ], + "Landroid/content/pm/IPackageManager$Stub$Proxy;" : [ + ("F", "installPackage", "(Landroid/net/Uri; Landroid/content/pm/IPackageInstallObserver; I Ljava/lang/String;)"), + ], +}, +"SET_DEBUG_APP" : { + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "setDebugApp", "(Ljava/lang/String; B B)"), + ], +}, +"INSTALL_LOCATION_PROVIDER" : { + "Landroid/location/ILocationManager$Stub$Proxy;" : [ + ("F", "reportLocation", "(Landroid/location/Location; B)"), + ], +}, +"SET_WALLPAPER_HINTS" : { + "Landroid/app/WallpaperManager;" : [ + ("F", "suggestDesiredDimensions", "(I I)"), + ], + "Landroid/app/IWallpaperManager$Stub$Proxy;" : [ + ("F", "setDimensionHints", "(I I)"), + ], +}, +"READ_CONTACTS" : { + "Landroid/app/ContextImpl$ApplicationContentResolver;" : [ + ("F", "openFileDescriptor", "(Landroid/net/Uri; Ljava/lang/String;)"), + ("F", "openInputStream", "(Landroid/net/Uri;)"), + ("F", "openOutputStream", "(Landroid/net/Uri;)"), + ("F", "query", "(Landroid/net/Uri; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)"), + ], + "Lcom/android/internal/telephony/IccPhoneBookInterfaceManager$Stub$Proxy;" : [ + ("F", "getAdnRecordsInEf", "(I)"), + ], + "Landroid/provider/Contacts$People;" : [ + ("F", "addToGroup", "(Landroid/content/ContentResolver; J Ljava/lang/String;)"), + ("F", "addToMyContactsGroup", "(Landroid/content/ContentResolver; J)"), + ("F", "createPersonInMyContactsGroup", "(Landroid/content/ContentResolver; Landroid/content/ContentValues;)"), + ("F", "loadContactPhoto", "(Landroid/content/Context; Landroid/net/Uri; I Landroid/graphics/BitmapFactory$Options;)"), + ("F", "markAsContacted", "(Landroid/content/ContentResolver; J)"), + ("F", "openContactPhotoInputStream", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ("F", "queryGroups", "(Landroid/content/ContentResolver; J)"), + ("F", "setPhotoData", "(Landroid/content/ContentResolver; Landroid/net/Uri; [L;)"), + ("F", "tryGetMyContactsGroupId", "(Landroid/content/ContentResolver;)"), + ], + "Landroid/provider/ContactsContract$Data;" : [ + ("F", "getContactLookupUri", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ], + "Landroid/provider/ContactsContract$Contacts;" : [ + ("F", "getLookupUri", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ("F", "lookupContact", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ("F", "openContactPhotoInputStream", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ], + "Landroid/pim/vcard/VCardComposer;" : [ + ("F", "createOneEntry", "()"), + ("F", "createOneEntry", "(Ljava/lang/reflect/Method;)"), + ("F", "createOneEntryInternal", "(Ljava/lang/String; Ljava/lang/reflect/Method;)"), + ("F", "init", "()"), + ("F", "init", "(Ljava/lang/String; [L[Ljava/lang/Strin;)"), + ], + "Landroid/pim/vcard/VCardComposer$OneEntryHandler;" : [ + ("F", "onInit", "(Landroid/content/Context;)"), + ], + "Lcom/android/internal/telephony/CallerInfo;" : [ + ("F", "getCallerId", "(Landroid/content/Context; Ljava/lang/String;)"), + ("F", "getCallerInfo", "(Landroid/content/Context; Ljava/lang/String;)"), + ], + "Landroid/provider/Contacts$Settings;" : [ + ("F", "getSetting", "(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)"), + ], + "Landroid/provider/ContactsContract$RawContacts;" : [ + ("F", "getContactLookupUri", "(Landroid/content/ContentResolver; Landroid/net/Uri;)"), + ], + "Landroid/provider/CallLog$Calls;" : [ + ("F", "addCall", "(Lcom/android/internal/telephony/CallerInfo; Landroid/content/Context; Ljava/lang/String; I I J I)"), + ("F", "getLastOutgoingCall", "(Landroid/content/Context;)"), + ], + "Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;" : [ + ("F", "getAdnRecordsInEf", "(I)"), + ], + "Landroid/pim/vcard/VCardComposer$HandlerForOutputStream;" : [ + ("F", "onInit", "(Landroid/content/Context;)"), + ], + "Landroid/provider/ContactsContract$CommonDataKinds$Phone;" : [ + ("C", "CONTENT_URI", "Landroid/net/Uri;"), + ], + "Landroid/widget/QuickContactBadge;" : [ + ("F", "assignContactFromEmail", "(Ljava/lang/String; B)"), + ("F", "assignContactFromPhone", "(Ljava/lang/String; B)"), + ("F", "trigger", "(Landroid/net/Uri;)"), + ], + "Landroid/content/ContentResolver;" : [ + ("F", "openFileDescriptor", "(Landroid/net/Uri; Ljava/lang/String;)"), + ("F", "openInputStream", "(Landroid/net/Uri;)"), + ("F", "openOutputStream", "(Landroid/net/Uri;)"), + ("F", "query", "(Landroid/net/Uri; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)"), + ], +}, +"BACKUP" : { + "Landroid/app/backup/IBackupManager$Stub$Proxy;" : [ + ("F", "backupNow", "()"), + ("F", "beginRestoreSession", "(Ljava/lang/String;)"), + ("F", "clearBackupData", "(Ljava/lang/String;)"), + ("F", "dataChanged", "(Ljava/lang/String;)"), + ("F", "getCurrentTransport", "()"), + ("F", "isBackupEnabled", "()"), + ("F", "listAllTransports", "()"), + ("F", "selectBackupTransport", "(Ljava/lang/String;)"), + ("F", "setAutoRestore", "(B)"), + ("F", "setBackupEnabled", "(B)"), + ], + "Landroid/app/IActivityManager$Stub$Proxy;" : [ + ("F", "bindBackupAgent", "(Landroid/content/pm/ApplicationInfo; I)"), + ], + "Landroid/app/backup/BackupManager;" : [ + ("F", "beginRestoreSession", "()"), + ("F", "dataChanged", "(Ljava/lang/String;)"), + ("F", "requestRestore", "(Landroid/app/backup/RestoreObserver;)"), + ], +}, +} + +DVM_PERMISSIONS_BY_ELEMENT = { + "Landroid/app/admin/DeviceAdminReceiver;-ACTION_DEVICE_ADMIN_ENABLED-Ljava/lang/String;" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/DevicePolicyManager;-getRemoveWarning-(Landroid/content/ComponentName; Landroid/os/RemoteCallback;)" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/DevicePolicyManager;-reportFailedPasswordAttempt-()" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/DevicePolicyManager;-reportSuccessfulPasswordAttempt-()" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/DevicePolicyManager;-setActiveAdmin-(Landroid/content/ComponentName;)" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/DevicePolicyManager;-setActivePasswordState-(I I)" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;-getRemoveWarning-(Landroid/content/ComponentName; Landroid/os/RemoteCallback;)" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;-reportFailedPasswordAttempt-()" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;-reportSuccessfulPasswordAttempt-()" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;-setActiveAdmin-(Landroid/content/ComponentName;)" : "BIND_DEVICE_ADMIN", + "Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;-setActivePasswordState-(I I)" : "BIND_DEVICE_ADMIN", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getIsSyncable-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getMasterSyncAutomatically-()" : "READ_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getPeriodicSyncs-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentService;-getIsSyncable-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentService;-getMasterSyncAutomatically-()" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentService;-getPeriodicSyncs-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentService;-getSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-getIsSyncable-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-getMasterSyncAutomatically-()" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-getPeriodicSyncs-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-getSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-getIsSyncable-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-getMasterSyncAutomatically-()" : "READ_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-getPeriodicSyncs-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-getSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_SETTINGS", + "Landroid/content/pm/ApplicationInfo;-FLAG_FACTORY_TEST-I" : "FACTORY_TEST", + "Landroid/content/pm/ApplicationInfo;-flags-I" : "FACTORY_TEST", + "Landroid/content/Intent;-IntentResolution-Ljava/lang/String;" : "FACTORY_TEST", + "Landroid/content/Intent;-ACTION_FACTORY_TEST-Ljava/lang/String;" : "FACTORY_TEST", + "Landroid/app/IActivityManager$Stub$Proxy;-setAlwaysFinish-(B)" : "SET_ALWAYS_FINISH", + "Landroid/provider/Calendar$CalendarAlerts;-alarmExists-(Landroid/content/ContentResolver; J J J)" : "READ_CALENDAR", + "Landroid/provider/Calendar$CalendarAlerts;-findNextAlarmTime-(Landroid/content/ContentResolver; J)" : "READ_CALENDAR", + "Landroid/provider/Calendar$CalendarAlerts;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)" : "READ_CALENDAR", + "Landroid/provider/Calendar$Calendars;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)" : "READ_CALENDAR", + "Landroid/provider/Calendar$Events;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)" : "READ_CALENDAR", + "Landroid/provider/Calendar$Events;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)" : "READ_CALENDAR", + "Landroid/provider/Calendar$Instances;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; J J Ljava/lang/String; Ljava/lang/String;)" : "READ_CALENDAR", + "Landroid/provider/Calendar$Instances;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; J J)" : "READ_CALENDAR", + "Landroid/provider/Calendar$EventDays;-query-(Landroid/content/ContentResolver; I I)" : "READ_CALENDAR", + "Landroid/provider/DrmStore;-enforceAccessDrmPermission-(Landroid/content/Context;)" : "ACCESS_DRM", + "Landroid/app/IActivityManager$Stub$Proxy;-updateConfiguration-(Landroid/content/res/Configuration;)" : "CHANGE_CONFIGURATION", + "Landroid/app/IActivityManager$Stub$Proxy;-profileControl-(Ljava/lang/String; B Ljava/lang/String; Landroid/os/ParcelFileDescriptor;)" : "SET_ACTIVITY_WATCHER", + "Landroid/app/IActivityManager$Stub$Proxy;-setActivityController-(Landroid/app/IActivityController;)" : "SET_ACTIVITY_WATCHER", + "Landroid/app/ContextImpl$ApplicationPackageManager;-getPackageSizeInfo-(Ljava/lang/String; LIPackageStatsObserver;)" : "GET_PACKAGE_SIZE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-getPackageSizeInfo-(Ljava/lang/String; Landroid/content/pm/IPackageStatsObserver;)" : "GET_PACKAGE_SIZE", + "Landroid/content/pm/PackageManager;-getPackageSizeInfo-(Ljava/lang/String; Landroid/content/pm/IPackageStatsObserver;)" : "GET_PACKAGE_SIZE", + "Landroid/telephony/TelephonyManager;-disableLocationUpdates-()" : "CONTROL_LOCATION_UPDATES", + "Landroid/telephony/TelephonyManager;-enableLocationUpdates-()" : "CONTROL_LOCATION_UPDATES", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-disableLocationUpdates-()" : "CONTROL_LOCATION_UPDATES", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-enableLocationUpdates-()" : "CONTROL_LOCATION_UPDATES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-freeStorage-(J LIntentSender;)" : "CLEAR_APP_CACHE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-freeStorageAndNotify-(J LIPackageDataObserver;)" : "CLEAR_APP_CACHE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-freeStorage-(J Landroid/content/IntentSender;)" : "CLEAR_APP_CACHE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-freeStorageAndNotify-(J Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_CACHE", + "Landroid/content/pm/PackageManager;-freeStorage-(J Landroid/content/IntentSender;)" : "CLEAR_APP_CACHE", + "Landroid/content/pm/PackageManager;-freeStorageAndNotify-(J Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_CACHE", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-freeStorage-(J Landroid/content/IntentSender;)" : "CLEAR_APP_CACHE", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-freeStorageAndNotify-(J Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_CACHE", + "Landroid/view/inputmethod/InputMethod;-SERVICE_INTERFACE-Ljava/lang/String;" : "BIND_INPUT_METHOD", + "Landroid/app/IActivityManager$Stub$Proxy;-signalPersistentProcesses-(I)" : "SIGNAL_PERSISTENT_PROCESSES", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-getAwakeTimeBattery-()" : "BATTERY_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-getAwakeTimePlugged-()" : "BATTERY_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-getStatistics-()" : "BATTERY_STATS", + "Landroid/accounts/AccountManager;-addAccountExplicitly-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-getPassword-(Landroid/accounts/Account;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-getUserData-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-peekAuthToken-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setPassword-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setUserData-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-addAccountExplicitly-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-getPassword-(Landroid/accounts/Account;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-getUserData-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-peekAuthToken-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setPassword-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManager;-setUserData-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-addAccount-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-checkAuthenticateAccountsPermission-(Landroid/accounts/Account;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-getPassword-(Landroid/accounts/Account;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-getUserData-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-peekAuthToken-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-setAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-setPassword-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-setUserData-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-addAccount-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-getPassword-(Landroid/accounts/Account;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-getUserData-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-peekAuthToken-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-setAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-setPassword-(Landroid/accounts/Account; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-setUserData-(Landroid/accounts/Account; Ljava/lang/String; Ljava/lang/String;)" : "AUTHENTICATE_ACCOUNTS", + "Landroid/net/IConnectivityManager$Stub$Proxy;-setBackgroundDataSetting-(B)" : "CHANGE_BACKGROUND_DATA_SETTING", + "Landroid/net/ConnectivityManager;-setBackgroundDataSetting-(B)" : "CHANGE_BACKGROUND_DATA_SETTING", + "Landroid/app/ActivityManagerNative;-killBackgroundProcesses-(Ljava/lang/String;)" : "RESTART_PACKAGES", + "Landroid/app/ActivityManagerNative;-restartPackage-(Ljava/lang/String;)" : "RESTART_PACKAGES", + "Landroid/app/ActivityManager;-killBackgroundProcesses-(Ljava/lang/String;)" : "RESTART_PACKAGES", + "Landroid/app/ActivityManager;-restartPackage-(Ljava/lang/String;)" : "RESTART_PACKAGES", + "Landroid/telephony/TelephonyManager;-getCompleteVoiceMailNumber-()" : "CALL_PRIVILEGED", + "Landroid/telephony/PhoneNumberUtils;-getNumberFromIntent-(Landroid/content/Intent; Landroid/content/Context;)" : "CALL_PRIVILEGED", + "Landroid/app/IWallpaperManager$Stub$Proxy;-setWallpaperComponent-(Landroid/content/ComponentName;)" : "SET_WALLPAPER_COMPONENT", + "Landroid/view/IWindowManager$Stub$Proxy;-disableKeyguard-(Landroid/os/IBinder; Ljava/lang/String;)" : "DISABLE_KEYGUARD", + "Landroid/view/IWindowManager$Stub$Proxy;-exitKeyguardSecurely-(Landroid/view/IOnKeyguardExitResult;)" : "DISABLE_KEYGUARD", + "Landroid/view/IWindowManager$Stub$Proxy;-reenableKeyguard-(Landroid/os/IBinder;)" : "DISABLE_KEYGUARD", + "Landroid/app/KeyguardManager;-exitKeyguardSecurely-(Landroid/app/KeyguardManager$OnKeyguardExitResult;)" : "DISABLE_KEYGUARD", + "Landroid/app/KeyguardManager$KeyguardLock;-disableKeyguard-()" : "DISABLE_KEYGUARD", + "Landroid/app/KeyguardManager$KeyguardLock;-reenableKeyguard-()" : "DISABLE_KEYGUARD", + "Landroid/app/ContextImpl$ApplicationPackageManager;-deletePackage-(Ljava/lang/String; LIPackageDeleteObserver; I)" : "DELETE_PACKAGES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-deletePackage-(Ljava/lang/String; LIPackageDeleteObserver; I)" : "DELETE_PACKAGES", + "Landroid/content/pm/PackageManager;-deletePackage-(Ljava/lang/String; LIPackageDeleteObserver; I)" : "DELETE_PACKAGES", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-deletePackage-(Ljava/lang/String; Landroid/content/pm/IPackageDeleteObserver; I)" : "DELETE_PACKAGES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-setApplicationEnabledSetting-(Ljava/lang/String; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-setComponentEnabledSetting-(LComponentName; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-setApplicationEnabledSetting-(Ljava/lang/String; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-setComponentEnabledSetting-(Landroid/content/ComponentName; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/content/pm/PackageManager;-setApplicationEnabledSetting-(Ljava/lang/String; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/content/pm/PackageManager;-setComponentEnabledSetting-(Landroid/content/ComponentName; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-setApplicationEnabledSetting-(Ljava/lang/String; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-setComponentEnabledSetting-(Landroid/content/ComponentName; I I)" : "CHANGE_COMPONENT_ENABLED_STATE", + "Landroid/os/storage/IMountService$Stub$Proxy;-getSecureContainerList-()" : "ASEC_ACCESS", + "Landroid/os/storage/IMountService$Stub$Proxy;-getSecureContainerPath-(Ljava/lang/String;)" : "ASEC_ACCESS", + "Landroid/os/storage/IMountService$Stub$Proxy;-isSecureContainerMounted-(Ljava/lang/String;)" : "ASEC_ACCESS", + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;-noteLaunchTime-(LComponentName;)" : "UPDATE_DEVICE_STATS ", + "Landroid/net/sip/SipAudioCall;-startAudio-()" : "RECORD_AUDIO", + "Landroid/media/MediaRecorder;-setAudioSource-(I)" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-cancel-()" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-handleCancelMessage-()" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-handleStartListening-(Landroid/content/Intent;)" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-handleStopMessage-()" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-startListening-(Landroid/content/Intent;)" : "RECORD_AUDIO", + "Landroid/speech/SpeechRecognizer;-stopListening-()" : "RECORD_AUDIO", + "Landroid/media/AudioRecord;--(I I I I I)" : "RECORD_AUDIO", + "Landroid/location/LocationManager;-addTestProvider-(Ljava/lang/String; B B B B B B B I I)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderEnabled-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderLocation-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderStatus-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-removeTestProvider-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderEnabled-(Ljava/lang/String; B)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderLocation-(Ljava/lang/String; Landroid/location/Location;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderStatus-(Ljava/lang/String; I Landroid/os/Bundle; J)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-addTestProvider-(Ljava/lang/String; B B B B B B B I I)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderEnabled-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderLocation-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-clearTestProviderStatus-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-removeTestProvider-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderEnabled-(Ljava/lang/String; B)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderLocation-(Ljava/lang/String; Landroid/location/Location;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/LocationManager;-setTestProviderStatus-(Ljava/lang/String; I Landroid/os/Bundle; J)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-addTestProvider-(Ljava/lang/String; B B B B B B B I I)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-clearTestProviderEnabled-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-clearTestProviderLocation-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-clearTestProviderStatus-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-removeTestProvider-(Ljava/lang/String;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-setTestProviderEnabled-(Ljava/lang/String; B)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-setTestProviderLocation-(Ljava/lang/String; Landroid/location/Location;)" : "ACCESS_MOCK_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-setTestProviderStatus-(Ljava/lang/String; I Landroid/os/Bundle; J)" : "ACCESS_MOCK_LOCATION", + "Landroid/media/AudioManager;-EXTRA_RINGER_MODE-Ljava/lang/String;" : "VIBRATE", + "Landroid/media/AudioManager;-EXTRA_VIBRATE_SETTING-Ljava/lang/String;" : "VIBRATE", + "Landroid/media/AudioManager;-EXTRA_VIBRATE_TYPE-Ljava/lang/String;" : "VIBRATE", + "Landroid/media/AudioManager;-FLAG_REMOVE_SOUND_AND_VIBRATE-I" : "VIBRATE", + "Landroid/media/AudioManager;-FLAG_VIBRATE-I" : "VIBRATE", + "Landroid/media/AudioManager;-RINGER_MODE_VIBRATE-I" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_SETTING_CHANGED_ACTION-Ljava/lang/String;" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_SETTING_OFF-I" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_SETTING_ON-I" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_SETTING_ONLY_SILENT-I" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_TYPE_NOTIFICATION-I" : "VIBRATE", + "Landroid/media/AudioManager;-VIBRATE_TYPE_RINGER-I" : "VIBRATE", + "Landroid/media/AudioManager;-getRingerMode-()" : "VIBRATE", + "Landroid/media/AudioManager;-getVibrateSetting-(I)" : "VIBRATE", + "Landroid/media/AudioManager;-setRingerMode-(I)" : "VIBRATE", + "Landroid/media/AudioManager;-setVibrateSetting-(I I)" : "VIBRATE", + "Landroid/media/AudioManager;-shouldVibrate-(I)" : "VIBRATE", + "Landroid/os/Vibrator;-cancel-()" : "VIBRATE", + "Landroid/os/Vibrator;-vibrate-([L; I)" : "VIBRATE", + "Landroid/os/Vibrator;-vibrate-(J)" : "VIBRATE", + "Landroid/provider/Settings/System;-VIBRATE_ON-Ljava/lang/String;" : "VIBRATE", + "Landroid/app/NotificationManager;-notify-(I Landroid/app/Notification;)" : "VIBRATE", + "Landroid/app/NotificationManager;-notify-(Ljava/lang/String; I Landroid/app/Notification;)" : "VIBRATE", + "Landroid/app/Notification/Builder;-setDefaults-(I)" : "VIBRATE", + "Landroid/os/IVibratorService$Stub$Proxy;-cancelVibrate-(Landroid/os/IBinder;)" : "VIBRATE", + "Landroid/os/IVibratorService$Stub$Proxy;-vibrate-(J Landroid/os/IBinder;)" : "VIBRATE", + "Landroid/os/IVibratorService$Stub$Proxy;-vibratePattern-([L; I Landroid/os/IBinder;)" : "VIBRATE", + "Landroid/app/Notification;-DEFAULT_VIBRATE-I" : "VIBRATE", + "Landroid/app/Notification;-defaults-I" : "VIBRATE", + "Landroid/os/storage/IMountService$Stub$Proxy;-createSecureContainer-(Ljava/lang/String; I Ljava/lang/String; Ljava/lang/String; I)" : "ASEC_CREATE", + "Landroid/os/storage/IMountService$Stub$Proxy;-finalizeSecureContainer-(Ljava/lang/String;)" : "ASEC_CREATE", + "Landroid/bluetooth/BluetoothAdapter;-setScanMode-(I I)" : "WRITE_SECURE_SETTINGS", + "Landroid/bluetooth/BluetoothAdapter;-setScanMode-(I)" : "WRITE_SECURE_SETTINGS", + "Landroid/server/BluetoothService;-setScanMode-(I I)" : "WRITE_SECURE_SETTINGS", + "Landroid/os/IPowerManager$Stub$Proxy;-setMaximumScreenOffTimeount-(I)" : "WRITE_SECURE_SETTINGS", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-setInstallLocation-(I)" : "WRITE_SECURE_SETTINGS", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setScanMode-(I I)" : "WRITE_SECURE_SETTINGS", + "Landroid/view/IWindowManager$Stub$Proxy;-setRotation-(I B I)" : "SET_ORIENTATION", + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;-getAllPkgUsageStats-()" : "PACKAGE_USAGE_STATS", + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;-getPkgUsageStats-(LComponentName;)" : "PACKAGE_USAGE_STATS", + "Landroid/os/IHardwareService$Stub$Proxy;-setFlashlightEnabled-(B)" : "FLASHLIGHT", + "Landroid/app/SearchManager;-EXTRA_SELECT_QUERY-Ljava/lang/String;" : "GLOBAL_SEARCH", + "Landroid/app/SearchManager;-INTENT_ACTION_GLOBAL_SEARCH-Ljava/lang/String;" : "GLOBAL_SEARCH", + "Landroid/server/search/Searchables;-buildSearchableList-()" : "GLOBAL_SEARCH", + "Landroid/server/search/Searchables;-findGlobalSearchActivity-()" : "GLOBAL_SEARCH", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-addOrUpdateNetwork-(Landroid/net/wifi/WifiConfiguration;)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-disableNetwork-(I)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-disconnect-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-enableNetwork-(I B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-pingSupplicant-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-reassociate-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-reconnect-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-removeNetwork-(I)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-saveConfiguration-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-setNumAllowedChannels-(I B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-setWifiApEnabled-(Landroid/net/wifi/WifiConfiguration; B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-setWifiEnabled-(B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-startScan-(B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-addNetwork-(Landroid/net/wifi/WifiConfiguration;)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-addOrUpdateNetwork-(Landroid/net/wifi/WifiConfiguration;)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-disableNetwork-(I)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-disconnect-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-enableNetwork-(I B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-pingSupplicant-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-reassociate-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-reconnect-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-removeNetwork-(I)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-saveConfiguration-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-setNumAllowedChannels-(I B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-setWifiApEnabled-(Landroid/net/wifi/WifiConfiguration; B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-setWifiEnabled-(B)" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-startScan-()" : "CHANGE_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-startScanActive-()" : "CHANGE_WIFI_STATE", + "Landroid/app/ExpandableListActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ExpandableListActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ExpandableListActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/accessibilityservice/AccessibilityService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accessibilityservice/AccessibilityService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accessibilityservice/AccessibilityService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/accounts/GrantCredentialsPermissionActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accounts/GrantCredentialsPermissionActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accounts/GrantCredentialsPermissionActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgent;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgent;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgent;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/service/wallpaper/WallpaperService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/service/wallpaper/WallpaperService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/service/wallpaper/WallpaperService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgentHelper;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgentHelper;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/backup/BackupAgentHelper;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/accounts/AccountAuthenticatorActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accounts/AccountAuthenticatorActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/accounts/AccountAuthenticatorActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/IActivityManager$Stub$Proxy;-unbroadcastIntent-(Landroid/app/IApplicationThread; Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ActivityGroup;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ActivityGroup;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ActivityGroup;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/content/ContextWrapper;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/ContextWrapper;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/ContextWrapper;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/ContextWrapper;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/ContextWrapper;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/Activity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Activity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Activity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/ContextImpl;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ContextImpl;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ContextImpl;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/AliasActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/AliasActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/AliasActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/content/Context;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/Context;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/Context;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/Context;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/Context;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/service/urlrenderer/UrlRendererService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/service/urlrenderer/UrlRendererService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/service/urlrenderer/UrlRendererService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/FullBackupAgent;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/FullBackupAgent;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/FullBackupAgent;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/TabActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/TabActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/TabActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/view/ContextThemeWrapper;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/view/ContextThemeWrapper;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/view/ContextThemeWrapper;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/speech/RecognitionService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/speech/RecognitionService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/speech/RecognitionService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/IntentService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/IntentService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/IntentService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/inputmethodservice/AbstractInputMethodService;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/inputmethodservice/AbstractInputMethodService;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/inputmethodservice/AbstractInputMethodService;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/Application;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Application;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Application;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/Application;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/ListActivity;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ListActivity;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/ListActivity;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/Service;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Service;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/app/Service;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/content/MutableContextWrapper;-removeStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/MutableContextWrapper;-sendStickyBroadcast-(Landroid/content/Intent;)" : "BROADCAST_STICKY", + "Landroid/content/MutableContextWrapper;-sendStickyOrderedBroadcast-(Landroid/content/Intent; Landroid/content/BroadcastReceiver; Landroid/os/Handler; I Ljava/lang/String; Landroid/os/Bundle;)" : "BROADCAST_STICKY", + "Landroid/app/IActivityManager$Stub$Proxy;-forceStopPackage-(Ljava/lang/String;)" : "FORCE_STOP_PACKAGES", + "Landroid/app/ActivityManagerNative;-forceStopPackage-(Ljava/lang/String;)" : "FORCE_STOP_PACKAGES", + "Landroid/app/ActivityManager;-forceStopPackage-(Ljava/lang/String;)" : "FORCE_STOP_PACKAGES", + "Landroid/app/IActivityManager$Stub$Proxy;-killBackgroundProcesses-(Ljava/lang/String;)" : "KILL_BACKGROUND_PROCESSES", + "Landroid/app/ActivityManager;-killBackgroundProcesses-(Ljava/lang/String;)" : "KILL_BACKGROUND_PROCESSES", + "Landroid/app/AlarmManager;-setTimeZone-(Ljava/lang/String;)" : "SET_TIME_ZONE", + "Landroid/app/AlarmManager;-setTimeZone-(Ljava/lang/String;)" : "SET_TIME_ZONE", + "Landroid/app/IAlarmManager$Stub$Proxy;-setTimeZone-(Ljava/lang/String;)" : "SET_TIME_ZONE", + "Landroid/server/BluetoothA2dpService;-connectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothA2dpService;-disconnectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothA2dpService;-resumeSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothA2dpService;-setSinkPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothA2dpService;-setSinkPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothA2dpService;-suspendSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothPbap;-disconnect-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-connectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-disconnectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-resumeSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-setSinkPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-suspendSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-cancelDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-disable-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-enable-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-setName-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-startDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-cancelDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-disable-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-enable-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-setDiscoverableTimeout-(I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-setName-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothAdapter;-startDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-cancelBondProcess-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-cancelDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-cancelPairingUserInput-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-createBond-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-disable-()" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-disable-(B)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-enable-()" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-enable-(B)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-removeBond-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setDiscoverableTimeout-(I)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setName-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setPairingConfirmation-(Ljava/lang/String; B)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setPasskey-(Ljava/lang/String; I)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setPin-(Ljava/lang/String; [L;)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-setTrust-(Ljava/lang/String; B)" : "BLUETOOTH_ADMIN", + "Landroid/server/BluetoothService;-startDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothHeadset;-connectHeadset-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothHeadset;-disconnectHeadset-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothHeadset;-setPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-connectHeadset-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-disconnectHeadset-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-setPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-cancelBondProcess-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-cancelPairingUserInput-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-createBond-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-removeBond-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-setPairingConfirmation-(B)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-setPasskey-(I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothDevice;-setPin-([L;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-connect-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-disconnect-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothA2dp;-connectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothA2dp;-disconnectSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothA2dp;-resumeSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothA2dp;-setSinkPriority-(Landroid/bluetooth/BluetoothDevice; I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/BluetoothA2dp;-suspendSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-cancelBondProcess-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-cancelDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-cancelPairingUserInput-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-createBond-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-disable-(B)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-enable-()" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-removeBond-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setDiscoverableTimeout-(I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setName-(Ljava/lang/String;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setPairingConfirmation-(Ljava/lang/String; B)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setPasskey-(Ljava/lang/String; I)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setPin-(Ljava/lang/String; [L;)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-setTrust-(Ljava/lang/String; B)" : "BLUETOOTH_ADMIN", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-startDiscovery-()" : "BLUETOOTH_ADMIN", + "Landroid/view/IWindowManager$Stub$Proxy;-injectKeyEvent-(Landroid/view/KeyEvent; B)" : "INJECT_EVENTS", + "Landroid/view/IWindowManager$Stub$Proxy;-injectPointerEvent-(Landroid/view/MotionEvent; B)" : "INJECT_EVENTS", + "Landroid/view/IWindowManager$Stub$Proxy;-injectTrackballEvent-(Landroid/view/MotionEvent; B)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-invokeContextMenuAction-(Landroid/app/Activity; I I)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendCharacterSync-(I)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendKeyDownUpSync-(I)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendKeySync-(Landroid/view/KeyEvent;)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendPointerSync-(Landroid/view/MotionEvent;)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendStringSync-(Ljava/lang/String;)" : "INJECT_EVENTS", + "Landroid/app/Instrumentation;-sendTrackballEventSync-(Landroid/view/MotionEvent;)" : "INJECT_EVENTS", + "Landroid/hardware/Camera/ErrorCallback;-onError-(I Landroid/hardware/Camera;)" : "CAMERA", + "Landroid/media/MediaRecorder;-setVideoSource-(I)" : "CAMERA", + "Landroid/view/KeyEvent;-KEYCODE_CAMERA-I" : "CAMERA", + "Landroid/bluetooth/BluetoothClass/Device;-AUDIO_VIDEO_VIDEO_CAMERA-I" : "CAMERA", + "Landroid/provider/MediaStore;-INTENT_ACTION_STILL_IMAGE_CAMERA-Ljava/lang/String;" : "CAMERA", + "Landroid/provider/MediaStore;-INTENT_ACTION_VIDEO_CAMERA-Ljava/lang/String;" : "CAMERA", + "Landroid/hardware/Camera/CameraInfo;-CAMERA_FACING_BACK-I" : "CAMERA", + "Landroid/hardware/Camera/CameraInfo;-CAMERA_FACING_FRONT-I" : "CAMERA", + "Landroid/hardware/Camera/CameraInfo;-facing-I" : "CAMERA", + "Landroid/provider/ContactsContract/StatusColumns;-CAPABILITY_HAS_CAMERA-I" : "CAMERA", + "Landroid/hardware/Camera/Parameters;-setRotation-(I)" : "CAMERA", + "Landroid/media/MediaRecorder/VideoSource;-CAMERA-I" : "CAMERA", + "Landroid/content/Intent;-IntentResolution-Ljava/lang/String;" : "CAMERA", + "Landroid/content/Intent;-ACTION_CAMERA_BUTTON-Ljava/lang/String;" : "CAMERA", + "Landroid/content/pm/PackageManager;-FEATURE_CAMERA-Ljava/lang/String;" : "CAMERA", + "Landroid/content/pm/PackageManager;-FEATURE_CAMERA_AUTOFOCUS-Ljava/lang/String;" : "CAMERA", + "Landroid/content/pm/PackageManager;-FEATURE_CAMERA_FLASH-Ljava/lang/String;" : "CAMERA", + "Landroid/content/pm/PackageManager;-FEATURE_CAMERA_FRONT-Ljava/lang/String;" : "CAMERA", + "Landroid/hardware/Camera;-CAMERA_ERROR_SERVER_DIED-I" : "CAMERA", + "Landroid/hardware/Camera;-CAMERA_ERROR_UNKNOWN-I" : "CAMERA", + "Landroid/hardware/Camera;-setDisplayOrientation-(I)" : "CAMERA", + "Landroid/hardware/Camera;-native_setup-(Ljava/lang/Object;)" : "CAMERA", + "Landroid/hardware/Camera;-open-()" : "CAMERA", + "Landroid/app/Activity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/Activity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/Activity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/ExpandableListActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/ExpandableListActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/ExpandableListActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/accessibilityservice/AccessibilityService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/accessibilityservice/AccessibilityService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/accessibilityservice/AccessibilityService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/accounts/GrantCredentialsPermissionActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/accounts/GrantCredentialsPermissionActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/accounts/GrantCredentialsPermissionActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgent;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgent;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgent;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/service/wallpaper/WallpaperService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/service/wallpaper/WallpaperService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/service/wallpaper/WallpaperService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgentHelper;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgentHelper;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/backup/BackupAgentHelper;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/accounts/AccountAuthenticatorActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/accounts/AccountAuthenticatorActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/accounts/AccountAuthenticatorActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/IWallpaperManager$Stub$Proxy;-setWallpaper-(Ljava/lang/String;)" : "SET_WALLPAPER", + "Landroid/app/ActivityGroup;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/ActivityGroup;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/ActivityGroup;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/content/ContextWrapper;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/content/ContextWrapper;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/content/ContextWrapper;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/WallpaperManager;-setBitmap-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/WallpaperManager;-clear-()" : "SET_WALLPAPER", + "Landroid/app/WallpaperManager;-setBitmap-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/WallpaperManager;-setResource-(I)" : "SET_WALLPAPER", + "Landroid/app/WallpaperManager;-setStream-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/ContextImpl;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/ContextImpl;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/ContextImpl;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/AliasActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/AliasActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/AliasActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/content/Context;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/content/Context;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/content/Context;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/service/urlrenderer/UrlRendererService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/service/urlrenderer/UrlRendererService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/service/urlrenderer/UrlRendererService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/FullBackupAgent;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/FullBackupAgent;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/FullBackupAgent;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/TabActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/TabActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/TabActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/view/ContextThemeWrapper;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/view/ContextThemeWrapper;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/view/ContextThemeWrapper;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/speech/RecognitionService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/speech/RecognitionService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/speech/RecognitionService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/IntentService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/IntentService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/IntentService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/inputmethodservice/AbstractInputMethodService;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/inputmethodservice/AbstractInputMethodService;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/inputmethodservice/AbstractInputMethodService;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/Application;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/Application;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/Application;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/ListActivity;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/ListActivity;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/ListActivity;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/app/Service;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/app/Service;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/app/Service;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/content/MutableContextWrapper;-clearWallpaper-()" : "SET_WALLPAPER", + "Landroid/content/MutableContextWrapper;-setWallpaper-(Landroid/graphics/Bitmap;)" : "SET_WALLPAPER", + "Landroid/content/MutableContextWrapper;-setWallpaper-(Ljava/io/InputStream;)" : "SET_WALLPAPER", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-acquireWifiLock-(Landroid/os/IBinder; I Ljava/lang/String;)" : "WAKE_LOCK", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-releaseWifiLock-(Landroid/os/IBinder;)" : "WAKE_LOCK", + "Landroid/bluetooth/HeadsetBase;-acquireWakeLock-()" : "WAKE_LOCK", + "Landroid/bluetooth/HeadsetBase;-finalize-()" : "WAKE_LOCK", + "Landroid/bluetooth/HeadsetBase;-handleInput-(Ljava/lang/String;)" : "WAKE_LOCK", + "Landroid/bluetooth/HeadsetBase;-releaseWakeLock-()" : "WAKE_LOCK", + "Landroid/os/PowerManager$WakeLock;-acquire-()" : "WAKE_LOCK", + "Landroid/os/PowerManager$WakeLock;-acquire-(J)" : "WAKE_LOCK", + "Landroid/os/PowerManager$WakeLock;-release-()" : "WAKE_LOCK", + "Landroid/os/PowerManager$WakeLock;-release-(I)" : "WAKE_LOCK", + "Landroid/media/MediaPlayer;-setWakeMode-(Landroid/content/Context; I)" : "WAKE_LOCK", + "Landroid/media/MediaPlayer;-start-()" : "WAKE_LOCK", + "Landroid/media/MediaPlayer;-stayAwake-(B)" : "WAKE_LOCK", + "Landroid/media/MediaPlayer;-stop-()" : "WAKE_LOCK", + "Landroid/bluetooth/ScoSocket;-acquireWakeLock-()" : "WAKE_LOCK", + "Landroid/bluetooth/ScoSocket;-close-()" : "WAKE_LOCK", + "Landroid/bluetooth/ScoSocket;-finalize-()" : "WAKE_LOCK", + "Landroid/bluetooth/ScoSocket;-releaseWakeLock-()" : "WAKE_LOCK", + "Landroid/bluetooth/ScoSocket;-releaseWakeLockNow-()" : "WAKE_LOCK", + "Landroid/media/AsyncPlayer;-acquireWakeLock-()" : "WAKE_LOCK", + "Landroid/media/AsyncPlayer;-enqueueLocked-(Landroid/media/AsyncPlayer$Command;)" : "WAKE_LOCK", + "Landroid/media/AsyncPlayer;-play-(Landroid/content/Context; Landroid/net/Uri; B I)" : "WAKE_LOCK", + "Landroid/media/AsyncPlayer;-releaseWakeLock-()" : "WAKE_LOCK", + "Landroid/media/AsyncPlayer;-stop-()" : "WAKE_LOCK", + "Landroid/net/wifi/WifiManager$WifiLock;-acquire-()" : "WAKE_LOCK", + "Landroid/net/wifi/WifiManager$WifiLock;-finalize-()" : "WAKE_LOCK", + "Landroid/net/wifi/WifiManager$WifiLock;-release-()" : "WAKE_LOCK", + "Landroid/os/IPowerManager$Stub$Proxy;-acquireWakeLock-(I Landroid/os/IBinder; Ljava/lang/String;)" : "WAKE_LOCK", + "Landroid/os/IPowerManager$Stub$Proxy;-releaseWakeLock-(Landroid/os/IBinder; I)" : "WAKE_LOCK", + "Landroid/net/sip/SipAudioCall;-startAudio-()" : "WAKE_LOCK", + "Landroid/os/PowerManager;-ACQUIRE_CAUSES_WAKEUP-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-FULL_WAKE_LOCK-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-ON_AFTER_RELEASE-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-PARTIAL_WAKE_LOCK-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-SCREEN_BRIGHT_WAKE_LOCK-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-SCREEN_DIM_WAKE_LOCK-I" : "WAKE_LOCK", + "Landroid/os/PowerManager;-newWakeLock-(I Ljava/lang/String;)" : "WAKE_LOCK", + "Landroid/accounts/AccountManager;-addAccount-(Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-clearPassword-(Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-confirmCredentials-(Landroid/accounts/Account; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-editProperties-(Ljava/lang/String; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAuthTokenByFeatures-(Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Landroid/app/Activity; Landroid/os/Bundle; Landroid/os/Bundle; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-invalidateAuthToken-(Ljava/lang/String; Ljava/lang/String;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-removeAccount-(Landroid/accounts/Account; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-updateCredentials-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-addAccount-(Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-clearPassword-(Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-confirmCredentials-(Landroid/accounts/Account; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-editProperties-(Ljava/lang/String; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-invalidateAuthToken-(Ljava/lang/String; Ljava/lang/String;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-removeAccount-(Landroid/accounts/Account; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManager;-updateCredentials-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-addAcount-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; B Landroid/os/Bundle;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-checkManageAccountsOrUseCredentialsPermissions-()" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-checkManageAccountsPermission-()" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-clearPassword-(Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-confirmCredentials-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Landroid/os/Bundle; B)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-editProperties-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; B)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-invalidateAuthToken-(Ljava/lang/String; Ljava/lang/String;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-removeAccount-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-updateCredentials-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B Landroid/os/Bundle;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-addAcount-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; B Landroid/os/Bundle;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-clearPassword-(Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-confirmCredentials-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Landroid/os/Bundle; B)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-editProperties-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; B)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-invalidateAuthToken-(Ljava/lang/String; Ljava/lang/String;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-removeAccount-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account;)" : "MANAGE_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-updateCredentials-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B Landroid/os/Bundle;)" : "MANAGE_ACCOUNTS", + "Landroid/provider/Calendar$CalendarAlerts;-insert-(Landroid/content/ContentResolver; J J J J I)" : "WRITE_CALENDAR", + "Landroid/provider/Calendar$Calendars;-delete-(Landroid/content/ContentResolver; Ljava/lang/String; [L[Ljava/lang/Strin;)" : "WRITE_CALENDAR", + "Landroid/provider/Calendar$Calendars;-deleteCalendarsForAccount-(Landroid/content/ContentResolver; Landroid/accounts/Account;)" : "WRITE_CALENDAR", + "Landroid/appwidget/AppWidgetManager;-bindAppWidgetId-(I Landroid/content/ComponentName;)" : "BIND_APPWIDGET", + "Lcom/android/internal/appwidget/IAppWidgetService$Stub$Proxy;-bindAppWidgetId-(I LComponentName;)" : "BIND_APPWIDGET", + "Landroid/os/storage/IMountService$Stub$Proxy;-mountSecureContainer-(Ljava/lang/String; Ljava/lang/String; I)" : "ASEC_MOUNT_UNMOUNT", + "Landroid/os/storage/IMountService$Stub$Proxy;-unmountSecureContainer-(Ljava/lang/String; B)" : "ASEC_MOUNT_UNMOUNT", + "Landroid/app/ContextImpl$ApplicationPackageManager;-addPreferredActivity-(LIntentFilter; I [LComponentName; LComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-clearPackagePreferredActivities-(Ljava/lang/String;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-replacePreferredActivity-(LIntentFilter; I [LComponentName; LComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-addPreferredActivity-(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-clearPackagePreferredActivities-(Ljava/lang/String;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-replacePreferredActivity-(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/PackageManager;-addPreferredActivity-(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/PackageManager;-clearPackagePreferredActivities-(Ljava/lang/String;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/PackageManager;-replacePreferredActivity-(Landroid/content/IntentFilter; I [Landroid/content/ComponentName; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-addPreferredActivity-(Landroid/content/IntentFilter; I [L[Landroid/content/ComponentNam; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-clearPackagePreferredActivities-(Ljava/lang/String;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-replacePreferredActivity-(Landroid/content/IntentFilter; I [L[Landroid/content/ComponentNam; Landroid/content/ComponentName;)" : "SET_PREFERRED_APPLICATIONS", + "Landroid/inputmethodservice/InputMethodService;-SoftInputView-I" : "NFC", + "Landroid/inputmethodservice/InputMethodService;-CandidatesView-I" : "NFC", + "Landroid/inputmethodservice/InputMethodService;-FullscreenMode-I" : "NFC", + "Landroid/inputmethodservice/InputMethodService;-GeneratingText-I" : "NFC", + "Landroid/nfc/tech/NfcA;-close-()" : "NFC", + "Landroid/nfc/tech/NfcA;-connect-()" : "NFC", + "Landroid/nfc/tech/NfcA;-get-(Landroid/nfc/Tag;)" : "NFC", + "Landroid/nfc/tech/NfcA;-transceive-([B)" : "NFC", + "Landroid/nfc/tech/NfcB;-close-()" : "NFC", + "Landroid/nfc/tech/NfcB;-connect-()" : "NFC", + "Landroid/nfc/tech/NfcB;-get-(Landroid/nfc/Tag;)" : "NFC", + "Landroid/nfc/tech/NfcB;-transceive-([B)" : "NFC", + "Landroid/nfc/NfcAdapter;-ACTION_TECH_DISCOVERED-Ljava/lang/String;" : "NFC", + "Landroid/nfc/NfcAdapter;-disableForegroundDispatch-(Landroid/app/Activity;)" : "NFC", + "Landroid/nfc/NfcAdapter;-disableForegroundNdefPush-(Landroid/app/Activity;)" : "NFC", + "Landroid/nfc/NfcAdapter;-enableForegroundDispatch-(Landroid/app/Activity; Landroid/app/PendingIntent; [Landroid/content/IntentFilter; [[Ljava/lang/String[];)" : "NFC", + "Landroid/nfc/NfcAdapter;-enableForegroundNdefPush-(Landroid/app/Activity; Landroid/nfc/NdefMessage;)" : "NFC", + "Landroid/nfc/NfcAdapter;-getDefaultAdapter-()" : "NFC", + "Landroid/nfc/NfcAdapter;-getDefaultAdapter-(Landroid/content/Context;)" : "NFC", + "Landroid/nfc/NfcAdapter;-isEnabled-()" : "NFC", + "Landroid/nfc/tech/NfcF;-close-()" : "NFC", + "Landroid/nfc/tech/NfcF;-connect-()" : "NFC", + "Landroid/nfc/tech/NfcF;-get-(Landroid/nfc/Tag;)" : "NFC", + "Landroid/nfc/tech/NfcF;-transceive-([B)" : "NFC", + "Landroid/nfc/tech/NdefFormatable;-close-()" : "NFC", + "Landroid/nfc/tech/NdefFormatable;-connect-()" : "NFC", + "Landroid/nfc/tech/NdefFormatable;-format-(Landroid/nfc/NdefMessage;)" : "NFC", + "Landroid/nfc/tech/NdefFormatable;-formatReadOnly-(Landroid/nfc/NdefMessage;)" : "NFC", + "Landroid/app/Activity;-Fragments-I" : "NFC", + "Landroid/app/Activity;-ActivityLifecycle-I" : "NFC", + "Landroid/app/Activity;-ConfigurationChanges-I" : "NFC", + "Landroid/app/Activity;-StartingActivities-I" : "NFC", + "Landroid/app/Activity;-SavingPersistentState-I" : "NFC", + "Landroid/app/Activity;-Permissions-I" : "NFC", + "Landroid/app/Activity;-ProcessLifecycle-I" : "NFC", + "Landroid/nfc/tech/MifareClassic;-KEY_NFC_FORUM-[B" : "NFC", + "Landroid/nfc/tech/MifareClassic;-authenticateSectorWithKeyA-(I [B)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-authenticateSectorWithKeyB-(I [B)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-close-()" : "NFC", + "Landroid/nfc/tech/MifareClassic;-connect-()" : "NFC", + "Landroid/nfc/tech/MifareClassic;-decrement-(I I)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-increment-(I I)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-readBlock-(I)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-restore-(I)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-transceive-([B)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-transfer-(I)" : "NFC", + "Landroid/nfc/tech/MifareClassic;-writeBlock-(I [B)" : "NFC", + "Landroid/nfc/Tag;-getTechList-()" : "NFC", + "Landroid/app/Service;-WhatIsAService-I" : "NFC", + "Landroid/app/Service;-ServiceLifecycle-I" : "NFC", + "Landroid/app/Service;-Permissions-I" : "NFC", + "Landroid/app/Service;-ProcessLifecycle-I" : "NFC", + "Landroid/app/Service;-LocalServiceSample-I" : "NFC", + "Landroid/app/Service;-RemoteMessengerServiceSample-I" : "NFC", + "Landroid/nfc/NfcManager;-getDefaultAdapter-()" : "NFC", + "Landroid/nfc/tech/MifareUltralight;-close-()" : "NFC", + "Landroid/nfc/tech/MifareUltralight;-connect-()" : "NFC", + "Landroid/nfc/tech/MifareUltralight;-readPages-(I)" : "NFC", + "Landroid/nfc/tech/MifareUltralight;-transceive-([B)" : "NFC", + "Landroid/nfc/tech/MifareUltralight;-writePage-(I [B)" : "NFC", + "Landroid/nfc/tech/NfcV;-close-()" : "NFC", + "Landroid/nfc/tech/NfcV;-connect-()" : "NFC", + "Landroid/nfc/tech/NfcV;-get-(Landroid/nfc/Tag;)" : "NFC", + "Landroid/nfc/tech/NfcV;-transceive-([B)" : "NFC", + "Landroid/nfc/tech/TagTechnology;-close-()" : "NFC", + "Landroid/nfc/tech/TagTechnology;-connect-()" : "NFC", + "Landroid/preference/PreferenceActivity;-SampleCode-Ljava/lang/String;" : "NFC", + "Landroid/content/pm/PackageManager;-FEATURE_NFC-Ljava/lang/String;" : "NFC", + "Landroid/content/Context;-NFC_SERVICE-Ljava/lang/String;" : "NFC", + "Landroid/nfc/tech/Ndef;-NFC_FORUM_TYPE_1-Ljava/lang/String;" : "NFC", + "Landroid/nfc/tech/Ndef;-NFC_FORUM_TYPE_2-Ljava/lang/String;" : "NFC", + "Landroid/nfc/tech/Ndef;-NFC_FORUM_TYPE_3-Ljava/lang/String;" : "NFC", + "Landroid/nfc/tech/Ndef;-NFC_FORUM_TYPE_4-Ljava/lang/String;" : "NFC", + "Landroid/nfc/tech/Ndef;-close-()" : "NFC", + "Landroid/nfc/tech/Ndef;-connect-()" : "NFC", + "Landroid/nfc/tech/Ndef;-getType-()" : "NFC", + "Landroid/nfc/tech/Ndef;-isWritable-()" : "NFC", + "Landroid/nfc/tech/Ndef;-makeReadOnly-()" : "NFC", + "Landroid/nfc/tech/Ndef;-writeNdefMessage-(Landroid/nfc/NdefMessage;)" : "NFC", + "Landroid/nfc/tech/IsoDep;-close-()" : "NFC", + "Landroid/nfc/tech/IsoDep;-connect-()" : "NFC", + "Landroid/nfc/tech/IsoDep;-setTimeout-(I)" : "NFC", + "Landroid/nfc/tech/IsoDep;-transceive-([B)" : "NFC", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-call-(Ljava/lang/String;)" : "CALL_PHONE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-endCall-()" : "CALL_PHONE", + "Lcom/android/http/multipart/FilePart;-sendData-(Ljava/io/OutputStream;)" : "INTERNET", + "Lcom/android/http/multipart/FilePart;-sendDispositionHeader-(Ljava/io/OutputStream;)" : "INTERNET", + "Ljava/net/HttpURLConnection;--(Ljava/net/URL;)" : "INTERNET", + "Ljava/net/HttpURLConnection;-connect-()" : "INTERNET", + "Landroid/webkit/WebSettings;-setBlockNetworkLoads-(B)" : "INTERNET", + "Landroid/webkit/WebSettings;-verifyNetworkAccess-()" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;--()" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;--(Lorg/apache/http/params/HttpParams;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;--(Lorg/apache/http/conn/ClientConnectionManager; Lorg/apache/http/params/HttpParams;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest;)" : "INTERNET", + "Lorg/apache/http/impl/client/DefaultHttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/client/ResponseHandler;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest;)" : "INTERNET", + "Lorg/apache/http/impl/client/HttpClient;-execute-(Lorg/apache/http/HttpHost; Lorg/apache/http/client/methods/HttpUriRequest; Lorg/apache/http/protocol/HttpContext;)" : "INTERNET", + "Lcom/android/http/multipart/Part;-send-(Ljava/io/OutputStream;)" : "INTERNET", + "Lcom/android/http/multipart/Part;-sendParts-(Ljava/io/OutputStream; [Lcom/android/http/multipart/Part;)" : "INTERNET", + "Lcom/android/http/multipart/Part;-sendParts-(Ljava/io/OutputStream; [Lcom/android/http/multipart/Part; [B)" : "INTERNET", + "Lcom/android/http/multipart/Part;-sendStart-(Ljava/io/OutputStream;)" : "INTERNET", + "Lcom/android/http/multipart/Part;-sendTransferEncodingHeader-(Ljava/io/OutputStream;)" : "INTERNET", + "Landroid/drm/DrmErrorEvent;-TYPE_NO_INTERNET_CONNECTION-I" : "INTERNET", + "Landroid/webkit/WebViewCore;--(Landroid/content/Context; Landroid/webkit/WebView; Landroid/webkit/CallbackProxy; Ljava/util/Map;)" : "INTERNET", + "Ljava/net/URLConnection;-connect-()" : "INTERNET", + "Ljava/net/URLConnection;-getInputStream-()" : "INTERNET", + "Landroid/app/Activity;-setContentView-(I)" : "INTERNET", + "Ljava/net/MulticastSocket;--()" : "INTERNET", + "Ljava/net/MulticastSocket;--(I)" : "INTERNET", + "Ljava/net/MulticastSocket;--(Ljava/net/SocketAddress;)" : "INTERNET", + "Lcom/android/http/multipart/StringPart;-sendData-(Ljava/io/OuputStream;)" : "INTERNET", + "Ljava/net/URL;-getContent-([Ljava/lang/Class;)" : "INTERNET", + "Ljava/net/URL;-getContent-()" : "INTERNET", + "Ljava/net/URL;-openConnection-(Ljava/net/Proxy;)" : "INTERNET", + "Ljava/net/URL;-openConnection-()" : "INTERNET", + "Ljava/net/URL;-openStream-()" : "INTERNET", + "Ljava/net/DatagramSocket;--()" : "INTERNET", + "Ljava/net/DatagramSocket;--(I)" : "INTERNET", + "Ljava/net/DatagramSocket;--(I Ljava/net/InetAddress;)" : "INTERNET", + "Ljava/net/DatagramSocket;--(Ljava/net/SocketAddress;)" : "INTERNET", + "Ljava/net/ServerSocket;--()" : "INTERNET", + "Ljava/net/ServerSocket;--(I)" : "INTERNET", + "Ljava/net/ServerSocket;--(I I)" : "INTERNET", + "Ljava/net/ServerSocket;--(I I Ljava/net/InetAddress;)" : "INTERNET", + "Ljava/net/ServerSocket;-bind-(Ljava/net/SocketAddress;)" : "INTERNET", + "Ljava/net/ServerSocket;-bind-(Ljava/net/SocketAddress; I)" : "INTERNET", + "Ljava/net/Socket;--()" : "INTERNET", + "Ljava/net/Socket;--(Ljava/lang/String; I)" : "INTERNET", + "Ljava/net/Socket;--(Ljava/lang/String; I Ljava/net/InetAddress; I)" : "INTERNET", + "Ljava/net/Socket;--(Ljava/lang/String; I B)" : "INTERNET", + "Ljava/net/Socket;--(Ljava/net/InetAddress; I)" : "INTERNET", + "Ljava/net/Socket;--(Ljava/net/InetAddress; I Ljava/net/InetAddress; I)" : "INTERNET", + "Ljava/net/Socket;--(Ljava/net/InetAddress; I B)" : "INTERNET", + "Landroid/webkit/WebView;--(Landroid/content/Context; Landroid/util/AttributeSet; I)" : "INTERNET", + "Landroid/webkit/WebView;--(Landroid/content/Context; Landroid/util/AttributeSet;)" : "INTERNET", + "Landroid/webkit/WebView;--(Landroid/content/Context;)" : "INTERNET", + "Ljava/net/NetworkInterface;--()" : "INTERNET", + "Ljava/net/NetworkInterface;--(Ljava/lang/String; I Ljava/net/InetAddress;)" : "INTERNET", + "Landroid/webkit/WebChromeClient;-onGeolocationPermissionsShowPrompt-(Ljava/lang/String; Landroid/webkit/GeolocationPermissions/Callback;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-GPS_PROVIDER-Ljava/lang/String;" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-NETWORK_PROVIDER-Ljava/lang/String;" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-PASSIVE_PROVIDER-Ljava/lang/String;" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-addGpsStatusListener-(Landroid/location/GpsStatus/Listener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-addNmeaListener-(Landroid/location/GpsStatus/NmeaListener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-_requestLocationUpdates-(Ljava/lang/String; J F Landroid/app/PendingIntent;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-_requestLocationUpdates-(Ljava/lang/String; J F Landroid/location/LocationListener; Landroid/os/Looper;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-addGpsStatusListener-(Landroid/location/GpsStatus$Listener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-addNmeaListener-(Landroid/location/GpsStatus$NmeaListener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-addProximityAlert-(D D F J Landroid/app/PendingIntent;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-best-(Ljava/util/List;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-getBestProvider-(Landroid/location/Criteria; B)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-getLastKnownLocation-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-getProvider-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-getProviders-(Landroid/location/Criteria; B)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-getProviders-(B)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-isProviderEnabled-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-requestLocationUpdates-(Ljava/lang/String; J F Landroid/app/PendingIntent;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-requestLocationUpdates-(Ljava/lang/String; J F Landroid/location/LocationListener; Landroid/os/Looper;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-requestLocationUpdates-(Ljava/lang/String; J F Landroid/location/LocationListener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/LocationManager;-sendExtraCommand-(Ljava/lang/String; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCESS_FINE_LOCATION", + "Landroid/webkit/GeolocationService;-registerForLocationUpdates-()" : "ACCESS_FINE_LOCATION", + "Landroid/webkit/GeolocationService;-setEnableGps-(B)" : "ACCESS_FINE_LOCATION", + "Landroid/webkit/GeolocationService;-start-()" : "ACCESS_FINE_LOCATION", + "Landroid/telephony/TelephonyManager;-getCellLocation-()" : "ACCESS_FINE_LOCATION", + "Landroid/telephony/TelephonyManager;-getCellLocation-()" : "ACCESS_FINE_LOCATION", + "Landroid/telephony/TelephonyManager;-getNeighboringCellInfo-()" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-addGpsStatusListener-(Landroid/location/IGpsStatusListener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-addProximityAlert-(D D F J Landroid/app/PendingIntent;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-getLastKnownLocation-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-getProviderInfo-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-getProviders-(B)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-isProviderEnabled-(Ljava/lang/String;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-requestLocationUpdates-(Ljava/lang/String; J F Landroid/location/ILocationListener;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-requestLocationUpdatesPI-(Ljava/lang/String; J F Landroid/app/PendingIntent;)" : "ACCESS_FINE_LOCATION", + "Landroid/location/ILocationManager$Stub$Proxy;-sendExtraCommand-(Ljava/lang/String; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCESS_FINE_LOCATION", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-getCellLocation-()" : "ACCESS_FINE_LOCATION", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-getNeighboringCellInfo-()" : "ACCESS_FINE_LOCATION", + "Landroid/webkit/GeolocationPermissions$Callback;-invok-()" : "ACCESS_FINE_LOCATION", + "Landroid/provider/Telephony$Sms$Inbox;-addMessage-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B)" : "READ_SMS", + "Landroid/provider/Telephony$Threads;-getOrCreateThreadId-(Landroid/content/Context; Ljava/lang/String;)" : "READ_SMS", + "Landroid/provider/Telephony$Threads;-getOrCreateThreadId-(Landroid/content/Context; Ljava/util/Set;)" : "READ_SMS", + "Landroid/provider/Telephony$Mms;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)" : "READ_SMS", + "Landroid/provider/Telephony$Mms;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)" : "READ_SMS", + "Landroid/provider/Telephony$Sms$Draft;-addMessage-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long;)" : "READ_SMS", + "Landroid/provider/Telephony$Sms$Sent;-addMessage-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long;)" : "READ_SMS", + "Landroid/provider/Telephony$Sms;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin; Ljava/lang/String; Ljava/lang/String;)" : "READ_SMS", + "Landroid/provider/Telephony$Sms;-query-(Landroid/content/ContentResolver; [L[Ljava/lang/Strin;)" : "READ_SMS", + "Landroid/view/SurfaceSession;--()" : "ACCESS_SURFACE_FLINGER", + "Landroid/view/Surface;-closeTransaction-()" : "ACCESS_SURFACE_FLINGER", + "Landroid/view/Surface;-freezeDisplay-(I)" : "ACCESS_SURFACE_FLINGER", + "Landroid/view/Surface;-setOrientation-(I I I)" : "ACCESS_SURFACE_FLINGER", + "Landroid/view/Surface;-setOrientation-(I I)" : "ACCESS_SURFACE_FLINGER", + "Landroid/view/Surface;-unfreezeDisplay-(I)" : "ACCESS_SURFACE_FLINGER", + "Landroid/app/IActivityManager$Stub$Proxy;-moveTaskBackwards-(I)" : "REORDER_TASKS", + "Landroid/app/IActivityManager$Stub$Proxy;-moveTaskToBack-(I)" : "REORDER_TASKS", + "Landroid/app/IActivityManager$Stub$Proxy;-moveTaskToFront-(I)" : "REORDER_TASKS", + "Landroid/app/ActivityManager;-moveTaskToFront-(I I)" : "REORDER_TASKS", + "Landroid/net/sip/SipAudioCall;-setSpeakerMode-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/server/BluetoothA2dpService;-checkSinkSuspendState-(I)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/server/BluetoothA2dpService;-handleSinkStateChange-(Landroid/bluetooth/BluetoothDevice;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/server/BluetoothA2dpService;-onBluetoothDisable-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/server/BluetoothA2dpService;-onBluetoothEnable-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/IAudioService$Stub$Proxy;-setBluetoothScoOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/IAudioService$Stub$Proxy;-setMode-(I Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/IAudioService$Stub$Proxy;-setSpeakerphoneOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/IAudioService$Stub$Proxy;-startBluetoothSco-(Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/IAudioService$Stub$Proxy;-stopBluetoothSco-(Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioService;-setBluetoothScoOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioService;-setMode-(I Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioService;-setSpeakerphoneOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioService;-startBluetoothSco-(Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioService;-stopBluetoothSco-(Landroid/os/IBinder;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-startBluetoothSco-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-stopBluetoothSco-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-isBluetoothA2dpOn-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-isWiredHeadsetOn-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setBluetoothScoOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setMicrophoneMute-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setMode-(I)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setParameter-(Ljava/lang/String; Ljava/lang/String;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setParameters-(Ljava/lang/String;)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-setSpeakerphoneOn-(B)" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-startBluetoothSco-()" : "MODIFY_AUDIO_SETTINGS", + "Landroid/media/AudioManager;-stopBluetoothSco-()" : "MODIFY_AUDIO_SETTINGS", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getDeviceId-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getDeviceSvn-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getIccSerialNumber-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getLine1AlphaTag-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getLine1Number-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getSubscriberId-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getVoiceMailAlphaTag-()" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-getVoiceMailNumber-()" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneStateListener;-LISTEN_CALL_FORWARDING_INDICATOR-I" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneStateListener;-LISTEN_CALL_STATE-I" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneStateListener;-LISTEN_DATA_ACTIVITY-I" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneStateListener;-LISTEN_MESSAGE_WAITING_INDICATOR-I" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneStateListener;-LISTEN_SIGNAL_STRENGTH-I" : "READ_PHONE_STATE", + "Landroid/accounts/AccountManagerService$SimWatcher;-onReceive-(Landroid/content/Context; Landroid/content/Intent;)" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/CallerInfo;-markAsVoiceMail-()" : "READ_PHONE_STATE", + "Landroid/os/Build/VERSION_CODES;-DONUT-I" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-ACTION_PHONE_STATE_CHANGED-Ljava/lang/String;" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getDeviceId-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getDeviceSoftwareVersion-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getLine1Number-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getSimSerialNumber-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getSubscriberId-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getVoiceMailAlphaTag-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getVoiceMailNumber-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getDeviceId-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getDeviceSoftwareVersion-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getLine1AlphaTag-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getLine1Number-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getSimSerialNumber-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getSubscriberId-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getVoiceMailAlphaTag-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-getVoiceMailNumber-()" : "READ_PHONE_STATE", + "Landroid/telephony/TelephonyManager;-listen-(Landroid/telephony/PhoneStateListener; I)" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-listen-(Ljava/lang/String; Lcom/android/internal/telephony/IPhoneStateListener; I B)" : "READ_PHONE_STATE", + "Landroid/telephony/PhoneNumberUtils;-isVoiceMailNumber-(Ljava/lang/String;)" : "READ_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-isSimPinEnabled-()" : "READ_PHONE_STATE", + "Landroid/media/RingtoneManager;-setActualDefaultRingtoneUri-(Landroid/content/Context; I Landroid/net/Uri;)" : "WRITE_SETTINGS", + "Landroid/os/IPowerManager$Stub$Proxy;-setStayOnSetting-(I)" : "WRITE_SETTINGS", + "Landroid/server/BluetoothService;-persistBluetoothOnSetting-(B)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Secure;-putFloat-(Landroid/content/ContentResolver; Ljava/lang/String; F)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Secure;-putInt-(Landroid/content/ContentResolver; Ljava/lang/String; I)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Secure;-putLong-(Landroid/content/ContentResolver; Ljava/lang/String; J)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Secure;-putString-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Secure;-setLocationProviderEnabled-(Landroid/content/ContentResolver; Ljava/lang/String; B)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Bookmarks;-add-(Landroid/content/ContentResolver; Landroid/content/Intent; Ljava/lang/String; Ljava/lang/String; C I)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$Bookmarks;-getIntentForShortcut-(Landroid/content/ContentResolver; C)" : "WRITE_SETTINGS", + "Landroid/os/IMountService$Stub$Proxy;-setAutoStartUm-()" : "WRITE_SETTINGS", + "Landroid/os/IMountService$Stub$Proxy;-setPlayNotificationSound-()" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-putConfiguration-(Landroid/content/ContentResolver; Landroid/content/res/Configuration;)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-putFloat-(Landroid/content/ContentResolver; Ljava/lang/String; F)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-putInt-(Landroid/content/ContentResolver; Ljava/lang/String; I)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-putLong-(Landroid/content/ContentResolver; Ljava/lang/String; J)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-putString-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_SETTINGS", + "Landroid/provider/Settings$System;-setShowGTalkServiceStatus-(Landroid/content/ContentResolver; B)" : "WRITE_SETTINGS", + "Landroid/service/wallpaper/WallpaperService;-SERVICE_INTERFACE-Ljava/lang/String;" : "BIND_WALLPAPER", + "Lcom/android/server/WallpaperManagerService;-bindWallpaperComponentLocked-(Landroid/content/ComponentName;)" : "BIND_WALLPAPER", + "Landroid/content/ContentService;-dump-(Ljava/io/FileDescriptor; Ljava/io/PrintWriter; [L[Ljava/lang/Strin;)" : "DUMP", + "Landroid/view/IWindowManager$Stub$Proxy;-isViewServerRunning-()" : "DUMP", + "Landroid/view/IWindowManager$Stub$Proxy;-startViewServer-(I)" : "DUMP", + "Landroid/view/IWindowManager$Stub$Proxy;-stopViewServer-()" : "DUMP", + "Landroid/os/Debug;-dumpService-(Ljava/lang/String; Ljava/io/FileDescriptor; [Ljava/lang/String;)" : "DUMP", + "Landroid/os/IBinder;-DUMP_TRANSACTION-I" : "DUMP", + "Lcom/android/server/WallpaperManagerService;-dump-(Ljava/io/FileDescriptor; Ljava/io/PrintWriter; [L[Ljava/lang/Stri;)" : "DUMP", + "Landroid/accounts/AccountManager;-blockingGetAuthToken-(Landroid/accounts/Account; Ljava/lang/String; B)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-getAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-getAuthToken-(Landroid/accounts/Account; Ljava/lang/String; B Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-invalidateAuthToken-(Ljava/lang/String; Ljava/lang/String;)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-blockingGetAuthToken-(Landroid/accounts/Account; Ljava/lang/String; B)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-getAuthToken-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; Landroid/app/Activity; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManager;-getAuthToken-(Landroid/accounts/Account; Ljava/lang/String; B Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "USE_CREDENTIALS", + "Landroid/accounts/AccountManagerService;-getAuthToken-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B B Landroid/os/Bundle;)" : "USE_CREDENTIALS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-getAuthToken-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; Ljava/lang/String; B B Landroid/os/Bundle;)" : "USE_CREDENTIALS", + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;-notePauseComponent-(LComponentName;)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IUsageStats$Stub$Proxy;-noteResumeComponent-(LComponentName;)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteFullWifiLockAcquired-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteFullWifiLockReleased-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteInputEvent-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-notePhoneDataConnectionState-(I B)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-notePhoneOff-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-notePhoneOn-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-notePhoneSignalStrength-(LSignalStrength;)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-notePhoneState-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteScanWifiLockAcquired-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteScanWifiLockReleased-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteScreenBrightness-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteScreenOff-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteScreenOn-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStartGps-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStartSensor-(I I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStartWakelock-(I Ljava/lang/String; I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStopGps-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStopSensor-(I I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteStopWakelock-(I Ljava/lang/String; I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteUserActivity-(I I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiMulticastDisabled-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiMulticastEnabled-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiOff-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiOn-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiRunning-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-noteWifiStopped-()" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-recordCurrentLevel-(I)" : "UPDATE_DEVICE_STATS", + "Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-setOnBattery-(B I)" : "UPDATE_DEVICE_STATS", + "Landroid/telephony/gsm/SmsManager;-getDefault-()" : "SEND_SMS", + "Landroid/telephony/gsm/SmsManager;-sendDataMessage-(Ljava/lang/String; Ljava/lang/String; S [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/gsm/SmsManager;-sendTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/gsm/SmsManager;-sendDataMessage-(Ljava/lang/String; Ljava/lang/String; S [L; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/gsm/SmsManager;-sendMultipartTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/util/ArrayList; Ljava/util/ArrayList; Ljava/util/ArrayList;)" : "SEND_SMS", + "Landroid/telephony/gsm/SmsManager;-sendTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/SmsManager;-getDefault-()" : "SEND_SMS", + "Landroid/telephony/SmsManager;-sendDataMessage-(Ljava/lang/String; Ljava/lang/String; S [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/SmsManager;-sendTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/SmsManager;-sendDataMessage-(Ljava/lang/String; Ljava/lang/String; S [L; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/telephony/SmsManager;-sendMultipartTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/util/ArrayList; Ljava/util/ArrayList; Ljava/util/ArrayList;)" : "SEND_SMS", + "Landroid/telephony/SmsManager;-sendTextMessage-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-sendData-(Ljava/lang/String; Ljava/lang/String; I [B Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-sendMultipartText-(Ljava/lang/String; Ljava/lang/String; Ljava/util/List; Ljava/util/List; Ljava/util/List;)" : "SEND_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-sendText-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)" : "SEND_SMS", + "Landroid/provider/UserDictionary$Words;-addWord-(Landroid/content/Context; Ljava/lang/String; I I)" : "WRITE_USER_DICTIONARY", + "Landroid/telephony/TelephonyManager;-getCellLocation-()" : "ACCESS_COARSE_LOCATION", + "Landroid/telephony/PhoneStateListener;-LISTEN_CELL_LOCATION-I" : "ACCESS_COARSE_LOCATION", + "Landroid/location/LocationManager;-NETWORK_PROVIDER-Ljava/lang/String;" : "ACCESS_COARSE_LOCATION", + "Landroid/os/storage/IMountService$Stub$Proxy;-renameSecureContainer-(Ljava/lang/String; Ljava/lang/String;)" : "ASEC_RENAME", + "Landroid/view/IWindowSession$Stub$Proxy;-add-(Landroid/view/IWindow; Landroid/view/WindowManager$LayoutParams; I Landroid/graphics/Rect;)" : "SYSTEM_ALERT_WINDOW", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-acquireMulticastLock-(Landroid/os/IBinder; Ljava/lang/String;)" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-initializeMulticastFiltering-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-releaseMulticastLock-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/WifiManager$MulticastLock;-acquire-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/WifiManager$MulticastLock;-finalize-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/WifiManager$MulticastLock;-release-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/net/wifi/WifiManager;-initializeMulticastFiltering-()" : "CHANGE_WIFI_MULTICAST_STATE", + "Landroid/content/Intent;-ACTION_BOOT_COMPLETED-Ljava/lang/String;" : "RECEIVE_BOOT_COMPLETED", + "Landroid/provider/AlarmClock;-ACTION_SET_ALARM-Ljava/lang/String;" : "SET_ALARM", + "Landroid/provider/AlarmClock;-EXTRA_HOUR-Ljava/lang/String;" : "SET_ALARM", + "Landroid/provider/AlarmClock;-EXTRA_MESSAGE-Ljava/lang/String;" : "SET_ALARM", + "Landroid/provider/AlarmClock;-EXTRA_MINUTES-Ljava/lang/String;" : "SET_ALARM", + "Landroid/provider/AlarmClock;-EXTRA_SKIP_UI-Ljava/lang/String;" : "SET_ALARM", + "Lcom/android/internal/telephony/IccPhoneBookInterfaceManager$Stub$Proxy;-updateAdnRecordsInEfByIndex-(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_CONTACTS", + "Lcom/android/internal/telephony/IccPhoneBookInterfaceManager$Stub$Proxy;-updateAdnRecordsInEfBySearch-(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_CONTACTS", + "Landroid/provider/Contacts$People;-addToGroup-(Landroid/content/ContentResolver; J J)" : "WRITE_CONTACTS", + "Landroid/provider/ContactsContract$Contacts;-markAsContacted-(Landroid/content/ContentResolver; J)" : "WRITE_CONTACTS", + "Landroid/provider/Contacts$Settings;-setSetting-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_CONTACTS", + "Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;-updateAdnRecordsInEfByIndex-(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_CONTACTS", + "Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;-updateAdnRecordsInEfBySearch-(I Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "WRITE_CONTACTS", + "Landroid/provider/CallLog$Calls;-removeExpiredEntries-(Landroid/content/Context;)" : "WRITE_CONTACTS", + "Landroid/pim/vcard/VCardEntryCommitter;-onEntryCreated-(Landroid/pim/vcard/VCardEntry;)" : "WRITE_CONTACTS", + "Landroid/pim/vcard/VCardEntryHandler;-onEntryCreated-(Landroid/pim/vcard/VCardEntry;)" : "WRITE_CONTACTS", + "Landroid/pim/vcard/VCardEntry;-pushIntoContentResolver-(Landroid/content/ContentResolver;)" : "WRITE_CONTACTS", + "Landroid/content/Intent;-ACTION_NEW_OUTGOING_CALL-Ljava/lang/String;" : "PROCESS_OUTGOING_CALLS", + "Landroid/app/StatusBarManager;-collapse-()" : "EXPAND_STATUS_BAR", + "Landroid/app/StatusBarManager;-expand-()" : "EXPAND_STATUS_BAR", + "Landroid/app/StatusBarManager;-toggle-()" : "EXPAND_STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-activate-()" : "EXPAND_STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-deactivate-()" : "EXPAND_STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-toggle-()" : "EXPAND_STATUS_BAR", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-answerRingingCall-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-cancelMissedCallsNotification-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-disableApnType-(Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-disableDataConnectivity-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-enableApnType-(Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-enableDataConnectivity-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-handlePinMmi-(Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-setRadio-(B)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-silenceRinger-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-supplyPin-(Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-toggleRadioOnOff-()" : "MODIFY_PHONE_STATE", + "Landroid/net/MobileDataStateTracker;-reconnect-()" : "MODIFY_PHONE_STATE", + "Landroid/net/MobileDataStateTracker;-setRadio-(B)" : "MODIFY_PHONE_STATE", + "Landroid/net/MobileDataStateTracker;-teardown-()" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyCallForwardingChanged-(B)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyCallState-(I Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyCellLocation-(Landroid/os/Bundle;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyDataActivity-(I)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyDataConnection-(I B Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String; Ljava/lang/String; I)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyDataConnectionFailed-(Ljava/lang/String;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyMessageWaitingChanged-(B)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifyServiceState-(Landroid/telephony/ServiceState;)" : "MODIFY_PHONE_STATE", + "Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-notifySignalStrength-(Landroid/telephony/SignalStrength;)" : "MODIFY_PHONE_STATE", + "Landroid/os/IMountService$Stub$Proxy;-formatMedi-()" : "MOUNT_FORMAT_FILESYSTEMS", + "Landroid/os/storage/IMountService$Stub$Proxy;-formatVolume-(Ljava/lang/String;)" : "MOUNT_FORMAT_FILESYSTEMS", + "Landroid/net/Downloads$DownloadBase;-startDownloadByUri-(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ByUri;-getCurrentOtaDownloads-(Landroid/content/Context; Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ByUri;-getProgressCursor-(Landroid/content/Context; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ByUri;-getStatus-(Landroid/content/Context; Ljava/lang/String; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ByUri;-removeAllDownloadsByPackage-(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ByUri;-startDownloadByUri-(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-deleteDownload-(Landroid/content/Context; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-getMimeTypeForId-(Landroid/content/Context; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-getStatus-(Landroid/content/Context; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-openDownload-(Landroid/content/Context; J Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-openDownloadStream-(Landroid/content/Context; J)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/net/Downloads$ById;-startDownloadByUri-(Landroid/content/Context; Ljava/lang/String; Ljava/lang/String; B I B B Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "ACCESS_DOWNLOAD_MANAGER", + "Landroid/view/IWindowManager$Stub$Proxy;-getDPadKeycodeState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getDPadScancodeState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getKeycodeState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getKeycodeStateForDevice-(I I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getScancodeState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getScancodeStateForDevice-(I I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getSwitchState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getSwitchStateForDevice-(I I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getTrackballKeycodeState-(I)" : "READ_INPUT_STATE", + "Landroid/view/IWindowManager$Stub$Proxy;-getTrackballScancodeState-(I)" : "READ_INPUT_STATE", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getCurrentSync-()" : "READ_SYNC_STATS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-getSyncStatus-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-isSyncActive-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-isSyncPending-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentService;-getCurrentSync-()" : "READ_SYNC_STATS", + "Landroid/content/ContentService;-getSyncStatus-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentService;-isSyncActive-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentService;-isSyncPending-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentResolver;-getCurrentSync-()" : "READ_SYNC_STATS", + "Landroid/content/ContentResolver;-getSyncStatus-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentResolver;-isSyncActive-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/ContentResolver;-isSyncPending-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/IContentService$Stub$Proxy;-getCurrentSync-()" : "READ_SYNC_STATS", + "Landroid/content/IContentService$Stub$Proxy;-getSyncStatus-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/IContentService$Stub$Proxy;-isSyncActive-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/content/IContentService$Stub$Proxy;-isSyncPending-(Landroid/accounts/Account; Ljava/lang/String;)" : "READ_SYNC_STATS", + "Landroid/app/AlarmManager;-setTime-(J)" : "SET_TIME", + "Landroid/app/AlarmManager;-setTimeZone-(Ljava/lang/String;)" : "SET_TIME", + "Landroid/app/AlarmManager;-setTime-(J)" : "SET_TIME", + "Landroid/app/IAlarmManager$Stub$Proxy;-setTime-(J)" : "SET_TIME", + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;-setWimaxEnable-()" : "CHANGE_WIMAX_STATE", + "Landroid/os/IMountService$Stub$Proxy;-mountMedi-()" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/IMountService$Stub$Proxy;-unmountMedi-()" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/IMountService$Stub$Proxy;-getStorageUsers-(Ljava/lang/String;)" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/IMountService$Stub$Proxy;-mountVolume-(Ljava/lang/String;)" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/IMountService$Stub$Proxy;-setUsbMassStorageEnabled-(B)" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/IMountService$Stub$Proxy;-unmountVolume-(Ljava/lang/String; B)" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/StorageManager;-disableUsbMassStorage-()" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/os/storage/StorageManager;-enableUsbMassStorage-()" : "MOUNT_UNMOUNT_FILESYSTEMS", + "Landroid/app/ContextImpl$ApplicationPackageManager;-movePackage-(Ljava/lang/String; LIPackageMoveObserver; I)" : "MOVE_PACKAGE", + "Landroid/app/ContextImpl$ApplicationPackageManager;-movePackage-(Ljava/lang/String; LIPackageMoveObserver; I)" : "MOVE_PACKAGE", + "Landroid/content/pm/PackageManager;-movePackage-(Ljava/lang/String; LIPackageMoveObserver; I)" : "MOVE_PACKAGE", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-movePackage-(Ljava/lang/String; Landroid/content/pm/IPackageMoveObserver; I)" : "MOVE_PACKAGE", + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;-getConnectionInf-()" : "ACCESS_WIMAX_STATE", + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;-getWimaxStat-()" : "ACCESS_WIMAX_STATE", + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;-isBackoffStat-()" : "ACCESS_WIMAX_STATE", + "Lcom/htc/net/wimax/WimaxController$Stub$Proxy;-isWimaxEnable-()" : "ACCESS_WIMAX_STATE", + "Landroid/net/sip/SipAudioCall;-startAudio-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getConfiguredNetworks-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getConnectionInfo-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getDhcpInfo-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getNumAllowedChannels-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getScanResults-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getValidChannelCounts-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getWifiApEnabledState-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-getWifiEnabledState-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/IWifiManager$Stub$Proxy;-isMulticastEnabled-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getConfiguredNetworks-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getConnectionInfo-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getDhcpInfo-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getNumAllowedChannels-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getScanResults-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getValidChannelCounts-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getWifiApState-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-getWifiState-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-isMulticastEnabled-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-isWifiApEnabled-()" : "ACCESS_WIFI_STATE", + "Landroid/net/wifi/WifiManager;-isWifiEnabled-()" : "ACCESS_WIFI_STATE", + "Landroid/webkit/WebIconDatabase;-bulkRequestIconForPageUrl-(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase$IconListener;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-BOOKMARKS_URI-Landroid/net/Uri;" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-SEARCHES_URI-Landroid/net/Uri;" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-addSearchUrl-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-canClearHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getAllBookmarks-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getAllVisitedUrls-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-requestAllIcons-(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase/IconListener;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-truncateHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-updateVisitedHistory-(Landroid/content/ContentResolver; Ljava/lang/String; B)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-addSearchUrl-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-canClearHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-clearHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-deleteFromHistory-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-deleteHistoryTimeFrame-(Landroid/content/ContentResolver; J J)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-deleteHistoryWhere-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getAllBookmarks-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getAllVisitedUrls-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getVisitedHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-getVisitedLike-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-requestAllIcons-(Landroid/content/ContentResolver; Ljava/lang/String; Landroid/webkit/WebIconDatabase$IconListener;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-truncateHistory-(Landroid/content/ContentResolver;)" : "READ_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-updateVisitedHistory-(Landroid/content/ContentResolver; Ljava/lang/String; B)" : "READ_HISTORY_BOOKMARKS", + "Landroid/os/storage/IMountService$Stub$Proxy;-destroySecureContainer-(Ljava/lang/String; B)" : "ASEC_DESTROY", + "Landroid/net/ThrottleManager;-getByteCount-(Ljava/lang/String; I I I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ThrottleManager;-getCliffLevel-(Ljava/lang/String; I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ThrottleManager;-getCliffThreshold-(Ljava/lang/String; I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ThrottleManager;-getHelpUri-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ThrottleManager;-getPeriodStartTime-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ThrottleManager;-getResetTime-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/NetworkInfo;-isConnectedOrConnecting-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getDnsForwarders-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getInterfaceRxCounter-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getInterfaceRxThrottle-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getInterfaceTxCounter-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getInterfaceTxThrottle-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-getIpForwardingEnabled-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-isTetheringStarted-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-isUsbRNDISStarted-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-listInterfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-listTetheredInterfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-listTtys-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getActiveNetworkInfo-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getAllNetworkInfo-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getLastTetherError-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getMobileDataEnabled-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getNetworkInfo-(I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getNetworkPreference-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getTetherableIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getTetherableUsbRegexs-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getTetherableWifiRegexs-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getTetheredIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-getTetheringErroredIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-isTetheringSupported-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-startUsingNetworkFeature-(I Ljava/lang/String; Landroid/os/IBinder;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getByteCount-(Ljava/lang/String; I I I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getCliffLevel-(Ljava/lang/String; I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getCliffThreshold-(Ljava/lang/String; I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getHelpUri-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getPeriodStartTime-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getResetTime-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/IThrottleManager$Stub$Proxy;-getThrottle-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getActiveNetworkInfo-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getAllNetworkInfo-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getLastTetherError-(Ljava/lang/String;)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getMobileDataEnabled-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getNetworkInfo-(I)" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getNetworkPreference-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getTetherableIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getTetherableUsbRegexs-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getTetherableWifiRegexs-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getTetheredIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-getTetheringErroredIfaces-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-isTetheringSupported-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/http/RequestQueue;-enablePlatformNotifications-()" : "ACCESS_NETWORK_STATE", + "Landroid/net/http/RequestQueue;-setProxyConfig-()" : "ACCESS_NETWORK_STATE", + "Landroid/app/IActivityManager$Stub$Proxy;-getRecentTasks-(I I)" : "GET_TASKS", + "Landroid/app/IActivityManager$Stub$Proxy;-getTasks-(I I Landroid/app/IThumbnailReceiver;)" : "GET_TASKS", + "Landroid/app/ActivityManagerNative;-getRecentTasks-(I I)" : "GET_TASKS", + "Landroid/app/ActivityManagerNative;-getRunningTasks-(I)" : "GET_TASKS", + "Landroid/app/ActivityManager;-getRecentTasks-(I I)" : "GET_TASKS", + "Landroid/app/ActivityManager;-getRunningTasks-(I)" : "GET_TASKS", + "Landroid/app/ActivityManager;-getRecentTasks-(I I)" : "GET_TASKS", + "Landroid/app/ActivityManager;-getRunningTasks-(I)" : "GET_TASKS", + "Landroid/view/View/OnSystemUiVisibilityChangeListener;-onSystemUiVisibilityChange-(I)" : "STATUS_BAR", + "Landroid/view/View;-STATUS_BAR_HIDDEN-I" : "STATUS_BAR", + "Landroid/view/View;-STATUS_BAR_VISIBLE-I" : "STATUS_BAR", + "Landroid/app/StatusBarManager;-addIcon-(Ljava/lang/String; I I)" : "STATUS_BAR", + "Landroid/app/StatusBarManager;-disable-(I)" : "STATUS_BAR", + "Landroid/app/StatusBarManager;-removeIcon-(Landroid/os/IBinder;)" : "STATUS_BAR", + "Landroid/app/StatusBarManager;-updateIcon-(Landroid/os/IBinder; Ljava/lang/String; I I)" : "STATUS_BAR", + "Landroid/view/WindowManager/LayoutParams;-TYPE_STATUS_BAR-I" : "STATUS_BAR", + "Landroid/view/WindowManager/LayoutParams;-TYPE_STATUS_BAR_PANEL-I" : "STATUS_BAR", + "Landroid/view/WindowManager/LayoutParams;-systemUiVisibility-I" : "STATUS_BAR", + "Landroid/view/WindowManager/LayoutParams;-type-I" : "STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-addIcon-(Ljava/lang/String; Ljava/lang/String; I I)" : "STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-disable-(I Landroid/os/IBinder; Ljava/lang/String;)" : "STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-removeIcon-(Landroid/os/IBinder;)" : "STATUS_BAR", + "Landroid/app/IStatusBar$Stub$Proxy;-updateIcon-(Landroid/os/IBinder; Ljava/lang/String; Ljava/lang/String; I I)" : "STATUS_BAR", + "Landroid/app/IActivityManager$Stub$Proxy;-shutdown-(I)" : "SHUTDOWN", + "Landroid/os/IMountService$Stub$Proxy;-shutdow-()" : "SHUTDOWN", + "Landroid/os/storage/IMountService$Stub$Proxy;-shutdown-(Landroid/os/storage/IMountShutdownObserver;)" : "SHUTDOWN", + "Landroid/os/INetworkManagementService$Stub$Proxy;-shutdown-()" : "SHUTDOWN", + "Landroid/os/DropBoxManager;-ACTION_DROPBOX_ENTRY_ADDED-Ljava/lang/String;" : "READ_LOGS", + "Landroid/os/DropBoxManager;-getNextEntry-(Ljava/lang/String; J)" : "READ_LOGS", + "Landroid/os/DropBoxManager;-getNextEntry-(Ljava/lang/String; J)" : "READ_LOGS", + "Lcom/android/internal/os/IDropBoxManagerService$Stub$Proxy;-getNextEntry-(Ljava/lang/String; J)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-(Ljava/lang/String;)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-([Ljava/lang/String;)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-([Ljava/lang/String; [Ljava/lang/String;)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-([Ljava/lang/String; [Ljava/lang/String; Ljava/io/File;)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-(Ljava/lang/String; [Ljava/lang/String;)" : "READ_LOGS", + "Ljava/lang/Runtime;-exec-(Ljava/lang/String; [Ljava/lang/String; Ljava/io/File;)" : "READ_LOGS", + "Landroid/os/Process;-BLUETOOTH_GID-I" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-ACTION_CONNECTION_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-ACTION_PLAYING_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getConnectedDevices-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getConnectionState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getDevicesMatchingConnectionStates-([I)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-isA2dpPlaying-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getConnectedSinks-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getNonDisconnectedSinks-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getSinkPriority-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-getSinkState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothA2dp;-isSinkConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/media/AudioManager;-ROUTE_BLUETOOTH-I" : "BLUETOOTH", + "Landroid/media/AudioManager;-ROUTE_BLUETOOTH_A2DP-I" : "BLUETOOTH", + "Landroid/media/AudioManager;-ROUTE_BLUETOOTH_SCO-I" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-getConnectedSinks-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-getNonDisconnectedSinks-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-getSinkPriority-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-getSinkState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothSocket;-connect-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothPbap;-getClient-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothPbap;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothPbap;-isConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/provider/Settings/System;-AIRPLANE_MODE_RADIOS-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings/System;-BLUETOOTH_DISCOVERABILITY-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings/System;-BLUETOOTH_DISCOVERABILITY_TIMEOUT-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings/System;-BLUETOOTH_ON-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings/System;-RADIO_BLUETOOTH-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings/System;-VOLUME_BLUETOOTH_SCO-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/provider/Settings;-ACTION_BLUETOOTH_SETTINGS-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-addRfcommServiceRecord-(Ljava/lang/String; Landroid/os/ParcelUuid; I Landroid/os/IBinder;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-fetchRemoteUuids-(Ljava/lang/String; Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetoothCallback;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getAddress-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getBluetoothState-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getBondState-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getDiscoverableTimeout-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getName-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getRemoteClass-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getRemoteName-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getRemoteServiceChannel-(Ljava/lang/String; Landroid/os/ParcelUuid;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getRemoteUuids-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getScanMode-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-getTrustState-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-isDiscovering-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-isEnabled-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-listBonds-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetooth$Stub$Proxy;-removeServiceRecord-(I)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_CONNECTION_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_DISCOVERY_FINISHED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_DISCOVERY_STARTED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_LOCAL_NAME_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_REQUEST_DISCOVERABLE-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_REQUEST_ENABLE-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_SCAN_MODE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-ACTION_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-cancelDiscovery-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-disable-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-enable-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getAddress-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getBondedDevices-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getName-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getScanMode-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-isDiscovering-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-isEnabled-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-listenUsingInsecureRfcommWithServiceRecord-(Ljava/lang/String; Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-listenUsingRfcommWithServiceRecord-(Ljava/lang/String; Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-setName-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-startDiscovery-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getAddress-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getBondedDevices-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getDiscoverableTimeout-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getName-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getScanMode-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-isDiscovering-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-isEnabled-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAdapter;-listenUsingRfcommWithServiceRecord-(Ljava/lang/String; Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothProfile;-getConnectedDevices-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothProfile;-getConnectionState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothProfile;-getDevicesMatchingConnectionStates-([I)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-ACTION_AUDIO_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-ACTION_CONNECTION_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-ACTION_VENDOR_SPECIFIC_HEADSET_EVENT-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getConnectedDevices-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getConnectionState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getDevicesMatchingConnectionStates-([I)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-isAudioConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-startVoiceRecognition-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-stopVoiceRecognition-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getBatteryUsageHint-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getCurrentHeadset-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getPriority-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-isConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-startVoiceRecognition-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothHeadset;-stopVoiceRecognition-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-getBatteryUsageHint-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-getCurrentHeadset-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-getPriority-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-isConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-startVoiceRecognition-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-stopVoiceRecognition-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_ACL_CONNECTED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_ACL_DISCONNECTED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_ACL_DISCONNECT_REQUESTED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_BOND_STATE_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_CLASS_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_FOUND-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-ACTION_NAME_CHANGED-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-createInsecureRfcommSocketToServiceRecord-(Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-createRfcommSocketToServiceRecord-(Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getBluetoothClass-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getBondState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getName-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-createRfcommSocketToServiceRecord-(Ljava/util/UUID;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-fetchUuidsWithSdp-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getBondState-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getName-()" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getServiceChannel-(Landroid/os/ParcelUuid;)" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothDevice;-getUuids-()" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;--(Landroid/content/Context; Landroid/server/BluetoothService;)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-addAudioSink-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-getConnectedSinks-()" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-getNonDisconnectedSinks-()" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-getSinkPriority-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-getSinkState-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-isSinkDevice-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-lookupSinksMatchingStates-([I)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-onConnectSinkResult-(Ljava/lang/String; B)" : "BLUETOOTH", + "Landroid/server/BluetoothA2dpService;-onSinkPropertyChanged-(Ljava/lang/String; [L[Ljava/lang/Strin;)" : "BLUETOOTH", + "Landroid/provider/Settings/Secure;-BLUETOOTH_ON-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-getClient-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-getState-()" : "BLUETOOTH", + "Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-isConnected-(Landroid/bluetooth/BluetoothDevice;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-addRemoteDeviceProperties-(Ljava/lang/String; [L[Ljava/lang/Strin;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-addRfcommServiceRecord-(Ljava/lang/String; Landroid/os/ParcelUuid; I Landroid/os/IBinder;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-fetchRemoteUuids-(Ljava/lang/String; Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetoothCallback;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getAddress-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getAddressFromObjectPath-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getAllProperties-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getBluetoothState-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getBondState-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getDiscoverableTimeout-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getName-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getObjectPathFromAddress-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getProperty-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getPropertyInternal-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getRemoteClass-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getRemoteName-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getRemoteServiceChannel-(Ljava/lang/String; Landroid/os/ParcelUuid;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getRemoteUuids-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getScanMode-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-getTrustState-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-isDiscovering-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-isEnabled-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-listBonds-()" : "BLUETOOTH", + "Landroid/server/BluetoothService;-removeServiceRecord-(I)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-sendUuidIntent-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-setLinkTimeout-(Ljava/lang/String; I)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-setPropertyBoolean-(Ljava/lang/String; B)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-setPropertyInteger-(Ljava/lang/String; I)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-setPropertyString-(Ljava/lang/String; Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-updateDeviceServiceChannelCache-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/server/BluetoothService;-updateRemoteDevicePropertiesCache-(Ljava/lang/String;)" : "BLUETOOTH", + "Landroid/content/pm/PackageManager;-FEATURE_BLUETOOTH-Ljava/lang/String;" : "BLUETOOTH", + "Landroid/bluetooth/BluetoothAssignedNumbers;-BLUETOOTH_SIG-I" : "BLUETOOTH", + "Landroid/app/ActivityManagerNative;-clearApplicationUserData-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/app/ContextImpl$ApplicationPackageManager;-clearApplicationUserData-(Ljava/lang/String; LIPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/app/ContextImpl$ApplicationPackageManager;-clearApplicationUserData-(Ljava/lang/String; LIPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/app/ActivityManager;-clearApplicationUserData-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/app/IActivityManager$Stub$Proxy;-clearApplicationUserData-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/content/pm/PackageManager;-clearApplicationUserData-(Ljava/lang/String; LIPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-clearApplicationUserData-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "CLEAR_APP_USER_DATA", + "Landroid/provider/Telephony$Sms;-addMessageToUri-(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B B J)" : "WRITE_SMS", + "Landroid/provider/Telephony$Sms;-addMessageToUri-(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B B)" : "WRITE_SMS", + "Landroid/provider/Telephony$Sms;-moveMessageToFolder-(Landroid/content/Context; Landroid/net/Uri; I I)" : "WRITE_SMS", + "Landroid/provider/Telephony$Sms$Outbox;-addMessage-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/Long; B J)" : "WRITE_SMS", + "Landroid/provider/Telephony$Sms$Draft;-saveMessage-(Landroid/content/ContentResolver; Landroid/net/Uri; Ljava/lang/String;)" : "WRITE_SMS", + "Landroid/app/IActivityManager$Stub$Proxy;-setProcessForeground-(Landroid/os/IBinder; I B)" : "SET_PROCESS_LIMIT", + "Landroid/app/IActivityManager$Stub$Proxy;-setProcessLimit-(I)" : "SET_PROCESS_LIMIT", + "Landroid/os/PowerManager;-goToSleep-(J)" : "DEVICE_POWER", + "Landroid/os/PowerManager;-setBacklightBrightness-(I)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-clearUserActivityTimeout-(J J)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-goToSleep-(J)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-goToSleepWithReason-(J I)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-preventScreenOn-(B)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-setAttentionLight-(B I)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-setBacklightBrightness-(I)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-setPokeLock-(I Landroid/os/IBinder; Ljava/lang/String;)" : "DEVICE_POWER", + "Landroid/os/IPowerManager$Stub$Proxy;-userActivityWithForce-(J B B)" : "DEVICE_POWER", + "Landroid/app/ExpandableListActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/accounts/GrantCredentialsPermissionActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/Activity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/ListActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/AliasActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/accounts/AccountAuthenticatorActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/IActivityManager$Stub$Proxy;-setPersistent-(Landroid/os/IBinder; B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/TabActivity;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/app/ActivityGroup;-setPersistent-(B)" : "PERSISTENT_ACTIVITY", + "Landroid/view/IWindowManager$Stub$Proxy;-addAppToken-(I Landroid/view/IApplicationToken; I I B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-addWindowToken-(Landroid/os/IBinder; I)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-executeAppTransition-()" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-moveAppToken-(I Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-moveAppTokensToBottom-(Ljava/util/List;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-moveAppTokensToTop-(Ljava/util/List;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-pauseKeyDispatching-(Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-prepareAppTransition-(I)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-removeAppToken-(Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-removeWindowToken-(Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-resumeKeyDispatching-(Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setAppGroupId-(Landroid/os/IBinder; I)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setAppOrientation-(Landroid/view/IApplicationToken; I)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setAppStartingWindow-(Landroid/os/IBinder; Ljava/lang/String; I Ljava/lang/CharSequence; I I Landroid/os/IBinder; B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setAppVisibility-(Landroid/os/IBinder; B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setAppWillBeHidden-(Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setEventDispatching-(B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setFocusedApp-(Landroid/os/IBinder; B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-setNewConfiguration-(Landroid/content/res/Configuration;)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-startAppFreezingScreen-(Landroid/os/IBinder; I)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-stopAppFreezingScreen-(Landroid/os/IBinder; B)" : "MANAGE_APP_TOKENS", + "Landroid/view/IWindowManager$Stub$Proxy;-updateOrientationFromAppTokens-(Landroid/content/res/Configuration; Landroid/os/IBinder;)" : "MANAGE_APP_TOKENS", + "Landroid/provider/Browser;-BOOKMARKS_URI-Landroid/net/Uri;" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-SEARCHES_URI-Landroid/net/Uri;" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-addSearchUrl-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-clearHistory-(Landroid/content/ContentResolver;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-clearSearches-(Landroid/content/ContentResolver;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-deleteFromHistory-(Landroid/content/ContentResolver; Ljava/lang/String;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-deleteHistoryTimeFrame-(Landroid/content/ContentResolver; J J)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-truncateHistory-(Landroid/content/ContentResolver;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-updateVisitedHistory-(Landroid/content/ContentResolver; Ljava/lang/String; B)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/provider/Browser;-clearSearches-(Landroid/content/ContentResolver;)" : "WRITE_HISTORY_BOOKMARKS", + "Landroid/app/IActivityManager$Stub$Proxy;-unhandledBack-(I)" : "FORCE_BACK", + "Landroid/net/IConnectivityManager$Stub$Proxy;-requestRouteToHost-(I I)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-setMobileDataEnabled-(B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-setNetworkPreference-(I)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-setRadio-(I B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-setRadios-(B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-stopUsingNetworkFeature-(I Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-tether-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/IConnectivityManager$Stub$Proxy;-untether-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-requestRouteToHost-(I I)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-setMobileDataEnabled-(B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-setNetworkPreference-(I)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-setRadio-(I B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-setRadios-(B)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-startUsingNetworkFeature-(I Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-stopUsingNetworkFeature-(I Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-tether-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/net/ConnectivityManager;-untether-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-attachPppd-(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-detachPppd-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-disableNat-(Ljava/lang/String; Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-enableNat-(Ljava/lang/String; Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-setAccessPoint-(Landroid/net/wifi/WifiConfiguration; Ljava/lang/String; Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-setInterfaceThrottle-(Ljava/lang/String; I I)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-setIpForwardingEnabled-(B)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-startAccessPoint-(Landroid/net/wifi/WifiConfiguration; Ljava/lang/String; Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-startUsbRNDIS-()" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-stopAccessPoint-()" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-stopTethering-()" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-stopUsbRNDIS-()" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-tetherInterface-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-unregisterObserver-(Landroid/net/INetworkManagementEventObserver;)" : "CHANGE_NETWORK_STATE", + "Landroid/os/INetworkManagementService$Stub$Proxy;-untetherInterface-(Ljava/lang/String;)" : "CHANGE_NETWORK_STATE", + "Landroid/app/ContextImpl$ApplicationContentResolver;-addPeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)" : "WRITE_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-removePeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "WRITE_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-setIsSyncable-(Landroid/accounts/Account; Ljava/lang/String; I)" : "WRITE_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-setMasterSyncAutomatically-(B)" : "WRITE_SYNC_SETTINGS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-setSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String; B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentService;-addPeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentService;-removePeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentService;-setIsSyncable-(Landroid/accounts/Account; Ljava/lang/String; I)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentService;-setMasterSyncAutomatically-(B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentService;-setSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String; B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-addPeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-removePeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-setIsSyncable-(Landroid/accounts/Account; Ljava/lang/String; I)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-setMasterSyncAutomatically-(B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/ContentResolver;-setSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String; B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-addPeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle; J)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-removePeriodicSync-(Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-setIsSyncable-(Landroid/accounts/Account; Ljava/lang/String; I)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-setMasterSyncAutomatically-(B)" : "WRITE_SYNC_SETTINGS", + "Landroid/content/IContentService$Stub$Proxy;-setSyncAutomatically-(Landroid/accounts/Account; Ljava/lang/String; B)" : "WRITE_SYNC_SETTINGS", + "Landroid/accounts/AccountManager;-KEY_ACCOUNT_MANAGER_RESPONSE-Ljava/lang/String;" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-checkBinderPermission-()" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-confirmCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-editProperties-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-getAccountRemovalAllowed-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-getAuthToken-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-getAuthTokenLabel-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-hasFeatures-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-updateCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator;-addAccount-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-addAccount-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-confirmCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-editProperties-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-getAccountRemovalAllowed-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-getAuthToken-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-getAuthTokenLabel-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-hasFeatures-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/AbstractAccountAuthenticator$Transport;-updateCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-addAccount-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-confirmCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-editProperties-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-getAccountRemovalAllowed-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-getAuthToken-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-getAuthTokenLabel-(Landroid/accounts/IAccountAuthenticatorResponse; Ljava/lang/String;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-hasFeatures-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)" : "ACCOUNT_MANAGER", + "Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-updateCredentials-(Landroid/accounts/IAccountAuthenticatorResponse; Landroid/accounts/Account; Ljava/lang/String; Landroid/os/Bundle;)" : "ACCOUNT_MANAGER", + "Landroid/view/IWindowManager$Stub$Proxy;-setAnimationScale-(I F)" : "SET_ANIMATION_SCALE", + "Landroid/view/IWindowManager$Stub$Proxy;-setAnimationScales-([L;)" : "SET_ANIMATION_SCALE", + "Landroid/accounts/AccountManager;-getAccounts-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAccountsByType-(Ljava/lang/String;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAccountsByTypeAndFeatures-(Ljava/lang/String; [Ljava/lang/String; [Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-addOnAccountsUpdatedListener-(Landroid/accounts/OnAccountsUpdateListener; Landroid/os/Handler; B)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAccounts-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAccountsByType-(Ljava/lang/String;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAccountsByTypeAndFeatures-(Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-getAuthTokenByFeatures-(Ljava/lang/String; Ljava/lang/String; [L[Ljava/lang/Strin; Landroid/app/Activity; Landroid/os/Bundle; Landroid/os/Bundle; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager;-hasFeatures-(Landroid/accounts/Account; [L[Ljava/lang/Strin; Landroid/accounts/AccountManagerCallback; Landroid/os/Handler;)" : "GET_ACCOUNTS", + "Landroid/content/ContentService;--(Landroid/content/Context; B)" : "GET_ACCOUNTS", + "Landroid/content/ContentService;-main-(Landroid/content/Context; B)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager$GetAuthTokenByTypeAndFeaturesTask;-doWork-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager$GetAuthTokenByTypeAndFeaturesTask;-start-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager$AmsTask;-doWork-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManager$AmsTask;-start-()" : "GET_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-getAccounts-(Ljava/lang/String;)" : "GET_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-getAccountsByFeatures-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; [L[Ljava/lang/Strin;)" : "GET_ACCOUNTS", + "Landroid/accounts/IAccountManager$Stub$Proxy;-hasFeatures-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-checkReadAccountsPermission-()" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-getAccounts-(Ljava/lang/String;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-getAccountsByFeatures-(Landroid/accounts/IAccountManagerResponse; Ljava/lang/String; [L[Ljava/lang/Strin;)" : "GET_ACCOUNTS", + "Landroid/accounts/AccountManagerService;-hasFeatures-(Landroid/accounts/IAccountManagerResponse; Landroid/accounts/Account; [L[Ljava/lang/Strin;)" : "GET_ACCOUNTS", + "Landroid/telephony/gsm/SmsManager;-copyMessageToSim-([L; [L; I)" : "RECEIVE_SMS", + "Landroid/telephony/gsm/SmsManager;-deleteMessageFromSim-(I)" : "RECEIVE_SMS", + "Landroid/telephony/gsm/SmsManager;-getAllMessagesFromSim-()" : "RECEIVE_SMS", + "Landroid/telephony/gsm/SmsManager;-updateMessageOnSim-(I I [L;)" : "RECEIVE_SMS", + "Landroid/telephony/SmsManager;-copyMessageToIcc-([L; [L; I)" : "RECEIVE_SMS", + "Landroid/telephony/SmsManager;-deleteMessageFromIcc-(I)" : "RECEIVE_SMS", + "Landroid/telephony/SmsManager;-getAllMessagesFromIcc-()" : "RECEIVE_SMS", + "Landroid/telephony/SmsManager;-updateMessageOnIcc-(I I [L;)" : "RECEIVE_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-copyMessageToIccEf-(I [B [B)" : "RECEIVE_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-getAllMessagesFromIccEf-()" : "RECEIVE_SMS", + "Lcom/android/internal/telephony/ISms$Stub$Proxy;-updateMessageOnIccEf-(I I [B)" : "RECEIVE_SMS", + "Landroid/app/IActivityManager$Stub$Proxy;-resumeAppSwitches-()" : "STOP_APP_SWITCHES", + "Landroid/app/IActivityManager$Stub$Proxy;-stopAppSwitches-()" : "STOP_APP_SWITCHES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-deleteApplicationCacheFiles-(Ljava/lang/String; LIPackageDataObserver;)" : "DELETE_CACHE_FILES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-deleteApplicationCacheFiles-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "DELETE_CACHE_FILES", + "Landroid/content/pm/PackageManager;-deleteApplicationCacheFiles-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "DELETE_CACHE_FILES", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-deleteApplicationCacheFiles-(Ljava/lang/String; Landroid/content/pm/IPackageDataObserver;)" : "DELETE_CACHE_FILES", + "Landroid/os/Build/VERSION_CODES;-DONUT-I" : "WRITE_EXTERNAL_STORAGE", + "Landroid/app/DownloadManager/Request;-setDestinationUri-(Landroid/net/Uri;)" : "WRITE_EXTERNAL_STORAGE", + "Landroid/os/RecoverySystem;-installPackage-(Landroid/content/Context; Ljava/io/File;)" : "REBOOT", + "Landroid/os/RecoverySystem;-rebootWipeUserData-(Landroid/content/Context;)" : "REBOOT", + "Landroid/os/RecoverySystem;-bootCommand-(Landroid/content/Context; Ljava/lang/String;)" : "REBOOT", + "Landroid/os/RecoverySystem;-installPackage-(Landroid/content/Context; Ljava/io/File;)" : "REBOOT", + "Landroid/os/RecoverySystem;-rebootWipeUserData-(Landroid/content/Context;)" : "REBOOT", + "Landroid/content/Intent;-IntentResolution-Ljava/lang/String;" : "REBOOT", + "Landroid/content/Intent;-ACTION_REBOOT-Ljava/lang/String;" : "REBOOT", + "Landroid/os/PowerManager;-reboot-(Ljava/lang/String;)" : "REBOOT", + "Landroid/os/PowerManager;-reboot-(Ljava/lang/String;)" : "REBOOT", + "Landroid/os/IPowerManager$Stub$Proxy;-crash-(Ljava/lang/String;)" : "REBOOT", + "Landroid/os/IPowerManager$Stub$Proxy;-reboot-(Ljava/lang/String;)" : "REBOOT", + "Landroid/app/ContextImpl$ApplicationPackageManager;-installPackage-(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)" : "INSTALL_PACKAGES", + "Landroid/app/ContextImpl$ApplicationPackageManager;-installPackage-(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)" : "INSTALL_PACKAGES", + "Landroid/content/pm/PackageManager;-installPackage-(Landroid/net/Uri; LIPackageInstallObserver; I Ljava/lang/String;)" : "INSTALL_PACKAGES", + "Landroid/content/pm/IPackageManager$Stub$Proxy;-installPackage-(Landroid/net/Uri; Landroid/content/pm/IPackageInstallObserver; I Ljava/lang/String;)" : "INSTALL_PACKAGES", + "Landroid/app/IActivityManager$Stub$Proxy;-setDebugApp-(Ljava/lang/String; B B)" : "SET_DEBUG_APP", + "Landroid/location/ILocationManager$Stub$Proxy;-reportLocation-(Landroid/location/Location; B)" : "INSTALL_LOCATION_PROVIDER", + "Landroid/app/WallpaperManager;-suggestDesiredDimensions-(I I)" : "SET_WALLPAPER_HINTS", + "Landroid/app/IWallpaperManager$Stub$Proxy;-setDimensionHints-(I I)" : "SET_WALLPAPER_HINTS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-openFileDescriptor-(Landroid/net/Uri; Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-openInputStream-(Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-openOutputStream-(Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/app/ContextImpl$ApplicationContentResolver;-query-(Landroid/net/Uri; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)" : "READ_CONTACTS", + "Lcom/android/internal/telephony/IccPhoneBookInterfaceManager$Stub$Proxy;-getAdnRecordsInEf-(I)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-addToGroup-(Landroid/content/ContentResolver; J Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-addToMyContactsGroup-(Landroid/content/ContentResolver; J)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-createPersonInMyContactsGroup-(Landroid/content/ContentResolver; Landroid/content/ContentValues;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-loadContactPhoto-(Landroid/content/Context; Landroid/net/Uri; I Landroid/graphics/BitmapFactory$Options;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-markAsContacted-(Landroid/content/ContentResolver; J)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-openContactPhotoInputStream-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-queryGroups-(Landroid/content/ContentResolver; J)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-setPhotoData-(Landroid/content/ContentResolver; Landroid/net/Uri; [L;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$People;-tryGetMyContactsGroupId-(Landroid/content/ContentResolver;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$Data;-getContactLookupUri-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$Contacts;-getLookupUri-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$Contacts;-lookupContact-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$Contacts;-openContactPhotoInputStream-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer;-createOneEntry-()" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer;-createOneEntry-(Ljava/lang/reflect/Method;)" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer;-createOneEntryInternal-(Ljava/lang/String; Ljava/lang/reflect/Method;)" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer;-init-()" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer;-init-(Ljava/lang/String; [L[Ljava/lang/Strin;)" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer$OneEntryHandler;-onInit-(Landroid/content/Context;)" : "READ_CONTACTS", + "Lcom/android/internal/telephony/CallerInfo;-getCallerId-(Landroid/content/Context; Ljava/lang/String;)" : "READ_CONTACTS", + "Lcom/android/internal/telephony/CallerInfo;-getCallerInfo-(Landroid/content/Context; Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/provider/Contacts$Settings;-getSetting-(Landroid/content/ContentResolver; Ljava/lang/String; Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$RawContacts;-getContactLookupUri-(Landroid/content/ContentResolver; Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/provider/CallLog$Calls;-addCall-(Lcom/android/internal/telephony/CallerInfo; Landroid/content/Context; Ljava/lang/String; I I J I)" : "READ_CONTACTS", + "Landroid/provider/CallLog$Calls;-getLastOutgoingCall-(Landroid/content/Context;)" : "READ_CONTACTS", + "Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;-getAdnRecordsInEf-(I)" : "READ_CONTACTS", + "Landroid/pim/vcard/VCardComposer$HandlerForOutputStream;-onInit-(Landroid/content/Context;)" : "READ_CONTACTS", + "Landroid/provider/ContactsContract$CommonDataKinds$Phone;-CONTENT_URI-Landroid/net/Uri;" : "READ_CONTACTS", + "Landroid/widget/QuickContactBadge;-assignContactFromEmail-(Ljava/lang/String; B)" : "READ_CONTACTS", + "Landroid/widget/QuickContactBadge;-assignContactFromPhone-(Ljava/lang/String; B)" : "READ_CONTACTS", + "Landroid/widget/QuickContactBadge;-trigger-(Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/content/ContentResolver;-openFileDescriptor-(Landroid/net/Uri; Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/content/ContentResolver;-openInputStream-(Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/content/ContentResolver;-openOutputStream-(Landroid/net/Uri;)" : "READ_CONTACTS", + "Landroid/content/ContentResolver;-query-(Landroid/net/Uri; [L[Ljava/lang/Strin; Ljava/lang/String; [L[Ljava/lang/Strin; Ljava/lang/String;)" : "READ_CONTACTS", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-backupNow-()" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-beginRestoreSession-(Ljava/lang/String;)" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-clearBackupData-(Ljava/lang/String;)" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-dataChanged-(Ljava/lang/String;)" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-getCurrentTransport-()" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-isBackupEnabled-()" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-listAllTransports-()" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-selectBackupTransport-(Ljava/lang/String;)" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-setAutoRestore-(B)" : "BACKUP", + "Landroid/app/backup/IBackupManager$Stub$Proxy;-setBackupEnabled-(B)" : "BACKUP", + "Landroid/app/IActivityManager$Stub$Proxy;-bindBackupAgent-(Landroid/content/pm/ApplicationInfo; I)" : "BACKUP", + "Landroid/app/backup/BackupManager;-beginRestoreSession-()" : "BACKUP", + "Landroid/app/backup/BackupManager;-dataChanged-(Ljava/lang/String;)" : "BACKUP", + "Landroid/app/backup/BackupManager;-requestRestore-(Landroid/app/backup/RestoreObserver;)" : "BACKUP", +} diff --git a/androguard/core/bytecodes/apk.py b/androguard/core/bytecodes/apk.py new file mode 100644 index 00000000..f5ea8b70 --- /dev/null +++ b/androguard/core/bytecodes/apk.py @@ -0,0 +1,1799 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from androguard.core import bytecode +from androguard.core import androconf +from androguard.core.bytecodes.dvm_permissions import DVM_PERMISSIONS + +import StringIO +from struct import pack, unpack +from xml.sax.saxutils import escape +from zlib import crc32 +import re + +from xml.dom import minidom + +# 0: chilkat +# 1: default python zipfile module +# 2: patch zipfile module +ZIPMODULE = 1 + +import sys +if sys.hexversion < 0x2070000 : + try : + import chilkat + ZIPMODULE = 0 + # UNLOCK : change it with your valid key ! + try : + CHILKAT_KEY = open("key.txt", "rb").read() + except Exception : + CHILKAT_KEY = "testme" + + except ImportError : + ZIPMODULE = 1 +else : + ZIPMODULE = 1 + +################################################### CHILKAT ZIP FORMAT ##################################################### +class ChilkatZip : + def __init__(self, raw) : + self.files = [] + self.zip = chilkat.CkZip() + + self.zip.UnlockComponent( CHILKAT_KEY ) + + self.zip.OpenFromMemory( raw, len(raw) ) + + filename = chilkat.CkString() + e = self.zip.FirstEntry() + while e != None : + e.get_FileName(filename) + self.files.append( filename.getString() ) + e = e.NextEntry() + + def delete(self, patterns) : + el = [] + + filename = chilkat.CkString() + e = self.zip.FirstEntry() + while e != None : + e.get_FileName(filename) + + if re.match(patterns, filename.getString()) != None : + el.append( e ) + e = e.NextEntry() + + for i in el : + self.zip.DeleteEntry( i ) + + def remplace_file(self, filename, buff) : + entry = self.zip.GetEntryByName(filename) + if entry != None : + + obj = chilkat.CkByteData() + obj.append2( buff, len(buff) ) + return entry.ReplaceData( obj ) + return False + + def write(self) : + obj = chilkat.CkByteData() + self.zip.WriteToMemory( obj ) + return obj.getBytes() + + def namelist(self) : + return self.files + + def read(self, elem) : + e = self.zip.GetEntryByName( elem ) + s = chilkat.CkByteData() + + e.Inflate( s ) + return s.getBytes() + + +def sign_apk(filename, keystore, storepass): + from subprocess import Popen, PIPE, STDOUT + compile = Popen([androconf.CONF["PATH_JARSIGNER"], + "-sigalg", + "MD5withRSA", + "-digestalg", + "SHA1", + + "-storepass", + storepass, + + "-keystore", + keystore, + + filename, + "alias_name"], + stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + + +######################################################## APK FORMAT ######################################################## +class APK: + """ + This class can access to all elements in an APK file + + :param filename: specify the path of the file, or raw data + :param raw: specify if the filename is a path or raw data (optional) + :param mode: specify the mode to open the file (optional) + :param magic_file: specify the magic file (optional) + :param zipmodule: specify the type of zip module to use (0:chilkat, 1:zipfile, 2:patch zipfile) + + :type filename: string + :type raw: boolean + :type mode: string + :type magic_file: string + :type zipmodule: int + + :Example: + APK("myfile.apk") + APK(open("myfile.apk", "rb").read(), raw=True) + """ + def __init__(self, filename, raw=False, mode="r", magic_file=None, zipmodule=ZIPMODULE): + self.filename = filename + + self.xml = {} + self.axml = {} + self.arsc = {} + + self.package = "" + self.androidversion = {} + self.permissions = [] + self.valid_apk = False + + self.files = {} + self.files_crc32 = {} + + self.magic_file = magic_file + + if raw == True: + self.__raw = filename + else: + fd = open(filename, "rb") + self.__raw = fd.read() + fd.close() + + self.zipmodule = zipmodule + + if zipmodule == 0: + self.zip = ChilkatZip(self.__raw) + elif zipmodule == 2: + from androguard.patch import zipfile + self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode) + else: + import zipfile + self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode) + + for i in self.zip.namelist(): + if i == "AndroidManifest.xml": + self.axml[i] = AXMLPrinter(self.zip.read(i)) + try: + self.xml[i] = minidom.parseString(self.axml[i].get_buff()) + except: + self.xml[i] = None + + if self.xml[i] != None: + self.package = self.xml[i].documentElement.getAttribute("package") + self.androidversion["Code"] = self.xml[i].documentElement.getAttribute("android:versionCode") + self.androidversion["Name"] = self.xml[i].documentElement.getAttribute("android:versionName") + + for item in self.xml[i].getElementsByTagName('uses-permission'): + self.permissions.append(str(item.getAttribute("android:name"))) + + self.valid_apk = True + + self.get_files_types() + + def get_AndroidManifest(self): + """ + Return the Android Manifest XML file + + :rtype: xml object + """ + return self.xml["AndroidManifest.xml"] + + def is_valid_APK(self): + """ + Return true if the APK is valid, false otherwise + + :rtype: boolean + """ + return self.valid_apk + + def get_filename(self): + """ + Return the filename of the APK + + :rtype: string + """ + return self.filename + + def get_package(self): + """ + Return the name of the package + + :rtype: string + """ + return self.package + + def get_androidversion_code(self): + """ + Return the android version code + + :rtype: string + """ + return self.androidversion["Code"] + + def get_androidversion_name(self): + """ + Return the android version name + + :rtype: string + """ + return self.androidversion["Name"] + + def get_files(self): + """ + Return the files inside the APK + + :rtype: a list of strings + """ + return self.zip.namelist() + + def get_files_types(self): + """ + Return the files inside the APK with their associated types (by using python-magic) + + :rtype: a dictionnary + """ + try: + import magic + except ImportError: + # no lib magic ! + for i in self.get_files(): + buffer = self.zip.read(i) + self.files_crc32[i] = crc32(buffer) + self.files[i] = "Unknown" + return self.files + + if self.files != {}: + return self.files + + builtin_magic = 0 + try: + getattr(magic, "MagicException") + except AttributeError: + builtin_magic = 1 + + if builtin_magic: + ms = magic.open(magic.MAGIC_NONE) + ms.load() + + for i in self.get_files(): + buffer = self.zip.read(i) + self.files[i] = ms.buffer(buffer) + self.files[i] = self._patch_magic(buffer, self.files[i]) + self.files_crc32[i] = crc32(buffer) + else: + m = magic.Magic(magic_file=self.magic_file) + for i in self.get_files(): + buffer = self.zip.read(i) + self.files[i] = m.from_buffer(buffer) + self.files[i] = self._patch_magic(buffer, self.files[i]) + self.files_crc32[i] = crc32(buffer) + + return self.files + + def _patch_magic(self, buffer, orig): + if ("Zip" in orig) or ("DBase" in orig): + val = androconf.is_android_raw(buffer) + if val == "APK": + if androconf.is_valid_android_raw(buffer): + return "Android application package file" + elif val == "AXML": + return "Android's binary XML" + + return orig + + def get_files_crc32(self): + if self.files_crc32 == {}: + self.get_files_types() + + return self.files_crc32 + + def get_files_information(self): + """ + Return the files inside the APK with their associated types and crc32 + + :rtype: string, string, int + """ + if self.files == {}: + self.get_files_types() + + for i in self.get_files(): + try: + yield i, self.files[i], self.files_crc32[i] + except KeyError: + yield i, "", "" + + def get_raw(self): + """ + Return raw bytes of the APK + + :rtype: string + """ + return self.__raw + + def get_file(self, filename): + """ + Return the raw data of the specified filename + + :rtype: string + """ + try: + return self.zip.read(filename) + except KeyError: + return "" + + def get_dex(self): + """ + Return the raw data of the classes dex file + + :rtype: string + """ + return self.get_file("classes.dex") + + def get_elements(self, tag_name, attribute): + """ + Return elements in xml files which match with the tag name and the specific attribute + + :param tag_name: a string which specify the tag name + :param attribute: a string which specify the attribute + """ + l = [] + for i in self.xml : + for item in self.xml[i].getElementsByTagName(tag_name) : + value = item.getAttribute(attribute) + value = self.format_value( value ) + + + l.append( str( value ) ) + return l + + def format_value(self, value) : + if len(value) > 0 : + if value[0] == "." : + value = self.package + value + else : + v_dot = value.find(".") + if v_dot == 0 : + value = self.package + "." + value + elif v_dot == -1 : + value = self.package + "." + value + return value + + def get_element(self, tag_name, attribute): + """ + Return element in xml files which match with the tag name and the specific attribute + + :param tag_name: specify the tag name + :type tag_name: string + :param attribute: specify the attribute + :type attribute: string + + :rtype: string + """ + for i in self.xml : + for item in self.xml[i].getElementsByTagName(tag_name) : + value = item.getAttribute(attribute) + + if len(value) > 0 : + return value + return None + + def get_main_activity(self) : + """ + Return the name of the main activity + + :rtype: string + """ + x = set() + y = set() + + for i in self.xml: + for item in self.xml[i].getElementsByTagName("activity") : + for sitem in item.getElementsByTagName( "action" ) : + val = sitem.getAttribute( "android:name" ) + if val == "android.intent.action.MAIN" : + x.add( item.getAttribute( "android:name" ) ) + + for sitem in item.getElementsByTagName( "category" ) : + val = sitem.getAttribute( "android:name" ) + if val == "android.intent.category.LAUNCHER" : + y.add( item.getAttribute( "android:name" ) ) + + z = x.intersection(y) + if len(z) > 0 : + return self.format_value(z.pop()) + return None + + def get_activities(self): + """ + Return the android:name attribute of all activities + + :rtype: a list of string + """ + return self.get_elements("activity", "android:name") + + def get_services(self): + """ + Return the android:name attribute of all services + + :rtype: a list of string + """ + return self.get_elements("service", "android:name") + + def get_receivers(self) : + """ + Return the android:name attribute of all receivers + + :rtype: a list of string + """ + return self.get_elements("receiver", "android:name") + + def get_providers(self): + """ + Return the android:name attribute of all providers + + :rtype: a list of string + """ + return self.get_elements("provider", "android:name") + + def get_intent_filters(self, category, name): + d = {} + + d["action"] = [] + d["category"] = [] + + for i in self.xml: + for item in self.xml[i].getElementsByTagName(category): + if self.format_value(item.getAttribute("android:name")) == name: + for sitem in item.getElementsByTagName("intent-filter"): + for ssitem in sitem.getElementsByTagName("action"): + if ssitem.getAttribute("android:name") not in d["action"]: + d["action"].append(ssitem.getAttribute("android:name")) + for ssitem in sitem.getElementsByTagName("category"): + if ssitem.getAttribute("android:name") not in d["category"]: + d["category"].append(ssitem.getAttribute("android:name")) + + if not d["action"]: + del d["action"] + + if not d["category"]: + del d["category"] + + return d + + def get_permissions(self): + """ + Return permissions + + :rtype: list of string + """ + return self.permissions + + def get_details_permissions(self): + """ + Return permissions with details + + :rtype: list of string + """ + l = {} + + for i in self.permissions : + perm = i + pos = i.rfind(".") + + if pos != -1 : + perm = i[pos+1:] + + try : + l[ i ] = DVM_PERMISSIONS["MANIFEST_PERMISSION"][ perm ] + except KeyError : + l[ i ] = [ "normal", "Unknown permission from android reference", "Unknown permission from android reference" ] + + return l + + def get_max_sdk_version(self): + """ + Return the android:maxSdkVersion attribute + + :rtype: string + """ + return self.get_element("uses-sdk", "android:maxSdkVersion") + + def get_min_sdk_version(self): + """ + Return the android:minSdkVersion attribute + + :rtype: string + """ + return self.get_element("uses-sdk", "android:minSdkVersion") + + def get_target_sdk_version(self) : + """ + Return the android:targetSdkVersion attribute + + :rtype: string + """ + return self.get_element( "uses-sdk", "android:targetSdkVersion" ) + + def get_libraries(self) : + """ + Return the android:name attributes for libraries + + :rtype: list + """ + return self.get_elements( "uses-library", "android:name" ) + + def get_certificate(self, filename): + """ + Return a certificate object by giving the name in the apk file + """ + import chilkat + + cert = chilkat.CkCert() + f = self.get_file(filename) + success = cert.LoadFromBinary2(f, len(f)) + + return success, cert + + def new_zip(self, filename, deleted_files=None, new_files={}) : + """ + Create a new zip file + + :param filename: the output filename of the zip + :param deleted_files: a regex pattern to remove specific file + :param new_files: a dictionnary of new files + + :type filename: string + :type deleted_files: None or a string + :type new_files: a dictionnary (key:filename, value:content of the file) + """ + if self.zipmodule == 2: + from androguard.patch import zipfile + zout = zipfile.ZipFile(filename, 'w') + else: + import zipfile + zout = zipfile.ZipFile(filename, 'w') + + for item in self.zip.infolist(): + if deleted_files != None: + if re.match(deleted_files, item.filename) == None: + if item.filename in new_files: + zout.writestr(item, new_files[item.filename]) + else: + buffer = self.zip.read(item.filename) + zout.writestr(item, buffer) + zout.close() + + def get_android_manifest_axml(self): + """ + Return the :class:`AXMLPrinter` object which corresponds to the AndroidManifest.xml file + + :rtype: :class:`AXMLPrinter` + """ + try: + return self.axml["AndroidManifest.xml"] + except KeyError: + return None + + def get_android_manifest_xml(self): + """ + Return the xml object which corresponds to the AndroidManifest.xml file + + :rtype: object + """ + try: + return self.xml["AndroidManifest.xml"] + except KeyError: + return None + + def get_android_resources(self): + """ + Return the :class:`ARSCParser` object which corresponds to the resources.arsc file + + :rtype: :class:`ARSCParser` + """ + try: + return self.arsc["resources.arsc"] + except KeyError: + try: + self.arsc["resources.arsc"] = ARSCParser(self.zip.read("resources.arsc")) + return self.arsc["resources.arsc"] + except KeyError: + return None + + def get_signature_name(self): + signature_expr = re.compile("^(META-INF/)(.*)(\.RSA)$") + for i in self.get_files(): + if signature_expr.search(i): + return i + return None + + def get_signature(self): + signature_expr = re.compile("^(META-INF/)(.*)(\.RSA)$") + for i in self.get_files(): + if signature_expr.search(i): + return self.get_file(i) + return None + + def show(self): + self.get_files_types() + + print "FILES: " + for i in self.get_files(): + try: + print "\t", i, self.files[i], "%x" % self.files_crc32[i] + except KeyError: + print "\t", i, "%x" % self.files_crc32[i] + + print "PERMISSIONS: " + details_permissions = self.get_details_permissions() + for i in details_permissions: + print "\t", i, details_permissions[i] + print "MAIN ACTIVITY: ", self.get_main_activity() + + print "ACTIVITIES: " + activities = self.get_activities() + for i in activities: + filters = self.get_intent_filters("activity", i) + print "\t", i, filters or "" + + print "SERVICES: " + services = self.get_services() + for i in services: + filters = self.get_intent_filters("service", i) + print "\t", i, filters or "" + + print "RECEIVERS: " + receivers = self.get_receivers() + for i in receivers: + filters = self.get_intent_filters("receiver", i) + print "\t", i, filters or "" + + print "PROVIDERS: ", self.get_providers() + + +def show_Certificate(cert): + print "Issuer: C=%s, CN=%s, DN=%s, E=%s, L=%s, O=%s, OU=%s, S=%s" % (cert.issuerC(), cert.issuerCN(), cert.issuerDN(), cert.issuerE(), cert.issuerL(), cert.issuerO(), cert.issuerOU(), cert.issuerS()) + print "Subject: C=%s, CN=%s, DN=%s, E=%s, L=%s, O=%s, OU=%s, S=%s" % (cert.subjectC(), cert.subjectCN(), cert.subjectDN(), cert.subjectE(), cert.subjectL(), cert.subjectO(), cert.subjectOU(), cert.subjectS()) + + +######################################################## AXML FORMAT ######################################################## +# Translated from http://code.google.com/p/android4me/source/browse/src/android/content/res/AXmlResourceParser.java + +UTF8_FLAG = 0x00000100 + + +class StringBlock: + def __init__(self, buff): + self.start = buff.get_idx() + self._cache = {} + self.header = unpack('= len(self.m_stringOffsets): + return "" + + offset = self.m_stringOffsets[idx] + + if not self.m_isUTF8: + length = self.getShort2(self.m_strings, offset) + offset += 2 + self._cache[idx] = self.decode(self.m_strings, offset, length) + else: + offset += self.getVarint(self.m_strings, offset)[1] + varint = self.getVarint(self.m_strings, offset) + + offset += varint[1] + length = varint[0] + + self._cache[idx] = self.decode2(self.m_strings, offset, length) + + return self._cache[idx] + + def getStyle(self, idx): + print idx + print idx in self.m_styleOffsets, self.m_styleOffsets[idx] + + print self.m_styles[0] + + def decode(self, array, offset, length): + length = length * 2 + length = length + length % 2 + + data = "" + + for i in range(0, length): + t_data = pack("=b", self.m_strings[offset + i]) + data += unicode(t_data, errors='ignore') + if data[-2:] == "\x00\x00": + break + + end_zero = data.find("\x00\x00") + if end_zero != -1: + data = data[:end_zero] + + return data.decode("utf-16", 'replace') + + def decode2(self, array, offset, length): + data = "" + + for i in range(0, length): + t_data = pack("=b", self.m_strings[offset + i]) + data += unicode(t_data, errors='ignore') + + return data.decode("utf-8", 'replace') + + def getVarint(self, array, offset): + val = array[offset] + more = (val & 0x80) != 0 + val &= 0x7f + + if not more: + return val, 1 + return val << 8 | array[offset + 1] & 0xff, 2 + + def getShort(self, array, offset): + value = array[offset / 4] + if ((offset % 4) / 2) == 0: + return value & 0xFFFF + else: + return value >> 16 + + def getShort2(self, array, offset): + return (array[offset + 1] & 0xff) << 8 | array[offset] & 0xff + + def show(self): + print "StringBlock", hex(self.start), hex(self.header), hex(self.header_size), hex(self.chunkSize), hex(self.stringsOffset), self.m_stringOffsets + for i in range(0, len(self.m_stringOffsets)): + print i, repr(self.getString(i)) + +ATTRIBUTE_IX_NAMESPACE_URI = 0 +ATTRIBUTE_IX_NAME = 1 +ATTRIBUTE_IX_VALUE_STRING = 2 +ATTRIBUTE_IX_VALUE_TYPE = 3 +ATTRIBUTE_IX_VALUE_DATA = 4 +ATTRIBUTE_LENGHT = 5 + +CHUNK_AXML_FILE = 0x00080003 +CHUNK_RESOURCEIDS = 0x00080180 +CHUNK_XML_FIRST = 0x00100100 +CHUNK_XML_START_NAMESPACE = 0x00100100 +CHUNK_XML_END_NAMESPACE = 0x00100101 +CHUNK_XML_START_TAG = 0x00100102 +CHUNK_XML_END_TAG = 0x00100103 +CHUNK_XML_TEXT = 0x00100104 +CHUNK_XML_LAST = 0x00100104 + +START_DOCUMENT = 0 +END_DOCUMENT = 1 +START_TAG = 2 +END_TAG = 3 +TEXT = 4 + + +class AXMLParser: + def __init__(self, raw_buff): + self.reset() + + self.valid_axml = True + self.buff = bytecode.BuffHandle(raw_buff) + + axml_file = unpack(' CHUNK_XML_LAST: + androconf.warning("invalid chunk type") + + # Fake START_DOCUMENT event. + if chunkType == CHUNK_XML_START_TAG and event == -1: + self.m_event = START_DOCUMENT + break + + self.buff.read(4) # /*chunkSize*/ + lineNumber = unpack('> 16) - 1 + attributeCount = attributeCount & 0xFFFF + self.m_classAttribute = unpack('> 16) - 1 + + self.m_classAttribute = (self.m_classAttribute & 0xFFFF) - 1 + + for i in range(0, attributeCount * ATTRIBUTE_LENGHT): + self.m_attributes.append(unpack('> 24 + + self.m_event = START_TAG + break + + if chunkType == CHUNK_XML_END_TAG: + self.m_namespaceUri = unpack('= len(self.m_attributes): + androconf.warning("Invalid attribute index") + + return offset + + def getAttributeCount(self): + if self.m_event != START_TAG: + return -1 + + return len(self.m_attributes) / ATTRIBUTE_LENGHT + + def getAttributePrefix(self, index): + offset = self.getAttributeOffset(index) + uri = self.m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI] + + prefix = self.getPrefixByUri(uri) + + if prefix == -1: + return "" + + return self.sb.getString(prefix) + + def getAttributeName(self, index) : + offset = self.getAttributeOffset(index) + name = self.m_attributes[offset+ATTRIBUTE_IX_NAME] + + if name == -1 : + return "" + + return self.sb.getString( name ) + + def getAttributeValueType(self, index) : + offset = self.getAttributeOffset(index) + return self.m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE] + + def getAttributeValueData(self, index) : + offset = self.getAttributeOffset(index) + return self.m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA] + + def getAttributeValue(self, index) : + offset = self.getAttributeOffset(index) + valueType = self.m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE] + if valueType == TYPE_STRING : + valueString = self.m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING] + return self.sb.getString( valueString ) + # WIP + return "" + #int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA]; + #return TypedValue.coerceToString(valueType,valueData); + +TYPE_ATTRIBUTE = 2 +TYPE_DIMENSION = 5 +TYPE_FIRST_COLOR_INT = 28 +TYPE_FIRST_INT = 16 +TYPE_FLOAT = 4 +TYPE_FRACTION = 6 +TYPE_INT_BOOLEAN = 18 +TYPE_INT_COLOR_ARGB4 = 30 +TYPE_INT_COLOR_ARGB8 = 28 +TYPE_INT_COLOR_RGB4 = 31 +TYPE_INT_COLOR_RGB8 = 29 +TYPE_INT_DEC = 16 +TYPE_INT_HEX = 17 +TYPE_LAST_COLOR_INT = 31 +TYPE_LAST_INT = 31 +TYPE_NULL = 0 +TYPE_REFERENCE = 1 +TYPE_STRING = 3 + +RADIX_MULTS = [ 0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010 ] +DIMENSION_UNITS = [ "px","dip","sp","pt","in","mm" ] +FRACTION_UNITS = [ "%", "%p" ] + +COMPLEX_UNIT_MASK = 15 + + +def complexToFloat(xcomplex): + return (float)(xcomplex & 0xFFFFFF00) * RADIX_MULTS[(xcomplex >> 4) & 3] + + +class AXMLPrinter: + def __init__(self, raw_buff): + self.axml = AXMLParser(raw_buff) + self.xmlns = False + + self.buff = u'' + + while True and self.axml.is_valid(): + _type = self.axml.next() +# print "tagtype = ", _type + + if _type == START_DOCUMENT: + self.buff += u'\n' + elif _type == START_TAG: + self.buff += u'<' + self.getPrefix(self.axml.getPrefix()) + self.axml.getName() + u'\n' + self.buff += self.axml.getXMLNS() + + for i in range(0, self.axml.getAttributeCount()): + self.buff += "%s%s=\"%s\"\n" % (self.getPrefix( + self.axml.getAttributePrefix(i)), self.axml.getAttributeName(i), self._escape(self.getAttributeValue(i))) + + self.buff += u'>\n' + + elif _type == END_TAG: + self.buff += "\n" % (self.getPrefix(self.axml.getPrefix()), self.axml.getName()) + + elif _type == TEXT: + self.buff += "%s\n" % self.axml.getText() + + elif _type == END_DOCUMENT: + break + + # pleed patch + def _escape(self, s): + s = s.replace("&", "&") + s = s.replace('"', """) + s = s.replace("'", "'") + s = s.replace("<", "<") + s = s.replace(">", ">") + return escape(s) + + def get_buff(self): + return self.buff.encode('utf-8') + + def get_xml(self): + return minidom.parseString(self.get_buff()).toprettyxml(encoding="utf-8") + + def get_xml_obj(self): + return minidom.parseString(self.get_buff()) + + def getPrefix(self, prefix): + if prefix == None or len(prefix) == 0: + return u'' + + return prefix + u':' + + def getAttributeValue(self, index): + _type = self.axml.getAttributeValueType(index) + _data = self.axml.getAttributeValueData(index) + + if _type == TYPE_STRING: + return self.axml.getAttributeValue(index) + + elif _type == TYPE_ATTRIBUTE: + return "?%s%08X" % (self.getPackage(_data), _data) + + elif _type == TYPE_REFERENCE: + return "@%s%08X" % (self.getPackage(_data), _data) + + elif _type == TYPE_FLOAT: + return "%f" % unpack("=f", pack("=L", _data))[0] + + elif _type == TYPE_INT_HEX: + return "0x%08X" % _data + + elif _type == TYPE_INT_BOOLEAN: + if _data == 0: + return "false" + return "true" + + elif _type == TYPE_DIMENSION: + return "%f%s" % (complexToFloat(_data), DIMENSION_UNITS[_data & COMPLEX_UNIT_MASK]) + + elif _type == TYPE_FRACTION: + return "%f%s" % (complexToFloat(_data) * 100, FRACTION_UNITS[_data & COMPLEX_UNIT_MASK]) + + elif _type >= TYPE_FIRST_COLOR_INT and _type <= TYPE_LAST_COLOR_INT: + return "#%08X" % _data + + elif _type >= TYPE_FIRST_INT and _type <= TYPE_LAST_INT: + return "%d" % androconf.long2int(_data) + + return "<0x%X, type 0x%02X>" % (_data, _type) + + def getPackage(self, id): + if id >> 24 == 1: + return "android:" + return "" + + +RES_NULL_TYPE = 0x0000 +RES_STRING_POOL_TYPE = 0x0001 +RES_TABLE_TYPE = 0x0002 +RES_XML_TYPE = 0x0003 + +# Chunk types in RES_XML_TYPE +RES_XML_FIRST_CHUNK_TYPE = 0x0100 +RES_XML_START_NAMESPACE_TYPE= 0x0100 +RES_XML_END_NAMESPACE_TYPE = 0x0101 +RES_XML_START_ELEMENT_TYPE = 0x0102 +RES_XML_END_ELEMENT_TYPE = 0x0103 +RES_XML_CDATA_TYPE = 0x0104 +RES_XML_LAST_CHUNK_TYPE = 0x017f + +# This contains a uint32_t array mapping strings in the string +# pool back to resource identifiers. It is optional. +RES_XML_RESOURCE_MAP_TYPE = 0x0180 + +# Chunk types in RES_TABLE_TYPE +RES_TABLE_PACKAGE_TYPE = 0x0200 +RES_TABLE_TYPE_TYPE = 0x0201 +RES_TABLE_TYPE_SPEC_TYPE = 0x0202 + + +class ARSCParser: + def __init__(self, raw_buff): + self.analyzed = False + self.buff = bytecode.BuffHandle(raw_buff) + #print "SIZE", hex(self.buff.size()) + + self.header = ARSCHeader(self.buff) + self.packageCount = unpack('> 24) & 0xFF), ((entry_data >> 16) & 0xFF), ((entry_data >> 8) & 0xFF), (entry_data & 0xFF))] + + def get_resource_dimen(self, ate): + try: + return [ate.get_value(), "%s%s" % (complexToFloat(ate.key.get_data()), DIMENSION_UNITS[ate.key.get_data() & COMPLEX_UNIT_MASK])] + except Exception, why: + androconf.warning(why.__str__()) + return [ate.get_value(), ate.key.get_data()] + + # FIXME + def get_resource_style(self, ate): + return ["", ""] + + def get_packages_names(self): + return self.packages.keys() + + def get_locales(self, package_name): + self._analyse() + return self.values[package_name].keys() + + def get_types(self, package_name, locale): + self._analyse() + return self.values[package_name][locale].keys() + + def get_public_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["public"]: + buff += '\n' % (i[0], i[1], i[2]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_string_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["string"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_strings_resources(self): + self._analyse() + + buff = '\n' + + buff += "\n" + for package_name in self.get_packages_names(): + buff += "\n" % package_name + + for locale in self.get_locales(package_name): + buff += "\n" % repr(locale) + + buff += '\n' + try: + for i in self.values[package_name][locale]["string"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + buff += '\n' + + buff += "\n" + + buff += "\n" + + return buff.encode('utf-8') + + def get_id_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["id"]: + if len(i) == 1: + buff += '\n' % (i[0]) + else: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_bool_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["bool"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_integer_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["integer"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_color_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["color"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_dimen_resources(self, package_name, locale='\x00\x00'): + self._analyse() + + buff = '\n' + buff += '\n' + + try: + for i in self.values[package_name][locale]["dimen"]: + buff += '%s\n' % (i[0], i[1]) + except KeyError: + pass + + buff += '\n' + + return buff.encode('utf-8') + + def get_id(self, package_name, rid, locale='\x00\x00'): + self._analyse() + + try: + for i in self.values[package_name][locale]["public"]: + if i[2] == rid: + return i + except KeyError: + return None + + def get_string(self, package_name, name, locale='\x00\x00'): + self._analyse() + + try: + for i in self.values[package_name][locale]["string"]: + if i[0] == name: + return i + except KeyError: + return None + + def get_items(self, package_name): + self._analyse() + return self.packages[package_name] + + +class PackageContext: + def __init__(self, current_package, stringpool_main, mTableStrings, mKeyStrings): + self.stringpool_main = stringpool_main + self.mTableStrings = mTableStrings + self.mKeyStrings = mKeyStrings + self.current_package = current_package + + def get_mResId(self): + return self.current_package.mResId + + def set_mResId(self, mResId): + self.current_package.mResId = mResId + + +class ARSCHeader: + def __init__(self, buff): + self.start = buff.get_idx() + self.type = unpack('= 32: + self.screenConfig = unpack('= 36: + self.screenSizeDp = unpack(' 0: + androconf.warning("too much bytes !") + self.padding = buff.read(self.exceedingSize) + + #print "ARSCResTableConfig", hex(self.start), hex(self.size), hex(self.imsi), hex(self.locale), repr(self.get_language()), repr(self.get_country()), hex(self.screenType), hex(self.input), hex(self.screenSize), hex(self.version), hex(self.screenConfig), hex(self.screenSizeDp) + + def get_language(self): + x = self.locale & 0x0000ffff + return chr(x & 0x00ff) + chr((x & 0xff00) >> 8) + + def get_country(self): + x = (self.locale & 0xffff0000) >> 16 + return chr(x & 0x00ff) + chr((x & 0xff00) >> 8) + + +class ARSCResTableEntry: + def __init__(self, buff, mResId, parent=None): + self.start = buff.get_idx() + self.mResId = mResId + self.parent = parent + self.size = unpack(' Sections' + for i in b.get_sections (): + print 'offset=0x%08x va=0x%08x size=%05i %s' % (i.offset, baddr+i.rva, i.size, i.name) + + core = r_core.RCore() + core.config.set_i("io.va", 1) + core.config.set_i("anal.split", 1) + + core.file_open("./apks/exploits/617efb2d51ad5c4aed50b76119ad880c6adcd4d2e386b3170930193525b0563d", 0, 0) + core.bin_load( None ) + + core.anal_all() + + for fcn in core.anal.get_fcns() : + print type(fcn), fcn.type, "%x" % fcn.addr, fcn.ninstr, fcn.name + # if (fcn.type == FcnType_FCN or fcn.type == FcnType_SYM): + + for s in core.bin.get_entries() : + print s, type(s), s.rva, "%x" % s.offset + + + #a = r_asm.RAsm() + for s in core.bin.get_symbols() : + print s, s.name, s.rva, s.offset, s.size + if s.name == "rootshell" : + #print core.disassemble_bytes( 0x8000 + s.offset, s.size ) + + #core.assembler.mdisassemble( 0x8000 + s.offset, s.size ) + z = core.op_anal( 0x8000 + s.offset ) + print z.mnemonic + + raise("oo") + + print core.bin.bins, core.bin.user + d = core.bin.read_at( 0x8000 + s.offset, x, s.size ) + print d + raise("ooo") + j = 0 + while j < s.size : + v = core.disassemble( 0x8000 + s.offset + j ) + v1 = core.op_str( 0x8000 + s.offset + j ) + + print v1 + # print 0x8000 + s.offset + j, j, v.inst_len, v.buf_asm + j += v.inst_len + + #for i in core.asm_bwdisassemble(s.rva, 4, s.size/4) : + # print "la", i + # print a.mdisassemble( 20, 0x90 ) #"main", "main" ) #s.name ) + diff --git a/androguard/core/bytecodes/dvm.py b/androguard/core/bytecodes/dvm.py new file mode 100644 index 00000000..daaf6112 --- /dev/null +++ b/androguard/core/bytecodes/dvm.py @@ -0,0 +1,8372 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012/2013, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from androguard.core import bytecode +from androguard.core.androconf import CONF, debug, warning, is_android_raw + +import sys +import re +import struct +from struct import pack, unpack, calcsize + +DEX_FILE_MAGIC_35 = 'dex\n035\x00' +DEX_FILE_MAGIC_36 = 'dex\n036\x00' +ODEX_FILE_MAGIC_35 = 'dey\n035\x00' +ODEX_FILE_MAGIC_36 = 'dey\n036\x00' + + +TYPE_MAP_ITEM = { + 0x0: "TYPE_HEADER_ITEM", + 0x1: "TYPE_STRING_ID_ITEM", + 0x2: "TYPE_TYPE_ID_ITEM", + 0x3: "TYPE_PROTO_ID_ITEM", + 0x4: "TYPE_FIELD_ID_ITEM", + 0x5: "TYPE_METHOD_ID_ITEM", + 0x6: "TYPE_CLASS_DEF_ITEM", + 0x1000: "TYPE_MAP_LIST", + 0x1001: "TYPE_TYPE_LIST", + 0x1002: "TYPE_ANNOTATION_SET_REF_LIST", + 0x1003: "TYPE_ANNOTATION_SET_ITEM", + 0x2000: "TYPE_CLASS_DATA_ITEM", + 0x2001: "TYPE_CODE_ITEM", + 0x2002: "TYPE_STRING_DATA_ITEM", + 0x2003: "TYPE_DEBUG_INFO_ITEM", + 0x2004: "TYPE_ANNOTATION_ITEM", + 0x2005: "TYPE_ENCODED_ARRAY_ITEM", + 0x2006: "TYPE_ANNOTATIONS_DIRECTORY_ITEM", + } + +ACCESS_FLAGS = [ + (0x1, 'public'), + (0x2, 'private'), + (0x4, 'protected'), + (0x8, 'static'), + (0x10, 'final'), + (0x20, 'synchronized'), + (0x40, 'bridge'), + (0x80, 'varargs'), + (0x100, 'native'), + (0x200, 'interface'), + (0x400, 'abstract'), + (0x800, 'strict'), + (0x1000, 'synthetic'), + (0x4000, 'enum'), + (0x8000, 'unused'), + (0x10000, 'constructor'), + (0x20000, 'synchronized'), +] + +TYPE_DESCRIPTOR = { + 'V': 'void', + 'Z': 'boolean', + 'B': 'byte', + 'S': 'short', + 'C': 'char', + 'I': 'int', + 'J': 'long', + 'F': 'float', + 'D': 'double', + 'STR': 'String', + 'StringBuilder': 'String' +} + +def get_access_flags_string(value) : + """ + Transform an access flags to the corresponding string + + :param value: the value of the access flags + :type value: int + + :rtype: string + """ + buff = "" + for i in ACCESS_FLAGS : + if (i[0] & value) == i[0] : + buff += i[1] + " " + + if buff != "" : + return buff[:-1] + return buff + + +def get_type(atype, size=None): + """ + Retrieve the type of a descriptor (e.g : I) + """ + if atype.startswith('java.lang'): + atype = atype.replace('java.lang.', '') + res = TYPE_DESCRIPTOR.get(atype.lstrip('java.lang')) + if res is None: + if atype[0] == 'L': + res = atype[1:-1].replace('/', '.') + elif atype[0] == '[': + if size is None: + res = '%s[]' % get_type(atype[1:]) + else: + res = '%s[%s]' % (get_type(atype[1:]), size) + else: + res = atype + return res + + +MATH_DVM_OPCODES = { "add." : '+', + "div." : '/', + "mul." : '*', + "or." : '|', + "sub." : '-', + "and." : '&', + "xor." : '^', + "shl." : "<<", + "shr." : ">>", + } + +FIELD_READ_DVM_OPCODES = [ ".get" ] +FIELD_WRITE_DVM_OPCODES = [ ".put" ] + +BREAK_DVM_OPCODES = [ "invoke.", "move.", ".put", "if." ] + +BRANCH_DVM_OPCODES = [ "throw", "throw.", "if.", "goto", "goto.", "return", "return.", "packed-switch$", "sparse-switch$" ] + +def clean_name_instruction( instruction ) : + op_value = instruction.get_op_value() + + # goto range + if op_value >= 0x28 and op_value <= 0x2a : + return "goto" + + return instruction.get_name() + +def static_operand_instruction( instruction ) : + buff = "" + + if isinstance(instruction, Instruction) : + # get instructions without registers + for val in instruction.get_literals() : + buff += "%s" % val + + op_value = instruction.get_op_value() + if op_value == 0x1a or op_value == 0x1b : + buff += instruction.get_string() + + return buff + +html_escape_table = { + "&": "&", + '"': """, + "'": "'", + ">": ">", + "<": "<", +} + +def readuleb128(buff) : + result = ord( buff.read(1) ) + if result > 0x7f : + cur = ord( buff.read(1) ) + result = (result & 0x7f) | ((cur & 0x7f) << 7) + if cur > 0x7f : + cur = ord( buff.read(1) ) + result |= (cur & 0x7f) << 14 + if cur > 0x7f : + cur = ord( buff.read(1) ) + result |= (cur & 0x7f) << 21 + if cur > 0x7f : + cur = ord( buff.read(1) ) + if cur > 0x0f : + warning("possible error while decoding number") + result |= cur << 28 + + return result + +def readusleb128(buff) : + result = ord( buff.read(1) ) + if result > 0x7f : + cur = ord( buff.read(1) ) + result = (result & 0x7f) | ((cur & 0x7f) << 7) + if cur > 0x7f : + cur = ord( buff.read(1) ) + result |= (cur & 0x7f) << 14 + if cur > 0x7f : + cur = ord( buff.read(1) ) + result |= (cur & 0x7f) << 21 + if cur > 0x7f : + cur = ord( buff.read(1) ) + result |= cur << 28 + + return result + +def readuleb128p1(buff) : + return readuleb128( buff ) - 1 + +def readsleb128(buff) : + result = unpack( '=b', buff.read(1) )[0] + + if result <= 0x7f : + result = (result << 25) + if result > 0x7fffffff : + result = (0x7fffffff & result) - 0x80000000 + result = result >> 25 + else : + cur = unpack( '=b', buff.read(1) )[0] + result = (result & 0x7f) | ((cur & 0x7f) << 7) + if cur <= 0x7f : + result = (result << 18) >> 18 + else : + cur = unpack( '=b', buff.read(1) )[0] + result |= (cur & 0x7f) << 14 + if cur <= 0x7f : + result = (result << 11) >> 11 + else : + cur = unpack( '=b', buff.read(1) )[0] + result |= (cur & 0x7f) << 21 + if cur <= 0x7f : + result = (result << 4) >> 4 + else : + cur = unpack( '=b', buff.read(1) )[0] + result |= cur << 28 + + return result + +def get_sbyte(buff) : + return unpack( '=b', buff.read(1) )[0] + +def readsleb128_2(buff) : + result = get_sbyte(buff) + if result <= 0x7f : + result = (result << 25) >> 25 + else : + cur = get_sbyte(buff) + result = (result & 0x7f) | ((cur & 0x7f) << 7) + if cur <= 0x7f : + result = (result << 18) >> 18 + else : + cur = get_sbyte(buff) + result |= (cur & 0x7f) << 14 + if cur <= 0x7f : + result = (result << 11) >> 11 + else : + cur = get_sbyte(buff) + result |= (cur & 0x7f) << 21 + if cur <= 0x7f : + result = (result << 4) >> 4 + else : + cur = get_sbyte(buff) + result |= cur << 28 + + return result + + +def writeuleb128(value) : + remaining = value >> 7 + + buff = "" + while remaining > 0 : + buff += pack( "=B", ((value & 0x7f) | 0x80) ) + + value = remaining + remaining >>= 7 + + buff += pack( "=B", value & 0x7f ) + return buff + +def writesleb128(value) : + remaining = value >> 7 + hasMore = True + end = 0 + buff = "" + + if (value & (-sys.maxint - 1)) == 0 : + end = 0 + else : + end = -1 + + while hasMore : + hasMore = (remaining != end) or ((remaining & 1) != ((value >> 6) & 1)) + tmp = 0 + if hasMore : + tmp = 0x80 + + buff += pack( "=B", (value & 0x7f) | (tmp) ) + value = remaining + remaining >>= 7 + + return buff + +def determineNext(i, end, m) : + op_value = i.get_op_value() + + # throw + return* + if (op_value == 0x27) or (0x0e <= op_value <= 0x11) : + return [ -1 ] + # goto + elif 0x28 <= op_value <= 0x2a : + off = i.get_ref_off() * 2 + return [ off + end ] + # if + elif 0x32 <= op_value <= 0x3d : + off = i.get_ref_off() * 2 + return [ end + i.get_length(), off + (end) ] + # sparse/packed + elif op_value in (0x2b, 0x2c) : + x = [] + + x.append( end + i.get_length() ) + + code = m.get_code().get_bc() + off = i.get_ref_off() * 2 + + data = code.get_ins_off( off + end ) + + if data != None : + for target in data.get_targets() : + x.append( target*2 + end ) + + return x + return [] + +def determineException(vm, m) : + # no exceptions ! + if m.get_code().get_tries_size() <= 0 : + return [] + + h_off = {} + + handler_catch_list = m.get_code().get_handlers() + + for try_item in m.get_code().get_tries() : + offset_handler = try_item.get_handler_off() + handler_catch_list.get_off() + if offset_handler in h_off : + h_off[ offset_handler ].append( [ try_item ] ) + else : + h_off[ offset_handler ] = [] + h_off[ offset_handler ].append( [ try_item ] ) + + #print m.get_name(), "\t HANDLER_CATCH_LIST SIZE", handler_catch_list.size, handler_catch_list.get_offset() + for handler_catch in handler_catch_list.get_list() : + if handler_catch.get_off() not in h_off : + continue + + for i in h_off[ handler_catch.get_off() ] : + i.append( handler_catch ) + + exceptions = [] + #print m.get_name(), h_off + for i in h_off : + for value in h_off[ i ] : + try_value = value[0] + + z = [ try_value.get_start_addr() * 2, (try_value.get_start_addr() * 2) + (try_value.get_insn_count() * 2) - 1 ] + + handler_catch = value[1] + if handler_catch.get_size() <= 0 : + z.append( [ "any", handler_catch.get_catch_all_addr() * 2 ] ) + + for handler in handler_catch.get_handlers() : + z.append( [ vm.get_cm_type( handler.get_type_idx() ), handler.get_addr() * 2 ] ) + + exceptions.append( z ) + + #print m.get_name(), exceptions + return exceptions + +class HeaderItem : + """ + This class can parse an header_item of a dex file + + :param buff: a string which represents a Buff object of the header_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.magic = unpack("=Q", buff.read(8))[0] + self.checksum = unpack("=i", buff.read(4))[0] + self.signature = unpack("=20s", buff.read(20))[0] + self.file_size = unpack("=I", buff.read(4))[0] + self.header_size = unpack("=I", buff.read(4))[0] + self.endian_tag = unpack("=I", buff.read(4))[0] + self.link_size = unpack("=I", buff.read(4))[0] + self.link_off = unpack("=I", buff.read(4))[0] + self.map_off = unpack("=I", buff.read(4))[0] + self.string_ids_size = unpack("=I", buff.read(4))[0] + self.string_ids_off = unpack("=I", buff.read(4))[0] + self.type_ids_size = unpack("=I", buff.read(4))[0] + self.type_ids_off = unpack("=I", buff.read(4))[0] + self.proto_ids_size = unpack("=I", buff.read(4))[0] + self.proto_ids_off = unpack("=I", buff.read(4))[0] + self.field_ids_size = unpack("=I", buff.read(4))[0] + self.field_ids_off = unpack("=I", buff.read(4))[0] + self.method_ids_size = unpack("=I", buff.read(4))[0] + self.method_ids_off = unpack("=I", buff.read(4))[0] + self.class_defs_size = unpack("=I", buff.read(4))[0] + self.class_defs_off = unpack("=I", buff.read(4))[0] + self.data_size = unpack("=I", buff.read(4))[0] + self.data_off = unpack("=I", buff.read(4))[0] + + self.map_off_obj = None + self.string_off_obj = None + self.type_off_obj = None + self.proto_off_obj = None + self.field_off_obj = None + self.method_off_obj = None + self.class_off_obj = None + self.data_off_obj = None + + def reload(self) : + pass + + def get_obj(self) : + if self.map_off_obj == None : + self.map_off_obj = self.__CM.get_item_by_offset( self.map_off ) + + if self.string_off_obj == None : + self.string_off_obj = self.__CM.get_item_by_offset( self.string_ids_off ) + + if self.type_off_obj == None : + self.type_off_obj = self.__CM.get_item_by_offset( self.type_ids_off ) + + if self.proto_off_obj == None : + self.proto_off_obj = self.__CM.get_item_by_offset( self.proto_ids_off ) + + if self.field_off_obj == None : + self.field_off_obj = self.__CM.get_item_by_offset( self.field_ids_off ) + + if self.method_off_obj == None : + self.method_off_obj = self.__CM.get_item_by_offset( self.method_ids_off ) + + if self.class_off_obj == None : + self.class_off_obj = self.__CM.get_item_by_offset( self.class_defs_off ) + + if self.data_off_obj == None : + self.data_off_obj = self.__CM.get_item_by_offset( self.data_off ) + + self.map_off = self.map_off_obj.get_off() + + self.string_ids_size = len(self.string_off_obj) + self.string_ids_off = self.string_off_obj[0].get_off() + + self.type_ids_size = len(self.type_off_obj.type) + self.type_ids_off = self.type_off_obj.get_off() + + self.proto_ids_size = len(self.proto_off_obj.proto) + self.proto_ids_off = self.proto_off_obj.get_off() + + self.field_ids_size = len(self.field_off_obj.elem) + self.field_ids_off = self.field_off_obj.get_off() + + self.method_ids_size = len(self.method_off_obj.methods) + self.method_ids_off = self.method_off_obj.get_off() + + self.class_defs_size = len(self.class_off_obj.class_def) + self.class_defs_off = self.class_off_obj.get_off() + + #self.data_size = len(self.data_off_obj) + self.data_off = self.data_off_obj[0].get_off() + + return pack("=Q", self.magic) + \ + pack("=I", self.checksum) + \ + pack("=20s", self.signature) + \ + pack("=I", self.file_size) + \ + pack("=I", self.header_size) + \ + pack("=I", self.endian_tag) + \ + pack("=I", self.link_size) + \ + pack("=I", self.link_off) + \ + pack("=I", self.map_off) + \ + pack("=I", self.string_ids_size) + \ + pack("=I", self.string_ids_off) + \ + pack("=I", self.type_ids_size) + \ + pack("=I", self.type_ids_off) + \ + pack("=I", self.proto_ids_size) + \ + pack("=I", self.proto_ids_off) + \ + pack("=I", self.field_ids_size) + \ + pack("=I", self.field_ids_off) + \ + pack("=I", self.method_ids_size) + \ + pack("=I", self.method_ids_off) + \ + pack("=I", self.class_defs_size) + \ + pack("=I", self.class_defs_off) + \ + pack("=I", self.data_size) + \ + pack("=I", self.data_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_raw()) + + def show(self) : + bytecode._PrintSubBanner("Header Item") + bytecode._PrintDefault("magic=%s, checksum=%s, signature=%s\n" % (self.magic, self.checksum, self.signature)) + bytecode._PrintDefault("file_size=%x, header_size=%x, endian_tag=%x\n" % (self.file_size, self.header_size, self.endian_tag)) + bytecode._PrintDefault("link_size=%x, link_off=%x\n" % (self.link_size, self.link_off)) + bytecode._PrintDefault("map_off=%x\n" % (self.map_off)) + bytecode._PrintDefault("string_ids_size=%x, string_ids_off=%x\n" % (self.string_ids_size, self.string_ids_off)) + bytecode._PrintDefault("type_ids_size=%x, type_ids_off=%x\n" % (self.type_ids_size, self.type_ids_off)) + bytecode._PrintDefault("proto_ids_size=%x, proto_ids_off=%x\n" % (self.proto_ids_size, self.proto_ids_off)) + bytecode._PrintDefault("field_ids_size=%x, field_ids_off=%x\n" % (self.field_ids_size, self.field_ids_off)) + bytecode._PrintDefault("method_ids_size=%x, method_ids_off=%x\n" % (self.method_ids_size, self.method_ids_off)) + bytecode._PrintDefault("class_defs_size=%x, class_defs_off=%x\n" % (self.class_defs_size, self.class_defs_off)) + bytecode._PrintDefault("data_size=%x, data_off=%x\n" % (self.data_size, self.data_off)) + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + +class AnnotationOffItem : + """ + This class can parse an annotation_off_item of a dex file + + :param buff: a string which represents a Buff object of the annotation_off_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.annotation_off = unpack("=I", buff.read( 4 ) )[0] + + def show(self) : + bytecode._PrintSubBanner("Annotation Off Item") + bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotation_off) + + def get_obj(self) : + if self.annotation_off != 0 : + self.annotation_off = self.__CM.get_obj_by_offset( self.annotation_off ).get_off() + + return pack("=I", self.annotation_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class AnnotationSetItem : + """ + This class can parse an annotation_set_item of a dex file + + :param buff: a string which represents a Buff object of the annotation_set_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + self.annotation_off_item = [] + + self.size = unpack("=I", buff.read( 4 ) )[0] + for i in xrange(0, self.size) : + self.annotation_off_item.append( AnnotationOffItem(buff, cm) ) + + def get_annotation_off_item(self) : + """ + Return the offset from the start of the file to an annotation + + :rtype: a list of :class:`AnnotationOffItem` + """ + return self.annotation_off_item + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("Annotation Set Item") + for i in self.annotation_off_item : + i.show() + + def get_obj(self) : + return pack("=I", self.size) + + def get_raw(self) : + return self.get_obj() + ''.join(i.get_raw() for i in self.annotation_off_item) + + def get_length(self) : + length = len(self.get_obj()) + + for i in self.annotation_off_item : + length += i.get_length() + + return length + +class AnnotationSetRefItem : + """ + This class can parse an annotation_set_ref_item of a dex file + + :param buff: a string which represents a Buff object of the annotation_set_ref_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.annotations_off = unpack("=I", buff.read( 4 ) )[0] + + def get_annotations_off(self) : + """ + Return the offset from the start of the file to the referenced annotation set or + 0 if there are no annotations for this element. + + :rtype: int + """ + return self.annotations_off + + def show(self) : + bytecode._PrintSubBanner("Annotation Set Ref Item") + bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotation_off) + + def get_obj(self) : + if self.annotations_off != 0 : + self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off() + + return pack("=I", self.annotations_off) + + def get_raw(self) : + return self.get_obj() + +class AnnotationSetRefList: + """ + This class can parse an annotation_set_ref_list_item of a dex file + + :param buff: a string which represents a Buff object of the annotation_set_ref_list_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.__CM = cm + self.list = [] + + self.size = unpack("=I", buff.read( 4 ) )[0] + for i in xrange(0, self.size) : + self.list.append( AnnotationSetRefItem(buff, cm) ) + + def get_list(self) : + """ + Return elements of the list + + :rtype: :class:`AnnotationSetRefItem` + """ + return self.list + + def get_off(self) : + return self.offset + + def set_off(self, off) : + self.offset = off + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("Annotation Set Ref List Item") + for i in self.list : + i.show() + + def get_obj(self) : + return [ i for i in self.list ] + + def get_raw(self) : + return pack("=I", self.size) + ''.join(i.get_raw() for i in self.list) + + def get_length(self) : + return len(self.get_raw()) + +class FieldAnnotation : + """ + This class can parse a field_annotation of a dex file + + :param buff: a string which represents a Buff object of the field_annotation + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.__CM = cm + self.field_idx = unpack("=I", buff.read( 4 ) )[0] + self.annotations_off = unpack("=I", buff.read( 4 ) )[0] + + def get_field_idx(self) : + """ + Return the index into the field_ids list for the identity of the field being annotated + + :rtype: int + """ + return self.get_field_idx + + def get_annotations_off(self) : + """ + Return the offset from the start of the file to the list of annotations for the field + + :rtype: int + """ + return self.annotations_off + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def show(self) : + bytecode._PrintSubBanner("Field Annotation") + bytecode._PrintDefault( "field_idx=0x%x annotations_off=0x%x\n" % (self.field_idx, self.annotations_off) ) + + def get_obj(self) : + if self.annotations_off != 0 : + self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off() + + return pack("=I", self.field_idx) + pack("=I", self.annotations_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_raw()) + +class MethodAnnotation : + """ + This class can parse a method_annotation of a dex file + + :param buff: a string which represents a Buff object of the method_annotation + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.__CM = cm + self.method_idx = unpack("=I", buff.read( 4 ) )[0] + self.annotations_off = unpack("=I", buff.read( 4 ) )[0] + + def get_method_idx(self) : + """ + Return the index into the method_ids list for the identity of the method being annotated + + :rtype: int + """ + return self.get_method_idx + + def get_annotations_off(self) : + """ + Return the offset from the start of the file to the list of annotations for the method + + :rtype: int + """ + return self.annotations_off + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def show(self) : + bytecode._PrintSubBanner("Method Annotation") + bytecode._PrintDefault( "method_idx=0x%x annotations_off=0x%x\n" % (self.method_idx, self.annotations_off) ) + + def get_obj(self) : + if self.annotations_off != 0 : + self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off() + + return pack("=I", self.method_idx) + pack("=I", self.annotations_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_raw()) + +class ParameterAnnotation : + """ + This class can parse a parameter_annotation of a dex file + + :param buff: a string which represents a Buff object of the parameter_annotation + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.__CM = cm + self.method_idx = unpack("=I", buff.read( 4 ) )[0] + self.annotations_off = unpack("=I", buff.read( 4 ) )[0] + + def get_method_idx(self) : + """ + Return the index into the method_ids list for the identity of the method whose parameters are being annotated + + :rtype: int + """ + return self.get_method_idx + + def get_annotations_off(self) : + """ + Return the offset from the start of the file to the list of annotations for the method parameters + + :rtype: int + """ + return self.annotations_off + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def show(self) : + bytecode._PrintSubBanner("Parameter Annotation") + bytecode._PrintDefault( "method_idx=0x%x annotations_off=0x%x\n" % (self.method_idx, self.annotations_off) ) + + def get_obj(self) : + if self.annotations_off != 0 : + self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off() + + return pack("=I", self.method_idx) + pack("=I", self.annotations_off) + + def get_raw(self): + return self.get_obj() + + def get_length(self): + return len(self.get_raw()) + +class AnnotationsDirectoryItem : + """ + This class can parse an annotations_directory_item of a dex file + + :param buff: a string which represents a Buff object of the annotations_directory_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.class_annotations_off = unpack("=I", buff.read(4))[0] + self.annotated_fields_size = unpack("=I", buff.read(4))[0] + self.annotated_methods_size = unpack("=I", buff.read(4))[0] + self.annotated_parameters_size = unpack("=I", buff.read(4))[0] + + self.field_annotations = [] + for i in xrange(0, self.annotated_fields_size) : + self.field_annotations.append( FieldAnnotation( buff, cm ) ) + + self.method_annotations = [] + for i in xrange(0, self.annotated_methods_size) : + self.method_annotations.append( MethodAnnotation( buff, cm ) ) + + self.parameter_annotations = [] + for i in xrange(0, self.annotated_parameters_size) : + self.parameter_annotations.append( ParameterAnnotation( buff, cm ) ) + + def get_class_annotations_off(self) : + """ + Return the offset from the start of the file to the annotations made directly on the class, + or 0 if the class has no direct annotations + + :rtype: int + """ + return self.class_annotations_off + + + def get_annotated_fields_size(self) : + """ + Return the count of fields annotated by this item + + :rtype: int + """ + return self.annotated_fields_size + + def get_annotated_methods_size(self) : + """ + Return the count of methods annotated by this item + + :rtype: int + """ + return self.annotated_methods_size + + def get_annotated_parameters_size(self) : + """ + Return the count of method parameter lists annotated by this item + + :rtype: int + """ + return self.annotated_parameters_size + + def get_field_annotations(self) : + """ + Return the list of associated field annotations + + :rtype: a list of :class:`FieldAnnotation` + """ + return self.field_annotations + + def get_method_annotations(self) : + """ + Return the list of associated method annotations + + :rtype: a list of :class:`MethodAnnotation` + """ + return self.method_annotations + + + def get_parameter_annotations(self) : + """ + Return the list of associated method parameter annotations + + :rtype: a list of :class:`ParameterAnnotation` + """ + return self.parameter_annotations + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("Annotations Directory Item") + bytecode._PrintDefault("class_annotations_off=0x%x annotated_fields_size=%d annotated_methods_size=%d annotated_parameters_size=%d\n" % + ( self.class_annotations_off, + self.annotated_fields_size, + self.annotated_methods_size, + self.annotated_parameters_size)) + + for i in self.field_annotations : + i.show() + + for i in self.method_annotations : + i.show() + + for i in self.parameter_annotations : + i.show() + + def get_obj(self) : + if self.class_annotations_off != 0 : + self.class_annotations_off = self.__CM.get_obj_by_offset( self.class_annotations_off ).get_off() + + return pack("=I", self.class_annotations_off) + \ + pack("=I", self.annotated_fields_size) + \ + pack("=I", self.annotated_methods_size) + \ + pack("=I", self.annotated_parameters_size) + + def get_raw(self) : + return self.get_obj() + \ + ''.join(i.get_raw() for i in self.field_annotations) + \ + ''.join(i.get_raw() for i in self.method_annotations) + \ + ''.join(i.get_raw() for i in self.parameter_annotations) + + def get_length(self) : + length = len( self.get_obj() ) + for i in self.field_annotations : + length += i.get_length() + + for i in self.method_annotations : + length += i.get_length() + + for i in self.parameter_annotations : + length += i.get_length() + + return length + +class TypeItem : + """ + This class can parse a type_item of a dex file + + :param buff: a string which represents a Buff object of the type_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.type_idx = unpack("=H", buff.read(2))[0] + + def get_type_idx(self) : + """ + Return the index into the type_ids list + + :rtype: int + """ + return self.type_idx + + def get_string(self) : + """ + Return the type string + + :rtype: string + """ + return self.__CM.get_type( self.type_idx ) + + def show(self) : + bytecode._PrintSubBanner("Type Item") + bytecode._PrintDefault("type_idx=%d\n" % self.type_idx) + + def get_obj(self) : + return pack("=H", self.type_idx) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class TypeList : + """ + This class can parse a type_list of a dex file + + :param buff: a string which represents a Buff object of the type_list + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.pad = "" + if self.offset % 4 != 0 : + self.pad = buff.read( self.offset % 4 ) + + self.len_pad = len(self.pad) + + self.size = unpack("=I", buff.read( 4 ) )[0] + + self.list = [] + for i in xrange(0, self.size) : + self.list.append( TypeItem( buff, cm ) ) + + def get_pad(self) : + """ + Return the alignment string + + :rtype: string + """ + return self.pad + + def get_type_list_off(self) : + """ + Return the offset of the item + + :rtype: int + """ + return self.offset + self.len_pad + + def get_string(self) : + """ + Return the concatenation of all strings + + :rtype: string + """ + return ' '.join(i.get_string() for i in self.list) + + def get_size(self) : + """ + Return the size of the list, in entries + + :rtype: int + """ + return self.size + + def get_list(self) : + """ + Return the list of TypeItem + + :rtype: a list of :class:`TypeItem` objects + """ + return self.list + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + self.len_pad + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("Type List") + bytecode._PrintDefault("size=%d\n" % self.size) + + for i in self.list : + i.show() + + def get_obj(self) : + return self.pad + pack("=I", self.size) + + def get_raw(self) : + return self.get_obj() + ''.join(i.get_raw() for i in self.list) + + def get_length(self) : + length = len(self.get_obj()) + + for i in self.list : + length += i.get_length() + + return length + +DBG_END_SEQUENCE = 0x00 # (none) terminates a debug info sequence for a code_item +DBG_ADVANCE_PC = 0x01 # uleb128 addr_diff addr_diff: amount to add to address register advances the address register without emitting a positions entry +DBG_ADVANCE_LINE = 0x02 # sleb128 line_diff line_diff: amount to change line register by advances the line register without emitting a positions entry +DBG_START_LOCAL = 0x03 # uleb128 register_num + # uleb128p1 name_idx + # uleb128p1 type_idx + # register_num: register that will contain local name_idx: string index of the name + # type_idx: type index of the type introduces a local variable at the current address. Either name_idx or type_idx may be NO_INDEX to indicate that that value is unknown. +DBG_START_LOCAL_EXTENDED = 0x04 # uleb128 register_num uleb128p1 name_idx uleb128p1 type_idx uleb128p1 sig_idx + # register_num: register that will contain local + # name_idx: string index of the name + # type_idx: type index of the type + # sig_idx: string index of the type signature + # introduces a local with a type signature at the current address. Any of name_idx, type_idx, or sig_idx may be NO_INDEX to indicate that that value is unknown. ( + # If sig_idx is -1, though, the same data could be represented more efficiently using the opcode DBG_START_LOCAL.) + # Note: See the discussion under "dalvik.annotation.Signature" below for caveats about handling signatures. +DBG_END_LOCAL = 0x05 # uleb128 register_num + # register_num: register that contained local + # marks a currently-live local variable as out of scope at the current address +DBG_RESTART_LOCAL = 0x06 # uleb128 register_num + # register_num: register to restart re-introduces a local variable at the current address. + # The name and type are the same as the last local that was live in the specified register. +DBG_SET_PROLOGUE_END = 0x07 # (none) sets the prologue_end state machine register, indicating that the next position entry that is added should be considered the end of a + # method prologue (an appropriate place for a method breakpoint). The prologue_end register is cleared by any special (>= 0x0a) opcode. +DBG_SET_EPILOGUE_BEGIN = 0x08 # (none) sets the epilogue_begin state machine register, indicating that the next position entry that is added should be considered the beginning + # of a method epilogue (an appropriate place to suspend execution before method exit). The epilogue_begin register is cleared by any special (>= 0x0a) opcode. +DBG_SET_FILE = 0x09 # uleb128p1 name_idx + # name_idx: string index of source file name; NO_INDEX if unknown indicates that all subsequent line number entries make reference to this source file name, + # instead of the default name specified in code_item +DBG_Special_Opcodes_BEGIN = 0x0a # (none) advances the line and address registers, emits a position entry, and clears prologue_end and epilogue_begin. See below for description. +DBG_Special_Opcodes_END = 0xff +DBG_LINE_BASE = -4 +DBG_LINE_RANGE = 15 + + +class DBGBytecode : + def __init__(self, cm, op_value) : + self.CM = cm + self.op_value = op_value + self.format = [] + + def get_op_value(self) : + return self.op_value + + def add(self, value, ttype) : + self.format.append( (value, ttype) ) + + def get_value(self) : + if self.get_op_value() == DBG_START_LOCAL : + return self.CM.get_string(self.format[1][0]) + elif self.get_op_value() == DBG_START_LOCAL_EXTENDED : + return self.CM.get_string(self.format[1][0]) + + return None + + def show(self) : + bytecode._PrintSubBanner("DBGBytecode") + bytecode._PrintDefault("op_value=%x format=%s value=%s\n" % (self.op_value, str(self.format), self.get_value())) + + def get_obj(self) : + return [] + + def get_raw(self) : + buff = self.op_value.get_value_buff() + for i in self.format : + if i[1] == "u" : + buff += writeuleb128( i[0] ) + elif i[1] == "s" : + buff += writesleb128( i[0] ) + return buff + +class DebugInfoItem : + def __init__(self, buff, cm) : + self.CM = cm + + self.offset = buff.get_idx() + + self.line_start = readuleb128( buff ) + self.parameters_size = readuleb128( buff ) + + #print "line", self.line_start, "params", self.parameters_size + + self.parameter_names = [] + for i in xrange(0, self.parameters_size) : + self.parameter_names.append( readuleb128p1( buff ) ) + + self.bytecodes = [] + bcode = DBGBytecode( self.CM, unpack("=B", buff.read(1))[0] ) + self.bytecodes.append( bcode ) + + while bcode.get_op_value() != DBG_END_SEQUENCE : + bcode_value = bcode.get_op_value() + + if bcode_value == DBG_ADVANCE_PC : + bcode.add( readuleb128( buff ), "u" ) + elif bcode_value == DBG_ADVANCE_LINE : + bcode.add( readsleb128( buff ), "s" ) + elif bcode_value == DBG_START_LOCAL : + bcode.add( readusleb128( buff ), "u" ) + bcode.add( readuleb128p1( buff ), "u1" ) + bcode.add( readuleb128p1( buff ), "u1" ) + elif bcode_value == DBG_START_LOCAL_EXTENDED : + bcode.add( readusleb128( buff ), "u" ) + bcode.add( readuleb128p1( buff ), "u1" ) + bcode.add( readuleb128p1( buff ), "u1" ) + bcode.add( readuleb128p1( buff ), "u1" ) + elif bcode_value == DBG_END_LOCAL : + bcode.add( readusleb128( buff ), "u" ) + elif bcode_value == DBG_RESTART_LOCAL : + bcode.add( readusleb128( buff ), "u" ) + elif bcode_value == DBG_SET_PROLOGUE_END : + pass + elif bcode_value == DBG_SET_EPILOGUE_BEGIN : + pass + elif bcode_value == DBG_SET_FILE : + bcode.add( readuleb128p1( buff ), "u1" ) + else : #bcode_value >= DBG_Special_Opcodes_BEGIN and bcode_value <= DBG_Special_Opcodes_END : + pass + + bcode = DBGBytecode( self.CM, unpack("=B", buff.read(1))[0] ) + self.bytecodes.append( bcode ) + + def reload(self) : + pass + + def get_parameters_size(self) : + return self.parameters_size + + def get_line_start(self) : + return self.line_start + + def get_parameter_names(self) : + return self.parameter_names + + def get_translated_parameter_names(self) : + l = [] + for i in self.parameter_names : + if i == -1 : + l.append( None ) + else : + l.append( self.CM.get_string( i ) ) + return l + + def get_bytecodes(self) : + return self.bytecodes + + def show(self) : + bytecode._PrintSubBanner("Debug Info Item") + bytecode._PrintDefault("line_start=%d parameters_size=%d\n" % (self.line_start, self.parameters_size)) + nb = 0 + for i in self.parameter_names : + bytecode._PrintDefault("parameter_names[%d]=%s\n" % (nb, self.CM.get_string( i ))) + nb += 1 + + for i in self.bytecodes : + i.show() + + def get_raw(self) : + return [ bytecode.Buff( self.__offset, writeuleb128( self.line_start ) + \ + writeuleb128( self.parameters_size ) + \ + ''.join(writeuleb128(i) for i in self.parameter_names) + \ + ''.join(i.get_raw() for i in self.bytecodes) ) ] + + def get_off(self) : + return self.offset + +VALUE_BYTE = 0x00 # (none; must be 0) ubyte[1] signed one-byte integer value +VALUE_SHORT = 0x02 # size - 1 (0..1) ubyte[size] signed two-byte integer value, sign-extended +VALUE_CHAR = 0x03 # size - 1 (0..1) ubyte[size] unsigned two-byte integer value, zero-extended +VALUE_INT = 0x04 # size - 1 (0..3) ubyte[size] signed four-byte integer value, sign-extended +VALUE_LONG = 0x06 # size - 1 (0..7) ubyte[size] signed eight-byte integer value, sign-extended +VALUE_FLOAT = 0x10 # size - 1 (0..3) ubyte[size] four-byte bit pattern, zero-extended to the right, and interpreted as an IEEE754 32-bit floating point value +VALUE_DOUBLE = 0x11 # size - 1 (0..7) ubyte[size] eight-byte bit pattern, zero-extended to the right, and interpreted as an IEEE754 64-bit floating point value +VALUE_STRING = 0x17 # size - 1 (0..3) ubyte[size] unsigned (zero-extended) four-byte integer value, interpreted as an index into the string_ids section and representing a string value +VALUE_TYPE = 0x18 # size - 1 (0..3) ubyte[size] unsigned (zero-extended) four-byte integer value, interpreted as an index into the type_ids section and representing a reflective type/class value +VALUE_FIELD = 0x19 # size - 1 (0..3) ubyte[size] unsigned (zero-extended) four-byte integer value, interpreted as an index into the field_ids section and representing a reflective field value +VALUE_METHOD = 0x1a # size - 1 (0..3) ubyte[size] unsigned (zero-extended) four-byte integer value, interpreted as an index into the method_ids section and representing a reflective method value +VALUE_ENUM = 0x1b # size - 1 (0..3) ubyte[size] unsigned (zero-extended) four-byte integer value, interpreted as an index into the field_ids section and representing the value of an enumerated type constant +VALUE_ARRAY = 0x1c # (none; must be 0) encoded_array an array of values, in the format specified by "encoded_array Format" below. The size of the value is implicit in the encoding. +VALUE_ANNOTATION = 0x1d # (none; must be 0) encoded_annotation a sub-annotation, in the format specified by "encoded_annotation Format" below. The size of the value is implicit in the encoding. +VALUE_NULL = 0x1e # (none; must be 0) (none) null reference value +VALUE_BOOLEAN = 0x1f # boolean (0..1) (none) one-bit value; 0 for false and 1 for true. The bit is represented in the value_arg. + + +class DebugInfoItemEmpty : + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + self.__buff = buff + self.__raw = "" + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + offset = self.offset + + n = self.__CM.get_next_offset_item( offset ) + + s_idx = self.__buff.get_idx() + self.__buff.set_idx( offset ) + self.__raw = self.__buff.read( n - offset ) + self.__buff.set_idx( s_idx ) + + def show(self) : + pass + + def get_obj(self) : + return [] + + def get_raw(self) : + return self.__raw + + def get_length(self) : + return len(self.__raw) + +class EncodedArray : + """ + This class can parse an encoded_array of a dex file + + :param buff: a string which represents a Buff object of the encoded_array + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.size = readuleb128( buff ) + + self.values = [] + for i in xrange(0, self.size) : + self.values.append( EncodedValue(buff, cm) ) + + def get_size(self) : + """ + Return the number of elements in the array + + :rtype: int + """ + return self.size + + def get_values(self) : + """ + Return a series of size encoded_value byte sequences in the format specified by this section, + concatenated sequentially + + :rtype: a list of :class:`EncodedValue` objects + """ + return self.values + + def show(self) : + bytecode._PrintSubBanner("Encoded Array") + bytecode._PrintDefault("size=%d\n" % self.size) + + for i in self.values : + i.show() + + def get_obj(self) : + return writeuleb128( self.size ) + + def get_raw(self) : + return self.get_obj() + ''.join(i.get_raw() for i in self.values) + + def get_length(self) : + length = len(self.get_obj()) + for i in self.values : + length += i.get_length() + + return length + +class EncodedValue : + """ + This class can parse an encoded_value of a dex file + + :param buff: a string which represents a Buff object of the encoded_value + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.val = unpack("=B", buff.read(1))[0] + self.value_arg = self.val >> 5 + self.value_type = self.val & 0x1f + + self.raw_value = None + self.value = "" + + # TODO: parse floats/doubles correctly + if self.value_type >= VALUE_SHORT and self.value_type < VALUE_STRING : + self.value, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + elif self.value_type == VALUE_STRING : + id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + self.value = cm.get_raw_string(id) + elif self.value_type == VALUE_TYPE : + id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + self.value = cm.get_type(id) + elif self.value_type == VALUE_FIELD : + id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + self.value = cm.get_field(id) + elif self.value_type == VALUE_METHOD : + id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + self.value = cm.get_method(id) + elif self.value_type == VALUE_ENUM : + id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 )) + self.value = cm.get_field(id) + elif self.value_type == VALUE_ARRAY : + self.value = EncodedArray( buff, cm ) + elif self.value_type == VALUE_ANNOTATION : + self.value = EncodedAnnotation( buff, cm ) + elif self.value_type == VALUE_BYTE : + self.value = buff.read( 1 ) + elif self.value_type == VALUE_NULL : + self.value = None + elif self.value_type == VALUE_BOOLEAN : + if self.value_arg: + self.value = True + else: + self.value = False + else : + bytecode.Exit( "Unknown value 0x%x" % self.value_type ) + + def get_value(self) : + """ + Return the bytes representing the value, variable in length and interpreted differently for different value_type bytes, + though always little-endian + + :rtype: an object representing the value + """ + return self.value + + def get_value_type(self) : + return self.value_type + + def get_value_arg(self) : + return self.value_arg + + def _getintvalue(self, buf): + ret = 0 + shift = 0 + for b in buf: + ret |= ord(b) << shift + shift += 8 + + return ret, buf + + def show(self) : + bytecode._PrintSubBanner("Encoded Value") + bytecode._PrintDefault("val=%x value_arg=%x value_type=%x\n" % (self.val, self.value_arg, self.value_type)) + + def get_obj(self) : + if isinstance(self.value, str) == False : + return [ self.value ] + return [] + + def get_raw(self) : + if self.raw_value == None : + return pack("=B", self.val) + bytecode.object_to_str( self.value ) + else : + return pack("=B", self.val) + bytecode.object_to_str( self.raw_value ) + + def get_length(self) : + if self.raw_value == None : + return len(pack("=B", self.val)) + len(bytecode.object_to_str( self.value )) + else : + return len(pack("=B", self.val)) + len(bytecode.object_to_str( self.raw_value )) + +class AnnotationElement : + """ + This class can parse an annotation_element of a dex file + + :param buff: a string which represents a Buff object of the annotation_element + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.name_idx = readuleb128( buff ) + self.value = EncodedValue( buff, cm ) + + def get_name_idx(self) : + """ + Return the element name, represented as an index into the string_ids section + + :rtype: int + """ + return self.name_idx + + def get_value(self) : + """ + Return the element value (EncodedValue) + + :rtype: a :class:`EncodedValue` object + """ + return self.value + + def show(self) : + bytecode._PrintSubBanner("Annotation Element") + bytecode._PrintDefault("name_idx=%d\n" % self.name_idx) + self.value.show() + + def get_obj(self) : + return writeuleb128(self.name_idx) + + def get_raw(self) : + return self.get_obj() + self.value.get_raw() + + def get_length(self) : + return len(self.get_obj()) + self.value.get_length() + +class EncodedAnnotation : + """ + This class can parse an encoded_annotation of a dex file + + :param buff: a string which represents a Buff object of the encoded_annotation + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.type_idx = readuleb128( buff ) + self.size = readuleb128( buff ) + + self.elements = [] + for i in xrange(0, self.size) : + self.elements.append( AnnotationElement( buff, cm ) ) + + def get_type_idx(self) : + """ + Return the type of the annotation. This must be a class (not array or primitive) type + + :rtype: int + """ + return self.type_idx + + def get_size(self) : + """ + Return the number of name-value mappings in this annotation + + :rtype:int + """ + return self.size + + def get_elements(self) : + """ + Return the elements of the annotation, represented directly in-line (not as offsets) + + :rtype: a list of :class:`AnnotationElement` objects + """ + return self.elements + + def show(self) : + bytecode._PrintSubBanner("Encoded Annotation") + bytecode._PrintDefault("type_idx=%d size=%d\n" % (self.type_idx, self.size)) + + for i in self.elements : + i.show() + + def get_obj(self) : + return [ i for i in self.elements ] + + def get_raw(self) : + return writeuleb128(self.type_idx) + writeuleb128(self.size) + ''.join(i.get_raw() for i in self.elements) + + def get_length(self) : + length = len(writeuleb128(self.type_idx) + writeuleb128(self.size)) + + for i in self.elements : + length += i.get_length() + + return length + +class AnnotationItem : + """ + This class can parse an annotation_item of a dex file + + :param buff: a string which represents a Buff object of the annotation_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.visibility = unpack("=B", buff.read(1))[0] + self.annotation = EncodedAnnotation(buff, cm) + + def get_visibility(self) : + """ + Return the intended visibility of this annotation + + :rtype: int + """ + return self.visibility + + def get_annotation(self) : + """ + Return the encoded annotation contents + + :rtype: a :class:`EncodedAnnotation` object + """ + return self.annotation + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("Annotation Item") + bytecode._PrintDefault("visibility=%d\n" % self.visibility) + self.annotation.show() + + def get_obj(self) : + return [ self.annotation ] + + def get_raw(self) : + return pack("=B", self.visibility) + self.annotation.get_raw() + + def get_length(self) : + length = len(pack("=B", self.visibility)) + + length += self.annotation.get_length() + + return length + +class EncodedArrayItem : + """ + This class can parse an encoded_array_item of a dex file + + :param buff: a string which represents a Buff object of the encoded_array_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + self.value = EncodedArray( buff, cm ) + + def get_value(self) : + """ + Return the bytes representing the encoded array value + + :rtype: a :class:`EncodedArray` object + """ + return self.value + + def set_off(self, off) : + self.offset = off + + def reload(self) : + pass + + def get_value(self) : + return self.value + + def show(self) : + bytecode._PrintSubBanner("Encoded Array Item") + self.value.show() + + def get_obj(self) : + return [ self.value ] + + def get_raw(self) : + return self.value.get_raw() + + def get_length(self) : + return self.value.get_length() + + def get_off(self) : + return self.offset + + +def utf8_to_string(buff, length): + chars = [] + + for _ in xrange(length): + first_char = ord(buff.read(1)) + value = first_char >> 4 + if value in (0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07): + if first_char == 0: + warning('at offset %x: single zero byte illegal' % buff.get_idx()) + chars.append(chr(first_char)) + elif value in (0x0c, 0x0d): + second_char = ord(buff.read(1)) + if (second_char & 0xc0) != 0x80: + warning('bad utf8 at offset: %x' % buff.get_idx()) + value = ((first_char & 0x1f) << 6) | (second_char & 0x3f) + if value != 0 and value < 0x80: + warning('at offset %x: utf8 should have been represented with one byte encoding' % buff.get_idx()) + chars.append(unichr(value)) + elif value == 0x0e: + second_char = ord(buff.read(1)) + if second_char & 0xc0 != 0x80: + warning('bad utf8 byte %x at offset %x' % (second_char, buff.get_idx())) + third_char = ord(buff.read(1)) + if third_char & 0xc0 != 0x80: + warning('bad utf8 byte %x at offset %x' % (third_char, buff.get_idx())) + value = ((first_char & 0x0f) << 12) | ((second_char & 0x3f) << 6) | (third_char & 0x3f) + if value < 0x800: + warning('at offset %x: utf8 should have been represented with two-byte encoding' % buff.get_idx()) + chars.append(unichr(value)) + else: + warning('at offset %x: illegal utf8' % buff.get_idx()) + return ''.join(chars) + + +class StringDataItem : + """ + This class can parse a string_data_item of a dex file + + :param buff: a string which represents a Buff object of the string_data_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.utf16_size = readuleb128( buff ) + + self.data = utf8_to_string(buff, self.utf16_size) + expected = buff.read(1) + if expected != '\x00': + warning('\x00 expected at offset: %x, found: %x' % (buff.get_idx(), expected)) + + def get_utf16_size(self) : + """ + Return the size of this string, in UTF-16 code units + + :rtype:int + """ + return self.utf16_size + + def get_data(self) : + """ + Return a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes) followed by a byte of value 0 + + :rtype: string + """ + return self.data + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + pass + + def get(self) : + return self.data + + def show(self) : + bytecode._PrintSubBanner("String Data Item") + bytecode._PrintDefault("utf16_size=%d data=%s\n" % (self.utf16_size, repr( self.data ))) + + def get_obj(self) : + return [] + + def get_raw(self) : + return writeuleb128( self.utf16_size ) + self.data + + def get_length(self) : + return len(writeuleb128( self.utf16_size )) + len(self.data) + +class StringIdItem : + """ + This class can parse a string_id_item of a dex file + + :param buff: a string which represents a Buff object of the string_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.string_data_off = unpack("=I", buff.read(4))[0] + + def get_string_data_off(self): + """ + Return the offset from the start of the file to the string data for this item + + :rtype: int + """ + return self.string_data_off + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + pass + + def show(self) : + bytecode._PrintSubBanner("String Id Item") + bytecode._PrintDefault("string_data_off=%x\n" % self.string_data_off) + + def get_obj(self) : + if self.string_data_off != 0 : + self.string_data_off = self.__CM.get_string_by_offset( self.string_data_off ).get_off() + + return pack("=I", self.string_data_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class TypeIdItem : + """ + This class can parse a type_id_item of a dex file + + :param buff: a string which represents a Buff object of the type_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.descriptor_idx = unpack("=I", buff.read( 4 ) )[0] + self.descriptor_idx_value = None + + def get_descriptor_idx(self) : + """ + Return the index into the string_ids list for the descriptor string of this type + + :rtype: int + """ + return self.descriptor_idx + + def get_descriptor_idx_value(self) : + """ + Return the string associated to the descriptor + + :rtype: string + """ + return self.descriptor_idx_value + + def reload(self) : + self.descriptor_idx_value = self.__CM.get_string( self.descriptor_idx ) + + def show(self) : + bytecode._PrintSubBanner("Type Id Item") + bytecode._PrintDefault("descriptor_idx=%d descriptor_idx_value=%s\n" % (self.descriptor_idx, self.descriptor_idx_value)) + + def get_obj(self) : + return pack("=I", self.descriptor_idx) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class TypeHIdItem : + """ + This class can parse a list of type_id_item of a dex file + + :param buff: a string which represents a Buff object of the list of type_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.type = [] + for i in xrange(0, size) : + self.type.append( TypeIdItem( buff, cm ) ) + + def get_type(self) : + """ + Return the list of type_id_item + + :rtype: a list of :class:`TypeIdItem` objects + """ + return self.type + + def get(self, idx) : + try : + return self.type[ idx ].get_descriptor_idx() + except IndexError : + return -1 + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def reload(self) : + for i in self.type : + i.reload() + + def show(self) : + bytecode._PrintSubBanner("Type List Item") + for i in self.type : + i.show() + + def get_obj(self) : + return [ i for i in self.type ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.type) + + def get_length(self) : + length = 0 + for i in self.type : + length += i.get_length() + return length + +class ProtoIdItem : + """ + This class can parse a proto_id_item of a dex file + + :param buff: a string which represents a Buff object of the proto_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.shorty_idx = unpack("=I", buff.read(4))[0] + self.return_type_idx = unpack("=I", buff.read(4))[0] + self.parameters_off = unpack("=I", buff.read(4))[0] + + + self.shorty_idx_value = None + self.return_type_idx_value = None + self.parameters_off_value = None + + def reload(self) : + self.shorty_idx_value = self.__CM.get_string( self.shorty_idx ) + self.return_type_idx_value = self.__CM.get_type( self.return_type_idx ) + self.parameters_off_value = self.__CM.get_type_list( self.parameters_off ) + + def get_shorty_idx(self) : + """ + Return the index into the string_ids list for the short-form descriptor string of this prototype + + :rtype: int + """ + return self.shorty_idx + + def get_return_type_idx(self) : + """ + Return the index into the type_ids list for the return type of this prototype + + :rtype: int + """ + return self.return_type_idx + + def get_parameters_off(self) : + """ + Return the offset from the start of the file to the list of parameter types for this prototype, or 0 if this prototype has no parameters + + :rtype: int + """ + return self.parameters_off + + def get_shorty_idx_value(self) : + """ + Return the string associated to the shorty_idx + + :rtype: string + """ + return self.shorty_idx_value + + def get_return_type_idx_value(self) : + """ + Return the string associated to the return_type_idx + + :rtype: string + """ + return self.return_type_idx_value + + def get_parameters_off_value(self) : + """ + Return the string associated to the parameters_off + + :rtype: string + """ + return self.parameters_off_value + + def show(self) : + bytecode._PrintSubBanner("Proto Item") + bytecode._PrintDefault("shorty_idx=%d return_type_idx=%d parameters_off=%d\n" % (self.shorty_idx, self.return_type_idx, self.parameters_off)) + bytecode._PrintDefault("shorty_idx_value=%s return_type_idx_value=%s parameters_off_value=%s\n" % + (self.shorty_idx_value, self.return_type_idx_value, self.parameters_off_value)) + + + def get_obj(self) : + if self.parameters_off != 0 : + self.parameters_off = self.__CM.get_obj_by_offset( self.parameters_off ).get_off() + + return pack("=I", self.shorty_idx) + pack("=I", self.return_type_idx) + pack("=I", self.parameters_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class ProtoHIdItem : + """ + This class can parse a list of proto_id_item of a dex file + + :param buff: a string which represents a Buff object of the list of proto_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.proto = [] + + for i in xrange(0, size) : + self.proto.append( ProtoIdItem(buff, cm) ) + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def get(self, idx) : + try : + return self.proto[ idx ] + except IndexError : + return ProtoIdItemInvalid() + + def reload(self) : + for i in self.proto : + i.reload() + + def show(self) : + bytecode._PrintSubBanner("Proto List Item") + for i in self.proto : + i.show() + + def get_obj(self) : + return [ i for i in self.proto ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.proto) + + def get_length(self) : + length = 0 + for i in self.proto : + length += i.get_length() + return length + +class FieldIdItem : + """ + This class can parse a field_id_item of a dex file + + :param buff: a string which represents a Buff object of the field_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.class_idx = unpack("=H", buff.read(2))[0] + self.type_idx = unpack("=H", buff.read(2))[0] + self.name_idx = unpack("=I", buff.read(4))[0] + + self.class_idx_value = None + self.type_idx_value = None + self.name_idx_value = None + + def reload(self) : + self.class_idx_value = self.__CM.get_type( self.class_idx ) + self.type_idx_value = self.__CM.get_type( self.type_idx ) + self.name_idx_value = self.__CM.get_string( self.name_idx ) + + def get_class_idx(self) : + """ + Return the index into the type_ids list for the definer of this field + + :rtype: int + """ + return self.class_idx + + def get_type_idx(self) : + """ + Return the index into the type_ids list for the type of this field + + :rtype: int + """ + return self.type_idx + + def get_name_idx(self) : + """ + Return the index into the string_ids list for the name of this field + + :rtype: int + """ + return self.name_idx + + def get_class_name(self) : + """ + Return the class name of the field + + :rtype: string + """ + return self.class_idx_value + + def get_type(self) : + """ + Return the type of the field + + :rtype: string + """ + return self.type_idx_value + + def get_descriptor(self) : + """ + Return the descriptor of the field + + :rtype: string + """ + return self.type_idx_value + + def get_name(self) : + """ + Return the name of the field + + :rtype: string + """ + return self.name_idx_value + + def get_list(self) : + return [ self.get_class_name(), self.get_type(), self.get_name() ] + + def show(self) : + bytecode._PrintSubBanner("Field Id Item") + bytecode._PrintDefault("class_idx=%d type_idx=%d name_idx=%d\n" % (self.class_idx, self.type_idx, self.name_idx)) + bytecode._PrintDefault("class_idx_value=%s type_idx_value=%s name_idx_value=%s\n" % (self.class_idx_value, self.type_idx_value, self.name_idx_value)) + + def get_obj(self) : + return pack("=H", self.class_idx) + \ + pack("=H", self.type_idx) + \ + pack("=I", self.name_idx) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class FieldHIdItem : + """ + This class can parse a list of field_id_item of a dex file + + :param buff: a string which represents a Buff object of the list of field_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.offset = buff.get_idx() + + self.elem = [] + for i in xrange(0, size) : + self.elem.append( FieldIdItem(buff, cm) ) + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def gets(self) : + return self.elem + + def get(self, idx) : + try : + return self.elem[ idx ] + except IndexError : + return FieldIdItemInvalid() + + def reload(self) : + for i in self.elem : + i.reload() + + def show(self) : + nb = 0 + for i in self.elem : + print nb, + i.show() + nb = nb + 1 + + def get_obj(self) : + return [ i for i in self.elem ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.elem) + + def get_length(self) : + length = 0 + for i in self.elem : + length += i.get_length() + return length + + +class MethodIdItem : + """ + This class can parse a method_id_item of a dex file + + :param buff: a string which represents a Buff object of the method_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + self.offset = buff.get_idx() + + self.class_idx = unpack("=H", buff.read(2))[0] + self.proto_idx = unpack("=H", buff.read(2))[0] + self.name_idx = unpack("=I", buff.read(4))[0] + + self.class_idx_value = None + self.proto_idx_value = None + self.name_idx_value = None + + def reload(self) : + self.class_idx_value = self.__CM.get_type( self.class_idx ) + self.proto_idx_value = self.__CM.get_proto( self.proto_idx ) + self.name_idx_value = self.__CM.get_string( self.name_idx ) + + def get_class_idx(self) : + """ + Return the index into the type_ids list for the definer of this method + + :rtype: int + """ + return self.class_idx + + def get_proto_idx(self) : + """ + Return the index into the proto_ids list for the prototype of this method + + :rtype: int + """ + return self.proto_idx + + def get_name_idx(self) : + """ + Return the index into the string_ids list for the name of this method + + :rtype: int + """ + return self.name_idx + + def get_class_name(self) : + """ + Return the class name of the method + + :rtype: string + """ + return self.class_idx_value + + def get_proto(self) : + """ + Return the prototype of the method + + :rtype: string + """ + return self.proto_idx_value + + def get_descriptor(self) : + """ + Return the descriptor + + :rtype: string + """ + proto = self.get_proto() + return proto[0] + proto[1] + + def get_name(self) : + """ + Return the name of the method + + :rtype: string + """ + return self.name_idx_value + + def get_list(self) : + return [ self.get_class_name(), self.get_name(), self.get_proto() ] + + def show(self) : + bytecode._PrintSubBanner("Method Id Item") + bytecode._PrintDefault("class_idx=%d proto_idx=%d name_idx=%d\n" % (self.class_idx, self.proto_idx, self.name_idx)) + bytecode._PrintDefault("class_idx_value=%s proto_idx_value=%s name_idx_value=%s\n" % (self.class_idx_value, self.proto_idx_value, self.name_idx_value)) + + def get_obj(self) : + return pack("H", self.class_idx) + pack("H", self.proto_idx) + pack("I", self.name_idx) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class MethodHIdItem : + """ + This class can parse a list of method_id_item of a dex file + + :param buff: a string which represents a Buff object of the list of method_id_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.methods = [] + for i in xrange(0, size) : + self.methods.append( MethodIdItem(buff, cm) ) + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def get(self, idx) : + try : + return self.methods[ idx ] + except IndexError : + return MethodIdItemInvalid() + + def reload(self) : + for i in self.methods : + i.reload() + + def show(self) : + print "METHOD_ID_ITEM" + nb = 0 + for i in self.methods : + print nb, + i.show() + nb = nb + 1 + + def get_obj(self) : + return [ i for i in self.methods ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.methods) + + def get_length(self) : + length = 0 + for i in self.methods : + length += i.get_length() + return length + +class ProtoIdItemInvalid : + def get_params(self) : + return "AG:IPI:invalid_params;" + + def get_shorty(self) : + return "(AG:IPI:invalid_shorty)" + + def get_return_type(self) : + return "(AG:IPI:invalid_return_type)" + + def show(self) : + print "AG:IPI:invalid_proto_item", self.get_shorty(), self.get_return_type(), self.get_params() + +class FieldIdItemInvalid : + def get_class_name(self) : + return "AG:IFI:invalid_class_name;" + + def get_type(self) : + return "(AG:IFI:invalid_type)" + + def get_descriptor(self) : + return "(AG:IFI:invalid_descriptor)" + + def get_name(self) : + return "AG:IFI:invalid_name" + + def get_list(self) : + return [ self.get_class_name(), self.get_type(), self.get_name() ] + + def show(self) : + print "AG:IFI:invalid_field_item" + +class MethodIdItemInvalid : + def get_class_name(self) : + return "AG:IMI:invalid_class_name;" + + def get_descriptor(self) : + return "(AG:IMI:invalid_descriptor)" + + def get_proto(self) : + return "()AG:IMI:invalid_proto" + + def get_name(self) : + return "AG:IMI:invalid_name" + + def get_list(self) : + return [ self.get_class_name(), self.get_name(), self.get_proto() ] + + def show(self) : + print "AG:IMI:invalid_method_item" + + +class EncodedField: + """ + This class can parse an encoded_field of a dex file + + :param buff: a string which represents a Buff object of the encoded field + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm): + self.CM = cm + self.offset = buff.get_idx() + + self.field_idx_diff = readuleb128( buff ) + self.access_flags = readuleb128( buff ) + + self.field_idx = 0 + + self.name = None + self.proto = None + self.class_name = None + + self.init_value = None + self.access_flags_string = None + + def reload(self) : + name = self.CM.get_field( self.field_idx ) + self.class_name = name[0] + self.name = name[2] + self.proto = ''.join(i for i in name[1]) + + def set_init_value(self, value) : + """ + Setup the init value object of the field + + :param value: the init value + :type value: :class:`EncodedValue` + """ + self.init_value = value + + def get_init_value(self) : + """ + Return the init value object of the field + + :rtype: :class:`EncodedValue` + """ + return self.init_value + + def adjust_idx(self, val) : + self.field_idx = self.field_idx_diff + val + + + def get_field_idx_diff(self) : + """ + Return the index into the field_ids list for the identity of this field (includes the name and descriptor), + represented as a difference from the index of previous element in the list + + :rtype: int + """ + return self.field_idx_diff + + def get_field_idx(self) : + """ + Return the real index of the method + + :rtype: int + """ + return self.field_idx + + def get_access_flags(self) : + """ + Return the access flags of the field + + :rtype: int + """ + return self.access_flags + + def get_class_name(self) : + """ + Return the class name of the field + + :rtype: string + """ + return self.class_name + + def get_descriptor(self) : + """ + Return the descriptor of the field + + :rtype: string + """ + return self.proto + + def get_name(self) : + """ + Return the name of the field + + :rtype: string + """ + return self.name + + def get_access_flags_string(self) : + """ + Return the access flags string of the field + + :rtype: string + """ + if self.access_flags_string == None : + self.access_flags_string = get_access_flags_string( self.get_access_flags() ) + + if self.access_flags_string == "" : + self.access_flags_string = "0x%x" % self.get_access_flags() + return self.access_flags_string + + def set_name(self, value): + self.CM.set_hook_field_name(self, value) + self.reload() + + def get_obj(self) : + return [] + + def get_raw(self) : + return writeuleb128( self.field_idx_diff ) + writeuleb128( self.access_flags ) + + def get_size(self) : + return len(self.get_raw()) + + def show(self): + """ + Display the information about the field + """ + colors = bytecode.disable_print_colors() + self.pretty_show() + bytecode.enable_print_colors(colors) + + def pretty_show(self) : + """ + Display the information (with a pretty print) about the field + """ + bytecode._PrintSubBanner("Field Information") + bytecode._PrintDefault("%s->%s %s [access_flags=%s]\n" % ( self.get_class_name(), self.get_name(), self.get_descriptor(), self.get_access_flags_string() )) + + init_value = self.get_init_value() + if init_value != None : + bytecode._PrintDefault( "\tinit value: %s\n" % str( init_value.get_value() ) ) + + self.show_dref() + + def show_dref(self) : + """ + Display where this field is read or written + """ + try : + bytecode._PrintSubBanner("DREF") + bytecode._PrintDRef("R", self.DREFr.items) + bytecode._PrintDRef("W", self.DREFw.items) + bytecode._PrintSubBanner() + except AttributeError: + pass + +class EncodedMethod: + """ + This class can parse an encoded_method of a dex file + + :param buff: a string which represents a Buff object of the encoded_method + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.CM = cm + self.offset = buff.get_idx() + + self.method_idx_diff = readuleb128( buff ) #: method index diff in the corresponding section + self.access_flags = readuleb128( buff ) #: access flags of the method + self.code_off = readuleb128( buff ) #: offset of the code section + + self.method_idx = 0 + + self.name = None + self.proto = None + self.class_name = None + + self.code = None + + self.access_flags_string = None + + self.notes = [] + + def adjust_idx(self, val) : + self.method_idx = self.method_idx_diff + val + + def get_method_idx(self) : + """ + Return the real index of the method + + :rtype: int + """ + return self.method_idx + + def get_method_idx_diff(self) : + """ + Return index into the method_ids list for the identity of this method (includes the name and descriptor), + represented as a difference from the index of previous element in the lis + + :rtype: int + """ + return self.method_idx_diff + + def get_access_flags(self) : + """ + Return the access flags of the method + + :rtype: int + """ + return self.access_flags + + def get_code_off(self) : + """ + Return the offset from the start of the file to the code structure for this method, + or 0 if this method is either abstract or native + + :rtype: int + """ + return self.code_off + + def get_access_flags_string(self) : + """ + Return the access flags string of the method + + :rtype: string + """ + if self.access_flags_string == None : + self.access_flags_string = get_access_flags_string( self.get_access_flags() ) + + if self.access_flags_string == "" : + self.access_flags_string = "0x%x" % self.get_access_flags() + return self.access_flags_string + + def reload(self) : + v = self.CM.get_method( self.method_idx ) + + self.class_name = v[0] + self.name = v[1] + self.proto = ''.join(i for i in v[2]) + + self.code = self.CM.get_code( self.code_off ) + + def get_locals(self): + ret = self.proto.split(')') + params = ret[0][1:].split() + + return self.code.get_registers_size() - len(params) - 1 + + def get_information(self): + info = {} + if self.code: + nb = self.code.get_registers_size() + proto = self.get_descriptor() + + ret = proto.split(')') + params = ret[0][1:].split() + + ret = proto.split(')') + params = ret[0][1:].split() + if params: + info["registers"] = (0, nb - len(params) - 1) + j = 0 + info["params"] = [] + for i in xrange(nb - len(params), nb): + info["params"].append((i, get_type(params[j]))) + j += 1 + else: + info["registers"] = (0, nb - 1) + + info["return"] = get_type(ret[1]) + return info + + def each_params_by_register(self, nb, proto): + bytecode._PrintSubBanner("Params") + + ret = proto.split(')') + params = ret[0][1:].split() + if params: + bytecode._PrintDefault("- local registers: v%d...v%d\n" % (0, nb - len(params) - 1)) + j = 0 + for i in xrange(nb - len(params), nb): + bytecode._PrintDefault("- v%d: %s\n" % (i, get_type(params[j]))) + j += 1 + else: + bytecode._PrintDefault("local registers: v%d...v%d\n" % (0, nb - 1)) + + bytecode._PrintDefault("- return: %s\n" % get_type(ret[1])) + bytecode._PrintSubBanner() + + def show_info(self) : + """ + Display the basic information about the method + """ + bytecode._PrintSubBanner("Method Information") + bytecode._PrintDefault("%s->%s%s [access_flags=%s]\n" % ( self.get_class_name(), self.get_name(), self.get_descriptor(), self.get_access_flags_string() )) + + def show(self): + """ + Display the information about the method + """ + colors = bytecode.disable_print_colors() + self.pretty_show() + bytecode.enable_print_colors(colors) + + def pretty_show(self) : + """ + Display the information (with a pretty print) about the method + """ + self.show_info() + self.show_notes() + if self.code != None : + self.each_params_by_register( self.code.get_registers_size(), self.get_descriptor() ) + if self.CM.get_vmanalysis() == None : + self.code.show() + else : + self.code.pretty_show( self.CM.get_vmanalysis().get_method( self ) ) + self.show_xref() + + def show_xref(self): + """ + Display where the method is called or which method is called + """ + try: + bytecode._PrintSubBanner("XREF") + bytecode._PrintXRef("F", self.XREFfrom.items) + bytecode._PrintXRef("T", self.XREFto.items) + bytecode._PrintSubBanner() + except AttributeError: + pass + + def show_notes(self) : + """ + Display the notes about the method + """ + if self.notes != [] : + bytecode._PrintSubBanner("Notes") + for i in self.notes : + bytecode._PrintNote(i) + bytecode._PrintSubBanner() + + def source(self): + """ + Return the source code of this method + + :rtype: string + """ + self.CM.decompiler_ob.display_source(self) + + def get_source(self): + return self.CM.decompiler_ob.get_source_method(self) + + def get_length(self) : + """ + Return the length of the associated code of the method + + :rtype: int + """ + if self.code != None : + return self.code.get_length() + return 0 + + def get_code(self) : + """ + Return the code object associated to the method + + :rtype: :class:`DalvikCode` object + """ + return self.code + + def get_instructions(self) : + """ + Get the instructions + + :rtype: a generator of each :class:`Instruction` (or a cached list of instructions if you have setup instructions) + """ + if self.code == None : + return [] + return self.code.get_bc().get_instructions() + + def set_instructions(self, instructions) : + """ + Set the instructions + + :param instructions: the list of instructions + :type instructions: a list of :class:`Instruction` + """ + if self.code == None : + return [] + return self.code.get_bc().set_instructions(instructions) + + def get_instruction(self, idx, off=None) : + """ + Get a particular instruction by using (default) the index of the address if specified + + :param idx: index of the instruction (the position in the list of the instruction) + :type idx: int + :param off: address of the instruction + :type off: int + + :rtype: an :class:`Instruction` object + """ + if self._code != None : + return self.code.get_bc().get_instruction(idx, off) + return None + + def get_debug(self) : + """ + Return the debug object associated to this method + + :rtype: :class:`DebugInfoItem` + """ + if self.code == None : + return None + return self.code.get_debug() + + def get_descriptor(self) : + """ + Return the descriptor of the method + + :rtype: string + """ + return self.proto + + def get_class_name(self) : + """ + Return the class name of the method + + :rtype: string + """ + return self.class_name + + def get_name(self) : + """ + Return the name of the method + + :rtype: string + """ + return self.name + + def add_inote(self, msg, idx, off=None) : + """ + Add a message to a specific instruction by using (default) the index of the address if specified + + :param msg: the message + :type msg: string + :param idx: index of the instruction (the position in the list of the instruction) + :type idx: int + :param off: address of the instruction + :type off: int + """ + if self.code != None : + self.code.add_inote(msg, idx, off) + + def add_note(self, msg) : + """ + Add a message to this method + + :param msg: the message + :type msg: string + """ + self.notes.append( msg ) + + def set_code_idx(self, idx) : + """ + Set the start address of the buffer to disassemble + + :param idx: the index + :type idx: int + """ + if self.code != None : + self.code.set_idx( idx ) + + def set_name(self, value) : + self.CM.set_hook_method_name( self, value ) + self.reload() + + def get_raw(self) : + if self.code != None : + self.code_off = self.code.get_off() + + return writeuleb128( self.method_idx_diff ) + writeuleb128( self.access_flags ) + writeuleb128( self.code_off ) + + def get_size(self) : + return len(self.get_raw()) + +class ClassDataItem : + """ + This class can parse a class_data_item of a dex file + + :param buff: a string which represents a Buff object of the class_data_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.static_fields_size = readuleb128( buff ) + self.instance_fields_size = readuleb128( buff ) + self.direct_methods_size = readuleb128( buff ) + self.virtual_methods_size = readuleb128( buff ) + + self.static_fields = [] + self.instance_fields = [] + self.direct_methods = [] + self.virtual_methods = [] + + self._load_elements( self.static_fields_size, self.static_fields, EncodedField, buff, cm ) + self._load_elements( self.instance_fields_size, self.instance_fields, EncodedField, buff, cm ) + self._load_elements( self.direct_methods_size, self.direct_methods, EncodedMethod, buff, cm ) + self._load_elements( self.virtual_methods_size, self.virtual_methods, EncodedMethod, buff, cm ) + + def get_static_fields_size(self) : + """ + Return the number of static fields defined in this item + + :rtype: int + """ + return self.static_fields_size + + def get_instance_fields_size(self) : + """ + Return the number of instance fields defined in this item + + :rtype: int + """ + return self.instance_fields_size + + def get_direct_methods_size(self) : + """ + Return the number of direct methods defined in this item + + :rtype: int + """ + return self.direct_methods_size + + def get_virtual_methods_size(self) : + """ + Return the number of virtual methods defined in this item + + :rtype: int + """ + return self.virtual_methods_size + + def get_static_fields(self) : + """ + Return the defined static fields, represented as a sequence of encoded elements + + :rtype: a list of :class:`EncodedField` objects + """ + return self.static_fields + + def get_instance_fields(self) : + """ + Return the defined instance fields, represented as a sequence of encoded elements + + :rtype: a list of :class:`EncodedField` objects + """ + return self.instance_fields + + def get_direct_methods(self) : + """ + Return the defined direct (any of static, private, or constructor) methods, represented as a sequence of encoded elements + + :rtype: a list of :class:`EncodedMethod` objects + """ + return self.direct_methods + + def get_virtual_methods(self) : + """ + Return the defined virtual (none of static, private, or constructor) methods, represented as a sequence of encoded elements + + :rtype: a list of :class:`EncodedMethod` objects + """ + return self.virtual_methods + + def get_methods(self) : + """ + Return direct and virtual methods + + :rtype: a list of :class:`EncodedMethod` objects + """ + return [ x for x in self.direct_methods ] + [ x for x in self.virtual_methods ] + + def get_fields(self) : + """ + Return static and instance fields + + :rtype: a list of :class:`EncodedField` objects + """ + return [ x for x in self.static_fields ] + [ x for x in self.instance_fields ] + + + def set_off(self, off) : + self.offset = off + + def set_static_fields(self, value) : + if value != None : + values = value.get_values() + if len(values) <= len(self.static_fields) : + for i in xrange(0, len(values)) : + self.static_fields[i].set_init_value( values[i] ) + + def _load_elements(self, size, l, Type, buff, cm) : + prev = 0 + for i in xrange(0, size) : + el = Type(buff, cm) + el.adjust_idx( prev ) + + if isinstance(el, EncodedField) : + prev = el.get_field_idx() + else : + prev = el.get_method_idx() + + l.append( el ) + + def reload(self) : + for i in self.static_fields : + i.reload() + + for i in self.instance_fields : + i.reload() + + for i in self.direct_methods : + i.reload() + + for i in self.virtual_methods : + i.reload() + + def show(self) : + self.pretty_show() + + def pretty_show(self) : + bytecode._PrintSubBanner("Class Data Item") + bytecode._PrintDefault("static_fields_size=%d instance_fields_size=%d direct_methods_size=%d virtual_methods_size=%d\n" % \ + (self.static_fields_size, self.instance_fields_size, self.direct_methods_size, self.virtual_methods_size)) + + bytecode._PrintSubBanner("Static Fields") + for i in self.static_fields : + i.show() + + bytecode._PrintSubBanner("Instance Fields") + for i in self.instance_fields : + i.show() + + bytecode._PrintSubBanner("Direct Methods") + for i in self.direct_methods : + i.pretty_show() + + bytecode._PrintSubBanner("Virtual Methods") + for i in self.virtual_methods : + i.pretty_show() + + def get_obj(self) : + return [ i for i in self.static_fields ] + \ + [ i for i in self.instance_fields ] + \ + [ i for i in self.direct_methods ] + \ + [ i for i in self.virtual_methods ] + + def get_raw(self) : + buff = writeuleb128( self.static_fields_size ) + \ + writeuleb128( self.instance_fields_size ) + \ + writeuleb128( self.direct_methods_size ) + \ + writeuleb128( self.virtual_methods_size ) + \ + ''.join(i.get_raw() for i in self.static_fields) + \ + ''.join(i.get_raw() for i in self.instance_fields) + \ + ''.join(i.get_raw() for i in self.direct_methods) + \ + ''.join(i.get_raw() for i in self.virtual_methods) + + return buff + + def get_length(self) : + length = len(writeuleb128( self.static_fields_size )) + \ + len(writeuleb128( self.instance_fields_size )) + \ + len(writeuleb128( self.direct_methods_size )) + \ + len(writeuleb128( self.virtual_methods_size )) + + for i in self.static_fields : + length += i.get_size() + + for i in self.instance_fields : + length += i.get_size() + + for i in self.direct_methods : + length += i.get_size() + + for i in self.virtual_methods : + length += i.get_size() + + return length + + def get_off(self) : + return self.offset + + +class ClassDefItem: + """ + This class can parse a class_def_item of a dex file + + :param buff: a string which represents a Buff object of the class_def_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm): + self.__CM = cm + self.offset = buff.get_idx() + + self.class_idx = unpack("=I", buff.read(4))[0] + self.access_flags = unpack("=I", buff.read(4))[0] + self.superclass_idx = unpack("=I", buff.read(4))[0] + self.interfaces_off = unpack("=I", buff.read(4))[0] + self.source_file_idx = unpack("=I", buff.read(4))[0] + self.annotations_off = unpack("=I", buff.read(4))[0] + self.class_data_off = unpack("=I", buff.read(4))[0] + self.static_values_off = unpack("=I", buff.read(4))[0] + + self.interfaces = None + self.class_data_item = None + self.static_values = None + + self.name = None + self.sname = None + self.access_flags_string = None + + def reload(self) : + self.name = self.__CM.get_type( self.class_idx ) + self.sname = self.__CM.get_type( self.superclass_idx ) + + if self.interfaces_off != 0 : + self.interfaces = self.__CM.get_type_list( self.interfaces_off ) + + if self.class_data_off != 0 : + self.class_data_item = self.__CM.get_class_data_item( self.class_data_off ) + self.class_data_item.reload() + + if self.static_values_off != 0 : + self.static_values = self.__CM.get_encoded_array_item ( self.static_values_off ) + + if self.class_data_item != None : + self.class_data_item.set_static_fields( self.static_values.get_value() ) + + def get_methods(self) : + """ + Return all methods of this class + + :rtype: a list of :class:`EncodedMethod` objects + """ + if self.class_data_item != None : + return self.class_data_item.get_methods() + return [] + + def get_fields(self) : + """ + Return all fields of this class + + :rtype: a list of :class:`EncodedField` objects + """ + if self.class_data_item != None : + return self.class_data_item.get_fields() + return [] + + def get_class_idx(self) : + """ + Return the index into the type_ids list for this class + + :rtype: int + """ + return self.class_idx + + def get_access_flags(self) : + """ + Return the access flags for the class (public, final, etc.) + + :rtype: int + """ + return self.access_flags + + def get_superclass_idx(self) : + """ + Return the index into the type_ids list for the superclass + + :rtype: int + """ + return self.superclass_idx + + def get_interfaces_off(self) : + """ + Return the offset from the start of the file to the list of interfaces, or 0 if there are none + + :rtype: int + """ + return self.interfaces_off + + def get_source_file_idx(self) : + """ + Return the index into the string_ids list for the name of the file containing the original + source for (at least most of) this class, or the special value NO_INDEX to represent a lack of this information + + :rtype: int + """ + return self.source_file_idx + + def get_annotations_off(self) : + """ + Return the offset from the start of the file to the annotations structure for this class, + or 0 if there are no annotations on this class. + + :rtype: int + """ + return self.annotations_off + + def get_class_data_off(self) : + """ + Return the offset from the start of the file to the associated class data for this item, + or 0 if there is no class data for this class + + :rtype: int + """ + return self.class_data_off + + def get_static_values_off(self) : + """ + Return the offset from the start of the file to the list of initial values for static fields, + or 0 if there are none (and all static fields are to be initialized with 0 or null) + + :rtype: int + """ + return self.static_values_off + + + def get_class_data(self) : + """ + Return the associated class_data_item + + :rtype: a :class:`ClassDataItem` object + """ + return self.class_data_item + + def get_name(self) : + """ + Return the name of this class + + :rtype: int + """ + return self.name + + def get_superclassname(self) : + """ + Return the name of the super class + + :rtype: string + """ + return self.sname + + def get_interfaces(self) : + """ + Return the name of the interface + + :rtype: string + """ + return self.interfaces + + def get_access_flags_string(self) : + """ + Return the access flags string of the class + + :rtype: string + """ + if self.access_flags_string == None : + self.access_flags_string = get_access_flags_string( self.get_access_flags() ) + + if self.access_flags_string == "" : + self.access_flags_string = "0x%x" % self.get_access_flags() + return self.access_flags_string + + def show(self): + bytecode._PrintSubBanner("Class Def Item") + bytecode._PrintDefault("name=%s, sname=%s, interfaces=%s, access_flags=%s\n" % + (self.name, + self.sname, + self.interfaces, + self.get_access_flags_string())) + bytecode._PrintDefault("class_idx=%d, superclass_idx=%d, interfaces_off=%x, source_file_idx=%d, annotations_off=%x, class_data_off=%x, static_values_off=%x\n" % + (self.class_idx, + self.superclass_idx, + self.interfaces_off, + self.source_file_idx, + self.annotations_off, + self.class_data_off, + self.static_values_off)) + self.show_xref() + + def show_xref(self): + """ + Display where the method is called or which method is called + """ + try: + bytecode._PrintSubBanner("XREF") + bytecode._PrintXRef("F", self.XREFfrom.items) + bytecode._PrintSubBanner() + except AttributeError: + pass + + def source(self): + """ + Return the source code of the entire class + + :rtype: string + """ + self.__CM.decompiler_ob.display_all(self) + + def get_source(self): + return self.__CM.decompiler_ob.get_source_class(self) + + def set_name(self, value) : + self.__CM.set_hook_class_name( self, value ) + + def get_obj(self) : + if self.interfaces_off != 0 : + self.interfaces_off = self.__CM.get_obj_by_offset( self.interfaces_off ).get_off() + + if self.annotations_off != 0 : + self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off() + + if self.class_data_off != 0 : + self.class_data_off = self.__CM.get_obj_by_offset( self.class_data_off ).get_off() + + if self.static_values_off != 0 : + self.static_values_off = self.__CM.get_obj_by_offset( self.static_values_off ).get_off() + + return pack("=I", self.class_idx) + \ + pack("=I", self.access_flags) + \ + pack("=I", self.superclass_idx) + \ + pack("=I", self.interfaces_off) + \ + pack("=I", self.source_file_idx) + \ + pack("=I", self.annotations_off) + \ + pack("=I", self.class_data_off) + \ + pack("=I", self.static_values_off) + + def get_raw(self) : + return self.get_obj() + + def get_length(self) : + return len(self.get_obj()) + +class ClassHDefItem : + """ + This class can parse a list of class_def_item of a dex file + + :param buff: a string which represents a Buff object of the list of class_def_item + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.class_def = [] + + for i in xrange(0, size) : + idx = buff.get_idx() + + class_def = ClassDefItem( buff, cm ) + self.class_def.append( class_def ) + + buff.set_idx( idx + calcsize("=IIIIIIII") ) + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def get_class_idx(self, idx) : + for i in self.class_def : + if i.get_class_idx() == idx : + return i + return None + + def get_method(self, name_class, name_method) : + l = [] + + for i in self.class_def : + if i.get_name() == name_class : + for j in i.get_methods() : + if j.get_name() == name_method : + l.append(j) + + return l + + def get_names(self) : + return [ x.get_name() for x in self.class_def ] + + def reload(self) : + for i in self.class_def : + i.reload() + + def show(self) : + for i in self.class_def : + i.show() + + def get_obj(self) : + return [ i for i in self.class_def ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.class_def) + + def get_length(self) : + length = 0 + for i in self.class_def : + length += i.get_length() + return length + +class EncodedTypeAddrPair : + """ + This class can parse an encoded_type_addr_pair of a dex file + + :param buff: a string which represents a Buff object of the encoded_type_addr_pair + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff) : + self.type_idx = readuleb128( buff ) + self.addr = readuleb128( buff ) + + def get_type_idx(self) : + """ + Return the index into the type_ids list for the type of the exception to catch + + :rtype: int + """ + return self.type_idx + + def get_addr(self) : + """ + Return the bytecode address of the associated exception handler + + :rtype: int + """ + return self.addr + + def get_obj(self) : + return [] + + def show(self) : + bytecode._PrintSubBanner("Encoded Type Addr Pair") + bytecode._PrintDefault("type_idx=%d addr=%x\n" % (self.type_idx, self.addr)) + + def get_raw(self) : + return writeuleb128( self.type_idx ) + writeuleb128( self.addr ) + + def get_length(self) : + return len(self.get_raw()) + +class EncodedCatchHandler : + """ + This class can parse an encoded_catch_handler of a dex file + + :param buff: a string which represents a Buff object of the encoded_catch_handler + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.size = readsleb128( buff ) + + self.handlers = [] + + for i in xrange(0, abs(self.size)) : + self.handlers.append( EncodedTypeAddrPair(buff) ) + + if self.size <= 0 : + self.catch_all_addr = readuleb128( buff ) + + def get_size(self) : + """ + Return the number of catch types in this list + + :rtype: int + """ + return self.size + + def get_handlers(self) : + """ + Return the stream of abs(size) encoded items, one for each caught type, in the order that the types should be tested. + + :rtype: a list of :class:`EncodedTypeAddrPair` objects + """ + return self.handlers + + def get_catch_all_addr(self) : + """ + Return the bytecode address of the catch-all handler. This element is only present if size is non-positive. + + :rtype: int + """ + return self.catch_all_addr + + def get_off(self) : + return self.offset + + def set_off(self, off) : + self.offset = off + + def show(self) : + bytecode._PrintSubBanner("Encoded Catch Handler") + bytecode._PrintDefault("size=%d\n" % self.size) + + for i in self.handlers : + i.show() + + if self.size <= 0 : + bytecode._PrintDefault("catch_all_addr=%x\n" % self.catch_all_addr) + + def get_raw(self) : + buff = writesleb128( self.size ) + ''.join(i.get_raw() for i in self.handlers) + + if self.size <= 0 : + buff += writeuleb128( self.catch_all_addr ) + + return buff + + def get_length(self) : + length = len(writesleb128( self.size )) + + for i in self.handlers : + length += i.get_length() + + if self.size <= 0 : + length += len(writeuleb128( self.catch_all_addr )) + + return length + +class EncodedCatchHandlerList : + """ + This class can parse an encoded_catch_handler_list of a dex file + + :param buff: a string which represents a Buff object of the encoded_catch_handler_list + :type buff: Buff object + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.size = readuleb128( buff ) + self.list = [] + + for i in xrange(0, self.size) : + self.list.append( EncodedCatchHandler(buff, cm) ) + + + def get_size(self) : + """ + Return the size of this list, in entries + + :rtype: int + """ + return self.size + + def get_list(self) : + """ + Return the actual list of handler lists, represented directly (not as offsets), and concatenated sequentially + + :rtype: a list of :class:`EncodedCatchHandler` objects + """ + return self.list + + def show(self) : + bytecode._PrintSubBanner("Encoded Catch Handler List") + bytecode._PrintDefault("size=%d\n" % self.size) + + for i in self.list : + i.show() + + def get_off(self) : + return self.offset + + def set_off(self, off) : + self.offset = off + + def get_obj(self) : + return writeuleb128( self.size ) + + def get_raw(self) : + return self.get_obj() + ''.join(i.get_raw() for i in self.list) + + def get_length(self) : + length = len(self.get_obj()) + + for i in self.list : + length += i.get_length() + return length + + +KIND_METH = 0 +KIND_STRING = 1 +KIND_FIELD = 2 +KIND_TYPE = 3 +VARIES = 4 +INLINE_METHOD = 5 +VTABLE_OFFSET = 6 +FIELD_OFFSET = 7 +KIND_RAW_STRING = 8 + +OPERAND_REGISTER = 0 +OPERAND_LITERAL = 1 +OPERAND_RAW = 2 +OPERAND_OFFSET = 3 +OPERAND_KIND = 0x100 + +def get_kind(cm, kind, value): + """ + Return the value of the 'kind' argument + + :param cm: a ClassManager object + :type cm: :class:`ClassManager` + :param kind: the type of the 'kind' argument + :type kind: int + :param value: the value of the 'kind' argument + :type value: int + + :rtype: string + """ + if kind == KIND_METH: + method = cm.get_method_ref(value) + class_name = method.get_class_name() + name = method.get_name() + descriptor = method.get_descriptor() + + return "%s->%s%s" % (class_name, name, descriptor) + + elif kind == KIND_STRING: + return repr(cm.get_string(value)) + + elif kind == KIND_RAW_STRING: + return cm.get_string(value) + + elif kind == KIND_FIELD: + class_name, proto, field_name = cm.get_field(value) + return "%s->%s %s" % (class_name, field_name, proto) + + elif kind == KIND_TYPE: + return cm.get_type(value) + + elif kind == VTABLE_OFFSET: + return "vtable[0x%x]" % value + + elif kind == FIELD_OFFSET: + return "field[0x%x]" % value + + elif kind == INLINE_METHOD: + buff = "inline[0x%x]" % value + + # FIXME: depends of the android version ... + if len(INLINE_METHODS) > value: + elem = INLINE_METHODS[value] + buff += " %s->%s%s" % (elem[0], elem[1], elem[2]) + + return buff + + return None + + +class Instruction(object): + """ + This class represents a dalvik instruction + """ + def get_kind(self): + """ + Return the 'kind' argument of the instruction + + :rtype: int + """ + if self.OP > 0xff: + if self.OP >= 0xf2ff: + return DALVIK_OPCODES_OPTIMIZED[self.OP][1][1] + return DALVIK_OPCODES_EXTENDED_WIDTH[self.OP][1][1] + return DALVIK_OPCODES_FORMAT[self.OP][1][1] + + def get_name(self): + """ + Return the name of the instruction + + :rtype: string + """ + if self.OP > 0xff: + if self.OP >= 0xf2ff: + return DALVIK_OPCODES_OPTIMIZED[self.OP][1][0] + return DALVIK_OPCODES_EXTENDED_WIDTH[self.OP][1][0] + return DALVIK_OPCODES_FORMAT[self.OP][1][0] + + def get_op_value(self): + """ + Return the value of the opcode + + :rtype: int + """ + return self.OP + + def get_literals(self): + """ + Return the associated literals + + :rtype: list of int + """ + return [] + + def show(self, idx): + """ + Print the instruction + """ + print self.get_name() + " " + self.get_output(idx), + + def show_buff(self, idx): + """ + Return the display of the instruction + + :rtype: string + """ + return self.get_output(idx) + + def get_translated_kind(self): + """ + Return the translated value of the 'kind' argument + + :rtype: string + """ + return get_kind(self.cm, self.get_kind(), self.get_ref_kind()) + + def get_output(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + raise("not implemented") + + def get_operands(self, idx=-1): + """ + Return all operands + + :rtype: list + """ + raise("not implemented") + + def get_length(self): + """ + Return the length of the instruction + + :rtype: int + """ + raise("not implemented") + + def get_raw(self): + """ + Return the object in a raw format + + :rtype: string + """ + raise("not implemented") + + def get_ref_kind(self): + """ + Return the value of the 'kind' argument + + :rtype: value + """ + raise("not implemented") + + def get_formatted_operands(self): + return None + + +class InstructionInvalid(Instruction): + """ + This class represents an invalid instruction + """ + def __init__(self, cm, buff): + super(InstructionInvalid, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + + #debug("OP:%x" % (self.OP)) + + def get_name(self): + """ + Return the name of the instruction + + :rtype: string + """ + return "AG:invalid_instruction" + + def get_output(self, idx=-1): + return "(OP:%x)" % self.OP + + def get_operands(self, idx=-1): + return [] + + def get_length(self): + return 2 + + def get_raw(self): + return pack("=H", self.OP) + + +class FillArrayData: + """ + This class can parse a FillArrayData instruction + + :param buff: a Buff object which represents a buffer where the instruction is stored + """ + def __init__(self, buff): + self.notes = [] + + self.format_general_size = calcsize("=HHI") + self.ident = unpack("=H", buff[0:2])[0] + self.element_width = unpack("=H", buff[2:4])[0] + self.size = unpack("=I", buff[4:8])[0] + + self.data = buff[self.format_general_size:self.format_general_size + (self.size * self.element_width) + 1] + + def add_note(self, msg): + """ + Add a note to this instruction + + :param msg: the message + :type msg: objects (string) + """ + self.notes.append(msg) + + def get_notes(self): + """ + Get all notes from this instruction + + :rtype: a list of objects + """ + return self.notes + + def get_op_value(self): + """ + Get the value of the opcode + + :rtype: int + """ + return self.ident + + def get_data(self): + """ + Return the data of this instruction (the payload) + + :rtype: string + """ + return self.data + + def get_output(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + buff = "" + + data = self.get_data() + + buff += repr(data) + " | " + for i in xrange(0, len(data)): + buff += "\\x%02x" % ord(data[i]) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_RAW, repr(self.get_data()))] + + def get_formatted_operands(self): + return None + + def get_name(self): + """ + Return the name of the instruction + + :rtype: string + """ + return "fill-array-data-payload" + + def show_buff(self, pos): + """ + Return the display of the instruction + + :rtype: string + """ + buff = self.get_name() + " " + + for i in xrange(0, len(self.data)): + buff += "\\x%02x" % ord(self.data[i]) + return buff + + def show(self, pos): + """ + Print the instruction + """ + print self.show_buff(pos), + + def get_length(self): + """ + Return the length of the instruction + + :rtype: int + """ + return ((self.size * self.element_width + 1) / 2 + 4) * 2 + + def get_raw(self): + return pack("=H", self.ident) + pack("=H", self.element_width) + pack("=I", self.size) + self.data + + +class SparseSwitch: + """ + This class can parse a SparseSwitch instruction + + :param buff: a Buff object which represents a buffer where the instruction is stored + """ + def __init__(self, buff): + self.notes = [] + + self.format_general_size = calcsize("=HH") + self.ident = unpack("=H", buff[0:2])[0] + self.size = unpack("=H", buff[2:4])[0] + + self.keys = [] + self.targets = [] + + idx = self.format_general_size + for i in xrange(0, self.size): + self.keys.append(unpack('=l', buff[idx:idx + 4])[0]) + idx += 4 + + for i in xrange(0, self.size): + self.targets.append(unpack('=l', buff[idx:idx + 4])[0]) + idx += 4 + + def add_note(self, msg): + """ + Add a note to this instruction + + :param msg: the message + :type msg: objects (string) + """ + self.notes.append(msg) + + def get_notes(self): + """ + Get all notes from this instruction + + :rtype: a list of objects + """ + return self.notes + + def get_op_value(self): + """ + Get the value of the opcode + + :rtype: int + """ + return self.ident + + def get_keys(self): + """ + Return the keys of the instruction + + :rtype: a list of long + """ + return self.keys + + def get_values(self): + return self.get_keys() + + def get_targets(self): + """ + Return the targets (address) of the instruction + + :rtype: a list of long + """ + return self.targets + + def get_output(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + return " ".join("%x" % i for i in self.keys) + + def get_operands(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + return [] + + def get_formatted_operands(self): + return None + + def get_name(self): + """ + Return the name of the instruction + + :rtype: string + """ + return "sparse-switch-payload" + + def show_buff(self, pos): + """ + Return the display of the instruction + + :rtype: string + """ + buff = self.get_name() + " " + for i in xrange(0, len(self.keys)): + buff += "%x:%x " % (self.keys[i], self.targets[i]) + + return buff + + def show(self, pos): + """ + Print the instruction + """ + print self.show_buff(pos), + + def get_length(self): + return self.format_general_size + (self.size * calcsize(' len(buff): + max_size = len(buff) - idx - 8 + + for i in xrange(0, max_size): + self.targets.append(unpack('=l', buff[idx:idx + 4])[0]) + idx += 4 + + def add_note(self, msg): + """ + Add a note to this instruction + + :param msg: the message + :type msg: objects (string) + """ + self.notes.append(msg) + + def get_notes(self): + """ + Get all notes from this instruction + + :rtype: a list of objects + """ + return self.notes + + def get_op_value(self): + """ + Get the value of the opcode + + :rtype: int + """ + return self.ident + + def get_keys(self): + """ + Return the keys of the instruction + + :rtype: a list of long + """ + return [(self.first_key + i) for i in range(0, len(self.targets))] + + def get_values(self): + return self.get_keys() + + def get_targets(self): + """ + Return the targets (address) of the instruction + + :rtype: a list of long + """ + return self.targets + + def get_output(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + return " ".join("%x" % (self.first_key + i) for i in range(0, len(self.targets))) + + def get_operands(self, idx=-1): + """ + Return an additional output of the instruction + + :rtype: string + """ + return [] + + def get_formatted_operands(self): + return None + + def get_name(self): + """ + Return the name of the instruction + + :rtype: string + """ + return "packed-switch-payload" + + def show_buff(self, pos): + """ + Return the display of the instruction + + :rtype: string + """ + buff = self.get_name() + " " + buff += "%x:" % self.first_key + + for i in self.targets: + buff += " %x" % i + + return buff + + def show(self, pos): + """ + Print the instruction + """ + print self.show_buff(pos), + + def get_length(self): + return self.format_general_size + (self.size * calcsize('=L')) + + def get_raw(self): + return pack("=H", self.ident) + pack("=H", self.size) + pack("=i", self.first_key) + ''.join(pack("=l", i) for i in self.targets) + + +class Instruction35c(Instruction): + """ + This class represents all instructions which have the 35c format + """ + def __init__(self, cm, buff): + super(Instruction35c, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.G = (i16 >> 8) & 0xf + self.A = (i16 >> 12) & 0xf + self.BBBB = unpack("=H", buff[2:4])[0] + + i16 = unpack("=H", buff[4:6])[0] + self.C = i16 & 0xf + self.D = (i16 >> 4) & 0xf + self.E = (i16 >> 8) & 0xf + self.F = (i16 >> 12) & 0xf + + def get_output(self, idx=-1): + buff = "" + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 0: + buff += "%s" % (kind) + elif self.A == 1: + buff += "v%d, %s" % (self.C, kind) + elif self.A == 2: + buff += "v%d, v%d, %s" % (self.C, self.D, kind) + elif self.A == 3: + buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind) + elif self.A == 4: + buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind) + elif self.A == 5: + buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind) + + return buff + + def get_operands(self, idx=-1): + l = [] + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 0: + l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind)) + elif self.A == 1: + l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 2: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 3: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 4: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 5: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + + return l + + def get_length(self): + return 6 + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C) + + +class Instruction10x(Instruction): + """ + This class represents all instructions which have the 10x format + """ + def __init__(self, cm, buff): + super(Instruction10x, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + + #log_andro.debug("OP:%x %s" % (self.OP, args[0])) + + def get_output(self, idx=-1): + return "" + + def get_operands(self, idx=-1): + return [] + + def get_length(self): + return 2 + + def get_raw(self): + return pack("=H", self.OP) + + +class Instruction21h(Instruction): + """ + This class represents all instructions which have the 21h format + """ + def __init__(self, cm, buff): + super(Instruction21h, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=h", buff[2:4])[0] + + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + self.formatted_operands = [] + + if self.OP == 0x15: + self.formatted_operands.append(unpack('=f', '\x00\x00' + pack('=h', self.BBBB))[0]) + elif self.OP == 0x19: + self.formatted_operands.append(unpack('=d', '\x00\x00\x00\x00\x00\x00' + pack('=h', self.BBBB))[0]) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, %d" % (self.AA, self.BBBB) + + if self.formatted_operands != []: + buff += " # %s" % (str(self.formatted_operands)) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBB)] + + def get_formatted_operands(self): + return self.formatted_operands + + def get_literals(self): + return [self.BBBB] + + def get_raw(self): + return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction11n(Instruction): + """ + This class represents all instructions which have the 11n format + """ + def __init__(self, cm, buff): + super(Instruction11n, self).__init__() + + i16 = unpack("=h", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) + + #log_andro.debug("OP:%x %s A:%x B:%x" % (self.OP, args[0], self.A, self.B)) + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, %d" % (self.A, self.B) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.A), (OPERAND_LITERAL, self.B)] + + def get_literals(self): + return [self.B] + + def get_length(self): + return 2 + + def get_raw(self): + return pack("=h", (self.B << 12) | (self.A << 8) | self.OP) + + +class Instruction21c(Instruction): + """ + This class represents all instructions which have the 21c format + """ + def __init__(self, cm, buff): + super(Instruction21c, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + buff += "v%d, %s" % (self.AA, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + return [(OPERAND_REGISTER, self.AA), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)] + + def get_ref_kind(self): + return self.BBBB + + def get_string(self): + return get_kind(self.cm, self.get_kind(), self.BBBB) + + def get_raw_string(self): + return get_kind(self.cm, KIND_RAW_STRING, self.BBBB) + + def get_raw(self): + return pack("=HH", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction21s(Instruction): + """ + This class represents all instructions which have the 21s format + """ + def __init__(self, cm, buff): + super(Instruction21s, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=h", buff[2:4])[0] + + self.formatted_operands = [] + + if self.OP == 0x16: + self.formatted_operands.append(unpack('=d', pack('=d', self.BBBB))[0]) + + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, %d" % (self.AA, self.BBBB) + + if self.formatted_operands != []: + buff += " # %s" % str(self.formatted_operands) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBB)] + + def get_literals(self): + return [self.BBBB] + + def get_formatted_operands(self): + return self.formatted_operands + + def get_raw(self): + return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction22c(Instruction): + """ + This class represents all instructions which have the 22c format + """ + def __init__(self, cm, buff): + super(Instruction22c, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) & 0xf + self.CCCC = unpack("=H", buff[2:4])[0] + + #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + kind = get_kind(self.cm, self.get_kind(), self.CCCC) + buff += "v%d, v%d, %s" % (self.A, self.B, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.CCCC) + return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (self.get_kind() + OPERAND_KIND, self.CCCC, kind)] + + def get_ref_kind(self): + return self.CCCC + + def get_raw(self): + return pack("=HH", (self.B << 12) | (self.A << 8) | (self.OP), self.CCCC) + + +class Instruction22cs(Instruction): + """ + This class represents all instructions which have the 22cs format + """ + def __init__(self, cm, buff): + super(Instruction22cs, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) & 0xf + self.CCCC = unpack("=H", buff[2:4])[0] + + #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + kind = get_kind(self.cm, self.get_kind(), self.CCCC) + buff += "v%d, v%d, %s" % (self.A, self.B, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.CCCC) + return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (self.get_kind() + OPERAND_KIND, self.CCCC, kind)] + + def get_ref_kind(self): + return self.CCCC + + def get_raw(self): + return pack("=HH", (self.B << 12) | (self.A << 8) | (self.OP), self.CCCC) + + +class Instruction31t(Instruction): + """ + This class represents all instructions which have the 31t format + """ + def __init__(self, cm, buff): + super(Instruction31t, self).__init__() + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBBBBBB = unpack("=i", buff[2:6])[0] + #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, +%x (0x%x)" % (self.AA, self.BBBBBBBB, self.BBBBBBBB * 2 + idx) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBB)] + + def get_ref_off(self): + return self.BBBBBBBB + + def get_raw(self): + return pack("=Hi", (self.AA << 8) | self.OP, self.BBBBBBBB) + + +class Instruction31c(Instruction): + """ + This class represents all instructions which have the 31c format + """ + def __init__(self, cm, buff): + super(Instruction31c, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBBBBBB = unpack("=I", buff[2:6])[0] + #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + buff += "v%d, %s" % (self.AA, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + return [(OPERAND_REGISTER, self.AA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)] + + def get_ref_kind(self): + return self.BBBBBBBB + + def get_string(self): + """ + Return the string associated to the 'kind' argument + + :rtype: string + """ + return get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + + def get_raw_string(self): + return get_kind(self.cm, KIND_RAW_STRING, self.BBBBBBBB) + + def get_raw(self): + return pack("=HI", (self.AA << 8) | self.OP, self.BBBBBBBB) + + +class Instruction12x(Instruction): + """ + This class represents all instructions which have the 12x format + """ + def __init__(self, cm, buff): + super(Instruction12x, self).__init__() + + i16 = unpack("=h", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) & 0xf + + #log_andro.debug("OP:%x %s A:%x B:%x" % (self.OP, args[0], self.A, self.B)) + + def get_length(self): + return 2 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d" % (self.A, self.B) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B)] + + def get_raw(self): + return pack("=H", (self.B << 12) | (self.A << 8) | (self.OP)) + + +class Instruction11x(Instruction): + """ + This class represents all instructions which have the 11x format + """ + def __init__(self, cm, buff): + super(Instruction11x, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + #log_andro.debug("OP:%x %s AA:%x" % (self.OP, args[0], self.AA)) + + def get_length(self): + return 2 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d" % (self.AA) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA)] + + def get_raw(self): + return pack("=H", (self.AA << 8) | self.OP) + + +class Instruction51l(Instruction): + """ + This class represents all instructions which have the 51l format + """ + def __init__(self, cm, buff): + super(Instruction51l, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBBBBBBBBBBBBBB = unpack("=q", buff[2:10])[0] + + self.formatted_operands = [] + + if self.OP == 0x18: + self.formatted_operands.append(unpack('=d', pack('=q', self.BBBBBBBBBBBBBBBB))[0]) + + #log_andro.debug("OP:%x %s AA:%x BBBBBBBBBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBBBBBBBBBB)) + + def get_length(self): + return 10 + + def get_output(self, idx=-1): + buff = "" + + buff += "v%d, %d" % (self.AA, self.BBBBBBBBBBBBBBBB) + + if self.formatted_operands: + buff += " # %s" % str(self.formatted_operands) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBBBBBBBBBB)] + + def get_formatted_operands(self): + return self.formatted_operands + + def get_literals(self): + return [self.BBBBBBBBBBBBBBBB] + + def get_raw(self): + return pack("=Hq", (self.AA << 8) | self.OP, self.BBBBBBBBBBBBBBBB) + + +class Instruction31i(Instruction): + """ + This class represents all instructions which have the 3li format + """ + def __init__(self, cm, buff): + super(Instruction31i, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBBBBBB = unpack("=i", buff[2:6])[0] + + self.formatted_operands = [] + + if self.OP == 0x14: + self.formatted_operands.append(unpack("=f", pack("=i", self.BBBBBBBB))[0]) + + elif self.OP == 0x17: + self.formatted_operands.append(unpack('=d', pack('=d', self.BBBBBBBB))[0]) + + #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, %d" % (self.AA, self.BBBBBBBB) + + if self.formatted_operands: + buff += " # %s" % str(self.formatted_operands) + + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBB)] + + def get_formatted_operands(self): + return self.formatted_operands + + def get_literals(self): + return [self.BBBBBBBB] + + def get_raw(self): + return pack("=Hi", (self.AA << 8) | self.OP, self.BBBBBBBB) + + +class Instruction22x(Instruction): + """ + This class represents all instructions which have the 22x format + """ + def __init__(self, cm, buff): + super(Instruction22x, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d" % (self.AA, self.BBBB) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BBBB)] + + def get_raw(self): + return pack("=HH", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction23x(Instruction): + """ + This class represents all instructions which have the 23x format + """ + def __init__(self, cm, buff): + super(Instruction23x, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + i16 = unpack("=H", buff[2:4])[0] + self.BB = i16 & 0xff + self.CC = (i16 >> 8) & 0xff + + #log_andro.debug("OP:%x %s AA:%x BB:%x CC:%x" % (self.OP, args[0], self.AA, self.BB, self.CC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d, v%d" % (self.AA, self.BB, self.CC) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BB), (OPERAND_REGISTER, self.CC)] + + def get_raw(self): + return pack("=HH", (self.AA << 8) | self.OP, (self.CC << 8) | self.BB) + + +class Instruction20t(Instruction): + """ + This class represents all instructions which have the 20t format + """ + def __init__(self, cm, buff): + super(Instruction20t, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AAAA = unpack("=h", buff[2:4])[0] + + #log_andro.debug("OP:%x %s AAAA:%x" % (self.OP, args[0], self.AAAA)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "%+x" % (self.AAAA) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_OFFSET, self.AAAA)] + + def get_ref_off(self): + return self.AAAA + + def get_raw(self): + return pack("=Hh", self.OP, self.AAAA) + + +class Instruction21t(Instruction): + """ + This class represents all instructions which have the 21t format + """ + def __init__(self, cm, buff): + super(Instruction21t, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=h", buff[2:4])[0] + + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, %+x" % (self.AA, self.BBBB) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_OFFSET, self.BBBB)] + + def get_ref_off(self): + return self.BBBB + + def get_raw(self): + return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction10t(Instruction): + """ + This class represents all instructions which have the 10t format + """ + def __init__(self, cm, buff): + super(Instruction10t, self).__init__() + + self.OP = unpack("=B", buff[0:1])[0] + self.AA = unpack("=b", buff[1:2])[0] + + #log_andro.debug("OP:%x %s AA:%x" % (self.OP, args[0], self.AA)) + + def get_length(self): + return 2 + + def get_output(self, idx=-1): + buff = "" + buff += "%+x" % (self.AA) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_OFFSET, self.AA)] + + def get_ref_off(self): + return self.AA + + def get_raw(self): + return pack("=Bb", self.OP, self.AA) + + +class Instruction22t(Instruction): + """ + This class represents all instructions which have the 22t format + """ + def __init__(self, cm, buff): + super(Instruction22t, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) & 0xf + self.CCCC = unpack("=h", buff[2:4])[0] + + #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d, %+x" % (self.A, self.B, self.CCCC) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (OPERAND_OFFSET, self.CCCC)] + + def get_ref_off(self): + return self.CCCC + + def get_raw(self): + return pack("=Hh", (self.B << 12) | (self.A << 8) | self.OP, self.CCCC) + + +class Instruction22s(Instruction): + """ + This class represents all instructions which have the 22s format + """ + def __init__(self, cm, buff): + super(Instruction22s, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.A = (i16 >> 8) & 0xf + self.B = (i16 >> 12) & 0xf + self.CCCC = unpack("=h", buff[2:4])[0] + + #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d, %d" % (self.A, self.B, self.CCCC) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (OPERAND_LITERAL, self.CCCC)] + + def get_literals(self): + return [self.CCCC] + + def get_raw(self): + return pack("=Hh", (self.B << 12) | (self.A << 8) | self.OP, self.CCCC) + + +class Instruction22b(Instruction): + """ + This class represents all instructions which have the 22b format + """ + def __init__(self, cm, buff): + super(Instruction22b, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BB = unpack("=B", buff[2:3])[0] + self.CC = unpack("=b", buff[3:4])[0] + + #log_andro.debug("OP:%x %s AA:%x BB:%x CC:%x" % (self.OP, args[0], self.AA, self.BB, self.CC)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d, %d" % (self.AA, self.BB, self.CC) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BB), (OPERAND_LITERAL, self.CC)] + + def get_literals(self): + return [self.CC] + + def get_raw(self): + return pack("=Hh", (self.AA << 8) | self.OP, (self.CC << 8) | self.BB) + + +class Instruction30t(Instruction): + """ + This class represents all instructions which have the 30t format + """ + def __init__(self, cm, buff): + super(Instruction30t, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + + self.AAAAAAAA = unpack("=i", buff[2:6])[0] + + #log_andro.debug("OP:%x %s AAAAAAAA:%x" % (self.OP, args[0], self.AAAAAAAA)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + buff += "%+x" % (self.AAAAAAAA) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_OFFSET, self.AAAAAAAA)] + + def get_ref_off(self): + return self.AAAAAAAA + + def get_raw(self): + return pack("=Hi", self.OP, self.AAAAAAAA) + + +class Instruction3rc(Instruction): + """ + This class represents all instructions which have the 3rc format + """ + def __init__(self, cm, buff): + super(Instruction3rc, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + self.CCCC = unpack("=H", buff[4:6])[0] + + self.NNNN = self.CCCC + self.AA - 1 + + #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN: + buff += "v%d, %s" % (self.CCCC, kind) + else: + buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN: + return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)] + else: + l = [] + for i in range(self.CCCC, self.NNNN): + l.append((OPERAND_REGISTER, i)) + + l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind)) + return l + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC) + + +class Instruction32x(Instruction): + """ + This class represents all instructions which have the 32x format + """ + def __init__(self, cm, buff): + super(Instruction32x, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AAAA = unpack("=H", buff[2:4])[0] + self.BBBB = unpack("=H", buff[4:6])[0] + + #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBB)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + buff += "v%d, v%d" % (self.AAAA, self.BBBB) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_REGISTER, self.AAAA), (OPERAND_REGISTER, self.BBBB)] + + def get_raw(self): + return pack("=HHH", self.OP, self.AAAA, self.BBBB) + + +class Instruction20bc(Instruction): + """ + This class represents all instructions which have the 20bc format + """ + def __init__(self, cm, buff): + super(Instruction20bc, self).__init__() + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + + #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB)) + + def get_length(self): + return 4 + + def get_output(self, idx=-1): + buff = "" + buff += "%d, %d" % (self.AA, self.BBBB) + return buff + + def get_operands(self, idx=-1): + return [(OPERAND_LITERAL, self.AA), (OPERAND_LITERAL, self.BBBB)] + + def get_raw(self): + return pack("=HH", (self.AA << 8) | self.OP, self.BBBB) + + +class Instruction35mi(Instruction): + """ + This class represents all instructions which have the 35mi format + """ + def __init__(self, cm, buff): + super(Instruction35mi, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.G = (i16 >> 8) & 0xf + self.A = (i16 >> 12) & 0xf + self.BBBB = unpack("=H", buff[2:4])[0] + + i16 = unpack("=H", buff[4:6])[0] + self.C = i16 & 0xf + self.D = (i16 >> 4) & 0xf + self.E = (i16 >> 8) & 0xf + self.F = (i16 >> 12) & 0xf + + #log_andro.debug("OP:%x %s G:%x A:%x BBBB:%x C:%x D:%x E:%x F:%x" % (self.OP, args[0], self.G, self.A, self.BBBB, self.C, self.D, self.E, self.F)) + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 1: + buff += "v%d, %s" % (self.C, kind) + elif self.A == 2: + buff += "v%d, v%d, %s" % (self.C, self.D, kind) + elif self.A == 3: + buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind) + elif self.A == 4: + buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind) + elif self.A == 5: + buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind) + + return buff + + def get_operands(self, idx=-1): + l = [] + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 1: + l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 2: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 3: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 4: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 5: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + + return l + + def get_length(self): + return 6 + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C) + + +class Instruction35ms(Instruction): + """ + This class represents all instructions which have the 35ms format + """ + def __init__(self, cm, buff): + super(Instruction35ms, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.G = (i16 >> 8) & 0xf + self.A = (i16 >> 12) & 0xf + self.BBBB = unpack("=H", buff[2:4])[0] + + i16 = unpack("=H", buff[4:6])[0] + self.C = i16 & 0xf + self.D = (i16 >> 4) & 0xf + self.E = (i16 >> 8) & 0xf + self.F = (i16 >> 12) & 0xf + + #log_andro.debug("OP:%x %s G:%x A:%x BBBB:%x C:%x D:%x E:%x F:%x" % (self.OP, args[0], self.G, self.A, self.BBBB, self.C, self.D, self.E, self.F)) + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 1: + buff += "v%d, %s" % (self.C, kind) + elif self.A == 2: + buff += "v%d, v%d, %s" % (self.C, self.D, kind) + elif self.A == 3: + buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind) + elif self.A == 4: + buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind) + elif self.A == 5: + buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind) + + return buff + + def get_operands(self, idx=-1): + l = [] + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.A == 1: + l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 2: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 3: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 4: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + elif self.A == 5: + l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]) + + return l + + def get_length(self): + return 6 + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C) + + +class Instruction3rmi(Instruction): + """ + This class represents all instructions which have the 3rmi format + """ + def __init__(self, cm, buff): + super(Instruction3rmi, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + self.CCCC = unpack("=H", buff[4:6])[0] + + self.NNNN = self.CCCC + self.AA - 1 + + #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN: + buff += "v%d, %s" % (self.CCCC, kind) + else: + buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN: + return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)] + else: + l = [] + for i in range(self.CCCC, self.NNNN): + l.append((OPERAND_REGISTER, i)) + + l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind)) + return l + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC) + + +class Instruction3rms(Instruction): + """ + This class represents all instructions which have the 3rms format + """ + def __init__(self, cm, buff): + super(Instruction3rms, self).__init__() + self.cm = cm + + i16 = unpack("=H", buff[0:2])[0] + self.OP = i16 & 0xff + self.AA = (i16 >> 8) & 0xff + + self.BBBB = unpack("=H", buff[2:4])[0] + self.CCCC = unpack("=H", buff[4:6])[0] + + self.NNNN = self.CCCC + self.AA - 1 + + #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN)) + + def get_length(self): + return 6 + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN : + buff += "v%d, %s" % (self.CCCC, kind) + else : + buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBB) + + if self.CCCC == self.NNNN: + return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)] + else: + l = [] + for i in range(self.CCCC, self.NNNN): + l.append((OPERAND_REGISTER, i)) + + l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind)) + return l + + def get_ref_kind(self): + return self.BBBB + + def get_raw(self): + return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC) + + +class Instruction41c(Instruction): + """ + This class represents all instructions which have the 41c format + """ + def __init__(self, cm, buff): + super(Instruction41c, self).__init__() + self.cm = cm + + self.OP = unpack("=H", buff[0:2])[0] + self.BBBBBBBB = unpack("=I", buff[2:6])[0] + + self.AAAA = unpack("=H", buff[6:8])[0] + + #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBBBBBB)) + + def get_length(self): + return 8 + + def get_output(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + + buff = "" + buff += "v%d, %s" % (self.AAAA, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + return [(OPERAND_REGISTER, self.AAAA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)] + + def get_ref_kind(self): + return self.BBBBBBBB + + def get_raw(self): + return pack("=HIH", self.OP, self.BBBBBBBB, self.AAAA) + + +class Instruction40sc(Instruction): + """ + This class represents all instructions which have the 40sc format + """ + def __init__(self, cm, buff): + super(Instruction40sc, self).__init__() + self.cm = cm + + self.OP = unpack("=H", buff[0:2])[0] + self.BBBBBBBB = unpack("=I", buff[2:6])[0] + self.AAAA = unpack("=H", buff[6:8])[0] + + #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBBBBBB)) + + def get_length(self): + return 8 + + def get_output(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + + buff = "" + buff += "%d, %s" % (self.AAAA, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + return [(OPERAND_LITERAL, self.AAAA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)] + + def get_ref_kind(self): + return self.BBBBBBBB + + def get_raw(self): + return pack("=HIH", self.OP, self.BBBBBBBB, self.AAAA) + + +class Instruction52c(Instruction): + """ + This class represents all instructions which have the 52c format + """ + def __init__(self, cm, buff): + super(Instruction52c, self).__init__() + self.cm = cm + + self.OP = unpack("=H", buff[0:2])[0] + self.CCCCCCCC = unpack("=I", buff[2:6])[0] + self.AAAA = unpack("=H", buff[6:8])[0] + self.BBBB = unpack("=H", buff[8:10])[0] + + #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBB)) + + def get_length(self): + return 10 + + def get_output(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC) + + buff = "" + buff += "v%d, v%d, %s" % (self.AAAA, self.BBBB, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC) + return [(OPERAND_LITERAL, self.AAAA), (OPERAND_LITERAL, self.BBBB), (self.get_kind() + OPERAND_KIND, self.CCCCCCCC, kind)] + + def get_ref_kind(self): + return self.CCCCCCCC + + def get_raw(self): + return pack("=HIHH", self.OP, self.CCCCCCCC, self.AAAA, self.BBBB) + + +class Instruction5rc(Instruction): + """ + This class represents all instructions which have the 5rc format + """ + def __init__(self, cm, buff): + super(Instruction5rc, self).__init__() + self.cm = cm + + self.OP = unpack("=H", buff[0:2])[0] + self.BBBBBBBB = unpack("=I", buff[2:6])[0] + self.AAAA = unpack("=H", buff[6:8])[0] + self.CCCC = unpack("=H", buff[8:10])[0] + + self.NNNN = self.CCCC + self.AAAA - 1 + + #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AAAA, self.BBBBBBBB, self.CCCC, self.NNNN)) + + def get_length(self): + return 10 + + def get_output(self, idx=-1): + buff = "" + + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + + if self.CCCC == self.NNNN: + buff += "v%d, %s" % (self.CCCC, kind) + else: + buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind) + return buff + + def get_operands(self, idx=-1): + kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB) + + if self.CCCC == self.NNNN: + return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)] + else: + l = [] + for i in range(self.CCCC, self.NNNN): + l.append((OPERAND_REGISTER, i)) + + l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind)) + return l + + def get_ref_kind(self): + return self.BBBBBBBB + + def get_raw(self): + return pack("=HIHH", self.OP, self.BBBBBBBB, self.AAAA, self.CCCC) + + +DALVIK_OPCODES_FORMAT = { + 0x00 : [Instruction10x, [ "nop" ] ], + 0x01 : [Instruction12x, [ "move" ] ], + 0x02 : [Instruction22x, [ "move/from16" ] ], + 0x03 : [Instruction32x, [ "move/16" ] ], + 0x04 : [Instruction12x, [ "move-wide" ] ], + 0x05 : [Instruction22x, [ "move-wide/from16" ] ], + 0x06 : [Instruction32x, [ "move-wide/16" ] ], + 0x07 : [Instruction12x, [ "move-object" ] ], + 0x08 : [Instruction22x, [ "move-object/from16" ] ], + 0x09 : [Instruction32x, [ "move-object/16" ] ], + 0x0a : [Instruction11x, [ "move-result" ] ], + 0x0b : [Instruction11x, [ "move-result-wide" ] ], + 0x0c : [Instruction11x, [ "move-result-object" ] ], + 0x0d : [Instruction11x, [ "move-exception" ] ], + 0x0e : [Instruction10x, [ "return-void" ] ], + 0x0f : [Instruction11x, [ "return" ] ], + 0x10 : [Instruction11x, [ "return-wide" ] ], + 0x11 : [Instruction11x, [ "return-object" ] ], + 0x12 : [Instruction11n, [ "const/4" ] ], + 0x13 : [Instruction21s, [ "const/16" ] ], + 0x14 : [Instruction31i, [ "const" ] ], + 0x15 : [Instruction21h, [ "const/high16" ] ], + 0x16 : [Instruction21s, [ "const-wide/16" ] ], + 0x17 : [Instruction31i, [ "const-wide/32" ] ], + 0x18 : [Instruction51l, [ "const-wide" ] ], + 0x19 : [Instruction21h, [ "const-wide/high16" ] ], + 0x1a : [Instruction21c, [ "const-string", KIND_STRING ] ], + 0x1b : [Instruction31c, [ "const-string/jumbo", KIND_STRING ] ], + 0x1c : [Instruction21c, [ "const-class", KIND_TYPE ] ], + 0x1d : [Instruction11x, [ "monitor-enter" ] ], + 0x1e : [Instruction11x, [ "monitor-exit" ] ], + 0x1f : [Instruction21c, [ "check-cast", KIND_TYPE ] ], + 0x20 : [Instruction22c, [ "instance-of", KIND_TYPE ] ], + 0x21 : [Instruction12x, [ "array-length", KIND_TYPE ] ], + 0x22 : [Instruction21c, [ "new-instance", KIND_TYPE ] ], + 0x23 : [Instruction22c, [ "new-array", KIND_TYPE ] ], + + 0x24 : [Instruction35c, [ "filled-new-array", KIND_TYPE ] ], + 0x25 : [Instruction3rc, [ "filled-new-array/range", KIND_TYPE ] ], + 0x26 : [Instruction31t, [ "fill-array-data" ] ], + + 0x27 : [Instruction11x, [ "throw" ] ], + + 0x28 : [Instruction10t, [ "goto" ] ], + 0x29 : [Instruction20t, [ "goto/16" ] ], + 0x2a : [Instruction30t, [ "goto/32" ] ], + + 0x2b : [Instruction31t, [ "packed-switch" ] ], + 0x2c : [Instruction31t, [ "sparse-switch" ] ], + + 0x2d : [Instruction23x, [ "cmpl-float" ] ], + 0x2e : [Instruction23x, [ "cmpg-float" ] ], + 0x2f : [Instruction23x, [ "cmpl-double" ] ], + 0x30 : [Instruction23x, [ "cmpg-double" ] ], + 0x31 : [Instruction23x, [ "cmp-long" ] ], + + 0x32 : [Instruction22t, [ "if-eq" ] ], + 0x33 : [Instruction22t, [ "if-ne" ] ], + 0x34 : [Instruction22t, [ "if-lt" ] ], + 0x35 : [Instruction22t, [ "if-ge" ] ], + 0x36 : [Instruction22t, [ "if-gt" ] ], + 0x37 : [Instruction22t, [ "if-le" ] ], + + 0x38 : [Instruction21t, [ "if-eqz" ] ], + 0x39 : [Instruction21t, [ "if-nez" ] ], + 0x3a : [Instruction21t, [ "if-ltz" ] ], + 0x3b : [Instruction21t, [ "if-gez" ] ], + 0x3c : [Instruction21t, [ "if-gtz" ] ], + 0x3d : [Instruction21t, [ "if-lez" ] ], + + #unused + 0x3e : [Instruction10x, [ "nop" ] ], + 0x3f : [Instruction10x, [ "nop" ] ], + 0x40 : [Instruction10x, [ "nop" ] ], + 0x41 : [Instruction10x, [ "nop" ] ], + 0x42 : [Instruction10x, [ "nop" ] ], + 0x43 : [Instruction10x, [ "nop" ] ], + + 0x44 : [Instruction23x, [ "aget" ] ], + 0x45 : [Instruction23x, [ "aget-wide" ] ], + 0x46 : [Instruction23x, [ "aget-object" ] ], + 0x47 : [Instruction23x, [ "aget-boolean" ] ], + 0x48 : [Instruction23x, [ "aget-byte" ] ], + 0x49 : [Instruction23x, [ "aget-char" ] ], + 0x4a : [Instruction23x, [ "aget-short" ] ], + 0x4b : [Instruction23x, [ "aput" ] ], + 0x4c : [Instruction23x, [ "aput-wide" ] ], + 0x4d : [Instruction23x, [ "aput-object" ] ], + 0x4e : [Instruction23x, [ "aput-boolean" ] ], + 0x4f : [Instruction23x, [ "aput-byte" ] ], + 0x50 : [Instruction23x, [ "aput-char" ] ], + 0x51 : [Instruction23x, [ "aput-short" ] ], + + 0x52 : [Instruction22c, [ "iget", KIND_FIELD ] ], + 0x53 : [Instruction22c, [ "iget-wide", KIND_FIELD ] ], + 0x54 : [Instruction22c, [ "iget-object", KIND_FIELD ] ], + 0x55 : [Instruction22c, [ "iget-boolean", KIND_FIELD ] ], + 0x56 : [Instruction22c, [ "iget-byte", KIND_FIELD ] ], + 0x57 : [Instruction22c, [ "iget-char", KIND_FIELD ] ], + 0x58 : [Instruction22c, [ "iget-short", KIND_FIELD ] ], + 0x59 : [Instruction22c, [ "iput", KIND_FIELD ] ], + 0x5a : [Instruction22c, [ "iput-wide", KIND_FIELD ] ], + 0x5b : [Instruction22c, [ "iput-object", KIND_FIELD ] ], + 0x5c : [Instruction22c, [ "iput-boolean", KIND_FIELD ] ], + 0x5d : [Instruction22c, [ "iput-byte", KIND_FIELD ] ], + 0x5e : [Instruction22c, [ "iput-char", KIND_FIELD ] ], + 0x5f : [Instruction22c, [ "iput-short", KIND_FIELD ] ], + + + 0x60 : [Instruction21c, [ "sget", KIND_FIELD ] ], + 0x61 : [Instruction21c, [ "sget-wide", KIND_FIELD ] ], + 0x62 : [Instruction21c, [ "sget-object", KIND_FIELD ] ], + 0x63 : [Instruction21c, [ "sget-boolean", KIND_FIELD ] ], + 0x64 : [Instruction21c, [ "sget-byte", KIND_FIELD ] ], + 0x65 : [Instruction21c, [ "sget-char", KIND_FIELD ] ], + 0x66 : [Instruction21c, [ "sget-short", KIND_FIELD ] ], + 0x67 : [Instruction21c, [ "sput", KIND_FIELD ] ], + 0x68 : [Instruction21c, [ "sput-wide", KIND_FIELD ] ], + 0x69 : [Instruction21c, [ "sput-object", KIND_FIELD ] ], + 0x6a : [Instruction21c, [ "sput-boolean", KIND_FIELD ] ], + 0x6b : [Instruction21c, [ "sput-byte", KIND_FIELD ] ], + 0x6c : [Instruction21c, [ "sput-char", KIND_FIELD ] ], + 0x6d : [Instruction21c, [ "sput-short", KIND_FIELD ] ], + + + 0x6e : [Instruction35c, [ "invoke-virtual", KIND_METH ] ], + 0x6f : [Instruction35c, [ "invoke-super", KIND_METH ] ], + 0x70 : [Instruction35c, [ "invoke-direct", KIND_METH ] ], + 0x71 : [Instruction35c, [ "invoke-static", KIND_METH ] ], + 0x72 : [Instruction35c, [ "invoke-interface", KIND_METH ] ], + + # unused + 0x73 : [Instruction10x, [ "nop" ] ], + + 0x74 : [Instruction3rc, [ "invoke-virtual/range", KIND_METH ] ], + 0x75 : [Instruction3rc, [ "invoke-super/range", KIND_METH ] ], + 0x76 : [Instruction3rc, [ "invoke-direct/range", KIND_METH ] ], + 0x77 : [Instruction3rc, [ "invoke-static/range", KIND_METH ] ], + 0x78 : [Instruction3rc, [ "invoke-interface/range", KIND_METH ] ], + + # unused + 0x79 : [Instruction10x, [ "nop" ] ], + 0x7a : [Instruction10x, [ "nop" ] ], + + + 0x7b : [Instruction12x, [ "neg-int" ] ], + 0x7c : [Instruction12x, [ "not-int" ] ], + 0x7d : [Instruction12x, [ "neg-long" ] ], + 0x7e : [Instruction12x, [ "not-long" ] ], + 0x7f : [Instruction12x, [ "neg-float" ] ], + 0x80 : [Instruction12x, [ "neg-double" ] ], + 0x81 : [Instruction12x, [ "int-to-long" ] ], + 0x82 : [Instruction12x, [ "int-to-float" ] ], + 0x83 : [Instruction12x, [ "int-to-double" ] ], + 0x84 : [Instruction12x, [ "long-to-int" ] ], + 0x85 : [Instruction12x, [ "long-to-float" ] ], + 0x86 : [Instruction12x, [ "long-to-double" ] ], + 0x87 : [Instruction12x, [ "float-to-int" ] ], + 0x88 : [Instruction12x, [ "float-to-long" ] ], + 0x89 : [Instruction12x, [ "float-to-double" ] ], + 0x8a : [Instruction12x, [ "double-to-int" ] ], + 0x8b : [Instruction12x, [ "double-to-long" ] ], + 0x8c : [Instruction12x, [ "double-to-float" ] ], + 0x8d : [Instruction12x, [ "int-to-byte" ] ], + 0x8e : [Instruction12x, [ "int-to-char" ] ], + 0x8f : [Instruction12x, [ "int-to-short" ] ], + + + 0x90 : [Instruction23x, [ "add-int" ] ], + 0x91 : [Instruction23x, [ "sub-int" ] ], + 0x92 : [Instruction23x, [ "mul-int" ] ], + 0x93 : [Instruction23x, [ "div-int" ] ], + 0x94 : [Instruction23x, [ "rem-int" ] ], + 0x95 : [Instruction23x, [ "and-int" ] ], + 0x96 : [Instruction23x, [ "or-int" ] ], + 0x97 : [Instruction23x, [ "xor-int" ] ], + 0x98 : [Instruction23x, [ "shl-int" ] ], + 0x99 : [Instruction23x, [ "shr-int" ] ], + 0x9a : [Instruction23x, [ "ushr-int" ] ], + 0x9b : [Instruction23x, [ "add-long" ] ], + 0x9c : [Instruction23x, [ "sub-long" ] ], + 0x9d : [Instruction23x, [ "mul-long" ] ], + 0x9e : [Instruction23x, [ "div-long" ] ], + 0x9f : [Instruction23x, [ "rem-long" ] ], + 0xa0 : [Instruction23x, [ "and-long" ] ], + 0xa1 : [Instruction23x, [ "or-long" ] ], + 0xa2 : [Instruction23x, [ "xor-long" ] ], + 0xa3 : [Instruction23x, [ "shl-long" ] ], + 0xa4 : [Instruction23x, [ "shr-long" ] ], + 0xa5 : [Instruction23x, [ "ushr-long" ] ], + 0xa6 : [Instruction23x, [ "add-float" ] ], + 0xa7 : [Instruction23x, [ "sub-float" ] ], + 0xa8 : [Instruction23x, [ "mul-float" ] ], + 0xa9 : [Instruction23x, [ "div-float" ] ], + 0xaa : [Instruction23x, [ "rem-float" ] ], + 0xab : [Instruction23x, [ "add-double" ] ], + 0xac : [Instruction23x, [ "sub-double" ] ], + 0xad : [Instruction23x, [ "mul-double" ] ], + 0xae : [Instruction23x, [ "div-double" ] ], + 0xaf : [Instruction23x, [ "rem-double" ] ], + + + 0xb0 : [Instruction12x, [ "add-int/2addr" ] ], + 0xb1 : [Instruction12x, [ "sub-int/2addr" ] ], + 0xb2 : [Instruction12x, [ "mul-int/2addr" ] ], + 0xb3 : [Instruction12x, [ "div-int/2addr" ] ], + 0xb4 : [Instruction12x, [ "rem-int/2addr" ] ], + 0xb5 : [Instruction12x, [ "and-int/2addr" ] ], + 0xb6 : [Instruction12x, [ "or-int/2addr" ] ], + 0xb7 : [Instruction12x, [ "xor-int/2addr" ] ], + 0xb8 : [Instruction12x, [ "shl-int/2addr" ] ], + 0xb9 : [Instruction12x, [ "shr-int/2addr" ] ], + 0xba : [Instruction12x, [ "ushr-int/2addr" ] ], + 0xbb : [Instruction12x, [ "add-long/2addr" ] ], + 0xbc : [Instruction12x, [ "sub-long/2addr" ] ], + 0xbd : [Instruction12x, [ "mul-long/2addr" ] ], + 0xbe : [Instruction12x, [ "div-long/2addr" ] ], + 0xbf : [Instruction12x, [ "rem-long/2addr" ] ], + 0xc0 : [Instruction12x, [ "and-long/2addr" ] ], + 0xc1 : [Instruction12x, [ "or-long/2addr" ] ], + 0xc2 : [Instruction12x, [ "xor-long/2addr" ] ], + 0xc3 : [Instruction12x, [ "shl-long/2addr" ] ], + 0xc4 : [Instruction12x, [ "shr-long/2addr" ] ], + 0xc5 : [Instruction12x, [ "ushr-long/2addr" ] ], + 0xc6 : [Instruction12x, [ "add-float/2addr" ] ], + 0xc7 : [Instruction12x, [ "sub-float/2addr" ] ], + 0xc8 : [Instruction12x, [ "mul-float/2addr" ] ], + 0xc9 : [Instruction12x, [ "div-float/2addr" ] ], + 0xca : [Instruction12x, [ "rem-float/2addr" ] ], + 0xcb : [Instruction12x, [ "add-double/2addr" ] ], + 0xcc : [Instruction12x, [ "sub-double/2addr" ] ], + 0xcd : [Instruction12x, [ "mul-double/2addr" ] ], + 0xce : [Instruction12x, [ "div-double/2addr" ] ], + 0xcf : [Instruction12x, [ "rem-double/2addr" ] ], + + 0xd0 : [Instruction22s, [ "add-int/lit16" ] ], + 0xd1 : [Instruction22s, [ "rsub-int" ] ], + 0xd2 : [Instruction22s, [ "mul-int/lit16" ] ], + 0xd3 : [Instruction22s, [ "div-int/lit16" ] ], + 0xd4 : [Instruction22s, [ "rem-int/lit16" ] ], + 0xd5 : [Instruction22s, [ "and-int/lit16" ] ], + 0xd6 : [Instruction22s, [ "or-int/lit16" ] ], + 0xd7 : [Instruction22s, [ "xor-int/lit16" ] ], + + + 0xd8 : [Instruction22b, [ "add-int/lit8" ] ], + 0xd9 : [Instruction22b, [ "rsub-int/lit8" ] ], + 0xda : [Instruction22b, [ "mul-int/lit8" ] ], + 0xdb : [Instruction22b, [ "div-int/lit8" ] ], + 0xdc : [Instruction22b, [ "rem-int/lit8" ] ], + 0xdd : [Instruction22b, [ "and-int/lit8" ] ], + 0xde : [Instruction22b, [ "or-int/lit8" ] ], + 0xdf : [Instruction22b, [ "xor-int/lit8" ] ], + 0xe0 : [Instruction22b, [ "shl-int/lit8" ] ], + 0xe1 : [Instruction22b, [ "shr-int/lit8" ] ], + 0xe2 : [Instruction22b, [ "ushr-int/lit8" ] ], + + + # expanded opcodes + 0xe3 : [Instruction22c, [ "iget-volatile", KIND_FIELD ] ], + 0xe4 : [Instruction22c, [ "iput-volatile", KIND_FIELD ] ], + 0xe5 : [Instruction21c, [ "sget-volatile", KIND_FIELD ] ], + 0xe6 : [Instruction21c, [ "sput-volatile", KIND_FIELD ] ], + 0xe7 : [Instruction22c, [ "iget-object-volatile", KIND_FIELD ] ], + 0xe8 : [Instruction22c, [ "iget-wide-volatile", KIND_FIELD ] ], + 0xe9 : [Instruction22c, [ "iput-wide-volatile", KIND_FIELD ] ], + 0xea : [Instruction21c, [ "sget-wide-volatile", KIND_FIELD ] ], + 0xeb : [Instruction21c, [ "sput-wide-volatile", KIND_FIELD ] ], + + 0xec : [Instruction10x, [ "breakpoint" ] ], + 0xed : [Instruction20bc, [ "throw-verification-error", VARIES ] ], + 0xee : [Instruction35mi, [ "execute-inline", INLINE_METHOD ] ], + 0xef : [Instruction3rmi, [ "execute-inline/range", INLINE_METHOD ] ], + 0xf0 : [Instruction35c, [ "invoke-object-init/range", KIND_METH ] ], + 0xf1 : [Instruction10x, [ "return-void-barrier" ] ], + + 0xf2 : [Instruction22cs, [ "iget-quick", FIELD_OFFSET ] ], + 0xf3 : [Instruction22cs, [ "iget-wide-quick", FIELD_OFFSET ] ], + 0xf4 : [Instruction22cs, [ "iget-object-quick", FIELD_OFFSET ] ], + 0xf5 : [Instruction22cs, [ "iput-quick", FIELD_OFFSET ] ], + 0xf6 : [Instruction22cs, [ "iput-wide-quick", FIELD_OFFSET ] ], + 0xf7 : [Instruction22cs, [ "iput-object-quick", FIELD_OFFSET ] ], + 0xf8 : [Instruction35ms, [ "invoke-virtual-quick", VTABLE_OFFSET ] ], + 0xf9 : [Instruction3rms, [ "invoke-virtual-quick/range", VTABLE_OFFSET ] ], + 0xfa : [Instruction35ms, [ "invoke-super-quick", VTABLE_OFFSET ] ], + 0xfb : [Instruction3rms, [ "invoke-super-quick/range", VTABLE_OFFSET ] ], + 0xfc : [Instruction22c, [ "iput-object-volatile", KIND_FIELD ] ], + 0xfd : [Instruction21c, [ "sget-object-volatile", KIND_FIELD ] ], + 0xfe : [Instruction21c, [ "sput-object-volatile", KIND_FIELD ] ], +} + +DALVIK_OPCODES_PAYLOAD = { + 0x0100 : [PackedSwitch], + 0x0200 : [SparseSwitch], + 0x0300 : [FillArrayData], +} + +INLINE_METHODS = [ + [ "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "()V" ], + + [ "Ljava/lang/String;", "charAt", "(I)C" ], + [ "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" ], + [ "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" ], + [ "Ljava/lang/String;", "fastIndexOf", "(II)I" ], + [ "Ljava/lang/String;", "isEmpty", "()Z" ], + [ "Ljava/lang/String;", "length", "()I" ], + + [ "Ljava/lang/Math;", "abs", "(I)I" ], + [ "Ljava/lang/Math;", "abs", "(J)J" ], + [ "Ljava/lang/Math;", "abs", "(F)F" ], + [ "Ljava/lang/Math;", "abs", "(D)D" ], + [ "Ljava/lang/Math;", "min", "(II)I" ], + [ "Ljava/lang/Math;", "max", "(II)I" ], + [ "Ljava/lang/Math;", "sqrt", "(D)D" ], + [ "Ljava/lang/Math;", "cos", "(D)D" ], + [ "Ljava/lang/Math;", "sin", "(D)D" ], + + [ "Ljava/lang/Float;", "floatToIntBits", "(F)I" ], + [ "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" ], + [ "Ljava/lang/Float;", "intBitsToFloat", "(I)F" ], + [ "Ljava/lang/Double;", "doubleToLongBits", "(D)J" ], + [ "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" ], + [ "Ljava/lang/Double;", "longBitsToDouble", "(J)D" ], +] + +DALVIK_OPCODES_EXTENDED_WIDTH = { + 0x00ff: [ Instruction41c, ["const-class/jumbo", KIND_TYPE ] ], + 0x01ff: [ Instruction41c, ["check-cast/jumbo", KIND_TYPE ] ], + + 0x02ff: [ Instruction52c, ["instance-of/jumbo", KIND_TYPE ] ], + + 0x03ff: [ Instruction41c, ["new-instance/jumbo", KIND_TYPE ] ], + + 0x04ff: [ Instruction52c, ["new-array/jumbo", KIND_TYPE ] ], + + 0x05ff: [ Instruction5rc, ["filled-new-array/jumbo", KIND_TYPE ] ], + + 0x06ff: [ Instruction52c, ["iget/jumbo", KIND_FIELD ] ], + 0x07ff: [ Instruction52c, ["iget-wide/jumbo", KIND_FIELD ] ], + 0x08ff: [ Instruction52c, ["iget-object/jumbo", KIND_FIELD ] ], + 0x09ff: [ Instruction52c, ["iget-boolean/jumbo", KIND_FIELD ] ], + 0x0aff: [ Instruction52c, ["iget-byte/jumbo", KIND_FIELD ] ], + 0x0bff: [ Instruction52c, ["iget-char/jumbo", KIND_FIELD ] ], + 0x0cff: [ Instruction52c, ["iget-short/jumbo", KIND_FIELD ] ], + 0x0dff: [ Instruction52c, ["iput/jumbo", KIND_FIELD ] ], + 0x0eff: [ Instruction52c, ["iput-wide/jumbo", KIND_FIELD ] ], + 0x0fff: [ Instruction52c, ["iput-object/jumbo", KIND_FIELD ] ], + 0x10ff: [ Instruction52c, ["iput-boolean/jumbo", KIND_FIELD ] ], + 0x11ff: [ Instruction52c, ["iput-byte/jumbo", KIND_FIELD ] ], + 0x12ff: [ Instruction52c, ["iput-char/jumbo", KIND_FIELD ] ], + 0x13ff: [ Instruction52c, ["iput-short/jumbo", KIND_FIELD ] ], + + 0x14ff: [ Instruction41c, ["sget/jumbo", KIND_FIELD ] ], + 0x15ff: [ Instruction41c, ["sget-wide/jumbo", KIND_FIELD ] ], + 0x16ff: [ Instruction41c, ["sget-object/jumbo", KIND_FIELD ] ], + 0x17ff: [ Instruction41c, ["sget-boolean/jumbo", KIND_FIELD ] ], + 0x18ff: [ Instruction41c, ["sget-byte/jumbo", KIND_FIELD ] ], + 0x19ff: [ Instruction41c, ["sget-char/jumbo", KIND_FIELD ] ], + 0x1aff: [ Instruction41c, ["sget-short/jumbo", KIND_FIELD ] ], + 0x1bff: [ Instruction41c, ["sput/jumbo", KIND_FIELD ] ], + 0x1cff: [ Instruction41c, ["sput-wide/jumbo", KIND_FIELD ] ], + 0x1dff: [ Instruction41c, ["sput-object/jumbo", KIND_FIELD ] ], + 0x1eff: [ Instruction41c, ["sput-boolean/jumbo", KIND_FIELD ] ], + 0x1fff: [ Instruction41c, ["sput-byte/jumbo", KIND_FIELD ] ], + 0x20ff: [ Instruction41c, ["sput-char/jumbo", KIND_FIELD ] ], + 0x21ff: [ Instruction41c, ["sput-short/jumbo", KIND_FIELD ] ], + + 0x22ff: [ Instruction5rc, ["invoke-virtual/jumbo", KIND_METH ] ], + 0x23ff: [ Instruction5rc, ["invoke-super/jumbo", KIND_METH ] ], + 0x24ff: [ Instruction5rc, ["invoke-direct/jumbo", KIND_METH ] ], + 0x25ff: [ Instruction5rc, ["invoke-static/jumbo", KIND_METH ] ], + 0x26ff: [ Instruction5rc, ["invoke-interface/jumbo", KIND_METH ] ], +} + +DALVIK_OPCODES_OPTIMIZED = { + 0xf2ff : [ Instruction5rc, ["invoke-object-init/jumbo", KIND_METH ] ], + + 0xf3ff : [ Instruction52c, ["iget-volatile/jumbo", KIND_FIELD ] ], + 0xf4ff : [ Instruction52c, ["iget-wide-volatile/jumbo", KIND_FIELD ] ], + 0xf5ff : [ Instruction52c, ["iget-object-volatile/jumbo ", KIND_FIELD ] ], + 0xf6ff : [ Instruction52c, ["iput-volatile/jumbo", KIND_FIELD ] ], + 0xf7ff : [ Instruction52c, ["iput-wide-volatile/jumbo", KIND_FIELD ] ], + 0xf8ff : [ Instruction52c, ["iput-object-volatile/jumbo", KIND_FIELD ] ], + 0xf9ff : [ Instruction41c, ["sget-volatile/jumbo", KIND_FIELD ] ], + 0xfaff : [ Instruction41c, ["sget-wide-volatile/jumbo", KIND_FIELD ] ], + 0xfbff : [ Instruction41c, ["sget-object-volatile/jumbo", KIND_FIELD ] ], + 0xfcff : [ Instruction41c, ["sput-volatile/jumbo", KIND_FIELD ] ], + 0xfdff : [ Instruction41c, ["sput-wide-volatile/jumbo", KIND_FIELD ] ], + 0xfeff : [ Instruction41c, ["sput-object-volatile/jumbo", KIND_FIELD ] ], + + 0xffff : [ Instruction40sc, ["throw-verification-error/jumbo", VARIES ] ], +} + + +class Unresolved(Instruction): + def __init__(self, cm, data): + self.cm = cm + self.data = data + + def get_name(self): + return "unresolved" + + def get_operands(self, idx=-1): + return [(OPERAND_KIND + KIND_STRING, -1, "AG:OP: invalid opcode " + repr(self.data))] + + def get_op_value(self): + return -1 + + def get_output(self, idx=-1): + return repr(self.data) + + def get_length(self): + return len(self.data) + + def get_raw(self): + return self.data + + +def get_instruction(cm, op_value, buff, odex=False): + try: + if not odex and (op_value >= 0xe3 and op_value <= 0xfe): + return InstructionInvalid(cm, buff) + + try: + return DALVIK_OPCODES_FORMAT[op_value][0](cm, buff) + except KeyError: + return InstructionInvalid(cm, buff) + except: + return Unresolved(cm, buff) + + +def get_extented_instruction(cm, op_value, buff): + return DALVIK_OPCODES_EXTENDED_WIDTH[op_value][0]( cm, buff ) + + +def get_optimized_instruction(cm, op_value, buff) : + return DALVIK_OPCODES_OPTIMIZED[op_value][0]( cm, buff ) + + +def get_instruction_payload(op_value, buff) : + return DALVIK_OPCODES_PAYLOAD[op_value][0]( buff ) + + +class LinearSweepAlgorithm : + """ + This class is used to disassemble a method. The algorithm used by this class is linear sweep. + """ + def get_instructions(self, cm, size, insn, idx): + """ + :param cm: a ClassManager object + :type cm: :class:`ClassManager` object + :param size: the total size of the buffer + :type size: int + :param insn: a raw buffer where are the instructions + :type insn: string + :param idx: a start address in the buffer + :type idx: int + + :rtype: a generator of :class:`Instruction` objects + """ + self.odex = cm.get_odex_format() + + max_idx = size * calcsize('=H') + if max_idx > len(insn): + max_idx = len(insn) + + # Get instructions + while idx < max_idx: + obj = None + classic_instruction = True + + op_value = unpack('=B', insn[idx])[0] + + #print "%x %x" % (op_value, idx) + + #payload instructions or extented/optimized instructions + if (op_value == 0x00 or op_value == 0xff) and ((idx + 2) < max_idx): + op_value = unpack('=H', insn[idx:idx + 2])[0] + + # payload instructions ? + if op_value in DALVIK_OPCODES_PAYLOAD: + try: + obj = get_instruction_payload(op_value, insn[idx:]) + classic_instruction = False + except struct.error: + warning("error while decoding instruction ...") + + elif op_value in DALVIK_OPCODES_EXTENDED_WIDTH: + try: + obj = get_extented_instruction(cm, op_value, insn[idx:]) + classic_instruction = False + except struct.error, why: + warning("error while decoding instruction ..." + why.__str__()) + + # optimized instructions ? + elif self.odex and (op_value in DALVIK_OPCODES_OPTIMIZED): + obj = get_optimized_instruction(cm, op_value, insn[idx:]) + classic_instruction = False + + # classical instructions + if classic_instruction: + op_value = unpack('=B', insn[idx])[0] + obj = get_instruction(cm, op_value, insn[idx:], self.odex) + + # emit instruction + yield obj + idx = idx + obj.get_length() + + +class DCode: + """ + This class represents the instructions of a method + + :param class_manager: the ClassManager + :type class_manager: :class:`ClassManager` object + :param offset: the offset of the buffer + :type offset: int + :param size: the total size of the buffer + :type size: int + :param buff: a raw buffer where are the instructions + :type buff: string + """ + def __init__(self, class_manager, offset, size, buff): + self.CM = class_manager + self.insn = buff + self.offset = offset + self.size = size + + self.notes = {} + self.cached_instructions = [] + self.rcache = 0 + + self.idx = 0 + + def get_insn(self): + """ + Get the insn buffer + + :rtype: string + """ + return self.insn + + def set_insn(self, insn): + """ + Set a new raw buffer to disassemble + + :param insn: the buffer + :type insn: string + """ + self.insn = insn + self.size = len(self.insn) + + def set_idx(self, idx): + """ + Set the start address of the buffer + + :param idx: the index + :type idx: int + """ + self.idx = idx + + def set_instructions(self, instructions): + """ + Set the instructions + + :param instructions: the list of instructions + :type instructions: a list of :class:`Instruction` + """ + self.cached_instructions = instructions + + def get_instructions(self): + """ + Get the instructions + + :rtype: a generator of each :class:`Instruction` (or a cached list of instructions if you have setup instructions) + """ + # it is possible to a cache for instructions (avoid a new disasm) + if self.cached_instructions: + for i in self.cached_instructions: + yield i + + else: + if self.rcache >= 5: + lsa = LinearSweepAlgorithm() + for i in lsa.get_instructions(self.CM, self.size, self.insn, self.idx): + self.cached_instructions.append(i) + + for i in self.cached_instructions: + yield i + else: + self.rcache += 1 + if self.size >= 1000: + self.rcache = 5 + + lsa = LinearSweepAlgorithm() + for i in lsa.get_instructions(self.CM, self.size, self.insn, self.idx): + yield i + + def reload(self): + pass + + def add_inote(self, msg, idx, off=None): + """ + Add a message to a specific instruction by using (default) the index of the address if specified + + :param msg: the message + :type msg: string + :param idx: index of the instruction (the position in the list of the instruction) + :type idx: int + :param off: address of the instruction + :type off: int + """ + if off != None: + idx = self.off_to_pos(off) + + if idx not in self.notes: + self.notes[idx] = [] + + self.notes[idx].append(msg) + + def get_instruction(self, idx, off=None): + """ + Get a particular instruction by using (default) the index of the address if specified + + :param idx: index of the instruction (the position in the list of the instruction) + :type idx: int + :param off: address of the instruction + :type off: int + + :rtype: an :class:`Instruction` object + """ + if off != None: + idx = self.off_to_pos(off) + return [i for i in self.get_instructions()][idx] + + def off_to_pos(self, off): + """ + Get the position of an instruction by using the address + + :param off: address of the instruction + :type off: int + + :rtype: int + """ + idx = 0 + nb = 0 + for i in self.get_instructions(): + if idx == off: + return nb + nb += 1 + idx += i.get_length() + return -1 + + def get_ins_off(self, off): + """ + Get a particular instruction by using the address + + :param off: address of the instruction + :type off: int + + :rtype: an :class:`Instruction` object + """ + idx = 0 + for i in self.get_instructions(): + if idx == off: + return i + idx += i.get_length() + return None + + def show(self): + """ + Display this object + """ + nb = 0 + idx = 0 + for i in self.get_instructions(): + print "%-8d(%08x)" % (nb, idx), + i.show(nb) + print + + idx += i.get_length() + nb += 1 + + def pretty_show(self, m_a): + """ + Display (with a pretty print) this object + + :param m_a: :class:`MethodAnalysis` object + """ + bytecode.PrettyShow(m_a, m_a.basic_blocks.gets(), self.notes) + bytecode.PrettyShowEx(m_a.exceptions.gets()) + + def get_raw(self): + """ + Return the raw buffer of this object + + :rtype: string + """ + return ''.join(i.get_raw() for i in self.get_instructions()) + + def get_length(self): + """ + Return the length of this object + + :rtype: int + """ + return len(self.get_raw()) + + +class TryItem: + """ + This class represents the try_item format + + :param buff: a raw buffer where are the try_item format + :type buff: string + :param cm: the ClassManager + :type cm: :class:`ClassManager` object + """ + def __init__(self, buff, cm) : + self.offset = buff.get_idx() + + self.__CM = cm + + self.start_addr = unpack("=I", buff.read(4))[0] + self.insn_count = unpack("=H", buff.read(2))[0] + self.handler_off = unpack("=H", buff.read(2))[0] + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def get_start_addr(self) : + """ + Get the start address of the block of code covered by this entry. The address is a count of 16-bit code units to the start of the first covered instruction. + + :rtype: int + """ + return self.start_addr + + def get_insn_count(self) : + """ + Get the number of 16-bit code units covered by this entry + + :rtype: int + """ + return self.insn_count + + def get_handler_off(self) : + """ + Get the offset in bytes from the start of the associated :class:`EncodedCatchHandlerList` to the :class:`EncodedCatchHandler` for this entry. + + :rtype: int + """ + return self.handler_off + + def get_raw(self) : + return pack("=I", self.start_addr) + pack("=H", self.insn_count) + pack("=H", self.handler_off) + + def get_length(self) : + return len(self.get_raw()) + +class DalvikCode: + """ + This class represents the instructions of a method + + :param buff: a raw buffer where are the instructions + :type buff: string + :param cm: the ClassManager + :type cm: :class:`ClassManager` object + """ + def __init__(self, buff, cm): + self.__CM = cm + self.offset = buff.get_idx() + + self.int_padding = "" + off = buff.get_idx() + while off % 4 != 0: + self.int_padding += '\00' + off += 1 + buff.set_idx(off) + + self.__off = buff.get_idx() + + self.registers_size = unpack("=H", buff.read(2))[0] + self.ins_size = unpack("=H", buff.read(2))[0] + self.outs_size = unpack("=H", buff.read(2))[0] + self.tries_size = unpack("=H", buff.read(2))[0] + self.debug_info_off = unpack("=I", buff.read(4))[0] + self.insns_size = unpack("=I", buff.read(4))[0] + + ushort = calcsize('=H') + + self.code = DCode(self.__CM, buff.get_idx(), self.insns_size, buff.read(self.insns_size * ushort)) + + if (self.insns_size % 2 == 1): + self.padding = unpack("=H", buff.read(2))[0] + + self.tries = [] + self.handlers = None + if self.tries_size > 0: + for i in xrange(0, self.tries_size): + self.tries.append(TryItem(buff, self.__CM)) + + self.handlers = EncodedCatchHandlerList(buff, self.__CM) + + def get_registers_size(self): + """ + Get the number of registers used by this code + + :rtype: int + """ + return self.registers_size + + def get_ins_size(self): + """ + Get the number of words of incoming arguments to the method that this code is for + + :rtype: int + """ + return self.ins_size + + def get_outs_size(self): + """ + Get the number of words of outgoing argument space required by this code for method invocation + + :rtype: int + """ + return self.outs_size + + def get_tries_size(self): + """ + Get the number of :class:`TryItem` for this instance + + :rtype: int + """ + return self.tries_size + + def get_debug_info_off(self): + """ + Get the offset from the start of the file to the debug info (line numbers + local variable info) sequence for this code, or 0 if there simply is no information + + :rtype: int + """ + return self.debug_info_off + + def get_insns_size(self): + """ + Get the size of the instructions list, in 16-bit code units + + :rtype: int + """ + return self.insns_size + + def get_handlers(self): + """ + Get the bytes representing a list of lists of catch types and associated handler addresses. + + :rtype: :class:`EncodedCatchHandlerList` + """ + return self.handlers + + def get_tries(self): + """ + Get the array indicating where in the code exceptions are caught and how to handle them + + :rtype: a list of :class:`TryItem` objects + """ + return self.tries + + def get_debug(self): + """ + Return the associated debug object + + :rtype: :class:`DebugInfoItem` + """ + return self.__CM.get_debug_off(self.debug_info_off) + + def get_bc(self): + """ + Return the associated code object + + :rtype: :class:`DCode` + """ + return self.code + + def set_idx(self, idx): + self.code.set_idx(idx) + + def reload(self): + self.code.reload() + + def get_length(self): + return self.insns_size + + def _begin_show(self): + debug("registers_size: %d" % self.registers_size) + debug("ins_size: %d" % self.ins_size) + debug("outs_size: %d" % self.outs_size) + debug("tries_size: %d" % self.tries_size) + debug("debug_info_off: %d" % self.debug_info_off) + debug("insns_size: %d" % self.insns_size) + + bytecode._PrintBanner() + + def show(self): + self._begin_show() + self.code.show() + self._end_show() + + def _end_show(self): + bytecode._PrintBanner() + + def pretty_show(self, m_a): + self._begin_show() + self.code.pretty_show(m_a) + self._end_show() + + def get_obj(self): + return [self.code, self.tries, self.handlers] + + def get_raw(self): + code_raw = self.code.get_raw() + self.insns_size = (len(code_raw) / 2) + (len(code_raw) % 2) + + buff = self.int_padding + buff += pack("=H", self.registers_size) + \ + pack("=H", self.ins_size) + \ + pack("=H", self.outs_size) + \ + pack("=H", self.tries_size) + \ + pack("=I", self.debug_info_off) + \ + pack("=I", self.insns_size) + \ + code_raw + + # if (self.insns_size % 2 == 1): + # buff += pack("=H", self.padding) + + if self.tries_size > 0: + buff += ''.join(i.get_raw() for i in self.tries) + buff += self.handlers.get_raw() + + return buff + + def add_inote(self, msg, idx, off=None): + """ + Add a message to a specific instruction by using (default) the index of the address if specified + + :param msg: the message + :type msg: string + :param idx: index of the instruction (the position in the list of the instruction) + :type idx: int + :param off: address of the instruction + :type off: int + """ + if self.code: + return self.code.add_inote(msg, idx, off) + + def get_instruction(self, idx, off=None): + if self.code: + return self.code.get_instruction(idx, off) + + def get_size(self): + length = len(self.int_padding) + + length += len( pack("=H", self.registers_size) + \ + pack("=H", self.ins_size) + \ + pack("=H", self.outs_size) + \ + pack("=H", self.tries_size) + \ + pack("=I", self.debug_info_off) + \ + pack("=I", self.insns_size) ) + length += self.code.get_length() + + if (self.insns_size % 2 == 1) : + length += len(pack("=H", self.padding)) + + if self.tries_size > 0 : + for i in self.tries : + length += i.get_length() + + length += self.handlers.get_length() + + return length + + def get_off(self) : + return self.__off + +class CodeItem : + def __init__(self, size, buff, cm) : + self.__CM = cm + + self.offset = buff.get_idx() + + self.code = [] + self.__code_off = {} + + for i in xrange(0, size) : + x = DalvikCode( buff, cm ) + self.code.append( x ) + self.__code_off[ x.get_off() ] = x + + def set_off(self, off) : + self.offset = off + + def get_off(self) : + return self.offset + + def get_code(self, off) : + try : + return self.__code_off[off] + except KeyError : + return None + + def reload(self) : + for i in self.code : + i.reload() + + def show(self) : + print "CODE_ITEM" + for i in self.code : + i.show() + + def get_obj(self) : + return [ i for i in self.code ] + + def get_raw(self) : + return ''.join(i.get_raw() for i in self.code) + + def get_length(self) : + length = 0 + for i in self.code : + length += i.get_size() + return length + +class MapItem : + def __init__(self, buff, cm) : + self.__CM = cm + + self.off = buff.get_idx() + + self.type = unpack("=H", buff.read(2))[0] + self.unused = unpack("=H", buff.read(2))[0] + self.size = unpack("=I", buff.read(4))[0] + self.offset = unpack("=I", buff.read(4))[0] + + self.item = None + + buff.set_idx( self.offset ) + + lazy_analysis = self.__CM.get_lazy_analysis() + + if lazy_analysis : + self.next_lazy(buff, cm) + else : + self.next(buff, cm) + + def get_off(self) : + return self.off + + def get_offset(self) : + return self.offset + + def get_type(self) : + return self.type + + def get_size(self) : + return self.size + + def next(self, buff, cm): + debug("%s @ 0x%x(%d) %x %x" % (TYPE_MAP_ITEM[self.type], buff.get_idx(), buff.get_idx(), self.size, self.offset)) + + if TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_ID_ITEM" : + self.item = [ StringIdItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CODE_ITEM" : + self.item = CodeItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_ID_ITEM" : + self.item = TypeHIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_PROTO_ID_ITEM" : + self.item = ProtoHIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_FIELD_ID_ITEM" : + self.item = FieldHIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_METHOD_ID_ITEM" : + self.item = MethodHIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DEF_ITEM" : + self.item = ClassHDefItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_HEADER_ITEM" : + self.item = HeaderItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_ITEM" : + self.item = [ AnnotationItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_SET_ITEM" : + self.item = [ AnnotationSetItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATIONS_DIRECTORY_ITEM" : + self.item = [ AnnotationsDirectoryItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_SET_REF_LIST" : + self.item = [ AnnotationSetRefList( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_LIST" : + self.item = [ TypeList( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_DATA_ITEM" : + self.item = [ StringDataItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_DEBUG_INFO_ITEM" : + self.item = DebugInfoItemEmpty( buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ENCODED_ARRAY_ITEM" : + self.item = [ EncodedArrayItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DATA_ITEM" : + self.item = [ ClassDataItem(buff, cm) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_MAP_LIST" : + pass # It's me I think !!! + + else : + bytecode.Exit( "Map item %d @ 0x%x(%d) is unknown" % (self.type, buff.get_idx(), buff.get_idx()) ) + + def next_lazy(self, buff, cm) : + if TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_ID_ITEM" : + self.item = [ StringIdItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CODE_ITEM" : + self.item = CodeItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_ID_ITEM" : + self.item = TypeIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_PROTO_ID_ITEM" : + self.item = ProtoIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_FIELD_ID_ITEM" : + self.item = FieldIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_METHOD_ID_ITEM" : + self.item = MethodIdItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DEF_ITEM" : + self.item = ClassDefItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_HEADER_ITEM" : + self.item = HeaderItem( self.size, buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_LIST" : + self.item = [ TypeList( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_DATA_ITEM" : + self.item = [ StringDataItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_DEBUG_INFO_ITEM" : + self.item = DebugInfoItemEmpty( buff, cm ) + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ENCODED_ARRAY_ITEM" : + self.item = [ EncodedArrayItem( buff, cm ) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DATA_ITEM" : + self.item = [ ClassDataItem(buff, cm) for i in xrange(0, self.size) ] + + elif TYPE_MAP_ITEM[ self.type ] == "TYPE_MAP_LIST" : + pass # It's me I think !!! + + + def reload(self) : + if self.item != None : + if isinstance( self.item, list ): + for i in self.item : + i.reload() + else : + self.item.reload() + + def show(self) : + bytecode._Print( "\tMAP_TYPE_ITEM", TYPE_MAP_ITEM[ self.type ]) + + if self.item != None : + if isinstance( self.item, list ): + for i in self.item : + i.show() + else : + self.item.show() + + def pretty_show(self) : + bytecode._Print( "\tMAP_TYPE_ITEM", TYPE_MAP_ITEM[ self.type ]) + + if self.item != None : + if isinstance( self.item, list ): + for i in self.item : + if isinstance(i, ClassDataItem) : + i.pretty_show() + else : + i.show() + else : + self.item.show() + + def get_obj(self) : + return self.item + + def get_raw(self) : + if isinstance(self.item, list) : + self.offset = self.item[0].get_off() + else : + self.offset = self.item.get_off() + + return pack("=H", self.type) + pack("=H", self.unused) + pack("=I", self.size) + pack("=I", self.offset) + + def get_length(self) : + return calcsize( "=HHII" ) + + def get_item(self) : + return self.item + + def set_item(self, item) : + self.item = item + + +class OffObj: + def __init__(self, o): + self.off = o + + +class ClassManager: + """ + This class is used to access to all elements (strings, type, proto ...) of the dex format + """ + def __init__(self, vm, config): + self.vm = vm + self.buff = vm + + self.decompiler_ob = None + self.vmanalysis_ob = None + self.gvmanalysis_ob = None + + self.__manage_item = {} + self.__manage_item_off = [] + + self.__strings_off = {} + + self.__obj_offset = {} + self.__item_offset = {} + + self.__cached_type_list = {} + self.__cached_proto = {} + + self.recode_ascii_string = config["RECODE_ASCII_STRING"] + self.recode_ascii_string_meth = None + if config["RECODE_ASCII_STRING_METH"]: + self.recode_ascii_string_meth = config["RECODE_ASCII_STRING_METH"] + + self.lazy_analysis = config["LAZY_ANALYSIS"] + + self.hook_strings = {} + + self.engine = [] + self.engine.append("python") + + if self.vm != None: + self.odex_format = self.vm.get_format_type() == "ODEX" + + def get_ascii_string(self, s): + try: + return s.decode("ascii") + except UnicodeDecodeError: + d = "" + for i in s: + if ord(i) < 128: + d += i + else: + d += "%x" % ord(i) + return d + + def get_odex_format(self): + return self.odex_format + + def get_obj_by_offset(self, offset) : + return self.__obj_offset[ offset ] + + def get_item_by_offset(self, offset) : + return self.__item_offset[ offset ] + + def get_string_by_offset(self, offset) : + return self.__strings_off[ offset ] + + def get_lazy_analysis(self) : + return self.lazy_analysis + + def get_vmanalysis(self) : + return self.vmanalysis_ob + + def set_vmanalysis(self, vmanalysis) : + self.vmanalysis_ob = vmanalysis + + def get_gvmanalysis(self) : + return self.gvmanalysis_ob + + def set_gvmanalysis(self, gvmanalysis) : + self.gvmanalysis_ob = gvmanalysis + + def set_decompiler(self, decompiler) : + self.decompiler_ob = decompiler + + def get_engine(self) : + return self.engine[0] + + def get_all_engine(self) : + return self.engine + + def add_type_item(self, type_item, c_item, item) : + self.__manage_item[ type_item ] = item + + self.__obj_offset[ c_item.get_off() ] = c_item + self.__item_offset[ c_item.get_offset() ] = item + + sdi = False + if type_item == "TYPE_STRING_DATA_ITEM" : + sdi = True + + if item != None : + if isinstance(item, list) : + for i in item : + goff = i.offset + self.__manage_item_off.append( goff ) + + self.__obj_offset[ i.get_off() ] = i + + if sdi == True : + self.__strings_off[ goff ] = i + else : + self.__manage_item_off.append( c_item.get_offset() ) + + def get_code(self, idx) : + try : + return self.__manage_item[ "TYPE_CODE_ITEM" ].get_code( idx ) + except KeyError : + return None + + def get_class_data_item(self, off) : + for i in self.__manage_item[ "TYPE_CLASS_DATA_ITEM" ] : + if i.get_off() == off : + return i + + bytecode.Exit( "unknown class data item @ 0x%x" % off ) + + def get_encoded_array_item(self, off) : + for i in self.__manage_item["TYPE_ENCODED_ARRAY_ITEM" ] : + if i.get_off() == off : + return i + + def get_string(self, idx) : + if idx in self.hook_strings : + return self.hook_strings[ idx ] + + try : + off = self.__manage_item[ "TYPE_STRING_ID_ITEM" ][idx].get_string_data_off() + except IndexError : + bytecode.Warning( "unknown string item @ %d" % (idx) ) + return "AG:IS: invalid string" + + try: + if self.recode_ascii_string: + if self.recode_ascii_string_meth: + return self.recode_ascii_string_meth(self.__strings_off[off].get()) + return self.get_ascii_string(self.__strings_off[off].get()) + return self.__strings_off[off].get() + except KeyError: + bytecode.Warning( "unknown string item @ 0x%x(%d)" % (off,idx) ) + return "AG:IS: invalid string" + + def get_raw_string(self, idx) : + try : + off = self.__manage_item[ "TYPE_STRING_ID_ITEM" ][idx].get_string_data_off() + except IndexError : + bytecode.Warning( "unknown string item @ %d" % (idx) ) + return "AG:IS: invalid string" + + try : + return self.__strings_off[off].get() + except KeyError : + bytecode.Warning( "unknown string item @ 0x%x(%d)" % (off,idx) ) + return "AG:IS: invalid string" + + def get_type_list(self, off) : + if off == 0 : + return "()" + + if off in self.__cached_type_list : + return self.__cached_type_list[ off ] + + for i in self.__manage_item[ "TYPE_TYPE_LIST" ] : + if i.get_type_list_off() == off : + ret = "(" + i.get_string() + ")" + self.__cached_type_list[ off ] = ret + return ret + + return None + + def get_type(self, idx) : + _type = self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( idx ) + if _type == -1 : + return "AG:ITI: invalid type" + return self.get_string( _type ) + + def get_type_ref(self, idx) : + return self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( idx ) + + def get_proto(self, idx) : + try : + proto = self.__cached_proto[ idx ] + except KeyError : + proto = self.__manage_item[ "TYPE_PROTO_ID_ITEM" ].get( idx ) + self.__cached_proto[ idx ] = proto + + return [ proto.get_parameters_off_value(), proto.get_return_type_idx_value() ] + + def get_field(self, idx) : + field = self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( idx ) + return [ field.get_class_name(), field.get_type(), field.get_name() ] + + def get_field_ref(self, idx) : + return self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( idx ) + + def get_method(self, idx) : + method = self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( idx ) + return method.get_list() + + def get_method_ref(self, idx) : + return self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( idx ) + + def set_hook_class_name(self, class_def, value) : + _type = self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( class_def.get_class_idx() ) + self.set_hook_string( _type, value ) + + self.vm._delete_python_export_class( class_def ) + + class_def.reload() + + # FIXME + self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].reload() + + for i in class_def.get_methods() : + i.reload() + + for i in class_def.get_fields() : + i.reload() + + self.vm._create_python_export_class( class_def ) + + def set_hook_method_name(self, encoded_method, value): + python_export = True + + method = self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( encoded_method.get_method_idx() ) + self.set_hook_string( method.get_name_idx(), value ) + + class_def = self.__manage_item[ "TYPE_CLASS_DEF_ITEM" ].get_class_idx( method.get_class_idx() ) + if class_def != None: + try: + name = "METHOD_" + bytecode.FormatNameToPython( encoded_method.get_name() ) + except AttributeError: + name += "_" + bytecode.FormatDescriptorToPython(encoded_method.get_descriptor()) + + try: + delattr(class_def, name) + except AttributeError: + python_export = False + + if python_export: + name = "METHOD_" + bytecode.FormatNameToPython(value) + setattr(class_def, name, encoded_method) + + method.reload() + + def set_hook_field_name(self, encoded_field, value): + python_export = True + + field = self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( encoded_field.get_field_idx() ) + self.set_hook_string( field.get_name_idx(), value ) + + class_def = self.__manage_item[ "TYPE_CLASS_DEF_ITEM" ].get_class_idx( field.get_class_idx() ) + if class_def != None : + try : + name = "FIELD_" + bytecode.FormatNameToPython( encoded_field.get_name() ) + except AttributeError: + name += "_" + bytecode.FormatDescriptorToPython( encoded_field.get_descriptor() ) + + + try: + delattr( class_def, name ) + except AttributeError: + python_export = False + + if python_export: + name = "FIELD_" + bytecode.FormatNameToPython( value ) + setattr( class_def, name, encoded_field ) + + field.reload() + + + def set_hook_string(self, idx, value) : + self.hook_strings[ idx ] = value + + def get_next_offset_item(self, idx) : + for i in self.__manage_item_off : + if i > idx : + return i + return idx + + def get_debug_off(self, off) : + self.buff.set_idx( off ) + + return DebugInfoItem( self.buff, self ) + +class MapList : + """ + This class can parse the "map_list" of the dex format + """ + def __init__(self, cm, off, buff) : + self.CM = cm + + buff.set_idx( off ) + + self.offset = off + + self.size = unpack("=I", buff.read( 4 ) )[0] + + self.map_item = [] + for i in xrange(0, self.size) : + idx = buff.get_idx() + + mi = MapItem( buff, self.CM ) + self.map_item.append( mi ) + + buff.set_idx( idx + mi.get_length() ) + + c_item = mi.get_item() + if c_item == None : + mi.set_item( self ) + c_item = mi.get_item() + + self.CM.add_type_item( TYPE_MAP_ITEM[ mi.get_type() ], mi, c_item ) + + for i in self.map_item : + i.reload() + + def reload(self) : + pass + + def get_off(self) : + return self.offset + + def set_off(self, off) : + self.offset = off + + def get_item_type(self, ttype) : + """ + Get a particular item type + + :param ttype: a string which represents the desired type + + :rtype: None or the item object + """ + for i in self.map_item : + if TYPE_MAP_ITEM[ i.get_type() ] == ttype : + return i.get_item() + return None + + def show(self) : + """ + Print the MapList object + """ + bytecode._Print("MAP_LIST SIZE", self.size) + for i in self.map_item : + if i.item != self : + i.show() + + def pretty_show(self) : + """ + Print with a pretty display the MapList object + """ + bytecode._Print("MAP_LIST SIZE", self.size) + for i in self.map_item : + if i.item != self : + i.pretty_show() + + def get_obj(self) : + return [ x.get_obj() for x in self.map_item ] + + def get_raw(self) : + return pack("=I", self.size) + ''.join(x.get_raw() for x in self.map_item) + + def get_class_manager(self) : + return self.CM + + def get_length(self) : + return len(self.get_raw()) + +class XREF : + def __init__(self) : + self.items = [] + + def add(self, x, y): + self.items.append((x, y)) + +class DREF : + def __init__(self) : + self.items = [] + + def add(self, x, y): + self.items.append((x, y)) + + +class DalvikVMFormat(bytecode._Bytecode): + """ + This class can parse a classes.dex file of an Android application (APK). + + :param buff: a string which represents the classes.dex file + :param decompiler: associate a decompiler object to display the java source code + :type buff: string + :type decompiler: object + + :Example: + DalvikVMFormat( open("classes.dex", "rb").read() ) + """ + def __init__(self, buff, decompiler=None, config=None): + super(DalvikVMFormat, self).__init__(buff) + + self.config = config + if not self.config: + self.config = {"RECODE_ASCII_STRING": CONF["RECODE_ASCII_STRING"], + "RECODE_ASCII_STRING_METH": CONF["RECODE_ASCII_STRING_METH"], + "LAZY_ANALYSIS": CONF["LAZY_ANALYSIS"]} + + self.CM = ClassManager(self, self.config) + self.CM.set_decompiler(decompiler) + + self._preload(buff) + self._load(buff) + + def _preload(self, buff): + pass + + def _load(self, buff): + self.__header = HeaderItem(0, self, ClassManager(None, self.config)) + + if self.__header.map_off == 0: + bytecode.Warning("no map list ...") + else: + self.map_list = MapList( self.CM, self.__header.map_off, self ) + + self.classes = self.map_list.get_item_type( "TYPE_CLASS_DEF_ITEM" ) + self.methods = self.map_list.get_item_type( "TYPE_METHOD_ID_ITEM" ) + self.fields = self.map_list.get_item_type( "TYPE_FIELD_ID_ITEM" ) + self.codes = self.map_list.get_item_type( "TYPE_CODE_ITEM" ) + self.strings = self.map_list.get_item_type( "TYPE_STRING_DATA_ITEM" ) + self.debug = self.map_list.get_item_type( "TYPE_DEBUG_INFO_ITEM" ) + self.header = self.map_list.get_item_type( "TYPE_HEADER_ITEM" ) + + self.classes_names = None + self.__cache_methods = None + self.__cached_methods_idx = None + + def get_classes_def_item(self) : + """ + This function returns the class def item + + :rtype: :class:`ClassDefItem` object + """ + return self.classes + + def get_methods_id_item(self) : + """ + This function returns the method id item + + :rtype: :class:`MethodIdItem` object + """ + return self.methods + + def get_fields_id_item(self) : + """ + This function returns the field id item + + :rtype: :class:`FieldIdItem` object + """ + return self.fields + + def get_codes_item(self) : + """ + This function returns the code item + + :rtype: :class:`CodeItem` object + """ + return self.codes + + def get_string_data_item(self) : + """ + This function returns the string data item + + :rtype: :class:`StringDataItem` object + """ + return self.strings + + def get_debug_info_item(self) : + """ + This function returns the debug info item + + :rtype: :class:`DebugInfoItem` object + """ + return self.debug + + def get_header_item(self) : + """ + This function returns the header item + + :rtype: :class:`HeaderItem` object + """ + return self.header + + def get_class_manager(self) : + """ + This function returns a ClassManager object which allow you to get + access to all index references (strings, methods, fields, ....) + + :rtype: :class:`ClassManager` object + """ + return self.CM + + def show(self) : + """ + Show the all information in the object + """ + self.map_list.show() + + def pretty_show(self): + """ + Show (but pretty !) the all information in the object + """ + self.map_list.pretty_show() + + def save(self): + """ + Return the dex (with the modifications) into raw format (fix checksums) + (beta: do not use !) + + :rtype: string + """ + l = [] + h = {} + s = {} + h_r = {} + + idx = 0 + for i in self.map_list.get_obj(): + length = 0 + + if isinstance(i, list): + for j in i: + if isinstance(j, AnnotationsDirectoryItem) : + if idx % 4 != 0 : + idx = idx + (4 - (idx % 4)) + + l.append( j ) + + c_length = j.get_length() + h[ j ] = idx + length + h_r[ idx + length ] = j + s[ idx + length ] = c_length + + length += c_length + #debug("SAVE" + str(j) + " @ 0x%x" % (idx+length)) + + debug("SAVE " + str(i[0]) + " @0x%x (%x)" % (idx, length)) + + else : + if isinstance(i, MapList) : + if idx % 4 != 0 : + idx = idx + (4 - (idx % 4)) + + l.append( i ) + h[ i ] = idx + h_r[ idx ] = i + + length = i.get_length() + + s[idx] = length + + debug("SAVE " + str(i) + " @0x%x (%x)" % (idx, length)) + + idx += length + + self.header.file_size = idx + + last_idx = 0 + for i in l : + idx = h[ i ] + i.set_off( h[ i ] ) + +# print i, hex(h[ i ]) + + last_idx = idx + s[ idx ] + + last_idx = 0 + buff = "" + for i in l : + idx = h[ i ] + + if idx != last_idx : + debug( "Adjust alignment @%x with 00 %x" % (idx, idx - last_idx) ) + buff += "\x00" * (idx - last_idx) + + buff += i.get_raw() + last_idx = idx + s[ idx ] + + debug("GLOBAL SIZE %d" % len(buff)) + + return self.fix_checksums(buff) + + def fix_checksums(self, buff) : + """ + Fix a dex format buffer by setting all checksums + + :rtype: string + """ + import zlib + import hashlib + + signature = hashlib.sha1(buff[32:]).digest() + + buff = buff[:12] + signature + buff[32:] + checksum = zlib.adler32(buff[12:]) + buff = buff[:8] + pack("=i", checksum) + buff[12:] + + debug("NEW SIGNATURE %s" % repr(signature)) + debug("NEW CHECKSUM %x" % checksum) + + return buff + + def get_cm_field(self, idx) : + """ + Get a specific field by using an index + + :param idx: index of the field + :type idx: int + """ + return self.CM.get_field(idx) + + def get_cm_method(self, idx) : + """ + Get a specific method by using an index + + :param idx: index of the method + :type idx: int + """ + return self.CM.get_method(idx) + + def get_cm_string(self, idx) : + """ + Get a specific string by using an index + + :param idx: index of the string + :type idx: int + """ + return self.CM.get_raw_string( idx ) + + def get_cm_type(self, idx) : + """ + Get a specific type by using an index + + :param idx: index of the type + :type idx: int + """ + return self.CM.get_type( idx ) + + def get_classes_names(self) : + """ + Return the names of classes + + :rtype: a list of string + """ + if self.classes_names == None : + self.classes_names = [ i.get_name() for i in self.classes.class_def ] + return self.classes_names + + def get_classes(self) : + """ + Return all classes + + :rtype: a list of :class:`ClassDefItem` objects + """ + return self.classes.class_def + + def get_class(self, name): + """ + Return a specific class + + :param name: the name of the class + + :rtype: a :class:`ClassDefItem` object + """ + for i in self.classes.class_def: + if i.get_name() == name: + return i + return None + + def get_method(self, name) : + """ + Return a list all methods which corresponds to the regexp + + :param name: the name of the method (a python regexp) + + :rtype: a list with all :class:`EncodedMethod` objects + """ + prog = re.compile(name) + l = [] + for i in self.classes.class_def : + for j in i.get_methods() : + if prog.match( j.get_name() ) : + l.append( j ) + return l + + def get_field(self, name) : + """ + Return a list all fields which corresponds to the regexp + + :param name: the name of the field (a python regexp) + + :rtype: a list with all :class:`EncodedField` objects + """ + prog = re.compile(name) + l = [] + for i in self.classes.class_def : + for j in i.get_fields() : + if prog.match( j.get_name() ) : + l.append( j ) + return l + + def get_all_fields(self) : + """ + Return a list of field items + + :rtype: a list of :class:`FieldIdItem` objects + """ + try : + return self.fields.gets() + except AttributeError : + return [] + + def get_fields(self) : + """ + Return all field objects + + :rtype: a list of :class:`EncodedField` objects + """ + l = [] + for i in self.classes.class_def : + for j in i.get_fields() : + l.append( j ) + return l + + + def get_methods(self) : + """ + Return all method objects + + :rtype: a list of :class:`EncodedMethod` objects + """ + l = [] + for i in self.classes.class_def : + for j in i.get_methods() : + l.append( j ) + return l + + def get_len_methods(self) : + """ + Return the number of methods + + :rtype: int + """ + return len( self.get_methods() ) + + def get_method_by_idx(self, idx) : + """ + Return a specific method by using an index + :param idx: the index of the method + :type idx: int + + :rtype: None or an :class:`EncodedMethod` object + """ + if self.__cached_methods_idx == None : + self.__cached_methods_idx = {} + for i in self.classes.class_def : + for j in i.get_methods() : + self.__cached_methods_idx[ j.get_method_idx() ] = j + + try : + return self.__cached_methods_idx[ idx ] + except KeyError : + return None + + def get_method_descriptor(self, class_name, method_name, descriptor) : + """ + Return the specific method + + :param class_name: the class name of the method + :type class_name: string + :param method_name: the name of the method + :type method_name: string + :param descriptor: the descriptor of the method + :type descriptor: string + + :rtype: None or a :class:`EncodedMethod` object + """ + key = class_name + method_name + descriptor + + if self.__cache_methods == None : + self.__cache_methods = {} + for i in self.classes.class_def : + for j in i.get_methods() : + self.__cache_methods[ j.get_class_name() + j.get_name() + j.get_descriptor() ] = j + + try : + return self.__cache_methods[ key ] + except KeyError : + return None + + def get_methods_descriptor(self, class_name, method_name): + """ + Return the specific methods of the class + + :param class_name: the class name of the method + :type class_name: string + :param method_name: the name of the method + :type method_name: string + + :rtype: None or a :class:`EncodedMethod` object + """ + l = [] + for i in self.classes.class_def: + if i.get_name() == class_name: + for j in i.get_methods(): + if j.get_name() == method_name: + l.append(j) + + return l + + def get_methods_class(self, class_name) : + """ + Return all methods of a specific class + + :param class_name: the class name + :type class_name: string + + :rtype: a list with :class:`EncodedMethod` objects + """ + l = [] + for i in self.classes.class_def : + for j in i.get_methods() : + if class_name == j.get_class_name() : + l.append( j ) + + return l + + def get_fields_class(self, class_name) : + """ + Return all fields of a specific class + + :param class_name: the class name + :type class_name: string + + :rtype: a list with :class:`EncodedField` objects + """ + l = [] + for i in self.classes.class_def : + for j in i.get_fields() : + if class_name == j.get_class_name() : + l.append( j ) + + return l + + def get_field_descriptor(self, class_name, field_name, descriptor) : + """ + Return the specific field + + :param class_name: the class name of the field + :type class_name: string + :param field_name: the name of the field + :type field_name: string + :param descriptor: the descriptor of the field + :type descriptor: string + + :rtype: None or a :class:`EncodedField` object + """ + for i in self.classes.class_def : + if class_name == i.get_name() : + for j in i.get_fields() : + if field_name == j.get_name() and descriptor == j.get_descriptor() : + return j + return None + + def get_strings(self) : + """ + Return all strings + + :rtype: a list with all strings used in the format (types, names ...) + """ + return [i.get() for i in self.strings] + + def get_regex_strings(self, regular_expressions) : + """ + Return all target strings matched the regex + + :param regular_expressions: the python regex + :type regular_expressions: string + + :rtype: a list of strings matching the regex expression + """ + str_list = [] + if regular_expressions.count is None : + return None + for i in self.get_strings() : + if re.match(regular_expressions, i) : + str_list.append(i) + return str_list + + def get_format_type(self): + """ + Return the type + + :rtype: a string + """ + return "DEX" + + def create_xref(self, python_export=True): + """ + Create XREF for this object + + :param python_export (boolean): export xref in each method + """ + gvm = self.CM.get_gvmanalysis() + + for _class in self.get_classes(): + key = _class.get_name() + if key in gvm.nodes: + _class.XREFfrom = XREF() + for i in gvm.GI.successors(gvm.nodes[key].id): + xref = gvm.nodes_id[i] + xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor) + if python_export == True: + name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \ + bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \ + bytecode.FormatDescriptorToPython(xref_meth.get_descriptor()) + setattr(_class.XREFfrom, name, xref_meth) + _class.XREFfrom.add(xref_meth, xref.edges[gvm.nodes[key]]) + + for method in _class.get_methods(): + method.XREFfrom = XREF() + method.XREFto = XREF() + + key = "%s %s %s" % (method.get_class_name(), method.get_name(), method.get_descriptor()) + + if key in gvm.nodes: + for i in gvm.G.predecessors(gvm.nodes[key].id): + xref = gvm.nodes_id[i] + xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor) + if xref_meth != None: + name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \ + bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \ + bytecode.FormatDescriptorToPython(xref_meth.get_descriptor()) + + if python_export == True: + setattr(method.XREFfrom, name, xref_meth) + method.XREFfrom.add(xref_meth, xref.edges[gvm.nodes[key]]) + + for i in gvm.G.successors(gvm.nodes[key].id): + xref = gvm.nodes_id[i] + xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor) + if xref_meth != None: + name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \ + bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \ + bytecode.FormatDescriptorToPython(xref_meth.get_descriptor()) + + if python_export == True: + setattr(method.XREFto, name, xref_meth) + method.XREFto.add(xref_meth, gvm.nodes[key].edges[xref]) + + def create_dref(self, python_export=True): + """ + Create DREF for this object + + :param python_export (boolean): export dref in each field + """ + vmx = self.CM.get_vmanalysis() + + for _class in self.get_classes() : + for field in _class.get_fields() : + field.DREFr = DREF() + field.DREFw = DREF() + + paths = vmx.tainted_variables.get_field( field.get_class_name(), field.get_name(), field.get_descriptor() ) + + if paths != None : + access = {} + access["R"] = {} + access["W"] = {} + + for path in paths.get_paths() : + access_val, idx = path[0] + m_idx = path[1] + + if access_val == 'R' : + dref_meth = self.get_method_by_idx( m_idx ) + name = bytecode.FormatClassToPython( dref_meth.get_class_name() ) + "__" + \ + bytecode.FormatNameToPython( dref_meth.get_name() ) + "__" + \ + bytecode.FormatDescriptorToPython( dref_meth.get_descriptor() ) + + if python_export == True : + setattr( field.DREFr, name, dref_meth ) + + try : + access["R"][ dref_meth ].append( idx ) + except KeyError : + access["R"][ dref_meth ] = [] + access["R"][ dref_meth ].append( idx ) + + else : + dref_meth = self.get_method_by_idx( m_idx ) + name = bytecode.FormatClassToPython( dref_meth.get_class_name() ) + "__" + \ + bytecode.FormatNameToPython( dref_meth.get_name() ) + "__" + \ + bytecode.FormatDescriptorToPython( dref_meth.get_descriptor() ) + + if python_export == True : + setattr( field.DREFw, name, dref_meth ) + + try : + access["W"][ dref_meth ].append( idx ) + except KeyError : + access["W"][ dref_meth ] = [] + access["W"][ dref_meth ].append( idx ) + + for i in access["R"] : + field.DREFr.add( i, access["R"][i] ) + for i in access["W"] : + field.DREFw.add( i, access["W"][i] ) + + def create_python_export(self) : + """ + Export classes/methods/fields' names in the python namespace + """ + for _class in self.get_classes() : + self._create_python_export_class(_class) + + def _delete_python_export_class(self, _class) : + self._create_python_export_class( _class, True) + + def _create_python_export_class(self, _class, delete=False) : + if _class != None : + ### Class + name = "CLASS_" + bytecode.FormatClassToPython( _class.get_name() ) + if delete : + delattr( self, name ) + return + else : + setattr( self, name, _class ) + + ### Methods + m = {} + for method in _class.get_methods() : + if method.get_name() not in m : + m[ method.get_name() ] = [] + m[ method.get_name() ].append( method ) + + for i in m : + if len(m[i]) == 1 : + j = m[i][0] + name = "METHOD_" + bytecode.FormatNameToPython( j.get_name() ) + setattr( _class, name, j ) + else : + for j in m[i] : + name = "METHOD_" + bytecode.FormatNameToPython( j.get_name() ) + "_" + bytecode.FormatDescriptorToPython( j.get_descriptor() ) + setattr( _class, name, j ) + + ### Fields + f = {} + for field in _class.get_fields() : + if field.get_name() not in f : + f[ field.get_name() ] = [] + f[ field.get_name() ].append( field ) + + for i in f : + if len(f[i]) == 1 : + j = f[i][0] + name = "FIELD_" + bytecode.FormatNameToPython( j.get_name() ) + setattr( _class, name, j ) + else : + for j in f[i] : + name = "FIELD_" + bytecode.FormatNameToPython( j.get_name() ) + "_" + bytecode.FormatDescriptorToPython( j.get_descriptor() ) + setattr( _class, name, j ) + + def get_BRANCH_DVM_OPCODES(self) : + return BRANCH_DVM_OPCODES + + def get_determineNext(self) : + return determineNext + + def get_determineException(self) : + return determineException + + def get_DVM_TOSTRING(self): + return DVM_TOSTRING() + + def set_decompiler(self, decompiler): + self.CM.set_decompiler(decompiler) + + def set_vmanalysis(self, vmanalysis): + self.CM.set_vmanalysis(vmanalysis) + + def set_gvmanalysis(self, gvmanalysis): + self.CM.set_gvmanalysis(gvmanalysis) + + def disassemble(self, offset, size): + """ + Disassembles a given offset in the DEX file + + :param dex: the filename of the android dex file + :type filename: string + :param offset: offset to disassemble in the file (from the beginning of the file) + :type offset: int + :param size: + :type size: + """ + for i in DCode(self.CM, offset, size, self.get_buff()[offset:offset + size]).get_instructions(): + yield i + + def _get_class_hierarchy(self): + ids = {} + present = {} + r_ids = {} + to_add = {} + els = [] + + for current_class in self.get_classes(): + s_name = current_class.get_superclassname()[1:-1] + c_name = current_class.get_name()[1:-1] + + if s_name not in ids: + ids[s_name] = len(ids) + 1 + r_ids[ids[s_name]] = s_name + + if c_name not in ids: + ids[c_name] = len(ids) + 1 + + els.append([ids[c_name], ids[s_name], c_name]) + present[ids[c_name]] = True + + for i in els: + if i[1] not in present: + to_add[i[1]] = r_ids[i[1]] + + for i in to_add: + els.append([i, 0, to_add[i]]) + + treeMap = {} + Root = bytecode.Node(0, "Root") + treeMap[Root.id] = Root + for element in els: + nodeId, parentId, title = element + if not nodeId in treeMap: + treeMap[nodeId] = bytecode.Node(nodeId, title) + else: + treeMap[nodeId].id = nodeId + treeMap[nodeId].title = title + + if not parentId in treeMap: + treeMap[parentId] = bytecode.Node(0, '') + treeMap[parentId].children.append(treeMap[nodeId]) + + return Root + + def print_classes_hierarchy(self): + def print_map(node, l, lvl=0): + for n in node.children: + if lvl == 0: + l.append("%s" % (n.title)) + else: + l.append("%s %s" % ('\t' * lvl, n.title)) + if len(n.children) > 0: + print_map(n, l, lvl + 1) + + l = [] + print_map(self._get_class_hierarchy(), l) + return l + + def list_classes_hierarchy(self): + def print_map(node, l): + if node.title not in l: + l[node.title] = [] + + for n in node.children: + if len(n.children) > 0: + w = {} + w[n.title] = [] + l[node.title].append(w) + + print_map(n, w) + else: + l[node.title].append(n.title) + + l = {} + print_map(self._get_class_hierarchy(), l) + + return l + + def get_format(self): + objs = self.map_list.get_obj() + + h = {} + index = {} + self._get_objs(h, index, objs) + + return h, index + + def _get_objs(self, h, index, objs): + for i in objs: + if isinstance(i, list): + self._get_objs(h, index, i) + else: + try: + if i != None: + h[i] = {} + index[i] = i.offset + except AttributeError: + pass + + try: + if not isinstance(i, MapList): + next_objs = i.get_obj() + if isinstance(next_objs, list): + self._get_objs(h[i], index, next_objs) + except AttributeError: + pass + + def colorize_operands(self, operands, colors): + for operand in operands: + if operand[0] == OPERAND_REGISTER: + yield "%sv%d%s" % (colors["registers"], operand[1], colors["normal"]) + + elif operand[0] == OPERAND_LITERAL: + yield "%s%d%s" % (colors["literal"], operand[1], colors["normal"]) + + elif operand[0] == OPERAND_RAW: + yield "%s%s%s" % (colors["raw"], operand[1], colors["normal"]) + + elif operand[0] == OPERAND_OFFSET: + yield "%s%d%s" % (colors["offset"], operand[1], colors["normal"]) + + elif operand[0] & OPERAND_KIND: + if operand[0] == (OPERAND_KIND + KIND_STRING): + yield "%s%s%s" % (colors["string"], operand[2], colors["normal"]) + elif operand[0] == (OPERAND_KIND + KIND_METH): + yield "%s%s%s" % (colors["meth"], operand[2], colors["normal"]) + elif operand[0] == (OPERAND_KIND + KIND_FIELD): + yield "%s%s%s" % (colors["field"], operand[2], colors["normal"]) + elif operand[0] == (OPERAND_KIND + KIND_TYPE): + yield "%s%s%s" % (colors["type"], operand[2], colors["normal"]) + else: + yield "%s" % repr(operands[2]) + else: + yield "%s" % repr(operands[1]) + + def get_operand_html(self, operand, registers_colors, colors, escape_fct, wrap_fct): + if operand[0] == OPERAND_REGISTER: + return "v%s" % (registers_colors[operand[1]], operand[1]) + + elif operand[0] == OPERAND_LITERAL: + return "0x%x" % (colors["literal"], operand[1]) + + elif operand[0] == OPERAND_RAW: + if len(operand[1]) > 32: + wrapped = wrap_fct(operand[1], 32) + wrapped_adjust = "
" + "
".join(escape_fct(repr(i)[1:-1]) for i in wrapped) + return "%s" % (colors["raw"], wrapped_adjust) + + return "%s" % (colors["raw"], escape_fct(repr(operand[1])[1:-1])) + + elif operand[0] == OPERAND_OFFSET: + return "0x%x" % (colors["offset"], operand[1]) + + elif operand[0] & OPERAND_KIND: + if operand[0] == (OPERAND_KIND + KIND_STRING): + if len(operand[2]) > 32: + wrapped = wrap_fct(operand[2], 32) + wrapped_adjust = "
" + "
".join(escape_fct(i) for i in wrapped) + return "%s" % (colors["string"], wrapped_adjust) + + return "%s" % (colors["string"], escape_fct(operand[2])) + elif operand[0] == (OPERAND_KIND + KIND_METH): + return "%s" % (colors["method"], escape_fct(operand[2])) + elif operand[0] == (OPERAND_KIND + KIND_FIELD): + return "%s" % (colors["field"], escape_fct(operand[2])) + elif operand[0] == (OPERAND_KIND + KIND_TYPE): + return "%s" % (colors["type"], escape_fct(operand[2])) + + return escape_fct(str(operand[2])) + + return escape_fct(str(operand[1])) + + +class OdexHeaderItem: + """ + This class can parse the odex header + + :param buff: a Buff object string which represents the odex dependencies + """ + def __init__(self, buff): + buff.set_idx(8) + + self.dex_offset = unpack("=I", buff.read(4))[0] + self.dex_length = unpack("=I", buff.read(4))[0] + self.deps_offset = unpack("=I", buff.read(4))[0] + self.deps_length = unpack("=I", buff.read(4))[0] + self.aux_offset = unpack("=I", buff.read(4))[0] + self.aux_length = unpack("=I", buff.read(4))[0] + self.flags = unpack("=I", buff.read(4))[0] + self.padding = unpack("=I", buff.read(4))[0] + + def show(self): + print "dex_offset:%x dex_length:%x deps_offset:%x deps_length:%x aux_offset:%x aux_length:%x flags:%x" % (self.dex_offset, + self.dex_length, + self.deps_offset, + self.deps_length, + self.aux_offset, + self.aux_length, + self.flags) + + def get_raw(self): + return pack("=I", self.dex_offset) + \ + pack("=I", self.dex_length) + \ + pack("=I", self.deps_offset) + \ + pack("=I", self.deps_length) + \ + pack("=I", self.aux_offset) + \ + pack("=I", self.aux_length) + \ + pack("=I", self.flags) + \ + pack("=I", self.padding) + + +class OdexDependencies: + """ + This class can parse the odex dependencies + + :param buff: a Buff object string which represents the odex dependencies + """ + def __init__(self, buff): + self.modification_time = unpack("=I", buff.read(4))[0] + self.crc = unpack("=I", buff.read(4))[0] + self.dalvik_build = unpack("=I", buff.read(4))[0] + self.dependency_count = unpack("=I", buff.read(4))[0] + self.dependencies = [] + self.dependency_checksums = [] + + for i in range(0, self.dependency_count): + string_length = unpack("=I", buff.read(4))[0] + name_dependency = buff.read(string_length) + self.dependencies.append(name_dependency) + self.dependency_checksums.append(buff.read(20)) + + def get_dependencies(self): + """ + Return the list of dependencies + + :rtype: a list of strings + """ + return self.dependencies + + def get_raw(self): + dependencies = "" + + for idx, value in enumerate(self.dependencies): + dependencies += pack("=I", len(value)) + \ + pack("=%ds" % len(value), value) + \ + pack("=20s", self.dependency_checksums[idx]) + + return pack("=I", self.modification_time) + \ + pack("=I", self.crc) + \ + pack("=I", self.dalvik_build) + \ + pack("=I", self.dependency_count) + \ + dependencies + + +class DalvikOdexVMFormat(DalvikVMFormat): + """ + This class can parse an odex file + + :param buff: a string which represents the odex file + :param decompiler: associate a decompiler object to display the java source code + :type buff: string + :type decompiler: object + + :Example: + DalvikOdexVMFormat( open("classes.odex", "rb").read() ) + """ + def _preload(self, buff): + self.orig_buff = buff + self.magic = buff[:8] + if self.magic == ODEX_FILE_MAGIC_35 or self.magic == ODEX_FILE_MAGIC_36: + self.odex_header = OdexHeaderItem(self) + + self.set_idx(self.odex_header.deps_offset) + self.dependencies = OdexDependencies(self) + + self.padding = buff[self.odex_header.deps_offset + self.odex_header.deps_length:] + + self.set_idx(self.odex_header.dex_offset) + self.set_buff(self.read(self.odex_header.dex_length)) + self.set_idx(0) + + def save(self): + """ + Do not use ! + """ + dex_raw = super(DalvikOdexVMFormat, self).save() + return self.magic + self.odex_header.get_raw() + dex_raw + self.dependencies.get_raw() + self.padding + + def get_buff(self): + return self.magic + self.odex_header.get_raw() + super(DalvikOdexVMFormat, self).get_buff() + self.dependencies.get_raw() + self.padding + + def get_dependencies(self): + """ + Return the odex dependencies object + + :rtype: an OdexDependencies object + """ + return self.dependencies + + def get_format_type(self): + """ + Return the type + + :rtype: a string + """ + return "ODEX" + + +def get_params_info(nb, proto): + i_buffer = "# Parameters:\n" + + ret = proto.split(')') + params = ret[0][1:].split() + if params: + i_buffer += "# - local registers: v%d...v%d\n" % (0, nb - len(params) - 1) + j = 0 + for i in xrange(nb - len(params), nb): + i_buffer += "# - v%d:%s\n" % (i, get_type(params[j])) + j += 1 + else: + i_buffer += "# local registers: v%d...v%d\n" % (0, nb - 1) + + i_buffer += "#\n# - return:%s\n\n" % get_type(ret[1]) + + return i_buffer + + +def get_bytecodes_method(dex_object, ana_object, method): + mx = ana_object.get_method(method) + return get_bytecodes_methodx(method, mx) + + +def get_bytecodes_methodx(method, mx): + basic_blocks = mx.basic_blocks.gets() + i_buffer = "" + + idx = 0 + nb = 0 + + i_buffer += "# %s->%s%s [access_flags=%s]\n#\n" % (method.get_class_name(), method.get_name(), method.get_descriptor(), method.get_access_flags_string()) + if method.code != None: + i_buffer += get_params_info(method.code.get_registers_size(), method.get_descriptor()) + + for i in basic_blocks: + bb_buffer = "" + ins_buffer = "" + + bb_buffer += "%s : " % (i.name) + + instructions = i.get_instructions() + for ins in instructions: + ins_buffer += "\t%-8d(%08x) " % (nb, idx) + ins_buffer += "%-20s %s" % (ins.get_name(), ins.get_output(idx)) + + op_value = ins.get_op_value() + if ins == instructions[-1] and i.childs != []: + # packed/sparse-switch + if (op_value == 0x2b or op_value == 0x2c) and len(i.childs) > 1: + values = i.get_special_ins(idx).get_values() + bb_buffer += "[ D:%s " % (i.childs[0][2].name) + bb_buffer += ' '.join("%d:%s" % (values[j], i.childs[j + 1][2].name) for j in range(0, len(i.childs) - 1)) + " ]" + else: + #if len(i.childs) == 2: + # i_buffer += "%s[ %s%s " % (branch_false_color, i.childs[0][2].name, branch_true_color)) + # print_fct(' '.join("%s" % c[2].name for c in i.childs[1:]) + " ]%s" % normal_color) + #else : + bb_buffer += "[ " + ' '.join("%s" % c[2].name for c in i.childs) + " ]" + + idx += ins.get_length() + nb += 1 + + ins_buffer += "\n" + + if i.get_exception_analysis() != None: + ins_buffer += "\t%s\n" % (i.exception_analysis.show_buff()) + + i_buffer += bb_buffer + "\n" + ins_buffer + "\n" + + return i_buffer + + +def auto(filename, raw=None): + """ + :param filename: + :param raw: + :type filename: + :type raw: + """ + data_raw = raw + if raw == None: + data_raw = open(filename, "rb").read() + ret_type = is_android_raw(data_raw[:10]) + if ret_type == "DEX": + return DalvikVMFormat(data_raw) + elif ret_type == "ODEX": + return DalvikOdexVMFormat(data_raw) + + return None diff --git a/androguard/core/bytecodes/dvm_permissions.py b/androguard/core/bytecodes/dvm_permissions.py new file mode 100644 index 00000000..a5ed175b --- /dev/null +++ b/androguard/core/bytecodes/dvm_permissions.py @@ -0,0 +1,341 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# frameworks/base/core/res/AndroidManifest.xml +########################################## PERMISSIONS ######################################################## +DVM_PERMISSIONS = { + "MANIFEST_PERMISSION": { + + # MESSAGES + "SEND_SMS": ["dangerous", "send SMS messages", "Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."], + "SEND_SMS_NO_CONFIRMATION": ["signatureOrSystem", "send SMS messages", "send SMS messages via the Messaging app with no user input or confirmation"], + "RECEIVE_SMS": ["dangerous", "receive SMS", "Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."], + "RECEIVE_MMS": ["dangerous", "receive MMS", "Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."], + "RECEIVE_EMERGENCY_BROADCAST": [ "signatureOrSystem", "", "Allows an application to receive emergency cell broadcast messages, to record or display them to the user. Reserved for system apps." ], + "READ_CELL_BROADCASTS" : [ "dangerous", "received cell broadcast messages", "Allows an application to read previously received cell broadcast "\ + "messages and to register a content observer to get notifications when "\ + "a cell broadcast has been received and added to the database. For "\ + "emergency alerts, the database is updated immediately after the "\ + "alert dialog and notification sound/vibration/speech are presented."\ + "The \"read\" column is then updated after the user dismisses the alert."\ + "This enables supplementary emergency assistance apps to start loading "\ + "additional emergency information (if Internet access is available) "\ + "when the alert is first received, and to delay presenting the info "\ + "to the user until after the initial alert dialog is dismissed." ], + "READ_SMS" : [ "dangerous" , "read SMS or MMS" , "Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages." ], + "WRITE_SMS" : [ "dangerous" , "edit SMS or MMS" , "Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages." ], + "RECEIVE_WAP_PUSH" : [ "dangerous" , "receive WAP" , "Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you." ], + "BROADCAST_SMS" : [ "signature" , "send SMS-received broadcast" , "Allows an application to broadcast a notification that an SMS message has been received. Malicious applications may use this to forge incoming SMS messages." ], + "BROADCAST_WAP_PUSH" : [ "signature" , "send WAP-PUSH-received broadcast" , "Allows an application to broadcast a notification that a WAP-PUSH message has been received. Malicious applications may use this to forge MMS message receipt or to replace the content of any web page silently with malicious variants." ], + + # SOCIAL_INFO + "READ_CONTACTS" : [ "dangerous" , "read contact data" , "Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people." ], + "WRITE_CONTACTS" : [ "dangerous" , "write contact data" , "Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data." ], + "BIND_DIRECTORY_SEARCH" : [ "signatureOrSystem", "execute contacts directory search", "Allows an application to execute contacts directory search. This should only be used by ContactsProvider." ], + "READ_CALL_LOG": [ "dangerous", "read the user's call log.", "Allows an application to read the user's call log." ], + "WRITE_CALL_LOG": [ "dangerous", "write (but not read) the user's contacts data.", "Allows an application to write (but not read) the user's contacts data." ], + "READ_SOCIAL_STREAM" : [ "dangerous", "read from the user's social stream", "Allows an application to read from the user's social stream." ], + "WRITE_SOCIAL_STREAM" : [ "dangerous", "write the user's social stream", "Allows an application to write (but not read) the user's social stream data." ], + + # PERSONAL_INFO + "READ_PROFILE" : [ "dangerous", "read the user's personal profile data", "Allows an application to read the user's personal profile data."], + "WRITE_PROFILE" : [ "dangerous", "write the user's personal profile data", "Allows an application to write (but not read) the user's personal profile data."], + "RETRIEVE_WINDOW_CONTENT": [ "signatureOrSystem", "", "Allows an application to retrieve the content of the active window An active window is the window that has fired an accessibility event. " ], + "BIND_APPWIDGET" : [ "signatureOrSystem" , "choose widgets" , "Allows the application to tell the system which widgets can be used by which application. With this permission, applications can give access to personal data to other applications. Not for use by normal applications." ], + "BIND_KEYGUARD_APPWIDGET" : [ "signatureOrSystem", "", "Private permission, to restrict who can bring up a dialog to add a new keyguard widget" ], + + # CALENDAR + "READ_CALENDAR" : [ "dangerous" , "read calendar events" , "Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people." ], + "WRITE_CALENDAR": [ "dangerous" , "add or modify calendar events and send emails to guests" , "Allows an application to add or change the events on your calendar, which may send emails to guests. Malicious applications can use this to erase or modify your calendar events or to send emails to guests." ], + + + # USER_DICTIONARY + "READ_USER_DICTIONARY" : [ "dangerous" , "read user-defined dictionary" , "Allows an application to read any private words, names and phrases that the user may have stored in the user dictionary." ], + + # WRITE_USER_DICTIONARY + "WRITE_USER_DICTIONARY" : [ "normal" , "write to user-defined dictionary" , "Allows an application to write new words into the user dictionary." ], + + # BOOKMARKS + "READ_HISTORY_BOOKMARKS" : [ "dangerous" , "read Browser\'s history and bookmarks" , "Allows the application to read all the URLs that the browser has visited and all of the browser\'s bookmarks." ], + "WRITE_HISTORY_BOOKMARKS" : [ "dangerous" , "write Browser\'s history and bookmarks" , "Allows an application to modify the browser\'s history or bookmarks stored on your phone. Malicious applications can use this to erase or modify your browser\'s data." ], + + # DEVICE_ALARMS + "SET_ALARM" : [ "normal" , "set alarm in alarm clock" , "Allows the application to set an alarm in an installed alarm clock application. Some alarm clock applications may not implement this feature." ], + + # VOICEMAIL + "ADD_VOICEMAIL" : [ "dangerous", "add voicemails into the system", "Allows an application to add voicemails into the system." ], + + # LOCATION + "ACCESS_FINE_LOCATION" : [ "dangerous" , "fine (GPS) location" , "Access fine location sources, such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are and may consume additional battery power." ], + "ACCESS_COARSE_LOCATION" : [ "dangerous" , "coarse (network-based) location" , "Access coarse location sources, such as the mobile network database, to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are." ], + "ACCESS_MOCK_LOCATION" : [ "dangerous" , "mock location sources for testing" , "Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers." ], + "ACCESS_LOCATION_EXTRA_COMMANDS" : [ "normal" , "access extra location provider commands" , "Access extra location provider commands. Malicious applications could use this to interfere with the operation of the GPS or other location sources." ], + "INSTALL_LOCATION_PROVIDER" : [ "signatureOrSystem" , "permission to install a location provider" , "Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers, or monitor and report your location to an external source." ], + + + # NETWORK + "INTERNET" : [ "dangerous" , "full Internet access" , "Allows an application to create network sockets." ], + "ACCESS_NETWORK_STATE" : [ "normal" , "view network status" , "Allows an application to view the status of all networks." ], + "ACCESS_WIFI_STATE" : [ "normal" , "view Wi-Fi status" , "Allows an application to view the information about the status of Wi-Fi." ], + "CHANGE_WIFI_STATE" : [ "dangerous" , "change Wi-Fi status" , "Allows an application to connect to and disconnect from Wi-Fi access points and to make changes to configured Wi-Fi networks." ], + "CHANGE_NETWORK_STATE" : [ "normal" , "change network connectivity" , "Allows an application to change the state of network connectivity." ], + "ACCESS_WIMAX_STATE": [ "normal", "", "" ], + "CHANGE_WIMAX_STATE": [ "dangerous", "", "" ], + "NFC" : [ "dangerous" , "control Near-Field Communication" , "Allows an application to communicate with Near-Field Communication (NFC) tags, cards and readers." ], + "CONNECTIVITY_INTERNAL": [ "signatureOrSystem", "use privileged ConnectivityManager API", "Allows an internal user to use privileged ConnectivityManager API" ], + "RECEIVE_DATA_ACTIVITY_CHANGE": [ "signatureOrSystem", "", "" ], + + + # BLUETOOTH_NETWORK + "BLUETOOTH" : [ "dangerous" , "create Bluetooth connections" , "Allows an application to view configuration of the local Bluetooth phone and to make and accept connections with paired devices." ], + "BLUETOOTH_ADMIN" : [ "dangerous" , "bluetooth administration" , "Allows an application to configure the local Bluetooth phone and to discover and pair with remote devices." ], + + + # SYSTEM TOOLS + "BLUETOOTH_STACK": [ "signature", "", "" ], + "NET_ADMIN": [ "signature", "configure network interfaces, configure/use IPSec, etc", "Allows access to configure network interfaces, configure/use IPSec, etc." ], + "REMOTE_AUDIO_PLAYBACK": [ "signature", "remote audio playback", "Allows registration for remote audio playback" ], + "READ_EXTERNAL_STORAGE" : [ "normal", "read from external storage", "Allows an application to read from external storage" ], + "INTERACT_ACROSS_USERS": [ "signatureOrSystemOrDevelopment", "", "Allows an application to call APIs that allow it to do interactions across the users on the device, using singleton services and user-targeted broadcasts. This permission is not available to third party applications." ], + "INTERACT_ACROSS_USERS_FULL": [ "signature", "", "Fuller form of INTERACT_ACROSS_USERS that removes restrictions on where broadcasts can be sent and allows other types of interactions." ], + "MANAGE_USERS": [ "signatureOrSystem", "", "Allows an application to call APIs that allow it to query and manage users on the device. This permission is not available to third party applications." ], + "GET_DETAILED_TASKS": [ "signature", "", "Allows an application to get full detailed information about recently running tasks, with full fidelity to the real state." ], + "START_ANY_ACTIVITY": [ "signature", "", "Allows an application to start any activity, regardless of permission protection or exported state." ], + "SET_SCREEN_COMPATIBILITY": [ "signature", "", "Change the screen compatibility mode of applications" ], + "CHANGE_CONFIGURATION" : [ "signatureOrSystemOrDevelopment" , "change your UI settings" , "Allows an application to change the current configuration, such as the locale or overall font size." ], + "FORCE_STOP_PACKAGES" : [ "signature" , "force-stop other applications" , "Allows an application to stop other applications forcibly." ], + "SET_ANIMATION_SCALE" : [ "signatureOrSystemOrDevelopment" , "modify global animation speed" , "Allows an application to change the global animation speed (faster or slower animations) at any time." ], + "GET_PACKAGE_SIZE" : [ "normal" , "measure application storage space" , "Allows an application to retrieve its code, data and cache sizes" ], + "SET_PREFERRED_APPLICATIONS" : [ "signature" , "set preferred applications" , "Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you." ], + "BROADCAST_STICKY" : [ "normal" , "send sticky broadcast" , "Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory." ], + "MOUNT_UNMOUNT_FILESYSTEMS" : [ "signatureOrSystem" , "mount and unmount file systems" , "Allows the application to mount and unmount file systems for removable storage." ], + "MOUNT_FORMAT_FILESYSTEMS" : [ "signatureOrSystem" , "format external storage" , "Allows the application to format removable storage." ], + "ASEC_ACCESS" : [ "signature" , "get information on internal storage" , "Allows the application to get information on internal storage." ], + "ASEC_CREATE" : [ "signature" , "create internal storage" , "Allows the application to create internal storage." ], + "ASEC_DESTROY" : [ "signature" , "destroy internal storage" , "Allows the application to destroy internal storage." ], + "ASEC_MOUNT_UNMOUNT" : [ "signature" , "mount/unmount internal storage" , "Allows the application to mount/unmount internal storage." ], + "ASEC_RENAME" : [ "signature" , "rename internal storage" , "Allows the application to rename internal storage." ], + "WRITE_APN_SETTINGS" : [ "signatureOrSystem" , "write Access Point Name settings" , "Allows an application to modify the APN settings, such as Proxy and Port of any APN." ], + "SUBSCRIBED_FEEDS_READ" : [ "normal" , "read subscribed feeds" , "Allows an application to receive details about the currently synced feeds." ], + "SUBSCRIBED_FEEDS_WRITE" : [ "dangerous" , "write subscribed feeds" , "Allows an application to modify your currently synced feeds. This could allow a malicious application to change your synced feeds." ], + "CLEAR_APP_CACHE" : [ "dangerous" , "delete all application cache data" , "Allows an application to free phone storage by deleting files in application cache directory. Access is usually very restricted to system process." ], + "DIAGNOSTIC" : [ "signature" , "read/write to resources owned by diag" , "Allows an application to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator." ], + "BROADCAST_PACKAGE_REMOVED" : [ "signature" , "send package removed broadcast" , "Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other application running." ], + "BATTERY_STATS" : [ "dangerous" , "modify battery statistics" , "Allows the modification of collected battery statistics. Not for use by normal applications." ], + "MODIFY_APPWIDGET_BIND_PERMISSIONS" : [ "signatureOrSystem", "query/set which applications can bind AppWidgets.", "Internal permission allowing an application to query/set which applications can bind AppWidgets." ], + "CHANGE_BACKGROUND_DATA_SETTING" : [ "signature" , "change background data usage setting" , "Allows an application to change the background data usage setting." ], + "GLOBAL_SEARCH" : [ "signatureOrSystem" , "" , "This permission can be used on content providers to allow the global search " \ + "system to access their data. Typically it used when the provider has some " \ + "permissions protecting it (which global search would not be expected to hold)," \ + "and added as a read-only permission to the path in the provider where global "\ + "search queries are performed. This permission can not be held by regular applications; "\ + "it is used by applications to protect themselves from everyone else besides global search" ], + "GLOBAL_SEARCH_CONTROL" : [ "signature" , "" , "Internal permission protecting access to the global search " \ + "system: ensures that only the system can access the provider " \ + "to perform queries (since this otherwise provides unrestricted " \ + "access to a variety of content providers), and to write the " \ + "search statistics (to keep applications from gaming the source " \ + "ranking)." ], + "SET_WALLPAPER_COMPONENT" : [ "signatureOrSystem" , "set a live wallpaper" , "Allows applications to set a live wallpaper." ], + "READ_DREAM_STATE" : [ "signature", "", "Allows applications to read dream settings and dream state." ], + "WRITE_DREAM_STATE" : [ "signature", "", "Allows applications to write dream settings, and start or stop dreaming." ], + "WRITE_SETTINGS" : [ "normal" , "modify global system settings" , "Allows an application to modify the system\'s settings data. Malicious applications can corrupt your system\'s configuration." ], + + # ACCOUNTS + "GET_ACCOUNTS" : [ "normal" , "discover known accounts" , "Allows an application to access the list of accounts known by the phone." ], + "AUTHENTICATE_ACCOUNTS" : [ "dangerous" , "act as an account authenticator" , "Allows an application to use the account authenticator capabilities of the Account Manager, including creating accounts as well as obtaining and setting their passwords." ], + "USE_CREDENTIALS" : [ "dangerous" , "use the authentication credentials of an account" , "Allows an application to request authentication tokens." ], + "MANAGE_ACCOUNTS" : [ "dangerous" , "manage the accounts list" , "Allows an application to perform operations like adding and removing accounts and deleting their password." ], + "ACCOUNT_MANAGER" : [ "signature" , "act as the Account Manager Service" , "Allows an application to make calls to Account Authenticators" ], + + # AFFECTS_BATTERY + "CHANGE_WIFI_MULTICAST_STATE" : [ "dangerous" , "allow Wi-Fi Multicast reception" , "Allows an application to receive packets not directly addressed to your device. This can be useful when discovering services offered nearby. It uses more power than the non-multicast mode." ], + "VIBRATE" : [ "normal" , "control vibrator" , "Allows the application to control the vibrator." ], + "FLASHLIGHT" : [ "normal" , "control flashlight" , "Allows the application to control the flashlight." ], + "WAKE_LOCK" : [ "normal" , "prevent phone from sleeping" , "Allows an application to prevent the phone from going to sleep." ], + + # AUDIO_SETTINGS + "MODIFY_AUDIO_SETTINGS" : [ "normal" , "change your audio settings" , "Allows application to modify global audio settings, such as volume and routing." ], + + # HARDWARE_CONTROLS + "MANAGE_USB": [ "signatureOrSystem", "manage preferences and permissions for USB devices", "Allows an application to manage preferences and permissions for USB devices" ], + "ACCESS_MTP": [ "signatureOrSystem", "access the MTP USB kernel driver", "Allows an application to access the MTP USB kernel driver. For use only by the device side MTP implementation." ], + "HARDWARE_TEST" : [ "signature" , "test hardware" , "Allows the application to control various peripherals for the purpose of hardware testing." ], + + # MICROPHONE + "RECORD_AUDIO" : [ "dangerous" , "record audio" , "Allows application to access the audio record path." ], + + # CAMERA + "CAMERA" : [ "dangerous" , "take pictures and videos" , "Allows application to take pictures and videos with the camera. This allows the application to collect images that the camera is seeing at any time." ], + + # PHONE_CALLS + "PROCESS_OUTGOING_CALLS" : [ "dangerous" , "intercept outgoing calls" , "Allows application to process outgoing calls and change the number to be dialled. Malicious applications may monitor, redirect or prevent outgoing calls." ], + "MODIFY_PHONE_STATE" : [ "signatureOrSystem" , "modify phone status" , "Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls." ], + "READ_PHONE_STATE" : [ "dangerous" , "read phone state and identity" , "Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and so on." ], + "READ_PRIVILEGED_PHONE_STATE": [ "signatureOrSystem", "read access to privileged phone state", "Allows read access to privileged phone state." ], + "CALL_PHONE" : [ "dangerous" , "directly call phone numbers" , "Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call being placed. " ], + "USE_SIP" : [ "dangerous" , "make/receive Internet calls" , "Allows an application to use the SIP service to make/receive Internet calls." ], + + # STORAGE + "WRITE_EXTERNAL_STORAGE" : [ "dangerous" , "modify/delete SD card contents" , "Allows an application to write to the SD card." ], + "WRITE_MEDIA_STORAGE": [ "signatureOrSystem", "write to internal media storage", "Allows an application to write to internal media storage" ], + + # SCREENLOCK + "DISABLE_KEYGUARD" : [ "dangerous" , "disable key lock" , "Allows an application to disable the key lock and any associated password security. A legitimate example of this is the phone disabling the key lock when receiving an incoming phone call, then re-enabling the key lock when the call is finished." ], + + # APP_INFO + "GET_TASKS" : [ "dangerous" , "retrieve running applications" , "Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications." ], + "REORDER_TASKS" : [ "normal" , "reorder applications running" , "Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control." ], + "REMOVE_TASKS": [ "signature", "", "Allows an application to change to remove/kill tasks" ], + "RESTART_PACKAGES" : [ "normal" , "kill background processes" , "Allows an application to kill background processes of other applications, even if memory is not low." ], + "KILL_BACKGROUND_PROCESSES" : [ "normal" , "kill background processes" , "Allows an application to kill background processes of other applications, even if memory is not low." ], + "PERSISTENT_ACTIVITY" : [ "normal" , "make application always run" , "Allows an application to make parts of itself persistent, so that the system can\'t use it for other applications." ], + "RECEIVE_BOOT_COMPLETED" : [ "normal" , "automatically start at boot" , "Allows an application to start itself as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running." ], + + # DISPLAY + "SYSTEM_ALERT_WINDOW" : [ "dangerous" , "display system-level alerts" , "Allows an application to show system-alert windows. Malicious applications can take over the entire screen of the phone." ], + + # WALLPAPER + "SET_WALLPAPER" : [ "normal" , "set wallpaper" , "Allows the application to set the system wallpaper." ], + "SET_WALLPAPER_HINTS" : [ "normal" , "set wallpaper size hints" , "Allows the application to set the system wallpaper size hints." ], + + # SYSTEM_CLOCK + "SET_TIME_ZONE" : [ "normal" , "set time zone" , "Allows an application to change the phone\'s time zone." ], + + # STATUS_BAR + "EXPAND_STATUS_BAR" : [ "normal" , "expand/collapse status bar" , "Allows application to expand or collapse the status bar." ], + + # SYNC_SETTINGS + "READ_SYNC_SETTINGS" : [ "normal" , "read sync settings" , "Allows an application to read the sync settings, such as whether sync is enabled for Contacts." ], + "WRITE_SYNC_SETTINGS" : [ "normal" , "write sync settings" , "Allows an application to modify the sync settings, such as whether sync is enabled for Contacts." ], + "READ_SYNC_STATS" : [ "normal" , "read sync statistics" , "Allows an application to read the sync stats; e.g. the history of syncs that have occurred." ], + + # DEVELOPMENT_TOOLS + "WRITE_SECURE_SETTINGS" : [ "signatureOrSystemOrDevelopment" , "modify secure system settings" , "Allows an application to modify the system\'s secure settings data. Not for use by normal applications." ], + "DUMP" : [ "signatureOrSystemOrDevelopment" , "retrieve system internal status" , "Allows application to retrieve internal status of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never normally need." ], + "READ_LOGS" : [ "signatureOrSystemOrDevelopment" , "read sensitive log data" , "Allows an application to read from the system\'s various log files. This allows it to discover general information about what you are doing with the phone, potentially including personal or private information." ], + "SET_DEBUG_APP" : [ "signatureOrSystemOrDevelopment" , "enable application debugging" , "Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications." ], + "SET_PROCESS_LIMIT" : [ "signatureOrSystemOrDevelopment" , "limit number of running processes" , "Allows an application to control the maximum number of processes that will run. Never needed for normal applications." ], + "SET_ALWAYS_FINISH" : [ "signatureOrSystemOrDevelopment" , "make all background applications close" , "Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for normal applications." ], + "SIGNAL_PERSISTENT_PROCESSES" : [ "signatureOrSystemOrDevelopment" , "send Linux signals to applications" , "Allows application to request that the supplied signal be sent to all persistent processes." ], + "ACCESS_ALL_EXTERNAL_STORAGE" : [ "signature", "", "Allows an application to access all multi-user external storage" ], + + # No groups ... + "SET_TIME": [ "signatureOrSystem" , "set time" , "Allows an application to change the phone\'s clock time." ], + "ALLOW_ANY_CODEC_FOR_PLAYBACK": [ "signatureOrSystem", "", "Allows an application to use any media decoder when decoding for playback." ], + "STATUS_BAR" : [ "signatureOrSystem" , "disable or modify status bar" , "Allows application to disable the status bar or add and remove system icons." ], + "STATUS_BAR_SERVICE" : [ "signature" , "status bar" , "Allows the application to be the status bar." ], + "FORCE_BACK" : [ "signature" , "force application to close" , "Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for normal applications." ], + "UPDATE_DEVICE_STATS" : [ "signatureOrSystem" , "modify battery statistics" , "Allows the modification of collected battery statistics. Not for use by normal applications." ], + "INTERNAL_SYSTEM_WINDOW" : [ "signature" , "display unauthorised windows" , "Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications." ], + "MANAGE_APP_TOKENS" : [ "signature" , "manage application tokens" , "Allows applications to create and manage their own tokens, bypassing their normal Z-ordering. Should never be needed for normal applications." ], + "FREEZE_SCREEN": [ "signature", "", "Allows the application to temporarily freeze the screen for a full-screen transition." ], + "INJECT_EVENTS" : [ "signature" , "inject user events" , "Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window. Without this permission, you can only deliver events to windows in your own process. Very few applications should need to use this permission" ], + "FILTER_EVENTS": [ "signature", "", "Allows an application to register an input filter which filters the stream of user events (keys, touch, trackball) before they are dispatched to any window" ], + "RETRIEVE_WINDOW_INFO" : [ "signature", "", "Allows an application to retrieve info for a window from the window manager." ], + "TEMPORARY_ENABLE_ACCESSIBILITY": [ "signature", "", "Allows an application to temporary enable accessibility on the device." ], + "MAGNIFY_DISPLAY": [ "signature", "", "Allows an application to magnify the content of a display." ], + "SET_ACTIVITY_WATCHER" : [ "signature" , "monitor and control all application launching" , "Allows an application to monitor and control how the system launches activities. Malicious applications may compromise the system completely. This permission is needed only for development, never for normal phone usage." ], + "SHUTDOWN" : [ "signatureOrSystem" , "partial shutdown" , "Puts the activity manager into a shut-down state. Does not perform a complete shut down." ], + "STOP_APP_SWITCHES" : [ "signatureOrSystem" , "prevent app switches" , "Prevents the user from switching to another application." ], + "READ_INPUT_STATE" : [ "signature" , "record what you type and actions that you take" , "Allows applications to watch the keys that you press even when interacting with another application (such as entering a password). Should never be needed for normal applications." ], + "BIND_INPUT_METHOD" : [ "signature" , "bind to an input method" , "Allows the holder to bind to the top-level interface of an input method. Should never be needed for normal applications." ], + "BIND_ACCESSIBILITY_SERVICE" : [ "signature", "", "Must be required by an android.accessibilityservice.AccessibilityService to ensure that only the system can bind to it. " ], + "BIND_TEXT_SERVICE" : [ "signature", "", "Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it." ], + "BIND_VPN_SERVICE" : [ "signature", "", "Must be required by an {@link android.net.VpnService}, to ensure that only the system can bind to it." ], + "BIND_WALLPAPER" : [ "signatureOrSystem" , "bind to wallpaper" , "Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications." ], + "BIND_DEVICE_ADMIN" : [ "signature" , "interact with device admin" , "Allows the holder to send intents to a device administrator. Should never be needed for normal applications." ], + "SET_ORIENTATION" : [ "signature" , "change screen orientation" , "Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications." ], + "SET_POINTER_SPEED" : [ "signature", "", "Allows low-level access to setting the pointer speed. Not for use by normal applications. " ], + "SET_KEYBOARD_LAYOUT" : [ "signature", "", "Allows low-level access to setting the keyboard layout. Not for use by normal applications." ], + "INSTALL_PACKAGES" : [ "signatureOrSystem" , "directly install applications" , "Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions." ], + "CLEAR_APP_USER_DATA" : [ "signature" , "delete other applications\' data" , "Allows an application to clear user data." ], + "DELETE_CACHE_FILES" : [ "signatureOrSystem" , "delete other applications\' caches" , "Allows an application to delete cache files." ], + "DELETE_PACKAGES" : [ "signatureOrSystem" , "delete applications" , "Allows an application to delete Android packages. Malicious applications can use this to delete important applications." ], + "MOVE_PACKAGE" : [ "signatureOrSystem" , "Move application resources" , "Allows an application to move application resources from internal to external media and vice versa." ], + "CHANGE_COMPONENT_ENABLED_STATE" : [ "signatureOrSystem" , "enable or disable application components" , "Allows an application to change whether or not a component of another application is enabled. Malicious applications can use this to disable important phone capabilities. It is important to be careful with permission, as it is possible to bring application components into an unusable, inconsistent or unstable state." ], + "GRANT_REVOKE_PERMISSIONS" : [ "signature", "", "Allows an application to grant or revoke specific permissions." ], + "ACCESS_SURFACE_FLINGER" : [ "signature" , "access SurfaceFlinger" , "Allows application to use SurfaceFlinger low-level features." ], + "READ_FRAME_BUFFER" : [ "signatureOrSystem" , "read frame buffer" , "Allows application to read the content of the frame buffer." ], + "CONFIGURE_WIFI_DISPLAY" : [ "signature", "", "Allows an application to configure and connect to Wifi displays" ], + "CONTROL_WIFI_DISPLAY" : [ "signature", "", "Allows an application to control low-level features of Wifi displays such as opening an RTSP socket. This permission should only be used by the display manager." ], + "BRICK" : [ "signature" , "permanently disable phone" , "Allows the application to disable the entire phone permanently. This is very dangerous." ], + "REBOOT" : [ "signatureOrSystem" , "force phone reboot" , "Allows the application to force the phone to reboot." ], + "DEVICE_POWER" : [ "signature" , "turn phone on or off" , "Allows the application to turn the phone on or off." ], + "NET_TUNNELING" : [ "signature", "", "Allows low-level access to tun tap driver " ], + "FACTORY_TEST" : [ "signature" , "run in factory test mode" , "Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode." ], + "MASTER_CLEAR" : [ "signatureOrSystem" , "reset system to factory defaults" , "Allows an application to completely reset the system to its factory settings, erasing all data, configuration and installed applications." ], + "CALL_PRIVILEGED" : [ "signatureOrSystem" , "directly call any phone numbers" , "Allows the application to call any phone number, including emergency numbers, without your intervention. Malicious applications may place unnecessary and illegal calls to emergency services." ], + "PERFORM_CDMA_PROVISIONING" : [ "signatureOrSystem" , "directly start CDMA phone setup" , "Allows the application to start CDMA provisioning. Malicious applications may start CDMA provisioning unnecessarily" ], + "CONTROL_LOCATION_UPDATES" : [ "signatureOrSystem" , "control location update notifications" , "Allows enabling/disabling location update notifications from the radio. Not for use by normal applications." ], + "ACCESS_CHECKIN_PROPERTIES" : [ "signatureOrSystem" , "access check-in properties" , "Allows read/write access to properties uploaded by the check-in service. Not for use by normal applications." ], + "PACKAGE_USAGE_STATS" : [ "signatureOrSystem" , "update component usage statistics" , "Allows the modification of collected component usage statistics. Not for use by normal applications." ], + "BACKUP" : [ "signatureOrSystem" , "control system back up and restore" , "Allows the application to control the system\'s back-up and restore mechanism. Not for use by normal applications." ], + "CONFIRM_FULL_BACKUP" : [ "signature", "", "Allows a package to launch the secure full-backup confirmation UI. ONLY the system process may hold this permission." ], + "BIND_REMOTEVIEWS" : [ "signatureOrSystem", "", "Must be required by a {@link android.widget.RemoteViewsService}, to ensure that only the system can bind to it." ], + "ACCESS_CACHE_FILESYSTEM" : [ "signatureOrSystem" , "access the cache file system" , "Allows an application to read and write the cache file system." ], + "COPY_PROTECTED_DATA" : [ "signature" , "Allows to invoke default container service to copy content. Not for use by normal applications." , "Allows to invoke default container service to copy content. Not for use by normal applications." ], + "CRYPT_KEEPER" : [ "signatureOrSystem", "access to the encryption methods", "Internal permission protecting access to the encryption methods" ], + "READ_NETWORK_USAGE_HISTORY" : [ "signatureOrSystem", "read historical network usage for specific networks and applications.", "Allows an application to read historical network usage for specific networks and applications."], + "MANAGE_NETWORK_POLICY": [ "signature", "manage network policies and to define application-specific rules.", "Allows an application to manage network policies and to define application-specific rules."], + "MODIFY_NETWORK_ACCOUNTING" : [ "signatureOrSystem", "account its network traffic against other UIDs.", "Allows an application to account its network traffic against other UIDs."], + "C2D_MESSAGE" : [ "signature" , "C2DM permission." , "C2DM permission." ], + "PACKAGE_VERIFICATION_AGENT" : [ "signatureOrSystem", "Package verifier needs to have this permission before the PackageManager will trust it to verify packages.", "Package verifier needs to have this permission before the PackageManager will trust it to verify packages."], + "BIND_PACKAGE_VERIFIER" : [ "signature", "", "Must be required by package verifier receiver, to ensure that only the system can interact with it.."], + "SERIAL_PORT" : [ "signature", "", "Allows applications to access serial ports via the SerialManager." ], + "ACCESS_CONTENT_PROVIDERS_EXTERNALLY": [ "signature", "", "Allows the holder to access content providers from outside an ApplicationThread. This permission is enforced by the ActivityManagerService on the corresponding APIs,in particular ActivityManagerService#getContentProviderExternal(String) and ActivityManagerService#removeContentProviderExternal(String)."], + "UPDATE_LOCK" : [ "signatureOrSystem", "", "Allows an application to hold an UpdateLock, recommending that a headless OTA reboot "\ + "*not* occur while the lock is held"], + "WRITE_GSERVICES" : [ "signatureOrSystem" , "modify the Google services map" , "Allows an application to modify the Google services map. Not for use by normal applications." ], + + "ACCESS_USB" : [ "signatureOrSystem" , "access USB devices" , "Allows the application to access USB devices." ], + }, + + "MANIFEST_PERMISSION_GROUP": + { + "ACCOUNTS": "Permissions for direct access to the accounts managed by the Account Manager.", + "AFFECTS_BATTERY": "Used for permissions that provide direct access to the hardware on the device that has an effect on battery life. This includes vibrator, flashlight, etc.", + "APP_INFO": "Group of permissions that are related to the other applications installed on the system.", + "AUDIO_SETTINGS": "Used for permissions that provide direct access to speaker settings the device.", + "BLUETOOTH_NETWORK": "Used for permissions that provide access to other devices through Bluetooth.", + "BOOKMARKS": "Used for permissions that provide access to the user bookmarks and browser history.", + "CALENDAR": "Used for permissions that provide access to the device calendar to create / view events", + "CAMERA": "Used for permissions that are associated with accessing camera or capturing images/video from the device.", + "COST_MONEY": "Used for permissions that can be used to make the user spend money without their direct involvement.", + "DEVICE_ALARMS": "Used for permissions that provide access to the user voicemail box.", + "DEVELOPMENT_TOOLS": "Group of permissions that are related to development features.", + "DISPLAY": "Group of permissions that allow manipulation of how another application displays UI to the user.", + "HARDWARE_CONTROLS": "Used for permissions that provide direct access to the hardware on the device.", + "LOCATION": "Used for permissions that allow access to the user's current location.", + "MESSAGES": "Used for permissions that allow an application to send messages on behalf of the user or intercept messages being received by the user.", + "MICROPHONE": "Used for permissions that are associated with accessing microphone audio from the device. Note that phone calls also capture audio but are in a separate (more visible) permission group.", + "NETWORK": "Used for permissions that provide access to networking services.", + "PERSONAL_INFO": "Used for permissions that provide access to the user's private data, such as contacts, calendar events, e-mail messages, etc.", + "PHONE_CALLS": "Used for permissions that are associated with accessing and modifyign telephony state: intercepting outgoing calls, reading and modifying the phone state.", + "STORAGE": "Group of permissions that are related to SD card access.", + "SOCIAL_INFO": "Used for permissions that provide access to the user's social connections, such as contacts, call logs, social stream, etc. This includes both reading and writing of this data (which should generally be expressed as two distinct permissions)", + "SCREENLOCK": "Group of permissions that are related to the screenlock.", + "STATUS_BAR": "Used for permissions that change the status bar.", + "SYSTEM_CLOCK": "Group of permissions that are related to system clock.", + "SYSTEM_TOOLS": "Group of permissions that are related to system APIs.", + "SYNC_SETTINGS": "Used for permissions that access the sync settings or sync related information.", + "USER_DICTIONARY": "Used for permissions that provide access to the user calendar to create / view events.", + "VOICEMAIL": "Used for permissions that provide access to the user voicemail box.", + "WALLPAPER": "Group of permissions that allow manipulation of how another application displays UI to the user.", + "WRITE_USER_DICTIONARY": "Used for permissions that provide access to the user calendar to create / view events.", + }, +} diff --git a/androguard/core/bytecodes/jvm.py b/androguard/core/bytecodes/jvm.py new file mode 100644 index 00000000..c4dcf3d8 --- /dev/null +++ b/androguard/core/bytecodes/jvm.py @@ -0,0 +1,3445 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from struct import pack, unpack, calcsize +from collections import namedtuple +import re, zipfile, StringIO, os + +from androguard.core import bytecode +from androguard.core.bytecode import SV, SVs + + +######################################################## JAR FORMAT ######################################################## +class JAR : + def __init__(self, filename, raw=False) : + self.filename = filename + + if raw == True : + self.__raw = filename + else : + fd = open( filename, "rb" ) + self.__raw = fd.read() + fd.close() + + self.zip = zipfile.ZipFile( StringIO.StringIO( self.__raw ) ) + + def get_classes(self) : + l = [] + for i in self.zip.namelist() : + if ".class" in i : + l.append( (i, self.zip.read(i)) ) + + return l + + + def show(self) : + print self.zip.namelist() + +######################################################## CLASS FORMAT ######################################################## + +# Special functions to manage more easily special arguments of bytecode +def special_F0(x) : + return [ i for i in x ] + +def special_F0R(x) : + return [ x ] + +def special_F1(x) : + return (x[0] << 8) | x[1] + +def special_F1R(x) : + return [ (x & 0xFF00) >> 8, x & 0x00FF ] + +def special_F2(x) : + v = ((x[0] << 8) | x[1]) + if v > 0x7FFF : + v = (0x7FFF & v) - 0x8000 + + return v + +def special_F2R(x) : + val = x & 0xFFFF + return [ (val & 0xFF00) >> 8, val & 0x00FF ] + +def special_F3(x) : + val = (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] + if val > 0x7fffffff : + val = (0x7fffffff & val) - 0x80000000 + return val + +def special_F3R(x) : + val = x & 0xFFFFFFFF + return [ (val & 0xFF000000) >> 24, (val & 0x00FF0000) >> 16, (val & 0x0000FF00) >> 8, val & 0x000000FF ] + +def special_F4(x) : + return [ (x[0] << 8) | x[1], x[2] ] + +def special_F4R(x) : + pass + +def specialSwitch(x) : + return x + +FD = { "B" : "byte", + "C" : "char", + "D" : "double", + "F" : "float", + "I" : "int", + "J" : "long", + "S" : "short", + "Z" : "boolean", + "V" : "void", +} + +def formatFD(v) : + #print v, "--->", + l = [] + + i = 0 + while i < len(v) : + if v[i] == "L" : + base_object = "" + i = i + 1 + while v[i] != ";" : + base_object += v[i] + i = i + 1 + l.append( os.path.basename( base_object ) ) + elif v[i] == "[" : + z = [] + while v[i] == "[" : + z.append( "[]" ) + i = i + 1 + + l.append( [ FD[ v[i] ], z ] ) + else : + l.append( FD[ v[i] ] ) + i = i + 1 + + #print l + return l + +def TableSwitch(idx, raw_format) : + r_buff = [] + r_format = ">" + + idx = idx + 1 + + n = 0 + if idx % 4 : + n = 4 - (idx % 4) + + for i in range(0, n) : + r_buff.append( "bytepad%d" % i ) + r_format += "B" + + r_buff.extend( [ "default", "low", "high" ] ) + r_format += "LLL" + + idx = 1 + n + 4 + + low = unpack('>L', raw_format[ idx : idx + 4 ])[0] + idx = idx + 4 + high = unpack('>L', raw_format[ idx : idx + 4 ])[0] + + for i in range(0, high - low + 1) : + r_buff.append( "offset%d" % i ) + r_format += "L" + + return specialSwitch, specialSwitch, r_buff, r_format, None + +def LookupSwitch(idx, raw_format) : + r_buff = [] + r_format = ">" + + idx = idx + 1 + + n = 0 + if idx % 4 : + n = 4 - (idx % 4) + + for i in range(0, n) : + r_buff.append( "bytepad%d" % i ) + r_format += "B" + + r_buff.extend( [ "default", "npairs" ] ) + r_format += "LL" + + idx = 1 + n + 4 + for i in range(0, unpack('>L', raw_format[ idx : idx + 4 ])[0]) : + r_buff.extend( [ "match%d" % i, "offset%d" % i ] ) + r_format += "LL" + + return specialSwitch, specialSwitch, r_buff, r_format, None + +# The list of java bytecodes, with their value, name, and special functions ! +JAVA_OPCODES = { + 0x32 : [ "aaload" ], + 0x53 : [ "aastore" ], + 0x1 : [ "aconst_null" ], + 0x19 : [ "aload", "index:B", special_F0, special_F0, None ], + 0x2a : [ "aload_0" ], + 0x2b : [ "aload_1" ], + 0x2c : [ "aload_2" ], + 0x2d : [ "aload_3" ], + 0xbd : [ "anewarray", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_class" ], + 0xb0 : [ "areturn" ], + 0xbe : [ "arraylength" ], + 0x3a : [ "astore", "index:B", special_F0, special_F0, None ], + 0x4b : [ "astore_0" ], + 0x4c : [ "astore_1" ], + 0x4d : [ "astore_2" ], + 0x4e : [ "astore_3" ], + 0xbf : [ "athrow" ], + 0x33 : [ "baload" ], + 0x54 : [ "bastore" ], + 0x10 : [ "bipush", "byte:B", special_F0, special_F0R, None ], + 0x34 : [ "caload" ], + 0x55 : [ "castore" ], + 0xc0 : [ "checkcast", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, None ], + 0x90 : [ "d2f" ], + 0x8e : [ "d2i" ], + 0x8f : [ "d2l" ], + 0x63 : [ "dadd" ], + 0x31 : [ "daload" ], + 0x52 : [ "dastore" ], + 0x98 : [ "dcmpg" ], + 0x97 : [ "dcmpl" ], + 0xe : [ "dconst_0" ], + 0xf : [ "dconst_1" ], + 0x6f : [ "ddiv" ], + 0x18 : [ "dload", "index:B", special_F0, special_F0, None ], + 0x26 : [ "dload_0" ], + 0x27 : [ "dload_1" ], + 0x28 : [ "dload_2" ], + 0x29 : [ "dload_3" ], + 0x6b : [ "dmul" ], + 0x77 : [ "dneg" ], + 0x73 : [ "drem" ], + 0xaf : [ "dreturn" ], + 0x39 : [ "dstore", "index:B", special_F0, special_F0, None ], + 0x47 : [ "dstore_0" ], + 0x48 : [ "dstore_1" ], + 0x49 : [ "dstore_2" ], + 0x4a : [ "dstore_3" ], + 0x67 : [ "dsub" ], + 0x59 : [ "dup" ], + 0x5a : [ "dup_x1" ], + 0x5b : [ "dup_x2" ], + 0x5c : [ "dup2" ], + 0x5d : [ "dup2_x1" ], + 0x5e : [ "dup2_x2" ], + 0x8d : [ "f2d" ], + 0x8b : [ "f2i" ], + 0x8c : [ "f2l" ], + 0x62 : [ "fadd" ], + 0x30 : [ "faload" ], + 0x51 : [ "fastore" ], + 0x96 : [ "fcmpg" ], + 0x95 : [ "fcmpl" ], + 0xb : [ "fconst_0" ], + 0xc : [ "fconst_1" ], + 0xd : [ "fconst_2" ], + 0x6e : [ "fdiv" ], + 0x17 : [ "fload", "index:B", special_F0, special_F0, None ], + 0x22 : [ "fload_0" ], + 0x23 : [ "fload_1" ], + 0x24 : [ "fload_2" ], + 0x25 : [ "fload_3" ], + 0x6a : [ "fmul" ], + 0x76 : [ "fneg" ], + 0x72 : [ "frem" ], + 0xae : [ "freturn" ], + 0x38 : [ "fstore", "index:B", special_F0, special_F0, None ], + 0x43 : [ "fstore_0" ], + 0x44 : [ "fstore_1" ], + 0x45 : [ "fstore_2" ], + 0x46 : [ "fstore_3" ], + 0x66 : [ "fsub" ], + 0xb4 : [ "getfield", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field" ], + 0xb2 : [ "getstatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index" ], + 0xa7 : [ "goto", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xc8 : [ "goto_w", "branchbyte1:B branchbyte2:B branchbyte3:B branchbyte4:B", special_F3, special_F3R, None ], + 0x91 : [ "i2b" ], + 0x92 : [ "i2c" ], + 0x87 : [ "i2d" ], + 0x86 : [ "i2f" ], + 0x85 : [ "i2l" ], + 0x93 : [ "i2s" ], + 0x60 : [ "iadd" ], + 0x2e : [ "iaload" ], + 0x7e : [ "iand" ], + 0x4f : [ "iastore" ], + 0x2 : [ "iconst_m1" ], + 0x3 : [ "iconst_0" ], + 0x4 : [ "iconst_1" ], + 0x5 : [ "iconst_2" ], + 0x6 : [ "iconst_3" ], + 0x7 : [ "iconst_4" ], + 0x8 : [ "iconst_5" ], + 0x6c : [ "idiv" ], + 0xa5 : [ "if_acmpeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa6 : [ "if_acmpne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9f : [ "if_icmpeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa0 : [ "if_icmpne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa1 : [ "if_icmplt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa2 : [ "if_icmpge", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa3 : [ "if_icmpgt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xa4 : [ "if_icmple", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x99 : [ "ifeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9a : [ "ifne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9b : [ "iflt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9c : [ "ifge", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9d : [ "ifgt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x9e : [ "ifle", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xc7 : [ "ifnonnull", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xc6 : [ "ifnull", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0x84 : [ "iinc", "index:B const:B", special_F0, special_F0, None ], + 0x15 : [ "iload", "index:B", special_F0, special_F0, None ], + 0x1a : [ "iload_0" ], + 0x1b : [ "iload_1" ], + 0x1c : [ "iload_2" ], + 0x1d : [ "iload_3" ], + 0x68 : [ "imul" ], + 0x74 : [ "ineg" ], + 0xc1 : [ "instanceof", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None ], + 0xb9 : [ "invokeinterface", "indexbyte1:B indexbyte2:B count:B null:B", special_F1, special_F1R, "get_interface", "get_interface_index" ], + 0xb7 : [ "invokespecial", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index" ], + 0xb8 : [ "invokestatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index" ], + 0xb6 : [ "invokevirtual", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index" ], + 0x80 : [ "ior" ], + 0x70 : [ "irem" ], + 0xac : [ "ireturn" ], + 0x78 : [ "ishl" ], + 0x7a : [ "ishr" ], + 0x36 : [ "istore", "index:B", special_F0, special_F0, None ], + 0x3b : [ "istore_0" ], + 0x3c : [ "istore_1" ], + 0x3d : [ "istore_2" ], + 0x3e : [ "istore_3" ], + 0x64 : [ "isub" ], + 0x7c : [ "iushr" ], + 0x82 : [ "ixor" ], + 0xa8 : [ "jsr", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None ], + 0xc9 : [ "jsr_w", "branchbyte1:B branchbyte2:B branchbyte3:B branchbyte4:B", special_F3, special_F3R, None ], + 0x8a : [ "l2d" ], + 0x89 : [ "l2f" ], + 0x88 : [ "l2i" ], + 0x61 : [ "ladd" ], + 0x2f : [ "laload" ], + 0x7f : [ "land" ], + 0x50 : [ "lastore" ], + 0x94 : [ "lcmp" ], + 0x9 : [ "lconst_0" ], + 0xa : [ "lconst_1" ], + 0x12 : [ "ldc", "index:B", special_F0, special_F0R, "get_value" ], + 0x13 : [ "ldc_w", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None ], + 0x14 : [ "ldc2_w", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None ], + 0x6d : [ "ldiv" ], + 0x16 : [ "lload", "index:B", special_F0, special_F0, None ], + 0x1e : [ "lload_0" ], + 0x1f : [ "lload_1" ], + 0x20 : [ "lload_2" ], + 0x21 : [ "lload_3" ], + 0x69 : [ "lmul" ], + 0x75 : [ "lneg" ], + 0xab : [ "lookupswitch", LookupSwitch ], + 0x81 : [ "lor" ], + 0x71 : [ "lrem" ], + 0xad : [ "lreturn" ], + 0x79 : [ "lshl" ], + 0x7b : [ "lshr" ], + 0x37 : [ "lstore", "index:B", special_F0, special_F0, None ], + 0x3f : [ "lstore_0" ], + 0x40 : [ "lstore_1" ], + 0x41 : [ "lstore_2" ], + 0x42 : [ "lstore_3" ], + 0x65 : [ "lsub" ], + 0x7d : [ "lushr" ], + 0x83 : [ "lxor" ], + 0xc2 : [ "monitorenter" ], + 0xc3 : [ "monitorexit" ], + 0xc5 : [ "multianewarray", "indexbyte1:B indexbyte2:B dimensions:B", special_F4, special_F4R, None ], + 0xbb : [ "new", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_class", "get_class_index2" ], + 0xbc : [ "newarray", "atype:B", special_F0, special_F0, "get_array_type" ], + 0x0 : [ "nop" ], + 0x57 : [ "pop" ], + 0x58 : [ "pop2" ], + 0xb5 : [ "putfield", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index" ], + 0xb3 : [ "putstatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index" ], + 0xa9 : [ "ret", "index:B", special_F0, special_F0, None ], + 0xb1 : [ "return" ], + 0x35 : [ "saload" ], + 0x56 : [ "sastore" ], + 0x11 : [ "sipush", "byte1:B byte2:B", special_F1, special_F1R, None ], + 0x5f : [ "swap" ], + 0xaa : [ "tableswitch", TableSwitch ], + 0xc4 : [ "wide" ], # FIXME + } + +# Invert the value and the name of the bytecode +INVERT_JAVA_OPCODES = dict([( JAVA_OPCODES[k][0], k ) for k in JAVA_OPCODES]) + +# List of java bytecodes which can modify the control flow +BRANCH_JVM_OPCODES = [ "goto", "goto_w", "if_acmpeq", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ifnonnull", "ifnull", "jsr", "jsr_w" ] + +BRANCH2_JVM_OPCODES = [ "goto", "goto.", "jsr", "jsr.", "if.", "return", ".return", "tableswitch", "lookupswitch" ] + +MATH_JVM_OPCODES = { ".and" : '&', + ".add" : '+', + ".sub" : '-', + ".mul" : '*', + ".div" : '/', + ".shl" : '<<', + ".shr" : '>>', + ".xor" : '^', + ".or" : '|', + } + +MATH_JVM_RE = [] +for i in MATH_JVM_OPCODES : + MATH_JVM_RE.append( (re.compile( i ), MATH_JVM_OPCODES[i]) ) + +INVOKE_JVM_OPCODES = [ "invoke." ] +FIELD_READ_JVM_OPCODES = [ "get." ] +FIELD_WRITE_JVM_OPCODES = [ "put." ] + +BREAK_JVM_OPCODES = [ "invoke.", "put.", ".store", "iinc", "pop", ".return", "if." ] + +INTEGER_INSTRUCTIONS = [ "bipush", "sipush" ] + +def EXTRACT_INFORMATION_SIMPLE(op_value) : + """Extract information (special functions) about a bytecode""" + r_function = JAVA_OPCODES[ op_value ][2] + v_function = JAVA_OPCODES[ op_value ][3] + f_function = JAVA_OPCODES[ op_value ][4] + + r_format = ">" + r_buff = [] + + format = JAVA_OPCODES[ op_value ][1] + l = format.split(" ") + for j in l : + operands = j.split(":") + + name = operands[0] + " " + val = operands[1] + + r_buff.append( name.replace(' ', '') ) + r_format += val + + return ( r_function, v_function, r_buff, r_format, f_function ) + +def EXTRACT_INFORMATION_VARIABLE(idx, op_value, raw_format) : + r_function, v_function, r_buff, r_format, f_function = JAVA_OPCODES[ op_value ][1]( idx, raw_format ) + return ( r_function, v_function, r_buff, r_format, f_function ) + +def determineNext(i, end, m) : + #if "invoke" in i.get_name() : + # self.childs.append( self.end, -1, ExternalMethod( i.get_operands()[0], i.get_operands()[1], i.get_operands()[2] ) ) + # self.childs.append( self.end, self.end, self.__context.get_basic_block( self.end + 1 ) ) + if "return" in i.get_name() : + return [ -1 ] + elif "goto" in i.get_name() : + return [ i.get_operands() + end ] + elif "jsr" in i.get_name() : + return [ i.get_operands() + end ] + elif "if" in i.get_name() : + return [ end + i.get_length(), i.get_operands() + end ] + elif "tableswitch" in i.get_name() : + x = [] + + x.append( i.get_operands().default + end ) + for idx in range(0, (i.get_operands().high - i.get_operands().low) + 1) : + off = getattr(i.get_operands(), "offset%d" % idx) + + x.append( off + end ) + return x + elif "lookupswitch" in i.get_name() : + x = [] + + x.append( i.get_operands().default + end ) + + for idx in range(0, i.get_operands().npairs) : + off = getattr(i.get_operands(), "offset%d" % idx) + x.append( off + end ) + return x + return [] + +def determineException(vm, m) : + return [] + +def classToJclass(x) : + return "L%s;" % x + +METHOD_INFO = [ '>HHHH', namedtuple("MethodInfo", "access_flags name_index descriptor_index attributes_count") ] +ATTRIBUTE_INFO = [ '>HL', namedtuple("AttributeInfo", "attribute_name_index attribute_length") ] +FIELD_INFO = [ '>HHHH', namedtuple("FieldInfo", "access_flags name_index descriptor_index attributes_count") ] +LINE_NUMBER_TABLE = [ '>HH', namedtuple("LineNumberTable", "start_pc line_number") ] +EXCEPTION_TABLE = [ '>HHHH', namedtuple("ExceptionTable", "start_pc end_pc handler_pc catch_type") ] +LOCAL_VARIABLE_TABLE = [ '>HHHHH', namedtuple("LocalVariableTable", "start_pc length name_index descriptor_index index") ] +LOCAL_VARIABLE_TYPE_TABLE = [ '>HHHHH', namedtuple("LocalVariableTypeTable", "start_pc length name_index signature_index index") ] + +CODE_LOW_STRUCT = [ '>HHL', namedtuple( "LOW", "max_stack max_locals code_length" ) ] + +ARRAY_TYPE = { + 4 : "T_BOOLEAN", + 5 : "T_CHAR", + 6 : "T_FLOAT", + 7 : "T_DOUBLE", + 8 : "T_BYTE", + 9 : "T_SHORT", + 10 : "T_INT", + 11 : "T_LONG", + } +INVERT_ARRAY_TYPE = dict([( ARRAY_TYPE[k][0], k ) for k in ARRAY_TYPE]) + + +ACC_CLASS_FLAGS = { + 0x0001 : [ "ACC_PUBLIC", "Declared public; may be accessed from outside its package." ], + 0x0010 : [ "ACC_FINAL", "Declared final; no subclasses allowed." ], + 0x0020 : [ "ACC_SUPER", "Treat superclass methods specially when invoked by the invokespecial instruction." ], + 0x0200 : [ "ACC_INTERFACE", "Is an interface, not a class." ], + 0x0400 : [ "ACC_ABSTRACT", "Declared abstract; may not be instantiated." ], + } +INVERT_ACC_CLASS_FLAGS = dict([( ACC_CLASS_FLAGS[k][0], k ) for k in ACC_CLASS_FLAGS]) + + +ACC_FIELD_FLAGS = { + 0x0001 : [ "ACC_PUBLIC", "Declared public; may be accessed from outside its package." ], + 0x0002 : [ "ACC_PRIVATE", "Declared private; usable only within the defining class." ], + 0x0004 : [ "ACC_PROTECTED", "Declared protected; may be accessed within subclasses." ], + 0x0008 : [ "ACC_STATIC", "Declared static." ], + 0x0010 : [ "ACC_FINAL", "Declared final; no further assignment after initialization." ], + 0x0040 : [ "ACC_VOLATILE", "Declared volatile; cannot be cached." ], + 0x0080 : [ "ACC_TRANSIENT", "Declared transient; not written or read by a persistent object manager." ], + } +INVERT_ACC_FIELD_FLAGS = dict([( ACC_FIELD_FLAGS[k][0], k ) for k in ACC_FIELD_FLAGS]) + + +ACC_METHOD_FLAGS = { + 0x0001 : [ "ACC_PUBLIC", "Declared public; may be accessed from outside its package." ], + 0x0002 : [ "ACC_PRIVATE", "Declared private; accessible only within the defining class." ], + 0x0004 : [ "ACC_PROTECTED", "Declared protected; may be accessed within subclasses." ], + 0x0008 : [ "ACC_STATIC", "Declared static." ], + 0x0010 : [ "ACC_FINAL", "Declared final; may not be overridden." ], + 0x0020 : [ "ACC_SYNCHRONIZED", "Declared synchronized; invocation is wrapped in a monitor lock." ], + 0x0100 : [ "ACC_NATIVE", "Declared native; implemented in a language other than Java." ], + 0x0400 : [ "ACC_ABSTRACT", "Declared abstract; no implementation is provided." ], + 0x0800 : [ "ACC_STRICT", "Declared strictfp; floating-point mode is FP-strict" ] + } +INVERT_ACC_METHOD_FLAGS = dict([( ACC_METHOD_FLAGS[k][0], k ) for k in ACC_METHOD_FLAGS]) + +class CpInfo(object) : + """Generic class to manage constant info object""" + def __init__(self, buff) : + self.__tag = SV( '>B', buff.read_b(1) ) + + self.__bytes = None + self.__extra = 0 + + tag_value = self.__tag.get_value() + format = CONSTANT_INFO[ tag_value ][1] + + self.__name = CONSTANT_INFO[ tag_value ][0] + + self.format = SVs( format, CONSTANT_INFO[ tag_value ][2], buff.read( calcsize( format ) ) ) + + # Utf8 value ? + if tag_value == 1 : + self.__extra = self.format.get_value().length + self.__bytes = SVs( ">%ss" % self.format.get_value().length, namedtuple( CONSTANT_INFO[ tag_value ][0] + "_next", "bytes" ), buff.read( self.format.get_value().length ) ) + + def get_format(self) : + return self.format + + def get_name(self) : + return self.__name + + def get_bytes(self) : + return self.__bytes.get_value().bytes + + def set_bytes(self, name) : + self.format.set_value( { "length" : len(name) } ) + self.__extra = self.format.get_value().length + self.__bytes = SVs( ">%ss" % self.format.get_value().length, namedtuple( CONSTANT_INFO[ self.__tag.get_value() ][0] + "_next", "bytes" ), name ) + + def get_length(self) : + return self.__extra + calcsize( CONSTANT_INFO[ self.__tag.get_value() ][1] ) + + def get_raw(self) : + if self.__bytes != None : + return self.format.get_value_buff() + self.__bytes.get_value_buff() + return self.format.get_value_buff() + + def show(self) : + if self.__bytes != None : + print self.format.get_value(), self.__bytes.get_value() + else : + print self.format.get_value() + +class MethodRef(CpInfo) : + def __init__(self, class_manager, buff) : + super(MethodRef, self).__init__( buff ) + + def get_class_index(self) : + return self.format.get_value().class_index + + def get_name_and_type_index(self) : + return self.format.get_value().name_and_type_index + +class InterfaceMethodRef(CpInfo) : + def __init__(self, class_manager, buff) : + super(InterfaceMethodRef, self).__init__( buff ) + + def get_class_index(self) : + return self.format.get_value().class_index + + def get_name_and_type_index(self) : + return self.format.get_value().name_and_type_index + +class FieldRef(CpInfo) : + def __init__(self, class_manager, buff) : + super(FieldRef, self).__init__( buff ) + + def get_class_index(self) : + return self.format.get_value().class_index + + def get_name_and_type_index(self) : + return self.format.get_value().name_and_type_index + +class Class(CpInfo) : + def __init__(self, class_manager, buff) : + super(Class, self).__init__( buff ) + + def get_name_index(self) : + return self.format.get_value().name_index + +class Utf8(CpInfo) : + def __init__(self, class_manager, buff) : + super(Utf8, self).__init__( buff ) + +class String(CpInfo) : + def __init__(self, class_manager, buff) : + super(String, self).__init__( buff ) + +class Integer(CpInfo) : + def __init__(self, class_manager, buff) : + super(Integer, self).__init__( buff ) + +class Float(CpInfo) : + def __init__(self, class_manager, buff) : + super(Float, self).__init__( buff ) + +class Long(CpInfo) : + def __init__(self, class_manager, buff) : + super(Long, self).__init__( buff ) + +class Double(CpInfo) : + def __init__(self, class_manager, buff) : + super(Double, self).__init__( buff ) + +class NameAndType(CpInfo) : + def __init__(self, class_manager, buff) : + super(NameAndType, self).__init__( buff ) + + def get_get_name_index(self) : + return self.format.get_value().get_name_index + + def get_name_index(self) : + return self.format.get_value().name_index + + def get_descriptor_index(self) : + return self.format.get_value().descriptor_index + +class EmptyConstant : + def __init__(self) : + pass + + def get_name(self) : + return "" + + def get_raw(self) : + return "" + + def get_length(self) : + return 0 + + def show(self) : + pass + + +CONSTANT_INFO = { + 7 : [ "CONSTANT_Class", '>BH', namedtuple( "CONSTANT_Class_info", "tag name_index" ), Class ], + 9 : [ "CONSTANT_Fieldref", '>BHH', namedtuple( "CONSTANT_Fieldref_info", "tag class_index name_and_type_index" ), FieldRef ], + 10 : [ "CONSTANT_Methodref", '>BHH', namedtuple( "CONSTANT_Methodref_info", "tag class_index name_and_type_index" ), MethodRef ], + 11 : [ "CONSTANT_InterfaceMethodref", '>BHH', namedtuple( "CONSTANT_InterfaceMethodref_info", "tag class_index name_and_type_index" ), InterfaceMethodRef ], + 8 : [ "CONSTANT_String", '>BH', namedtuple( "CONSTANT_String_info", "tag string_index" ), String ], + 3 : [ "CONSTANT_Integer", '>BL', namedtuple( "CONSTANT_Integer_info", "tag bytes" ), Integer ], + 4 : [ "CONSTANT_Float", '>BL', namedtuple( "CONSTANT_Float_info", "tag bytes" ), Float ], + 5 : [ "CONSTANT_Long", '>BLL', namedtuple( "CONSTANT_Long_info", "tag high_bytes low_bytes" ), Long ], + 6 : [ "CONSTANT_Double", '>BLL', namedtuple( "CONSTANT_Long_info", "tag high_bytes low_bytes" ), Double ], + 12 : [ "CONSTANT_NameAndType", '>BHH', namedtuple( "CONSTANT_NameAndType_info", "tag name_index descriptor_index" ), NameAndType ], + 1 : [ "CONSTANT_Utf8", '>BH', namedtuple( "CONSTANT_Utf8_info", "tag length" ), Utf8 ] + } +INVERT_CONSTANT_INFO = dict([( CONSTANT_INFO[k][0], k ) for k in CONSTANT_INFO]) +ITEM_Top = 0 +ITEM_Integer = 1 +ITEM_Float = 2 +ITEM_Long = 4 +ITEM_Double = 3 +ITEM_Null = 5 +ITEM_UninitializedThis = 6 +ITEM_Object = 7 +ITEM_Uninitialized = 8 + +VERIFICATION_TYPE_INFO = { + ITEM_Top : [ "Top_variable_info", '>B', namedtuple( "Top_variable_info", "tag" ) ], + ITEM_Integer : [ "Integer_variable_info", '>B', namedtuple( "Integer_variable_info", "tag" ) ], + ITEM_Float : [ "Float_variable_info", '>B', namedtuple( "Float_variable_info", "tag" ) ], + ITEM_Long : [ "Long_variable_info", '>B', namedtuple( "Long_variable_info", "tag" ) ], + ITEM_Double : [ "Double_variable_info", '>B', namedtuple( "Double_variable_info", "tag" ) ], + ITEM_Null : [ "Null_variable_info", '>B', namedtuple( "Null_variable_info", "tag" ) ], + ITEM_UninitializedThis : [ "UninitializedThis_variable_info", '>B', namedtuple( "UninitializedThis_variable_info", "tag" ) ], + ITEM_Object : [ "Object_variable_info", '>BH', namedtuple( "Object_variable_info", "tag cpool_index" ), [ ("cpool_index", "get_class") ] ], + ITEM_Uninitialized : [ "Uninitialized_variable_info", '>BH', namedtuple( "Uninitialized_variable_info", "tag offset" ) ], + } + +class FieldInfo : + """An object which represents a Field""" + def __init__(self, class_manager, buff) : + self.__raw_buff = buff.read( calcsize( FIELD_INFO[0] ) ) + self.format = SVs( FIELD_INFO[0], FIELD_INFO[1], self.__raw_buff ) + + self.__CM = class_manager + self.__attributes = [] + + for i in range(0, self.format.get_value().attributes_count) : + ai = AttributeInfo( self.__CM, buff ) + self.__attributes.append( ai ) + + def get_raw(self) : + return self.__raw_buff + ''.join(x.get_raw() for x in self.__attributes) + + def get_length(self) : + val = 0 + for i in self.__attributes : + val += i.length + return val + calcsize( FIELD_INFO[0] ) + + def get_access(self) : + try : + return ACC_FIELD_FLAGS[ self.format.get_value().access_flags ][0] + except KeyError : + ok = True + access = "" + for i in ACC_FIELD_FLAGS : + if (i & self.format.get_value().access_flags) == i : + access += ACC_FIELD_FLAGS[ i ][0] + " " + ok = False + + if ok == False : + return access[:-1] + + return "ACC_PRIVATE" + + def set_access(self, value) : + self.format.set_value( { "access_flags" : value } ) + + def get_class_name(self) : + return self.__CM.get_this_class_name() + + def get_name(self) : + return self.__CM.get_string( self.format.get_value().name_index ) + + def set_name(self, name) : + return self.__CM.set_string( self.format.get_value().name_index, name ) + + def get_descriptor(self) : + return self.__CM.get_string( self.format.get_value().descriptor_index ) + + def set_descriptor(self, name) : + return self.__CM.set_string( self.format.get_value().descriptor_index, name ) + + def get_attributes(self) : + return self.__attributes + + def get_name_index(self) : + return self.format.get_value().name_index + + def get_descriptor_index(self) : + return self.format.get_value().descriptor_index + + def show(self) : + print self.format.get_value(), self.get_name(), self.get_descriptor() + for i in self.__attributes : + i.show() + +class MethodInfo : + """An object which represents a Method""" + def __init__(self, class_manager, buff) : + self.format = SVs( METHOD_INFO[0], METHOD_INFO[1], buff.read( calcsize( METHOD_INFO[0] ) ) ) + + self.__CM = class_manager + self.__code = None + self.__attributes = [] + + for i in range(0, self.format.get_value().attributes_count) : + ai = AttributeInfo( self.__CM, buff ) + self.__attributes.append( ai ) + + if ai.get_name() == "Code" : + self.__code = ai + + def get_raw(self) : + return self.format.get_value_buff() + ''.join(x.get_raw() for x in self.__attributes) + + def get_length(self) : + val = 0 + for i in self.__attributes : + val += i.length + + return val + calcsize( METHOD_INFO[0] ) + + def get_attributes(self) : + return self.__attributes + + def get_access(self) : + return ACC_METHOD_FLAGS[ self.format.get_value().access_flags ][0] + + def set_access(self, value) : + self.format.set_value( { "access_flags" : value } ) + + def get_name(self) : + return self.__CM.get_string( self.format.get_value().name_index ) + + def set_name(self, name) : + return self.__CM.set_string( self.format.get_value().name_index, name ) + + def get_descriptor(self) : + return self.__CM.get_string( self.format.get_value().descriptor_index ) + + def set_descriptor(self, name) : + return self.__CM.set_string( self.format.get_value().name_descriptor, name ) + + def get_name_index(self) : + return self.format.get_value().name_index + + def get_descriptor_index(self) : + return self.format.get_value().descriptor_index + + def get_local_variables(self) : + return self.get_code().get_local_variables() + + def get_code(self) : + if self.__code == None : + return None + return self.__code.get_item() + + def set_name_index(self, name_index) : + self.format.set_value( { "name_index" : name_index } ) + + def set_descriptor_index(self, descriptor_index) : + self.format.set_value( { "descriptor_index" : descriptor_index } ) + + def get_class_name(self) : + return self.__CM.get_this_class_name() + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__attributes : + i.set_cm( cm ) + + def with_descriptor(self, descriptor) : + return descriptor == self.__CM.get_string( self.format.get_value().descriptor_index ) + + def _patch_bytecodes(self) : + return self.get_code()._patch_bytecodes() + + def show(self) : + print "*" * 80 + print self.format.get_value(), self.get_class_name(), self.get_name(), self.get_descriptor() + for i in self.__attributes : + i.show() + print "*" * 80 + + def pretty_show(self, vm_a) : + print "*" * 80 + print self.format.get_value(), self.get_class_name(), self.get_name(), self.get_descriptor() + for i in self.__attributes : + i.pretty_show(vm_a.hmethods[ self ]) + print "*" * 80 + +class CreateString : + """Create a specific String constant by given the name index""" + def __init__(self, class_manager, bytes) : + self.__string_index = class_manager.add_string( bytes ) + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_String" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__string_index ) + + return buff + +class CreateInteger : + """Create a specific Integer constant by given the name index""" + def __init__(self, byte) : + self.__byte = byte + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_Integer" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__byte ) + + return buff + +class CreateClass : + """Create a specific Class constant by given the name index""" + def __init__(self, class_manager, name_index) : + self.__CM = class_manager + + self.__name_index = name_index + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_Class" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__name_index ) + + return buff + +class CreateNameAndType : + """Create a specific NameAndType constant by given the name and the descriptor index""" + def __init__(self, class_manager, name_index, descriptor_index) : + self.__CM = class_manager + + self.__name_index = name_index + self.__descriptor_index = descriptor_index + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_NameAndType" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__name_index, self.__descriptor_index ) + + return buff + +class CreateFieldRef : + """Create a specific FieldRef constant by given the class and the NameAndType index""" + def __init__(self, class_manager, class_index, name_and_type_index) : + self.__CM = class_manager + + self.__class_index = class_index + self.__name_and_type_index = name_and_type_index + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_Fieldref" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__class_index, self.__name_and_type_index ) + + return buff + +class CreateMethodRef : + """Create a specific MethodRef constant by given the class and the NameAndType index""" + def __init__(self, class_manager, class_index, name_and_type_index) : + self.__CM = class_manager + + self.__class_index = class_index + self.__name_and_type_index = name_and_type_index + + def get_raw(self) : + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_Methodref" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, self.__class_index, self.__name_and_type_index ) + + return buff + +class CreateCodeAttributeInfo : + """Create a specific CodeAttributeInfo by given bytecodes (into an human readable format)""" + def __init__(self, class_manager, codes) : + self.__CM = class_manager + +#ATTRIBUTE_INFO = [ '>HL', namedtuple("AttributeInfo", "attribute_name_index attribute_length") ] + self.__attribute_name_index = self.__CM.get_string_index( "Code" ) + self.__attribute_length = 0 +######## + +# CODE_LOW_STRUCT = [ '>HHL', namedtuple( "LOW", "max_stack max_locals code_length" ) ] + self.__max_stack = 1 + self.__max_locals = 2 + self.__code_length = 0 +######## + +# CODE + raw_buff = "" + + for i in codes : + op_name = i[0] + op_value = INVERT_JAVA_OPCODES[ op_name ] + raw_buff += pack( '>B', op_value ) + + if len( JAVA_OPCODES[ op_value ] ) > 1 : + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + raw_buff += pack(r_format, *v_function( *i[1:] ) ) + + self.__code = JavaCode( self.__CM, raw_buff ) + self.__code_length = len( raw_buff ) +######## + +# EXCEPTION + # u2 exception_table_length; + self.__exception_table_length = 0 + + # { u2 start_pc; + # u2 end_pc; + # u2 handler_pc; + # u2 catch_type; + # } exception_table[exception_table_length]; + self.__exception_table = [] +######## + +# ATTRIBUTES + # u2 attributes_count; + self.__attributes_count = 0 + + # attribute_info attributes[attributes_count]; + self.__attributes = [] +######## + + # FIXME : remove calcsize + self.__attribute_length = calcsize( ATTRIBUTE_INFO[0] ) + \ + calcsize( CODE_LOW_STRUCT[0] ) + \ + self.__code_length + \ + calcsize('>H') + \ + calcsize('>H') + + def get_raw(self) : + return pack( ATTRIBUTE_INFO[0], self.__attribute_name_index, self.__attribute_length ) + \ + pack( CODE_LOW_STRUCT[0], self.__max_stack, self.__max_locals, self.__code_length ) + \ + self.__code.get_raw() + \ + pack( '>H', self.__exception_table_length ) + \ + ''.join( i.get_raw() for i in self.__exception_table ) + \ + pack( '>H', self.__attributes_count ) + \ + ''.join( i.get_raw() for i in self.__attributes ) + +# FIELD_INFO = [ '>HHHH', namedtuple("FieldInfo", "access_flags name_index descriptor_index attributes_count") ] +class CreateFieldInfo : + """Create a specific FieldInfo by given the name, the prototype of the "new" field""" + def __init__(self, class_manager, name, proto) : + self.__CM = class_manager + + access_flags_value = proto[0] + type_value = proto[1] + + self.__access_flags = INVERT_ACC_FIELD_FLAGS[ access_flags_value ] + self.__name_index = self.__CM.get_string_index( name ) + if self.__name_index == -1 : + self.__name_index = self.__CM.add_string( name ) + else : + bytecode.Exit("field %s is already present ...." % name) + + self.__descriptor_index = self.__CM.add_string( type_value ) + + self.__attributes = [] + + def get_raw(self) : + buff = pack( FIELD_INFO[0], self.__access_flags, self.__name_index, self.__descriptor_index, len(self.__attributes) ) + + for i in self.__attributes : + buff += i.get_raw() + + return buff + +# METHOD_INFO = [ '>HHHH', namedtuple("MethodInfo", "access_flags name_index descriptor_index attributes_count") ] +class CreateMethodInfo : + """Create a specific MethodInfo by given the name, the prototype and the code (into an human readable format) of the "new" method""" + def __init__(self, class_manager, name, proto, codes) : + self.__CM = class_manager + + access_flags_value = proto[0] + return_value = proto[1] + arguments_value = proto[2] + + self.__access_flags = INVERT_ACC_METHOD_FLAGS[ access_flags_value ] + + self.__name_index = self.__CM.get_string_index( name ) + if self.__name_index == -1 : + self.__name_index = self.__CM.add_string( name ) + + proto_final = "(" + arguments_value + ")" + return_value + self.__descriptor_index = self.__CM.add_string( proto_final ) + + self.__attributes = [] + + self.__attributes.append( CreateCodeAttributeInfo( self.__CM, codes ) ) + + def get_raw(self) : + buff = pack( METHOD_INFO[0], self.__access_flags, self.__name_index, self.__descriptor_index, len(self.__attributes) ) + + for i in self.__attributes : + buff += i.get_raw() + + return buff + +class JBC : + """JBC manages each bytecode with the value, name, raw buffer and special functions""" + # special --> ( r_function, v_function, r_buff, r_format, f_function ) + def __init__(self, class_manager, op_name, raw_buff, special=None) : + self.__CM = class_manager + self.__op_name = op_name + self.__raw_buff = raw_buff + + self.__special = special + self.__special_value = None + + self._load() + + def _load(self) : + if self.__special != None : + ntuple = namedtuple( self.__op_name, self.__special[2] ) + x = ntuple._make( unpack( self.__special[3], self.__raw_buff[1:] ) ) + + if self.__special[4] == None : + self.__special_value = self.__special[0]( x ) + else : + self.__special_value = getattr(self.__CM, self.__special[4])( self.__special[0]( x ) ) + + def reload(self, raw_buff) : + """Reload the bytecode with a new raw buffer""" + self.__raw_buff = raw_buff + self._load() + + def set_cm(self, cm) : + self.__CM = cm + + def get_length(self) : + """Return the length of the bytecode""" + return len( self.__raw_buff ) + + def get_raw(self) : + """Return the current raw buffer of the bytecode""" + return self.__raw_buff + + def get_name(self) : + """Return the name of the bytecode""" + return self.__op_name + + def get_operands(self) : + """Return the operands of the bytecode""" + if isinstance( self.__special_value, list ): + if len(self.__special_value) == 1 : + return self.__special_value[0] + return self.__special_value + + def get_formatted_operands(self) : + return [] + + def adjust_r(self, pos, pos_modif, len_modif) : + """Adjust the bytecode (if necessary (in this cas the bytecode is a branch bytecode)) when a bytecode has been removed""" +# print self.__op_name, pos, pos_modif, len_modif, self.__special_value, type(pos), type(pos_modif), type(len_modif), type(self.__special_value) + + if pos > pos_modif : + if (self.__special_value + pos) < (pos_modif) : +# print "MODIF +", self.__special_value, len_modif, + self.__special_value += len_modif +# print self.__special_value + self.__raw_buff = pack( '>B', INVERT_JAVA_OPCODES[ self.__op_name ] ) + pack(self.__special[3], *self.__special[1]( self.__special_value ) ) + + elif pos < pos_modif : + if (self.__special_value + pos) > (pos_modif) : +# print "MODIF -", self.__special_value, len_modif, + self.__special_value -= len_modif +# print self.__special_value + self.__raw_buff = pack( '>B', INVERT_JAVA_OPCODES[ self.__op_name ] ) + pack(self.__special[3], *self.__special[1]( self.__special_value ) ) + + def adjust_i(self, pos, pos_modif, len_modif) : + """Adjust the bytecode (if necessary (in this cas the bytecode is a branch bytecode)) when a bytecode has been inserted""" + #print self.__op_name, pos, pos_modif, len_modif, self.__special_value, type(pos), type(pos_modif), type(len_modif), type(self.__special_value) + + if pos > pos_modif : + if (self.__special_value + pos) < (pos_modif) : +# print "MODIF +", self.__special_value, len_modif, + self.__special_value -= len_modif +# print self.__special_value + self.__raw_buff = pack( '>B', INVERT_JAVA_OPCODES[ self.__op_name ] ) + pack(self.__special[3], *self.__special[1]( self.__special_value ) ) + + elif pos < pos_modif : + if (self.__special_value + pos) > (pos_modif) : +# print "MODIF -", self.__special_value, len_modif, + self.__special_value += len_modif +# print self.__special_value + self.__raw_buff = pack( '>B', INVERT_JAVA_OPCODES[ self.__op_name ] ) + pack(self.__special[3], *self.__special[1]( self.__special_value ) ) + + def show_buff(self, pos) : + buff = "" + if self.__special_value == None : + buff += self.__op_name + else : + if self.__op_name in BRANCH_JVM_OPCODES : + buff += "%s %s %s" % (self.__op_name, self.__special_value, self.__special_value + pos) + else : + buff += "%s %s" % (self.__op_name, self.__special_value) + + return buff + + def show(self, pos) : + """Show the bytecode at a specific position + + pos - the position into the bytecodes (integer) + """ + print self.show_buff( pos ), + + +class JavaCode : + """JavaCode manages a list of bytecode to a specific method, by decoding a raw buffer and transform each bytecode into a JBC object""" + def __init__(self, class_manager, buff) : + self.__CM = class_manager + + self.__raw_buff = buff + self.__bytecodes = [] + self.__maps = [] + self.__branches = [] + + i = 0 + while i < len(self.__raw_buff) : + op_value = unpack( '>B', self.__raw_buff[i])[0] + if op_value in JAVA_OPCODES : + if len( JAVA_OPCODES[ op_value ] ) >= 2 : + # it's a fixed length opcode + if isinstance(JAVA_OPCODES[ op_value ][1], str) == True : + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + # it's a variable length opcode + else : + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_VARIABLE( i, op_value, self.__raw_buff[ i : ] ) + + len_format = calcsize(r_format) + raw_buff = self.__raw_buff[ i : i + 1 + len_format ] + + jbc = JBC( class_manager, JAVA_OPCODES[ op_value ][0], raw_buff, ( r_function, v_function, r_buff, r_format, f_function ) ) + self.__bytecodes.append( jbc ) + + i += len_format + else : + self.__bytecodes.append( JBC( class_manager, JAVA_OPCODES[ op_value ][0], self.__raw_buff[ i ] ) ) + else : + bytecode.Exit( "op_value 0x%x is unknown" % op_value ) + + i += 1 + + # Create branch bytecodes list + idx = 0 + nb = 0 + for i in self.__bytecodes : + self.__maps.append( idx ) + + if i.get_name() in BRANCH_JVM_OPCODES : + self.__branches.append( nb ) + + idx += i.get_length() + nb += 1 + + def _patch_bytecodes(self) : + methods = [] + for i in self.__bytecodes : + if "invoke" in i.get_name() : + operands = i.get_operands() + methods.append( operands ) + op_value = INVERT_JAVA_OPCODES[ i.get_name() ] + raw_buff = pack( '>B', op_value ) + + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + new_class_index = self.__CM.create_class( operands[0] ) + new_name_and_type_index = self.__CM.create_name_and_type( operands[1], operands[2] ) + + self.__CM.create_method_ref( new_class_index, new_name_and_type_index ) + + value = getattr( self.__CM, JAVA_OPCODES[ op_value ][5] )( *operands[0:] ) + if value == -1 : + bytecode.Exit( "Unable to found method " + str(operands) ) + + raw_buff += pack(r_format, *v_function( value ) ) + + i.reload( raw_buff ) + + elif "anewarray" in i.get_name() : + operands = i.get_operands() + op_value = INVERT_JAVA_OPCODES[ i.get_name() ] + raw_buff = pack( '>B', op_value ) + + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + new_class_index = self.__CM.create_class( operands ) + + raw_buff += pack(r_format, *v_function( new_class_index ) ) + + i.reload( raw_buff ) + + elif "getstatic" == i.get_name() : + operands = i.get_operands() + op_value = INVERT_JAVA_OPCODES[ i.get_name() ] + raw_buff = pack( '>B', op_value ) + + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + new_class_index = self.__CM.create_class( operands[0] ) + new_name_and_type_index = self.__CM.create_name_and_type( operands[1], operands[2] ) + + self.__CM.create_field_ref( new_class_index, new_name_and_type_index ) + + + value = getattr( self.__CM, JAVA_OPCODES[ op_value ][5] )( *operands[1:] ) + if value == -1 : + bytecode.Exit( "Unable to found method " + str(operands) ) + + raw_buff += pack(r_format, *v_function( value ) ) + + i.reload( raw_buff ) + + elif "ldc" == i.get_name() : + operands = i.get_operands() + op_value = INVERT_JAVA_OPCODES[ i.get_name() ] + raw_buff = pack( '>B', op_value ) + + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + if operands[0] != "CONSTANT_Integer" and operands[0] != "CONSTANT_String" : + bytecode.Exit( "...." ) + + if operands[0] == "CONSTANT_Integer" : + new_int_index = self.__CM.create_integer( operands[1] ) + raw_buff += pack(r_format, *v_function( new_int_index ) ) + + elif operands[0] == "CONSTANT_String" : + new_string_index = self.__CM.create_string( operands[1] ) + + raw_buff += pack(r_format, *v_function( new_string_index ) ) + + i.reload( raw_buff ) + + elif "new" == i.get_name() : + operands = i.get_operands() + op_value = INVERT_JAVA_OPCODES[ i.get_name() ] + raw_buff = pack( '>B', op_value ) + + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + new_class_index = self.__CM.create_class( operands ) + + raw_buff += pack(r_format, *v_function( new_class_index ) ) + + i.reload( raw_buff ) + + return methods + + def get(self) : + """ + Return all bytecodes + + @rtype : L{list} + """ + return self.__bytecodes + + def get_raw(self) : + return ''.join(x.get_raw() for x in self.__bytecodes) + + def show(self) : + """ + Display the code like a disassembler + """ + nb = 0 + for i in self.__bytecodes : + print nb, self.__maps[nb], + i.show( self.__maps[nb] ) + print + nb += 1 + + def pretty_show(self, m_a) : + """ + Display the code like a disassembler but with instructions' links + """ + bytecode.PrettyShow( m_a.basic_blocks.gets() ) + bytecode.PrettyShowEx( m_a.exceptions.gets() ) + + def get_relative_idx(self, idx) : + """ + Return the relative idx by given an offset in the code + + @param idx : an offset in the code + + @rtype : the relative index in the code, it's the position in the list of a bytecode + """ + n = 0 + x = 0 + for i in self.__bytecodes : + #print n, idx + if n == idx : + return x + n += i.get_length() + x += 1 + return -1 + + def get_at(self, idx) : + """ + Return a specific bytecode at an index + + @param : the index of a bytecode + + @rtype : L{JBC} + """ + return self.__bytecodes[ idx ] + + def remove_at(self, idx) : + """ + Remove bytecode at a specific index + + @param idx : the index to remove the bytecode + + @rtype : the length of the removed bytecode + """ + val = self.__bytecodes[idx] + val_m = self.__maps[idx] + + # Remove the index if it's in our branch list + if idx in self.__branches : + self.__branches.remove( idx ) + + # Adjust each branch + for i in self.__branches : + self.__bytecodes[i].adjust_r( self.__maps[i], val_m, val.get_length() ) + + # Remove it ! + self.__maps.pop(idx) + self.__bytecodes.pop(idx) + + # Adjust branch and map list + self._adjust_maps( val_m, val.get_length() * -1 ) + self._adjust_branches( idx, -1 ) + + return val.get_length() + + def _adjust_maps(self, val, size) : + nb = 0 + for i in self.__maps : + if i > val : + self.__maps[ nb ] = i + size + nb = nb + 1 + + def _adjust_maps_i(self, val, size) : + nb = 0 + x = 0 + for i in self.__maps : + if i == val : + x+=1 + + if x == 2 : + self.__maps[ nb ] = i + size + + if i > val : + self.__maps[ nb ] = i + size + nb = nb + 1 + + def _adjust_branches(self, val, size) : + nb = 0 + for i in self.__branches : + if i > val : + self.__branches[ nb ] = i + size + nb += 1 + + def insert_at(self, idx, byte_code) : + """ + Insert bytecode at a specific index + + @param idx : the index to insert the bytecode + @param bytecode : a list which represent the bytecode + + @rtype : the length of the inserted bytecode + """ + # Get the op_value and add it to the raw_buff + op_name = byte_code[0] + op_value = INVERT_JAVA_OPCODES[ op_name ] + raw_buff = pack( '>B', op_value ) + + new_jbc = None + + # If it's an op_value with args, we must handle that ! + if len( JAVA_OPCODES[ op_value ] ) > 1 : + + # Find information about the op_value + r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE( op_value ) + + # Special values for this op_value (advanced bytecode) + if len( JAVA_OPCODES[ op_value ] ) == 6 : + + value = getattr( self.__CM, JAVA_OPCODES[ op_value ][5] )( *byte_code[1:] ) + if value == -1 : + bytecode.Exit( "Unable to found " + str(byte_code[1:]) ) + + raw_buff += pack(r_format, *v_function( value ) ) + else : + raw_buff += pack(r_format, *v_function( *byte_code[1:] ) ) + + new_jbc = JBC(self.__CM, op_name, raw_buff, ( r_function, v_function, r_buff, r_format, f_function ) ) + else : + new_jbc = JBC(self.__CM, op_name, raw_buff) + + # Adjust each branch with the new insertion + val_m = self.__maps[ idx ] + for i in self.__branches : + self.__bytecodes[i].adjust_i( self.__maps[i], val_m, new_jbc.get_length() ) + + # Insert the new bytecode at the correct index + # Adjust maps + branches + self.__bytecodes.insert( idx, new_jbc ) + self.__maps.insert( idx, val_m ) + self._adjust_maps_i( val_m, new_jbc.get_length() ) + + self._adjust_branches( idx, 1 ) + + # Add it to the branches if it's a correct op_value + if new_jbc.get_name() in BRANCH_JVM_OPCODES : + self.__branches.append( idx ) + + # FIXME + # modify the exception table + # modify tableswitch and lookupswitch instructions + + # return the length of the raw_buff + return len(raw_buff) + + def remplace_at(self, idx, bytecode) : + """ + Remplace bytecode at a specific index by another bytecode (remplace = remove + insert) + + @param idx : the index to insert the bytecode + @param bytecode : a list which represent the bytecode + + @rtype : the length of the inserted bytecode + """ + self.remove_at(idx) * (-1) + size = self.insert_at(idx, bytecode) + + return size + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__bytecodes : + i.set_cm( cm ) + +class BasicAttribute(object) : + def __init__(self) : + self.__attributes = [] + + def get_attributes(self) : + return self.__attributes + + def set_cm(self, cm) : + self.__CM = cm + +class CodeAttribute(BasicAttribute) : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + + super(CodeAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 max_stack; + # u2 max_locals; + # u4 code_length; + # u1 code[code_length]; + self.low_struct = SVs( CODE_LOW_STRUCT[0], CODE_LOW_STRUCT[1], buff.read( calcsize(CODE_LOW_STRUCT[0]) ) ) + + self.__code = JavaCode( class_manager, buff.read( self.low_struct.get_value().code_length ) ) + + # u2 exception_table_length; + self.exception_table_length = SV( '>H', buff.read(2) ) + + # { u2 start_pc; + # u2 end_pc; + # u2 handler_pc; + # u2 catch_type; + # } exception_table[exception_table_length]; + self.__exception_table = [] + for i in range(0, self.exception_table_length.get_value()) : + et = SVs( EXCEPTION_TABLE[0], EXCEPTION_TABLE[1], buff.read( calcsize(EXCEPTION_TABLE[0]) ) ) + self.__exception_table.append( et ) + + # u2 attributes_count; + self.attributes_count = SV( '>H', buff.read(2) ) + + # attribute_info attributes[attributes_count]; + self.__attributes = [] + for i in range(0, self.attributes_count.get_value()) : + ai = AttributeInfo( self.__CM, buff ) + self.__attributes.append( ai ) + + def get_attributes(self) : + return self.__attributes + + def get_exceptions(self) : + return self.__exception_table + + def get_raw(self) : + return self.low_struct.get_value_buff() + \ + self.__code.get_raw() + \ + self.exception_table_length.get_value_buff() + \ + ''.join(x.get_value_buff() for x in self.__exception_table) + \ + self.attributes_count.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__attributes) + + def get_length(self) : + return self.low_struct.get_value().code_length + + + def get_max_stack(self) : + return self.low_struct.get_value().max_stack + + def get_max_locals(self) : + return self.low_struct.get_value().max_locals + + def get_local_variables(self) : + for i in self.__attributes : + if i.get_name() == "StackMapTable" : + return i.get_item().get_local_variables() + return [] + + def get_bc(self) : + return self.__code + + # FIXME : show* --> add exceptions + def show_info(self) : + print "!" * 70 + print self.low_struct.get_value() + bytecode._Print( "ATTRIBUTES_COUNT", self.attributes_count.get_value() ) + for i in self.__attributes : + i.show() + print "!" * 70 + + def _begin_show(self) : + print "!" * 70 + print self.low_struct.get_value() + + def _end_show(self) : + bytecode._Print( "ATTRIBUTES_COUNT", self.attributes_count.get_value() ) + for i in self.__attributes : + i.show() + print "!" * 70 + + def show(self) : + self._begin_show() + self.__code.show() + self._end_show() + + def pretty_show(self, m_a) : + self._begin_show() + self.__code.pretty_show(m_a) + self._end_show() + + def _patch_bytecodes(self) : + return self.__code._patch_bytecodes() + + def remplace_at(self, idx, bytecode) : + size = self.__code.remplace_at(idx, bytecode) + + # Adjust the length of our bytecode + self.low_struct.set_value( { "code_length" : self.low_struct.get_value().code_length + size } ) + + def remove_at(self, idx) : + size = self.__code.remove_at(idx) + # Adjust the length of our bytecode + self.low_struct.set_value( { "code_length" : self.low_struct.get_value().code_length - size } ) + + def removes_at(self, l_idx) : + i = 0 + while i < len(l_idx) : + self.remove_at( l_idx[i] ) + + j = i + 1 + while j < len(l_idx) : + if l_idx[j] > l_idx[i] : + l_idx[j] -= 1 + + j += 1 + + i += 1 + + def inserts_at(self, idx, l_bc) : +# self.low_struct.set_value( { "max_stack" : self.low_struct.get_value().max_stack + 2 } ) +# print self.low_struct.get_value() + total_size = 0 + for i in l_bc : + size = self.insert_at( idx, i ) + idx += 1 + total_size += size + return total_size + + def insert_at(self, idx, bytecode) : + size = self.__code.insert_at(idx, bytecode) + # Adjust the length of our bytecode + self.low_struct.set_value( { "code_length" : self.low_struct.get_value().code_length + size } ) + + return size + + def get_relative_idx(self, idx) : + return self.__code.get_relative_idx(idx) + + def get_at(self, idx) : + return self.__code.get_at(idx) + + def gets_at(self, l_idx) : + return [ self.__code.get_at(i) for i in l_idx ] + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__attributes : + i.set_cm( cm ) + self.__code.set_cm( cm ) + + def _fix_attributes(self, new_cm) : + for i in self.__attributes : + i._fix_attributes( new_cm ) + +class SourceFileAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(SourceFileAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 sourcefile_index; + self.sourcefile_index = SV( '>H', buff.read(2) ) + + def get_raw(self) : + return self.sourcefile_index.get_value_buff() + + def show(self) : + print self.sourcefile_index + +class LineNumberTableAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(LineNumberTableAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 line_number_table_length; + # { u2 start_pc; + # u2 line_number; + # } line_number_table[line_number_table_length]; + + self.line_number_table_length = SV( '>H', buff.read( 2 ) ) + + self.__line_number_table = [] + for i in range(0, self.line_number_table_length.get_value()) : + lnt = SVs( LINE_NUMBER_TABLE[0], LINE_NUMBER_TABLE[1], buff.read( 4 ) ) + self.__line_number_table.append( lnt ) + + def get_raw(self) : + return self.line_number_table_length.get_value_buff() + \ + ''.join(x.get_value_buff() for x in self.__line_number_table) + + def get_line_number_table(self) : + return self.__line_number_table + + def show(self) : + bytecode._Print("LINE_NUMBER_TABLE_LENGTH", self.line_number_table_length.get_value()) + for x in self.__line_number_table : + print "\t", x.get_value() + + def _fix_attributes(self, new_cm) : + pass + +class LocalVariableTableAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(LocalVariableTableAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 local_variable_table_length; + # { u2 start_pc; + # u2 length; + # u2 name_index; + # u2 descriptor_index; + # u2 index; + # } local_variable_table[local_variable_table_length]; + self.local_variable_table_length = SV( '>H', buff.read(2) ) + + self.local_variable_table = [] + for i in range(0, self.local_variable_table_length.get_value()) : + lvt = SVs( LOCAL_VARIABLE_TABLE[0], LOCAL_VARIABLE_TABLE[1], buff.read( calcsize(LOCAL_VARIABLE_TABLE[0]) ) ) + self.local_variable_table.append( lvt ) + + def get_raw(self) : + return self.local_variable_table_length.get_value_buff() + \ + ''.join(x.get_value_buff() for x in self.local_variable_table) + + def show(self) : + print "LocalVariableTable", self.local_variable_table_length.get_value() + for x in self.local_variable_table : + print x.get_value() + +class LocalVariableTypeTableAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(LocalVariableTypeTableAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 local_variable_type_table_length; + # { u2 start_pc; + # u2 length; + # u2 name_index; + # u2 signature_index; + # u2 index; + # } local_variable_type_table[local_variable_type_table_length]; + self.local_variable_type_table_length = SV( '>H', buff.read(2) ) + + self.local_variable_type_table = [] + for i in range(0, self.local_variable_type_table_length.get_value()) : + lvtt = SVs( LOCAL_VARIABLE_TYPE_TABLE[0], LOCAL_VARIABLE_TYPE_TABLE[1], buff.read( calcsize(LOCAL_VARIABLE_TYPE_TABLE[0]) ) ) + self.local_variable_type_table.append( lvtt ) + + def get_raw(self) : + return self.local_variable_type_table_length.get_value_buff() + \ + ''.join(x.get_value_buff() for x in self.local_variable_type_table) + + def show(self) : + print "LocalVariableTypeTable", self.local_variable_type_table_length.get_value() + for x in self.local_variable_type_table : + print x.get_value() + +class SourceDebugExtensionAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(SourceDebugExtensionAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + # u1 debug_extension[attribute_length]; + + self.debug_extension = buff.read( self.attribute_length ) + + def get_raw(self) : + return self.debug_extension + + def show(self) : + print "SourceDebugExtension", self.debug_extension.get_value() + +class DeprecatedAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(DeprecatedAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + def get_raw(self) : + return '' + + def show(self) : + print "Deprecated" + +class SyntheticAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(SyntheticAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + def get_raw(self) : + return '' + + def show(self) : + print "Synthetic" + +class SignatureAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(SignatureAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 signature_index; + self.signature_index = SV( '>H', buff.read(2) ) + + def get_raw(self) : + return self.signature_index.get_value_buff() + + def show(self) : + print "Signature", self.signature_index.get_value() + +class RuntimeVisibleAnnotationsAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(RuntimeVisibleAnnotationsAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 num_annotations; + # annotation annotations[num_annotations]; + self.num_annotations = SV( '>H', buff.read(2) ) + + self.annotations = [] + for i in range(0, self.num_annotations.get_value()) : + self.annotations.append( Annotation(cm, buff) ) + + def get_raw(self) : + return self.num_annotations.get_value_buff() + \ + ''.join(x.get_raw() for x in self.annotations) + + def show(self) : + print "RuntimeVisibleAnnotations", self.num_annotations.get_value() + for i in self.annotations : + i.show() + +class RuntimeInvisibleAnnotationsAttribute(RuntimeVisibleAnnotationsAttribute) : + def show(self) : + print "RuntimeInvisibleAnnotations", self.num_annotations.get_value() + for i in self.annotations : + i.show() + +class RuntimeVisibleParameterAnnotationsAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(RuntimeVisibleParameterAnnotationsAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u1 num_parameters; + #{ + # u2 num_annotations; + # annotation annotations[num_annotations]; + #} parameter_annotations[num_parameters]; + + self.num_parameters = SV( '>H', buff.read(2) ) + self.parameter_annotations = [] + for i in range(0, self.num_parameters.get_value()) : + self.parameter_annotations.append( ParameterAnnotation( cm, buff ) ) + + def get_raw(self) : + return self.num_parameters.get_value_buff() + \ + ''.join(x.get_raw() for x in self.parameter_annotations) + + def show(self) : + print "RuntimeVisibleParameterAnnotations", self.num_parameters.get_value() + for i in self.parameter_annotations : + i.show() + +class RuntimeInvisibleParameterAnnotationsAttribute(RuntimeVisibleParameterAnnotationsAttribute) : + def show(self) : + print "RuntimeVisibleParameterAnnotations", self.num_annotations.get_value() + for i in self.parameter_annotations : + i.show() + +class ParameterAnnotation : + def __init__(self, cm, buff) : + # u2 num_annotations; + # annotation annotations[num_annotations]; + self.num_annotations = SV( '>H', buff.read(2) ) + self.annotations = [] + + for i in range(0, self.num_annotations.get_value()) : + self.annotations = Annotation( cm, buff ) + + + def get_raw(self) : + return self.num_annotations.get_value_buff() + \ + ''.join(x.get_raw() for x in self.annotations) + + def show(self) : + print "ParameterAnnotation", self.num_annotations.get_value() + for i in self.annotations : + i.show() + +class AnnotationDefaultAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(AnnotationDefaultAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # element_value default_value; + + self.default_value = ElementValue( cm, buff ) + + def get_raw(self) : + return self.default_value.get_raw() + + def show(self) : + print "AnnotationDefault" + self.default_value.show() + +class Annotation : + def __init__(self, cm, buff) : + # u2 type_index; + # u2 num_element_value_pairs; + # { u2 element_name_index; + # element_value value; + # } element_value_pairs[num_element_value_pairs] + self.type_index = SV( '>H', buff.read(2) ) + self.num_element_value_pairs = SV( '>H', buff.read(2) ) + + self.element_value_pairs = [] + + for i in range(0, self.num_element_value_pairs.get_value()) : + self.element_value_pairs.append( ElementValuePair(cm, buff) ) + + def get_raw(self) : + return self.type_index.get_value_buff() + self.num_element_value_pairs.get_value_buff() + \ + ''.join(x.get_raw() for x in self.element_value_pairs) + + def show(self) : + print "Annotation", self.type_index.get_value(), self.num_element_value_pairs.get_value() + for i in self.element_value_pairs : + i.show() + + +class ElementValuePair : + def __init__(self, cm, buff) : + # u2 element_name_index; + # element_value value; + self.element_name_index = SV( '>H', buff.read(2) ) + self.value = ElementValue(cm, buff) + + def get_raw(self) : + return self.element_name_index.get_value_buff() + \ + self.value.get_raw() + + def show(self) : + print "ElementValuePair", self.element_name_index.get_value() + self.value.show() + +ENUM_CONST_VALUE = [ '>HH', namedtuple("EnumConstValue", "type_name_index const_name_index") ] +class ElementValue : + def __init__(self, cm, buff) : + # u1 tag; + # union { + # u2 const_value_index; + # { + # u2 type_name_index; + # u2 const_name_index; + # } enum_const_value; + # u2 class_info_index; + # annotation annotation_value; + # { + # u2 num_values; + # element_value values[num_values]; + # } array_value; + # } value; + self.tag = SV( '>B', buff.read(1) ) + + tag = chr( self.tag.get_value() ) + if tag == 'B' or tag == 'C' or tag == 'D' or tag == 'F' or tag == 'I' or tag == 'J' or tag == 'S' or tag == 'Z' or tag == 's' : + self.value = SV( '>H', buff.read(2) ) + elif tag == 'e' : + self.value = SVs( ENUM_CONST_VALUE[0], ENUM_CONST_VALUE[1], buff.read( calcsize(ENUM_CONST_VALUE[0]) ) ) + elif tag == 'c' : + self.value = SV( '>H', buff.read(2) ) + elif tag == '@' : + self.value = Annotation( cm, buff ) + elif tag == '[' : + self.value = ArrayValue( cm, buff ) + else : + bytecode.Exit( "tag %c not in VERIFICATION_TYPE_INFO" % self.tag.get_value() ) + + def get_raw(self) : + if isinstance(self.value, SV) or isinstance(self.value, SVs) : + return self.tag.get_value_buff() + self.value.get_value_buff() + + return self.tag.get_value_buff() + self.value.get_raw() + + def show(self) : + print "ElementValue", self.tag.get_value() + if isinstance(self.value, SV) or isinstance(self.value, SVs) : + print self.value.get_value() + else : + self.value.show() + +class ArrayValue : + def __init__(self, cm, buff) : + # u2 num_values; + # element_value values[num_values]; + self.num_values = SV( '>H', buff.read(2) ) + + self.values = [] + for i in range(0, self.num_values.get_value()) : + self.values.append( ElementValue(cm, buff) ) + + def get_raw(self) : + return self.num_values.get_value_buff() + \ + ''.join(x.get_raw() for x in self.values) + + def show(self) : + print "ArrayValue", self.num_values.get_value() + for i in self.values : + i.show() + +class ExceptionsAttribute(BasicAttribute) : + def __init__(self, cm, buff) : + super(ExceptionsAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 number_of_exceptions; + # u2 exception_index_table[number_of_exceptions]; + self.number_of_exceptions = SV( '>H', buff.read(2) ) + + self.__exception_index_table = [] + for i in range(0, self.number_of_exceptions.get_value()) : + self.__exception_index_table.append( SV( '>H', buff.read(2) ) ) + + def get_raw(self) : + return self.number_of_exceptions.get_value_buff() + ''.join(x.get_value_buff() for x in self.__exception_index_table) + + def get_exception_index_table(self) : + return self.__exception_index_table + + def show(self) : + print "Exceptions", self.number_of_exceptions.get_value() + for i in self.__exception_index_table : + print "\t", i + +class VerificationTypeInfo : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + tag = SV( '>B', buff.read_b(1) ).get_value() + + if tag not in VERIFICATION_TYPE_INFO : + bytecode.Exit( "tag not in VERIFICATION_TYPE_INFO" ) + + format = VERIFICATION_TYPE_INFO[ tag ][1] + self.format = SVs( format, VERIFICATION_TYPE_INFO[ tag ][2], buff.read( calcsize( format ) ) ) + + def get_raw(self) : + return self.format.get_value_buff() + + def show(self) : + general_format = self.format.get_value() + if len( VERIFICATION_TYPE_INFO[ general_format.tag ] ) > 3 : + print general_format, + for (i,j) in VERIFICATION_TYPE_INFO[ general_format.tag ][3] : + print getattr(self.__CM, j)( getattr(general_format, i) ) + else : + print general_format + + def _fix_attributes(self, new_cm) : + general_format = self.format.get_value() + + if len( VERIFICATION_TYPE_INFO[ general_format.tag ] ) > 3 : + for (i,j) in VERIFICATION_TYPE_INFO[ general_format.tag ][3] : + # Fix the first object which is the current class + if getattr(self.__CM, j)( getattr(general_format, i) )[0] == self.__CM.get_this_class_name() : + self.format.set_value( { "cpool_index" : new_cm.get_this_class() } ) + # Fix other objects + else : + new_class_index = new_cm.create_class( getattr(self.__CM, j)( getattr(general_format, i) )[0] ) + self.format.set_value( { "cpool_index" : new_class_index } ) + + def set_cm(self, cm) : + self.__CM = cm + +class FullFrame : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + # u1 frame_type = FULL_FRAME; /* 255 */ + # u2 offset_delta; + # u2 number_of_locals; + self.frame_type = SV( '>B', buff.read(1) ) + self.offset_delta = SV( '>H', buff.read(2) ) + self.number_of_locals = SV( '>H', buff.read(2) ) + + # verification_type_info locals[number_of_locals]; + self.__locals = [] + for i in range(0, self.number_of_locals.get_value()) : + self.__locals.append( VerificationTypeInfo( self.__CM, buff ) ) + + # u2 number_of_stack_items; + self.number_of_stack_items = SV( '>H', buff.read(2) ) + # verification_type_info stack[number_of_stack_items]; + self.__stack = [] + for i in range(0, self.number_of_stack_items.get_value()) : + self.__stack.append( VerificationTypeInfo( self.__CM, buff ) ) + + def get_locals(self) : + return self.__locals + + def get_raw(self) : + return self.frame_type.get_value_buff() + \ + self.offset_delta.get_value_buff() + \ + self.number_of_locals.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__locals) + \ + self.number_of_stack_items.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__stack) + + def show(self) : + print "#" * 60 + bytecode._Print("\tFULL_FRAME", self.frame_type.get_value()) + bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value()) + + bytecode._Print("\tNUMBER_OF_LOCALS", self.number_of_locals.get_value()) + for i in self.__locals : + i.show() + + bytecode._Print("\tNUMBER_OF_STACK_ITEMS", self.number_of_stack_items.get_value()) + for i in self.__stack : + i.show() + + print "#" * 60 + + def _fix_attributes(self, new_cm) : + for i in self.__locals : + i._fix_attributes( new_cm ) + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__locals : + i.set_cm( cm ) + +class ChopFrame : + def __init__(self, buff) : + # u1 frame_type=CHOP; /* 248-250 */ + # u2 offset_delta; + self.frame_type = SV( '>B', buff.read(1) ) + self.offset_delta = SV( '>H', buff.read(2) ) + + def get_raw(self) : + return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff() + + def show(self) : + print "#" * 60 + bytecode._Print("\tCHOP_FRAME", self.frame_type.get_value()) + bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value()) + print "#" * 60 + + def _fix_attributes(self, cm) : + pass + + def set_cm(self, cm) : + pass + +class SameFrame : + def __init__(self, buff) : + # u1 frame_type = SAME;/* 0-63 */ + self.frame_type = SV( '>B', buff.read(1) ) + + def get_raw(self) : + return self.frame_type.get_value_buff() + + def show(self) : + print "#" * 60 + bytecode._Print("\tSAME_FRAME", self.frame_type.get_value()) + print "#" * 60 + + def _fix_attributes(self, new_cm) : + pass + + def set_cm(self, cm) : + pass + +class SameLocals1StackItemFrame : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + # u1 frame_type = SAME_LOCALS_1_STACK_ITEM;/* 64-127 */ + # verification_type_info stack[1]; + self.frame_type = SV( '>B', buff.read(1) ) + self.stack = VerificationTypeInfo( self.__CM, buff ) + + def show(self) : + print "#" * 60 + bytecode._Print("\tSAME_LOCALS_1_STACK_ITEM_FRAME", self.frame_type.get_value()) + self.stack.show() + print "#" * 60 + + def get_raw(self) : + return self.frame_type.get_value_buff() + self.stack.get_raw() + + def _fix_attributes(self, new_cm) : + pass + + def set_cm(self, cm) : + self.__CM = cm + +class SameLocals1StackItemFrameExtended : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + # u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; /* 247 */ + # u2 offset_delta; + # verification_type_info stack[1]; + self.frame_type = SV( '>B', buff.read(1) ) + self.offset_delta = SV( '>H', buff.read(2) ) + self.stack = VerificationTypeInfo( self.__CM, buff ) + + def get_raw(self) : + return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff() + self.stack.get_value_buff() + + def _fix_attributes(self, new_cm) : + pass + + def set_cm(self, cm) : + self.__CM = cm + + def show(self) : + print "#" * 60 + bytecode._Print("\tSAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED", self.frame_type.get_value()) + bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value()) + self.stack.show() + print "#" * 60 + +class SameFrameExtended : + def __init__(self, buff) : + # u1 frame_type = SAME_FRAME_EXTENDED;/* 251*/ + # u2 offset_delta; + self.frame_type = SV( '>B', buff.read(1) ) + self.offset_delta = SV( '>H', buff.read(2) ) + + def get_raw(self) : + return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff() + + def _fix_attributes(self, cm) : + pass + + def set_cm(self, cm) : + pass + + def show(self) : + print "#" * 60 + bytecode._Print("\tSAME_FRAME_EXTENDED", self.frame_type.get_value()) + bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value()) + print "#" * 60 + +class AppendFrame : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + # u1 frame_type = APPEND; /* 252-254 */ + # u2 offset_delta; + self.frame_type = SV( '>B', buff.read(1) ) + self.offset_delta = SV( '>H', buff.read(2) ) + + # verification_type_info locals[frame_type -251]; + self.__locals = [] + k = self.frame_type.get_value() - 251 + for i in range(0, k) : + self.__locals.append( VerificationTypeInfo( self.__CM, buff ) ) + + def get_locals(self) : + return self.__locals + + def show(self) : + print "#" * 60 + bytecode._Print("\tAPPEND_FRAME", self.frame_type.get_value()) + bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value()) + + for i in self.__locals : + i.show() + + print "#" * 60 + + def get_raw(self) : + return self.frame_type.get_value_buff() + \ + self.offset_delta.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__locals) + + def _fix_attributes(self, new_cm) : + for i in self.__locals : + i._fix_attributes( new_cm ) + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__locals : + i.set_cm( cm ) + +class StackMapTableAttribute(BasicAttribute) : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + + super(StackMapTableAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length + + # u2 number_of_entries; + self.number_of_entries = SV( '>H', buff.read(2) ) + + # stack_map_frame entries[number_of_entries]; + self.__entries = [] + for i in range(0, self.number_of_entries.get_value()) : + frame_type = SV( '>B', buff.read_b(1) ).get_value() + + if frame_type >= 0 and frame_type <= 63 : + self.__entries.append( SameFrame( buff ) ) + elif frame_type >= 64 and frame_type <= 127 : + self.__entries.append( SameLocals1StackItemFrame( self.__CM, buff ) ) + elif frame_type == 247 : + self.__entries.append( SameLocals1StackItemFrameExtended( self.__CM, buff ) ) + elif frame_type >= 248 and frame_type <= 250 : + self.__entries.append( ChopFrame( buff ) ) + elif frame_type == 251 : + self.__entries.append( SameFrameExtended( buff ) ) + elif frame_type >= 252 and frame_type <= 254 : + self.__entries.append( AppendFrame( self.__CM, buff ) ) + elif frame_type == 255 : + self.__entries.append( FullFrame( self.__CM, buff ) ) + else : + bytecode.Exit( "Frame type %d is unknown" % frame_type ) + + def get_entries(self) : + return self.__entries + + def get_local_variables(self) : + for i in self.__entries : + if isinstance(i, FullFrame) : + return i.get_local_variables() + + return [] + + def get_raw(self) : + return self.number_of_entries.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__entries ) + + def show(self) : + bytecode._Print("NUMBER_OF_ENTRIES", self.number_of_entries.get_value()) + for i in self.__entries : + i.show() + + def _fix_attributes(self, new_cm) : + for i in self.__entries : + i._fix_attributes( new_cm ) + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__entries : + i.set_cm( cm ) + +class InnerClassesDesc : + def __init__(self, class_manager, buff) : + INNER_CLASSES_FORMAT = [ ">HHHH", "inner_class_info_index outer_class_info_index inner_name_index inner_class_access_flags" ] + + self.__CM = class_manager + + self.__raw_buff = buff.read( calcsize( INNER_CLASSES_FORMAT[0] ) ) + + self.format = SVs( INNER_CLASSES_FORMAT[0], namedtuple( "InnerClassesFormat", INNER_CLASSES_FORMAT[1] ), self.__raw_buff ) + + def show(self) : + print self.format + + def get_raw(self) : + return self.format.get_value_buff() + + def set_cm(self, cm) : + self.__CM = cm + +class InnerClassesAttribute(BasicAttribute) : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + + super(InnerClassesAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length + + # u2 number_of_classes; + self.number_of_classes = SV( '>H', buff.read(2) ) + + # { u2 inner_class_info_index; + # u2 outer_class_info_index; + # u2 inner_name_index; + # u2 inner_class_access_flags; + # } classes[number_of_classes]; + self.__classes = [] + + for i in range(0, self.number_of_classes.get_value()) : + self.__classes.append( InnerClassesDesc( self.__CM, buff ) ) + + def get_classes(self) : + return self.__classes + + def show(self) : + print self.number_of_classes + for i in self.__classes : + i.show() + + def set_cm(self, cm) : + self.__CM = cm + for i in self.__classes : + i.set_cm( cm ) + + def get_raw(self) : + return self.number_of_classes.get_value_buff() + \ + ''.join(x.get_raw() for x in self.__classes) + +class ConstantValueAttribute(BasicAttribute) : + def __init__(self, class_manager, buff) : + self.__CM = class_manager + + super(ConstantValueAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 constantvalue_index; + self.constantvalue_index = SV( '>H', buff.read(2) ) + + def show(self) : + print self.constantvalue_index + + def set_cm(self, cm) : + self.__CM = cm + + def get_raw(self) : + return self.constantvalue_index.get_value_buff() + +class EnclosingMethodAttribute(BasicAttribute) : + def __init__(self, class_manager, buff) : + ENCLOSING_METHOD_FORMAT = [ '>HH', "class_index method_index" ] + + self.__CM = class_manager + + super(EnclosingMethodAttribute, self).__init__() + # u2 attribute_name_index; + # u4 attribute_length; + + # u2 class_index + # u2 method_index; + + self.__raw_buff = buff.read( calcsize( ENCLOSING_METHOD_FORMAT[0] ) ) + self.format = SVs( ENCLOSING_METHOD_FORMAT[0], namedtuple( "EnclosingMethodFormat", ENCLOSING_METHOD_FORMAT[1] ), self.__raw_buff ) + + def show(self) : + print self.format + + def set_cm(self, cm) : + self.__CM = cm + + def get_raw(self) : + return self.format.get_value_buff() + +ATTRIBUTE_INFO_DESCR = { + "Code" : CodeAttribute, + "Deprecated" : DeprecatedAttribute, + "SourceFile" : SourceFileAttribute, + "Exceptions" : ExceptionsAttribute, + "LineNumberTable" : LineNumberTableAttribute, + "LocalVariableTable" : LocalVariableTableAttribute, + "LocalVariableTypeTable" : LocalVariableTypeTableAttribute, + "StackMapTable" : StackMapTableAttribute, + "InnerClasses" : InnerClassesAttribute, + "ConstantValue" : ConstantValueAttribute, + "EnclosingMethod" : EnclosingMethodAttribute, + "Signature" : SignatureAttribute, + "Synthetic" : SyntheticAttribute, + "SourceDebugExtension" : SourceDebugExtensionAttribute, + "RuntimeVisibleAnnotations" : RuntimeVisibleAnnotationsAttribute, + "RuntimeInvisibleAnnotations" : RuntimeInvisibleAnnotationsAttribute, + "RuntimeVisibleParameterAnnotations" : RuntimeVisibleParameterAnnotationsAttribute, + "RuntimeInvisibleParameterAnnotations" : RuntimeInvisibleParameterAnnotationsAttribute, + "AnnotationDefault" : AnnotationDefaultAttribute, +} + +class AttributeInfo : + """AttributeInfo manages each attribute info (Code, SourceFile ....)""" + def __init__(self, class_manager, buff) : + self.__CM = class_manager + self.__raw_buff = buff.read( calcsize( ATTRIBUTE_INFO[0] ) ) + + self.format = SVs( ATTRIBUTE_INFO[0], ATTRIBUTE_INFO[1], self.__raw_buff ) + self.__name = self.__CM.get_string( self.format.get_value().attribute_name_index ) + + try : + self._info = ATTRIBUTE_INFO_DESCR[ self.__name ](self.__CM, buff) + except KeyError, ke : + bytecode.Exit( "AttributeInfo %s doesn't exit" % self.__name ) + + def get_item(self) : + """Return the specific attribute info""" + return self._info + + def get_name(self) : + """Return the name of the attribute""" + return self.__name + + def get_raw(self) : + v1 = self.format.get_value().attribute_length + v2 = len(self._info.get_raw()) + if v1 != v2 : + self.set_attribute_length( v2 ) + + return self.format.get_value_buff() + self._info.get_raw() + + def get_attribute_name_index(self) : + return self.format.get_value().attribute_name_index + + def set_attribute_name_index(self, value) : + self.format.set_value( { "attribute_name_index" : value } ) + + def set_attribute_length(self, value) : + self.format.set_value( { "attribute_length" : value } ) + + def get_attributes(self) : + return self.format + + def _fix_attributes(self, new_cm) : + self._info._fix_attributes( new_cm ) + + def set_cm(self, cm) : + self.__CM = cm + self._info.set_cm( cm ) + + def show(self) : + print self.format, self.__name + if self._info != None : + self._info.show() + + def pretty_show(self, m_a) : + print self.format, self.__name + if self._info != None : + if isinstance(self._info, CodeAttribute) : + self._info.pretty_show(m_a) + else : + self._info.show() + +class ClassManager : + """ClassManager can be used by all classes to get more information""" + def __init__(self, constant_pool, constant_pool_count) : + self.constant_pool = constant_pool + self.constant_pool_count = constant_pool_count + + self.__this_class = None + + def get_value(self, idx) : + name = self.get_item(idx[0]).get_name() + if name == "CONSTANT_Integer" : + return [ name, self.get_item(idx[0]).get_format().get_value().bytes ] + elif name == "CONSTANT_String" : + return [ name, self.get_string( self.get_item(idx[0]).get_format().get_value().string_index ) ] + elif name == "CONSTANT_Class" : + return [ name, self.get_class( idx[0] ) ] + elif name == "CONSTANT_Fieldref" : + return [ name, self.get_field( idx[0] ) ] + elif name == "CONSTANT_Float" : + return [ name, self.get_item(idx[0]).get_format().get_value().bytes ] + + bytecode.Exit( "get_value not yet implemented for %s" % name ) + + def get_item(self, idx) : + return self.constant_pool[ idx - 1] + + def get_interface(self, idx) : + if self.get_item(idx).get_name() != "CONSTANT_InterfaceMethodref" : + return [] + + class_idx = self.get_item(idx).get_class_index() + name_and_type_idx = self.get_item(idx).get_name_and_type_index() + + return [ self.get_string( self.get_item(class_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_descriptor_index() ) + ] + + def get_interface_index(self, class_name, name, descriptor) : + raise("ooo") + + def get_method(self, idx) : + if self.get_item(idx).get_name() != "CONSTANT_Methodref" : + return [] + + class_idx = self.get_item(idx).get_class_index() + name_and_type_idx = self.get_item(idx).get_name_and_type_index() + + return [ self.get_string( self.get_item(class_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_descriptor_index() ) + ] + + def get_method_index(self, class_name, name, descriptor) : + idx = 1 + for i in self.constant_pool : + res = self.get_method( idx ) + if res != [] : + m_class_name, m_name, m_descriptor = res + if m_class_name == class_name and m_name == name and m_descriptor == descriptor : + return idx + idx += 1 + + return -1 + + def get_field(self, idx) : + if self.get_item(idx).get_name() != "CONSTANT_Fieldref" : + return [] + + class_idx = self.get_item(idx).get_class_index() + name_and_type_idx = self.get_item(idx).get_name_and_type_index() + + return [ self.get_string( self.get_item(class_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_name_index() ), + self.get_string( self.get_item(name_and_type_idx).get_descriptor_index() ) + ] + + def get_field_index(self, name, descriptor) : + idx = 1 + for i in self.constant_pool : + res = self.get_field( idx ) + if res != [] : + _, m_name, m_descriptor = res + if m_name == name and m_descriptor == descriptor : + return idx + idx += 1 + + def get_class(self, idx) : + if self.get_item(idx).get_name() != "CONSTANT_Class" : + return [] + + return [ self.get_string( self.get_item(idx).get_name_index() ) ] + + def get_array_type(self, idx) : + return ARRAY_TYPE[ idx[0] ] + + def get_string_index(self, name) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Utf8" : + if i.get_bytes() == name : + return idx + idx += 1 + return -1 + + def get_integer_index(self, value) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Integer" : + if i.get_format().get_value().bytes == value : + return idx + idx += 1 + return -1 + + def get_cstring_index(self, value) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_String" : + if self.get_string( i.get_format().get_value().string_index ) == value : + return idx + idx += 1 + return -1 + + def get_name_and_type_index(self, name_method_index, descriptor_method_index) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_NameAndType" : + value = i.get_format().get_value() + if value.name_index == name_method_index and value.descriptor_index == descriptor_method_index : + return idx + idx += 1 + return -1 + + def get_class_by_index(self, name_index) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Class" : + value = i.get_format().get_value() + if value.name_index == name_index : + return idx + idx += 1 + return -1 + + def get_method_ref_index(self, new_class_index, new_name_and_type_index) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Methodref" : + value = i.get_format().get_value() + if value.class_index == new_class_index and value.name_and_type_index == new_name_and_type_index : + return idx + idx += 1 + return -1 + + def get_field_ref_index(self, new_class_index, new_name_and_type_index) : + idx = 1 + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Fieldref" : + value = i.get_format().get_value() + if value.class_index == new_class_index and value.name_and_type_index == new_name_and_type_index : + return idx + idx += 1 + return -1 + + def get_class_index(self, method_name) : + idx = 1 + for i in self.constant_pool : + res = self.get_method( idx ) + if res != [] : + _, name, _ = res + if name == method_name : + return i.get_class_index() + idx += 1 + return -1 + + def get_class_index2(self, class_name) : + idx = 1 + for i in self.constant_pool : + res = self.get_class( idx ) + if res != [] : + name = res[0] + if name == class_name : + return idx + idx += 1 + return -1 + + def get_used_fields(self) : + l = [] + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Fieldref" : + l.append( i ) + return l + + def get_used_methods(self) : + l = [] + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Methodref" : + l.append( i ) + return l + + def get_string(self, idx) : + if self.constant_pool[idx - 1].get_name() == "CONSTANT_Utf8" : + return self.constant_pool[idx - 1].get_bytes() + return None + + def set_string(self, idx, name) : + if self.constant_pool[idx - 1].get_name() == "CONSTANT_Utf8" : + self.constant_pool[idx - 1].set_bytes( name ) + else : + bytecode.Exit( "invalid index %d to set string %s" % (idx, name) ) + + def add_string(self, name) : + name_index = self.get_string_index(name) + if name_index != -1 : + return name_index + + tag_value = INVERT_CONSTANT_INFO[ "CONSTANT_Utf8" ] + buff = pack( CONSTANT_INFO[ tag_value ][1], tag_value, len(name) ) + pack( ">%ss" % len(name), name ) + ci = CONSTANT_INFO[ tag_value ][-1]( self, bytecode.BuffHandle( buff ) ) + + self.constant_pool.append( ci ) + self.constant_pool_count.set_value( self.constant_pool_count.get_value() + 1 ) + + return self.constant_pool_count.get_value() - 1 + + def set_this_class(self, this_class) : + self.__this_class = this_class + + def get_this_class(self) : + return self.__this_class.get_value() + + def get_this_class_name(self) : + return self.get_class( self.__this_class.get_value() )[0] + + def add_constant_pool(self, elem) : + self.constant_pool.append( elem ) + self.constant_pool_count.set_value( self.constant_pool_count.get_value() + 1 ) + + def get_constant_pool_count(self) : + return self.constant_pool_count.get_value() + + def create_class(self, name) : + class_name_index = self.add_string( name ) + return self._create_class( class_name_index ) + + def _create_class(self, class_name_index) : + class_index = self.get_class_by_index( class_name_index ) + if class_index == -1 : + new_class = CreateClass( self, class_name_index ) + self.add_constant_pool( Class( self, bytecode.BuffHandle( new_class.get_raw() ) ) ) + class_index = self.get_constant_pool_count() - 1 + return class_index + + def create_name_and_type(self, name, desc) : + name_index = self.add_string( name ) + descriptor_index = self.add_string( desc ) + + return self._create_name_and_type( name_index, descriptor_index ) + + def create_name_and_type_by_index(self, name_method_index, descriptor_method_index) : + return self._create_name_and_type( name_method_index, descriptor_method_index ) + + def _create_name_and_type(self, name_method_index, descriptor_method_index) : + name_and_type_index = self.get_name_and_type_index( name_method_index, descriptor_method_index ) + if name_and_type_index == -1 : + new_nat = CreateNameAndType( self, name_method_index, descriptor_method_index ) + self.add_constant_pool( NameAndType( self, bytecode.BuffHandle( new_nat.get_raw() ) ) ) + name_and_type_index = self.get_constant_pool_count() - 1 + return name_and_type_index + + def create_method_ref(self, new_class_index, new_name_and_type_index) : + new_mr_index = self.get_method_ref_index( new_class_index, new_name_and_type_index ) + if new_mr_index == -1 : + new_mr = CreateMethodRef( self, new_class_index, new_name_and_type_index ) + self.add_constant_pool( MethodRef( self, bytecode.BuffHandle( new_mr.get_raw() ) ) ) + new_mr_index = self.get_constant_pool_count() - 1 + return new_mr_index + + def create_field_ref(self, new_class_index, new_name_and_type_index) : + new_fr_index = self.get_field_ref_index( new_class_index, new_name_and_type_index ) + if new_fr_index == -1 : + new_fr = CreateFieldRef( self, new_class_index, new_name_and_type_index ) + self.add_constant_pool( FieldRef( self, bytecode.BuffHandle( new_fr.get_raw() ) ) ) + new_fr_index = self.get_constant_pool_count() - 1 + return new_fr_index + + def create_integer(self, value) : + new_int_index = self.get_integer_index( value ) + if new_int_index == -1 : + new_int = CreateInteger( value ) + self.add_constant_pool( Integer( self, bytecode.BuffHandle( new_int.get_raw() ) ) ) + new_int_index = self.get_constant_pool_count() - 1 + + return new_int_index + + def create_string(self, value) : + new_string_index = self.get_cstring_index( value ) + if new_string_index == -1 : + new_string = CreateString( self, value ) + self.add_constant_pool( String( self, bytecode.BuffHandle( new_string.get_raw() ) ) ) + new_string_index = self.get_constant_pool_count() - 1 + return new_string_index + + +class JVMFormat(bytecode._Bytecode) : + """ + An object which is the main class to handle properly a class file. + Exported fields : magic, minor_version, major_version, constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, methods_count, attributes_count + """ + def __init__(self, buff) : + """ + @param buff : the buffer which represents the open file + """ + super(JVMFormat, self).__init__( buff ) + + self._load_class() + + def _load_class(self) : + # u4 magic; + # u2 minor_version; + # u2 major_version; + self.magic = SV( '>L', self.read( 4 ) ) + self.minor_version = SV( '>H', self.read( 2 ) ) + self.major_version = SV( '>H', self.read( 2 ) ) + + # u2 constant_pool_count; + self.constant_pool_count = SV( '>H', self.read( 2 ) ) + + # cp_info constant_pool[constant_pool_count-1]; + self.constant_pool = [] + self.__CM = ClassManager( self.constant_pool, self.constant_pool_count ) + + i = 1 + while(i < self.constant_pool_count.get_value()) : + tag = SV( '>B', self.read_b( 1 ) ) + + if tag.get_value() not in CONSTANT_INFO : + bytecode.Exit( "tag %d not in CONSTANT_INFO" % tag.get_value() ) + + ci = CONSTANT_INFO[ tag.get_value() ][-1]( self.__CM, self ) + self.constant_pool.append( ci ) + + i = i + 1 + # CONSTANT_Long or CONSTANT_Double + # If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item + # in the constant_pool table at index n, then the next usable item in the pool is + # located at index n + 2. The constant_pool index n + 1 must be valid but is + # considered unusable. + if tag.get_value() == 5 or tag.get_value() == 6 : + self.constant_pool.append( EmptyConstant() ) + i = i + 1 + + # u2 access_flags; + # u2 this_class; + # u2 super_class; + self.access_flags = SV( '>H', self.read( 2 ) ) + self.this_class = SV( '>H', self.read( 2 ) ) + self.super_class = SV( '>H', self.read( 2 ) ) + + self.__CM.set_this_class( self.this_class ) + + # u2 interfaces_count; + self.interfaces_count = SV( '>H', self.read( 2 ) ) + + # u2 interfaces[interfaces_count]; + self.interfaces = [] + for i in range(0, self.interfaces_count.get_value()) : + tag = SV( '>H', self.read( 2 ) ) + self.interfaces.append( tag ) + + + # u2 fields_count; + self.fields_count = SV( '>H', self.read( 2 ) ) + + # field_info fields[fields_count]; + self.fields = [] + for i in range(0, self.fields_count.get_value()) : + fi = FieldInfo( self.__CM, self ) + self.fields.append( fi ) + + # u2 methods_count; + self.methods_count = SV( '>H', self.read( 2 ) ) + + # method_info methods[methods_count]; + self.methods = [] + for i in range(0, self.methods_count.get_value()) : + mi = MethodInfo( self.__CM, self ) + self.methods.append( mi ) + + # u2 attributes_count; + self.attributes_count = SV( '>H', self.read( 2 ) ) + + # attribute_info attributes[attributes_count]; + self.__attributes = [] + for i in range(0, self.attributes_count.get_value()) : + ai = AttributeInfo( self.__CM, self ) + self.__attributes.append( ai ) + + def get_class(self, class_name) : + """ + Verify the name of the class + + @param class_name : the name of the class + + @rtype : True if the class name is valid, otherwise it's False + """ + x = self.__CM.get_this_class_name() == class_name + if x == True : + return x + + return self.__CM.get_this_class_name() == class_name.replace(".", "/") + + def get_classes_names(self) : + """ + Return the names of classes + """ + return [ self.__CM.get_this_class_name() ] + + def get_name(self) : + """ + + """ + return self.__CM.get_this_class_name() + + def get_classes(self) : + """ + + """ + return [ self ] + + def get_field(self, name) : + """ + Return into a list all fields which corresponds to the regexp + + @param name : the name of the field (a regexp) + """ + prog = re.compile( name ) + fields = [] + for i in self.fields : + if prog.match( i.get_name() ) : + fields.append( i ) + return fields + + def get_method_descriptor(self, class_name, method_name, descriptor) : + """ + Return the specific method + + @param class_name : the class name of the method + @param method_name : the name of the method + @param descriptor : the descriptor of the method + + @rtype: L{MethodInfo} + """ + # FIXME : handle multiple class name ? + if class_name != None : + if class_name != self.__CM.get_this_class_name() : + return None + + for i in self.methods : + if method_name == i.get_name() and descriptor == i.get_descriptor() : + return i + + return None + + def get_field_descriptor(self, class_name, field_name, descriptor) : + """ + Return the specific field + + @param class_name : the class name of the field + @param field_name : the name of the field + @param descriptor : the descriptor of the field + + @rtype: L{FieldInfo} + """ + # FIXME : handle multiple class name ? + if class_name != None : + if class_name != self.__CM.get_this_class_name() : + return None + + for i in self.fields : + if field_name == i.get_name() and descriptor == i.get_descriptor() : + return i + return None + + def get_method(self, name) : + """Return into a list all methods which corresponds to the regexp + + @param name : the name of the method (a regexp) + """ + prog = re.compile( name ) + methods = [] + for i in self.methods : + if prog.match( i.get_name() ) : + methods.append( i ) + return methods + + def get_all_fields(self) : + return self.fields + + def get_fields(self) : + """Return all objects fields""" + return self.fields + + def get_methods(self) : + """Return all objects methods""" + return self.methods + + def get_constant_pool(self) : + """Return the constant pool list""" + return self.constant_pool + + def get_strings(self) : + """Return all strings into the class""" + l = [] + for i in self.constant_pool : + if i.get_name() == "CONSTANT_Utf8" : + l.append( i.get_bytes() ) + return l + + def get_class_manager(self) : + """ + Return directly the class manager + + @rtype : L{ClassManager} + """ + return self.__CM + + def set_used_field(self, old, new) : + """ + Change the description of a field + + @param old : a list of string which contained the original class name, the original field name and the original descriptor + @param new : a list of string which contained the new class name, the new field name and the new descriptor + """ + used_fields = self.__CM.get_used_fields() + for i in used_fields : + class_idx = i.format.get_value().class_index + name_and_type_idx = i.format.get_value().name_and_type_index + class_name = self.__CM.get_string( self.__CM.get_item(class_idx).get_name_index() ) + field_name = self.__CM.get_string( self.__CM.get_item(name_and_type_idx).get_name_index() ) + descriptor = self.__CM.get_string( self.__CM.get_item(name_and_type_idx).get_descriptor_index() ) + + if old[0] == class_name and old[1] == field_name and old[2] == descriptor : +# print "SET USED FIELD", class_name, method_name, descriptor + + self.__CM.set_string( self.__CM.get_item(class_idx).get_name_index(), new[0] ) + self.__CM.set_string( self.__CM.get_item(name_and_type_idx).get_name_index(), new[1] ) + self.__CM.set_string( self.__CM.get_item(name_and_type_idx).get_descriptor_index(), new[2] ) + + def set_used_method(self, old, new) : + """ + Change the description of a method + @param old : a list of string which contained the original class name, the original method name and the original descriptor + @param new : a list of string which contained the new class name, the new method name and the new descriptor + """ + used_methods = self.__CM.get_used_methods() + for i in used_methods : + class_idx = i.format.get_value().class_index + name_and_type_idx = i.format.get_value().name_and_type_index + class_name = self.__CM.get_string( self.__CM.get_item(class_idx).get_name_index() ) + method_name = self.__CM.get_string( self.__CM.get_item(name_and_type_idx).get_name_index() ) + descriptor = self.__CM.get_string( self.__CM.get_item(name_and_type_idx).get_descriptor_index() ) + + if old[0] == class_name and old[1] == method_name and old[2] == descriptor : +# print "SET USED METHOD", class_name, method_name, descriptor + + self.__CM.set_string( self.__CM.get_item(class_idx).get_name_index(), new[0] ) + self.__CM.set_string( self.__CM.get_item(name_and_type_idx).get_name_index(), new[1] ) + self.__CM.set_string( self.__CM.get_item(name_and_type_idx).get_descriptor_index(), new[2] ) + + + def show(self) : + """ + Show the .class format into a human readable format + """ + bytecode._Print( "MAGIC", self.magic.get_value() ) + bytecode._Print( "MINOR VERSION", self.minor_version.get_value() ) + bytecode._Print( "MAJOR VERSION", self.major_version.get_value() ) + bytecode._Print( "CONSTANT POOL COUNT", self.constant_pool_count.get_value() ) + + nb = 0 + for i in self.constant_pool : + print nb, + i.show() + nb += 1 + + + bytecode._Print( "ACCESS FLAGS", self.access_flags.get_value() ) + bytecode._Print( "THIS CLASS", self.this_class.get_value() ) + bytecode._Print( "SUPER CLASS", self.super_class.get_value() ) + + bytecode._Print( "INTERFACE COUNT", self.interfaces_count.get_value() ) + nb = 0 + for i in self.interfaces : + print nb, + print i + + bytecode._Print( "FIELDS COUNT", self.fields_count.get_value() ) + nb = 0 + for i in self.fields : + print nb, + i.show() + nb += 1 + + + bytecode._Print( "METHODS COUNT", self.methods_count.get_value() ) + nb = 0 + for i in self.methods : + print nb, + i.show() + nb += 1 + + + bytecode._Print( "ATTRIBUTES COUNT", self.attributes_count.get_value() ) + nb = 0 + for i in self.__attributes : + print nb, + i.show() + nb += 1 + + def pretty_show(self, vm_a) : + """ + Show the .class format into a human readable format + """ + bytecode._Print( "MAGIC", self.magic.get_value() ) + bytecode._Print( "MINOR VERSION", self.minor_version.get_value() ) + bytecode._Print( "MAJOR VERSION", self.major_version.get_value() ) + bytecode._Print( "CONSTANT POOL COUNT", self.constant_pool_count.get_value() ) + + nb = 0 + for i in self.constant_pool : + print nb, + i.show() + nb += 1 + + + bytecode._Print( "ACCESS FLAGS", self.access_flags.get_value() ) + bytecode._Print( "THIS CLASS", self.this_class.get_value() ) + bytecode._Print( "SUPER CLASS", self.super_class.get_value() ) + + bytecode._Print( "INTERFACE COUNT", self.interfaces_count.get_value() ) + nb = 0 + for i in self.interfaces : + print nb, + i.show() + + bytecode._Print( "FIELDS COUNT", self.fields_count.get_value() ) + nb = 0 + for i in self.fields : + print nb, + i.show() + nb += 1 + + + bytecode._Print( "METHODS COUNT", self.methods_count.get_value() ) + nb = 0 + for i in self.methods : + print nb, + i.pretty_show(vm_a) + nb += 1 + + + bytecode._Print( "ATTRIBUTES COUNT", self.attributes_count.get_value() ) + nb = 0 + for i in self.__attributes : + print nb, + i.show() + + def insert_string(self, value) : + """Insert a string into the constant pool list (Constant_Utf8) + + @param value : the new string + """ + self.__CM.add_string( value ) + + def insert_field(self, class_name, name, descriptor) : + """ + Insert a field into the class + + @param class_name : the class of the field + @param name : the name of the field + @param descriptor : a list with the access_flag and the descriptor ( [ "ACC_PUBLIC", "I" ] ) + """ + new_field = CreateFieldInfo( self.__CM, name, descriptor ) + + new_field = FieldInfo( self.__CM, bytecode.BuffHandle( new_field.get_raw() ) ) + + self.fields.append( new_field ) + self.fields_count.set_value( self.fields_count.get_value() + 1 ) + + # Add a FieldRef and a NameAndType + name_and_type_index = self.__CM.create_name_and_type_by_index( new_field.get_name_index(), new_field.get_descriptor_index() ) + self.__CM.create_field_ref( self.__CM.get_this_class(), name_and_type_index ) + + def insert_craft_method(self, name, proto, codes) : + """ + Insert a craft method into the class + + @param name : the name of the new method + @param proto : a list which describe the method ( [ ACCESS_FLAGS, RETURN_TYPE, ARGUMENTS ], ie : [ "ACC_PUBLIC", "[B", "[B" ] ) + @param codes : a list which represents the code into a human readable format ( [ "aconst_null" ], [ "areturn" ] ] ) + """ + # Create new method + new_method = CreateMethodInfo(self.__CM, name, proto, codes) + + # Insert the method by casting it directly into a MethodInfo with the raw buffer + self._insert_basic_method( MethodInfo( self.__CM, bytecode.BuffHandle( new_method.get_raw() ) ) ) + + def insert_direct_method(self, name, ref_method) : + """ + Insert a direct method (MethodInfo object) into the class + + @param name : the name of the new method + @param ref_method : the MethodInfo Object + """ + if ref_method == None : + return + + # Change the name_index + name_index = self.__CM.get_string_index( name ) + if name_index != -1 : + bytecode.Exit( "method %s already exits" % name ) + + name_index = self.__CM.add_string( name ) + ref_method.set_name_index( name_index ) + + # Change the descriptor_index + descriptor_index = self.__CM.get_string_index( ref_method.get_descriptor() ) + if descriptor_index == -1 : + descriptor_index = self.__CM.add_string( ref_method.get_descriptor() ) + ref_method.set_descriptor_index( descriptor_index ) + + # Change attributes name index + self._fix_attributes_external( ref_method ) + + # Change internal index + self._fix_attributes_internal( ref_method ) + + # Insert the method + self._insert_basic_method( ref_method ) + + def _fix_attributes_external(self, ref_method) : + for i in ref_method.get_attributes() : + attribute_name_index = self.__CM.add_string( i.get_name() ) + + i.set_attribute_name_index( attribute_name_index ) + + self._fix_attributes_external( i.get_item() ) + + def _fix_attributes_internal(self, ref_method) : + for i in ref_method.get_attributes() : + attribute_name_index = self.__CM.add_string( i.get_name() ) + + i._fix_attributes( self.__CM ) + + i.set_attribute_name_index( attribute_name_index ) + + def _insert_basic_method(self, ref_method) : + # Add a MethodRef and a NameAndType + name_and_type_index = self.__CM.create_name_and_type_by_index( ref_method.get_name_index(), ref_method.get_descriptor_index() ) + + self.__CM.create_method_ref( self.__CM.get_this_class(), name_and_type_index ) + + # Change the class manager + ref_method.set_cm( self.__CM ) + + # Insert libraries/constants dependances + methods = ref_method._patch_bytecodes() + + # FIXME : insert needed fields + methods + prog = re.compile( "^java*" ) + for i in methods : + if prog.match( i[0] ) == None : + bytecode.Exit( "ooooops" ) + + + #ref_method.show() + + # Insert the method + self.methods.append( ref_method ) + self.methods_count.set_value( self.methods_count.get_value() + 1 ) + + def _get_raw(self) : + # u4 magic; + # u2 minor_version; + # u2 major_version; + buff = self.magic.get_value_buff() + buff += self.minor_version.get_value_buff() + buff += self.major_version.get_value_buff() + + # u2 constant_pool_count; + buff += self.constant_pool_count.get_value_buff() + + # cp_info constant_pool[constant_pool_count-1]; + for i in self.constant_pool : + buff += i.get_raw() + + # u2 access_flags; + # u2 this_class; + # u2 super_class; + buff += self.access_flags.get_value_buff() + buff += self.this_class.get_value_buff() + buff += self.super_class.get_value_buff() + + # u2 interfaces_count; + buff += self.interfaces_count.get_value_buff() + + # u2 interfaces[interfaces_count]; + for i in self.interfaces : + buff += i.get_value_buff() + + # u2 fields_count; + buff += self.fields_count.get_value_buff() + + # field_info fields[fields_count]; + for i in self.fields : + buff += i.get_raw() + + # u2 methods_count; + buff += self.methods_count.get_value_buff() + + # method_info methods[methods_count]; + for i in self.methods : + buff += i.get_raw() + + # u2 attributes_count; + buff += self.attributes_count.get_value_buff() + + # attribute_info attributes[attributes_count]; + for i in self.__attributes : + buff += i.get_raw() + + return buff + + def save(self) : + """ + Return the class (with the modifications) into raw format + + @rtype: string + """ + return self._get_raw() + + def set_vmanalysis(self, vmanalysis) : + pass + + def get_generator(self) : + import jvm_generate + return jvm_generate.JVMGenerate + + def get_INTEGER_INSTRUCTIONS(self) : + return INTEGER_INSTRUCTIONS + + def get_type(self) : + return "JVM" diff --git a/androguard/core/bytecodes/jvm_generate.py b/androguard/core/bytecodes/jvm_generate.py new file mode 100644 index 00000000..035e48f5 --- /dev/null +++ b/androguard/core/bytecodes/jvm_generate.py @@ -0,0 +1,137 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012 Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import random + +from androconf import error +import jvm + +class Automaton : + def __init__(self, _analysis) : + self.__analysis = _analysis + + try : + from networkx import DiGraph + from networkx import draw_graphviz, write_dot + except ImportError : + error("module networkx not found") + + self.__G = DiGraph() + + for m in self.__analysis.get_methods() : + for bb in m.basic_blocks.get() : + for trace in bb.stack_traces.get() : + for mre in jvm.MATH_JVM_RE : + if mre[0].match( trace[2].get_name() ) : + for i in trace[3].gets() : + self._add( str(i) ) + + def _add(self, elem) : + l = [] + x = "" + for i in elem : + if i not in jvm.MATH_JVM_OPCODES.values() : + x += i + else : + l.append( x ) + l.append( i ) + x = "" + + if len(l) > 1 : + l.append( x ) + + self._add_expr( l ) + + def _add_expr(self, l) : + if l == [] : + return + i = 0 + while i < (len(l)-1) : + self.__G.add_edge( self._transform(l[i]), self._transform(l[i+1]) ) + + i += 1 + + def _transform(self, i) : + if "VARIABLE" in i : + return "V" + return i + + def new(self, loop) : + expr = [] + + l = list( self.__G.node ) + + init = l[ random.randint(0, len(l) - 1) ] + while init in jvm.MATH_JVM_OPCODES.values() : + init = l[ random.randint(0, len(l) - 1) ] + + expr.append( init ) + + i = 0 + while i <= loop : + l = list( self.__G.edge[ init ] ) + if l == [] : + break + + init = l[ random.randint(0, len(l) - 1) ] + expr.append( init ) + + i += 1 + + return expr + + def show(self) : + print self.__G.node + print self.__G.edge + + #draw_graphviz(self.__G) + #write_dot(self.__G,'file.dot') + +class JVMGenerate : + def __init__(self, _vm, _analysis) : + self.__vm = _vm + self.__analysis = _analysis + + self.__automaton = Automaton( self.__analysis ) + self.__automaton.show() + + def create_affectation(self, method_name, desc) : + l = [] + + if desc[0] == 0 : + l.append( [ "aload_0" ] ) + l.append( [ "bipush", desc[2] ] ) + l.append( [ "putfield", desc[1].get_name(), desc[1].get_descriptor() ] ) + + return l + + def write(self, method, offset, field) : + print method, offset, field + expr = self.__automaton.new( 5 ) + + print field.get_name(), "EXPR ->", expr + + self._transform( expr ) + + + def _transform(self, expr) : + if len(expr) == 1 : + return + + x = [ expr.pop(0), expr.pop(1), expr.pop(0) ] + +# while expr != [] : diff --git a/androguard/core/bytecodes/libdvm/Makefile b/androguard/core/bytecodes/libdvm/Makefile new file mode 100644 index 00000000..4e0efce4 --- /dev/null +++ b/androguard/core/bytecodes/libdvm/Makefile @@ -0,0 +1,33 @@ +SRC = dvm.cc buff.cc + +CUROS = $(shell uname -s) +ifeq ($(CUROS),Darwin) +LDFLAGS = -lpython +else +LDFLAGS = +endif + +CFLAGS += -g -fPIC -I/usr/include/python2.7/ +mkdir = mkdir -p +CD = cd +RM = rm -f + +CCP = g++ + +LIBNAME = dvmnative + +OBJ = $(SRC:.cc=.o) + +.SILENT: + +all : $(OBJ) LIBDVM + +LIBDVM : + $(CCP) -o $(LIBNAME).so $(OBJ) -shared $(LDFLAGS) + +clean : + $(RM) *.o $(LIBNAME).so + +%.o : %.cc + echo " CCP $@" + $(CCP) $(CFLAGS) -c -o $@ $< diff --git a/androguard/core/bytecodes/libdvm/__init__.py b/androguard/core/bytecodes/libdvm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/bytecodes/libdvm/buff.cc b/androguard/core/bytecodes/libdvm/buff.cc new file mode 100644 index 00000000..9136d3c0 --- /dev/null +++ b/androguard/core/bytecodes/libdvm/buff.cc @@ -0,0 +1,99 @@ +/* + This file is part of Androguard. + + Copyright (C) 2011, Anthony Desnos + All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS-IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include "buff.h" + +#include + +Buff::Buff() { + +} + +Buff::Buff(const char *data, size_t data_len) { + bdata = data; + bdata_len = data_len; + bcurrent_idx = 0; +} + +Buff:: Buff(const char *data, size_t data_len, size_t current_idx) { + bdata = data; + bdata_len = data_len; + bcurrent_idx = current_idx; +} + +void Buff::setup(const char *data, size_t data_len, size_t current_idx) { + bdata = data; + bdata_len = data_len; + bcurrent_idx = current_idx; +} + +const char *Buff::read(size_t len) { + //cout << "read add " << bcurrent_idx << " " << len << "\n"; + bcurrent_idx += len; + return (bdata + (bcurrent_idx - len)); +} + +const char *Buff::readat(size_t pos, size_t len) { + return (bdata + (pos)); +} + +const char *Buff::read_false(size_t len) { + return (bdata + (bcurrent_idx)); +} + +size_t Buff::get_current_idx() { + return bcurrent_idx; +} + +size_t Buff::get_end() { + return bdata_len; +} + +bool Buff::empty() { + return bcurrent_idx == bdata_len; +} + +int Buff::register_dynamic_offset(unsigned int *addr) { + DynamicOffsets.push_back( addr ); +} + +int Buff::set_idx(unsigned int idx) { + bcurrent_idx = idx; +} + +unsigned char Buff::read_uc() { + return *( reinterpret_cast( const_cast(this->read(1))) ); +} + +char Buff::read_c() { + return *( reinterpret_cast( const_cast(this->read(1))) ); +} + +unsigned long Buff::read_ul() { + return *( reinterpret_cast( const_cast(this->read(4))) ); +} + +unsigned int Buff::read_ui() { + return *( reinterpret_cast( const_cast(this->read(4))) ); +} + +unsigned short Buff::read_us() { + return *( reinterpret_cast( const_cast(this->read(2))) ); +} diff --git a/androguard/core/bytecodes/libdvm/buff.h b/androguard/core/bytecodes/libdvm/buff.h new file mode 100644 index 00000000..84e1873f --- /dev/null +++ b/androguard/core/bytecodes/libdvm/buff.h @@ -0,0 +1,69 @@ +/* + This file is part of Androguard. + + Copyright (C) 2011, Anthony Desnos + All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS-IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef BUFF_H +#define BUFF_H + +#ifdef __cplusplus + +#if defined __GNUC__ || defined __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include + +using namespace __gnu_cxx; +using namespace std; +using std::cout; +using std::endl; + +class Buff { + public : + const char *bdata; + size_t bdata_len; + size_t bcurrent_idx; + + vector DynamicOffsets; + public : + Buff(); + Buff(const char *data, size_t data_len); + Buff(const char *data, size_t data_len, size_t current_idx); + void setup(const char *data, size_t data_len, size_t current_idx); + const char *read(size_t len); + const char *readat(size_t pos, size_t len); + const char *read_false(size_t len); + size_t get_current_idx(); + size_t get_end(); + bool empty(); + int register_dynamic_offset(unsigned int *addr); + int set_idx(unsigned int); + unsigned char read_uc(); + char read_c(); + unsigned long read_ul(); + unsigned int read_ui(); + unsigned short read_us(); +}; + +#endif + +#endif diff --git a/androguard/core/bytecodes/libdvm/dvm.cc b/androguard/core/bytecodes/libdvm/dvm.cc new file mode 100644 index 00000000..a09073c2 --- /dev/null +++ b/androguard/core/bytecodes/libdvm/dvm.cc @@ -0,0 +1,1886 @@ +/* + This file is part of Androguard. + + Copyright (C) 2012, Anthony Desnos + All rights reserved. + + Androguard is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Androguard is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Androguard. If not, see . +*/ + +#include "dvm.h" + +unsigned int B_A_OP_CCCC(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + unsigned short *si16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + //memcpy( &i16, b->read( 2 ), 2 ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 12) & 0xf) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + //memcpy( &i16, b->read( 2 ), 2 ); + v->push_back( (unsigned int)i16 ); + + return 4; +} + +unsigned int B_A_OP_CCCC_3_FIELD(Buff *b, vector *v, vector *vdesc) { + unsigned int size = B_A_OP_CCCC( b, v, vdesc ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + (*vdesc)[3] = FIELD; + + return size; +} + +unsigned int B_A_OP_CCCC_3_TYPE(Buff *b, vector *v, vector *vdesc) { + unsigned int size = B_A_OP_CCCC( b, v, vdesc ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + (*vdesc)[3] = TYPE; + + return size; +} + +unsigned int B_A_OP_CCCC_G_F_E_D(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + //memcpy( &i16, b->read( 2 ), 2 ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 12) & 0xf) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + //memcpy( &i16, b->read( 2 ), 2 ); + v->push_back( (unsigned int)i16 ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + //memcpy( &i16, b->read( 2 ), 2 ); + v->push_back( (unsigned int)(i16 & 0xf) ); + + v->push_back( (unsigned int)((i16 >> 4) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 12) & 0xf) ); + + return 6; +} + +unsigned int OP_00(Buff *b, vector *v, vector *vdesc) { + unsigned char i8; + + i8 = *( reinterpret_cast( const_cast(b->read(1))) ); + v->push_back( (unsigned int)(i8) ); + + b->read(1); + + vdesc->push_back( OPVALUE ); + + return 2; +} + +unsigned int AA_OP_SBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + signed short si16; + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + + return 4; +} + +unsigned int AA_OP_SBBBB_BRANCH(Buff *b, vector *v, vector *vdesc) { + unsigned int size = AA_OP_SBBBB(b, v, vdesc); + + (*vdesc)[2] = INTEGER_BRANCH; + + return size; +} + +unsigned int SB_A_OP(Buff *b, vector *v, vector *vdesc) { + signed short si16; + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(si16 & 0xff) ); + v->push_back( (unsigned int)((si16 >> 8) & 0xf) ); + v->push_back( (signed int)((si16 >> 12) & 0xf) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + + return 2; +} + +unsigned int AA_OP(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + + return 2; +} + +unsigned int AA_OP_BBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + return 4; +} + +unsigned int DAA_OP_DBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( INTEGER ); + + return 4; +} + + +unsigned int AA_OP_BBBB_2_FIELD(Buff *b, vector *v, vector *vdesc) { + unsigned int size = AA_OP_BBBB( b, v, vdesc ); + + (*vdesc)[2] = FIELD; + + return size; +} + +unsigned int AA_OP_BBBB_2_TYPE(Buff *b, vector *v, vector *vdesc) { + unsigned int size = AA_OP_BBBB( b, v, vdesc ); + + (*vdesc)[2] = TYPE; + + return size; +} + +unsigned int AA_OP_BBBB_2_STRING(Buff *b, vector *v, vector *vdesc) { + unsigned int size = AA_OP_BBBB( b, v, vdesc ); + + (*vdesc)[2] = STRING; + + return size; +} + +unsigned int AA_OP_BBBBBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + unsigned int i32; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i32 = *( reinterpret_cast( const_cast(b->read(4))) ); + v->push_back( (unsigned int)(i32) ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + return 6; +} + +unsigned int AA_OP_BBBBBBBB_2_STRING(Buff *b, vector *v, vector *vdesc) { + unsigned int size = AA_OP_BBBBBBBB(b, v, vdesc); + + (*vdesc)[2] = STRING; + + return size; +} + +unsigned int OP_SAA(Buff *b, vector *v, vector *vdesc) { + unsigned char i8; + signed char si8; + + i8 = *( reinterpret_cast( const_cast(b->read(1))) ); + v->push_back( (unsigned int)(i8) ); + + si8 = *( reinterpret_cast( const_cast(b->read(1))) ); + v->push_back( (signed int)(si8) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( INTEGER ); + + return 2; +} + +unsigned int OP_SAA_BRANCH(Buff *b, vector *v, vector *vdesc) { + unsigned int size = OP_SAA(b, v, vdesc); + + (*vdesc)[ 1 ] = INTEGER_BRANCH; + + return size; +} + +unsigned int B_A_OP(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 12) & 0xf) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( REGISTER ); + + return 2; +} + +unsigned int _00_OP_SAAAA(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed short si16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( INTEGER ); + + return 4; +} + +unsigned int _00_OP_SAAAA_BRANCH(Buff *b, vector *v, vector *vdesc) { + unsigned int size = _00_OP_SAAAA(b, v, vdesc); + + (*vdesc)[ 1 ] = INTEGER_BRANCH; + + return size; +} + +unsigned int _00_OP_SAAAAAAAA(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed int si32; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + + si32 = *( reinterpret_cast( const_cast(b->read(4))) ); + v->push_back( (signed int)(si32) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( INTEGER ); + + return 6; +} + +unsigned int _00_OP_SAAAAAAAA_BRANCH(Buff *b, vector *v, vector *vdesc) { + unsigned int size = _00_OP_SAAAAAAAA(b, v, vdesc); + + (*vdesc)[ 1 ] = INTEGER_BRANCH; + + return size; +} + +unsigned int B_A_OP_SCCCC(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed short si16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xf) ); + v->push_back( (unsigned int)((i16 >> 12) & 0xf) ); + + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)si16 ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + + return 4; +} + +unsigned int B_A_OP_SCCCC_BRANCH(Buff *b, vector *v, vector *vdesc) { + unsigned int size = B_A_OP_SCCCC(b, v, vdesc); + + (*vdesc)[3] = INTEGER_BRANCH; + + return size; +} + +unsigned int AA_OP_CC_BB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( REGISTER ); + vdesc->push_back( REGISTER ); + + return 4; +} + +unsigned int AA_OP_BB_SCC(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + unsigned char i8; + char si8; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i8 = *( reinterpret_cast( const_cast(b->read(1))) ); + v->push_back( (unsigned int)(i8) ); + + si8 = *( reinterpret_cast( const_cast(b->read(1))) ); + v->push_back( (signed int)(si8) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + + return 4; +} + +unsigned int AA_OP_SBBBBBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed int si32; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + si32 = *( reinterpret_cast( const_cast(b->read(4))) ); + v->push_back( (signed int)(si32) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + + return 6; +} + +unsigned int AA_OP_BBBB_CCCC(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + return 6; +} + +unsigned int AA_OP_SBBBB_SBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed short si16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + vdesc->push_back( INTEGER ); + + return 6; +} + +unsigned int AA_OP_SBBBB_SBBBB_SBBBB_SBBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + signed short si16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + v->push_back( (unsigned int)((i16 >> 8) & 0xff) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + si16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (signed int)(si16) ); + + vdesc->push_back( OPVALUE ); + vdesc->push_back( REGISTER ); + vdesc->push_back( INTEGER ); + vdesc->push_back( INTEGER ); + vdesc->push_back( INTEGER ); + vdesc->push_back( INTEGER ); + + return 10; +} + +unsigned int _00_OP_AAAA_BBBB(Buff *b, vector *v, vector *vdesc) { + unsigned short i16; + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16 & 0xff) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + i16 = *( reinterpret_cast( const_cast(b->read(2))) ); + v->push_back( (unsigned int)(i16) ); + + return 6; +} + +void INVOKE(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + unsigned int nb_arg = (*v)[2]; + unsigned int meth = (*v)[3]; + vector::iterator it; + + if (nb_arg == 5) { + unsigned int op_1 = (*v)[1]; + + it=v->begin()+4; + v->insert( v->begin()+1, it, it+4+nb_arg ); + v->erase( v->begin()+nb_arg, v->end() ); + + v->push_back( op_1 ); + v->push_back( meth ); + } + else { + it=v->begin()+4; + v->insert( v->begin()+1, it, it+4+nb_arg ); + v->erase( v->begin()+nb_arg+1, v->end() ); + + v->push_back( meth ); + } + + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + (*vdesc)[ vdesc->size() - 1 ] = METHOD; +} + +void FILLEDNEWARRAY(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + INVOKE(b, v, vdesc, d, min_data); + (*vdesc)[ vdesc->size() - 1 ] = TYPE; +} + +void INVOKERANGE(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + unsigned int nb_arg = (*v)[1]; + unsigned int meth = (*v)[2]; + vector::iterator it; + + unsigned int NNNN = (*v)[3] + (*v)[1] + 1; + + for(int ii = (*v)[3]+1; ii < NNNN - 1; ii++) { + v->push_back( ii ); + } + + v->push_back( meth ); + v->erase( v->begin()+1, v->begin()+3 ); + + vdesc->push_back( OPVALUE ); + for(int i=1; i < v->size(); i++) + vdesc->push_back( REGISTER ); + + (*vdesc)[ vdesc->size() - 1 ] = METHOD; +} + +void FILLEDNEWARRAYRANGE(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + INVOKERANGE(b, v, vdesc, d, min_data); + (*vdesc)[ vdesc->size() - 1 ] = TYPE; +} + +void FILLARRAYDATA(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + unsigned int value = ((*v)[2] * 2) + b->get_current_idx() - 6; + + // printf("MIN_DATA = %d %d %d %d %d\n", b->get_end(), b->get_current_idx(), *min_data, (*v)[3], value); + if (*min_data > value) { + *min_data = value; + } + + d->push_back( 0 ); + d->push_back( value ); + + (*vdesc)[2] = INTEGER_BRANCH; +} + +void SPARSESWITCH(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + // printf("SPARSESWITCH\n"); fflush(stdout); + + unsigned int value = ((*v)[2] * 2) + b->get_current_idx() - 6; + + if (*min_data > value) { + *min_data = value; + } + + d->push_back( 1 ); + d->push_back( value ); + + (*vdesc)[2] = INTEGER_BRANCH; +} + +void PACKEDSWITCH(Buff *b, vector *v, vector *vdesc, vector *d, unsigned int *min_data) { + // printf("PACKEDSWITCH\n"); fflush(stdout); + + unsigned int value = ((*v)[2] * 2) + b->get_current_idx() - 6; + + //printf("MIN_DATA = %d %d %d %d %d\n", b->get_end(), b->get_current_idx(), *min_data, (*v)[2], value); + if (*min_data > value) { + *min_data = value; + } + + d->push_back( 2 ); + d->push_back( value ); + + (*vdesc)[2] = INTEGER_BRANCH; +} + + +DBC::DBC(unsigned char value, const char *name, vector *v, vector *vdesc, size_t length) { + op_value = value; + op_name = name; + voperands = v; + vdescoperands = vdesc; + op_length = length; + vstrings = NULL; +} + +DBC::~DBC() { +#ifdef DEBUG_DESTRUCTOR + cout << "~DBC\n"; +#endif + + this->voperands->clear(); + this->vdescoperands->clear(); + + delete this->voperands; + delete this->vdescoperands; + + if (this->vstrings != NULL) { + this->vstrings->clear(); + delete this->vstrings; + } +} + +int DBC::get_opvalue() { + return op_value; +} + +const char *DBC::get_opname() { + return op_name; +} + +size_t DBC::get_length() { + return op_length; +} + +FillArrayData::FillArrayData(Buff *b, unsigned int off) { + memcpy( &fadt, b->readat( off, sizeof(fillarraydata_t) ), sizeof(fillarraydata_t) ); + data_size = fadt.size * fadt.element_width; + data = (char *)malloc( data_size ); + memcpy(data, b->readat( off + sizeof(fillarraydata_t), data_size ), data_size); +} + +FillArrayData::~FillArrayData() { + if (this->data != NULL) + free(data); +} + +const char *FillArrayData::get_opname() { + return "FILL-ARRAY-DATA"; +} + +size_t FillArrayData::get_length() { + return ((fadt.size * fadt.element_width + 1) / 2 + 4) * 2; +} + +size_t FillArrayData::get_type() { + return 0; +} + +SparseSwitch::SparseSwitch(Buff *b, unsigned int off) { + memcpy( &sst, b->readat( off, sizeof(sparseswitch_t) ), sizeof(sparseswitch_t) ); + + int idx = off + sizeof(sparseswitch_t); + for(int ii=0; ii < sst.size * 4; ii+=4, idx+=4) { + int si32 = *( reinterpret_cast( const_cast(b->readat( idx, 4 ))) ); + keys.push_back( si32 ); + } + + for(int ii=0; ii < sst.size * 4; ii+=4, idx+=4) { + int si32 = *( reinterpret_cast( const_cast(b->readat( idx, 4 ))) ); + targets.push_back( si32 ); + } +} + +SparseSwitch::~SparseSwitch() { + keys.clear(); + targets.clear(); +} + +const char *SparseSwitch::get_opname() { + return "SPARSE-SWITCH"; +} + +size_t SparseSwitch::get_length() { + return sizeof(sparseswitch_t) + (sst.size * 4) * 2; +} + +size_t SparseSwitch::get_type() { + return 1; +} + +PackedSwitch::PackedSwitch(Buff *b, unsigned int off) { + memcpy( &pst, b->readat( off, sizeof(packedswitch_t) ), sizeof(packedswitch_t) ); + + int idx = off + sizeof(packedswitch_t) ; + for(int ii=0; ii < pst.size; ii+=1) { + int si32 = *( reinterpret_cast( const_cast(b->readat( idx, 4 ))) ); + targets.push_back( si32 ); + + idx += 4; + } +} + +PackedSwitch::~PackedSwitch() { + targets.clear(); +} + +const char *PackedSwitch::get_opname() { + return "PACKED-SWITCH"; +} + +size_t PackedSwitch::get_length() { + return sizeof(packedswitch_t) + pst.size * 4; +} + +size_t PackedSwitch::get_type() { + return 2; +} + +DCode::DCode() { + +} + +DCode::~DCode() { +#ifdef DEBUG_DESTRUCTOR + cout << "~DCode\n"; +#endif + + for(int ii=0; ii < this->bytecodes.size(); ii++) { + delete this->bytecodes[ ii ]; + } + this->bytecodes.clear(); + + for(int ii=0; ii < this->bytecodes_spe.size(); ii++) { + delete this->bytecodes_spe[ ii ]; + } + this->bytecodes_spe.clear(); +} + +DCode::DCode(vector*, vector*)> *parsebytecodes, + vector *, vector *, vector *, unsigned int *)> *postbytecodes, + vector *bytecodes_names, + Buff *b) { + unsigned char op_value; + unsigned int size; + + vector *datas; + unsigned int min_data = b->get_end(); + + datas = new vector; + + while (b->empty() == false) { + op_value = *( reinterpret_cast( const_cast(b->read_false(1))) ); + + vector *v = new vector; + vector *vdesc = new vector; + size = (*parsebytecodes)[ op_value ]( b, v, vdesc ); + + if ((*postbytecodes)[ op_value ] != NULL) + (*postbytecodes)[ op_value ]( b, v, vdesc, datas, &min_data ); + + bytecodes.push_back( new DBC(op_value, (*bytecodes_names)[ op_value ], v, vdesc, size) ); + + /*printf("OP_VALUE %x ---> ", op_value); fflush(stdout); + for(int ii=0; ii < v->size(); ii++) { + printf("%d ", (*v)[ii]); + } + printf(" : "); + for(int ii=0; ii < vdesc->size(); ii++) { + printf("%d ", (*vdesc)[ii]); + } + printf("\n"); + */ + + if (b->get_current_idx() >= min_data) { + break; + } + } + + if (b->empty() == false) { + for(int ii=0; ii < datas->size(); ii+=2) { + //printf("SPECIFIC %d %d\n", (*datas)[ii], (*datas)[ii+1]); + + if ((*datas)[ii] == 0) { + bytecodes_spe.push_back( new FillArrayData( b, (*datas)[ii+1] ) ); + } else if ((*datas)[ii] == 1) { + bytecodes_spe.push_back( new SparseSwitch( b, (*datas)[ii+1] ) ); + } else if ((*datas)[ii] == 2) { + bytecodes_spe.push_back( new PackedSwitch( b, (*datas)[ii+1] ) ); + } + } + //printf("\n"); + //cout << "la" << b->get_end() << " " << b->get_current_idx() << "\n"; + } + + datas->clear(); + delete datas; +} + +int DCode::size() { + return bytecodes.size() + bytecodes_spe.size(); +} + +DBC *DCode::get_bytecode_at(int i) { + return bytecodes[ i ]; +} + +DalvikBytecode::DalvikBytecode() { + for (int ii=0; ii < 0xff; ii++) + bytecodes_names.push_back( NULL ); + + for (int ii=0; ii < 0xff; ii++) + bytecodes.push_back( NULL ); + + for (int ii=0; ii < 0xff; ii++) + postbytecodes.push_back( NULL ); + + bytecodes_names[ 0x0 ] = "nop"; + bytecodes_names[ 0x0 ] = "nop"; + bytecodes_names[ 0x1 ] = "move"; + bytecodes_names[ 0x2 ] = "move/from16"; + bytecodes_names[ 0x3 ] = "move/16"; + bytecodes_names[ 0x4 ] = "move-wide"; + bytecodes_names[ 0x5 ] = "move-wide/from16"; + bytecodes_names[ 0x6 ] = "move-wide/16"; + bytecodes_names[ 0x7 ] = "move-object"; + bytecodes_names[ 0x8 ] = "move-object/from16"; + bytecodes_names[ 0x9 ] = "move-object/16"; + bytecodes_names[ 0xa ] = "move-result"; + bytecodes_names[ 0xb ] = "move-result-wide"; + bytecodes_names[ 0xc ] = "move-result-object"; + bytecodes_names[ 0xd ] = "move-exception"; + bytecodes_names[ 0xe ] = "return-void"; + bytecodes_names[ 0xf ] = "return"; + bytecodes_names[ 0x10 ] = "return-wide"; + bytecodes_names[ 0x11 ] = "return-object"; + bytecodes_names[ 0x12 ] = "const/4"; + bytecodes_names[ 0x13 ] = "const/16"; + bytecodes_names[ 0x14 ] = "const"; + bytecodes_names[ 0x15 ] = "const/high16"; + bytecodes_names[ 0x16 ] = "const-wide/16"; + bytecodes_names[ 0x17 ] = "const-wide/32"; + bytecodes_names[ 0x18 ] = "const-wide"; + bytecodes_names[ 0x19 ] = "const-wide/high16"; + bytecodes_names[ 0x1a ] = "const-string"; + bytecodes_names[ 0x1b ] = "const-string/jumbo"; + bytecodes_names[ 0x1c ] = "const-class"; + bytecodes_names[ 0x1d ] = "monitor-enter"; + bytecodes_names[ 0x1e ] = "monitor-exit"; + bytecodes_names[ 0x1f ] = "check-cast"; + bytecodes_names[ 0x20 ] = "instance-of"; + bytecodes_names[ 0x21 ] = "array-length"; + bytecodes_names[ 0x22 ] = "new-instance"; + bytecodes_names[ 0x23 ] = "new-array"; + bytecodes_names[ 0x24 ] = "filled-new-array"; + bytecodes_names[ 0x25 ] = "filled-new-array/range"; + bytecodes_names[ 0x26 ] = "fill-array-data"; + bytecodes_names[ 0x27 ] = "throw"; + bytecodes_names[ 0x28 ] = "goto"; + bytecodes_names[ 0x29 ] = "goto/16"; + bytecodes_names[ 0x2a ] = "goto/32"; + bytecodes_names[ 0x2b ] = "packed-switch"; + bytecodes_names[ 0x2c ] = "sparse-switch"; + bytecodes_names[ 0x2d ] = "cmpl-float"; + bytecodes_names[ 0x2e ] = "cmpg-float"; + bytecodes_names[ 0x2f ] = "cmpl-double"; + bytecodes_names[ 0x30 ] = "cmpg-double"; + bytecodes_names[ 0x31 ] = "cmp-long"; + bytecodes_names[ 0x32 ] = "if-eq"; + bytecodes_names[ 0x33 ] = "if-ne"; + bytecodes_names[ 0x34 ] = "if-lt"; + bytecodes_names[ 0x35 ] = "if-ge"; + bytecodes_names[ 0x36 ] = "if-gt"; + bytecodes_names[ 0x37 ] = "if-le"; + bytecodes_names[ 0x38 ] = "if-eqz"; + bytecodes_names[ 0x39 ] = "if-nez"; + bytecodes_names[ 0x3a ] = "if-ltz"; + bytecodes_names[ 0x3b ] = "if-gez"; + bytecodes_names[ 0x3c ] = "if-gtz"; + bytecodes_names[ 0x3d ] = "if-lez"; + bytecodes_names[ 0x3e ] = "nop"; + bytecodes_names[ 0x3f ] = "nop"; + bytecodes_names[ 0x40 ] = "nop"; + bytecodes_names[ 0x41 ] = "nop"; + bytecodes_names[ 0x42 ] = "nop"; + bytecodes_names[ 0x43 ] = "nop"; + bytecodes_names[ 0x44 ] = "aget"; + bytecodes_names[ 0x45 ] = "aget-wide"; + bytecodes_names[ 0x46 ] = "aget-object"; + bytecodes_names[ 0x47 ] = "aget-boolean"; + bytecodes_names[ 0x48 ] = "aget-byte"; + bytecodes_names[ 0x49 ] = "aget-char"; + bytecodes_names[ 0x4a ] = "aget-short"; + bytecodes_names[ 0x4b ] = "aput"; + bytecodes_names[ 0x4c ] = "aput-wide"; + bytecodes_names[ 0x4d ] = "aput-object"; + bytecodes_names[ 0x4e ] = "aput-boolean"; + bytecodes_names[ 0x4f ] = "aput-byte"; + bytecodes_names[ 0x50 ] = "aput-char"; + bytecodes_names[ 0x51 ] = "aput-short"; + bytecodes_names[ 0x52 ] = "iget"; + bytecodes_names[ 0x53 ] = "iget-wide"; + bytecodes_names[ 0x54 ] = "iget-object"; + bytecodes_names[ 0x55 ] = "iget-boolean"; + bytecodes_names[ 0x56 ] = "iget-byte"; + bytecodes_names[ 0x57 ] = "iget-char"; + bytecodes_names[ 0x58 ] = "iget-short"; + bytecodes_names[ 0x59 ] = "iput"; + bytecodes_names[ 0x5a ] = "iput-wide"; + bytecodes_names[ 0x5b ] = "iput-object"; + bytecodes_names[ 0x5c ] = "iput-boolean"; + bytecodes_names[ 0x5d ] = "iput-byte"; + bytecodes_names[ 0x5e ] = "iput-char"; + bytecodes_names[ 0x5f ] = "iput-short"; + bytecodes_names[ 0x60 ] = "sget"; + bytecodes_names[ 0x61 ] = "sget-wide"; + bytecodes_names[ 0x62 ] = "sget-object"; + bytecodes_names[ 0x63 ] = "sget-boolean"; + bytecodes_names[ 0x64 ] = "sget-byte"; + bytecodes_names[ 0x65 ] = "sget-char"; + bytecodes_names[ 0x66 ] = "sget-short"; + bytecodes_names[ 0x67 ] = "sput"; + bytecodes_names[ 0x68 ] = "sput-wide"; + bytecodes_names[ 0x69 ] = "sput-object"; + bytecodes_names[ 0x6a ] = "sput-boolean"; + bytecodes_names[ 0x6b ] = "sput-byte"; + bytecodes_names[ 0x6c ] = "sput-char"; + bytecodes_names[ 0x6d ] = "sput-short"; + bytecodes_names[ 0x6e ] = "invoke-virtual"; + bytecodes_names[ 0x6f ] = "invoke-super"; + bytecodes_names[ 0x70 ] = "invoke-direct"; + bytecodes_names[ 0x71 ] = "invoke-static"; + bytecodes_names[ 0x72 ] = "invoke-interface"; + bytecodes_names[ 0x73 ] = "nop"; + bytecodes_names[ 0x74 ] = "invoke-virtual/range"; + bytecodes_names[ 0x75 ] = "invoke-super/range"; + bytecodes_names[ 0x76 ] = "invoke-direct/range"; + bytecodes_names[ 0x77 ] = "invoke-static/range"; + bytecodes_names[ 0x78 ] = "invoke-interface/range"; + bytecodes_names[ 0x79 ] = "nop"; + bytecodes_names[ 0x7a ] = "nop"; + bytecodes_names[ 0x7b ] = "neg-int"; + bytecodes_names[ 0x7c ] = "not-int"; + bytecodes_names[ 0x7d ] = "neg-long"; + bytecodes_names[ 0x7e ] = "not-long"; + bytecodes_names[ 0x7f ] = "neg-float"; + bytecodes_names[ 0x80 ] = "neg-double"; + bytecodes_names[ 0x81 ] = "int-to-long"; + bytecodes_names[ 0x82 ] = "int-to-float"; + bytecodes_names[ 0x83 ] = "int-to-double"; + bytecodes_names[ 0x84 ] = "long-to-int"; + bytecodes_names[ 0x85 ] = "long-to-float"; + bytecodes_names[ 0x86 ] = "long-to-double"; + bytecodes_names[ 0x87 ] = "float-to-int"; + bytecodes_names[ 0x88 ] = "float-to-long"; + bytecodes_names[ 0x89 ] = "float-to-double"; + bytecodes_names[ 0x8a ] = "double-to-int"; + bytecodes_names[ 0x8b ] = "double-to-long"; + bytecodes_names[ 0x8c ] = "double-to-float"; + bytecodes_names[ 0x8d ] = "int-to-byte"; + bytecodes_names[ 0x8e ] = "int-to-char"; + bytecodes_names[ 0x8f ] = "int-to-short"; + bytecodes_names[ 0x90 ] = "add-int"; + bytecodes_names[ 0x91 ] = "sub-int"; + bytecodes_names[ 0x92 ] = "mul-int"; + bytecodes_names[ 0x93 ] = "div-int"; + bytecodes_names[ 0x94 ] = "rem-int"; + bytecodes_names[ 0x95 ] = "and-int"; + bytecodes_names[ 0x96 ] = "or-int"; + bytecodes_names[ 0x97 ] = "xor-int"; + bytecodes_names[ 0x98 ] = "shl-int"; + bytecodes_names[ 0x99 ] = "shr-int"; + bytecodes_names[ 0x9a ] = "ushr-int"; + bytecodes_names[ 0x9b ] = "add-long"; + bytecodes_names[ 0x9c ] = "sub-long"; + bytecodes_names[ 0x9d ] = "mul-long"; + bytecodes_names[ 0x9e ] = "div-long"; + bytecodes_names[ 0x9f ] = "rem-long"; + bytecodes_names[ 0xa0 ] = "and-long"; + bytecodes_names[ 0xa1 ] = "or-long"; + bytecodes_names[ 0xa2 ] = "xor-long"; + bytecodes_names[ 0xa3 ] = "shl-long"; + bytecodes_names[ 0xa4 ] = "shr-long"; + bytecodes_names[ 0xa5 ] = "ushr-long"; + bytecodes_names[ 0xa6 ] = "add-float"; + bytecodes_names[ 0xa7 ] = "sub-float"; + bytecodes_names[ 0xa8 ] = "mul-float"; + bytecodes_names[ 0xa9 ] = "div-float"; + bytecodes_names[ 0xaa ] = "rem-float"; + bytecodes_names[ 0xab ] = "add-double"; + bytecodes_names[ 0xac ] = "sub-double"; + bytecodes_names[ 0xad ] = "mul-double"; + bytecodes_names[ 0xae ] = "div-double"; + bytecodes_names[ 0xaf ] = "rem-double"; + bytecodes_names[ 0xb0 ] = "add-int/2addr"; + bytecodes_names[ 0xb1 ] = "sub-int/2addr"; + bytecodes_names[ 0xb2 ] = "mul-int/2addr"; + bytecodes_names[ 0xb3 ] = "div-int/2addr"; + bytecodes_names[ 0xb4 ] = "rem-int/2addr"; + bytecodes_names[ 0xb5 ] = "and-int/2addr"; + bytecodes_names[ 0xb6 ] = "or-int/2addr"; + bytecodes_names[ 0xb7 ] = "xor-int/2addr"; + bytecodes_names[ 0xb8 ] = "shl-int/2addr"; + bytecodes_names[ 0xb9 ] = "shr-int/2addr"; + bytecodes_names[ 0xba ] = "ushr-int/2addr"; + bytecodes_names[ 0xbb ] = "add-long/2addr"; + bytecodes_names[ 0xbc ] = "sub-long/2addr"; + bytecodes_names[ 0xbd ] = "mul-long/2addr"; + bytecodes_names[ 0xbe ] = "div-long/2addr"; + bytecodes_names[ 0xbf ] = "rem-long/2addr"; + bytecodes_names[ 0xc0 ] = "and-long/2addr"; + bytecodes_names[ 0xc1 ] = "or-long/2addr"; + bytecodes_names[ 0xc2 ] = "xor-long/2addr"; + bytecodes_names[ 0xc3 ] = "shl-long/2addr"; + bytecodes_names[ 0xc4 ] = "shr-long/2addr"; + bytecodes_names[ 0xc5 ] = "ushr-long/2addr"; + bytecodes_names[ 0xc6 ] = "add-float/2addr"; + bytecodes_names[ 0xc7 ] = "sub-float/2addr"; + bytecodes_names[ 0xc8 ] = "mul-float/2addr"; + bytecodes_names[ 0xc9 ] = "div-float/2addr"; + bytecodes_names[ 0xca ] = "rem-float/2addr"; + bytecodes_names[ 0xcb ] = "add-double/2addr"; + bytecodes_names[ 0xcc ] = "sub-double/2addr"; + bytecodes_names[ 0xcd ] = "mul-double/2addr"; + bytecodes_names[ 0xce ] = "div-double/2addr"; + bytecodes_names[ 0xcf ] = "rem-double/2addr"; + bytecodes_names[ 0xd0 ] = "add-int/lit16"; + bytecodes_names[ 0xd1 ] = "rsub-int"; + bytecodes_names[ 0xd2 ] = "mul-int/lit16"; + bytecodes_names[ 0xd3 ] = "div-int/lit16"; + bytecodes_names[ 0xd4 ] = "rem-int/lit16"; + bytecodes_names[ 0xd5 ] = "and-int/lit16"; + bytecodes_names[ 0xd6 ] = "or-int/lit16"; + bytecodes_names[ 0xd7 ] = "xor-int/lit16"; + bytecodes_names[ 0xd8 ] = "add-int/lit8"; + bytecodes_names[ 0xd9 ] = "rsub-int/lit8"; + bytecodes_names[ 0xda ] = "mul-int/lit8"; + bytecodes_names[ 0xdb ] = "div-int/lit8"; + bytecodes_names[ 0xdc ] = "rem-int/lit8"; + bytecodes_names[ 0xdd ] = "and-int/lit8"; + bytecodes_names[ 0xde ] = "or-int/lit8"; + bytecodes_names[ 0xdf ] = "xor-int/lit8"; + bytecodes_names[ 0xe0 ] = "shl-int/lit8"; + bytecodes_names[ 0xe1 ] = "shr-int/lit8"; + bytecodes_names[ 0xe2 ] = "ushr-int/lit8"; + bytecodes_names[ 0xe3 ] = "nop"; + bytecodes_names[ 0xe4 ] = "nop"; + bytecodes_names[ 0xe5 ] = "nop"; + bytecodes_names[ 0xe6 ] = "nop"; + bytecodes_names[ 0xe7 ] = "nop"; + bytecodes_names[ 0xe8 ] = "nop"; + bytecodes_names[ 0xe9 ] = "nop"; + bytecodes_names[ 0xea ] = "nop"; + bytecodes_names[ 0xeb ] = "nop"; + bytecodes_names[ 0xec ] = "nop"; + bytecodes_names[ 0xed ] = "^throw-verification-error"; + bytecodes_names[ 0xee ] = "nop"; + bytecodes_names[ 0xef ] = "nop"; + bytecodes_names[ 0xf0 ] = "nop"; + bytecodes_names[ 0xf1 ] = "nop"; + bytecodes_names[ 0xf2 ] = "nop"; + bytecodes_names[ 0xf3 ] = "nop"; + bytecodes_names[ 0xf4 ] = "nop"; + bytecodes_names[ 0xf5 ] = "nop"; + bytecodes_names[ 0xf6 ] = "nop"; + bytecodes_names[ 0xf7 ] = "nop"; + bytecodes_names[ 0xf8 ] = "nop"; + bytecodes_names[ 0xf9 ] = "nop"; + bytecodes_names[ 0xfa ] = "nop"; + bytecodes_names[ 0xfb ] = "nop"; + bytecodes_names[ 0xfc ] = "nop"; + bytecodes_names[ 0xfd ] = "nop"; + bytecodes_names[ 0xfe ] = "nop"; + bytecodes_names[ 0xff ] = "nop"; + + bytecodes[ 0x0 ] = &OP_00; + + bytecodes[ 0x1 ] = &B_A_OP; + + bytecodes[ 0x2 ] = &AA_OP_BBBB; + + bytecodes[ 0x3 ] = &_00_OP_AAAA_BBBB; + + bytecodes[ 0x4 ] = &B_A_OP; + bytecodes[ 0x5 ] = &AA_OP_BBBB; + + bytecodes[ 0x6 ] = &_00_OP_AAAA_BBBB; + + bytecodes[ 0x7 ] = &B_A_OP; + bytecodes[ 0x8 ] = &AA_OP_BBBB; + + bytecodes[ 0x9 ] = &_00_OP_AAAA_BBBB; + + bytecodes[ 0xa ] = &AA_OP; + bytecodes[ 0xb ] = &AA_OP; + bytecodes[ 0xc ] = &AA_OP; + bytecodes[ 0xd ] = &AA_OP; + + bytecodes[ 0xe ] = &OP_00; + + bytecodes[ 0xf ] = &AA_OP; + + bytecodes[ 0x10 ] = &AA_OP; + bytecodes[ 0x11 ] = &AA_OP; + bytecodes[ 0x12 ] = &SB_A_OP; + + bytecodes[ 0x13 ] = &AA_OP_SBBBB; + bytecodes[ 0x14 ] = &AA_OP_SBBBB_SBBBB; + bytecodes[ 0x15 ] = &AA_OP_SBBBB; + bytecodes[ 0x16 ] = &AA_OP_SBBBB; + + bytecodes[ 0x17 ] = &AA_OP_SBBBB_SBBBB; + bytecodes[ 0x18 ] = &AA_OP_SBBBB_SBBBB_SBBBB_SBBBB; + + bytecodes[ 0x19 ] = &AA_OP_SBBBB; + + bytecodes[ 0x1a ] = &AA_OP_BBBB_2_STRING; + bytecodes[ 0x1b ] = &AA_OP_BBBBBBBB_2_STRING; + bytecodes[ 0x1c ] = &AA_OP_BBBB_2_TYPE; + + bytecodes[ 0x1d ] = &AA_OP; + bytecodes[ 0x1e ] = &AA_OP; + + bytecodes[ 0x1f ] = &AA_OP_BBBB_2_TYPE; + + bytecodes[ 0x20 ] = &B_A_OP_CCCC_3_TYPE; + bytecodes[ 0x21 ] = &B_A_OP; + bytecodes[ 0x22 ] = &AA_OP_BBBB_2_TYPE; + + bytecodes[ 0x23 ] = &B_A_OP_CCCC_3_TYPE; + + bytecodes[ 0x24 ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x24 ] = &FILLEDNEWARRAY; + bytecodes[ 0x25 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x25 ] = &FILLEDNEWARRAYRANGE; + + bytecodes[ 0x26 ] = &AA_OP_SBBBBBBBB; postbytecodes[ 0x26 ] = &FILLARRAYDATA; + + bytecodes[ 0x27 ] = &B_A_OP; + + bytecodes[ 0x28 ] = &OP_SAA_BRANCH; + bytecodes[ 0x29 ] = &_00_OP_SAAAA_BRANCH; + bytecodes[ 0x2a ] = &_00_OP_SAAAAAAAA_BRANCH; + + bytecodes[ 0x2b ] = &AA_OP_SBBBBBBBB; postbytecodes[ 0x2b ] = &PACKEDSWITCH; + bytecodes[ 0x2c ] = &AA_OP_SBBBBBBBB; postbytecodes[ 0x2c ] = &SPARSESWITCH; + + bytecodes[ 0x2d ] = &AA_OP_CC_BB; + bytecodes[ 0x2e ] = &AA_OP_CC_BB; + bytecodes[ 0x2f ] = &AA_OP_CC_BB; + bytecodes[ 0x30 ] = &AA_OP_CC_BB; + bytecodes[ 0x31 ] = &AA_OP_CC_BB; + + bytecodes[ 0x32 ] = &B_A_OP_SCCCC_BRANCH; + bytecodes[ 0x33 ] = &B_A_OP_SCCCC_BRANCH; + bytecodes[ 0x34 ] = &B_A_OP_SCCCC_BRANCH; + bytecodes[ 0x35 ] = &B_A_OP_SCCCC_BRANCH; + bytecodes[ 0x36 ] = &B_A_OP_SCCCC_BRANCH; + bytecodes[ 0x37 ] = &B_A_OP_SCCCC_BRANCH; + + bytecodes[ 0x38 ] = &AA_OP_SBBBB_BRANCH; + bytecodes[ 0x39 ] = &AA_OP_SBBBB_BRANCH; + bytecodes[ 0x3a ] = &AA_OP_SBBBB_BRANCH; + bytecodes[ 0x3b ] = &AA_OP_SBBBB_BRANCH; + bytecodes[ 0x3c ] = &AA_OP_SBBBB_BRANCH; + bytecodes[ 0x3d ] = &AA_OP_SBBBB_BRANCH; + + bytecodes[ 0x3e ] = &OP_00; + bytecodes[ 0x3f ] = &OP_00; + bytecodes[ 0x40 ] = &OP_00; + bytecodes[ 0x41 ] = &OP_00; + bytecodes[ 0x42 ] = &OP_00; + bytecodes[ 0x43 ] = &OP_00; + + bytecodes[ 0x44 ] = &AA_OP_CC_BB; + bytecodes[ 0x45 ] = &AA_OP_CC_BB; + bytecodes[ 0x46 ] = &AA_OP_CC_BB; + bytecodes[ 0x47 ] = &AA_OP_CC_BB; + bytecodes[ 0x48 ] = &AA_OP_CC_BB; + bytecodes[ 0x49 ] = &AA_OP_CC_BB; + bytecodes[ 0x4a ] = &AA_OP_CC_BB; + bytecodes[ 0x4b ] = &AA_OP_CC_BB; + bytecodes[ 0x4c ] = &AA_OP_CC_BB; + bytecodes[ 0x4d ] = &AA_OP_CC_BB; + bytecodes[ 0x4e ] = &AA_OP_CC_BB; + bytecodes[ 0x4f ] = &AA_OP_CC_BB; + bytecodes[ 0x50 ] = &AA_OP_CC_BB; + bytecodes[ 0x51 ] = &AA_OP_CC_BB; + + bytecodes[ 0x52 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x53 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x54 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x55 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x56 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x57 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x58 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x59 ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5a ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5b ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5c ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5d ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5e ] = &B_A_OP_CCCC_3_FIELD; + bytecodes[ 0x5f ] = &B_A_OP_CCCC_3_FIELD; + + bytecodes[ 0x60 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x61 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x62 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x63 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x64 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x65 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x66 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x67 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x68 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x69 ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x6a ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x6b ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x6c ] = &AA_OP_BBBB_2_FIELD; + bytecodes[ 0x6d ] = &AA_OP_BBBB_2_FIELD; + + bytecodes[ 0x6e ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x6e ] = &INVOKE; + bytecodes[ 0x6f ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x6f ] = &INVOKE; + bytecodes[ 0x70 ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x70 ] = &INVOKE; + bytecodes[ 0x71 ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x71 ] = &INVOKE; + bytecodes[ 0x72 ] = &B_A_OP_CCCC_G_F_E_D; postbytecodes[ 0x72 ] = &INVOKE; + + bytecodes[ 0x73 ] = &OP_00; + + bytecodes[ 0x74 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x74 ] = &INVOKERANGE; + bytecodes[ 0x75 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x75 ] = &INVOKERANGE; + bytecodes[ 0x76 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x76 ] = &INVOKERANGE; + bytecodes[ 0x77 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x77 ] = &INVOKERANGE; + bytecodes[ 0x78 ] = &AA_OP_BBBB_CCCC; postbytecodes[ 0x78 ] = &INVOKERANGE; + + bytecodes[ 0x79 ] = &OP_00; + bytecodes[ 0x7a ] = &OP_00; + + bytecodes[ 0x7b ] = &B_A_OP; + bytecodes[ 0x7c ] = &B_A_OP; + bytecodes[ 0x7d ] = &B_A_OP; + bytecodes[ 0x7e ] = &B_A_OP; + bytecodes[ 0x7f ] = &B_A_OP; + bytecodes[ 0x80 ] = &B_A_OP; + bytecodes[ 0x81 ] = &B_A_OP; + bytecodes[ 0x82 ] = &B_A_OP; + bytecodes[ 0x83 ] = &B_A_OP; + bytecodes[ 0x84 ] = &B_A_OP; + bytecodes[ 0x85 ] = &B_A_OP; + bytecodes[ 0x86 ] = &B_A_OP; + bytecodes[ 0x87 ] = &B_A_OP; + bytecodes[ 0x88 ] = &B_A_OP; + bytecodes[ 0x89 ] = &B_A_OP; + bytecodes[ 0x8a ] = &B_A_OP; + bytecodes[ 0x8b ] = &B_A_OP; + bytecodes[ 0x8c ] = &B_A_OP; + bytecodes[ 0x8d ] = &B_A_OP; + bytecodes[ 0x8e ] = &B_A_OP; + bytecodes[ 0x8f ] = &B_A_OP; + + bytecodes[ 0x90 ] = &AA_OP_CC_BB; + bytecodes[ 0x91 ] = &AA_OP_CC_BB; + bytecodes[ 0x92 ] = &AA_OP_CC_BB; + bytecodes[ 0x93 ] = &AA_OP_CC_BB; + bytecodes[ 0x94 ] = &AA_OP_CC_BB; + bytecodes[ 0x95 ] = &AA_OP_CC_BB; + bytecodes[ 0x96 ] = &AA_OP_CC_BB; + bytecodes[ 0x97 ] = &AA_OP_CC_BB; + bytecodes[ 0x98 ] = &AA_OP_CC_BB; + bytecodes[ 0x99 ] = &AA_OP_CC_BB; + bytecodes[ 0x9a ] = &AA_OP_CC_BB; + bytecodes[ 0x9b ] = &AA_OP_CC_BB; + bytecodes[ 0x9c ] = &AA_OP_CC_BB; + bytecodes[ 0x9d ] = &AA_OP_CC_BB; + bytecodes[ 0x9e ] = &AA_OP_CC_BB; + bytecodes[ 0x9f ] = &AA_OP_CC_BB; + bytecodes[ 0xa0 ] = &AA_OP_CC_BB; + bytecodes[ 0xa1 ] = &AA_OP_CC_BB; + bytecodes[ 0xa2 ] = &AA_OP_CC_BB; + bytecodes[ 0xa3 ] = &AA_OP_CC_BB; + bytecodes[ 0xa4 ] = &AA_OP_CC_BB; + bytecodes[ 0xa5 ] = &AA_OP_CC_BB; + bytecodes[ 0xa6 ] = &AA_OP_CC_BB; + bytecodes[ 0xa7 ] = &AA_OP_CC_BB; + bytecodes[ 0xa8 ] = &AA_OP_CC_BB; + bytecodes[ 0xa9 ] = &AA_OP_CC_BB; + bytecodes[ 0xaa ] = &AA_OP_CC_BB; + bytecodes[ 0xab ] = &AA_OP_CC_BB; + bytecodes[ 0xac ] = &AA_OP_CC_BB; + bytecodes[ 0xad ] = &AA_OP_CC_BB; + bytecodes[ 0xae ] = &AA_OP_CC_BB; + bytecodes[ 0xaf ] = &AA_OP_CC_BB; + + bytecodes[ 0xb0 ] = &B_A_OP; + bytecodes[ 0xb1 ] = &B_A_OP; + bytecodes[ 0xb2 ] = &B_A_OP; + bytecodes[ 0xb3 ] = &B_A_OP; + bytecodes[ 0xb4 ] = &B_A_OP; + bytecodes[ 0xb5 ] = &B_A_OP; + bytecodes[ 0xb6 ] = &B_A_OP; + bytecodes[ 0xb7 ] = &B_A_OP; + bytecodes[ 0xb8 ] = &B_A_OP; + bytecodes[ 0xb9 ] = &B_A_OP; + bytecodes[ 0xba ] = &B_A_OP; + bytecodes[ 0xbb ] = &B_A_OP; + bytecodes[ 0xbc ] = &B_A_OP; + bytecodes[ 0xbd ] = &B_A_OP; + bytecodes[ 0xbe ] = &B_A_OP; + bytecodes[ 0xbf ] = &B_A_OP; + bytecodes[ 0xc0 ] = &B_A_OP; + bytecodes[ 0xc1 ] = &B_A_OP; + bytecodes[ 0xc2 ] = &B_A_OP; + bytecodes[ 0xc3 ] = &B_A_OP; + bytecodes[ 0xc4 ] = &B_A_OP; + bytecodes[ 0xc5 ] = &B_A_OP; + bytecodes[ 0xc6 ] = &B_A_OP; + bytecodes[ 0xc7 ] = &B_A_OP; + bytecodes[ 0xc8 ] = &B_A_OP; + bytecodes[ 0xc9 ] = &B_A_OP; + bytecodes[ 0xca ] = &B_A_OP; + bytecodes[ 0xcb ] = &B_A_OP; + bytecodes[ 0xcc ] = &B_A_OP; + bytecodes[ 0xcd ] = &B_A_OP; + bytecodes[ 0xce ] = &B_A_OP; + bytecodes[ 0xcf ] = &B_A_OP; + + bytecodes[ 0xd0 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd1 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd2 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd3 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd4 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd5 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd6 ] = &B_A_OP_SCCCC; + bytecodes[ 0xd7 ] = &B_A_OP_SCCCC; + + bytecodes[ 0xd8 ] = &AA_OP_BB_SCC; + bytecodes[ 0xd9 ] = &AA_OP_BB_SCC; + bytecodes[ 0xda ] = &AA_OP_BB_SCC; + bytecodes[ 0xdb ] = &AA_OP_BB_SCC; + bytecodes[ 0xdc ] = &AA_OP_BB_SCC; + bytecodes[ 0xdd ] = &AA_OP_BB_SCC; + bytecodes[ 0xde ] = &AA_OP_BB_SCC; + bytecodes[ 0xdf ] = &AA_OP_BB_SCC; + bytecodes[ 0xe0 ] = &AA_OP_BB_SCC; + bytecodes[ 0xe1 ] = &AA_OP_BB_SCC; + bytecodes[ 0xe2 ] = &AA_OP_BB_SCC; + + bytecodes[ 0xe3 ] = &OP_00; + bytecodes[ 0xe4 ] = &OP_00; + bytecodes[ 0xe5 ] = &OP_00; + bytecodes[ 0xe6 ] = &OP_00; + bytecodes[ 0xe7 ] = &OP_00; + bytecodes[ 0xe8 ] = &OP_00; + bytecodes[ 0xe9 ] = &OP_00; + bytecodes[ 0xea ] = &OP_00; + bytecodes[ 0xeb ] = &OP_00; + bytecodes[ 0xec ] = &OP_00; + + bytecodes[ 0xed ] = &DAA_OP_DBBBB; + + bytecodes[ 0xee ] = &OP_00; + bytecodes[ 0xef ] = &OP_00; + bytecodes[ 0xf0 ] = &OP_00; + bytecodes[ 0xf1 ] = &OP_00; + bytecodes[ 0xf2 ] = &OP_00; + bytecodes[ 0xf3 ] = &OP_00; + bytecodes[ 0xf4 ] = &OP_00; + bytecodes[ 0xf5 ] = &OP_00; + bytecodes[ 0xf6 ] = &OP_00; + bytecodes[ 0xf7 ] = &OP_00; + bytecodes[ 0xf8 ] = &OP_00; + bytecodes[ 0xf9 ] = &OP_00; + bytecodes[ 0xfa ] = &OP_00; + bytecodes[ 0xfb ] = &OP_00; + bytecodes[ 0xfc ] = &OP_00; + bytecodes[ 0xfd ] = &OP_00; + bytecodes[ 0xfe ] = &OP_00; + bytecodes[ 0xff ] = &OP_00; +} + +DCode *DalvikBytecode::new_code(const char *data, size_t data_len) { + Buff b = Buff( data, data_len ); + DCode *d = new DCode( &bytecodes, &postbytecodes, &bytecodes_names, &b ); + + return d; +} + +/* PYTHON BINDING */ +void DBC_dealloc(dvm_DBCObject* self) +{ +#ifdef DEBUG_DESTRUCTOR + cout << "DBC_dealloc\n"; +#endif + + delete self->d; + //Py_DECREF( self->operands ); + self->ob_type->tp_free((PyObject*)self); +} + +PyObject *DBC_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dvm_DBCObject *self; + + self = (dvm_DBCObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->d = NULL; + self->operands = NULL; + } + + return (PyObject *)self; +} + +int DBC_init(dvm_DBCObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +PyObject *DBC_get_opvalue(dvm_DBCObject *self, PyObject* args) +{ + return Py_BuildValue("i", self->d->get_opvalue()); +} + +PyObject *DBC_get_length(dvm_DBCObject *self, PyObject* args) +{ + return Py_BuildValue("i", self->d->get_length()); +} + +PyObject *DBC_get_name(dvm_DBCObject *self, PyObject* args) +{ + return PyString_FromString( self->d->get_opname() ); +} + +PyObject *DBC_get_operands(dvm_DBCObject *self, PyObject* args) +{ + if (self->operands != NULL) { + Py_INCREF( self->operands ); + return self->operands; + } + + self->operands = PyList_New( 0 ); + int present; + + for(int ii=1; ii < self->d->voperands->size(); ii++) { + PyObject *ioperands = PyList_New( 0 ); + present = -1; + + if ((*self->d->vdescoperands)[ii] == FIELD) { + PyList_Append( ioperands, PyString_FromString( "field@" ) ); present = 0; + } else if ((*self->d->vdescoperands)[ii] == METHOD) { + PyList_Append( ioperands, PyString_FromString( "meth@" ) ); present = 0; + } else if ((*self->d->vdescoperands)[ii] == TYPE) { + PyList_Append( ioperands, PyString_FromString( "type@" ) ); present = 0; + } else if ((*self->d->vdescoperands)[ii] == INTEGER) { + PyList_Append( ioperands, PyString_FromString( "#+" ) ); + } else if ((*self->d->vdescoperands)[ii] == STRING) { + PyList_Append( ioperands, PyString_FromString( "string@" ) ); present = 0; + } else if ((*self->d->vdescoperands)[ii] == INTEGER_BRANCH) { + PyList_Append( ioperands, PyString_FromString( "+" ) ); + } else { + PyList_Append( ioperands, PyString_FromString( "v" ) ); + } + + PyList_Append( ioperands, PyInt_FromLong( (*self->d->voperands)[ii] ) ); + + if (present==0 && self->d->vstrings != NULL) { + for(int jj=0; jj < self->d->vstrings->size(); jj++) { + PyList_Append( ioperands, PyString_FromString( (*self->d->vstrings)[jj].c_str() ) ); + } + + present = -1; + } + + Py_INCREF( ioperands ); + PyList_Append( self->operands, ioperands ); + } + + Py_INCREF( self->operands ); + return self->operands; +} + +PyObject *DBC_get_type_ins(dvm_DBCObject *self, PyObject* args) +{ + return Py_BuildValue("i", 0); +} + +void DBCSpe_dealloc(dvm_DBCSpeObject* self) +{ +#ifdef DEBUG_DESTRUCTOR + cout << "DBCSpe_dealloc\n"; +#endif + + delete self->d; + self->ob_type->tp_free((PyObject*)self); +} + +PyObject *DBCSpe_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dvm_DBCSpeObject *self; + + self = (dvm_DBCSpeObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->d = NULL; + } + + return (PyObject *)self; +} + +int DBCSpe_init(dvm_DBCSpeObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +PyObject *DBCSpe_get_opvalue(dvm_DBCSpeObject *self, PyObject* args) +{ + return Py_BuildValue("i", -1); +} + +PyObject *DBCSpe_get_name(dvm_DBCSpeObject *self, PyObject* args) +{ + return PyString_FromString( self->d->get_opname() ); +} + +PyObject *DBCSpe_get_operands(dvm_DBCSpeObject *self, PyObject* args) +{ + if (self->d->get_type() == 0) { + FillArrayData *fad = reinterpret_cast( self->d ); + return PyString_FromStringAndSize( fad->data, fad->data_size ); + } else if (self->d->get_type() == 1) { + SparseSwitch *ss = reinterpret_cast( self->d ); + + PyObject *operands = PyList_New( 0 ); + + PyObject *ioperands = PyList_New( 0 ); + for (int ii = 0; ii < ss->keys.size(); ii++) + PyList_Append( ioperands, PyInt_FromLong( ss->keys[ii] ) ); + PyList_Append( operands, ioperands ); + + ioperands = PyList_New( 0 ); + for (int ii = 0; ii < ss->targets.size(); ii++) + PyList_Append( ioperands, PyInt_FromLong( ss->targets[ii] ) ); + PyList_Append( operands, ioperands ); + + return operands; + } else if (self->d->get_type() == 2) { + PackedSwitch *ps = reinterpret_cast( self->d ); + + PyObject *operands = PyList_New( 0 ); + PyList_Append( operands, PyInt_FromLong( ps->pst.first_key ) ); + + PyObject *ioperands = PyList_New( 0 ); + for (int ii = 0; ii < ps->targets.size(); ii++) + PyList_Append( ioperands, PyInt_FromLong( ps->targets[ii] ) ); + PyList_Append( operands, ioperands ); + + return operands; + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject *DBCSpe_get_targets(dvm_DBCSpeObject *self, PyObject* args) +{ + if (self->d->get_type() == 1) { + SparseSwitch *ss = reinterpret_cast( self->d ); + + PyObject *operands = PyList_New( 0 ); + for (int ii = 0; ii < ss->targets.size(); ii++) + PyList_Append( operands, PyInt_FromLong( ss->targets[ii] ) ); + + return operands; + } else if (self->d->get_type() == 2) { + PackedSwitch *ps = reinterpret_cast( self->d ); + + PyObject *operands = PyList_New( 0 ); + for (int ii = 0; ii < ps->targets.size(); ii++) + PyList_Append( operands, PyInt_FromLong( ps->targets[ii] ) ); + + return operands; + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject *DBCSpe_get_length(dvm_DBCSpeObject *self, PyObject* args) +{ + return Py_BuildValue("i", self->d->get_length()); +} + +PyObject *DBCSpe_get_type_ins(dvm_DBCSpeObject *self, PyObject* args) +{ + return Py_BuildValue("i", 1); +} + +typedef struct { + PyObject_HEAD; + DalvikBytecode *dparent; + DCode *d; + PyObject *bytecodes_list; + PyObject *bytecodes_spe_list; +} dvm_DCodeObject; + +static void +DCode_dealloc(dvm_DCodeObject* self) +{ +#ifdef DEBUG_DESTRUCTOR + cout << "DCode_dealloc\n"; +#endif + delete self->d; + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject *DCode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dvm_DCodeObject *self; + + self = (dvm_DCodeObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->d = NULL; + self->bytecodes_list = NULL; + self->bytecodes_spe_list = NULL; + } + + return (PyObject *)self; +} + +static int +DCode_init(dvm_DCodeObject *self, PyObject *args, PyObject *kwds) +{ + const char *code; + size_t code_len; + + if (self != NULL) { + int ok = PyArg_ParseTuple( args, "s#", &code, &code_len); + if(!ok) return -1; + + + self->d = self->dparent->new_code( code, code_len ); + } + + return 0; +} + +static PyObject *DCode_get_nb_bytecodes(dvm_DCodeObject *self, PyObject* args) +{ + return Py_BuildValue("i", self->d->size()); +} + +static PyObject *DCode_get_bytecodes(dvm_DCodeObject *self, PyObject* args) +{ + if (self->bytecodes_list != NULL) { + Py_INCREF( self->bytecodes_list ); + return self->bytecodes_list; + } + + self->bytecodes_list = PyList_New( 0 ); + + for (int ii=0; ii < self->d->bytecodes.size(); ii++) { + PyObject *nc = DBC_new(&dvm_DBCType, NULL, NULL); + dvm_DBCObject *dc = (dvm_DBCObject *)nc; + + dc->d = self->d->bytecodes[ii]; + + Py_INCREF( nc ); + + PyList_Append( self->bytecodes_list, nc ); + } + + Py_INCREF( self->bytecodes_list ); + return self->bytecodes_list; +} + +static PyObject *DCode_get_bytecodes_spe(dvm_DCodeObject *self, PyObject* args) +{ + if (self->bytecodes_spe_list != NULL) { + Py_INCREF( self->bytecodes_spe_list ); + return self->bytecodes_spe_list; + } + + self->bytecodes_spe_list = PyList_New( 0 ); + + for (int ii=0; ii < self->d->bytecodes_spe.size(); ii++) { + PyObject *nc = DBCSpe_new(&dvm_DBCSpeType, NULL, NULL); + dvm_DBCSpeObject *dc = (dvm_DBCSpeObject *)nc; + + dc->d = self->d->bytecodes_spe[ii]; + + Py_INCREF( nc ); + + PyList_Append( self->bytecodes_spe_list, nc ); + } + + Py_INCREF( self->bytecodes_spe_list ); + return self->bytecodes_spe_list; +} + +static PyMethodDef DCode_methods[] = { + {"get_nb_bytecodes", (PyCFunction)DCode_get_nb_bytecodes, METH_NOARGS, "get nb bytecodes" }, + {"get_bytecodes", (PyCFunction)DCode_get_bytecodes, METH_NOARGS, "get nb bytecodes" }, + {"get_bytecodes_spe", (PyCFunction)DCode_get_bytecodes_spe, METH_NOARGS, "get nb bytecodes" }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static PyTypeObject dvm_DCodeType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "dvm.DCode", /*tp_name*/ + sizeof(dvm_DCodeObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)DCode_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "DCode objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DCode_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DCode_init, /* tp_init */ + 0, /* tp_alloc */ + DCode_new, /* tp_new */ +}; + +typedef struct { + PyObject_HEAD; + DalvikBytecode *d; +} dvm_DalvikBytecodeObject; + +static void +DalvikBytecode_dealloc(dvm_DalvikBytecodeObject* self) +{ +#ifdef DEBUG_DESTRUCTOR + cout << "DalvikBytecode_dealloc\n"; +#endif + delete self->d; + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject *DalvikBytecode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dvm_DalvikBytecodeObject *self; + + self = (dvm_DalvikBytecodeObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->d = NULL; + } + + return (PyObject *)self; +} + +static int +DalvikBytecode_init(dvm_DalvikBytecodeObject *self, PyObject *args, PyObject *kwds) +{ + if (self != NULL) + self->d = new DalvikBytecode(); + + return 0; +} + +static PyObject *DalvikBytecode_new_code(dvm_DalvikBytecodeObject *self, PyObject* args) +{ + //cout<<"Called new code()\n"; + + PyObject *nc = DCode_new(&dvm_DCodeType, NULL, NULL); + + dvm_DCodeObject *dnc = (dvm_DCodeObject *)nc; + + dnc->dparent = self->d; + DCode_init( (dvm_DCodeObject *)nc, args, NULL ); + + return nc; +} + +static PyMethodDef DalvikBytecode_methods[] = { + {"new_code", (PyCFunction)DalvikBytecode_new_code, METH_VARARGS, "new code" }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static PyTypeObject dvm_DalvikBytecodeType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "dvm.DalvikBytecode", /*tp_name*/ + sizeof(dvm_DalvikBytecodeObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)DalvikBytecode_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "DalvikBytecode objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DalvikBytecode_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DalvikBytecode_init, /* tp_init */ + 0, /* tp_alloc */ + DalvikBytecode_new, /* tp_new */ +}; + +static PyMethodDef dvm_methods[] = { + {NULL} /* Sentinel */ +}; + +extern "C" PyMODINIT_FUNC initdvmnative(void) { + PyObject *m; + + dvm_DalvikBytecodeType.tp_new = PyType_GenericNew; + if (PyType_Ready(&dvm_DalvikBytecodeType) < 0) + return; + + dvm_DCodeType.tp_new = PyType_GenericNew; + if (PyType_Ready(&dvm_DCodeType) < 0) + return; + + dvm_DBCType.tp_new = PyType_GenericNew; + if (PyType_Ready(&dvm_DBCType) < 0) + return; + + dvm_DBCSpeType.tp_new = PyType_GenericNew; + if (PyType_Ready(&dvm_DBCSpeType) < 0) + return; + + m = Py_InitModule3("dvmnative", dvm_methods, "Example module that creates an extension type."); + + Py_INCREF(&dvm_DalvikBytecodeType); + PyModule_AddObject(m, "DalvikBytecode", (PyObject *)&dvm_DalvikBytecodeType); + + Py_INCREF(&dvm_DCodeType); + PyModule_AddObject(m, "DCode", (PyObject *)&dvm_DCodeType); + + Py_INCREF(&dvm_DBCType); + PyModule_AddObject(m, "DBC", (PyObject *)&dvm_DBCType); + + Py_INCREF(&dvm_DBCSpeType); + PyModule_AddObject(m, "DBCSpe", (PyObject *)&dvm_DBCSpeType); +} + diff --git a/androguard/core/bytecodes/libdvm/dvm.h b/androguard/core/bytecodes/libdvm/dvm.h new file mode 100644 index 00000000..66610c3b --- /dev/null +++ b/androguard/core/bytecodes/libdvm/dvm.h @@ -0,0 +1,302 @@ +/* + This file is part of Androguard. + + Copyright (C) 2011, Anthony Desnos + All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +#ifndef DVM_H +#define DVM_H + +#include + +#ifdef __cplusplus + +#include +#include +#include + +#if defined __GNUC__ || defined __APPLE__ +#include +#else +#include +#endif + +#include "buff.h" + +#define OPVALUE 0 +#define REGISTER 1 +#define FIELD 2 +#define METHOD 3 +#define TYPE 4 +#define INTEGER 5 +#define STRING 6 +#define INTEGER_BRANCH 7 + + +//#define DEBUG_DESTRUCTOR +#undef DEBUG_DESTRUCTOR + +using namespace __gnu_cxx; +using namespace std; +using std::cout; +using std::endl; + +typedef struct fillarraydata { + unsigned short ident; + unsigned short element_width; + unsigned int size; +} fillarraydata_t; + +typedef struct sparseswitch { + unsigned short ident; + unsigned short size; +} sparseswitch_t; + +typedef struct packedswitch { + unsigned short ident; + unsigned short size; + unsigned int first_key; +} packedswitch_t; + +class DBC { + public : + unsigned char op_value; + const char *op_name; + size_t op_length; + vector *voperands; + vector *vdescoperands; + vector *vstrings; + + public : + DBC(unsigned char value, const char *name, vector *v, vector *vdesc, size_t length); + ~DBC(); + int get_opvalue(); + const char *get_opname(); + size_t get_length(); +}; + +class DBCSpe { + public : + virtual const char *get_opname()=0; + virtual size_t get_length()=0; + virtual size_t get_type()=0; +}; + +class FillArrayData : public DBCSpe { + public : + fillarraydata_t fadt; + char *data; + size_t data_size; + public : + FillArrayData(Buff *b, unsigned int off); + ~FillArrayData(); + const char *get_opname(); + size_t get_length(); + size_t get_type(); +}; + +class SparseSwitch : public DBCSpe { + public : + sparseswitch_t sst; + vector keys; + vector targets; + + public : + SparseSwitch(Buff *b, unsigned int off); + ~SparseSwitch(); + const char *get_opname(); + size_t get_length(); + size_t get_type(); +}; + +class PackedSwitch : public DBCSpe { + public : + packedswitch_t pst; + vector targets; + + public : + PackedSwitch(Buff *b, unsigned int off); + ~PackedSwitch(); + const char *get_opname(); + size_t get_length(); + size_t get_type(); +}; + +class DCode { + public : + vector bytecodes; + vector bytecodes_spe; + + public : + DCode(); + ~DCode(); + DCode(vector*, vector*)> *parsebytecodes, + vector *, vector *, vector *, unsigned int *)> *postbytecodes, + vector *bytecodes_names, + Buff *b); + int size(); + DBC *get_bytecode_at(int i); +}; + +class DalvikBytecode { + public : + vector*, vector*)> bytecodes; + vector *, vector *, vector *, unsigned int *)> postbytecodes; + + vector bytecodes_names; + + public : + DalvikBytecode(); + DCode *new_code(const char *data, size_t data_len); +}; + +typedef struct { + PyObject_HEAD; + DBC *d; + PyObject *operands; +} dvm_DBCObject; + +PyObject *DBC_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +void DBC_dealloc(dvm_DBCObject* self); +PyObject *DBC_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +int DBC_init(dvm_DBCObject *self, PyObject *args, PyObject *kwds); +PyObject *DBC_get_opvalue(dvm_DBCObject *self, PyObject* args); +PyObject *DBC_get_length(dvm_DBCObject *self, PyObject* args); +PyObject *DBC_get_name(dvm_DBCObject *self, PyObject* args); +PyObject *DBC_get_operands(dvm_DBCObject *self, PyObject* args); +PyObject *DBC_get_type_ins(dvm_DBCObject *self, PyObject* args); + +static PyMethodDef DBC_methods[] = { + {"get_op_value", (PyCFunction)DBC_get_opvalue, METH_NOARGS, "get nb bytecodes" }, + {"get_length", (PyCFunction)DBC_get_length, METH_NOARGS, "get nb bytecodes" }, + {"get_name", (PyCFunction)DBC_get_name, METH_NOARGS, "get nb bytecodes" }, + {"get_operands", (PyCFunction)DBC_get_operands, METH_NOARGS, "get nb bytecodes" }, + {"get_type_ins", (PyCFunction)DBC_get_type_ins, METH_NOARGS, "get type ins" }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static PyTypeObject dvm_DBCType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "dvm.DBC", /*tp_name*/ + sizeof(dvm_DBCObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)DBC_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "DBC objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DBC_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DBC_init, /* tp_init */ + 0, /* tp_alloc */ + DBC_new, /* tp_new */ +}; + +typedef struct { + PyObject_HEAD; + DBCSpe *d; +} dvm_DBCSpeObject; + +void DBCSpe_dealloc(dvm_DBCSpeObject* self); +PyObject *DBCSpe_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +int DBCSpe_init(dvm_DBCSpeObject *self, PyObject *args, PyObject *kwds); +PyObject *DBCSpe_get_opvalue(dvm_DBCSpeObject *self, PyObject* args); +PyObject *DBCSpe_get_name(dvm_DBCSpeObject *self, PyObject* args); +PyObject *DBCSpe_get_operands(dvm_DBCSpeObject *self, PyObject* args); +PyObject *DBCSpe_get_targets(dvm_DBCSpeObject *self, PyObject* args); +PyObject *DBCSpe_get_length(dvm_DBCSpeObject *self, PyObject* args); +PyObject *DBCSpe_get_type_ins(dvm_DBCSpeObject *self, PyObject* args); + +static PyMethodDef DBCSpe_methods[] = { + {"get_name", (PyCFunction)DBCSpe_get_name, METH_NOARGS, "get nb bytecodes" }, + {"get_op_value", (PyCFunction)DBCSpe_get_opvalue, METH_NOARGS, "get nb bytecodes" }, + {"get_operands", (PyCFunction)DBCSpe_get_operands, METH_NOARGS, "get nb bytecodes" }, + {"get_targets", (PyCFunction)DBCSpe_get_targets, METH_NOARGS, "get nb bytecodes" }, + {"get_length", (PyCFunction)DBCSpe_get_length, METH_NOARGS, "get nb bytecodes" }, + {"get_type_ins", (PyCFunction)DBCSpe_get_type_ins, METH_NOARGS, "get type ins" }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static PyTypeObject dvm_DBCSpeType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "dvm.DBCSpe", /*tp_name*/ + sizeof(dvm_DBCSpeObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)DBCSpe_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "DBC objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DBCSpe_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DBCSpe_init, /* tp_init */ + 0, /* tp_alloc */ + DBCSpe_new, /* tp_new */ +}; + + +#endif +#endif diff --git a/androguard/core/bytecodes/libdvm/test_dvm.py b/androguard/core/bytecodes/libdvm/test_dvm.py new file mode 100755 index 00000000..63b514e7 --- /dev/null +++ b/androguard/core/bytecodes/libdvm/test_dvm.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2011, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys, itertools, time, os, random +from ctypes import cdll, c_float, c_int, c_uint, c_void_p, Structure, addressof, create_string_buffer, cast, POINTER, pointer +from struct import pack, unpack, calcsize + +PATH_INSTALL = "../../../" +sys.path.append(PATH_INSTALL + "./") +sys.path.append(PATH_INSTALL + "./core") +sys.path.append(PATH_INSTALL + "./core/bytecodes") +sys.path.append(PATH_INSTALL + "./core/analysis") + +import apk, dvm, analysis, msign + +if __name__ == "__main__" : +# a = apk.APK( PATH_INSTALL + "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" ) +# a = apk.APK( PATH_INSTALL + "apks/drweb-600-android-beta.apk" ) +# a = apk.APK( PATH_INSTALL + "debug/062d5e38dc4618a8b1c6bf3587dc2016a3a3db146aea0d82cc227a18ca21ad13") + a = apk.APK( PATH_INSTALL + "apks/malwares/kungfu/sample2.apk" ) + + t1 = time.time() + + + if len(sys.argv) > 1 : + d = dvm.DalvikVMFormat( a.get_dex(), engine=["python"] ) + else : + d = dvm.DalvikVMFormat( a.get_dex() ) + + t2 = time.time() + x = analysis.VMAnalysis( d ) + + t3 = time.time() + print '-> %0.8f %0.8f %0.8f' % ((t2-t1, t3-t2, t3-t1)) + + sys.exit(0) + + for method in d.get_methods() : + print method.get_class_name(), method.get_name(), method.get_descriptor() + + code = method.get_code() + if code == None : + continue + + bc = code.get_bc() + + idx = 0 + for i in bc.get() : + print "\t", "%x" % idx, i.get_op_value(), i.get_name(), i.get_operands()#, i.get_formatted_operands() + idx += i.get_length() + + sys.exit(0) diff --git a/androguard/core/data/__init__.py b/androguard/core/data/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/core/data/data.py b/androguard/core/data/data.py new file mode 100644 index 00000000..8f3cce17 --- /dev/null +++ b/androguard/core/data/data.py @@ -0,0 +1,395 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from networkx import DiGraph +import os +from xml.sax.saxutils import escape + + +from androguard.core.analysis import analysis + +try : + from androguard.core.analysis.libsign.libsign import entropy +except ImportError : + import math + def entropy(data): + entropy = 0 + + if len(data) == 0 : + return entropy + + for x in range(256): + p_x = float(data.count(chr(x)))/len(data) + if p_x > 0: + entropy += - p_x*math.log(p_x, 2) + return entropy + +DEFAULT_SIGNATURE = analysis.SIGNATURE_L0_4 +def create_entropies(vmx, m) : + try : + default_signature = vmx.get_method_signature(m, predef_sign = DEFAULT_SIGNATURE).get_string() + l = [ default_signature, + entropy( vmx.get_method_signature(m, "L4", { "L4" : { "arguments" : ["Landroid"] } } ).get_string() ), + entropy( vmx.get_method_signature(m, "L4", { "L4" : { "arguments" : ["Ljava"] } } ).get_string() ), + entropy( vmx.get_method_signature(m, "hex" ).get_string() ), + entropy( vmx.get_method_signature(m, "L2" ).get_string() ), + ] + return l + except KeyError : + return [ "", 0.0, 0.0, 0.0, 0.0 ] + +def create_info(vmx, m) : + E = create_entropies(vmx, m) + + H = {} + H["signature"] = E[0] + H["signature_entropy"] = entropy( E[0] ) + H["android_api_entropy"] = E[1] + H["java_api_entropy"] = E[2] + H["hex_entropy"] = E[3] + H["exceptions_entropy"] = E[4] + + return H + +class Data : + def __init__(self, vm, vmx, gvmx, a=None) : + self.vm = vm + self.vmx = vmx + self.gvmx = gvmx + self.a = a + + self.apk_data = None + self.dex_data = None + + if self.a != None : + self.apk_data = ApkViewer( self.a ) + + self.dex_data = DexViewer( vm, vmx, gvmx ) + + self.gvmx.set_new_attributes( create_info ) + self.export_methods_to_gml() + + def export_methodcalls_to_gml(self) : + return self.gvmx.export_to_gml() + + def export_methods_to_gml(self) : + print self.gvmx.G + + for node in self.gvmx.G.nodes() : + print self.gvmx.nodes_id[ node ].method_name, self.gvmx.nodes_id[ node ].get_attributes() + + def export_apk_to_gml(self) : + if self.apk_data != None : + return self.apk_data.export_to_gml() + + def export_dex_to_gml(self) : + if self.dex_data != None : + return self.dex_data.export_to_gml() + +class DexViewer : + def __init__(self, vm, vmx, gvmx) : + self.vm = vm + self.vmx = vmx + self.gvmx = gvmx + + + def _create_node(self, id, height, width, color, label) : + buff = "\n" % id + buff += "\n" + buff += "\n" + + buff += "\n" % (16 * height, 7.5 * width) + buff += "\n" % color + + buff += "\n" + + buff += escape(label) + + buff += "\n" + buff += "\n" + buff += "\n" + + buff += "\n" + + return buff + + def add_exception_node(self, exception, id_i) : + buff = "" + # 9933FF + height = 2 + width = 0 + label = "" + + label += "%x:%x\n" % (exception.start, exception.end) + for i in exception.exceptions : + c_label = "\t(%s -> %x %s)\n" % (i[0], i[1], i[2].get_name()) + label += c_label + + width = max(len(c_label), width) + height += 1 + + return self._create_node( id_i, height, width, "9333FF", label ) + + def add_method_node(self, i, id_i) : + height = 0 + width = 0 + label = "" + + label += i.get_name() + "\n" + label += i.get_descriptor() + + height = 3 + width = len(label) + + return self._create_node( id_i, height, width, "FF0000", label ) + + def add_node(self, i, id_i) : + height = 0 + width = 0 + idx = i.start + label = "" + for ins in i.get_instructions() : + c_label = "%x %s\n" % (idx, self.vm.dotbuff(ins, idx)) + idx += ins.get_length() + label += c_label + width = max(width, len(c_label)) + height += 1 + + if height < 10 : + height += 3 + + return self._create_node( id_i, height, width, "FFCC00", label ) + + def add_edge(self, i, id_i, j, id_j, l_eid, val) : + buff = "\n" % (len(l_eid), id_i, id_j) + + buff += "\n" + buff += "\n" + buff += "\n" + + if val == 0 : + buff += "\n" + elif val == 1 : + buff += "\n" + else : + buff += "\n" + + buff += "\n" + buff += "\n" + + buff += "\n" + + l_eid[ "%d+%d" % (id_i, id_j) ] = len(l_eid) + return buff + + def new_id(self, i, l) : + try : + return l[i] + except KeyError : + l[i] = len(l) + return l[i] + + def export_to_gml(self) : + H = {} + + for _class in self.vm.get_classes() : + name = _class.get_name() + name = name[1:-1] + + buff = "" + + buff += "\n" + buff += "\n" + + buff += "\n" + buff += "\n" + buff += "\n" + + buff += "\n" + + print name + + buff_nodes = "" + buff_edges = "" + l_id = {} + l_eid = {} + + for method in _class.get_methods() : + mx = self.vmx.get_method( method ) + exceptions = mx.exceptions + + id_method = self.new_id(method, l_id) + buff_nodes += self.add_method_node(method, id_method) + + for i in mx.basic_blocks.get() : + + id_i = self.new_id(i, l_id) + print i, id_i, i.exception_analysis + + buff_nodes += self.add_node( i, id_i ) + + # add childs nodes + val = 0 + if len(i.childs) > 1 : + val = 1 + elif len(i.childs) == 1 : + val = 2 + + for j in i.childs : + print "\t", j + + id_j = self.new_id(j[-1], l_id) + buff_edges += self.add_edge(i, id_i, j[-1], id_j, l_eid, val) + if val == 1 : + val = 0 + + # add exceptions node + if i.exception_analysis != None : + id_exceptions = self.new_id(i.exception_analysis, l_id) + buff_nodes += self.add_exception_node(i.exception_analysis, id_exceptions) + buff_edges += self.add_edge(None, id_exceptions, None, id_i, l_eid, 2) + + buff_edges += self.add_edge(None, id_method, None, id_method+1, l_eid, 2) + + buff += buff_nodes + buff += buff_edges + + + buff += "\n" + buff += "\n" + + H[ name ] = buff + return H + +class Directory : + def __init__(self, name) : + self.name = name + self.basename = os.path.basename(name) + self.color = "FF0000" + + self.width = len(self.name) + + def set_color(self, color) : + self.color = color + +class File : + def __init__(self, name, file_type, file_crc) : + self.name = name + self.basename = os.path.basename(name) + self.file_type = file_type + self.file_crc = file_crc + + self.color = "FFCC00" + + self.width = max(len(self.name), len(self.file_type)) + +def splitall(path, z) : + if len(path) == 0 : + return + + l = os.path.split( path ) + z.append(l[0]) + + for i in l : + return splitall( i, z ) + +class ApkViewer : + def __init__(self, a) : + self.a = a + + self.G = DiGraph() + self.all_files = {} + self.ids = {} + + root = Directory( "APK" ) + root.set_color( "00FF00" ) + + self.ids[ root ] = len(self.ids) + self.G.add_node( root ) + + for x, y, z in self.a.get_files_information() : + print x, y, z, os.path.basename(x) + + l = [] + splitall( x, l ) + l.reverse() + l.pop(0) + + + last = root + for i in l : + if i not in self.all_files : + tmp = Directory( i ) + self.ids[ tmp ] = len(self.ids) + self.all_files[ i ] = tmp + else : + tmp = self.all_files[ i ] + + self.G.add_edge(last, tmp) + last = tmp + + n1 = last + n2 = File( x, y, z ) + self.G.add_edge(n1, n2) + + self.ids[ n2 ] = len(self.ids) + + def export_to_gml(self) : + buff = "\n" + buff += "\n" + + buff += "\n" + buff += "\n" + + + buff += "\n" + + + for node in self.G.nodes() : + print node + + buff += "\n" % self.ids[node] + buff += "\n" + buff += "\n" + + buff += "\n" % (60.0, 7 * node.width) + buff += "\n" % node.color + + buff += "\n" + buff += "%s\n" % node.basename + + if isinstance(node, File) : + buff += "%s\n" % node.file_type + buff += "%s\n" % hex(node.file_crc) + + buff += "\n" + + buff += "\n" + buff += "\n" + + buff += "\n" + + nb = 0 + for edge in self.G.edges() : + buff += "\n" % (nb, self.ids[edge[0]], self.ids[edge[1]]) + buff += "\n" + nb += 1 + + buff += "\n" + buff += "\n" + + return buff diff --git a/androguard/core/debugger/__init__.py b/androguard/core/debugger/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/decompiler/__init__.py b/androguard/decompiler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/decompiler/dad/README.txt b/androguard/decompiler/dad/README.txt new file mode 100644 index 00000000..e69de29b diff --git a/androguard/decompiler/dad/__init__.py b/androguard/decompiler/dad/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/decompiler/dad/basic_blocks.py b/androguard/decompiler/dad/basic_blocks.py new file mode 100644 index 00000000..b9baacf4 --- /dev/null +++ b/androguard/decompiler/dad/basic_blocks.py @@ -0,0 +1,349 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from collections import defaultdict +from androguard.decompiler.dad.opcode_ins import INSTRUCTION_SET +from androguard.decompiler.dad.node import Node + + +logger = logging.getLogger('dad.basic_blocks') + + +class BasicBlock(Node): + def __init__(self, name, block_ins): + super(BasicBlock, self).__init__(name) + self.ins = block_ins + self.ins_range = None + self.loc_ins = None + self.var_to_declare = set() + + def get_ins(self): + return self.ins + + def get_loc_with_ins(self): + if self.loc_ins is None: + self.loc_ins = zip(range(*self.ins_range), self.ins) + return self.loc_ins + + def remove_ins(self, loc, ins): + self.ins.remove(ins) + self.loc_ins.remove((loc, ins)) + + def add_ins(self, new_ins_list): + for new_ins in new_ins_list: + self.ins.append(new_ins) + + def add_variable_declaration(self, variable): + self.var_to_declare.add(variable) + + def number_ins(self, num): + last_ins_num = num + len(self.ins) + self.ins_range = [num, last_ins_num] + self.loc_ins = None + return last_ins_num + + +class StatementBlock(BasicBlock): + def __init__(self, name, block_ins): + super(StatementBlock, self).__init__(name, block_ins) + self.type.is_stmt = True + + def visit(self, visitor): + return visitor.visit_statement_node(self) + + def __str__(self): + return '%d-Statement(%s)' % (self.num, self.name) + + +class ReturnBlock(BasicBlock): + def __init__(self, name, block_ins): + super(ReturnBlock, self).__init__(name, block_ins) + self.type.is_return = True + + def visit(self, visitor): + return visitor.visit_return_node(self) + + def __str__(self): + return '%d-Return(%s)' % (self.num, self.name) + + +class ThrowBlock(BasicBlock): + def __init__(self, name, block_ins): + super(ThrowBlock, self).__init__(name, block_ins) + self.type.is_throw = True + + def visit(self, visitor): + return visitor.visit_throw_node(self) + + def __str__(self): + return '%d-Throw(%s)' % (self.num, self.name) + + +class SwitchBlock(BasicBlock): + def __init__(self, name, switch, block_ins): + super(SwitchBlock, self).__init__(name, block_ins) + self.switch = switch + self.cases = [] + self.default = None + self.node_to_case = defaultdict(list) + self.type.is_switch = True + + def add_case(self, case): + self.cases.append(case) + + def visit(self, visitor): + return visitor.visit_switch_node(self) + + def copy_from(self, node): + super(SwitchBlock, self).copy_from(node) + self.cases = node.cases[:] + self.switch = node.switch[:] + + def update_attribute_with(self, n_map): + super(SwitchBlock, self).update_attribute_with(n_map) + self.cases = [n_map.get(n, n) for n in self.cases] + for node1, node2 in n_map.iteritems(): + if node1 in self.node_to_case: + self.node_to_case[node2] = self.node_to_case.pop(node1) + + def order_cases(self): + values = self.switch.get_values() + if len(values) < len(self.cases): + self.default = self.cases.pop(0) + for case, node in zip(values, self.cases): + self.node_to_case[node].append(case) + + def __str__(self): + return '%d-Switch(%s)' % (self.num, self.name) + + +class CondBlock(BasicBlock): + def __init__(self, name, block_ins): + super(CondBlock, self).__init__(name, block_ins) + self.true = None + self.false = None + self.type.is_cond = True + + def update_attribute_with(self, n_map): + super(CondBlock, self).update_attribute_with(n_map) + self.true = n_map.get(self.true, self.true) + self.false = n_map.get(self.false, self.false) + + def neg(self): + if len(self.ins) != 1: + raise RuntimeWarning('Condition should have only 1 instruction !') + self.ins[-1].neg() + + def visit(self, visitor): + return visitor.visit_cond_node(self) + + def visit_cond(self, visitor): + if len(self.ins) != 1: + raise RuntimeWarning('Condition should have only 1 instruction !') + return visitor.visit_ins(self.ins[-1]) + + def __str__(self): + return '%d-If(%s)' % (self.num, self.name) + + +class Condition(object): + def __init__(self, cond1, cond2, isand, isnot): + self.cond1 = cond1 + self.cond2 = cond2 + self.isand = isand + self.isnot = isnot + + def neg(self): + self.isand = not self.isand + self.cond1.neg() + self.cond2.neg() + + def get_ins(self): + lins = [] + lins.extend(self.cond1.get_ins()) + lins.extend(self.cond2.get_ins()) + return lins + + def get_loc_with_ins(self): + loc_ins = [] + loc_ins.extend(self.cond1.get_loc_with_ins()) + loc_ins.extend(self.cond2.get_loc_with_ins()) + return loc_ins + + def visit(self, visitor): + return visitor.visit_short_circuit_condition(self.isnot, self.isand, + self.cond1, self.cond2) + + def __str__(self): + if self.isnot: + ret = '!%s %s %s' + else: + ret = '%s %s %s' + return ret % (self.cond1, ['||', '&&'][self.isand], self.cond2) + + +class ShortCircuitBlock(CondBlock): + def __init__(self, name, cond): + super(ShortCircuitBlock, self).__init__(name, None) + self.cond = cond + + def get_ins(self): + return self.cond.get_ins() + + def get_loc_with_ins(self): + return self.cond.get_loc_with_ins() + + def neg(self): + self.cond.neg() + + def visit_cond(self, visitor): + return self.cond.visit(visitor) + + def __str__(self): + return '%d-SC(%s)' % (self.num, self.cond) + + +class LoopBlock(CondBlock): + def __init__(self, name, cond): + super(LoopBlock, self).__init__(name, None) + self.cond = cond + + def get_ins(self): + return self.cond.get_ins() + + def neg(self): + self.cond.neg() + + def get_loc_with_ins(self): + return self.cond.get_loc_with_ins() + + def visit(self, visitor): + return visitor.visit_loop_node(self) + + def visit_cond(self, visitor): + return self.cond.visit_cond(visitor) + + def update_attribute_with(self, n_map): + super(LoopBlock, self).update_attribute_with(n_map) + self.cond.update_attribute_with(n_map) + + def __str__(self): + if self.looptype.is_pretest: + if self.false in self.loop_nodes: + return '%d-While(!%s)[%s]' % (self.num, self.name, self.cond) + return '%d-While(%s)[%s]' % (self.num, self.name, self.cond) + elif self.looptype.is_posttest: + return '%d-DoWhile(%s)[%s]' % (self.num, self.name, self.cond) + elif self.looptype.is_endless: + return '%d-WhileTrue(%s)[%s]' % (self.num, self.name, self.cond) + return '%d-WhileNoType(%s)' % (self.num, self.name) + + +class TryBlock(BasicBlock): + def __init__(self, node): + super(TryBlock, self).__init__('Try-%s' % node.name, None) + self.try_start = node + self.catch = [] + + def add_catch_node(self, node): + self.catch.append(node) + + def visit(self, visitor): + visitor.visit_try_node(self) + + def __str__(self): + return 'Try(%s)[%s]' % (self.name, self.catch) + + +class CatchBlock(BasicBlock): + def __init__(self, node): + self.exception = node.ins[0] + node.ins.pop(0) + super(CatchBlock, self).__init__('Catch-%s' % node.name, node.ins) + self.catch_start = node + + def visit(self, visitor): + visitor.visit_catch_node(self) + + def visit_exception(self, visitor): + visitor.visit_ins(self.exception) + + def __str__(self): + return 'Catch(%s)' % self.name + + +def build_node_from_block(block, vmap, gen_ret, exception_type=None): + ins, lins = None, [] + idx = block.get_start() + for ins in block.get_instructions(): + opcode = ins.get_op_value() + # check-cast + if opcode in (0x1f, -1): # FIXME? or opcode in (0x0300, 0x0200, 0x0100): + idx += ins.get_length() + continue + try: + _ins = INSTRUCTION_SET[opcode] + except IndexError: + logger.error('Unknown instruction : %s.', ins.get_name().lower()) + raise + # fill-array-data + if opcode == 0x26: + fillaray = block.get_special_ins(idx) + lins.append(_ins(ins, vmap, fillaray)) + # invoke-kind[/range] + elif (0x6e <= opcode <= 0x72 or 0x74 <= opcode <= 0x78): + lins.append(_ins(ins, vmap, gen_ret)) + # filled-new-array[/range] + elif 0x24 <= opcode <= 0x25: + lins.append(_ins(ins, vmap, gen_ret.new())) + # move-result* + elif 0xa <= opcode <= 0xc: + lins.append(_ins(ins, vmap, gen_ret.last())) + # move-exception + elif opcode == 0xd: + lins.append(_ins(ins, vmap, exception_type)) + # monitor-{enter,exit} + elif 0x1d <= opcode <= 0x1e: + idx += ins.get_length() + continue + else: + lins.append(_ins(ins, vmap)) + idx += ins.get_length() + name = block.get_name() + # return* + if 0xe <= opcode <= 0x11: + node = ReturnBlock(name, lins) + # {packed,sparse}-switch + elif 0x2b <= opcode <= 0x2c: + idx -= ins.get_length() + values = block.get_special_ins(idx) + node = SwitchBlock(name, values, lins) + # if-test[z] + elif 0x32 <= opcode <= 0x3d: + node = CondBlock(name, lins) + node.off_last_ins = ins.get_ref_off() + # throw + elif opcode == 0x27: + node = ThrowBlock(name, lins) + else: + # goto* + if 0x28 <= opcode <= 0x2a: + lins.pop() + node = StatementBlock(name, lins) + return node + diff --git a/androguard/decompiler/dad/control_flow.py b/androguard/decompiler/dad/control_flow.py new file mode 100644 index 00000000..0a1cb2ab --- /dev/null +++ b/androguard/decompiler/dad/control_flow.py @@ -0,0 +1,432 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from collections import defaultdict +from androguard.decompiler.dad.basic_blocks import (CatchBlock, + Condition, + LoopBlock, + ShortCircuitBlock, + TryBlock) +from androguard.decompiler.dad.graph import Graph +from androguard.decompiler.dad.node import Interval +from androguard.decompiler.dad.util import common_dom + + +logger = logging.getLogger('dad.control_flow') + + +def intervals(graph): + ''' + Compute the intervals of the graph + Returns + interval_graph: a graph of the intervals of G + interv_heads: a dict of (header node, interval) + ''' + interval_graph = Graph() # graph of intervals + heads = [graph.entry] # list of header nodes + interv_heads = {} # interv_heads[i] = interval of header i + processed = dict([(i, False) for i in graph]) + edges = defaultdict(list) + + while heads: + head = heads.pop(0) + + if not processed[head]: + processed[head] = True + interv_heads[head] = Interval(head) + + # Check if there is a node which has all its predecessor in the + # current interval. If there is, add that node to the interval and + # repeat until all the possible nodes have been added. + change = True + while change: + change = False + for node in graph.rpo[1:]: + if all(p in interv_heads[head] for p in graph.all_preds(node)): + change |= interv_heads[head].add_node(node) + + # At this stage, a node which is not in the interval, but has one + # of its predecessor in it, is the header of another interval. So + # we add all such nodes to the header list. + for node in graph: + if node not in interv_heads[head] and node not in heads: + if any(p in interv_heads[head] for p in graph.all_preds(node)): + edges[interv_heads[head]].append(node) + assert(node not in heads) + heads.append(node) + + interval_graph.add_node(interv_heads[head]) + interv_heads[head].compute_end(graph) + + # Edges is a mapping of 'Interval -> [header nodes of interval successors]' + for interval, heads in edges.items(): + for head in heads: + interval_graph.add_edge(interval, interv_heads[head]) + + interval_graph.entry = graph.entry.interval + if graph.exit: + interval_graph.exit = graph.exit.interval + + return interval_graph, interv_heads + + +def derived_sequence(graph): + ''' + Compute the derived sequence of the graph G + The intervals of G are collapsed into nodes, intervals of these nodes are + built, and the process is repeated iteratively until we obtain a single + node (if the graph is not irreducible) + ''' + deriv_seq = [graph] + deriv_interv = [] + single_node = False + + while not single_node: + + interv_graph, interv_heads = intervals(graph) + deriv_interv.append(interv_heads) + + single_node = len(interv_graph) == 1 + if not single_node: + deriv_seq.append(interv_graph) + + graph = interv_graph + graph.compute_rpo() + + return deriv_seq, deriv_interv + + +def mark_loop_rec(graph, node, s_num, e_num, interval, nodes_in_loop): + if node in nodes_in_loop: + return + nodes_in_loop.append(node) + for pred in graph.all_preds(node): + if s_num < pred.num <= e_num and pred in interval: + mark_loop_rec(graph, pred, s_num, e_num, interval, nodes_in_loop) + + +def mark_loop(graph, start, end, interval): + logger.debug('MARKLOOP : %s END : %s', start, end) + head = start.get_head() + latch = end.get_end() + nodes_in_loop = [head] + mark_loop_rec(graph, latch, head.num, latch.num, interval, nodes_in_loop) + head.startloop = True + head.latch = latch + return nodes_in_loop + + +def loop_type(start, end, nodes_in_loop): + if end.type.is_cond: + if start.type.is_cond: + if start.true in nodes_in_loop and start.false in nodes_in_loop: + start.looptype.is_posttest = True + else: + start.looptype.is_pretest = True + else: + start.looptype.is_posttest = True + else: + if start.type.is_cond: + if start.true in nodes_in_loop and start.false in nodes_in_loop: + start.looptype.is_endless = True + else: + start.looptype.is_pretest = True + else: + start.looptype.is_endless = True + + +def loop_follow(start, end, nodes_in_loop): + follow = None + if start.looptype.is_pretest: + if start.true in nodes_in_loop: + follow = start.false + else: + follow = start.true + elif start.looptype.is_posttest: + if end.true in nodes_in_loop: + follow = end.false + else: + follow = end.true + else: + num_next = float('inf') + for node in nodes_in_loop: + if node.type.is_cond: + if (node.true.num < num_next + and node.true not in nodes_in_loop): + follow = node.true + num_next = follow.num + elif (node.false.num < num_next + and node.false not in nodes_in_loop): + follow = node.false + num_next = follow.num + start.follow['loop'] = follow + for node in nodes_in_loop: + node.follow['loop'] = follow + logger.debug('Start of loop %s', start) + logger.debug('Follow of loop: %s', start.follow['loop']) + + +def loop_struct(graphs_list, intervals_list): + first_graph = graphs_list[0] + for i, graph in enumerate(graphs_list): + interval = intervals_list[i] + for head in sorted(interval.keys(), key=lambda x: x.num): + loop_nodes = [] + for node in graph.all_preds(head): + if node.interval is head.interval: + lnodes = mark_loop(first_graph, head, node, head.interval) + for lnode in lnodes: + if lnode not in loop_nodes: + loop_nodes.append(lnode) + head.get_head().loop_nodes = loop_nodes + + +def if_struct(graph, idoms): + unresolved = set() + for node in graph.post_order(): + if node.type.is_cond: + ldominates = [] + for n, idom in idoms.iteritems(): + if node is idom and len(graph.reverse_edges.get(n, [])) > 1: + ldominates.append(n) + if len(ldominates) > 0: + n = max(ldominates, key=lambda x: x.num) + node.follow['if'] = n + for x in unresolved.copy(): + if node.num < x.num < n.num: + x.follow['if'] = n + unresolved.remove(x) + else: + unresolved.add(node) + return unresolved + + +def switch_struct(graph, idoms): + unresolved = set() + for node in graph.post_order(): + if node.type.is_switch: + m = node + for suc in graph.sucs(node): + if idoms[suc] is not node: + m = common_dom(idoms, node, suc) + ldominates = [] + for n, dom in idoms.iteritems(): + if m is dom and len(graph.all_preds(n)) > 1: + ldominates.append(n) + if len(ldominates) > 0: + n = max(ldominates, key=lambda x: x.num) + node.follow['switch'] = n + for x in unresolved: + x.follow['switch'] = n + unresolved = set() + else: + unresolved.add(node) + node.order_cases() + + +# TODO: deal with preds which are in catch +def short_circuit_struct(graph, idom, node_map): + def MergeNodes(node1, node2, is_and, is_not): + lpreds = set() + ldests = set() + for node in (node1, node2): + lpreds.update(graph.preds(node)) + ldests.update(graph.sucs(node)) + graph.remove_node(node) + done.add(node) + lpreds.difference_update((node1, node2)) + ldests.difference_update((node1, node2)) + + entry = graph.entry in (node1, node2) + + new_name = '%s+%s' % (node1.name, node2.name) + condition = Condition(node1, node2, is_and, is_not) + + new_node = ShortCircuitBlock(new_name, condition) + for old_n, new_n in node_map.iteritems(): + if new_n in (node1, node2): + node_map[old_n] = new_node + node_map[node1] = new_node + node_map[node2] = new_node + idom[new_node] = idom[node1] + idom.pop(node1) + idom.pop(node2) + new_node.copy_from(node1) + + graph.add_node(new_node) + + for pred in lpreds: + pred.update_attribute_with(node_map) + graph.add_edge(node_map.get(pred, pred), new_node) + for dest in ldests: + graph.add_edge(new_node, node_map.get(dest, dest)) + if entry: + graph.entry = new_node + return new_node + + change = True + while change: + change = False + done = set() + for node in graph.post_order(): + if node.type.is_cond and node not in done: + then = node.true + els = node.false + if node in (then, els): + continue + if then.type.is_cond and len(graph.preds(then)) == 1: + if then.false is els: # node && t + change = True + merged_node = MergeNodes(node, then, True, False) + merged_node.true = then.true + merged_node.false = els + elif then.true is els: # !node || t + change = True + merged_node = MergeNodes(node, then, False, True) + merged_node.true = els + merged_node.false = then.false + elif els.type.is_cond and len(graph.preds(els)) == 1: + if els.false is then: # !node && e + change = True + merged_node = MergeNodes(node, els, True, True) + merged_node.true = els.true + merged_node.false = then + elif els.true is then: # node || e + change = True + merged_node = MergeNodes(node, els, False, False) + merged_node.true = then + merged_node.false = els.false + done.add(node) + if change: + graph.reset_rpo() + + +def while_block_struct(graph, node_map): + change = False + for node in graph.rpo[:]: + if node.startloop: + change = True + new_node = LoopBlock(node.name, node) + node_map[node] = new_node + new_node.copy_from(node) + + entry = node is graph.entry + lpreds = graph.preds(node) + lsuccs = graph.sucs(node) + + for pred in lpreds: + graph.add_edge(node_map.get(pred, pred), new_node) + + for suc in lsuccs: + graph.add_edge(new_node, node_map.get(suc, suc)) + if entry: + graph.entry = new_node + + if node.type.is_cond: + new_node.true = node.true + new_node.false = node.false + + graph.add_node(new_node) + graph.remove_node(node) + + if change: + graph.reset_rpo() + + +def catch_struct(graph, idoms): + block_try_nodes = {} + node_map = {} + for catch_block in graph.reverse_catch_edges: + if catch_block in graph.catch_edges: + continue + catch_node = CatchBlock(catch_block) + + try_block = idoms[catch_block] + try_node = block_try_nodes.get(try_block) + if try_node is None: + block_try_nodes[try_block] = TryBlock(try_block) + try_node = block_try_nodes[try_block] + + node_map[try_block] = try_node + for pred in graph.all_preds(try_block): + pred.update_attribute_with(node_map) + if try_block in graph.sucs(pred): + graph.edges[pred].remove(try_block) + graph.add_edge(pred, try_node) + + if try_block.type.is_stmt: + follow = graph.sucs(try_block) + if follow: + try_node.follow = graph.sucs(try_block)[0] + else: + try_node.follow = None + elif try_block.type.is_cond: + loop_follow = try_block.follow['loop'] + if loop_follow: + try_node.follow = loop_follow + else: + try_node.follow = try_block.follow['if'] + elif try_block.type.is_switch: + try_node.follow = try_block.follow['switch'] + else: # return or throw + try_node.follow = None + + try_node.add_catch_node(catch_node) + for node in graph.nodes: + node.update_attribute_with(node_map) + if graph.entry in node_map: + graph.entry = node_map[graph.entry] + + +def update_dom(idoms, node_map): + for n, dom in idoms.iteritems(): + idoms[n] = node_map.get(dom, dom) + + +def identify_structures(graph, idoms): + Gi, Li = derived_sequence(graph) + switch_struct(graph, idoms) + loop_struct(Gi, Li) + node_map = {} + + short_circuit_struct(graph, idoms, node_map) + update_dom(idoms, node_map) + + if_unresolved = if_struct(graph, idoms) + + while_block_struct(graph, node_map) + update_dom(idoms, node_map) + + loop_starts = [] + for node in graph.rpo: + node.update_attribute_with(node_map) + if node.startloop: + loop_starts.append(node) + for node in loop_starts: + loop_type(node, node.latch, node.loop_nodes) + loop_follow(node, node.latch, node.loop_nodes) + + for node in if_unresolved: + follows = [n for n in (node.follow['loop'], + node.follow['switch']) if n] + if len(follows) >= 1: + follow = min(follows, key=lambda x: x.num) + node.follow['if'] = follow + + catch_struct(graph, idoms) + diff --git a/androguard/decompiler/dad/dataflow.py b/androguard/decompiler/dad/dataflow.py new file mode 100644 index 00000000..89a3f95d --- /dev/null +++ b/androguard/decompiler/dad/dataflow.py @@ -0,0 +1,562 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from collections import defaultdict +from androguard.decompiler.dad.graph import Graph +from androguard.decompiler.dad.instruction import Variable, Param +from androguard.decompiler.dad.util import build_path, common_dom +from androguard.decompiler.dad.node import Node + + +logger = logging.getLogger('dad.control_flow') + + +def dominance_frontier(graph, idoms): + ''' + Create the dominance frontier of each nodes of the graph. + The dominance frontier of a node n is the set of all nodes m such that + n dominates an immediate predecessor of m but does not strictly dominate m. + ''' + DF = {} + for node in graph: + DF[node] = set() + for node in graph: + # Nodes in a DF set must be join points in the graph + preds = graph.preds(node) + if len(preds) > 1: + # We found a join point. Now for each of its predecessor we walk up + # the dominator tree to find a node that dominates it. + # The join point belong to the DF of all the nodes which are on the + # dominator tree walk. + for pred in preds: + runner = pred + while runner != idoms[node]: + DF[runner].add(node) + runner = idoms[runner] + return DF + + +def dom_tree(idoms): + g = Graph() + for node in idoms: + g.add_node(node) + for node, idom in idoms.iteritems(): + if node: + g.add_edge(idom, node) + return g + + +def dom_frontier(graph, idoms): + dtree = dom_tree(idoms) + dtree.entry = graph.entry + DF = {} + for node in dtree.post_order(): + DF[node] = set() + for suc in graph.sucs(node): + if idoms[suc] != node: + DF[node].add(suc) + for child in dtree.sucs(node): + for p in DF[child]: + if idoms[p] != node: + DF[node].add(p) + return DF + + +def phi_placement(graph, DF, lvars, UD, DU): + worklist = [] + inserted = {} + in_worklist = {} + for node in graph: + inserted[node] = None + in_worklist[node] = None + + var_to_loc = defaultdict(list) + for var, loc in UD: + if var in lvars: + var_to_loc[var].append(loc) + + for var, locs in var_to_loc.iteritems(): + for node in set([graph.get_node_from_loc(loc) for loc in locs]): + in_worklist[node] = var + worklist.append(node) + + while worklist: + node = worklist.pop() + for m in DF[node]: + if inserted[m] != var: + pass + + + +class BasicReachDef(object): + def __init__(self, graph, params): + self.g = graph + self.A = defaultdict(set) + self.R = defaultdict(set) + self.DB = defaultdict(set) + self.defs = defaultdict(lambda: defaultdict(set)) + self.def_to_loc = defaultdict(set) + # Deal with special entry node + entry = graph.entry + self.A[entry] = set([-1]) + for param in params: + self.defs[entry][param].add(-1) + self.def_to_loc[param].add(-1) + # Deal with the other nodes + for node in graph.rpo: + for i, ins in node.get_loc_with_ins(): + kill = ins.get_lhs() + if kill is not None: + self.defs[node][kill].add(i) + self.def_to_loc[kill].add(i) + for defs, values in self.defs[node].items(): + self.DB[node].add(max(values)) + + def run(self): + nodes = self.g.rpo[:] + while nodes: + node = nodes.pop(0) + newR = set() + for pred in self.g.all_preds(node): + newR.update(self.A[pred]) + if newR and newR != self.R[node]: + self.R[node] = newR + for suc in self.g.all_sucs(node): + if suc not in nodes: + nodes.append(suc) + + killed_locs = set() + for reg in self.defs[node]: + for loc in self.def_to_loc[reg]: + killed_locs.add(loc) + + A = set() + for loc in self.R[node]: + if loc not in killed_locs: + A.add(loc) + newA = A.union(self.DB[node]) + if newA != self.A[node]: + self.A[node] = newA + for suc in self.g.all_sucs(node): + if suc not in nodes: + nodes.append(suc) + + +def update_chain(graph, loc, du, ud): + ''' + Updates the DU chain of the instruction located at loc such that there is + no more reference to it so that we can remove it. + When an instruction is found to be dead (i.e it has no side effect, and the + register defined is not used) we have to update the DU chain of all the + variables that may me used by the dead instruction. + ''' + ins = graph.get_ins_from_loc(loc) + for var in ins.get_used_vars(): + # We get the definition points of the current variable + for def_loc in set(ud[(var, loc)]): + # We remove the use of the variable at loc from the DU chain of + # the variable definition located at def_loc + du[(var, def_loc)].remove(loc) + ud[(var, loc)].remove(def_loc) + if not ud.get((var, loc)): + ud.pop((var, loc)) + # If the DU chain of the defined variable is now empty, this means + # that we may have created a new dead instruction, so we check that + # the instruction has no side effect and we update the DU chain of + # the new dead instruction, and we delete it. + # We also make sure that def_loc is not -1. This is the case when + # the current variable is a method parameter. + if def_loc >= 0 and not du[(var, def_loc)]: + du.pop((var, def_loc)) + def_ins = graph.get_ins_from_loc(def_loc) + if def_ins.is_call(): + def_ins.remove_defined_var() + elif def_ins.has_side_effect(): + continue + else: + update_chain(graph, def_loc, du, ud) + graph.remove_ins(def_loc) + + +def dead_code_elimination(graph, du, ud): + ''' + Run a dead code elimination pass. + Instructions are checked to be dead. If it is the case, we remove them and + we update the DU & UD chains of its variables to check for further dead + instructions. + ''' + for node in graph.rpo: + for i, ins in node.get_loc_with_ins()[:]: + reg = ins.get_lhs() + if reg is not None: + # If the definition is not used, we check that the instruction + # has no side effect. If there is one and this is a call, we + # remove only the unused defined variable. else, this is + # something like an array access, so we do nothing. + # Otherwise (no side effect) we can remove the instruction from + # the node. + if (reg, i) not in du: + if ins.is_call(): + ins.remove_defined_var() + elif ins.has_side_effect(): + continue + else: + # We can delete the instruction. First update the DU + # chain of the variables used by the instruction to + # `let them know` that they are not used anymore by the + # deleted instruction. + # Then remove the instruction. + update_chain(graph, i, du, ud) + graph.remove_ins(i) + + +def clear_path_node(graph, reg, loc1, loc2): + for loc in xrange(loc1, loc2): + ins = graph.get_ins_from_loc(loc) + logger.debug(' treat loc: %d, ins: %s', loc, ins) + if ins is None: + continue + logger.debug(' LHS: %s, side_effect: %s', ins.get_lhs(), + ins.has_side_effect()) + if ins.get_lhs() == reg or ins.has_side_effect(): + return False + return True + + +def clear_path(graph, reg, loc1, loc2): + ''' + Check that the path from loc1 to loc2 is clear. + We have to check that there is no side effect between the two location + points. We also have to check that the variable `reg` is not redefined + along one of the possible pathes from loc1 to loc2. + ''' + logger.debug('clear_path: reg(%s), loc1(%s), loc2(%s)', reg, loc1, loc2) + node1 = graph.get_node_from_loc(loc1) + node2 = graph.get_node_from_loc(loc2) + # If both instructions are in the same node, we only have to check that the + # path is clear inside the node + if node1 is node2: + return clear_path_node(graph, reg, loc1 + 1, loc2) + + # If instructions are in different nodes, we also have to check the nodes + # in the path between the two locations. + if not clear_path_node(graph, reg, loc1 + 1, node1.ins_range[1]): + return False + path = build_path(graph, node1, node2) + for node in path: + locs = node.ins_range + end_loc = loc2 if (locs[0] <= loc2 <= locs[1]) else locs[1] + if not clear_path_node(graph, reg, locs[0], end_loc): + return False + return True + + +def register_propagation(graph, du, ud): + ''' + Propagate the temporary registers between instructions and remove them if + necessary. + We process the nodes of the graph in reverse post order. For each + instruction in the node, we look at the variables that it uses. For each of + these variables we look where it is defined and if we can replace it with + its definition. + We have to be careful to the side effects some instructions may have. + To do the propagation, we use the computed DU and UD chains. + ''' + change = True + while change: + change = False + for node in graph.rpo: + for i, ins in node.get_loc_with_ins()[:]: + logger.debug('Treating instruction %d: %s', i, ins) + # We make sure the ins has not been deleted since the start of + # the iteration + if ins not in node.get_ins(): + logger.debug(' => skip instruction (deleted)') + continue + logger.debug(' Used vars: %s', ins.get_used_vars()) + for var in ins.get_used_vars(): + # Get the list of locations this variable is defined at. + locs = ud[(var, i)] + logger.debug(' var %s defined in lines %s', var, locs) + # If the variable is uniquely defined for this instruction + # it may be eligible for propagation. + if len(locs) != 1: + continue + + loc = locs[0] + # Methods parameters are defined with a location of -1. + if loc == -1: + continue + orig_ins = graph.get_ins_from_loc(loc) + logger.debug(' -> %s', orig_ins) + + logger.debug(' -> DU(%s, %s) = %s', var, loc, + du[(var, loc)]) + + # We defined some instructions as not propagable. + # Actually this is the case only for array creation + # (new foo[x]) + if not orig_ins.is_propagable(): + logger.debug(' %s not propagable...', orig_ins) + continue + + # We only try to propagate constants and definition + # points which are used at only one location. + if len(du[(var, loc)]) > 1: + if not orig_ins.get_rhs().is_const(): + logger.debug(' => variable has multiple uses' + ' and is not const => skip') + continue + + # We check that the propagation is safe for all the + # variables that are used in the instruction. + # The propagation is not safe if there is a side effect + # along the path from the definition of the variable + # to its use in the instruction, or if the variable may + # be redifined along this path. + safe = True + orig_ins_used_vars = orig_ins.get_used_vars() + logger.debug(' variables used by the original ' + 'instruction: %s', orig_ins_used_vars) + for var2 in orig_ins_used_vars: + # loc is the location of the defined variable + # i is the location of the current instruction + if not clear_path(graph, var2, loc, i): + safe = False + break + if not safe: + logger.debug('Propagation NOT SAFE') + continue + + # We also check that the instruction itself is + # propagable. If the instruction has a side effect it + # cannot be propagated if there is another side effect + # along the path + if orig_ins.has_side_effect(): + if not clear_path(graph, None, loc, i): + logger.debug(' %s has side effect and the ' + 'path is not clear !', orig_ins) + continue + + logger.debug(' => Modification of the instruction!') + logger.debug(' - BEFORE: %s', ins) + ins.replace(var, orig_ins.get_rhs()) + logger.debug(' -> AFTER: %s', ins) + logger.debug('\t UD(%s, %s) : %s', var, i, ud[(var, i)]) + ud[(var, i)].remove(loc) + logger.debug('\t -> %s', ud[(var, i)]) + if len(ud[(var, i)]) == 0: + ud.pop((var, i)) + for var2 in orig_ins.get_used_vars(): + # We update the UD chain of the variables we + # propagate. We also have to take the + # definition points of all the variables used + # by the instruction and update the DU chain + # with this information. + old_ud = ud.get((var2, loc)) + logger.debug('\t ud(%s, %s) = %s', var2, loc, old_ud) + # If the instruction use the same variable + # multiple times, the second+ time the ud chain + # will be None because already treated. + if old_ud is None: + continue + ud[(var2, i)].extend(old_ud) + logger.debug('\t - ud(%s, %s) = %s', var2, i, + ud[(var2, i)]) + ud.pop((var2, loc)) + + for def_loc in old_ud: + du[(var2, def_loc)].remove(loc) + du[(var2, def_loc)].append(i) + + new_du = du[(var, loc)] + logger.debug('\t new_du(%s, %s): %s', var, loc, new_du) + new_du.remove(i) + logger.debug('\t -> %s', new_du) + if not new_du: + logger.debug('\t REMOVING INS %d', loc) + du.pop((var, loc)) + graph.remove_ins(loc) + change = True + + +class DummyNode(Node): + def __init__(self, name): + super(DummyNode, self).__init__(name) + + def get_loc_with_ins(self): + return [] + + def __repr__(self): + return '%s-dumnode' % self.name + + def __str__(self): + return '%s-dummynode' % self.name + + +def split_variables(graph, lvars, DU, UD): + treated = defaultdict(list) + variables = defaultdict(list) + for var, loc in sorted(DU): + if var not in lvars: + continue + if loc in treated[var]: + continue + defs = [loc] + uses = set(DU[(var, loc)]) + change = True + while change: + change = False + for use in uses: + ldefs = UD[(var, use)] + for ldef in ldefs: + if ldef not in defs: + defs.append(ldef) + change = True + for ldef in defs[1:]: + luses = set(DU[(var, ldef)]) + for use in luses: + if use not in uses: + uses.add(use) + change = True + treated[var].extend(defs) + variables[var].append((defs, list(uses))) + + if lvars: + nb_vars = max(lvars) + 1 + else: + nb_vars = 0 + for var, versions in variables.iteritems(): + nversions = len(versions) + if nversions == 1: + continue + orig_var = lvars.pop(var) + for i, (defs, uses) in enumerate(versions): + if -1 in defs: # Param + new_version = Param(var, orig_var.type) + lvars[var] = new_version + else: + new_version = Variable(nb_vars) + new_version.type = orig_var.type + lvars[nb_vars] = new_version # add new version to variables + nb_vars += 1 + new_version.name = '%d_%d' % (var, i) + + for loc in defs: + if loc == -1: + continue + ins = graph.get_ins_from_loc(loc) + ins.replace_lhs(new_version) + for loc in uses: + ins = graph.get_ins_from_loc(loc) + ins.replace_var(var, new_version) + + +def build_def_use(graph, lparams): + ''' + Builds the Def-Use and Use-Def (DU/UD) chains of the variables of the + method. + ''' + # We insert two special nodes : entry & exit, to the graph. + # This is done to simplify the reaching definition analysis. + old_entry = graph.entry + old_exit = graph.exit + new_entry = DummyNode('entry') + graph.add_node(new_entry) + graph.add_edge(new_entry, old_entry) + graph.entry = new_entry + if old_exit: + new_exit = DummyNode('exit') + graph.add_node(new_exit) + graph.add_edge(old_exit, new_exit) + graph.rpo.append(new_exit) + + analysis = BasicReachDef(graph, set(lparams)) + analysis.run() + + # The analysis is done, We can now remove the two special nodes. + graph.remove_node(new_entry) + if old_exit: + graph.remove_node(new_exit) + graph.entry = old_entry + + UD = defaultdict(list) + for node in graph.rpo: + for i, ins in node.get_loc_with_ins(): + for var in ins.get_used_vars(): + # var not in analysis.def_to_loc: test that the register + # exists. It is possible that it is not the case, when a + # variable is of a type which is stored on multiple registers + # e.g: a 'double' stored in v3 is also present in v4, so a call + # to foo(v3), will in fact call foo(v3, v4). + if var not in analysis.def_to_loc: + continue + ldefs = analysis.defs[node] + prior_def = -1 + for v in ldefs.get(var, set()): + if prior_def < v < i: + prior_def = v + if prior_def >= 0: + UD[(var, i)].append(prior_def) + else: + intersect = analysis.def_to_loc[var].intersection( + analysis.R[node]) + UD[(var, i)].extend(intersect) + DU = defaultdict(list) + for var_loc, defs_loc in UD.items(): + var, loc = var_loc + # FIXME: should not have to add this + if not defs_loc: + DU[(var, -1)].append(loc) + for def_loc in defs_loc: + DU[(var, def_loc)].append(loc) + + return UD, DU + + +def place_declarations(graph, dvars, du, ud): + idom = graph.immediate_dominators() + for node in graph.rpo: + for loc, ins in node.get_loc_with_ins(): + used_vars = ins.get_used_vars() + for var in used_vars: + if (not isinstance(dvars[var], Variable) + or isinstance(dvars[var], Param)): + continue + var_defs_locs = ud[(var, loc)] + # FIXME: this should not happen. + if var_defs_locs is None: + continue + def_nodes = set() + for def_loc in var_defs_locs: + def_node = graph.get_node_from_loc(def_loc) + # TODO: place declarations in catch if needed + if def_node.in_catch: + continue + def_nodes.add(def_node) + if not def_nodes: + continue + common_dominator = def_nodes.pop() + for def_node in def_nodes: + common_dominator = common_dom( + idom,common_dominator, def_node) + if any(var in range(*common_dominator.ins_range) + for var in ud[(var, loc)]): + continue + common_dominator.add_variable_declaration(dvars[var]) + diff --git a/androguard/decompiler/dad/decompile.py b/androguard/decompiler/dad/decompile.py new file mode 100644 index 00000000..cc13e419 --- /dev/null +++ b/androguard/decompiler/dad/decompile.py @@ -0,0 +1,346 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +sys.path.append('./') + +import logging +from collections import defaultdict +import androguard.core.androconf as androconf +import androguard.decompiler.dad.util as util +from androguard.core.analysis import analysis +from androguard.core.bytecodes import apk, dvm +from androguard.decompiler.dad.control_flow import identify_structures +from androguard.decompiler.dad.dataflow import (build_def_use, + place_declarations, + dead_code_elimination, + register_propagation, + phi_placement, + split_variables) +from androguard.decompiler.dad.graph import construct +from androguard.decompiler.dad.instruction import Param, ThisParam +from androguard.decompiler.dad.writer import Writer + + +def auto_vm(filename): + ret = androconf.is_android(filename) + if ret == 'APK': + return dvm.DalvikVMFormat(apk.APK(filename).get_dex()) + elif ret == 'DEX': + return dvm.DalvikVMFormat(open(filename, 'rb').read()) + elif ret == 'ODEX': + return dvm.DalvikOdexVMFormat(open(filename, 'rb').read()) + return None + + +class DvMethod(): + def __init__(self, methanalysis): + method = methanalysis.get_method() + self.start_block = next(methanalysis.get_basic_blocks().get(), None) + self.cls_name = method.get_class_name() + self.name = method.get_name() + self.lparams = [] + self.var_to_name = defaultdict() + self.writer = None + self.graph = None + + access = method.get_access_flags() + self.access = [name for flag, name in + util.ACCESS_FLAGS_METHODS.iteritems() if flag & access] + desc = method.get_descriptor() + self.type = desc.split(')')[-1] + self.params_type = util.get_params_type(desc) + + self.exceptions = methanalysis.exceptions.exceptions + + code = method.get_code() + if code is None: + logger.debug('No code : %s %s', self.name, self.cls_name) + else: + start = code.registers_size - code.ins_size + if 'static' not in self.access: + self.var_to_name[start] = ThisParam(start, self.name) + self.lparams.append(start) + start += 1 + num_param = 0 + for ptype in self.params_type: + param = start + num_param + self.lparams.append(param) + self.var_to_name[param] = Param(param, ptype) + num_param += util.get_type_size(ptype) + if not __debug__: + from androguard.core import bytecode + bytecode.method2png('/tmp/dad/graphs/%s#%s.png' % \ + (self.cls_name.split('/')[-1][:-1], self.name), methanalysis) + + def process(self): + logger.debug('METHOD : %s', self.name) + + # Native methods... no blocks. + if self.start_block is None: + logger.debug('Native Method.') + self.writer = Writer(None, self) + self.writer.write_method() + return + + graph = construct(self.start_block, self.var_to_name, self.exceptions) + self.graph = graph + + if not __debug__: + util.create_png(self.cls_name, self.name, graph, '/tmp/dad/blocks') + + #idoms = graph.immediate_dominators() + #DF = dominance_frontier(graph, idoms) + use_defs, def_uses = build_def_use(graph, self.lparams) + #phi_placement(graph, DF, self.var_to_name, use_defs, def_uses) + split_variables(graph, self.var_to_name, def_uses, use_defs) + # TODO: split_variables should update DU/UD + use_defs, def_uses = build_def_use(graph, self.lparams) + + dead_code_elimination(graph, def_uses, use_defs) + register_propagation(graph, def_uses, use_defs) + + place_declarations(graph, self.var_to_name, def_uses, use_defs) + del def_uses, use_defs + # After the DCE pass, some nodes may be empty, so we can simplify the + # graph to delete these nodes. + # We start by restructuring the graph by spliting the conditional nodes + # into a pre-header and a header part. + graph.split_if_nodes() + # We then simplify the graph by merging multiple statement nodes into + # a single statement node when possible. This also delete empty nodes. + + graph.simplify() + graph.reset_rpo() + + identify_structures(graph, graph.immediate_dominators()) + + if not __debug__: + util.create_png(self.cls_name, self.name, graph, + '/tmp/dad/structured') + + self.writer = Writer(graph, self) + self.writer.write_method() + del graph + + def show_source(self): + print self.get_source() + + def get_source(self): + if self.writer: + return '%s' % self.writer + return '' + + def __repr__(self): + return 'Method %s' % self.name + + +class DvClass(): + def __init__(self, dvclass, vma): + name = dvclass.get_name() + if name.find('/') > 0: + pckg, name = name.rsplit('/', 1) + else: + pckg, name = '', name + self.package = pckg[1:].replace('/', '.') + self.name = name[:-1] + + self.vma = vma + self.methods = dict((meth.get_method_idx(), meth) + for meth in dvclass.get_methods()) + self.fields = dict((field.get_name(), field) + for field in dvclass.get_fields()) + self.subclasses = {} + self.code = [] + self.inner = False + + access = dvclass.get_access_flags() + self.access = [util.ACCESS_FLAGS_CLASSES[flag] for flag in + util.ACCESS_FLAGS_CLASSES if flag & access] + self.prototype = '%s class %s' % (' '.join(self.access), self.name) + + self.interfaces = dvclass.interfaces + self.superclass = dvclass.get_superclassname() + + logger.info('Class : %s', self.name) + logger.info('Methods added :') + for index, meth in self.methods.iteritems(): + logger.info('%s (%s, %s)', index, self.name, meth.name) + logger.info('') + + def add_subclass(self, innername, dvclass): + self.subclasses[innername] = dvclass + dvclass.inner = True + + def get_methods(self): + return self.methods + + def process_method(self, num): + methods = self.methods + if num in methods: + method = methods[num] + if not isinstance(method, DvMethod): + method.set_instructions([i for i in method.get_instructions()]) + meth = methods[num] = DvMethod(self.vma.get_method(method)) + meth.process() + method.set_instructions([]) + else: + method.process() + else: + logger.error('Method %s not found.', num) + + def process(self): + for klass in self.subclasses.values(): + klass.process() + for meth in self.methods: + self.process_method(meth) + + def get_source(self): + source = [] + if not self.inner and self.package: + source.append('package %s;\n' % self.package) + + if self.superclass is not None: + self.superclass = self.superclass[1:-1].replace('/', '.') + if self.superclass.split('.')[-1] == 'Object': + self.superclass = None + if self.superclass is not None: + self.prototype += ' extends %s' % self.superclass + if self.interfaces is not None: + interfaces = self.interfaces[1:-1].split(' ') + self.prototype += ' implements %s' % ', '.join( + [n[1:-1].replace('/', '.') for n in interfaces]) + + source.append('%s {\n' % self.prototype) + for field in self.fields.values(): + field_access_flags = field.get_access_flags() + access = [util.ACCESS_FLAGS_FIELDS[flag] for flag in + util.ACCESS_FLAGS_FIELDS if flag & field_access_flags] + f_type = util.get_type(field.get_descriptor()) + name = field.get_name() + source.append(' %s %s %s;\n' % (' '.join(access), f_type, name)) + + for klass in self.subclasses.values(): + source.append(klass.get_source()) + + for _, method in self.methods.iteritems(): + if isinstance(method, DvMethod): + source.append(method.get_source()) + source.append('}\n') + return ''.join(source) + + def show_source(self): + print self.get_source() + + def __repr__(self): + if not self.subclasses: + return 'Class(%s)' % self.name + return 'Class(%s) -- Subclasses(%s)' % (self.name, self.subclasses) + + +class DvMachine(): + def __init__(self, name): + vm = auto_vm(name) + if vm is None: + raise ValueError('Format not recognised: %s' % name) + self.vma = analysis.uVMAnalysis(vm) + self.classes = dict((dvclass.get_name(), dvclass) + for dvclass in vm.get_classes()) + #util.merge_inner(self.classes) + + def get_classes(self): + return self.classes.keys() + + def get_class(self, class_name): + for name, klass in self.classes.iteritems(): + if class_name in name: + if isinstance(klass, DvClass): + return klass + dvclass = self.classes[name] = DvClass(klass, self.vma) + return dvclass + + def process(self): + for name, klass in self.classes.iteritems(): + logger.info('Processing class: %s', name) + if isinstance(klass, DvClass): + klass.process() + else: + dvclass = self.classes[name] = DvClass(klass, self.vma) + dvclass.process() + + def show_source(self): + for klass in self.classes.values(): + klass.show_source() + + def process_and_show(self): + for name, klass in sorted(self.classes.iteritems()): + logger.info('Processing class: %s', name) + if not isinstance(klass, DvClass): + klass = DvClass(klass, self.vma) + klass.process() + klass.show_source() + + +logger = logging.getLogger('dad') +sys.setrecursionlimit(5000) + + +def main(): + # logger.setLevel(logging.DEBUG) for debugging output + # comment the line to disable the logging. + logger.setLevel(logging.INFO) + console_hdlr = logging.StreamHandler(sys.stdout) + console_hdlr.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + logger.addHandler(console_hdlr) + + default_file = 'examples/android/TestsAndroguard/bin/TestActivity.apk' + if len(sys.argv) > 1: + machine = DvMachine(sys.argv[1]) + else: + machine = DvMachine(default_file) + + logger.info('========================') + logger.info('Classes:') + for class_name in sorted(machine.get_classes()): + logger.info(' %s', class_name) + logger.info('========================') + + cls_name = raw_input('Choose a class: ') + if cls_name == '*': + machine.process_and_show() + else: + cls = machine.get_class(cls_name) + if cls is None: + logger.error('%s not found.', cls_name) + else: + logger.info('======================') + for method_id, method in cls.get_methods().items(): + logger.info('%d: %s', method_id, method.name) + logger.info('======================') + meth = raw_input('Method: ') + if meth == '*': + logger.info('CLASS = %s', cls) + cls.process() + else: + cls.process_method(int(meth)) + logger.info('Source:') + logger.info('===========================') + cls.show_source() + +if __name__ == '__main__': + main() + diff --git a/androguard/decompiler/dad/graph.py b/androguard/decompiler/dad/graph.py new file mode 100644 index 00000000..6668a9cf --- /dev/null +++ b/androguard/decompiler/dad/graph.py @@ -0,0 +1,453 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from collections import defaultdict +from androguard.decompiler.dad.basic_blocks import (build_node_from_block, + StatementBlock, CondBlock) +from androguard.decompiler.dad.instruction import Variable +from androguard.decompiler.dad.util import common_dom + + +logger = logging.getLogger('dad.graph') + + +class Graph(): + def __init__(self): + self.entry = None + self.exit = None + self.nodes = list() + self.rpo = [] + self.edges = defaultdict(list) + self.catch_edges = defaultdict(list) + self.reverse_edges = defaultdict(list) + self.reverse_catch_edges = defaultdict(list) + self.loc_to_ins = None + self.loc_to_node = None + + def sucs(self, node): + return self.edges.get(node, []) + + def all_sucs(self, node): + return self.edges.get(node, []) + self.catch_edges.get(node, []) + + def preds(self, node): + return [n for n in self.reverse_edges.get(node, []) + if not n.in_catch] + + def all_preds(self, node): + return (self.reverse_edges.get(node, []) + + self.reverse_catch_edges.get(node, [])) + + def add_node(self, node): + self.nodes.append(node) + + def add_edge(self, e1, e2): + lsucs = self.edges[e1] + if e2 not in lsucs: + lsucs.append(e2) + lpreds = self.reverse_edges[e2] + if e1 not in lpreds: + lpreds.append(e1) + + def add_catch_edge(self, e1, e2): + lsucs = self.catch_edges[e1] + if e2 not in lsucs: + lsucs.append(e2) + lpreds = self.reverse_catch_edges[e2] + if e1 not in lpreds: + lpreds.append(e1) + + def remove_node(self, node): + preds = self.reverse_edges.pop(node, []) + for pred in preds: + self.edges[pred].remove(node) + + succs = self.edges.pop(node, []) + for suc in succs: + self.reverse_edges[suc].remove(node) + + exc_preds = self.reverse_catch_edges.pop(node, []) + for pred in exc_preds: + self.catch_edges[pred].remove(node) + + exc_succs = self.catch_edges.pop(node, []) + for suc in exc_succs: + self.reverse_catch_edges[suc].remove(node) + + self.nodes.remove(node) + if node in self.rpo: + self.rpo.remove(node) + del node + + def number_ins(self): + self.loc_to_ins = {} + self.loc_to_node = {} + num = 0 + for node in self.rpo: + start_node = num + num = node.number_ins(num) + end_node = num - 1 + self.loc_to_ins.update(node.get_loc_with_ins()) + self.loc_to_node[(start_node, end_node)] = node + + def get_ins_from_loc(self, loc): + return self.loc_to_ins.get(loc) + + def get_node_from_loc(self, loc): + for (start, end), node in self.loc_to_node.iteritems(): + if start <= loc <= end: + return node + + def remove_ins(self, loc): + ins = self.get_ins_from_loc(loc) + self.get_node_from_loc(loc).remove_ins(loc, ins) + self.loc_to_ins.pop(loc) + + def split_if_nodes(self): + ''' + Split IfNodes in two nodes, the first node is the header node, the + second one is only composed of the jump condition. + ''' + node_map = {} + to_update = set() + for node in self.nodes[:]: + if node.type.is_cond: + if len(node.get_ins()) > 1: + pre_ins = node.get_ins()[:-1] + last_ins = node.get_ins()[-1] + pre_node = StatementBlock('%s-pre' % node.name, pre_ins) + cond_node = CondBlock('%s-cond' % node.name, [last_ins]) + node_map[node] = pre_node + + pre_node.copy_from(node) + cond_node.copy_from(node) + for var in node.var_to_declare: + pre_node.add_variable_declaration(var) + pre_node.type.is_stmt = True + cond_node.true = node.true + cond_node.false = node.false + + for pred in self.all_preds(node): + pred_node = node_map.get(pred, pred) + # Verify that the link is not an exception link + if node not in self.sucs(pred): + self.add_catch_edge(pred_node, pre_node) + continue + if pred is node: + pred_node = cond_node + if pred.type.is_cond: # and not (pred is node): + if pred.true is node: + pred_node.true = pre_node + if pred.false is node: + pred_node.false = pre_node + self.add_edge(pred_node, pre_node) + for suc in self.sucs(node): + self.add_edge(cond_node, node_map.get(suc, suc)) + + # We link all the exceptions to the pre node instead of the + # condition node, which should not trigger any of them. + for suc in self.catch_edges.get(node, []): + self.add_catch_edge(pre_node, node_map.get(suc, suc)) + + if node is self.entry: + self.entry = pre_node + + self.add_node(pre_node) + self.add_node(cond_node) + self.add_edge(pre_node, cond_node) + pre_node.update_attribute_with(node_map) + cond_node.update_attribute_with(node_map) + self.remove_node(node) + else: + to_update.add(node) + for node in to_update: + node.update_attribute_with(node_map) + + def simplify(self): + ''' + Simplify the CFG by merging/deleting statement nodes when possible: + If statement B follows statement A and if B has no other predecessor + besides A, then we can merge A and B into a new statement node. + We also remove nodes which do nothing except redirecting the control + flow (nodes which only contains a goto). + ''' + redo = True + while redo: + redo = False + node_map = {} + to_update = set() + for node in self.nodes[:]: + if node.type.is_stmt and node in self.nodes: + sucs = self.all_sucs(node) + if len(sucs) == 0 or len(sucs) > 1: + continue + suc = sucs[0] + if len(node.get_ins()) == 0: + if any(pred.type.is_switch + for pred in self.all_preds(node)): + continue + suc = self.edges.get(node)[0] + if node is suc: + continue + node_map[node] = suc + + add_edge = self.add_edge + if node.in_catch: + add_edge = self.add_catch_edge + for pred in self.all_preds(node): + pred.update_attribute_with(node_map) + if node not in self.sucs(pred): + self.add_catch_edge(pred, suc) + continue + self.add_edge(pred, suc) + redo = True + if node is self.entry: + self.entry = suc + self.remove_node(node) + elif (suc.type.is_stmt and + len(self.all_preds(suc)) == 1 and + not (suc in self.catch_edges) and + not ((node is suc) or (suc is self.entry))): + ins_to_merge = suc.get_ins() + node.add_ins(ins_to_merge) + for var in suc.var_to_declare: + node.add_variable_declaration(var) + new_suc = self.sucs(suc)[0] + if new_suc: + self.add_edge(node, new_suc) + for exception_suc in self.catch_edges.get(suc, []): + self.add_catch_edge(node, exception_suc) + redo = True + self.remove_node(suc) + else: + to_update.add(node) + for node in to_update: + node.update_attribute_with(node_map) + + + def _traverse(self, node, visit, res): + if node in visit: + return + visit.add(node) + for suc in self.all_sucs(node): + self._traverse(suc, visit, res) + res.insert(0, node) + + def compute_rpo(self): + ''' + Number the nodes in reverse post order. + An RPO traversal visit as many predecessors of a node as possible + before visiting the node itself. + ''' + visit = set() + res = [] + self._traverse(self.entry, visit, res) + for i, n in enumerate(res, 1): + n.num = i + self.rpo.append(n) + + def reset_rpo(self): + self.rpo = [] + self.compute_rpo() + + def post_order(self, start=None, visited=None, res=None): + ''' + Return the nodes of the graph in post-order i.e we visit all the + children of a node before visiting the node itself. + ''' + if visited is None: + res = [] + visited = set() + start = self.entry + visited.add(start) + for suc in self.all_sucs(start): + if not suc in visited: + self.post_order(suc, visited, res) + res.append(start) + return res + + def draw(self, name, dname, draw_branches=True): + from pydot import Dot, Edge + g = Dot() + g.set_node_defaults(color='lightgray', style='filled', shape='box', + fontname='Courier', fontsize='10') + for node in sorted(self.nodes, key=lambda x: x.num): + if draw_branches and node.type.is_cond: + g.add_edge(Edge(str(node), str(node.true), color='green')) + g.add_edge(Edge(str(node), str(node.false), color='red')) + else: + for suc in self.sucs(node): + g.add_edge(Edge(str(node), str(suc), color='blue')) + for except_node in self.catch_edges.get(node, []): + g.add_edge(Edge(str(node), str(except_node), + color='black', style='dashed')) + + g.write_png('%s/%s.png' % (dname, name)) + + def immediate_dominators(self): + ''' + Create a mapping of the nodes of a graph with their corresponding + immediate dominator + ''' + idom = dict((n, None) for n in self.nodes) + for node in self.rpo: + if node.in_catch: + predecessor = self.all_preds + else: + predecessor = self.preds + for pred in predecessor(node): + if pred.num < node.num: + idom[node] = common_dom(idom, idom[node], pred) + return idom + + def __len__(self): + return len(self.nodes) + + def __repr__(self): + return str(self.nodes) + + def __iter__(self): + for node in self.nodes: + yield node + + +def bfs(start): + to_visit = [start] + visited = set([start]) + while to_visit: + node = to_visit.pop(0) + yield node + if node.exception_analysis: + for _, _, exception in node.exception_analysis.exceptions: + if exception not in visited: + to_visit.append(exception) + visited.add(exception) + for _, _, child in node.childs: + if child not in visited: + to_visit.append(child) + visited.add(child) + + +class GenInvokeRetName(object): + def __init__(self): + self.num = 0 + self.ret = None + + def new(self): + self.num += 1 + self.ret = Variable('tmp%d' % self.num) + return self.ret + + def set_to(self, ret): + self.ret = ret + + def last(self): + return self.ret + + +def make_node(graph, block, block_to_node, vmap, gen_ret): + node = block_to_node.get(block) + if node is None: + node = build_node_from_block(block, vmap, gen_ret) + block_to_node[block] = node + if block.exception_analysis: + for _type, _, exception_target in block.exception_analysis.exceptions: + exception_node = block_to_node.get(exception_target) + if exception_node is None: + exception_node = build_node_from_block(exception_target, + vmap, gen_ret, _type) + exception_node.in_catch = True + block_to_node[exception_target] = exception_node + graph.add_catch_edge(node, exception_node) + for _, _, child_block in block.childs: + child_node = block_to_node.get(child_block) + if child_node is None: + child_node = build_node_from_block(child_block, vmap, gen_ret) + block_to_node[child_block] = child_node + graph.add_edge(node, child_node) + if node.type.is_switch: + node.add_case(child_node) + if node.type.is_cond: + if_target = ((block.end / 2) - (block.last_length / 2) + + node.off_last_ins) + child_addr = child_block.start / 2 + if if_target == child_addr: + node.true = child_node + else: + node.false = child_node + + # Check that both branch of the if point to something + # It may happen that both branch point to the same node, in this case + # the false branch will be None. So we set it to the right node. + # TODO: In this situation, we should transform the condition node into + # a statement node + if node.type.is_cond and node.false is None: + node.false = node.true + + return node + + +def construct(start_block, vmap, exceptions): + bfs_blocks = bfs(start_block) + + graph = Graph() + gen_ret = GenInvokeRetName() + + # Construction of a mapping of basic blocks into Nodes + block_to_node = {} + + exceptions_start_block = [] + for exception in exceptions: + for _, _, block in exception.exceptions: + exceptions_start_block.append(block) + + for block in bfs_blocks: + node = make_node(graph, block, block_to_node, vmap, gen_ret) + graph.add_node(node) + + graph.entry = block_to_node[start_block] + del block_to_node, bfs_blocks + + graph.compute_rpo() + graph.number_ins() + + for node in graph.rpo: + preds = [pred for pred in graph.all_preds(node) + if pred.num < node.num] + if preds and all(pred.in_catch for pred in preds): + node.in_catch = True + + # Create a list of Node which are 'return' node + # There should be one and only one node of this type + # If this is not the case, try to continue anyway by setting the exit node + # to the one which has the greatest RPO number (not necessarily the case) + lexit_nodes = [node for node in graph if node.type.is_return] + + if len(lexit_nodes) > 1: + # Not sure that this case is possible... + logger.error('Multiple exit nodes found !') + graph.exit = graph.rpo[-1] + elif len(lexit_nodes) < 1: + # A method can have no return if it has throw statement(s) or if its + # body is a while(1) whitout break/return. + logger.debug('No exit node found !') + else: + graph.exit = lexit_nodes[0] + + return graph + diff --git a/androguard/decompiler/dad/instruction.py b/androguard/decompiler/dad/instruction.py new file mode 100644 index 00000000..2c0f97a4 --- /dev/null +++ b/androguard/decompiler/dad/instruction.py @@ -0,0 +1,1338 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Geoffroy Gueguen +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class IRForm(object): + def __init__(self): + self.var_map = {} + self.type = None + + def is_call(self): + return False + + def is_cond(self): + return False + + def is_const(self): + return False + + def is_ident(self): + return False + + def is_propagable(self): + return True + + def get_type(self): + return self.type + + def set_type(self, _type): + self.type = _type + + def has_side_effect(self): + return False + + def get_used_vars(self): + return [] + + def replace(self, old, new): + raise NotImplementedError('replace not implemented in %r' % self) + + def replace_lhs(self, new): + raise NotImplementedError('replace_lhs not implemented in %r' % self) + + def replace_var(self, old, new): + raise NotImplementedError('replace_var not implemented in %r' % self) + + def remove_defined_var(self): + pass + + def get_rhs(self): + return [] + + def get_lhs(self): + return None + + def visit(self, visitor): + pass + + +class Constant(IRForm): + def __init__(self, value, atype, int_value=None): + self.v = 'c%s' % value + self.cst = value + if int_value is None: + self.cst2 = value + else: + self.cst2 = int_value + self.type = atype + + def get_used_vars(self): + return [] + + def is_call(self): + return False + + def is_const(self): + return True + + def get_int_value(self): + return self.cst2 + + def get_type(self): + return self.type + + def visit(self, visitor, to_int=False): + if self.type == 'Z': + if self.cst == 0: + return visitor.visit_constant('false') + else: + return visitor.visit_constant('true') + elif self.type == 'class': + return visitor.visit_base_class(self.cst) + elif to_int: + return visitor.visit_constant(self.cst2) + else: + return visitor.visit_constant(self.cst) + + def __str__(self): + return 'CST_%s' % repr(self.cst) + + +class BaseClass(IRForm): + def __init__(self, name): + self.v = 'c%s' % name + self.cls = name + + def is_const(self): + return True + + def visit(self, visitor): + return visitor.visit_base_class(self.cls) + + def __str__(self): + return 'BASECLASS_%s' % self.cls + + +class Variable(IRForm): + def __init__(self, value): + self.v = value + self.declared = False + self.type = None + self.name = value + + def get_used_vars(self): + return [self.v] + + def is_call(self): + return False + + def is_ident(self): + return True + + def value(self): + return self.v + + def visit(self, visitor): + return visitor.visit_variable(self) + + def visit_decl(self, visitor): + return visitor.visit_decl(self) + + def __str__(self): + return 'VAR_%s' % self.name + + +class Param(Variable): + def __init__(self, value, atype): + super(Param, self).__init__(value) + self.declared = True + self.type = atype + + def visit(self, visitor): + return visitor.visit_param(self.v) + + def __str__(self): + return 'PARAM_%s' % self.name + + +class ThisParam(Param): + def __init__(self, value, atype): + super(ThisParam, self).__init__(value, atype) + + def is_const(self): + return True + + def get_used_vars(self): + return [] + + def visit(self, visitor): + return visitor.visit_this() + + def __str__(self): + return 'THIS' + + +class AssignExpression(IRForm): + def __init__(self, lhs, rhs): + super(AssignExpression, self).__init__() + self.lhs = lhs.v + self.rhs = rhs + self.var_map[lhs.v] = lhs + lhs.set_type(rhs.get_type()) + + def is_propagable(self): + return self.rhs.is_propagable() + + def is_call(self): + return self.rhs.is_call() + + def has_side_effect(self): + return self.rhs.has_side_effect() + + def get_rhs(self): + return self.rhs + + def get_lhs(self): + return self.lhs + + def get_used_vars(self): + return self.rhs.get_used_vars() + + def remove_defined_var(self): + self.lhs = None + + def replace(self, old, new): + self.rhs.replace(old, new) + + def replace_lhs(self, new): + self.var_map.pop(self.lhs) + self.lhs = new.v + self.var_map[new.v] = new + + def replace_var(self, old, new): + self.rhs.replace_var(old, new) + + def visit(self, visitor): + return visitor.visit_assign(self.var_map.get(self.lhs), self.rhs) + + def __str__(self): + return 'ASSIGN(%s, %s)' % (self.var_map.get(self.lhs), self.rhs) + + +class MoveExpression(IRForm): + def __init__(self, lhs, rhs): + super(MoveExpression, self).__init__() + self.lhs = lhs.v + self.rhs = rhs.v + self.var_map.update([(lhs.v, lhs), (rhs.v, rhs)]) + lhs.set_type(rhs.get_type()) + + def has_side_effect(self): + return False + + def is_call(self): + return self.var_map[self.rhs].is_call() + + def get_used_vars(self): + return self.var_map[self.rhs].get_used_vars() + + def get_rhs(self): + return self.var_map[self.rhs] + + def get_lhs(self): + return self.lhs + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_move(v_m[self.lhs], v_m[self.rhs]) + + def replace(self, old, new): + v_m = self.var_map + rhs = v_m[self.rhs] + if not (rhs.is_const() or rhs.is_ident()): + rhs.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.rhs = new.value() + else: + v_m[old] = new + + def replace_lhs(self, new): + self.var_map.pop(self.lhs) + self.lhs = new.v + self.var_map[new.v] = new + + def replace_var(self, old, new): + self.var_map.pop(self.rhs) + self.rhs = new.v + self.var_map[new.v] = new + + def __str__(self): + v_m = self.var_map + return '%s = %s' % (v_m.get(self.lhs), v_m.get(self.rhs)) + + +class MoveResultExpression(MoveExpression): + def __init__(self, lhs, rhs): + super(MoveResultExpression, self).__init__(lhs, rhs) + + def is_propagable(self): + return self.var_map[self.rhs].is_propagable() + + def has_side_effect(self): + return self.var_map[self.rhs].has_side_effect() + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_move_result(v_m[self.lhs], v_m[self.rhs]) + + def __str__(self): + v_m = self.var_map + return '%s = %s' % (v_m.get(self.lhs), v_m.get(self.rhs)) + + +class ArrayStoreInstruction(IRForm): + def __init__(self, rhs, array, index, _type): + super(ArrayStoreInstruction, self).__init__() + self.rhs = rhs.v + self.array = array.v + self.index = index.v + self.var_map.update([(rhs.v, rhs), (array.v, array), (index.v, index)]) + self.type = _type + + def has_side_effect(self): + return True + + def get_used_vars(self): + v_m = self.var_map + lused_vars = v_m[self.array].get_used_vars() + lused_vars.extend(v_m[self.index].get_used_vars()) + lused_vars.extend(v_m[self.rhs].get_used_vars()) + return list(set(lused_vars)) + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_astore(v_m[self.array], + v_m[self.index], v_m[self.rhs]) + + def replace_var(self, old, new): + if self.rhs == old: + self.rhs = new.v + if self.array == old: + self.array = new.v + if self.index == old: + self.index = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + #v_m.pop(old) + if self.rhs == old: + self.rhs = new.value() + if self.array == old: + self.array = new.value() + if self.index == old: + self.array = new.value() + else: + v_m[old] = new + else: + for arg in (v_m[self.array], v_m[self.index], v_m[self.rhs]): + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + + def __str__(self): + v_m = self.var_map + return '%s[%s] = %s' % (v_m[self.array], v_m[self.index], v_m[self.rhs]) + + +class StaticInstruction(IRForm): + def __init__(self, rhs, klass, ftype, name): + super(StaticInstruction, self).__init__() + self.rhs = rhs.v + self.cls = klass + self.ftype = ftype + self.name = name + self.var_map[rhs.v] = rhs + + def has_side_effect(self): + return True + + def get_used_vars(self): + return self.var_map[self.rhs].get_used_vars() + + def get_lhs(self): + return None + + def visit(self, visitor): + return visitor.visit_put_static( + self.cls, self.name, self.var_map[self.rhs]) + + def replace_var(self, old, new): + self.rhs = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + rhs = v_m[self.rhs] + if not (rhs.is_const() or rhs.is_ident()): + rhs.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.rhs = new.value() + else: + v_m[old] = new + + def __str__(self): + return '%s.%s = %s' % (self.cls, self.name, self.var_map[self.rhs]) + + +class InstanceInstruction(IRForm): + def __init__(self, rhs, lhs, klass, atype, name): + super(InstanceInstruction, self).__init__() + self.lhs = lhs.v + self.rhs = rhs.v + self.atype = atype + self.cls = klass + self.name = name + self.var_map.update([(lhs.v, lhs), (rhs.v, rhs)]) + + def has_side_effect(self): + return True + + def get_used_vars(self): + v_m = self.var_map + lused_vars = v_m[self.lhs].get_used_vars() + lused_vars.extend(v_m[self.rhs].get_used_vars()) + return list(set(lused_vars)) + + def get_lhs(self): + return None + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_put_instance(v_m[self.lhs], + self.name, v_m[self.rhs]) + + def replace_var(self, old, new): + if self.lhs == old: + self.lhs = new.v + else: + self.rhs = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + if self.lhs == old: + self.lhs = new.value() + if self.rhs == old: + self.rhs = new.value() + else: + v_m[old] = new + else: + for arg in (v_m[self.lhs], v_m[self.rhs]): + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + + def __str__(self): + v_m = self.var_map + return '%s.%s = %s' % (v_m[self.lhs], self.name, v_m[self.rhs]) + + +class NewInstance(IRForm): + def __init__(self, ins_type): + super(NewInstance, self).__init__() + self.type = ins_type + + def get_type(self): + return self.type + + def get_used_vars(self): + return [] + + def visit(self, visitor): + return visitor.visit_new(self.type) + + def replace(self, old, new): + pass + + def __str__(self): + return 'NEW(%s)' % self.type + + +class InvokeInstruction(IRForm): + def __init__(self, clsname, name, base, rtype, ptype, args): + super(InvokeInstruction, self).__init__() + self.cls = clsname + self.name = name + self.base = base.v + self.rtype = rtype + self.ptype = ptype + self.args = [arg.v for arg in args] + self.var_map[base.v] = base + for arg in args: + self.var_map[arg.v] = arg + + def get_type(self): + if self.name == '': + return self.var_map[self.base].get_type() + return self.rtype + + def is_call(self): + return True + + def has_side_effect(self): + return True + + def replace_var(self, old, new): + if self.base == old: + self.base = new.v + else: + new_args = [] + for arg in self.args: + if arg != old: + new_args.append(arg) + else: + new_args.append(new.v) + self.args = new_args + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_ident() or arg.is_const()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + if self.base == old: + self.base = new.value() + for idx, arg in enumerate(self.args): + if arg == old: + self.args.pop(idx) + self.args.insert(idx, new.value()) + else: + v_m[old] = new + else: + base = v_m[self.base] + if not (base.is_ident() or base.is_const()): + base.replace(old, new) + for arg in self.args: + cnt = v_m[arg] + if not (cnt.is_ident() or cnt.is_const()): + cnt.replace(old, new) + + def get_used_vars(self): + v_m = self.var_map + lused_vars = [] + for arg in self.args: + lused_vars.extend(v_m[arg].get_used_vars()) + lused_vars.extend(v_m[self.base].get_used_vars()) + return list(set(lused_vars)) + + def visit(self, visitor): + v_m = self.var_map + largs = [v_m[arg] for arg in self.args] + return visitor.visit_invoke(self.name, v_m[self.base], self.rtype, + self.ptype, largs) + + def __str__(self): + v_m = self.var_map + return '%s.%s(%s)' % (v_m[self.base], self.name, + ', '.join('%s' % v_m[i] for i in self.args)) + + +class InvokeRangeInstruction(InvokeInstruction): + def __init__(self, clsname, name, rtype, ptype, args): + base = args.pop(0) + super(InvokeRangeInstruction, self).__init__(clsname, name, base, + rtype, ptype, args) + + +class InvokeDirectInstruction(InvokeInstruction): + def __init__(self, clsname, name, base, rtype, ptype, args): + super(InvokeDirectInstruction, self).__init__(clsname, name, base, + rtype, ptype, args) + + +class InvokeStaticInstruction(InvokeInstruction): + def __init__(self, clsname, name, base, rtype, ptype, args): + super(InvokeStaticInstruction, self).__init__(clsname, name, base, + rtype, ptype, args) + + def get_used_vars(self): + v_m = self.var_map + lused_vars = [] + for arg in self.args: + lused_vars.extend(v_m[arg].get_used_vars()) + return list(set(lused_vars)) + + +class ReturnInstruction(IRForm): + def __init__(self, arg): + super(ReturnInstruction, self).__init__() + self.arg = arg + if arg is not None: + self.var_map[arg.v] = arg + self.arg = arg.v + + def get_used_vars(self): + if self.arg is None: + return [] + return self.var_map[self.arg].get_used_vars() + + def get_lhs(self): + return None + + def visit(self, visitor): + if self.arg is None: + return visitor.visit_return_void() + else: + return visitor.visit_return(self.var_map[self.arg]) + + def replace_var(self, old, new): + self.arg = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + arg = v_m[self.arg] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.arg = new.value() + else: + v_m[old] = new + + def __str__(self): + if self.arg is not None: + return 'RETURN(%s)' % self.var_map.get(self.arg) + return 'RETURN' + + +class NopExpression(IRForm): + def __init__(self): + pass + + def get_used_vars(self): + return [] + + def get_lhs(self): + return None + + def visit(self, visitor): + return visitor.visit_nop() + + +class SwitchExpression(IRForm): + def __init__(self, src, branch): + super(SwitchExpression, self).__init__() + self.src = src.v + self.branch = branch + self.var_map[src.v] = src + + def get_used_vars(self): + return self.var_map[self.src].get_used_vars() + + def visit(self, visitor): + return visitor.visit_switch(self.var_map[self.src]) + + def replace_var(self, old, new): + self.src = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + src = v_m[self.src] + if not (src.is_const() or src.is_ident()): + src.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.src = new.value() + else: + v_m[old] = new + + def __str__(self): + return 'SWITCH(%s)' % (self.var_map[self.src]) + + +class CheckCastExpression(IRForm): + def __init__(self, arg, _type): + super(CheckCastExpression, self).__init__() + self.arg = arg.v + self.var_map[arg.v] = arg + self.type = _type + + def get_used_vars(self): + return self.var_map[self.arg].get_used_vars() + + def visit(self, visitor): + return visitor.visit_check_cast(self.var_map[self.arg], self.type) + + def replace(self, old, new): + v_m = self.var_map + arg = v_m[self.arg] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.arg = new.value() + else: + v_m[old] = new + + +class ArrayExpression(IRForm): + def __init__(self): + super(ArrayExpression, self).__init__() + + +class ArrayLoadExpression(ArrayExpression): + def __init__(self, arg, index, _type): + super(ArrayLoadExpression, self).__init__() + self.array = arg.v + self.idx = index.v + self.var_map.update([(arg.v, arg), (index.v, index)]) + self.type = _type + + def get_used_vars(self): + v_m = self.var_map + lused_vars = v_m[self.array].get_used_vars() + lused_vars.extend(v_m[self.idx].get_used_vars()) + return list(set(lused_vars)) + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_aload(v_m[self.array], v_m[self.idx]) + + def get_type(self): + return self.var_map[self.array].get_type()[1:] + + def replace_var(self, old, new): + if self.array == old: + self.array = new.v + else: + self.idx = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_ident() or arg.is_const()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + if self.array == old: + self.array = new.value() + if self.idx == old: + self.idx = new.value() + else: + v_m[old] = new + else: + for arg in (self.array, self.idx): + cnt = v_m[arg] + if not (cnt.is_ident() or cnt.is_const()): + cnt.replace(old, new) + + def __str__(self): + v_m = self.var_map + return 'ARRAYLOAD(%s, %s)' % (v_m[self.array], v_m[self.idx]) + + +class ArrayLengthExpression(ArrayExpression): + def __init__(self, array): + super(ArrayLengthExpression, self).__init__() + self.array = array.v + self.var_map[array.v] = array + + def get_type(self): + return 'I' + + def get_used_vars(self): + return self.var_map[self.array].get_used_vars() + + def visit(self, visitor): + return visitor.visit_alength(self.var_map[self.array]) + + def replace_var(self, old, new): + self.array = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + array = v_m[self.array] + if not (array.is_const() or array.is_ident()): + array.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + self.array = new.value() + else: + v_m[old] = new + + def __str__(self): + return 'ARRAYLEN(%s)' % (self.var_map[self.array]) + + +class NewArrayExpression(ArrayExpression): + def __init__(self, asize, atype): + super(NewArrayExpression, self).__init__() + self.size = asize.v + self.type = atype + self.var_map[asize.v] = asize + + def get_used_vars(self): + return self.var_map[self.size].get_used_vars() + + def visit(self, visitor): + return visitor.visit_new_array(self.type, self.var_map[self.size]) + + def replace_var(self, old, new): + self.size = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + size = v_m[self.size] + if not (size.is_const() or size.is_ident()): + size.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.size = new.value() + else: + v_m[old] = new + + def __str__(self): + return 'NEWARRAY_%s[%s]' % (self.type, self.var_map[self.size]) + + +class FilledArrayExpression(ArrayExpression): + def __init__(self, asize, atype, args): + super(FilledArrayExpression, self).__init__() + self.size = asize + self.type = atype + self.args = [] + for arg in args: + self.var_map[arg.v] = arg + self.args.append(arg.v) + + def get_used_vars(self): + lused_vars = [] + for arg in self.args: + lused_vars.extend(self.var_map[arg].get_used_vars()) + return list(set(lused_vars)) + + def replace_var(self, old, new): + new_args = [] + for arg in self.args: + if arg == old: + new_args.append(new.v) + else: + new_args.append(arg) + self.args = new_args + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_ident() or arg.is_const()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + for idx, arg in enumerate(self.args): + if arg == old: + self.args.pop(idx) + self.args.insert(idx, new.value()) + else: + v_m[old] = new + else: + for arg in self.args: + cnt = v_m[arg] + if not (cnt.is_ident() or cnt.is_const()): + cnt.replace(old, new) + + def visit(self, visitor): + v_m = self.var_map + largs = [v_m[arg] for arg in self.args] + return visitor.visit_filled_new_array(self.type, self.size, largs) + + +class FillArrayExpression(ArrayExpression): + def __init__(self, reg, value): + super(FillArrayExpression, self).__init__() + self.reg = reg.v + self.var_map[reg.v] = reg + self.value = value + + def is_propagable(self): + return False + + def get_rhs(self): + return self.reg + + def replace_var(self, old, new): + self.reg = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def get_used_vars(self): + return self.var_map[self.reg].get_used_vars() + + def visit(self, visitor): + return visitor.visit_fill_array(self.var_map[self.reg], self.value) + + +class RefExpression(IRForm): + def __init__(self, ref): + super(RefExpression, self).__init__() + self.ref = ref.v + self.var_map[ref.v] = ref + + def is_propagable(self): + return False + + def get_used_vars(self): + return self.var_map[self.ref].get_used_vars() + + def replace_var(self, old, new): + self.ref = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + ref = v_m[self.ref] + if not (ref.is_const() or ref.is_ident()): + ref.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.ref = new.value() + else: + v_m[old] = new + + +class MoveExceptionExpression(RefExpression): + def __init__(self, ref, _type): + super(MoveExceptionExpression, self).__init__(ref) + self.type = _type + ref.set_type(_type) + + def get_lhs(self): + return self.ref + + def has_side_effect(self): + return True + + def get_used_vars(self): + return [] + + def replace_lhs(self, new): + self.var_map.pop(self.ref) + self.ref = new.v + self.var_map[new.v] = new + + def visit(self, visitor): + return visitor.visit_move_exception(self.var_map[self.ref]) + + def __str__(self): + return 'MOVE_EXCEPT %s' % self.var_map[self.ref] + + +class MonitorEnterExpression(RefExpression): + def __init__(self, ref): + super(MonitorEnterExpression, self).__init__(ref) + + def visit(self, visitor): + return visitor.visit_monitor_enter(self.var_map[self.ref]) + + +class MonitorExitExpression(RefExpression): + def __init__(self, ref): + super(MonitorExitExpression, self).__init__(ref) + + def visit(self, visitor): + return visitor.visit_monitor_exit(self.var_map[self.ref]) + + +class ThrowExpression(RefExpression): + def __init__(self, ref): + super(ThrowExpression, self).__init__(ref) + + def visit(self, visitor): + return visitor.visit_throw(self.var_map[self.ref]) + + def __str__(self): + return 'Throw %s' % self.var_map[self.ref] + + +class BinaryExpression(IRForm): + def __init__(self, op, arg1, arg2, _type): + super(BinaryExpression, self).__init__() + self.op = op + self.arg1 = arg1.v + self.arg2 = arg2.v + self.var_map.update([(arg1.v, arg1), (arg2.v, arg2)]) + self.type = _type + + def has_side_effect(self): + v_m = self.var_map + return (v_m[self.arg1].has_side_effect() or + v_m[self.arg2].has_side_effect()) + + def get_used_vars(self): + v_m = self.var_map + lused_vars = v_m[self.arg1].get_used_vars() + lused_vars.extend(v_m[self.arg2].get_used_vars()) + return list(set(lused_vars)) + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_binary_expression(self.op, v_m[self.arg1], + v_m[self.arg2]) + + def replace_var(self, old, new): + if self.arg1 == old: + self.arg1 = new.v + if self.arg2 == old: + self.arg2 = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + if self.arg1 == old: + self.arg1 = new.value() + if self.arg2 == old: + self.arg2 = new.value() + else: + v_m[old] = new + else: + for arg in (v_m[self.arg1], v_m[self.arg2]): + if not (arg.is_ident() or arg.is_const()): + arg.replace(old, new) + + def __str__(self): + v_m = self.var_map + return '(%s %s %s)' % (self.op, v_m[self.arg1], v_m[self.arg2]) + + +class BinaryCompExpression(BinaryExpression): + def __init__(self, op, arg1, arg2, _type): + super(BinaryCompExpression, self).__init__(op, arg1, arg2, _type) + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_cond_expression(self.op, v_m[self.arg1], + v_m[self.arg2]) + + +class BinaryExpression2Addr(BinaryExpression): + def __init__(self, op, dest, arg, _type): + super(BinaryExpression2Addr, self).__init__(op, dest, arg, _type) + + +class BinaryExpressionLit(BinaryExpression): + def __init__(self, op, arg1, arg2): + super(BinaryExpressionLit, self).__init__(op, arg1, arg2, 'I') + + +class UnaryExpression(IRForm): + def __init__(self, op, arg, _type): + super(UnaryExpression, self).__init__() + self.op = op + self.arg = arg.v + self.var_map[arg.v] = arg + self.type = _type + + def get_type(self): + return self.var_map[self.arg].get_type() + + def get_used_vars(self): + return self.var_map[self.arg].get_used_vars() + + def visit(self, visitor): + return visitor.visit_unary_expression(self.op, self.var_map[self.arg]) + + def replace_var(self, old, new): + self.arg = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + arg = v_m[self.arg] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + elif old in v_m: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.arg = new.value() + else: + v_m[old] = new + + def __str__(self): + return '(%s, %s)' % (self.op, self.var_map[self.arg]) + + +class CastExpression(UnaryExpression): + def __init__(self, op, atype, arg): + super(CastExpression, self).__init__(op, arg, atype) + + def get_type(self): + return self.type + + def get_used_vars(self): + return self.var_map[self.arg].get_used_vars() + + def visit(self, visitor): + return visitor.visit_cast(self.op, self.var_map[self.arg]) + + def __str__(self): + return 'CAST_%s(%s)' % (self.op, self.var_map[self.arg]) + + +CONDS = { + '==': '!=', + '!=': '==', + '<': '>=', + '<=': '>', + '>=': '<', + '>': '<=', +} + + +class ConditionalExpression(IRForm): + def __init__(self, op, arg1, arg2): + super(ConditionalExpression, self).__init__() + self.op = op + self.arg1 = arg1.v + self.arg2 = arg2.v + self.var_map.update([(arg1.v, arg1), (arg2.v, arg2)]) + + def get_lhs(self): + return None + + def is_cond(self): + return True + + def get_used_vars(self): + v_m = self.var_map + lused_vars = v_m[self.arg1].get_used_vars() + lused_vars.extend(v_m[self.arg2].get_used_vars()) + return list(set(lused_vars)) + + def neg(self): + self.op = CONDS[self.op] + + def visit(self, visitor): + v_m = self.var_map + return visitor.visit_cond_expression(self.op, v_m[self.arg1], + v_m[self.arg2]) + + def replace_var(self, old, new): + if self.arg1 == old: + self.arg1 = new.v + else: + self.arg2 = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + if old in v_m: + arg = v_m[old] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + else: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + if self.arg1 == old: + self.arg1 = new.value() + if self.arg2 == old: + self.arg2 = new.value() + else: + v_m[old] = new + else: + for arg in (v_m[self.arg1], v_m[self.arg2]): + if not (arg.is_ident() or arg.is_const()): + arg.replace(old, new) + + def __str__(self): + v_m = self.var_map + return 'COND(%s, %s, %s)' % (self.op, v_m[self.arg1], v_m[self.arg2]) + + +class ConditionalZExpression(IRForm): + def __init__(self, op, arg): + super(ConditionalZExpression, self).__init__() + self.op = op + self.arg = arg.v + self.var_map[arg.v] = arg + + def get_lhs(self): + return None + + def is_cond(self): + return True + + def get_used_vars(self): + return self.var_map[self.arg].get_used_vars() + + def neg(self): + self.op = CONDS[self.op] + + def visit(self, visitor): + return visitor.visit_condz_expression(self.op, self.var_map[self.arg]) + + def replace_var(self, old, new): + self.arg = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + arg = v_m[self.arg] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + elif old in v_m: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.arg = new.value() + else: + v_m[old] = new + + def __str__(self): + return '(IS%s0, %s)' % (self.op, self.var_map[self.arg]) + + +class InstanceExpression(IRForm): + def __init__(self, arg, klass, ftype, name): + super(InstanceExpression, self).__init__() + self.arg = arg.v + self.cls = klass + self.ftype = ftype + self.name = name + self.var_map[arg.v] = arg + + def get_type(self): + return self.ftype + + def get_used_vars(self): + return self.var_map[self.arg].get_used_vars() + + def visit(self, visitor): + return visitor.visit_get_instance(self.var_map[self.arg], self.name) + + def replace_var(self, old, new): + self.arg = new.v + self.var_map.pop(old) + self.var_map[new.v] = new + + def replace(self, old, new): + v_m = self.var_map + arg = v_m[self.arg] + if not (arg.is_const() or arg.is_ident()): + arg.replace(old, new) + elif old in v_m: + if new.is_ident(): + v_m[new.value()] = new + v_m.pop(old) + self.arg = new.value() + else: + v_m[old] = new + + def __str__(self): + return '%s.%s' % (self.var_map[self.arg], self.name) + + +class StaticExpression(IRForm): + def __init__(self, cls_name, field_type, field_name): + super(StaticExpression, self).__init__() + self.cls = cls_name + self.ftype = field_type + self.name = field_name + + def get_type(self): + return self.ftype + + def visit(self, visitor): + return visitor.visit_get_static(self.cls, self.name) + + def replace(self, old, new): + pass + + def __str__(self): + return '%s.%s' % (self.cls, self.name) + diff --git a/androguard/decompiler/dad/node.py b/androguard/decompiler/dad/node.py new file mode 100644 index 00000000..40fca11c --- /dev/null +++ b/androguard/decompiler/dad/node.py @@ -0,0 +1,159 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class MakeProperties(type): + def __init__(cls, name, bases, dct): + def _wrap_set(names, name): + def fun(self, value): + for field in names: + self.__dict__[field] = (name == field) and value + return fun + + def _wrap_get(name): + def fun(self): + return self.__dict__[name] + return fun + + super(MakeProperties, cls).__init__(name, bases, dct) + attrs = [] + prefixes = ('_get_', '_set_') + for key in dct.keys(): + for prefix in prefixes: + if key.startswith(prefix): + attrs.append(key[4:]) + delattr(cls, key) + for attr in attrs: + setattr(cls, attr[1:], + property(_wrap_get(attr), _wrap_set(attrs, attr))) + cls._attrs = attrs + + def __call__(cls, *args, **kwds): + obj = super(MakeProperties, cls).__call__(*args, **kwds) + for attr in cls._attrs: + obj.__dict__[attr] = False + return obj + + +class LoopType(object): + __metaclass__ = MakeProperties + _set_is_pretest = _set_is_posttest = _set_is_endless = None + _get_is_pretest = _get_is_posttest = _get_is_endless = None + + def copy(self): + res = LoopType() + for key, value in self.__dict__.iteritems(): + setattr(res, key, value) + return res + + +class NodeType(object): + __metaclass__ = MakeProperties + _set_is_cond = _set_is_switch = _set_is_stmt = None + _get_is_cond = _get_is_switch = _get_is_stmt = None + _set_is_return = _set_is_throw = None + _get_is_return = _get_is_throw = None + + def copy(self): + res = NodeType() + for key, value in self.__dict__.iteritems(): + setattr(res, key, value) + return res + + +class Node(object): + def __init__(self, name): + self.name = name + self.num = 0 + self.follow = {'if': None, 'loop': None, 'switch': None} + self.looptype = LoopType() + self.type = NodeType() + self.in_catch = False + self.interval = None + self.startloop = False + self.latch = None + self.loop_nodes = [] + + def copy_from(self, node): + self.num = node.num + self.looptype = node.looptype.copy() + self.interval = node.interval + self.startloop = node.startloop + self.type = node.type.copy() + self.follow = node.follow.copy() + self.latch = node.latch + self.loop_nodes = node.loop_nodes + self.in_catch = node.in_catch + + def update_attribute_with(self, n_map): + self.latch = n_map.get(self.latch, self.latch) + for follow_type, value in self.follow.iteritems(): + self.follow[follow_type] = n_map.get(value, value) + self.loop_nodes = list(set(n_map.get(n, n) for n in self.loop_nodes)) + + def get_head(self): + return self + + def get_end(self): + return self + + def __repr__(self): + return '%s' % self + + +class Interval(object): + def __init__(self, head): + self.name = 'Interval-%s' % head.name + self.content = set([head]) + self.end = None + self.head = head + self.in_catch = head.in_catch + head.interval = self + + def __contains__(self, item): + # If the interval contains nodes, check if the item is one of them + if item in self.content: + return True + # If the interval contains intervals, we need to check them + return any(item in node for node in self.content + if isinstance(node, Interval)) + + def add_node(self, node): + if node in self.content: + return False + self.content.add(node) + node.interval = self + return True + + def compute_end(self, graph): + for node in self.content: + for suc in graph.sucs(node): + if suc not in self.content: + self.end = node + + def get_end(self): + return self.end.get_end() + + def get_head(self): + return self.head.get_head() + + def __len__(self): + return len(self.content) + + def __repr__(self): + return '%s(%s)' % (self.name, self.content) + diff --git a/androguard/decompiler/dad/opcode_ins.py b/androguard/decompiler/dad/opcode_ins.py new file mode 100644 index 00000000..bb609339 --- /dev/null +++ b/androguard/decompiler/dad/opcode_ins.py @@ -0,0 +1,1983 @@ +# This file is part of Androguard. +# +# Copyright (C) 2012, Geoffroy Gueguen +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from struct import pack, unpack +import androguard.decompiler.dad.util as util +from androguard.decompiler.dad.instruction import (ArrayLengthExpression, + ArrayLoadExpression, ArrayStoreInstruction, + AssignExpression, BaseClass, BinaryCompExpression, + BinaryExpression, BinaryExpression2Addr, + BinaryExpressionLit, CastExpression, + CheckCastExpression, ConditionalExpression, + ConditionalZExpression, Constant, + FillArrayExpression, FilledArrayExpression, + InstanceExpression, InstanceInstruction, + InvokeInstruction, InvokeDirectInstruction, + InvokeRangeInstruction, InvokeStaticInstruction, + MonitorEnterExpression, MonitorExitExpression, + MoveExceptionExpression, MoveExpression, + MoveResultExpression, NewArrayExpression, + NewInstance, NopExpression, ThrowExpression, + Variable, ReturnInstruction, StaticExpression, + StaticInstruction, SwitchExpression, + UnaryExpression) + + +logger = logging.getLogger('dad.opcode_ins') + + +class Op(object): + CMP = 'cmp' + ADD = '+' + SUB = '-' + MUL = '*' + DIV = '/' + MOD = '%' + AND = '&' + OR = '|' + XOR = '^' + EQUAL = '==' + NEQUAL = '!=' + GREATER = '>' + LOWER = '<' + GEQUAL = '>=' + LEQUAL = '<=' + NEG = '-' + NOT = '~' + INTSHL = '<<' # '(%s << ( %s & 0x1f ))' + INTSHR = '>>' # '(%s >> ( %s & 0x1f ))' + LONGSHL = '<<' # '(%s << ( %s & 0x3f ))' + LONGSHR = '>>' # '(%s >> ( %s & 0x3f ))' + + +def get_variables(vmap, *variables): + res = [] + for variable in variables: + res.append(vmap.setdefault(variable, Variable(variable))) + if len(res) == 1: + return res[0] + return res + + +def assign_const(dest_reg, cst, vmap): + return AssignExpression(get_variables(vmap, dest_reg), cst) + + +def assign_cmp(val_a, val_b, val_c, cmp_type, vmap): + reg_a, reg_b, reg_c = get_variables(vmap, val_a, val_b, val_c) + exp = BinaryCompExpression(Op.CMP, reg_b, reg_c, cmp_type) + return AssignExpression(reg_a, exp) + + +def load_array_exp(val_a, val_b, val_c, ar_type, vmap): + reg_a, reg_b, reg_c = get_variables(vmap, val_a, val_b, val_c) + return AssignExpression(reg_a, ArrayLoadExpression(reg_b, reg_c, ar_type)) + + +def store_array_inst(val_a, val_b, val_c, ar_type, vmap): + reg_a, reg_b, reg_c = get_variables(vmap, val_a, val_b, val_c) + return ArrayStoreInstruction(reg_a, reg_b, reg_c, ar_type) + + +def assign_cast_exp(val_a, val_b, val_op, op_type, vmap): + reg_a, reg_b = get_variables(vmap, val_a, val_b) + return AssignExpression(reg_a, CastExpression(val_op, op_type, reg_b)) + + +def assign_binary_exp(ins, val_op, op_type, vmap): + reg_a, reg_b, reg_c = get_variables(vmap, ins.AA, ins.BB, ins.CC) + return AssignExpression(reg_a, BinaryExpression(val_op, reg_b, + reg_c, op_type)) + + +def assign_binary_2addr_exp(ins, val_op, op_type, vmap): + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + return AssignExpression(reg_a, BinaryExpression2Addr(val_op, reg_a, + reg_b, op_type)) + + +def assign_lit(op_type, val_cst, val_a, val_b, vmap): + cst = Constant(val_cst, 'I') + var_a, var_b = get_variables(vmap, val_a, val_b) + return AssignExpression(var_a, BinaryExpressionLit(op_type, var_b, cst)) + + +# nop +def nop(ins, vmap): + return NopExpression() + + +# move vA, vB ( 4b, 4b ) +def move(ins, vmap): + logger.debug('Move %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + return MoveExpression(reg_a, reg_b) + + +# move/from16 vAA, vBBBB ( 8b, 16b ) +def movefrom16(ins, vmap): + logger.debug('MoveFrom16 %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move/16 vAAAA, vBBBB ( 16b, 16b ) +def move16(ins, vmap): + logger.debug('Move16 %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AAAA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move-wide vA, vB ( 4b, 4b ) +def movewide(ins, vmap): + logger.debug('MoveWide %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + return MoveExpression(reg_a, reg_b) + + +# move-wide/from16 vAA, vBBBB ( 8b, 16b ) +def movewidefrom16(ins, vmap): + logger.debug('MoveWideFrom16 : %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move-wide/16 vAAAA, vBBBB ( 16b, 16b ) +def movewide16(ins, vmap): + logger.debug('MoveWide16 %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AAAA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move-object vA, vB ( 4b, 4b ) +def moveobject(ins, vmap): + logger.debug('MoveObject %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + return MoveExpression(reg_a, reg_b) + + +# move-object/from16 vAA, vBBBB ( 8b, 16b ) +def moveobjectfrom16(ins, vmap): + logger.debug('MoveObjectFrom16 : %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move-object/16 vAAAA, vBBBB ( 16b, 16b ) +def moveobject16(ins, vmap): + logger.debug('MoveObject16 : %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.AAAA, ins.BBBB) + return MoveExpression(reg_a, reg_b) + + +# move-result vAA ( 8b ) +def moveresult(ins, vmap, ret): + logger.debug('MoveResult : %s', ins.get_output()) + return MoveResultExpression(get_variables(vmap, ins.AA), ret) + + +# move-result-wide vAA ( 8b ) +def moveresultwide(ins, vmap, ret): + logger.debug('MoveResultWide : %s', ins.get_output()) + return MoveResultExpression(get_variables(vmap, ins.AA), ret) + + +# move-result-object vAA ( 8b ) +def moveresultobject(ins, vmap, ret): + logger.debug('MoveResultObject : %s', ins.get_output()) + return MoveResultExpression(get_variables(vmap, ins.AA), ret) + + +# move-exception vAA ( 8b ) +def moveexception(ins, vmap, _type): + logger.debug('MoveException : %s', ins.get_output()) + return MoveExceptionExpression(get_variables(vmap, ins.AA), _type) + + +# return-void +def returnvoid(ins, vmap): + logger.debug('ReturnVoid') + return ReturnInstruction(None) + + +# return vAA ( 8b ) +def return_reg(ins, vmap): + logger.debug('Return : %s', ins.get_output()) + return ReturnInstruction(get_variables(vmap, ins.AA)) + + +# return-wide vAA ( 8b ) +def returnwide(ins, vmap): + logger.debug('ReturnWide : %s', ins.get_output()) + return ReturnInstruction(get_variables(vmap, ins.AA)) + + +# return-object vAA ( 8b ) +def returnobject(ins, vmap): + logger.debug('ReturnObject : %s', ins.get_output()) + return ReturnInstruction(get_variables(vmap, ins.AA)) + + +# const/4 vA, #+B ( 4b, 4b ) +def const4(ins, vmap): + logger.debug('Const4 : %s', ins.get_output()) + cst = Constant(ins.B, 'I') + return assign_const(ins.A, cst, vmap) + + +# const/16 vAA, #+BBBB ( 8b, 16b ) +def const16(ins, vmap): + logger.debug('Const16 : %s', ins.get_output()) + cst = Constant(ins.BBBB, 'I') + return assign_const(ins.AA, cst, vmap) + + +# const vAA, #+BBBBBBBB ( 8b, 32b ) +def const(ins, vmap): + logger.debug('Const : %s', ins.get_output()) + value = unpack("=f", pack("=i", ins.BBBBBBBB))[0] + cst = Constant(value, 'F', ins.BBBBBBBB) + return assign_const(ins.AA, cst, vmap) + + +# const/high16 vAA, #+BBBB0000 ( 8b, 16b ) +def consthigh16(ins, vmap): + logger.debug('ConstHigh16 : %s', ins.get_output()) + value = unpack('=f', '\x00\x00' + pack('=h', ins.BBBB))[0] + cst = Constant(value, 'F', ins.BBBB) + return assign_const(ins.AA, cst, vmap) + + +# const-wide/16 vAA, #+BBBB ( 8b, 16b ) +def constwide16(ins, vmap): + logger.debug('ConstWide16 : %s', ins.get_output()) + value = unpack('=d', pack('=d', ins.BBBB))[0] + cst = Constant(value, 'J', ins.BBBB) + return assign_const(ins.AA, cst, vmap) + + +# const-wide/32 vAA, #+BBBBBBBB ( 8b, 32b ) +def constwide32(ins, vmap): + logger.debug('ConstWide32 : %s', ins.get_output()) + value = unpack('=d', pack('=d', ins.BBBBBBBB))[0] + cst = Constant(value, 'J', ins.BBBBBBBB) + return assign_const(ins.AA, cst, vmap) + + +# const-wide vAA, #+BBBBBBBBBBBBBBBB ( 8b, 64b ) +def constwide(ins, vmap): + logger.debug('ConstWide : %s', ins.get_output()) + value = unpack('=d', pack('=q', ins.BBBBBBBBBBBBBBBB))[0] + cst = Constant(value, 'D', ins.BBBBBBBBBBBBBBBB) + return assign_const(ins.AA, cst, vmap) + + +# const-wide/high16 vAA, #+BBBB000000000000 ( 8b, 16b ) +def constwidehigh16(ins, vmap): + logger.debug('ConstWideHigh16 : %s', ins.get_output()) + value = unpack('=d', + '\x00\x00\x00\x00\x00\x00' + pack('=h', ins.BBBB))[0] + cst = Constant(value, 'D', ins.BBBB) + return assign_const(ins.AA, cst, vmap) + + +# const-string vAA ( 8b ) +def conststring(ins, vmap): + logger.debug('ConstString : %s', ins.get_output()) + cst = Constant(ins.get_raw_string(), 'STR') + return assign_const(ins.AA, cst, vmap) + + +# const-string/jumbo vAA ( 8b ) +def conststringjumbo(ins, vmap): + logger.debug('ConstStringJumbo %s', ins.get_output()) + cst = Constant(ins.get_raw_string(), 'STR') + return assign_const(ins.AA, cst, vmap) + + +# const-class vAA, type@BBBB ( 8b ) +def constclass(ins, vmap): + logger.debug('ConstClass : %s', ins.get_output()) + cst = Constant(util.get_type(ins.get_string()), 'class') + return assign_const(ins.AA, cst, vmap) + + +# monitor-enter vAA ( 8b ) +def monitorenter(ins, vmap): + logger.debug('MonitorEnter : %s', ins.get_output()) + return MonitorEnterExpression(get_variables(vmap, ins.AA)) + + +# monitor-exit vAA ( 8b ) +def monitorexit(ins, vmap): + logger.debug('MonitorExit : %s', ins.get_output()) + a = get_variables(vmap, ins.AA) + return MonitorExitExpression(a) + + +# check-cast vAA ( 8b ) +def checkcast(ins, vmap): + logger.debug('CheckCast: %s', ins.get_output()) + cast_type = util.get_type(ins.get_translated_kind()) + return CheckCastExpression(get_variables(vmap, ins.AA), cast_type) + + +# instance-of vA, vB ( 4b, 4b ) +def instanceof(ins, vmap): + logger.debug('InstanceOf : %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + reg_c = BaseClass(util.get_type(ins.get_translated_kind())) + exp = BinaryExpression('instanceof', reg_b, reg_c, 'Z') + return AssignExpression(reg_a, exp) + + +# array-length vA, vB ( 4b, 4b ) +def arraylength(ins, vmap): + logger.debug('ArrayLength: %s', ins.get_output()) + reg_a, reg_b = get_variables(vmap, ins.A, ins.B) + return AssignExpression(reg_a, ArrayLengthExpression(reg_b)) + + +# new-instance vAA ( 8b ) +def newinstance(ins, vmap): + logger.debug('NewInstance : %s', ins.get_output()) + reg_a = get_variables(vmap, ins.AA) + ins_type = ins.cm.get_type(ins.BBBB) + return AssignExpression(reg_a, NewInstance(ins_type)) + + +# new-array vA, vB ( 8b, size ) +def newarray(ins, vmap): + logger.debug('NewArray : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = NewArrayExpression(b, ins.cm.get_type(ins.CCCC)) + return AssignExpression(a, exp) + + +# filled-new-array {vD, vE, vF, vG, vA} ( 4b each ) +def fillednewarray(ins, vmap, ret): + logger.debug('FilledNewArray : %s', ins.get_output()) + c, d, e, f, g = get_variables(vmap, ins.C, ins.D, + ins.E, ins.F, ins.G) + array_type = ins.cm.get_type(ins.BBBB) + exp = FilledArrayExpression(ins.A, array_type, [c, d, e, f, g][:ins.A]) + return AssignExpression(ret, exp) + + +# filled-new-array/range {vCCCC..vNNNN} ( 16b ) +def fillednewarrayrange(ins, vmap, ret): + logger.debug('FilledNewArrayRange : %s', ins.get_output()) + a, c, n = get_variables(vmap, ins.AA, ins.BBBB, ins.CCCC, ins.NNNN) + array_type = ins.cm.get_type(ins.BBBB) + exp = FilledArrayExpression(a, array_type, [c, n]) + return AssignExpression(ret, exp) + + +# fill-array-data vAA, +BBBBBBBB ( 8b, 32b ) +def fillarraydata(ins, vmap, value): + logger.debug('FillArrayData : %s', ins.get_output()) + return FillArrayExpression(get_variables(vmap, ins.AA), value) + + +# fill-array-data-payload vAA, +BBBBBBBB ( 8b, 32b ) +def fillarraydatapayload(ins, vmap): + logger.debug('FillArrayDataPayload : %s', ins.get_output()) + return FillArrayExpression(None) + + +# throw vAA ( 8b ) +def throw(ins, vmap): + logger.debug('Throw : %s', ins.get_output()) + return ThrowExpression(get_variables(vmap, ins.AA)) + + +# goto +AA ( 8b ) +def goto(ins, vmap): + return NopExpression() + + +# goto/16 +AAAA ( 16b ) +def goto16(ins, vmap): + return NopExpression() + + +# goto/32 +AAAAAAAA ( 32b ) +def goto32(ins, vmap): + return NopExpression() + + +# packed-switch vAA, +BBBBBBBB ( reg to test, 32b ) +def packedswitch(ins, vmap): + logger.debug('PackedSwitch : %s', ins.get_output()) + reg_a = get_variables(vmap, ins.AA) + return SwitchExpression(reg_a, ins.BBBBBBBB) + + +# sparse-switch vAA, +BBBBBBBB ( reg to test, 32b ) +def sparseswitch(ins, vmap): + logger.debug('SparseSwitch : %s', ins.get_output()) + reg_a = get_variables(vmap, ins.AA) + return SwitchExpression(reg_a, ins.BBBBBBBB) + + +# cmpl-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def cmplfloat(ins, vmap): + logger.debug('CmpglFloat : %s', ins.get_output()) + return assign_cmp(ins.AA, ins.BB, ins.CC, 'F', vmap) + + +# cmpg-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def cmpgfloat(ins, vmap): + logger.debug('CmpgFloat : %s', ins.get_output()) + return assign_cmp(ins.AA, ins.BB, ins.CC, 'F', vmap) + + +# cmpl-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def cmpldouble(ins, vmap): + logger.debug('CmplDouble : %s', ins.get_output()) + return assign_cmp(ins.AA, ins.BB, ins.CC, 'D', vmap) + + +# cmpg-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def cmpgdouble(ins, vmap): + logger.debug('CmpgDouble : %s', ins.get_output()) + return assign_cmp(ins.AA, ins.BB, ins.CC, 'D', vmap) + + +# cmp-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def cmplong(ins, vmap): + logger.debug('CmpLong : %s', ins.get_output()) + return assign_cmp(ins.AA, ins.BB, ins.CC, 'J', vmap) + + +# if-eq vA, vB, +CCCC ( 4b, 4b, 16b ) +def ifeq(ins, vmap): + logger.debug('IfEq : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.EQUAL, a, b) + + +# if-ne vA, vB, +CCCC ( 4b, 4b, 16b ) +def ifne(ins, vmap): + logger.debug('IfNe : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.NEQUAL, a, b) + + +# if-lt vA, vB, +CCCC ( 4b, 4b, 16b ) +def iflt(ins, vmap): + logger.debug('IfLt : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.LOWER, a, b) + + +# if-ge vA, vB, +CCCC ( 4b, 4b, 16b ) +def ifge(ins, vmap): + logger.debug('IfGe : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.GEQUAL, a, b) + + +# if-gt vA, vB, +CCCC ( 4b, 4b, 16b ) +def ifgt(ins, vmap): + logger.debug('IfGt : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.GREATER, a, b) + + +# if-le vA, vB, +CCCC ( 4b, 4b, 16b ) +def ifle(ins, vmap): + logger.debug('IfLe : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + return ConditionalExpression(Op.LEQUAL, a, b) + + +# if-eqz vAA, +BBBB ( 8b, 16b ) +def ifeqz(ins, vmap): + logger.debug('IfEqz : %s', ins.get_output()) + return ConditionalZExpression(Op.EQUAL, get_variables(vmap, ins.AA)) + + +# if-nez vAA, +BBBB ( 8b, 16b ) +def ifnez(ins, vmap): + logger.debug('IfNez : %s', ins.get_output()) + return ConditionalZExpression(Op.NEQUAL, get_variables(vmap, ins.AA)) + + +# if-ltz vAA, +BBBB ( 8b, 16b ) +def ifltz(ins, vmap): + logger.debug('IfLtz : %s', ins.get_output()) + return ConditionalZExpression(Op.LOWER, get_variables(vmap, ins.AA)) + + +# if-gez vAA, +BBBB ( 8b, 16b ) +def ifgez(ins, vmap): + logger.debug('IfGez : %s', ins.get_output()) + return ConditionalZExpression(Op.GEQUAL, get_variables(vmap, ins.AA)) + + +# if-gtz vAA, +BBBB ( 8b, 16b ) +def ifgtz(ins, vmap): + logger.debug('IfGtz : %s', ins.get_output()) + return ConditionalZExpression(Op.GREATER, get_variables(vmap, ins.AA)) + + +# if-lez vAA, +BBBB (8b, 16b ) +def iflez(ins, vmap): + logger.debug('IfLez : %s', ins.get_output()) + return ConditionalZExpression(Op.LEQUAL, get_variables(vmap, ins.AA)) + + +#TODO: check type for all aget +# aget vAA, vBB, vCC ( 8b, 8b, 8b ) +def aget(ins, vmap): + logger.debug('AGet : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, None, vmap) + + +# aget-wide vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetwide(ins, vmap): + logger.debug('AGetWide : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'W', vmap) + + +# aget-object vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetobject(ins, vmap): + logger.debug('AGetObject : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'O', vmap) + + +# aget-boolean vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetboolean(ins, vmap): + logger.debug('AGetBoolean : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'Z', vmap) + + +# aget-byte vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetbyte(ins, vmap): + logger.debug('AGetByte : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'B', vmap) + + +# aget-char vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetchar(ins, vmap): + logger.debug('AGetChar : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'C', vmap) + + +# aget-short vAA, vBB, vCC ( 8b, 8b, 8b ) +def agetshort(ins, vmap): + logger.debug('AGetShort : %s', ins.get_output()) + return load_array_exp(ins.AA, ins.BB, ins.CC, 'S', vmap) + + +# aput vAA, vBB, vCC +def aput(ins, vmap): + logger.debug('APut : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, None, vmap) + + +# aput-wide vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputwide(ins, vmap): + logger.debug('APutWide : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'W', vmap) + + +# aput-object vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputobject(ins, vmap): + logger.debug('APutObject : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'O', vmap) + + +# aput-boolean vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputboolean(ins, vmap): + logger.debug('APutBoolean : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'Z', vmap) + + +# aput-byte vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputbyte(ins, vmap): + logger.debug('APutByte : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'B', vmap) + + +# aput-char vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputchar(ins, vmap): + logger.debug('APutChar : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'C', vmap) + + +# aput-short vAA, vBB, vCC ( 8b, 8b, 8b ) +def aputshort(ins, vmap): + logger.debug('APutShort : %s', ins.get_output()) + return store_array_inst(ins.AA, ins.BB, ins.CC, 'S', vmap) + + +# iget vA, vB ( 4b, 4b ) +def iget(ins, vmap): + logger.debug('IGet : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-wide vA, vB ( 4b, 4b ) +def igetwide(ins, vmap): + logger.debug('IGetWide : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-object vA, vB ( 4b, 4b ) +def igetobject(ins, vmap): + logger.debug('IGetObject : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-boolean vA, vB ( 4b, 4b ) +def igetboolean(ins, vmap): + logger.debug('IGetBoolean : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-byte vA, vB ( 4b, 4b ) +def igetbyte(ins, vmap): + logger.debug('IGetByte : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-char vA, vB ( 4b, 4b ) +def igetchar(ins, vmap): + logger.debug('IGetChar : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iget-short vA, vB ( 4b, 4b ) +def igetshort(ins, vmap): + logger.debug('IGetShort : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + exp = InstanceExpression(b, klass, ftype, name) + return AssignExpression(a, exp) + + +# iput vA, vB ( 4b, 4b ) +def iput(ins, vmap): + logger.debug('IPut %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-wide vA, vB ( 4b, 4b ) +def iputwide(ins, vmap): + logger.debug('IPutWide %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-object vA, vB ( 4b, 4b ) +def iputobject(ins, vmap): + logger.debug('IPutObject %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-boolean vA, vB ( 4b, 4b ) +def iputboolean(ins, vmap): + logger.debug('IPutBoolean %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-byte vA, vB ( 4b, 4b ) +def iputbyte(ins, vmap): + logger.debug('IPutByte %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-char vA, vB ( 4b, 4b ) +def iputchar(ins, vmap): + logger.debug('IPutChar %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# iput-short vA, vB ( 4b, 4b ) +def iputshort(ins, vmap): + logger.debug('IPutShort %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.CCCC) + klass = util.get_type(klass) + a, b = get_variables(vmap, ins.A, ins.B) + return InstanceInstruction(a, b, klass, atype, name) + + +# sget vAA ( 8b ) +def sget(ins, vmap): + logger.debug('SGet : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-wide vAA ( 8b ) +def sgetwide(ins, vmap): + logger.debug('SGetWide : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-object vAA ( 8b ) +def sgetobject(ins, vmap): + logger.debug('SGetObject : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-boolean vAA ( 8b ) +def sgetboolean(ins, vmap): + logger.debug('SGetBoolean : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-byte vAA ( 8b ) +def sgetbyte(ins, vmap): + logger.debug('SGetByte : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-char vAA ( 8b ) +def sgetchar(ins, vmap): + logger.debug('SGetChar : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sget-short vAA ( 8b ) +def sgetshort(ins, vmap): + logger.debug('SGetShort : %s', ins.get_output()) + klass, atype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + exp = StaticExpression(klass, atype, name) + a = get_variables(vmap, ins.AA) + return AssignExpression(a, exp) + + +# sput vAA ( 8b ) +def sput(ins, vmap): + logger.debug('SPut : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-wide vAA ( 8b ) +def sputwide(ins, vmap): + logger.debug('SPutWide : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-object vAA ( 8b ) +def sputobject(ins, vmap): + logger.debug('SPutObject : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-boolean vAA ( 8b ) +def sputboolean(ins, vmap): + logger.debug('SPutBoolean : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-wide vAA ( 8b ) +def sputbyte(ins, vmap): + logger.debug('SPutByte : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-char vAA ( 8b ) +def sputchar(ins, vmap): + logger.debug('SPutChar : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +# sput-short vAA ( 8b ) +def sputshort(ins, vmap): + logger.debug('SPutShort : %s', ins.get_output()) + klass, ftype, name = ins.cm.get_field(ins.BBBB) + klass = util.get_type(klass) + a = get_variables(vmap, ins.AA) + return StaticInstruction(a, klass, ftype, name) + + +def get_args(vmap, param_type, largs): + num_param = 0 + args = [] + for type_ in param_type: + param = largs[num_param] + args.append(param) + num_param += util.get_type_size(type_) + + if len(param_type) == 1: + return [get_variables(vmap, *args)] + return get_variables(vmap, *args) + + +# invoke-virtual {vD, vE, vF, vG, vA} ( 4b each ) +def invokevirtual(ins, vmap, ret): + logger.debug('InvokeVirtual : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = [ins.D, ins.E, ins.F, ins.G] + args = get_args(vmap, param_type, largs) + c = get_variables(vmap, ins.C) + exp = InvokeInstruction(cls_name, name, c, ret_type, + param_type, args) + return AssignExpression(ret.new(), exp) + + +# invoke-super {vD, vE, vF, vG, vA} ( 4b each ) +def invokesuper(ins, vmap, ret): + logger.debug('InvokeSuper : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + nbargs = ins.A - 1 + largs = [ins.D, ins.E, ins.F, ins.G] + args = get_args(vmap, param_type, largs) + superclass = BaseClass('super') + exp = InvokeInstruction(cls_name, name, superclass, ret_type, + param_type, args) + return AssignExpression(ret.new(), exp) + + +# invoke-direct {vD, vE, vF, vG, vA} ( 4b each ) +def invokedirect(ins, vmap, ret): + logger.debug('InvokeDirect : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = [ins.D, ins.E, ins.F, ins.G] + args = get_args(vmap, param_type, largs) + base = get_variables(vmap, ins.C) + if ret_type != 'V': + returned = ret.new() + else: + returned = base + ret.set_to(base) + exp = InvokeDirectInstruction(cls_name, name, base, ret_type, + param_type, args) + return AssignExpression(returned, exp) + + +# invoke-static {vD, vE, vF, vG, vA} ( 4b each ) +def invokestatic(ins, vmap, ret): + logger.debug('InvokeStatic : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = [ins.C, ins.D, ins.E, ins.F, ins.G] + args = get_args(vmap, param_type, largs) + base = BaseClass(cls_name) + exp = InvokeStaticInstruction(cls_name, name, base, ret_type, + param_type, args) + return AssignExpression(ret.new(), exp) + + +# invoke-interface {vD, vE, vF, vG, vA} ( 4b each ) +def invokeinterface(ins, vmap, ret): + logger.debug('InvokeInterface : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = [ins.D, ins.E, ins.F, ins.G] + args = get_args(vmap, param_type, largs) + c = get_variables(vmap, ins.C) + exp = InvokeInstruction(cls_name, name, c, ret_type, + param_type, args) + return AssignExpression(ret.new(), exp) + + +# invoke-virtual/range {vCCCC..vNNNN} ( 16b each ) +def invokevirtualrange(ins, vmap, ret): + logger.debug('InvokeVirtualRange : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = range(ins.CCCC, ins.NNNN + 1) + this_arg = get_variables(vmap, largs[0]) + args = get_args(vmap, param_type, largs[1:]) + exp = InvokeRangeInstruction(cls_name, name, ret_type, + param_type, [this_arg] + args) + return AssignExpression(ret.new(), exp) + + +# invoke-super/range {vCCCC..vNNNN} ( 16b each ) +def invokesuperrange(ins, vmap, ret): + logger.debug('InvokeSuperRange : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = range(ins.CCCC, ins.NNNN + 1) + args = get_args(vmap, param_type, largs[1:]) + base = get_variables(vmap, ins.CCCC) + if ret_type != 'V': + returned = ret.new() + else: + returned = base + ret.set_to(base) + superclass = BaseClass('super') + exp = InvokeRangeInstruction(cls_name, name, ret_type, + param_type, [superclass] + args) + return AssignExpression(returned, exp) + + +# invoke-direct/range {vCCCC..vNNNN} ( 16b each ) +def invokedirectrange(ins, vmap, ret): + logger.debug('InvokeDirectRange : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = range(ins.CCCC, ins.NNNN + 1) + this_arg = get_variables(vmap, largs[0]) + args = get_args(vmap, param_type, largs[1:]) + base = get_variables(vmap, ins.CCCC) + if ret_type != 'V': + returned = ret.new() + else: + returned = base + ret.set_to(base) + exp = InvokeRangeInstruction(cls_name, name, ret_type, + param_type, [this_arg] + args) + return AssignExpression(returned, exp) + + +# invoke-static/range {vCCCC..vNNNN} ( 16b each ) +def invokestaticrange(ins, vmap, ret): + logger.debug('InvokeStaticRange : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = range(ins.CCCC, ins.NNNN + 1) + args = get_args(vmap, param_type, largs) + base = BaseClass(cls_name) + exp = InvokeStaticInstruction(cls_name, name, base, ret_type, + param_type, args) + return AssignExpression(ret.new(), exp) + + +# invoke-interface/range {vCCCC..vNNNN} ( 16b each ) +def invokeinterfacerange(ins, vmap, ret): + logger.debug('InvokeInterfaceRange : %s', ins.get_output()) + method = ins.cm.get_method_ref(ins.BBBB) + cls_name = util.get_type(method.get_class_name()) + name = method.get_name() + param_type, ret_type = method.get_proto() + param_type = util.get_params_type(param_type) + largs = range(ins.CCCC, ins.NNNN + 1) + base_arg = get_variables(vmap, largs[0]) + args = get_args(vmap, param_type, largs[1:]) + exp = InvokeRangeInstruction(cls_name, name, ret_type, + param_type, [base_arg] + args) + return AssignExpression(ret.new(), exp) + + +# neg-int vA, vB ( 4b, 4b ) +def negint(ins, vmap): + logger.debug('NegInt : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NEG, b, 'I') + return AssignExpression(a, exp) + + +# not-int vA, vB ( 4b, 4b ) +def notint(ins, vmap): + logger.debug('NotInt : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NOT, b, 'I') + return AssignExpression(a, exp) + + +# neg-long vA, vB ( 4b, 4b ) +def neglong(ins, vmap): + logger.debug('NegLong : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NEG, b, 'J') + return AssignExpression(a, exp) + + +# not-long vA, vB ( 4b, 4b ) +def notlong(ins, vmap): + logger.debug('NotLong : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NOT, b, 'J') + return AssignExpression(a, exp) + + +# neg-float vA, vB ( 4b, 4b ) +def negfloat(ins, vmap): + logger.debug('NegFloat : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NEG, b, 'F') + return AssignExpression(a, exp) + + +# neg-double vA, vB ( 4b, 4b ) +def negdouble(ins, vmap): + logger.debug('NegDouble : %s', ins.get_output()) + a, b = get_variables(vmap, ins.A, ins.B) + exp = UnaryExpression(Op.NEG, b, 'D') + return AssignExpression(a, exp) + + +# int-to-long vA, vB ( 4b, 4b ) +def inttolong(ins, vmap): + logger.debug('IntToLong : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(long)', 'J', vmap) + + +# int-to-float vA, vB ( 4b, 4b ) +def inttofloat(ins, vmap): + logger.debug('IntToFloat : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(float)', 'F', vmap) + + +# int-to-double vA, vB ( 4b, 4b ) +def inttodouble(ins, vmap): + logger.debug('IntToDouble : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(double)', 'D', vmap) + + +# long-to-int vA, vB ( 4b, 4b ) +def longtoint(ins, vmap): + logger.debug('LongToInt : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(int)', 'I', vmap) + + +# long-to-float vA, vB ( 4b, 4b ) +def longtofloat(ins, vmap): + logger.debug('LongToFloat : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(float)', 'F', vmap) + + +# long-to-double vA, vB ( 4b, 4b ) +def longtodouble(ins, vmap): + logger.debug('LongToDouble : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(double)', 'D', vmap) + + +# float-to-int vA, vB ( 4b, 4b ) +def floattoint(ins, vmap): + logger.debug('FloatToInt : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(int)', 'I', vmap) + + +# float-to-long vA, vB ( 4b, 4b ) +def floattolong(ins, vmap): + logger.debug('FloatToLong : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(long)', 'J', vmap) + + +# float-to-double vA, vB ( 4b, 4b ) +def floattodouble(ins, vmap): + logger.debug('FloatToDouble : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(double)', 'D', vmap) + + +# double-to-int vA, vB ( 4b, 4b ) +def doubletoint(ins, vmap): + logger.debug('DoubleToInt : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(int)', 'I', vmap) + + +# double-to-long vA, vB ( 4b, 4b ) +def doubletolong(ins, vmap): + logger.debug('DoubleToLong : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(long)', 'J', vmap) + + +# double-to-float vA, vB ( 4b, 4b ) +def doubletofloat(ins, vmap): + logger.debug('DoubleToFloat : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(float)', 'F', vmap) + + +# int-to-byte vA, vB ( 4b, 4b ) +def inttobyte(ins, vmap): + logger.debug('IntToByte : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(byte)', 'B', vmap) + + +# int-to-char vA, vB ( 4b, 4b ) +def inttochar(ins, vmap): + logger.debug('IntToChar : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(char)', 'C', vmap) + + +# int-to-short vA, vB ( 4b, 4b ) +def inttoshort(ins, vmap): + logger.debug('IntToShort : %s', ins.get_output()) + return assign_cast_exp(ins.A, ins.B, '(short)', 'S', vmap) + + +# add-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def addint(ins, vmap): + logger.debug('AddInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.ADD, 'I', vmap) + + +# sub-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def subint(ins, vmap): + logger.debug('SubInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.SUB, 'I', vmap) + + +# mul-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def mulint(ins, vmap): + logger.debug('MulInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MUL, 'I', vmap) + + +# div-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def divint(ins, vmap): + logger.debug('DivInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.DIV, 'I', vmap) + + +# rem-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def remint(ins, vmap): + logger.debug('RemInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MOD, 'I', vmap) + + +# and-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def andint(ins, vmap): + logger.debug('AndInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.AND, 'I', vmap) + + +# or-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def orint(ins, vmap): + logger.debug('OrInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.OR, 'I', vmap) + + +# xor-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def xorint(ins, vmap): + logger.debug('XorInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.XOR, 'I', vmap) + + +# shl-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def shlint(ins, vmap): + logger.debug('ShlInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.INTSHL, 'I', vmap) + + +# shr-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def shrint(ins, vmap): + logger.debug('ShrInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.INTSHR, 'I', vmap) + + +# ushr-int vAA, vBB, vCC ( 8b, 8b, 8b ) +def ushrint(ins, vmap): + logger.debug('UShrInt : %s', ins.get_output()) + return assign_binary_exp(ins, Op.INTSHR, 'I', vmap) + + +# add-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def addlong(ins, vmap): + logger.debug('AddLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.ADD, 'J', vmap) + + +# sub-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def sublong(ins, vmap): + logger.debug('SubLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.SUB, 'J', vmap) + + +# mul-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def mullong(ins, vmap): + logger.debug('MulLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MUL, 'J', vmap) + + +# div-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def divlong(ins, vmap): + logger.debug('DivLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.DIV, 'J', vmap) + + +# rem-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def remlong(ins, vmap): + logger.debug('RemLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MOD, 'J', vmap) + + +# and-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def andlong(ins, vmap): + logger.debug('AndLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.AND, 'J', vmap) + + +# or-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def orlong(ins, vmap): + logger.debug('OrLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.OR, 'J', vmap) + + +# xor-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def xorlong(ins, vmap): + logger.debug('XorLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.XOR, 'J', vmap) + + +# shl-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def shllong(ins, vmap): + logger.debug('ShlLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.LONGSHL, 'J', vmap) + + +# shr-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def shrlong(ins, vmap): + logger.debug('ShrLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.LONGSHR, 'J', vmap) + + +# ushr-long vAA, vBB, vCC ( 8b, 8b, 8b ) +def ushrlong(ins, vmap): + logger.debug('UShrLong : %s', ins.get_output()) + return assign_binary_exp(ins, Op.LONGSHR, 'J', vmap) + + +# add-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def addfloat(ins, vmap): + logger.debug('AddFloat : %s', ins.get_output()) + return assign_binary_exp(ins, Op.ADD, 'F', vmap) + + +# sub-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def subfloat(ins, vmap): + logger.debug('SubFloat : %s', ins.get_output()) + return assign_binary_exp(ins, Op.SUB, 'F', vmap) + + +# mul-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def mulfloat(ins, vmap): + logger.debug('MulFloat : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MUL, 'F', vmap) + + +# div-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def divfloat(ins, vmap): + logger.debug('DivFloat : %s', ins.get_output()) + return assign_binary_exp(ins, Op.DIV, 'F', vmap) + + +# rem-float vAA, vBB, vCC ( 8b, 8b, 8b ) +def remfloat(ins, vmap): + logger.debug('RemFloat : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MOD, 'F', vmap) + + +# add-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def adddouble(ins, vmap): + logger.debug('AddDouble : %s', ins.get_output()) + return assign_binary_exp(ins, Op.ADD, 'D', vmap) + + +# sub-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def subdouble(ins, vmap): + logger.debug('SubDouble : %s', ins.get_output()) + return assign_binary_exp(ins, Op.SUB, 'D', vmap) + + +# mul-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def muldouble(ins, vmap): + logger.debug('MulDouble : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MUL, 'D', vmap) + + +# div-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def divdouble(ins, vmap): + logger.debug('DivDouble : %s', ins.get_output()) + return assign_binary_exp(ins, Op.DIV, 'D', vmap) + + +# rem-double vAA, vBB, vCC ( 8b, 8b, 8b ) +def remdouble(ins, vmap): + logger.debug('RemDouble : %s', ins.get_output()) + return assign_binary_exp(ins, Op.MOD, 'D', vmap) + + +# add-int/2addr vA, vB ( 4b, 4b ) +def addint2addr(ins, vmap): + logger.debug('AddInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.ADD, 'I', vmap) + + +# sub-int/2addr vA, vB ( 4b, 4b ) +def subint2addr(ins, vmap): + logger.debug('SubInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.SUB, 'I', vmap) + + +# mul-int/2addr vA, vB ( 4b, 4b ) +def mulint2addr(ins, vmap): + logger.debug('MulInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MUL, 'I', vmap) + + +# div-int/2addr vA, vB ( 4b, 4b ) +def divint2addr(ins, vmap): + logger.debug('DivInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.DIV, 'I', vmap) + + +# rem-int/2addr vA, vB ( 4b, 4b ) +def remint2addr(ins, vmap): + logger.debug('RemInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MOD, 'I', vmap) + + +# and-int/2addr vA, vB ( 4b, 4b ) +def andint2addr(ins, vmap): + logger.debug('AndInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.AND, 'I', vmap) + + +# or-int/2addr vA, vB ( 4b, 4b ) +def orint2addr(ins, vmap): + logger.debug('OrInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.OR, 'I', vmap) + + +# xor-int/2addr vA, vB ( 4b, 4b ) +def xorint2addr(ins, vmap): + logger.debug('XorInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.XOR, 'I', vmap) + + +# shl-int/2addr vA, vB ( 4b, 4b ) +def shlint2addr(ins, vmap): + logger.debug('ShlInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.INTSHL, 'I', vmap) + + +# shr-int/2addr vA, vB ( 4b, 4b ) +def shrint2addr(ins, vmap): + logger.debug('ShrInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.INTSHR, 'I', vmap) + + +# ushr-int/2addr vA, vB ( 4b, 4b ) +def ushrint2addr(ins, vmap): + logger.debug('UShrInt2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.INTSHR, 'I', vmap) + + +# add-long/2addr vA, vB ( 4b, 4b ) +def addlong2addr(ins, vmap): + logger.debug('AddLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.ADD, 'J', vmap) + + +# sub-long/2addr vA, vB ( 4b, 4b ) +def sublong2addr(ins, vmap): + logger.debug('SubLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.SUB, 'J', vmap) + + +# mul-long/2addr vA, vB ( 4b, 4b ) +def mullong2addr(ins, vmap): + logger.debug('MulLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MUL, 'J', vmap) + + +# div-long/2addr vA, vB ( 4b, 4b ) +def divlong2addr(ins, vmap): + logger.debug('DivLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.DIV, 'J', vmap) + + +# rem-long/2addr vA, vB ( 4b, 4b ) +def remlong2addr(ins, vmap): + logger.debug('RemLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MOD, 'J', vmap) + + +# and-long/2addr vA, vB ( 4b, 4b ) +def andlong2addr(ins, vmap): + logger.debug('AndLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.AND, 'J', vmap) + + +# or-long/2addr vA, vB ( 4b, 4b ) +def orlong2addr(ins, vmap): + logger.debug('OrLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.OR, 'J', vmap) + + +# xor-long/2addr vA, vB ( 4b, 4b ) +def xorlong2addr(ins, vmap): + logger.debug('XorLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.XOR, 'J', vmap) + + +# shl-long/2addr vA, vB ( 4b, 4b ) +def shllong2addr(ins, vmap): + logger.debug('ShlLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.LONGSHL, 'J', vmap) + + +# shr-long/2addr vA, vB ( 4b, 4b ) +def shrlong2addr(ins, vmap): + logger.debug('ShrLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.LONGSHR, 'J', vmap) + + +# ushr-long/2addr vA, vB ( 4b, 4b ) +def ushrlong2addr(ins, vmap): + logger.debug('UShrLong2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.LONGSHR, 'J', vmap) + + +# add-float/2addr vA, vB ( 4b, 4b ) +def addfloat2addr(ins, vmap): + logger.debug('AddFloat2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.ADD, 'F', vmap) + + +# sub-float/2addr vA, vB ( 4b, 4b ) +def subfloat2addr(ins, vmap): + logger.debug('SubFloat2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.SUB, 'F', vmap) + + +# mul-float/2addr vA, vB ( 4b, 4b ) +def mulfloat2addr(ins, vmap): + logger.debug('MulFloat2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MUL, 'F', vmap) + + +# div-float/2addr vA, vB ( 4b, 4b ) +def divfloat2addr(ins, vmap): + logger.debug('DivFloat2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.DIV, 'F', vmap) + + +# rem-float/2addr vA, vB ( 4b, 4b ) +def remfloat2addr(ins, vmap): + logger.debug('RemFloat2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MOD, 'F', vmap) + + +# add-double/2addr vA, vB ( 4b, 4b ) +def adddouble2addr(ins, vmap): + logger.debug('AddDouble2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.ADD, 'D', vmap) + + +# sub-double/2addr vA, vB ( 4b, 4b ) +def subdouble2addr(ins, vmap): + logger.debug('subDouble2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.SUB, 'D', vmap) + + +# mul-double/2addr vA, vB ( 4b, 4b ) +def muldouble2addr(ins, vmap): + logger.debug('MulDouble2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MUL, 'D', vmap) + + +# div-double/2addr vA, vB ( 4b, 4b ) +def divdouble2addr(ins, vmap): + logger.debug('DivDouble2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.DIV, 'D', vmap) + + +# rem-double/2addr vA, vB ( 4b, 4b ) +def remdouble2addr(ins, vmap): + logger.debug('RemDouble2Addr : %s', ins.get_output()) + return assign_binary_2addr_exp(ins, Op.MOD, 'D', vmap) + + +# add-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def addintlit16(ins, vmap): + logger.debug('AddIntLit16 : %s', ins.get_output()) + return assign_lit(Op.ADD, ins.CCCC, ins.A, ins.B, vmap) + + +# rsub-int vA, vB, #+CCCC ( 4b, 4b, 16b ) +def rsubint(ins, vmap): + logger.debug('RSubInt : %s', ins.get_output()) + return assign_lit(Op.SUB, ins.CCCC, ins.A, ins.B, vmap) + + +# mul-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def mulintlit16(ins, vmap): + logger.debug('MulIntLit16 : %s', ins.get_output()) + return assign_lit(Op.MUL, ins.CCCC, ins.A, ins.B, vmap) + + +# div-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def divintlit16(ins, vmap): + logger.debug('DivIntLit16 : %s', ins.get_output()) + return assign_lit(Op.DIV, ins.CCCC, ins.A, ins.B, vmap) + + +# rem-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def remintlit16(ins, vmap): + logger.debug('RemIntLit16 : %s', ins.get_output()) + return assign_lit(Op.MOD, ins.CCCC, ins.A, ins.B, vmap) + + +# and-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def andintlit16(ins, vmap): + logger.debug('AndIntLit16 : %s', ins.get_output()) + return assign_lit(Op.AND, ins.CCCC, ins.A, ins.B, vmap) + + +# or-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def orintlit16(ins, vmap): + logger.debug('OrIntLit16 : %s', ins.get_output()) + return assign_lit(Op.OR, ins.CCCC, ins.A, ins.B, vmap) + + +# xor-int/lit16 vA, vB, #+CCCC ( 4b, 4b, 16b ) +def xorintlit16(ins, vmap): + logger.debug('XorIntLit16 : %s', ins.get_output()) + return assign_lit(Op.XOR, ins.CCCC, ins.A, ins.B, vmap) + + +# add-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def addintlit8(ins, vmap): + logger.debug('AddIntLit8 : %s', ins.get_output()) + literal, op = [(ins.CC, Op.ADD), (-ins.CC, Op.SUB)][ins.CC < 0] + return assign_lit(op, literal, ins.AA, ins.BB, vmap) + + +# rsub-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def rsubintlit8(ins, vmap): + logger.debug('RSubIntLit8 : %s', ins.get_output()) + return assign_lit(Op.SUB, ins.CC, ins.AA, ins.BB, vmap) + + +# mul-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def mulintlit8(ins, vmap): + logger.debug('MulIntLit8 : %s', ins.get_output()) + return assign_lit(Op.MUL, ins.CC, ins.AA, ins.BB, vmap) + + +# div-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def divintlit8(ins, vmap): + logger.debug('DivIntLit8 : %s', ins.get_output()) + return assign_lit(Op.DIV, ins.CC, ins.AA, ins.BB, vmap) + + +# rem-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def remintlit8(ins, vmap): + logger.debug('RemIntLit8 : %s', ins.get_output()) + return assign_lit(Op.MOD, ins.CC, ins.AA, ins.BB, vmap) + + +# and-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def andintlit8(ins, vmap): + logger.debug('AndIntLit8 : %s', ins.get_output()) + return assign_lit(Op.AND, ins.CC, ins.AA, ins.BB, vmap) + + +# or-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def orintlit8(ins, vmap): + logger.debug('OrIntLit8 : %s', ins.get_output()) + return assign_lit(Op.OR, ins.CC, ins.AA, ins.BB, vmap) + + +# xor-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def xorintlit8(ins, vmap): + logger.debug('XorIntLit8 : %s', ins.get_output()) + return assign_lit(Op.XOR, ins.CC, ins.AA, ins.BB, vmap) + + +# shl-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def shlintlit8(ins, vmap): + logger.debug('ShlIntLit8 : %s', ins.get_output()) + return assign_lit(Op.INTSHL, ins.CC, ins.AA, ins.BB, vmap) + + +# shr-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def shrintlit8(ins, vmap): + logger.debug('ShrIntLit8 : %s', ins.get_output()) + return assign_lit(Op.INTSHR, ins.CC, ins.AA, ins.BB, vmap) + + +# ushr-int/lit8 vAA, vBB, #+CC ( 8b, 8b, 8b ) +def ushrintlit8(ins, vmap): + logger.debug('UShrIntLit8 : %s', ins.get_output()) + return assign_lit(Op.INTSHR, ins.CC, ins.AA, ins.BB, vmap) + +INSTRUCTION_SET = [ + # 0x00 + nop, # nop + move, # move + movefrom16, # move/from16 + move16, # move/16 + movewide, # move-wide + movewidefrom16, # move-wide/from16 + movewide16, # move-wide/16 + moveobject, # move-object + moveobjectfrom16, # move-object/from16 + moveobject16, # move-object/16 + moveresult, # move-result + moveresultwide, # move-result-wide + moveresultobject, # move-result-object + moveexception, # move-exception + returnvoid, # return-void + return_reg, # return + + # 0x10 + returnwide, # return-wide + returnobject, # return-object + const4, # const/4 + const16, # const/16 + const, # const + consthigh16, # const/high16 + constwide16, # const-wide/16 + constwide32, # const-wide/32 + constwide, # const-wide + constwidehigh16, # const-wide/high16 + conststring, # const-string + conststringjumbo, # const-string/jumbo + constclass, # const-class + monitorenter, # monitor-enter + monitorexit, # monitor-exit + checkcast, # check-cast + + # 0x20 + instanceof, # instance-of + arraylength, # array-length + newinstance, # new-instance + newarray, # new-array + fillednewarray, # filled-new-array + fillednewarrayrange, # filled-new-array/range + fillarraydata, # fill-array-data + # 'fill-array-data-payload': fillarraydatapayload + throw, # throw + goto, # goto + goto16, # goto/16 + goto32, # goto/32 + packedswitch, # packed-switch + sparseswitch, # sparse-switch + cmplfloat, # cmpl-float + cmpgfloat, # cmpg-float + cmpldouble, # cmpl-double + + # 0x30 + cmpgdouble, # cmpg-double + cmplong, # cmp-long + ifeq, # if-eq + ifne, # if-ne + iflt, # if-lt + ifge, # if-ge + ifgt, # if-gt + ifle, # if-le + ifeqz, # if-eqz + ifnez, # if-nez + ifltz, # if-ltz + ifgez, # if-gez + ifgtz, # if-gtz + iflez, # if-l + nop, # unused + nop, # unused + + # 0x40 + nop, # unused + nop, # unused + nop, # unused + nop, # unused + aget, # aget + agetwide, # aget-wide + agetobject, # aget-object + agetboolean, # aget-boolean + agetbyte, # aget-byte + agetchar, # aget-char + agetshort, # aget-short + aput, # aput + aputwide, # aput-wide + aputobject, # aput-object + aputboolean, # aput-boolean + aputbyte, # aput-byte + + # 0x50 + aputchar, # aput-char + aputshort, # aput-short + iget, # iget + igetwide, # iget-wide + igetobject, # iget-object + igetboolean, # iget-boolean + igetbyte, # iget-byte + igetchar, # iget-char + igetshort, # iget-short + iput, # iput + iputwide, # iput-wide + iputobject, # iput-object + iputboolean, # iput-boolean + iputbyte, # iput-byte + iputchar, # iput-char + iputshort, # iput-short + + # 0x60 + sget, # sget + sgetwide, # sget-wide + sgetobject, # sget-object + sgetboolean, # sget-boolean + sgetbyte, # sget-byte + sgetchar, # sget-char + sgetshort, # sget-short + sput, # sput + sputwide, # sput-wide + sputobject, # sput-object + sputboolean, # sput-boolean + sputbyte, # sput-byte + sputchar, # sput-char + sputshort, # sput-short + invokevirtual, # invoke-virtual + invokesuper, # invoke-super + + # 0x70 + invokedirect, # invoke-direct + invokestatic, # invoke-static + invokeinterface, # invoke-interface + nop, # unused + invokevirtualrange, # invoke-virtual/range + invokesuperrange, # invoke-super/range + invokedirectrange, # invoke-direct/range + invokestaticrange, # invoke-static/range + invokeinterfacerange, # invoke-interface/range + nop, # unused + nop, # unused + negint, # neg-int + notint, # not-int + neglong, # neg-long + notlong, # not-long + negfloat, # neg-float + + # 0x80 + negdouble, # neg-double + inttolong, # int-to-long + inttofloat, # int-to-float + inttodouble, # int-to-double + longtoint, # long-to-int + longtofloat, # long-to-float + longtodouble, # long-to-double + floattoint, # float-to-int + floattolong, # float-to-long + floattodouble, # float-to-double + doubletoint, # double-to-int + doubletolong, # double-to-long + doubletofloat, # double-to-float + inttobyte, # int-to-byte + inttochar, # int-to-char + inttoshort, # int-to-short + + # 0x90 + addint, # add-int + subint, # sub-int + mulint, # mul-int + divint, # div-int + remint, # rem-int + andint, # and-int + orint, # or-int + xorint, # xor-int + shlint, # shl-int + shrint, # shr-int + ushrint, # ushr-int + addlong, # add-long + sublong, # sub-long + mullong, # mul-long + divlong, # div-long + remlong, # rem-long + + # 0xa0 + andlong, # and-long + orlong, # or-long + xorlong, # xor-long + shllong, # shl-long + shrlong, # shr-long + ushrlong, # ushr-long + addfloat, # add-float + subfloat, # sub-float + mulfloat, # mul-float + divfloat, # div-float + remfloat, # rem-float + adddouble, # add-double + subdouble, # sub-double + muldouble, # mul-double + divdouble, # div-double + remdouble, # rem-double + + # 0xb0 + addint2addr, # add-int/2addr + subint2addr, # sub-int/2addr + mulint2addr, # mul-int/2addr + divint2addr, # div-int/2addr + remint2addr, # rem-int/2addr + andint2addr, # and-int/2addr + orint2addr, # or-int/2addr + xorint2addr, # xor-int/2addr + shlint2addr, # shl-int/2addr + shrint2addr, # shr-int/2addr + ushrint2addr, # ushr-int/2addr + addlong2addr, # add-long/2addr + sublong2addr, # sub-long/2addr + mullong2addr, # mul-long/2addr + divlong2addr, # div-long/2addr + remlong2addr, # rem-long/2addr + + # 0xc0 + andlong2addr, # and-long/2addr + orlong2addr, # or-long/2addr + xorlong2addr, # xor-long/2addr + shllong2addr, # shl-long/2addr + shrlong2addr, # shr-long/2addr + ushrlong2addr, # ushr-long/2addr + addfloat2addr, # add-float/2addr + subfloat2addr, # sub-float/2addr + mulfloat2addr, # mul-float/2addr + divfloat2addr, # div-float/2addr + remfloat2addr, # rem-float/2addr + adddouble2addr, # add-double/2addr + subdouble2addr, # sub-double/2addr + muldouble2addr, # mul-double/2addr + divdouble2addr, # div-double/2addr + remdouble2addr, # rem-double/2addr + + # 0xd0 + addintlit16, # add-int/lit16 + rsubint, # rsub-int + mulintlit16, # mul-int/lit16 + divintlit16, # div-int/lit16 + remintlit16, # rem-int/lit16 + andintlit16, # and-int/lit16 + orintlit16, # or-int/lit16 + xorintlit16, # xor-int/lit16 + addintlit8, # add-int/lit8 + rsubintlit8, # rsub-int/lit8 + mulintlit8, # mul-int/lit8 + divintlit8, # div-int/lit8 + remintlit8, # rem-int/lit8 + andintlit8, # and-int/lit8 + orintlit8, # or-int/lit8 + xorintlit8, # xor-int/lit8 + + # 0xe0 + shlintlit8, # shl-int/lit8 + shrintlit8, # shr-int/lit8 + ushrintlit8, # ushr-int/lit8 +] + diff --git a/androguard/decompiler/dad/util.py b/androguard/decompiler/dad/util.py new file mode 100644 index 00000000..ae75d1e9 --- /dev/null +++ b/androguard/decompiler/dad/util.py @@ -0,0 +1,190 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +logger = logging.getLogger('dad.util') + +TYPE_DESCRIPTOR = { + 'V': 'void', + 'Z': 'boolean', + 'B': 'byte', + 'S': 'short', + 'C': 'char', + 'I': 'int', + 'J': 'long', + 'F': 'float', + 'D': 'double', + 'STR': 'String', + 'StringBuilder': 'String', +} + +ACCESS_FLAGS_CLASSES = { + 0x1: 'public', + 0x2: 'private', + 0x4: 'protected', + 0x8: 'static', + 0x10: 'final', + 0x200: 'interface', + 0x400: 'abstract', + 0x1000: 'synthetic', + 0x2000: 'annotation', + 0x4000: 'enum', +} + +ACCESS_FLAGS_FIELDS = { + 0x1: 'public', + 0x2: 'private', + 0x4: 'protected', + 0x8: 'static', + 0x10: 'final', + 0x40: 'volatile', + 0x80: 'transient', + 0x1000: 'synthetic', + 0x4000: 'enum', +} + +ACCESS_FLAGS_METHODS = { + 0x1: 'public', + 0x2: 'private', + 0x4: 'protected', + 0x8: 'static', + 0x10: 'final', + 0x20: 'synchronized', + 0x40: 'bridge', + 0x80: 'varargs', + 0x100: 'native', + 0x400: 'abstract', + 0x800: 'strict', + 0x1000: 'synthetic', + 0x10000: 'constructor', + 0x20000: 'synchronized', +} + +TYPE_LEN = { + 'J': 2, + 'D': 2, +} + + +def build_path(graph, node1, node2, path=None): + ''' + Build the path from node1 to node2. + The path is composed of all the nodes between node1 and node2, + node1 excluded. Although if there is a loop starting from node1, it will be + included in the path. + ''' + if path is None: + path = [] + if node1 is node2: + return path + path.append(node2) + for pred in graph.all_preds(node2): + if pred in path: + continue + build_path(graph, node1, pred, path) + return path + + +def common_dom(idom, cur, pred): + if not (cur and pred): + return cur or pred + while cur is not pred: + while cur.num < pred.num: + pred = idom[pred] + while cur.num > pred.num: + cur = idom[cur] + return cur + + +def merge_inner(clsdict): + ''' + Merge the inner class(es) of a class : + e.g class A { ... } class A$foo{ ... } class A$bar{ ... } + ==> class A { class foo{...} class bar{...} ... } + ''' + samelist = False + done = {} + while not samelist: + samelist = True + classlist = clsdict.keys() + for classname in classlist: + parts_name = classname.rsplit('$', 1) + if len(parts_name) > 1: + mainclass, innerclass = parts_name + innerclass = innerclass[:-1] # remove ';' of the name + mainclass += ';' + if mainclass in clsdict: + clsdict[mainclass].add_subclass(innerclass, + clsdict[classname]) + clsdict[classname].name = innerclass + done[classname] = clsdict[classname] + del clsdict[classname] + samelist = False + elif mainclass in done: + cls = done[mainclass] + cls.add_subclass(innerclass, clsdict[classname]) + clsdict[classname].name = innerclass + done[classname] = done[mainclass] + del clsdict[classname] + samelist = False + + +def get_type_size(param): + ''' + Return the number of register needed by the type @param + ''' + return TYPE_LEN.get(param, 1) + + +def get_type(atype, size=None): + ''' + Retrieve the java type of a descriptor (e.g : I) + ''' + res = TYPE_DESCRIPTOR.get(atype) + if res is None: + if atype[0] == 'L': + if atype.startswith('Ljava/lang'): + res = atype[1:-1].lstrip('java/lang/').replace('/', '.') + else: + res = atype[1:-1].replace('/', '.') + elif atype[0] == '[': + if size is None: + res = '%s[]' % get_type(atype[1:]) + else: + res = '%s[%s]' % (get_type(atype[1:]), size) + else: + res = atype + logger.debug('Unknown descriptor: "%s".', atype) + return res + + +def get_params_type(descriptor): + ''' + Return the parameters type of a descriptor (e.g (IC)V) + ''' + params = descriptor.split(')')[0][1:].split() + if params: + return [param for param in params] + return [] + + +def create_png(cls_name, meth_name, graph, dir_name='graphs2'): + m_name = ''.join(x for x in meth_name if x.isalnum()) + name = ''.join((cls_name.split('/')[-1][:-1], '#', m_name)) + graph.draw(name, dir_name) + diff --git a/androguard/decompiler/dad/writer.py b/androguard/decompiler/dad/writer.py new file mode 100644 index 00000000..4a16e231 --- /dev/null +++ b/androguard/decompiler/dad/writer.py @@ -0,0 +1,559 @@ +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from androguard.decompiler.dad.util import get_type, ACCESS_FLAGS_METHODS +from androguard.decompiler.dad.opcode_ins import Op +from androguard.decompiler.dad.instruction import (Constant, ThisParam, + BinaryExpression, + BinaryCompExpression) + + +logger = logging.getLogger('dad.writer') + + +class Writer(object): + def __init__(self, graph, method): + self.graph = graph + self.method = method + self.visited_nodes = set() + self.ind = 4 + self.buffer = [] + self.loop_follow = [None] + self.if_follow = [None] + self.switch_follow = [None] + self.latch_node = [None] + self.try_follow = [None] + self.next_case = None + self.skip = False + self.need_break = True + + def __str__(self): + return ''.join(self.buffer) + + def inc_ind(self, i=1): + self.ind += (4 * i) + + def dec_ind(self, i=1): + self.ind -= (4 * i) + + def space(self): + if self.skip: + self.skip = False + return '' + return ' ' * self.ind + + def write_ind(self): + if self.skip: + self.skip = False + else: + self.write(self.space()) + + def write(self, s): + self.buffer.append(s) + + def end_ins(self): + self.write(';\n') + + def write_ind_visit_end(self, lhs, s, rhs=None): + self.write_ind() + lhs.visit(self) + self.write(s) + if rhs is not None: + rhs.visit(self) + self.end_ins() + + def write_inplace_if_possible(self, lhs, rhs): + if isinstance(rhs, BinaryExpression) and lhs == rhs.var_map[rhs.arg1]: + exp_rhs = rhs.var_map[rhs.arg2] + if rhs.op in '+-' and isinstance(exp_rhs, Constant) and\ + exp_rhs.get_int_value() == 1: + return self.write_ind_visit_end(lhs, rhs.op * 2) + return self.write_ind_visit_end(lhs, ' %s= ' % rhs.op, exp_rhs) + return self.write_ind_visit_end(lhs, ' = ', rhs) + + def visit_ins(self, ins): + ins.visit(self) + + def write_method(self): + acc = [] + access = self.method.access + self.constructor = False + for modifier in access: + if modifier == 'constructor': + self.constructor = True + continue + acc.append(modifier) + if self.constructor: + name = get_type(self.method.cls_name).split('.')[-1] + proto = '%s %s' % (' '.join(acc), name) + else: + name = self.method.name + proto = '%s %s %s' % ( + ' '.join(acc), get_type(self.method.type), name) + self.write('\n%s%s' % (self.space(), proto)) + params = self.method.lparams + if 'static' not in access: + params = params[1:] + proto = '' + if self.method.params_type: + proto = ', '.join(['%s p%s' % (get_type(p_type), param) for + p_type, param in zip(self.method.params_type, params)]) + self.write('(%s)' % proto) + if self.graph is None: + return self.write(';\n') + self.write('\n%s{\n' % self.space()) + self.inc_ind() + self.visit_node(self.graph.entry) + self.dec_ind() + self.write('%s}\n' % self.space()) + + def visit_node(self, node): + if node in (self.if_follow[-1], self.switch_follow[-1], + self.loop_follow[-1], self.latch_node[-1], + self.try_follow[-1]): + return + if not node.type.is_return and node in self.visited_nodes: + return + self.visited_nodes.add(node) + for var in node.var_to_declare: + var.visit_decl(self) + var.declared = True + node.visit(self) + + def visit_loop_node(self, loop): + follow = loop.follow['loop'] + if follow is None and not loop.looptype.is_endless: + logger.error('Loop has no follow !') + if loop.looptype.is_pretest: + if loop.true is follow: + loop.neg() + loop.true, loop.false = loop.false, loop.true + self.write('%swhile (' % self.space()) + loop.visit_cond(self) + self.write(') {\n') + elif loop.looptype.is_posttest: + self.write('%sdo {\n' % self.space()) + self.latch_node.append(loop.latch) + elif loop.looptype.is_endless: + self.write('%swhile(true) {\n' % self.space()) + self.inc_ind() + self.loop_follow.append(follow) + if loop.looptype.is_pretest: + self.visit_node(loop.true) + else: + self.visit_node(loop.cond) + self.loop_follow.pop() + self.dec_ind() + if loop.looptype.is_pretest: + self.write('%s}\n' % self.space()) + elif loop.looptype.is_posttest: + self.latch_node.pop() + self.write('%s} while(' % self.space()) + loop.latch.visit_cond(self) + self.write(');\n') + else: + self.inc_ind() + self.visit_node(loop.latch) + self.dec_ind() + self.write('%s}\n' % self.space()) + if follow is not None: + self.visit_node(follow) + + def visit_cond_node(self, cond): + follow = cond.follow['if'] + if cond.false is cond.true: + self.write('%s// Both branches of the conditions point to the same' + ' code.\n' % self.space()) + self.write('%s// if (' % self.space()) + cond.visit_cond(self) + self.write(') {\n') + self.inc_ind() + self.visit_node(cond.true) + self.dec_ind() + self.write('%s// }\n' % self.space()) + return + if cond.false is self.loop_follow[-1]: + cond.neg() + cond.true, cond.false = cond.false, cond.true + if self.loop_follow[-1] in (cond.true, cond.false): + self.write('%sif (' % self.space()) + cond.visit_cond(self) + self.write(') {\n') + self.inc_ind() + self.write('%sbreak;\n' % self.space()) + self.dec_ind() + self.write('%s}\n' % self.space()) + self.visit_node(cond.false) + elif follow is not None: + if cond.true in (follow, self.next_case) or\ + cond.num > cond.true.num: + # or cond.true.num > cond.false.num: + cond.neg() + cond.true, cond.false = cond.false, cond.true + self.if_follow.append(follow) + if not cond.true in self.visited_nodes: + self.write('%sif (' % self.space()) + cond.visit_cond(self) + self.write(') {\n') + self.inc_ind() + self.visit_node(cond.true) + self.dec_ind() + is_else = not (follow in (cond.true, cond.false)) + if is_else and not cond.false in self.visited_nodes: + self.write('%s} else {\n' % self.space()) + self.inc_ind() + self.visit_node(cond.false) + self.dec_ind() + self.if_follow.pop() + self.write('%s}\n' % self.space()) + self.visit_node(follow) + else: + self.write('%sif (' % self.space()) + cond.visit_cond(self) + self.write(') {\n') + self.inc_ind() + self.visit_node(cond.true) + self.dec_ind() + self.write('%s} else {\n' % self.space()) + self.inc_ind() + self.visit_node(cond.false) + self.dec_ind() + self.write('%s}\n' % self.space()) + + def visit_short_circuit_condition(self, nnot, aand, cond1, cond2): + if nnot: + cond1.neg() + self.write('(') + cond1.visit_cond(self) + self.write(') %s (' % ['||', '&&'][aand]) + cond2.visit_cond(self) + self.write(')') + + def visit_switch_node(self, switch): + lins = switch.get_ins() + for ins in lins[:-1]: + self.visit_ins(ins) + switch_ins = switch.get_ins()[-1] + self.write('%sswitch (' % self.space()) + self.visit_ins(switch_ins) + self.write(') {\n') + follow = switch.follow['switch'] + cases = switch.cases + self.switch_follow.append(follow) + default = switch.default + for i, node in enumerate(cases): + if node in self.visited_nodes: + continue + self.inc_ind() + for case in switch.node_to_case[node]: + self.write('%scase %d:\n' % (self.space(), case)) + if i + 1 < len(cases): + self.next_case = cases[i + 1] + else: + self.next_case = None + if node is default: + self.write('%sdefault:\n' % self.space()) + default = None + self.inc_ind() + self.visit_node(node) + if self.need_break: + self.write('%sbreak;\n' % self.space()) + else: + self.need_break = True + self.dec_ind(2) + if default not in (None, follow): + self.inc_ind() + self.write('%sdefault:\n' % self.space()) + self.inc_ind() + self.visit_node(default) + self.dec_ind(2) + self.write('%s}\n' % self.space()) + self.switch_follow.pop() + self.visit_node(follow) + + def visit_statement_node(self, stmt): + sucs = self.graph.sucs(stmt) + for ins in stmt.get_ins(): + self.visit_ins(ins) + if len(sucs) == 1: + if sucs[0] is self.loop_follow[-1]: + self.write('%sbreak;\n' % self.space()) + elif sucs[0] is self.next_case: + self.need_break = False + else: + self.visit_node(sucs[0]) + + def visit_try_node(self, try_node): + self.write('%stry {\n' % self.space()) + self.inc_ind() + self.try_follow.append(try_node.follow) + self.visit_node(try_node.try_start) + self.dec_ind() + self.write('%s}' % self.space()) + for catch in try_node.catch: + self.visit_node(catch) + self.write('\n') + self.visit_node(self.try_follow.pop()) + + + def visit_catch_node(self, catch_node): + self.write(' catch (') + catch_node.visit_exception(self) + self.write(') {\n') + self.inc_ind() + self.visit_node(catch_node.catch_start) + self.dec_ind() + self.write('%s}' % self.space()) + + def visit_return_node(self, ret): + self.need_break = False + for ins in ret.get_ins(): + self.visit_ins(ins) + + def visit_throw_node(self, throw): + for ins in throw.get_ins(): + self.visit_ins(ins) + + def visit_decl(self, var): + if not var.declared: + var_type = var.get_type() or 'unknownType' + self.write('%s%s v%s' % ( + self.space(), get_type(var_type), var.value())) + self.end_ins() + + def visit_constant(self, cst): + if isinstance(cst, str) or isinstance(cst, unicode): + return self.write(string(cst)) + self.write('%r' % cst) + + def visit_base_class(self, cls): + self.write(cls) + + def visit_variable(self, var): + if not var.declared: + var_type = var.get_type() or 'unknownType' + self.write('%s ' % get_type(var_type)) + var.declared = True + self.write('v%s' % var.value()) + + def visit_param(self, param): + self.write('p%s' % param) + + def visit_this(self): + self.write('this') + + def visit_assign(self, lhs, rhs): + if lhs is not None: + return self.write_inplace_if_possible(lhs, rhs) + self.write_ind() + rhs.visit(self) + if not self.skip: + self.end_ins() + + def visit_move_result(self, lhs, rhs): + self.write_ind_visit_end(lhs, ' = ', rhs) + + def visit_move(self, lhs, rhs): + if lhs is not rhs: + self.write_inplace_if_possible(lhs, rhs) + + def visit_astore(self, array, index, rhs): + self.write_ind() + array.visit(self) + self.write('[') + if isinstance(index, Constant): + index.visit(self, 'I') + else: + index.visit(self) + self.write('] = ') + rhs.visit(self) + self.end_ins() + + def visit_put_static(self, cls, name, rhs): + self.write_ind() + self.write('%s.%s = ' % (cls, name)) + rhs.visit(self) + self.end_ins() + + def visit_put_instance(self, lhs, name, rhs): + self.write_ind_visit_end(lhs, '.%s = ' % name, rhs) + + def visit_new(self, atype): + self.write('new %s' % get_type(atype)) + + def visit_invoke(self, name, base, ptype, rtype, args): + if isinstance(base, ThisParam): + if name == '' and self.constructor and len(args) == 0: + self.skip = True + return + base.visit(self) + if name != '': + self.write('.%s' % name) + self.write('(') + comma = False + for arg in args: + if comma: + self.write(', ') + comma = True + arg.visit(self) + self.write(')') + + def visit_return_void(self): + self.write_ind() + self.write('return') + self.end_ins() + + def visit_return(self, arg): + self.write_ind() + self.write('return ') + arg.visit(self) + self.end_ins() + + def visit_nop(self): + pass + + def visit_switch(self, arg): + arg.visit(self) + + def visit_check_cast(self, arg, atype): + self.write('(checkcast)(') + arg.visit(self) + self.write(', %s)' % atype) + + def visit_aload(self, array, index): + array.visit(self) + self.write('[') + index.visit(self) + self.write(']') + + def visit_alength(self, array): + array.visit(self) + self.write('.length') + + def visit_new_array(self, atype, size): + self.write('new %s[' % get_type(atype[1:])) + size.visit(self) + self.write(']') + + def visit_filled_new_array(self, atype, size, args): + self.write('new %s {' % get_type(atype)) + for idx, arg in enumerate(args): + arg.visit(self) + if idx + 1 < len(args): + self.write(', ') + self.write('})') + + def visit_fill_array(self, array, value): + self.write_ind() + array.visit(self) + self.write(' = {') + data = value.get_data() + self.write(', '.join(['%d' % ord(c) for c in data[:-1]])) + self.write('}') + self.end_ins() + + def visit_move_exception(self, var): + var.declared = True + var_type = var.get_type() or 'unknownType' + self.write('%s v%s' % (get_type(var_type), var.value())) + + def visit_monitor_enter(self, ref): + self.write_ind() + self.write('synchronized(') + ref.visit(self) + self.write(') {\n') + self.inc_ind() + + def visit_monitor_exit(self, ref): + self.dec_ind() + self.write_ind() + self.write('}\n') + + def visit_throw(self, ref): + self.write_ind() + self.write('throw ') + ref.visit(self) + self.end_ins() + + def visit_binary_expression(self, op, arg1, arg2): + self.write('(') + arg1.visit(self) + self.write(' %s ' % op) + arg2.visit(self) + self.write(')') + + def visit_unary_expression(self, op, arg): + self.write('(%s ' % op) + arg.visit(self) + self.write(')') + + def visit_cast(self, op, arg): + self.write('(%s ' % op) + arg.visit(self) + self.write(')') + + def visit_cond_expression(self, op, arg1, arg2): + arg1.visit(self) + self.write(' %s ' % op) + arg2.visit(self) + + def visit_condz_expression(self, op, arg): + if isinstance(arg, BinaryCompExpression): + arg.op = op + return arg.visit(self) + atype = arg.get_type() + if atype == 'Z': + if op is Op.EQUAL: + self.write('!') + arg.visit(self) + else: + arg.visit(self) + if atype in 'VBSCIJFD': + self.write(' %s 0' % op) + else: + self.write(' %s null' % op) + + def visit_get_instance(self, arg, name): + arg.visit(self) + self.write('.%s' % name) + + def visit_get_static(self, cls, name): + self.write('%s.%s' % (cls, name)) + + +def string(s): + ret = ['"'] + for c in s: + if c >= ' ' and c < '\x7f': + if c == "'" or c == '"' or c == '\\': + ret.append('\\') + ret.append(c) + continue + elif c <= '\x7f': + if c in ('\r', '\n', '\t'): + ret.append(c.encode('unicode-escape')) + continue + i = ord(c) + ret.append('\\u') + ret.append('%x' % (i >> 12)) + ret.append('%x' % ((i >> 8) & 0x0f)) + ret.append('%x' % ((i >> 4) & 0x0f)) + ret.append('%x' % (i & 0x0f)) + ret.append('"') + return ''.join(ret) + diff --git a/androguard/decompiler/decompiler.py b/androguard/decompiler/decompiler.py new file mode 100644 index 00000000..5c57d4b2 --- /dev/null +++ b/androguard/decompiler/decompiler.py @@ -0,0 +1,504 @@ +# This file is part of Androguard. +# +# Copyright (C) 2013, Anthony Desnos +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from subprocess import Popen, PIPE, STDOUT + +import tempfile +import os + +from androguard.core.androconf import rrmdir +from androguard.decompiler.dad import decompile + +PYGMENTS = True +try: + from pygments.filter import Filter + from pygments import highlight + from pygments.lexers import get_lexer_by_name + from pygments.formatters import TerminalFormatter + from pygments.token import Token +except ImportError: + PYGMENTS = False + class Filter: + pass + + +class Dex2Jar: + def __init__(self, vm, path_dex2jar="./decompiler/dex2jar/", bin_dex2jar="dex2jar.sh", tmp_dir="/tmp/"): + pathtmp = tmp_dir + if not os.path.exists(pathtmp): + os.makedirs(pathtmp) + + fd, fdname = tempfile.mkstemp(dir=pathtmp) + fd = os.fdopen(fd, "w+b") + fd.write(vm.get_buff()) + fd.flush() + fd.close() + + compile = Popen([path_dex2jar + bin_dex2jar, fdname], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname) + + self.jarfile = fdname + "_dex2jar.jar" + + def get_jar(self): + return self.jarfile + + +class DecompilerDex2Jad: + def __init__(self, vm, path_dex2jar="./decompiler/dex2jar/", bin_dex2jar="dex2jar.sh", path_jad="./decompiler/jad/", bin_jad="jad", tmp_dir="/tmp/"): + self.classes = {} + self.classes_failed = [] + + pathtmp = tmp_dir + if not os.path.exists(pathtmp): + os.makedirs(pathtmp) + + fd, fdname = tempfile.mkstemp(dir=pathtmp) + fd = os.fdopen(fd, "w+b") + fd.write(vm.get_buff()) + fd.flush() + fd.close() + + compile = Popen([path_dex2jar + bin_dex2jar, fdname], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname) + + pathclasses = fdname + "dex2jar/" + compile = Popen(["unzip", fdname + "_dex2jar.jar", "-d", pathclasses], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname + "_dex2jar.jar") + + for root, dirs, files in os.walk(pathclasses, followlinks=True): + if files != []: + for f in files: + real_filename = root + if real_filename[-1] != "/": + real_filename += "/" + real_filename += f + + compile = Popen([path_jad + bin_jad, "-o", "-d", root, real_filename], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + + for i in vm.get_classes(): + fname = pathclasses + "/" + i.get_name()[1:-1] + ".jad" + if os.path.isfile(fname) == True: + fd = open(fname, "r") + self.classes[i.get_name()] = fd.read() + fd.close() + else: + self.classes_failed.append(i.get_name()) + + rrmdir(pathclasses) + + def get_source_method(self, method): + class_name = method.get_class_name() + method_name = method.get_name() + + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + lexer.add_filter(MethodFilter(method_name=method_name)) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + + return self.classes[class_name] + + def display_source(self, method): + print self.get_source_method(method) + + def get_source_class(self, _class): + return self.classes[_class.get_name()] + + def get_all(self, class_name): + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + return self.classes[class_name] + + def display_all(self, _class): + print self.get_all(_class.get_name()) + + +class DecompilerDex2WineJad: + def __init__(self, vm, path_dex2jar="./decompiler/dex2jar/", bin_dex2jar="dex2jar.sh", path_jad="./decompiler/jad/", bin_jad="jad", tmp_dir="/tmp/"): + self.classes = {} + self.classes_failed = [] + + pathtmp = tmp_dir + if not os.path.exists(pathtmp): + os.makedirs(pathtmp) + + fd, fdname = tempfile.mkstemp(dir=pathtmp) + fd = os.fdopen(fd, "w+b") + fd.write(vm.get_buff()) + fd.flush() + fd.close() + + compile = Popen([path_dex2jar + bin_dex2jar, fdname], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname) + + pathclasses = fdname + "dex2jar/" + compile = Popen(["unzip", fdname + "_dex2jar.jar", "-d", pathclasses], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname + "_dex2jar.jar") + + for root, dirs, files in os.walk(pathclasses, followlinks=True): + if files != []: + for f in files: + real_filename = root + if real_filename[-1] != "/": + real_filename += "/" + real_filename += f + + compile = Popen(["wine", path_jad + bin_jad, "-o", "-d", root, real_filename], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + + for i in vm.get_classes(): + fname = pathclasses + "/" + i.get_name()[1:-1] + ".jad" + if os.path.isfile(fname) == True: + fd = open(fname, "r") + self.classes[i.get_name()] = fd.read() + fd.close() + else: + self.classes_failed.append(i.get_name()) + + rrmdir(pathclasses) + + def get_source_method(self, method): + class_name = method.get_class_name() + method_name = method.get_name() + + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + lexer.add_filter(MethodFilter(method_name=method_name)) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + + return self.classes[class_name] + + def display_source(self, method): + print self.get_source_method(method) + + def get_source_class(self, _class): + return self.classes[_class.get_name()] + + def get_all(self, class_name): + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + return self.classes[class_name] + + def display_all(self, _class): + print self.get_all(_class.get_name()) + +class DecompilerDed: + def __init__(self, vm, path="./decompiler/ded/", bin_ded="ded.sh", tmp_dir="/tmp/"): + self.classes = {} + self.classes_failed = [] + + pathtmp = tmp_dir + if not os.path.exists(pathtmp) : + os.makedirs( pathtmp ) + + fd, fdname = tempfile.mkstemp( dir=pathtmp ) + fd = os.fdopen(fd, "w+b") + fd.write( vm.get_buff() ) + fd.flush() + fd.close() + + dirname = tempfile.mkdtemp(prefix=fdname + "-src") + compile = Popen([ path + bin_ded, "-c", "-o", "-d", dirname, fdname ], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink( fdname ) + + findsrc = None + for root, dirs, files in os.walk( dirname + "/optimized-decompiled/" ) : + if dirs != [] : + for f in dirs : + if f == "src" : + findsrc = root + if findsrc[-1] != "/" : + findsrc += "/" + findsrc += f + break + if findsrc != None : + break + + for i in vm.get_classes() : + fname = findsrc + "/" + i.get_name()[1:-1] + ".java" + #print fname + if os.path.isfile(fname) == True : + fd = open(fname, "r") + self.classes[ i.get_name() ] = fd.read() + fd.close() + else : + self.classes_failed.append( i.get_name() ) + + rrmdir( dirname ) + + def get_source_method(self, method): + class_name = method.get_class_name() + method_name = method.get_name() + + if class_name not in self.classes: + return "" + + lexer = get_lexer_by_name("java", stripall=True) + lexer.add_filter(MethodFilter(method_name=method_name)) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + + def display_source(self, method): + print self.get_source_method(method) + + def get_all(self, class_name): + if class_name not in self.classes: + return "" + + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + + def get_source_class(self, _class): + return self.classes[_class.get_name()] + + def display_all(self, _class): + print self.get_all(_class.get_name()) + + +class DecompilerDex2Fernflower: + def __init__(self, + vm, + path_dex2jar="./decompiler/dex2jar/", + bin_dex2jar="dex2jar.sh", + path_fernflower="./decompiler/fernflower/", + bin_fernflower="fernflower.jar", + options_fernflower={"dgs": '1', "asc": '1'}, + tmp_dir="/tmp/"): + self.classes = {} + self.classes_failed = [] + + pathtmp = tmp_dir + if not os.path.exists(pathtmp): + os.makedirs(pathtmp) + + fd, fdname = tempfile.mkstemp(dir=pathtmp) + fd = os.fdopen(fd, "w+b") + fd.write(vm.get_buff()) + fd.flush() + fd.close() + + compile = Popen([path_dex2jar + bin_dex2jar, fdname], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname) + + pathclasses = fdname + "dex2jar/" + compile = Popen(["unzip", fdname + "_dex2jar.jar", "-d", pathclasses], stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + os.unlink(fdname + "_dex2jar.jar") + + for root, dirs, files in os.walk(pathclasses, followlinks=True): + if files != []: + for f in files: + real_filename = root + if real_filename[-1] != "/": + real_filename += "/" + real_filename += f + + l = ["java", "-jar", path_fernflower + bin_fernflower] + + for option in options_fernflower: + l.append("-%s:%s" % (option, options_fernflower[option])) + l.append(real_filename) + l.append(root) + + compile = Popen(l, stdout=PIPE, stderr=STDOUT) + stdout, stderr = compile.communicate() + + for i in vm.get_classes(): + fname = pathclasses + "/" + i.get_name()[1:-1] + ".java" + if os.path.isfile(fname) == True: + fd = open(fname, "r") + self.classes[i.get_name()] = fd.read() + fd.close() + else: + self.classes_failed.append(i.get_name()) + + rrmdir(pathclasses) + + def get_source_method(self, method): + class_name = method.get_class_name() + method_name = method.get_name() + + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + lexer.add_filter(MethodFilter(method_name=method_name)) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + + return self.classes[class_name] + + def display_source(self, method): + print self.get_source_method(method) + + def get_source_class(self, _class): + return self.classes[_class.get_name()] + + def get_all(self, class_name): + if class_name not in self.classes: + return "" + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(self.classes[class_name], lexer, formatter) + return result + return self.classes[class_name] + + def display_all(self, _class): + print self.get_all(_class.get_name()) + + +class MethodFilter(Filter): + def __init__(self, **options): + Filter.__init__(self, **options) + + self.method_name = options["method_name"] + #self.descriptor = options["descriptor"] + + self.present = False + self.get_desc = True #False + + def filter(self, lexer, stream) : + a = [] + l = [] + rep = [] + + for ttype, value in stream: + if self.method_name == value and (ttype is Token.Name.Function or ttype is Token.Name) : + #print ttype, value + + item_decl = -1 + for i in range(len(a)-1, 0, -1) : + if a[i][0] is Token.Keyword.Declaration : + if a[i][1] != "class" : + item_decl = i + break + + if item_decl != -1 : + self.present = True + l.extend( a[item_decl:] ) + + + if self.present and ttype is Token.Keyword.Declaration : + item_end = -1 + for i in range(len(l)-1, 0, -1) : + if l[i][0] is Token.Operator and l[i][1] == "}" : + item_end = i + break + + if item_end != -1 : + rep.extend( l[:item_end+1] ) + l = [] + self.present = False + + if self.present : + l.append( (ttype, value) ) + + a.append( (ttype, value) ) + + + if self.present : + nb = 0 + item_end = -1 + for i in range(len(l)-1, 0, -1) : + if l[i][0] is Token.Operator and l[i][1] == "}" : + nb += 1 + if nb == 2 : + item_end = i + break + + rep.extend( l[:item_end+1] ) + + return rep + + +class DecompilerDAD: + def __init__(self, vm, vmx): + self.vm = vm + self.vmx = vmx + + def get_source_method(self, m): + mx = self.vmx.get_method(m) + z = decompile.DvMethod(mx) + z.process() + + result = z.get_source() + return result + + def display_source(self, m): + result = self.get_source_method(m) + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(result, lexer, formatter) + print result + + def get_source_class(self, _class): + c = decompile.DvClass(_class, self.vmx) + c.process() + + result = c.get_source() + + return result + + def display_all(self, _class): + result = self.get_source_class(_class) + + if PYGMENTS: + lexer = get_lexer_by_name("java", stripall=True) + formatter = TerminalFormatter() + result = highlight(result, lexer, formatter) + print result + + def get_all(self, class_name): + pass diff --git a/androguard/patch/__init__.py b/androguard/patch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/androguard/patch/zipfile.py b/androguard/patch/zipfile.py new file mode 100644 index 00000000..b7b00c03 --- /dev/null +++ b/androguard/patch/zipfile.py @@ -0,0 +1,1435 @@ +""" +Read and write ZIP files. +""" +import struct, os, time, sys, shutil +import binascii, cStringIO, stat +import io +import re + +try: + import zlib # We may need its compression method + crc32 = zlib.crc32 +except ImportError: + zlib = None + crc32 = binascii.crc32 + +__all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile", + "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile" ] + +class BadZipfile(Exception): + pass + + +class LargeZipFile(Exception): + """ + Raised when writing a zipfile, the zipfile requires ZIP64 extensions + and those extensions are disabled. + """ + +error = BadZipfile # The exception raised by this module + +ZIP64_LIMIT = (1 << 31) - 1 +ZIP_FILECOUNT_LIMIT = 1 << 16 +ZIP_MAX_COMMENT = (1 << 16) - 1 + +# constants for Zip file compression methods +ZIP_STORED = 0 +ZIP_DEFLATED = 8 +# Other ZIP compression methods not supported + +# Below are some formats and associated data for reading/writing headers using +# the struct module. The names and structures of headers/records are those used +# in the PKWARE description of the ZIP file format: +# http://www.pkware.com/documents/casestudies/APPNOTE.TXT +# (URL valid as of January 2008) + +# The "end of central directory" structure, magic number, size, and indices +# (section V.I in the format document) +structEndArchive = "<4s4H2LH" +stringEndArchive = "PK\005\006" +sizeEndCentDir = struct.calcsize(structEndArchive) + +_ECD_SIGNATURE = 0 +_ECD_DISK_NUMBER = 1 +_ECD_DISK_START = 2 +_ECD_ENTRIES_THIS_DISK = 3 +_ECD_ENTRIES_TOTAL = 4 +_ECD_SIZE = 5 +_ECD_OFFSET = 6 +_ECD_COMMENT_SIZE = 7 +# These last two indices are not part of the structure as defined in the +# spec, but they are used internally by this module as a convenience +_ECD_COMMENT = 8 +_ECD_LOCATION = 9 + +# The "central directory" structure, magic number, size, and indices +# of entries in the structure (section V.F in the format document) +structCentralDir = "<4s4B4HL2L5H2L" +stringCentralDir = "PK\001\002" +sizeCentralDir = struct.calcsize(structCentralDir) + +# indexes of entries in the central directory structure +_CD_SIGNATURE = 0 +_CD_CREATE_VERSION = 1 +_CD_CREATE_SYSTEM = 2 +_CD_EXTRACT_VERSION = 3 +_CD_EXTRACT_SYSTEM = 4 +_CD_FLAG_BITS = 5 +_CD_COMPRESS_TYPE = 6 +_CD_TIME = 7 +_CD_DATE = 8 +_CD_CRC = 9 +_CD_COMPRESSED_SIZE = 10 +_CD_UNCOMPRESSED_SIZE = 11 +_CD_FILENAME_LENGTH = 12 +_CD_EXTRA_FIELD_LENGTH = 13 +_CD_COMMENT_LENGTH = 14 +_CD_DISK_NUMBER_START = 15 +_CD_INTERNAL_FILE_ATTRIBUTES = 16 +_CD_EXTERNAL_FILE_ATTRIBUTES = 17 +_CD_LOCAL_HEADER_OFFSET = 18 + +# The "local file header" structure, magic number, size, and indices +# (section V.A in the format document) +structFileHeader = "<4s2B4HL2L2H" +stringFileHeader = "PK\003\004" +sizeFileHeader = struct.calcsize(structFileHeader) + +_FH_SIGNATURE = 0 +_FH_EXTRACT_VERSION = 1 +_FH_EXTRACT_SYSTEM = 2 +_FH_GENERAL_PURPOSE_FLAG_BITS = 3 +_FH_COMPRESSION_METHOD = 4 +_FH_LAST_MOD_TIME = 5 +_FH_LAST_MOD_DATE = 6 +_FH_CRC = 7 +_FH_COMPRESSED_SIZE = 8 +_FH_UNCOMPRESSED_SIZE = 9 +_FH_FILENAME_LENGTH = 10 +_FH_EXTRA_FIELD_LENGTH = 11 + +# The "Zip64 end of central directory locator" structure, magic number, and size +structEndArchive64Locator = "<4sLQL" +stringEndArchive64Locator = "PK\x06\x07" +sizeEndCentDir64Locator = struct.calcsize(structEndArchive64Locator) + +# The "Zip64 end of central directory" record, magic number, size, and indices +# (section V.G in the format document) +structEndArchive64 = "<4sQ2H2L4Q" +stringEndArchive64 = "PK\x06\x06" +sizeEndCentDir64 = struct.calcsize(structEndArchive64) + +_CD64_SIGNATURE = 0 +_CD64_DIRECTORY_RECSIZE = 1 +_CD64_CREATE_VERSION = 2 +_CD64_EXTRACT_VERSION = 3 +_CD64_DISK_NUMBER = 4 +_CD64_DISK_NUMBER_START = 5 +_CD64_NUMBER_ENTRIES_THIS_DISK = 6 +_CD64_NUMBER_ENTRIES_TOTAL = 7 +_CD64_DIRECTORY_SIZE = 8 +_CD64_OFFSET_START_CENTDIR = 9 + +def _check_zipfile(fp): + try: + if _EndRecData(fp): + return True # file has correct magic number + except IOError: + pass + return False + +def is_zipfile(filename): + """Quickly see if a file is a ZIP file by checking the magic number. + + The filename argument may be a file or file-like object too. + """ + result = False + try: + if hasattr(filename, "read"): + result = _check_zipfile(fp=filename) + else: + with open(filename, "rb") as fp: + result = _check_zipfile(fp) + except IOError: + pass + return result + +def _EndRecData64(fpin, offset, endrec): + """ + Read the ZIP64 end-of-archive records and use that to update endrec + """ + try: + fpin.seek(offset - sizeEndCentDir64Locator, 2) + except IOError: + # If the seek fails, the file is not large enough to contain a ZIP64 + # end-of-archive record, so just return the end record we were given. + return endrec + + data = fpin.read(sizeEndCentDir64Locator) + sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data) + if sig != stringEndArchive64Locator: + return endrec + + if diskno != 0 or disks != 1: + raise BadZipfile("zipfiles that span multiple disks are not supported") + + # Assume no 'zip64 extensible data' + fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2) + data = fpin.read(sizeEndCentDir64) + sig, sz, create_version, read_version, disk_num, disk_dir, \ + dircount, dircount2, dirsize, diroffset = \ + struct.unpack(structEndArchive64, data) + if sig != stringEndArchive64: + return endrec + + # Update the original endrec using data from the ZIP64 record + endrec[_ECD_SIGNATURE] = sig + endrec[_ECD_DISK_NUMBER] = disk_num + endrec[_ECD_DISK_START] = disk_dir + endrec[_ECD_ENTRIES_THIS_DISK] = dircount + endrec[_ECD_ENTRIES_TOTAL] = dircount2 + endrec[_ECD_SIZE] = dirsize + endrec[_ECD_OFFSET] = diroffset + return endrec + + +def _EndRecData(fpin): + """Return data from the "End of Central Directory" record, or None. + + The data is a list of the nine items in the ZIP "End of central dir" + record followed by a tenth item, the file seek offset of this record.""" + + # Determine file size + fpin.seek(0, 2) + filesize = fpin.tell() + + # Check to see if this is ZIP file with no archive comment (the + # "end of central directory" structure should be the last item in the + # file if this is the case). + try: + fpin.seek(-sizeEndCentDir, 2) + except IOError: + return None + data = fpin.read() + if data[0:4] == stringEndArchive and data[-2:] == "\000\000": + # the signature is correct and there's no comment, unpack structure + endrec = struct.unpack(structEndArchive, data) + endrec=list(endrec) + + # Append a blank comment and record start offset + endrec.append("") + endrec.append(filesize - sizeEndCentDir) + + # Try to read the "Zip64 end of central directory" structure + return _EndRecData64(fpin, -sizeEndCentDir, endrec) + + # Either this is not a ZIP file, or it is a ZIP file with an archive + # comment. Search the end of the file for the "end of central directory" + # record signature. The comment is the last item in the ZIP file and may be + # up to 64K long. It is assumed that the "end of central directory" magic + # number does not appear in the comment. + maxCommentStart = max(filesize - (1 << 16) - sizeEndCentDir, 0) + fpin.seek(maxCommentStart, 0) + data = fpin.read() + start = data.rfind(stringEndArchive) + if start >= 0: + # found the magic number; attempt to unpack and interpret + recData = data[start:start+sizeEndCentDir] + endrec = list(struct.unpack(structEndArchive, recData)) + commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file + comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize] + endrec.append(comment) + endrec.append(maxCommentStart + start) + + # Try to read the "Zip64 end of central directory" structure + return _EndRecData64(fpin, maxCommentStart + start - filesize, + endrec) + + # Unable to find a valid end of central directory structure + return + + +class ZipInfo (object): + """Class with attributes describing each file in the ZIP archive.""" + + __slots__ = ( + 'orig_filename', + 'filename', + 'date_time', + 'compress_type', + 'comment', + 'extra', + 'create_system', + 'create_version', + 'extract_version', + 'reserved', + 'flag_bits', + 'volume', + 'internal_attr', + 'external_attr', + 'header_offset', + 'CRC', + 'compress_size', + 'file_size', + '_raw_time', + ) + + def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)): + self.orig_filename = filename # Original file name in archive + + # Terminate the file name at the first null byte. Null bytes in file + # names are used as tricks by viruses in archives. + null_byte = filename.find(chr(0)) + if null_byte >= 0: + filename = filename[0:null_byte] + # This is used to ensure paths in generated ZIP files always use + # forward slashes as the directory separator, as required by the + # ZIP format specification. + if os.sep != "/" and os.sep in filename: + filename = filename.replace(os.sep, "/") + + self.filename = filename # Normalized file name + self.date_time = date_time # year, month, day, hour, min, sec + # Standard values: + self.compress_type = ZIP_STORED # Type of compression for the file + self.comment = "" # Comment for each file + self.extra = "" # ZIP extra data + if sys.platform == 'win32': + self.create_system = 0 # System which created ZIP archive + else: + # Assume everything else is unix-y + self.create_system = 3 # System which created ZIP archive + self.create_version = 20 # Version which created ZIP archive + self.extract_version = 20 # Version needed to extract archive + self.reserved = 0 # Must be zero + self.flag_bits = 0 # ZIP flag bits + self.volume = 0 # Volume number of file header + self.internal_attr = 0 # Internal attributes + self.external_attr = 0 # External file attributes + # Other attributes are set by class ZipFile: + # header_offset Byte offset to the file header + # CRC CRC-32 of the uncompressed file + # compress_size Size of the compressed file + # file_size Size of the uncompressed file + + def FileHeader(self): + """Return the per-file header as a string.""" + dt = self.date_time + dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] + dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) + if self.flag_bits & 0x08: + # Set these to zero because we write them after the file data + CRC = compress_size = file_size = 0 + else: + CRC = self.CRC + compress_size = self.compress_size + file_size = self.file_size + + extra = self.extra + + if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: + # File is larger than what fits into a 4 byte integer, + # fall back to the ZIP64 extension + fmt = '= 4: + tp, ln = unpack('= 24: + counts = unpack('> 1) & 0x7FFFFFFF) ^ poly + else: + crc = ((crc >> 1) & 0x7FFFFFFF) + table[i] = crc + return table + crctable = _GenerateCRCTable() + + def _crc32(self, ch, crc): + """Compute the CRC32 primitive on one byte.""" + return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ord(ch)) & 0xff] + + def __init__(self, pwd): + self.key0 = 305419896 + self.key1 = 591751049 + self.key2 = 878082192 + for p in pwd: + self._UpdateKeys(p) + + def _UpdateKeys(self, c): + self.key0 = self._crc32(c, self.key0) + self.key1 = (self.key1 + (self.key0 & 255)) & 4294967295 + self.key1 = (self.key1 * 134775813 + 1) & 4294967295 + self.key2 = self._crc32(chr((self.key1 >> 24) & 255), self.key2) + + def __call__(self, c): + """Decrypt a single character.""" + c = ord(c) + k = self.key2 | 2 + c = c ^ (((k * (k^1)) >> 8) & 255) + c = chr(c) + self._UpdateKeys(c) + return c + +class ZipExtFile(io.BufferedIOBase): + """File-like object for reading an archive member. + Is returned by ZipFile.open(). + """ + + # Max size supported by decompressor. + MAX_N = 1 << 31 - 1 + + # Read from compressed files in 4k blocks. + MIN_READ_SIZE = 4096 + + # Search for universal newlines or line chunks. + PATTERN = re.compile(r'^(?P[^\r\n]+)|(?P\n|\r\n?)') + + def __init__(self, fileobj, mode, zipinfo, decrypter=None): + self._fileobj = fileobj + self._decrypter = decrypter + + self._compress_type = zipinfo.compress_type + self._compress_size = zipinfo.compress_size + self._compress_left = zipinfo.compress_size + + if self._compress_type == ZIP_DEFLATED: + self._decompressor = zlib.decompressobj(-15) + self._unconsumed = '' + + self._readbuffer = '' + self._offset = 0 + + self._universal = 'U' in mode + self.newlines = None + + # Adjust read size for encrypted files since the first 12 bytes + # are for the encryption/password information. + if self._decrypter is not None: + self._compress_left -= 12 + + self.mode = mode + self.name = zipinfo.filename + + if hasattr(zipinfo, 'CRC'): + self._expected_crc = zipinfo.CRC + self._running_crc = crc32(b'') & 0xffffffff + else: + self._expected_crc = None + + def readline(self, limit=-1): + """Read and return a line from the stream. + + If limit is specified, at most limit bytes will be read. + """ + + if not self._universal and limit < 0: + # Shortcut common case - newline found in buffer. + i = self._readbuffer.find('\n', self._offset) + 1 + if i > 0: + line = self._readbuffer[self._offset: i] + self._offset = i + return line + + if not self._universal: + return io.BufferedIOBase.readline(self, limit) + + line = '' + while limit < 0 or len(line) < limit: + readahead = self.peek(2) + if readahead == '': + return line + + # + # Search for universal newlines or line chunks. + # + # The pattern returns either a line chunk or a newline, but not + # both. Combined with peek(2), we are assured that the sequence + # '\r\n' is always retrieved completely and never split into + # separate newlines - '\r', '\n' due to coincidental readaheads. + # + match = self.PATTERN.search(readahead) + newline = match.group('newline') + if newline is not None: + if self.newlines is None: + self.newlines = [] + if newline not in self.newlines: + self.newlines.append(newline) + self._offset += len(newline) + return line + '\n' + + chunk = match.group('chunk') + if limit >= 0: + chunk = chunk[: limit - len(line)] + + self._offset += len(chunk) + line += chunk + + return line + + def peek(self, n=1): + """Returns buffered bytes without advancing the position.""" + if n > len(self._readbuffer) - self._offset: + chunk = self.read(n) + self._offset -= len(chunk) + + # Return up to 512 bytes to reduce allocation overhead for tight loops. + return self._readbuffer[self._offset: self._offset + 512] + + def readable(self): + return True + + def read(self, n=-1): + """Read and return up to n bytes. + If the argument is omitted, None, or negative, data is read and returned until EOF is reached.. + """ + buf = '' + if n is None: + n = -1 + while True: + if n < 0: + data = self.read1(n) + elif n > len(buf): + data = self.read1(n - len(buf)) + else: + return buf + if len(data) == 0: + return buf + buf += data + + def _update_crc(self, newdata, eof): + # Update the CRC using the given data. + if self._expected_crc is None: + # No need to compute the CRC if we don't have a reference value + return + self._running_crc = crc32(newdata, self._running_crc) & 0xffffffff + # Check the CRC if we're at the end of the file + if eof and self._running_crc != self._expected_crc: + raise BadZipfile("Bad CRC-32 for file %r" % self.name) + + def read1(self, n): + """Read up to n bytes with at most one read() system call.""" + + # Simplify algorithm (branching) by transforming negative n to large n. + if n < 0 or n is None: + n = self.MAX_N + + # Bytes available in read buffer. + len_readbuffer = len(self._readbuffer) - self._offset + + # Read from file. + if self._compress_left > 0 and n > len_readbuffer + len(self._unconsumed): + nbytes = n - len_readbuffer - len(self._unconsumed) + nbytes = max(nbytes, self.MIN_READ_SIZE) + nbytes = min(nbytes, self._compress_left) + + data = self._fileobj.read(nbytes) + self._compress_left -= len(data) + + if data and self._decrypter is not None: + data = ''.join(map(self._decrypter, data)) + + if self._compress_type == ZIP_STORED: + self._update_crc(data, eof=(self._compress_left==0)) + self._readbuffer = self._readbuffer[self._offset:] + data + self._offset = 0 + else: + # Prepare deflated bytes for decompression. + self._unconsumed += data + + # Handle unconsumed data. + if (len(self._unconsumed) > 0 and n > len_readbuffer and + self._compress_type == ZIP_DEFLATED): + data = self._decompressor.decompress( + self._unconsumed, + max(n - len_readbuffer, self.MIN_READ_SIZE) + ) + + self._unconsumed = self._decompressor.unconsumed_tail + eof = len(self._unconsumed) == 0 and self._compress_left == 0 + if eof: + data += self._decompressor.flush() + + self._update_crc(data, eof=eof) + self._readbuffer = self._readbuffer[self._offset:] + data + self._offset = 0 + + # Read from buffer. + data = self._readbuffer[self._offset: self._offset + n] + self._offset += len(data) + return data + + + +class ZipFile: + """ Class with methods to open, read, write, close, list zip files. + + z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=False) + + file: Either the path to the file, or a file-like object. + If it is a path, the file will be opened and closed by ZipFile. + mode: The mode can be either read "r", write "w" or append "a". + compression: ZIP_STORED (no compression) or ZIP_DEFLATED (requires zlib). + allowZip64: if True ZipFile will create files with ZIP64 extensions when + needed, otherwise it will raise an exception when this would + be necessary. + + """ + + fp = None # Set here since __del__ checks it + + def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False): + """Open the ZIP file with mode read "r", write "w" or append "a".""" + if mode not in ("r", "w", "a"): + raise RuntimeError('ZipFile() requires mode "r", "w", or "a"') + + if compression == ZIP_STORED: + pass + elif compression == ZIP_DEFLATED: + if not zlib: + raise RuntimeError,\ + "Compression requires the (missing) zlib module" + else: + raise RuntimeError, "That compression method is not supported" + + self._allowZip64 = allowZip64 + self._didModify = False + self.debug = 0 # Level of printing: 0 through 3 + self.NameToInfo = {} # Find file info given name + self.filelist = [] # List of ZipInfo instances for archive + self.compression = compression # Method of compression + self.mode = key = mode.replace('b', '')[0] + self.pwd = None + self.comment = '' + + # Check if we were passed a file-like object + if isinstance(file, basestring): + self._filePassed = 0 + self.filename = file + modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'} + try: + self.fp = open(file, modeDict[mode]) + except IOError: + if mode == 'a': + mode = key = 'w' + self.fp = open(file, modeDict[mode]) + else: + raise + else: + self._filePassed = 1 + self.fp = file + self.filename = getattr(file, 'name', None) + + if key == 'r': + self._GetContents() + elif key == 'w': + # set the modified flag so central directory gets written + # even if no files are added to the archive + self._didModify = True + elif key == 'a': + try: + # See if file is a zip file + self._RealGetContents() + # seek to start of directory and overwrite + self.fp.seek(self.start_dir, 0) + except BadZipfile: + # file is not a zip file, just append + self.fp.seek(0, 2) + + # set the modified flag so central directory gets written + # even if no files are added to the archive + self._didModify = True + else: + if not self._filePassed: + self.fp.close() + self.fp = None + raise RuntimeError, 'Mode must be "r", "w" or "a"' + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + def _GetContents(self): + """Read the directory, making sure we close the file if the format + is bad.""" + try: + self._RealGetContents() + except BadZipfile: + if not self._filePassed: + self.fp.close() + self.fp = None + raise + + def _RealGetContents(self): + """Read in the table of contents for the ZIP file.""" + fp = self.fp + try: + endrec = _EndRecData(fp) + except IOError: + raise BadZipfile("File is not a zip file") + if not endrec: + raise BadZipfile, "File is not a zip file" + if self.debug > 1: + print endrec + size_cd = endrec[_ECD_SIZE] # bytes in central directory + offset_cd = endrec[_ECD_OFFSET] # offset of central directory + self.comment = endrec[_ECD_COMMENT] # archive comment + + # "concat" is zero, unless zip was concatenated to another file + concat = endrec[_ECD_LOCATION] - size_cd - offset_cd + if endrec[_ECD_SIGNATURE] == stringEndArchive64: + # If Zip64 extension structures are present, account for them + concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) + + if self.debug > 2: + inferred = concat + offset_cd + print "given, inferred, offset", offset_cd, inferred, concat + # self.start_dir: Position of start of central directory + self.start_dir = offset_cd + concat + fp.seek(self.start_dir, 0) + data = fp.read(size_cd) + fp = cStringIO.StringIO(data) + total = 0 + while total < size_cd: + centdir = fp.read(sizeCentralDir) + if centdir[0:4] != stringCentralDir: + raise BadZipfile, "Bad magic number for central directory" + centdir = struct.unpack(structCentralDir, centdir) + if self.debug > 2: + print centdir + filename = fp.read(centdir[_CD_FILENAME_LENGTH]) + # Create ZipInfo instance to store file information + x = ZipInfo(filename) + x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH]) + x.comment = fp.read(centdir[_CD_COMMENT_LENGTH]) + x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET] + (x.create_version, x.create_system, x.extract_version, x.reserved, + x.flag_bits, x.compress_type, t, d, + x.CRC, x.compress_size, x.file_size) = centdir[1:12] + x.volume, x.internal_attr, x.external_attr = centdir[15:18] + # Convert date/time code to (year, month, day, hour, min, sec) + x._raw_time = t + x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F, + t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) + + x._decodeExtra() + x.header_offset = x.header_offset + concat + x.filename = x._decodeFilename() + self.filelist.append(x) + self.NameToInfo[x.filename] = x + + # update total bytes read from central directory + total = (total + sizeCentralDir + centdir[_CD_FILENAME_LENGTH] + + centdir[_CD_EXTRA_FIELD_LENGTH] + + centdir[_CD_COMMENT_LENGTH]) + + if self.debug > 2: + print "total", total + + + def namelist(self): + """Return a list of file names in the archive.""" + l = [] + for data in self.filelist: + l.append(data.filename) + return l + + def infolist(self): + """Return a list of class ZipInfo instances for files in the + archive.""" + return self.filelist + + def printdir(self): + """Print a table of contents for the zip file.""" + print "%-46s %19s %12s" % ("File Name", "Modified ", "Size") + for zinfo in self.filelist: + date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time[:6] + print "%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size) + + def testzip(self): + """Read all the files and check the CRC.""" + chunk_size = 2 ** 20 + for zinfo in self.filelist: + try: + # Read by chunks, to avoid an OverflowError or a + # MemoryError with very large embedded files. + f = self.open(zinfo.filename, "r") + while f.read(chunk_size): # Check CRC-32 + pass + except BadZipfile: + return zinfo.filename + + def getinfo(self, name): + """Return the instance of ZipInfo given 'name'.""" + info = self.NameToInfo.get(name) + if info is None: + raise KeyError( + 'There is no item named %r in the archive' % name) + + return info + + def setpassword(self, pwd): + """Set default password for encrypted files.""" + self.pwd = pwd + + def read(self, name, pwd=None): + """Return file bytes (as a string) for name.""" + return self.open(name, "r", pwd).read() + + def open(self, name, mode="r", pwd=None): + """Return file-like object for 'name'.""" + if mode not in ("r", "U", "rU"): + raise RuntimeError, 'open() requires mode "r", "U", or "rU"' + if not self.fp: + raise RuntimeError, \ + "Attempt to read ZIP archive that was already closed" + + # Only open a new file for instances where we were not + # given a file object in the constructor + if self._filePassed: + zef_file = self.fp + else: + zef_file = open(self.filename, 'rb') + + # Make sure we have an info object + if isinstance(name, ZipInfo): + # 'name' is already an info object + zinfo = name + else: + # Get info object for name + zinfo = self.getinfo(name) + + zef_file.seek(zinfo.header_offset, 0) + + # Skip the file header: + fheader = zef_file.read(sizeFileHeader) + if fheader[0:4] != stringFileHeader: + raise BadZipfile, "Bad magic number for file header" + + fheader = struct.unpack(structFileHeader, fheader) + fname = zef_file.read(fheader[_FH_FILENAME_LENGTH]) + if fheader[_FH_EXTRA_FIELD_LENGTH]: + zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH]) + + if fname != zinfo.orig_filename: + raise BadZipfile, \ + 'File name in directory "%s" and header "%s" differ.' % ( + zinfo.orig_filename, fname) + + # check for encrypted flag & handle password + is_encrypted = zinfo.flag_bits & 0x1 + zd = None + if is_encrypted: + if not pwd: + pwd = self.pwd + if not pwd: + raise RuntimeError, "File %s is encrypted, " \ + "password required for extraction" % name + + zd = _ZipDecrypter(pwd) + # The first 12 bytes in the cypher stream is an encryption header + # used to strengthen the algorithm. The first 11 bytes are + # completely random, while the 12th contains the MSB of the CRC, + # or the MSB of the file time depending on the header type + # and is used to check the correctness of the password. + bytes = zef_file.read(12) + h = map(zd, bytes[0:12]) + if zinfo.flag_bits & 0x8: + # compare against the file type from extended local headers + check_byte = (zinfo._raw_time >> 8) & 0xff + else: + # compare against the CRC otherwise + check_byte = (zinfo.CRC >> 24) & 0xff + if ord(h[11]) != check_byte: + raise RuntimeError("Bad password for file", name) + + return ZipExtFile(zef_file, mode, zinfo, zd) + + def extract(self, member, path=None, pwd=None): + """Extract a member from the archive to the current working directory, + using its full name. Its file information is extracted as accurately + as possible. `member' may be a filename or a ZipInfo object. You can + specify a different directory using `path'. + """ + if not isinstance(member, ZipInfo): + member = self.getinfo(member) + + if path is None: + path = os.getcwd() + + return self._extract_member(member, path, pwd) + + def extractall(self, path=None, members=None, pwd=None): + """Extract all members from the archive to the current working + directory. `path' specifies a different directory to extract to. + `members' is optional and must be a subset of the list returned + by namelist(). + """ + if members is None: + members = self.namelist() + + for zipinfo in members: + self.extract(zipinfo, path, pwd) + + def _extract_member(self, member, targetpath, pwd): + """Extract the ZipInfo object 'member' to a physical + file on the path targetpath. + """ + # build the destination pathname, replacing + # forward slashes to platform specific separators. + # Strip trailing path separator, unless it represents the root. + if (targetpath[-1:] in (os.path.sep, os.path.altsep) + and len(os.path.splitdrive(targetpath)[1]) > 1): + targetpath = targetpath[:-1] + + # don't include leading "/" from file name if present + if member.filename[0] == '/': + targetpath = os.path.join(targetpath, member.filename[1:]) + else: + targetpath = os.path.join(targetpath, member.filename) + + targetpath = os.path.normpath(targetpath) + + # Create all upper directories if necessary. + upperdirs = os.path.dirname(targetpath) + if upperdirs and not os.path.exists(upperdirs): + os.makedirs(upperdirs) + + if member.filename[-1] == '/': + if not os.path.isdir(targetpath): + os.mkdir(targetpath) + return targetpath + + source = self.open(member, pwd=pwd) + target = file(targetpath, "wb") + shutil.copyfileobj(source, target) + source.close() + target.close() + + return targetpath + + def _writecheck(self, zinfo): + """Check for errors before writing a file to the archive.""" + if zinfo.filename in self.NameToInfo: + if self.debug: # Warning for duplicate names + print "Duplicate name:", zinfo.filename + if self.mode not in ("w", "a"): + raise RuntimeError, 'write() requires mode "w" or "a"' + if not self.fp: + raise RuntimeError, \ + "Attempt to write ZIP archive that was already closed" + if zinfo.compress_type == ZIP_DEFLATED and not zlib: + raise RuntimeError, \ + "Compression requires the (missing) zlib module" + if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED): + raise RuntimeError, \ + "That compression method is not supported" + if zinfo.file_size > ZIP64_LIMIT: + if not self._allowZip64: + raise LargeZipFile("Filesize would require ZIP64 extensions") + if zinfo.header_offset > ZIP64_LIMIT: + if not self._allowZip64: + raise LargeZipFile("Zipfile size would require ZIP64 extensions") + + def write(self, filename, arcname=None, compress_type=None): + """Put the bytes from filename into the archive under the name + arcname.""" + if not self.fp: + raise RuntimeError( + "Attempt to write to ZIP archive that was already closed") + + st = os.stat(filename) + isdir = stat.S_ISDIR(st.st_mode) + mtime = time.localtime(st.st_mtime) + date_time = mtime[0:6] + # Create ZipInfo instance to store file information + if arcname is None: + arcname = filename + arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) + while arcname[0] in (os.sep, os.altsep): + arcname = arcname[1:] + if isdir: + arcname += '/' + zinfo = ZipInfo(arcname, date_time) + zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes + if compress_type is None: + zinfo.compress_type = self.compression + else: + zinfo.compress_type = compress_type + + zinfo.file_size = st.st_size + zinfo.flag_bits = 0x00 + zinfo.header_offset = self.fp.tell() # Start of header bytes + + self._writecheck(zinfo) + self._didModify = True + + if isdir: + zinfo.file_size = 0 + zinfo.compress_size = 0 + zinfo.CRC = 0 + self.filelist.append(zinfo) + self.NameToInfo[zinfo.filename] = zinfo + self.fp.write(zinfo.FileHeader()) + return + + with open(filename, "rb") as fp: + # Must overwrite CRC and sizes with correct data later + zinfo.CRC = CRC = 0 + zinfo.compress_size = compress_size = 0 + zinfo.file_size = file_size = 0 + self.fp.write(zinfo.FileHeader()) + if zinfo.compress_type == ZIP_DEFLATED: + cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, + zlib.DEFLATED, -15) + else: + cmpr = None + while 1: + buf = fp.read(1024 * 8) + if not buf: + break + file_size = file_size + len(buf) + CRC = crc32(buf, CRC) & 0xffffffff + if cmpr: + buf = cmpr.compress(buf) + compress_size = compress_size + len(buf) + self.fp.write(buf) + if cmpr: + buf = cmpr.flush() + compress_size = compress_size + len(buf) + self.fp.write(buf) + zinfo.compress_size = compress_size + else: + zinfo.compress_size = file_size + zinfo.CRC = CRC + zinfo.file_size = file_size + # Seek backwards and write CRC and file sizes + position = self.fp.tell() # Preserve current position in file + self.fp.seek(zinfo.header_offset + 14, 0) + self.fp.write(struct.pack(" ZIP64_LIMIT \ + or zinfo.compress_size > ZIP64_LIMIT: + extra.append(zinfo.file_size) + extra.append(zinfo.compress_size) + file_size = 0xffffffff + compress_size = 0xffffffff + else: + file_size = zinfo.file_size + compress_size = zinfo.compress_size + + if zinfo.header_offset > ZIP64_LIMIT: + extra.append(zinfo.header_offset) + header_offset = 0xffffffffL + else: + header_offset = zinfo.header_offset + + extra_data = zinfo.extra + if extra: + # Append a ZIP64 field to the extra's + extra_data = struct.pack( + '>sys.stderr, (structCentralDir, + stringCentralDir, create_version, + zinfo.create_system, extract_version, zinfo.reserved, + zinfo.flag_bits, zinfo.compress_type, dostime, dosdate, + zinfo.CRC, compress_size, file_size, + len(zinfo.filename), len(extra_data), len(zinfo.comment), + 0, zinfo.internal_attr, zinfo.external_attr, + header_offset) + raise + self.fp.write(centdir) + self.fp.write(filename) + self.fp.write(extra_data) + self.fp.write(zinfo.comment) + + pos2 = self.fp.tell() + # Write end-of-zip-archive record + centDirCount = count + centDirSize = pos2 - pos1 + centDirOffset = pos1 + if (centDirCount >= ZIP_FILECOUNT_LIMIT or + centDirOffset > ZIP64_LIMIT or + centDirSize > ZIP64_LIMIT): + # Need to write the ZIP64 end-of-archive records + zip64endrec = struct.pack( + structEndArchive64, stringEndArchive64, + 44, 45, 45, 0, 0, centDirCount, centDirCount, + centDirSize, centDirOffset) + self.fp.write(zip64endrec) + + zip64locrec = struct.pack( + structEndArchive64Locator, + stringEndArchive64Locator, 0, pos2, 1) + self.fp.write(zip64locrec) + centDirCount = min(centDirCount, 0xFFFF) + centDirSize = min(centDirSize, 0xFFFFFFFF) + centDirOffset = min(centDirOffset, 0xFFFFFFFF) + + # check for valid comment length + if len(self.comment) >= ZIP_MAX_COMMENT: + if self.debug > 0: + msg = 'Archive comment is too long; truncating to %d bytes' \ + % ZIP_MAX_COMMENT + self.comment = self.comment[:ZIP_MAX_COMMENT] + + endrec = struct.pack(structEndArchive, stringEndArchive, + 0, 0, centDirCount, centDirCount, + centDirSize, centDirOffset, len(self.comment)) + self.fp.write(endrec) + self.fp.write(self.comment) + self.fp.flush() + + if not self._filePassed: + self.fp.close() + self.fp = None + + +class PyZipFile(ZipFile): + """Class to create ZIP archives with Python library files and packages.""" + + def writepy(self, pathname, basename = ""): + """Add all files from "pathname" to the ZIP archive. + + If pathname is a package directory, search the directory and + all package subdirectories recursively for all *.py and enter + the modules into the archive. If pathname is a plain + directory, listdir *.py and enter all modules. Else, pathname + must be a Python *.py file and the module will be put into the + archive. Added modules are always module.pyo or module.pyc. + This method will compile the module.py into module.pyc if + necessary. + """ + dir, name = os.path.split(pathname) + if os.path.isdir(pathname): + initname = os.path.join(pathname, "__init__.py") + if os.path.isfile(initname): + # This is a package directory, add it + if basename: + basename = "%s/%s" % (basename, name) + else: + basename = name + if self.debug: + print "Adding package in", pathname, "as", basename + fname, arcname = self._get_codename(initname[0:-3], basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + dirlist = os.listdir(pathname) + dirlist.remove("__init__.py") + # Add all *.py files and package subdirectories + for filename in dirlist: + path = os.path.join(pathname, filename) + root, ext = os.path.splitext(filename) + if os.path.isdir(path): + if os.path.isfile(os.path.join(path, "__init__.py")): + # This is a package directory, add it + self.writepy(path, basename) # Recursive call + elif ext == ".py": + fname, arcname = self._get_codename(path[0:-3], + basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + else: + # This is NOT a package directory, add its files at top level + if self.debug: + print "Adding files from directory", pathname + for filename in os.listdir(pathname): + path = os.path.join(pathname, filename) + root, ext = os.path.splitext(filename) + if ext == ".py": + fname, arcname = self._get_codename(path[0:-3], + basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + else: + if pathname[-3:] != ".py": + raise RuntimeError, \ + 'Files added with writepy() must end with ".py"' + fname, arcname = self._get_codename(pathname[0:-3], basename) + if self.debug: + print "Adding file", arcname + self.write(fname, arcname) + + def _get_codename(self, pathname, basename): + """Return (filename, archivename) for the path. + + Given a module name path, return the correct file path and + archive name, compiling if necessary. For example, given + /python/lib/string, return (/python/lib/string.pyc, string). + """ + file_py = pathname + ".py" + file_pyc = pathname + ".pyc" + file_pyo = pathname + ".pyo" + if os.path.isfile(file_pyo) and \ + os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime: + fname = file_pyo # Use .pyo file + elif not os.path.isfile(file_pyc) or \ + os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime: + import py_compile + if self.debug: + print "Compiling", file_py + try: + py_compile.compile(file_py, file_pyc, None, True) + except py_compile.PyCompileError,err: + print err.msg + fname = file_pyc + else: + fname = file_pyc + archivename = os.path.split(fname)[1] + if basename: + archivename = "%s/%s" % (basename, archivename) + return (fname, archivename) + + +def main(args = None): + import textwrap + USAGE=textwrap.dedent("""\ + Usage: + zipfile.py -l zipfile.zip # Show listing of a zipfile + zipfile.py -t zipfile.zip # Test if a zipfile is valid + zipfile.py -e zipfile.zip target # Extract zipfile into target dir + zipfile.py -c zipfile.zip src ... # Create zipfile from sources + """) + if args is None: + args = sys.argv[1:] + + if not args or args[0] not in ('-l', '-c', '-e', '-t'): + print USAGE + sys.exit(1) + + if args[0] == '-l': + if len(args) != 2: + print USAGE + sys.exit(1) + zf = ZipFile(args[1], 'r') + zf.printdir() + zf.close() + + elif args[0] == '-t': + if len(args) != 2: + print USAGE + sys.exit(1) + zf = ZipFile(args[1], 'r') + badfile = zf.testzip() + if badfile: + print("The following enclosed file is corrupted: {!r}".format(badfile)) + print "Done testing" + + elif args[0] == '-e': + if len(args) != 3: + print USAGE + sys.exit(1) + + zf = ZipFile(args[1], 'r') + out = args[2] + for path in zf.namelist(): + if path.startswith('./'): + tgt = os.path.join(out, path[2:]) + else: + tgt = os.path.join(out, path) + + tgtdir = os.path.dirname(tgt) + if not os.path.exists(tgtdir): + os.makedirs(tgtdir) + with open(tgt, 'wb') as fp: + fp.write(zf.read(path)) + zf.close() + + elif args[0] == '-c': + if len(args) < 3: + print USAGE + sys.exit(1) + + def addToZip(zf, path, zippath): + if os.path.isfile(path): + zf.write(path, zippath, ZIP_DEFLATED) + elif os.path.isdir(path): + for nm in os.listdir(path): + addToZip(zf, + os.path.join(path, nm), os.path.join(zippath, nm)) + # else: ignore + + zf = ZipFile(args[1], 'w', allowZip64=True) + for src in args[2:]: + addToZip(zf, src, os.path.basename(src)) + + zf.close() + +if __name__ == "__main__": + main() diff --git a/androlyze.py b/androlyze.py new file mode 100755 index 00000000..29f46c9a --- /dev/null +++ b/androlyze.py @@ -0,0 +1,328 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os, cmd, threading, code, re + +from optparse import OptionParser + +from androguard.core import * +from androguard.core.androgen import * +from androguard.core.androconf import * +from androguard.core.bytecode import * +from androguard.core.bytecodes.jvm import * +from androguard.core.bytecodes.dvm import * +from androguard.core.bytecodes.apk import * + +from androguard.core.analysis.analysis import * +from androguard.core.analysis.ganalysis import * +from androguard.core.analysis.risk import * +from androguard.decompiler.decompiler import * + + +from androguard.core import androconf + +from IPython.frontend.terminal.embed import InteractiveShellEmbed +from IPython.config.loader import Config + +from cPickle import dumps, loads + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename', 'nargs' : 1 } +option_1 = { 'name' : ('-d', '--display'), 'help' : 'display the file in human readable format', 'action' : 'count' } +option_2 = { 'name' : ('-m', '--method'), 'help' : 'display method(s) respect with a regexp', 'nargs' : 1 } +option_3 = { 'name' : ('-f', '--field'), 'help' : 'display field(s) respect with a regexp', 'nargs' : 1 } +option_4 = { 'name' : ('-s', '--shell'), 'help' : 'open an interactive shell to play more easily with objects', 'action' : 'count' } +option_5 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } +option_6 = { 'name' : ('-p', '--pretty'), 'help' : 'pretty print !', 'action' : 'count' } +option_8 = { 'name' : ('-x', '--xpermissions'), 'help' : 'show paths of permissions', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4, option_5, option_6, option_8] + + +def init_print_colors(): + from IPython.utils import coloransi, io + default_colors(coloransi.TermColors) + CONF["PRINT_FCT"] = io.stdout.write + + +def interact(): + cfg = Config() + ipshell = InteractiveShellEmbed(config=cfg, banner1="Androlyze version %s" % androconf.ANDROGUARD_VERSION) + init_print_colors() + ipshell() + + +def save_session(l, filename): + """ + save your session ! + + :param l: a list of objects + :type: a list of object + :param filename: output filename to save the session + :type filename: string + + :Example: + save_session([a, vm, vmx], "msession.json") + """ + fd = open(filename, "w") + fd.write(dumps(l, -1)) + fd.close() + + +def load_session(filename): + """ + load your session ! + + :param filename: the filename where the session has been saved + :type filename: string + + :rtype: the elements of your session :) + + :Example: + a, vm, vmx = load_session("mysession.json") + """ + return loads(open(filename, "r").read()) + + +def AnalyzeAPK(filename, raw=False, decompiler=None): + """ + Analyze an android application and setup all stuff for a more quickly analysis ! + + :param filename: the filename of the android application or a buffer which represents the application + :type filename: string + :param raw: True is you would like to use a buffer (optional) + :type raw: boolean + :param decompiler: ded, dex2jad, dad (optional) + :type decompiler: string + + :rtype: return the :class:`APK`, :class:`DalvikVMFormat`, and :class:`VMAnalysis` objects + """ + androconf.debug("APK ...") + a = APK(filename, raw) + d, dx = AnalyzeDex(a.get_dex(), raw=True, decompiler=decompiler) + return a, d, dx + + +def AnalyzeDex(filename, raw=False, decompiler=None): + """ + Analyze an android dex file and setup all stuff for a more quickly analysis ! + + :param filename: the filename of the android dex file or a buffer which represents the dex file + :type filename: string + :param raw: True is you would like to use a buffer (optional) + :type raw: boolean + + :rtype: return the :class:`DalvikVMFormat`, and :class:`VMAnalysis` objects + """ + androconf.debug("DalvikVMFormat ...") + + d = None + if raw == False: + d = DalvikVMFormat(open(filename, "rb").read()) + else: + d = DalvikVMFormat(filename) + + androconf.debug("Export VM to python namespace") + d.create_python_export() + + androconf.debug("VMAnalysis ...") + dx = uVMAnalysis(d) + + androconf.debug("GVMAnalysis ...") + gx = GVMAnalysis(dx, None) + + d.set_vmanalysis(dx) + d.set_gvmanalysis(gx) + + RunDecompiler(d, dx, decompiler) + + androconf.debug("XREF ...") + d.create_xref() + androconf.debug("DREF ...") + d.create_dref() + + return d, dx + + +def AnalyzeODex(filename, raw=False, decompiler=None): + """ + Analyze an android odex file and setup all stuff for a more quickly analysis ! + + :param filename: the filename of the android dex file or a buffer which represents the dex file + :type filename: string + :param raw: True is you would like to use a buffer (optional) + :type raw: boolean + + :rtype: return the :class:`DalvikOdexVMFormat`, and :class:`VMAnalysis` objects + """ + androconf.debug("DalvikOdexVMFormat ...") + d = None + if raw == False: + d = DalvikOdexVMFormat(open(filename, "rb").read()) + else: + d = DalvikOdexVMFormat(filename) + + androconf.debug("Export VM to python namespace") + d.create_python_export() + + androconf.debug("VMAnalysis ...") + dx = uVMAnalysis(d) + + androconf.debug("GVMAnalysis ...") + gx = GVMAnalysis(dx, None) + + d.set_vmanalysis(dx) + d.set_gvmanalysis(gx) + + RunDecompiler(d, dx, decompiler) + + androconf.debug("XREF ...") + d.create_xref() + androconf.debug("DREF ...") + d.create_dref() + + return d, dx + + +def RunDecompiler(d, dx, decompiler): + """ + Run the decompiler on a specific analysis + + :param d: the DalvikVMFormat object + :type d: :class:`DalvikVMFormat` object + :param dx: the analysis of the format + :type dx: :class:`VMAnalysis` object + :param decompiler: the type of decompiler to use ("dad", "dex2jad", "ded") + :type decompiler: string + """ + if decompiler != None: + androconf.debug("Decompiler ...") + decompiler = decompiler.lower() + if decompiler == "dex2jad": + d.set_decompiler(DecompilerDex2Jad(d, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_JAD"], + androconf.CONF["BIN_JAD"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler == "dex2fernflower": + d.set_decompiler(DecompilerDex2Fernflower(d, + androconf.CONF["PATH_DEX2JAR"], + androconf.CONF["BIN_DEX2JAR"], + androconf.CONF["PATH_FERNFLOWER"], + androconf.CONF["BIN_FERNFLOWER"], + androconf.CONF["OPTIONS_FERNFLOWER"], + androconf.CONF["TMP_DIRECTORY"])) + elif decompiler == "ded": + d.set_decompiler(DecompilerDed(d, + androconf.CONF["PATH_DED"], + androconf.CONF["BIN_DED"], + androconf.CONF["TMP_DIRECTORY"])) + else: + d.set_decompiler(DecompilerDAD(d, dx)) + + +def AnalyzeElf(filename, raw=False): + # avoid to install smiasm for everybody + from androguard.core.binaries.elf import ELF + + e = None + if raw == False: + e = ELF(open(filename, "rb").read()) + else: + e = ELF(filename) + + ExportElfToPython(e) + + return e + + +def ExportElfToPython(e): + for function in e.get_functions(): + name = "FUNCTION_" + function.name + setattr(e, name, function) + + +def AnalyzeJAR(filename, raw=False): + androconf.debug("JAR ...") + a = JAR(filename, raw) + + d = AnalyzeClasses(a.get_classes()) + + return a, d + + +def AnalyzeClasses(classes): + d = {} + for i in classes: + d[i[0]] = JVMFormat(i[1]) + + return d + + +def main(options, arguments): + if options.shell != None: + interact() + + elif options.input != None : + _a = AndroguardS( options.input ) + + if options.pretty != None : + init_print_colors() + + if options.display != None : + if options.pretty != None : + _a.ianalyze() + _a.pretty_show() + else : + _a.show() + + elif options.method != None : + for method in _a.get("method", options.method) : + if options.pretty != None : + _a.ianalyze() + method.pretty_show() + else : + method.show() + + elif options.field != None : + for field in _a.get("field", options.field) : + field.show() + + elif options.xpermissions != None : + _a.ianalyze() + perms_access = _a.get_analysis().get_permissions( [] ) + for perm in perms_access : + print "PERM : ", perm + for path in perms_access[ perm ] : + show_Path( _a.get_vm(), path ) + + elif options.version != None : + print "Androlyze version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/andromercury.py b/andromercury.py new file mode 100755 index 00000000..5484b935 --- /dev/null +++ b/andromercury.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, re, os + +from optparse import OptionParser + +from androguard.core.bytecodes import apk + +sys.path.append("./elsim/") +from elsim.elsign import dalvik_elsign + +sys.path.append("./mercury/client") +from merc.lib.common import Session + +option_0 = { 'name' : ('-l', '--list'), 'help' : 'list all packages', 'nargs' : 1 } +option_1 = { 'name' : ('-i', '--input'), 'help' : 'get specific packages (a filter)', 'nargs' : 1 } +option_2 = { 'name' : ('-r', '--remotehost'), 'help' : 'specify ip of emulator/device', 'nargs' : 1 } +option_3 = { 'name' : ('-p', '--port'), 'help' : 'specify the port', 'nargs' : 1 } +option_4 = { 'name' : ('-o', '--output'), 'help' : 'output directory to write packages', 'nargs' : 1 } +option_5 = { 'name' : ('-b', '--database'), 'help' : 'database : use this database', 'nargs' : 1 } +option_6 = { 'name' : ('-c', '--config'), 'help' : 'use this configuration', 'nargs' : 1 } +option_7 = { 'name' : ('-v', '--verbose'), 'help' : 'display debug information', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4, option_5, option_6, option_7] + +def display(ret, debug) : + print "---->", ret[0], + +def main(options, arguments) : + sessionip = "127.0.0.1" + sessionport = 31415 + + if options.remotehost : + sessionip = options.remotehost + + if options.port : + sessionport = int(options.port) + + newsession = Session(sessionip, sessionport, "bind") + + # Check if connection can be established + if newsession.executeCommand("core", "ping", None).data == "pong": + + if options.list : + request = {'filter': options.list, 'permissions': None } + apks_info = newsession.executeCommand("packages", "info", {}).getPaddedErrorOrData() + print apks_info + + elif options.input and options.output : + s = None + if options.database != None or options.config != None : + s = dalvik_elsign.MSignature( options.database, options.config, options.verbose != None, ps = dalvik_elsign.PublicSignature) + + request = {'filter': options.input, 'permissions': None } + apks_info = newsession.executeCommand("packages", "info", request).getPaddedErrorOrData() + print apks_info + + for i in apks_info.split("\n") : + if re.match("APK path:", i) != None : + name_app = i.split(":")[1][1:] + print name_app, + response = newsession.downloadFile(name_app, options.output) + print response.data, response.error, + + if s != None : + a = apk.APK( options.output + "/" + os.path.basename(name_app) ) + if a.is_valid_APK() : + display( s.check_apk( a ), options.verbose ) + print + else: + print "\n**Network Error** Could not connect to " + sessionip + ":" + str(sessionport) + "\n" + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androrisk.py b/androrisk.py new file mode 100755 index 00000000..d7b63e4d --- /dev/null +++ b/androrisk.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os + +from optparse import OptionParser + +from androguard.core import androconf +from androguard.core.bytecodes import apk +from androguard.core.analysis import risk + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use these filenames', 'nargs' : 1 } +option_1 = { 'name' : ('-m', '--method'), 'help' : 'perform analysis of each method', 'action' : 'count' } +option_2 = { 'name' : ('-d', '--directory'), 'help' : 'directory : use this directory', 'nargs' : 1 } +option_3 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3] + +def display_result(res) : + for i in res : + print "\t", i + for j in res[i] : + print "\t\t", j, res[i][j] + +def analyze_app(filename, ri, a) : + print filename + display_result( ri.with_apk( a ) ) + +def analyze_dex(filename, ri, d) : + print filename + display_result( ri.with_dex( d ) ) + +def main(options, arguments) : + ri = risk.RiskIndicator() + ri.add_risk_analysis( risk.RedFlags() ) + ri.add_risk_analysis( risk.FuzzyRisk() ) + + if options.input != None : + ret_type = androconf.is_android( options.input ) + if ret_type == "APK" : + a = apk.APK( options.input ) + analyze_app( options.input, ri, a ) + elif ret_type == "DEX" : + analyze_dex( options.input, ri, open(options.input, "r").read() ) + + + elif options.directory != None : + for root, dirs, files in os.walk( options.directory, followlinks=True ) : + if files != [] : + for f in files : + real_filename = root + if real_filename[-1] != "/" : + real_filename += "/" + real_filename += f + + ret_type = androconf.is_android( real_filename ) + if ret_type == "APK" : + try : + a = apk.APK( real_filename ) + analyze_app( real_filename, ri, a ) + except Exception, e : + print e + + elif ret_type == "DEX" : + analyze_dex( real_filename, ri, open(real_filename, "r").read() ) + + elif options.version != None : + print "Androrisk version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androsign.py b/androsign.py new file mode 100755 index 00000000..21619b03 --- /dev/null +++ b/androsign.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os + +from optparse import OptionParser + +from androguard.core import androconf +from androguard.core.bytecodes import apk + +sys.path.append("./elsim/") +from elsim.elsign import dalvik_elsign + + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use this filename', 'nargs' : 1 } +option_1 = { 'name' : ('-d', '--directory'), 'help' : 'directory : use this directory', 'nargs' : 1 } +option_2 = { 'name' : ('-b', '--database'), 'help' : 'database : use this database', 'nargs' : 1 } +option_3 = { 'name' : ('-c', '--config'), 'help' : 'use this configuration', 'nargs' : 1 } +option_4 = { 'name' : ('-v', '--verbose'), 'help' : 'display debug information', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4] + +def display(ret, debug) : + print "---->", ret[0] + sys.stdout.flush() + +def main(options, arguments) : + if options.database == None or options.config == None : + return + + s = dalvik_elsign.MSignature( options.database, options.config, options.verbose != None, ps = dalvik_elsign.PublicSignature) + + if options.input != None : + ret_type = androconf.is_android( options.input ) + + print os.path.basename(options.input), ":", + sys.stdout.flush() + if ret_type == "APK" : + try : + a = apk.APK( options.input ) + if a.is_valid_APK() : + display( s.check_apk( a ), options.verbose ) + else : + print "INVALID" + except Exception, e : + print "ERROR", e + + elif ret_type == "DEX" : + display( s.check_dex( open(options.input, "rb").read() ), options.verbose ) + elif options.directory != None : + for root, dirs, files in os.walk( options.directory, followlinks=True ) : + if files != [] : + for f in files : + real_filename = root + if real_filename[-1] != "/" : + real_filename += "/" + real_filename += f + + ret_type = androconf.is_android( real_filename ) + if ret_type == "APK" : + print os.path.basename( real_filename ), ":", + sys.stdout.flush() + try : + a = apk.APK( real_filename ) + if a.is_valid_APK() : + display( s.check_apk( a ), options.verbose ) + else : + print "INVALID APK" + except Exception, e : + print "ERROR", e + elif ret_type == "DEX" : + try : + print os.path.basename( real_filename ), ":", + sys.stdout.flush() + display( s.check_dex( open(real_filename, "rb").read() ), options.verbose ) + except Exception, e : + print "ERROR", e + + elif options.version != None : + print "Androsign version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androsim.py b/androsim.py new file mode 100755 index 00000000..ff40d646 --- /dev/null +++ b/androsim.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os + +from optparse import OptionParser + +from androguard.core import androconf +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis import analysis + +sys.path.append("./elsim") +from elsim import elsim +from elsim.elsim_dalvik import ProxyDalvik, FILTERS_DALVIK_SIM +from elsim.elsim_dalvik import ProxyDalvikStringMultiple, ProxyDalvikStringOne, FILTERS_DALVIK_SIM_STRING + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'file : use these filenames', 'nargs' : 2 } +option_1 = { 'name' : ('-t', '--threshold'), 'help' : 'specify the threshold (0.0 to 1.0) to know if a method is similar. This option will impact on the filtering method. Because if you specify a higher value of the threshold, you will have more associations', 'nargs' : 1 } +option_2 = { 'name' : ('-c', '--compressor'), 'help' : 'specify the compressor (BZ2, ZLIB, SNAPPY, LZMA, XZ). The final result depends directly of the type of compressor. But if you use LZMA for example, the final result will be better, but it take more time', 'nargs' : 1 } +option_4 = { 'name' : ('-d', '--display'), 'help' : 'display all information about methods', 'action' : 'count' } +option_5 = { 'name' : ('-n', '--new'), 'help' : 'calculate the final score only by using the ratio of included methods', 'action' : 'count' } +option_6 = { 'name' : ('-e', '--exclude'), 'help' : 'exclude specific class name (python regexp)', 'nargs' : 1 } +option_7 = { 'name' : ('-s', '--size'), 'help' : 'exclude specific method below the specific size (specify the minimum size of a method to be used (it is the length (bytes) of the dalvik method)', 'nargs' : 1 } +option_8 = { 'name' : ('-x', '--xstrings'), 'help' : 'display similarities of strings', 'action' : 'count' } +option_9 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } +option_10 = { 'name' : ('-l', '--library'), 'help' : 'use python library (python) or specify the path of the shared library)', 'nargs' : 1 } + +options = [option_0, option_1, option_2, option_4, option_5, option_6, option_7, option_8, option_9, option_10] + +def check_one_file(a, d1, dx1, FS, threshold, file_input, view_strings=False, new=True, library=True) : + d2 = None + ret_type = androconf.is_android( file_input ) + if ret_type == "APK" : + a = apk.APK( file_input ) + d2 = dvm.DalvikVMFormat( a.get_dex() ) + elif ret_type == "DEX" : + d2 = dvm.DalvikVMFormat( open(file_input, "rb").read() ) + + if d2 == None : + return + dx2 = analysis.VMAnalysis( d2 ) + + el = elsim.Elsim( ProxyDalvik(d1, dx1), ProxyDalvik(d2, dx2), FS, threshold, options.compressor, libnative=library ) + el.show() + print "\t--> methods: %f%% of similarities" % el.get_similarity_value(new) + + + if options.display : + print "SIMILAR methods:" + diff_methods = el.get_similar_elements() + for i in diff_methods : + el.show_element( i ) + + print "IDENTICAL methods:" + new_methods = el.get_identical_elements() + for i in new_methods : + el.show_element( i ) + + print "NEW methods:" + new_methods = el.get_new_elements() + for i in new_methods : + el.show_element( i, False ) + + print "DELETED methods:" + del_methods = el.get_deleted_elements() + for i in del_methods : + el.show_element( i ) + + print "SKIPPED methods:" + skipped_methods = el.get_skipped_elements() + for i in skipped_methods : + el.show_element( i ) + + if view_strings : + els = elsim.Elsim( ProxyDalvikStringMultiple(d1, dx1), + ProxyDalvikStringMultiple(d2, dx2), + FILTERS_DALVIK_SIM_STRING, + threshold, + options.compressor, + libnative=library ) + #els = elsim.Elsim( ProxyDalvikStringOne(d1, dx1), + # ProxyDalvikStringOne(d2, dx2), FILTERS_DALVIK_SIM_STRING, threshold, options.compressor, libnative=library ) + els.show() + print "\t--> strings: %f%% of similarities" % els.get_similarity_value(new) + + if options.display : + print "SIMILAR strings:" + diff_strings = els.get_similar_elements() + for i in diff_strings : + els.show_element( i ) + + print "IDENTICAL strings:" + new_strings = els.get_identical_elements() + for i in new_strings : + els.show_element( i ) + + print "NEW strings:" + new_strings = els.get_new_elements() + for i in new_strings : + els.show_element( i, False ) + + print "DELETED strings:" + del_strings = els.get_deleted_elements() + for i in del_strings : + els.show_element( i ) + + print "SKIPPED strings:" + skipped_strings = els.get_skipped_elements() + for i in skipped_strings : + els.show_element( i ) + + +def check_one_directory(a, d1, dx1, FS, threshold, directory, view_strings=False, new=True, library=True) : + for root, dirs, files in os.walk( directory, followlinks=True ) : + if files != [] : + for f in files : + real_filename = root + if real_filename[-1] != "/" : + real_filename += "/" + real_filename += f + + print "filename: %s ..." % real_filename + check_one_file(a, d1, dx1, FS, threshold, real_filename, view_strings, new, library) + +############################################################ +def main(options, arguments) : + if options.input != None : + a = None + ret_type = androconf.is_android( options.input[0] ) + if ret_type == "APK" : + a = apk.APK( options.input[0] ) + d1 = dvm.DalvikVMFormat( a.get_dex() ) + elif ret_type == "DEX" : + d1 = dvm.DalvikVMFormat( open(options.input[0], "rb").read() ) + + dx1 = analysis.VMAnalysis( d1 ) + + threshold = None + if options.threshold != None : + threshold = float(options.threshold) + + FS = FILTERS_DALVIK_SIM + FS[elsim.FILTER_SKIPPED_METH].set_regexp( options.exclude ) + FS[elsim.FILTER_SKIPPED_METH].set_size( options.size ) + + new = True + if options.new != None : + new = False + + library = True + if options.library != None : + library = options.library + if options.library == "python" : + library = False + + if os.path.isdir( options.input[1] ) == False : + check_one_file( a, d1, dx1, FS, threshold, options.input[1], options.xstrings, new, library ) + else : + check_one_directory(a, d1, dx1, FS, threshold, options.input[1], options.xstrings, new, library ) + + elif options.version != None : + print "Androsim version %s" % androconf.ANDROGUARD_VERSION + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/androxgmml.py b/androxgmml.py new file mode 100755 index 00000000..204ac447 --- /dev/null +++ b/androxgmml.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +from xml.sax.saxutils import escape +import sys, os +from optparse import OptionParser + +from androguard.core.androgen import Androguard +from androguard.core.analysis import analysis + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'filename input', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--output'), 'help' : 'filename output of the xgmml', 'nargs' : 1 } +option_2 = { 'name' : ('-f', '--functions'), 'help' : 'include function calls', 'action' : 'count' } +option_3 = { 'name' : ('-e', '--externals'), 'help' : 'include extern function calls', 'action' : 'count' } +option_4 = { 'name' : ('-v', '--version'), 'help' : 'version of the API', 'action' : 'count' } + +options = [option_0, option_1, option_2, option_3, option_4] + +METHODS_ID = {} +EXTERNAL_METHODS_ID = {} +NODES_ID = {} +EDGES_ID = {} + +NODE_GRAPHIC = { + "classic" : { + "h" : 20.0, + "w" : 20.0, + "type" : "ELLIPSE", + "width" : 1, + "fill" : "#e1e1e1", + "outline" : "#000000", + }, + + "extern" : { + "h" : 20.0, + "w" : 20.0, + "type" : "ELLIPSE", + "width" : 1, + "fill" : "#ff8c00", + "outline" : "#000000", + } +} + +EDGE_GRAPHIC = { + "cfg" : { + "width" : 2, + "fill" : "#0000e1", + }, + + "fcg" : { + "width" : 3, + "fill" : "#9acd32", + }, + + "efcg" : { + "width" : 3, + "fill" : "#808000", + } +} + +def get_node_name(method, bb) : + return "%s-%s-%s" % ( method.get_class_name(), escape(bb.name), escape(method.get_descriptor()) ) + +def export_xgmml_cfg(g, fd) : + method = g.get_method() + + name = method.get_name() + class_name = method.get_class_name() + descriptor = method.get_descriptor() + + if method.get_code() != None : + size_ins = method.get_code().get_length() + + for i in g.basic_blocks.get() : + fd.write("\n" % (len(NODES_ID), get_node_name(method, i))) + + fd.write("\n" % (escape(class_name))) + fd.write("\n" % (escape(name))) + fd.write("\n" % (escape(descriptor))) + + fd.write("\n" % (i.start)) + + cl = NODE_GRAPHIC["classic"] + width = cl["width"] + fill = cl["fill"] + + # No child ... + if i.childs == [] : + fill = "#87ceeb" + + if i.start == 0 : + fd.write("\n" % (escape(name), i.get_instructions()[-1].get_name())) + width = 3 + fill = "#ff0000" + + METHODS_ID[ class_name + name + descriptor ] = len(NODES_ID) + else : + fd.write("\n" % (i.start, i.get_instructions()[-1].get_name())) + + size = 0 + for tmp_ins in i.get_instructions() : + size += (tmp_ins.get_length() / 2) + + + h = ((size / float(size_ins)) * 20) + cl["h"] + + fd.write("\n" % ( cl["type"], h, h, width, fill, cl["outline"])) + fd.write("\n") + + fd.write("\n") + + NODES_ID[ class_name + i.name + descriptor ] = len(NODES_ID) + + for i in g.basic_blocks.get() : + for j in i.childs : + if j[-1] != None : + label = "%s (cfg) %s" % (get_node_name(method, i), get_node_name(method, j[-1])) + id = len(NODES_ID) + len(EDGES_ID) + fd.write( "\n" % (id, label, NODES_ID[ class_name + i.name + descriptor ], NODES_ID[ class_name + j[-1].name + descriptor ]) ) + + cl = EDGE_GRAPHIC["cfg"] + fd.write("\n" % (cl["width"], cl["fill"]) ) + fd.write("\n") + + fd.write("\n") + + EDGES_ID[ label ] = id + +def export_xgmml_fcg(a, x, fd) : + classes = a.get_classes_names() + + # Methods flow graph + for m, _ in x.get_tainted_packages().get_packages() : + paths = m.get_methods() + for j in paths : + if j.get_method().get_class_name() in classes and m.get_info() in classes : + if j.get_access_flag() == analysis.TAINTED_PACKAGE_CALL : + t = m.get_info() + j.get_name() + j.get_descriptor() + if t not in METHODS_ID : + continue + + bb1 = x.get_method( j.get_method() ).basic_blocks.get_basic_block( j.get_idx() ) + + node1 = get_node_name(j.get_method(), bb1) + "@0x%x" % j.get_idx() + node2 = "%s-%s-%s" % (m.get_info(), escape(j.get_name()), escape(j.get_descriptor())) + + label = "%s (fcg) %s" % (node1, node2) + + if label in EDGES_ID : + continue + + id = len(NODES_ID) + len(EDGES_ID) + + fd.write( "\n" % (id, + label, + NODES_ID[ j.get_method().get_class_name() + bb1.name + j.get_method().get_descriptor() ], + METHODS_ID[ m.get_info() + j.get_name() + j.get_descriptor() ]) ) + + cl = EDGE_GRAPHIC["fcg"] + fd.write("\n" % (cl["width"], cl["fill"]) ) + fd.write("\n") + + fd.write("\n") + + EDGES_ID[ label ] = id + +def export_xgmml_efcg(a, x, fd) : + classes = a.get_classes_names() + + # Methods flow graph + for m, _ in x.get_tainted_packages().get_packages() : + paths = m.get_methods() + for j in paths : + if j.get_method().get_class_name() in classes and m.get_info() not in classes : + if j.get_access_flag() == analysis.TAINTED_PACKAGE_CALL : + t = m.get_info() + j.get_name() + j.get_descriptor() + if t not in EXTERNAL_METHODS_ID : + fd.write("\n" % (len(NODES_ID), escape(t))) + + fd.write("\n" % (escape(m.get_info()))) + fd.write("\n" % (escape(j.get_name()))) + fd.write("\n" % (escape(j.get_descriptor()))) + + cl = NODE_GRAPHIC["extern"] + + fd.write("\n" % (escape(m.get_info()), escape(j.get_name()), escape(j.get_descriptor()))) + + fd.write("\n" % ( cl["type"], cl["h"], cl["h"], cl["width"], cl["fill"], cl["outline"])) + fd.write("\n") + + fd.write("\n") + + NODES_ID[ t ] = len(NODES_ID) + EXTERNAL_METHODS_ID[ t ] = NODES_ID[ t ] + + bb1 = x.get_method( j.get_method() ).basic_blocks.get_basic_block( j.get_idx() ) + + node1 = get_node_name(j.get_method(), bb1) + "@0x%x" % j.get_idx() + node2 = "%s-%s-%s" % (m.get_info(), escape(j.get_name()), escape(j.get_descriptor())) + + label = "%s (efcg) %s" % (node1, node2) + + if label in EDGES_ID : + continue + + id = len(NODES_ID) + len(EDGES_ID) + + fd.write( "\n" % (id, + label, + NODES_ID[ j.get_method().get_class_name() + bb1.name + j.get_method().get_descriptor() ], + EXTERNAL_METHODS_ID[ m.get_info() + j.get_name() + j.get_descriptor() ]) ) + + cl = EDGE_GRAPHIC["efcg"] + fd.write("\n" % (cl["width"], cl["fill"]) ) + fd.write("\n") + + fd.write("\n") + + EDGES_ID[ label ] = id + +def export_apps_to_xgmml( input, output, fcg, efcg ) : + a = Androguard( [ input ] ) + + fd = open(output, "w") + fd.write("\n") + fd.write("\n" % (os.path.basename(input))) + + for vm in a.get_vms() : + x = analysis.VMAnalysis( vm ) + # CFG + for method in vm.get_methods() : + g = x.get_method( method ) + export_xgmml_cfg(g, fd) + + if fcg : + export_xgmml_fcg(vm, x, fd) + + if efcg : + export_xgmml_efcg(vm, x, fd) + + fd.write("") + fd.close() + +def main(options, arguments) : + if options.input != None and options.output != None : + export_apps_to_xgmml( options.input, options.output, options.functions, options.externals ) + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/apkviewer.py b/apkviewer.py new file mode 100755 index 00000000..6380f967 --- /dev/null +++ b/apkviewer.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys, os +from optparse import OptionParser + +from androguard.core.bytecodes import apk, dvm +from androguard.core.data import data +from androguard.core.analysis import analysis, ganalysis +from androguard.core import androconf + +option_0 = { 'name' : ('-i', '--input'), 'help' : 'filename input (dex, apk)', 'nargs' : 1 } +option_1 = { 'name' : ('-o', '--output'), 'help' : 'directory output', 'nargs' : 1 } + +options = [option_0, option_1] + +def create_directory( class_name, output ) : + output_name = output + if output_name[-1] != "/" : + output_name = output_name + "/" + + try : + os.makedirs( output_name + class_name ) + except OSError : + pass + +def create_directories( vm, output ) : + for class_name in vm.get_classes_names() : + z = os.path.split( class_name )[0] + create_directory( z[1:], output ) + +def main(options, arguments) : + if options.input != None and options.output != None : + + ret_type = androconf.is_android( options.input ) + vm = None + a = None + if ret_type == "APK" : + a = apk.APK( options.input ) + if a.is_valid_APK() : + vm = dvm.DalvikVMFormat( a.get_dex() ) + else : + print "INVALID APK" + elif ret_type == "DEX" : + try : + vm = dvm.DalvikVMFormat( open(options.input, "rb").read() ) + except Exception, e : + print "INVALID DEX", e + + + vmx = analysis.VMAnalysis( vm ) + gvmx = ganalysis.GVMAnalysis( vmx, a ) + + create_directories( vm, options.output ) + +# dv.export_to_gml( options.output ) + + dd = data.Data(vm, vmx, gvmx, a) + + buff = dd.export_apk_to_gml() + androconf.save_to_disk( buff, options.output + "/" + "apk.graphml" ) + + buff = dd.export_methodcalls_to_gml() + androconf.save_to_disk( buff, options.output + "/" + "methodcalls.graphml" ) + + buff = dd.export_dex_to_gml() + for i in buff : + androconf.save_to_disk( buff[i], options.output + "/" + i + ".graphml" ) + +if __name__ == "__main__" : + parser = OptionParser() + for option in options : + param = option['name'] + del option['name'] + parser.add_option(*param, **option) + + + options, arguments = parser.parse_args() + sys.argv[:] = arguments + main(options, arguments) diff --git a/demos/androguard_ANALYSIS.py b/demos/androguard_ANALYSIS.py new file mode 100755 index 00000000..276ef103 --- /dev/null +++ b/demos/androguard_ANALYSIS.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +import sys, hashlib +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "./") + +from androguard.core.androgen import AndroguardS +from androguard.core.analysis import analysis + +OUTPUT = "./output/" +#TEST = 'examples/java/test/orig/Test1.class' +#TEST = 'examples/java/Demo1/orig/DES.class' +#TEST = 'examples/java/Demo1/orig/Util.class' +#TEST = "apks/DroidDream/tmp/classes.dex" +#TEST = "./examples/android/TCDiff/bin/classes.dex" +TEST = "apks/iCalendar.apk" +#TEST = "apks/adrd/5/8370959.dex" + +def display_CFG(a, x, classes) : + for method in a.get_methods() : + g = x.get_method( method ) + + print method.get_class_name(), method.get_name(), method.get_descriptor() + for i in g.basic_blocks.get() : + print "\t %s %x %x" % (i.name, i.start, i.end), '[ NEXT = ', ', '.join( "%x-%x-%s" % (j[0], j[1], j[2].get_name()) for j in i.childs ), ']', '[ PREV = ', ', '.join( j[2].get_name() for j in i.fathers ), ']' + + +def display_STRINGS(a, x, classes) : + print "STRINGS" + for s, _ in x.get_tainted_variables().get_strings() : + print "String : ", repr(s.get_info()) + analysis.show_PathVariable( a, s.get_paths() ) + +def display_FIELDS(a, x, classes) : + print "FIELDS" + for f, _ in x.get_tainted_variables().get_fields() : + print "field : ", repr(f.get_info()) + analysis.show_PathVariable( a, f.get_paths() ) + +def display_PACKAGES(a, x, classes) : + print "CREATED PACKAGES" + for m, _ in x.get_tainted_packages().get_packages() : + m.show() + +def display_PACKAGES_II(a, x, classes) : +# Internal Methods -> Internal Methods + print "Internal --> Internal" + for j in x.get_tainted_packages().get_internal_packages() : + analysis.show_Path( a, j ) + +def display_PACKAGES_IE(a, x, classes) : +# Internal Methods -> External Methods + print "Internal --> External" + for j in x.get_tainted_packages().get_external_packages() : + analysis.show_Path( a, j ) + +def display_SEARCH_PACKAGES(a, x, classes, package_name) : + print "Search package", package_name + analysis.show_Paths( a, x.get_tainted_packages().search_packages( package_name ) ) + +def display_SEARCH_METHODS(a, x, classes, package_name, method_name, descriptor) : + print "Search method", package_name, method_name, descriptor + analysis.show_Paths( a, x.get_tainted_packages().search_methods( package_name, method_name, descriptor) ) + +def display_PERMISSION(a, x, classes) : + # Show methods used by permission + perms_access = x.get_tainted_packages().get_permissions( [] ) + for perm in perms_access : + print "PERM : ", perm + analysis.show_Paths( a, perms_access[ perm ] ) + +def display_OBJECT_CREATED(a, x, class_name) : + print "Search object", class_name + analysis.show_Paths( a, x.get_tainted_packages().search_objects( class_name ) ) + +a = AndroguardS( TEST ) +x = analysis.uVMAnalysis( a.get_vm() ) + +#print a.get_vm().get_strings() +print a.get_vm().get_regex_strings( "access" ) +print a.get_vm().get_regex_strings( "(long).*2" ) +print a.get_vm().get_regex_strings( ".*(t\_t).*" ) + +classes = a.get_vm().get_classes_names() +vm = a.get_vm() + +display_CFG( a, x, classes ) +display_STRINGS( vm, x, classes ) +display_FIELDS( vm, x, classes ) +display_PACKAGES( vm, x, classes ) +display_PACKAGES_IE( vm, x, classes ) +display_PACKAGES_II( vm, x, classes ) +display_PERMISSION( vm, x, classes ) + +display_SEARCH_PACKAGES( a, x, classes, "Landroid/telephony/" ) +display_SEARCH_PACKAGES( a, x, classes, "Ljavax/crypto/" ) +display_SEARCH_METHODS( a, x, classes, "Ljavax/crypto/", "generateSecret", "." ) + +display_OBJECT_CREATED( a, x, "." ) diff --git a/demos/apk_format_1.py b/demos/apk_format_1.py new file mode 100755 index 00000000..51be496a --- /dev/null +++ b/demos/apk_format_1.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append( PATH_INSTALL ) + +from androguard.core.bytecodes import dvm, apk + +TEST = "./examples/android/TC/bin/TC-debug.apk" + +a = apk.APK( TEST ) +a.show() + +j = dvm.DalvikVMFormat( a.get_dex() ) + +# SHOW CLASS (verbose) +#j.show() diff --git a/demos/apk_format_2.py b/demos/apk_format_2.py new file mode 100755 index 00000000..693019df --- /dev/null +++ b/demos/apk_format_2.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append( PATH_INSTALL ) + +from androguard.core.bytecodes import dvm, apk + +TEST = "./apks/crash/mikecc/e0399fdd481992bc049b6e9d765da7f007f89875.apk" + +a = apk.APK( TEST, zipmodule=2 ) +a.show() + +j = dvm.DalvikVMFormat( a.get_dex() ) + +# SHOW CLASS (verbose) +#j.show() diff --git a/demos/arm_format_1.py b/demos/arm_format_1.py new file mode 100755 index 00000000..34a05d94 --- /dev/null +++ b/demos/arm_format_1.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") +sys.path.append(PATH_INSTALL + "/core/assembly/") +sys.path.append(PATH_INSTALL + "/core/assembly/libassembly") + +import assembly +assembly.ASM() + +#import arm +#arm.ARM() + +#a = apk.APK( TEST ) +#a.show() + diff --git a/demos/axml_format_1.py b/demos/axml_format_1.py new file mode 100755 index 00000000..b9ed1a65 --- /dev/null +++ b/demos/axml_format_1.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import apk + + +from xml.dom import minidom + +ap = apk.AXMLPrinter( open("examples/axml/AndroidManifest2.xml", "r").read() ) + +print minidom.parseString( ap.getBuff() ).toxml() diff --git a/demos/benchmark.py b/demos/benchmark.py new file mode 100755 index 00000000..a6c093ba --- /dev/null +++ b/demos/benchmark.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +import sys, os +import cProfile + +# http://code.activestate.com/recipes/286222-memory-usage/ +_proc_status = '/proc/%d/status' % os.getpid() + +_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0, + 'KB': 1024.0, 'MB': 1024.0*1024.0} + +def _VmB(VmKey): + global _proc_status, _scale + # get pseudo file /proc//status + try: + t = open(_proc_status) + v = t.read() + t.close() + except: + return 0.0 # non-Linux? + # get VmKey line e.g. 'VmRSS: 9999 kB\n ...' + i = v.index(VmKey) + v = v[i:].split(None, 3) # whitespace + if len(v) < 3: + return 0.0 # invalid format? + # convert Vm value to bytes + return float(v[1]) * _scale[v[2]] + + +def memory(since=0.0): + '''Return memory usage in bytes. + ''' + return _VmB('VmSize:') - since + + +def resident(since=0.0): + '''Return resident memory usage in bytes. + ''' + return _VmB('VmRSS:') - since + + +def stacksize(since=0.0): + '''Return stack size in bytes. + ''' + return _VmB('VmStk:') - since + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "./") + +import androguard, analysis + +# a directory with apks files" + +TEST = "./apks/" + +l = [] +for i in os.walk( TEST ) : + for j in i[2] : + l.append( i[0] + j ) + +print len(l), l + +_a = androguard.Androguard( l ) + +print "MEMORY : ", memory() / _scale["MB"], "RESIDENT ", resident() / _scale["MB"], "STACKSIZE ", stacksize() / _scale["MB"] diff --git a/demos/crackme_dexlabs_patch.py b/demos/crackme_dexlabs_patch.py new file mode 100755 index 00000000..c77f16f1 --- /dev/null +++ b/demos/crackme_dexlabs_patch.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.analysis import analysis +from androguard.core import androconf + +class Nop(dvm.Instruction10x) : + def __init__(self) : + self.OP = 0x00 + +def patch_dex( m ) : + for i in m.get_methods() : + if i.get_class_name() == "Lorg/dexlabs/poc/dexdropper/DropActivity;" : + print i.get_class_name(), i.get_name() + + patch_method_3( i ) + # or + # patch_method_X( i ) + + +def patch_method_1( method ) : + buff = method.get_code().get_bc().insn + buff = "\x00" * 0x12 + buff[0x12:] + method.get_code().get_bc().insn = buff + +def patch_method_2( method ) : + method.set_code_idx( 0x12 ) + instructions = [ j for j in method.get_instructions() ] + for j in range(0, 9) : + instructions.insert(0, Nop() ) + method.set_instructions( instructions ) + +def patch_method_3( method ) : + method.set_code_idx( 0x12 ) + instructions = [ j for j in method.get_instructions() ] + for j in range(0, 9) : + instructions.insert(0, dvm.Instruction10x(None, "\x00\x00") ) + method.set_instructions( instructions ) + + +FILENAME_INPUT = "apks/crash/crackme-obfuscator.apk" + +FILENAME_OUTPUT = "./toto.dex" + +androconf.set_debug() + +a = apk.APK( FILENAME_INPUT ) +vm = dvm.DalvikVMFormat( a.get_dex() ) +vmx = analysis.VMAnalysis( vm ) + +patch_dex( vm ) + +new_dex = vm.save() + +fd = open(FILENAME_OUTPUT, "w") +fd.write( new_dex ) +fd.close() \ No newline at end of file diff --git a/demos/create_invalid_apk.py b/demos/create_invalid_apk.py new file mode 100755 index 00000000..6b3b8adc --- /dev/null +++ b/demos/create_invalid_apk.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.analysis import analysis +from androguard.core import androconf + + +def patch_dex(m): + for i in m.get_methods(): + if i.get_class_name() == "Lre/androguard/android/invalid/MainActivity;": + #if i.get_name() == "testStrings": + # instructions = [ins for ins in i.get_instructions()] + # instructions[0].BBBB = 10000 + # i.set_instructions(instructions) + if i.get_name() == "testInstances": + instructions = [ins for ins in i.get_instructions()] + instructions[0].BBBB = 0x4141 + i.set_instructions(instructions) + +FILENAME_INPUT = "./examples/android/Invalid/Invalid.apk" +FILENAME_OUTPUT = "./toto.apk" + +androconf.set_debug() + +a = apk.APK(FILENAME_INPUT) +vm = dvm.DalvikVMFormat(a.get_dex()) +vmx = analysis.VMAnalysis(vm) + +patch_dex(vm) + +new_dex = vm.save() + +a.new_zip(filename=FILENAME_OUTPUT, + deleted_files="(META-INF/.)", + new_files={"classes.dex": new_dex}) + +# Please configure your keystore !! :) follow the tutorial on android website +apk.sign_apk(FILENAME_OUTPUT, "./keystore/keystore1", "tototo") diff --git a/demos/create_invalid_dex.py b/demos/create_invalid_dex.py new file mode 100755 index 00000000..65a2f6dd --- /dev/null +++ b/demos/create_invalid_dex.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core import androconf + + +FILENAME_INPUT = "examples/android/TestsAndroguard/bin/classes.dex" +FILENAME_OUTPUT = "./toto.dex" + +androconf.set_debug() + +vm = dvm.DalvikVMFormat(open(FILENAME_INPUT, "rb").read()) + +print hex(vm.header.link_off), hex(vm.header.link_size) +vm.header.link_off, vm.header.link_size = 0x41414141, 0x1337 +print hex(vm.header.link_off), hex(vm.header.link_size) + +new_dex = vm.save() + +open(FILENAME_OUTPUT, "wb").write(new_dex) diff --git a/demos/dad_emul.py b/demos/dad_emul.py new file mode 100755 index 00000000..44778eb9 --- /dev/null +++ b/demos/dad_emul.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys +sys.path.append('./') + +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis.analysis import uVMAnalysis +from androguard.decompiler.dad.decompile import DvMethod +from androguard.decompiler.dad.instruction import (Constant, + BinaryCompExpression) + + +class DemoEmulator(object): + def __init__(self, graph): + self.graph = graph + self.loop = [] + self.mem = {} + + def init(self, key, value): + self.mem[key] = value + + def visit(self, node): + if node not in self.loop: + node.visit(self) + + def visit_ins(self, ins): + return ins.visit(self) + + def visit_loop_node(self, loop): + self.loop.append(loop) + follow = loop.get_loop_follow() + if loop.looptype.pretest(): + if loop.true is follow: + loop.neg() + loop.true, loop.false = loop.false, loop.true + while loop.visit_cond(self): + loop.true.visit(self) + self.loop.pop() + if follow is not None: + self.visit(follow) + + def visit_cond_node(self, cond): + follow = cond.get_if_follow() + if follow is not None: + has_else = not (follow in (cond.true, cond.false)) + cnd = cond.visit_cond(self) + if cnd: + cond.true.visit(self) + elif has_else: + cond.false.visit(self) + self.visit(follow) + + def visit_statement_node(self, stmt): + sucs = self.graph.sucs(stmt) + for ins in stmt.get_ins(): + self.visit_ins(ins) + if len(sucs): + self.visit(sucs[0]) + + def visit_return_node(self, ret): + for ins in ret.get_ins(): + self.visit_ins(ins) + + def visit_constant(self, cst): + return cst + + def visit_variable(self, var): + return self.mem[var] + + def visit_param(self, param): + return param + + def visit_assign(self, lhs, rhs): + if lhs is None: + rhs.visit(self) + else: + self.mem[lhs.v] = rhs.visit(self) + + def visit_astore(self, array, index, rhs): + array = array.visit(self) + if isinstance(index, Constant): + idx = index.visit(self, 'I') + else: + idx = index.visit(self) + self.mem[array][idx] = rhs.visit(self) + + def visit_return_void(self): + pass + + def visit_aload(self, array, index): + arr = array.visit(self) + idx = index.visit(self) + return self.mem[arr][idx] + + def visit_alength(self, array): + return len(self.mem[array.visit(self)]) + + def visit_binary_expression(self, op, arg1, arg2): + arg1 = arg1.visit(self) + if not isinstance(arg1, int): + arg1 = ord(arg1) + arg2 = arg2.visit(self) + if not isinstance(arg2, int): + arg2 = ord(arg2) + return eval('%s %s %s' % (arg1, op, arg2)) + + def visit_unary_expression(self, op, arg): + arg.visit(self) + + def visit_cast(self, op, arg): + return arg.visit(self) + + def visit_cond_expression(self, op, arg1, arg2): + arg1 = arg1.visit(self) + if not isinstance(arg1, int): + arg1 = ord(arg1) + arg2 = arg2.visit(self) + if not isinstance(arg2, int): + arg2 = ord(arg2) + return eval('%s %s %s' % (arg1, op, arg2)) + + def visit_get_static(self, cls, name): + return self.mem[name] + + +TEST = './apks/pacsec/magicspiral.apk' + +vm = dvm.DalvikVMFormat(apk.APK(TEST).get_dex()) +vma = uVMAnalysis(vm) + +method = vm.get_method('crypt')[0] + +amethod = vma.get_method(method) +dvmethod = DvMethod(amethod) +dvmethod.process() # build IR Form / control flow... + +graph = dvmethod.graph +visitor = DemoEmulator(graph) + +l = [94, 42, 93, 88, 3, 2, 95, 2, 13, 85, 11, 2, 19, 1, 125, 19, 0, 102, + 30, 24, 19, 99, 76, 21, 102, 22, 26, 111, 39, 125, 2, 44, 80, 10, 90, + 5, 119, 100, 119, 60, 4, 87, 79, 42, 52] +visitor.init(dvmethod.lparams[0], l) + +KEYVALUE = '6^)(9-p35a%3#4S!4S0)$Yt%^&5(j.g^&o(*0)$Yv!#O@6GpG@=+3j.&6^)(0-=1' +visitor.init('KEYVALUE', '[BKEYVALUE') +visitor.init('[BKEYVALUE', KEYVALUE) + +visitor.init('keylen', len(KEYVALUE)) + +method.show() + +def show_mem(visitor): + print 'Memory[4]: %s' % visitor.mem[4] + print '==> %r' % ''.join(chr(i) for i in visitor.mem[4]) + +show_mem(visitor) +print '\nStarting visit...', +graph.get_entry().visit(visitor) +print ' done !\n' +show_mem(visitor) + diff --git a/demos/dad_print.py b/demos/dad_print.py new file mode 100755 index 00000000..12a8a4f8 --- /dev/null +++ b/demos/dad_print.py @@ -0,0 +1,329 @@ +#!/usr/bin/env python +# This file is part of Androguard. +# +# Copyright (c) 2012 Geoffroy Gueguen +# All Rights Reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + +import sys +sys.path.append('./') + +from androguard.core.bytecodes import apk, dvm +from androguard.core.analysis.analysis import uVMAnalysis +from androguard.decompiler.dad.decompile import DvMethod +from androguard.decompiler.dad.instruction import Constant, BinaryCompExpression + + +class PrintVisitor(object): + def __init__(self, graph): + self.graph = graph + self.visited_nodes = set() + self.loop_follow = [None] + self.latch_node = [None] + self.if_follow = [None] + self.switch_follow = [None] + self.next_case = None + + def visit_ins(self, ins): + return ins.visit(self) + + def visit_node(self, node): + if node in (self.if_follow[-1], self.switch_follow[-1], + self.loop_follow[-1], self.latch_node[-1]): + return + if node in self.visited_nodes: + return + self.visited_nodes.add(node) + node.visit(self) + + def visit_loop_node(self, loop): + print '- Loop node', loop.num + follow = loop.get_loop_follow() + if follow is None and not loop.looptype.endless(): + exit('Loop has no follow !', 'error') + if loop.looptype.pretest(): + if loop.true is follow: + loop.neg() + loop.true, loop.false = loop.false, loop.true + cnd = loop.visit_cond(self) + print 'while(%s) {' % cnd + elif loop.looptype.posttest(): + print 'do {' + self.latch_node.append(loop.latch) + elif loop.looptype.endless(): + print 'while(true) {' + pass + self.loop_follow.append(follow) + if loop.looptype.pretest(): + self.visit_node(loop.true) + else: + self.visit_node(loop.cond) + self.loop_follow.pop() + if loop.looptype.pretest(): + print '}' + elif loop.looptype.posttest(): + print '} while(', + self.latch_node.pop() + loop.latch.visit_cond(self) + print ')' + else: + self.visit_node(loop.latch) + if follow is not None: + self.visit_node(follow) + + def visit_cond_node(self, cond): + print '- Cond node', cond.num + follow = cond.get_if_follow() + if cond.false is self.loop_follow[-1]: + cond.neg() + cond.true, cond.false = cond.false, cond.true + cond.visit_cond(self) + self.visit_node(cond.false) + elif follow is not None: + is_else = not (follow in (cond.true, cond.false)) + if (cond.true in (follow, self.next_case) + or cond.num > cond.true.num): + cond.neg() + cond.true, cond.false = cond.false, cond.true + self.if_follow.append(follow) + if not cond.true in self.visited_nodes: + cnd = cond.visit_cond(self) + print 'if (%s) {' % cnd + self.visit_node(cond.true) + if is_else and not cond.false in self.visited_nodes: + print '} else {' + self.visit_node(cond.false) + print '}' + self.if_follow.pop() + self.visit_node(follow) + else: + cond.visit_cond(self) + self.visit_node(cond.true) + self.visit_node(cond.false) + + def visit_short_circuit_condition(self, nnot, aand, cond1, cond2): + if nnot: + cond1.neg() + cond1.visit_cond(self) + cond2.visit_cond(self) + + def visit_switch_node(self, switch): + lins = switch.get_ins() + for ins in lins[:-1]: + self.visit_ins(ins) + switch_ins = switch.get_ins()[-1] + self.visit_ins(switch_ins) + follow = switch.switch_follow + cases = switch.cases + self.switch_follow.append(follow) + default = switch.default + for i, node in enumerate(cases): + if node in self.visited_nodes: + continue + for case in switch.node_to_case[node]: + pass + if i + 1 < len(cases): + self.next_case = cases[i + 1] + else: + self.next_case = None + if node is default: + default = None + self.visit_node(node) + if default not in (None, follow): + self.visit_node(default) + self.switch_follow.pop() + self.visit_node(follow) + + def visit_statement_node(self, stmt): + print '- Statement node', stmt.num + sucs = self.graph.sucs(stmt) + for ins in stmt.get_ins(): + self.visit_ins(ins) + if len(sucs) == 0: + return + follow = sucs[0] + self.visit_node(follow) + + def visit_return_node(self, ret): + print '- Return node', ret.num + for ins in ret.get_ins(): + self.visit_ins(ins) + + def visit_throw_node(self, throw): + for ins in throw.get_ins(): + self.visit_ins(ins) + + def visit_constant(self, cst): + return cst + + def visit_base_class(self, cls): + return cls + + def visit_variable(self, var): + return 'v%s' % var + + def visit_param(self, param): + return 'p%s' % param + + def visit_this(self): + return 'this' + + def visit_assign(self, lhs, rhs): + if lhs is None: + rhs.visit(self) + return + l = lhs.visit(self) + r = rhs.visit(self) + print '%s = %s;' % (l, r) + + def visit_move_result(self, lhs, rhs): + l = lhs.visit(self) + r = rhs.visit(self) + print '%s = %s;' % (l, r) + + def visit_move(self, lhs, rhs): + if lhs is rhs: + return + l = lhs.visit(self) + r = rhs.visit(self) + print '%s = %s;' % (l, r) + + def visit_astore(self, array, index, rhs): + arr = array.visit(self) + if isinstance(index, Constant): + idx = index.visit(self, 'I') + else: + idx = index.visit(self) + r = rhs.visit(self) + print '%s[%s] = %s' % (arr, idx, r) + + def visit_put_static(self, cls, name, rhs): + r = rhs.visit(self) + return '%s.%s = %s' % (cls, name, r) + + def visit_put_instance(self, lhs, name, rhs): + l = lhs.visit(self) + r = rhs.visit(self) + return '%s.%s = %s' % (l, name, r) + + def visit_new(self, atype): + pass + + def visit_invoke(self, name, base, args): + base.visit(self) + for arg in args: + arg.visit(self) + + def visit_return_void(self): + print 'return;' + + def visit_return(self, arg): + a = arg.visit(self) + print 'return %s;' % a + + def visit_nop(self): + pass + + def visit_switch(self, arg): + arg.visit(self) + + def visit_check_cast(self, arg, atype): + arg.visit(self) + + def visit_aload(self, array, index): + arr = array.visit(self) + idx = index.visit(self) + return '%s[%s]' % (arr, idx) + + def visit_alength(self, array): + res = array.visit(self) + return '%s.length' % res + + def visit_new_array(self, atype, size): + size.visit(self) + + def visit_filled_new_array(self, atype, size, args): + atype.visit(self) + size.visit(self) + for arg in args: + arg.visit(self) + + def visit_fill_array(self, array, value): + array.visit(self) + + def visit_monitor_enter(self, ref): + ref.visit(self) + + def visit_monitor_exit(self, ref): + pass + + def visit_throw(self, ref): + ref.visit(self) + + def visit_binary_expression(self, op, arg1, arg2): + val1 = arg1.visit(self) + val2 = arg2.visit(self) + return '%s %s %s' % (val1, op, val2) + + def visit_unary_expression(self, op, arg): + arg.visit(self) + + def visit_cast(self, op, arg): + a = arg.visit(self) + return '(%s %s)' % (op, a) + + def visit_cond_expression(self, op, arg1, arg2): + val1 = arg1.visit(self) + val2 = arg2.visit(self) + return '%s %s %s' % (val1, op, val2) + + def visit_condz_expression(self, op, arg): + if isinstance(arg, BinaryCompExpression): + arg.op = op + arg.visit(self) + else: + arg.visit(self) + + def visit_get_instance(self, arg, name): + arg.visit(self) + + def visit_get_static(self, cls, name): + return '%s.%s' % (cls, name) + +TEST = '../DroidDream/magicspiral.apk' + +vm = dvm.DalvikVMFormat(apk.APK(TEST).get_dex()) +vma = uVMAnalysis(vm) + +method = vm.get_method('crypt')[0] +method.show() + +amethod = vma.get_method(method) +dvmethod = DvMethod(amethod) + +dvmethod.process() # build IR Form / control flow... + +graph = dvmethod.graph + +print 'Entry block : %s\n' % graph.get_entry() + +for block in graph: # graph.get_rpo() to iterate in reverse post order + print 'Block : %s' % block + for ins in block.get_ins(): + print ' - %s' % ins +print + +visitor = PrintVisitor(graph) +graph.get_entry().visit(visitor) diff --git a/demos/dalvikvm_format_1.py b/demos/dalvikvm_format_1.py new file mode 100755 index 00000000..e67362e8 --- /dev/null +++ b/demos/dalvikvm_format_1.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) +from androguard.core.bytecodes import dvm + +TEST = "./examples/dalvik/test/bin/classes.dex" + +j = dvm.DalvikVMFormat(open(TEST).read()) + +# SHOW CLASS (verbose) +j.show() + +# SHOW FIELDS +for i in j.get_fields(): + print i.get_access_flags(), i.get_name(), i.get_descriptor() + +print + +# SHOW METHODS +for i in j.get_methods(): + print i.get_access_flags(), i.get_name(), i.get_descriptor() diff --git a/demos/dalvikvm_format_2.py b/demos/dalvikvm_format_2.py new file mode 100755 index 00000000..0648a68d --- /dev/null +++ b/demos/dalvikvm_format_2.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import sys, random, string + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm + +TEST = "./examples/dalvik/test/bin/classes.dex" +TEST_OUTPUT = "./examples/dalvik/test/bin/classes_output.dex" + +j = dvm.DalvikVMFormat( open(TEST).read() ) + +# Modify the name of each field +#for field in j.get_fields() : +# field.set_name( random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] ) ) + +# Modify the name of each method (minus the constructor () and a extern called method (go)) +#for method in j.get_methods() : +# if method.get_name() != "go" and method.get_name() != "" : +# method.set_name( random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] ) ) + +# SAVE CLASS +fd = open( TEST_OUTPUT, "w" ) +fd.write( j.save() ) +fd.close() diff --git a/demos/dalvikvm_format_3.py b/demos/dalvikvm_format_3.py new file mode 100755 index 00000000..b53554fb --- /dev/null +++ b/demos/dalvikvm_format_3.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis + +TEST = "examples/android/TestsAndroguard/bin/classes.dex" + +j = dvm.DalvikVMFormat( open(TEST).read() ) +x = analysis.VMAnalysis( j ) +j.set_vmanalysis( x ) + +# SHOW CLASSES (verbose and pretty) +j.pretty_show() + +# SHOW METHODS +for i in j.get_methods() : + i.pretty_show( ) diff --git a/demos/dalvikvm_format_4.py b/demos/dalvikvm_format_4.py new file mode 100755 index 00000000..b95b4943 --- /dev/null +++ b/demos/dalvikvm_format_4.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis +from androguard.decompiler import decompiler + +TEST = "examples/android/TestsAndroguard/bin/classes.dex" + +j = dvm.DalvikVMFormat( open(TEST).read() ) +jx = analysis.VMAnalysis( j ) + +#d = decompiler.DecompilerDex2Jad( j ) +#d = decompiler.DecompilerDed( j ) +d = decompiler.DecompilerDAD( j, jx ) + +j.set_decompiler( d ) + +# SHOW METHODS +for i in j.get_methods() : + if i.get_name() == "onCreate" : + print i.get_class_name(), i.get_name() + i.source() + +# if i.get_name() == "testWhileTrue" : +# i.source() diff --git a/demos/dalvikvm_format_6.py b/demos/dalvikvm_format_6.py new file mode 100755 index 00000000..d8b62a6d --- /dev/null +++ b/demos/dalvikvm_format_6.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.analysis import analysis +from androguard.core import androconf + + +import hashlib + +def hexdump(src, length=8, off=0): + result = [] + digits = 4 if isinstance(src, unicode) else 2 + for i in xrange(0, len(src), length): + s = src[i:i+length] + hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s]) + text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s]) + result.append( b"%04X %-*s %s" % (i+off, length*(digits + 1), hexa, text) ) + return b'\n'.join(result) + +class MDalvikVMFormat: + def __init__(self, vm, vmx) : + self.vm = vm + self.vmx = vmx + + def modify_instruction(self, class_name, method_name, descriptor, offset, instructions) : + pass + + def test_save(self) : + original_buff = self.vm.get_buff() + + b1 = original_buff + + method = self.vm.get_method_descriptor( + "Lfr/t0t0/android/TestModifActivity;", "onCreate", + "(Landroid/os/Bundle;)V" ) +# method.show() +# print hex(method.code_off) + +# instructions = [i for i in method.get_instructions()] +# ins = instructions[3] +# print ins +# ins.BBBB = 12 +# instructions.insert(3, ins) +# method.set_instructions( instructions ) + + b2 = self.vm.save() + + self.check(b1, b2, 40) + + return b2 + + def check(self, b1, b2, off) : + if hashlib.md5( b1 ).hexdigest() != hashlib.md5( b2 ).hexdigest() : + j = 0 + end = max(len(b1), len(b2)) + while j < end : + if j < off : + j += 1 + continue + + if j >= len(b1) : + print "OUT OF B1 @ OFFSET 0x%x(%d)" % (j,j) + raise("ooo") + + if j >= len(b2) : + print "OUT OF B2 @ OFFSET 0x%x(%d)" % (j,j) + raise("ooo") + + if b1[j] != b2[j] : + print "BEGIN @ OFFSET 0x%x" % j + print "ORIG : " + print hexdump(b1[j - 8: j + 8], off=j-8) + "\n" + print "NEW : " + print hexdump(b2[j - 8: j + 8], off=j-8) + "\n" + + j += 1 + + + print "OK" + + +#TEST = "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" +TEST = "apks/malwares/smszombie/40F3F16742CD8AC8598BF859A23AC290.apk" +FILENAME = "./toto.apk" + +androconf.set_debug() + +a = apk.APK( TEST ) +j = dvm.DalvikVMFormat( a.get_dex() ) +x = analysis.VMAnalysis( j ) + +m = MDalvikVMFormat(j, x) +print j, x, m + +new_dex = m.test_save() + +a.new_zip( filename=FILENAME, + deleted_files="(META-INF/.)", new_files = { + "classes.dex" : new_dex } ) +apk.sign_apk( FILENAME, "./keystore/keystore1", "tototo" ) diff --git a/demos/dalvikvm_format_7.py b/demos/dalvikvm_format_7.py new file mode 100755 index 00000000..d1ce1551 --- /dev/null +++ b/demos/dalvikvm_format_7.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk + + +TEST = "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" + + +a = apk.APK( TEST ) +j = dvm.DalvikVMFormat( a.get_dex() ) + +for m in j.get_methods() : + print m.get_class_name(), m.get_name(), m.get_descriptor() + code_debug = m.get_debug() + if code_debug != None : + print code_debug.get_line_start(), code_debug.get_parameters_size(), code_debug.get_parameter_names(), code_debug.get_translated_parameter_names() + for i in code_debug.get_bytecodes() : + print i.get_op_value(), i.get_format(), i.get_value() diff --git a/demos/dalvikvm_format_8.py b/demos/dalvikvm_format_8.py new file mode 100755 index 00000000..3ef4be86 --- /dev/null +++ b/demos/dalvikvm_format_8.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.androconf import CONF +from androguard.core.analysis import analysis, ganalysis + + +#CONF["LAZY_ANALYSIS"] = True + +TEST = "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" + +a = apk.APK( TEST ) +j = dvm.DalvikVMFormat( a.get_dex() ) +dx = analysis.uVMAnalysis( j ) +gx = ganalysis.GVMAnalysis( dx, None ) + +j.set_vmanalysis( dx ) +j.set_gvmanalysis( gx ) + +j.create_xref() +j.create_dref() + +for m in dx.get_methods() : + + idx = 0 + for i in m.basic_blocks.get() : + print "\t %s %x %x" % (i.name, i.start, i.end), i.get_instructions()[-1].get_name() + + print m.method.XREFfrom, m.method.XREFto diff --git a/demos/decompiler_dad.py b/demos/decompiler_dad.py new file mode 100755 index 00000000..7ed36a46 --- /dev/null +++ b/demos/decompiler_dad.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis +from androguard.decompiler.dad import decompile + +TEST = 'examples/android/TestsAndroguard/bin/classes.dex' + +vm = dvm.DalvikVMFormat(open(TEST, "r").read()) +vmx = analysis.VMAnalysis(vm) + +# CFG +for method in vm.get_methods(): + mx = vmx.get_method(method) + + if method.get_code() == None: + continue + + print method.get_class_name(), method.get_name(), method.get_descriptor() + + ms = decompile.DvMethod(mx) + ms.process() + + print ms.get_source() diff --git a/demos/disassembler.py b/demos/disassembler.py new file mode 100755 index 00000000..a051caad --- /dev/null +++ b/demos/disassembler.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.androgen import AndroguardS +from androguard.core.analysis import analysis + +TEST = 'examples/android/TestsAndroguard/bin/classes.dex' + +a = AndroguardS(TEST) +x = analysis.VMAnalysis(a.get_vm()) + +for method in a.get_methods(): + print method.get_class_name(), method.get_name(), method.get_descriptor() + code = method.get_code() + + if code != None: + bc = code.get_bc() + idx = 0 + for i in bc.get_instructions(): + print "\t", "%x" % idx, i.get_name(), i.get_output() + idx += i.get_length() + + +for method in a.get_methods(): + print method.get_class_name(), method.get_name(), method.get_descriptor() + idx = 0 + for i in method.get_instructions(): + print "\t", "%x" % idx, i.get_name(), i.get_output() + idx += i.get_length() diff --git a/demos/disassembler_analysis.py b/demos/disassembler_analysis.py new file mode 100755 index 00000000..3c305bbb --- /dev/null +++ b/demos/disassembler_analysis.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.analysis import analysis + +TEST = 'examples/android/TestsAndroguard/bin/classes.dex' + +d = dvm.DalvikVMFormat(open(TEST, "r").read()) +x = analysis.VMAnalysis(d) + +# CFG +for method in d.get_methods(): + g = x.get_method(method) + + if method.get_code() == None: + continue + + print method.get_class_name(), method.get_name(), method.get_descriptor() + + idx = 0 + for i in g.get_basic_blocks().get(): + print "\t %s %x %x" % (i.name, i.start, i.end), '[ NEXT = ', ', '.join( "%x-%x-%s" % (j[0], j[1], j[2].get_name()) for j in i.get_next() ), ']', '[ PREV = ', ', '.join( j[2].get_name() for j in i.get_prev() ), ']' + + for ins in i.get_instructions(): + print "\t\t %x" % idx, ins.get_name(), ins.get_output() + idx += ins.get_length() + + print "" diff --git a/demos/disassembler_exceptions.py b/demos/disassembler_exceptions.py new file mode 100755 index 00000000..634bb348 --- /dev/null +++ b/demos/disassembler_exceptions.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +import sys, hashlib + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.androgen import AndroguardS +from androguard.core.analysis import analysis +from androguard.core.bytecodes import dvm + +TEST = 'examples/android/TestsAndroguard/bin/classes.dex' + +a = AndroguardS( TEST ) +x = analysis.VMAnalysis( a.get_vm() ) + + +# CFG +for method in a.get_methods() : + g = x.get_method( method ) + + # Display only methods with exceptions + if method.get_code() == None : + continue + + if method.get_code().tries_size <= 0 : + continue + + print method.get_class_name(), method.get_name(), method.get_descriptor(), method.get_code().get_length(), method.get_code().registers_size + + idx = 0 + for i in g.basic_blocks.get() : + print "\t %s %x %x" % (i.name, i.start, i.end), '[ NEXT = ', ', '.join( "%x-%x-%s" % (j[0], j[1], j[2].get_name()) for j in i.childs ), ']', '[ PREV = ', ', '.join( j[2].get_name() for j in i.fathers ), ']' + + for ins in i.get_instructions() : + print "\t\t %x" % idx, ins.get_name(), ins.get_output() + idx += ins.get_length() + + print "" + + for i in g.exceptions.gets() : + print '%x %x %s' % (i.start, i.end, i.exceptions) + + print dvm.determineException(a.get_vm(), method) + diff --git a/demos/disassembler_special_ins.py b/demos/disassembler_special_ins.py new file mode 100755 index 00000000..4a260ebb --- /dev/null +++ b/demos/disassembler_special_ins.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import sys, hashlib + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.androgen import AndroguardS +from androguard.core.analysis import analysis + +TEST = 'examples/android/TestsAndroguard/bin/classes.dex' + +a = AndroguardS( TEST ) +x = analysis.VMAnalysis( a.get_vm() ) + +for method in a.get_methods() : + g = x.get_method( method ) + + if method.get_code() == None : + continue + + idx = 0 + for i in g.basic_blocks.get() : + for ins in i.get_instructions() : + op_value = ins.get_op_value() + + # packed/sparse + if op_value == 0x2b or op_value == 0x2c : + special_ins = i.get_special_ins(idx) + if special_ins != None : + print "\t %x" % idx, ins, special_ins, ins.get_name(), ins.get_output(), special_ins.get_values() + # fill + if op_value == 0x26 : + special_ins = i.get_special_ins(idx) + if special_ins != None : + print "\t %x" % idx, ins, special_ins, ins.get_name(), ins.get_output(), repr( special_ins.get_data() ) + + idx += ins.get_length() \ No newline at end of file diff --git a/demos/example_idapipe.py b/demos/example_idapipe.py new file mode 100755 index 00000000..bc3efa33 --- /dev/null +++ b/demos/example_idapipe.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# This file is part of Androguard. +# +# Copyright (C) 2012, Anthony Desnos +# All rights reserved. +# +# Androguard is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Androguard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Androguard. If not, see . + + +import sys, os +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.binaries import idapipe + +PATH_IDA = os.path.expanduser("~") + "/ida-6.2/idal" +PATH_WRAPPER = "./androguard/core/binaries/idawrapper.py" + +ip = idapipe.IDAPipe( PATH_IDA, PATH_WRAPPER, "./elsim/examples/x86/elf/polarssl/libpolarssl.so" ) +#ip = idapipe.IDAPipe( "/media/truecrypt1/ida/6.2/ida-6.2/idal", "examples/x86/pe/win32k-5.1.2600.6119.sys" ) + +try : + f = ip.get_quick_functions() + + # print len(f) + + idapipe.display_function( f[ 15344 ] ) + #ip.get_raw() + #ip.get_functions() + #ip.get_function_name( "aes_gen_tables" ) + + ip.quit() +except : + import traceback + traceback.print_exc() + ip.quit() diff --git a/demos/geinimi_analysis.py b/demos/geinimi_analysis.py new file mode 100755 index 00000000..a44a5dbf --- /dev/null +++ b/demos/geinimi_analysis.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys +import hashlib + +import pyDes + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "./") +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") +sys.path.append(PATH_INSTALL + "/core/analysis") + +from androguard import * +import analysis + +TEST = "./geinimi/geinimi.apk" + +_a = AndroguardS( TEST ) +_x = analysis.VMAnalysis( _a.get_vm() ) + +#print _a.get_strings() + +KEY = "\x01\x02\x03\x04\x05\x06\x07\x08" +_des = pyDes.des( KEY ) + +#_x.tainted_packages.export_call_graph("toto.dot", "Lcom/swampy/sexpos/pos") + +tainted_string = _x.tainted_variables.get_string( "DES" ) +if tainted_string != None : + print "\t -->", tainted_string.get_info() + for path in tainted_string.get_paths() : + print "\t\t =>", path.get_access_flag(), path.get_method().get_class_name(), path.get_method().get_name(), path.get_method().get_descriptor(), path.get_bb().get_name(), "%x" % ( path.get_bb().start + path.get_idx() ) + +tainted_field = _x.tainted_variables.get_field( "Lcom/swampy/sexpos/pos/e/k;", "b", "[B" ) +if tainted_field != None : + print "\t -->", tainted_field.get_info() + for path in tainted_field.get_paths() : + print "\t\t =>", path.get_access_flag(), path.get_method().get_class_name(), path.get_method().get_name(), path.get_method().get_descriptor(), path.get_bb().get_name(), "%x" % (path.get_bb().start + path.get_idx() ) + + +tainted_field = _x.tainted_variables.get_field( "Lcom/swampy/sexpos/pos/e/p;", "a", "[[B" ) +if tainted_field != None : + print "\t -->", tainted_field.get_info() + for path in tainted_field.get_paths() : + print "\t\t =>", path.get_access_flag(), path.get_method().get_class_name(), path.get_method().get_name(), path.get_method().get_descriptor(), path.get_bb().get_name(), "%x" % (path.get_bb().start + path.get_idx() ) + if path.get_access_flag() == "W" : + b = "" + for ins in path.get_method().get_code().get_bc().get() : + if ins.get_name() == "FILL-ARRAY-DATA" : + b += ins.get_data() + + print repr( _des.decrypt( b ) ) + +tainted_field = _x.tainted_variables.get_field( "Lcom/swampy/sexpos/pos/a;", "g", "Ljava/lang/String;" ) +if tainted_field != None : + print "\t -->", tainted_field.get_info() + for path in tainted_field.get_paths() : + print "\t\t =>", path.get_access_flag(), path.get_method().get_class_name(), path.get_method().get_name(), path.get_method().get_descriptor(), path.get_bb().get_name(), "%x" % (path.get_bb().start + path.get_idx() ) + +tainted_method = _x.tainted_packages.get_method( "Lcom/swampy/sexpos/pos/e/q;", "a", "(Ljava/lang/String;)Ljava/lang/String;" ) +for path in tainted_method : + print path.get_access_flag(), path.get_method().get_class_name(), path.get_method().get_name(), path.get_method().get_descriptor(), path.get_bb().get_name(), "%x" % (path.get_bb().start + path.get_idx() ) diff --git a/demos/jvm_format_1.py b/demos/jvm_format_1.py new file mode 100755 index 00000000..aeebee8b --- /dev/null +++ b/demos/jvm_format_1.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") + +import jvm + +TEST = "./examples/java/test/orig/Test1.class" + +j = jvm.JVMFormat( open(TEST).read() ) + +# SHOW CLASS (verbose) +j.show() + +# SHOW FIELDS +for i in j.get_fields() : + print i.get_access(), i.get_name(), i.get_descriptor() + +print + +# SHOW METHODS +for i in j.get_methods() : + print i.get_access(), i.get_name(), i.get_descriptor() diff --git a/demos/jvm_format_2.py b/demos/jvm_format_2.py new file mode 100755 index 00000000..9a714842 --- /dev/null +++ b/demos/jvm_format_2.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import sys, random, string + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") + +import jvm + +TEST = "./examples/java/test/orig/Test1.class" +TEST_OUTPUT = "./examples/java/test/new/Test1.class" + +j = jvm.JVMFormat( open(TEST).read() ) + +# Modify the name of each field +for field in j.get_fields() : + field.set_name( random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] ) ) + +# Modify the name of each method (minus the constructor () and a extern called method (go)) +for method in j.get_methods() : + if method.get_name() != "go" and method.get_name() != "" : + method.set_name( random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] ) ) + +# SAVE CLASS +fd = open( TEST_OUTPUT, "w" ) +fd.write( j.save() ) +fd.close() diff --git a/demos/jvm_format_3.py b/demos/jvm_format_3.py new file mode 100755 index 00000000..4f8808a9 --- /dev/null +++ b/demos/jvm_format_3.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import sys, random, string + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") + +import jvm + +TEST = "./examples/java/test/orig/Test1.class" +TEST_REF = "./examples/java/Hello.class" +TEST_OUTPUT = "./examples/java/test/new/Test1.class" + +j = jvm.JVMFormat( open(TEST).read() ) +j2 = jvm.JVMFormat( open(TEST_REF).read() ) + +# Insert a craft method :) +j.insert_craft_method( "toto", [ "ACC_PUBLIC", "[B", "[B" ], [ [ "aconst_null" ], [ "areturn" ] ] ) + +# Insert a method with no dependances methods +j.insert_direct_method( "toto2", j2.get_method("test3")[0] ) + +# SAVE CLASS +fd = open( TEST_OUTPUT, "w" ) +fd.write( j.save() ) +fd.close() diff --git a/demos/jvm_format_4.py b/demos/jvm_format_4.py new file mode 100755 index 00000000..42bb1edd --- /dev/null +++ b/demos/jvm_format_4.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import sys, random, string + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") + +import jvm + +TEST = "./examples/java/test/orig/Test1.class" +TEST_REF = "./examples/java/Hello.class" +TEST_OUTPUT = "./examples/java/test/new/Test1.class" + +j = jvm.JVMFormat( open(TEST).read() ) +j2 = jvm.JVMFormat( open(TEST_REF).read() ) + +# Insert a method with java dependances methods/class +j.insert_direct_method( "toto2", j2.get_method("test5")[0] ) + +# SAVE CLASS +fd = open( TEST_OUTPUT, "w" ) +fd.write( j.save() ) +fd.close() diff --git a/demos/jvm_format_5.py b/demos/jvm_format_5.py new file mode 100755 index 00000000..bf4f93b0 --- /dev/null +++ b/demos/jvm_format_5.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL + "/core") +sys.path.append(PATH_INSTALL + "/core/bytecodes") +sys.path.append(PATH_INSTALL + "/core/analysis") + +import jvm, analysis + +TEST = "./examples/java/test/orig/Test1.class" + +j = jvm.JVMFormat( open(TEST).read() ) +x = analysis.VMAnalysis( j ) + +# SHOW CLASS (verbose and pretty) +#j.pretty_show( x ) + +# SHOW METHODS +for i in j.get_methods() : + print i + i.pretty_show( x ) diff --git a/demos/tags.py b/demos/tags.py new file mode 100755 index 00000000..03f57af3 --- /dev/null +++ b/demos/tags.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import sys + +PATH_INSTALL = "./" +sys.path.append(PATH_INSTALL) + +from androguard.core.bytecodes import dvm +from androguard.core.bytecodes import apk +from androguard.core.analysis import analysis +from androguard.core import androconf + + +import hashlib + +TEST = "examples/android/TestsAndroguard/bin/TestsAndroguard.apk" + +androconf.set_debug() + +a = apk.APK( TEST ) +vm = dvm.DalvikVMFormat( a.get_dex() ) +vmx = analysis.VMAnalysis( vm ) + +for i in vmx.get_methods() : + i.create_tags() + + tags = i.get_tags() + if not tags.empty() : + print tags diff --git a/examples/android/Demo1/AndroidManifest.xml b/examples/android/Demo1/AndroidManifest.xml new file mode 100644 index 00000000..b9a3126c --- /dev/null +++ b/examples/android/Demo1/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/examples/android/Demo1/androguard.xml b/examples/android/Demo1/androguard.xml new file mode 100644 index 00000000..c8b89c03 --- /dev/null +++ b/examples/android/Demo1/androguard.xml @@ -0,0 +1,17 @@ + + + + + + org/t0t0/androguard/android/Demo1Math + x + . + + + + + + VM_INT_BASIC_MATH_FORMULA + + + diff --git a/examples/android/Demo1/bin/classes.dex b/examples/android/Demo1/bin/classes.dex new file mode 100644 index 00000000..7518025a Binary files /dev/null and b/examples/android/Demo1/bin/classes.dex differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/BaseCipher.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/BaseCipher.class new file mode 100644 index 00000000..b7a78a48 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/BaseCipher.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES$Context.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES$Context.class new file mode 100644 index 00000000..1b8c2bd7 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES$Context.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES.class new file mode 100644 index 00000000..dbf008fb Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/DES.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Activity.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Activity.class new file mode 100644 index 00000000..8091c46a Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Activity.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Math.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Math.class new file mode 100644 index 00000000..202cfcad Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Demo1Math.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipher.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipher.class new file mode 100644 index 00000000..3766bf40 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipher.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipherSpi.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipherSpi.class new file mode 100644 index 00000000..5d982d3a Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/IBlockCipherSpi.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties$1.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties$1.class new file mode 100644 index 00000000..de9adf89 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties$1.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties.class new file mode 100644 index 00000000..7631afd0 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Properties.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$attr.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$attr.class new file mode 100644 index 00000000..34f3d210 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$attr.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$drawable.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$drawable.class new file mode 100644 index 00000000..de986d28 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$drawable.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$layout.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$layout.class new file mode 100644 index 00000000..884d29bf Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$layout.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$string.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$string.class new file mode 100644 index 00000000..87973fec Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R$string.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R.class new file mode 100644 index 00000000..89551198 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/R.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Registry.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Registry.class new file mode 100644 index 00000000..b970a6fc Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Registry.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Util.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Util.class new file mode 100644 index 00000000..f6b65629 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/Util.class differ diff --git a/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/WeakKeyException.class b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/WeakKeyException.class new file mode 100644 index 00000000..28869676 Binary files /dev/null and b/examples/android/Demo1/bin/classes/org/t0t0/androguard/android/WeakKeyException.class differ diff --git a/examples/android/Demo1/build.properties b/examples/android/Demo1/build.properties new file mode 100644 index 00000000..edc7f230 --- /dev/null +++ b/examples/android/Demo1/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/examples/android/Demo1/build.xml b/examples/android/Demo1/build.xml new file mode 100644 index 00000000..c167d89a --- /dev/null +++ b/examples/android/Demo1/build.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/Demo1/default.properties b/examples/android/Demo1/default.properties new file mode 100644 index 00000000..9d135cb8 --- /dev/null +++ b/examples/android/Demo1/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/examples/android/Demo1/gen/org/t0t0/androguard/android/R.java b/examples/android/Demo1/gen/org/t0t0/androguard/android/R.java new file mode 100644 index 00000000..8ceb1477 --- /dev/null +++ b/examples/android/Demo1/gen/org/t0t0/androguard/android/R.java @@ -0,0 +1,22 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.t0t0.androguard.android; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class layout { + public static final int main=0x7f030000; + } + public static final class string { + public static final int app_name=0x7f040000; + } +} diff --git a/examples/android/Demo1/local.properties b/examples/android/Demo1/local.properties new file mode 100644 index 00000000..dad9e131 --- /dev/null +++ b/examples/android/Demo1/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/desnos/android/android-sdk-linux_x86 diff --git a/examples/android/Demo1/res/drawable-hdpi/icon.png b/examples/android/Demo1/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/examples/android/Demo1/res/drawable-hdpi/icon.png differ diff --git a/examples/android/Demo1/res/drawable-ldpi/icon.png b/examples/android/Demo1/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..1095584e Binary files /dev/null and b/examples/android/Demo1/res/drawable-ldpi/icon.png differ diff --git a/examples/android/Demo1/res/drawable-mdpi/icon.png b/examples/android/Demo1/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..a07c69fa Binary files /dev/null and b/examples/android/Demo1/res/drawable-mdpi/icon.png differ diff --git a/examples/android/Demo1/res/layout/main.xml b/examples/android/Demo1/res/layout/main.xml new file mode 100644 index 00000000..fb944107 --- /dev/null +++ b/examples/android/Demo1/res/layout/main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/examples/android/Demo1/res/values/strings.xml b/examples/android/Demo1/res/values/strings.xml new file mode 100644 index 00000000..bf555d14 --- /dev/null +++ b/examples/android/Demo1/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Demo1Activity + diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/BaseCipher.java b/examples/android/Demo1/src/org/t0t0/androguard/android/BaseCipher.java new file mode 100644 index 00000000..1fea093d --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/BaseCipher.java @@ -0,0 +1,264 @@ +package org.t0t0.androguard.android; + +// ---------------------------------------------------------------------------- +// $Id: BaseCipher.java,v 1.10 2003/09/26 23:37:37 raif Exp $ +// +// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + *

A basic abstract class to facilitate implementing symmetric key block + * ciphers.

+ * + * @version $Revision: 1.10 $ + */ +public abstract class BaseCipher implements IBlockCipher, IBlockCipherSpi { + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the cipher. */ + protected String name; + + /** The default block size, in bytes. */ + protected int defaultBlockSize; + + /** The default key size, in bytes. */ + protected int defaultKeySize; + + /** The current block size, in bytes. */ + protected int currentBlockSize; + + /** The session key for this instance. */ + protected transient Object currentKey; + + /** The instance lock. */ + protected Object lock = new Object(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this instance. + * @param defaultBlockSize the default block size in bytes. + * @param defaultKeySize the default key size in bytes. + */ + protected BaseCipher(String name, int defaultBlockSize, int defaultKeySize) { + super(); + + this.name = name; + this.defaultBlockSize = defaultBlockSize; + this.defaultKeySize = defaultKeySize; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IBlockCipher interface implementation ----------------------------------- + + public abstract Object clone(); + + public String name() { + StringBuffer sb = new StringBuffer(name).append('-'); + if (currentKey == null) { + sb.append(String.valueOf(8*defaultBlockSize)); + } else { + sb.append(String.valueOf(8*currentBlockSize)); + } + return sb.toString(); + } + + public int defaultBlockSize() { + return defaultBlockSize; + } + + public int defaultKeySize() { + return defaultKeySize; + } + + public void init(Map attributes) throws InvalidKeyException { + synchronized(lock) { + if (currentKey != null) { + throw new IllegalStateException(); + } + + Integer bs = (Integer) attributes.get(CIPHER_BLOCK_SIZE); + if (bs == null) { // no block size was specified. + if (currentBlockSize == 0) { // happy birthday + currentBlockSize = defaultBlockSize; + } // else it's a clone. use as is + } else { + currentBlockSize = bs.intValue(); + // ensure that value is valid + Iterator it; + boolean ok = false; + for (it = blockSizes(); it.hasNext(); ) { + ok = (currentBlockSize == ((Integer) it.next()).intValue()); + if (ok) { + break; + } + } + if (!ok) { + throw new IllegalArgumentException(IBlockCipher.CIPHER_BLOCK_SIZE); + } + } + + byte[] k = (byte[]) attributes.get(KEY_MATERIAL); + currentKey = makeKey(k, currentBlockSize); + } + } + + public int currentBlockSize() { + if (currentKey == null) { + throw new IllegalStateException(); + } + return currentBlockSize; + } + + public void reset() { + synchronized(lock) { +// currentBlockSize = 0; + currentKey = null; + } + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException { + synchronized(lock) { + if (currentKey == null) { + throw new IllegalStateException(); + } + + encrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException { + synchronized(lock) { + if (currentKey == null) { + throw new IllegalStateException(); + } + + decrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public boolean selfTest() { + int ks; + Iterator bit; + + // do symmetry tests for all block-size/key-size combos + for (Iterator kit = keySizes(); kit.hasNext(); ) { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext(); ) { + if (!testSymmetry(ks, ((Integer) bit.next()).intValue())) { + return false; + } + } + } + + return true; + } + + // own methods ------------------------------------------------------------- + + private boolean testSymmetry(int ks, int bs) { + try { + byte[] kb = new byte[ks]; + byte[] pt = new byte[bs]; + byte[] ct = new byte[bs]; + byte[] cpt = new byte[bs]; + int i; + for (i = 0; i < ks; i++) { + kb[i] = (byte) i; + } + for (i = 0; i < bs; i++) { + pt[i] = (byte) i; + } + + Object k = makeKey(kb, bs); + encrypt(pt, 0, ct, 0, k, bs); + decrypt(ct, 0, cpt, 0, k, bs); + + return Arrays.equals(pt, cpt); + + } catch (Exception x) { + x.printStackTrace(System.err); + return false; + } + } + + protected boolean testKat(byte[] kb, byte[] ct) { + return testKat(kb, ct, new byte[ct.length]); // all-zero plaintext + } + + protected boolean testKat(byte[] kb, byte[] ct, byte[] pt) { + try { + int bs = pt.length; + byte[] t = new byte[bs]; + + Object k = makeKey(kb, bs); + + // test encryption + encrypt(pt, 0, t, 0, k, bs); + if (!Arrays.equals(t, ct)) { + return false; + } + // test decryption + decrypt(t, 0, t, 0, k, bs); + return Arrays.equals(t, pt); + + } catch (Exception x) { + x.printStackTrace(System.err); + return false; + } + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/DES.java b/examples/android/Demo1/src/org/t0t0/androguard/android/DES.java new file mode 100644 index 00000000..263c73c7 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/DES.java @@ -0,0 +1,716 @@ +package org.t0t0.androguard.android; + +// ---------------------------------------------------------------------------- +// $Id: DES.java,v 1.3 2003/10/05 03:41:38 raif Exp $ +// +// Copyright (C) 2002, 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// +// -------------------------------------------------------------------------- + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +/** + *

The Data Encryption Standard. DES is a 64-bit block cipher with a 56-bit + * key, developed by IBM in the 1970's for the standardization process begun by + * the National Bureau of Standards (now NIST).

+ * + *

New applications should not use DES except for compatibility.

+ * + *

This version is based upon the description and sample implementation in + * [1].

+ * + *

References:

+ *
    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Pages 265--301, 623--632.
  2. + *
+ * + * @version $Revision: 1.3 $ + */ +public class DES extends BaseCipher { + + // Constants and variables + // ------------------------------------------------------------------------- + + /** DES operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + + /** DES uses 56 bits of a 64 bit parity-adjusted key. */ + public static final int KEY_SIZE = 8; + + // S-Boxes 1 through 8. + private static final int[] SP1 = new int[] { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 + }; + + private static final int[] SP2 = new int[] { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 + }; + + private static final int[] SP3 = new int[] { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 + }; + + private static final int[] SP4 = new int[] { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 + }; + + private static final int[] SP5 = new int[] { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 + }; + + private static final int[] SP6 = new int[] { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 + }; + + private static final int[] SP7 = new int[] { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 + }; + + private static final int[] SP8 = new int[] { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 + }; + + /** + * Constants that help in determining whether or not a byte array is parity + * adjusted. + */ + private static final byte[] PARITY = { + 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8 + }; + + // Key schedule constants. + + private static final byte[] ROTARS = { + 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 + }; + + private static final byte[] PC1 = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 + }; + + private static final byte[] PC2 = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 + }; + + /** + * Weak keys (parity adjusted): If all the bits in each half are either 0 + * or 1, then the key used for any cycle of the algorithm is the same as + * all other cycles. + */ + public static final byte[][] WEAK_KEYS = { + Util.toBytesFromString("0101010101010101"), + Util.toBytesFromString("01010101FEFEFEFE"), + Util.toBytesFromString("FEFEFEFE01010101"), + Util.toBytesFromString("FEFEFEFEFEFEFEFE") + }; + + /** + * Semi-weak keys (parity adjusted): Some pairs of keys encrypt plain text + * to identical cipher text. In other words, one key in the pair can decrypt + * messages that were encrypted with the other key. These keys are called + * semi-weak keys. This occurs because instead of 16 different sub-keys being + * generated, these semi-weak keys produce only two different sub-keys. + */ + public static final byte[][] SEMIWEAK_KEYS = { + Util.toBytesFromString("01FE01FE01FE01FE"), Util.toBytesFromString("FE01FE01FE01FE01"), + Util.toBytesFromString("1FE01FE00EF10EF1"), Util.toBytesFromString("E01FE01FF10EF10E"), + Util.toBytesFromString("01E001E001F101F1"), Util.toBytesFromString("E001E001F101F101"), + Util.toBytesFromString("1FFE1FFE0EFE0EFE"), Util.toBytesFromString("FE1FFE1FFE0EFE0E"), + Util.toBytesFromString("011F011F010E010E"), Util.toBytesFromString("1F011F010E010E01"), + Util.toBytesFromString("E0FEE0FEF1FEF1FE"), Util.toBytesFromString("FEE0FEE0FEF1FEF1") + }; + + /** Possible weak keys (parity adjusted) --produce 4 instead of 16 subkeys. */ + public static final byte[][] POSSIBLE_WEAK_KEYS = { + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("E0E00101F1F10101"), + Util.toBytesFromString("FEFE0101FEFE0101"), + Util.toBytesFromString("FEE01F01FEF10E01"), + Util.toBytesFromString("E0FE1F01F1FE0E01"), + Util.toBytesFromString("FEE0011FFEF1010E"), + Util.toBytesFromString("E0FE011FF1FE010E"), + Util.toBytesFromString("E0E01F1FF1F10E0E"), + Util.toBytesFromString("FEFE1F1FFEFE0E0E"), + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("01E0E00101F1F101"), + Util.toBytesFromString("1FFEE0010EFEF001"), + Util.toBytesFromString("1FE0FE010EF1FE01"), + Util.toBytesFromString("01FEFE0101FEFE01"), + Util.toBytesFromString("1FE0E01F0EF1F10E"), + Util.toBytesFromString("01FEE01F01FEF10E"), + Util.toBytesFromString("01E0FE1F01F1FE0E"), + Util.toBytesFromString("1FFEFE1F0EFEFE0E"), + + Util.toBytesFromString("E00101E0F10101F1"), + Util.toBytesFromString("FE1F01E0FE0E0EF1"), + Util.toBytesFromString("FE011FE0FE010EF1"), + Util.toBytesFromString("E01F1FE0F10E0EF1"), + Util.toBytesFromString("FE0101FEFE0101FE"), + Util.toBytesFromString("E01F01FEF10E01FE"), + Util.toBytesFromString("E0011FFEF1010EFE"), + Util.toBytesFromString("FE1F1FFEFE0E0EFE"), + Util.toBytesFromString("1FFE01E00EFE01F1"), + Util.toBytesFromString("01FE1FE001FE0EF1"), + Util.toBytesFromString("1FE001FE0EF101FE"), + Util.toBytesFromString("01E01FFE01F10EFE"), + Util.toBytesFromString("0101E0E00101F1F1"), + Util.toBytesFromString("1F1FE0E00E0EF1F1"), + Util.toBytesFromString("1F01FEE00E01FEF1"), + Util.toBytesFromString("011FFEE0010EFEF1"), + Util.toBytesFromString("1F01E0FE0E01F1FE"), + Util.toBytesFromString("011FE0FE010EF1FE"), + Util.toBytesFromString("0101FEFE0001FEFE"), + Util.toBytesFromString("1F1FFEFE0E0EFEFE"), + Util.toBytesFromString("FEFEE0E0FEFEF1F1"), + Util.toBytesFromString("E0FEFEE0F1FEFEF1"), + Util.toBytesFromString("FEE0E0FEFEF1F1FE"), + Util.toBytesFromString("E0E0FEFEF1F1FEFE") + }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Default 0-argument constructor. */ + public DES() { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Adjust the parity for a raw key array. This essentially means that each + * byte in the array will have an odd number of '1' bits (the last bit in + * each byte is unused.

+ * + * @param kb The key array, to be parity-adjusted. + * @param offset The starting index into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) { + for (int i = offset; i < KEY_SIZE; i++) { + kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0; + } + } + + /** + *

Test if a byte array, which must be at least 8 bytes long, is parity + * adjusted.

+ * + * @param kb The key bytes. + * @param offset The starting index into the key bytes. + * @return true if the first 8 bytes of kb have been + * parity adjusted. false otherwise. + */ + public static boolean isParityAdjusted(byte[] kb, int offset) { + int w = 0x88888888; + int n = PARITY[kb[offset+0] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+1] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+2] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+3] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+4] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+5] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+6] & 0xff]; n <<= 4; + n |= PARITY[kb[offset+7] & 0xff]; + return (n & w) == 0; + } + + /** + *

Test if a key is a weak key.

+ * + * @param kb The key to test. + * @return true if the key is weak. + */ + public static boolean isWeak(byte[] kb) { +// return Arrays.equals(kb, WEAK_KEYS[0]) || Arrays.equals(kb, WEAK_KEYS[1]) +// || Arrays.equals(kb, WEAK_KEYS[2]) || Arrays.equals(kb, WEAK_KEYS[3]) +// || Arrays.equals(kb, WEAK_KEYS[4]) || Arrays.equals(kb, WEAK_KEYS[5]) +// || Arrays.equals(kb, WEAK_KEYS[6]) || Arrays.equals(kb, WEAK_KEYS[7]); + for (int i = 0; i < WEAK_KEYS.length; i++) { + if (Arrays.equals(WEAK_KEYS[i], kb)) { + return true; + } + } + return false; + } + + /** + *

Test if a key is a semi-weak key.

+ * + * @param kb The key to test. + * @return true if this key is semi-weak. + */ + public static boolean isSemiWeak(byte[] kb) { +// return Arrays.equals(kb, SEMIWEAK_KEYS[0]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[1]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[2]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[3]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[4]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[5]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[6]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[7]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[8]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[9]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[10]) +// || Arrays.equals(kb, SEMIWEAK_KEYS[11]); + for (int i = 0; i < SEMIWEAK_KEYS.length; i++) { + if (Arrays.equals(SEMIWEAK_KEYS[i], kb)) { + return true; + } + } + return false; + } + + /** + *

Test if the designated byte array represents a possibly weak key.

+ * + * @param kb the byte array to test. + * @return true if kbrepresents a possibly weak key. + * Returns false otherwise. + */ + public static boolean isPossibleWeak(byte[] kb) { + for (int i = 0; i < POSSIBLE_WEAK_KEYS.length; i++) { + if (Arrays.equals(POSSIBLE_WEAK_KEYS[i], kb)) { + return true; + } + } + return false; + } + + /** + *

The core DES function. This is used for both encryption and decryption, + * the only difference being the key.

+ * + * @param in The input bytes. + * @param i The starting offset into the input bytes. + * @param out The output bytes. + * @param o The starting offset into the output bytes. + * @param key The working key. + */ + private static void desFunc(byte[] in, int i, byte[] out, int o, int[] key) { + int right, left, work; + + // Load. + left = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 | in[i++] & 0xff; + right = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 | in[i ] & 0xff; + + // Initial permutation. + work = ((left >>> 4) ^ right) & 0x0F0F0F0F; + left ^= work << 4; + right ^= work; + + work = ((left >>> 16) ^ right) & 0x0000FFFF; + left ^= work << 16; + right ^= work; + + work = ((right >>> 2) ^ left) & 0x33333333; + right ^= work << 2; + left ^= work; + + work = ((right >>> 8) ^ left) & 0x00FF00FF; + right ^= work << 8; + left ^= work; + + right = ((right << 1) | ((right >>> 31) & 1)) & 0xFFFFFFFF; + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = ((left << 1) | ((left >>> 31) & 1)) & 0xFFFFFFFF; + + int k = 0, t; + for (int round = 0; round < 8; round++) { + work = right >>> 4 | right << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; work >>>= 8; + t |= SP5[work & 0x3F]; work >>>= 8; + t |= SP3[work & 0x3F]; work >>>= 8; + t |= SP1[work & 0x3F]; + work = right ^ key[k++]; + t |= SP8[work & 0x3F]; work >>>= 8; + t |= SP6[work & 0x3F]; work >>>= 8; + t |= SP4[work & 0x3F]; work >>>= 8; + t |= SP2[work & 0x3F]; + left ^= t; + + work = left >>> 4 | left << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; work >>>= 8; + t |= SP5[work & 0x3F]; work >>>= 8; + t |= SP3[work & 0x3F]; work >>>= 8; + t |= SP1[work & 0x3F]; + work = left ^ key[k++]; + t |= SP8[work & 0x3F]; work >>>= 8; + t |= SP6[work & 0x3F]; work >>>= 8; + t |= SP4[work & 0x3F]; work >>>= 8; + t |= SP2[work & 0x3F]; + right ^= t; + } + + // The final permutation. + right = (right << 31) | (right >>> 1); + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = (left << 31) | (left >>> 1); + + work = ((left >>> 8) ^ right) & 0x00FF00FF; + left ^= work << 8; + right ^= work; + + work = ((left >>> 2) ^ right) & 0x33333333; + left ^= work << 2; + right ^= work; + + work = ((right >>> 16) ^ left) & 0x0000FFFF; + right ^= work << 16; + left ^= work; + + work = ((right >>> 4) ^ left) & 0x0F0F0F0F; + right ^= work << 4; + left ^= work; + + out[o++] = (byte)(right >>> 24); + out[o++] = (byte)(right >>> 16); + out[o++] = (byte)(right >>> 8); + out[o++] = (byte) right; + out[o++] = (byte)(left >>> 24); + out[o++] = (byte)(left >>> 16); + out[o++] = (byte)(left >>> 8); + out[o ] = (byte) left; + } + + // Instance methods implementing BaseCipher + // ------------------------------------------------------------------------- + + public Object clone() { + return new DES(); + } + + public Iterator blockSizes() { + return Collections.singleton(new Integer(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() { + return Collections.singleton(new Integer(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException { + if (kb == null || kb.length != KEY_SIZE) + throw new InvalidKeyException("DES keys must be 8 bytes long"); + + if (Properties.checkForWeakKeys() + && (isWeak(kb) || isSemiWeak(kb) || isPossibleWeak(kb))) { + throw new WeakKeyException(); + } + + int i, j, l, m, n; + long pc1m = 0, pcr = 0; + + for (i = 0; i < 56; i++) { + l = PC1[i]; + pc1m |= ((kb[l >>> 3] & (0x80 >>> (l & 7))) != 0) + ? (1L << (55 - i)) : 0; + } + + Context ctx = new Context(); + + // Encryption key first. + for (i = 0; i < 16; i++) { + pcr = 0; + m = i << 1; + n = m + 1; + for (j = 0; j < 28; j++) { + l = j + ROTARS[i]; + if (l < 28) pcr |= ((pc1m & 1L << (55 - l)) != 0) + ? (1L << (55 - j)) : 0; + else pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) + ? (1L << (55 - j)) : 0; + } + for (j = 28; j < 56; j++) { + l = j + ROTARS[i]; + if (l < 56) pcr |= ((pc1m & 1L << (55 - l)) != 0) + ? (1L << (55 - j)) : 0; + else pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) + ? (1L << (55 - j)) : 0; + } + for (j = 0; j < 24; j++) { + if ((pcr & 1L << (55 - PC2[j ])) != 0) ctx.ek[m] |= 1 << (23 - j); + if ((pcr & 1L << (55 - PC2[j+24])) != 0) ctx.ek[n] |= 1 << (23 - j); + } + } + + // The decryption key is the same, but in reversed order. + for (i = 0; i < Context.EXPANDED_KEY_SIZE; i += 2) { + ctx.dk[30 - i] = ctx.ek[i]; + ctx.dk[31 - i] = ctx.ek[i+1]; + } + + // "Cook" the keys. + for (i = 0; i < 32; i += 2) { + int x, y; + + x = ctx.ek[i ]; + y = ctx.ek[i+1]; + + ctx.ek[i ] = ((x & 0x00FC0000) << 6) | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) | ((y & 0x00000FC0) >>> 6); + ctx.ek[i+1] = ((x & 0x0003F000) << 12) | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) | (y & 0x0000003F); + + x = ctx.dk[i ]; + y = ctx.dk[i+1]; + + ctx.dk[i ] = ((x & 0x00FC0000) << 6) | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) | ((y & 0x00000FC0) >>> 6); + ctx.dk[i+1] = ((x & 0x0003F000) << 12) | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) | (y & 0x0000003F); + } + + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) { + desFunc(in, i, out, o, ((Context) K).ek); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) { + desFunc(in, i, out, o, ((Context) K).dk); + } + + // Inner classe(s) + // ========================================================================= + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context { + + // Constants and variables + // ---------------------------------------------------------------------- + + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + Context() { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + byte[] getEncryptionKeyBytes() { + return toByteArray(ek); + } + + byte[] getDecryptionKeyBytes() { + return toByteArray(dk); + } + + byte[] toByteArray(int[] k) { + byte[] result = new byte[4 * k.length]; + for (int i = 0, j = 0; i < k.length; i++) { + result[j++] = (byte)(k[i] >>> 24); + result[j++] = (byte)(k[i] >>> 16); + result[j++] = (byte)(k[i] >>> 8); + result[j++] = (byte) k[i]; + } + return result; + } + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Activity.java b/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Activity.java new file mode 100644 index 00000000..983ed612 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Activity.java @@ -0,0 +1,15 @@ +package org.t0t0.androguard.android; + +import android.app.Activity; +import android.os.Bundle; + +public class Demo1Activity extends Activity +{ + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Math.java b/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Math.java new file mode 100644 index 00000000..6f9b23a9 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/Demo1Math.java @@ -0,0 +1,238 @@ +package org.t0t0.androguard.android; + +import java.util.Arrays; +import java.util.HashMap; + +public class Demo1Math { + // Constants and variables. + // ----------------------------------------------------------------------- + + /** + *

Test vectors from NBS SP-500, "Validating the Correctness of Hardware + * Implementations of the NBS Data Encryption Standard".

+ */ + static final String[][] TV = { + // key bytes clear bytes cipher bytes + // IP and E test + { "0101010101010101", "95F8A5E5DD31D900", "8000000000000000" }, + { "0101010101010101", "DD7F121CA5015619", "4000000000000000" }, + { "0101010101010101", "2E8653104F3834EA", "2000000000000000" }, + { "0101010101010101", "4BD388FF6CD81D4F", "1000000000000000" }, + { "0101010101010101", "20B9E767B2FB1456", "0800000000000000" }, + { "0101010101010101", "55579380D77138EF", "0400000000000000" }, + { "0101010101010101", "6CC5DEFAAF04512F", "0200000000000000" }, + { "0101010101010101", "0D9F279BA5D87260", "0100000000000000" }, + { "0101010101010101", "D9031B0271BD5A0A", "0080000000000000" }, + { "0101010101010101", "424250B37C3DD951", "0040000000000000" }, + { "0101010101010101", "B8061B7ECD9A21E5", "0020000000000000" }, + { "0101010101010101", "F15D0F286B65BD28", "0010000000000000" }, + { "0101010101010101", "ADD0CC8D6E5DEBA1", "0008000000000000" }, + { "0101010101010101", "E6D5F82752AD63D1", "0004000000000000" }, + { "0101010101010101", "ECBFE3BD3F591A5E", "0002000000000000" }, + { "0101010101010101", "F356834379D165CD", "0001000000000000" }, + { "0101010101010101", "2B9F982F20037FA9", "0000800000000000" }, + { "0101010101010101", "889DE068A16F0BE6", "0000400000000000" }, + { "0101010101010101", "E19E275D846A1298", "0000200000000000" }, + { "0101010101010101", "329A8ED523D71AEC", "0000100000000000" }, + { "0101010101010101", "E7FCE22557D23C97", "0000080000000000" }, + { "0101010101010101", "12A9F5817FF2D65D", "0000040000000000" }, + { "0101010101010101", "A484C3AD38DC9C19", "0000020000000000" }, + { "0101010101010101", "FBE00A8A1EF8AD72", "0000010000000000" }, + { "0101010101010101", "750D079407521363", "0000008000000000" }, + { "0101010101010101", "64FEED9C724C2FAF", "0000004000000000" }, + { "0101010101010101", "F02B263B328E2B60", "0000002000000000" }, + { "0101010101010101", "9D64555A9A10B852", "0000001000000000" }, + { "0101010101010101", "D106FF0BED5255D7", "0000000800000000" }, + { "0101010101010101", "E1652C6B138C64A5", "0000000400000000" }, + { "0101010101010101", "E428581186EC8F46", "0000000200000000" }, + { "0101010101010101", "AEB5F5EDE22D1A36", "0000000100000000" }, + { "0101010101010101", "E943D7568AEC0C5C", "0000000080000000" }, + { "0101010101010101", "DF98C8276F54B04B", "0000000040000000" }, + { "0101010101010101", "B160E4680F6C696F", "0000000020000000" }, + { "0101010101010101", "FA0752B07D9C4AB8", "0000000010000000" }, + { "0101010101010101", "CA3A2B036DBC8502", "0000000008000000" }, + { "0101010101010101", "5E0905517BB59BCF", "0000000004000000" }, + { "0101010101010101", "814EEB3B91D90726", "0000000002000000" }, + { "0101010101010101", "4D49DB1532919C9F", "0000000001000000" }, + { "0101010101010101", "25EB5FC3F8CF0621", "0000000000800000" }, + { "0101010101010101", "AB6A20C0620D1C6F", "0000000000400000" }, + { "0101010101010101", "79E90DBC98F92CCA", "0000000000200000" }, + { "0101010101010101", "866ECEDD8072BB0E", "0000000000100000" }, + { "0101010101010101", "8B54536F2F3E64A8", "0000000000080000" }, + { "0101010101010101", "EA51D3975595B86B", "0000000000040000" }, + { "0101010101010101", "CAFFC6AC4542DE31", "0000000000020000" }, + { "0101010101010101", "8DD45A2DDF90796C", "0000000000010000" }, + { "0101010101010101", "1029D55E880EC2D0", "0000000000008000" }, + { "0101010101010101", "5D86CB23639DBEA9", "0000000000004000" }, + { "0101010101010101", "1D1CA853AE7C0C5F", "0000000000002000" }, + { "0101010101010101", "CE332329248F3228", "0000000000001000" }, + { "0101010101010101", "8405D1ABE24FB942", "0000000000000800" }, + { "0101010101010101", "E643D78090CA4207", "0000000000000400" }, + { "0101010101010101", "48221B9937748A23", "0000000000000200" }, + { "0101010101010101", "DD7C0BBD61FAFD54", "0000000000000100" }, + { "0101010101010101", "2FBC291A570DB5C4", "0000000000000080" }, + { "0101010101010101", "E07C30D7E4E26E12", "0000000000000040" }, + { "0101010101010101", "0953E2258E8E90A1", "0000000000000020" }, + { "0101010101010101", "5B711BC4CEEBF2EE", "0000000000000010" }, + { "0101010101010101", "CC083F1E6D9E85F6", "0000000000000008" }, + { "0101010101010101", "D2FD8867D50D2DFE", "0000000000000004" }, + { "0101010101010101", "06E7EA22CE92708F", "0000000000000002" }, + { "0101010101010101", "166B40B44ABA4BD6", "0000000000000001" }, + + // PC1 and PC2 test + { "8001010101010101", "0000000000000000", "95A8D72813DAA94D" }, + { "4001010101010101", "0000000000000000", "0EEC1487DD8C26D5" }, + { "2001010101010101", "0000000000000000", "7AD16FFB79C45926" }, + { "1001010101010101", "0000000000000000", "D3746294CA6A6CF3" }, + { "0801010101010101", "0000000000000000", "809F5F873C1FD761" }, + { "0401010101010101", "0000000000000000", "C02FAFFEC989D1FC" }, + { "0201010101010101", "0000000000000000", "4615AA1D33E72F10" }, + { "0180010101010101", "0000000000000000", "2055123350C00858" }, + { "0140010101010101", "0000000000000000", "DF3B99D6577397C8" }, + { "0120010101010101", "0000000000000000", "31FE17369B5288C9" }, + { "0110010101010101", "0000000000000000", "DFDD3CC64DAE1642" }, + { "0108010101010101", "0000000000000000", "178C83CE2B399D94" }, + { "0104010101010101", "0000000000000000", "50F636324A9B7F80" }, + { "0102010101010101", "0000000000000000", "A8468EE3BC18F06D" }, + { "0101800101010101", "0000000000000000", "A2DC9E92FD3CDE92" }, + { "0101400101010101", "0000000000000000", "CAC09F797D031287" }, + { "0101200101010101", "0000000000000000", "90BA680B22AEB525" }, + { "0101100101010101", "0000000000000000", "CE7A24F350E280B6" }, + { "0101080101010101", "0000000000000000", "882BFF0AA01A0B87" }, + { "0101040101010101", "0000000000000000", "25610288924511C2" }, + { "0101020101010101", "0000000000000000", "C71516C29C75D170" }, + { "0101018001010101", "0000000000000000", "5199C29A52C9F059" }, + { "0101014001010101", "0000000000000000", "C22F0A294A71F29F" }, + { "0101012001010101", "0000000000000000", "EE371483714C02EA" }, + { "0101011001010101", "0000000000000000", "A81FBD448F9E522F" }, + { "0101010801010101", "0000000000000000", "4F644C92E192DFED" }, + { "0101010401010101", "0000000000000000", "1AFA9A66A6DF92AE" }, + { "0101010201010101", "0000000000000000", "B3C1CC715CB879D8" }, + { "0101010180010101", "0000000000000000", "19D032E64AB0BD8B" }, + { "0101010140010101", "0000000000000000", "3CFAA7A7DC8720DC" }, + { "0101010120010101", "0000000000000000", "B7265F7F447AC6F3" }, + { "0101010110010101", "0000000000000000", "9DB73B3C0D163F54" }, + { "0101010108010101", "0000000000000000", "8181B65BABF4A975" }, + { "0101010104010101", "0000000000000000", "93C9B64042EAA240" }, + { "0101010102010101", "0000000000000000", "5570530829705592" }, + { "0101010101800101", "0000000000000000", "8638809E878787A0" }, + { "0101010101400101", "0000000000000000", "41B9A79AF79AC208" }, + { "0101010101200101", "0000000000000000", "7A9BE42F2009A892" }, + { "0101010101100101", "0000000000000000", "29038D56BA6D2745" }, + { "0101010101080101", "0000000000000000", "5495C6ABF1E5DF51" }, + { "0101010101040101", "0000000000000000", "AE13DBD561488933" }, + { "0101010101020101", "0000000000000000", "024D1FFA8904E389" }, + { "0101010101018001", "0000000000000000", "D1399712F99BF02E" }, + { "0101010101014001", "0000000000000000", "14C1D7C1CFFEC79E" }, + { "0101010101012001", "0000000000000000", "1DE5279DAE3BED6F" }, + { "0101010101011001", "0000000000000000", "E941A33F85501303" }, + { "0101010101010801", "0000000000000000", "DA99DBBC9A03F379" }, + { "0101010101010401", "0000000000000000", "B7FC92F91D8E92E9" }, + { "0101010101010201", "0000000000000000", "AE8E5CAA3CA04E85" }, + { "0101010101010180", "0000000000000000", "9CC62DF43B6EED74" }, + { "0101010101010140", "0000000000000000", "D863DBB5C59A91A0" }, + { "0101010101010120", "0000000000000000", "A1AB2190545B91D7" }, + { "0101010101010110", "0000000000000000", "0875041E64C570F7" }, + { "0101010101010108", "0000000000000000", "5A594528BEBEF1CC" }, + { "0101010101010104", "0000000000000000", "FCDB3291DE21F0C0" }, + { "0101010101010102", "0000000000000000", "869EFD7F9F265A09" }, + + // P test + { "1046913489980131", "0000000000000000", "88D55E54F54C97B4" }, + { "1007103489988020", "0000000000000000", "0C0CC00C83EA48FD" }, + { "10071034C8980120", "0000000000000000", "83BC8EF3A6570183" }, + { "1046103489988020", "0000000000000000", "DF725DCAD94EA2E9" }, + { "1086911519190101", "0000000000000000", "E652B53B550BE8B0" }, + { "1086911519580101", "0000000000000000", "AF527120C485CBB0" }, + { "5107B01519580101", "0000000000000000", "0F04CE393DB926D5" }, + { "1007B01519190101", "0000000000000000", "C9F00FFC74079067" }, + { "3107915498080101", "0000000000000000", "7CFD82A593252B4E" }, + { "3107919498080101", "0000000000000000", "CB49A2F9E91363E3" }, + { "10079115B9080140", "0000000000000000", "00B588BE70D23F56" }, + { "3107911598090140", "0000000000000000", "406A9A6AB43399AE" }, + { "1007D01589980101", "0000000000000000", "6CB773611DCA9ADA" }, + { "9107911589980101", "0000000000000000", "67FD21C17DBB5D70" }, + { "9107D01589190101", "0000000000000000", "9592CB4110430787" }, + { "1007D01598980120", "0000000000000000", "A6B7FF68A318DDD3" }, + { "1007940498190101", "0000000000000000", "4D102196C914CA16" }, + { "0107910491190401", "0000000000000000", "2DFA9F4573594965" }, + { "0107910491190101", "0000000000000000", "B46604816C0E0774" }, + { "0107940491190401", "0000000000000000", "6E7E6221A4F34E87" }, + { "19079210981A0101", "0000000000000000", "AA85E74643233199" }, + { "1007911998190801", "0000000000000000", "2E5A19DB4D1962D6" }, + { "10079119981A0801", "0000000000000000", "23A866A809D30894" }, + { "1007921098190101", "0000000000000000", "D812D961F017D320" }, + { "100791159819010B", "0000000000000000", "055605816E58608F" }, + { "1004801598190101", "0000000000000000", "ABD88E8B1B7716F1" }, + { "1004801598190102", "0000000000000000", "537AC95BE69DA1E1" }, + { "1004801598190108", "0000000000000000", "AED0F6AE3C25CDD8" }, + { "1002911598100104", "0000000000000000", "B3E35A5EE53E7B8D" }, + { "1002911598190104", "0000000000000000", "61C79C71921A2EF8" }, + { "1002911598100201", "0000000000000000", "E2F5728F0995013C" }, + { "1002911698100101", "0000000000000000", "1AEAC39A61F0A464" }, + + // S-Box test. + { "7CA110454A1A6E57", "01A1D6D039776742", "690F5B0D9A26939B" }, + { "0131D9619DC1376E", "5CD54CA83DEF57DA", "7A389D10354BD271" }, + { "07A1133E4A0B2686", "0248D43806F67172", "868EBB51CAB4599A" }, + { "3849674C2602319E", "51454B582DDF440A", "7178876E01F19B2A" }, + { "04B915BA43FEB5B6", "42FD443059577FA2", "AF37FB421F8C4095" }, + { "0113B970FD34F2CE", "059B5E0851CF143A", "86A560F10EC6D85B" }, + { "0170F175468FB5E6", "0756D8E0774761D2", "0CD3DA020021DC09" }, + { "43297FAD38E373FE", "762514B829BF486A", "EA676B2CB7DB2B7A" }, + { "07A7137045DA2A16", "3BDD119049372802", "DFD64A815CAF1A0F" }, + { "04689104C2FD3B2F", "26955F6835AF609A", "5C513C9C4886C088" }, + { "37D06BB516CB7546", "164D5E404F275232", "0A2AEEAE3FF4AB77" }, + { "1F08260D1AC2465E", "6B056E18759F5CCA", "EF1BF03E5DFA575A" }, + { "584023641ABA6176", "004BD6EF09176062", "88BF0DB6D70DEE56" }, + { "025816164629B007", "480D39006EE762F2", "A1F9915541020B56" }, + { "49793EBC79B3258F", "437540C8698F3CFA", "6FBF1CAFCFFD0556" }, + { "4FB05E1515AB73A7", "072D43A077075292", "2F22E49BAB7CA1AC" }, + { "49E95D6D4CA229BF", "02FE55778117F12A", "5A6B612CC26CCE4A" }, + { "018310DC409B26D6", "1D9D5C5018F728C2", "5F4C038ED12B2E41" }, + { "1C587F1C13924FEF", "305532286D6F295A", "63FAC0D034D9F793" } + }; + + // Constructors. + // ----------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods. + // ----------------------------------------------------------------------- + + // Instance methods. + // ----------------------------------------------------------------------- + + public Demo1Math() { + DES cipher = new DES(); + //HashMap attrib = new HashMap(); + //attrib.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(8)); + //attrib.put(IBlockCipher.KEY_MATERIAL, new byte[8]); + + Properties.setCheckForWeakKeys(false); + + try { + HashMap attrib = new HashMap(); + byte[] kb, pt, ct1, ct2 = new byte[8], cpt = new byte[8]; + for (int i = 0; i < TV.length; i++) { + kb = Util.toBytesFromString(TV[i][0]); + pt = Util.toBytesFromString(TV[i][1]); + ct1 = Util.toBytesFromString(TV[i][2]); + attrib.put(IBlockCipher.KEY_MATERIAL, kb); + cipher.reset(); + cipher.init(attrib); + cipher.encryptBlock(pt, 0, ct2, 0); + if (!Arrays.equals(ct1, ct2)) { + System.out.println(Util.toString(ct1) + " " + Util.toString(ct2)); + } + cipher.decryptBlock(ct2, 0, cpt, 0); + if (!Arrays.equals(pt, cpt)) { + System.out.println(Util.toString(pt) + " " + Util.toString(cpt)); + } + } + } catch (Exception x) { + System.out.println(x); + } + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipher.java b/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipher.java new file mode 100644 index 00000000..13788db5 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipher.java @@ -0,0 +1,212 @@ +package org.t0t0.androguard.android; + +// ---------------------------------------------------------------------------- +// $Id: IBlockCipher.java,v 1.7 2002/11/07 17:17:45 raif Exp $ +// +// Copyright (C) 2001, 2002, Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.security.InvalidKeyException; +import java.util.Iterator; +import java.util.Map; + +/** + *

The basic visible methods of any symmetric key block cipher.

+ * + *

A symmetric key block cipher is a function that maps n-bit plaintext + * blocks to n-bit ciphertext blocks; n being the cipher's block size. + * This encryption function is parameterised by a k-bit key, and is invertible. + * Its inverse is the decryption function.

+ * + *

Possible initialisation values for an instance of this type are:

+ * + *
    + *
  • The block size in which to operate this block cipher instance. This + * value is optional, if unspecified, the block cipher's default + * block size shall be used.
  • + * + *
  • The byte array containing the user supplied key material to use for + * generating the cipher's session key(s). This value is mandatory + * and should be included in the initialisation parameters. If it isn't, + * an {@link IllegalStateException} will be thrown if any method, other than + * reset() is invoked on the instance. Furthermore, the size of + * this key material shall be taken as an indication on the key size in which + * to operate this instance.
  • + *
+ * + *

IMPLEMENTATION NOTE: Although all the concrete classes in this + * package implement the {@link Cloneable} interface, it is important to note + * here that such an operation DOES NOT clone any session key material + * that may have been used in initialising the source cipher (the instance to be + * cloned). Instead a clone of an already initialised cipher is another instance + * that operates with the same block size but without any knowledge of + * neither key material nor key size.

+ * + * @version $Revision: 1.7 $ + */ +public interface IBlockCipher extends Cloneable { + + // Constants + // ------------------------------------------------------------------------- + + /** + *

Property name of the block size in which to operate a block cipher. + * The value associated with this property name is taken to be an + * {@link Integer}.

+ */ + String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size"; + + /** + *

Property name of the user-supplied key material. The value associated + * to this property name is taken to be a byte array.

+ */ + String KEY_MATERIAL = "gnu.crypto.cipher.key.material"; + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this instance.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + *

Returns the default value, in bytes, of the algorithm's block size.

+ * + * @return the default value, in bytes, of the algorithm's block size. + */ + int defaultBlockSize(); + + /** + *

Returns the default value, in bytes, of the algorithm's key size.

+ * + * @return the default value, in bytes, of the algorithm's key size. + */ + int defaultKeySize(); + + /** + *

Returns an {@link Iterator} over the supported block sizes. Each + * element returned by this object is an {@link Integer}.

+ * + * @return an {@link Iterator} over the supported block sizes. + */ + Iterator blockSizes(); + + /** + *

Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is an {@link Integer}.

+ * + * @return an {@link Iterator} over the supported key sizes. + */ + Iterator keySizes(); + + /** + *

Returns a clone of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone(); + + /** + *

Initialises the algorithm with designated attributes. Permissible names + * and values are described in the class documentation above.

+ * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #KEY_MATERIAL + * @see #CIPHER_BLOCK_SIZE + */ + void init(Map attributes) + throws InvalidKeyException, IllegalStateException; + + /** + *

Returns the currently set block size for this instance.

+ * + * @return the current block size for this instance. + * @exception IllegalStateException if the instance is not initialised. + */ + int currentBlockSize() throws IllegalStateException; + + /** + *

Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds.

+ */ + void reset(); + + /** + *

Encrypts exactly one block of plaintext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + *

Decrypts exactly one block of ciphertext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + *

A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT).

+ * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipherSpi.java b/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipherSpi.java new file mode 100644 index 00000000..1968e874 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/IBlockCipherSpi.java @@ -0,0 +1,133 @@ +package org.t0t0.androguard.android; +// ---------------------------------------------------------------------------- +// $Id: IBlockCipherSpi.java,v 1.4 2002/11/07 17:17:45 raif Exp $ +// +// Copyright (C) 2001, 2002, Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.security.InvalidKeyException; +import java.util.Iterator; + +/** + *

Package-private interface exposing mandatory methods to be implemented by + * concrete {@link gnu.crypto.cipher.BaseCipher} sub-classes.

+ * + * @version $Revision: 1.4 $ + */ +interface IBlockCipherSpi extends Cloneable { + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns an {@link java.util.Iterator} over the supported block sizes. + * Each element returned by this object is a {@link java.lang.Integer}.

+ * + * @return an Iterator over the supported block sizes. + */ + Iterator blockSizes(); + + /** + *

Returns an {@link java.util.Iterator} over the supported key sizes. + * Each element returned by this object is a {@link java.lang.Integer}.

+ * + * @return an Iterator over the supported key sizes. + */ + Iterator keySizes(); + + /** + *

Expands a user-supplied key material into a session key for a + * designated block size.

+ * + * @param k the user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is invalid. + * @exception InvalidKeyException if the key data is invalid. + */ + Object makeKey(byte[]k, int bs) throws InvalidKeyException; + + /** + *

Encrypts exactly one block of plaintext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store the result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void + encrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, int bs); + + /** + *

Decrypts exactly one block of ciphertext.

+ * + * @param in the ciphertext. + * @param inOffset index of in from which to start considering + * data. + * @param out the plaintext. + * @param outOffset index of out from which to store the result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void + decrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, int bs); + + /** + *

A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT).

+ * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/Properties.java b/examples/android/Demo1/src/org/t0t0/androguard/android/Properties.java new file mode 100644 index 00000000..9976ddd3 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/Properties.java @@ -0,0 +1,344 @@ +package org.t0t0.androguard.android; + +// ---------------------------------------------------------------------------- +// $Id: Properties.java,v 1.7 2004/01/14 23:17:42 rsdio Exp $ +// +// Copyright (C) 2003, 2004 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.util.HashMap; +import java.util.PropertyPermission; + +/** + *

A global object containing build-specific properties that affect the + * behaviour of the generated binaries from this library.

+ * + * @version $Revision: 1.7 $ + */ +public final class Properties { + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "Properties"; + private static final boolean DEBUG = true; +// private static final int debuglevel = 9; + private static final PrintWriter err = new PrintWriter(System.out, true); + private static void debug(final String s) { + err.println(">>> "+NAME+": "+s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String PROPERTIES_FILE = "gnu.crypto.properties.file"; + public static final String REPRODUCIBLE_PRNG = "gnu.crypto.with.reproducible.prng"; + public static final String CHECK_WEAK_KEYS = "gnu.crypto.with.check.for.weak.keys"; + public static final String DO_RSA_BLINDING = "gnu.crypto.with.rsa.blinding"; + + private static final String TRUE = Boolean.TRUE.toString(); + private static final String FALSE = Boolean.FALSE.toString(); + private static final HashMap props = new HashMap(); + private static Properties singleton = null; + + private boolean reproducible = false; + private boolean checkForWeakKeys = true; + private boolean doRSABlinding = true; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Properties() { + super(); + + init(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns the string representation of the library global configuration + * property with the designated key.

+ * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @return the string representation of the designated property, or + * null if such property is not yet set, or key is + * empty. + */ + public static synchronized final String getProperty(String key) { + if (key == null) { + return null; + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(key, "read")); + } + key = key.trim().toLowerCase(); + if ("".equals(key)) { + return null; + } + return (String) props.get(key); + } + + /** + *

Sets the value of a designated library global configuration property, + * to a string representation of what should be a legal value.

+ * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @param value the non-null, non-empty string representation of a legal + * value of the configuration property named by key. + */ + public static synchronized final void setProperty(String key, String value) { + if (key == null || value == null) { + return; + } + key = key.trim().toLowerCase(); + if ("".equals(key)) { + return; + } + value = value.trim(); + if ("".equals(value)) { + return; + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(key, "write")); + } + if (key.equals(REPRODUCIBLE_PRNG) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) { + setReproducible(Boolean.valueOf(value).booleanValue()); + } else if (key.equals(CHECK_WEAK_KEYS) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) { + setCheckForWeakKeys(Boolean.valueOf(value).booleanValue()); + } else if (key.equals(DO_RSA_BLINDING) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) { + setDoRSABlinding(Boolean.valueOf(value).booleanValue()); + } else { + props.put(key, value); + } + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if the default Pseudo Random Number + * Generator produces, or not, the same bit stream when instantiated.

+ * + * @return true if the default PRNG produces the same bit stream + * with every VM instance. Returns false if the default PRNG is + * seeded with the time of day of its first invocation. + */ + public static synchronized final boolean isReproducible() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "read")); + } + return instance().reproducible; + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if the implementations of symmetric + * key block ciphers check, or not, for possible/potential weak and semi-weak + * keys that may be produced in the course of generating round encryption + * and/or decryption keys.

+ * + * @return true if the cipher implementations check for weak and + * semi-weak keys. Returns false if the cipher implementations + * do not check for weak or semi-weak keys. + */ + public static synchronized final boolean checkForWeakKeys() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "read")); + } + return instance().checkForWeakKeys; + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if RSA decryption (RSADP primitive), + * does, or not, blinding against timing attacks.

+ * + * @return true if the RSA decryption primitive includes a + * blinding operation. Returns false if the RSA decryption + * primitive does not include the additional blinding operation. + */ + public static synchronized final boolean doRSABlinding() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "read")); + } + return instance().doRSABlinding; + } + + /** + *

A convenience method to set the global property for reproducibility of + * the default PRNG bit stream output.

+ * + * @param value if true then the default PRNG bit stream output + * is the same with every invocation of the VM. + */ + public static synchronized final void setReproducible(final boolean value) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "write")); + } + instance().reproducible = value; + props.put(REPRODUCIBLE_PRNG, String.valueOf(value)); + } + + /** + *

A convenience method to set the global property for checking for weak + * and semi-weak cipher keys.

+ * + * @param value if true then the cipher implementations will + * invoke additional checks for weak and semi-weak key values that may get + * generated. + */ + public static synchronized final void setCheckForWeakKeys(final boolean value) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "write")); + } + instance().checkForWeakKeys = value; + props.put(CHECK_WEAK_KEYS, String.valueOf(value)); + } + + /** + *

A convenience method to set the global property fo adding a blinding + * operation when executing the RSA decryption primitive.

+ * + * @param value if true then the code for performing the RSA + * decryption primitive will include a blinding operation. + */ + public static synchronized final void setDoRSABlinding(final boolean value) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "write")); + } + instance().doRSABlinding = value; + props.put(DO_RSA_BLINDING, String.valueOf(value)); + } + + private static synchronized final Properties instance() { + if (singleton == null) { + singleton = new Properties(); + } + return singleton; + } + + // Instance methods + // ------------------------------------------------------------------------- + + private void init() { + // default values + props.put(REPRODUCIBLE_PRNG, new Boolean(reproducible).toString()); + props.put(CHECK_WEAK_KEYS, new Boolean(checkForWeakKeys).toString()); + props.put(DO_RSA_BLINDING, new Boolean(doRSABlinding).toString()); + + // 1. allow site-wide override by reading a properties file + String propFile = null; + try { + propFile = (String) AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return System.getProperty(PROPERTIES_FILE); + } + } + ); + } catch (SecurityException se) { + if (DEBUG) debug("Reading property "+PROPERTIES_FILE+" not allowed. Ignored."); + } + if (propFile != null) { + try { + final java.util.Properties temp = new java.util.Properties(); + final FileInputStream fin = new FileInputStream(propFile); + temp.load(fin); + temp.list(System.out); + props.putAll(temp); + } catch (IOException ioe) { + if (DEBUG) debug("IO error reading "+propFile+": "+ioe.getMessage()); + } catch (SecurityException se) { + if (DEBUG) debug("Security error reading "+propFile+": "+se.getMessage()); + } + } + + // 2. allow vm-specific override by allowing -D options in launcher + handleBooleanProperty(REPRODUCIBLE_PRNG); + handleBooleanProperty(CHECK_WEAK_KEYS); + handleBooleanProperty(DO_RSA_BLINDING); + + // re-sync the 'known' properties + reproducible = new Boolean((String) props.get(REPRODUCIBLE_PRNG)).booleanValue(); + checkForWeakKeys = new Boolean((String) props.get(CHECK_WEAK_KEYS)).booleanValue(); + doRSABlinding = new Boolean((String) props.get(DO_RSA_BLINDING)).booleanValue(); + } + + private void handleBooleanProperty(final String name) { + String s = null; + try { + s = System.getProperty(name); + } catch (SecurityException x) { + if (DEBUG) debug("SecurityManager forbids reading system properties. Ignored"); + } + if (s != null) { + s = s.trim().toLowerCase(); + // we have to test for explicit "true" or "false". anything else may + // hide valid value set previously + if (s.equals(TRUE) || s.equals(FALSE)) { + if (DEBUG) debug("Setting "+name+" to '"+s+"'"); + props.put(name, s); + } else { + if (DEBUG) debug("Invalid value for -D"+name+": "+s+". Ignored"); + } + } + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/Registry.java b/examples/android/Demo1/src/org/t0t0/androguard/android/Registry.java new file mode 100644 index 00000000..5461522b --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/Registry.java @@ -0,0 +1,338 @@ +package org.t0t0.androguard.android; + +// ---------------------------------------------------------------------------- +// $Id: Registry.java,v 1.24 2003/11/21 09:19:25 raif Exp $ +// +// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +/** + * A placeholder for names and literals used throughout this + * library. + * + * @version $Revision: 1.24 $ + */ +public interface Registry { + + // Constants + // ------------------------------------------------------------------------- + + /** The name of our Provider. */ + String GNU_CRYPTO = "GNU-CRYPTO"; + + // Names of properties to use in Maps when initialising primitives ......... + + // Symmetric block cipher algorithms and synonyms........................... + + String ANUBIS_CIPHER = "anubis"; + String BLOWFISH_CIPHER = "blowfish"; + String DES_CIPHER = "des"; + String KHAZAD_CIPHER = "khazad"; + String RIJNDAEL_CIPHER = "rijndael"; + String SERPENT_CIPHER = "serpent"; + String SQUARE_CIPHER = "square"; + String TRIPLEDES_CIPHER = "tripledes"; + String TWOFISH_CIPHER = "twofish"; + String CAST5_CIPHER = "cast5"; + String NULL_CIPHER = "null"; + + /** AES is synonymous to Rijndael for 128-bit block size only. */ + String AES_CIPHER = "aes"; + + /** TripleDES is also known as DESede. */ + String DESEDE_CIPHER = "desede"; + + /** CAST5 is also known as CAST-128. */ + String CAST128_CIPHER = "cast128"; + String CAST_128_CIPHER = "cast-128"; + + // Message digest algorithms and synonyms................................... + + String WHIRLPOOL_HASH = "whirlpool"; + String RIPEMD128_HASH = "ripemd128"; + String RIPEMD160_HASH = "ripemd160"; + String SHA160_HASH = "sha-160"; + String SHA256_HASH = "sha-256"; + String SHA384_HASH = "sha-384"; + String SHA512_HASH = "sha-512"; + String TIGER_HASH = "tiger"; + String HAVAL_HASH = "haval"; + String MD5_HASH = "md5"; + String MD4_HASH = "md4"; + String MD2_HASH = "md2"; + + /** RIPEMD-128 is synonymous to RIPEMD128. */ + String RIPEMD_128_HASH = "ripemd-128"; + + /** RIPEMD-160 is synonymous to RIPEMD160. */ + String RIPEMD_160_HASH = "ripemd-160"; + + /** SHA-1 is synonymous to SHA-160. */ + String SHA_1_HASH = "sha-1"; + + /** SHA1 is synonymous to SHA-160. */ + String SHA1_HASH = "sha1"; + + /** SHA is synonymous to SHA-160. */ + String SHA_HASH = "sha"; + + // Symmetric block cipher modes of operations............................... + + /** Electronic CodeBook mode. */ + String ECB_MODE = "ecb"; + + /** Counter (NIST) mode. */ + String CTR_MODE = "ctr"; + + /** Integer Counter Mode (David McGrew). */ + String ICM_MODE = "icm"; + + /** Output Feedback Mode (NIST). */ + String OFB_MODE = "ofb"; + + /** Cipher block chaining mode (NIST). */ + String CBC_MODE = "cbc"; + + /** Cipher feedback mode (NIST). */ + String CFB_MODE = "cfb"; + + // Padding scheme names and synonyms........................................ + + /** PKCS#7 padding scheme. */ + String PKCS7_PAD = "pkcs7"; + + /** Trailing Bit Complement padding scheme. */ + String TBC_PAD = "tbc"; + + /** EME-PKCS1-v1_5 padding as described in section 7.2 in RFC-3447. */ + String EME_PKCS1_V1_5_PAD = "eme-pkcs1-v1.5"; + + // Pseudo-random number generators.......................................... + + /** (Apparently) RC4 keystream PRNG. */ + String ARCFOUR_PRNG = "arcfour"; + + /** We use "rc4" as an alias for "arcfour". */ + String RC4_PRNG = "rc4"; + + /** PRNG based on David McGrew's Integer Counter Mode. */ + String ICM_PRNG = "icm"; + + /** PRNG based on a designated hash function. */ + String MD_PRNG = "md"; + + /** PRNG based on UMAC's Key Derivation Function. */ + String UMAC_PRNG = "umac-kdf"; + + /** + * PRNG based on PBKDF2 from PKCS #5 v.2. This is suffixed with the name + * of a MAC to be used as a PRF. + */ + String PBKDF2_PRNG_PREFIX = "pbkdf2-"; + + // Asymmetric keypair generators............................................ + + String DSS_KPG = "dss"; + String RSA_KPG = "rsa"; + String DH_KPG = "dh"; + String SRP_KPG = "srp"; + + /** DSA is synonymous to DSS. */ + String DSA_KPG = "dsa"; + + // Signature-with-appendix schemes.......................................... + + String DSS_SIG = "dss"; + String RSA_PSS_SIG = "rsa-pss"; + String RSA_PKCS1_V1_5_SIG = "rsa-pkcs1-v1.5"; + + /** DSA is synonymous to DSS. */ + String DSA_SIG = "dsa"; + + // Key agreement protocols ................................................. + + String DH_KA = "dh"; + String ELGAMAL_KA = "elgamal"; + String SRP6_KA = "srp6"; + String SRP_SASL_KA = "srp-sasl"; + String SRP_TLS_KA = "srp-tls"; + + // Keyed-Hash Message Authentication Code .................................. + + /** Name prefix of every HMAC implementation. */ + String HMAC_NAME_PREFIX = "hmac-"; + + // Other MAC algorithms .................................................... + + /** Message Authentication Code using Universal Hashing (Ted Krovetz). */ + String UHASH32 = "uhash32"; + String UMAC32 = "umac32"; + /** The Truncated Multi-Modular Hash Function -v1 (David McGrew). */ + String TMMH16 = "tmmh16"; +// String TMMH32 = "tmmh32"; + + // Format IDs used to identify how we externalise asymmetric keys .......... + String RAW_ENCODING = "gnu.crypto.raw.format"; + int RAW_ENCODING_ID = 1; + + // Magic bytes we generate/expect in externalised asymmetric keys .......... + // the four bytes represent G (0x47) for GNU, 1 (0x01) for Raw format, + // D (0x44) for DSS, R (0x52) for RSA, H (0x48) for Diffie-Hellman, or S + // (0x53) for SRP-6, and finally P (0x50) for Public, p (0x70) for private, + // or S (0x53) for signature. + byte[] MAGIC_RAW_DSS_PUBLIC_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x44, 0x50}; + byte[] MAGIC_RAW_DSS_PRIVATE_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x44, 0x70}; + byte[] MAGIC_RAW_DSS_SIGNATURE = new byte[] {0x47, RAW_ENCODING_ID, 0x44, 0x53}; + byte[] MAGIC_RAW_RSA_PUBLIC_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x52, 0x50}; + byte[] MAGIC_RAW_RSA_PRIVATE_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x52, 0x70}; + byte[] MAGIC_RAW_RSA_PSS_SIGNATURE = new byte[] {0x47, RAW_ENCODING_ID, 0x52, 0x53}; + + byte[] MAGIC_RAW_DH_PUBLIC_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x48, 0x50}; + byte[] MAGIC_RAW_DH_PRIVATE_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x48, 0x70}; + + byte[] MAGIC_RAW_SRP_PUBLIC_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x53, 0x50}; + byte[] MAGIC_RAW_SRP_PRIVATE_KEY = new byte[] {0x47, RAW_ENCODING_ID, 0x53, 0x70}; + + // SASL Property names ..................................................... + + String SASL_PREFIX = "gnu.crypto.sasl"; + + /** Name of username property. */ + String SASL_USERNAME = SASL_PREFIX + ".username"; + + /** Name of password property. */ + String SASL_PASSWORD = SASL_PREFIX + ".password"; + + /** Name of authentication information provider packages. */ + String SASL_AUTH_INFO_PROVIDER_PKGS = SASL_PREFIX + ".auth.info.provider.pkgs"; + + /** SASL authorization ID. */ + String SASL_AUTHORISATION_ID = SASL_PREFIX + ".authorisation.ID"; + + /** SASL protocol. */ + String SASL_PROTOCOL = SASL_PREFIX + ".protocol"; + + /** SASL Server name. */ + String SASL_SERVER_NAME = SASL_PREFIX + ".server.name"; + + /** SASL Callback handler. */ + String SASL_CALLBACK_HANDLER = SASL_PREFIX + ".callback.handler"; + + /** SASL channel binding. */ + String SASL_CHANNEL_BINDING = SASL_PREFIX + ".channel.binding"; + + // SASL data element size limits ........................................... + + /** The size limit, in bytes, of a SASL OS (Octet Sequence) element. */ + int SASL_ONE_BYTE_MAX_LIMIT = 255; + + /** + * The size limit, in bytes, of both a SASL MPI (Multi-Precision Integer) + * element and a SASL Text element. + */ + int SASL_TWO_BYTE_MAX_LIMIT = 65535; + + /** The size limit, in bytes, of a SASL EOS (Extended Octet Sequence) element. */ + int SASL_FOUR_BYTE_MAX_LIMIT = 2147483383; + + /** The size limit, in bytes, of a SASL Buffer. */ + int SASL_BUFFER_MAX_LIMIT = 2147483643; + + // Canonical names of SASL mechanisms ...................................... + + String SASL_ANONYMOUS_MECHANISM = "ANONYMOUS"; + String SASL_CRAM_MD5_MECHANISM = "CRAM-MD5"; + String SASL_PLAIN_MECHANISM = "PLAIN"; + String SASL_SRP_MECHANISM = "SRP"; + + // Canonical names of Integrity Protection algorithms ...................... + + String SASL_HMAC_MD5_IALG = "HMACwithMD5"; + String SASL_HMAC_SHA_IALG = "HMACwithSHA"; + + // Quality Of Protection string representations ............................ + + /** authentication only. */ + String QOP_AUTH = "auth"; + /** authentication plus integrity protection. */ + String QOP_AUTH_INT = "auth-int"; + /** authentication plus integrity and confidentiality protection. */ + String QOP_AUTH_CONF = "auth-conf"; + + // SASL mechanism strength string representation ........................... + + String STRENGTH_HIGH = "high"; + String STRENGTH_MEDIUM = "medium"; + String STRENGTH_LOW = "low"; + + // SASL Server Authentication requirement .................................. + + /** Server must authenticate to the client. */ + String SERVER_AUTH_TRUE = "true"; + /** Server does not need to, or cannot, authenticate to the client. */ + String SERVER_AUTH_FALSE = "false"; + + // SASL mechanism reuse capability ......................................... + + String REUSE_TRUE = "true"; + String REUSE_FALSE = "false"; + + // Keyrings ............................................................... + + byte[] GKR_MAGIC = new byte[] { 0x47, 0x4b, 0x52, 0x01 }; + + // Ring usage fields. + int GKR_PRIVATE_KEYS = 0; + int GKR_PUBLIC_CREDENTIALS = 1; + int GKR_CERTIFICATES = 3; + + // HMac types. + int GKR_HMAC_MD5_128 = 0; + int GKR_HMAC_SHA_160 = 1; + int GKR_HMAC_MD5_96 = 2; + int GKR_HMAC_SHA_96 = 3; + + // Cipher types. + int GKR_CIPHER_AES_128_OFB = 0; + int GKR_CIPHER_AES_128_CBC = 1; + + // Methods + // ------------------------------------------------------------------------- +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/Util.java b/examples/android/Demo1/src/org/t0t0/androguard/android/Util.java new file mode 100644 index 00000000..5af59c17 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/Util.java @@ -0,0 +1,611 @@ +package org.t0t0.androguard.android; +// ---------------------------------------------------------------------------- +// $Id: Util.java,v 1.10 2003/09/27 00:03:01 raif Exp $ +// +// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.math.BigInteger; + +/** + *

A collection of utility methods used throughout this project.

+ * + * @version $Revision: 1.10 $ + */ +public class Util { + + // Constants and variables + // ------------------------------------------------------------------------- + + // Hex charset + private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); + + // Base-64 charset + private static final String BASE64_CHARS = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; + private static final char[] BASE64_CHARSET = BASE64_CHARS.toCharArray(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Util() { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included.

+ * + *

This method calls the method with same name and three arguments as:

+ * + *
+    *    toString(ba, 0, ba.length);
+    * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte array. + */ + public static String toString(byte[] ba) { + return toString(ba, 0, ba.length); + } + + /** + *

Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each byte + * is converted to 2 hex symbols; zero(es) included.

+ * + * @param ba the byte array to convert. + * @param offset the index from which to start considering the bytes to + * convert. + * @param length the count of bytes, starting from the designated offset to + * convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte sub-array. + */ + public static final String toString(byte[] ba, int offset, int length) { + char[] buf = new char[length * 2]; + for (int i = 0, j = 0, k; i < length; ) { + k = ba[offset + i++]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included. The argument is + * treated as a large little-endian integer and is returned as a + * large big-endian integer.

+ * + *

This method calls the method with same name and three arguments as:

+ * + *
+    *    toReversedString(ba, 0, ba.length);
+    * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte array. + */ + public static String toReversedString(byte[] ba) { + return toReversedString(ba, 0, ba.length); + } + + /** + *

Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each byte + * is converted to 2 hex symbols; zero(es) included.

+ * + *

The byte array is treated as a large little-endian integer, and + * is returned as a large big-endian integer.

+ * + * @param ba the byte array to convert. + * @param offset the index from which to start considering the bytes to + * convert. + * @param length the count of bytes, starting from the designated offset to + * convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte sub-array. + */ + public static final String + toReversedString(byte[] ba, int offset, int length) { + char[] buf = new char[length * 2]; + for (int i = offset+length-1, j = 0, k; i >= offset; ) { + k = ba[offset + i--]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a byte array from a string of hexadecimal digits.

+ * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toBytesFromString(String s) { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0, j = 0; + if ((limit % 2) == 1) { + result[j++] = (byte) fromDigit(s.charAt(i++)); + } + while (i < limit) { + result[j ] = (byte) (fromDigit(s.charAt(i++)) << 4); + result[j++] |= (byte) fromDigit(s.charAt(i++)); + } + return result; + } + + /** + *

Returns a byte array from a string of hexadecimal digits, interpreting + * them as a large big-endian integer and returning it as a large + * little-endian integer.

+ * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toReversedBytesFromString(String s) { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0; + if ((limit % 2) == 1) { + result[i++] = (byte) fromDigit(s.charAt(--limit)); + } + while (limit > 0) { + result[i ] = (byte) fromDigit(s.charAt(--limit)); + result[i++] |= (byte) (fromDigit(s.charAt(--limit)) << 4); + } + return result; + } + + /** + *

Returns a number from 0 to 15 corresponding + * to the designated hexadecimal digit.

+ * + * @param c a hexadecimal ASCII symbol. + */ + public static int fromDigit(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else + throw new IllegalArgumentException("Invalid hexadecimal digit: " + c); + } + + /** + *

Returns a string of 8 hexadecimal digits (most significant digit first) + * corresponding to the unsigned integer n.

+ * + * @param n the unsigned integer to convert. + * @return a hexadecimal string 8-character long. + */ + public static String toString(int n) { + char[] buf = new char[8]; + for (int i = 7; i >= 0; i--) { + buf[i] = HEX_DIGITS[n & 0x0F]; + n >>>= 4; + } + return new String(buf); + } + + /** + *

Returns a string of hexadecimal digits from an integer array. Each int + * is converted to 4 hex symbols.

+ */ + public static String toString(int[] ia) { + int length = ia.length; + char[] buf = new char[length * 8]; + for (int i = 0, j = 0, k; i < length; i++) { + k = ia[i]; + buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 8) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a string of 16 hexadecimal digits (most significant digit first) + * corresponding to the unsigned long n.

+ * + * @param n the unsigned long to convert. + * @return a hexadecimal string 16-character long. + */ + public static String toString(long n) { + char[] b = new char[16]; + for (int i = 15; i >= 0; i--) { + b[i] = HEX_DIGITS[(int)(n & 0x0FL)]; + n >>>= 4; + } + return new String(b); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static String toUnicodeString(byte[] ba) { + return toUnicodeString(ba, 0, ba.length); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static final String + toUnicodeString(byte[] ba, int offset, int length) { + StringBuffer sb = new StringBuffer(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < length) { + sb.append("\\u"); + + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + + if ((++j % 8) == 0) { + sb.append("\"+").append('\n').append("\""); + } + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise integer arrays that will be constructed later from such + * strings; eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is not a multiple of 4. + */ + public static String toUnicodeString(int[] ia) { + StringBuffer sb = new StringBuffer(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < ia.length) { + k = ia[i++]; + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 28) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 24) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 20) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 16) & 0x0F]); + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 12) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 8) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + + if ((++j % 4) == 0) { + sb.append("\"+").append('\n').append("\""); + } + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + public static byte[] toBytesFromUnicode(String s) { + int limit = s.length() * 2; + byte[] result = new byte[limit]; + char c; + for (int i = 0; i < limit; i++) { + c = s.charAt(i >>> 1); + result[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c); + } + return result; + } + + /** + *

Dumps a byte array as a string, in a format that is easy to read for + * debugging. The string m is prepended to the start of each + * line.

+ * + *

If offset and length are omitted, the whole + * array is used. If m is omitted, nothing is prepended to each + * line.

+ * + * @param data the byte array to be dumped. + * @param offset the offset within data to start from. + * @param length the number of bytes to dump. + * @param m a string to be prepended to each line. + * @return a string containing the result. + */ + public static String dumpString(byte[] data, int offset, int length, String m) { + if (data == null) { + return m + "null\n"; + } + StringBuffer sb = new StringBuffer(length * 3); + if (length > 32) { + sb.append(m).append("Hexadecimal dump of ").append(length).append(" bytes...\n"); + } + // each line will list 32 bytes in 4 groups of 8 each + int end = offset + length; + String s; + int l = Integer.toString(length).length(); + if (l < 4) { + l = 4; + } + for ( ; offset < end; offset += 32) { + if (length > 32) { + s = " " + offset; + sb.append(m).append(s.substring(s.length()-l)).append(": "); + } + int i = 0; + for ( ; i < 32 && offset + i + 7 < end; i += 8) { + sb.append(toString(data, offset + i, 8)).append(' '); + } + if (i < 32) { + for ( ; i < 32 && offset + i < end; i++) { + sb.append(byteToString(data[offset + i])); + } + } + sb.append('\n'); + } + return sb.toString(); + } + + public static String dumpString(byte[] data) { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, ""); + } + + public static String dumpString(byte[] data, String m) { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, m); + } + + public static String dumpString(byte[] data, int offset, int length) { + return dumpString(data, offset, length, ""); + } + + /** + *

Returns a string of 2 hexadecimal digits (most significant digit first) + * corresponding to the lowest 8 bits of n.

+ * + * @param n the byte value to convert. + * @return a string of 2 hex characters representing the input. + */ + public static String byteToString(int n) { + char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[n & 0x0F] }; + return new String(buf); + } + + /** + *

Converts a designated byte array to a Base-64 representation, with the + * exceptions that (a) leading 0-byte(s) are ignored, and (b) the character + * '.' (dot) shall be used instead of "+' (plus).

+ * + *

Used by SASL password file manipulation primitives.

+ * + * @param buffer an arbitrary sequence of bytes to represent in Base-64. + * @return unpadded (without the '=' character(s)) Base-64 representation of + * the input. + */ + public static final String toBase64(byte[] buffer) { + int len = buffer.length, pos = len % 3; + byte b0 = 0, b1 = 0, b2 = 0; + switch (pos) { + case 1: + b2 = buffer[0]; + break; + case 2: + b1 = buffer[0]; + b2 = buffer[1]; + break; + } + StringBuffer sb = new StringBuffer(); + int c; + boolean notleading = false; + do { + c = (b0 & 0xFC) >>> 2; + if (notleading || c != 0) { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >>> 4); + if (notleading || c != 0) { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >>> 6); + if (notleading || c != 0) { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = b2 & 0x3F; + if (notleading || c != 0) { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + if (pos >= len) { + break; + } else { + try { + b0 = buffer[pos++]; + b1 = buffer[pos++]; + b2 = buffer[pos++]; + } catch (ArrayIndexOutOfBoundsException x) { + break; + } + } + } while (true); + + if (notleading) { + return sb.toString(); + } + return "0"; + } + + /** + *

The inverse function of the above.

+ * + *

Converts a string representing the encoding of some bytes in Base-64 + * to their original form.

+ * + * @param str the Base-64 encoded representation of some byte(s). + * @return the bytes represented by the str. + * @throws NumberFormatException if str is null, or + * str contains an illegal Base-64 character. + * @see #toBase64(byte[]) + */ + public static final byte[] fromBase64(String str) { + int len = str.length(); + if (len == 0) { + throw new NumberFormatException("Empty string"); + } + byte[] a = new byte[len + 1]; + int i, j; + for (i = 0; i < len; i++) { + try { + a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i)); + } catch (ArrayIndexOutOfBoundsException x) { + throw new NumberFormatException("Illegal character at #"+i); + } + } + i = len - 1; + j = len; + try { + while (true) { + a[j] = a[i]; + if (--i < 0) { + break; + } + a[j] |= (a[i] & 0x03) << 6; + j--; + a[j] = (byte)((a[i] & 0x3C) >>> 2); + if (--i < 0) { + break; + } + a[j] |= (a[i] & 0x0F) << 4; + j--; + a[j] = (byte)((a[i] & 0x30) >>> 4); + if (--i < 0) { + break; + } + a[j] |= (a[i] << 2); + j--; + a[j] = 0; + if (--i < 0) { + break; + } + } + } catch (Exception ignored) { + } + + try { // ignore leading 0-bytes + while(a[j] == 0) { + j++; + } + } catch (Exception x) { + return new byte[1]; // one 0-byte + } + byte[] result = new byte[len - j + 1]; + System.arraycopy(a, j, result, 0, len - j + 1); + return result; + } + + // BigInteger utilities ---------------------------------------------------- + + /** + *

Treats the input as the MSB representation of a number, and discards + * leading zero elements. For efficiency, the input is simply returned if no + * leading zeroes are found.

+ * + * @param n the {@link BigInteger} to trim. + * @return the byte array representation of the designated {@link BigInteger} + * with no leading 0-bytes. + */ + public static final byte[] trim(BigInteger n) { + byte[] in = n.toByteArray(); + if (in.length == 0 || in[0] != 0) { + return in; + } + int len = in.length; + int i = 1; + while (in[i] == 0 && i < len) { + ++i; + } + byte[] result = new byte[len - i]; + System.arraycopy(in, i, result, 0, len - i); + return result; + } + + /** + *

Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}. + *

+ * + * @param x the {@link BigInteger} to display. + * @return the string representation of the designated {@link BigInteger}. + */ + public static final String dump(BigInteger x) { + return dumpString(trim(x)); + } +} diff --git a/examples/android/Demo1/src/org/t0t0/androguard/android/WeakKeyException.java b/examples/android/Demo1/src/org/t0t0/androguard/android/WeakKeyException.java new file mode 100644 index 00000000..fc384f47 --- /dev/null +++ b/examples/android/Demo1/src/org/t0t0/androguard/android/WeakKeyException.java @@ -0,0 +1,74 @@ +package org.t0t0.androguard.android; +// ---------------------------------------------------------------------------- +// $Id: WeakKeyException.java,v 1.1 2003/09/26 23:38:33 raif Exp $ +// +// Copyright (C) 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +import java.security.InvalidKeyException; + +/** + *

Checked exception thrown to indicate that a weak key has been generated + * and or specified instead of a valid non-weak value.

+ * + * @version $Revision: 1.1 $ + */ +public class WeakKeyException extends InvalidKeyException { + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WeakKeyException() { + super(); + } + + public WeakKeyException(String msg) { + super(msg); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/examples/android/Demo1StealSource/AndroidManifest.xml b/examples/android/Demo1StealSource/AndroidManifest.xml new file mode 100644 index 00000000..847b95e1 --- /dev/null +++ b/examples/android/Demo1StealSource/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/examples/android/Demo1StealSource/bin/classes.dex b/examples/android/Demo1StealSource/bin/classes.dex new file mode 100644 index 00000000..a0c08bee Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes.dex differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.class new file mode 100644 index 00000000..d8cc4b5b Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.class differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$attr.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$attr.class new file mode 100644 index 00000000..bca0bdd0 Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$attr.class differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$drawable.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$drawable.class new file mode 100644 index 00000000..a99b0701 Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$drawable.class differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$layout.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$layout.class new file mode 100644 index 00000000..008a7fbe Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$layout.class differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$string.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$string.class new file mode 100644 index 00000000..07a89086 Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R$string.class differ diff --git a/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R.class b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R.class new file mode 100644 index 00000000..ffef9d3d Binary files /dev/null and b/examples/android/Demo1StealSource/bin/classes/org/t0t0/androguard/watermarks/R.class differ diff --git a/examples/android/Demo1StealSource/build.properties b/examples/android/Demo1StealSource/build.properties new file mode 100644 index 00000000..edc7f230 --- /dev/null +++ b/examples/android/Demo1StealSource/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/examples/android/Demo1StealSource/build.xml b/examples/android/Demo1StealSource/build.xml new file mode 100644 index 00000000..da16db3a --- /dev/null +++ b/examples/android/Demo1StealSource/build.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/Demo1StealSource/default.properties b/examples/android/Demo1StealSource/default.properties new file mode 100644 index 00000000..9d135cb8 --- /dev/null +++ b/examples/android/Demo1StealSource/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/examples/android/Demo1StealSource/local.properties b/examples/android/Demo1StealSource/local.properties new file mode 100644 index 00000000..bb759453 --- /dev/null +++ b/examples/android/Demo1StealSource/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/pouik/Bureau/android/android-sdk-linux_86 diff --git a/examples/android/Demo1StealSource/res/drawable-hdpi/icon.png b/examples/android/Demo1StealSource/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/examples/android/Demo1StealSource/res/drawable-hdpi/icon.png differ diff --git a/examples/android/Demo1StealSource/res/drawable-ldpi/icon.png b/examples/android/Demo1StealSource/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..1095584e Binary files /dev/null and b/examples/android/Demo1StealSource/res/drawable-ldpi/icon.png differ diff --git a/examples/android/Demo1StealSource/res/drawable-mdpi/icon.png b/examples/android/Demo1StealSource/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..a07c69fa Binary files /dev/null and b/examples/android/Demo1StealSource/res/drawable-mdpi/icon.png differ diff --git a/examples/android/Demo1StealSource/res/layout/main.xml b/examples/android/Demo1StealSource/res/layout/main.xml new file mode 100644 index 00000000..6179c7f5 --- /dev/null +++ b/examples/android/Demo1StealSource/res/layout/main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/examples/android/Demo1StealSource/res/values/strings.xml b/examples/android/Demo1StealSource/res/values/strings.xml new file mode 100644 index 00000000..5a5418d3 --- /dev/null +++ b/examples/android/Demo1StealSource/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Demo1StealSourceActivity + diff --git a/examples/android/Demo1StealSource/src/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.java b/examples/android/Demo1StealSource/src/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.java new file mode 100644 index 00000000..005159e5 --- /dev/null +++ b/examples/android/Demo1StealSource/src/org/t0t0/androguard/watermarks/Demo1StealSourceActivity.java @@ -0,0 +1,43 @@ +package org.t0t0.androguard.watermarks; + +import android.app.Activity; +import android.os.Bundle; + +public class Demo1StealSourceActivity extends Activity +{ + private byte state[] = new byte[256]; + private int x, y; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + public byte[] rc4(byte[] buf) { + int xorIndex; + byte tmp; + + if (buf == null) { + return null; + } + + byte[] result = new byte[buf.length]; + + for (int i=0; i < buf.length; i++) { + + x = (x + 1) & 0xff; + y = ((state[x] & 0xff) + y) & 0xff; + + tmp = state[x]; + state[x] = state[y]; + state[y] = tmp; + + xorIndex = ((state[x] &0xff) + (state[y] & 0xff)) & 0xff; + result[i] = (byte)(buf[i] ^ state[xorIndex]); + } + return result; + } +} diff --git a/examples/android/Invalid/Invalid.apk b/examples/android/Invalid/Invalid.apk new file mode 100644 index 00000000..c2911308 Binary files /dev/null and b/examples/android/Invalid/Invalid.apk differ diff --git a/examples/android/TC/AndroidManifest.xml b/examples/android/TC/AndroidManifest.xml new file mode 100644 index 00000000..e5f6f1d3 --- /dev/null +++ b/examples/android/TC/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/examples/android/TC/androguard.xml b/examples/android/TC/androguard.xml new file mode 100644 index 00000000..4f7759b4 --- /dev/null +++ b/examples/android/TC/androguard.xml @@ -0,0 +1,30 @@ + + + + ./examples/android/TC/ + ./libs/ + + + BM_A0 + BM_A1 + wm.xml + + + + + + + + + org/t0t0/androguard/TC/TCActivity + + + + org/t0t0/androguard/TC/TCMod1 + TC1 + I + + + + + diff --git a/examples/android/TC/bin/TC-debug.apk b/examples/android/TC/bin/TC-debug.apk new file mode 100644 index 00000000..cc0fb744 Binary files /dev/null and b/examples/android/TC/bin/TC-debug.apk differ diff --git a/examples/android/TC/bin/classes.dex b/examples/android/TC/bin/classes.dex new file mode 100644 index 00000000..178eb262 Binary files /dev/null and b/examples/android/TC/bin/classes.dex differ diff --git a/examples/android/TC/build.properties b/examples/android/TC/build.properties new file mode 100644 index 00000000..ee52d86d --- /dev/null +++ b/examples/android/TC/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/examples/android/TC/build.xml b/examples/android/TC/build.xml new file mode 100644 index 00000000..034a3af4 --- /dev/null +++ b/examples/android/TC/build.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/TC/default.properties b/examples/android/TC/default.properties new file mode 100644 index 00000000..e2e8061f --- /dev/null +++ b/examples/android/TC/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-8 diff --git a/examples/android/TC/local.properties b/examples/android/TC/local.properties new file mode 100644 index 00000000..dfd1408b --- /dev/null +++ b/examples/android/TC/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/desnos/android/android-sdk-linux_x86 diff --git a/examples/android/TC/proguard.cfg b/examples/android/TC/proguard.cfg new file mode 100644 index 00000000..8ad7d335 --- /dev/null +++ b/examples/android/TC/proguard.cfg @@ -0,0 +1,34 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/examples/android/TC/res/drawable-hdpi/icon.png b/examples/android/TC/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/examples/android/TC/res/drawable-hdpi/icon.png differ diff --git a/examples/android/TC/res/drawable-ldpi/icon.png b/examples/android/TC/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..1095584e Binary files /dev/null and b/examples/android/TC/res/drawable-ldpi/icon.png differ diff --git a/examples/android/TC/res/drawable-mdpi/icon.png b/examples/android/TC/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..a07c69fa Binary files /dev/null and b/examples/android/TC/res/drawable-mdpi/icon.png differ diff --git a/examples/android/TC/res/layout/main.xml b/examples/android/TC/res/layout/main.xml new file mode 100644 index 00000000..b6cf25ff --- /dev/null +++ b/examples/android/TC/res/layout/main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/examples/android/TC/res/values/strings.xml b/examples/android/TC/res/values/strings.xml new file mode 100644 index 00000000..3aa22bd8 --- /dev/null +++ b/examples/android/TC/res/values/strings.xml @@ -0,0 +1,4 @@ + + + TCActivity + diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCA.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCA.java new file mode 100644 index 00000000..adef33f2 --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCA.java @@ -0,0 +1,33 @@ +package org.t0t0.androguard.TC; + +public class TCA { + public int TC1 = 30; + private int TC2 = -6; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCA() + { + System.out.println("TCA TC1 == 30 : " + this.equal( this.TC1, "30" )); + System.out.println("TCA TC2 == -6 : " + this.equal( this.TC2, "-6" )); + TC1 = 20; + System.out.println("TCA TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + TCC c = new TCC(); + + c.T1(); + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCActivity.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCActivity.java new file mode 100644 index 00000000..dc548ec9 --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCActivity.java @@ -0,0 +1,15 @@ +package org.t0t0.androguard.TC; + +import android.app.Activity; +import android.os.Bundle; + +public class TCActivity extends Activity +{ + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCB.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCB.java new file mode 100644 index 00000000..d4eafe16 --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCB.java @@ -0,0 +1,32 @@ +package org.t0t0.androguard.TC; + +public class TCB { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCB(TCA a) + { + System.out.println("TCB TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCB TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + TC1 = 20; + System.out.println("TCB TC1 == 20 : " + this.equal( this.TC1, "20" )); + + a.T1(); + } + + public void T1() + { + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCC.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCC.java new file mode 100644 index 00000000..4b46eadd --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCC.java @@ -0,0 +1,30 @@ +package org.t0t0.androguard.TC; + +public class TCC { + public int TC1 = 30; + private int TC2 = -6; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCC() + { + System.out.println("TCC TC1 == 30 : " + this.equal( this.TC1, "30" )); + System.out.println("TCC TC2 == -6 : " + this.equal( this.TC2, "-6" )); + TC1 = 20; + System.out.println("TCC TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCD.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCD.java new file mode 100644 index 00000000..8ca665ed --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCD.java @@ -0,0 +1,33 @@ +package org.t0t0.androguard.TC; + +public class TCD { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCD() + { + System.out.println("TCD TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCD TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + TC1 = 20; + System.out.println("TCD TC1 == 20 : " + this.equal( this.TC1, "20" )); + + TCE e = new TCE(); + e.T1(); + } + + public void T1() + { + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCE.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCE.java new file mode 100644 index 00000000..f2ea5b57 --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCE.java @@ -0,0 +1,75 @@ +package org.t0t0.androguard.TC; + +public class TCE { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCE() + { + System.out.println("TCE TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCE TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + + this.TC1 = 20; + System.out.println("TCE TC1 == 20 : " + this.equal( this.TC1, "20" )); + + this.TC2 = -30; + System.out.println("TCE TC2 == -30 : " + this.equal( this.TC2, "-30" )); + + int y = 0; + for(int i = 0; i < (this.TC1 - this.TC2); i++) { + for(int j=0; j < i; j++) { + y = y + this.TCE_t1( 400 ); + } + + switch( this.TC1 ) { + case 0 : y += 1; + default : y = y + this.TCE_t2(); + } + + switch( this.TC2 ) { + case 0 : y += 30; + case 45 : y += 2; + case -6 : y = y + this.TCE_t3(); + } + } + + this.TC1 = y; + + System.out.println("TCE TC1 == 3433300 : " + this.equal( this.TC1, "3433300" )); + + TCC c = new TCC(); + c.T1(); + } + + public int TCE_t1(int a) + { + return a * 7; + } + + public int TCE_t2() + { + return 0x42; + } + + public int TCE_t3() + { + return 0x45; + } + + + public void T1() + { + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TCMod1.java b/examples/android/TC/src/org/t0t0/androguard/TC/TCMod1.java new file mode 100644 index 00000000..12a3abac --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TCMod1.java @@ -0,0 +1,78 @@ +package org.t0t0.androguard.TC; + +public class TCMod1 { + public int TC1 = 0; + private int TC2 = 3; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCMod1() + { + System.out.println("TC1 == 0 : " + this.equal( this.TC1, "0" )); + System.out.println("TC2 == 3 : " + this.equal( this.TC2, "3" )); + TC1 = 20; + System.out.println("TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + int i; + for(i = 0; i < 30; i++) + { + this.TC1 += i; + } + System.out.println("TC1 == 455 : " + this.equal( this.TC1, "455" )); + + int j = 40; + System.out.println("J == 40 : " + this.equal( j, "40" )); + + for(; j < 40000; j++); + System.out.println("J == 40000 : " + this.equal( j, "40000" )); + + this.TC1 += j; + System.out.println("TC1 == 40455 : " + this.equal( this.TC1, "40455" )); + + int k[][] = { { 40, 30 }, { 60000, -788 }, { -2344556, 10000 } }; + + for(i = 0; i < k.length; i++) { + for(j=0; j < k[i].length; j++) { + this.TC1 += k[i][j]; + } + } + + TCA a = new TCA() ; + a.T1(); + + System.out.println("TC1 == -2234819 : " + this.equal( this.TC1, "-2234819" )); + + i = 300; j =-188; + System.out.println("I == 300 : " + this.equal( i, "300" )); + System.out.println("J == -188 : " + this.equal( j, "-188" )); + + TCD d = new TCD(); + d.T1(); + + do { + this.TC2 += ( j - i ); + j += 3; + i -= 2; + } while ( j < i ); + System.out.println("TC2 == -24056 : " + this.equal( this.TC2, "-24056" )); + TCA a1 = new TCA() ; + a1.T1(); + + TCB b = new TCB( a ); + b.T1(); + + } +} diff --git a/examples/android/TC/src/org/t0t0/androguard/TC/TestType1.java b/examples/android/TC/src/org/t0t0/androguard/TC/TestType1.java new file mode 100644 index 00000000..4894606f --- /dev/null +++ b/examples/android/TC/src/org/t0t0/androguard/TC/TestType1.java @@ -0,0 +1,23 @@ +package org.t0t0.androguard.TC; + +public class TestType1 +{ + public TestType1() + { + long long_tc1 = 42; + long long_tc2 = -42; + long long_tc3 = 0; + + int int_tc1 = 42; + int int_tc2 = -42; + int int_tc3 = 0; + + double double_tc1 = 42.0; + double double_tc2 = -42.0; + double double_tc3 = 0.0; + + float float_tc1 = 42.0f; + float float_tc2 = -42.0f; + float float_tc3 = 0.0f; + } +} diff --git a/examples/android/TCDiff/AndroidManifest.xml b/examples/android/TCDiff/AndroidManifest.xml new file mode 100644 index 00000000..7e046220 --- /dev/null +++ b/examples/android/TCDiff/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/examples/android/TCDiff/androguard.xml b/examples/android/TCDiff/androguard.xml new file mode 100644 index 00000000..80b0f173 --- /dev/null +++ b/examples/android/TCDiff/androguard.xml @@ -0,0 +1,30 @@ + + + + ./examples/android/TCDiff/ + ./libs/ + + + BM_A0 + BM_A1 + wm.xml + + + + + + + + + org/t0t0/androguard/TCDiff/TCActivity + + + + org/t0t0/androguard/TCDiff/TCMod1 + TC1 + I + + + + + diff --git a/examples/android/TCDiff/bin/TCDiff-debug.apk b/examples/android/TCDiff/bin/TCDiff-debug.apk new file mode 100644 index 00000000..0a8f99e1 Binary files /dev/null and b/examples/android/TCDiff/bin/TCDiff-debug.apk differ diff --git a/examples/android/TCDiff/bin/classes.dex b/examples/android/TCDiff/bin/classes.dex new file mode 100644 index 00000000..020fc9fe Binary files /dev/null and b/examples/android/TCDiff/bin/classes.dex differ diff --git a/examples/android/TCDiff/build.properties b/examples/android/TCDiff/build.properties new file mode 100644 index 00000000..ee52d86d --- /dev/null +++ b/examples/android/TCDiff/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/examples/android/TCDiff/build.xml b/examples/android/TCDiff/build.xml new file mode 100644 index 00000000..d532d055 --- /dev/null +++ b/examples/android/TCDiff/build.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/TCDiff/default.properties b/examples/android/TCDiff/default.properties new file mode 100644 index 00000000..e2e8061f --- /dev/null +++ b/examples/android/TCDiff/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-8 diff --git a/examples/android/TCDiff/local.properties b/examples/android/TCDiff/local.properties new file mode 100644 index 00000000..dfd1408b --- /dev/null +++ b/examples/android/TCDiff/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/desnos/android/android-sdk-linux_x86 diff --git a/examples/android/TCDiff/proguard.cfg b/examples/android/TCDiff/proguard.cfg new file mode 100644 index 00000000..8ad7d335 --- /dev/null +++ b/examples/android/TCDiff/proguard.cfg @@ -0,0 +1,34 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/examples/android/TCDiff/res/drawable-hdpi/icon.png b/examples/android/TCDiff/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/examples/android/TCDiff/res/drawable-hdpi/icon.png differ diff --git a/examples/android/TCDiff/res/drawable-ldpi/icon.png b/examples/android/TCDiff/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..1095584e Binary files /dev/null and b/examples/android/TCDiff/res/drawable-ldpi/icon.png differ diff --git a/examples/android/TCDiff/res/drawable-mdpi/icon.png b/examples/android/TCDiff/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..a07c69fa Binary files /dev/null and b/examples/android/TCDiff/res/drawable-mdpi/icon.png differ diff --git a/examples/android/TCDiff/res/layout/main.xml b/examples/android/TCDiff/res/layout/main.xml new file mode 100644 index 00000000..b6cf25ff --- /dev/null +++ b/examples/android/TCDiff/res/layout/main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/examples/android/TCDiff/res/values/strings.xml b/examples/android/TCDiff/res/values/strings.xml new file mode 100644 index 00000000..3aa22bd8 --- /dev/null +++ b/examples/android/TCDiff/res/values/strings.xml @@ -0,0 +1,4 @@ + + + TCActivity + diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCA.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCA.java new file mode 100644 index 00000000..d0659e60 --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCA.java @@ -0,0 +1,39 @@ +package org.t0t0.androguard.TCDiff; + +public class TCA { + public int TC1 = 30; + private int TC2 = -6; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCA() + { + System.out.println("TCA TC1 == 30 : " + this.equal( this.TC1, "30" )); + System.out.println("TCA TC2 == -6 : " + this.equal( this.TC2, "-6" )); + TC1 = 20; + System.out.println("TCA TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + TCC c = new TCC(); + + // PATCH + if ((TC2 % 2) == 1) { + TC1 = 3; + } + // END PATCH + + c.T1(); + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCActivity.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCActivity.java new file mode 100644 index 00000000..b943db92 --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCActivity.java @@ -0,0 +1,15 @@ +package org.t0t0.androguard.TCDiff; + +import android.app.Activity; +import android.os.Bundle; + +public class TCActivity extends Activity +{ + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCB.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCB.java new file mode 100644 index 00000000..49acfbf5 --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCB.java @@ -0,0 +1,32 @@ +package org.t0t0.androguard.TCDiff; + +public class TCB { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCB(TCA a) + { + System.out.println("TCB TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCB TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + TC1 = 20; + System.out.println("TCB TC1 == 20 : " + this.equal( this.TC1, "20" )); + + a.T1(); + } + + public void T1() + { + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCC.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCC.java new file mode 100644 index 00000000..21961fcb --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCC.java @@ -0,0 +1,30 @@ +package org.t0t0.androguard.TCDiff; + +public class TCC { + public int TC1 = 30; + private int TC2 = -6; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCC() + { + System.out.println("TCC TC1 == 30 : " + this.equal( this.TC1, "30" )); + System.out.println("TCC TC2 == -6 : " + this.equal( this.TC2, "-6" )); + TC1 = 20; + System.out.println("TCC TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCD.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCD.java new file mode 100644 index 00000000..ba21f76f --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCD.java @@ -0,0 +1,33 @@ +package org.t0t0.androguard.TCDiff; + +public class TCD { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCD() + { + System.out.println("TCD TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCD TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + TC1 = 20; + System.out.println("TCD TC1 == 20 : " + this.equal( this.TC1, "20" )); + + TCE e = new TCE(); + e.T1(); + } + + public void T1() + { + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCE.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCE.java new file mode 100644 index 00000000..612fef1c --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCE.java @@ -0,0 +1,80 @@ +package org.t0t0.androguard.TCDiff; + +public class TCE { + public int TC1 = 1337; + private int TC2 = -90000; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCE() + { + System.out.println("TCE TC1 == 1337 : " + this.equal( this.TC1, "1337" )); + System.out.println("TCE TC2 == -90000 : " + this.equal( this.TC2, "-90000" )); + + this.TC1 = 20; + System.out.println("TCE TC1 == 20 : " + this.equal( this.TC1, "20" )); + + this.TC2 = -30; + System.out.println("TCE TC2 == -30 : " + this.equal( this.TC2, "-30" )); + + int y = 0; + for(int i = 0; i < (this.TC1 - this.TC2); i++) { + for(int j=0; j < i; j++) { + y = y + this.TCE_t1( 400 ); + } + + switch( this.TC1 ) { + case 0 : y += 1; + default : y = y + this.TCE_t2(); + } + + switch( this.TC2 ) { + case 0 : y += 30; + case 45 : y += 2; + case -6 : y = y + this.TCE_t3(); + } + } + + this.TC1 = y; + + System.out.println("TCE TC1 == 3433300 : " + this.equal( this.TC1, "3433300" )); + + TCC c = new TCC(); + c.T1(); + } + + public int TCE_t1(int a) + { + return a * 7; + } + + public int TCE_t2() + { + return 0x42; + } + + public int TCE_t3() + { + return 0x45; + } + + // NEW METHOD + public int TCE_t4() + { + return 0x90; + } + + public void T1() + { + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCMod1.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCMod1.java new file mode 100644 index 00000000..044d6838 --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TCMod1.java @@ -0,0 +1,86 @@ +package org.t0t0.androguard.TCDiff; + +public class TCMod1 { + public int TC1 = 0; + private int TC2 = 3; + + public String equal(int a, String b) + { + String c = Integer.toString( a ); + + System.out.print(c + " " + b + " ---- "); + if (c.equals(b)) { + return " OK "; + } + + return " X "; + } + + public TCMod1() + { + System.out.println("TC1 == 0 : " + this.equal( this.TC1, "0" )); + System.out.println("TC2 == 3 : " + this.equal( this.TC2, "3" )); + TC1 = 20; + System.out.println("TC1 == 20 : " + this.equal( this.TC1, "20" )); + } + + public void T1() + { + int i; + for(i = 0; i < 30; i++) + { + this.TC1 += i; + } + System.out.println("TC1 == 455 : " + this.equal( this.TC1, "455" )); + + int j = 40; + System.out.println("J == 40 : " + this.equal( j, "40" )); + + for(; j < 40000; j++); + System.out.println("J == 40000 : " + this.equal( j, "40000" )); + + this.TC1 += j; + System.out.println("TC1 == 40455 : " + this.equal( this.TC1, "40455" )); + + int k[][] = { { 40, 30 }, { 60000, -788 }, { -2344556, 10000 } }; + + for(i = 0; i < k.length; i++) { + for(j=0; j < k[i].length; j++) { + // PATCH + this.TC1 += k[i][j] + 1; + // END PATCH + } + } + + TCA a = new TCA() ; + a.T1(); + + System.out.println("TC1 == -2234819 : " + this.equal( this.TC1, "-2234819" )); + + i = 300; j =-188; + System.out.println("I == 300 : " + this.equal( i, "300" )); + System.out.println("J == -188 : " + this.equal( j, "-188" )); + + TCD d = new TCD(); + d.T1(); + + do { + this.TC2 += ( j - i ); + j += 3; + // PATCH + if (j == 4) { + break; + } + // END PATCH + + i -= 2; + } while ( j < i ); + System.out.println("TC2 == -24056 : " + this.equal( this.TC2, "-24056" )); + TCA a1 = new TCA() ; + a1.T1(); + + TCB b = new TCB( a ); + b.T1(); + + } +} diff --git a/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TestType1.java b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TestType1.java new file mode 100644 index 00000000..0a1089e1 --- /dev/null +++ b/examples/android/TCDiff/src/org/t0t0/androguard/TCDiff/TestType1.java @@ -0,0 +1,23 @@ +package org.t0t0.androguard.TCDiff; + +public class TestType1 +{ + public TestType1() + { + long long_tc1 = 42; + long long_tc2 = -42; + long long_tc3 = 0; + + int int_tc1 = 42; + int int_tc2 = -42; + int int_tc3 = 0; + + double double_tc1 = 42.0; + double double_tc2 = -42.0; + double double_tc3 = 0.0; + + float float_tc1 = 42.0f; + float float_tc2 = -42.0f; + float float_tc3 = 0.0f; + } +} diff --git a/examples/android/TestsAndroguard/.classpath b/examples/android/TestsAndroguard/.classpath new file mode 100644 index 00000000..b1bf8312 --- /dev/null +++ b/examples/android/TestsAndroguard/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/examples/android/TestsAndroguard/.project b/examples/android/TestsAndroguard/.project new file mode 100644 index 00000000..206d059b --- /dev/null +++ b/examples/android/TestsAndroguard/.project @@ -0,0 +1,33 @@ + + + TestsAndroguard + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/examples/android/TestsAndroguard/AndroidManifest.xml b/examples/android/TestsAndroguard/AndroidManifest.xml new file mode 100644 index 00000000..36204969 --- /dev/null +++ b/examples/android/TestsAndroguard/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/android/TestsAndroguard/bin/TestActivity.apk b/examples/android/TestsAndroguard/bin/TestActivity.apk new file mode 100644 index 00000000..b43a1d3d Binary files /dev/null and b/examples/android/TestsAndroguard/bin/TestActivity.apk differ diff --git a/examples/android/TestsAndroguard/bin/classes.dex b/examples/android/TestsAndroguard/bin/classes.dex new file mode 100644 index 00000000..9974c580 Binary files /dev/null and b/examples/android/TestsAndroguard/bin/classes.dex differ diff --git a/examples/android/TestsAndroguard/gen/tests/androguard/R.java b/examples/android/TestsAndroguard/gen/tests/androguard/R.java new file mode 100644 index 00000000..8811d479 --- /dev/null +++ b/examples/android/TestsAndroguard/gen/tests/androguard/R.java @@ -0,0 +1,23 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package tests.androguard; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class layout { + public static final int main=0x7f030000; + } + public static final class string { + public static final int app_name=0x7f040001; + public static final int hello=0x7f040000; + } +} diff --git a/examples/android/TestsAndroguard/libs/android-support-v4.jar b/examples/android/TestsAndroguard/libs/android-support-v4.jar new file mode 100644 index 00000000..6080877d Binary files /dev/null and b/examples/android/TestsAndroguard/libs/android-support-v4.jar differ diff --git a/examples/android/TestsAndroguard/project.properties b/examples/android/TestsAndroguard/project.properties new file mode 100644 index 00000000..b7c2081d --- /dev/null +++ b/examples/android/TestsAndroguard/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-10 diff --git a/examples/android/TestsAndroguard/res/drawable-hdpi/icon.png b/examples/android/TestsAndroguard/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/examples/android/TestsAndroguard/res/drawable-hdpi/icon.png differ diff --git a/examples/android/TestsAndroguard/res/drawable-ldpi/icon.png b/examples/android/TestsAndroguard/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..1095584e Binary files /dev/null and b/examples/android/TestsAndroguard/res/drawable-ldpi/icon.png differ diff --git a/examples/android/TestsAndroguard/res/drawable-mdpi/icon.png b/examples/android/TestsAndroguard/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..a07c69fa Binary files /dev/null and b/examples/android/TestsAndroguard/res/drawable-mdpi/icon.png differ diff --git a/examples/android/TestsAndroguard/res/layout/main.xml b/examples/android/TestsAndroguard/res/layout/main.xml new file mode 100644 index 00000000..3a5f117d --- /dev/null +++ b/examples/android/TestsAndroguard/res/layout/main.xml @@ -0,0 +1,12 @@ + + + + diff --git a/examples/android/TestsAndroguard/res/values/strings.xml b/examples/android/TestsAndroguard/res/values/strings.xml new file mode 100644 index 00000000..598dbd52 --- /dev/null +++ b/examples/android/TestsAndroguard/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World, TestActivity! kikoololmodif + TestsAndroguardApplication + diff --git a/examples/android/TestsAndroguard/src/TestDefaultPackage.java b/examples/android/TestsAndroguard/src/TestDefaultPackage.java new file mode 100644 index 00000000..85835d03 --- /dev/null +++ b/examples/android/TestsAndroguard/src/TestDefaultPackage.java @@ -0,0 +1,82 @@ +import java.util.ArrayList; +import java.util.List; + + +public class TestDefaultPackage { + + static long [] test_; + private class TestInnerClass { + private int a, b; + + private TestInnerClass(int a, int b) + { + this.a = a; + this.b = b; + } + + public void Test(int d) + { + System.out.println("Test2: " + this.a + d + this.b); + } + + private class TestInnerInnerClass { + private int a, c; + + private TestInnerInnerClass(int a, int c) + { + this.a = a; + this.c = c; + } + + public void Test(int b) + { + System.out.println("Test: " + this.a * b + this.c); + } + } + } + + public void const4() + { + byte _ = -8; + byte a = -7; + byte b = -6; + byte c = -5; + byte d = -4; + byte e = -3; + byte f = -2; + byte g = -1; + byte h = 0; + byte i = 1; + byte j = 2; + byte k = 3; + byte l = 4; + byte m = 5; + byte n = 6; + byte o = 7; + System.out.println("" + _ + a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + } + + public static void main(String [] z) + { + int a = 5; + switch(a) + { + case 1: + case 2: + System.out.println("1 || 2"); + break; + case 3: + System.out.print("3 || "); + case 4: + default: + System.out.println("4"); + break; + case 5: + System.out.println("5"); + } + TestDefaultPackage p = new TestDefaultPackage(); + TestInnerClass t = p.new TestInnerClass(3, 4); + TestInnerClass.TestInnerInnerClass t2 = t.new TestInnerInnerClass(3, 4); + System.out.println("t.a = " + t.a); + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/Eratosthene.java b/examples/android/TestsAndroguard/src/tests/androguard/Eratosthene.java new file mode 100644 index 00000000..b297a7d4 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/Eratosthene.java @@ -0,0 +1,36 @@ +package tests.androguard; + +public class Eratosthene { + public static int[] eratosthenes(int n) { + boolean a[] = new boolean[n+1]; + a[0] = true; + a[1] = true; + + int sqn = (int)Math.sqrt(n); + for(int i = 2; i <= sqn; i++) { + if(!a[i]) { + int j = i*i; + while(j <= n) { + a[j] = true; + j += i; + } + } + } + + int cnt = 0; + for(boolean b: a) { + if(!b) { + cnt++; + } + } + + int j = 0; + int[] primes = new int[cnt]; + for(int i = 0; i < a.length; i++) { + if(!a[i]) { + primes[j++] = i; + } + } + return primes; + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/Lzss.java b/examples/android/TestsAndroguard/src/tests/androguard/Lzss.java new file mode 100644 index 00000000..06f515a8 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/Lzss.java @@ -0,0 +1,59 @@ +package tests.androguard; + +public class Lzss { + public static int lzss_decompress(byte[] in, byte[] out) { + int i = 0; + int j = 0; + int flags = 0; + int cnt = 7; + + while(j < out.length) { + + if(++cnt == 8) { + if(i >= in.length) { + break; + } + flags = in[i++] & 0xFF; + cnt = 0; + } + + if((flags & 1) == 0) { + if(i >= in.length) { + break; + } + out[j] = in[i]; + j++; + i++; + } + else { + if((i + 1) >= in.length) { + return -1; + } + int v = (in[i] & 0xFF) | (in[i+1] & 0xFF) << 8; + i += 2; + + int offset = (v >> 4) + 1; + int length = (v & 0xF) + 3; + + // not enough data decoded + if(offset > j) { + return -1; + } + + // output buffer is too small + if((out.length - j) < length) { + return -1; + } + + for(int k = 0; k < length; k++) { + out[j+k] = out[j+k-offset]; + } + j += length; + } + + flags >>= 1; + } + + return j; + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/RC4.java b/examples/android/TestsAndroguard/src/tests/androguard/RC4.java new file mode 100644 index 00000000..17ff0dd0 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/RC4.java @@ -0,0 +1,41 @@ +package tests.androguard; + +public class RC4 { + +public static void rc4_crypt(byte[] key, byte[] data) { + int keylen = key.length; + int datalen = data.length; + int i; + int j; + + // key scheduling + byte[] sbox = new byte[256]; + for(i = 0; i < 256; i++) { + sbox[i] = (byte)i; + } + j = 0; + for(i = 0; i < 256; i++) { + j = ((j + sbox[i] + key[i % keylen]) % 256) & 0xFF; + byte tmp = sbox[i]; + sbox[i] = sbox[j]; + sbox[j] = tmp; + } + + // generate output + i = 0; + j = 0; + int index = 0; + while(index < datalen) { + i = ((i + 1) % 256) & 0xFF; + j = ((j + sbox[i]) % 256) & 0xFF; + + byte tmp = sbox[i]; + sbox[i] = sbox[j]; + sbox[j] = tmp; + + byte k = (byte)(sbox[((sbox[i] + sbox[j]) % 256) & 0xFF]); + data[index] ^= k; + index++; + } +} +} \ No newline at end of file diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestActivity.java b/examples/android/TestsAndroguard/src/tests/androguard/TestActivity.java new file mode 100644 index 00000000..61755889 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestActivity.java @@ -0,0 +1,373 @@ +package tests.androguard; + +import java.io.PrintStream; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; +import android.widget.Toast; + +public class TestActivity extends Activity { + public int value; + public int value2; + private int test = 10; + private static final int test2 = 20; + public int test3 = 30; + public int tab[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + static { + int t = 5; + System.out.println("foobar"); + } + + public TestActivity() { + value = 100; + value2 = 200; + } + + public TestActivity(int value, int value2) { + this.value = value; + this.value2 = value2; + } + + public TestActivity(double value, double value2) { + this.test = 5; + this.value = (int) value; + this.value2 = (int) value2; + } + + public int test_base(int _value, int _value2) { + int y = 0; + double sd = -6; + double zz = -5; + double yy = -4; + double xx = -3; + double w = -2; + double x = -1; + double k = 0.0; + double d = 1; + double b = 2; + double c = 3; + double f = 4; + double z = 5; + double cd = 6; + float g = 4.20f; + + double useless = g * c + b - y + d; + + System.out.println("VALUE = " + this.value + " VALUE 2 = " + + this.value2); + + for (int i = 0; i < (_value + _value2); i++) { + y = this.value + y - this.value2; + y = y & 200 * test1(20); + + y = this.value2 - y; + } + + try { + int[] t = new int[5]; + t[6] = 1; + } catch (java.lang.ArrayIndexOutOfBoundsException e) { + System.out.println("boom"); + } + + if (this.value > 0) { + this.value2 = y; + } + + switch (this.value) { + case 0: + this.value2 = this.pouet(); + break; + default: + this.value2 = this.pouet2(); + } + + switch (this.value) { + case 1: + this.value2 = this.pouet(); + break; + case 2: + this.value2 = this.pouet2(); + break; + case 3: + this.value2 = this.pouet3(); + } + + return y; + } + + public int foo(int i, int j) { + while (true) { + try { + while (i < j) + i = j++ / i; + } catch (RuntimeException re) { + i = 10; + continue; + } + if (i == 0) + return j; + } + } + + public int foobis(int i, int j) { + while (i < j && i != 10) { + try { + i = j++ / i; + } catch (RuntimeException re) { + i = 10; + continue; + } + } + return j; + + } + + public int foo2(int i, int j) { + while (true) { + if (i < j) { + try { + i = j++ / i; + } catch (RuntimeException re) { + i = 10; + continue; + } + } + if (i == 0) + return j; + } + } + + public int foo4(int i, int j) { + while (i < j) { + try { + i = j++ / i; + } catch (RuntimeException re) { + i = 10; + } + } + return j; + } + + public int test1(int val) { + int a = 0x10; + + return val + a - 60 * this.value; + } + + public int pouet() { + int v = this.value; + return v; + } + + public void testVars(int z, char y) { + int a = this.value * 2; + int b = 3; + int c = 4; + int d = c + b * a - 1 / 3 * this.value; + int e = c + b - a; + int f = e + 2; + int g = 3 * d - c + f - 8; + int h = 10 + this.value + a + b + c + d + e + f + g; + int i = 150 - 40 + 12; + int j = h - i + g; + int k = 10; + int l = 5; + int m = 2; + int n = 10; + int o = k * l + m - n * this.value + c / e - f * g + h - j; + int p = a + b + c; + int q = p - k + o - l; + int r = a + b - c * d / e - f + g - h * i + j * k * l - m - n + o / p + * q; + System.out.println(" meh " + r); + System.out.println(y); + y += 'a'; + this.testVars(a, y); + this.test1(10); + pouet2(); + this.pouet2(); + int s = pouet2(); + } + + public static void testDouble() { + double f = -5; + double g = -4; + double h = -3; + double i = -2; + double j = -1; + double k = 0; + double l = 1; + double m = 2; + double n = 3; + double o = 4; + double p = 5; + + long ff = -5; + long gg = -4; + long hh = -3; + long ii = -2; + long jj = -1; + long kk = 0; + long ll = 1; + long mm = 2; + long nn = 3; + long oo = 4; + long pp = 5; + + float fff = -5; + float ggg = -4; + float hhh = -3; + float iii = -2; + float jjj = -1; + float kkk = 0; + float lll = 1; + float mmm = 2; + float nnn = 3; + float ooo = 4; + float ppp = 5; + + double abc = 65534; + double def = 65535; + double ghi = 65536; + double jkl = 65537; + + double mno = 32769; + double pqr = 32768; + double stu = 32767; + double vwx = 32766; + + long aabc = 65534; + long adef = 65535; + long aghi = 65536; + long ajkl = 65537; + + long amno = 32769; + long apqr = 32768; + long astu = 32767; + long avwx = 32766; + + float babc = 65534; + float bdef = 65535; + float bghi = 65536; + float bjkl = 65537; + + float bmno = 32769; + float bpqr = 32768; + float bstu = 32767; + float bvwx = 32766; + + double abcd = 5346952; + long dcba = 5346952; + float cabd = 5346952; + + double zabc = 65534.50; + double zdef = 65535.50; + double zghi = 65536.50; + double zjkl = 65537.50; + + double zmno = 32769.50; + double zpqr = 32768.50; + double zstu = 32767.50; + double zvwx = 32766.50; + + float xabc = 65534.50f; + float xdef = 65535.50f; + float xghi = 65536.50f; + float xjkl = 65537.50f; + + float xmno = 32769.50f; + float xpqr = 32768.50f; + float xstu = 32767.50f; + float xvwx = 32766.50f; + + float ymno = -5f; + float ypqr = -65535f; + float ystu = -65536f; + float yvwx = -123456789123456789.555555555f; + double yvwx2 = -123456789123456789.555555555; + int boom = -606384730; + float reboom = -123456790519087104f; + float gettype = boom + 2 + 3.5f; + System.out.println(gettype); + } + + public static void testCall1(float b) { + System.out.println("k" + b); + } + + public static void testCall2(long i) { + new PrintStream(System.out).println("k" + i); + } + + public static void testCalls(TestIfs d) { + testCall2(3); + TestIfs.testIF(5); + System.out.println(d.getClass()); + } + + public static void testLoop(double a) { + while (a < 10) { + System.out.println(a); + a *= 2; + } + } + + public void testVarArgs(int p, long[] p2, String... p3) { + + } + + public void testString( ) + { + String a = "foo"; + String b = new String("bar"); + System.out.println(a + b); + } + + public synchronized int pouet2() { + int i = 0, j = 10; + System.out.println("test"); + + while (i < j) { + try { + i = j++ / i; + } catch (RuntimeException re) { + i = 10; + } + } + this.value = i; + return 90; + } + + public int pouet3() { + return 80; + } + + public int go() { + System.out.println(" test_base(500, 3) " + this.test_base(500, 3)); + return test + test2 + 10; + } + + public void testAccessField() { + TestArr$ays a = new TestArr$ays(); + a.d = new byte[5]; + a.d[2] = 'c'; + System.out.println("test :" + a.d[2]); + } + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + Toast toast = Toast.makeText(getApplicationContext(), "this is a test ! " + 42, Toast.LENGTH_LONG); + toast.show(); + /* + TestLoops o = new TestLoops(); + o.testIrreducible(test3, test2); + */ + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestArr$ays.java b/examples/android/TestsAndroguard/src/tests/androguard/TestArr$ays.java new file mode 100644 index 00000000..9121c181 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestArr$ays.java @@ -0,0 +1,44 @@ +package tests.androguard; + +public class TestArr$ays { + + public static class InternField { + public static byte[] b; + } + + private byte[] b; + public byte[] d; + + public TestArr$ays( ) { + b = new byte[5]; + } + + public TestArr$ays( byte [] b ) { + this.b = b; + } + + public TestArr$ays( int i ) { + byte [] a = { 1, 2, 3, 4, 5 }; + b = a; + } + + public void testEmptyArrayByte( ) { + byte [] b = new byte[5]; + InternField.b = b; + } + + public void testFullArrayByte( ) { + byte[] b = { 1, 2, 4, 39, 20 }; + this.b = b; + } + + public void testModifArrayByte( ) { + b[2000000] = 2; + } + + public void testInstanceInternArrayByte( ){ + InternField f = new InternField(); + f.b = new byte[5]; + f.b[2] = 40; + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestExceptions.java b/examples/android/TestsAndroguard/src/tests/androguard/TestExceptions.java new file mode 100644 index 00000000..687aafe8 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestExceptions.java @@ -0,0 +1,146 @@ +package tests.androguard; + +public class TestExceptions { + + public int testException1( int a ) + { + try { + a = 5 / 0; + } catch ( ArithmeticException e ) { + a = 3; + } + return a; + } + + public static int testException2( int a, int b ) throws ArrayIndexOutOfBoundsException + { + int [] t = new int[b]; + + if ( b == 10 ) + b++; + + for( int i = 0; i < b; i++ ) + { + t[i] = 5; + } + + return a + t[0]; + } + + public int testException3( int a, int[] t ) + { + int result = 0; + + if ( a % 2 == 0 ) + { + try { + result = t[a]; + } catch (ArrayIndexOutOfBoundsException e) { + result = 1337; + } + } + else if ( a % 3 == 0 ) { + result = a * 2; + } else { + result = t[0] - 10; + } + + return result; + } + + public int testException4( int a ) + { + int res = 15; + + res += a; + + try { + Runtime b = Runtime.getRuntime(); + b.notifyAll(); + } catch( RuntimeException e ) { + System.out.println("runtime " + e.getMessage()); + } + + try { + Runtime c = Runtime.getRuntime(); + c.wait(); + } + catch (RuntimeException e) { + System.out.println("runtime " + e.getMessage()); + } + catch (Exception e) { + System.out.println("exception e " + e.getMessage()); + } + + try { + res /= a; + } catch (Exception e) { + System.out.println("exception e " + e.getMessage()); + } + + System.out.println("end"); + return res; + + } + + public static void testTry1(int b) + { + int a = 15; + try { + if ( b % 2 == 0) + { + a = a / b; + if ( a - 3 == 4 ) + System.out.println("lll"); + } + else { + a = a * b; + System.out.println("ppp"); + } + } catch(ArithmeticException e){ + System.out.println("oupla"); + } + } + + public static void testCatch1(int b) + { + int a = 15; + try { + if ( b % 2 == 0 ) + { + a = a / b; + if ( a - 3 == 4 ) + System.out.println("mmm"); + } else { + a = a * b; + System.out.println("qqq"); + } + } catch(ArithmeticException e) + { + if ( a == 12 ) + System.out.println("test"); + else { + b += 3 * a; + System.out.println("test2 " + b); + } + } + } + + public static void testExceptions( String [] z ) + { + System.out.println( "Result test1 : " + new TestExceptions().testException1( 10 ) ); + + System.out.println( "=================================" ); + try { + System.out.println( "Result test2 : " + testException2( 5, 10 ) ); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println( "Result test2 : " + testException2( 5, 9 ) ); + } + + System.out.println( "=================================" ); + int [] t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + System.out.println( "Result test3 : " + new TestExceptions().testException3( 8, t ) ); + System.out.println( "Result test3 : " + new TestExceptions().testException3( 9, t ) ); + System.out.println( "Result test3 : " + new TestExceptions().testException3( 7, t ) ); + } +} \ No newline at end of file diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestIfs.java b/examples/android/TestsAndroguard/src/tests/androguard/TestIfs.java new file mode 100644 index 00000000..561d2a65 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestIfs.java @@ -0,0 +1,145 @@ +package tests.androguard; + +public class TestIfs { + private boolean P, Q, R, S, T; + + public static int testIF(int p) { + int i; + + if (p > 0) { + i = p * 2; + } else { + i = p + 2; + } + return i; + } + + public static int testIF2(int p) { + int i = 0; + + if (p > 0) { + i = p * 2; + } else { + i = p + 2; + } + return i; + } + + public static int testIF3(int p) { + int i = 0; + if (p > 0) { + i = p * 2; + } + return i; + } + + public static int testIF4(int p, int i) { + if (p > 0 && p % 2 == 3) { + i += p * 3; + } + return i; + } + + public static int testIF5(int p, int i) { + if ((p <= 0 && i == 0) || (p == i * 2 || i == p / 3)) { + i = -p; + } + return i; + } + + public static int testIfBool(int p, boolean b) { + int i = 0; + if ( p > 0 && b ) + i += p * 3; + else if (b) + i += 5; + else + i = 2; + return i; + } + + public static int testShortCircuit(int p) { + int i = 0; + if (p > 0 && p % 2 == 3) { + i = p + 1; + } else { + i = -p; + } + return i; + } + + public static int testShortCircuit2(int p) { + int i = 0; + if (p <= 0 || p % 2 != 3) + i = -p; + else + i = p + 1; + return i; + } + + public static int testShortCircuit3(int p, int i) { + if ((p <= 0 && i == 0) || (p == i * 2 || i == p / 3)) { + i = -p; + } else { + i = p + 1; + } + return i; + } + + public static int testShortCircuit4(int p, int i) { + if ((p <= 0 || i == 0) && (p == i * 2 || i == p / 3)) + i = -p; + else + i = p + 1; + return i; + } + + public void testCFG() { + int I = 1, J = 1, K = 1, L = 1; + + do { + if (P) { + J = I; + if (Q) + L = 2; + else + L = 3; + K++; + } else { + K += 2; + } + System.out.println(I + "," + J + "," + K + "," + L); + do { + if (R) + L += 4; + } while (!S); + I += 6; + } while (!T); + } + + public void testCFG2(int a, int b, int c) { + a += 5; + b += a * 5; + if (a < b) { + if (b < c) { + System.out.println("foo"); + } else { + System.out.println("bar"); + } + } + a = 10; + while (a < c) { + a += c; + do { + b = a++; + System.out.println("baz"); + } while (c < b); + b++; + } + System.out.println("foobar"); + if (a >= 5 || b * c <= c + 10) { + System.out.println("a = " + 5); + } + System.out.println("end"); + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestInvoke.java b/examples/android/TestsAndroguard/src/tests/androguard/TestInvoke.java new file mode 100644 index 00000000..5bc08468 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestInvoke.java @@ -0,0 +1,50 @@ +package tests.androguard; + + +public class TestInvoke { + + public TestInvoke( ) { + TestInvoke1(42 ); + } + + public int TestInvoke1( int a ) + { + return TestInvoke2( a, 42 ); + } + + public int TestInvoke2( int a, int b ) + { + return TestInvoke3( a, b, 42 ); + } + + public int TestInvoke3( int a, int b, int c ) + { + return TestInvoke4( a, b, c, 42 ); + } + + public int TestInvoke4( int a, int b, int c, int d ) + { + return TestInvoke5( a, b, c, d, 42 ); + } + + public int TestInvoke5(int a, int b, int c, int d, int e) + { + return TestInvoke6( a, b, c, d, e, 42 ); + } + + public int TestInvoke6( int a, int b, int c, int d, int e, int f ) + { + return TestInvoke7( a, b, c, d, e, f, 42); + } + + public int TestInvoke7( int a, int b, int c, int d, int e, int f, int g ) + { + return TestInvoke8( a, b, c, d, e, f, g, 42); + } + + public int TestInvoke8( int a, int b, int c, int d, int e, int f, int g, int h ) + { + return a * b * c * d * e *f * g *h; + } + +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestLoops.java b/examples/android/TestsAndroguard/src/tests/androguard/TestLoops.java new file mode 100644 index 00000000..1172c2e3 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestLoops.java @@ -0,0 +1,238 @@ +package tests.androguard; + +import android.content.pm.LabeledIntent; +import android.util.Log; + +public class TestLoops { + + protected static class Loop { + public static int i; + public static int j; + } + + public void testWhile() { + int i = 5, j = 10; + while (i < j) { + j += i / 2.0 + j; + i += i * 2; + } + Loop.i = i; + Loop.j = j; + } + + public void testWhile2() { + while(true) + System.out.println("toto"); + } + + public void testWhile3(int i, int j) + { + while ( i < j && i % 2 == 0 ) + { + i += j / 3; + } + } + + public void testWhile4(int i, int j) + { + while ( i < j || i % 2 == 0 ) + { + i += j / 3; + } + } + + public void testWhile5(int i, int j, int k ) + { + while ( ( i < j || i % 2 == 0 ) && ( j < k || k % 2 == 0) ) + i += k - j; + } + + public void testFor() { + int i, j; + for (i = 5, j = 10; i < j; i += i * 2) { + j += i / 2.0 + j; + } + Loop.i = i; + Loop.j = j; + } + + public void testDoWhile() { + int i = 5, j = 10; + do { + j += i / 2.0 + j; + i += i * 2; + } while (i < j); + Loop.i = i; + Loop.j = j; + } + + public int testNestedLoops(int a) { + if (a > 1000) { + return testNestedLoops(a / 2); + } else { + while (a > 0) { + a += 1; + while (a % 2 == 0) { + a *= 2; + while (a % 3 == 0) { + a -= 3; + } + } + } + } + return a; + } + + public void testMultipleLoops() { + int a = 0; + while (a < 50) + a += 2; + while (a % 3 == 0) + a *= 5; + while (a < 789 && a > 901) + System.out.println("woo"); + } + + public int testDoWhileTrue(int n) { + do { + n--; + if (n == 2) + return 5; + if (n < 2) + n = 500; + } while (true); + } + + public int testWhileTrue(int n) { + while (true) { + n--; + if (n == 2) + return 5; + if (n < 2) + n = 500; + } + } + + public int testDiffWhileDoWhile(int n) { + while (n != 2) { + if (n < 2) + n = 500; + } + return 5; + } + + public void testReducible(boolean x, boolean y) { + int a = 0, b = 0; + if (x) + while (y) { + a = b + 1; + b++; + } + else + while (y) { + b++; + a = b + 1; + } + Loop.i = a; + Loop.j = b; + } + + public void testIrreducible(int a, int b) { + while (true) { + if (b < a) { + Log.i("test", "In BasicBlock A"); + } + b = a - 1; + Log.i("test2", "In BasicBlock B"); + } + } + + public int testBreak( boolean b ) { + int a = 0, c = 0; + while(true) { + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 ) + b = true; + if ( b ) + break; + } + return a + c; + } + + public int testBreakbis( boolean b ) { + int a = 0, c = 0; + do { + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 ) + b = true; + if ( b ) + break; + } while(true); + return a + c; + } + + public int testBreakMid( boolean b ) { + int a = Loop.i, c = Loop.j; + while(true) { + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 ) + b = !b; + if ( b ) break; + System.out.println("bar"); + a *= 2; + } + return a + c; + } + + public int testBreakDoWhile( boolean b ) { + int a = 0, c = 0; + do { + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 ) + b = true; + }while ( b ); + return a + c; + } + + public int testBreak2( boolean b ) { + int a = 0, c = 0; + while (true) { + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 && b ) + break; + } + return a + c; + } + + public void testBreak3( boolean b ) { + int a = 0, c = 0; + while ( true ){ + System.out.println("foo"); + a += c; + c += 5; + if ( a == 50 && b ) + break; + } + } + + public void testBreak4( boolean b, int d ) { + int a = 0, c = 0; + while ( c < 50 ) { + System.out.println("foo"); + a += c; + c +=5; + if ( a == d ) + break; + } + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort.java b/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort.java new file mode 100644 index 00000000..cc580971 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort.java @@ -0,0 +1,45 @@ +package tests.androguard; + +public class TestQuickSort { + public int a = 10; + + public static void Main(String[] args) { + int[] intArray = new int[args.length]; + for (int i = 0; i < intArray.length; i++) { + intArray[i] = Integer.parseInt(args[i]); + } + QuickSort(intArray, 0, intArray.length - 1); + for (int i = 0; i < intArray.length; i++) { + System.out.println(intArray[i] + " "); + } + } + + public static void QuickSort(int[] array, int left, int right) { + if (right > left) { + int pivotIndex = (left + right) / 2; + int pivotNew = Partition(array, left, right, pivotIndex); + QuickSort(array, left, pivotNew - 1); + QuickSort(array, pivotNew + 1, right); + } + } + + static int Partition(int[] array, int left, int right, int pivotIndex) { + int pivotValue = array[pivotIndex]; + Swap(array, pivotIndex, right); + int storeIndex = left; + for (int i = left; i < right; i++) { + if (array[i] <= pivotValue) { + Swap(array, storeIndex, i); + storeIndex++; + } + } + Swap(array, right, storeIndex); + return storeIndex; + } + + static void Swap(int[] array, int index1, int index2) { + int tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort2.java b/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort2.java new file mode 100644 index 00000000..ed4eedab --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestQuickSort2.java @@ -0,0 +1,51 @@ +package tests.androguard; + +public class TestQuickSort2 { + + public int a = 10; + + public static void Main(String[] args) { + int[] intArray = new int[args.length]; + for (int i = 0; i < intArray.length; i++) { + intArray[i] = Integer.parseInt(args[i]); + } + quicksort(intArray, 0, intArray.length - 1); + for (int i = 0; i < intArray.length; i++) { + System.out.println(intArray[i] + " "); + } + } + + public static void quicksort(int[] array, int lo, int hi) { + int i = lo; + int j = hi; + + int pivot = array[lo + (hi - lo) / 2]; + + while(i <= j) { + + while(array[i] < pivot) { + i++; + } + + while(array[j] > pivot) { + j--; + } + + if(i <= j) { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } + } + + if(lo < j) { + quicksort(array, lo, j); + } + + if(i < hi) { + quicksort(array, i, hi); + } + } +} diff --git a/examples/android/TestsAndroguard/src/tests/androguard/TestSynthetic.java b/examples/android/TestsAndroguard/src/tests/androguard/TestSynthetic.java new file mode 100644 index 00000000..a60a3997 --- /dev/null +++ b/examples/android/TestsAndroguard/src/tests/androguard/TestSynthetic.java @@ -0,0 +1,76 @@ +package tests.androguard; + +public class TestSynthetic { + + public static void TestSynthetic1( ){ + final Object o = new Object(); + + new Thread(){ + public void run(){ + System.out.println( "o : " + o.hashCode() ); + } + }.start(); + } + + public static void TestSynthetic2() { + System.out.println( "o : " + + new Object(){ + public int toto(char c){ + return Integer.parseInt("" + c); + } + }.toto('k') + ); + } + + public static void TestSynthetic3( ){ + Integer o = Integer.valueOf(5); + + new Thread(){ + Integer o = this.o; + public void run(){ + System.out.println( "o : " + o.hashCode() ); + } + }.start(); + } + + public static void TestSynthetic4( final int t ) { + final Object o = new Object(); + + new Thread(){ + public void run(){ + synchronized(o){ + if ( t == 0 ) { + TestSynthetic1(); + } + else { + TestSynthetic2(); + } + } + } + }.start(); + + System.out.println("end"); + } + + + public class Bridge { + public T getT(T arg){ + return arg; + } + } + + public class BridgeExt extends Bridge{ + public String getT(String arg){ + return arg; + } + } + + public static void TestBridge( ){ + TestSynthetic p = new TestSynthetic(); + TestSynthetic.Bridge x = p.new Bridge(); + System.out.println("bridge " + x.getT(5)); + TestSynthetic.Bridge w = p.new BridgeExt(); + System.out.println("bridgeext " + w.getT("toto")); + } + +} diff --git a/examples/android/gtalksms/AUTHORS b/examples/android/gtalksms/AUTHORS new file mode 100644 index 00000000..5d7d6788 --- /dev/null +++ b/examples/android/gtalksms/AUTHORS @@ -0,0 +1,3 @@ +Christophe-Marie Duquesne +Florent Lopez +Michael Cukier diff --git a/examples/android/gtalksms/AndroidManifest.xml b/examples/android/gtalksms/AndroidManifest.xml new file mode 100644 index 00000000..2260d28f --- /dev/null +++ b/examples/android/gtalksms/AndroidManifest.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/gtalksms/Changelog b/examples/android/gtalksms/Changelog new file mode 100644 index 00000000..c959dea5 --- /dev/null +++ b/examples/android/gtalksms/Changelog @@ -0,0 +1,22 @@ +0.4 +Fix contact search using phone numbers +Add battery notification interval preference (1,5,10,20) in percent +Send message on closing if connection notifications are enabled +Add calls commands that shows call logs + +0.3 +Add command "sms" without parameter that shows last sms from everyone +Optimize sms read by limiting search results +Add Widget support to XMPP connection + +0.2 +Recode ContactsManager to manage all accounts (GMail, Exchange) with SDK 2.0 +Adapt SmsManager for ContactsManager compatibility +Set min SDK version to 2.0 ECLAIR +Fix ForceClose on XMPP disconnection +Add current version in the main window + +0.1 +Create GTalkSMS from TalkMyPhone +Fix long SMS issues +Add new features as formated responses, dial number... \ No newline at end of file diff --git a/examples/android/gtalksms/Donors b/examples/android/gtalksms/Donors new file mode 100644 index 00000000..3e0a9608 --- /dev/null +++ b/examples/android/gtalksms/Donors @@ -0,0 +1,11 @@ +* Arnaud Didry +* Ludovic S. +* Adrien Decremps +* Anton Parup Kylling +* Jorge Pérez Castorena +* Paul D. Spradling +* Dominique Lemieux +* Timothy O'Connell +* Yip Shing +* Christophe-Marie Duquesne +* Roddie Hasan \ No newline at end of file diff --git a/examples/android/gtalksms/androguard.xml b/examples/android/gtalksms/androguard.xml new file mode 100644 index 00000000..94d374b0 --- /dev/null +++ b/examples/android/gtalksms/androguard.xml @@ -0,0 +1,17 @@ + + + + + WM_L5 + wm.xml + + + + externals + + + + externals + + + diff --git a/examples/android/gtalksms/bin/classes.dex b/examples/android/gtalksms/bin/classes.dex new file mode 100644 index 00000000..909d7165 Binary files /dev/null and b/examples/android/gtalksms/bin/classes.dex differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/BootReceiver.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/BootReceiver.class new file mode 100644 index 00000000..64fb4207 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/BootReceiver.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CallReceiver.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CallReceiver.class new file mode 100644 index 00000000..2bcdfefe Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CallReceiver.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CommandsManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CommandsManager.class new file mode 100644 index 00000000..8206bd8a Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/CommandsManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/EditIntegerPreference.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/EditIntegerPreference.class new file mode 100644 index 00000000..7468a3e7 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/EditIntegerPreference.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService$1.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService$1.class new file mode 100644 index 00000000..b601f626 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService$1.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService.class new file mode 100644 index 00000000..e55d30f0 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/LocationService.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/MediaManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/MediaManager.class new file mode 100644 index 00000000..52192961 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/MediaManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/NetworkConnectivityReceiver.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/NetworkConnectivityReceiver.class new file mode 100644 index 00000000..2549d512 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/NetworkConnectivityReceiver.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/PhoneCallListener.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/PhoneCallListener.class new file mode 100644 index 00000000..94659214 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/PhoneCallListener.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$array.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$array.class new file mode 100644 index 00000000..71118b44 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$array.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$attr.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$attr.class new file mode 100644 index 00000000..7ca2ea30 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$attr.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$drawable.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$drawable.class new file mode 100644 index 00000000..492ae1f9 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$drawable.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$id.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$id.class new file mode 100644 index 00000000..4a6d7b6d Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$id.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$layout.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$layout.class new file mode 100644 index 00000000..321d9507 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$layout.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$string.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$string.class new file mode 100644 index 00000000..9ae768ed Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$string.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$xml.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$xml.class new file mode 100644 index 00000000..9ebb840e Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R$xml.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R.class new file mode 100644 index 00000000..367c3f84 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/R.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SettingsManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SettingsManager.class new file mode 100644 index 00000000..b603d89b Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SettingsManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SmsReceiver.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SmsReceiver.class new file mode 100644 index 00000000..8b45f96e Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/SmsReceiver.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/Tools.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/Tools.class new file mode 100644 index 00000000..f952c8b2 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/Tools.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetActivator.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetActivator.class new file mode 100644 index 00000000..4b08d00d Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetActivator.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetProvider.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetProvider.class new file mode 100644 index 00000000..5debc7a2 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/WidgetProvider.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$1.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$1.class new file mode 100644 index 00000000..4f057130 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$1.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$2.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$2.class new file mode 100644 index 00000000..9af06778 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$2.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$3.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$3.class new file mode 100644 index 00000000..5b4b9178 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService$3.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService.class new file mode 100644 index 00000000..4f683d54 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/XmppService.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/Contact.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/Contact.class new file mode 100644 index 00000000..b8f5cd64 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/Contact.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactAddress.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactAddress.class new file mode 100644 index 00000000..94b7ad14 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactAddress.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactsManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactsManager.class new file mode 100644 index 00000000..4eeea1a5 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/contacts/ContactsManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoManager.class new file mode 100644 index 00000000..7d74b85f Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$1.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$1.class new file mode 100644 index 00000000..ee4a64c7 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$1.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$2.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$2.class new file mode 100644 index 00000000..a3600df7 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup$2.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup.class new file mode 100644 index 00000000..a70e3fc7 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/geo/GeoPopup.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$1.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$1.class new file mode 100644 index 00000000..0a3ff0c6 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$1.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$2.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$2.class new file mode 100644 index 00000000..04c794a4 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen$2.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen.class new file mode 100644 index 00000000..515db569 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/MainScreen.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/Preferences.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/Preferences.class new file mode 100644 index 00000000..77d56baa Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/panels/Preferences.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Call.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Call.class new file mode 100644 index 00000000..3ea343d5 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Call.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Phone.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Phone.class new file mode 100644 index 00000000..5d159901 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/Phone.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/PhoneManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/PhoneManager.class new file mode 100644 index 00000000..2c58985e Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/phone/PhoneManager.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/Sms.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/Sms.class new file mode 100644 index 00000000..170b2b58 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/Sms.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$1.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$1.class new file mode 100644 index 00000000..cbeb0be6 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$1.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$2.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$2.class new file mode 100644 index 00000000..05eecb12 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager$2.class differ diff --git a/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager.class b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager.class new file mode 100644 index 00000000..fa3f0950 Binary files /dev/null and b/examples/android/gtalksms/bin/classes/com/googlecode/gtalksms/sms/SmsMmsManager.class differ diff --git a/examples/android/gtalksms/build.xml b/examples/android/gtalksms/build.xml new file mode 100644 index 00000000..61f294e2 --- /dev/null +++ b/examples/android/gtalksms/build.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/gtalksms/default.properties b/examples/android/gtalksms/default.properties new file mode 100644 index 00000000..4686f7f8 --- /dev/null +++ b/examples/android/gtalksms/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-9 diff --git a/examples/android/gtalksms/libs/smack.jar b/examples/android/gtalksms/libs/smack.jar new file mode 100644 index 00000000..b957edf8 Binary files /dev/null and b/examples/android/gtalksms/libs/smack.jar differ diff --git a/examples/android/gtalksms/local.properties b/examples/android/gtalksms/local.properties new file mode 100644 index 00000000..dfd1408b --- /dev/null +++ b/examples/android/gtalksms/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/desnos/android/android-sdk-linux_x86 diff --git a/examples/android/gtalksms/proguard.cfg b/examples/android/gtalksms/proguard.cfg new file mode 100644 index 00000000..8ad7d335 --- /dev/null +++ b/examples/android/gtalksms/proguard.cfg @@ -0,0 +1,34 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/examples/android/gtalksms/res/drawable-hdpi/icon_blue.png b/examples/android/gtalksms/res/drawable-hdpi/icon_blue.png new file mode 100644 index 00000000..91a26c8f Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/icon_blue.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/icon_green.png b/examples/android/gtalksms/res/drawable-hdpi/icon_green.png new file mode 100644 index 00000000..862b07a5 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/icon_green.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/icon_orange.png b/examples/android/gtalksms/res/drawable-hdpi/icon_orange.png new file mode 100644 index 00000000..0d6df6dd Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/icon_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/icon_red.png b/examples/android/gtalksms/res/drawable-hdpi/icon_red.png new file mode 100644 index 00000000..60237feb Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/icon_red.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/status_green.png b/examples/android/gtalksms/res/drawable-hdpi/status_green.png new file mode 100644 index 00000000..fac75b03 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/status_green.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/status_orange.png b/examples/android/gtalksms/res/drawable-hdpi/status_orange.png new file mode 100644 index 00000000..d49b0f42 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/status_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-hdpi/status_red.png b/examples/android/gtalksms/res/drawable-hdpi/status_red.png new file mode 100644 index 00000000..56ee862d Binary files /dev/null and b/examples/android/gtalksms/res/drawable-hdpi/status_red.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/icon_blue.png b/examples/android/gtalksms/res/drawable-ldpi/icon_blue.png new file mode 100644 index 00000000..8f02961f Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/icon_blue.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/icon_green.png b/examples/android/gtalksms/res/drawable-ldpi/icon_green.png new file mode 100644 index 00000000..99ef46df Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/icon_green.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/icon_orange.png b/examples/android/gtalksms/res/drawable-ldpi/icon_orange.png new file mode 100644 index 00000000..6a596619 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/icon_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/icon_red.png b/examples/android/gtalksms/res/drawable-ldpi/icon_red.png new file mode 100644 index 00000000..ccc92a3e Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/icon_red.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/status_green.png b/examples/android/gtalksms/res/drawable-ldpi/status_green.png new file mode 100644 index 00000000..528d006a Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/status_green.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/status_orange.png b/examples/android/gtalksms/res/drawable-ldpi/status_orange.png new file mode 100644 index 00000000..8879128f Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/status_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-ldpi/status_red.png b/examples/android/gtalksms/res/drawable-ldpi/status_red.png new file mode 100644 index 00000000..5ba8ade2 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-ldpi/status_red.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/icon_blue.png b/examples/android/gtalksms/res/drawable-mdpi/icon_blue.png new file mode 100644 index 00000000..0203118d Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/icon_blue.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/icon_green.png b/examples/android/gtalksms/res/drawable-mdpi/icon_green.png new file mode 100644 index 00000000..a93bb8f6 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/icon_green.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/icon_orange.png b/examples/android/gtalksms/res/drawable-mdpi/icon_orange.png new file mode 100644 index 00000000..d2d332cb Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/icon_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/icon_red.png b/examples/android/gtalksms/res/drawable-mdpi/icon_red.png new file mode 100644 index 00000000..e9d8bcd0 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/icon_red.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/status_green.png b/examples/android/gtalksms/res/drawable-mdpi/status_green.png new file mode 100644 index 00000000..138cae66 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/status_green.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/status_orange.png b/examples/android/gtalksms/res/drawable-mdpi/status_orange.png new file mode 100644 index 00000000..da828eb6 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/status_orange.png differ diff --git a/examples/android/gtalksms/res/drawable-mdpi/status_red.png b/examples/android/gtalksms/res/drawable-mdpi/status_red.png new file mode 100644 index 00000000..e7dd37d3 Binary files /dev/null and b/examples/android/gtalksms/res/drawable-mdpi/status_red.png differ diff --git a/examples/android/gtalksms/res/layout/appwidget.xml b/examples/android/gtalksms/res/layout/appwidget.xml new file mode 100644 index 00000000..f8a08d03 --- /dev/null +++ b/examples/android/gtalksms/res/layout/appwidget.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/examples/android/gtalksms/res/layout/main.xml b/examples/android/gtalksms/res/layout/main.xml new file mode 100644 index 00000000..fb5a594b --- /dev/null +++ b/examples/android/gtalksms/res/layout/main.xml @@ -0,0 +1,17 @@ + + + +