[
  {
    "path": ".gradle/8.8/dependencies-accessors/gc.properties",
    "content": ""
  },
  {
    "path": ".gradle/8.9/dependencies-accessors/gc.properties",
    "content": ""
  },
  {
    "path": ".gradle/8.9/gc.properties",
    "content": ""
  },
  {
    "path": ".gradle/buildOutputCleanup/cache.properties",
    "content": "#Fri Mar 07 17:06:23 CET 2025\ngradle.version=8.8\n"
  },
  {
    "path": ".gradle/vcs-1/gc.properties",
    "content": ""
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.md",
    "content": "**AndroTickler**\n=================\n\nA java tool that helps to pentest Android apps faster, more easily and more efficiently. AndroTickler offers many features of information gathering, static and dynamic checks that cover most of the aspects of Android apps pentesting. It also offers several features that pentesters need during their pentests. AndroTickler also integrates with Frida to provide method tracing and manipulation. It was previously published under the name of **Tickler**.\n\nAndroTickler requires a linux host and a rooted Android device connected to its USB port. The tool does not install anything on the Android device, it only creates a *Tickler* directory on /sdcard . AndroTickler depends on Android SDK to run commands on the device and copy app's data to *TicklerWorkspace* directory on the host for further analysis. *TicklerWorkspace* is the working directory of AndroTickler and each app has a separate subdirectory in *TicklerWorkspace* which can contain the following (depending on user actions):\n- DataDir directory: a copy of the data directory of the app\n- extracted directory: Output of apktool on the app, contains smali code, resources, libraries...etc.\n- bgSnapshots directory: Contains background snapshots copied from the device.\n- images directory: contains any screenshots taken for the app.\n- JavaCode directory: Contains app's Java code decompiled by dex2jar and JD tools\n- logs directory: contains log files produced by -t -log, as explained below\n- transfers: files and directories copied from the device to the host using -copy2host\n- AndroidManifest.xml: The manifest file of the app as per apktool\n- base.apk: the APK file of the app, installed on the device\n- debuggable.apk: a debuggable version of the app, produced by -dbg\n\n*libs* directory and *Tickler.conf* configuration file exist in the same directory of the jar file. The configuration file sets the location of *TicklerDir* directory on the host and *Tickler* on /sdcard of the android device. If the configuration file does not exist or these 2 directories are not set, then default values will be used (Tickler\\_workspace on the current directory and /sdcard/Tickler respectively). *Tickler_lib* directory contains some Java libraries and external tools used by AndroTickler such as apktool and dex2jar. \n\nAndroTickler highly depends on the following tools, so they should exist on your machine before using it:\n- Java 7 or higher\n- Android SDK tools (adb and friends) \n- sqlite3\n\nOther tools are required for some features, but AndroTickler can still run without them:\n- Frida\n- jarsigner\n\nHow to build it\n================\n1) Build tool from code\n\n\tgradle build\n\n2) Move AndroTickler.jar is to the same directory as Tickler_lib directory and Tickler.conf file (automatically created in build/libs)\n3) Set dex2jar to executable (libs/notJars//dex2jar-2.1/d2j-dex2jar.sh and libs/notJars//dex2jar-2.1/d2j_invoke.sh)\n4) Connect your Android device with the application-to-test installed on   \n\n**Note**: If building the source code fails, you can download the latest compiled release from the [releases](https://github.com/ernw/AndroTickler/releases) tab\n\nThe current version does the following:\n\nCommand help\n=============\n    java -jar AndroTickler.jar -h\n\nInformation gathering/Static analysis:\n======================================\nList installed Apps on the device:\n\n    java -jar AndroTickler.jar -pkgs\n\n\nSearches for an app (package) installed on the device, whose package name contains the searchKey\n\n    java -jar AndroTickler.jar -findPkg <searchKey>\n\n \n \n### package without extra attributes \n    java -jar AndroTickler.jar -pkg <package> [other options]\nAny command with a -pkg option (whether used with any of the following options or not), does the following actions if they have not been done before:\n- Copies the app from the device\n- Extracts the Manifest file of the app\n- Decompiles the app to Java code using dex2jar and JD tools\n\n### General Info\n\n    java -jar AndroTickler.jar -pkg <package> -info\n\nReturns the following information:\n- App's user ID\n- App's Directories path\n- If the app's code indicate usage of external storage\n- App's directories that already exist in External storage\n- Content URIs in the code\n- If the app is backable\n- If the app is debuggable\n- Data schemes (like iOS IPC)\n- The permissions it uses\n\n## Code Squeezing\n\n    java -jar AndroTickler.jar -pkg <package> -squeeze [short | <codeLocation> ]\n\nFetches the following from the decompiled Java code of the app:\n- Log messages\n- Any indication of possible user credentials\n- Java comments\n- Used libs\n- URLs in code\n- Usage of shared preferences\n- Usage of external storage\n- Common components such as OkHttp and WebView\n\nUnsurprisingly, its output is usually huge, so it is recommended to redirect the command's output to a file\n\n*short* \nSqueezes only the decompiled code that belongs to the developer. For example, if an app has a package name of com.notEnaf.myapp, then *squeeze short* squeezes only the code in com/notEnaf directory.\n \n*<codeLocation>* \nSqueezes the code only in *codeLocation* directory. Helpful to limit your search or squeeze the source code if available.\n\n\n## Listing Components\n\n    java -jar AndroTickler.jar -pkg <package> -l [-exp] [-v]\nLists all components of the app \n\n*-exp*\nShows only exported components\n\n*-v*\nGives more detailed information for each component:\n - Component type\n - Whether exported or not\n - Its intent filters \n - The tool checks the corresponding Java class to each component and returns all possible intent extras \n\n### Listing any kind of components\n\n    java -jar AndroTickler.jar -pkg <package> -l [-act | -ser | -rec | -prov ] [-exp] [-v]\n\n- -act : activities\n- -ser : services\n- -rec: broadcast receivers\n- -prov: Content providers\n- -exp: show only exported components of any of the above type \n\n\n## Databases\n\n    java -jar AndroTickler.jar -pkg <package> -db [|e|l|d] [nu]\n\t\nBy default, all -db commands update the app's data storage directory on the host before running the check.\n\n*no attribute OR e*\nTests whether the databases of the app are encrypted. It is the default action in case no option is given after -db flag.\n*l*\nLists all databases of the app. Encrypted databases might not be detected.\n*d*\nTakes a sqlite dump of any of the unencrypted databases.\n*nu* \nnoUpdate: runs any of the above options without updating the app's data directory on the host.\n\n## Data Storage Directory Comparison\n\n    java -jar AndroTickler.jar -pkg <package> -diff [d|detailed]\n\t\nCopies the data storage directory of the app (to DataDirOld) then asks the user to do the action he wants and to press Enter when he's done. Then it copies the data storage directory again (to DataDir) and runs diff between them to show which files got added, deleted or modified. \n\n*d|detailed*\nDoes the same as the normal -diff command, also shows what exactly changed in text files and unencrypted databases.\n\n## Search\n### Code\n    java -jar AndroTickler.jar -pkg <package> -sc <key> [<customLocation>]\n\nSearches for the *key* in the following locations:\n- The decompiled Java code of the app\n- res/values/strings.xml\n- res/values/arrays.xml\n\nSearch is case insensitive.\n\n*<customLocation>*\nReplaces the decompiled Java code location with the custom location.\n\n### Storage\n\n    java -jar AndroTickler.jar -pkg <package> -sd <key>\nSearches the Data storage directory of the app for the given key\n\n\nTickling\n=========\nTriggers components of the app, by all possible combinations of intents. For example, if an activity has an intent-filter of 2 possible actions and 3 data URI schemes, then AndroTickler will trigger this activity with all possible combinations of this intent. Additionally, AndroTickler captures the intent extras mentioned in the Java class corresponding to the component, assign them dummy values and add them to the possible intent combinations. Only extras of type boolean, string, int and float are supported. \n \nif the *-exp* option is used, then the components will be triggered without root privileges or any special permissions. If not, then the components will be trigged with root privileges. This helps to test the app in 2 different scenarios: against normal-privileged or high-privileged attackers.\n\nBefore triggering components, AndroTickler prints all the commands to be executed. Then for each command, it triggers the component, prints the command then waits for the user. This gives the user enough time to do any extra checks after the command's execution. Before the user moves on to the next command, he's given the option to capture a screenshot of the device for PoC documentation.\n\n\n\n    java -jar AndroTickler.jar -pkg <package> -t [-all | -exp] [target] [-log]\n\n*target* as explained with list command, can be:\n- -act : activities. starts the (activity/activities) with all intent combinations as explained above\n- -ser : services. starts the service(s) with all intent combinations as explained above\n- -rec: broadcast receivers: sends all possible broadcast messages that would match the broadcast receiver(s)\n- -prov: Content providers:  queries the content provider(s)\n\nif no value, then the target is all of the above\n\n*[-comp] <component_name>*\nSpecifies one component only. You can also use *<component_name>* directly without -comp flag.\n*-exp*\nAndroTickler uses normal privileges to trigger only the exported targets.\n*-all* \nThe default option. AndroTickler uses root privileges to trigger the exported targets\n*-log* \nCaptures all logcat messages generated during the triggering session. Log file is saved in logs subdirectory.\n\n\nFrida:\n======\nFrida should be installed on your host machine. Also the location of Frida server on the Android device should be added to *Tickler.conf* file in the *Frida_server_path* entry\n\n## Capture Arguments and return value\n\n    java -jar AndroTickler.jar -pkg <package> -frida vals <ClassName> <MethodName> <NumberOfArgs> [-reuse]\nDisplays arguments and return value of this method (only primitive datatypes and String)\n\n*reuse*\nIn case of vals and set options, Frida creates/updates a Frida script of that functionality. You can modify the created script as you want, then if you want to run it through AndroTickler, then use *-reuse* option so that it doesn't get overridden.\n\n## Modify Arguments or Return Value\n    java -jar AndroTickler.jar -pkg <package> -frida set <ClassName> <MethodName> <NumberOfArgs> <NumberOfArgToModify> <newValue>[-reuse]\nSets the argument number *NumberOfArgToModify* to *newValue* (only primitive datatypes and String). \n*NumberOfArgToModify* starts with 0: First argument --> NumberOfArgToModify = 0, ...etc \nTo modify return value --> set NumberOfArgToModify to *ret*\n \n\n## Run JS Frida script\n    java -jar AndroTickler.jar -pkg <package> -frida script <scriptPath>\nRuns a frida JS script located at *scriptPath* on your host\n\nEnumerate loaded classes:\n\n    java -jar AndroTickler.jar -pkg <package> -frida enum\n\nOther Features\n================= \n### Debuggable version\n    java -jar AndroTickler.jar -pkg <package> -dbg\nCreates a debuggable version of the app, which can be installed on the device and debugged using any external tool.\nAndroTickler comes with a keystore to sign the debuggable apk, but it requires *jarsigner* tool on the host.\n\n### Custom version\n    java -jar AndroTickler.jar -pkg <package> -apk <decompiledDirectory>\nBuilds an apk file from a directory, signs it and installs it.\n\n\n### Background Snapshots\n    java -jar AndroTickler.jar [-pkg <package>] [-bg|--bgSnapshots]\nCopies the background snapshots taken by the device (works with and without -pkg option) to *bgSnapshots* subdirectory.\n\n### Copy files / directories\nCopy Data storage directory:\n\n    java -jar AndroTickler.jar -pkg <package> -dataDir  [dest]\nCopies Data storage directory to DataDir\n*dest*\nOptional name of the destination directory, which will be located anyway at *transfers* sudirectory. \n\nCopy any file / directory:\n\n    java -jar AndroTickler.jar -pkg <package> -cp2host <source_path> [dest]\nCopies files / directories from the android devices. \n- source_path is the absolute location of what you want to copy from the android device\n- dest: optional name of the destination directory, which will be located anyway at *transfers* sudirectory. \n\nIf dest option is not given then the directory's name will be the timestamp of the transaction. \n\n### Screenshot\n    java -jar AndroTickler.jar [-pkg <package>] -screen\n- Captures the current screenshot of the device and saves them in *images* subdirectory\n- Works with or without the package flag\n\n\n\n### Note\n\nFor the options that do not require -pkg option, their data will be saved at  *Tickler_Dir*/NoPackage\n\n\n\nExamples:\n=========\n\n    java -jar AndroTickler.jar -pkg <package> -t  -act -exp\nTriggers exported activities\n\n    java -jar AndroTickler.jar -pkg <package> -t -prov -log\nQueries all content providers and saves logcat messages until the tool stops execution\n\n    java -jar AndroTickler.jar -pkg <package> -t <component_name> \nTriggers the component, type of triggering depends on the type of the component\n\n    java -jar AndroTickler.jar -pkg de.not3naf.myApp -frida set de.not3naf.myApp.myActivity myMethod 2 0 \"newValue\" \nHooks to the method \"myMethod\" that has 2 arguments and changes value of the first argument (args[0]) to \"newValue\" \n\n    java -jar AndroTickler.jar -pkg de.not3naf.myApp -frida set de.not3naf.myApp.myActivity myMethod 2 2 false \nHooks to the method \"myMethod\" that has 2 arguments and changes the return value to boolean false \n\n\n\n"
  },
  {
    "path": "Tickler.conf",
    "content": "Tickler_local_directory = \nTickler_sdcard_directory = /sdcard/Tickler/\nFrida_server_path = /data/local/tmp/frida-server\n"
  },
  {
    "path": "build.gradle",
    "content": "apply plugin: 'java'\napply plugin: 'eclipse'\n\nrepositories {\n    jcenter()\n mavenCentral()\n}\n\n\ndependencies {\n\n    compile 'org.slf4j:slf4j-api:1.7.13'\n    compile files('libs/jars/commons-cli-1.3.jar')\n    compile files('libs/jars/commons-io-2.4.jar')\n    compile files('libs/jars/apktool_2.2.2.jar')\n    compile files('libs/jars/commons-codec-1.10.jar')\n    compile files('libs/jars/jd-core-java-1.2.jar')\n    compile files('libs/jars/json-simple-1.1.1.jar')\n    runtime files('libs/jars/commons-cli-1.3.jar')\n    runtime fileTree(dir: 'libs/jars', include: '*.jar')\n}\n\njar {\n\tbaseName='AndroTickler'\n  \tmanifest {\n    \t\tattributes(\n      \t\t\t'Class-Path': configurations.compile.collect { it.getName() }.join(' '),\n      \t\t\t'Main-Class': 'cliGui.TicklerCLI'\n    \t\t)\n  \t}\n\t\n\t    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }\n     }\n\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/LICENSE.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/NOTICE.txt",
    "content": "dex2jar - Tools to work with android .dex and java .class files\r\nCopyright (c) 2009-2014 Panxiaobo\r\n\r\ncontributors\r\n  - Bob Pan <pxb1988#gmail.com>\r\n  - Enea Stanzani <aeneas.ltr#gmail.com>\r\n  - t3stwhat <t3stwhat#gmail.com>\r\n  - paulhooijenga <paulhooijenga#gmail.com>\r\n  - yyjdelete <yyjdelete#gmail.com>\r\n  - jcmdev0 <jcmdev0#gmail.com>\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/bin/dex-tools",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  dex-tools start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/..\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"dex-tools\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and DEX_TOOLS_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/lib/ST4-4.0.8.jar:$APP_HOME/lib/org.abego.treelayout.core-1.0.1.jar:$APP_HOME/lib/antlr4-runtime-4.5.jar:$APP_HOME/lib/d2j-smali-2.1-SNAPSHOT.jar:$APP_HOME/lib/dex-writer-2.1-SNAPSHOT.jar:$APP_HOME/lib/antlr-runtime-3.5.2.jar:$APP_HOME/lib/asm-debug-all-5.0.3.jar:$APP_HOME/lib/dex-translator-2.1-SNAPSHOT.jar:$APP_HOME/lib/dex-reader-2.1-SNAPSHOT.jar:$APP_HOME/lib/dx-23.0.0.jar:$APP_HOME/lib/dex-reader-api-2.1-SNAPSHOT.jar:$APP_HOME/lib/antlr4-4.5.jar:$APP_HOME/lib/dex-tools-2.1-SNAPSHOT.jar:$APP_HOME/lib/d2j-jasmin-2.1-SNAPSHOT.jar:$APP_HOME/lib/dex-ir-2.1-SNAPSHOT.jar:$APP_HOME/lib/d2j-base-cmd-2.1-SNAPSHOT.jar:$APP_HOME/lib/antlr-3.5.2.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $DEX_TOOLS_OPTS -classpath \"\\\"$CLASSPATH\\\"\" com.googlecode.dex2jar.tools.BaseCmd \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/bin/dex-tools.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  dex-tools startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%..\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and DEX_TOOLS_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\lib\\ST4-4.0.8.jar;%APP_HOME%\\lib\\org.abego.treelayout.core-1.0.1.jar;%APP_HOME%\\lib\\antlr4-runtime-4.5.jar;%APP_HOME%\\lib\\d2j-smali-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\dex-writer-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\antlr-runtime-3.5.2.jar;%APP_HOME%\\lib\\asm-debug-all-5.0.3.jar;%APP_HOME%\\lib\\dex-translator-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\dex-reader-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\dx-23.0.0.jar;%APP_HOME%\\lib\\dex-reader-api-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\antlr4-4.5.jar;%APP_HOME%\\lib\\dex-tools-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\d2j-jasmin-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\dex-ir-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\d2j-base-cmd-2.1-SNAPSHOT.jar;%APP_HOME%\\lib\\antlr-3.5.2.jar\r\n\r\n@rem Execute dex-tools\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %DEX_TOOLS_OPTS%  -classpath \"%CLASSPATH%\" com.googlecode.dex2jar.tools.BaseCmd %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable DEX_TOOLS_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%DEX_TOOLS_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-apk-sign.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.ApkSign %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-apk-sign.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.ApkSign\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-asm-verify.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.AsmVerify %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-asm-verify.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.AsmVerify\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-baksmali.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.d2j.smali.BaksmaliCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-baksmali.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.d2j.smali.BaksmaliCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-class-version-switch.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.ClassVersionSwitch %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-class-version-switch.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.ClassVersionSwitch\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-decrypt-string.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.DecryptStringCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-decrypt-string.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.DecryptStringCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex-recompute-checksum.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.DexRecomputeChecksum %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex-recompute-checksum.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.DexRecomputeChecksum\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex-weaver.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.DexWeaverCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex-weaver.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.DexWeaverCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex2jar.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.Dex2jarCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex2jar.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.Dex2jarCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex2smali.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.d2j.smali.BaksmaliCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-dex2smali.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.d2j.smali.BaksmaliCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar-access.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.JarAccessCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar-access.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.JarAccessCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar-weaver.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.JarWeaverCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar-weaver.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.JarWeaverCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar2dex.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.Jar2Dex %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar2dex.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.Jar2Dex\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar2jasmin.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.d2j.jasmin.Jar2JasminCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jar2jasmin.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.d2j.jasmin.Jar2JasminCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jasmin2jar.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.d2j.jasmin.Jasmin2JarCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-jasmin2jar.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.d2j.jasmin.Jasmin2JarCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-smali.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.d2j.smali.SmaliCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-smali.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.d2j.smali.SmaliCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-std-apk.bat",
    "content": "@echo off\r\n\r\nREM\r\nREM dex2jar - Tools to work with android .dex and java .class files\r\nREM Copyright (c) 2009-2013 Panxiaobo\r\nREM \r\nREM Licensed under the Apache License, Version 2.0 (the \"License\");\r\nREM you may not use this file except in compliance with the License.\r\nREM You may obtain a copy of the License at\r\nREM \r\nREM      http://www.apache.org/licenses/LICENSE-2.0\r\nREM \r\nREM Unless required by applicable law or agreed to in writing, software\r\nREM distributed under the License is distributed on an \"AS IS\" BASIS,\r\nREM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nREM See the License for the specific language governing permissions and\r\nREM limitations under the License.\r\nREM\r\n\r\nREM call d2j_invoke.bat to setup java environment\r\n@\"%~dp0d2j_invoke.bat\" com.googlecode.dex2jar.tools.StdApkCmd %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j-std-apk.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"com.googlecode.dex2jar.tools.StdApkCmd\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j_invoke.bat",
    "content": "@echo off\r\nREM better invocation scripts for windows from lanchon, release in public domain. thanks!\r\nREM https://code.google.com/p/dex2jar/issues/detail?id=192\r\n\r\nsetlocal enabledelayedexpansion\r\n\r\nset LIB=%~dp0lib\r\n\r\nset CP=\r\nfor %%X in (\"%LIB%\"\\*.jar) do (\r\n    set CP=!CP!%%X;\r\n)\r\n\r\njava -Xms512m -Xmx1024m -cp \"%CP%\" %*\r\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/d2j_invoke.sh",
    "content": "#!/bin/sh\n\n#\n# dex2jar - Tools to work with android .dex and java .class files\n# Copyright (c) 2009-2013 Panxiaobo\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#      http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# copy from $Tomcat/bin/startup.sh\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\nwhile [ -h \"$PRG\" ] ; do\n  ls=`ls -ld \"$PRG\"`\n  link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n  if expr \"$link\" : '/.*' > /dev/null; then\n    PRG=\"$link\"\n  else\n    PRG=`dirname \"$PRG\"`/\"$link\"\n  fi\ndone\nPRGDIR=`dirname \"$PRG\"`\n#\n\n_classpath=\".\"\nif [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath};`cygpath -w ${k}`\"\n    done\nelse\n    for k in \"$PRGDIR\"/lib/*.jar\n    do\n        _classpath=\"${_classpath}:${k}\"\n    done\nfi\n\njava -Xms512m -Xmx1024m -classpath \"${_classpath}\" \"$@\"\n"
  },
  {
    "path": "libs/notJars/dex2jar-2.1/lib/open-source-license.txt",
    "content": "==== dx-*.jar\nApache 2.0 http://www.apache.org/licenses/LICENSE-2.0.html\n\n\n==== antlr-*.jar\n[The BSD License]\nCopyright (c) 2003-2007, Terence Parr\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n* Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n* Neither the name of the author nor the names of its contributors\n  may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n\n==== asm-*.jar\n\n ASM: a very small and fast Java bytecode manipulation framework\n Copyright (c) 2000-2005 INRIA, France Telecom\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n 3. Neither the name of the copyright holders nor the names of its\n    contributors may be used to endorse or promote products derived from\n    this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n THE POSSIBILITY OF SUCH DAMAGE.\n\n"
  },
  {
    "path": "libs/notJars/fridaScripts/enumerate_classes.py",
    "content": "#!/usr/bin/python\nimport frida\nimport sys\nappName= sys.argv[1]\nprint(appName)\n# put your javascript-code here\njscode= \"\"\"\nJava.perform(\n\tfunction(){\n\t\tvar grepped = \"ssl\";\n\t\tJava.enumerateLoadedClasses(\n  \t\t\t{\n\t\t\t  \"onMatch\": function(className){ \n\t\t\t  //if (className.toLowerCase().includes(grepped))\n\t\t   \t  console.log(className) \n\t\t        \t},\n\t\t\t  \"onComplete\":function(){}\n  \t\t\t}\n\t\t)\n\t})\n\n\n\n\"\"\"\n\n# startup frida and attach to com.android.chrome process on a usb device\nsession = frida.get_usb_device().attach(appName)\n\n# create a script for frida of jsccode\nscript = session.create_script(jscode)\n\n# and load the script\nscript.load()\n\nsession.detach()\n\n"
  },
  {
    "path": "libs/notJars/fridaScripts/get_attributes_output.js",
    "content": "\t        setTimeout(function(){\t\n\t        Java.perform(function () {\t\n\t            var className = Java.use(\"java.lang.String\");\t\n\t\t\t            className.equals.implementation = function (arg0) {\t\n\t  var returnValue = this.equals(arg0);\t\n\tconsole.log(\"Input: \"+arg0);\n\t\n\t                \t\t\tif (returnValue != null ) {console.log(\"Output: \"+returnValue.toString());}\n\t\t\treturn returnValue;\t\n\t\t\t            };\t\n\t\t\t        });\t\n\t\t\t    },0);\t\n"
  },
  {
    "path": "libs/notJars/fridaScripts/unpin_sslContext.py",
    "content": "#!/usr/bin/python\nimport frida\nimport sys\nappName= sys.argv[1]\n\ndef on_message(message, data):\n    if message['type'] == 'send':\n        print(\"[*] {0}\".format(message['payload']))\n    else:\n        print(message)\n\njs= \"\"\"\n//Originally written by Piergiovanni Cipolloni : https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/\nJava.perform(function (){\n    \tconsole.log(\"\");\n\t    console.log(\"[.] Cert Pinning Bypass/Re-Pinning\");\n\n\t    var CertificateFactory = Java.use(\"java.security.cert.CertificateFactory\");\n\t    var FileInputStream = Java.use(\"java.io.FileInputStream\");\n\t    var BufferedInputStream = Java.use(\"java.io.BufferedInputStream\");\n\t    var X509Certificate = Java.use(\"java.security.cert.X509Certificate\");\n\t    var KeyStore = Java.use(\"java.security.KeyStore\");\n\t    var TrustManagerFactory = Java.use(\"javax.net.ssl.TrustManagerFactory\");\n\t    var SSLContext = Java.use(\"javax.net.ssl.SSLContext\");\n\n\t    // Load CAs from an InputStream\n\t    console.log(\"[+] Loading our CA...\")\n\t    cf = CertificateFactory.getInstance(\"X.509\");\n\t    \n\t    try {\n\t    \tvar fileInputStream = FileInputStream.$new(\"/data/local/tmp/not3naf.cer\");\n\t    }\n\t    catch(err) {\n\t    \tconsole.log(\"[o] \" + err);\n\t    }\n\t    \n\t    var bufferedInputStream = BufferedInputStream.$new(fileInputStream);\n\t  \tvar ca = cf.generateCertificate(bufferedInputStream);\n\t    bufferedInputStream.close();\n\n\t\tvar certInfo = Java.cast(ca, X509Certificate);\n\t    console.log(\"[o] Our CA Info: \" + certInfo.getSubjectDN());\n\n\t    // Create a KeyStore containing our trusted CAs\n\t    console.log(\"[+] Creating a KeyStore for our CA...\");\n\t    var keyStoreType = KeyStore.getDefaultType();\n\t    var keyStore = KeyStore.getInstance(keyStoreType);\n\t    keyStore.load(null, null);\n\t    keyStore.setCertificateEntry(\"ca\", ca);\n\t    \n\t    // Create a TrustManager that trusts the CAs in our KeyStore\n\t    console.log(\"[+] Creating a TrustManager that trusts the CA in our KeyStore...\");\n\t    var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();\n\t    var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);\n\t    tmf.init(keyStore);\n\t    console.log(\"[+] Our TrustManager is ready...\");\n\n\t    console.log(\"[+] Hijacking SSLContext methods now...\")\n\t    console.log(\"[-] Waiting for the app to invoke SSLContext.init()...\")\n\n\t   \tSSLContext.init.overload(\"[Ljavax.net.ssl.KeyManager;\", \"[Ljavax.net.ssl.TrustManager;\", \"java.security.SecureRandom\").implementation = function(a,b,c) {\n\t   \t\tconsole.log(\"[o] App invoked javax.net.ssl.SSLContext.init...\");\n\t   \t\tSSLContext.init.overload(\"[Ljavax.net.ssl.KeyManager;\", \"[Ljavax.net.ssl.TrustManager;\", \"java.security.SecureRandom\").call(this, a, tmf.getTrustManagers(), c);\n\t   \t\tconsole.log(\"[+] SSLContext initialized with our custom TrustManager!\");\n\t   \t}\n\n\t\n\n\n\n    });\n\"\"\"\nsession = frida.get_usb_device().attach(appName)\nscript = session.create_script(js)\nscript.load()\n#session.detach()\n\n"
  },
  {
    "path": "src/main/java/.gradle/2.10/taskArtifacts/cache.properties",
    "content": "#Fri Mar 06 02:03:30 CET 2020\n"
  },
  {
    "path": "src/main/java/actions/Comparer.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage actions;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport base.CopyUtil;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport commandExec.Commando;\nimport db.DatabaseTester;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class Comparer {\n\n\tprivate Commando commando;\n\tprivate FileUtil fileTrans;\n\tprivate CopyUtil copyz;\n\tprivate String dataDirOld, extDirOld, storageOld;\n\t\n\tpublic Comparer() {\n\t\t\n\t\tthis.copyz = new CopyUtil();\n\t\tthis.commando = new Commando();\n\t\tthis.fileTrans = new FileUtil();\t\t\n\t}\n\t/*\n\tpublic void diffOld(boolean detailed) {\n\t\tthis.clearDataDirs();\n\t\t\n\t\tthis.copyz.copyDataDir(TicklerVars.appTickDir+\"DataDirOld/\");\n\t\tSystem.out.println(\"\\n\\n>>>>>>>>>>>>>>>> Go crazy then press Enter to compare data directories....\\n\");\n\t\tOtherUtil.pressAnyKeySilent();\n\t\t//Copy both local and external storage\n\t\tcopyz.copyDataDir();\n//\t\tcopyz.copyStorage();\n\t\t\n\t\tString command = \"diff -rq \"+ TicklerVars.appTickDir+\"DataDirOld/ \"+TicklerVars.appTickDir+\"DataDir/\";\n\t\tString output = this.commando.executeCommand(command);\n\t\tSystem.out.println(output.replace(TicklerVars.appTickDir, \"[Tickler_App_Dir]/\"));\n\t\tif (output.isEmpty())\n\t\t\tSystem.out.println(\"No change in the app's Data directory\");\n\t\telse\n\t\t\tSystem.out.println(\"\\n...Where [Tickler_App_Dir] is \"+TicklerVars.appTickDir);\n\t\t\n\t\tif (detailed){\n\t\t\tthis.diffDetailed(output);\n\t\t}\n\t}\t\n\t*/\n\tpublic void diff(boolean detailed) {\n\t\t\n\t\t//Init here\n\t\tthis.storageOld = TicklerVars.transferDir+TicklerConst.DIFF_OLD_STORAGE;\n\t\tthis.dataDirOld = this.storageOld+TicklerConst.DATA_DIR_NAME;\n\t\tthis.extDirOld = this.storageOld+TicklerConst.EXTERNAL_STORAGE_Dir;\n\t\t\n\t\tString old_storage=TicklerConst.DIFF_OLD_STORAGE.substring(0, TicklerConst.DIFF_OLD_STORAGE.length()-1);\n\t\t\n\t\tthis.clearDataDirs();\n//\t\tthis.copyz.copyStorage(TicklerConst.DIFF_OLD_STORAGE);\n\t\tthis.copyz.copyStorage(old_storage);\n\t\t\n\t\tSystem.out.println(\"\\n\\n>>>>>>>>>>>>>>>> Go crazy then press Enter to compare data directories....\\n\");\n\t\tOtherUtil.pressAnyKeySilent();\n\t\t\n\t\tcopyz.copyStorage();\n\t\t\n\t\tString command = \"diff -rq \"+ this.dataDirOld +\" \"+TicklerVars.dataDir;\n\t\tString output = this.commando.executeCommand(command);\n\t\tSystem.out.println(output.replace(TicklerVars.appTickDir, \"[Tickler_App_Dir]/\"));\n\t\t\n\t\t// Quick and Dirty: Repeated for external storage \n\t\tcommand = \"diff -rq \"+ this.extDirOld +\" \"+TicklerVars.extDataDir;\n\t\toutput = this.commando.executeCommand(command);\n\t\tSystem.out.println(output.replace(TicklerVars.appTickDir, \"[Tickler_App_Dir]/\"));\n\t\t\n\t\tif (output.isEmpty())\n\t\t\tSystem.out.println(\"No change in the app's Data directory\");\n\t\telse\n\t\t\tSystem.out.println(\"\\n...Where [Tickler_App_Dir] is \"+TicklerVars.appTickDir);\n\t\t\n\t\tif (detailed){\n\t\t\tthis.diffDetailed(output);\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * A detailed output of changed files:\n\t * 1) text files: classic diff output\n\t * 2) DB files: dump and show the difference\n\t * @param output: output of undetailed diff \n\t */\n\t\n\tpublic void diffDetailed(String output){\n\t\tSystem.out.println(\"\\nDetailed Comparison result:\\n===========================\\n\");\n\t\t\n\t\t//1- get file names\n\t\tArrayList<String> diffFileNames = this.getDiffFileNames(output);\n\t\tif (!diffFileNames.isEmpty()){\n\t\t\t//2- diff files \n\t\t\tfor (String s:diffFileNames)\n\t\t\t\tcheckFileTypeAndCompare(s);\n\t\t\t}\n\t}\n\t\n\tprivate ArrayList<String> getDiffFileNames(String output){\n\t\tArrayList<String> filePathsArray = new ArrayList<String>();\n\t\t\n\t\tString[] opArray=output.split(\"\\n\");\n\t\tif (opArray.length>0 && opArray[0]!=\"\"){\n\t\t\tfor (String s:opArray)\n\t\t\t{\n\t\t\t\tMatcher m = Pattern.compile(\"differ$\").matcher(s);\n\t\t\t\tif (m.find()){\n\t\t\t\t\tString filePath = s.split(\" \")[1];\n\t\t\t\t\tfilePathsArray.add(filePath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn filePathsArray;\n\t}\n\t\n\tprivate void checkFileTypeAndCompare(String fileName){\n\t\tFile f = new File(fileName);\n\t\tString output,fileTypeCommand;\n\t\tfileTypeCommand = this.fileTrans.fileType(f);\n\t\tDatabaseTester dbT = new DatabaseTester();\n\t\t///File is a text file or human readable\n\t\tif (fileTypeCommand.contains(\"text\")){\n\t\t\t//File is a text file\n\t\t\tthis.compareTextfiles(fileName);\n\t\t}\n\t\t//If the file is a database file\n\t\telse if (dbT.isFileDB(f)){\n\t\t\tthis.compareDB(f);\n\t\t}\n\t}\n\tprivate void compareTextfiles(String fileName){\n\t\tString command,output,fName;\n\t\t\n\t\tfName=this.fileTrans.getFileNameFromPath(fileName);\n\t\tSystem.out.println(\"---------- \"+fName+\" ----------\");\n\t\tcommand=\"diff \"+fileName+\" \"+fileName.replace(\"DataDirOld\", \"DataDir\");\n\t\toutput=this.commando.executeCommand(command);\n\t\tSystem.out.println(output+\"\\n\");\n\t\t\n\t}\n\t\n\t/**\n\t * Comapres between 2 DBs by string diff their dumps \n\t * @param f\n\t */\n\tprivate void compareDB(File f){\n\t\tDatabaseTester dbT = new DatabaseTester();\n\t\tString filePath=f.getAbsolutePath();\n\t\tString oldDump = dbT.dumpDBToFile(filePath,null);\n\t\tString newDump = dbT.dumpDBToFile(filePath.replace(\"DataDirOld\", \"DataDir\"),null);\n\t\t\n\t\tSystem.out.println(\"------- Database File: \"+f.getName()+\" -------\");\n\t\t\n\t\tString command = \"diff \"+ oldDump+\" \"+newDump;\n\t\tString output = this.commando.executeCommand(command);\n\t\tSystem.out.println(output);\n\t\t\n\t\tthis.fileTrans.deleteFromHost(oldDump);\n\t\tthis.fileTrans.deleteFromHost(newDump);\n\t}\n\t\n\t/**\n\t * Clears Datadir, ExtDataDir and their old versions before diff\n\t */\n\tprivate void clearDataDirs(){\n//\t\tthis.fileTrans.warnOverrideAndDelete(TicklerVars.appTickDir+\"DataDirOld/\");\n//\t\tthis.fileTrans.warnOverrideAndDelete(TicklerVars.dataDir);\n\t\t\n\t\tString[] directories = {TicklerVars.dataDir,TicklerVars.extDataDir,this.dataDirOld,this.extDirOld};\n\t\tfor (String dir: directories) {\n\t\t\tthis.fileTrans.warnOverrideAndDelete(dir);\n\t\t}\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/actions/Comparer_Old.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage actions;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport base.CopyUtil;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport commandExec.Commando;\nimport db.DatabaseTester;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class Comparer_Old {\n\n\tprivate Commando commando;\n\tprivate FileUtil fileTrans;\n\tprivate CopyUtil copyz;\n\tprivate String dataDirOld, extDirOld, storageOld;\n\t\n\tpublic Comparer_Old() {\n\t\t\n\t\tthis.copyz = new CopyUtil();\n\t\tthis.commando = new Commando();\n\t\tthis.fileTrans = new FileUtil();\n\t\tthis.dataDirOld = TicklerVars.appTickDir+TicklerConst.DATA_DIR_OLD;\n\t\tthis.extDirOld = TicklerVars.appTickDir+TicklerConst.EXT_DIR_OLD;\n\t\tthis.storageOld = TicklerVars.appTickDir+\"Storage_old/\";\n\t}\n\t\n\tpublic void diffOld(boolean detailed) {\n\t\tthis.clearDataDirs();\n\t\t\n\t\tthis.copyz.copyDataDir(TicklerVars.appTickDir+\"DataDirOld/\");\n\t\tSystem.out.println(\"\\n\\n>>>>>>>>>>>>>>>> Go crazy then press Enter to compare data directories....\\n\");\n\t\tOtherUtil.pressAnyKeySilent();\n\t\t//Copy both local and external storage\n\t\tcopyz.copyDataDir();\n//\t\tcopyz.copyStorage();\n\t\t\n\t\tString command = \"diff -rq \"+ TicklerVars.appTickDir+\"DataDirOld/ \"+TicklerVars.appTickDir+\"DataDir/\";\n\t\tString output = this.commando.executeCommand(command);\n\t\tSystem.out.println(output.replace(TicklerVars.appTickDir, \"[Tickler_App_Dir]/\"));\n\t\tif (output.isEmpty())\n\t\t\tSystem.out.println(\"No change in the app's Data directory\");\n\t\telse\n\t\t\tSystem.out.println(\"\\n...Where [Tickler_App_Dir] is \"+TicklerVars.appTickDir);\n\t\t\n\t\tif (detailed){\n\t\t\tthis.diffDetailed(output);\n\t\t}\n\t}\t\n\t\n\tpublic void diff(boolean detailed) {\n\t\tthis.clearDataDirs();\n\t\tthis.copyz.copyStorage(this.storageOld);\n\t\t\n\t\tSystem.out.println(\"\\n\\n>>>>>>>>>>>>>>>> Go crazy then press Enter to compare data directories....\\n\");\n\t\tOtherUtil.pressAnyKeySilent();\n\t\t\n\t\tcopyz.copyStorage();\n\t\t\n\t\tString command = \"diff -rq \"+ this.dataDirOld +\" \"+TicklerVars.dataDir;\n\t\t\n\t\t\n\t}\n\t\n\t/**\n\t * A detailed output of changed files:\n\t * 1) text files: classic diff output\n\t * 2) DB files: query and show the difference\n\t * @param output: output of undetailed diff \n\t */\n\t\n\tpublic void diffDetailed(String output){\n\t\tSystem.out.println(\"\\nDetailed Comparison result:\\n===========================\\n\");\n\t\t\n\t\t//1- get file names\n\t\tArrayList<String> diffFileNames = this.getDiffFileNames(output);\n\t\tif (!diffFileNames.isEmpty()){\n\t\t\t//2- diff files \n\t\t\tfor (String s:diffFileNames)\n\t\t\t\tcheckFileTypeAndCompare(s);\n\t\t\t}\n\t}\n\t\n\tprivate ArrayList<String> getDiffFileNames(String output){\n\t\tArrayList<String> filePathsArray = new ArrayList<String>();\n\t\t\n\t\tString[] opArray=output.split(\"\\n\");\n\t\tif (opArray.length>0 && opArray[0]!=\"\"){\n\t\t\tfor (String s:opArray)\n\t\t\t{\n\t\t\t\tMatcher m = Pattern.compile(\"differ$\").matcher(s);\n\t\t\t\tif (m.find()){\n\t\t\t\t\tString filePath = s.split(\" \")[1];\n\t\t\t\t\tfilePathsArray.add(filePath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn filePathsArray;\n\t}\n\t\n\tprivate void checkFileTypeAndCompare(String fileName){\n\t\tFile f = new File(fileName);\n\t\tString output,fileTypeCommand;\n\t\tfileTypeCommand = this.fileTrans.fileType(f);\n\t\tDatabaseTester dbT = new DatabaseTester();\n\t\t///File is a text file or human readable\n\t\tif (fileTypeCommand.contains(\"text\")){\n\t\t\t//File is a text file\n\t\t\tthis.compareTextfiles(fileName);\n\t\t}\n\t\t//If the file is a database file\n\t\telse if (dbT.isFileDB(f)){\n\t\t\tthis.compareDB(f);\n\t\t}\n\t}\n\tprivate void compareTextfiles(String fileName){\n\t\tString command,output,fName;\n\t\t\n\t\tfName=this.fileTrans.getFileNameFromPath(fileName);\n\t\tSystem.out.println(\"---------- \"+fName+\" ----------\");\n\t\tcommand=\"diff \"+fileName+\" \"+fileName.replace(\"DataDirOld\", \"DataDir\");\n\t\toutput=this.commando.executeCommand(command);\n\t\tSystem.out.println(output+\"\\n\");\n\t\t\n\t}\n\t\n\t/**\n\t * Comapres between 2 DBs by string diff their dumps \n\t * @param f\n\t */\n\tprivate void compareDB(File f){\n\t\tDatabaseTester dbT = new DatabaseTester();\n\t\tString filePath=f.getAbsolutePath();\n\t\tString oldDump = dbT.dumpDBToFile(filePath,null);\n\t\tString newDump = dbT.dumpDBToFile(filePath.replace(\"DataDirOld\", \"DataDir\"),null);\n\t\t\n\t\tSystem.out.println(\"------- Database File: \"+f.getName()+\" -------\");\n\t\t\n\t\tString command = \"diff \"+ oldDump+\" \"+newDump;\n\t\tString output = this.commando.executeCommand(command);\n\t\tSystem.out.println(output);\n\t\t\n\t\tthis.fileTrans.deleteFromHost(oldDump);\n\t\tthis.fileTrans.deleteFromHost(newDump);\n\t}\n\t\n\t/**\n\t * Clears Datadir, ExtDataDir and their old versions before diff\n\t */\n\tprivate void clearDataDirs(){\n//\t\tthis.fileTrans.warnOverrideAndDelete(TicklerVars.appTickDir+\"DataDirOld/\");\n//\t\tthis.fileTrans.warnOverrideAndDelete(TicklerVars.dataDir);\n\t\t\n\t\tString[] directories = {TicklerVars.dataDir,TicklerVars.extDataDir,this.dataDirOld,this.extDirOld};\n\t\tfor (String dir: directories) {\n\t\t\tthis.fileTrans.warnOverrideAndDelete(dir);\n\t\t}\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/actions/Searcher.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage actions;\n\nimport java.util.ArrayList;\nimport java.io.File;\nimport java.util.AbstractMap.SimpleEntry;\n\nimport base.Base64Util;\nimport base.CopyUtil;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport db.DatabaseTester;\nimport info.InfoGathering;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class Searcher {\n\t\n\tprivate SearchUtil searchUtil;\n\tprivate String codeLoc;\n\tprivate CopyUtil copyUtil;\n\tprivate FileUtil fileUtil;\n\t\n\tpublic Searcher() {\n\t\tthis.searchUtil = new SearchUtil();\n\t\tthis.codeLoc = TicklerVars.jClassDir;\n\t\tthis.copyUtil = new CopyUtil();\n\t\tthis.fileUtil = new FileUtil();\n\t}\n\n\t\n\t/**\n\t * Searches for a key in decompiled java code and in strings.xml\n\t * @param key\n\t */\n\tpublic void sC(String key,boolean all){\n\t\t\n\t\tArrayList<SimpleEntry> hits = this.searchInCodeWithOption(key, all);\n\t\tOtherUtil.printSimpleEntryArray(hits, this.codeLoc, \"[Java_Code_Dir]\");\n\t\t\n\t\t//Search in Manifest\n\t\tArrayList<SimpleEntry> result = new ArrayList<>();\n\t\t\n\t\tresult = this.searchUtil.search4KeyInDirFName(TicklerVars.tickManifestFile, key);\n\t\tif (!result.isEmpty()) {\n\t\t\tOutBut.printH2(\"Search results in Manifest File\");\n\t\t\tOtherUtil.printSimpleEntryArray(result, TicklerVars.tickManifestFile, \"[res]\");\n\t\t}\n\t\t\n\t\t// Search for a key in res directory and print the results\n\t\tthis.searchInRes(key);\n\t\t\n\t\t\n\t}\n\t\t\n\t\tprivate ArrayList<String> sCInFile(File file, String fileName, String key){\n\t\t\tArrayList<String> result = new ArrayList<>();\n\t\t\tif (file.exists()){\n\t\t\t\tOutBut.printH2(\"Searching for \"+key+\" in \"+fileName);\n\t\t\t\tresult = this.searchUtil.findInFile(file, key);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\t\n\t\t/**\n\t\t * Search for a key in the res directory and print the results\n\t\t * @param key\n\t\t * @return\n\t\t */\n\t\tprivate void searchInRes(String key){\n\t\t\tArrayList<SimpleEntry> result = new ArrayList<>();\n\t\t\tString resDir= TicklerVars.extractedDir+\"res/\";\n\t\t\t\n\t\t\tresult = this.searchUtil.search4KeyInDirFName(resDir, key);\n\t\t\tif (!result.isEmpty()) {\n\t\t\t\tOutBut.printH2(\"Search results in res directory\");\n\t\t\t\tOtherUtil.printSimpleEntryArray(result, resDir, \"[res]\");\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t\t/**\n\t\t * Search fo rkey in strings and arrays.xml but I don't all it as it is replaced by searchinRes()\n\t\t * @param key\n\t\t */\n\t\tprivate void searchInStringsArrays(String key) {\n\t\t\tFile stringsXml = new File(TicklerVars.extractedDir+\"res/values/strings.xml\");\n\t\t\tFile arraysXml = new File(TicklerVars.extractedDir+\"res/values/arrays.xml\");\n\t\t\t\n\t\t\tArrayList<String> hits2 = this.sCInFile(stringsXml, \"strings.xml\", key);\n\t\t\thits2.addAll(this.sCInFile(arraysXml, \"arrays.xml\", key));\n\t\t\t\n\t\t\t\n\t\t\tif (!hits2.isEmpty())\n\t\t\t\tfor (String s: hits2)\n\t\t\t\t\tOutBut.printNormal(\" \"+s+\"\\n\");\n\t\t\t\n\t\t}\n\t\n\t/**\n\t * Searches in source code in a custom location.\n\t * @param key\n\t * @param loc\n\t */\n\tpublic void scCustomCodeLoc(String key, String codeRoot){\n\t\tif (codeRoot != null){\n\t\t\tString codeRootNotHome=codeRoot.replace(\"~\", System.getProperty(\"user.home\"));\n\t\t\tFile cR = new File(codeRootNotHome);\n\t\t\tif (cR.exists()){\n\t\t\t\tthis.codeLoc = codeRootNotHome;\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\telse\n\t\t\t{\n\t\t\t\tOutBut.printError(\"The code location you entered \"+codeRoot+\" does not exist\");\n\t\t\t\tOutBut.printStep(\"Using decompiled Java code from the APK....\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.sC(key,false);\n\t}\n\t\n\t/**\n\t * Searches in code based on option: sc_all --> all = true, sc --> all=false\n\t * @param key\n\t * @param all\n\t * @return\n\t */\n\tprivate ArrayList<SimpleEntry> searchInCodeWithOption(String key, boolean all){\n\t\tArrayList<SimpleEntry> hits = new ArrayList<>();\n\t\t\n\t\tif (all){\n\t\t\tOutBut.printH2(\"Searching for \"+key+\" in Decompiled Java Code\");\n\t\t\thits = this.searchUtil.search4KeyInDirFName(this.codeLoc, key) ;\n\t\t}\n\t\telse {\n\t\t\tOutBut.printH2(\"Searching for \"+key+\" in Decompiled Code of the app\");\n\t\t\thits = this.searchUtil.searchForKeyInJava(key, this.codeLoc);\n\t\t}\n\t\t\n\t\treturn hits;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Search for a key in the Data directory of an App, including files and unencrypted databases.\n\t * Also search for the key in clear text and in Base64 format\n\t * Also check in External Dir if exists\n\t * @param key\n\t */\n\tpublic void searchForKeyInDataDir(String key, boolean isCopy){\n\t\t\n\t\tif (isCopy){\n\t\t\tOutBut.printStep(\"Updating Data Directory\");\n\t\t\tCopyUtil copyz = new CopyUtil();\n\t\t\tcopyz.copyDataDir();\n\t\t}\n\t\telse {\n\t\t\tOutBut.printWarning(\"Data storage directory is not updated\");\n\t\t}\n\t\t//Search in files\n\t\tOutBut.printH2(\"Searching Files in Data Directory of the app\");\n\t\tArrayList<SimpleEntry> hits = this.searchUtil.search4KeyInDirFName(TicklerVars.dataDir, key);\n\t\t\n\t\tOtherUtil.printSimpleEntryArray(hits, TicklerVars.dataDir, \"[Data_Dir]\");\n\t\t\n\t\t// Search Base64\n\t\tthis.base64Search(key);\n\t\t\n\t\t//Search in DB\n\t\tOutBut.printH2(\"Searching Files in the app's unencrypted databases\");\n\t\tDatabaseTester db = new DatabaseTester();\n\t\tdb.searchForKeyInDb(key);\n\n\t\t//search in external memory\n\t\tthis.searchExternalStorage(key);\n\t}\n\t\n\n\t\n\tprivate void base64Search(String key){\n\t\tBase64Util b64 = new Base64Util();\n\t\tArrayList<String> base64Hits = b64.searchB64DataDir(key);\n\t\t\n\t\tif (!base64Hits.isEmpty()){\n\t\t\tOutBut.printH2(\"The key is base64 encrypted in the following file(s)\");\n\t\t\tfor (String s: base64Hits){\n\t\t\t\tString filePath = s.replaceAll(this.codeLoc, \"[Data_Dir]\"); \n\t\t\t\tSystem.out.println(\"#FileName: \"+filePath);\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Copy external storage into transfers file\n\t * Then saerch in it\n\t * Copying code moved to CopyUtil and a new method is created only to search there\n\t * @param key\n\t */\n\t/*\n\tprivate void searchExternalStorage(String key) {\n\t\tInfoGathering info = new InfoGathering();\n\t\tFileUtil fU = new FileUtil();\n\t\tString extDir = info.getSdcardDirectory().replaceAll(\"\\\\n\", \"\");\n\t\tString destExtDir=TicklerVars.transferDir+TicklerConst.COPIED_EXTERNAL_STORAGE_NAME;\n\t\tif (!extDir.isEmpty()){\n\t\t\tOutBut.printH2(\"Searching the app's external memory\");\n\t\t\tfU.copyDirToHost(extDir, destExtDir,true);\n\t\t\tSystem.out.println(\"\");\n\t\t\tOutBut.printStep(\"Copying External Storage Directory: \"+extDir+\"\\n\");\n\t\t\tArrayList<SimpleEntry> hits = this.searchUtil.search4KeyInDirFName(destExtDir, key);\n\t\t\tOtherUtil.printSimpleEntryArray(hits, extDir, \"[External_Dir]\");\n\t\t}\n\t}*/\n\t\n\t/**\n\t * Searching for a key in External Directory\n\t * @param key\n\t */\n\tprivate void searchExternalStorage(String key) {\n\t\t//OutBut.printStep(\"Updating External Storage Directory\\n\");\n\t\tif ( fileUtil.isExistOnDevice(TicklerVars.extDataDir)) {\n\t\t\tcopyUtil.copyExtDir(TicklerVars.extDataDir);\n\t\t\tArrayList<SimpleEntry> hits = this.searchUtil.search4KeyInDirFName(TicklerVars.extDataDir, key);\n\t\t\tOtherUtil.printSimpleEntryArray(hits, TicklerVars.extDataDir, \"[External_Dir]\");\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/actions/Snapshots.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage actions;\n\nimport java.io.File;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class Snapshots {\n\t\n\tprivate Commando commando;\n\tprivate FileUtil fileTrans;\n\t\n\tpublic Snapshots() {\n\t\t\n\t\tthis.commando = new Commando();\n\t\tthis.fileTrans = new FileUtil();\n\t}\n\n\tpublic void takeSnapshot(){\n\t\tString timestamp = new SimpleDateFormat(\"dd.MM.yy_HH.mm.ss\").format(new Date());\n\t\tString imgName = TicklerVars.pkgName+\"_\"+timestamp+\".png\";\n\t\tString path=TicklerVars.sdCardPath+imgName;\n\t\t\n\t\t//In case of no package\n\t\tthis.fileTrans.createDirOnDevice(TicklerVars.sdCardPath);\n\t\t\n\t\tthis.executeSnapshot(path);\n\t\t\n\t\tString imgDir=TicklerVars.imageDir;\n\t\tthis.fileTrans.createDirOnHost(imgDir);\n\t\tthis.fileTrans.pullFromSDcard(path, imgDir);\n\t\t\n\t\tif (new File(TicklerVars.imageDir+imgName).exists())\n\t\t\tOutBut.printStep(\"Screenshot taken succesfully and saved at \"+TicklerVars.imageDir+imgName);\n\t\t\n\t}\n\t\n\tpublic void executeSnapshot(String path) {\n\t\tString command = \"screencap -p \"+path;\n\t\tthis.commando.execADB(command);\n\t}\n\t\n\tpublic void getBackGroundSnapshots(){\n\t\t//quick and dirty: try both locations\n//\t\tString path = \"/data/system/recent_images\";\n\t\tString[] paths = {\"/data/system_ce/0/recent_images\",\"/data/system/recent_images\", \"/data/system_ce/0/snapshots/\" };\n\t\tthis.fileTrans.createDirOnHost(TicklerVars.bgSnapshotsDir);\n\t\tOutBut.printH1(\"Collecting stored Background screenshots\");\n\t\tOutBut.printH2(\"Screenshots are stored in only one of the following location. So ignore \\\"Directory does not exist\\\" errors if 1 location does not report any error\");\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"Copying Background snapshots to host...\");\n\t\tfor (String path : paths)\n\t\t\tthis.fileTrans.copyDirToHost(path, TicklerVars.bgSnapshotsDir,false);\n\t\t\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/apk/ApkSigner.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage apk;\n\nimport java.io.File;\n\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\n/**\n * Signs an APK if Jarsigner exists on the device\n * @author aabolhadid\n *\n */\npublic class ApkSigner {\n\n\tprivate boolean checkJarsigner(){\n\t\t//check if jarsigner exists\n\t\tCommando commando = new Commando();\n\t\tString cmd = \"jarsigner -h\";\n\t\tint result = commando.executeProcessListPrintOP(cmd, false);\n\t\tif (result == 0)\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\tprivate boolean isKeyStoreExist(){\n\t\tFile keystore = new File(TicklerVars.keyStore);\n\t\treturn keystore.exists();\n\t}\n\t\n\t\n\tpublic boolean signApk(String apkPath){\n\t\t\n\t\tboolean ok = false;\n\t\tif (!this.checkJarsigner()){\n\t\t\tOutBut.printWarning(\"Cannot sign the new apk because jarsigner is not found on the host\");\n\t\t\tOutBut.printNormal(\"\\nThe debuggable apk needs to be signed, in order to be installed on the device.\\njarsigner can be installed by installing Java JDK\\n\");\n\t\t\t\n\t\t}\n\t\t\t//jarsigner exists\n\t\telse if (!this.isKeyStoreExist()){\n\t\t\tOutBut.printError(\"Keystore needed to sign the new apk is not found at \"+TicklerVars.keyStore);\n\t\t}\n\t\t\t\n\t\telse{\n\t\t\tOutBut.printStep(\"Signing the app using Tickler keystore\");\n\t\t\tString cmd = \"jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore \"+TicklerVars.keyStore+\" -storepass itsalright \"+apkPath+\" Tickler\";\n\t\t\tCommando commando = new Commando();\n\t\t\tint result = commando.executeProcessListPrintOP(cmd, true);\n\t\t\tif (result == 0)\n\t\t\t\tok = true;\n\t\t}\n\t\t\n\t\treturn ok;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/apk/ApkToolClass.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\n\nimport org.apache.commons.io.FileUtils;\n\nimport base.FileUtil;\nimport brut.androlib.Androlib;\nimport brut.androlib.ApkDecoder;\nimport brut.androlib.ApkOptions;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerVars;\n\n/**\n * Responsible for APKtool actions\n * @author aabolhadid\n *\n */\npublic class ApkToolClass {\n\n\tString debuggableApk;\n\tpublic ApkToolClass(){\n\t\tthis.debuggableApk = TicklerVars.appTickDir+\"debuggable.apk\";\n\t}\n\t\n\t/**\n\t * APK tool decompiles the apk into Manifest, res dir and Smali files,\n\t * @throws TNotFoundEx if apktool fails to get the manifest file\n\t * @param apkPath\n\t */\n\tpublic void apkToolDecode(String apkPath) throws TNotFoundEx{\n\t\tFileUtil fileT = new FileUtil(); \n\t\tbrut.androlib.ApkDecoder dec = new ApkDecoder();\n\t\tFile apkPathFile = new File(apkPath);\n\n\t\tdec.setApkFile(apkPathFile);\n\t\tthis.deleteExistingDecodedDir();\n\t\t\n\t\ttry {\n\t\t\tFile file = new File(\"/dev/null\");\n\t\t\tPrintStream ps = new PrintStream(new FileOutputStream(file));\n\t\t\tSystem.setErr(ps);\n\t\t\tdec.setOutDir(new File (TicklerVars.extractedDir));\n\t\t\tdec.decode();\n\t\t\tSystem.setErr(System.err);\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tfileT.copyOnHost(TicklerVars.extractedDir+\"AndroidManifest.xml\", TicklerVars.tickManifestFile,true);\n\t\t}\n\t\tcatch(Exception e){\n\t\t\tOutBut.printError(\"Decompilation failed and Manifest cannot be obtained\");\n\t\t\tTNotFoundEx eNotFound = new TNotFoundEx(\"Decompilation failed and Manifest cannot be obtained\");\n\t\t\tthrow eNotFound;\n\t\t}\n\t}\n\t\n\t/**\n\t * Compile a customized app to an apk\n\t * @param dirPath the directory of the modififed app\n\t * @param apkPath output apk\n\t */\n\tpublic void apkToolCompile(String dirPath, String apkPath){\n\t\tString tempApktoolLog = TicklerVars.logDir+\"debuggableCompile.log\";\n\t\tApkOptions apkOptions = new ApkOptions();\n\t\t\n\t\ttry{\n\t\t\tFile file = new File(tempApktoolLog);\n\t\t\tOutBut.printH3(\"APKTool output:\");\n\t\t\tnew Androlib(apkOptions).build(new File(dirPath), new File(apkPath));\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\tprivate void deleteExistingDecodedDir(){\n\t\tFile decodedDir = new File (TicklerVars.extractedDir);\n\t\tif (decodedDir.exists()){\n\t\t\ttry{\n\t\t\t\tFileUtils.deleteDirectory(decodedDir);\n\t\t\t\tSystem.out.println(\"Existing SMALI directory will be deleted....\");\n\t\t\t}\n\t\t\tcatch(IOException e){\n\t\t\t\tSystem.out.println(\"Cannot delete old extracted directory \"+decodedDir.getAbsolutePath()+\"\\nPlease delete it manually and repeat\");;\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/main/java/apk/ApkToolDude.java",
    "content": "package apk;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.PrintStream;\n\nimport base.FileUtil;\nimport brut.androlib.Androlib;\nimport brut.androlib.ApkOptions;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerVars;\n\n// Replacing ApkToolClass in this version to run apktool.jar ... rewritten in v3\npublic class ApkToolDude {\n\t\n\tString debuggableApk;\n\tpublic ApkToolDude(){\n\t\tthis.debuggableApk = TicklerVars.appTickDir+\"debuggable.apk\";\n\t}\n\t\n\t/**\n\t * Normal apkdecode as pervious versions... decompiling resources\n\t * @param apkPath\n\t * @throws TNotFoundEx\n\t */\n\tpublic void apkToolDecode(String apkPath) throws TNotFoundEx {\n\t\tString args = \" d -o \"+TicklerVars.extractedDir+\" \"+apkPath;\n\t\tthis.apkToolDecodeGeneral(apkPath, args);\n\t\t\n\t}\n\t\n\tprivate void apkToolDecodeGeneral(String apkPath, String args) throws TNotFoundEx{\n\t\tFileUtil fileT = new FileUtil(); \n\t\tFile apkPathFile = new File(apkPath);\n\t\t\n\n\t\ttry {\n\t\t\tFile file = new File(\"/dev/null\");\n\t\t\tPrintStream ps = new PrintStream(new FileOutputStream(file));\n\t\t\tSystem.setErr(ps);\n\t\t\t\n\t\t\tthis.executeApktoolCommand(args);\n\t\t\t\n\t\t\tSystem.setErr(System.err);\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tfileT.copyOnHost(TicklerVars.extractedDir+\"AndroidManifest.xml\", TicklerVars.tickManifestFile,true);\n\t\t}\n\t\tcatch(Exception e){\n\t\t\tOutBut.printError(\"Decompilation failed and Manifest cannot be obtained\");\n\t\t\tTNotFoundEx eNotFound = new TNotFoundEx(\"Decompilation failed and Manifest cannot be obtained\");\n\t\t\tthrow eNotFound;\n\t\t}\n\t}\n\t\n\t\n\tpublic void apkToolCompile(String dirPath, String apkPath){\n\t\tString tempApktoolLog = TicklerVars.logDir+\"debuggableCompile.log\";\n\t\tString args = \" b \"+dirPath+\" -o \"+apkPath;\n//\t\tApkOptions apkOptions = new ApkOptions();\n\t\t\n\t\ttry{\n\t\t\tFile file = new File(tempApktoolLog);\n\t\t\tOutBut.printH3(\"APKTool output:\");\n\t\t\tthis.executeApktoolCommand(args);\n//\t\t\tnew Androlib(apkOptions).build(new File(dirPath), new File(apkPath));\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Wrapper of apktool.jar\n\t * @param args\n\t */\n\tprivate void executeApktoolCommand(String args) {\n\t\tCommando command = new Commando();\n\t\tString cmd = \"java -jar \"+TicklerVars.apktoolPath + args;\n\t\t\n\t\tcommand.executeProcessString(cmd);\n\t}\n}\n"
  },
  {
    "path": "src/main/java/apk/AppBroker.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.apache.commons.io.FileUtils;\n\nimport base.OtherUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport components.Activity;\nimport components.Manifest;\nimport initialization.TicklerVars;\n\n/**\n * Starts, stops, (un)install apps, backs up data dir before installation of an enhanced app\n * @author aabolhadid\n *\n */\npublic class AppBroker {\n\t\n\tprivate String pkgName,outputPath,sdCardPath;\n\tprivate Commando commando;\n\t\n\t\n\t/**\n\t * @param laucher\n\t * @param pkgName\n\t */\n\tpublic AppBroker(Activity laucher,String pkgName) {\n\t\tsuper();\n\t\tthis.pkgName = pkgName;\n\t\tthis.commando = new Commando();\n\t\tthis.sdCardPath=TicklerVars.sdCardPath;\n\n\t}\n\t\n\tpublic AppBroker(String pkgName) {\n\t\tsuper();\n\t\tthis.pkgName = pkgName;\n\t\tthis.commando = new Commando();\n\t\t\n\t\t\n\t}\n\n\t\n\tpublic String forceStopApp() {\n\t\t\n\t\treturn \"am force-stop \"+this.getPkgName();\n\t}\n\t\n\t///////////////////////// Install and Uninstall\n\t\n\t\n\tpublic void installApk(String apk){\n\t\tString command = \"adb install \"+apk;\n\t\tthis.commando.executeProcessListPrintOP(command, true);\n\t}\n\t\n\tpublic void uninstallPackage(String pkgName){\n\t\tString command = \"pm uninstall \"+pkgName;\n\t\tthis.commando.execRootPrintOP(command);\n\t}\n\t\n\t//////////////////////Backup Data Directory \n\t\n\tpublic void backupDataDir(String bkpLoc){\n\t\t\n\t\tFile destLoc;\n\t\tFile appDir = new File(TicklerVars.appTickDir);\n\n\t\tif (appDir.exists())\n\t\t{\t\n\t\t\tif (bkpLoc == null){\n\t\t\t\tString timestamp = new SimpleDateFormat(\"dd-MM-yy_HH.mm.ss\").format(new Date());\n\t\t\t\tdestLoc=new File(TicklerVars.ticklerDir+TicklerVars.pkgName+\"_bkp_\"+timestamp);\n\t\t\t}\n\t\t\telse\n\t\t\t\tdestLoc = new File(bkpLoc);\n\t\t\t\n\t\t\ttry{\n\t\t\t\t\n//\t\t\t\tFileUtils.moveDirectory(appDir, destLoc);\n\t\t\t\tFiles.move(appDir.toPath(), destLoc.toPath(), StandardCopyOption.REPLACE_EXISTING);\n\t\t\t\t\n//\t\t\t\tFileUtils.moveDirectoryToDirectory(destLoc, appDir, true);\n\t\t\t\t\n\t\t\t}\n\t\t\tcatch(IOException e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate boolean isReinstallQuestion(){\n\t\tOutBut.printWarning(\"\\nDo you want to uninstall the original app and install the modified one?\");\n\t\tOutBut.printNormal(\"If yes, the following steps are executed:\");\n\t\tOutBut.printNormal(\"\\t1- Uninstall the original app\");\n\t\tOutBut.printNormal(\"\\t2- Backup Tickler working directory, if it exists \");\n\t\tOutBut.printNormal(\"\\t3- Install the modified app\");\n\t\tOutBut.printNormal(\"\\nIf agree, enter yes or y\");\n\t\t\n\t\tString choice = OtherUtil.pressAnyKeySilent();\n\t\tif (choice.toLowerCase().equals(\"yes\") || choice.toLowerCase().equals(\"y\"))\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * After creation of debuggable or MitM, the user can uninstall the original APK and install the modified one\n\t * @param apk\n\t */\n\tpublic void reinstall(String apk){\n\t\tif (this.isReinstallQuestion()){\n\t\t\tthis.uninstallPackage(TicklerVars.pkgName);\n\t\t\tthis.installApk(apk);\n\t\t\tthis.backupDataDir(null);\n\t\t}\n\t}\n\t\n\t////////////// Getters and Setters \n\n\tpublic String getPkgName() {\n\t\treturn pkgName;\n\t}\n\n\tpublic void setPkgName(String pkgName) {\n\t\tthis.pkgName = pkgName;\n\t}\n\n\tpublic String getOutputPath() {\n\t\treturn outputPath;\n\t}\n\n\tpublic void setOutputPath(String outputPath) {\n\t\tthis.outputPath = outputPath;\n\t}\n\n\tpublic String getSdCardPath() {\n\t\treturn sdCardPath;\n\t}\n\n\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/apk/Decompiler.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\n\nimport base.FileUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\n\npublic class Decompiler {\n\tprivate String jarLoc;\n\t\n\tprivate boolean checkD2jExists() {\n\t\tif (new File(TicklerVars.dex2jarPath).exists()){\n\t\t\treturn true;\n\t\t}\n\t\tSystem.out.println(\"!!!!!ERROR: The stand alone version does not support dex2jar\");\n\t\treturn false;\n\t\t\n\t}\n\t\n\tprivate File getApkFromTicklerDir(){\n\t\tFile apkFile;\n\t\tSearchUtil searcher = new SearchUtil();\n\t\tString[] keys ={\"base.apk\"};  \n\t\tList<File> apkList = searcher.search4FileInDir(TicklerVars.appTickDir, keys);\n\t\tapkFile = apkList.get(0);\n\t\tif (apkFile.getName().equals(\"debuggable.apk\"))\n\t\t\tapkFile = apkList.get(1);\n\t\t\n\t\treturn apkFile;\n\t}\n\n\tpublic void decompile(){\n\t\tthis.dex2jar();\n\t\tthis.jdCore();\n\t\t\n\t}\n\t\n\tpublic void dex2jar()\n\t{\n\t\t//If dex2jar scripts exist and executable\n\t\tif (this.checkD2jExists() && this.checkDex2JarExecutable()){\n\t\t\t\n\t\t\tFileUtil ft = new FileUtil();\n\t\t\tCommando command = new Commando();\n\t\t\tft.createDirOnHost(TicklerVars.dex2jarDir);\n\t\t\tthis.jarLoc = TicklerVars.dex2jarDir+\"app.jar\";\n\t\t\tString cmd = TicklerVars.dex2jarPath + \" \"+ this.getApkFromTicklerDir() +\" -o \"+TicklerVars.jClassDir+\".jar\";\n\t\t\tOutBut.printStep(\"Decompiling the app using Dex2Jar tool......\");\n\t\t\tcommand.executeProcessString(cmd);\n\t\t\t\n\t\t}\n\t}\n\t\n\t\n\tprivate void jdCore(){\n\t\ttry{\n\t\t\tOutBut.printStep(\"Obtaining Java code using JDCore tool. This might take some time ......\");\n//\t\t\tString cmd = \"java -jar /home/a7mad/tools/Android/Decompile/JD-core/jd-core-1.1.3.jar \"+TicklerVars.jClassDir+\".jar \"+TicklerVars.jClassDir;\n//\t\t\tCommando command = new Commando();\n//\t\t\tcommand.executeProcessListPrintOP(cmd,true);\n//\t\t\t\n//\t\t\tnew jd.core.Decompiler().decompile(TicklerVars.jClassDir+\".zip\", TicklerVars.jClassDir);\n\t\t\tnew jd.core.Decompiler().decompile(TicklerVars.jClassDir+\".jar\", TicklerVars.jClassDir);\n\n\t\t}\n\t\tcatch(Exception e){\n\t\t\t//e.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * If required dex2jar files are executable \n\t * @param path\n\t */\n\tprivate boolean checkDex2JarExecutable(){\n\t\tboolean isExec = true;\n\t\tFileUtil ft = new FileUtil();\n\t\tCommando command = new Commando();\n\t\tString d2jInvokeFile = TicklerVars.dex2jarPath.replace(\"d2j-dex2jar.sh\", \"d2j_invoke.sh\");\n\t\tString[] execs = {TicklerVars.dex2jarPath, d2jInvokeFile};\n\t\tfor (String exec : execs){\n\t\t\tif (!ft.isExecutable(exec)){\n\t\t\t\tisExec = false;\n\t\t\t\tOutBut.printError(\"Please change mode of \"+exec+\" to executable and rerun the command\" );\n\t\t\t}\n\t\t}\n\t\treturn isExec;\n\t}\n\t\n\t/**\n\t * return if dex2jar exists and executable\n\t * @return\n\t */\n\tpublic boolean isDex2Jar() {\n\t\treturn this.checkD2jExists() && this.checkDex2JarExecutable();\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/apk/newApks/CreateApk.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk.newApks;\n\nimport java.io.File;\n\nimport apk.ApkSigner;\nimport apk.ApkToolClass;\nimport apk.ApkToolDude;\nimport apk.AppBroker;\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerVars;\nimport initialization.TicklerConst;\n\n/**\n * Creates new APK versions of the original APK\n * MITM: a modification to network secrutiy configuration of the app in order to accept user added certificates to trust store\n * @author aabolhadid\n *\n */\npublic class CreateApk {\n\tprivate ApkToolDude apktool;\n\tprivate FileUtil ft;\n\tprivate ApkSigner signer;\n\tprivate String newAppDir,netSecConfFileName,netSecConfFilePath,apk;\n\tprivate boolean isMitm;\n\tprivate INewApk newApk;\n\t\n\tpublic CreateApk(int apkID){\n\t\t// Ahmad: replacing ApkToolClass\n\t\tthis.apktool = new ApkToolDude();\n\t\tthis.ft = new FileUtil(); \n\t\tthis.signer = new ApkSigner();\n\t\tthis.newAppDir = TicklerVars.appTickDir+TicklerConst.newAppTempDir;\n\t\tthis.netSecConfFileName = TicklerConst.mitmXmlName; \n\t\tthis.netSecConfFilePath = newAppDir+\"res/xml/\"+netSecConfFileName;\t\n\t\t\n\t\tthis.initNewApp(apkID);\n\t\t\n\t\t\n\t}\n\t\n\tprivate void initNewApp(int apkID){\n\t\t\n\t\tswitch(apkID){\n\t\tcase TicklerConst.debuggable:\n\t\t\tnewApk = new Debuggable();\n\t\t\tbreak;\n\t\t\t\n\t\tcase TicklerConst.mitm:\n\t\t\tnewApk = new NougatMitM();\n\t\t\tbreak;\n\t\t\t\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Create a new APK, debuggable or mitm compatible\n\t * @param isInstall whether to install the apk after creation \n\t */\n\tpublic void createNewApk(){\n\t\tboolean successfulSign;\n\t\ttry {\n\t\t\tOutBut.printWarning(\"Decompiling and Recompiling of the APK might have some errors, which might lead to incorrect behavior of the modified app\");\n\t\t\tthis.apk = this.newApk.getNewApkName();\n\t\t\t\n\t\t\tthis.ft.copyOnHost(TicklerVars.extractedDir, TicklerVars.newApkTempDir, true);\n\t\t\tthis.newApk.changeManifest();\n\t\t\t\n\t\t\tthis.apktool.apkToolCompile(this.newAppDir,this.apk);\n\t\t\tthis.afterCompilation(false);\n\t\t\tsuccessfulSign =this.signer.signApk(this.apk);\n\t\t\tif (successfulSign)\n\t\t\t\tthis.reinstallNewApk();\n\t\t}\n\t\tcatch(TNotFoundEx e){\n\t\t\tOutBut.printError(e.getMessage());\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic void createAnyApk(String decompiledDir, String name) {\n\t\t\n\t\tthis.apk = TicklerVars.appTickDir+name;\n\t\tOutBut.printStep(\"Creating a new APK at: \"+this.apk);\n\t\t\n\t\tthis.apktool.apkToolCompile(decompiledDir,this.apk);\n\t\tthis.afterCompilation(true);\n\t\tboolean successfulSign =this.signer.signApk(this.apk);\n\t\tif (successfulSign)\n\t\t\tthis.reinstallNewApk();\n\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param isCustom boolean if it's creating a custom APK (not dbg nor mitm) then don't delete the source directory\n\t */\n\tprivate void afterCompilation(boolean isCustom) {\n\t\tif (!isCustom)\n\t\t\tthis.ft.deleteFromHost(TicklerVars.newApkTempDir);\n\t\t\n\t\tif ( this.ft.isExist(this.apk)){\n\t\t\tSystem.out.println(\"\\n\\n\");\n\t\t\tOutBut.printStep(\"App is created successfully at \"+this.apk+\" \\n\");\n\t\t}\n\t}\n\n\tprivate void reinstallNewApk(){\n\t\tAppBroker broker = new AppBroker(TicklerVars.pkgName);\n\t\tbroker.reinstall(this.apk);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/apk/newApks/Debuggable.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk.newApks;\n\nimport java.io.IOException;\n\nimport base.FileUtil;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class Debuggable implements INewApk {\n\n\tprivate String newAppDir;\n\tprivate FileUtil fU;\n\t\n\tpublic Debuggable(){\n\t\tthis.newAppDir = TicklerVars.appTickDir+TicklerConst.newAppTempDir;\n\t\tthis.fU = new FileUtil();\n\t}\n\t\n\t@Override\n\tpublic String getNewApkName() {\n\t\treturn TicklerVars.appTickDir+TicklerConst.debuggableName;\n\t\t\n\t}\n\n\t@Override\n\tpublic void changeManifest() {\n\t\t\n\t\ttry {\n\t\t\tString manString = this.fU.readFile(newAppDir+\"AndroidManifest.xml\");\n\t\t\t//DEbuggable\n\t\t\tif (manString.contains(\"android:debuggable\"))\n\t\t\t\tmanString = manString.replaceAll(\"debuggable=\\\"false\\\"\", \"debuggable=\\\"true\\\"\");\n\t\t\telse\n\t\t\t\tmanString = manString.replaceAll(\"<application \", \"<application android:debuggable=\\\"true\\\" \");\n\t\t\t\n\t\t\tthis.fU.writeFile(newAppDir+\"AndroidManifest.xml\", manString);\n\t\t}\n\t\tcatch (IOException e)\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/apk/newApks/INewApk.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk.newApks;\n\nimport exceptions.TNotFoundEx;\n\npublic interface INewApk {\n\t\n\tpublic String getNewApkName();\n\tpublic void changeManifest() throws TNotFoundEx ;\n\n}\n"
  },
  {
    "path": "src/main/java/apk/newApks/NougatMitM.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage apk.newApks;\n\nimport java.io.IOException;\n\nimport base.FileUtil;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class NougatMitM implements INewApk{\n\n\tprivate String newAppDir,netSecConfFilePath;\n\tprivate FileUtil fU;\n\t\n\tpublic NougatMitM() {\n\t\tthis.newAppDir = TicklerVars.appTickDir+TicklerConst.newAppTempDir;\n\t\tthis.netSecConfFilePath = newAppDir+\"res/xml/\"+TicklerConst.mitmXmlName;\n\t\tthis.fU = new FileUtil();\n\t}\n\t\n\t@Override\n\tpublic String getNewApkName() {\n\t\t// TODO Auto-generated method stub\n\t\treturn TicklerVars.appTickDir+TicklerConst.mitmApkName;\n\t}\n\t@Override\n\tpublic void changeManifest() throws TNotFoundEx {\n\t\ttry{\n\t\t\tString manString = this.fU.readFile(newAppDir+\"AndroidManifest.xml\");\n\t\t\t\n\t\t\tif (!manString.contains(\"android:networkSecurityConfig\"))\n\t\t\t\tmanString = manString.replaceAll(\"<application \", \"<application android:networkSecurityConfig=\\\"@xml/\"+TicklerConst.mitmXmlName+\"\\\" \");\n\t\t\telse{\n\t\t\t\t//throw new TNotFoundEx(\"Manifest file already has a networkSecurityConfig entry, please check the configuration manually\");\n\t\t\t\t//Just replace the original network security config with our file\n\t\t\t\tmanString = manString.replaceAll(\".*android:networkSecurityConfig=\\\"@xml/(.*)\\\".* \", TicklerConst.mitmXmlName);\n\t\t\t}\n\t\t\t\n\t\t\tthis.fU.writeFile(newAppDir+\"AndroidManifest.xml\", manString);\n\t\t\tthis.createNetSecConf();\n\t\t}\n\t\tcatch (IOException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t}\n\t\n\tprivate void createNetSecConf(){\n\t\tString xmlFile=\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\t\t\t+\"<network-security-config>\\n\"\n\t\t\t\t+\"<base-config>\\n\"\n\t\t\t\t+\"<trust-anchors> \\n\"\n\t\t\t\t+\"<certificates src=\\\"system\\\" />\\n\"\n\t\t\t\t+\"  <certificates src=\\\"user\\\" />\\n\"\n\t\t\t\t+\"</trust-anchors>\\n\"\n\t\t\t\t+\"</base-config>\\n\"\n\t\t\t\t+\"</network-security-config>\";\n\t\t\n\t\tthis.fU.writeFile(netSecConfFilePath, xmlFile);\n\t\t\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/attacks/ActivityStarter.java",
    "content": "/*******************************************************************************\n\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage attacks;\n\nimport java.util.ArrayList;\nimport commandExec.Commando;\nimport components.Activity;\nimport components.IActivityService;\nimport components.Intent;\nimport manifest.handlers.IntentHandler;\n\n/**\n * \n * @author aabolhadid\n * Starts Activities\n */\npublic class ActivityStarter {\n\n\tString pkgName;\n\tString actStartCommand;\n\tIActivityService activity;\n\tArrayList<String> commands;\n\tCommando c;\n\t\n\tpublic ActivityStarter(String pkgname) {\n\t\tthis.pkgName = pkgname;\n\t\tthis.commands = new ArrayList<String>();\n\t}\n\t\n\tpublic ArrayList<String> startActivityfully(IActivityService actSer) {\n\t\t\n\t\tArrayList<String> commands=new ArrayList<String>();\n\t\tString startCommand = this.startActivity(actSer);\n\t\tcommands.add(startCommand);\n\t\t\n\t\tIntentHandler iHandler;\n\t\t\n\t\tif (actSer.getIntent()!= null) {\n\t\t\tfor (Intent i:actSer.getIntent())\n\t\t\t{\n\t\t\t\tiHandler= new IntentHandler(startCommand,i);\n\t\t\t\tcommands.addAll(iHandler.fullIntent());\n\t\t\t\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\t\n\t/**\n\t * Starts activity without intents\n\t * @return Command to start\n\t */\n\tpublic String startActivity() {\n\t\t\n\t\tString amCommand = this.createAmCommand(this.activity);\n\t\treturn amCommand+this.getPkgName()+\"/\" + this.getActivity().getName();\n\t}\n\t\n\tpublic String startActivity(IActivityService actSer){\n\t\tthis.setActivity(actSer);\n\t\treturn this.startActivity();\n\t}\n\t\n\t\n\t\n\tprivate String createAmCommand(IActivityService comp) {\n\t\tif (comp.getClass().equals(Activity.class)){\n\t\t\treturn \"am start -n \";\n\t\t}\n\t\treturn \"am startservice -n \";\n\t\t\n\t\t\n\t}\n\n\tpublic String getPkgName() {\n\t\treturn this.pkgName;\n\t}\n\n\tpublic void setPkgName(String pkgName) {\n\t\tthis.pkgName = pkgName;\n\t}\n\n\tpublic IActivityService getActivity() {\n\t\treturn activity;\n\t}\n\n\tpublic void setActivity(IActivityService a) {\n\t\tthis.activity = a;\n\t}\n\n\tpublic Commando getC() {\n\t\treturn c;\n\t}\n\n\tpublic void setC(Commando c) {\n\t\tthis.c = c;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/attacks/Broadcaster.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage attacks;\n\nimport java.util.ArrayList;\n\nimport components.Intent;\nimport components.Receiver;\nimport manifest.handlers.IntentHandler;\n\npublic class Broadcaster {\n\n\tString pkgName;\n\tReceiver rec;\n\tIntentHandler iHandler;\n\t\n\tpublic Broadcaster(String pkgName) {\n\t\tthis.pkgName = pkgName;\n\t}\n\n\tpublic Broadcaster(String pkgName,Receiver rec) {\n\t\tthis.pkgName = pkgName;\n\t\tthis.setRec(rec);\n\t}\n\t\n\tpublic Receiver getRec() {\n\t\treturn rec;\n\t}\n\n\tpublic void setRec(Receiver rec) {\n\t\tthis.rec = rec;\n\t}\n\t\n\tpublic ArrayList<String> generateBroadcast(Receiver rec) {\n\t\tArrayList<String> commands = new ArrayList<String>();\n\t\tString baseCommand = \"am broadcast -n \"+this.pkgName+\"/\"+rec.getName();\n\t\tcommands.add(baseCommand);\n\t\t\n\t\tif (rec.getIntent() != null)\n\t\t\tfor (Intent i : rec.getIntent()){\n\t\t\t\tiHandler = new IntentHandler(baseCommand,i);\n\t\t\t\tcommands.addAll(iHandler.fullIntent());\n\t\t\t}\n\t\treturn commands;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/attacks/ProviderAttacker.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage attacks;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport base.SearchUtil;\nimport components.Provider;\n\n/**\n * 1- Get content URIs from provider authorities\n * 2- Get content URIs from DEX\n * 3- Add content URIs from 2 if do not exist\n * @author aabolhadid\n *\n */\n\npublic class ProviderAttacker {\n\tprivate ArrayList<String> contentURIs;\n\tprivate Provider provider;\n\t\n\t\n\t/////////////////// SMALI //////////////////////\n\t\n\tpublic ArrayList<String> queryUrisFromSmali(String smaliPath){\n\t\tArrayList<String> commands = new ArrayList<String>();\n\t\tthis.getContentURIsFromSmali(smaliPath);\n\t\tfor (String uri:this.contentURIs)\n\t\t\tcommands.add(this.queryContent(uri));\n\t\t\n\t\treturn commands;\n\t}\n\t\n\tpublic void getContentURIsFromSmali(String smaliPath){\n\t\t\n\t\tthis.contentURIs = new ArrayList<String>();\n\t\tArrayList<String> contents = new ArrayList<String>();\n\t\tArrayList<SimpleEntry> contentsReturn =new ArrayList<SimpleEntry>(); \n\t\tSearchUtil searcher = new SearchUtil();\n\t\tString contentUri;\n\t\t\n\t\tcontents = searcher.search4KeyInDir(smaliPath, \"content://\");\n\t\t\n\t\tfor (String c:contents){\n\t\t\tif (!\"\".equals(contentUri = this.correctContentUri(c)))\n\t\t\t\tthis.contentURIs.add(contentUri);\n\t\t}\n\t\tthis.contentURIs = this.removeDuplicates(this.contentURIs);\n\t}\n\t\n\tprivate String correctContentUri(String line) {\n\t\tString contentUri=\"\";\n\t\t//Content URI = content://+any_number_of(non space char) until the first occurrence of \" or ' or a space character (space or new line)\n\t\tMatcher m = Pattern.compile(\"content://(\\\\S+?)[\\\"'\\\\s]\").matcher(line);\n\t\tif (m.find()) {\n\t\t\tcontentUri = line.substring(m.start(0),m.end(0)-1);\n\t\t}\n\t\treturn contentUri;\n\t}\n\t\n\t\n\tprivate void checkAndAddUri(String uri) {\n\t\tif (!uri.equals(\"content://\")){\n\t\t\tthis.contentURIs.add(uri);\n\t\t}\n\t\tif (!uri.endsWith(\"/\")){\n\t\t\tthis.contentURIs.add(uri+\"/\");\n\t\t}\n\t}\n\t\n\t///////////////////////////// From manifest ///////////////////////////\n\t\n\tpublic String prepareContentFromAuthority(Provider prov){\n\t\tString uri= \"content://\"+prov.getAuthorities();\n\t\treturn uri;\n\t}\n\t\n\t////////////////////////// Query /////////////////////////////\n\tpublic String queryContent(String contentURI) {\n\t\treturn \"content query --uri \"+contentURI;\n\t}\n\t\n\tpublic ArrayList<String> queryContents(){\n\t\tArrayList<String> queryCommands = new ArrayList<String>();\n\t\tfor (String cont:this.contentURIs){\n\t\t\tqueryCommands.add(this.queryContent(cont));\n\t\t}\n\t\t\n\t\treturn queryCommands;\n\t\t\t\n\t}\n\t\n\t/**\n\t * 1- get content URI from authorities\n\t * 2- add related Content URIs\n\t * 3- query content\n\t * 4- sql injection \n\t * @param prov\n\t * @return\n\t */\n\tpublic ArrayList<String> attackProvider(Provider prov){\n\t\tArrayList<String> relatedUris = new ArrayList<String>();\n\t\tArrayList<String> commands = new ArrayList<String>();\n\t\tString uriFromAuth = this.prepareContentFromAuthority(prov);\n\t\trelatedUris.add(uriFromAuth);\n\t\tcommands.add(this.queryContent(uriFromAuth));\n\n\t\tfor (String uri:this.contentURIs){\n\t\t\tif (uri.contains(prov.getAuthorities()) && !uri.equals(uriFromAuth)){\n\t\t\t\trelatedUris.add(uri);\n\t\t\t\tcommands.add(this.queryContent(uri));\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn commands;\n\t\t\n\t}\n\n\tpublic ArrayList<String> getContentURIs() {\n\t\treturn contentURIs;\n\t}\n\n\tpublic void setContentURIs(ArrayList<String> contentURIs) {\n\t\tthis.contentURIs = contentURIs;\n\t}\n\t\n\tprivate ArrayList<String> removeDuplicates(ArrayList<String> orig){\n\t\treturn new ArrayList<String>(new LinkedHashSet<String>(orig));\n\t\t\n\t}\n\n\t\n\t}\n"
  },
  {
    "path": "src/main/java/attacks/StartAttack.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage attacks;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport actions.Snapshots;\nimport apk.AppBroker;\nimport base.OtherUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\nimport logs.LogReader;\nimport logs.LogReaderController;\n\n/**\n * Migrating the start components functionality from Tickler class without missing up with Starter class\n * @author aabolhadid\n *\n */\npublic class StartAttack extends Starter {\n\tprivate AppBroker broker;\n\tprivate Commando commando;\n\tprivate ArrayList<String> commands;\n\tprivate boolean isLogger;\n\tprivate Runnable log;\n\tprivate Thread th1;\n\tprivate String logFileName;\n\tprivate LogReaderController logController;\n\tprivate Snapshots snaps;\n\n\t\n\tpublic StartAttack(){\n\t\tsuper();\n\t\tthis.broker = new AppBroker(TicklerVars.pkgName);\n\t\tthis.commando = new Commando();\n\t\tthis.snaps = new Snapshots();\n\t\t\n\t}\n\t\n\t/**\n\t * Replaces executeAttackCommand. \n\t * @param origCommands\n\t * @param exported\n\t * @param output\n\t */\n\tpublic void executeTriggerCommands(ArrayList<String> origCommands, boolean exported){\n\t\tString anyKey=\"\";\n\n\t\tArrayList<String> commands = this.removeDuplicates(origCommands);\n\t\tthis.printCommandsToBeExecuted(commands);\n\t\t\n\t\t//Executing commands\n\t\tfor (String command : commands)\n\t\t{\n\t\t\tOutBut.printH2(\"Attacking Component\");\n\t\t\tSystem.out.println(command);\n\t\t\t\n\t\t\tif (this.isLogger()){\n\t\t\t\tthis.writeCommandInLogFile(command);\n\t\t\t}\n\n\t\t\t\n\t\t\t// Quick and dirty: don't start the app before bcast receiver and content provider attacks\n\t\t\t\n\t\t\tif (command.contains(\"content\") || command.contains(\"am broadcast\")){\n\t\t\t\t\n\t\t\t}\n\t\t\tif (!exported)\n\t\t\t\tthis.commando.execRootPrintOP(command);\n\t\t\telse\n\t\t\t\tthis.commando.execADBPrintOP(command);\n\t\t\t\n\t\t\tanyKey=OtherUtil.pressAnykey();\n\t\t\t\n\t\t\tif (anyKey.equals(\"snapshot\")){\n\t\t\t\tthis.snaps.takeSnapshot();\n\t\t\t}\n\t\t\t\n\t\t\t // Do not terminate app between Tickles\n\t\t\t//this.commando.execADB(this.broker.forceStopApp());\n\t\t\t\n\t\t}\n\n\t\t\n\t}\n\t\n\t/**\n\t * Print in the beginning the list of commands to be executed\n\t */\n\tprivate void printCommandsToBeExecuted(ArrayList<String> origCommands){\n\t\tif (this.isLogger){\n\t\t\tOutBut.printH2(\"Logcat messages are saved in the following file: \");\n\t\t\tOutBut.printNormal(this.logFileName);\n\t\t}\n\t\tOutBut.printH2(\"Commands to be executed\");\n\t\tArrayList<String> commands = this.removeDuplicates(origCommands);\n\t\tfor (String c:commands)\n\t\t\tSystem.out.println(c);\n\t}\n\t\n\tprivate ArrayList<String> removeDuplicates(ArrayList<String> orig){\n\t\treturn new ArrayList<String>(new LinkedHashSet<String>(orig));\n\t}\n\t\n\t\n\n\tpublic ArrayList<String> getCommands() {\n\t\treturn commands;\n\t}\n\n\n\tpublic void setCommands(ArrayList<String> commands) {\n\t\tthis.commands = commands;\n\t}\n\n\n\n\tpublic boolean isLogger() {\n\t\treturn isLogger;\n\t}\n\n\n\n\tpublic void setLogger(boolean isLogger) {\n\t\tthis.isLogger = isLogger;\n\t\t\n\t\tif (isLogger){\n\t\t\t\n\t\t\tthis.prepareLoggerThread();\n\t\t}\n\t\t\t\n\t}\n\t\n\t////////////////////// Logging ////////////////////////////////////\n\t/**\n\t * Set and start the logger thread\n\t */\n\tprivate void prepareLoggerThread(){\n\t\tthis.makeLogFileName();\n\t\tthis.logController = new LogReaderController();\n\t\tthis.logController.setLogFileName(this.logFileName);\n\t\tthis.logController.setStop(false);\n\t\tthis.log = new LogReader(this.logController);\n\t\tthis.th1 = new Thread(this.log);\n\t\tth1.start();\n\t\t\n\t}\n\t\n\tprivate void makeLogFileName(){\n\t\tString timestamp = new SimpleDateFormat(\"dd.MM.yy_HH.mm.ss\").format(new Date());\n\t\tthis.logFileName=TicklerVars.logDir+TicklerVars.pkgName+\"_\"+timestamp+\".log\";\n\t}\n\t\n\tprivate synchronized void writeCommandInLogFile(String command){\n\n\t\tFile logFile = new File(this.logFileName);\n\t\tString line=\"\\n\\n************************************ Tickler: Executing Command ************************************************\\n\"\n\t\t+command+\"\\n\t *******************************************************************************************************************\\n\\n\";\n\t\ttry{\n\t\t\tFileWriter w = new FileWriter(logFile,true);\n\t\t\tw.append(line);\n\t\t\tw.close();\n\t\t}\n\t\tcatch (IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\tpublic void stopLogging(){\n\t\tif (this.logController != null)\n\t\tthis.logController.setStop(true);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/attacks/Starter.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage attacks;\n\nimport java.util.ArrayList;\nimport cliGui.OutBut;\nimport code.ExtrasUtil;\nimport components.IActivityService;\nimport components.IComponent;\nimport components.Provider;\nimport components.Receiver;\nimport initialization.TicklerVars;\n\n/**\n * I mean component attacker :) so it triggers attacks of Activities, services, content providers and B/C receivers\n * @author aabolhadid\n *\n */\npublic class Starter {\n\n\tprivate ActivityStarter actStarter;\n\tprivate Broadcaster broadcaster;\n\tpublic ProviderAttacker provAtt;\n\tpublic String manifestPath;\n\t\n\tpublic Starter() {\n\t\tString pkgName = TicklerVars.pkgName;\n\t\tthis.actStarter = new ActivityStarter(pkgName);\n\t\tthis.broadcaster = new Broadcaster(pkgName);\n\t\tthis.provAtt = new ProviderAttacker();\n\t}\n\t\n\t\n\t/**\n\t * Collects commands of starting the selected components\n\t * @param components\n\t * @return\n\t */\n\tpublic ArrayList<String> attackComponents(ArrayList<IComponent> components){\n\t\tArrayList<String> commands = new ArrayList<String>();\n\t\tfor (IComponent c:components){\n\t\t\tcommands.addAll(this.attackComponent(c));\n\t\t}\n\t\t\n\t\treturn commands;\n\t}\n\t\n\t/**\n\t * Collect the commands to start a specific component, based on its type\n\t * @param comp\n\t * @return\n\t */\n\tpublic ArrayList<String> attackComponent(IComponent comp) {\n\t\tArrayList<String> commands = new ArrayList<String>();\n\t\t\n\t\tif (comp instanceof IActivityService) {\n\t\t\tcommands.addAll(this.actStarter.startActivityfully((IActivityService)comp));\n\t\t}\n\t\telse if (comp instanceof Receiver) {\n\t\t\tcommands.addAll(broadcaster.generateBroadcast((Receiver) comp));\n\t\t}\n\t\t\n\t\telse if (comp instanceof Provider) {\n\n\t\t\t//Query only the URI from Authority\n\t\t\tString uri = this.provAtt.prepareContentFromAuthority((Provider)comp);\n\t\t\tcommands.add(this.provAtt.queryContent(uri));\t\t\t\n\t\t}\n\t\t\n\t\tExtrasUtil cU = new ExtrasUtil();\n\t\tif (cU.isJClassDir()){\n\t\t\tArrayList<String> commandsWithExtras = this.addExtrasOfComp(comp, commands);\n\t\t\treturn commandsWithExtras;\n\t\t}\n\t\telse {\n\t\t\tOutBut.printWarning(\"Extras cannot be obtained. PLease make sure that the lib directory lies in the same directory as Tickler Jar file and contains dex2jar-2.0 folder\");\n\t\t\treturn commands;\n\t\t}\n\t\t\n\t}\n\t\n\tpublic ArrayList<String> queryUrisFromSmali(){\n\t\treturn this.provAtt.queryUrisFromSmali(TicklerVars.extractedDir);\n\t}\n\t\n\tpublic ArrayList<String> getContentUriFromDex(String dexPath) {\n\t\tprovAtt.getContentURIsFromSmali(dexPath);\n\t\treturn provAtt.queryContents();\n\t}\n\t\n\tpublic void prepareProviderAttacks(String dexPath) {\n\t\tthis.setManifestPath(dexPath);\n\t\tthis.provAtt.getContentURIsFromSmali(dexPath);\n\t}\n\t\n\n\tpublic String getManifestPath() {\n\t\treturn manifestPath;\n\t}\n\n\tpublic void setManifestPath(String manifestPath) {\n\t\tthis.manifestPath = manifestPath;\n\t}\n\n\n\n\t////// Get Extras //////\n\tprivate String getExtrasOfComp(IComponent comp){\n\t\tString extrasLine = \" \";\n\t\tExtrasUtil cU = new ExtrasUtil();\n\t\textrasLine = cU.getExtras(comp.getName());\n\t\t\n\t\treturn extrasLine;\n\t}\n\t\n\tprivate ArrayList<String> addExtrasToCommands(String extrasLine, ArrayList<String> commands ) {\n\t\tArrayList<String> additionalCommands = new ArrayList<>();\n\t\tfor (String cmd : commands){\n\t\t\tadditionalCommands.add(cmd + extrasLine);\n\t\t}\n\t\t\n\t\tcommands.addAll(additionalCommands);\n\t\treturn commands;\n\t}\n\t\n\t/**\n\t * Adds extras commands if exist\n\t * @param comp\n\t * @param commands\n\t * @return\n\t */\n\tprivate ArrayList<String> addExtrasOfComp(IComponent comp,ArrayList<String> commands) {\n\t\tString extrasLine = this.getExtrasOfComp(comp);\n\t\tif (!extrasLine.equals(\" \"))\n\t\t\treturn this.addExtrasToCommands(extrasLine, commands);\n\t\treturn commands;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/base/Base64Util.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\n/**\n * Find Base64 values in a directory\n * @author aabolhadid\n *\n */\npublic class Base64Util {\n\tprivate FileUtil fU;\n\tprivate SearchUtil searcher;\n\n\tpublic Base64Util(){\n\t\tthis.searcher = new SearchUtil();\n\t\tthis.fU = new FileUtil();\n\t}\n\t\n\t/**\n\t * @param dir\n\t * @param key\n\t * @return\n\t */\n\tpublic ArrayList<String> searchB64inDir(String dir, String key){\n\t\tString keyLower = key.toLowerCase();\n\t\tArrayList<String> results = new ArrayList<>();\n\t\tList<File> files = this.searcher.search4FileInDir(dir, null);\n\t\t\n\t\tfor (File f : files){\n\t\t\tString decoded = this.fileToBase64(f.getAbsolutePath());\n\t\t\tif (decoded.toLowerCase().contains(keyLower)){\n\t\t\t\tresults.add(f.getAbsolutePath());\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn results;\n\t}\n\t\n\t/**\n\t * Searches for a key in the DataDir of an app\n\t * @param key\n\t * @return\tNames of the files that contain the base64 value of the key\n\t */\n\tpublic ArrayList<String> searchB64DataDir(String key){\n\t\treturn this.searchB64inDir(TicklerVars.dataDir, key);\n\n\t}\n\t\n\t\n\t\n\t/**\n\t * Check first if the file is not empty!!!, then read the file and base64 Dec every line\n\t * @param filePath\n\t * @return\n\t */\n\tpublic String fileToBase64(String filePath){\n\t\tString theFile=\"\", decLine, returnString=\"\";\n\t\tString ls = System.getProperty(\"line.separator\");\n\t\t\n\t\ttry{\n\t\t\ttheFile=this.fU.readFile(filePath);\n\t\t}\n\t\tcatch(IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tif (!theFile.isEmpty()){\n\t\t\tString[] fileArray= theFile.split(ls);\n\t\t\t\n\t\t\tfor (String s:fileArray){\n\t\t\t\tdecLine= this.breakLineBase64Dec(s);\n\t\t\t\tif (!decLine.isEmpty()|| !decLine.matches(\"^\\\\s*$\"))\n\t\t\t\t\treturnString+= decLine+ls;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn returnString;\n\t}\n\t\n\t/**\n\t * Break every line with delimiter of non-char or non-digit (except for = ??) then decode every part\n\t * @param line\n\t * @return\n\t */\n\tprivate String breakLineBase64Dec(String line){\n\t\tString[] broken = line.split(\"[^\\\\w\\\\d=]\");\n\t\tString dec=\"\", returnString=\"\", asciiDec=\"\";\n\t\tfor (String s: broken){\n\t\t\tdec = this.getBase64Dec(s);\n\t\t\tasciiDec = this.getAsciiFromString(dec);\n\t\t\tif (!asciiDec.isEmpty())\n\t\t\t\treturnString+=asciiDec+\" \";\n\t\t}\n\t\treturn returnString;\n\t}\n\t\n\t\n\t\n\tpublic String getAsciiFromString(String complex){\n\n\t\tString pure = complex.replaceAll(\"[^\\\\x20-\\\\x7F]\", \"\");\n\t\treturn pure;\t\t\n\t}\n\t\n\t/**\n\t * Base64 decodes a String\n\t * @param orig\n\t * @return\n\t */\n\tpublic String getBase64Dec(String orig){\n\t\tbyte[] dec = org.apache.commons.codec.binary.Base64.decodeBase64(orig);\n\t\treturn new String(dec);\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/base/CopyUtil.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.io.File;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport info.InfoGathering;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\npublic class CopyUtil {\n\n\tprivate FileUtil fileTrans;\n\t\n\tpublic CopyUtil() {\n\t\tthis.fileTrans = new FileUtil();\n\t}\n\t\n/////////////////////////////////// Copy Data ////////////////////////////////////////////////\n\n\t/**\n\t * Updates local and external data directory\n\t */\n\tpublic void copyStorage() {\n\t\tthis.copyDataDir();\n\t\tthis.copyExtDir(TicklerVars.extDataDir);\n\t}\n\t/**\n\t * Copy local and external storage directories to their usual directories \n\t * OR copy them to Transfers directory\n\t * @param dest\n\t */\n\tpublic void copyStorage(String dest) {\n\t\tif (dest == null) {\n\t\t\tthis.copyStorage();\n\t\t}\n\t\telse {\n\t\t\tString mainDest =TicklerVars.transferDir+dest+\"/\";\n\t\t\tthis.copyDataDir(mainDest+TicklerConst.DATA_DIR_NAME);\n\t\t\tthis.copyExtDir(mainDest+TicklerConst.EXTERNAL_STORAGE_Dir);\n\t\t}\n\t}\n\t\n\t/**\n\t* Copies DAta directory from the device, replaces any space in any file or dir name with __\n\t*/\n\tpublic void copyDataDir() {\n\t\tthis.copyDataDir(TicklerVars.dataDir);\n\t}\n\t\n\t/**\n\t * Copy local Data Directory to a specific destination\n\t * @param dest\n\t */\n\tpublic void copyDataDir(String dest){\n\t\t\n\t\tString src = \"/data/data/\"+TicklerVars.pkgName;\n\t\tif (this.fileTrans.isExistOnDevice(src)) {\n\t\t\tthis.fileTrans.warnOverrideAndDelete(dest);\n\t\t\tSystem.out.println(\"\\n!!! NOTE: Space in Files' and Directories' names are replaced by two underscores __ !!!\\n\");\n\t\t\tthis.fileTrans.copyDirToHost(src, dest,false);\n\t\t\t\n\t\t\t//Escape space in file names\n\t\t\t\n\t\t\tthis.fileTrans.escapeSpaceInDir(new File(dest));\n\t\t}\n\t\telse {\n\t\t\tOutBut.printError(\"Data Directory does not exist on the device\");\n\t\t}\n\t\n\t}\n\t\n\t/**\n\t * Copy local data storage directory to a specific destination\n\t * I think it's duplicated and the code changed anyway to copy both local and ext storage\n\t * @param name\n\t */\n\t/*\n\tpublic void copyDataDirName(String name){\n\t\tString dest;\n\t\tif (name==null){\n\t\t\tdest = TicklerVars.dataDir;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdest =TicklerVars.transferDir+name;\n//\t\t\tFileUtil fU = new FileUtil();\n\t\t\tthis.fileTrans.createDirOnHost(TicklerVars.transferDir);\n\t\t}\n\t\t\n\t\tthis.copyDataDir(dest);\n\t\n\t}\n\t*/\n\t// Copy any file or directory from the device to the host\n\t//Create a new directory for each transfer\n\tpublic void copyToHost(String src, String dest){\n\t\n\t\tString timestamp = new SimpleDateFormat(\"dd-MM-yy_HH.mm.ss\").format(new Date());\n\t\tString srcName =  fileTrans.getFileNameFromPath(src);\n\t\tString dstDirName;\n\t\t\n\t\tif (dest == null){\n\t\t\tdstDirName = srcName+\"_\"+timestamp;\n\t\t}\n\t\telse {\n\t\t\tdstDirName = dest;\n\t\t}\n\t\t\n\t\tString destDir = TicklerVars.transferDir+dstDirName;\n\t\t\n\t\tthis.fileTrans.copyDirToHost(src, destDir,false);\n\t\t\n\t\t//Check\n\t\tif (new File(destDir).exists())\n\t\tSystem.out.println(src+\" has been copied successfully to \"+destDir);\n\t}\n\n\t/**\n\t * Copy External storage directory to a certain destination\n\t * @param destExtDir\n\t */\n\tpublic void copyExtDir(String destExtDir) {\n\t\t\n\t\tInfoGathering info = new InfoGathering();\n//\t\tFileUtil fU = new FileUtil();\n\t\tString extDir = info.getSdcardDirectory().replaceAll(\"\\\\n\", \"\");\n//\t\tString destExtDir=TicklerVars.transferDir+TicklerConst.COPIED_EXTERNAL_STORAGE_NAME;\n\t\tif (!extDir.isEmpty()){\n\t\t\tOutBut.printStep(\"Copying External Storage Directory: \"+extDir+\"\\n\");\n\t\t\tthis.fileTrans.copyDirToHost(extDir, destExtDir,false);\n\t\t\tSystem.out.println(\"\");\n\t\t}\n\t\t\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/main/java/base/DOMXMLReader.java",
    "content": "package base;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport javax.xml.crypto.Data;\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport cliGui.OutBut;\nimport components.Manifest;\nimport components.Permission;\nimport components.Provider;\nimport components.Receiver;\nimport components.Service;\nimport components.UsesPermission;\nimport components.Action;\nimport components.Activity;\nimport components.Application;\nimport components.Category;\nimport components.DataUri;\nimport components.IComponent;\nimport components.Intent;\n\n// Following https://www.journaldev.com/898/read-xml-file-java-dom-parser\n\npublic class DOMXMLReader {\n\t\n\tprivate String manifestPath;\n\tprivate Manifest manifest;\n\t\n\t public static void main(String[] args) {\n\t\t DOMXMLReader r = new DOMXMLReader(\"/home/a7mad/Documents/Mobiles/Android/AndroTickler/eclipseTickler/insecManTest.xml\");\n\t\t r.parselManifest();\n\t }\n\t\n\tpublic DOMXMLReader(String manifestFile) {\n\t\tthis.manifestPath = manifestFile;\n\t\tthis.manifest = new Manifest();\n\t\t\n\t}\n\t\n\t/**\n\t * Parse the Manifest File in general\n\t */\n\tpublic Manifest parselManifest() {\n\t\t\n\t\tFile manifestFile= new File(this.manifestPath);\n\t\tDocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();\n\t\tDocumentBuilder dBuilder;\n\t\ttry {\n\t\t\tdBuilder = dbFactory.newDocumentBuilder();\n\t        Document doc = dBuilder.parse(manifestFile);\n\t        doc.getDocumentElement().normalize();\n\t        this.parseManDoc(doc);\n\t        \n\t        return this.manifest;\n\t        \n\t        \n\t\t} catch (ParserConfigurationException | SAXException | IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t\t\n\t}\n\t\n\tprivate void parseManDoc(Document doc) {\n\t\tArrayList<UsesPermission> usesPerm = new ArrayList<UsesPermission>();\n\t\tArrayList<Permission> perms = new ArrayList<Permission>();\n\t\tApplication app = new Application();\n\t\n\t\tNodeList nl;\n\t\t\t\t\n\t\t//Application, components and Intent filters\n\t\tnl = doc.getElementsByTagName(\"application\");\n\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\tapp = this.parseApplication(nl.item(i));\n\t\t}\n\t\t\n\t\t\n\t\tnl = doc.getElementsByTagName(\"uses-permission\");\n\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\tElement e = (Element) nl.item(i);\n\t\t\tUsesPermission p = new UsesPermission();\n\t\t\tp.setName( e.getAttribute(\"android:name\"));\n\t\t\tusesPerm.add(p);\n\t\t}\n\t\t\n\t\tnl = doc.getElementsByTagName(\"permission\");\n\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\tElement e = (Element) nl.item(i);\n\t\t\tPermission p = new Permission();\n\t\t\tp.setName( e.getAttribute(\"android:name\"));\n\t\t\tp.setProtectionLevel(e.getAttribute(\"android:protectionLevel\"));\n\t\t\tperms.add(p);\n\t\t}\n\t\t\n\n\t\tthis.manifest.setPkgName(doc.getDocumentElement().getAttribute(\"package\"));\n\t\tthis.manifest.setApplication(app);\n\t\tthis.manifest.setUsesPermissions(usesPerm);\n\t\tthis.manifest.setPermissions(perms);\n\t\t\n\t\t\n\t}\n\t\n\t\n\n/////////////////////////////////////// Application /////////////////////////////////\n\t\n\tprivate Application parseApplication(Node node) {\n\t\tArrayList<Activity> actList = new ArrayList<Activity>();\n\t\tArrayList<Service> serList = new ArrayList<>();\n\t\tArrayList<Provider> provList = new ArrayList<>();\n\t\tArrayList<Receiver> recList = new ArrayList<Receiver>();\n\t\t\n\t\tApplication app = new Application();\n\t\tNodeList nl;\n\t\tapp.setAllowBackup(true);\n\t\tapp.setDebuggable(false);\n\t\t\n\t\t\n\t\tif (node.getNodeType()==Node.ELEMENT_NODE) {\n\t\t\tElement el = (Element) node;\n\t\t\tif (el.getAttribute(\"android:allowBackup\").toLowerCase().equals(\"false\"))\n\t\t\t\tapp.setAllowBackup(false);\n\t\t\t\n\t\t\tif (el.getAttribute(\"android:debuggable\").toLowerCase().equals(\"true\"))\n\t\t\t\tapp.setDebuggable(true);\n\t\t\t\n\t\t\tapp.setName(el.getAttribute(\"android:name\"));\n\t\t\n\t\t//Components\n\t\t\n\t\t\t\tnl = el.getElementsByTagName(\"activity\");\n\t\t\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\t\t\tactList.add(this.parseActivity(nl.item(i)) );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnl = el.getElementsByTagName(\"activity-alias\");\n\t\t\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\t\t\tactList.add(this.parseActivity(nl.item(i)) );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnl = el.getElementsByTagName(\"service\");\n\t\t\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\t\t\tserList.add(this.parseService(nl.item(i)) );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnl = el.getElementsByTagName(\"provider\");\n\t\t\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\t\t\tprovList.add( this.parseProvider(nl.item(i)) );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnl = el.getElementsByTagName(\"receiver\");\n\t\t\t\tfor (int i=0;i<nl.getLength();i++) {\n\t\t\t\t\trecList.add( this.parseReceiver(nl.item(i)) );\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tapp.setActivites(actList);\n\t\tapp.setServices(serList);\n\t\tapp.setProviders(provList);\n\t\tapp.setReceivers(recList);\n\t\t\n\t\treturn app; \n\t}\n\t\n\n//////////////////////////////////////////// Components ///////////////////////////////////\n\t\n\t// IComponent\n\t\n\tprivate IComponent parseIComponent(Node node,IComponent compy) {\n\t\tNodeList nl;\n\t\tArrayList<Intent> intFilList;\n\t\t\n\t\tif (node.getNodeType() == Node.ELEMENT_NODE) {\n\t\t\tElement element = (Element) node;\n\t\t\t\n    \t\tcompy.setName(element.getAttribute(\"android:name\"));\n    \t\tcompy.setPermission(element.getAttribute(\"android:permission\"));\n    \t\t\n\n    \t\t\n\t\t\t//Intent Filters\n\n            nl = element.getElementsByTagName(\"intent-filter\");\n            intFilList = new ArrayList();\n            \n    \t\tfor (int i=0;i<nl.getLength();i++) {\n    \t\t\tintFilList.add( this.parseIntentFilter(nl.item(i)) ) ;\n    \t\t}\n    \t\tcompy.setIntent(intFilList);\n    \t\t\n\n    \t\t//Exported\n    \t\tif((element.hasAttribute(\"android:exported\") && element.getAttribute(\"android:exported\").toLowerCase().equals(\"true\")) || ! intFilList.isEmpty() ) {\n    \t\t\tcompy.setExported(true);\n    \t\t}\n    \t\telse\n    \t\t\tcompy.setExported(false);\n\t\t\t\n    \t\t\n    \t\t\n\t\t}\n\n\t\treturn compy;\n\t}\n\t\n\t//Activity\n\t\n\tprivate Activity parseActivity(Node node) {\n\t\tActivity activity = new Activity();\n\t\t\n\t\tactivity = (Activity)this.parseIComponent(node, activity);\n\t\treturn activity;\n\t}\n\t\n\t\n\tprivate Service parseService(Node node) {\n\t\tService service = new Service();\n\t\t\n\t\tservice = (Service)this.parseIComponent(node, service);\n\t\treturn service;\n\t}\n\t\n\tprivate Provider parseProvider(Node node) {\n\t\tProvider prov = new Provider();\n\t\tprov = (Provider)this.parseIComponent(node, prov);\n\t\t\n\t\t if (node.getNodeType() == Node.ELEMENT_NODE) {\n\t            Element element = (Element) node;\n\t            prov.setAuthorities(element.getAttribute(\"android:authorities\"));\n\t\t }\n\t\t \n\t\t return prov;\n\t}\n\t\n\tprivate Receiver parseReceiver(Node node) {\n\t\tReceiver rec = new Receiver();\n\t\trec = (Receiver) this.parseIComponent(node, rec);\n\t\t\n\t\treturn rec;\n\t}\n\t\n\t\n///////////////////////////////////////////////////////// Intent Filters /////////////////////////////////////////\t\n\t\n\tprivate Intent parseIntentFilter(Node node) {\n\t\tIntent inFl = new Intent();\n\t\tNodeList nl;\n\t\tArrayList<Action> actionList;\n\t\tArrayList<Category> catList;\n\t\tArrayList<DataUri> dataList;\n\t\t\n\t\t if (node.getNodeType() == Node.ELEMENT_NODE) {\n\t            Element element = (Element) node;\n\t             \n\t            //Actions\n\t            nl = element.getElementsByTagName(\"action\");\n\t            actionList = new ArrayList();\n\t            for (int i=0;i<nl.getLength();i++) {\n\t            \tactionList.add(this.parseAction(nl.item(i)));\n\t    \t\t}\n\t            \n\t            //Categories\n\t            nl = element.getElementsByTagName(\"category\");\n\t    \t\tcatList = new ArrayList<Category>();\n\t    \t\tfor (int i=0;i<nl.getLength();i++) {\n\t    \t\t\tcatList.add(this.parseCategory(nl.item(i)));\n\t    \t\t}\n\t    \t\t\n\t    \t\t//Data \n\t            nl = element.getElementsByTagName(\"data\");\n\t    \t\tdataList = new ArrayList<DataUri>();\n\t    \t\tfor (int i=0;i<nl.getLength();i++) {\n\t    \t\t\tdataList.add(this.parseDataUri(nl.item(i)));\n//\t    \t\t\t\n\t    \t\t}\n\t    \t\t\n\t    \t\tinFl.setAction(actionList);\n\t    \t\tinFl.setCategory(catList);\n\t    \t\tinFl.setData(dataList);\n\t\t }\n\n\t\t\n\t\treturn inFl;\n\t}\n\t\n\t\n\tprivate Action parseAction(Node node) {\n\t\t\t\n\t\t\tAction action = new Action();\n\t\t\t\n\t        if (node.getNodeType() == Node.ELEMENT_NODE) {\n\t            Element element = (Element) node;\n\t            action.setName(element.getAttribute(\"android:name\"));\n\t        }\n\t\t\t\n\t\t\treturn action;\n\t\t}\n\t\n\tprivate Category parseCategory(Node node) {\n\t\t\n\t\tCategory cat = new Category();\n\t\t\n\t    if (node.getNodeType() == Node.ELEMENT_NODE) {\n\t        Element element = (Element) node;\n\t        cat.setName(element.getAttribute(\"android:name\"));\n\t        \n\t    }\n\t\t\n\t\treturn cat;\n\t}\n\t\n\tprivate DataUri parseDataUri(Node node) {\n\t\tDataUri data = new DataUri();\n\t\t\n\t\tif (node.getNodeType() == Node.ELEMENT_NODE) {\n\t\t\tElement e = (Element) node;\n\t\t\t\n\t\t\tdata.setHost(e.getAttribute(\"android:host\"));\n\t\t\tdata.setScheme(e.getAttribute(\"android:scheme\"));\n\t\t\tdata.setPort(e.getAttribute(\"android:port\"));\n\t\t\tdata.setPath(e.getAttribute(\"android:path\"));\n\t\t\tdata.setPathPrefix(e.getAttribute(\"android:pathPrefix\"));\n\t\t\tdata.setPathPattern(e.getAttribute(\"android:pathPattern\"));\n\t\t\tdata.setMimeType(e.getAttribute(\"android:mimeType\"));\n\t\t}\n\t\t\n\n\t\t\n\t\treturn data;\n\t}\n\n\n\t///////////////////////////////////// Util ////////////////////////////////////////\n\t\n\t  private String getTagValue(String tag, Element element) {\n\t        NodeList nodeList = element.getElementsByTagName(tag).item(0).getChildNodes();\n\t        Node node = (Node) nodeList.item(0);\n\t        return node.getNodeValue();\n\t    }\n\n}\n"
  },
  {
    "path": "src/main/java/base/FileUtil.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\n\nimport org.apache.commons.io.FileUtils;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerVars;\n/**\n * All File operations (copy, delete ...) on host or device\n * @author aabolhadid\n *\n */\npublic class FileUtil {\n\t\n\tprivate Commando commando;\n\n\tpublic FileUtil(){\n\t\tthis.commando = new Commando();\n\t}\n\t\t\n\t\n\t///////// HOST commands ////////////////\n\t/**\n\t * \n\t * @param src\n\t * @param dest\n\t * @param silent If true then it will not print the Copying message\n\t */\n\tpublic void copyOnHost(String src, String dest,boolean silent){\n\t\tif (!silent)\n\t\t\tSystem.out.println(\"Copying \"+src+\" to \"+dest+\".....\");\n\t\tString command = \"cp -fr \"+src+\" \"+dest;\n\t\tthis.commando.executeCommand(command);\n\t}\n\t\n\t\n\t/**\n\t * Checks subdirectories of each directory, escapes space in their files' names then change the subdirectories' names\n\t * @param dir\n\t */\n\tpublic void escapeSpaceInDir(File dir){\n\t\ttry {\n\t\t\tfor (File f : dir.listFiles())\n\t\t\t{\n\t\t\t\tif (f.isDirectory())\n\t\t\t\t\tthis.escapeSpaceInDir(f);\n\t\n\t\t\t\tthis.replaceSpace(f);\n\t\t\t}\n\t\t}\n\t\tcatch (java.lang.NullPointerException nullEx) {\n\t\t\tOutBut.printNormal(\".... Directory is empty\");\n\t\t}\n\n\t}\n\t\n\t/**\n\t * Since Java cannot handle files names or directories containing a space, this is to replace the space with two underscores\n\t * @param loc\n\t */\n\tprivate void replaceSpace(File f){\n\t\tString fName = f.getName();\n\t\tif (fName.contains(\" \")){\n\t\t\tString newPath = f.getParentFile().getAbsolutePath()+\"/\"+fName.replace(\" \", \"__\");\n\t\t\tFile newName = new File(newPath);\n\t\t\tf.renameTo(newName);\n\t\t\t\n\t\t}\n\t}\n\t\n\tpublic void deleteFromHost(String filename){\n\t\tFile file = new File(filename);\n\t\ttry{\n\t\t\tif (file.isDirectory())\n\t\t\t\tFileUtils.deleteDirectory(file);\n\t\t\telse\n\t\t\t\tFileUtils.forceDelete(file);\n\t\t}\n\t\tcatch(IOException e){\n\t\t\tSystem.out.println(\"!!!!!! ERROR: Cannot delete \"+file.getAbsolutePath()+\". Please delete the \"\n\t\t\t\t\t+ \"file / directory manually and rerun the command\");\n\t\t}\n\t}\n\t\n\t// If a directory does not exist, it creates it. \n\tpublic void createDirOnHost(String path) {\n\t\tif (!this.isExist(path)) {\n\t\t\tFile dir = new File(path);\n\t\t\tdir.mkdirs();\n\t\t}\n\t}\n\t\n\t/**\n\t * If Path exists on host, a warning message is printed and path is deleted\n\t * @param path\n\t */\n\tpublic void warnOverrideAndDelete(String path){\n\t\tif (this.isExist(path)){\n\t\t\tSystem.out.println(\"WARNING... \"+path+\" already exists with this same, !!OVERRIDING!! \");\n\t\t\tthis.deleteFromHost(path);\n\t\t}\n\t}\n\t\n\t\n\tpublic boolean isExist(String path){\n\t\tFile file = new File(path);\n\t\treturn file.exists();\n\t}\n\t\n\t/**\n\t * Returns whether a file is executable, used with dex2jar and other external tools\n\t * @param path\n\t * @return\n\t */\n\tpublic boolean isExecutable(String path){\n\t\tFile file = new File(path);\n\t\treturn file.canExecute();\n\t}\n\t\n\t/**\n\t * Checks the file type by executing the file command\n\t * @param f: file\n\t */\n\tpublic String fileType(File f){\n\t\tString path = f.getAbsolutePath().replaceAll(\"\\\\s\", \"\\\\ \");\n\t\tString command = \"file \"+ path;\n\t\tString result = commando.executeCommand(command);\n\t\t\n\t\treturn result;\n\t}\n\t\n\tpublic String getFileNameFromPath(String path){\n\t\tFile absPath = new File(path);\n\t\tString theName = absPath.getName();\n\t\tif (absPath.isDirectory())\n\t\t\ttheName=theName+\"/\";\n\t\t\n\t\treturn theName;\n\t\t\n\t}\n\t\n\t/**\n\t * Get files in Folder\n\t * Replacing FileUtils.listFiles problem\n\t * @param src\n\t * @param dest\n\t */\n\tpublic ArrayList<File> listFilesInDir(String dirLoc){\n\n\t\tArrayList<File> fileList = new ArrayList<File>();\t\n\t\ttry {\n\t\t Path source = Paths.get(dirLoc);\n\t     Files.walk(source).filter(Files::isRegularFile).forEach(p -> fileList.add(this.pathToFile(p)));\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn fileList;\n\t}\n\t\n\tprivate File pathToFile(Path p) {\n\t\tFile f=p.toFile();\n\t\tif (f.exists()) {\n\t\t\treturn f;\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * Search for files with specific extensions or contain a specific string.\n\t * Solving FileUtils issues\n\t * @param dirLoc\n\t * @param exts\n\t * @return\n\t */\n\tpublic ArrayList<File> listFilesInDirContain(String dirLoc,String[] exts) {\n\t\tArrayList<File> filez = this.listFilesInDir(dirLoc);\n\t\tArrayList<File> returnFilez = new ArrayList<File>();\n\t\t\n\t\tfor(File f : filez) {\n\t\t\tfor(String ext:exts)\n\t\t\t\tif (f.getName().contains(ext)) {\n\t\t\t\t\treturnFilez.add(f);\n\t\t\t\t}\n\t\t}\n\t\treturn returnFilez;\n\t\t\n\t}\n\t\n\t////////////// Android Device ////////////////\n\t\n\tpublic void copyOnDevice(String src, String dest) {\n\t\tString command = \"cp -fr \"+src+\" \"+dest;\n\t\tthis.commando.execRoot(command);\n\t\t\n\t}\n\t\n\tpublic void copyToDevice(String src, String dest) {\n\t\tString fName = this.getFileNameFromPath(src);\n//\t\tthis.warnOverrideAndDelete(dest+fName);\n\t\tString sdCardDestPath = TicklerVars.sdCardPath+fName;\n\t\tString command = \"adb push \"+src+\" \"+sdCardDestPath;\n\t\tint pullResult=this.commando.executeProcessForAdbPull(command);\n\t\t\n\t\tthis.copyOnDevice(sdCardDestPath, dest);\n//\t\tthis.deleteDirFromDevice(src);\n\t}\n\t\n\tpublic void pullFromSDcard(String src, String dest) {\n\t\tString fName = this.getFileNameFromPath(src);\n\t\tthis.warnOverrideAndDelete(dest+fName);\n\t\tString command = \"adb pull \"+src+\" \"+dest;\n\t\tint pullResult=this.commando.executeProcessForAdbPull(command);\n\t\tthis.deleteDirFromDevice(src);\n\t}\n\t\n\n\t\n\tpublic String createDirOnDevice(String path) {\n\t\tString command = \"mkdir -p \"+path;\n\t\treturn this.commando.execRoot(command);\n\t}\n\t\n\tpublic String deleteDirFromDevice(String path) {\n\t\tString command = \"rm -fr \"+path;\n\t\treturn this.commando.execRoot(command);\n\t}\n\t\n\t//Checks if the file exists on the android device\n\tpublic boolean isExistOnDevice(String path) {\n\t\tString command = \"ls \"+path;\n\t\tString op = this.commando.execRoot(command);\n\t\t\n\t\tif (op.toLowerCase().contains(\"no such file or directory\"))\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\t\n\tprivate void b4CopyChecks(String path) throws TNotFoundEx{\n\t\tif (!this.isExistOnDevice(path)){\n\t\t\tthrow new TNotFoundEx(\"!!!!!! ERROR: File / Directory does not exist on the device\");\n\t\t}\n\t}\n\t\n\t/////////////////////////////////////// Between Device and host //////////////////////////////////\n\t/**\n\t * Copies a file / directory from any location on the device to the host (linux) through SDcard\n\t * @param silent if true then don't print a message\n\t */\n\tpublic void copyDirToHost(String src,String dest,boolean silent) {\n\t\t\n\t\ttry{\n\t\t\tif (!silent)\n\t\t\t\tOutBut.printStep(\"Copying: \"+src+\" to ...\\n\"+dest+\" ......\");\n\t\t\tthis.b4CopyChecks(src);\n\t\t\tString srcName = this.getFileNameFromPath(src);\n\t\t\tthis.deleteDirFromDevice(TicklerVars.sdCardPath+srcName);\n\t\t\tthis.copyOnDevice(src, TicklerVars.sdCardPath);\n\t\t\tthis.prepareDestination(dest);\n\t\t\tthis.pullFromSDcard(TicklerVars.sdCardPath+srcName, dest+\"/\");\n\t\t\tFile f = new File(TicklerVars.sdCardPath+srcName);\n\t\t\t//Clean (uncommented)\n\t\t\tthis.deleteDirFromDevice(TicklerVars.sdCardPath+srcName);\n\t\t}\n\t\tcatch(TNotFoundEx e)\n\t\t{\n\t\t\tSystem.out.println(e.getMessage());\n\t\t}\n\t}\n\t\n\t\n\t/////////////// I/O ///////////////\n\tpublic String readFile(String file) throws IOException {\n\t    BufferedReader reader = new BufferedReader(new FileReader (file));\n\t    String line;\n\t    StringBuilder fileString = new StringBuilder();\n\t    String ls = System.getProperty(\"line.separator\");\n\n\t    try {\n\t        while((line = reader.readLine()) != null) {\n\t        \tfileString.append(line);\n\t        \tfileString.append(ls);\n\t        }\n\n\t        return fileString.toString();\n\t    } finally {\n\t        reader.close();\n\t    }\n\t}\n\t\n\tpublic void writeFile(String fileName, String content){\n\t\ttry {\n\t\t\tBufferedWriter writer = new  BufferedWriter(new FileWriter(fileName));\n\t\t\twriter.write(content);\n\t\t\twriter.close();\n\t\t}\n\t\tcatch(IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\t/////// Preparation of Transfer directory\n\tpublic String prepareTimestampTransfer(){\n\t\tString timestamp = new SimpleDateFormat(\"dd-MM-yy_HH.mm.ss\").format(new Date());\n\t\tif (!this.isExist(TicklerVars.transferDir))\n\t\t\tthis.createDirOnHost(TicklerVars.transferDir);\n\t\t\n\t\treturn timestamp;\n\t}\n\t\n\tprivate void prepareDestination(String dst) {\n\t\tFile destFile = new File(dst);\n\t\tthis.createDirOnHost(dst);\t\t\n\t}\n\t\n\n\n}\n"
  },
  {
    "path": "src/main/java/base/JsonParser.java",
    "content": "package base;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.text.ParseException;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\n\nimport cliGui.OutBut;\n\npublic class JsonParser {\n\t\n\t\n\n\tprivate JSONParser parser;\n\tprivate String squeezeFileLoc;\n\t\n\tpublic static void main(String[] args) {\n\t\tJsonParser jp = new JsonParser();\n//\t\tjp.parseJsonFile();\n\t\t\n\t\tString objo = \"{ \\\"squeeze\\\": [{\\\"Title\\\":\\\"World accessible files\\\",\\\"Values\\\":[ \\\"MODE_WORLD_READABLE\\\", \\\"MODE_WORLD_WRITABLE\\\"]},\"\n\t\t\t\t+ \"{\\\"Title\\\":\\\"WebView\\\",\\\"Values\\\":[ \\\"addJavascriptInterface\\\", \\\"setAllowContentAccess\\\", \\\"setAllowFileAccess\\\", \\\"setAllowUniversalAccess\\\" ]}]}\";\n\t\tArrayList<SimpleEntry<String,ArrayList<String>>> arr = jp.parseJsonString(objo);\n\t\t\n//\t\tSystem.out.println(\"--\"+title+\"--\");\n//\t\tfor (int j=0;j<valuesJA.size();j++) {\n//\t\t\tSystem.out.println(valuesJA.get(j).toString());\n//\t\t}\n\t\t\n\t\tfor (SimpleEntry<String,ArrayList<String>> e : arr) {\n\t\t\tSystem.out.println(e.getKey());\n\t\t\tOtherUtil.printStringArray(e.getValue());\n\t\t}\n\n\t\t\n\t}\n\t\n\tpublic JsonParser() {\n\t\tparser = new JSONParser();\n\t\t//For now\n\t\tsqueezeFileLoc=\"/home/a7mad/eclipse-workspace/TicklerV2.1/bin/Squeeze.conf\";\n\t}\n\t\n\t\n\tprivate void parseJsonFile() {\n\t\ttry {\n//\t\t\tString objo = \"\\\"squeeze\\\":[{\\\"a\\\":\\\"aa\\\",\\\"b\\\":\\\"bb\\\"}]}\";\n\t\t\tString objo = \"{ \\\"squeeze\\\": [{\\\"Title\\\":\\\"World accessible files\\\",\\\"values\\\":[ \\\"MODE_WORLD_READABLE\\\", \\\"MODE_WORLD_WRITABLE\\\"]},\"\n\t\t\t\t\t+ \"{\\\"Title\\\":\\\"WebView\\\",\\\"values\\\":[ \\\"addJavascriptInterface\\\", \\\"setAllowContentAccess\\\", \\\"setAllowFileAccess\\\", \\\"setAllowUniversalAccess\\\" ]}]}\";\n//\t\t\tObject objy = parser.parse(new FileReader(this.squeezeFileLoc));\n\t\t\tObject objy = parser.parse(objo);\n\t\t\tJSONObject jsonObj = (JSONObject) objy;\n\t\t\t\n//\t\t\tJSONArray arr = (JSONArray) objy; \n\t\t\tJSONArray arr = (JSONArray)jsonObj.get(\"squeeze\");\n\t\t\t\n\t\t\tSystem.out.println(arr.size());\n\t\t\t\n\t\t\tIterator itr1 = arr.iterator();\n\t\t\tIterator itr2 = arr.iterator(); \n\t\t\t\n//\t        while (itr2.hasNext())  \n//\t        { \n\t        \t\n//\t            itr1 = ((Map) itr2.next()).entrySet().iterator(); \n//\t            while (itr1.hasNext()) { \n//\t                Map.Entry pair = itr1.next(); \n//\t                System.out.println(pair.getKey() + \" : \" + pair.getValue()); \n//\t            } \n//\t        } \n\t\t\tString test=\"\";\n\t\t\tfor (int i=0;i<arr.size();i++) {\n\t\t\t\ttest= arr.get(i).toString();\n\t\t\t\tSystem.out.println(test);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t}\n\t\tcatch(Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic ArrayList<SimpleEntry<String,ArrayList<String>>> parseJsonString(String jsonString) {\n\n//\t\t\tString jsonString = \"{ \\\"squeeze\\\": [{\\\"Title\\\":\\\"World accessible files\\\",\\\"Values\\\":[ \\\"MODE_WORLD_READABLE\\\", \\\"MODE_WORLD_WRITABLE\\\"]},\"\n//\t\t\t\t\t+ \"{\\\"Title\\\":\\\"WebView\\\",\\\"Values\\\":[ \\\"addJavascriptInterface\\\", \\\"setAllowContentAccess\\\", \\\"setAllowFileAccess\\\", \\\"setAllowUniversalAccess\\\" ]}]}\";\n\t\n\t\tString jsonStr=\"\",title=\"\";\n\t\tJSONObject jsObj2;\n\t\tJSONArray valuesJA;\n\t\tSimpleEntry<String,ArrayList<String>> sEnt;\n//\t\tArrayList<SimpleEntry<String,ArrayList<String>>> squeezeParams= new ArrayList<>();\n\t\tArrayList<SimpleEntry<String,ArrayList<String>>> squeezeParams= new ArrayList<>();\n\t\t\t\n\t\tJSONObject rootJO = this.parseStringToObj(jsonString);\n\t\tJSONArray squeezeJA = (JSONArray)rootJO.get(\"squeeze\");\n\t\t\n\t\tfor (int i=0;i<squeezeJA.size();i++) {\n\t\t\t\n\t\t\tjsonStr= squeezeJA.get(i).toString();\n\t\t\tjsObj2 = this.parseStringToObj(jsonStr);\n\t\t\ttitle = (String)jsObj2.get(\"Title\");\n\t\t\n\t\t\tvaluesJA= (JSONArray) jsObj2.get(\"Values\");\n\t\t\tArrayList<String> aL= (ArrayList<String>)valuesJA;\n\t\t\tsEnt=new SimpleEntry<>(title,aL);\n\t\t\tsqueezeParams.add(sEnt);\n\t\t\t\n\t\t}\n\t\t\n\t\treturn squeezeParams;\n\t\t\n\t\t\n\t\t\n\t}\n\n\t\n\t\n\tprivate JSONObject parseStringToObj(String jsonStr) {\n\t\t\n\t\ttry {\n\t\t\tObject objy = parser.parse(jsonStr);\n\t\t\tJSONObject jsonObj = (JSONObject) objy;\n\t\t\treturn jsonObj;\n\t\t}\n\t\tcatch(Exception e) {\n\t\t\tOutBut.printError(\"Error while Parsing Squeeze JSON Configuration\");\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t\t\n//\t\treturn jsonObj;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/base/OtherUtil.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport cliGui.OutBut;\nimport initialization.TicklerVars;\n\n/**\n * Mainly regex operations now\n * @author aabolhadid\n *\n */\npublic class OtherUtil {\n\t/**\n\t * Gets all instances that match a regex in a string\n\t * @param s\n\t * @param regex\n\t * @return\n\t */\n\tpublic static ArrayList<String> getRegexFromString(String s, String regex){\n\t\t\n\t\tArrayList<String> result = new ArrayList<>();\n\t\t\n\t\tPattern p = Pattern.compile(regex);\n\t\tMatcher m = p.matcher(s);\n\t\ttry{\n\t\t\twhile(m.find())\t\t\n\t\t\t\tresult.add(m.group(1));\n\t\t}\n\t\tcatch(IndexOutOfBoundsException ex)\n\t\t{\n\t\t\t\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * Gets all instances that match a regex in a string\n\t * @param s\n\t * @param regex\n\t * @return\n\t */\n\tpublic static boolean isRegexInString(String s, String regex){\n\t\t\n\t\tPattern p = Pattern.compile(regex);\n\t\tMatcher m = p.matcher(s);\n\t\tif (m.matches())\t\t\t\n\t\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\tpublic static ArrayList<String> removeDuplicates(ArrayList<String> orig){\n\t\treturn new ArrayList<String>(new LinkedHashSet<String>(orig));\n\t\t\n\t}\n\t\n\tpublic static String pressAnykey(){\n\t\tBufferedReader is = new BufferedReader(new InputStreamReader(System.in));\n\t\tSystem.out.println(\"Press Enter to continue, or enter snapshot to take a snapshot ........\");\n\t\t\n\t\treturn OtherUtil.readInput();\n\t}\n\t\n\tpublic static String pressAnyKeySilent(){\n\t\tBufferedReader is = new BufferedReader(new InputStreamReader(System.in));\n\t\treturn OtherUtil.readInput();\n\t}\n\t\n\tprivate static String readInput(){\n\t\tBufferedReader is = new BufferedReader(new InputStreamReader(System.in));\n\t\tString key=\"\";\n\t\t\n\t\ttry {\n\t\t\tkey = is.readLine();\n\t\t\t\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn key;\n\t}\n\t\n\t/**\n\t * As in different functions in Searcher\n\t * @param hits\tARraylist of SimpleEntry, obtained after searching for a key\n\t * @param toBeReplaced\tReplace the long path name, such as TicklerVars.jClassDir\n\t * @param replacement\tReplacement such as [Data_Dir]\n\t */\n\tpublic static void printSimpleEntryArray(ArrayList<SimpleEntry> hits, String toBeReplaced, String replacement) {\n\t\tif (!hits.isEmpty()){\n\t\t\tOutBut.printNormal(hits.size()+\" Search Results are found :\\n===============================\\n\");\n\t\t\tfor (SimpleEntry e: hits){\n\t\t\t\tString filePath = e.getKey().toString().replaceAll(toBeReplaced, replacement); \n\t\t\t\tSystem.out.println(\"#FileName: \"+filePath);\n\t\t\t\tSystem.out.println(\" \"+e.getValue()+\"\\n\");\n\t\t\t}\n\t\t\t\n\t\t\tOutBut.printStep(\"Where \"+replacement+\" is \"+toBeReplaced);\n\t\t}\n\t}\n\t\n\t/**\n\t * Corrects a path if ~ is used\n\t * @param path\n\t * @return\n\t */\n\tpublic static String getAbsolutePath(String path){\n\t\tString codeRootNotHome=path.replace(\"~\", System.getProperty(\"user.home\"));\n\t\tFile cR = new File(codeRootNotHome);\n\t\tif (cR.exists()){\n\t\t\treturn codeRootNotHome;\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\tpublic static void  printStringArray(ArrayList<String> aL){\n\t\tfor (String s:aL)\n\t\t\tOutBut.printNormal(s);\n\t}\n\t\t\n}\n"
  },
  {
    "path": "src/main/java/base/SearchUtil.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n//import org.apache.commons.io.FileUtils;\n\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class SearchUtil {\n\t\t\n\t/**\n\t * Search for a key in a directory\n\t * @param path\n\t * @param key\n\t * @return ArrayList<String> All lines containing this key\n\t */\n\tpublic ArrayList<String> search4KeyInDir(String path, String key){\n\t\tList<File> files = this.search4FileInDir(path, null);\n\t\tArrayList<String> hits = new ArrayList<String>();\n\t\t\n\t\tfor (File f : files){\n\t\t\tArrayList<String> results = this.findInFile(f, key);\n\t\t\thits.addAll(results);\n\t\t}\n\t\t\n\t\treturn hits;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Searches for a key in a directory and returns the hits and their file names\n\t * @param path\n\t * @param key\n\t * @return ArrayList<SimpleEntry> of all lines containing this key and the file name of each hit\n\t */\n\tpublic ArrayList<SimpleEntry> search4KeyInDirFName(String path,String key){\n\t\tArrayList<SimpleEntry> hits = new ArrayList<>();\n\t\tList<File> files = this.search4FileInDir(path, null);\n\t\tfor (File f : files){\n\t\t\tArrayList<String> results = this.findInFile(f, key);\n\t\t\t//Print file path instead of just the name (better results for obfuscated code)\n\t\t\tString fName = f.getAbsolutePath();\n\t\t\tfor (String s:results){\n\t\t\t\tSimpleEntry e = new SimpleEntry<String, String>(fName, s);\n\t\t\t\thits.add(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn hits;\n\t}\n\t\n\t/**\n\t * Squeeze code located in a custom location\n\t * @param key\n\t * @param codeLoc\n\t * @return\n\t */\n\tpublic ArrayList<SimpleEntry> searchForKeyInJava(String key, String codeLoc){\n\t\t\n\t\tArrayList<SimpleEntry> hits = new ArrayList<>();\n\t\tList<File> files = this.search4FileInDir(codeLoc, null);\n\t\tfor (File f : files){\n\t\t\tString fName = f.getAbsolutePath();\n\t\t\tif (!fName.contains(\"com/google\") && !fName.contains(\"android/support\")){\n\t\t\t\tArrayList<String> results = this.findInFile(f, key);\n\t\t\t\tfor (String s:results){\n\t\t\t\t\tSimpleEntry e = new SimpleEntry<String, String>(fName, s);\n\t\t\t\t\thits.add(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn hits;\n\t}\n\t\n\tpublic ArrayList<SimpleEntry> searchForKeyInJava(String key){ \n\t\treturn this.searchForKeyInJava(key, TicklerVars.jClassDir);\n\t}\n\t\n\t/**\n\t * After searching for a key in files (which is faster), Refine the search by searching for a regex in the first search's result. \n\t * @param eArray\n\t * @param regex\n\t * @return\n\t */\n\tpublic ArrayList<SimpleEntry> refineSearch(ArrayList<SimpleEntry> eArray, String regex){\n\t\tArrayList<SimpleEntry> result = new ArrayList<>();\n\t\tArrayList<String> regexResult = new ArrayList<>();\n\t\tfor (SimpleEntry e: eArray){\n\t\t\tregexResult = OtherUtil.getRegexFromString(e.getValue().toString(), regex);\n\t\t\tif (!regexResult.isEmpty())\n\t\t\t\tresult.add(e);\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * USed with multiline comments disclosure for now.\n\t * \n\t * @param eArray\n\t * @param regex\n\t * @return\n\t */\n\tpublic ArrayList<SimpleEntry> refineSearchMatch(ArrayList<SimpleEntry> eArray, String regex){\n\t\tArrayList<SimpleEntry> result = new ArrayList<>();\n\n\t\tfor (SimpleEntry e: eArray){\n\t\t\t\t\tif (OtherUtil.isRegexInString(e.getValue().toString(), regex))\n\t\t\t\t\t\tresult.add(e);\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\n\t/**\n\t* Search for extensions in a directory (or list all files in directory)\n\t* @param path\n\t* @param extensions filter by extension types\n\t* @return\n\t*/\n\tpublic List<File> search4FileInDir(String path, String[] extensions){\n\t\tFileUtil fU = new FileUtil();\n//\t\tFile dir = new File(path);\n\t\tList<File> files;\n\t\tif (extensions != null){\n//\t\t\tfiles = (List<File>)FileUtils.listFiles(dir, extensions, true);\n\t\t\tfiles = fU.listFilesInDirContain(path, extensions);\n\t\t\t\n\t\t}\n\t\telse {\n//\t\t\tfiles = (List<File>)FileUtils.listFiles(dir, null, true);\n\t\t\tfiles = fU.listFilesInDir(path);\n\t\t}\n\t\treturn files;\n\t\t\n\t}\n\t\n\t/**\n\t * Search for a file on the host\n\t * @param path\n\t * @param key\n\t * @return\n\t */\n\tpublic String searchOnDevice(String path, String key){\n\t\tString command = \"find \"+path+ \" -name \"+key;\n\t\tCommando commando = new Commando();\n\t\tString result = commando.execRoot(command);\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t* Search for a key in a file (without regex)\n\t* @param f\n\t* @param key\n\t* @return\n\t*/\n\t\n\tpublic ArrayList<String> findInFile(File f, String key){\n\t\treturn this.searchInFile(f, key, false);\n\t}\n\t\n\t/**\n\t * Search for a regex in a file\n\t * @param f\n\t * @param regex\n\t * @return\n\t */\n\tpublic ArrayList<String> findRegexInFile(File f, String regex){\n\t\treturn this.searchInFile(f, regex,true);\n\t}\n\t\n\t\n\t/**\n\t* Searches for a key in a file, whether it is a normal string or a regex\n\t* The search is CASE INSENSITIVE\n\t* The main function for findInFile and findRegexInFile\n\t* @param f\n\t* @param key\n\t* @param regex true: search for regex, false: search for a String\n\t* @return\n\t*/\n\tprivate ArrayList<String> searchInFile(File f, String key,boolean regex){\n\t\tArrayList<String> results = new ArrayList<String>();\n\t\tString line;\n\t\t\n\t\ttry {\n\t\t\tBufferedReader reader = new BufferedReader(new FileReader(f));\n\t\t\twhile ((line =reader.readLine())!= null) {\n\t\t\t\tif (this.checkLineAndRegex(line,key,regex))\n\t\t\t\t\tresults.add(line);\n\t\t\t\t\n\t\t\t}\n\t\t\treader.close();\n\t\t\t\t\n\t\t}\n\t\tcatch (Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t\treturn results;\n\t}\n\t\n\t/**\n\t* Searches for a string in a line (CASE INSENSITIVE), or for a regex in a line\n\t* Considered the main check of findInFile and FindRegexInFile\n\t* @param line\n\t* @param key\n\t* @param regex\n\t* @return\n\t*/\n\tprivate boolean checkLineAndRegex(String line, String key, boolean regex){\n\t\tboolean result;\n\t\t//Search with regex\n\t\tif (regex){\n\t\t\tMatcher m = Pattern.compile(key).matcher(line);\n\t\t\tresult = m.matches();\n\t\t}\n\t\t//Normal contains()\n\t\telse\n\t\t{\n\t\t\tresult = line.toLowerCase().contains(key.toLowerCase());\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t\n\n\n\n}\n"
  },
  {
    "path": "src/main/java/base/Tickler.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\n\nimport java.io.File;\nimport java.util.ArrayList;\n\nimport org.apache.commons.codec.binary.StringUtils;\n\nimport actions.Comparer;\nimport actions.Searcher;\nimport actions.Snapshots;\nimport apk.Decompiler;\nimport apk.newApks.CreateApk;\nimport attacks.ActivityStarter;\nimport attacks.Broadcaster;\nimport attacks.StartAttack;\nimport cliGui.OutBut;\nimport code.JavaSqueezer;\nimport components.IActivityService;\nimport components.IComponent;\nimport components.Manifest;\nimport components.Receiver;\nimport db.DatabaseTester;\nimport device.Packagez;\nimport exceptions.TNotFoundEx;\nimport frida.FridaCli;\nimport info.InfoGathering;\nimport info.InfoGatheringReporting;\nimport info.ListComponents;\nimport initialization.TicklerChecks;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\nimport manifest.ManifestDealer;\n\npublic class Tickler {\n\tprivate Manifest manifest;\n\tprivate ManifestDealer dealer;\n\tprivate ActivityStarter actAttacker; \n\tprivate boolean isLog;\n\tprivate StartAttack startAttack;\n\tprivate DatabaseTester dbTest;\n\tprivate CreateApk newApk;\n\tprivate Searcher searcher;\n\tprivate CopyUtil copyz;\n\tprivate Snapshots snaps; \n\tprivate Comparer comps;\n\t\n\t// If offline not compatible --> raise exception when initalizeTicklerNoDevice runs (not to fuck up the whoile code)\n\tprivate boolean isOfflineCompatible = true;\n\tprivate boolean isDev=true;\n\n\t/**\n\t * \n\t * @param mode: Tickler's operation mode\n\t * \t\t- pkg:\tPackage mode (app) and device needed\n\t * \t\t- offline:\tPackage mode and device is not needed\n\t * \t\t- noPkg:\tApp not-related ops, such as generic snapshot\n\t * @param pkgName\n\t */\n\tpublic Tickler(String mode, String pkgName) {\n\t\tthis.inits();\n\t\t\n\t\t\n//\t\tif(mode.equals(\"pkg\")){\n//\t\t\tthis.ticklerPackageInit(pkgName);\n//\t\t}\n//\t\telse if (TicklerVars.pkgName == null){\n//\t\t\t\tTicklerChecks tc = new TicklerChecks();\n//\t\t\t\ttc.loadConfiguration();\n//\t\t\t\tTicklerVars.updateVars(\"NoPackage\");\t\t\t\t\t\t\t\t\n//\t\t}\n\t\t\n\t\tif (mode.equals(\"noPkg\")) {\n\t\t\tTicklerChecks tc = new TicklerChecks();\n\t\t\ttc.loadConfiguration();\n\t\t\tTicklerVars.updateVars(\"NoPackage\");\t\n\t\t\treturn;\n\t\t}\n\t\t\n\t\telse if (mode.equals(\"offline\")) {\n\t\t\tthis.isDev= false;\n\t\t\t\n\t\t}\n\t\t//else\n\t\t\tthis.ticklerPackageInit(pkgName, this.isDev);\n\t\t\t\n\t}\n\t/**\n\t * Instantiates necessary classes to start Tickler\n\t */\n\tprivate void inits() {\n\t\tthis.copyz = new CopyUtil();\n\t\tthis.snaps = new Snapshots();\n\t\tthis.comps = new Comparer();\n\t}\n\t\n\t/**\n\t * Initiates Tickler in Package mode, whether online or offline\n\t * @param pkgName\n\t * @param isDev\n\t */\n// For now isDev = true --> work online mode: needs a device alwasys connected\n\t\n\tprivate void ticklerPackageInit(String pkgName,boolean isDev){\n\t\t\n\t\ttry{\n\t\t\tthis.runTicklerChecks(pkgName, isDev);\n\t\t\tthis.dealer = new ManifestDealer();\n\t\t\tthis.dealer.meetThePackage(pkgName);\n\t\t\t\n\t\t\tif (!this.dealer.wasApkExist())\n\t\t\t\tthis.copyDataDir(null);\n\t\t}\n\t\tcatch(TNotFoundEx e)\n\t\t{\n\t\t\tOutBut.printError(e.getMessage());\n\t\t\tSystem.exit(0);\n\t\t}\n\t}\n\n\n\tprivate void runTicklerChecks(String pkgName, boolean isDev) throws TNotFoundEx {\n\t\tTicklerChecks tc = new TicklerChecks();\n\t\tif (isDev)\n\t\t\ttc.initiaizeTickler(pkgName);\n\t\telse\n\t\t\ttc.initalizeTicklerNoDevice(pkgName);\n\t}\n\t\n//////// Start components //////////\n\t\n\n\t\n\t/**\n\t * Start components (All vs. comp type, exported vs. all)\n\t * @param compType\n\t * @param exported\n\t */\n\tpublic void start(int compType, boolean exported){\n\t\t\n\t\tthis.prepareComponentAttack();\n\t\tthis.triggerGroup(compType, exported);\n\t}\n\t\n\t/**\n\t * Triggers groups of components (all or just one type, exported or not)\n\t * @param compType\n\t * @param exported\n\t */\n\tprivate void triggerGroup(int compType, boolean exported) {\n\t\t//1- Get components based on type and exported values\n\t\tArrayList<IComponent> components = this.dealer.getComponentsOfType(compType, exported);\n\t\t\n\t\t//2- Get commands strings\n\t\tArrayList<String> commands = this.startAttack.attackComponents(components);\n\t\t\n\t\t//3- Add Prov commands\n\t\tif ((compType == TicklerConst.PROVIDER || compType == TicklerConst.ALLCOMPS) && !exported){\n\t\t\tcommands.addAll(this.startAttack.queryUrisFromSmali());\n\t\t}\n\t\t\n\t\t//4- Start commands\n\t\tthis.startAttack.executeTriggerCommands(commands, exported);\n\t\t\n\t\t//5- Stop logger\n\t\tthis.startAttack.stopLogging();\n\t}\n\t\n\t\t/**\n\t\t * Trigger a component by name\n\t\t * @param compName\n\t\t */\n\tpublic void attackComponent(String compName){\n\t\tthis.prepareComponentAttack();\n\t\t\n\t\tif (this.dealer.isComponentExist(compName))\n\t\t{\n\t\t\tIComponent comp = this.dealer.getComponentByName(compName);\n\t\t\tArrayList<String> commands = this.startAttack.attackComponent(comp);\n\t\t\t\n\t\t\tthis.startAttack.executeTriggerCommands(commands, false);\n\t\t\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tOutBut.printError(\"No component of name \"+compName+\" found in the Manifest file\\n\"\n\t\t\t\t\t+ \"Use -l command to display all components of this app\");\n\t\t}\n\t\t\tthis.startAttack.stopLogging();\n\t}\n\t\n\t/**\n\t * Preparations before any kind of component triggering\n\t */\n\tpublic void prepareComponentAttack() {\n\t\t//1- Analyze manifest and get the components\n\t\tthis.dealer.analyzeManifest(TicklerVars.tickManifestFile);\n\t\t\n\t\t//2- Instantiate attacker\n\t\tthis.startAttack = new StartAttack();\n\t\t\n\t\t//3- Get Launchers but removed\n\t\t\n\t\t//4- Set logger to True, in order to write the command in the file\n\t\tthis.startAttack.setLogger(this.isLog);\n\t\t\n\t\t//5- Init TicklerGeneral.schemes to complete dataURI Intents\n\t\tTicklerGeneral.schemes = new ArrayList<String>();\n\t}\n\t\n\n///////////// copy  /////////////////\n\t/**\n\t *  Copy local and external data directories of the app to the Tickler folder\n\t * @param name\n\t */\n\t\n\tpublic void copyDataDir(String name){\n\t\t\n\t\tcopyz.copyStorage(name);\n//\t\tcopyz.copyDataDirName(name);\n//\t\tcopyz.copyDataDir(name+\"/DataDir\");\n//\t\tcopyz.copyExtDir(name+\"/ExtDataDir\");\n\t\t\n\t}\n\t\n\t//Copy any file / directory from the device to the host\n\tpublic void copyToHost(String src, String dest){\n\t\n\t\tcopyz.copyToHost(src, dest);\n\t}\n\t\n\t\n\t///////////////////////////// Databases //////////////////////////\n\t/**\n\t * Handles DB actions (check encryption, list DB, search)\n\t * @param param\t\tDatabase action\n\t * @param isCopy\tif false, don't update DataDir\n\t */\n\tpublic void databases(String param,boolean isCopy){\n\t\tthis.dbTest= new DatabaseTester();\n\t\t\n\t\t// Update DataDir?\n\t\tif (isCopy) {\n\t\t\t// Update DataDir whether it exists or not\n\t\t\tOutBut.printStep(\"Updating Data Directory\");\n\t\t\tthis.copyDataDir(null);\n\t\t}\n\t\t\n\t\tthis.dbTest.dbOption(param);\n\t}\n\t\n\t//////////////////// Other functions //////////////////\n\t\n\tpublic void snapshot(){\n\t\t\n\t\tthis.snaps.takeSnapshot();\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * Create a debuggable version of the app\n\t */\n\tpublic void createDebuggable(){\n\t\tthis.newApk = new CreateApk(TicklerConst.debuggable);\n\t\tthis.newApk.createNewApk();\n\t}\n\t\n\t/**\n\t * Solves the MitM issue with Android Nougat (netsecConfiguration)\n\t */\n\tpublic void createNougatMitM(){\n\t\tthis.newApk = new CreateApk(TicklerConst.mitm);\n\t\tthis.newApk.createNewApk();\n\t}\n\t\n\tpublic void createCustomAPK(String dir, String name){\n\t\tthis.newApk = new CreateApk(10);\n\t\tthis.newApk.createAnyApk(dir, name);\n\t}\n\n\tpublic void decompileApk(){\n\t\tDecompiler d2j = new Decompiler();\n\t\td2j.dex2jar();\n\t}\n\t\n\t/**\n\t * Copies the directory of background images from the android device to the host\n\t */\n\tpublic void backgroundSnapshots(){\n\t\t\n\t\tthis.snaps.getBackGroundSnapshots();\n\t}\n\t\n\n\t//Copy data directory twice, while you can go crazy in between. Then compares the 2 directories\n\tpublic void diffDataDir(String detailed){\n\t\tOutBut.printH1(\"Data Directory changes\");\n\t\tif (detailed == null)\n\t\t\tthis.comps.diff(false);\n\t\telse if (detailed.equalsIgnoreCase(\"detailed\")|| detailed.equalsIgnoreCase(\"d\"))\n\t\t\tthis.comps.diff(true);\n\t\telse{\n\t\t\tSystem.out.println(\"!!!!!!! WARNING: unknown parameter '\"+detailed+\"'. \\n\"\n\t\t\t\t\t+ \"!!!!!!! Showing only the names of the changed files\\n\"\n\t\t\t\t\t+ \"!!!!!!! For detailed comparison use -diff detailed or -diff d flag\\n\");\n\t\t\tthis.comps.diff(false);\n\t\t}\n\t}\n\t\n\t/**\n\t * Print version number\n\t */\n\tpublic void version(){\n\t\tOutBut.printNormal(\"Tickler version: \"+TicklerConst.version);\n\t}\n\t///////////////////// List ////////////////////\n\t\n\t\n\tpublic void list(int compType, boolean exported,boolean details){\n\t\tListComponents list = new ListComponents();\n\t\tlist.listThis(compType, exported,details);\n\t}\n\t\n\t\n\tpublic void listComponent(String compName){\n\t\tListComponents list = new ListComponents();\n\t\tlist.listComponent(compName);\n\t}\n\t\n\t///////////// General Information /////////////\n\tpublic void informationGathering() {\n\t\tInfoGatheringReporting infoRep = new InfoGatheringReporting();\n\t\tinfoRep.report();\n\t}\n\n\tpublic void printPackages(){\n\t\tPackagez pkgz = new Packagez();\n\t\tpkgz.printInstalledPkgs();\n\t}\n\t\n\tpublic void squeezeCode(String codeLoc){\n\t\tJavaSqueezer disc = new JavaSqueezer();\n\t\t\n\t\tif (codeLoc != null && codeLoc.equals(\"short\")){\n\t\t\tint index1 = TicklerVars.pkgName.indexOf('.')+1;\n\t\t\tString subloc= TicklerVars.pkgName.substring(0,TicklerVars.pkgName.indexOf('.', index1));\n\t\t\tcodeLoc = TicklerVars.jClassDir+\"/\"+subloc.replaceAll(\"\\\\.\", \"/\");\n\t\t}\n\t\tdisc.report(codeLoc);\n\t}\n\t\n\t//Neglecting jsonFile at the moment\n\tpublic void squeezeJSON(String jsonLoc) {\n\t\tJavaSqueezer disc = new JavaSqueezer();\n\t\tdisc.squeezeJson(jsonLoc);\n\t}\n\t\n\t/////////////// Search //////////////////\n\tpublic void searchPackage(String key){\n\t\tPackagez pkgz = new Packagez();\n\t\tpkgz.searchPackage(key,true);\n\t}\n\t\n\n\t\n\tpublic void searchInCode(String key,String codeLoc){\n\t\tthis.searcher = new Searcher();\n\t\tthis.searcher.scCustomCodeLoc(key, codeLoc);\n//\t\tthis.searcher.sC(key,false);\n\t}\n\t\n\tpublic void searchInCodeAll(String key){\n\t\tthis.searcher = new Searcher();\n\t\tthis.searcher.sC(key,true);\n\t}\n\t\n\tpublic void searchInDataDir(String key, boolean isCopy){\n\t\tthis.searcher = new Searcher();\n\t\tthis.searcher.searchForKeyInDataDir(key,isCopy);\n\t}\n\t\n\tpublic void b64Search(String key)\n\t{\n\t\tBase64Util b64 = new Base64Util();\n\t\tArrayList<String> result = b64.searchB64inDir(TicklerVars.dataDir, key);\n\t\t\n\t\tfor (String s : result)\n\t\t\tOutBut.printNormal(s);\n\t}\n\t\n\n\tpublic boolean isLog() {\n\t\treturn isLog;\n\t}\n\n\tpublic void setLog(boolean log) {\n\t\tthis.isLog = log;\n\t\tFileUtil ft=new FileUtil();\n\t\tft.createDirOnHost(TicklerVars.logDir);\n\t}\n\t\n\t///////////////////////////// Frida //////////////////////////////\n\t\n\tpublic void frida(String[] args, boolean reuse){\n\t\tFridaCli fridaCli = new FridaCli();\n\t\tfridaCli.fridaThis(args, reuse);\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/base/TicklerGeneral.java",
    "content": "package base;\n\nimport java.util.ArrayList;\n\npublic class TicklerGeneral {\n\t\n\t//Static Arraylist containing all Data URI schemes. Used to replace $scheme in intents\n\tpublic static ArrayList<String> schemes;\n\n}\n"
  },
  {
    "path": "src/main/java/base/XMLReader.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.awt.List;\nimport java.io.File;\nimport java.util.ArrayList;\nimport javax.xml.bind.JAXBContext;\nimport javax.xml.bind.Unmarshaller;\nimport javax.xml.bind.UnmarshallerHandler;\nimport attacks.ActivityStarter;\nimport attacks.Broadcaster;\n//import brut.androlib.ApktoolProperties;\nimport components.Manifest;\n\n/**\n * Marshal and Unmarshal Manifest file\n * Unused since v2.3\n * @author aabolhadid\n *\n */\npublic class XMLReader{\n\tprivate String manifestFile;\n\tprivate Manifest manifest;\n\t\n\tpublic XMLReader(String manifestFile) {\n\t\tthis.manifestFile = manifestFile;\n\t\tthis.unmarshalManifest();\n\t}\n\n\tpublic void unmarshalManifest() {\n\t\tManifest man=new Manifest();\n\t\tFile manifest = new File(this.manifestFile);\n\t\t\n\t\ttry {\n\t        \n\t\t\tJAXBContext context = JAXBContext.newInstance(Manifest.class);\n\t\t\tUnmarshaller jaxbUnmarshaller = context.createUnmarshaller();\n\t\t\tman = (Manifest) jaxbUnmarshaller.unmarshal(manifest);\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\tSystem.out.println(\"ERROR: Manifest cannot be parsed\");\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tthis.manifest = man;\n\t}\n\t\n\tpublic Manifest getManifest() {\n\t\treturn this.manifest;\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/cliGui/OutBut.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage cliGui;\n\npublic class OutBut {\n\t\n\t// Colors\n\tprivate static final String ANSI_RESET = \"\\u001B[0m\";\n\tprivate static final String ANSI_BOLD = \"\\u001B[1m\";\n\tprivate static final String ANSI_RED = \"\\u001B[31m\";\n\tprivate static final String ANSI_BLUE = \"\\u001B[34m\";\n\n\n\tpublic static void printH1(String line){\n\t\tString opLine = \"\\n=================================================================\\n\\t\\t\";\n\t\topLine+=ANSI_BOLD+line+ANSI_RESET;\n\t\topLine+=\"\\n=================================================================\\n\";\n\t\t\n\t\tSystem.out.println(opLine);\n\t}\n\t\n\tpublic static void printH2(String line){\n\t\tSystem.out.println(\"\\n===================== \"+line +\" =====================\");\n\t}\n\t\n\tpublic static void printH3(String line){\n\t\tint length = line.length();\n\t\tString underline=\"\";\n\t\t\n\t\tfor (int i=0;i<length;i++)\n\t\t\tunderline+=\"-\";\n\t\t\n\t\tSystem.out.println(line+\"\\n\"+underline);\n\t}\n\t\n\tpublic static void printStep(String line){\n\t\tSystem.out.println(\">>>>>>>> \"+line);\n\t}\n\t\n\tpublic static void printWarning(String line){\n\t\tSystem.out.println(\"!!!!!!!! WARNING: \"+line);\n\t}\n\t\n\tpublic static void printError(String line){\n\t\tSystem.out.println(ANSI_RED+ANSI_BOLD+\"XXXXX ERROR: \"+line +\" XXXXX\"+ANSI_RESET);\n\t}\n\t\n\t/**\n\t * Currently just prints as syso\n\t * @param line\n\t */\n\tpublic static void printNormal(String line){\n\t\tSystem.out.println(line);\n\t}\n\t\n\tpublic static void printH1Blue(String line){\n\t\tString opLine = ANSI_BLUE+\"=============================================\\n\\t\";\n\t\topLine+=line;\n\t\topLine+=\"\\n=============================================\"+ANSI_RESET;\n\t\t\n\t\tSystem.out.println(opLine);\n\t}\n}\n"
  },
  {
    "path": "src/main/java/cliGui/TicklerCLI.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage cliGui;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.cli.BasicParser;\nimport org.apache.commons.cli.CommandLine;\nimport org.apache.commons.cli.CommandLineParser;\nimport org.apache.commons.cli.MissingArgumentException;\nimport org.apache.commons.cli.Option;\nimport org.apache.commons.cli.OptionBuilder;\nimport org.apache.commons.cli.Options;\nimport org.apache.commons.cli.UnrecognizedOptionException;\n\nimport code.JavaSqueezer;\nimport exceptions.TNotFoundEx;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport base.Tickler;\nimport frida.FridaInit;\nimport frida.FridaEnumerateClasses;\nimport frida.FridaPythonScript;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\n\npublic class TicklerCLI {\n\tprivate Options options;\n\tprivate CommandLineParser parser;\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\tTicklerCLI cli = new TicklerCLI();\n\n\t\tcli.parser = new BasicParser();\n\t\tcli.options = new Options();\n\t\t\n\t\tOption findPkg = new Option(\"findPkg\",null, true, \"Search for a package name\");\n\t\tOption listPack = new Option(\"pkgs\",null, false,\"List all installed packages on this device\");\n\t\n\t\tOption pkg = new Option(\"pkg\",null, true, \"Name of an installed package\");\n\t\tOption trigger = new Option(\"t\",\"trigger\",false,\"Start components\");\n\t\tOption all = new Option(\"all\",null,false,\"Start all components\");\n\t\tOption exp = new Option(\"exp\",null,false,\"Apply only to Exported components\");\n\t\tOption attackComp = new Option(\"comp\",null, true, \"Attack a specific component. The name should be as in the manifest file\");\n\t\tOption help = new Option(\"h\", \"help\", false, \"Print this help menu\");\n\t\tOption activities = new Option(\"act\",\"activities\",false,\"Attack all activities\");\n\t\tOption services = new Option(\"ser\",\"services\",false,\"Attack all services\");\n\t\tOption providers = new Option(\"prov\",\"providers\",false,\"Attack all content providers\");\n\t\tOption receivers = new Option(\"rec\",\"receivers\",false,\"Attack all broadcast receivers\");\n\t\tOption list = new Option(\"l\",\"list\",false,\"List components\");\n\t\tOption info = new Option(\"i\",\"info\",false,\"List information about the app\");\n\t\tOption snap = new Option(\"screen\",\"screenshot\",false,\"takes a snapshot of the device's screen\");\n//\t\tOption searchInCode = new Option(\"sc\",\"searchCode\",true,\"Search for a specific key in Java code\");\n\t\tOption searchInCodeAll = new Option(\"sc_all\",null,true,\"Search for a specific key in Java code\");\n\t\tOption searchInSandbox = new Option(\"sd\",\"searchDataDir\",true, \"Search for a key in the Data Dir of an app (Files and DB)\");\n\t\tOption log = new Option(\"log\",null,false,\"capture LogCat messages\");\n\t\tOption details = new Option(\"v\",null,false,\"List in details\");\n\t\tOption bgSnap = new Option(\"bg\",\"backGroundSnapshots\",false,\"Get Background images from the device\");\n\t\tOption debuggable = new Option(\"dbg\",\"debuggable\",false,\"Create a debuggable APK\");\n\t\tOption decompile = new Option(\"decomp\",null,false, \"decompile apk into java code\");\n\t\tOption version = new Option(\"version\",null,false, \"Print version\");\n\t\tOption noCopy = new Option(\"nu\",\"noUpdate\",false, \"Doesn't update DataDir before execution (with db and big dataDir)\");\n\t\tOption mitm = new Option(\"mitm\",null,false, \"Allows user CA in Android 7\");\n\t\tOption fridaReuse = new Option(\"reuse\",null,false, \"Reuse existing Frida JS\");\n\t\tOption offline = new Option(\"offline\",null,false, \"Offline Mode, no devices needed to be connected\");\n\t\t\n\t\tOption copy2host = OptionBuilder.create(\"cp2host\");\n\t\tcopy2host.setOptionalArg(true);\n\t\tcopy2host.setArgs(2);\n\t\t\n\t\tOption diffDir = OptionBuilder.create(\"diff\");\n\t\tdiffDir.setOptionalArg(true);\n\t\tdiffDir.setArgs(2);\n\t\t\n\t\tOption db = OptionBuilder.create(\"db\");\n\t\tdb.setOptionalArg(true);\n\t\tdb.setArgs(1);\n\t\t\n\t\tOption dataDir = OptionBuilder.create(\"dataDir\");\n\t\tdataDir.setOptionalArg(true);\n\t\tdataDir.setArgs(1);\n\t\t\n\t\tOption squeeze = OptionBuilder.create(\"squeeze\");\n\t\tsqueeze.setOptionalArg(true);\n\t\tsqueeze.setArgs(1);\n\t\t\n\t\tOption sc = OptionBuilder.create(\"sc\");\n\t\tsc.setOptionalArg(true);\n\t\tsc.setArgs(2);\n\t\t\n\t\tOption apk = OptionBuilder.create(\"apk\");\n\t\tapk.setArgs(2);\n\t\t\n\t\tOption frida = OptionBuilder.create(\"frida\");\n\t\tfrida.setOptionalArg(true);\n\t\tfrida.setArgs(6);\n\t\t\n\t\tOption squeezeJSON = OptionBuilder.create(\"sq\");\n\t\tsqueezeJSON.setArgs(2);\n\t\t\n\t\tcli.options.addOption(pkg);\n\t\tcli.options.addOption(trigger);\n\t\tcli.options.addOption(all);\n\t\tcli.options.addOption(exp);\n\t\tcli.options.addOption(attackComp);\n\t\tcli.options.addOption(diffDir);\n\t\tcli.options.addOption(db);\n\t\tcli.options.addOption(help);\n\t\tcli.options.addOption(activities);\n\t\tcli.options.addOption(services);\n\t\tcli.options.addOption(providers);\n\t\tcli.options.addOption(receivers);\n\t\tcli.options.addOption(list);\n\t\tcli.options.addOption(info);\n\t\tcli.options.addOption(findPkg);\n\t\tcli.options.addOption(listPack);\n\t\tcli.options.addOption(snap);\n\t\tcli.options.addOption(sc);\n\t\tcli.options.addOption(searchInCodeAll);\n\t\tcli.options.addOption(searchInSandbox);\n\t\tcli.options.addOption(log);\n\t\tcli.options.addOption(bgSnap);\n\t\tcli.options.addOption(debuggable);\n\t\tcli.options.addOption(copy2host);\n\t\tcli.options.addOption(details);\n\t\tcli.options.addOption(dataDir);\n\t\tcli.options.addOption(decompile);\n\t\tcli.options.addOption(squeeze);\n\t\tcli.options.addOption(version);\n\t\tcli.options.addOption(noCopy);\n\t\tcli.options.addOption(mitm);\n\t\tcli.options.addOption(apk);\n\t\tcli.options.addOption(frida);\n\t\tcli.options.addOption(fridaReuse);\n\t\tcli.options.addOption(offline);\n\t\tcli.options.addOption(squeezeJSON);\n\t\t\n\t\t\n\t\ttry {\n\t\t\t\n\t\t\tCommandLine cl = cli.parser.parse(cli.options, args,false);\n\t\t\t\n\t\t\tcli.startTickler(cl);\n\t\t\t\n\t\t}\n\t\tcatch(UnrecognizedOptionException e){\n\t\t\tOutBut.printError(\"Unrecognized option \"+e.getOption());\n\t\t\tSystem.out.println(TicklerConst.helpMessage);\n\t\t}\n\t\tcatch(MissingArgumentException e){\n\t\t\tOutBut.printError(\"Missing parameter of option \"+e.getOption().getOpt());\n\t\t\tSystem.out.println(TicklerConst.helpMessage);\n\t\t}\n\t\t\n\t\tcatch(TNotFoundEx te) {\n\t\t\tOutBut.printError(te.getMessage());\n\t\t}\n\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t}\n\t\n\t\n\tpublic void startTickler(CommandLine cl) throws TNotFoundEx{\n\t\tboolean exported = false;\n\t\tboolean details = false;\t\t\n\t\tint target = TicklerConst.ALLCOMPS;\n\t\tString mode = \"pkg\";\n\t\t\n\t\t\n\t\tif (cl.hasOption(\"offline\")) {\n\t\t\tthis.checkOfflineFeasibility(cl);\n\t\t\tmode = \"offline\";\n\t\t\tTicklerVars.isOffline = true;\n\t\t}\n\t\t\n\t\tif (cl.hasOption(\"h\") || cl.hasOption(\"help\"))\n\t\t{\n\t\t\tSystem.out.println(TicklerConst.helpMessage);\n\n\t\t}\n\t\t\n\t\tif (cl.hasOption(\"findPkg\")){\n\t\t\tTickler t = new Tickler(\"noPkg\", \"findPkg\");\n\t\t\tt.searchPackage(cl.getOptionValue(\"findPkg\"));\n\t\t}\n\t\tif (cl.hasOption(\"pkgs\")){\n\t\t\tTickler t = new Tickler(\"noPkg\", \"pkgs\");\n\t\t\tt.printPackages();\n\t\t}\n\t\t\n\n\t\t\n\t\t////////////////////////////////// Pkg /////////////////////////////\n\t\tif (cl.hasOption(\"pkg\")) {\n\t\t\t\n\t\t\tTickler t = new Tickler(mode, cl.getOptionValue(\"pkg\"));\n\t\t\t\n\t\t\tif (cl.hasOption(\"exp\"))\n\t\t\t\texported = true;\n\t\t\t\n\t\t\t//Logcat\n\t\t\tif (cl.hasOption(\"log\")){\n\t\t\t\tt.setLog(true);\n\t\t\t}\n\t\t\telse if (cl.hasOption(\"mitm\")){\n\t\t\t\tt.createNougatMitM();\n\t\t\t}\n\t\t\telse if (cl.hasOption(\"debuggable\")){\n\t\t\t\tt.createDebuggable();\n\t\t\t}\n\t\t\telse if (cl.hasOption(\"apk\")){\n\t\t\t\tString[] apkArgs = cl.getOptionValues(\"apk\");\n\t\t\t\tt.createCustomAPK(apkArgs[0], apkArgs[1]);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t///// Targets\n\t\t\t\n\t\t\t\n\t\t\tList<String> args = cl.getArgList();\n\t\t\t\n\t\t\tif (cl.hasOption(\"act\"))\n\t\t\t\ttarget =TicklerConst.ACTIVITY;\n\t\t\t\n\t\t\telse if (cl.hasOption(\"ser\"))\n\t\t\t\ttarget = TicklerConst.SERVICE;\n\t\t\t\n\t\t\telse if (cl.hasOption(\"prov\"))\n\t\t\t\ttarget = TicklerConst.PROVIDER;\n\t\t\t\n\t\t\telse if (cl.hasOption(\"rec\"))\n\t\t\t\ttarget = TicklerConst.RECEIVER;\n\t\t\t\t\t\t\n\t\t\t\n\t\t\t////////// Actions /////////////\n\t\t\t//Trigger\n\t\t\tif (cl.hasOption(\"trigger\") || cl.hasOption(\"t\") ){\n\t\t\t\t//Trigger a component\n\t\t\t\tif (cl.hasOption(\"comp\")){\n\t\t\t\t\tt.attackComponent(cl.getOptionValue(\"comp\")); \n\t\t\t\t}\n\t\t\t\t//Component name is added without -comp flag\n\t\t\t\telse if (!args.isEmpty()){\n\t\t\t\t\tt.attackComponent(args.get(0));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tt.start(target, exported);\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t////List components \n\t\t\telse if (cl.hasOption(\"l\")||cl.hasOption(\"list\")){\n\t\t\t\tif (cl.hasOption(\"v\")){\n\t\t\t\t\tdetails=true;\n\t\t\t\t}\n\t\t\t\t//List a specific component\n\t\t\t\tif (cl.hasOption(\"comp\")){\n\t\t\t\t\tt.listComponent(cl.getOptionValue(\"comp\"));\n\t\t\t\t}\n\t\t\t\t// a component name without -comp flag\n\t\t\t\telse if (!args.isEmpty()){\n\t\t\t\t\tt.listComponent(args.get(0));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tt.list(target,exported,details);\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t//Search in Code\n\t\t\telse if (cl.hasOption(\"sc\") || cl.hasOption(\"searchCode\")){\n\t\t\t\t\n\t\t\t\tString[] scArgs = cl.getOptionValues(\"sc\");\n\t\t\t\tString key = scArgs[0];\n\t\t\t\tString loc = null;\n\t\t\t\tif (scArgs.length >1){\n\t\t\t\t\tloc = scArgs[1];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tt.searchInCode(key,loc);\n\t\t\t}\n\t\t\t\n\t\t\telse if (cl.hasOption(\"sc_all\") )\n\t\t\t\tt.searchInCodeAll(cl.getOptionValue(\"sc_all\"));\n\t\t\t\n\t\t\t// Update Data directory?\n\t\t\tboolean isCopy=true;\n\t\t\tif (cl.hasOption(\"noUpdate\") || cl.hasOption(\"nu\"))\n\t\t\t\tisCopy = false;\n\t\t\t\n\t\t\t// Search for a key in DataDir files and Unencrypted Databases \n\t\t\telse if (cl.hasOption(\"sd\")) {\n\t\t\t\tt.searchInDataDir(cl.getOptionValue(\"sd\"), isCopy);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t//Diff data directory before and after an operation\n\t\t\telse if (cl.hasOption(\"diff\")) \n\t\t\t\tt.diffDataDir(cl.getOptionValue(\"diff\"));\n\t\t\t\n\t\t\t//Check encryption of Databases\n\t\t\telse if (cl.hasOption(\"db\")){\n\t\t\t\t\n\t\t\t\tt.databases(cl.getOptionValue(\"db\"),isCopy);\n//\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t//Information\n\t\t\telse if (cl.hasOption(\"info\"))\n\t\t\t\tt.informationGathering();\n\t\t\t\n\t\t\t//Disclosure\n\t\t\telse if (cl.hasOption(\"squeeze\")){\n\t\t\t\tString codeLoc = cl.getOptionValue(\"squeeze\");\n\t\t\t\tt.squeezeCode(codeLoc);\n\t\t\t}\n\t\t\t\n\t\t\telse if (cl.hasOption(\"sq\")){\n\t\t\t\tString jsonLoc = cl.getOptionValue(\"sq\");\n\t\t\t\tt.squeezeJSON(jsonLoc);\n\t\t\t}\n\t\t\t\n\t\t\telse if (cl.hasOption(\"dataDir\")){\n\t\t\t\tString dest = cl.getOptionValue(\"dataDir\");\n\t\t\t\tt.copyDataDir(dest);\n\t\t\t}\n\t\t\t\t\n\t\t\t\n\t\t\telse if (cl.hasOption(\"decomp\"))\n\t\t\t\tt.decompileApk();\n\t\t\t\n\t\t\telse if (cl.hasOption(\"frida\")){\n\t\t\t\tboolean reuse = false;\n\t\t\t\tif (cl.hasOption(\"reuse\"))\n\t\t\t\t\treuse = true;\n\t\t\t\tString[] fridaArgs = cl.getOptionValues(\"frida\");\n\t\t\t\tt.frida(fridaArgs,reuse);\n\t\t\t}\n\t\t\t\n\t\t\tif(cl.hasOption(\"screen\")){\t\t\n\n\t\t\t\tt.snapshot();\n\t\t\t}\n\t\t\t\n\t\t\t// Background screenshots\n\t\t\tif (cl.hasOption(\"bg\")){\n\t\t\t\t//t = new Tickler(\"snapshot\", \"snapshot\");\n\t\t\t\tt.backgroundSnapshots();\n\t\t\t}\n\t\t\t\n\t\t\tif (cl.hasOption(\"cp2host\")){\n//\t\t\t\tTickler t = new Tickler(\"snapshot\",\"shanpshot\");\n\t\t\t\tString[] args2 = cl.getOptionValues(\"cp2host\");\n\t\t\t\tString src = args2[0];\n\t\t\t\tString dest;\n\t\t\t\tif (args2.length >1){\n\t\t\t\t\tdest = args2[1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdest = null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tt.copyToHost(src, dest);\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t//////////////////////////// With or without PKG /////////////////////////\n\t\t\n\t\tTickler t;\n\t\t//package\n\t\tif (! cl.hasOption(\"pkg\")) {\n\n\t\t\tt = new Tickler(\"noPkg\", \"snapshot\");\n\t\t\n\t\t// Snapshot, with or without package name\n\t\t\tif(cl.hasOption(\"screen\")){\t\t\n\t\n\t\t\t\tt.snapshot();\n\t\t\t}\n\t\t\t\n\t\t\t// Background screenshots\n\t\t\tif (cl.hasOption(\"bg\")){\n\t\t\t\t//t = new Tickler(\"snapshot\", \"snapshot\");\n\t\t\t\tt.backgroundSnapshots();\n\t\t\t}\n\t\t\t\n\t\t\tif (cl.hasOption(\"cp2host\")){\n\t//\t\t\tTickler t = new Tickler(\"snapshot\",\"shanpshot\");\n\t\t\t\tString[] args = cl.getOptionValues(\"cp2host\");\n\t\t\t\tString src = args[0];\n\t\t\t\tString dest;\n\t\t\t\tif (args.length >1){\n\t\t\t\t\tdest = args[1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdest = null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tt.copyToHost(src, dest);\n\t\t\t}\n\t\t}\n\t\t\n\t\t//Version\n\t\tif (cl.hasOption(\"version\")){\n\t\t\tTickler t2 = new Tickler(\"noPkg\",\"version\");\n\t\t\tt2.version();\n\t\t}\n\t}\n\t\n\tpublic void executeLogcat(String command, File logFile){\n\t\tProcess process;\n\t\ttry {\n\t\t\tprocess=Runtime.getRuntime().exec(command);\n\t\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\tPrintWriter writer = new PrintWriter(logFile);\n\t\t\tString line = \"\";\t\t\t\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\twriter.println(\"line\");\n\t\t\t}\n\t\t\t\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Migrated from TicklerChecks not to fuck with the whole code\n\t * @param command\n\t */\n\tpublic void checkOfflineFeasibility(CommandLine cli) throws TNotFoundEx {\n\t\tString [] offlineCommands = {\"findPkg\", \"pkgs\", \"log\", \"diff\", \"dataDir\", \"t\", \"screen\", \"bg\", \"cp2host\", \"frida\"};\n\t\t\n\t\tfor (String opt:offlineCommands) {\n\t\t\tif (cli.hasOption(opt)) {\n\t\t\t\tthrow new TNotFoundEx(\"Tickler command \"+opt+\" is not compatible with offline mode\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/code/ClassExtras.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage code;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n//import org.apache.commons.io.FileUtils;\n//import org.apache.commons.io.filefilter.TrueFileFilter;\n//import org.apache.commons.io.filefilter.WildcardFileFilter;\n\nimport base.FileUtil;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport initialization.TicklerVars;\n\n/**\n * EXtract extras from Java classes of every component\n * @author aabolhadid\n *\n */\npublic class ClassExtras {\n\t\n\tprivate String className;\n\tprivate Collection <File> files;\n\tprivate ArrayList<String> types, names, defaults,commands;\n\n\tpublic ClassExtras(String className){\n\t\tthis.className = className;\n\t\tthis.types = new ArrayList<>();\n\t\tthis.names = new ArrayList<>();\n\t\tthis.defaults = new ArrayList<>();\n\t\tthis.commands = new ArrayList<>();\n\t}\n\t\n\tpublic void process(){\n\t\t\n\t\tthis.getClassFiles();\n\t\tfor (File f : this.files){\t\t\n\t\t\tthis.getExtrasOfClass(f);\n\t\t}\n\t}\n\t\n\t/**\n\t * Gets the files whose names contain the class name\n\t */\n\tprivate void getClassFiles(){\n\t\tFileUtil fU = new FileUtil();\n\t\tString[] classNameArr = {this.className};\n\t\t\n//\t\tthis.files = FileUtils.listFiles( new File(TicklerVars.jClassDir), new WildcardFileFilter(\"*\" + this.className + \"*\"), TrueFileFilter.TRUE);\n\t\tthis.files = fU.listFilesInDirContain(TicklerVars.jClassDir, classNameArr);\n\t}\n\t\n\t\n\t/**\n\t * gets class name and searches for it in the Java class dir.\n\t * Then searches in each of these files for the names, types and the default values of each extra\n\t * regex *? to make the wildcard not gready and end with the first boundary\n\t * @param f\n\t * @return\n\t */\n\tpublic void getExtrasOfClass(File file){\n\t\tArrayList<String> extras = this.getExtraLines(file, this.className);\n\t\tfor (String line : extras){\t\t\n\t\t\tthis.types.addAll(OtherUtil.getRegexFromString(line, \"get(\\\\w+?)Extra\"));\n\t\t\tthis.names.addAll( OtherUtil.getRegexFromString(line, \"get\\\\w+?Extra\\\\(\\\"(.*?)\\\"\") );\n\t\t\tthis.defaults.addAll( OtherUtil.getRegexFromString(line, \".*Extra\\\\(.*,(.*?)\\\\)\") );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * return lines of the file \"file\" that contain the pattern get*Extra\n\t * @param file\n\t * @param className\n\t * @return\n\t */\n\tprivate ArrayList<String> getExtraLines(File file, String className){\n\t\tSearchUtil sr = new SearchUtil();\n\t\tArrayList<String> extras = sr.findRegexInFile(file, \".*get(.*)Extra.*\");\n\t\treturn extras;\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * returns the parts of syntax of all extras, but avoiding any duplicates of extras names\n\t * @return\n\t */\n\tpublic ArrayList<String> getExtrasCommands(){\n\t\tArrayList<String> addedExtras = new ArrayList<>();\n\t\tfor (int i=0; i<this.names.size();i++ ){\n\t\t\tif (!addedExtras.contains(this.names.get(i)) && this.isValidExtraType(i)){\n\t\t\t\tthis.commands.add(this.getExtraCommand(i));\n\t\t\t\taddedExtras.add(this.names.get(i));\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn this.commands;\n\t}\n\t\n\t/**\n\t * Whether the type of the extra is String, number or boolean\n\t * @param i\n\t * @return\n\t */\n\tprivate boolean isValidExtraType(int i){\n\t\tString type = this.types.get(i);\n\t\t\n\t\tif (type.equals(\"String\")|| type.equals(\"Boolean\")|| type.equals(\"Int\")|| type.equals(\"Long\") || type.equals(\"Float\") || type.equals(\"Double\"))\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * Returns the part of syntax to be added to the am command, such as -e Var1 Val1\n\t * Also taking care in case the default value is null --> assign a default value\n\t * To avoid errors: defaults have been excluded\n\t * @return\n\t */\n\tprivate String getExtraCommand(int i){\n\t\tString cmd = this.getE(this.types.get(i));\n\t\tString value=\"\";\n\t\t\n\t\tvalue = this.getExtraValue(this.types.get(i));\n\t\tString command = cmd + \" \" +this.names.get(i)+\" \"+value;\n\t\t\n\t\treturn command; \n\t\t\n\t}\n\t\n\t/**\n\t * Returns the information about Extras for -l command\n\t * @return\n\t */\n\tpublic ArrayList<String> getExtrasInfo(){\n\t\tArrayList<String> ExtrasInfo = new ArrayList<>();\n\t\tArrayList<String> addedExtras = new ArrayList<>();\n\t\t\n\t\t\n\t\tfor (int i=0; i<this.names.size();i++ ){\n\t\t\tif (!addedExtras.contains(this.names.get(i))){\n\t\t\t\tExtrasInfo.add(\"Extra Name: \"+this.names.get(i)+\"\\t\\t Extra Type: \"+this.types.get(i));\n\t\t\t\taddedExtras.add(this.names.get(i));\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn ExtrasInfo;\n\t}\n\n\t/**\n\t * Gets the extra flag according to the extra type\n\t * @param type\n\t * @return\n\t */\n\tpublic String getE(String type){\n\t\tString result=\"\";\n\t\tswitch(type){\n\t\t\n\t\tcase \"String\":\n\t\t\tresult=\"-e\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Int\":\n\t\t\tresult=\"--ei\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Boolean\":\n\t\t\tresult=\"--ez\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Long\":\n\t\t\tresult=\"--el\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Float\":\n\t\t\tresult=\"--ef\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Double\":\n\t\t\tresult=\"--ef\";\n\t\t\tbreak;\n\t\t\t\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * Gets a default value for an extra according to its type\n\t * @param type\n\t * @return\n\t */\n\tpublic String getExtraValue(String type){\n\t\tString result=\"\";\n\t\tswitch(type){\n\t\t\n\t\tcase \"String\":\n\t\t\tresult=\"TiCkLeR\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Int\":\n\t\t\tresult=\"9\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Boolean\":\n\t\t\tresult=\"true\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Long\":\n\t\t\tresult=\"999\";\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"Float\":\n\t\t\tresult=\"99\";\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\tpublic ArrayList<String> getTypes() {\n\t\treturn types;\n\t}\n\n\tpublic void setTypes(ArrayList<String> types) {\n\t\tthis.types = types;\n\t}\n\n\tpublic ArrayList<String> getNames() {\n\t\treturn names;\n\t}\n\n\tpublic void setNames(ArrayList<String> names) {\n\t\tthis.names = names;\n\t}\n\n\tpublic ArrayList<String> getDefaults() {\n\t\treturn defaults;\n\t}\n\n\tpublic void setDefaults(ArrayList<String> defaults) {\n\t\tthis.defaults = defaults;\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/code/ExtrasUtil.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage code;\n\nimport java.util.ArrayList;\n\nimport base.FileUtil;\nimport initialization.TicklerVars;\n\n/**\n * Extras in Java code\n * @author aabolhadid\n *\n */\npublic class ExtrasUtil {\n\tprivate FileUtil fT;\n\t\n\tpublic ExtrasUtil(){\n\t\tthis.fT = new FileUtil();\n\t}\n\t\n\t\n\t/**\n\t * Checks if the App is already decompiled in the proper directory\n\t * @return\n\t */\n\tpublic boolean isJClassDir() {\n\t\tif (this.fT.isExist(TicklerVars.jClassDir))\n\t\t\treturn true;\n\t\t\n\t\tSystem.out.println(\"!! ERROR: Decompiled code does not exist\");\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * Gets extras of a component\n\t * @param className\n\t */\n\tpublic String getExtras(String className){\n\t\tif (this.isJClassDir())\n\t\t\treturn this.getExtrasIfCodeExists(className);\n\t\treturn \"!! ERROR: run dex2jar first\";\n\t}\n\t\n\t/**\n\t * Gets the extras syntax of a class in one string (e.g. -e Var1 Val1 --ez Var2 Val2)\n\t * @param className\n\t */\n\tprivate String getExtrasIfCodeExists(String className){\n\t\t\n\t\tString cName = this.getClassNameFromCompName(className);\n\t\tArrayList<String> extrasCommands = this.prepareExtrasCommands(cName);\n\t\t\n\t\treturn this.getExtrasCommandLine(extrasCommands);\n\t}\n\t\n\tprivate String getClassNameFromCompName(String className){\n\t\tString cName = className;\n\t\t\n\t\tif (className.contains(\".\") && className.lastIndexOf(\".\") != 0){\n\t\t\tString[] cNames = className.split(\"\\\\.\");\n\t\t\tcName = cNames[cNames.length -1];\n\t\t}\n\t\t\n\t\treturn cName;\n\t}\n\t\n\t/**\n\t * Convert an array of extra parameters into one line\n\t * @param extrasCommands\n\t * @return\n\t */\n\tprivate String getExtrasCommandLine(ArrayList<String> extrasCommands) {\n\t\tString line =\" \";\n\t\t\n\t\tfor (String cmd : extrasCommands){\n\t\t\tline = line+cmd+\" \";\n\t\t}\n\t\t\n\t\treturn line;\n\t}\n\t\n\t/**\n\t * 1- Gets Extras Commands array from ClassExtra class\n\t * 2- Check for duplicates\n\t * 3- removes L and F from default values\n\t * 4- propose default values if there aren't any\n\t * @param cName\n\t * @return\n\t */\n\tprivate ArrayList<String> prepareExtrasCommands(String cName){\n\t\tClassExtras cExtra = new ClassExtras(cName);\n\t\tcExtra.process();\n\t\tArrayList<String> allExtras = cExtra.getExtrasCommands();\n\t\t\n\t\treturn allExtras;\n\n\t}\n\t\n\t/**\n\t * Gets Info about Extras for -l command\n\t * @return\n\t */\n\tpublic ArrayList<String> getExtrasInfo(String className){\n\t\tArrayList<String> extrasInfo = new ArrayList<>();\n\t\t\n\t\tif (this.isJClassDir()){\n\t\t\tString cName = this.getClassNameFromCompName(className);\n\t\t\tClassExtras cExtra = new ClassExtras(cName);\n\t\t\tcExtra.process();\n\t\t\textrasInfo = cExtra.getExtrasInfo();\n\t\t}\n\t\t\t\n\t\t\n\t\treturn extrasInfo;\n\t}\n\n}\n\t\n"
  },
  {
    "path": "src/main/java/code/JavaSqueezer.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage code;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.util.AbstractMap;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n//import org.apache.commons.io.FileUtils;\n\nimport actions.Searcher;\nimport base.FileUtil;\nimport base.JsonParser;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport info.InfoGathering;\nimport initialization.TicklerVars;\n\n/**\n * Extracts information from code such as log messages, comments, credentials, encryption and strings\n * @author aabolhadid\n *\n */\n\npublic class JavaSqueezer {\n\tprivate SearchUtil sU;\n\tprivate String codeRoot;\n\tprivate ArrayList<Map> squeezeList;\n\tprivate String jsonSq=\"{ \\\"squeeze\\\": [{\\\"Title\\\":\\\"World accessible files\\\",\\\"Values\\\":[ \\\"MODE_WORLD_READABLE\\\", \\\"MODE_WORLD_WRITABLE\\\"]},\"\n\t\t\t+ \"{\\\"Title\\\":\\\"WebView\\\",\\\"Values\\\":[ \\\"addJavascriptInterface\\\", \\\"setAllowContentAccess\\\", \\\"setAllowFileAccess\\\", \\\"setAllowUniversalAccess\\\" ]}]}\";\n\tprivate ArrayList<SimpleEntry> stringArrayList;\n\tprotected PrintStream origSysOut;\n\t\n\tpublic JavaSqueezer(){\n\t\tthis.sU = new SearchUtil();\n\t\tthis.codeRoot = TicklerVars.jClassDir;\n\t}\n\t\n\tpublic void report(String codeRoot){\n\t\tif (codeRoot != null){\n\t\t\tString codeRootNotHome=codeRoot.replace(\"~\", System.getProperty(\"user.home\"));\n\t\t\tFile cR = new File(codeRootNotHome);\n\t\t\tif (cR.exists()){\n\t\t\t\tthis.codeRoot = codeRootNotHome;\n\t\t\t\tthis.report();\n\t\t\t}\n\t\t\n\t\t\telse\n\t\t\t{\n\t\t\t\tOutBut.printError(\"The code location you entered \"+codeRoot+\" does not exist\");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t//Redirect system out to a file\n\t\t\t\n\t\t\tthis.report();\n\t\t}\n\t}\n\tpublic void report(){\n\t\t//Redirect ot Squeeze out file\n\t\tthis.writeSqueezeInFile();\n\t\t\n\t\t//Preparation: get Strings\n\t\tthis.getStringsInCode();\n\t\t//Components\n\t\tthis.libsAndComponents();\n\t\tthis.frameworks();\n\t\tthis.soLibFiles();\n\t\tthis.dllFiles();\n\t\t//Storage\n\t\tthis.storage();\n\t\tthis.externalStorageInCode();\n\t\t//Communication\n\t\tthis.httpUrls();\n\t\tthis.findSchemes();\n\t\tthis.pinning();\n\t\t//Crypto\n\t\tthis.weakCyphers();\n\t\tthis.crypto();\n\t\t//Disclosure\n\t\tthis.commentsInCode();\n\t\tthis.credentialsInCode();\n\t\tthis.logInCode();\n\t\tthis.testDisclosure();\n//\t\tthis.getStringsInCode();\n//\t\tthis.squeezeJSon();\n\t\t\n\t\tOutBut.printStep(\"Where [Java_Code_Dir] is \"+this.codeRoot);\n\t\t\n\t\t//Back to SYS Out\n\t\tthis.backToSystemOut();\n\t\t\n\t\t//Print Squeeze file\n\t\tthis.printSqueezeFile();\n\t}\n\t\n\t\n\t//////////////////////////////// Storage //////////////////////////////////\n\t/**\n\t * Search for any possible use of external storage\n\t */\n\tpublic void externalStorageInCode(){\n\t\tOutBut.printH2(\"Possible External Storage\");\n\t\tArrayList<SimpleEntry> eArray = this.sU.searchForKeyInJava(\"getExternal\",this.codeRoot);\n\t\t\n\t\tthis.printE(eArray);\n\t\t\n\t}\n\t\n\tprivate void storage(){\n\t\tOutBut.printH2(\"Storage: DBs and shared preferences\");\n\t\tString[] keys = {\"sharedpref\", \"SQLiteDatabase\", \"CacheDir\",\"AndroidKeyStore\", \"KeyStore\"};\n\t\tArrayList<SimpleEntry> eArray = this.returnFNameLineGroup(keys, false);\n\t\tthis.printE(eArray);\n\t}\n\t\n\t\n\t/////////////////////// Components //////////////////////////\n\t\n\tprivate void libsAndComponents(){\n\t\tOutBut.printH2(\"Imports\");\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\"import\",this.codeRoot) ;\n\t\tArrayList<SimpleEntry> e1 = this.sU.refineSearch(e,\"(^import.+)\") ;\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e1, \"^(?:(?!(import\\\\sjava|import\\\\sandroid)).)*$\");\n\t\tArrayList<String> files=this.returnValues(eResult);\n\t\t\n\t\t\n\t\tfor (String s:files)\n\t\t\tOutBut.printNormal(s);\n\t\t\n\t\tOutBut.printH2(\"Components and libraries\");\n\t\tString[] comps = {\"Webview\", \"Okhttp\", \"Sqlcipher\"};\n\t\tArrayList<SimpleEntry> hits = new ArrayList<>();\n\t\t files = new ArrayList<>();\n\t\t\n\t\tfor (String c:comps){\n\t\t\thits=this.sU.searchForKeyInJava(c,this.codeRoot);\n\t\t\tif (!hits.isEmpty()){\n\t\t\t\tOutBut.printH3(c);\n\t\t\t\tfiles=this.returnFileNames(hits);\n\t\t\t\n\t\t\t\tfor (String s:files)\n\t\t\t\t\tOutBut.printNormal(s);\n\t\t\t\tOutBut.printNormal(\"\\n---------------------------------------------------------------\");\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\t\n//\tprivate void libFiles(){\n//\t\tString[] extenstions = {\"so\"};\n//\t\tList<File> soLibs = this.sU.search4FileInDir(TicklerVars.extractedDir, extenstions);\n//\t\tif (!soLibs.isEmpty()) {\n//\t\t\tOutBut.printH2(\"Library files in the app\");\n//\t\t\tfor (File f:soLibs ){\n//\t\t\t\tOutBut.printNormal(f.getAbsolutePath().replaceAll(TicklerVars.extractedDir, \"[Extracted_Apk]\"));\n//\t\t\t}\n//\t\t\tOutBut.printNormal(\"\\nWhere [Extracted_Apk] is \"+TicklerVars.extractedDir);\n//\t\t}\n//\t}\n\t\n\t/**\n\t * Searches for so Libraries in the APK\n\t */\n\tpublic void soLibFiles(){\n\t\tString[] extenstions = {\".so\"};\n\t\tOutBut.printH2(\"Libraries in the APK\");\n\t\tthis.searchForFilesInAPK(extenstions);\n\t}\n\t\n\t/**\n\t * Searches for DLL files in the APK\n\t */\n\tpublic void dllFiles(){\n\t\tString[] extenstions = {\".dll\"};\n\t\tOutBut.printH2(\"DLLs in the APK\");\n\t\tthis.searchForFilesInAPK(extenstions);\n\t}\n\t\n\t/**\n\t * Checks for certificates in APK, taken from -info flag\n\t */\n\tprivate void certsInAPK() {\n\t\tInfoGathering info = new InfoGathering();\n\t\tinfo.getCertificatesInApkDirectory();\n\t}\n\t\n\tprivate void frameworks() {\n\t\tOutBut.printH2(\"Frameworks and Protocols\");\n\t\tString[] keys = {\"Cordova\",\"PhoneGap\", \"Xamarin\",\"Corona\",\"Appsee\",\"MQTT\", \"websocket\"};\n\t\tArrayList<SimpleEntry> hits = new ArrayList<AbstractMap.SimpleEntry>();\n\t\tArrayList<String> files = new ArrayList<String>();\n\t\t\n\t\tfor (String c:keys){\n\t\t\thits=this.sU.searchForKeyInJava(c,this.codeRoot);\n\t\t\tOutBut.printH3(c);\n\t\t\tif (!hits.isEmpty()){\n\t\t\t\tfiles=this.returnFileNames(hits);\n\t\t\t\n\t\t\t\tfor (String s:files)\n\t\t\t\t\tOutBut.printNormal(s);\n\t\t\t\tOutBut.printNormal(\"\\n---------------------------------------------------------------\");\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t}\n\t\n\t/////////////////////// Crypto ////////////////////////\n\t\t\n\t/**\n\t * Search for weak hashes\n\t */\n\tprivate void weakCyphers() {\n\t\tSystem.out.println(\"\\n\");\n\t\tString[] weakCrypto = {\"Rot13\", \"MD4\", \"MD5\", \"RC2\", \"RC4\", \"SHA1\"};\n\t\tOutBut.printH2(\"Possible use of weak Ciphers/hashes\");\n\t\t\n\t\tArrayList<SimpleEntry> eA = new ArrayList<>();\n\t\t\n\t\tfor (String c : weakCrypto)\n\t\t\teA.addAll(this.sU.searchForKeyInJava(c,this.codeRoot));\n\t\t\n\t\tthis.printE(eA);\n\t}\n\t\n\t/**\n\t * Use of cryptography \n\t */\n\tprivate void crypto(){\n\t\tOutBut.printH2(\"Crypto and hashing keywords\");\n\t\tString[] keys = {\"aes\", \"crypt\", \"cipher\", \"sha1\", \"sha2\",\"key\" };\n\t\tArrayList<SimpleEntry> eA = this.returnFNameLineGroup(keys, false);\n\t\t\n\t\tthis.printE(this.removeDuplicatedSimpleEntries(eA));\n\t}\n\t\n\t\n\t\n\t\n\t/**\n\t * Capture all strings in code and save the result to stringArrayList\n\t */\n\tprivate void getStringsInCode(){\n\t\tSystem.out.println(\"\\n\");\n//\t\tOutBut.printH2(\"Strings\");\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\"\\\"\",this.codeRoot);\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, \"[^:](\\\".+\\\")\");\n\t\t\n//\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, \"(\\\"\\\\w{32}\\\"|\\\"\\\\w{40}\\\"|\\\"\\\\w{56}\\\"|\\\"\\\\w{64}\\\")\");\n//\t\tthis.printE(this.removeDuplicatedSimpleEntries(eResult));\n\t\tthis.stringArrayList = eResult;\n\t}\n\t\n\tprivate void getHashes(){\n\t\tSystem.out.println(\"\\n\");\n\t\tOutBut.printH2(\"Strings\");\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\"\\\"\",this.codeRoot);\n\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, \"(\\\"\\\\w{32}\\\"|\\\"\\\\w{40}\\\"|\\\"\\\\w{56}\\\"|\\\"\\\\w{64}\\\")\");\n\t\tthis.printE(this.removeDuplicatedSimpleEntries(eResult));\n\t}\n\t\n\t\n\t\n\t///////////////////////////////// Communication ///////////////////////////////////\n\t\n\tprivate void httpUrls(){\n\t\tOutBut.printH2(\"URLs in code\");\n\t\tthis.getHttpUris();\n\t\tthis.getPathes();\n\t\tOutBut.printH2(\"IP addresses in code\");\n\t\tthis.getIPAddresses();\n\t}\n\t\n\tpublic void getHttpUris(){\n\t\tArrayList<SimpleEntry> hits = this.sU.searchForKeyInJava(\"http\",this.codeRoot); \n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(hits, \"(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]\");\n\n\t\tthis.printE(eResult);\n\t\t\n/*\t\tOutBut.printH3(\"HTTP URL summary:\");\n\t\tArrayList<String> uris = new ArrayList<>();\n\t\tfor (SimpleEntry e: hits){\n\t\t\turis.add(this.correctUrl((String)e.getValue()));\n//\t\t\tOutBut.printNormal(this.correctUrl((String)e.getValue()));\n\t\t}\n\t\t\n\t\tOtherUtil.printStringArray(OtherUtil.removeDuplicates(uris));\n*/\t\t\n\t}\n\t\n\t/**\n\t * Searches for any possible paths: whether API paths or other\n\t */\n\tprivate void getPathes() {\n//\t\tArrayList<SimpleEntry> hits = this.sU.searchForKeyInJava(\"\\\\(\\\\\\\"(.*\\\\/.*)\\\\\\\"\\\\)\",this.codeRoot); \n\t\tArrayList<SimpleEntry> hits = this.sU.refineSearch(this.stringArrayList, \"@\\\\w+\\\\(\\\\\\\"(.*\\\\/.*)+\\\\\\\"\\\\)\");\n\t\tif (!hits.isEmpty())\n\t\t{\n\t\t\tOutBut.printH3(\"Possible paths:\");\n\t\t\tthis.printE(hits);\n\t\t}\n\t}\n\t\n\tprivate void getIPAddresses() {\n\t\tString regex = \"([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\\"\n\t\t\t\t+ \".([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\";\n\t\t\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\".\",this.codeRoot);\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, regex);\n\t\t\n\t\tthis.printE(this.removeDuplicatedSimpleEntries(eResult));\n\t\t\n\t}\n\t\n\tprivate void findSchemes() {\n\t\tOutBut.printH2(\"Schemes and other URIs\");\n\t\tArrayList<SimpleEntry> hits = this.sU.searchForKeyInJava(\"://\",this.codeRoot); \n\t\tthis.printE(hits);\n\t}\n\t\n\tprivate void pinning(){\n\t\tOutBut.printH2(\"Pinning\");\n\t\tArrayList<SimpleEntry> hits = this.sU.searchForKeyInJava(\"certificatePinner\",this.codeRoot);\n\t\tthis.printE(hits);\n\t}\n\t\n\t\n\tprivate String correctUrl(String line) {\n\t\tString url=\"\";\n\t\tMatcher m = Pattern.compile(\"http(s?)://(.+?)[\\\"'\\\\s]\").matcher(line);\n\t\tif (m.find()) {\n\t\t\turl = line.substring(m.start(0),m.end(0)-1);\n\t\t}\n\t\treturn url;\n\t}\n\t\n\t//////////////////////////// Disclosure ////////////////////////////////////\n\t\n\t\n\n\t/**\n\t* Search For all logcat commands In Code\n\t*/\n\tpublic void logInCode(){\n\t\tOutBut.printH2(\"Logging messages in logcat\");\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\"Log\",this.codeRoot) ;\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, \".*Log\\\\.\\\\w\\\\((\\\\+?)\");\n\t\teResult.addAll(this.sU.refineSearch(e, \".*getLogger\\\\(\\\\)\\\\.(\\\\w)\"));\n\t\t\n\t\tthis.printE(eResult);\n\t\n\t}\n\t\n\tprivate void testDisclosure(){\n\t\tOutBut.printH2(\"Test\");\n\t\tArrayList<SimpleEntry> hits = this.sU.searchForKeyInJava(\"test\",this.codeRoot);\n\t\thits = this.sU.refineSearch(hits, \"(.*(test|TEST).*)\");\n\t\tthis.printE(hits);\n\t}\n\t\n\t\n\t/**\n\t *  stuff like // and maybe what's between /* and *\\/ \n\t *  Regex for comment: // not proceeded by a : (not a URI), proceeded by any space then no digit (eliminate undecompiled code) \n\t */\n\tpublic void commentsInCode(){\n\t\tSystem.out.println(\"\\n\");\n\t\tOutBut.printH2(\"Comments\");\n\t\t\n\t\tArrayList<SimpleEntry> eComments = new ArrayList<>();\n\t\tArrayList<SimpleEntry> e = this.sU.searchForKeyInJava(\"//\",this.codeRoot);\n\t\tArrayList<SimpleEntry> eResult = this.sU.refineSearch(e, \"^\\\\s*//(\\\\s*[a-zA-Z]+)\");\n\t\teResult= this.sU.refineSearch(eResult, \"^(?!\\\\s*//\\\\s*from\\\\s*to\\\\s*target\\\\s*type)(.*$)\");\n\t\teResult= this.sU.refineSearch(eResult, \"^(?!\\\\s*//\\\\s*Byte\\\\s*code:)(.*$)\");\n\t\teResult= this.sU.refineSearch(eResult, \"^(?!\\\\s*//\\\\s*start\\\\s*length\\\\s*slot\\\\s*name\\\\s*signature)(.*$)\");\n\t\teResult= this.sU.refineSearch(eResult, \"^(?!\\\\s*//\\\\s*Local\\\\s*variable\\\\s*table)(.*$)\");\n\t\teResult= this.sU.refineSearch(eResult, \"^(?!\\\\s*//\\\\s*Exception\\\\s*table:)(.*$)\");\n\t\n\t\teComments.addAll(eResult);\n\t\t\n\t\tArrayList<SimpleEntry> eM = this.sU.searchForKeyInJava(\"*\",this.codeRoot);\n\t\tArrayList<SimpleEntry> eResultMLine = this.sU.refineSearchMatch(eM, \"\\\\s*/\\\\*.+\");\n\t\teResultMLine = this.sU.refineSearchMatch(eResultMLine, \"^(?!\\\\s*/\\\\*\\\\s*Error\\\\s*\\\\*/)(.*$)\");\n//\t\tArrayList<SimpleEntry> eResultMLine2 = this.sU.refineSearchMatch(eM, \"\\\\s*\\\\*.+\");\n\t\t\n\t\teComments.addAll(eResultMLine);\n//\t\teComments.addAll(eResultMLine2);\n\t\tthis.printE(this.removeDuplicatedSimpleEntries(eComments));\n\t\t\n\t}\n\t/**\n\t * Search for anything that can disclose credentials:\n\t * pass, password, username, userID, credentials\n\t */\n\tpublic void credentialsInCode(){\n\t\tSystem.out.println(\"\\n\");\n\t\tOutBut.printH2(\"Possible credentials disclosure\");\n\t\t\n\t\tString[] keys = {\"pass\",\"password\", \"pwd\", \"username\", \"user name\", \"userID\", \"credential\", \"admin\"};\n\t\tArrayList<SimpleEntry> eA = this.returnFNameLineGroup(keys, false);\n\t\t\n\t\tthis.printE(this.removeDuplicatedSimpleEntries(eA));\n\t}\n\n//////////////////////////////////////Utils /////////////////////////////////\t\n\t\n\t/**\n\t * Print squeeze output to stdout\n\t * @param eArray\n\t */\n\tprivate void printE(ArrayList<SimpleEntry> eArray){\n\t\tfor (SimpleEntry e: eArray){\n\t\t\tString fileName=e.getKey().toString().replaceAll(this.codeRoot, \"[Java_Code_Dir]\");\n\t\t\tSystem.out.println(\"#FileName: \"+fileName);\n\t\t\tSystem.out.println(\" \"+e.getValue()+\"\\n\");\n\t\t}\n\t}\n\t\n\tprivate ArrayList<SimpleEntry> removeDuplicatedSimpleEntries(ArrayList<SimpleEntry> orig) {\n\t\treturn new ArrayList<SimpleEntry>(new LinkedHashSet<SimpleEntry>(orig));\n\t}\n\t\n\t/**\n\t * Get file names from a hits arraylist. Removes duplicates and sort\n\t * @param hits\n\t * @return\n\t */\n\tprivate ArrayList<String> returnFileNames(ArrayList<SimpleEntry> hits){\n\t\tArrayList<String> files = new ArrayList<>();\n\t\tfor (SimpleEntry e:hits)\n\t\t\tfiles.add(e.getKey().toString().replaceAll(this.codeRoot, \"[Java_Code_Dir]\"));\n\t\t \n\t\tArrayList<String> ret= new ArrayList<String>(new LinkedHashSet<String>(files));\n\t\treturn ret;\n\t}\n\t\n\tprivate ArrayList<String> returnValues(ArrayList<SimpleEntry> hits){\n\t\tArrayList<String> files = new ArrayList<>();\n\t\tfor (SimpleEntry e:hits)\n\t\t\tfiles.add(e.getValue().toString());\n\t\t\n\t\tCollections.sort(files);\n\t \n\t\tArrayList<String> ret= new ArrayList<String>(new LinkedHashSet<String>(files));\n\t\treturn ret;\n\t}\n\t\n\n\t/**\n\t * Searches for a group of Keys and print each occurrence and its file name. \n\t * @param keys\n\t */\n\tprivate ArrayList<SimpleEntry> returnFNameLineGroup(String[] keys, boolean printName){\n\t\tArrayList<SimpleEntry> eA = new ArrayList<>();\n\t\tArrayList<SimpleEntry> keyRes = new ArrayList<>();\n\t\t\n\t\tfor (String s: keys){\n\t\t\tkeyRes = this.sU.searchForKeyInJava(s,this.codeRoot);\n\t\t\tif (printName && (!keyRes.isEmpty()))\n\t\t\t\tOutBut.printH3(s);\n\t\t\t\n\t\t\teA.addAll(this.sU.searchForKeyInJava(s,this.codeRoot));\n\t\t}\n\t\t\n\t\treturn eA;\n\t\t\n\t}\n\t\n\t/**\n\t * Searches for a type of files in APK and prints a list of these files\n\t */\n\tprivate void searchForFilesInAPK(String[] extension){\n\t\tList<File> files = this.sU.search4FileInDir(TicklerVars.extractedDir, extension);\n\t\tif (!files.isEmpty()) {\n\t\t\tfor (File f:files ){\n\t\t\t\tOutBut.printNormal(f.getAbsolutePath().replaceAll(TicklerVars.extractedDir, \"[Extracted_Apk]\"));\n\t\t\t}\n\t\t\tOutBut.printNormal(\"\\nWhere [Extracted_Apk] is \"+TicklerVars.extractedDir);\n\t\t}\n\t}\n\n\n\t/**\n\t * Checks in a directory for the keywords of external storage\n\t */\n\t\n\tpublic boolean isExternalStorage(){\n\t\tArrayList<SimpleEntry> eArray = this.sU.searchForKeyInJava(\"getExternal\",this.codeRoot);\n\t\tif (!this.sU.refineSearch(eArray, \"(getExternalFilesDir)\").isEmpty() || !this.sU.refineSearch(eArray, \"getExternalStoragePublicDirectory\").isEmpty())\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\tpublic void squeezeJson(String filePath) {\n\t\tJsonParser jp = new JsonParser();\n\t\tArrayList<SimpleEntry> eA,summaryArray;\n\t\tSimpleEntry keyResult;\n\t\tString[] searchKeys;\n\t\tString json;\n\t\t\n\t\ttry {\n\t\t\tjson=this.readSqueezeJson(filePath);\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tjson=this.jsonSq;\n\t\t}\n\t\t\t\n\t\tsummaryArray=new ArrayList<AbstractMap.SimpleEntry>();\n\t\tArrayList<SimpleEntry<String,ArrayList<String>>> arr = jp.parseJsonString(json);\n\t\t\n\t\tfor (SimpleEntry<String,ArrayList<String>> e : arr) {\n\t\t\t\n\t\t\tOutBut.printH2(e.getKey());\n\t\t\tObject[] aL = e.getValue().toArray();\n\t\t\tsearchKeys= Arrays.copyOf(aL, aL.length, String[].class);;\n\t\t\t\n\t\t\t\n\t\t\t//To get the number of hits of each key in searchKeys\n\t\t\tfor (String key : searchKeys) {\n\t\t\t\tString[] keyArr =  {key}; \n\t\t\t\teA = this.returnFNameLineGroup(keyArr, false);\n\t\t\t\tkeyResult=new SimpleEntry<String, Integer>(key, eA.size());\n\t\t\t\tsummaryArray.add(keyResult);\n\t\t\t\tthis.printE(this.removeDuplicatedSimpleEntries(eA));\n\t\t\t}\n\t\t}\n\t\t\t\n\t\t//Print Summary\n\t\t\n\t\tOutBut.printH2(\"Results Summary\");\n\t\tfor (SimpleEntry<String, Integer> e : summaryArray) {\n\t\t\tOutBut.printNormal(e.getKey()+\":\\t\"+e.getValue());\n\t\t}\n\t\t\t\t\n\t\t\n\t\t\n\t\t\n//\t\tcatch(IOException e) {\n//\t\t\tOutBut.printError(\"JSON File \"+filePath+\" does not exist\");\n//\t\t}\n\t\t\n\t}\n\t\n\tprivate String readSqueezeJson(String filePath) throws IOException {\n\t\tFileUtil fU = new FileUtil();\n\n\t\treturn fU.readFile(filePath);\n\n\t}\n\t\n\t/**\n\t * Write squeeze output in a squeeze file\n\t */\n\tprivate void writeSqueezeInFile() {\n\t\ttry {\n\t\t\tthis.origSysOut = System.out;\n\t\t\tFileUtil fU = new FileUtil();\n//\t\t\tfU.writeFile(TicklerVars.squeezeFile, \"Tickler Squeeze\");\n\t\t\tPrintStream fileOut = new PrintStream(TicklerVars.squeezeFile);\n\t\t\tOutBut.printH1(\"Code Squeeze\");\n\t\t\tOutBut.printH2(\"Output is also saved at \"+ TicklerVars.squeezeFile);\n\t\t\tSystem.setOut(fileOut);\n\t\t}\n\t\tcatch(FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tprivate void printSqueezeFile() {\n\t\tFileUtil fU = new FileUtil();\n\t\ttry {\n\t\t\tString squeezeOutput = fU.readFile(TicklerVars.squeezeFile);\n\t\t\tOutBut.printNormal(squeezeOutput);\n\t\t\t}\n\t\tcatch (IOException e) {\n\t\t\tOutBut.printError(\"Problem reading squeeze output file: \"+TicklerVars.squeezeFile);\n\t\t}\n\t}\n\t\n\t/**\n\t * Write output back to system out\n\t */\n\tprivate void backToSystemOut() {\n\t\tSystem.setOut(this.origSysOut);\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/commandExec/Commando.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage commandExec;\n\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport initialization.TicklerVars;\nimport java.io.File;\nimport java.io.FileWriter;\n\npublic class Commando {\n\t\n\tprivate StringBuffer output;\n\n\n\t//////////////////// Process Commands //////////////////////\n\t/**\n\t * Execute a command as a process\n\t * @param command\n\t * @return ArrayList of 2 strings:\n\t * \t\t1) The output of the command\n\t * \t\t2) The error code of command execution\n\t */\n\tpublic ArrayList<String> executeProcessString(String command){\n\t\tint errCode=999;\n\t\tArrayList<String> returnArr = new ArrayList();\n\t\tList<String> args = Arrays.asList(command.split(\" \"));\n\t\tString output=\"!!! ERROR: command \"+command+\" failed to execute successfully :(\";\n\t\ttry{\n\t\t\tProcessBuilder build = new ProcessBuilder(args);\n\t\t\tProcess p = build.start();\n\t\t\terrCode = p.waitFor();\n\t\t\toutput= this.getProcessOp(p);\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturnArr.add(output);\n\t\treturnArr.add(new Integer(errCode).toString());\n\t\treturn returnArr;\n\t}\n\t\n\t/**\n\t * Execute a command as a list of arguments and prints its output if \"output\" is true\n\t * @param args\n\t * @return return code, errCode 999 is a default value in case an exception occurs before errCode is set \n\t */\n\tpublic int executeProcessListPrintOP(String command,boolean output){\n\t\treturn this.executeProcessListMain(command, output,false,false);\n\t}\n\t\n\tpublic int executeProcessListPrintOPError(String command){\n\t\treturn this.executeProcessListMain(command, true, true,false);\n\t}\n\t\n\tpublic int executeProcessForAdbPull(String command){\n\t\treturn this.executeProcessListMain(command, false, true, true);\n\t}\n\t\n\t/**\n\t * Main method for executing a command as a list\n\t * @param args\n\t * @param output boolean: if true then print output\n\t * @param error\tboolean: if true then print output / save output\n\t * @param file\tboolean: if true then save the output in a temporary file (used with adb pull)\n\t * @return\n\t */\n\tprivate int executeProcessListMain(String command,boolean output,boolean error,boolean file){\t\n\t\tList<String> args = Arrays.asList(command.split(\" \"));\n\t\t\n\t\tint errCode=999;\n\t\tString tempPullLog = TicklerVars.logDir+\".pullLog.log\";\n\t\tFileUtil fU = new FileUtil();\n\t\t\n\t\ttry{\n\t\t\tProcessBuilder build = new ProcessBuilder(args);\n\t\t\tbuild.redirectErrorStream(error);\n\t\t\tProcess p = build.start();\n\t\t\t\n\t\t\t//Print output?\n\t\t\tif (output){\n\t\t\t\tSystem.out.println();\n\t\t\t\tOutBut.printH3(\"Command Output\");\n\t\t\t\tthis.printProcessOp(p);\n\t\t\t}\n\t\t\t\n\t\t\t//Writes output in a file\n\t\t\telse if (file)\n\t\t\t{\n\t\t\t\tfU.createDirOnHost(TicklerVars.logDir);\n\t\t\t\tnew File(tempPullLog).createNewFile();\n\t\t\t\tthis.saveProcessOp(p, tempPullLog);\n\t\t\t}\n\t\t\terrCode = p.waitFor();\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t//If command is successful then delete temp log file of the command execution\n\t\tif (errCode == 0 && file){\n\t\t\tfU.deleteFromHost(tempPullLog);\n\t\t}\n\t\t\n\t\treturn errCode;\n\t}\n\t\n\t/**\n\t *Print stout of a command\n\t * @param process\n\t */\n\tprivate void printProcessOp(Process process) {\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\n\t\tString line = \"\";\t\n\t\t\n\t\ttry {\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\tSystem.out.println(line);\n\t\t\t}\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Used with adb pull command\n\t * @param process\n\t * @param fileName\n\t */\n\tprivate void saveProcessOp(Process process, String fileName){\n\t\t\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\n\t\tString line = \"\";\t\n\t\t\n\t\ttry {\n\t\t\tBufferedWriter writer = new  BufferedWriter(new FileWriter(fileName));\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\twriter.write(line+\"\\n\");\n\t\t\t}\n\t\t\twriter.close();\n\t\t}\n\t\tcatch(IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t/**\n\t * Retruns the output of the command \n\t * @param process\n\t * @return\n\t */\n\tprivate String getProcessOp(Process process){\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\n\t\tString line = \"\";\t\n\t\tStringBuffer outputBuff = new StringBuffer();\n\t\ttry {\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\toutputBuff.append(line + \"\\n\");\n\t\t\t}\n\t\t}\n\t\tcatch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn outputBuff.toString();\n\t}\n\t\n\t//////////////// Runtime execution ////////////////////\n\tpublic String executeCommand(String command)\n\t{\n\t\treturn this.executeCommand(command, true);\n\t}\n\t\n\t/**\n\t * Executes a command with an option not to wait.\n\t * @param command\n\t * @param wait\n\t * @return\n\t */\n\tpublic String executeCommand(String command, boolean wait)\n\t{\n\t\tthis.output = new StringBuffer(\t);\n\t\tProcess process;\n\t\ttry {\n\t\t\tprocess=Runtime.getRuntime().exec(command);\n\t\t\tif (wait)\n\t\t\t\tprocess.waitFor();\n\t\t\t\n\t\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\t\n\t\t\tString line = \"\";\t\t\t\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\toutput.append(line + \"\\n\");\n\t\t\t}\n\t\t\t\n\t\t\tif (output.toString().isEmpty()) {\n\t\t\t\treader = new BufferedReader(new InputStreamReader( process.getErrorStream()));\n\t\t\t\tline = \"\";\t\t\t\n\t\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\t\toutput.append(line + \"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn output.toString();\n\t}\n\t\n\tpublic String executePythonScript(String command)\n\t{\n//\t\tcommand = \"frida -U wana.notenaf.intenttest -l /home/aabolhadid/tools/Frida/myScripts/get_values.js\";\n\t\tthis.output = new StringBuffer(\t);\n\t\tProcess process;\n\t\ttry {\n\t\t\tprocess=Runtime.getRuntime().exec(command);\n\n\t\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getErrorStream()));\n\t\t\t\n\t\t\tString line = \"\";\t\t\t\n\t\t\twhile ((line = reader.readLine())!= null) {\n\t\t\t\toutput.append(line + \"\\n\");\n\t\t\t\tOutBut.printNormal(line);\n\t\t\t}\n\t\t\t\n\t\t\tif (output.toString().isEmpty()) {\n\t\t\t\treader = new BufferedReader(new InputStreamReader( process.getErrorStream()));\n\t\t\t\tline = \"\";\t\t\t\n\t\t\t\twhile ((line = reader.readLine())!= null) {\n//\t\t\t\t\toutput.append(line + \"\\n\");\n\t\t\t\t\tOutBut.printNormal(line);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn output.toString();\n\t}\n\t\n\t//////////////////////////////////// execute ADB or Root Commands //////////////////////////\n\tpublic String execADB(String command, boolean wait) {\n\t\treturn this.executeCommand(\"adb shell \"+command, wait);\n\t}\n\t\n\tpublic String execADB(String command) {\n\t\treturn this.executeCommand(\"adb shell \"+command);\n\t}\n\t\n\tpublic String execRoot(String command) {\n//\t\treturn this.executeCommand(\"adb shell su -c \"+command);\n\t\tString result = this.executeCommand(\"adb shell su -c \"+command);\n\t\tif (result.contains(\"invalid uid\")) {\n\t\t\t// DEvice / Emulator does not accept su -c, use su UID command\n\t\t\tresult = this.executeCommand(\"adb shell su 0 \"+command);\n\t\t}\n\t\t\n\t\treturn result;\n\t\t\n\t}\n\t\n\t/**\n\t * Currently used to print OP of Start commands\n\t * @param command\n\t * @return\n\t */\n\tpublic int execADBPrintOP(String command){\n\t\tString fullCommand = \"adb shell \"+command;\n\t\treturn this.executeProcessListPrintOP(fullCommand,true);\n\t}\n\t\n\t/**\n\t * Currently used to print OP of Start commands\n\t * @param command\n\t * @return\n\t */\n\tpublic int execRootPrintOP(String command){\n\t\tString fullCommand = \"adb shell su -c \"+command;\n\t\tint result=99;\n\t\t\n\t\t//Quick and Dirty solution to execute root commands on emulators, fixing invalid uid error\n\t\tString testCommand = this.executeCommand(\"adb shell su -c \");\n\t\tif (testCommand.contains(\"invalid uid\")) {\n\t\t\t result = this.executeProcessListPrintOP(\"adb shell su 0 \"+command,true);\n\t\t}\n\t\telse {\n\t\t\t result = this.executeProcessListPrintOP(fullCommand,true);\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\treturn result;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/Action.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\n\n\npublic class Action {\n\tString name;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String toString() {\n\t\treturn \"Action: name: \"+this.getName()+\"\\n\";\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/Activity.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\n\npublic class Activity implements IComponent,IActivityService{\n\n\tString name, exp, permission;\n\tboolean isExported;\n\tArrayList<Intent> intents;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t/*public void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\tpublic String getExp() {\n\t\treturn exp;\n\t}*/\n\t\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\tpublic void setExported(boolean exported) {\n\t\tthis.isExported = exported;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intents;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/Application.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.List;\n\n\npublic class Application {\n\t\n\tboolean isAllowBackup,isDebuggable;\n\tList<Activity> activites;\n\tList<Service> services;\n\tList<Receiver> receivers;\n\tList<Provider> providers;\n\tString name;\n\t\n\tpublic Application() {\n\t\tthis.isAllowBackup = false;\n\t}\n\t\n\tpublic boolean isAllowBackup() {\n\t\treturn isAllowBackup;\n\t}\n\tpublic void setAllowBackup(boolean isAllowBackup) {\n\t\tthis.isAllowBackup = isAllowBackup;\n\t}\n\t\n\tpublic List<Activity> getActivites() {\n\t\treturn activites;\n\t}\n\t\n\tpublic void setActivites(List<Activity> activites) {\n\t\tthis.activites = activites;\n\t}\n\tpublic List<Service> getServices() {\n\t\treturn services;\n\t}\n\t\n\tpublic void setServices(List<Service> services) {\n\t\tthis.services = services;\n\t}\n\t\n\tpublic List<Receiver> getReceivers() {\n\t\treturn receivers;\n\t}\n\t\n\tpublic void setReceivers(List<Receiver> receivers) {\n\t\tthis.receivers = receivers;\n\t}\n\n\tpublic List<Provider> getProviders() {\n\t\treturn providers;\n\t}\n\n\tpublic void setProviders(List<Provider> providers) {\n\t\tthis.providers = providers;\n\t}\n\t\n\tpublic boolean isDebuggable() {\n\t\treturn isDebuggable;\n\t}\n\n\tpublic void setDebuggable(boolean isDebuggable) {\n\t\tthis.isDebuggable = isDebuggable;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/Category.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\n\n\npublic class Category {\n\t\tString name;\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\t\t\n\t\tpublic String toString() {\n\t\t\treturn \"Category: name \"+this.getName()+\"\\n\";\n\t\t}\n\n}\n"
  },
  {
    "path": "src/main/java/components/DataUri.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * TODO: assume multiple mime-types, pathPrefixes\n * @author aabolhadid\n *\n */\npublic class DataUri {\n\tprivate String scheme,host,port,path,pathPrefix,pathPattern,mimeType;\n\tprivate Map<String,String>dataMap;\n\n\tpublic String getScheme() {\n\t\treturn scheme;\n\t}\n\n\tpublic void setScheme(String scheme) {\n\t\tthis.scheme = scheme;\n\t}\n\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic String getPort() {\n\t\treturn port;\n\t}\n\tpublic void setPort(String port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic String getPath() {\n\t\treturn path;\n\t}\n\tpublic void setPath(String path) {\n\t\tthis.path = path;\n\t}\n\n\tpublic String getPathPrefix() {\n\t\treturn pathPrefix;\n\t}\n\tpublic void setPathPrefix(String pathPrefix) {\n\t\tthis.pathPrefix = pathPrefix;\n\t}\n\n\tpublic String getPathPattern() {\n\t\treturn pathPattern;\n\t}\n\tpublic void setPathPattern(String pathPattern) {\n\t\tthis.pathPattern = pathPattern;\n\t}\n\n\tpublic String getMimeType() {\n\t\treturn mimeType;\n\t}\n\tpublic void setMimeType(String mimeType) {\n\t\tthis.mimeType = mimeType;\n\t}\n\t\n\tpublic Map<String,String> getDataMap(){\n\t\tdataMap =new HashMap<String,String>();\n\t\tthis.fillScheme();\n\n\t\tthis.fillRest(\"host\", host);\n\t\tthis.fillRest(\"path\", path);\n\t\tthis.fillRest(\"port\", port);\n\t\tthis.fillRest(\"pathPrefix\", pathPrefix);\n\t\tthis.fillRest(\"pathPattern\", pathPattern);\n\t\tthis.fillRest(\"mimeType\", mimeType);\n\t\t\n\t\treturn dataMap;\n\t}\n\t\n\t/**\n\t * Fill scheme in the map.\n\t * If empty then use content and file\n\t */\n\tprivate void fillScheme(){\n\t\tif (scheme !=null)\n\t\t\tdataMap.put(\"scheme\", this.getScheme());\n\t}\n\t\n\tprivate void fillRest(String key, String value){\n\t\tif (value != null)\n\t\t\tdataMap.put(key,value);\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/IActivityService.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.List;\n\npublic interface IActivityService {\n\n\tpublic List<Intent> getIntent();\n\tpublic String getName();\n}\n"
  },
  {
    "path": "src/main/java/components/IComponent.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\n\npublic interface IComponent {\n\n\tpublic boolean isExported();\n\tpublic void setExported(boolean isExported);\n\tpublic ArrayList<Intent> getIntent();\n\tpublic String getName();\n\tpublic String getPermission();\n\t\n\tpublic void setName(String name);\n\tpublic void setPermission(String permission);\n\tpublic void setIntent(ArrayList<Intent> intentFilters);\n\n}\n"
  },
  {
    "path": "src/main/java/components/Intent.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.List;\n\n\npublic class Intent {\n\tList<Action> actions;\n\tList<Category> categories;\n\tList<DataUri> data;\n\tint priority;\n\t\n\t\n\tpublic List<Action> getAction() {\n\t\treturn actions;\n\t}\n\n\tpublic void setAction(List<Action> action) {\n\t\tthis.actions = action;\n\t}\n\tpublic List<Category> getCategory() {\n\t\treturn categories;\n\t}\n\n\tpublic void setCategory(List<Category> category) {\n\t\tthis.categories = category;\n\t}\n\tpublic List<DataUri> getData() {\n\t\treturn data;\n\t}\n\n\tpublic void setData(List<DataUri> data) {\n\t\tthis.data = data;\n\t}\n\tpublic int getPriority() {\n\t\treturn priority;\n\t}\n\n\tpublic void setPriority(int priority) {\n\t\tthis.priority = priority;\n\t}\n\t\n\tpublic String toString() {\n\t\tString toReturn=\">>Intent: Data \"+this.getData()+\" Priority \"+Integer.toString(this.getPriority())+\"\\n\";\n\t\tfor (Action a : this.actions)\n\t\t{\n\t\t\ttoReturn+=a.toString();\n\t\t}\n\t\tfor (Category c : this.categories)\n\t\t{\n\t\t\ttoReturn+=c.toString();\n\t\t}\n\t\treturn toReturn;\n\t}\n\t\n}\n\n"
  },
  {
    "path": "src/main/java/components/Manifest.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\n\n\n\npublic class Manifest {\n\t\n\tprivate ArrayList<Intent> intents;\n\tprivate ArrayList<UsesPermission> usesPermissions;\n\tprivate ArrayList<Permission> Permissions;\n\tprivate Application application;\n\tprivate String pkgName;\n\n\tpublic ArrayList<Intent> getIntents() {\n\t\treturn intents;\n\t}\n\n\tpublic void setIntents(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\n\tpublic ArrayList<UsesPermission> getUsesPermissions() {\n\t\treturn usesPermissions;\n\t}\n\t\n\tpublic void setUsesPermissions(ArrayList<UsesPermission> usesPermissions) {\n\t\tthis.usesPermissions = usesPermissions;\n\t}\n\n\tpublic ArrayList<Permission> getPermissions() {\n\t\treturn Permissions;\n\t}\n\n\tpublic void setPermissions(ArrayList<Permission> permissions) {\n\t\tPermissions = permissions;\n\t}\n\n\tpublic Application getApplication() {\n\t\treturn application;\n\t}\n\n\tpublic void setApplication(Application application) {\n\t\tthis.application = application;\n\t}\n\t\n\tpublic String getPkgName() {\n\t\treturn pkgName;\n\t}\n\n\tpublic void setPkgName(String pkgName) {\n\t\tthis.pkgName = pkgName;\n\t}\n\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/Permission.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\n\npublic class Permission {\n\n\tString name,protectionLevel;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getProtectionLevel() {\n\t\treturn protectionLevel;\n\t}\n\n\tpublic void setProtectionLevel(String protectionLevel) {\n\t\tthis.protectionLevel = protectionLevel;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/Provider.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\n\npublic class Provider implements IComponent{\n\t\n\tString name,permission,authorities;\n\tboolean isExported;\n\tArrayList<Intent> intent;\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\tpublic String getAuthorities() {\n\t\treturn authorities;\n\t}\n\tpublic void setAuthorities(String authorities) {\n\t\tthis.authorities = authorities;\n\t}\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intent;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intent) {\n\t\tthis.intent = intent;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn null;\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/Receiver.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\n\n\npublic class Receiver implements IComponent{\n\t\n\tboolean isExported;\n\tString name,permission,exp;\n\tArrayList<Intent> intents;\n\t\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn exp;\n\t}\n\tpublic void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intents;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/Service.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class Service implements IComponent,IActivityService{\n\tString name,exp, permission;\n\tboolean isExported;\n\tArrayList<Intent> intent;\n\t\n\tpublic Service() {\n\t\tthis.isExported = false;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn exp;\n\t}\n\tpublic void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\t\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intent;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intent) {\n\t\tthis.intent = intent;\n\t}\n\t\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/components/UsesPermission.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components;\n\n\npublic class UsesPermission {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/Action.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\n\n\npublic class Action {\n\tString name;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String toString() {\n\t\treturn \"Action: name: \"+this.getName()+\"\\n\";\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/Activity.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\n\npublic class Activity implements IComponent,IActivityService{\n\n\tString name, exp, permission;\n\tboolean isExported;\n\tArrayList<Intent> intents;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t/*public void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\tpublic String getExp() {\n\t\treturn exp;\n\t}*/\n\t\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\tpublic void setExported(boolean exported) {\n\t\tthis.isExported = exported;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intents;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/Application.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.List;\n\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlElements;\n\npublic class Application {\n\t\n\tboolean isAllowBackup,isDebuggable;\n\tList<Activity> activites;\n\tList<Service> services;\n\tList<Receiver> receivers;\n\tList<Provider> providers;\n\tString name;\n\t\n\tpublic Application() {\n\t\tthis.isAllowBackup = false;\n\t}\n\t\n\tpublic boolean isAllowBackup() {\n\t\treturn isAllowBackup;\n\t}\n\tpublic void setAllowBackup(boolean isAllowBackup) {\n\t\tthis.isAllowBackup = isAllowBackup;\n\t}\n\t\n\tpublic List<Activity> getActivites() {\n\t\treturn activites;\n\t}\n\t@XmlElements({\n\t\t\t@XmlElement(name=\"activity\"),\n\t\t\t@XmlElement(name=\"activity-alias\")\n\t})\n\tpublic void setActivites(List<Activity> activites) {\n\t\tthis.activites = activites;\n\t}\n\tpublic List<Service> getServices() {\n\t\treturn services;\n\t}\n\t@XmlElement(name=\"service\")\n\tpublic void setServices(List<Service> services) {\n\t\tthis.services = services;\n\t}\n\t\n\tpublic List<Receiver> getReceivers() {\n\t\treturn receivers;\n\t}\n\t@XmlElement(name=\"receiver\")\n\tpublic void setReceivers(List<Receiver> receivers) {\n\t\tthis.receivers = receivers;\n\t}\n\n\tpublic List<Provider> getProviders() {\n\t\treturn providers;\n\t}\n\t@XmlElement(name=\"provider\")\n\tpublic void setProviders(List<Provider> providers) {\n\t\tthis.providers = providers;\n\t}\n\t\n\tpublic boolean isDebuggable() {\n\t\treturn isDebuggable;\n\t}\n\t@XmlAttribute(name=\"debuggable\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic void setDebuggable(boolean isDebuggable) {\n\t\tthis.isDebuggable = isDebuggable;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/Category.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\npublic class Category {\n\t\tString name;\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\t\t\n\t\tpublic String toString() {\n\t\t\treturn \"Category: name \"+this.getName()+\"\\n\";\n\t\t}\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/DataUri.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.xml.bind.annotation.XmlAttribute;\n/**\n * TODO: assume multiple mime-types, pathPrefixes\n * @author aabolhadid\n *\n */\npublic class DataUri {\n\tprivate String scheme,host,port,path,pathPrefix,pathPattern,mimeType;\n\tprivate Map<String,String>dataMap;\n\n\tpublic String getScheme() {\n\t\treturn scheme;\n\t}\n\t@XmlAttribute(name=\"scheme\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic void setScheme(String scheme) {\n\t\tthis.scheme = scheme;\n\t}\n\t@XmlAttribute(name=\"host\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\t@XmlAttribute(name=\"port\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getPort() {\n\t\treturn port;\n\t}\n\tpublic void setPort(String port) {\n\t\tthis.port = port;\n\t}\n\t@XmlAttribute(name=\"path\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getPath() {\n\t\treturn path;\n\t}\n\tpublic void setPath(String path) {\n\t\tthis.path = path;\n\t}\n\t@XmlAttribute(name=\"pathPrefix\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getPathPrefix() {\n\t\treturn pathPrefix;\n\t}\n\tpublic void setPathPrefix(String pathPrefix) {\n\t\tthis.pathPrefix = pathPrefix;\n\t}\n\t@XmlAttribute(name=\"pathPattern\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getPathPattern() {\n\t\treturn pathPattern;\n\t}\n\tpublic void setPathPattern(String pathPattern) {\n\t\tthis.pathPattern = pathPattern;\n\t}\n\t@XmlAttribute(name=\"mimeType\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic String getMimeType() {\n\t\treturn mimeType;\n\t}\n\tpublic void setMimeType(String mimeType) {\n\t\tthis.mimeType = mimeType;\n\t}\n\t\n\tpublic Map<String,String> getDataMap(){\n\t\tdataMap =new HashMap<String,String>();\n\t\tthis.fillScheme();\n\n\t\tthis.fillRest(\"host\", host);\n\t\tthis.fillRest(\"path\", path);\n\t\tthis.fillRest(\"port\", port);\n\t\tthis.fillRest(\"pathPrefix\", pathPrefix);\n\t\tthis.fillRest(\"pathPattern\", pathPattern);\n\t\tthis.fillRest(\"mimeType\", mimeType);\n\t\t\n\t\treturn dataMap;\n\t}\n\t\n\t/**\n\t * Fill scheme in the map.\n\t * If empty then use content and file\n\t */\n\tprivate void fillScheme(){\n\t\tif (scheme !=null)\n\t\t\tdataMap.put(\"scheme\", this.getScheme());\n\t}\n\t\n\tprivate void fillRest(String key, String value){\n\t\tif (value != null)\n\t\t\tdataMap.put(key,value);\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/IActivityService.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.List;\n\npublic interface IActivityService {\n\n\tpublic List<Intent> getIntent();\n\tpublic String getName();\n}\n"
  },
  {
    "path": "src/main/java/components/old/IComponent.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\n\npublic interface IComponent {\n\n\tpublic boolean isExported();\n\tpublic void setExported(boolean isExported);\n\tpublic ArrayList<Intent> getIntent();\n\tpublic String getName();\n\tpublic String getPermission();\n\t\n\tpublic void setName(String name);\n\tpublic void setPermission(String permission);\n\tpublic void setIntent(ArrayList<Intent> intentFilters);\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/Intent.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.List;\n\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\npublic class Intent {\n\tList<Action> actions;\n\tList<Category> categories;\n\tList<DataUri> data;\n\tint priority;\n\t\n\t\n\tpublic List<Action> getAction() {\n\t\treturn actions;\n\t}\n\t@XmlElement\n\tpublic void setAction(List<Action> action) {\n\t\tthis.actions = action;\n\t}\n\tpublic List<Category> getCategory() {\n\t\treturn categories;\n\t}\n\t@XmlElement\n\tpublic void setCategory(List<Category> category) {\n\t\tthis.categories = category;\n\t}\n\tpublic List<DataUri> getData() {\n\t\treturn data;\n\t}\n\t@XmlElement\n\tpublic void setData(List<DataUri> data) {\n\t\tthis.data = data;\n\t}\n\tpublic int getPriority() {\n\t\treturn priority;\n\t}\n\t@XmlAttribute\n\tpublic void setPriority(int priority) {\n\t\tthis.priority = priority;\n\t}\n\t\n\tpublic String toString() {\n\t\tString toReturn=\">>Intent: Data \"+this.getData()+\" Priority \"+Integer.toString(this.getPriority())+\"\\n\";\n\t\tfor (Action a : this.actions)\n\t\t{\n\t\t\ttoReturn+=a.toString();\n\t\t}\n\t\tfor (Category c : this.categories)\n\t\t{\n\t\t\ttoReturn+=c.toString();\n\t\t}\n\t\treturn toReturn;\n\t}\n\t\n}\n\n"
  },
  {
    "path": "src/main/java/components/old/Manifest.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\n\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlRootElement;\n\n\npublic class Manifest {\n\t\n\tprivate ArrayList<Intent> intents;\n\tprivate ArrayList<UsesPermission> usesPermissions;\n\tprivate ArrayList<Permission> Permissions;\n\tprivate Application application;\n\tprivate String pkgName;\n\n\tpublic ArrayList<Intent> getIntents() {\n\t\treturn intents;\n\t}\n\n\tpublic void setIntents(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\n\tpublic ArrayList<UsesPermission> getUsesPermissions() {\n\t\treturn usesPermissions;\n\t}\n\t\n\tpublic void setUsesPermissions(ArrayList<UsesPermission> usesPermissions) {\n\t\tthis.usesPermissions = usesPermissions;\n\t}\n\n\tpublic ArrayList<Permission> getPermissions() {\n\t\treturn Permissions;\n\t}\n\n\tpublic void setPermissions(ArrayList<Permission> permissions) {\n\t\tPermissions = permissions;\n\t}\n\n\tpublic Application getApplication() {\n\t\treturn application;\n\t}\n\n\tpublic void setApplication(Application application) {\n\t\tthis.application = application;\n\t}\n\t\n\tpublic String getPkgName() {\n\t\treturn pkgName;\n\t}\n\n\tpublic void setPkgName(String pkgName) {\n\t\tthis.pkgName = pkgName;\n\t}\n\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/Permission.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport javax.xml.bind.annotation.XmlAttribute;\n\npublic class Permission {\n\n\tString name,protectionLevel;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t@XmlAttribute(name=\"name\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getProtectionLevel() {\n\t\treturn protectionLevel;\n\t}\n\t@XmlAttribute(name=\"protectionLevel\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic void setProtectionLevel(String protectionLevel) {\n\t\tthis.protectionLevel = protectionLevel;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/Provider.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\n\nimport javax.xml.bind.annotation.XmlAttribute;\n\npublic class Provider implements IComponent{\n\t\n\tString name,permission,authorities;\n\tboolean isExported;\n\tArrayList<Intent> intent;\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\tpublic String getAuthorities() {\n\t\treturn authorities;\n\t}\n\tpublic void setAuthorities(String authorities) {\n\t\tthis.authorities = authorities;\n\t}\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intent;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intent) {\n\t\tthis.intent = intent;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn null;\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/Receiver.java",
    "content": "/*******************************************************************************\n * Copyright 2019 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\n\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\n\npublic class Receiver implements IComponent{\n\t\n\tboolean isExported;\n\tString name,permission,exp;\n\tArrayList<Intent> intents;\n\t\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn exp;\n\t}\n\tpublic void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intents;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intents) {\n\t\tthis.intents = intents;\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/Service.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.bind.annotation.XmlAttribute;\nimport javax.xml.bind.annotation.XmlElement;\n\npublic class Service implements IComponent,IActivityService{\n\tString name,exp, permission;\n\tboolean isExported;\n\tArrayList<Intent> intent;\n\t\n\tpublic Service() {\n\t\tthis.isExported = false;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getExp() {\n\t\treturn exp;\n\t}\n\tpublic void setExp(String exp) {\n\t\tthis.exp = exp;\n\t}\n\n\tpublic boolean isExported() {\n\t\treturn isExported;\n\t}\n\t\n\tpublic void setExported(boolean isExported) {\n\t\tthis.isExported = isExported;\n\t}\n\t\n\tpublic ArrayList<Intent> getIntent() {\n\t\treturn intent;\n\t}\n\tpublic void setIntent(ArrayList<Intent> intent) {\n\t\tthis.intent = intent;\n\t}\n\t\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/components/old/UsesPermission.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage components.old;\n\nimport javax.xml.bind.annotation.XmlAttribute;\n\npublic class UsesPermission {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t\n\t@XmlAttribute(name=\"name\",namespace=\"http://schemas.android.com/apk/res/android\")\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/components/old/XMLReader.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage base;\n\nimport java.awt.List;\nimport java.io.File;\nimport java.util.ArrayList;\nimport javax.xml.bind.JAXBContext;\nimport javax.xml.bind.Unmarshaller;\nimport javax.xml.bind.UnmarshallerHandler;\nimport attacks.ActivityStarter;\nimport attacks.Broadcaster;\n//import brut.androlib.ApktoolProperties;\nimport components.Manifest;\n\n/**\n * Marshal and Unmarshal Manifest file\n * Unused since v2.3\n * @author aabolhadid\n *\n */\npublic class XMLReader{\n\tprivate String manifestFile;\n\tprivate Manifest manifest;\n\t\n\tpublic XMLReader(String manifestFile) {\n\t\tthis.manifestFile = manifestFile;\n\t\tthis.unmarshalManifest();\n\t}\n\n\tpublic void unmarshalManifest() {\n\t\tManifest man=new Manifest();\n\t\tFile manifest = new File(this.manifestFile);\n\t\t\n\t\ttry {\n\t        \n\t\t\tJAXBContext context = JAXBContext.newInstance(Manifest.class);\n\t\t\tUnmarshaller jaxbUnmarshaller = context.createUnmarshaller();\n\t\t\tman = (Manifest) jaxbUnmarshaller.unmarshal(manifest);\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\tSystem.out.println(\"ERROR: Manifest cannot be parsed\");\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tthis.manifest = man;\n\t}\n\t\n\tpublic Manifest getManifest() {\n\t\treturn this.manifest;\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/db/DatabaseTester.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage db;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class DatabaseTester {\n\tprivate Commando commando;\n\tprivate FileUtil fileTrans;\n\t\n\tpublic DatabaseTester() {\n\t\tthis.commando = new Commando();\n\t\tthis.fileTrans = new FileUtil();\n\t}\n\t\n\tpublic ArrayList<File> fetchAllDBs(String dir){\n\t\tSearchUtil searcher = new SearchUtil();\n\t\tList<File> files = searcher.search4FileInDir(dir, null);\n\t\tArrayList<File> dbs = new ArrayList<File>();\n\t\t\n\t\tfor (File f:files){\n\t\t\tif (this.isFileDB(f))\n\t\t\t\tdbs.add(f);\n\t\t}\n\t\t\n\t\treturn dbs;\n\t}\n\t\n\tpublic void dbOption(String param){\n\t\tif (param == null ||param.equals(\"e\") || param.equals(\"encryption\")){\n\t\t\tOutBut.printH1(\"Database encryption\");\n\t\t\tthis.testDBAllFiles(TicklerVars.dataDir);\n\t\t\t}\n\t\t\n\t\telse if (param.equals(\"l\") || param.equals(\"list\")){\n\t\t\tthis.listDatabases(TicklerVars.dataDir);\n\t\t}\n\t\telse if (param.equals(\"d\") || param.equals(\"dump\")){\n\t\t\tthis.chooseDBToDump(TicklerVars.dataDir);\n\t\t} \n\t\telse {\n\t\t\tOutBut.printError(\"Unknown option \"+param);\n\t\t}\n\t}\n\t\n\t/**\n\t * Checks if the file is a database file\n\t * @param f File file under test\n\t * @return true: if file is DB\n\t */\n\tpublic boolean isFileDB(File f){\n\t\tString path = f.getAbsolutePath();\n\t\tString command = \"file \"+ path+\"\";\n\t\tString result = commando.executeProcessString(command).get(0);\n\t\tif (result.matches(\"(?s).*\\\\bdatabase\\\\b.*\")){\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * Lists all databases in a specific directory\n\t * @param dir\n\t */\n\tpublic ArrayList<File> listDatabases(String dir){\n\t\tArrayList<File> allDB = this.fetchAllDBs(dir);\n\t\tOutBut.printH1(\"List of Databases of the app\");\n\t\tSystem.out.println(\"!!!! WARNING: Encrypted databases might not be detected !!!!\\n\\n\");\n\t\tfor (int i=0;i<allDB.size();i++){\n\t\t\tFile f = allDB.get(i);\n\t\t\tSystem.out.println((i+1)+\"-\"+f.getName());\n\t\t\tSystem.out.println(\"\tLocation: \"+f.getAbsolutePath().replace(TicklerVars.appTickDir, \"[Tickler_App_Dir]/\"));\n\t\t}\n\t\t\n\t\tif (allDB.size()>1){\n\t\t\tSystem.out.println(\"\\n...Where [Tickler_App_Dir] is \"+TicklerVars.appTickDir);\n\t\t}\n\t\treturn allDB;\n\t}\n\t\n\t//////////////////////////// DB Encryption ///////////////////////////\n\t\n\t/**\n\t * Tests the encryption of all databases in a specific directory\n\t * @param dir\n\t */\n\tpublic void testDBAllFiles(String dir) {\n\t\t\n\t\tArrayList<File> dbs= this.fetchAllDBs(dir);\n\t\tfor (File f:dbs){\n\t\t\tthis.testDBEncryption(f);\n\t\t}\n\t\tSystem.out.println(\"!!! NOTE: Any path that contains a space is replaced by two underscores in the DataDir folder\"\n\t\t\t\t+ \" on your machine\");\n\t}\n\t\n\t/**\n\t * Runs the encryption Tests on a single DB\n\t * @param f\n\t */\n\tpublic void testDBEncryption(File f){\n\t\t\n\t\tString result=\"\";\n\t\t\tif (this.isDBEncrypted(TicklerVars.replaceSpace(f.getAbsolutePath())) )\n\t\t\t\tresult=\"encrypted\";\n\t\t\telse\n\t\t\t\tresult = \"NOT encrypted\";\n\t\t\t\n\t\t\tSystem.out.println(\"Database:\"+f.getName()+\" is \"+result);\n\t}\n\t\n\t/**\n\t * Tests if a single DB is encrypted\n\t * @param f\n\t */\n\tpublic boolean isDBEncrypted(String dbName) {\n\t\tString command = \"sqlite3 \"+dbName+\" .tables\";\n\t\tString output = this.commando.executeCommand(command);\n\t\tif (output.contains(\"encrypted or is not a database\"))\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\t\n\t\n\t///////////////////// Database Dump /////////////////////////////\n\t\n\t/**\n\t * Lists databases to user and dumps one of them based on his choice\n\t * @param dir\n\t */\n\tpublic void chooseDBToDump(String dir){\n\t\tArrayList<File> allDB = this.listDatabases(dir);\n\t\tSystem.out.println(\"\\nEnter the number of the database to be dumped....\");\n\t\tString choice = OtherUtil.pressAnyKeySilent();\n\t\tInteger i=999;\n\t\ttry {\n\t\t\ti = new Integer(choice);\t\n\t\t}\n\t\tcatch(Exception e){\n\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tif((i-1)< allDB.size() && i>0){\n\t\t\tString dbFile = allDB.get((i-1)).getAbsolutePath();\n\t\t\tString dbName = allDB.get((i-1)).getName();\n\t\t\tString ts =this.fileTrans.prepareTimestampTransfer();\n\t\t\tString dumpName=TicklerVars.transferDir+dbName+\"_\"+ts+\".dump\";\n\t\t\tthis.dumpDBToFile(dbFile, dumpName);\n\t\t\t\n\t\t\tif (this.fileTrans.isExist(dumpName)){\n\t\t\t\tSystem.out.println(\"Database is dumped to file: \"+dumpName);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSystem.out.println(\"Incorrect choice, please enter a number from the database list\");\n\t\t}\n\t}\n\t\n\t/**\n\t * Dumps the whole database\n\t * @param dbName String: path of the database file\n\t * @return\n\t */\n\tpublic String dumpDB(String dbName){\n\t\tString command = \"sqlite3 \"+dbName+\" .dump\";\n\t\tString output = this.commando.executeCommand(command,false);\n\t\t\n\t\treturn output;\n\t}\n\t\n\t/**\n\t * Dumps the whole database into a text file\n\t * @param dbName String: path of the database file\n\t * @return dumpName ; path of the dump file\n\t */\n\tpublic String dumpDBToFile(String dbName,String dumpFile){\n\t\tFileUtil ft = new FileUtil();\n\t\tif (dumpFile == null)\n\t\t\tdumpFile= dbName+\".dump\";\n\t\tString output = this.dumpDB(dbName);\n\t\tft.writeFile(dumpFile, output);\n\t\t\n\t\treturn dumpFile;\n\t}\n\t\n\n\t///////////////////////////// Search in DB /////////////////////////////\n\t\n\t\n\t/**\n\t * Search for a key in all databases in Data Dir\n\t * @param key\n\t */\n\tpublic void searchForKeyInDb(String key){\n\t\tArrayList<File> dbs = this.fetchAllDBs(TicklerVars.dataDir);\n\t\tboolean found = false;\n\t\t\n\t\tfor(File db: dbs){\n\t\t\tif (this.searchForKeyInSingleDB(key, db))\n\t\t\t\tfound = true;\n\t\t}\n\t\t\n\t\tif(found){\n\t\t\tOutBut.printNormal(\"\");\n\t\t\tOutBut.printStep(\"Where [Data_Dir] is \"+TicklerVars.dataDir);\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Search for a key in a single database file\n\t * @param key\n\t * @param db\n\t */\n\tprivate boolean searchForKeyInSingleDB(String key, File db){\n\t\tString dump, dbName, output;\n\t\tboolean found = false;\n\t\tArrayList<String> tableNames,noDupTabNames;\n\t\tdump = this.dumpDB(db.getAbsolutePath());\n\t\tif (dump.contains(key)) {\n\t\t\tfound = true;\n\t\t\tdbName= db.getAbsolutePath().replaceAll(TicklerVars.dataDir, \"[Data_Dir]/\");\n\t\t\ttableNames = this.getKeyInfoFromDBDump(key, dump);\n\t\t\tnoDupTabNames = OtherUtil.removeDuplicates(tableNames);\n\t\t\n\t\t\toutput = \"Database Name: \"+dbName+\"\\t\\tTable Name(s): \";\n\t\t\tfor(String tabName : noDupTabNames){\n\t\t\t\toutput+=tabName+\", \";\n\t\t\t}\n\t\t\t\n\t\t\tSystem.out.println(output.substring(0, output.length()-2));\n\t\t}\n\t\t\n\t\treturn found;\n\t}\n\t\n\t\n\t/**\n\t * Searches for a key in the dump of a database\n\t * @param key\n\t * @param dump\n\t * @return\n\t */\n\tprivate ArrayList<String> getKeyInfoFromDBDump(String key, String dump){\n\t\tArrayList<String> tables = new ArrayList<>();\n\t\tList<String> lines= Arrays.asList(dump.split(\"\\n\"));\n\t\tfor (String line: lines){\n\t\t\tif (line.contains(key)){\n\t\t\t\ttables.addAll(OtherUtil.getRegexFromString(line, \"INSERT INTO \\\"(.*?)\\\"\"));\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn tables;\n\t\t\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/device/Packagez.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage device;\n\nimport java.util.ArrayList;\n\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class Packagez {\n\n\t\n\tpublic boolean searchPackage(String key,boolean syso){\n\t\tboolean isFound=false;\n\t\tArrayList<String> results = new ArrayList<>();\n\t\t\n\t\tString output = this.fetchInstalledPkgs();\n\t\tString[] opLines = output.split(\"\\n\");\n\t\t\n\t\t\n\t\tfor (String s:opLines)\n\t\t\tif (s.toLowerCase().contains(key.toLowerCase())){\n\t\t\t\tisFound = true;\n\t\t\t\tresults.add(s);\n\t\t\t}\n\t\t\n\t\tif (!results.isEmpty() && syso){\n\t\t\tOutBut.printH2(\"Possible Package names\");\n\t\t\tfor (String s:results){\n\t\t\t\tString res = s.substring(s.indexOf(\":\")+1);\n\t\t\t\tSystem.out.println(res);\n\t\t\t}\n\t\t}\n\t\telse if (syso)\t\t\n\t\t\tSystem.out.println(\"No package matches the search key :(\");\n\t\treturn isFound;\n\t\t\n\t}\n\t/**\n\t * Makes sure that the exact pkgName exists, Case sensitive and full match\n\t * @param pkgName\n\t */\n\tpublic boolean isPackageExist(String pkgName){\n\t\tString[] packages = this.fetchInstalledPkgs().split(\"\\n\");\n\t\t\n\t\tfor (String pkg:packages){\n\t\t\tString pkg2 = pkg.replace(\"package:\", \"\");\n\t\t\tif (pkgName.equals(pkg2))\n\t\t\t\treturn true;\n\t\t}\n\t\t\n\t\treturn false;\n\t}\n\t\n\tpublic String fetchInstalledPkgs(){\n\t\tString command = \"pm list package \";\n\t\tCommando commando = new Commando();\n\t\tString output = commando.execADB(command);\n\t\t\n\t\treturn output;\n\t}\n\t\n\tpublic void printInstalledPkgs() {\n\t\tString pkgs = this.fetchInstalledPkgs();\n\t\tOutBut.printH1(\"Installed Packages\");\n\t\tSystem.out.println(pkgs);\n\t}\n\n\t/**\n\t * execute pm dump command to get a package's information\n\t * @return\n\t */\n\tpublic ArrayList<String> dumpInfo(){\n\t\tArrayList<String> matches = new ArrayList<>();\n\t\tString command = \"pm dump \"+TicklerVars.pkgName;\n\t\t\n\t\tCommando commando = new Commando();\n\t\tString dump = commando.execADB(command, false);\n\t\t\n\t\tString userID = this.getParameterFromDump(\"userId\", dump);\n\t\tString codePath = this.getParameterFromDump(\"codePath\", dump);\n\t\tString versionName = this.getParameterFromDump(\"versionName\", dump);\n\t\tString firstInstallTime = this.getParameterFromDump(\"firstInstallTime\", dump);\n\t\t\n\t\tmatches.add(\"userID: \"+userID);\n\t\tmatches.add(\"API path: \"+codePath);\n\t\tmatches.add(\"Version name: \"+versionName);\n\t\tmatches.add(\"Installation date: \"+firstInstallTime);\n\t\t\n\t\treturn matches;\n\t\t\n\t}\n\t\n\tpublic String getParameterFromDump(String par, String dump) {\n\t\tString value=\"\";\n\t\tint index = dump.indexOf(par);\n\t\tvalue = dump.substring(dump.indexOf(\"=\", index)+1, dump.indexOf(\"\\n\", index));\n\t\treturn value;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/docs/helpMsg.txt",
    "content": "\tusage: Tickler\t\n        ==============\n\tPlease make sure that the configuration file: Tickler.conf is at the same directory as\n\tthe Tickler .jar file. Tickler.conf file defines Tickler's directory on the host and the\n\ttemp directory on the android device.\n\n\tOptions\n\t---------\n\t-h, --help\t\t\t\t\tPrints this message\n\t-version\t\t\t\t\tPrint version\n    -screen\t\t\t\t\t\tTake a screenshot of the device\n    -findPkg <key>\t\t\t\tSearch for a package name\t\n\t-pkgs\t\t\t\t\t\tList all installed packages on the android device\t\n    -offline\t\t\t\t\tOffline Mode, no devices needed to be connected\n\t-pkg\t\t\t\t\t\tSpecify package name of the app\t\t\n\t\t\n\tOptions of pkg:\t\n\t--------------\t\n\t-info\t\t\t\t\t\tList information about the app\t\n\t-squeeze\t\t\t\t\tAll strings, log functions, possible credentials in decompiled APK\t\n\t-squeeze short\t\t\t\tLimits the squeezed code to the developer's code (most libraries excluded)\t\n\t-dbg, --debuggable\t\t\tCreate a debuggable version of the app\t\n\t-apk <dir> <name>\t\t\tCompiles a new apk from <dir> directory under the name of <name> \n\t-dataDir [name]\t\t\t\tCopies data directory of app to Tickler Directory (DataDir or transfers/name)\t\n\t-diff\t\t\t\t\t\tCopies app's data directory before and after a user's action, then diffs between them\n \t-diff \t[d| detailed]\t\tlike diff, but also shows the changes in case a text file or an unecrypted database is changed\n\t-db [option] [-nu]\t\t\t\tDatabase checks. By default app's Data Dir is copied to host before checks\n \t\t[-nu | --noUpdate]\t\t\tDoes not update DataDir on host before checks \n \t\t[option] can be:\n\t\t\t[ |e|encryption]\t\tChecks whether the database files of the app are encrypted or not\n\t\t\t[l |list]\t\t\t\tLists Databases of the app \n\t\t\t[d |dump]\t\t\t\tDumps an unencrypted database\n\t\t\t\n \t-sc <key>\t\t\t\t\tSearch for \"key\" in the app's decompiled Java code\n \t-sd <key> [-nu]\t\t\t\tPulls app's Data directory and searches for \"key\" in it\n \t\t\t[-nu | --noUpdate]\t\tDoes not pull DataDir on host before search\n \t\t\t\n\t-t [target] [-log]\t\t\tTickels a target. The type of the attack depends on the target\t\n \t   -log\t\t\t\t\t\t\tCaptures logcat messages \n\t-l,--list [target] [-v]\t\tList components of type target\t\n\t   -v \t\t\t\t\t\t\tList component(s) in details\n\t\t\n\t\t\n\tTargets:\t\n\t--------\t\n\t-act,--activities\t\tActivities\t\n\t-ser,--services\t\t\tServices\t\n\t-prov,--providers\t\tContent providers\t\n\t-rec,--receivers\t\tBroadcast receivers\t\n\t[ | -comp] <name>\t\tA specific component, its name has to be exactly as in Manifest file (also displayed by -l)\t\n\t-exp\t\t\t\t\tApplies [trigger | list] action to exported components only\t\n\t[ | -all]\t\t\t\tAll components (default if none of the above targets are specified)\t\n\t\t\n\tOptions that work with and without -pkg option\n\t-----------------------------------------------\n \t-screen\t\t\t\tCaptures a screenshot of the device\n \t-cp2host <source> [destName]\tCopies any file/directory to the tickler's app directoy on the host\n \t-bg,--bgSnapshots\t\tCopies background screenshots that are saved on the device\n\n\tFrida\t\n\t-----\t\n\t-frida enum \t\t\n\t\tEnumerates loaded classes\t\n\t-frida vals <ClassName> <MethodName> <NumberOfArgs> [-reuse]\t\n\t\tDisplays arguments and return value of this method (only primitive datatypes and String)\t\n\t\t\t\n\t-frida set <ClassName> <MethodName> <NumberOfArgs> <NumberOfArgToModify> <newValue>[-reuse]\t\n\t\tSets the argument number <NumberOfArgToModify> to <newValue> (only primitive datatypes and String)\t\n\t\tIf <NumberOfArgToModify> > <NumberOfArgs>: sets the return value \t\n\t\t\n\t-frida script <scriptPath>\n\t\tRun custom frida JS script \t\n\n\tExamples:\t\n\t---------\t\n\t1) List all components of package com.test.package, with detailed information\t\n\t-----------------------------------------------------------------------------\t\n\tjava -jar Tickler.jar -pkg com.test.package -l -v\t\n\t\t\n\t2) Trigger exported activities of package com.test.package\t\n\t-----------------------------------------------------------\t\n\tjava -jar Tickler.jar -pkg com.test.package -t -act -exp\t\n\n\t3) Squeeze app's decompiled Java code\tfor strings, log messages...etc\n\t-----------------------------------------------------------------------\t\n\tjava -jar Tickler.jar -pkg com.test.package -squeeze \n\t\t- output is automatically saved in squeeze.txt file in the app's directory"
  },
  {
    "path": "src/main/java/exceptions/TNotFoundEx.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage exceptions;\n\npublic class TNotFoundEx extends Exception {\n\tpublic TNotFoundEx(String message){\n\t\tsuper(message);\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaBase.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport apk.AppBroker;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class FridaBase {\n\t\n\tpublic FridaBase() {\n\t\t\n\t}\n\t\n\tpublic void fridaEnumerateClasses(boolean reuse){\n\t\tFridaEnumerateClasses enumClasses = new FridaEnumerateClasses(reuse);\n\t\tenumClasses.run();\n\t}\n\t\n\tpublic void fridaScript(ArrayList<String> args){\n//\t\tFridaPythonScript script = new FridaPythonScript(args);\n//\t\tscript.execute();\n\t\tFridaJsScript script = new FridaJsScript(args.get(1));\n\t\tscript.prepareCommandNoSpawning();\n\t\tOutBut.printNormal(\"\\nPlease start the app before running this command\\n\");\n\t\t\n\t\tscript.run();\n\t}\n\t\n\tpublic void fridaGetInputAndOutput(ArrayList<String> args, boolean reuse){\n\t\tFridaGetArgsAndReturn action = new FridaGetArgsAndReturn(reuse);\n\t\taction.run(args);\n\t}\n\t\n\tpublic void fridaSetValue(ArrayList<String> args, boolean reuse){\n\t\tFridaSetValue action = new FridaSetValue(reuse);\n\t\taction.run(args);\n\t}\n\t\n\tpublic void fridaUnpin(ArrayList<String> args, boolean reuse) {\n\t\tFridaUnpinSslContext action = new FridaUnpinSslContext(reuse);\n\t\taction.run(args);\n\t}\n\t\n\n\t\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaCli.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport cliGui.OutBut;\n\npublic class FridaCli {\n\n\tprivate FridaBase base;\n\tprivate FridaInit init;\n\t\n\tpublic FridaCli(){\n\t\tthis.base = new FridaBase();\n\t\tthis.init = new FridaInit();\n\t\t\n\t\tthis.init.initFrida();\n\t}\n\t\n\t/**\n\t * arg0: Name of function\n\t * arg1- : args of the function\n\t * @param args\n\t */\n\tpublic void fridaThis(String [] args, boolean reuse){\n\t\tString functionName = args[0];\n\t\tArrayList<String> scriptArgs = new ArrayList<>(Arrays.asList(args)); \n\t\t\n\t\tswitch(functionName){\n\t\tcase \"enum\":\n\t\t\tthis.base.fridaEnumerateClasses(reuse);\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"script\":\n\t\t\tthis.base.fridaScript(scriptArgs);\n//\t\t\n\t\t\n\t\tcase \"vals\":\n\t\t\tthis.base.fridaGetInputAndOutput(scriptArgs, reuse);\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"set\":\n\t\t\tthis.base.fridaSetValue(scriptArgs, reuse);\n\t\t\tbreak;\n\t\t\t\n\t\tcase \"unpin\":\n\t\t\tthis.base.fridaUnpin(scriptArgs, reuse);\n\t\t\tbreak;\n\t\t\t\n\t\tdefault:\n\t\t\t\tOutBut.printError(\"Unknown option \"+functionName);\n\t\t\t\tbreak;\n\t\t\n\t\t}\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaEnumerateClasses.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport cliGui.OutBut;\nimport initialization.TicklerVars;\n\npublic class FridaEnumerateClasses extends FridaJsAction{\n\n\t\n\tpublic FridaEnumerateClasses(boolean reuseScript) {\n\t\tthis.script = new FridaJsScript(FridaVars.ENUM_LOC);\n\t\tif (reuseScript)\n\t\t\tthis.code = this.script.getCodeFromScript();\n\t\telse\n\t\t\tthis.code = FridaVars.ENUM_CODE;\n\t}\n\t\n\tpublic void run(){\n\t\tOutBut.printNormal(\"\\nPlease start the app before running this command\\n\");\n\t\tthis.executeNoSpawn(this.code);\n\t}\n\t\n}\n\n"
  },
  {
    "path": "src/main/java/frida/FridaGetArgsAndReturn.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\n\nimport java.util.ArrayList;\n\nimport base.FileUtil;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\n/**\n * GEt input and output of a method, provided the following:\n * 1) the method is not overloaded: only one method of this name\n * 2) inputs and outputs are of primitive data types or String\n * @author aabolhadid\n *\n */\npublic class FridaGetArgsAndReturn extends FridaJsAction{\n\n\t\n\tpublic FridaGetArgsAndReturn(boolean reuseScript) {\n\t\tthis.script = new FridaJsScript(FridaVars.GET_VALS_JS);\n\t\tif (reuseScript)\n\t\t\tthis.code = this.script.getCodeFromScript();\n\t\telse\n\t\t\tthis.code = FridaVars.GET_VALS_CODE;\n\t}\n\t\n\tpublic void run(ArrayList<String> args){\n\t\tString finalCode = this.prepareCode(args);\n\t\tthis.execute(finalCode);\n\n\t}\n\t\n\n\tprivate String prepareCode(ArrayList<String> args){\n\t\tString tempCode = this.code.replaceAll(\"\\\\$className\", args.get(1)).replaceAll(\"\\\\$method_name\", args.get(2));\n\t\tint numberOfArgs = new Integer(args.get(3));\n\t\tArrayList<String> methodArgs = this.getMethodArguments(numberOfArgs);\n\t\t\n\t\tString methodArguments=\"\";\n\t\tString consoleLogArgs = \"\";\n\t\tfor (String s: methodArgs){\n\t\t\tmethodArguments+=s+\", \";\n\t\t\tconsoleLogArgs+=\"console.log(\\\"Input: \\\"+\"+s+\");\\n\"; \n\t\t}\n\t\tif (!methodArguments.isEmpty())\n\t\t\tmethodArguments = methodArguments.substring(0, methodArguments.length()-2);\n\t\t\n\t\ttempCode = tempCode.replaceAll(\"\\\\$args\", methodArguments);\n\t\ttempCode = tempCode.replaceAll(\"\\\\$console_log_inputs\", consoleLogArgs);\n\t\t\n\t\treturn tempCode;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaInit.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class FridaInit {\n\t\n\tprivate Commando commando;\n\tprivate FileUtil fU;\n\t\n\tpublic FridaInit()\n\t{\n\t\tthis.commando = new Commando();\n\t\tthis.fU = new FileUtil();\n\t}\n\t\n\t\n\tpublic void initFrida(){\n\t\tif (!(this.isFrida() && this.isFridaServer() && this.isPython())){\n\t\t\tOutBut.printError(\"Frida is not properly configured\");\n\t\t\tSystem.exit(127);\n\t\t}\n\t\t\n\t\tthis.fU.createDirOnHost(TicklerVars.fridaScriptsDir);\n\t\t\n\t}\n\t\n\t/**\n\t * Frida exists on host\n\t * @return\n\t */\n\tprivate boolean isFrida(){\n\t\tString cmd = \"frida -h\";\n\t\tint ret = commando.executeProcessListPrintOP(cmd,false);\n\t\t\n\t\tif (ret != 0)\n\t\t\treturn false;\n\t\t\n\t\treturn true;\n\t}\n\t\n\t/**\n\t * If Frida server exists on the device\n\t * @return\n\t */\n\tprivate boolean isFridaServer(){\n\t\tString cmd = TicklerVars.fridaServerLoc+\" -h\";\n\t\tString ret = commando.execADB(cmd);\n\t\t\n\t\tif (ret.toLowerCase().contains(\"--version\"))\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\t\n\tprivate boolean isPython(){\n\t\tString cmd = \"python3 -h\";\n\t\tint ret = commando.executeProcessListPrintOP(cmd,false);\n\t\t\n\t\tif (ret != 0)\n\t\t\treturn false;\n\t\t\n\t\treturn true;\n\t}\n\n\tpublic void startFridaServer(){\n\t\tString cmd = TicklerVars.fridaServerLoc+\"&\";\n\t\tcommando.execRoot(cmd);\n\t}\n\t\n\tpublic void stopFridaServer(){\n\t\tString[] serverName = TicklerVars.fridaServerLoc.split(\"/\");\n\t\tString serverPSOutput = commando.execRoot(\"ps | grep \"+serverName[serverName.length -1]);\n\t\tif (!serverPSOutput.isEmpty()){\n\t\t\tString serverPs = serverPSOutput.split(\"\\\\s+\")[1];\n\t\t\tcommando.execRoot(\"kill -9 \"+serverPs);\n\t\t\ttry {\n\t\t\t\tThread.sleep(5000);\n\t\t\t}\n\t\t\tcatch(InterruptedException e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\t\n\tprivate void restartFridaServer() {\n\t\tthis.stopFridaServer();\n\t\tthis.startFridaServer();\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaJsAction.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport commandExec.Commando;\nimport initialization.TicklerChecks;\nimport initialization.TicklerVars;\n\npublic class FridaJsAction {\n\tprotected FridaJsScript script;\n\tprotected String code;\n\t\n\tpublic void execute(String finalCode) {\n\t\tTicklerChecks ticklerChecks = new TicklerChecks();\n\t\tif(ticklerChecks.isEmulator() || this.isAppRunning())\n\t\t\tthis.executeNoSpawn(finalCode);\n\t\telse\n\t\t\tthis.executeSpawn(finalCode);\n\t\t\n\t}\n\t\n\tpublic void executeSpawn(String finalCode){\n\t\tthis.script.writeCodeInScript(finalCode);\n\t\tthis.script.prepareCommand();\n\t\tthis.script.run();\n\t\n\t\t\n\t}\n\t\n\t\n\tpublic void executeNoSpawn(String finalCode){\n\t\tthis.script.writeCodeInScript(finalCode);\n\t\tthis.script.prepareCommandNoSpawning();\n\t\tthis.script.run();\n\t\n\t\t\n\t}\n\t\n\t\n\tprotected ArrayList<String> getMethodArguments(int num){\n\t\tArrayList<String> methodArgs = new ArrayList<>();\n\t\tfor (int i=0;i<num;i++){\n\t\t\tmethodArgs.add(\"arg\"+i);\n\t\t}\n\t\treturn methodArgs;\n\t}\n\t\n\tpublic boolean isAppRunning() {\n\t\tCommando cmd = new Commando();\n\t\tString command=\"frida-ps -U\";\n\t\tString op = cmd.executeCommand(command);\n\t\t\n\t\tif (op.contains(TicklerVars.pkgName)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaJsScript.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\n\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport base.FileUtil;\nimport commandExec.Commando;\nimport initialization.TicklerChecks;\nimport initialization.TicklerVars;\n\n/**\n * GEt input and output of a method, provided the following:\n * 1) the method is not overloaded: only one method of this name\n * 2) inputs and outputs are of primitive data types or String\n * @author aabolhadid\n *\n */\npublic class FridaJsScript {\n\n\tprivate String scriptPath;\n\tprivate String command ;\n\tprivate FileUtil fU;\n\tprivate Commando commando;\n\tpublic FridaJsScript(String path) {\n\t\tthis.fU = new FileUtil();\n\t\tthis.commando = new Commando();\n\t\tthis.scriptPath=path;\n\t}\n\t\n\tpublic void run(){\n\t\t\n//\t\tcommando.executeProcessListPrintOPError(command);\t\n\t\tcommando.executeProcessListPrintOP(command, true);\n\t\t\n\t}\n\t\n\t/**\n\t * If Emulator --> Don't spawn !!\n\t */\n\tpublic void prepareCommand(){\n\t\tTicklerChecks ticklerChecks = new TicklerChecks();\n\t\tif(ticklerChecks.isEmulator() || this.isAppRunning())\n\t\t\tthis.prepareCommandNoSpawning();\n\t\telse\n\t\t\tthis.prepareCommandSpawn();\n\t\t\n\t}\n\t\n\tpublic void prepareCommandSpawn(){\n\t\tthis.command = \"frida -U -f \"+TicklerVars.pkgName+\" -l \"+this.scriptPath+\" --no-pause\" ;\n\t\t\n\t}\n\t\n\tpublic void prepareCommandNoSpawning(){\n\t\tthis.command = \"frida -U \"+TicklerVars.pkgName+\" -l \"+this.scriptPath ;\n\t}\n\n\n\t\n\tpublic void writeCodeInScript(String code){\n\t\tthis.fU = new FileUtil();\n\t\tthis.fU.writeFile(this.scriptPath, code);\n\t}\n\t\n\tpublic String getCodeFromScript(){\n\t\tString code =\"\";\n\t\ttry {\n\t\t\tcode = this.fU.readFile(this.scriptPath);\n\t\t}\n\t\tcatch(IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn code;\n\t}\n\t\n\tpublic ArrayList<String> getMethodArguments(int num){\n\t\tArrayList<String> methodArgs = new ArrayList<>();\n\t\tfor (int i=0;i<num;i++){\n\t\t\tmethodArgs.add(\"arg\"+i);\n\t\t}\n\t\treturn methodArgs;\n\t}\n\t\n\tpublic boolean isAppRunning() {\n\t\tCommando cmd = new Commando();\n\t\tString command=\"frida-ps -U\";\n\t\tString op = cmd.executeCommand(command);\n\t\t\n\t\tif (op.contains(TicklerVars.pkgName)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaPythonScript.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport base.OtherUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class FridaPythonScript {\n\n\tpublic String path;\n\tprivate Commando commando;\n\tprivate ArrayList<String> args;\n\t\n\tpublic FridaPythonScript(){\n\t\tthis.commando = new Commando();\n\t}\n\t\n\tpublic FridaPythonScript(ArrayList<String>args){\n\t\tthis();\n\t\tthis.prepareArgs(args);\n\t\t\t\n\t}\n\t\n\tprivate void prepareArgs(ArrayList<String>args){\n\t\tString origPath = args.get(1);\n\t\tString scriptPath = OtherUtil.getAbsolutePath(origPath);\n\t\tif (scriptPath == null){\n\t\t\tOutBut.printError(\"Path of the script: \"+origPath+\" does not exist\");\n\t\t\tSystem.exit(127);\n\t\t}\n\t\telse{\n\t\t\tthis.setPath(scriptPath);\n//\t\t\tthis.args = new ArrayList)args.subList(1, args.size());\n\t\t\tthis.args = new ArrayList<>( args.subList(2, args.size()));\n\t\t\tthis.args.add(0, TicklerVars.pkgName);\n\t\t}\n\t}\n\t\n\t\n\tpublic void execute(){\n\t\tString command = \"python3 \"+this.path;\n\t\tif (this.args!= null){\n\t\t\tfor (String s:this.args)\n\t\t\t\tcommand=command+\" \"+s;\n\t\t}\n\n\t\tcommando.executePythonScript(command);\n\t}\n\t\n\tpublic void execute(ArrayList<String> args){\n\t\tthis.args = args;\n\t\tthis.execute();\n\t}\n\t\n\tpublic ArrayList<String> executeReturnOutput(ArrayList<String> args){\n\t\tString command = \"python3 \"+this.path;\n\t\tif (args!= null){\n\t\t\tfor (String s:args)\n\t\t\t\tcommand=command+\" \"+s;\n\t\t}\n\t\t\n\t\tcommando.executeProcessListPrintOP(command, true);\n\t\treturn new ArrayList<String>();\n\t}\n\t\n\tpublic String getOutput(ArrayList<String> args){\n\t\treturn this.executeReturnOutput(args).get(1);\n\t}\n\t\n\tpublic void setPath(String path){\n\t\tString scriptPath = OtherUtil.getAbsolutePath(path);\n\t\tif (scriptPath == null){\n\t\t\tOutBut.printError(\"Path of the script: \"+path+\" does not exist\");\n\t\t\tSystem.exit(127);\n\t\t}\n\t\telse\n\t\t\tthis.path = scriptPath; \n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaScript.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport commandExec.Commando;\n\npublic class FridaScript {\n\n\tpublic String path;\n\tprivate Commando commando;\n\t\n\tpublic FridaScript(){\n\t\tthis.commando = new Commando();\n\t}\n\t\n\tpublic ArrayList<String> executeScript(ArrayList<String> args){\n\t\tString command = \"python3 \"+this.path;\n\t\tif (args!= null){\n\t\t\tfor (String s:args)\n\t\t\t\tcommand=command+\" \"+s;\n\t\t}\n\t\t\n\t\tArrayList<String> op =commando.executeProcessString(command);\n\t\treturn op;\n\t}\n\t\n\tpublic String getOutput(ArrayList<String> args){\n\t\treturn this.executeScript(args).get(1);\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaSetValue.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\n\nimport java.util.ArrayList;\n\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\n/**\n * GEt input and output of a method, provided the following:\n * 1) the method is not overloaded: only one method of this name\n * 2) inputs and outputs are of primitive data types or String\n * @author aabolhadid\n *\n */\npublic class FridaSetValue {\n\n\tprivate FridaJsScript script;\n\tprivate String code;\n\t\n\tpublic FridaSetValue(boolean reuseScript) {\n\t\tthis.script = new FridaJsScript(FridaVars.SET_VALS_JS);\n\t\t\n\t\tif (reuseScript)\n\t\t\tthis.code = this.script.getCodeFromScript();\n\t\telse\n\t\t\tthis.code = FridaVars.SET_VALS_CODE;\n\t}\n\t\n\tpublic void run(ArrayList<String> args){\n\t\tString finalCode = this.prepareCode(args);\n\t\tthis.script.writeCodeInScript(finalCode);\n\t\tthis.script.prepareCommand();\n\t\tthis.script.run();\n\t\n\t}\n\t\n\n\t// args would be like: set, ClassName, MethodName, number_of_args, valNum, newValue  \n\t// myArgs : pkgName, ClassName, MethodName, methodArgs(arg0,1...etc) \n\tprivate String prepareCode(ArrayList<String> args){\n\t\t\n\t\tString tempCode = this.code.replaceAll(\"\\\\$className\", args.get(1)).replaceAll(\"\\\\$methodName\", args.get(2));\n\t\tint numberOfArgs = new Integer(args.get(3));\n\t\t\n\t\tArrayList<String> methodArgs = this.getMethodArguments(numberOfArgs); \n\t\t\n\t\tString methodArguments=\"\";\n\t\tString consoleLog = \"\";\n\t\tfor (String s: methodArgs){\n\t\t\tmethodArguments+=s+\", \";\n\t\t}\n\t\t\n\t\tif (!methodArguments.isEmpty())\n\t\t\tmethodArguments = methodArguments.substring(0, methodArguments.length()-2);\n\t\t\n\t\ttempCode = tempCode.replaceAll(\"\\\\$args\", methodArguments);\n\t\t\n\t\t\n\t\t\n\t\t\n\t\tString newValue = this.correctStringsInArgs(args.get(5));\n\t\t\n\t\tif (this.isSetReturnValue(args.get(4))) {\n\t\t\t//Modify return value\n\t\t\ttempCode = tempCode.replaceAll(\"\\\\$returnValue\", newValue);\n\t\t\ttempCode = tempCode.replaceAll(\"\\\\$output_line\", \"console.log(\\\"Old return value: \\\"+orig_return.toString()+ \\\". New return value: \\\"+\"+newValue+\");\");\n\t\t}\n\t\telse {\n\t\t\tint numberOfTarget = new Integer(args.get(4));\n\t\t\t//Modify an argument\n\t\t\tString newArgs = this.getNewArgs(numberOfArgs,numberOfTarget,newValue);\n\t\t\ttempCode = tempCode.replaceAll(\"\\\\$returnValue\", \"this.\"+args.get(2)+newArgs);\n\t\t\tString y =\"console.log(\\\"Arg number \"+ numberOfTarget+\": old value: \\\"+\"+\"arg\"+numberOfTarget+ \"+\\\". New value: \\\"+\"+newValue+\");\"; \n\t\t\ttempCode = tempCode.replaceAll(\"\\\\$output_line\", y );\n\t\t}\n\t\t\n\t\ttempCode = tempCode.replaceAll(\"\\\\$output_line\", consoleLog);\n\t\t\n\t\treturn tempCode;\n\t}\n\t\t\n\t\n\tprivate ArrayList<String> getMethodArguments(int num){\n\t\tArrayList<String> methodArgs = new ArrayList<>();\n\t\tfor (int i=0;i<num;i++){\n\t\t\tmethodArgs.add(\"arg\"+i);\n\t\t}\n\t\treturn methodArgs;\n\t}\n\t\n\tprivate String correctStringsInArgs(String arg){\n\t\t\n\t\tif (Integer.getInteger(arg) == null)\n\t\t\tif (!arg.equals(\"true\") && !arg.equals(\"false\"))\n\t\t\t\treturn \"\\\\\\\"\"+arg+\"\\\\\\\"\";\n\t\t\n\t\treturn arg;\n\t\t\n\t}\n\t\n\tprivate String getNewArgs(int totalNumOfArgs, int argNum, String value){\n\t\tString methodArgs=\"(\";\n\t\t\n\t\tfor (int i=0;i<totalNumOfArgs;i++){\n\t\t\tif (i==argNum)\n\t\t\t\tmethodArgs+=value+\", \";\n\t\t\telse\n\t\t\t\tmethodArgs+=\"arg\"+i+\", \";\n\t\t}\n\t\t\n\t\tmethodArgs = methodArgs.substring(0, methodArgs.length()-2);\n\t\tmethodArgs +=\");\";\n\t\t\n\t\treturn methodArgs;\n\t\t\n\t}\n\t\n\tprivate boolean isSetReturnValue(String arg4) {\n\t\tif (arg4.equals(\"ret\"))\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaUnpinSslContext.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport java.util.ArrayList;\n\nimport base.FileUtil;\nimport commandExec.Commando;\n\npublic class FridaUnpinSslContext extends FridaJsAction{\n\tprivate FileUtil fU;\n\n\tpublic FridaUnpinSslContext(boolean reuseScript) {\n\t\tthis.fU = new FileUtil();\n\t\t\n\t\tthis.script = new FridaJsScript(FridaVars.SSL_CONTEXT_UNPIN_JS);\n\t\tif (reuseScript)\n\t\t\tthis.code = this.script.getCodeFromScript();\n\t\telse\n\t\t\tthis.code = FridaVars.sslContextUnpin;\n\t}\n\t\n\tpublic void run(ArrayList<String> args){\n\t\tString finalCode = this.prepareCode(args);\n\t\tthis.executeNoSpawn(finalCode);\n\t}\n\t\n\tprivate String prepareCode(ArrayList<String> args) {\n\t\tCommando commando = new Commando();\n\t\tString certLoc = args.get(1);\n\t\tString certName= this.fU.getFileNameFromPath(certLoc);\n\t\tString certOnDevice=\"/data/local/tmp/\"+certName;\n\t\tthis.fU.copyToDevice(certLoc, certOnDevice);\n\t\tString finalCode = this.code.replaceAll(\"\\\\$mitmCert\", certOnDevice);\n\t\tcommando.execRoot(\"chmod 666 \"+certOnDevice);\n\t\treturn finalCode;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/frida/FridaVars.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage frida;\n\nimport initialization.TicklerVars;\n\npublic abstract class FridaVars {\n\n\t//script locations\n\tpublic static String ENUM_LOC = TicklerVars.fridaScriptsDir+\"enumerate_classes.js\";\n\tpublic static String GET_VALS_JS = TicklerVars.fridaScriptsDir+\"get_attributes_output.js\";\n\tpublic static String SET_VALS_JS = TicklerVars.fridaScriptsDir+\"set_value_output.js\";\n\tpublic static String SSL_CONTEXT_UNPIN_JS = TicklerVars.fridaScriptsDir+\"unpin_ssl_context.js\";\n\t\n\t\n\t\n\t/// Frida JS Scripts code\n\tpublic static String GET_VALS_CODE= \"setTimeout(function(){\t\\n\"\t +\n\t\t\t\"\tJava.perform(function () {\t\\n\"\t +\n\t\t\t\"\t\tvar className = Java.use(\\\"$className\\\");\t\\n\"\t +\n\t\t\t\"\t            className.$method_name.implementation = function ($args) {\t\\n\"\t +\n\t\t\t\"\t\t\t\t\tconsole.log(\\\"$method_name\\\"+\\\" method started\\\");\t\\n\"\t +\n\t\t\t\"\t\t\t\t\tvar returnValue = this.$method_name($args);\t\\n\"\t +\n\t\t\t\"\t\t\t\t\t$console_log_inputs\t\\n\"\t +\n//\t\t\t\"\t                \t\"\t +\n\t\t\t\"\t\t\t\t\tif (returnValue != null ) {console.log(\\\"Output: \\\"+returnValue.toString()+\\\"\\\\n\\\");}\\n\"\t +\n\t\t\t\"\t\t\t\t\treturn returnValue;\t\\n\"\t +\n//\t\t\t\"\t\t\"\t +\n\t\t\t\"\t            };\t\\n\"\t +\n//\t\t\t\"\t\t\"\t +\n\t\t\t\"\t        });\t\\n\"\t +\n//\t\t\t\"\t\t\"\t +\n\t\t\t\"\t    },0);\t\\n\";\n\t\n\t\n\tpublic static String SET_VALS_CODE = \"\t setTimeout(function(){\t\\n\t\"\t +\n\t\t\t\"\t        Java.perform(function () {\t\\n\t\"\t +\n\t\t\t\"\t            var className = Java.use(\\\"$className\\\");\t\\n\t\"\t +\n\t\t\t\"\t            className.$methodName.implementation = function ($args) {\t\\n\t\"\t +\n\t\t\t\"\t\t\t\t\tconsole.log(\\\"$methodName\\\"+\\\" method started\\\");\t\\n\"\t +\n\t\t\t\"\t\t\tvar orig_return = this.$methodName($args);\t\\n\t\"\t +\n\t\t\t\"\t\t\t$output_line\t\\n\t\"\t +\n\t\t\t\"\t\t\treturn $returnValue;\t\\n\t\"\t +\n\t\t\t\"\t            };\t\\n\t\"\t +\n\t\t\t\"\t        });\t\\n\t\"\t +\n\t\t\t\"\t    },0);\t\\n\t\";\n\t\n\tpublic static String sslContextUnpin = \"\t//Originally written by Piergiovanni Cipolloni : https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/\t\\n\t\"\t +\n\t\t\t\"\tJava.perform(function (){\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[.] Cert Pinning Bypass/Re-Pinning\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var CertificateFactory = Java.use(\\\"java.security.cert.CertificateFactory\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var FileInputStream = Java.use(\\\"java.io.FileInputStream\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var BufferedInputStream = Java.use(\\\"java.io.BufferedInputStream\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var X509Certificate = Java.use(\\\"java.security.cert.X509Certificate\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var KeyStore = Java.use(\\\"java.security.KeyStore\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var TrustManagerFactory = Java.use(\\\"javax.net.ssl.TrustManagerFactory\\\");\t\\n\t\"\t +\n\t\t\t\"\t     var SSLContext = Java.use(\\\"javax.net.ssl.SSLContext\\\");\t\\n\t\"\t +\n\t\t\t\"\t// Load CAs from an InputStream\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[+] Loading our CA...\\\")\t\\n\t\"\t +\n\t\t\t\"\t     cf = CertificateFactory.getInstance(\\\"X.509\\\");\t\\n\t\"\t +\n\t\t\t\"\t     try {\t\\n\t\"\t +\n\t\t\t\"\t      var fileInputStream = FileInputStream.$new(\\\"$mitmCert\\\");\t\\n\t\"\t +\n\t\t\t\"\t\t    }\t\\n\t\"\t +\n\t\t\t\"\t    catch(err) {\t\\n\t\"\t +\n\t\t\t\"\t      console.log(\\\"[o] \\\" + err);\t\\n\t\"\t +\n\t\t\t\"\t\t    }\t\\n\t\"\t +\n\t\t\t\"\t\t    var bufferedInputStream = BufferedInputStream.$new(fileInputStream);\t\\n\t\"\t +\n\t\t\t\"\t\t  \tvar ca = cf.generateCertificate(bufferedInputStream);\t\\n\t\"\t +\n\t\t\t\"\t\t    bufferedInputStream.close();\t\\n\t\"\t +\n\t\t\t\"\t\t\tvar certInfo = Java.cast(ca, X509Certificate);\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[o] Our CA Info: \\\" + certInfo.getSubjectDN());\t\\n\t\"\t +\n\t\t\t\"\t\t    // Create a KeyStore containing our trusted CAs\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[+] Creating a KeyStore for our CA...\\\");\t\\n\t\"\t +\n\t\t\t\"\t\t    var keyStoreType = KeyStore.getDefaultType();\t\\n\t\"\t +\n\t\t\t\"\t\t    var keyStore = KeyStore.getInstance(keyStoreType);\t\\n\t\"\t +\n\t\t\t\"\t\t    keyStore.load(null, null);\t\\n\t\"\t +\n\t\t\t\"\t     keyStore.setCertificateEntry(\\\"ca\\\", ca);\t\\n\t\"\t +\n\t\t\t\"\t\t    // Create a TrustManager that trusts the CAs in our KeyStore\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[+] Creating a TrustManager that trusts the CA in our KeyStore...\\\");\t\\n\t\"\t +\n\t\t\t\"\t\t    var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();\t\\n\t\"\t +\n\t\t\t\"\t\t    var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);\t\\n\t\"\t +\n\t\t\t\"\t\t    tmf.init(keyStore);\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[+] Our TrustManager is ready...\\\");\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[+] Hijacking SSLContext methods now...\\\")\t\\n\t\"\t +\n\t\t\t\"\t     console.log(\\\"[-] Waiting for the app to invoke SSLContext.init()...\\\")\t\\n\t\"\t +\n\t\t\t\"\t     SSLContext.init.overload(\\\"[Ljavax.net.ssl.KeyManager;\\\", \\\"[Ljavax.net.ssl.TrustManager;\\\", \\\"java.security.SecureRandom\\\").implementation = function(a,b,c) {\t\\n\t\"\t +\n\t\t\t\"\t\t   \t\tconsole.log(\\\"[o] App invoked javax.net.ssl.SSLContext.init...\\\");\t\\n\t\"\t +\n\t\t\t\"\t      SSLContext.init.overload(\\\"[Ljavax.net.ssl.KeyManager;\\\", \\\"[Ljavax.net.ssl.TrustManager;\\\", \\\"java.security.SecureRandom\\\").call(this, a, tmf.getTrustManagers(), c);\t\\n\t\"\t +\n\t\t\t\"\t\t   \t\tconsole.log(\\\"[+] SSLContext initialized with our custom TrustManager!\\\");\t\\n\t\"\t +\n\t\t\t\"\t\t   \t}\t\\n\t\"\t +\n\t\t\t\"\t    });\t\\n\t\"\t;\n\t\n\tpublic static String ENUM_CODE=\"Java.perform(\\n\"\n\t+\"\tfunction(){\\n\"\n\t+\"\t\tJava.enumerateLoadedClasses(\\n\"\n  \t+\"\t\t{\\n\"\n\t+\"\t\t\t\\\"onMatch\\\": function(className){\\n\" \n\t+\"\t\t\t\tconsole.log(className) \\n\"\n\t+\"\t\t\t},\\n\"\n\t+\"\t\t\t\\\"onComplete\\\":function(){}\\n\"\n  \t+\"\t\t}\\n\"\n\t+\"\t)\\n\"\n\t+\"})\\n\";\n\n}\n"
  },
  {
    "path": "src/main/java/info/InfoGathering.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage info;\n\nimport java.util.List;\nimport java.io.File;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.LinkedHashSet;\n\nimport base.Base64Util;\nimport base.FileUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport code.JavaSqueezer;\n//import code.SmaliAnalyzer;\nimport commandExec.Commando;\nimport db.DatabaseTester;\nimport initialization.TicklerVars;\n\npublic class InfoGathering {\n\t\n\tprivate SearchUtil searcher;\n\tprivate String resXml;\n\t\n\tpublic InfoGathering(){\n\t\tthis.searcher = new SearchUtil();\n\t\tthis.resXml = \"res/xml/\";\n\t\t\n\t}\n\t\n\t//////////////////// SD card /////////////////////\n\t\n\tpublic String getSdcardDirectory(){\n\t\treturn this.searcher.searchOnDevice(\"/sdcard/Android\", TicklerVars.pkgName);\n\t\t\n\t}\n\t\n\t/**\n\t * Searches in Java and Smali code if the app uses external storage\n\t * @return\n\t */\n\tpublic boolean isExternalStorage(){\n\t\tJavaSqueezer jCA = new JavaSqueezer();\n\t\tboolean result = jCA.isExternalStorage();\n\t\tif (!result)\n\t\t\tresult = this.isExternalStorageDirectory(TicklerVars.smaliDir);\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * Checks in a directory for the keywords of external storage\n\t */\n\tprivate boolean isExternalStorageDirectory(String loc){\n\t\t\n\t\tArrayList<String> foundArray = searcher.search4KeyInDir(loc, \"getExternal\");\n\t\t\n\t\tfor (String s:foundArray)\n\t\t{\n\t\t\tif (s.contains(\"getExternalFilesDir\") || s.contains(\"getExternalStoragePublicDirectory\")){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn false;\n\t\t\n\t}\n\t\n\t\n\n\t\n\t//////////////////////////// Interesting things in APK ////////////////////////////\n\t\n\tpublic void getCertificatesInApkDirectory(){\n\t\tString[] certExtensions = {\".cer\",\".crt\",\".der\",\".csr\",\".pfx\",\".p12\",\".pem\",\".p7b\", \".p7r\", \".spc\"};\n\t\tList<File> result = this.searcher.search4FileInDir(TicklerVars.extractedDir, certExtensions );\n\t\tboolean found = false;\n\t\t\n\t\tfor (File f: result){\n\t\t\tfound = true;\n\t\t\tOutBut.printNormal(f.getAbsolutePath().replaceAll(TicklerVars.extractedDir, \"[ExtractedDir]\"));\n\t\t}\n\t\t\n\t\tif (found)\n\t\t\tOutBut.printStep(\"Where [ExtractedDir] is \"+ TicklerVars.extractedDir);\n\t\telse\n\t\t\tOutBut.printNormal(\"None is found\");\n\t}\n\t\n\t/**\n\t * Checking if the app already patched to work in mitm mode on Android 7\n\t * I think I will skip it for now\n\t */\n\n\t\n\tpublic boolean checkTicklerMitmModification(){\n\t\t\n\t\tFile ticklerNSC = new File(TicklerVars.appTickDir+this.resXml+TicklerVars.mitmXmlName);\n\t\tif (ticklerNSC.exists()){\n\t\t\tString searchKey=\"<application android:networkSecurityConfig=\\\"@xml/\"+TicklerVars.mitmXmlName+\"\\\"\";\n\t\t\tArrayList<String> searchResult = this.searcher.findInFile(new File(TicklerVars.tickManifestFile), searchKey);\n\t\t\tif (!searchResult.isEmpty())\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/info/InfoGatheringReporting.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage info;\n\nimport java.io.File;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\n\nimport attacks.StartAttack;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport cliGui.OutBut;\nimport code.JavaSqueezer;\nimport device.Packagez;\nimport initialization.TicklerVars;\nimport manifest.ManifestDealer;\n\npublic class InfoGatheringReporting {\n\tprivate ManifestDealer dealer;\n\tprivate StartAttack startAttack;\n\tprivate InfoGathering info;\n\tprivate ArrayList<String> infoArrayList;\n\tprivate Packagez pkgz;\n\t\n\tpublic InfoGatheringReporting(){\n\t\tthis.dealer = new ManifestDealer();\n\t\tthis.startAttack = new StartAttack();\n\t\tthis.infoArrayList = new ArrayList<String>();\n\t\tthis.info = new InfoGathering();\n\t\tthis.pkgz = new Packagez();\n\t}\n\n\tpublic void report() {\n\t\t\n\t\tOutBut.printH1(\"Package Information\");\t\t\n\t\tthis.printArrayList(this.pkgz.dumpInfo());\t\n\n\t\t\n\t\t////////////////////////// SD card ///////////////////////////////\n\t\t\n\t\tthis.sdcardChecks();\n\t\t\n\n\t\t///////////////////////// Manifest Analysis //////////////////////////////////\n\t\tthis.manifestAnalysis();\n\t\t\n\t\tOutBut.printH2(\"Certificates and Keys found in the APK zipped file\");\n\t\tthis.info.getCertificatesInApkDirectory();\n\t\t\n\t\t\n\t}\n\t\n\n\t/**\n\t * Checks if the app uses external storage\n\t */\n\tprivate void sdcardChecks(){\n\t\tthis.infoArrayList.clear();\n\t\t\n\t\tif (info.isExternalStorage()){\n\t\t\tSystem.out.println(\"Code shows that the app uses External storage\");\n\t\t}\n\t\t\n\t\t// search in SD card /sdcard/Android\n\t\tString sdCardPaths =info.getSdcardDirectory();\n\t\tif (sdCardPaths.isEmpty()){\n\t\t\tthis.infoArrayList.add(\"No Directories found for the app in external storage\");\n\t\t}\n\t\telse{\n\t\t\tthis.infoArrayList.add(\"Directories found for the app in external storage:\");\n\t\t\tfor (String s:sdCardPaths.split(\"\\n\")){\n\t\t\t\tthis.infoArrayList.add(\"\\t\"+s);\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.printArrayList(infoArrayList);\n\t\t\n\t}\n\t\n\t////////////////////////// Manifest Analysis /////////////////////////7\n\tprivate void manifestAnalysis(){\n\t\tthis.infoArrayList.clear();\n\t\t\n\t\tthis.printDebuggableBackable();\n\t\t\n\t\tthis.isTicklerMitM();\n\t\t\n\t\tOutBut.printH2(\"Uses Permissions\");\n\t\tthis.printArrayList(this.dealer.manAn.getUsesPermissions());\n\t\t\n\t\tOutBut.printH2(\"Components' Permissions\");\n\t\tArrayList<SimpleEntry> per =this.dealer.manAn.getComponentPermissions();\n\t\tfor (SimpleEntry e:per) { \n//\t\t\tOutBut.printNormal(\"Component: \"+e.getKey()+\"\\t\\trequests Permission: \"+e.getValue());\n\t\t\tOutBut.printNormal(\"Permission: \"+e.getValue()+\"\\n\\tis requested by Component: \"+e.getKey());\n\t\t}\n\t\t\n\t\tOutBut.printH2(\"Content URIs in Code\");\n\t\tthis.printArrayList(this.fetchContentUris());\n\t\t\n\t\tthis.printSchemes();\n\t\t\n\t\tthis.getMetaData();\n\t\tthis.findLibs();\n\n\t}\n\t\n\tprivate void printDebuggableBackable(){\n\t\tthis.dealer.analyzeManifest(TicklerVars.tickManifestFile);\n\t\tinfoArrayList.add(\"Backable: \"+this.dealer.manAn.getManifest().getApplication().isAllowBackup());\n\t\tinfoArrayList.add(\"Debuggable: \"+this.dealer.manAn.getManifest().getApplication().isDebuggable());\n\t\t\n\t\tthis.printArrayList(this.infoArrayList);\n\t}\n\t\n\tpublic ArrayList<String> fetchContentUris(){\n\t\tthis.startAttack.provAtt.getContentURIsFromSmali(TicklerVars.smaliDir);\n\t\treturn this.startAttack.provAtt.getContentURIs();\n\t}\n\t\n\tprivate void printSchemes(){\n\t\tArrayList<String> schemes = this.dealer.manAn.getSchemes();\n\t\tif (!schemes.isEmpty()){\n\t\t\tOutBut.printH2(\"Data Schemes\");\n\t\t\tschemes = OtherUtil.removeDuplicates(schemes);\n\t\t\tthis.printArrayList(schemes);\n\t\t}\n\t}\n\t\n\tprivate void isTicklerMitM(){\n\t\tif (this.info.checkTicklerMitmModification()){\n\t\t\tOutBut.printNormal(\"\\nThe app is already patched by Tickler to accept Certificates added by users to Trust store. \\n\"\n\t\t\t\t\t+ \"You can use Burp as MitM with the app if installed on Android 7.x\");\n\t\t}\n\t\t//else\n\t\t\t//OutBut.printNormal(\"\\nThe app is NOT patched by Tickler to work with Burp if installed on Android 7.x device\\n\"\n\t\t\t//\t\t+ \"You can run Tickler with -mitm flag to patch the app, if you're using an Android 7.x device\");\n\t}\n\t\n\tprivate void getMetaData(){\n\t\tSearchUtil sU = new SearchUtil();\n\t\tArrayList<String> result = sU.findInFile(new File(TicklerVars.tickManifestFile), \"meta-data\");\n\t\t\n\t\tif (!result.isEmpty()){\n\t\t\tOutBut.printH2(\"Meta-data in Manifest file\");\n\t\t\tthis.printArrayList(result);\n\t\t}\n\t}\n\n\t////////////////////////////////////////\n\t\n\tprivate void findLibs() {\n\t\tJavaSqueezer squeeze = new JavaSqueezer();\n\t\t\n\t\tsqueeze.soLibFiles();\n\t\t\n\t\tsqueeze.dllFiles();\n\t\t\n\t}\n\t\n\t\n\tprivate void printArrayList(ArrayList<String> list){\n\t\tfor (String s:list)\n\t\t\tSystem.out.println(s);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/info/ListComponents.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage info;\n\nimport java.util.ArrayList;\n\nimport cliGui.OutBut;\nimport code.ExtrasUtil;\nimport components.Action;\nimport components.Category;\nimport components.DataUri;\nimport components.IComponent;\nimport components.Intent;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\nimport manifest.ManifestDealer;\nimport manifest.handlers.DataUriHandler;\n\npublic class ListComponents {\n\tprivate ManifestDealer dealer;\n\t\n\tpublic ListComponents() {\n\t\tthis.dealer = new ManifestDealer();\n\t\t\n\t}\n\t\n\t/**\n\t * Lists any option given from Tickler\n\t * @param compType\n\t * @param exported\n\t * @param details\n\t */\n\tpublic void listThis(int compType, boolean exported,boolean details){\n\t\t\n\tif (compType==TicklerConst.ALLCOMPS){\n\t\tfor(int i=1;i<5;i++){\n\t\t\tthis.listType(i, exported,details);\n\t\t}\n\t}\n\telse{\n\t\tthis.listType(compType, exported,details);\n\t}\n\t\t\n}\n\t/**\n\t * Lists all components of a certain type\n\t * @param compType\t1--> 5 \n\t * @param exported\n\t * @param details\n\t */\n\tpublic void listType(int compType, boolean exported,boolean details){\t\t\n\t\tString expStr=\"\";\n\t\tboolean isProv = (compType == TicklerConst.PROVIDER);\n\t\tArrayList<String> names = this.getNamesOfCompTypes(compType, exported);\n\t\t\n\t\tif (exported)\n\t\t\texpStr=\"Exported \";\n\t\telse\n\t\t\texpStr=\"All \";\n\t\tOutBut.printH1(expStr+TicklerConst.compNames[compType]);\n\t\t\n\t\tif (isProv && !exported)\n\t\t\tOutBut.printH2(\"Content Providers in Manifest File\");\n\t\t\n\t\tfor (String n:names){\n\t\t\tif (details){\n\t\t\t\tthis.listComponent(n);\n\t\t\t}\n\t\t\telse\n\t\t\t\tSystem.out.println(n);\n\t\t}\n\t\t\n\t\tif (isProv && !exported){\n\t\t\tthis.listProvidersInCode();\n\t\t}\n\t}\n\t\n\t\n\tpublic void listComponent(String compName){\n\t\tthis.dealer.analyzeManifest(TicklerVars.tickManifestFile);\n\t\tif (this.dealer.isComponentExist(compName)){\n\t\t\tIComponent comp = this.dealer.getComponentByName(compName);\n\n\t\t\tif (comp.getIntent()!= null)\n\t\t\t\tfor (Intent i : comp.getIntent()){\n\t\t\t\t\tif (i.getData()!= null){\n\t\t\t\t\t\tDataUriHandler dh = new DataUriHandler(i);\n\t\t\t\t\t\tdh.doIt();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\tthis.printComponent(comp);\n\t\t\tthis.printExtrasInfo(comp);\n\t\t}\n\t\telse{\n\t\t\tOutBut.printError(\"Component \"+compName+\" does not exist in the Manifest file\");\n\t\t}\n\n\t}\n\t\n\t/**\n\t * Prints all Content Provider URIs \n\t */\n\tprivate void listProvidersInCode(){\n\t\tOutBut.printH2(\"All Content URIs In Code\");\n\t\tInfoGatheringReporting info = new InfoGatheringReporting();\n\t\tArrayList<String> prov = info.fetchContentUris();\n\t\t\n\t\tfor (String s : prov){\n\t\t\tSystem.out.println(s);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Print name, type and whether exported or not\n\t * @param comp\n\t */\n\tprivate void printComponent(IComponent comp){\n\t\tOutBut.printH2(comp.getName());\n\t\tSystem.out.println(\"Type: \"+this.getCompClassName(comp));\n\t\tSystem.out.println(\"Exported: \"+((comp.isExported())?\"True\":\"False\"));\n\t\tthis.printIntent(comp);\n\t\t\n\t}\n\t\n\t///////////////////////////// Intent Filters and Extras ///////////////////////////////\n\t/**\n\t * Printing intents of a component, assuming its intents are not null\n\t * @param comp\n\t */\n\tprivate void printIntent(IComponent comp){\n\t\tif (comp.getIntent()!=null) {\n\t\t\tfor(Intent i:comp.getIntent()){\n\t\t\t\tSystem.out.println(\"\\nIntent-Filter:\\n--------------\");\n\t\t\t\t\n\t\t\t\tif (i.getAction()!=null){\n\t\t\t\t\tthis.printActions(i);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (i.getCategory()!= null){\n\t\t\t\t\tthis.printCategories(i);\n\t\t\t\t}\n\t\t\t\tif (i.getData()!= null){\n\t\t\t\t\tthis.printData(i);\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\tprivate void printActions(Intent i){\n\t\tfor (Action a:i.getAction())\n\t\t\tSystem.out.println(\"Action: \"+a.getName());\n\t}\n\t\n\t/**\n\t * Print Categories of an intent\n\t * @param i Intent\n\t */\n\tprivate void printCategories(Intent i){\n\t\tfor (Category c:i.getCategory())\n\t\t\tSystem.out.println(\"Category: \"+c.getName());\n\t}\n\t\n\t\n\t/**\n\t * Printing the whole data URI (new function)\n\t * @param i\n\t */\n\tprivate void printData(Intent i){\n\t\tDataUriHandler dH = new DataUriHandler(i);\n\t\tSystem.out.println(\"Data URI: \");\n\t\tfor (DataUri d:i.getData()){\n\t\t\tdH.printData(d);\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t\n\t/**\n\t * Gets Extras Info from CodeUtil class and print the information\n\t * @param c\n\t */\n\tprivate void printExtrasInfo(IComponent c){\n\t\tString cName = c.getName();\n\t\tExtrasUtil cU = new ExtrasUtil();\n\t\tArrayList<String> extras = cU.getExtrasInfo(cName);\n\t\t\n\t\t\n\t\tif (extras.size()>0){\n\t\t\tSystem.out.println(\"\\nExtras:\\n--------\");\n\t\t\tfor (String s : extras)\n\t\t\t\tSystem.out.println(s);\n\t\t\t}\n\t}\n\t\n\t/////////////////// Util\n\t\n\tprivate String getCompClassName(IComponent c){\n\t\tString name=\"\";\n\t\tString className = c.getClass().getName();\n\t\t\n\t\tif (className.equals(\"components.Activity\"))\n\t\t\tname=\"Activity\";\n\t\telse if (className.equals(\"components.Service\"))\n\t\t\tname=\"Service\";\n\t\telse if (className.equals(\"components.Receiver\"))\n\t\t\tname=\"Broadcast Receiver\";\n\t\telse if (className.equals(\"components.Provider\"))\n\t\t\tname=\"Content Provider\";\n\t\t\n\t\treturn name;\n\t}\n\t\n\tprivate ArrayList<String> getNamesOfCompTypes(int type, boolean exported){\n\t\t\n\t\tArrayList<IComponent> components = this.dealer.getComponentsOfType(type, exported);\n\t\tArrayList<String> names= new ArrayList<>();\n\t\t\n\t\tfor (IComponent c:components)\n\t\t\tnames.add(c.getName());\n\t\t\n\t\treturn names;\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/initialization/TicklerChecks.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage initialization;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.security.CodeSource;\nimport java.util.AbstractMap.SimpleEntry;\nimport java.util.ArrayList;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport apk.Decompiler;\nimport base.FileUtil;\nimport base.OtherUtil;\nimport base.SearchUtil;\nimport base.Tickler;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport device.Packagez;\nimport exceptions.TNotFoundEx;\nimport info.InfoGathering;\n\npublic class TicklerChecks {\n\n\tprivate Commando commando; \n\tprivate String PKG_NOT_FOUND=\"Package $P does not exist on the connected device. Run -pkgs to see all installed packages\";\n\t\n\tpublic TicklerChecks(){\n\t\tthis.commando = new Commando();\n\t}\n\t\n\t\n\t////////////////////////Initiatlization ///////////////////////\n\t/**\n\t * Initializazion:\n\t * 1) check devices (offline checks migrated to initializeTicklerNoDevice\n\t * 2)host requirements (tools exist)\n\t * 3) load configurations from conf file\n\t * 4) Update TicklerVars\n\t * 5) create essential dirs\n\t * 6) check external library directory\n\t * @param pkgName\n\t * @param isDev\n\t * @throws TNotFoundEx\n\t */\n\tpublic void initiaizeTickler(String pkgName) throws TNotFoundEx{\n\n\t\tPackagez pkg = new Packagez();\n//\t\tif (isDev){\n\t\tthis.checkDevices();\n//\t\t}\n\t\t\n\t\tthis.checkRequirements();\n\t\t\n\t\tthis.loadConfiguration();\n\t\n\t\tif (!pkg.isPackageExist(pkgName)){\n\t\t\tthrow new TNotFoundEx(this.PKG_NOT_FOUND.replaceAll(\"\\\\$P\", pkgName));\n\t\t}\n\t\t\n\t\tTicklerVars.updateVars(pkgName);\n\t\t\n\t\tthis.createEssentialDirs();\t\n\t\tthis.checkExternalLibDir();\n\t\tthis.isDex2Jar();\n\t\n\t}\n\t\n\t\n\tpublic void initalizeTicklerNoDevice(String pkgName) throws TNotFoundEx{\n//\t\tthis.checkOfflineFeasibility(pkgName);\n\t\tthis.loadConfiguration();\n\t\tTicklerVars.updateVars(pkgName);\n\t\tthis.checkExternalLibDir();\n\t\t\n\t\tif (! this.isPkgFoundOffline(pkgName))\n\t\t\tthrow new TNotFoundEx(pkgName+\" has not been processed before by Tickler... \\n If you're decompiling it offline:then \"\n\t\t\t\t\t+ \"Create a directory in \"+TicklerVars.ticklerDir+\" with its package name\");\n\t\tthis.createEssentialDirs();\t\n\t\tthis.isDex2Jar();\n}\n\n\t/**\n\t * Check if only one device is connected to the host\n\t * @throws TNotFoundEx\n\t */\n\tpublic void checkDevices() throws TNotFoundEx{\n\t\tString command = \"adb devices -l\";\n\t\tCommando commando = new Commando();\n\t\tString op = commando.executeCommand(command);\n\t\t\n\t\tOtherUtil oU = new OtherUtil();\n\t\tArrayList<String> devices = oU.getRegexFromString(op, \"(model:.*?device:.+$?)\");\n\t\tint eligDevices = devices.size();\n\t\t\n\t\tif (eligDevices>1)\n\t\t\tthrow new TNotFoundEx(\"ERROR: 2 or more Android devices are connected to the host, please connect only one Android device.\");\n\t\tif (eligDevices == 0)\n\t\t\tthrow new TNotFoundEx(\"ERROR: No Android devices detected by the host. Execute adb devices -l to check the connected devices\");\n\t\t\t\n\t}\n\t/**\n\t * Check if the connected device is an emulator (quick and dirty)\n\t */\n\tpublic boolean isEmulator() {\n\t\tString command = \"adb devices -l\";\n\t\tCommando commando = new Commando();\n\t\tString op = commando.executeCommand(command);\n\t\t\n\t\tif(op.toLowerCase().contains(\"emulator\"))\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * Check if the host has the following tools: adb, sqlite3, strings\n\t * @throws TNotFoundEx\n\t */\n\tpublic void checkRequirements() throws TNotFoundEx{\n\t\t\n\t\tArrayList<SimpleEntry> toolsCheck = new ArrayList<>();\n\t\t\n\t\t//adb\n\t\ttoolsCheck.add(new SimpleEntry<String, String>(\"adb\", \"adb devices\"));\n\t\t//sqlite3\n\t\ttoolsCheck.add(new SimpleEntry<String, String>(\"sqlite3\", \"sqlite3 -version\"));\n\t\t//strings\n\t\ttoolsCheck.add(new SimpleEntry<String, String>(\"strings\", \"strings -v\"));\n\t\t\n\t\tboolean pass = this.checkToolOnHost(toolsCheck);\n\t\t\n\t\tif (!pass)\n\t\t\tthrow new TNotFoundEx(\"Missing tools on host: Please install the missing tools and rerun the command\");\n\t}\n\t\n\t/**\n\t * Executes a sample command of each tool to detect if it exists\n\t * ToDo: it prints stack trace which is not cool\n\t * @param toolCheck\n\t * @return false if any required tool doesn't exist, otehrwise true\n\t */\n\tprivate boolean checkToolOnHost(ArrayList<SimpleEntry> toolCheck) throws TNotFoundEx{\n\t\tint result=13;\n\t\tString cmd=\"\";\n\t\tboolean pass=true;\n\t\tfor(SimpleEntry s: toolCheck){\n\t\t\tcmd = s.getValue().toString();\n\t\t\tresult = this.commando.executeProcessListPrintOP(cmd, false);\n\n\t\t\t\tif (result != 0){\n\t\t\t\t\tOutBut.printError(\"Tool \"+s.getKey().toString()+\" does not exist on the host, please install it first\");\n\t\t\t\t\tpass=false;\n\t\t\t\t}\n\t\t\t}\n\t\treturn pass;\n\t}\n\t\n\tprivate void isDex2Jar() throws TNotFoundEx {\n\t\tDecompiler dec = new Decompiler();\n\t\tif (!dec.isDex2Jar())\n\t\t\tthrow new TNotFoundEx(\"Cannot run Dex2Jar tool. Make sure it exists in \"+TicklerVars.libNotJarLib+\" directory and that d2j-dex2jar.sh and d2j_invoke.sh are executable\");\n\t}\n\t\n\t/**\n\t * Load configurations from the config file\n\t */\n\tpublic void loadConfiguration(){\n\t\t\n\t\tString jarLoc = this.getJarLocation();\n\t\tTicklerVars.jarPath = jarLoc;\n\t\tTicklerVars.configPath=TicklerVars.jarPath+TicklerConst.configFileName;\n\t\t\n\t\t//Read configs from conf file\n\t\tif (new File(TicklerVars.configPath).exists()){\n\t\t\ttry {\n\t\t\t\tString line;\n\t\t\t\tBufferedReader reader = new BufferedReader(new FileReader(TicklerVars.configPath));\n\t\t\t\twhile ((line =reader.readLine())!= null) {\n\t\t\t\t\tif (line.contains(\"Tickler_local_directory\")){\n\t\t\t\t\t\tString loc = line.substring(line.indexOf(\"=\")+1, line.length());\n\t\t\t\t\t\tTicklerVars.ticklerDir = this.correctJarLoc(loc);\n\t\t\t\t\t}\n\t\t\t\t\telse if (line.contains(\"Tickler_sdcard_directory\")){\n\t\t\t\t\t\tString loc = line.substring(line.indexOf(\"=\")+1, line.length()-1);\n\t\t\t\t\t\tTicklerVars.sdCardPath = this.correctJarLoc(loc);\n\t\t\t\t\t}\n\t\t\t\t\telse if (line.contains(\"Frida_server_path\")){\n\t\t\t\t\t\tString loc = line.substring(line.indexOf(\"=\")+1, line.length());\n\t\t\t\t\t\tTicklerVars.fridaServerLoc = loc;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\treader.close();\n\t\t\t}\n\t\t\tcatch (Exception e)\n\t\t\t{\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t//Config path does not exist\n\t\t\n\t\telse\n\t\t{\n\t\t\tSystem.out.println(\"WARNING...... Configuration file does not exist!!!!\\nThe following default configurations are set:\\n\");\n\t\t\tTicklerVars.ticklerDir = TicklerVars.jarPath+TicklerConst.defaultTicklerDirName;\n\t\t\tSystem.out.println(\"Tickler Workspace directory on host: \"+TicklerVars.ticklerDir);\n\t\t\tSystem.out.println(\"Tickler temporary directory on device: \"+TicklerConst.sdCardPathDefault);\n\t\t}\n\t\t\n\t\tString x = TicklerVars.ticklerDir;\n\t\tif (TicklerVars.ticklerDir == null || TicklerVars.ticklerDir.matches(\"\\\\s*/\") ){\n\t\t\tTicklerVars.ticklerDir = TicklerVars.jarPath+TicklerConst.defaultTicklerDirName;\n//\t\t\tOutBut.printWarning(\"Configuration File \"+TicklerVars.configPath+ \" doesn't specify Tickler_local_directory. Workspace is set at \"+ TicklerVars.ticklerDir);\n\t\t\tOutBut.printStep(\"Tickler Workspace directory on host: \"+TicklerVars.ticklerDir);\n\t\t}\n\t\t\n\t\tif (TicklerVars.sdCardPath == null || TicklerVars.sdCardPath.matches(\"\\\\s*/\")) {\n\t\t\tTicklerVars.sdCardPath = TicklerConst.sdCardPathDefault;\t\n//\t\t\tOutBut.printWarning(\"Configuration File \"+TicklerVars.configPath+ \" doesn't specify Tickler's temp directory on the device. It is set to \"+ TicklerVars.sdCardPath);\n\t\t\tOutBut.printStep(\"Tickler temporary directory on device: \"+TicklerConst.sdCardPathDefault);\n\t\t}\n\t\t\t\n\t}\n\t\n\tpublic String getJarLocation(){\n\t\tFile myJar;\n\t\ttry{\n\t\t\t\n//\t\t\tFile myJar1 = new File(System.getProperty(\"java.class.path\"));\n\t\t\tmyJar = new File(ClassLoader.getSystemClassLoader().getResource(\".\").getPath());\n//\t\t\tmyJar = myJar1.getAbsoluteFile().getParentFile();\n\t\t}\n\t\tcatch(Exception e){\n\t\t\tmyJar = new File(\".\");\n\t\t}\n\t\t\n\t\tString jarLoc = this.correctJarLoc(myJar.getAbsolutePath());\n\t\treturn jarLoc;\n\t}\n\t\n\tpublic void getLibName(){\n\t\tSearchUtil searcher = new SearchUtil();\n\t\tString[] ext = {\"jar\"};\n\t\tString x = TicklerVars.jarPath;\n\t\tString JarName = searcher.search4FileInDir(TicklerVars.jarPath, ext ).get(0).getName();\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * Checks if the tool has external Lib directory or a stand alone Jar file\n\t * @return\n\t */\n\tprivate void checkExternalLibDir() throws TNotFoundEx{\n\t\tString jarLoc = this.getJarLocation();\n\t\tString libDirLoc=jarLoc+TicklerConst.generalLibName;\n\t\tFile tickLib = new File (libDirLoc);\n\t\tif (tickLib.exists()){\n\t\t\tTicklerVars.isLib = true;\n\t\t\tTicklerVars.libDir = libDirLoc;\n\t\t}\n\t\t//Lib directory not found\n\t\telse\n\t\t{\n\t\t\tthrow new TNotFoundEx(\"Lib directory not found. \\nMake sure that \"+TicklerConst.generalLibName+\" directory exists in the same directory as Tickler.jar\");\n\t\t}\n\t\t\n\t}\n\t\n\tpublic String correctJarLoc(String jarLoc){\n\t\tString finalLoc=jarLoc;\n\t\tif (jarLoc.contains(\":\"))\n\t\t\tfinalLoc = jarLoc.substring(0, jarLoc.indexOf(\":\"));\n\t\t\n\t\tMatcher m = Pattern.compile(\"\\\\s+(.+)\").matcher(jarLoc);\n\t\tif (m.find())\n\t\t\tfinalLoc = m.group(1);\n\t\tif (finalLoc.matches(\".+\\\\n$\")){\n\t\t\tfinalLoc = finalLoc.substring(0, jarLoc.length()-1);\n\t\t}\n\t\tif (finalLoc.matches(\".+\\\\.$\")){\n\t\t\tfinalLoc = finalLoc.substring(0, jarLoc.length()-1);\n\t\t}\n\t\tif (!finalLoc.matches(\".+/$\")){\n\t\t\tfinalLoc = finalLoc+\"/\";\n\t\t}\n\t\t\n\t\treturn finalLoc;\n\t}\n\t\n\t\n\t/**\n\t * Create sdCardPath and App directory in TicklerDir if they don't exist. \n\t */\n\tprivate void createEssentialDirs() throws TNotFoundEx{\n\t\tFileUtil fT = new FileUtil();\n\t\tfT.createDirOnDevice(TicklerVars.sdCardPath);\n\t\tif (!fT.isExistOnDevice(TicklerVars.sdCardPath))\n\t\t\tthrow new TNotFoundEx(\"Cannot create Tickler directory \"+TicklerVars.sdCardPath+\". Check your configurations in Tickler.conf file\");\n\t\tfT.createDirOnHost(TicklerVars.appTickDir);\n\t\tif (!fT.isExist(TicklerVars.appTickDir))\n\t\t\tthrow new TNotFoundEx(\"Cannot create Tickler directory \"+TicklerVars.appTickDir+\". Check your configurations in Tickler.conf file\");\n\t\t\n\t}\n\t\n\tprivate boolean isPkgNameExist(String pkgName){\n\n\t\tPackagez pkgz = new Packagez();\n\t\treturn pkgz.isPackageExist(pkgName);\n\n\t}\n\t\n\t/**\n\t * Checks if the tickler command is possible to be executed without the device\n\t * Migrated to TicklerCli as a quick and dirty solution\n\t * @param command\n\t */\n//\tpublic void checkOfflineFeasibility(String command) {\n//\t\tString [] offlineCommands = {\"sc\", \"sd\", \"apk\", \"mitm\", \"\"};\n//\t}\n\t\n\tprivate boolean isPkgFoundOffline(String pkgName) {\n\t\tFileUtil ft = new FileUtil();\n\t\tString pkgDir = TicklerVars.ticklerDir+pkgName;\n\t\tif (ft.isExist(pkgDir))\n\t\t\treturn true;\n\t\t\n\t\treturn false;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/initialization/TicklerConst.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage initialization;\n\npublic class TicklerConst {\n\n\t//Files and Directories names\n\tpublic static String configFileName=\"Tickler.conf\";\n\tpublic static String generalLibName = \"libs/\";\n\tpublic static String jarsLibName = \"jars/\";\n\tpublic static String notJarsLibName = \"notJars/\";\n\tpublic static String defaultTicklerDirName=\"Tickler_workspace/\";\n\tpublic static String sdCardPathDefault = \"/sdcard/Tickler/\";\n\tpublic static String MANIFEST_NAME = \"AndroidManifest.xml\";\n\tpublic static String DATA_DIR_NAME = \"DataDir/\";\n\tpublic static String EXTRACTED_NAME = \"apk/\";\n\tpublic static String SMALI_DIR_NAME = \"smali/\";\n\tpublic static String IMAGES_DIR_NAME= \"images/\";\n\tpublic static String LOGS_DIR_NAME = \"logs/\";\n\tpublic static String BG_DIR_NAME = \"bgSnapshots/\";\n\tpublic static String TRANSFER_DIR_NAME = \"transfers/\";\n\tpublic static String DEX2JAR_OP_DIR_NAME= \"JavaCode/\";\n\tpublic static String FRIDA_SCRIPTS_DIR_NAME= \"fridaScripts/\";\n\tpublic static String JAVA_CODE_DIR_NAME = DEX2JAR_OP_DIR_NAME+\"Code\";\n\tpublic static String newAppTempDir = \"newAppTemp/\";\n\tpublic static String EXTERNAL_STORAGE_Dir=\"ExtDataDir/\";\n\tpublic static String DIFF_OLD_STORAGE = \"Storage_old/\";\n\tpublic static String DATA_DIR_OLD=DIFF_OLD_STORAGE+DATA_DIR_NAME;\n\tpublic static String EXT_DIR_OLD=DIFF_OLD_STORAGE+EXTERNAL_STORAGE_Dir;\n\tpublic static String SQUEEZE_FILE_NAME= \"squeeze.txt\";\n\tpublic static String APKTOOL_FILE_NAME=\"apktool.jar\";\n\t\n\t//Tools names\n\tpublic static String DEX2JAR_EXEC = \"/dex2jar-2.1/d2j-dex2jar.sh\";\n\tpublic static String KEY_STORE_DIR_NAME = \"Keystore/Tickler.keystore\";\n\t\n\t\n\tpublic static int ALLCOMPS=0;\n\tpublic static int ACTIVITY=1;\n\tpublic static int SERVICE=2;\n\tpublic static int PROVIDER=3;\n\tpublic static int RECEIVER=4;\t\n\tpublic static String version=\"2.7\";\n\tpublic static final int debuggable=0;\n\tpublic static final int mitm=1;\n\tpublic static String mitmApkName = \"mitm.apk\";\n\tpublic static String debuggableName = \"debuggable.apk\";\n\tpublic static String mitmXmlName=\"tickler_network_security_config\";\n\tpublic static String[] compNames ={\"All components\",\"Activities\", \"Services\", \"Content Providers\",\n\t\"Broadcast Receivers\"};\n\t\n\t\n\tpublic static String helpMessage=\"\\n\tusage: Tickler\t\\n\"\n\t +\"        ==============\\n\"\n\t +\"\tPlease make sure that the configuration file: Tickler.conf is at the same directory as\\n\"\n\t +\"\tthe Tickler .jar file. Tickler.conf file defines Tickler's directory on the host and the\\n\"\n\t +\"\ttemp directory on the android device.\\n\\n\"\n\t +\"\tOptions\\n\"\n\t +\"\t---------\\n\"\n\t +\"\t-h, --help\t\t\tPrints this message\\n\"\n\t +\"        -screen\t\t\t\tTake a screenshot of the device\\n\"\n\t +\"        -findPkg <key>\t\t\tSearch for a package name\t\\n\"\n\t +\"        -version\t\t\tPrint version\t\\n\"\n\t +\"\t-pkgs\t\t\t\tList all installed packages on the android device\t\\n\"\n\t +\" -offline\t\t\tOffline Mode, no devices needed to be connected\\n\"\n\t +\"\t-pkg\t\t\t\tSpecify package name of the app\t\t\\n\"\n\t +\"\t\t\\n\"\n\t +\"\tOptions of pkg:\t\\n\"\n\t +\"\t--------------\t\\n\"\n\t +\"\t-info\t\t\t\tList information about the app\t\\n\"\n\t +\"\t-squeeze\t\t\tAll strings, log functions, possible credentials in decompiled APK\t\\n\"\n\t +\"\t-squeeze short\t\tLimits the squeezed code to the developer's code (most libraries excluded)\t\\n\"\n\t +\"\t-dbg, --debuggable\t\tCreate a debuggable version of the app\t\\n\"\n\t +\"\t-apk <dir> <name>\t\tCompiles a new apk from <dir> directory under the name of <name> \\n\"\n\t +\"\t-dataDir [name]\t\t\tCopies data directory of app to Tickler Directory (DataDir or transfers/name)\t\\n\"\n\t +\"\t-diff\t\t\t\tCopies app's data directory before and after a user's action, then diffs between them\\n\"\n\t +\" \t-diff \t[d| detailed]\t\tlike diff, but also shows the changes in case a text file or an unecrypted database is changed\\n\"\n\t +\"\t-db [option] [-nu]\t\tDatabase checks. By default app's Data Dir is copied to host before checks\\n\"\n\t +\" \t\t[-nu | --noUpdate]\tDoes not update DataDir on host before checks \\n\"\n\t +\" \t\t[option] can be:\\n\"\n\t +\"\t\t\t[ |e|encryption]\tChecks whether the database files of the app are encrypted or not\\n\"\n\t +\"\t\t\t[l |list]\t\tLists Databases of the app \\n\"\n\t +\"\t\t\t[d |dump]\t\tDumps an unencrypted database\\n\"\n\t +\" \t-sc, --searchCode <key>\t\tSearch for \\\"key\\\" in the app's decompiled Java code\\n\"\n\t +\" \t-sd, --searchDataDir <key>\t\tSearch for \\\"key\\\" in the app's Data Directory\\n\"\t\n\t +\"\t-t [target] [-log]\tTickels a target. The type of the attack depends on the target\t\\n\"\n\t +\" \t   -log\t\t\t\t\tCaptures logcat messages \\n\"\n\t +\"\t-l,--list [target] [-v]\t\tList components of type target\t\\n\"\n\t + \"\t   -v \t\t\t\t\tList component(s) in details\\n\"\n\t +\"\t\t\\n\"\n\t +\"\t\t\\n\"\n\t +\"\tTargets:\t\\n\"\n\t +\"\t--------\t\\n\"\n\t +\"\t-act,--activities\t\tActivities\t\\n\"\n\t +\"\t-ser,--services\t\t\tServices\t\\n\"\n\t +\"\t-prov,--providers\t\tContent providers\t\\n\"\n\t +\"\t-rec,--receivers\t\tBroadcast receivers\t\\n\"\n\t +\"\t[ | -comp] <name>\t\tA specific component, its name has to be exactly as in Manifest file (also displayed by -l -all)\t\\n\"\n\t +\"\t-exp\t\t\t\tApplies [trigger | list] action to exported components only\t\\n\"\n\t +\"\t[ | -all]\t\t\tAll components (default if none of the above targets are specified)\t\\n\"\n\t +\"\t\t\\n\"\n\t\n\t + \"\tOptions that work with and without -pkg option\\n\"\n\t + \"\t-----------------------------------------------\\n\"\n\t + \" \t-screen\t\t\t\tCaptures a screenshot of the device\\n\"\n\t + \" \t-cp2host <source> [destName]\tCopies any file/directory to the tickler's app directoy on the host\\n\"\n\t + \" \t-bg,--bgSnapshots\t\tCopies background screenshots that are saved on the device\\n\\n\"\n\t +\t\"\tFrida\t\\n\t\"\n\t +\t\"-----\t\\n\t\"\n\t +\t\"-frida enum \t\t\\n\t\"\n\t +\t\"\tEnumerates loaded classes\t\\n\t\"\n\t +\t\"-frida vals <ClassName> <MethodName> <NumberOfArgs> [-reuse]\t\\n\t\"\n\t +\t\"\tDisplays arguments and return value of this method (only primitive datatypes and String)\t\\n\t\"\n\t +\t\"\t\t\\n\t\"\n\t +\t\"-frida set <ClassName> <MethodName> <NumberOfArgs> <NumberOfArgToModify> <newValue>[-reuse]\t\\n\t\"\n\t +\t\"\tSets the argument number <NumberOfArgToModify> to <newValue> (only primitive datatypes and String)\t\\n\t\"\n\t +\t\"\tIf <NumberOfArgToModify> > <NumberOfArgs>: sets the return value \t\\n\t\"\n\t +\t\"\t\\n\t\"\n//\t +\t\"-frida unpin <CertificateLocation>\t\\n\t\"\n//\t +\t\"\tSSL pinning circumvention as in https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/\t\\n\t\"\n//\t +\t\"\t<CertificateLocation> is the location of your certificate on your host\\n\\n\t\"\n\t +\t\"-frida script <scriptPath>\\n\t\"\n\t +\t\"\tRun custom frida JS script \t\\n\\n\"\n\n\t +\"\tExamples:\t\\n\"\n\t +\"\t---------\t\\n\"\n\t +\"\t1) List all components of package com.test.package, with detailed information\t\\n\"\n\t +\"\t-----------------------------------------------------------------------------\t\\n\"\n\t +\"\tjava -jar Tickler.jar -pkg com.test.package -l -v\t\\n\"\n\t +\"\t\t\\n\"\n\t +\"\t2) Trigger exported activities of package com.test.package\t\\n\"\n\t +\"\t-----------------------------------------------------------\t\\n\"\n\t +\"\tjava -jar Tickler.jar -pkg com.test.package -t -act -exp\t\\n\\n\"\n\t +\"\t3) Squeeze app's decompiled Java code\tfor strings, log messages...etc\\n\"\n\t +\"\t-----------------------------------------------------------------------\t\\n\"\n\t +\"\tjava -jar Tickler.jar -pkg com.test.package -squeeze > output.txt\t\\n\"\n\t ;\n\t\n\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/initialization/TicklerVars.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage initialization;\n\npublic abstract class TicklerVars {\n\n\tpublic static String ticklerDir;\n\tpublic static String pkgName;\n\tpublic static boolean isLib,isOffline;\n\tpublic static String jarPath, configPath;\n\tpublic static String appTickDir,sdCardPath, tickManifestFile,extractedDir,dataDir\n\t,smaliDir, imageDir, logDir, bgSnapshotsDir,transferDir, libDir, libJarDir, libNotJarLib, dex2jarPath, apktoolPath,\n\tdex2jarDir,jClassDir,keyStore,newApkTempDir,mitmXmlName, fridaServerLoc, fridaScriptsDir,extDataDir, squeezeFile;\n\tpublic static String version=\"2.2\";\n\t\t\n\tpublic static void setPkgName(String pName){\n\t\tif (TicklerVars.pkgName!=null && !TicklerVars.pkgName.equals(pName)){\n//\t\t\tSystem.out.println(\"WARNING: Changing package name from \"+TicklerVars.pkgName+\" to \"+pName);\t\t\n\t\t}\n\t\tTicklerVars.pkgName = pName;\n\t}\n\t\n\tpublic static void updateVars(String pName){\n\t\tsetPkgName(pName);\n\t\tappTickDir = ticklerDir+pkgName+\"/\";\n\t\ttickManifestFile = appTickDir+TicklerConst.MANIFEST_NAME;\n\t\tsdCardPath = TicklerConst.sdCardPathDefault+pkgName +\"/\";\n\t\tdataDir = appTickDir+TicklerConst.DATA_DIR_NAME;\n\t\textractedDir = appTickDir+TicklerConst.EXTRACTED_NAME;\n\t\tsmaliDir = extractedDir+TicklerConst.SMALI_DIR_NAME;\n\t\timageDir= appTickDir+TicklerConst.IMAGES_DIR_NAME;\n\t\tlogDir = appTickDir+TicklerConst.LOGS_DIR_NAME;\n\t\tbgSnapshotsDir = appTickDir+TicklerConst.BG_DIR_NAME;\n\t\ttransferDir = appTickDir+TicklerConst.TRANSFER_DIR_NAME;\n\t\textDataDir = appTickDir+TicklerConst.EXTERNAL_STORAGE_Dir; \n\t\t\n\t\tlibDir=jarPath+TicklerConst.generalLibName;\n\t\tlibJarDir=libDir+TicklerConst.jarsLibName;\n\t\tlibNotJarLib=libDir+TicklerConst.notJarsLibName;\n\t\t\n\t\t// Will be set anyway whether they exist or not\n\t\t\n\t\tdex2jarPath = libNotJarLib+TicklerConst.DEX2JAR_EXEC;\n\t\tdex2jarDir = appTickDir+TicklerConst.DEX2JAR_OP_DIR_NAME;\n\t\tapktoolPath = libJarDir+TicklerConst.APKTOOL_FILE_NAME;\n\t\t\n\t\t// Output of Java classes\n\t\tjClassDir = appTickDir+TicklerConst.JAVA_CODE_DIR_NAME;\n\t\tkeyStore = libNotJarLib+TicklerConst.KEY_STORE_DIR_NAME;\n\t\tnewApkTempDir = appTickDir+TicklerConst.newAppTempDir;\n\t\t\n\t\tfridaScriptsDir = appTickDir+TicklerConst.FRIDA_SCRIPTS_DIR_NAME;\n\t\tsqueezeFile = appTickDir+TicklerConst.SQUEEZE_FILE_NAME;\n\t\t\n\t}\n\t\n\tpublic static void setTicklerDir(String dir){\n\t\tticklerDir = dir;\n\t}\n\t\n\tpublic static String replaceSpace(String s){\n\t\treturn s.replaceAll(\"\\\\s\", \"\\\\\\\\s\");\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/logs/LogReader.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage logs;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport base.FileUtil;\nimport commandExec.Commando;\nimport initialization.TicklerVars;\n\npublic class LogReader implements Runnable {\n\tString logFileName;\n\tCommando commando;\n\tFileWriter writer;\n\tprivate LogReaderController controller;\n\t\n\tpublic LogReader(LogReaderController controller){\n\t\tthis.commando = new Commando();\n\t\tthis.controller = controller;\n\t\tthis.logFileName = this.controller.getLogFileName();\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tthis.readWriteLogCat();\n\t}\n\t\t\n\tpublic void readWriteLogCat(){\n\t\tFile logFile = new File(this.logFileName);\n\t\tString command = \"adb logcat\";\n\t\tthis.executeLogcat(command, logFile);\n\t}\n\t\n\t\n\tpublic void executeLogcat(String command, File logFile){\n\t\tProcess process;\n\t\ttry {\n\t\t\tprocess=Runtime.getRuntime().exec(command);\n\t\t\tBufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream()));\n\t\t\tthis.writer = new FileWriter(logFile,true);\n\t\t\t\n\t\t\tString line = \"\";\t\t\t\n\t\t\twhile (((line = reader.readLine())!= null) && !this.controller.isStop()) {\n\t\t\t\tsynchronized(this){\n\t\t\t\t\tthis.writer.append(line+\"\\n\");\n\t\t\t\t\tthis.writer.flush();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tif (this.controller.isStop())\n\t\t\tthis.closeWriter();\n\t\t\n\t}\n\t\n\tpublic void closeWriter(){\n\t\ttry{\n\t\t\tthis.writer.close();\n\t\t}\n\t\tcatch(IOException e)\n\t\t{}\n\t}\n\n\tpublic String getLogFileName() {\n\t\treturn logFileName;\n\t}\n\n\tpublic void setLogFileName(String logFileName) {\n\t\tthis.logFileName = logFileName;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/logs/LogReaderController.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage logs;\n\npublic class LogReaderController {\n\tprivate String logFileName;\n\tprivate boolean stop;\n\t\n\tpublic String getLogFileName() {\n\t\treturn logFileName;\n\t}\n\tpublic void setLogFileName(String logFileName) {\n\t\tthis.logFileName = logFileName;\n\t}\n\tpublic boolean isStop() {\n\t\treturn stop;\n\t}\n\tpublic void setStop(boolean stop) {\n\t\tthis.stop = stop;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/manifest/ManifestAnalyzer.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage manifest;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.AbstractMap.SimpleEntry;\n\nimport components.Activity;\nimport components.DataUri;\nimport components.IComponent;\nimport components.Intent;\nimport components.Manifest;\nimport components.Provider;\nimport components.Receiver;\nimport components.Service;\nimport components.UsesPermission;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\nimport manifest.handlers.IntentHandler;\n\n/**\n * This class analyzes the Manifest file and extracts information from it\n * @author aabolhadid\n *\n */\npublic class ManifestAnalyzer {\n\n\tprivate Manifest manifest;\n\tprivate ArrayList<IComponent> components,exported,hidden;\n\t\n\tpublic ManifestAnalyzer(Manifest manifest) {\n\t\tthis.components = new ArrayList<IComponent>();\n\t\tthis.manifest = manifest;\n\t\tthis.collectAllComponents();\n\t\tthis.collectExportedComponents();\n\t}\n\t\n\tpublic void collectAllComponents() {\n\t\tthis.components.addAll(this.manifest.getApplication().getActivites());\n\t\tif (this.manifest.getApplication().getServices() != null)\n\t\t\tthis.components.addAll(this.manifest.getApplication().getServices());\n\t\tif (this.manifest.getApplication().getProviders() != null)\n\t\t\tthis.components.addAll(this.manifest.getApplication().getProviders());\n\t\tif (this.manifest.getApplication().getReceivers() != null)\n\t\t\tthis.components.addAll(this.manifest.getApplication().getReceivers());\n\t}\n\t\n\t/**\n\t * Divides all components over exported and hidden lists\n\t */\n\tpublic void collectExportedComponents() {\n\t\tthis.exported = new ArrayList<IComponent>();\n\t\tthis.hidden = new ArrayList<IComponent>();\n\t\t\n\t\t// Probably not needed because isExposed is decided during parsing XML\n//\t\tthis.decideExportedStatus();\n\t\t\n\t\tfor(IComponent c : this.components) {\n\t\t\tif (c.isExported())\n\t\t\t\tthis.exported.add(c);\n\t\t\telse\n\t\t\t\tthis.hidden.add(c);\n\t\t}\n\t\t\n\t}\n\t\n\t/**\n\t * Sets isExported, based on exported field in manifest and existence of implicit intents\n\t * Not called anymore because the decision on exported or not happens during parsing hte manifest file \n\t */\n//\tpublic void decideExportedStatus() {\n//\t\tfor(IComponent c : this.components) {\n//\t\t\tif ( c.isExported()) \n//\t\t\t\tc.setExported(true);\n//\t\t\telse if (c.isExported()!= null && c.isExported())\n//\t\t\t\tc.setExported(true);\n//\t\t\telse if (c.getExp()==null && c.getIntent()!=null)\n//\t\t\t\tc.setExported(true);\n//\t\t\telse\n//\t\t\t\tc.setExported(false);\n//\t\t}\n//\t}\n\t\t\n\tpublic IComponent getComponentByName(String compName){\n\t\tString name;\n\t\t\n\t\tfor (IComponent c:this.components){\n\t\t\tname = c.getName();\n\t\t\tif (name.equals(compName))\n\t\t\t\treturn c;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic ArrayList<IComponent> getComponentsOfType(int i, boolean exp) {\n\t\tArrayList<IComponent> list = new ArrayList<IComponent>();\n\t\t\n\t\tfor (IComponent c:this.components){\n\t\t\tif (!exp || (exp && c.isExported())){\n\t\t\t\tif ( i ==TicklerConst.ACTIVITY&& c instanceof Activity)\n\t\t\t\t\tlist.add(c);\n\t\t\t\telse if (i ==TicklerConst.SERVICE && c instanceof Service)\n\t\t\t\t\tlist.add(c);\n\t\t\t\telse if (i == TicklerConst.PROVIDER && c instanceof Provider)\n\t\t\t\t\tlist.add(c);\n\t\t\t\telse if (i == TicklerConst.RECEIVER && c instanceof Receiver)\n\t\t\t\t\tlist.add(c);\n\t\t\t}\n\t\t}\n\t\treturn list;\n\t}\n\t\n\tpublic ArrayList<String> getUsesPermissions(){\n\t\tArrayList<String> result = new ArrayList<>();\n\t\t\n\t\tfor (UsesPermission p: this.getManifest().getUsesPermissions()){\n\t\t\tresult.add(p.getName());\n\t\t}\n\t\t\n\t\treturn result;\t\n\t}\n\t\n\t/**\n\t * New: Get Permissions defined in all components\n\t * @return ArrayList<SimpleEntry<comp.name,permission.name>>\n\t */\n\t\n\tpublic ArrayList<SimpleEntry> getComponentPermissions(){\n\t\tArrayList<SimpleEntry> permissions = new ArrayList();\n\t\tfor (IComponent c:this.components) {\n\t\t\tif(c.getPermission()!=null && ! c.getPermission().isEmpty()) {\n\t\t\t\tSimpleEntry e = new SimpleEntry<String, String>(c.getName(), c.getPermission());\n\t\t\t\tpermissions.add(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn permissions;\n\t\t\n\t}\n\t\n\t\n\tpublic ArrayList<String> getSchemes(){\n\t\tList<Intent> intents;\n\t\tArrayList<String> schemes = new ArrayList<String>();\n\t\tArrayList<DataUri> data = new ArrayList<>();\n\t\t\n\t\tfor (IComponent c : this.components){\n\t\t\tif ((intents =c.getIntent()) != null){\n\t\t\t\tfor (Intent i:intents){\n\t\t\t\t\tif (i.getData()!=null)\n\t\t\t\t\t\tdata.addAll(i.getData());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor(DataUri d:data){\n\t\t\tschemes.add(d.getScheme());\n\t\t}\n\t\t\n\t\treturn schemes;\n\t\t\n\t}\n\t\n\t\n\t\n\t//////////////////////// Getters and Setters ////////////////////////\n\tpublic Manifest getManifest() {\n\t\treturn manifest;\n\t}\n\n\tpublic void setManifest(Manifest manifest) {\n\t\tthis.manifest = manifest;\n\t}\n\n\tpublic ArrayList<IComponent> getComponents() {\n\t\treturn components;\n\t}\n\t\n\n\tpublic void setComponents(ArrayList<IComponent> components) {\n\t\tthis.components = components;\n\t}\n\n\tpublic ArrayList<IComponent> getExported() {\n\t\treturn exported;\n\t}\n\n\tpublic void setExported(ArrayList<IComponent> exported) {\n\t\tthis.exported = exported;\n\t}\n\t\n\tpublic ArrayList<IComponent> getComponents(boolean exp) {\n\t\tif (exp){\n\t\t\treturn this.getExported();\n\t\t}\n\t\treturn components;\n\t}\n\t\n\tpublic ArrayList<IComponent> getHidden() {\n\t\treturn hidden;\n\t}\n\n\tpublic void setHidden(ArrayList<IComponent> hidden) {\n\t\tthis.hidden = hidden;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/manifest/ManifestDealer.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage manifest;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport apk.ApkToolClass;\nimport apk.ApkToolDude;\nimport apk.Decompiler;\nimport base.DOMXMLReader;\nimport base.FileUtil;\nimport cliGui.OutBut;\nimport commandExec.Commando;\nimport components.Activity;\nimport components.IComponent;\nimport components.Manifest;\nimport exceptions.TNotFoundEx;\nimport initialization.TicklerConst;\nimport initialization.TicklerVars;\n\n/**\n * Dunno how to call this class. \n * !!!!!!!!!!!! So far, it's the class that gives back Tickler its Manifest !!!!!!!!!!!!!!\n * @author aabolhadid\n *\n */\npublic class ManifestDealer {\n\tprivate String manifestPath,pkgName,appTickDir;\n\tprivate DOMXMLReader domXmlreader;\n\tpublic ManifestAnalyzer manAn;\n\tprivate FileUtil fileT;\n\tprivate ApkToolDude apkTool;\n\tprivate boolean apkExisted = true;\n\n\t/////////////////////// Package option /////////////////////////\n\tpublic void meetThePackage(String pkgName){\n\t\tthis.pkgName = pkgName;\n\t\tfileT = new FileUtil();\n\t\tthis.appTickDir = TicklerVars.appTickDir;\n\t\t// New ApkClass\n//\t\tthis.apkTool = new ApkToolClass();\n\t\tthis.apkTool = new ApkToolDude();\n\t\t\n\t\t//1- create apk tickler directory if it does not exist\n\t\tfileT.createDirOnHost(this.appTickDir);\n\t\t\n\t\t//2- Copy APK from device if it does not exist in the app tickler directory\n\t\tthis.copyApkFromDevice(); \n\t\t\n\n\t\t//3- Extract Manifest from APK if Manifest file does not exist\n\t\tif (!new File(this.appTickDir+\"/AndroidManifest.xml\").exists())\n\t\t{ \n\t\t\tString apkName = this.getApkName();\n\t\t\tString x = this.appTickDir+apkName;\n\t\t\ttry {\n\t\t\t\tthis.apkToolDecode(x);\n\t\t\t\tOutBut.printStep(\"Extracting Manifest file from APK\");\n\t\t\t}\n\t\t\tcatch(TNotFoundEx e){\n\t\t\t\tOutBut.printError(\"Cannot extract Manifest file from APK\");\n\t\t\t}\n\t\t}\n\t\t\n\t\t//4- Compile the apk using Dex2Jar\n\t\tthis.dex2Jar();\n\t\t\n\t}\n\t\n\t/**\n\t * Decompile the APK using dex2jar tool\n\t */\n\tprivate void dex2Jar(){\n\t\tif (!new File(TicklerVars.jClassDir).exists()){\n\t\t\tDecompiler d2j = new Decompiler();\n\t\t\td2j.decompile();\n\t\t}\n\n\t}\n\t\n\t\n\t/**\n\t * If APK does not exist in the package directory on the host, then Ticker fetches the apk\n\t */\n\tprivate void copyApkFromDevice() {\n\t\tif (!this.isApkExist()){\n\t\t\tOutBut.printStep(\"Copying APK file from the device\");\n\t\t\tfileT.copyDirToHost(this.getPackageApkPath(), this.appTickDir,true);\n\t\t\tthis.apkExisted = false;\n\t\t}\n\n\t}\n\t\n\tprivate boolean isApkExist(){\n\t\tif (TicklerVars.isOffline) {\n\t\t\tString [] apkArray = {\"apk\"};\n\t\t\tif (this.fileT.listFilesInDirContain(TicklerVars.appTickDir, apkArray )!= null)\n\t\t\t\treturn true;\n\t\t}\n\t\tString apkPath = this.getPackageApkPath();\n\t\tString apkName = this.getFileNameFromPath(apkPath);\n\t\tFile apk = new File(TicklerVars.appTickDir+apkName);\n\t\treturn apk.exists();\n\t}\n\t\n\t///////////////////// APK tool Encapsulation ///////////////////////\n\tprivate void apkToolDecode(String apkPath) throws TNotFoundEx{\n\t\tOutBut.printStep(\"Decompiling the APK file using APKTool\");\n\t\tthis.apkTool.apkToolDecode(apkPath);\n\t}\n\t\t\n\t\n\tprivate String getPackageApkPath(){\n\t\tString command = \"pm path \"+this.pkgName;\n\t\tCommando c = new Commando();\n\t\tString result = c.execADB(command);\n\t\treturn result.substring(result.indexOf(\":\")+1,result.indexOf(\"\\n\"));\n\t}\n\t\n\tpublic String getApkName(){\n\t\tString apkName2;\n\t\tif (TicklerVars.isOffline) {\n\t\t\t//Name will always be base.apk\n\t\t\tapkName2 = \"base.apk\";\n\t\t\t\n\t\t}\n\t\telse {\n\t\t\tString apkName = (new File(this.getPackageApkPath())).getName();\n\t\t\t apkName2 = apkName.substring(0,apkName.indexOf(\".apk\")+4);\n\t\t\tString filePath = this.appTickDir+\"/\"+apkName2+\".apk\";\n\t\t}\n\t\treturn apkName2;\n\t}\n\t\n\t/////////////////////////////// Common: For all ////////////////////////////////\n\t\n\tpublic void analyzeManifest(String manifestPath){\n\t\tManifest theManifest = this.generateManifestFromXML(manifestPath);\n\t\tthis.setPkgName(TicklerVars.pkgName);\n\t\tthis.manAn = new ManifestAnalyzer(theManifest);\n\t}\n\t\n\t// Modified : replacing xmlreader with DOMXmlreader\n\tpublic Manifest generateManifestFromXML(String path){\n//\t\tthis.xmlreader = new XMLReader(path);\n\t\tthis.domXmlreader = new DOMXMLReader(path);\n\t\tManifest theManifest = this.domXmlreader.parselManifest();\n\t\treturn theManifest;\n//\t\treturn this.xmlreader.getManifest();\n\t}\n\n\tprivate String getFileNameFromPath(String path){\n\t\tFile absPath = new File(path);\n\t\tString theName = absPath.getName();\n\t\tif (absPath.isDirectory())\n\t\t\ttheName=theName+\"/\";\n\t\t\n\t\treturn theName;\n\t\t\n\t}\n\t\n\t\n\t/////////////// Components //////////////\n\tpublic ArrayList<IComponent> getComponentsOfType(int i, boolean exp) {\n\t\tthis.analyzeManifest(TicklerVars.tickManifestFile);\n\t\tif (i == TicklerConst.ALLCOMPS)\n\t\t\treturn this.manAn.getComponents(exp);\n\t\treturn this.manAn.getComponentsOfType(i,exp);\n\t}\n\t\n\t/**\n\t * Checks if a component with this name exists\n\t * @param compName\n\t * @return\n\t */\n\tpublic boolean isComponentExist(String compName){\n\t\tif (this.manAn.getComponentByName(compName) != null)\n\t\t\treturn true;\n\t\telse\n\t\t\treturn false;\n\t}\n\t\n\t/**\n\t * Returns a component of a given name, should be used if isComponentExist = true\n\t * @param compName\n\t * @return\n\t */\n\tpublic IComponent getComponentByName(String compName){\n\t\treturn this.manAn.getComponentByName(compName);\n\t}\n\t\n\t\n\t\n\t////////////////////// Getters and setters\n\tpublic String getPkgName() {\n\t\treturn pkgName;\n\t}\n\n\tpublic void setPkgName(String pkgName) {\n\t\tif (TicklerVars.pkgName!=null && !TicklerVars.pkgName.equals(pkgName)){\n\t\t\tSystem.out.println(\"WARNING: Changing package name from \"+TicklerVars.pkgName+\" to \"+pkgName);\t\t\n\t\t}\n\t\tthis.pkgName = pkgName;\n\t}\n\t\n\tpublic String getManifestPath() {\n\t\treturn this.manifestPath;\n\t}\n\n\tpublic void setManifestPath(String path) {\n\t\tthis.manifestPath = path;\n\t}\n\n\tpublic boolean wasApkExist() {\n\t\treturn apkExisted;\n\t}\n\n\n}\n"
  },
  {
    "path": "src/main/java/manifest/handlers/DataUriHandler.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage manifest.handlers;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport base.TicklerGeneral;\nimport components.DataUri;\nimport components.Intent;\n\npublic class DataUriHandler {\n\tprivate ArrayList<DataUri> totalDU, outOfMishMash;\n\tprivate Intent intent;\n\tprivate ArrayList<Map<String,String>> collection;\n\t\n\tpublic DataUriHandler(Intent intent){\n\t\tthis.totalDU = new ArrayList<>();\n\t\tthis.outOfMishMash = new ArrayList<>();\n\t\tthis.intent = intent;\n\t\tthis.collection = new ArrayList<>();\n\t}\n\t\n\tpublic void doIt(){\n\t\tthis.collection = this.collectMap();\n\t\tthis.totalDU = this.createDUsForSchemes();\n\t\tthis.addDataUriComp(\"host\");\n\t\tthis.addDataUriComp(\"port\");\n\t\tthis.addDataUriComp(\"path\");\n\t\tthis.addDataUriComp(\"pathPattern\");\n\t\tthis.addDataUriComp(\"pathPrefix\");\n\t\tthis.addDataUriComp(\"mimeType\");\n\t\t// If there are only dataURI tags with only MimeType \n\t\tthis.addMimeTypeOnly();\n\t\tthis.addCompleteToMishmash();\n\t\t\n\t}\n\t\n\tprivate ArrayList<Map<String,String>> collectMap(){\n\t\tArrayList<Map<String,String>> collection = new ArrayList<>();\n\t\tfor (DataUri d:this.intent.getData()){\n\t\t\tMap<String,String> h = d.getDataMap();\n\t\t\tcollection.add(h);\n\t\t}\n\t\t\n\t\treturn collection;\n\t}\n\t\n\t/**\n\t * Creates an array of DataUris, one for each scheme\n\t * Problem: takes only the scheme !!!\n\t * @return\n\t */\n\tprivate ArrayList<DataUri> createDUsForSchemes(){\n\t\tArrayList<DataUri> arr = new ArrayList<>();\n\t\tfor (Map<String,String> h: this.collection){\n\t\t\tif (h.get(\"scheme\")!= null){\t\t\t\n\t\t\t\tDataUri d = this.getDataUriFromMap(h);\n\n\t\t\t\tif (this.isMapComplete(h))\n\t\t\t\t\tthis.outOfMishMash.add(d);\n\t\t\t\telse\n\t\t\t\t\tarr.add(d);\n\t\t\t\t\n\t\t\t}\n\t\t\t\t\n\t\t}\n\t\treturn arr;\n\t}\n\t\n\t/**\n\t * If the map has enough components to be independent : scheme & host, it will be excluded from other Data maps mishmash\n\t * @param map\n\t * @return\n\t */\n\tprivate boolean isMapComplete(Map<String,String> map){\n\t\tif (map.get(\"scheme\")!=null && map.get(\"host\")!=null)\n\t\t\treturn true;\n\t\treturn false;\n\t\t\n\t}\n\t\n\t\n\tprivate void addCompleteToMishmash(){\n\t\tthis.totalDU.addAll(outOfMishMash);\n\t}\n\t\n\tprivate void addMimeTypeOnly(){\n\t\tif (this.isMimeTypeOnly()){\n\t\t\tDataUri dTypeOnly = new DataUri();\n\t\t\tthis.totalDU.add(dTypeOnly);\n\t\t\tthis.addDataUriComp(\"mimeType\");\t\t\t\n\t\t}\n\t}\n\t\n\tprivate boolean isMimeTypeOnly(){\n\t\tfor (Map<String,String> h: this.collection){\n\t\t\tif (!(h.containsKey(\"mimeType\") && h.size()==1))\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tprivate void addDataUriComp(String compName){\n\t\tfor (Map<String,String> h: this.collection){\n\t\t\tif (h.get(compName)!= null){\n\t\t\t\tthis.updateTotalDU(compName, h);\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\t\n\tprivate void updateTotalDU(String compName, Map<String,String> h){\n\t\tArrayList<DataUri> tempDataUri = new ArrayList<>();\n\t\t\n\t\tfor (DataUri d:this.totalDU)\n\t\t{\n\t\t\tDataUri d2 = this.copyDataUri(d);\n\t\t\t\n\t\t\t\n\t\t\tif (!this.isDataUriCompEmpty(compName, d)){\n\t\t\t\ttempDataUri.add(d);\n\t\t\t\n\t\t\t\tif (this.isPathConflict(compName,d)){\n\t\t\t\t\tthis.clearPathValuesCuzConflict(d2);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\td2 = this.addCompByType(compName,h.get(compName),d);\n\t\t\ttempDataUri.add(d2);\n\t\t\t\n\t\t}\n\t\tthis.totalDU = tempDataUri;\n\t}\n\t\n\t/**\n\t * If there is a path conflict, delete all path properties in order to add the new one later\n\t * @param d\n\t */\n\tprivate void clearPathValuesCuzConflict(DataUri d){\n\t\td.setPath(null);\n\t\td.setPathPattern(null);\n\t\td.setPathPrefix(null);\n\t}\n\t\n\t/**\n\t * Added the occupied check to make sure that if multiple properties are defined in a single Data Tag, they will not be replaced (Not a solution asasan)\n\t * @param name\n\t * @param value\n\t * @param d\n\t * @return\n\t */\n\tprivate DataUri addCompByType(String name,String value,DataUri d){\n\t\tDataUri dTemp = this.copyDataUri(d);\n\t\tswitch(name)\n\t\t\t{\n\t\t\t\tcase \"scheme\":\n\t\t\t\t\tdTemp.setScheme(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"host\":\n\t\t\t\t\t\tdTemp.setHost(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"port\":\n\t\t\t\t\t\tdTemp.setPort(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"path\":\n\t\t\t\t\t\tdTemp.setPath(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"pathPattern\":\n\t\t\t\t\t\tdTemp.setPathPattern(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"pathPrefix\":\n\t\t\t\t\t\tdTemp.setPathPrefix(value);\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase \"mimeType\":\n\t\t\t\t\t\tdTemp.setMimeType(value);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn dTemp;\t\t\n\t}\n\t\n\t/**\n\t * Check if a map of a dataUri contains a DataUri component\n\t * @param name\n\t * @param h\n\t * @return\n\t */\n\tprivate boolean isDataUriCompEmpty(String name, DataUri d) {\n\t\tMap<String,String> h = d.getDataMap();\n\t\treturn (h.get(name)== null);\n\t}\n\t\n\t/**\n\t * If the component is a path* component and d has another path* component, return true\n\t * Bardo not a solution :(\n\t * @param compName\n\t * @param d\n\t * @return\n\t */\n\tprivate boolean isPathConflict(String compName,DataUri d){\n\t\tif (compName.contains(\"path\") && (d.getPath()!= null || d.getPathPattern()!= null || d.getPathPrefix()!= null))\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\t\n\tprivate DataUri getDataUriFromMap(Map<String,String> h){\n\t\tDataUri d = new DataUri();\n\t\tString[] comps = {\"scheme\",\"host\",\"port\",\"path\",\"pathPattern\",\"pathPrefix\",\"mimeType\"};\n\t\t\n\t\tfor(String s:comps){\n\t\t\td = this.addCompByType(s, h.get(s), d);\n\t\t}\n\t\t\n\t\treturn d;\n\t}\n\t\n\tprivate DataUri copyDataUri(DataUri d){\n\t\tDataUri d2 = new DataUri();\n\t\td2.setHost(d.getHost());\n\t\td2.setMimeType(d.getMimeType());\n\t\td2.setPath(d.getPath());\n\t\td2.setPathPattern(d.getPathPattern());\n\t\td2.setPathPrefix(d.getPathPrefix());\n\t\td2.setPort(d.getPort());\n\t\td2.setScheme(d.getScheme());\n\t\t\n\t\treturn d2;\n\t}\n\t\n\t/**\n\t * Prints Data URI component of an intent, used with  -l\n\t * @param d\n\t */\n\tpublic void printData(DataUri d) {\n\t\tif (d.getScheme()!=null)\n\t\t\tSystem.out.println(\"\\tScheme: \"+d.getScheme());\n\t\t\n\t\tif (d.getHost()!=null)\n\t\t\tSystem.out.println(\"\\tHost: \"+d.getHost());\n\t\t\n\t\tif (d.getPort()!=null)\n\t\t\tSystem.out.println(\"\\tPort: \"+d.getPort());\n\t\t\n\t\tif (d.getPath()!=null)\n\t\t\tSystem.out.println(\"\\tPath: \"+d.getPath());\n\t\t\n\t\tif (d.getPathPattern()!=null)\n\t\t\tSystem.out.println(\"\\tPath Pattern: \"+d.getPathPattern());\n\t\t\n\t\tif (d.getPathPrefix()!=null)\n\t\t\tSystem.out.println(\"\\tPath Prefix: \"+d.getPathPrefix());\n\t\t\n\t\tif (d.getMimeType()!=null)\n\t\t\tSystem.out.println(\"\\tMime Type: \"+d.getMimeType());\n\t}\n\t\n\t/**\n\t * Prepare the data URI part in am start command\n\t * @param d\n\t * @return\n\t */\n\tpublic String getStartCommand(DataUri d) {\n\t\tString cmd=\"\";\n\t\tif (d.getScheme()!=null && ! d.getScheme().isEmpty()) {\n\t\t\tcmd = \" -d \\\"\"+d.getScheme()+\"://\";\n\t\t\tTicklerGeneral.schemes.add(d.getScheme());\n\t\t}\n\t\t// If scheme is not in the same data entry, it might be declared in a previous or a next one.\n\t\t\n\t\telse if (!TicklerGeneral.schemes.isEmpty() /*&& !TicklerGeneral.schemes.contains(\"://\")*/) {\n\t\t\tcmd = \" -d \\\"\"+TicklerGeneral.schemes.get(0)+\"://\";\n\t\t}\n\t\t//Therefore add a dummy $scheme now and we'll replace it later\n\t\telse {\n\t\t\tcmd = \" -d \\\"$scheme://\";\n\t\t}\n\t\t// If a scheme is not specified for the intent filter, all the other URI attributes are ignored.\n\t\t// https://developer.android.com/guide/topics/manifest/data-element\n\t\t// Update: 10.21 --> This is false, because scheme could be defined in another XML entity. Don't ignore\n\t\t\tif (d.getHost()!=null && !d.getHost().isEmpty()){\n\t\t\t\tString newVal=this.replaceAstrexInPathValues(d.getHost());\n\t\t\t\tcmd = cmd+newVal+\"/\";\n\t\t\t}\n\n\t\t\t\n\t\t\tif (d.getPort()!=null && !d.getPort().equals(\"*\") && !d.getPort().isEmpty())\n\t\t\t\tcmd = cmd+ \":\"+d.getPort();\n\t\t\t\n\t\t\tif (d.getPath()!=null){\n\t\t\t\tString newVal = this.replaceAstrexInPathValues(d.getPath());\n\t\t\t\tcmd = cmd+newVal;\n\t\t\t}\n\t\t\t\n\t\t\tif (d.getPathPattern()!=null){\n\t\t\t\tString newVal = this.replaceAstrexInPathValues(d.getPathPattern());\n\t\t\t\tcmd = cmd + newVal;\n\t\t\t}\n\t\t\t\n\t\t\tif (d.getPathPrefix()!=null && !d.getPathPrefix().equals(\"*\"))\n\t\t\t\tcmd = cmd+ d.getPathPrefix();\n\t\t//}\n\t\tif (!cmd.isEmpty()) {\n\t\t\tcmd = cmd+\"TiCkLeR\\\"\";\n\t\t}\n\t\t\n\t\t\tif (d.getMimeType()!=null && ! d.getMimeType().isEmpty())\n\t\t\t\tcmd = cmd+\" -t \" +d.getMimeType();\n\t\t\t\n\t\t\t\n\t\t//if dataURI is empty then cmd is empty. It will be removed later\t\n\t\tif (cmd.equals(\" -d \\\"$scheme://TiCkLeR\\\"\")) {\n\t\t\tcmd=\"\";\n\t\t}\n\t\t\t\n\t\t\t\n\t\t\t\n\t\treturn cmd;\n\t\t\n\t}\n\t\n\t/**\n\t * REplace the wildcards in Path values (prefix and pattern) with a dummy value\n\t * @param path\n\t * @return\n\t */\n\tprivate String replaceAstrexInPathValues(String path){\n\t\tString newPath = path.replace(\".*\", \"TiCkLeR\");\n\t\tString newPath2 = newPath.replace(\"\\\\\", \"\");\n\t\tnewPath = newPath2.replace(\"*\", \"TiCkLeR\");\n\t\treturn newPath;\n\t}\n\t\n\t/**\n\t * Gets All Data URI combinations\n\t * @return\n\t */\n\tpublic ArrayList<DataUri> getTotalDU() {\n\t\treturn totalDU;\n\t}\n\n\tpublic void setTotalDU(ArrayList<DataUri> totalDU) {\n\t\tthis.totalDU = totalDU;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/manifest/handlers/IntentHandler.java",
    "content": "/*******************************************************************************\n * Copyright 2017 Ahmad Abolhadid\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *     http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\npackage manifest.handlers;\n\nimport java.util.ArrayList;\n\nimport base.TicklerGeneral;\nimport components.Action;\nimport components.Category;\nimport components.DataUri;\nimport components.Intent;\n\npublic class IntentHandler {\n\tprivate String command;\n\tprivate Intent intent;\n\tprivate ArrayList<String> commands,additionalCommands;\n\t\n\tpublic IntentHandler(String origCommand,Intent intent) {\n\t\tthis.command = origCommand;\n\t\tthis.intent = intent;\n\t\tthis.commands = new ArrayList<String>();\n\t\tthis.additionalCommands = new ArrayList<String>();\n\t}\n\t\n\t/**\n\t * Gets all combinations of Intent actions,and DAta URI\n\t * For now: the categories are excluded\n\t * @return\n\t */\n\tpublic ArrayList<String> fullIntent() {\n\t\t\n\t\tthis.commands.add(this.command);\n\t\tthis.addActions();\n\t\tthis.addData();\n\t\t\n\t\treturn this.commands;\n\t}\n\t\n\tprivate void addActions() {\n\t\tif (this.intent.getAction()!=null) {\n\t\t\tfor (Action a : this.intent.getAction()) \n\t\t\t\tthis.updateCommandsList(\" -a \"+a.getName());\n\t\t\tthis.commands.addAll(this.additionalCommands);\n\t\t\tthis.additionalCommands.clear();\n\t\t}\n\t}\n\t\n\t\n\tprivate void addData(){\n\t\tif (this.intent.getData() != null)\n\t\t{\n\t\t\tDataUriHandler dH = new DataUriHandler(this.intent);\n\t\t\tdH.doIt();\n\t\t\tArrayList<DataUri> totalDU = dH.getTotalDU();\n\t\t\tfor (DataUri d : totalDU){\n\t\t\t\tthis.updateCommandsList(dH.getStartCommand(d));\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tthis.commands.addAll(this.additionalCommands);\n\t\t\tthis.additionalCommands.clear();\n\t\t\tTicklerGeneral.schemes.clear();\n\t\t}\n\t}\n\t\n\tprivate void updateCommandsList(String s) {\n\t\tfor (String str:this.commands){\n\t\t\tthis.additionalCommands.add(str+s);\n\t\t}\n\t}\n\n\n}\n"
  }
]