Repository: lukeFalsina/Grab-n-Run Branch: master Commit: e8de92230247 Files: 145 Total size: 910.8 KB Directory structure: gitextract_0udiqonx/ ├── .gitmodules ├── COPYRIGHT ├── README.md ├── docs/ │ ├── .gitignore │ ├── .placeholder │ ├── Makefile │ ├── complementary.rst │ ├── conf.py │ ├── example.rst │ ├── index.rst │ ├── javaDoc/ │ │ ├── allclasses-frame.html │ │ ├── allclasses-noframe.html │ │ ├── constant-values.html │ │ ├── deprecated-list.html │ │ ├── help-doc.html │ │ ├── index-files/ │ │ │ ├── index-1.html │ │ │ ├── index-2.html │ │ │ ├── index-3.html │ │ │ ├── index-4.html │ │ │ ├── index-5.html │ │ │ └── index-6.html │ │ ├── index.html │ │ ├── it/ │ │ │ └── necst/ │ │ │ └── grabnrun/ │ │ │ ├── SecureDexClassLoader.html │ │ │ ├── SecureLoaderFactory.html │ │ │ ├── class-use/ │ │ │ │ ├── SecureDexClassLoader.html │ │ │ │ └── SecureLoaderFactory.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ ├── package-tree.html │ │ │ └── package-use.html │ │ ├── overview-tree.html │ │ ├── package-list │ │ └── stylesheet.css │ ├── repackaging.rst │ ├── security.rst │ └── tutorial.rst ├── downloads/ │ ├── 1.0/ │ │ ├── gnr-1.0.jar │ │ └── gnr-1.0.jar.sha1 │ ├── 1.0.1/ │ │ ├── gnr-1.0.1.aar │ │ ├── gnr-1.0.1.aar.sha1 │ │ ├── gnr-1.0.1.jar │ │ └── gnr-1.0.1.jar.sha1 │ ├── 1.0.2/ │ │ ├── gnr-1.0.2.aar │ │ ├── gnr-1.0.2.aar.sha1 │ │ ├── gnr-1.0.2.jar │ │ └── gnr-1.0.2.jar.sha1 │ ├── 1.0.3/ │ │ ├── grabnrun-1.0.3.aar │ │ ├── grabnrun-1.0.3.aar.sha1 │ │ ├── grabnrun-1.0.3.jar │ │ └── grabnrun-1.0.3.jar.sha1 │ └── 1.0.4/ │ ├── grabnrun-1.0.4.aar │ ├── grabnrun-1.0.4.aar.sha1 │ ├── grabnrun-1.0.4.jar │ └── grabnrun-1.0.4.jar.sha1 ├── example/ │ ├── ADT/ │ │ ├── .classpath │ │ ├── .gitignore │ │ ├── .project │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── exampleJar/ │ │ │ └── componentModifier.jar │ │ ├── libs/ │ │ │ └── gnr-1.0.1.jar │ │ ├── lint.xml │ │ ├── proguard-project.txt │ │ ├── project.properties │ │ ├── res/ │ │ │ ├── layout/ │ │ │ │ ├── activity_dex_class_sample.xml │ │ │ │ └── activity_main.xml │ │ │ └── values/ │ │ │ └── strings.xml │ │ └── src/ │ │ └── it/ │ │ └── polimi/ │ │ └── poccodeloading/ │ │ ├── ComponentModifier.java │ │ ├── DexClassSampleActivity.java │ │ └── MainActivity.java │ └── AS/ │ ├── .gitignore │ ├── app/ │ │ ├── build.gradle │ │ ├── lint.xml │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── exampleJar/ │ │ │ └── componentModifier.jar │ │ ├── java/ │ │ │ └── it/ │ │ │ └── polimi/ │ │ │ └── poccodeloading/ │ │ │ ├── ComponentModifier.java │ │ │ ├── DexClassSampleActivity.java │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_dex_class_sample.xml │ │ │ └── activity_main.xml │ │ └── values/ │ │ └── strings.xml │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── gnr/ │ ├── .gitignore │ ├── app/ │ │ ├── build.gradle │ │ ├── lint.xml │ │ ├── proguard-project.txt │ │ └── src/ │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── it/ │ │ │ │ └── necst/ │ │ │ │ └── grabnrun/ │ │ │ │ ├── CacheLogger.java │ │ │ │ ├── CertificateFileFilterByNameMatch.java │ │ │ │ ├── ContainerSignatureVerifier.java │ │ │ │ ├── DexPathStringProcessor.java │ │ │ │ ├── FileDownloader.java │ │ │ │ ├── FileFilterByNameMatch.java │ │ │ │ ├── FileHelper.java │ │ │ │ ├── PackageNameHelper.java │ │ │ │ ├── PackageNameTrie.java │ │ │ │ ├── SecureDexClassLoader.java │ │ │ │ └── SecureLoaderFactory.java │ │ │ └── res/ │ │ │ ├── values-v11/ │ │ │ │ └── styles.xml │ │ │ └── values-v14/ │ │ │ └── styles.xml │ │ └── test/ │ │ └── java/ │ │ └── it/ │ │ └── necst/ │ │ └── grabnrun/ │ │ ├── CacheLoggerTest.java │ │ ├── CertificateFileFilterByNameMatchTest.java │ │ ├── ContainerSignatureVerifierTest.java │ │ ├── DexPathStringProcessorTest.java │ │ ├── FileDownloaderTest.java │ │ ├── FileFilterByNameMatchTest.java │ │ ├── FileHelperTest.java │ │ ├── PackageNameHelperTest.java │ │ ├── PackageNameTrieTest.java │ │ ├── SecureDexClassLoaderTest.java │ │ ├── SecureLoaderFactoryTest.java │ │ └── shadows/ │ │ ├── BaseDexClassLoaderShadow.java │ │ └── DexFileShadow.java │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle-app.setting │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── grabandrun.bib └── repackPOC/ ├── .gitignore ├── RepackInputSelector/ │ ├── .classpath │ ├── .project │ └── src/ │ └── it/ │ └── necst/ │ └── grabnrun/ │ └── selector/ │ ├── LinkContainerDialog.java │ └── MainFrame.java ├── libs/ │ ├── RepackInputSelector.jar │ └── apktool.jar ├── repackagingTool.py ├── requirements.txt └── smaliRes/ └── grabnrun/ ├── CacheLogger.smali ├── CertFileFilter.smali ├── FileDownloader$1.smali ├── FileDownloader.smali ├── FileFilterByName.smali ├── PackageNameTrie.smali ├── RepackHandler.smali ├── RepackHandlerTail.smali ├── SecureDexClassLoader$SignatureVerificationTask.smali ├── SecureDexClassLoader.smali └── SecureLoaderFactory.smali ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitmodules ================================================ [submodule "repackPOC/androguard"] path = repackPOC/androguard url = https://github.com/androguard/androguard.git ================================================ FILE: COPYRIGHT ================================================ Copyright 2014 Luca Falsina Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # ![Logo](https://github.com/lukeFalsina/Grab-n-Run/raw/master/gnr/app/src/main/res/drawable-mdpi/logo_with_name.png) ## Research paper We present the findings of this work in a research paper: **Grab'n Run: Secure and Practical Dynamic Code Loading for Android Applications** Luca Falsina, Yanick Fratantonio, Stefano Zanero, Christopher Kruegel, Giovanni Vigna, Federico Maggi. *In Proceedings of the Annual Computer Security Applications Conference (ACSAC). Los Angeles, CA December, 2015* [[PDF](http://cs.ucsb.edu/~yanick/publications/2015_acsac_grabandrun.pdf)] [[Bibtex](https://github.com/lukeFalsina/Grab-n-Run/raw/master/grabandrun.bib)] If you use *Grab'n Run* in a scientific publication, we would appreciate citations to the previous paper. Please use this **Bibtex** entry: ``` tex @InProceedings{falsina15:grabandrun, author = {Luca Falsina and Yanick Fratantonio and Stefano Zanero and Christopher Kruegel and Giovanni Vigna and Federico Maggi}, title = {{Grab'n Run: Secure and Practical Dynamic Code Loading for Android Applications}}, booktitle = {Proceedings of the Annual Computer Security Applications Conference (ACSAC)}, month = {December}, year = {2015}, address = {Los Angeles, CA} } ``` ## News - *10/10/2015* - The **repackaging tool** is now **[online](http://grab-n-run.readthedocs.org/en/latest/repackaging.html)**. Use it to patch automatically your applications to use Grab'n Run APIs. - *01/17/2015* - **Grab'n Run** is now **available** on [JCenter](https://bintray.com/bintray/jcenter?filterByPkgName=grab-n-run) - *01/16/2015* - **Grab'n Run** project migrates to [Android Studio](http://developer.android.com/tools/studio/index.html), the official *IDE* for **Android application development**. However, you can still use the library also with your *ADT* projects! (*see below the "Quick Setup" section for further details*) - *11/26/2014* - **Grab'n Run is on line!** ## Introduction *Grab’n Run* (aka **GNR**) is a **simple** and **effective** Java Library that you can easily add to your Android projects to perform *secure dynamic class loading* operations over standard [DexClassLoader](http://developer.android.com/reference/dalvik/system/DexClassLoader.html). Previous research has shown that many applications often need to perform dynamic class loading to implement, for example, non-invasive self-update features. However, research has also shown that it is really challenging to *safely* implement these features. This is of particular importance as, in this context, **one single mistake** could open the application (and, therefore, the entire device) to **serious security vulnerabilities**, such as *remote code execution*. The main goal of *Grab's Run* is to offer an alternative to the native Android APIs, and its design enforces that even the most inexperienced developer cannot perform well-known, serious mistakes. For a **brief presentation** of the library and some of its features you can give a look at these [slides](https://goo.gl/QrwWey), while if you prefer a more **structured and complete description** with *set up information, tutorials, examples, tips&tricks, and a full presentation of the API* you should definitely check the [documentation](http://grab-n-run.readthedocs.org/en/latest/). If you desire to suggest new *features, improvements, criticisms* or whatever, I would be more than glad to hear **any kind of constructive feedback** :D You can contact me either by dropping an email at [lfalsina@gmail.com](mailto:lfalsina@gmail.com) or by pinging me on Twitter [@lfalsina](https://twitter.com/lfalsina). ## Main features Securely load code dynamically into your Android application from **APK** containers or **JAR** libraries translated to be *executable by both the Dalvik Virtual Machine (DVM) and the Android Runtime (ART)* (don't worry a [section](http://grab-n-run.readthedocs.org/en/latest/complementary.html#on-library-developer-side-how-to-prepare-a-valid-library-container-compatible-with-gnr) of the docs explains step-by-step how to do it). - *JAR* and *APK* containers can be either already stored on the device or **automatically fetched from remote locations** by GNR. - Retrieved containers signatures are compared against a **valid developer certificate**. Only containers that are **correctly signed** are allowed to have their classes loaded dynamically. This ensures **integrity** and **developer authentication** on all the retrieved containers. - Developer certificates are retrieved from remote locations securely and cached on the mobile phone for future verifications. - *Cached classes, containers and certificates* used for the signature verification are stored into *application-private* folders. This **prevents** your application **from code injection attacks** at runtime. - GNR implements an **effective caching system** that speeds up its execution and at the same time enables it to *work in most cases also when no connectivity is available*. - Transition to GNR is **smooth** for the application developer since its **API** where thought to be *as close as possible to the standard API* provided by the Android framework. - When *many containers* are provided as sources for class loading, *Grab'n Run* performs a **concurrent multi-thread signature verification** in order to *limit the performance overhead*. - GNR helps the application developer to **implement silent updating** on *remote third-party libraries in a secure and concise way*. ## Quick Setup This section explains how to setup *Grab'n Run* as a library for your Android applications. #### 1. Include library ###### a. Android Studio (AS) * Modify the *build.gradle* file in the *app* module of your Android project by adding the following *compile* line in the *dependencies* body: ``` gradle dependencies { // Grab'n Run will be imported from JCenter. // Verify that the string "jcenter()" is included in your repositories block! compile 'it.necst.grabnrun:grabnrun:1.0.4' } ``` * Resync your project to apply changes. ###### b. Android Development Tool (ADT) * [Download JAR](https://github.com/lukeFalsina/Grab-n-Run/raw/master/downloads/1.0.4/grabnrun-1.0.4.jar) * Put the JAR in the **libs** subfolder of your Android project #### 2. Android Manifest Modify the *Android Manifest* of your application by adding a couple of **required permissions**: ``` xml ... ``` ## Quick example of use This quick use case gives you a taste on how to use GNR once you have added it to your project. #### 1. Create a key pair to sign your code and export your developer certificate * Open a terminal and type the following command to **generate a keystore** and a **keypair**: ``` bash $ keytool -genkey -v -keystore my-tests-key.keystore -alias test_dev_key -keyalg RSA -keysize 2048 -validity 10000 ``` * Next **export** the public key **into a certificate** that will be *used to verify your library code* before dynamically loading it: ``` bash $ keytool -exportcert -keystore my-tests-key.keystore -alias test_dev_key -file certificate.pem ``` * You should now see in the folder a **certificate file** called *certificate.pem* #### 2. Publish your developer certificate on line at a remote location which uses HTTPS protocol You can publish the certificate wherever you like as long as **HTTPS** protocol is used and **everyone can access this location** from the web. As a **test** example you could store the *certificate.pem* in your "Public" *Dropbox* folder and then retrieve the **associated public link**, which could be for example something like "https://dl.dropboxusercontent.com/u/00000000/certificate.pem". Note this URL down, you will need it soon. #### 3. Export an unsigned container and sign it with your developer key Let's say that in your IDE (i.e., the *Android Development Tools (ADT)*) you have an Android project called **"LoaderApp"** from which you want to load some of its classes dynamically in another project. * In the *ADT Package Explorer* **right** click on **"LoaderApp"** -> Android Tools -> Export Unsigned Application Package... ![Screenshot](https://github.com/lukeFalsina/Grab-n-Run/raw/master/docs/images/ExportUnsignedContainer.png) * Next select the **same folder** where you have previously saved the keystore and the keypair as the *destination folder* and press OK. * Open a terminal which points to the destination folder and **sign the apk container** with the previously created key: ``` bash $ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-tests-key.keystore LoaderApp.apk test_dev_key ``` * Finally **align** the apk container to optimize access time to its resources: ``` bash $ /sdk/build-tools//zipalign -v 4 LoaderApp.apk LoaderAppAligned.apk ``` **P.S.** *Step 3* can also be directly performed by means of your favorite *IDE*. In **ADT** you would have to select the option *"Android Tools -> Export Signed Application Package..."* and, when it is required, navigate to the location of your keystore and inserting its password, the key id and the key password. On the other hand in **Android Studio** the signature process can be automatized by setting up a proper **signing configuration** as described [here](http://developer.android.com/tools/publishing/app-signing.html#release-mode). #### 4. Publish the signed and aligned version of the source container Once you have obtained *LoaderAppAligned.apk*, you need to make also this resource **available on line**. Notice that, in this case, both remote locations that use **HTTP** or **HTTPS** protocols are fine as long as they are accessible from the web. Again, as an example, you can store the container in your "Public" *Dropbox* folder and get back a **public URL** like "https://dl.dropboxusercontent.com/u/00000000/LoaderAppAligned.apk". #### 5. Set up dynamic code loading with GNR in the application In the end, it is time to set up a *SecureDexClassLoader* instance to **fetch your remote container and developer certificate**, **store it in a safe place** and **perform a signature verification** before dynamically loading your code. **Copy and paste** the code below in one of the Activity in your target Android project, where you have *already imported GNR*, to **dynamically and securely load** an instance of the class *"com.example.MyClass"*: ``` java MyClass myClassInstance = null; jarContainerPath = "https://dl.dropboxusercontent.com/u/00000000/LoaderAppAligned.apk"; try { Map packageNamesToCertMap = new HashMap(); packageNamesToCertMap.put("com.example", new URL("https://dl.dropboxusercontent.com/u/00000000/certificate.pem")); SecureLoaderFactory mSecureLoaderFactory = new SecureLoaderFactory(this); SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( jarContainerPath, null, getClass().getClassLoader(), packageNamesToCertMap); Class loadedClass = mSecureDexClassLoader.loadClass("com.example.MyClass"); // Check whether the signature verification process succeeded if (loadedClass != null) { // No security constraints were violated and so // class loading was successful. myClassInstance = (MyClass) loadedClass.newInstance(); // Do something with the loaded object myClassInstance // i.e. myClassInstance.doSomething(); } } catch (ClassNotFoundException e) { // This exception will be raised when the container of the target class // is genuine but this class file is missing.. e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (MalformedURLException e) { // The previous URL used for the packageNamesToCertMap entry was a malformed one. Log.e("Error", "A malformed URL was provided for a remote certificate location"); } ``` *Et voilà..* now you have an instance of *"MyClass"* loaded in a **secure way** at **run time**! ## Next steps :) * If you want to learn how to use *Grab'n Run* I suggest to start from the [tutorial](http://grab-n-run.readthedocs.org/en/latest/tutorial.html) and then moving on by analyzing the [example application](http://grab-n-run.readthedocs.org/en/latest/example.html). * If you are interested in understanding what are the **security threats** of *improper dynamic code loading* fixed by GNR check out the [security resume](http://grab-n-run.readthedocs.org/en/latest/security.html). * If you would like to implement cool features of GNR like **silent updates**, **handling more containers**, **concurrent code loading** or **dynamically loading JAR libraries in your applications** you should give a look at the [complementary topics](http://grab-n-run.readthedocs.org/en/latest/complementary.html). * You may also need to **consult** the *JavaDoc-like* [API documentation](https://rawgit.com/lukeFalsina/Grab-n-Run/master/docs/javaDoc/index.html). * Finally, you may want to convert automatically your applications to use Grab'n Run APIs for secure dynamic code loading. Give a try at the [repackaging tool](http://grab-n-run.readthedocs.org/en/latest/repackaging.html). ## License *Grab'n Run* is released under the *Apache* license. Check the *COPYRIGHT* file for further details. [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Grab--n--Run-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1185) ================================================ FILE: docs/.gitignore ================================================ /_build/ /javaAPI/ make.bat ================================================ FILE: docs/.placeholder ================================================ ================================================ FILE: docs/Makefile ================================================ # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/docgrabnrun.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/docgrabnrun.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/docgrabnrun" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/docgrabnrun" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." ================================================ FILE: docs/complementary.rst ================================================ Complementary topics ==================== In the end of this documentation a couple of not so trivial use cases of *Grab'n Run* are presented. This section will not introduce new core concepts but it may help the developer to handle some **tricky situations**. For such a reason feel free to **skip this part** and eventually **come back later** to revise it whenever you will encounter one of the following situations while using the library. Handle containers whose classes come from different package names which have a common relevant prefix ----------------------------------------------------------------------------------------------------- Before starting diving in this section it is important to recall the **relationship between package name and containers**. **Package name in apk containers** *Apk* containers must contain just **one package name**, which must be chosen by the developer when a new application is created. The package name is then stored in the *Android Manifest* of the application. In order to have an application being admitted on the *Google Play* store, it is also fundamental that the chosen package name is **unique** and should **not change** for the whole life cycle of the application. **Package name in jar containers** *Jar* containers on the other hand do **not** have such a **strict policy** as in *apk* containers. Hypothetically each class file contained in a *jar* archive may have a different package name and this mean that **many package names** can be present in the **same** *jar* container. **Common relevant prefix** In *Grab'n Run* two package names share a relevant common prefix if their prefix match for at least two words separated by one dot. **Example:** Consider the following package names: A. ``com.example.polimi`` B. ``it.example.polimi`` C. ``com.test`` D. ``com.example.application.system`` E. ``com.example.polimi.system`` * A. and B. do **not** share any **common relevant prefix** since they differ in the initial word of the package name (``com`` vs ``it``). * A. and C. do **not** share any **common relevant prefix** since they just have one word of the package name in common (``com``). * A. and D. share a **common relevant prefix** (``com.example``). * A. and E. share a **common relevant prefix** (``com.example.polimi``). Given these insights a first interesting situation to consider is when a developer wants to *load dynamically classes* from an external *jar* library which contains **more than one package name** that, anyway, share a **common relevant prefix**. Let us assume for example that the target library has the following structure: .. image:: images/JarContStructure.png In such a scenario we have four classes (``ClassA``, ``ClassB``, ``ClassC``, ``ClassD``) which belongs to **three different packages**, whose names are respectively ``com.example``, ``com.example.system`` and ``com.example.system.preference``. Let use also assume that this container has being signed with a *valid self-signed certificate*, remotely located at ``https://something.com/example_cert.pem``. Questions now for the developer are: 1. *How should I fill in the associative map which links package names to remote certificate location in order to being able to load all the classes in this container?* 2. *Am I obliged to insert all three package names pointing to the very same certificate?* Luckily the answer for the second question is **no**, which means that there is indeed an **easier way** to perform the job. *Grab'n Run* in fact was thought to make the whole dynamic class loading **secure but** at the same time **simple** for applications developers. You can in fact handle this situation correctly by simply inserting into the associative map a **single entry** where the *key corresponds to the shortest among the package names* belonging to one of the classes that need to be loaded and the *value is the location of the remote certificate* used to sign the container. So in the **previous case** since the classes with the shortest package name are ``com.example.ClassA`` and ``com.example.ClassB`` the following code is appropriate to populate the map:: Map packageNamesToCertMap = new HashMap(); try { packageNamesToCertMap.put( "com.example", new URL("https://something.com/example_cert.pem")); } catch (MalformedURLException e) { // The previous entry for the map may not necessarily be the right one // but still it is not malformed so no exception should be raised. Log.e(TAG_MAIN, "A malformed URL was provided for a remote certificate location"); } For the rest the developer may proceed as shown in :ref:`Using SecureDexClassLoader to load dynamic code securely`. The result will be that the container is going to be verified against the appropriate certificate and, if it is **genuine**, it will be *also possible to load the other two classes* in the archive with a **different package name** (``com.example.system.ClassC`` and ``com.example.system.preference.ClassD``). Handle containers whose classes come from different package names with no relevant common prefix ------------------------------------------------------------------------------------------------ Even if it is not such a common situation it is possible for a *jar* archive to *contain classes which belongs to different package names* and does not share any common relevant prefix. This situation, on the other hand, is **not practical** for *apk* containers since, in order to be **published** on Google Market, an application needs to have a **single** package name which more over must **not change** during its whole life cycle. Anyway let us try to sketch the case of the previous cited jar archive and how to handle it with ``SecureDexClassLoader``. As an example we can consider the scenario in which the goal is loading two classes, whose full class names are respectively ``com.example.MyFirstClass`` and ``com.test.MySecondClass`` and so which **differs** in the **package name** but are **both stored** in the **same container** ``exampleJar.jar``. It is also supposed that this container has being signed with a *valid self-signed certificate*, remotely located at ``https://something.com/example_cert.pem``. In order to handle this situation correctly the developer is required to fill the **associative map** which links package names and certificates with **two entries**, one per each package name, which will *point to the same remote certificate*. This is exemplified in the following snippet of code:: Map packageNamesToCertMap = new HashMap(); try { packageNamesToCertMap.put( "com.example", new URL("https://something.com/example_cert.pem")); packageNamesToCertMap.put( "com.test", new URL("https://something.com/example_cert.pem")); } catch (MalformedURLException e) { // The previous entries for the map may not be necessarily the right ones // but still they are not malformed so no exception should be raised. Log.e(TAG_MAIN, "A malformed URL was provided for a remote certificate location"); } For the rest the developer may proceed as shown in :ref:`Using SecureDexClassLoader to load dynamic code securely` and this procedure grants to succeed in the loading process for any of the two classes independently on the order in which they are attempted to be loaded. .. note:: By design ``SecureDexClassLoader`` assumes that **each package name** is intrinsically related to a **single container**, while it is not necessary true the opposite. This means that attempting to *load a class*, whose **package name** is associated with **more than one container** provided in *dexPath* (i.e. each one of the two containers contains at least one class with the same package name), will generate an **unpredictable behavior** since ``SecureDexClassLoader`` will associate that package name with just one of the two containers. So it is a **developer responsibility** to check the containers in order to avoid the occurrence of this rare but undesirable situation. .. _Reverse package name to obtain remote certificate URL: Reverse package name to obtain remote certificate URL ----------------------------------------------------- *Grab'n Run* provides as an extra feature the possibility to **reconstruct the remote URL location of the certificate by reversing the package name** provided into the associative map. To enable this feature simply add an entry to the associative map where the **key** is the **desired package name to reverse** and the **value** is ``null``. Here is a simple snippet of code to exemplify:: Map packageNamesToCertMap = new HashMap(); // Notice that a null entry won't raise a MalformedURLException.. packageNamesToCertMap.put("it.polimi.necst.mylibrary", null); What is going on behind the curtains is that whenever GNR find an entry with *a valid package name associated to a null value*, it will **reverse the package name** with the following convention: The **first word** of the package name will be considered as the **top level domain (TLD)**, while the **second** one is going to be the **main domain**. Any **following word** of the package name will be used in the **same order** as they are listed to define the **file path** on the remote server and of course since a secure connection is needed for the certificate, **HTTPS protocol** will be enforced. Let us translate this theory with some concrete examples: * Package name ``it`` won't be reverted since it contains just a world (at least two are required for real world package name). * Package name ``it.polimi`` will be reverted to the URL ``https://polimi.it/certificate.pem``. * Package name ``it.polimi.necst.mylibrary`` will be reverted to the URL ``https://polimi.it/necst/mylibrary/certificate.pem``. As you can see from the previous examples this naming convention assumes that the **final certificate** will be found in the *remote folder obtained by reverting the package name* and that the **certificate file** will have been **always renamed** ``certificate.pem``. Perform dynamic code loading concurrently ----------------------------------------- .. warning:: Before approaching this paragraph, a good idea is having **first read** the :doc:`security` section of this documentation and in particular the last part on performance-related topics. By default when a new ``SecureDexClassLoader`` object is instantiated, it will immediately **validate** all of its **containers concurrently** (**Eager signature verification strategy**). By the way sometimes when a large number of containers are assigned to a single ``SecureDexClassLoader`` object, it may just be *more convenient to evaluate each container separately just before loading classes from it*. So in such a scenario a **lazy signature verification strategy** would be advisable. An even better *performance concern strategy* is loading target classes in a **concurrent** way on different threads. This is perfectly fine with *Grab'n Run* since the library is **thread-safe**. As an example let us consider the case in which we want to *concurrently load some classes with a lazy strategy* from a ``SecureDexClassLoader`` instance with many containers associated to it. A possible code implementation which also makes use of `Executors `_ , `FixedThreadPool `_ and `Future `_ classes is the following:: // Make the assumption that packageNamesToCertMap has been already initialized; // moreover longListOfDexPath is the String with all the containers path listed and // separated by : SecureLoaderFactory mSecureLoaderFactory = new SecureLoaderFactory(this); // Initialize a SecureDexClassLoader instance in LAZY mode. SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( longListOfDexPath, null, getClass().getClassLoader(), packageNamesToCertMap, true); // Suppose these classes belongs only to three different containers; // while longListOfDexPath points to ten containers.. String[] classesToLoad = new String[] { "com.example.classA", "it.polimi.classB", "de.application.classC", "com.example.classD", "it.polimi.classE"}; // Suppose to store the loaded classes here.. Set> loadedClassesSet = Collections.synchronizedSet(new HashSet>()); // Initialize the thread pool executor with number of thread // equals to the number of classes to load.. ExecutorService threadLoadClassPool = Executors.newFixedThreadPool(classesToLoad.size()); List> futureTaskList = new ArrayList>(); Iterator classesToLoadIterator = classesToLoad.iterator(); while (classesToLoadIterator.hasNext()) { String classNameToLoad = classesToLoadIterator.next(); // Submit a new class load thread on a container and store // a reference in the future objects list. Future futureTask = threadLoadClassPool.submit(new classLoadingTask(mSecureDexClassLoader, classNameToLoad, loadedClassesSet)); futureTaskList.add(futureTask); } // Stop accepting new tasks for the current threadLoadClassPool threadLoadClassPool.shutdown(); for (Future futureTask : futureTaskList) { try { // Wait till the current task for class loading is finished.. futureTask.get(); } catch (InterruptedException | ExecutionException e) { // Issue while executing the verification on a thread e.printStackTrace() } } try { // Join all the threads here.. Use a timeout eventually.. threadLoadClassPool.awaitTermination( KEEP_ALIVE_NUMBER_OF_TIME_UNITS, KEEP_ALIVE_TIME_UNIT); } catch (InterruptedException e) { // One or more of the threads objects were still busy.. // And this should not happen.. e.printStackTrace() } And finally here it is the ``classLoadingTask``, an implementation of the `Runnable `_ interface, which is responsible for **dynamically loading** a single class with the previously created ``SecureDexClassLoader`` instance. Here is the class implementation:: class classLoadingTask implements Runnable { // The shared instance of SecureDexClassLoader for concurrent load ops. private SecureDexClassLoader mSecureDexClassLoader; // The name of the class to load. private String classNameToLoad; // Concurrent set of class objects that were successfully loaded. private Set successLoadedClassesSet; public classLoadingTask( SecureDexClassLoader mSecureDexClassLoader, String classNameToLoad, Set successLoadedClassesSet) { // Simply copy all the incoming parameters.. this.mSecureDexClassLoader = mSecureDexClassLoader; this.classNameToLoad = classNameToLoad; this.successLoadedClassesSet = successLoadedClassesSet; } @Override public void run() { // Set current thread priority to DEFAULT. android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT); try { // Load operation is invoked.. Class loadedClass = mSecureDexClassLoader.loadClass(classNameToLoad); // Check whether the loading operation succeeds if (loadedClass != null) { // Class loading was successful and performed in a safe way. // Add this class to the concurrent set successLoadedClassesSet.add(loadedClass); } } catch (ClassNotFoundException e) { // This exception will be raised when the container of the // target class is genuine but this class file is missing.. e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } The interesting **advantage** of this *concurrent evaluation* is that **only the first loaded class** belonging to each separate container will perform the **signature verification** process when the ``loadClass()`` method is invoked, while all the other loaded classes from the same container will benefit from the cached result of this verification and so their evaluation will be way faster (comparable to the ``loadClass()`` time execution of ``DexClassLoader``). .. note:: Using this **concurrent lazy approach** is a good way to *lower the performance overhead* that may be introduced by *Grab'n Run* and *keep your application always responsive*. Another slight shrewdness that you may consider when you are in need to *load many classes from containers that have to be downloaded* is considering to show a `ProgressDialog `_ or a similar object to *make the user aware that your application is performing some tasks that require him/her to wait* and at the same time prevent the user from clicking everywhere or terminating your application since it sometimes may seem not fully responsive. .. * By now use SecureDexClassLoader in Lazy mode. Instantiate such an object on the main thread. .. * Initialize a thread executor and then makes each thread load a class from the same SecureDexClassLoader object. Evaluation of containers will be performed only by the first thread to load a class into a container while the others will use the cached verification mechanism to directly load or reject loading for their target class. .. * Remember to put a join instruction at the end of the code block on the main thread to be sure that after that line all the classes that you need have attempted to being loaded. On library developer side: how to prepare a valid library container compatible with GNR --------------------------------------------------------------------------------------- For once in this tutorial the **focus is now moved** from the *application developer*, who wants to load classes from an external library, **to the library developer**, who wrote a library and wants to make it available to the application developers. What we are going to discuss about in this section is **how a library developer should prepare his/her library** in order to have it **compatible with GNR** system and more in general with **dynamic code loading**. A hint in this sense is provided by DexClassLoader `documentation `_, which states clearly that this class, and so also ``SecureDexClassLoader`` does, *"loads classes from .jar and .apk files containing a classes.dex entry."*. .. note:: The procedure outlined below must be performed entirely in case that you want to **export a library** into a *jar* container. The *typical use case* for such a situation is whenever you want to *export a library* which was *initially thought to work just for regular Java applications* but that now you would *also like to execute into an Android application*. On the other hand, if you decide to **export an Android application** as a source for dynamic class loading, part of the upcoming procedure won't be necessary anymore. This happens because: 1. When an *apk* container is generated, ``dx`` tool is automatically invoked. This means that by considering a valid *apk* container as a source for classes to load, the ``classes.dex`` entry will be already present and so you won't need to manually execute step *1* and step *2* of the following guide. 2. Since Android requires an *apk* container to be signed to allow execution, you can decide, whenever you are ready to **export your application as a library**, to right click on the project and choose ``Android Tools -> Export Signed Application Package...``. By completing the wizard procedure, you are going to export a signed version of the final *apk* container and this basically covers the first *4* steps of the following guide. So let us assume that you, as a library developer, want to export your project called "MyLibrary" into a *jar* archive compatible with ``SecureDexClassLoader``. The following steps should be performed: 1. Export the project "MyLibrary" into a jar archive. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. highlight:: bash If your project was developed using **Android Studio**, you can easily obtain a copy of your *jar* library by opening a terminal and pointing it to the main folder of your project and then by invoking a series of tasks through the ``./gradlew`` script as shown here:: $ cd $ ./gradlew clean build assembleRelease If the build process goes smoothly, you should now be able to find a file presumably called *"MyLibrary-release.jar"* located under one of your project ``build/outputs`` folder. .. highlight:: java On the other hand if you are relying on the **ADT (Android Development Tool)**, right-click on the project *"MyLibrary"* and select "Export...". .. image:: images/ExportJarOption.png Then choose the option "Jar File" and click "Next...". .. image:: images/ExportJarFile.png Finally choose the location of the exported *jar* archive by clicking on the "Browse..." button and then "Finish". .. image:: images/ExportJarFinish.png Independently from which of the two methods you implied, you should have now successfully exported your project into a *jar* container! 2. Translate Java Byte Code (.class) into Dalvik Byte Code (classes.dex). ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After having exported your project into a *jar* container you now have code that can run on a **Java Virtual Machine (JVM)** in the form of class file with the extensions ``.class``. Nevertheless in order to have your **code running** with ``SecureDexClassLoader`` **on an Android phone** it is necessary to **translate** the class files from Java Bytecode to **Dalvik Bytecode**. This task can be accomplished easily thanks to the ``dx`` tool, present in the Android SDK folder. .. note:: Notice that **Dalvik Bytecode** is also compatible with the new `Android Runtime (ART) `_ system. This means that, except for narrow cases, you won't generally need to worry since your library code should execute fine on both the *Dalvik Virtual Machine (DVM)* and the *Android Runtime (ART)*. As related to this guide and more in general to *Grab'n Run*, *choosing one runtime system in stead of the other should not be an issue at all*. .. highlight:: bash So by assuming that you have just exported the project into a file called *myLibrary.jar* in a terminal type the following commands:: $ cd $ //build-tools//dx --dex --output=myLibrary-dex.jar myLibrary.jar The result is an output *jar* container called *myLibrary-dex.jar*. You can easily spot that no ``.class`` file is stored in this container and in stead a file called ``classes.dex`` was added. This is the direct **result of the translation** mentioned before. 3. Generate a keypair and export the developer certificate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If this is the first time that you sign a container you will need to **generate a key pair** with ``keytool`` and then **export a certificate** containing the newly created public key. Otherwise if you *already have a key pair and the associated certificate, simply skip this section* and continue reading from the next one. In order to **generate a keystore and a key pair** type in the following command line in a terminal:: $ keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000 This line prompts you for passwords for the keystore and private key, and to provide the Distinguished Name fields for your key. It then generates the keystore as a file called ``my-release-key.keystore``. The keystore will contain a single key, valid for 10000 days. The **alias** is a name that you choose to **identify keys** inside the keystore. In this case this private key will be identified as ``alias_name``. If the previous step succeeded, now it is time to **export your developer certificate** that will be used by *application developers to verify your library code before dynamically loading it*. This can be accomplished again thanks to a ``keytool`` feature:: $ keytool -exportcert -keystore my-release-key.keystore -alias alias_name -file certificate.pem This command will export the certificate embedding the public key associated to the private key whose alias is ``alias_name``. This certificate will be stored in the file ``certificate.pem``. Even if the previous commands are all that you will need here, if you desire to deepen your knowledge on *keystore, keys and signing Android applications* visit these reference links: * https://www.digitalocean.com/community/tutorials/java-keytool-essentials-working-with-java-keystores * http://developer.android.com/tools/publishing/app-signing.html#signing-manually 4. Sign the library with the developer private key. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now it is time to **sign** the *jar* library with the **library developer private key** to enable the possibility to verify it. Assuming that you have generated a private key whose alias is ``alias_name`` and stored it in a keystore whose name is ``my-release-key.keystore`` in order to sign the *jar* container manually type in this line in your terminal:: $ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore myLibrary-dex.jar alias_name You can then verify that the jar container is actually signed by typing:: $ jarsigner -verify -verbose -certs myLibrary-dex.jar .. highlight:: java .. note:: When you verify the signature of the final container, you will receive a **warning message** like the following *"This jar contains entries whose certificate chain is not validated"*. This is absolutely normal since a **self-signed certificate** was used for the **verification process** and this is acceptable in Android as long as you are absolutely *sure that the certificate used for the verification is actually the library developer one*. In *Grab'n Run* the **chain of trust** is replaced by assuming that the certificate is stored on a domain which is directly controlled by the library developer and can only be retrieved via **HTTPS protocol**. 5. Make the library and the certificate publicly available. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The last step is **making public the signed version of the jar container**, obtained after the previous step, and the **exported certificate** embedding the library developer public key (*as explained in* `3. Generate a keypair and export the developer certificate`_ ). While you can *store the library container basically everywhere on the web* (application developers can retrieve your library via both HTTP or HTTPS protocol), it is **crucial and fundamental** for the whole security model to handle that you **publish your library developer certificate on a secure trustworthy remote location which can be accessed only via HTTPS protocol**. If you have successfully followed up all the previous steps, you have now correctly **published your library** and application developers will be able to **run your code securely** by using ``SecureDexClassLoader``. Let GNR automatically handle library updates silently ----------------------------------------------------- In the end of this section **silent updating**, a *powerful feature* of **dynamic code loading**, is presented and easily and securely implemented with the use of *Grab'n Run*. Performing silent updates is a convenient techniques which can be used to **keep always updated third-party libraries or frameworks** by *decoupling the update process of the main application from those ones of the non-standalone libraries*. The **advantage** of such an approach is clearly the possibility to have always the **latest features and security workaround on third-party libraries** without continuously bothering the user on updating the application. Dynamic code loading in this sense can be really effective in such a scenario since the latest version of the code can be retrieved from a remote URL just at runtime and then immediately executed. Let us now set up a possible use case for this technique and see how to implement it with Grab'n Run from both the library developer and the application developer side: imagine that an application developer wants to dynamically load the latest version of the already seen class ``com.example.ClassA`` stored in "myLibrary-dex.jar", a remote library. From the point of view of the **library developer** a couple of prerequisite steps must be performed: * The developer must prepare correctly a **signed version** of his/her library. For a complete walk-through on this task see the previous section `On library developer side: how to prepare a valid library container compatible with GNR`_. * Once that the last version of the library container is correctly prepared and signed, the **developer must publish** on a domain that (s)he controls a **redirect link** (i.e. ``http://mylibrary.it/downloads/mobile/latest``) which *points to the remote location where the library container is actually stored* (i.e. ``http://mylibrary.it/downloads/mobile/myLibrary-dex-1-8.jar``). * The developer must also set up a **secure link using HTTPS protocol**, which *points to the remote location of the certificate* associated to the private key used to sign the last version of the library (i.e. ``https://myLibrary.com/developerCert.pem``). * Every time that a **new version of the same library is ready** (i.e. version 1.9 of myLibrary is now available), the library developer will have to prepare the container in the usual way and sign it with the **SAME** private key associated to ``developerCert.pem`` and finally **update the redirect link** to *point to the location of the latest version of the container* (i.e. set up ``http://mylibrary.it/downloads/mobile/latest`` to redirect to ``http://mylibrary.it/downloads/mobile/myLibrary-dex-1-9.jar``). .. warning:: While *Grab'n Run* **supports redirect links for the container remote location**, this kind of link is arbitrarily not accepted for remote certificates!!! This is a **security-oriented choice** since redirect links may jump from an HTTPS link to an HTTP one making the whole system insecure in case that the attacker performs a **Man-In-The-Middle-Attack** and substitute the proper certificate for the verification with a different one generated by himself. That is the reason why **redirect links for remote certificates will not be followed** by Grab'n Run and so no certificate file will be found for the container signature verification. On the other hand the **application developer**, who wants to make use of the classes provided by ``myLibrary`` can easily accomplish this by setting up a ``SecureDexClassLoader`` where the *location pointing to the remote container* is the **redirect link** provided by the library developer and the **certificate** used for the verification is the *one stored at the secure URL on the library developer domain*. Here is a snippet of code that summarizes this operational description:: ClassA classAInstance = null; // The latest version of the library container is always found thanks to the redirect link jarContainerRemotePath = "http://mylibrary.it/downloads/mobile/latest"; try { Map packageNamesToCertMap = new HashMap(); // The package "com.example" is always signed by the library developer with // the same private key and so it can always be verified with the same // remote certificate. packageNamesToCertMap.put( "com.example", new URL("https://myLibrary.com/developerCert.pem")); // The second parameter used here specifies how many days are counted before // a cached copy of the remote library container is considered rotten // and automatically discarded. // Default value is 5 days, here the value is lowered to 3.. SecureLoaderFactory mSecureLoaderFactory = new SecureLoaderFactory(this, 3); SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( jarContainerRemotePath, null, packageNamesToCertMap, getClass().getClassLoader()); Class loadedClass = mSecureDexClassLoader.loadClass("com.example.ClassA"); // Check whether the signature verification process succeeds if (loadedClass != null) { // Class loading was successful and performed in a safe way. // The last version of ClassA has been successfully retrieved! classAInstance = (ClassA) loadedClass.newInstance(); // Do something with the loaded object classAInstance // i.e. classAInstance.doSomething(); } } catch (ClassNotFoundException e) { // This exception will be raised when the container of the target class // is genuine but this class file is missing.. e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (MalformedURLException e) { // The previous URL used for the packageNamesToCertMap entry was a malformed one. Log.e("Error", "A malformed URL was provided for a remote certificate location"); } .. Library developer side: .. * Read previous section. .. * Use a redirect HTTP link to point to the last version of the signed jar library container .. * Use an HTTPS link to make the certificate for verification public .. Application developer side: .. * Initialize SecureDexClassLoader with dexPath pointing to the redirect HTTP link for the updated container and associate the package name to the remote URL of the library developer certificate .. DONE :) ================================================ FILE: docs/conf.py ================================================ # -*- coding: utf-8 -*- # # docgrabnrun documentation build configuration file, created by # sphinx-quickstart on Tue Sep 23 09:59:33 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../../grab-n-run/gnr/src/')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', #'javasphinx', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'docgrabnrun' copyright = u'2014, Luca Falsina' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. release = '1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The language used in code block to set keywords highlight. highlight_language = 'java' # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Haiku theme # html_theme = 'haiku' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'docgrabnrundoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'docgrabnrun.tex', u'docgrabnrun Documentation', u'Luca Falsina', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'docgrabnrun', u'docgrabnrun Documentation', [u'Luca Falsina'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'docgrabnrun', u'docgrabnrun Documentation', u'Luca Falsina', 'docgrabnrun', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False ================================================ FILE: docs/example.rst ================================================ Discussion of an example project ================================ Before digging into this section, you are **strongly** encouraged to read :doc:`tutorial` for an **introductory description** on the features of Grab`n Run library. The **aim of the sample application** is to give you some *hints on how to use the classes in Grab'n Run and how they will behave across different contexts*. The **source code** of the example can be found in the ``example`` folder of *Grab'n Run* repository. Different extracts of code will be considered and explained in the following sections of this page but before analyzing the code it may be convenient to retrieve it and to set up an **already prepared Android smart phone emulator** that contains all the containers needed to run the example code.. Retrieve the example code and the emulator ------------------------------------------ Retrieve Grab'n Run full repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ At first you will need to recover *Grab'n Run* example code. In order to do so you need to have **Git** installed on your machine. The latest version can be found at Git download `page `_. .. highlight:: bash Next open a terminal and **clone** the example repository into ``grab-n-run``, a local folder located at ``absolute_path_to_gnr_repo``, through Git:: $ cd $ mkdir grab-n-run $ cd grab-n-run $ git clone "https://github.com/lukeFalsina/Grab-n-Run.git" .. highlight:: java At the end of the process you will have all the GNR code locally including a copy of the *example application* and of the *documentation*. Include Grab'n Run example code in your IDE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The next step is *importing the example sources* into an **IDE**. The process will be now described for both **Android Studio (AS)** and **Android Development Tool (ADT)**. a. **Android Studio (AS)** In the welcome window of Android Studio select from the *Quick Start* menu the option "Open an existing Android Studio project". .. image:: images/ASImportGNR1.png Next navigate to the ``grab-n-run`` folder in which you previously cloned the repository and then pick the project ``AS`` from the ``example`` subfolder as shown in the image below. .. image:: images/ASImportGNR2.png The example project should have been now successfully imported! It may be necessary to rebulit it again by picking the option "Make Project". .. image:: images/ASImportGNR3.png **P.S.** Notice that you can open in *Android Studio* also the **original GNR library project** by using the very same procedure but by picking the ``gnr`` Studio project from the main ``grab-n-run`` folder in stead of the ``example/AS`` one. .. image:: images/ASImportGNR4.png b. **Android Development Tool (ADT)** At first right click in the *Package Explorer* and select "Import.." .. image:: images/ADTImportGNR1.png Next select under the *Android* folder "Existing Android Code Into Workspace" and then "Next >" .. image:: images/ADTImportGNR2.png By pressing the "Browse..." button point the *Root Directory* to the ``grab-n-run`` folder in which you previously cloned the repository and then to the subfolder ``grab-n-run/example/ADT``. You should be now able to the see and select the candidate project ``ExampleAppGNR`` (*an example application which makes use of GNR*). In the end press "Finish" to import the example project. Below you can see a screenshot which summarizes all the settings before the "Finish" button is clicked. .. image:: images/ADTImportGNR3.png At the end of this process you should have been able to **correctly import** the example application! .. image:: images/ADTImportGNR4.png Retrieve and set up the emulator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. highlight:: bash Then it is time to retrieve the **emulator** used to run the example application. You can easily find it in the ``assets`` folder of the ``example`` repository. So once that you have located the compressed file ``ExampleAppGNREmu.tar.gz`` containing the emulator, open a terminal and at first copy this file into your *home* folder:: $ cd /example/ $ cp ExampleAppGNREmu.tar.gz ~ Next decompress this container:: $ cd ~ $ tar xzf ExampleAppGNREmu.tar.gz This operation will generate two files, a folder called ``ExampleAppGNREmu.avd`` and a configuration file ``ExampleAppGNREmu.ini``. In the end move these two files into the Android emulator folder, normally located at ``/home//.android/avd``:: $ mv ExampleAppGNREmu.avd ExampleAppGNREmu.ini .android/avd The last step consist in editing the ``path`` variable stored in the configuration file. So open ``ExampleAppGNREmu.ini`` at the final location with a text editor and change the path variable in order to match the current location of the ``ExampleAppGNREmu.avd`` folder. So if my user name is for example *bill90*, I need to change the path variable from ``path=/home//.android/avd/ExampleAppGNREmu.avd`` to ``path=/home/bill90/.android/avd/ExampleAppGNREmu.avd``. .. highlight:: java Before starting the emulator in your **IDE**, remember to **verify that the SDK version 17** is installed on your machine since the emulator targets that version. Otherwise you can *also edit the emulator configuration* from your IDE to target a different and **more recent** version of the SDK which is installed on your machine. .. note:: Android emulator is unfortunately pretty slow and requires also a big bunch of resources and that is the reason why it may be not supported by different machines. A couple of empirical suggestions in this direction are the following: * If possible, try to target directly **SDK version 17**, as it results to me that the more recent SDK version you target, the more time the emulator requires before setting up. * It is a really good idea to enable the **snapshot feature**. This lets the system frame the current situation of the emulator when you turn it off and load it back whenever you restart the emulator with a *significant reduction of the waiting time*. This `post `_ explains how to enable the feature. * Emulator can be switched between landscape and portrait view by pressing ``ctrl + F12``. This can be useful to interact properly with the example application. When the emulator is finally set up, you can start it in either **ADT Eclipse** or **Android Studio** (it may take time depending on your machine..). Next, whenever you want to run the example code and the IDE asks which device should be used, remember to **select this emulator as the running Android device**. In case you need to integrate this previous concise walk-through, please give a look at these other resources: * https://blahti.wordpress.com/2011/08/24/how-to-export-and-import-android-virtual-device-avd-files/ * http://stackoverflow.com/questions/4575167/android-how-to-copy-the-emulator-to-a-friend-for-testing List of example containers -------------------------- In order to understand correctly the following detailed discussion, it is fundamental to first introduce the containers (*jar* and *apk* archives), retrieved for the code loading in the example code. Here is a list of the string variables that store the path to various containers: * ``exampleSignedAPKPath``: URI of a **benign** toy *apk* container signed with a valid *developer certificate*. * ``exampleTestAPKPath``: path location pointing to the same **benign** *apk* container but this time signed with the *Android Debug Certificate*. * ``exampleSignedChangedAPKPath``: URI pointing to a **handled version** of the same container stored at ``exampleSignedAPKPath`` in which a part of the signatures has been modified. * ``jarContainerPath``: path location to the **benign** *jar* container used to customize the view elements inside an example activity. * ``jarContainerRepackPath``: URI pointing to a **malicious repackaged** version of the original container stored at ``jarContainerPath``. MainActivity.java ----------------- `MainActivity `_ is the **entry point** of the sample application. In its overloaded method ``onCreate()`` it initializes through a ``ListView`` a set of buttons used to select the *different test cases* present in the application. DexClassLoader (apk) vs SecureDexClassLoader (apk) ---------------------------------------------------- In this first scenario you will consider how to retrieve an `Activity `_ class, whose name is ``NasaDailyImage``, stored in the *apk* container, called *test.apk*, through the use of `DexClassLoader `_ and ``SecureDexClassLoader``. The relevant **code** in this case is the one of the two methods ``setUpDexClassLoader()`` and ``setUpSecureDexClassLoader()``, which are triggered by tapping the related two buttons on the ``MainActivity`` view. setUpDexClassLoader() ~~~~~~~~~~~~~~~~~~~~~ In this method a standard initialization of a ``DexClassLoader`` is applied. So at first the usual **application-private, writable directory** for caching loaded *.dex* classes must be set up. Then a ``DexClassLoader`` object is initialized using *test.apk*, a container located directly in the phone external storage ( as described by ``exampleTestAPKPath``), as its *jar path* for the classes to load. Finally the ``NasaDailyImage`` Activity is loaded. If such an operation is successful the **simple name** of the **loaded class** is shown to the user through a *toast message*; otherwise different **exceptions** are raised and show again through a toast message an appropriate helper message. setUpSecureDexClassLoader() ~~~~~~~~~~~~~~~~~~~~~~~~~~~ In this method **repeated** ``loadClass()`` **calls** are performed on differently initialized ``SecureDexClassLoader`` instances in order to *show different behaviors* of the loader class while retrieving the usual ``NasaDailyImage`` Activity. At first a ``SecureLoaderFactory`` object is created. Then this instance is used to generate three ``SecureDexClassLoader`` that covers different cases and ends up with different results on the load operation: 1. **Test case 1:** Load a class through ``SecureDexClassLoader`` without providing an associative map for certificates location This first test case shows a **possible error** that a developer may encounter when using this library for the first time. If you want to have the location of the certificate being computed by reversing the package name, as explained in :ref:`Reverse package name to obtain remote certificate URL`, you still need to **populate an associative map** with entries like (*"any.package.name"*, **null**) and use it as a parameter of the method ``createDexClassLoader()``. To understand why the class works in this way think of this system as a kind of `white listing `_. Only those classes inside package names which are *declared into the associative map* or *directly descend* from one of the declared package names will be considered as possible valid ones, while all classes belonging to a **not listed package name or not a descendant of the declared ones** will be **immediately rejected**. And this is exactly what happens in this test case where **no associative map is provided** and so all the classes in the two containers, including the target ``NasaDailyImage``, are **prevented from being loaded** since there is *no clue on the certificate location*. 2. **Test case 2:** Unsuccessful load of a class through ``SecureDexClassLoader`` with an associative map *(Debug certificate)* In the second test case you can see different ways to **populate** the associative map ``packageNamesToCertMap``, used to *link packages with certificates location*. .. warning:: Always keep in mind that **prior** to **downloading** a certificate from the **web** the certificate for that package will be **searched inside the application-private directory** reserved for certificates and then possibly at the remote location. If you wish to *just look at the remote URL* without considering cached certificates, always remember to **wipe out private application data** through the invocation of the method ``wipeOutPrivateAppCachedData()`` **before dismissing** your ``SecureDexClassLoader`` instances. In such a way every time that a new ``SecureDexClassLoader`` is created, you will be sure that no cached resource will be associated with it. The first ``put()`` *call* inserts the package name *headfirstlab.nasadailyimage* of the class that we would like to load later in the example and associates it with a **valid remote URL**. What you can immediately notice by pointing your browser to that URL is that the *remote certificate* in this case is a **self-signed developer** one since the **subject** of the certificate is **also** the **issuer** of it but, as it is mentioned in the :doc:`tutorial`, this is perfectly fine in the **Android** environment. The *second entry* inserted into the associative map provides a *remote URL* to an **inexistent certificate** (once again you can try to point there your browser to easy spot this out). More over since *no certificate for the package name ``it.polimi.example`` has been already cached into the application-private certificate directory*, then **no certificate** is **available** for it and that is the reason why *any class* belonging to the ``it.polimi.example`` package will be **rejected and prevented from being loaded** by ``SecureDexClassLoader``. Lastly the third ``put()`` call on the associative map will insert a package name that will be also used to *construct the remote certificate URL* (**reverse package name**). Once again the final remote URL (``https://polimi.it/example3/certificate.pem``) points to no certificate so any class, whose package name is *it.polimi.example3*, will be rejected from being loaded. In the end a ``SecureDexClassLoader`` is generated using as a container file a valid *apk* containing the target class but **signed with a certificate**, the *Debug Android Certificate*, which is different from the one issued by the developer. For such a reason the result of the ``loadClass()`` method will be that *no class object is going to be returned* since the apk is **not signed** with the **required certificate**. 3. **Test case 3:** Unsuccessful load of a class through ``SecureDexClassLoader`` with an associative map *(Failed signatures verification of some container's entries)* In the third test case you can immediately notice that all the settings for the invocation of ``SecureDexClassLoader`` are equals to those of the previous case except for the chosen *apk* container. In fact, while before the container was signed with a non valid certificate, this time the container is signed with the **right certificate** but someone **modified** a couple of the **entries signature**, which do not match anymore with the one obtained during the signing procedure. To sum up also in this case *no class will be loaded* since this container results to be **partially corrupted** and so not safe. 4. **Test case 4:** Successful load of a class through ``SecureDexClassLoader`` with an associative map In this last test case a **successful example** of dynamic code loading is shown. This time ``SecureDexClassLoader`` is initialized with a **valid** *apk* container, **signed** with the **correct developer certificate**, and with the associative map previously initialized in *Test case 2*. The whole process works fine since this associative map contains the necessary key entry *headfirstlab.nasadailyimage* and the related developer **certificate** has been **already cached** during *Test case 2*. Finally during the **signature verification step** inside the ``loadClass()`` method all the entries inside the container match properly with their signature and the certificate used for that signing process is exactly the one linked to *headfirstlab.nasadailyimage* package. That is the reason why *dynamic loading* of ``NasaDailyImage`` activity is **allowed**. DexClassLoader (jar) vs SecureDexClassLoader (jar) ---------------------------------------------------- A different scenario to show the power of *dynamic code* loading and the **security weakness** of the standard ``DexClassLoader`` is represented by the following example. In this case another activity (the source code is contained into *DexClassSampleActivity.java*) instantiates a certain number of **GUI components** (a couple of buttons, a text view, a switch..) and then **customizes** them according to the methods of an object belonging to the **external** class ``ComponentModifier``, which is **dynamically loaded** at run time. Depending on the user choice (tapping the first button in stead of the second one) a different extension class of ``ComponentModifier`` is loaded and a different behavior is shown to the user even if the static code shown in ``DexClassSampleActivity`` is exactly the same (as you can easily check by inspecting the method ``onBtnClick()``). This loading operation can be realized easily by means of ``DexClassLoader`` as shown in the method ``retrieveComponentModifier()`` of the source code.. That's just a pity that the container used to load dynamically the class by ``DexClassLoader`` in this example is actually *randomly selected at run time* between either a benign version or a **repackaged one** of the original *apk* and so **malicious code** could potentially have been **executed** *without the user even notice it*! But let's explain how this could possibly happen: in ``DexClassSampleActivity`` there is a simple private method called ``randomContainerPathChoice()``, which in this case is invoked before the instantiation of both ``DexClassLoader`` and ``SecureDexClassLoader`` and which **select randomly the path** of either the **benign** version of the ``ComponentModifier`` container, stored in the string ``jarContainerPath``, or the path of the **repackaged** one with the string ``jarContainerRepackPath``. ``DexClassLoader`` *won't notice and care* about this difference as long as in both the containers there is an implementation of the required **target class** to load and that is the reason why repeating tapping on the first button ''Click me!'' in the Activity screen multiple times will end up in executing two different version of the same ``FirstComponentModifierImpl`` class. On the other hand if you perform the same experiment with ``SecureDexClassLoader`` the repackaged *apk* container choice this time will be detected and blocked during the **signature verification procedure** against the developer certificate in the ``loadClass()`` method. This is possible since *malicious modified entries will not succeed in the signature verification check computed by considering both the initial signature stored inside the container and the developer certificate* retrieved from the associative map used to initialize the ``SecureDexClassLoader`` instance. Thanks to this, ``SecureDexClassLoader`` **won't load** the customization classes inside the *repackaged container* and it will just **end up the activity**, which is exactly the **secure** behavior that you, *as a developer*, would like to obtain :) .. Create PackageContext .. --------------------- .. Coming soon.. More or less ;) ================================================ FILE: docs/index.rst ================================================ .. docgrabnrun documentation master file, created by sphinx-quickstart on Tue Sep 23 09:59:33 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to Grab'n Run documentation! ==================================== *Grab'n Run* (aka **GNR**) is a **simple** and **effective** Java Library that you can add to your Android projects to secure *dynamic class loading* operations. For a **quick start** on how to include the library and how to use it in your projects give a look at :doc:`tutorial`. For a brief explanation on the **issue** of *insecure dynamic class loading* and on Grab'n Run purpose check the :doc:`security` section. A concise **example** of use of the library is provided into an Android toy-application `here `_. A *full explanation* of key extracts of this code is given into the :doc:`example` section. For a description on Grab'n Run **API** in *JavaDoc* style please refer to the `API documentation `_. For those willing for more **technicalities** and **advanced features** implemented in *Grab'n Run*, the section on :doc:`complementary` is a *must-read*. This part of the documentation can also be used for **reference** as it presents how to handle properly some **tricky situations** that may occur while using *GNR*. For an introduction on how to use the POC script for rewriting your application automatically to use the secure Grab'n Run API instead of the regualr ones for dynamic code loading, check out the :doc:`repackaging` section. .. toctree:: :maxdepth: 2 tutorial security example complementary repackaging Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: docs/javaDoc/allclasses-frame.html ================================================ All Classes

All Classes

================================================ FILE: docs/javaDoc/allclasses-noframe.html ================================================ All Classes

All Classes

================================================ FILE: docs/javaDoc/constant-values.html ================================================ Constant Field Values

Constant Field Values

Contents

it.necst.*

================================================ FILE: docs/javaDoc/deprecated-list.html ================================================ Deprecated List

Deprecated API

Contents

================================================ FILE: docs/javaDoc/help-doc.html ================================================ API Help

How This API Document Is Organized

This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
  • Package

    Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain six categories:

    • Interfaces (italic)
    • Classes
    • Enums
    • Exceptions
    • Errors
    • Annotation Types
  • Class/Interface

    Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

    • Class inheritance diagram
    • Direct Subclasses
    • All Known Subinterfaces
    • All Known Implementing Classes
    • Class/interface declaration
    • Class/interface description
    • Nested Class Summary
    • Field Summary
    • Constructor Summary
    • Method Summary
    • Field Detail
    • Constructor Detail
    • Method Detail

    Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.

  • Annotation Type

    Each annotation type has its own separate page with the following sections:

    • Annotation Type declaration
    • Annotation Type description
    • Required Element Summary
    • Optional Element Summary
    • Element Detail
  • Enum

    Each enum has its own separate page with the following sections:

    • Enum declaration
    • Enum description
    • Enum Constant Summary
    • Enum Constant Detail
  • Use

    Each documented package, class and interface has its own Use page. This page describes what packages, classes, methods, constructors and fields use any part of the given class or package. Given a class or interface A, its Use page includes subclasses of A, fields declared as A, methods that return A, and methods and constructors with parameters of type A. You can access this page by first going to the package, class or interface, then clicking on the "Use" link in the navigation bar.

  • Tree (Class Hierarchy)

    There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.

    • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
    • When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
  • Deprecated API

    The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.

  • Index

    The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.

  • Prev/Next

    These links take you to the next or previous class, interface, package, or related page.

  • Frames/No Frames

    These links show and hide the HTML frames. All pages are available with or without frames.

  • All Classes

    The All Classes link shows all classes and interfaces except non-static nested types.

  • Serialized Form

    Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.

  • Constant Field Values

    The Constant Field Values page lists the static final fields and their values.

This help file applies to API documentation generated using the standard doclet.
================================================ FILE: docs/javaDoc/index-files/index-1.html ================================================ C-Index
C D I L S W 

C

createDexClassLoader(String, String, ClassLoader, Map<String, URL>) - Method in class it.necst.grabnrun.SecureLoaderFactory
Creates a SecureDexClassLoader that finds interpreted and native code in a set of provided locations (either local or remote via HTTP or HTTPS) in dexPath.
createDexClassLoader(String, String, ClassLoader, Map<String, URL>, boolean) - Method in class it.necst.grabnrun.SecureLoaderFactory
This method returns a SecureDexClassLoader instance in the same way as it is explained in the createDexClassLoader(String, String, ClassLoader, Map).
C D I L S W 
================================================ FILE: docs/javaDoc/index-files/index-2.html ================================================ D-Index
C D I L S W 

D

DEFAULT_DAYS_BEFORE_CONTAINER_EXPIRACY - Static variable in class it.necst.grabnrun.SecureLoaderFactory
When a remote container URL is encountered, this field specifies the default time interval, expressed in days, before which a local copy of a remote container, stored in an application-private directory, will be considered fresh and so acceptable to be cached.
C D I L S W 
================================================ FILE: docs/javaDoc/index-files/index-3.html ================================================ I-Index
C D I L S W 

I

it.necst.grabnrun - package it.necst.grabnrun
 
C D I L S W 
================================================ FILE: docs/javaDoc/index-files/index-4.html ================================================ L-Index
C D I L S W 

L

loadClass(String) - Method in class it.necst.grabnrun.SecureDexClassLoader
 
C D I L S W 
================================================ FILE: docs/javaDoc/index-files/index-5.html ================================================ S-Index
C D I L S W 

S

SecureDexClassLoader - Class in it.necst.grabnrun
A class that provides an extension of default DexClassLoader provided by the Android system and it is used to load classes from jar and apk container files including a classes.dex entry in a secure way.
SecureLoaderFactory - Class in it.necst.grabnrun
A Factory class that generates instances of classes used to retrieve dynamic code in a secure way at run time.
SecureLoaderFactory(ContextWrapper) - Constructor for class it.necst.grabnrun.SecureLoaderFactory
Creates a SecureLoaderFactory used to check and generate instances from secure dynamic code loader classes.
SecureLoaderFactory(ContextWrapper, int) - Constructor for class it.necst.grabnrun.SecureLoaderFactory
This constructor works exactly as the previous one but it also allows to decide the time interval in days before which a local copy of a remote container, stored in an application-private directory, will be considered fresh and so acceptable to be cached.
C D I L S W 
================================================ FILE: docs/javaDoc/index-files/index-6.html ================================================ W-Index
C D I L S W 

W

wipeOutPrivateAppCachedData(boolean, boolean) - Method in class it.necst.grabnrun.SecureDexClassLoader
Sometimes it may be useful to remove those data that have been cached in the private application folders (basically for performance reason or for making SecureDexClassLoader works also partially offline).
C D I L S W 
================================================ FILE: docs/javaDoc/index.html ================================================ Generated Documentation (Untitled) <noscript> <div>JavaScript is disabled on your browser.</div> </noscript> <h2>Frame Alert</h2> <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="it/necst/grabnrun/package-summary.html">Non-frame version</a>.</p> ================================================ FILE: docs/javaDoc/it/necst/grabnrun/SecureDexClassLoader.html ================================================ SecureDexClassLoader
it.necst.grabnrun

Class SecureDexClassLoader



  • public class SecureDexClassLoader
    extends Object
    A class that provides an extension of default DexClassLoader provided by the Android system and it is used to load classes from jar and apk container files including a classes.dex entry in a secure way.

    In order to instantiate this class a call to SecureLoaderFactory.createDexClassLoader(String, String, ClassLoader, Map) must be performed.

    SecureDexClassLoader ensures integrity of loaded external remote classes by comparing them with the developer certificate, which is retrieved either by a provided associative map between package names and certificate remote URL or by simply reverting the first two words of the package name of the loaded class and then by adding each following word in the same order and separated by a slash "/".

    Package name reversion example:
    Class name = it.necst.grabnrun.example.TestClassImpl
    Constructed URL = https://necst.it/grabnrun/example
    Final certificate location = https://necst.it/grabnrun/example/certificate.pem

    A request is pointed to the final certificate location and if the file is found, it is imported in the local private application directory.

    Please note that in the current implementation certificates obtained by reverting package name must have been saved at the described location as "certificate.pem". Moreover all the certificates must fit requirements of a standard X509Certificate, they must be valid in the current time frame and of course they must have been used to sign the jar or apk, which contains the classes to be loaded.

    If any of these previous requirements is violated no class is loaded and this class returns without executing any class loading operation.

    Author:
    Luca Falsina
    • Method Detail

      • loadClass

        public Class<?> loadClass(String className)
                           throws ClassNotFoundException
        Parameters:
        className - the full class name to load. It must fit the form "package name + . + class name". A valid full class name is for example "it.polimi.myapplication.classA"; while "classA" is not enough since it misses the package name and so SecureDexClassLoader will not find any class to load.
        Returns:
        Either a class that needs to be casted at runtime accordingly to className if the verification process succeeds or a null pointer in case that at least one of the security constraints for secure dynamic class loading is violated.
        Throws:
        ClassNotFoundException - this exception is raised whenever no security constraint is violated but still the target class is not found in any of the available containers used to instantiate this SecureDexClassLoader object.
        See Also:
        ClassLoader.loadClass(java.lang.String)
      • wipeOutPrivateAppCachedData

        public void wipeOutPrivateAppCachedData(boolean containerPrivateFolder,
                                       boolean certificatePrivateFolder)
        Sometimes it may be useful to remove those data that have been cached in the private application folders (basically for performance reason or for making SecureDexClassLoader works also partially offline). A call to this method solves the issue.

        Please notice that a call to this method with both the parameters set to false has no effect.

        In any of the other cases the content of the related folder(s) will be erased and since some of the data may have been used by SecureDexClassLoader instances, it is required to the caller to create a new SecureDexClassLoader object through SecureLoaderFactory since the already present object is going to be disabled from loading classes dynamically.

        Parameters:
        containerPrivateFolder - if the private folder where jar and apk containers downloaded from remote URL or imported from local storage needs to be wiped out.
        certificatePrivateFolder - if the private folder containing certificates needs to be wiped out.
================================================ FILE: docs/javaDoc/it/necst/grabnrun/SecureLoaderFactory.html ================================================ SecureLoaderFactory
it.necst.grabnrun

Class SecureLoaderFactory



  • public class SecureLoaderFactory
    extends Object
    A Factory class that generates instances of classes used to retrieve dynamic code in a secure way at run time.
    Author:
    Luca Falsina
    • Field Detail

      • DEFAULT_DAYS_BEFORE_CONTAINER_EXPIRACY

        public static final int DEFAULT_DAYS_BEFORE_CONTAINER_EXPIRACY
        When a remote container URL is encountered, this field specifies the default time interval, expressed in days, before which a local copy of a remote container, stored in an application-private directory, will be considered fresh and so acceptable to be cached.

        On the other hand, all of those containers, whose life time is greater than this field value, will be immediately erased from the device storage in stead of being cached.

        You can change this duration by generating the SecureLoaderFactory instance with SecureLoaderFactory#SecureLoaderFactory(android.content.ContextWrapper, int).

        See Also:
        Constant Field Values
    • Constructor Detail

      • SecureLoaderFactory

        public SecureLoaderFactory(ContextWrapper parentContextWrapper)
        Creates a SecureLoaderFactory used to check and generate instances from secure dynamic code loader classes.

        It requires a ContextWrapper (i.e. the launching activity) which should be used to manage and retrieve internal directories of the application.

        Parameters:
        parentContextWrapper - The content wrapper coming from the launching Activity.
      • SecureLoaderFactory

        public SecureLoaderFactory(ContextWrapper parentContextWrapper,
                           int daysBeforeContainerCacheExpiration)
        This constructor works exactly as the previous one but it also allows to decide the time interval in days before which a local copy of a remote container, stored in an application-private directory, will be considered fresh and so acceptable to be cached.

        If a negative value is provided for the second parameter, SecureLoaderFactory will be instantiated with the time interval in days equal to DEFAULT_DAYS_BEFORE_CONTAINER_EXPIRACY.

        Parameters:
        parentContextWrapper - The content wrapper coming from the launching Activity.
        daysBeforeContainerCacheExpiration - The non negative value of days for which a local copy of a remote container imported into an application private folder is considered fresh and so acceptable to be cached.
    • Method Detail

      • createDexClassLoader

        public SecureDexClassLoader createDexClassLoader(String dexPath,
                                                String libraryPath,
                                                ClassLoader parent,
                                                Map<String,URL> packageNameToCertificateMap)
        Creates a SecureDexClassLoader that finds interpreted and native code in a set of provided locations (either local or remote via HTTP or HTTPS) in dexPath. Interpreted classes are found in a set of DEX files contained in Jar or Apk files and stored into an application-private, writable directory.

        Before executing one of these classes the signature of the target class is verified against the certificate associated with its package name. Certificates location are provided by filling appropriately packageNameToCertificateMap; each package name must be linked with the remote location of the certificate that should be used to validate all the classes of that package. It's important that each one of these locations uses HTTPS as its protocol; otherwise this choice will be enforced! If a class package name do not match any of the provided entries in the map, certificate location will be constructed by simply reverting package name and transforming it into a web-based URL using HTTPS.

        Note that this method returns null if no matching Jar or Apk file is found at the provided dexPath parameter; otherwise a SecureDexClassLoader instance is returned.

        Dynamic class loading with the returned SecureDexClassLoader will fail whether at least one of these conditions is not accomplished: target class is not found in dexPath or is in a missing remote container (i.e. Internet connectivity is not present), missing or invalid (i.e. expired) certificate is associated with the package name of the target class, target class signature check fails against the associated certificate.

        Parameters:
        dexPath - the list of jar/apk files containing classes and resources; these paths could be either local URLs pointing to a location in the device or URLs that links to a resource stored in the web via HTTP/HTTPS. In the latter case, if Internet connectivity is available, the resource will be imported in a private-application directory before being used.
        libraryPath - the list of directories containing native libraries; it may be null.
        parent - the parent class loader.
        packageNameToCertificateMap - a map that couples each package name to a URL which contains the certificate that must be used to validate all the classes that belong to that package before launching them at run time. Please notice that any URL in this map using HTTP protocol will be enforced to use HTTPS in stead.
        Returns:
        a SecureDexClassLoader object which can be used to load dynamic code securely and uses a Eager strategy for container signature verification.
      • createDexClassLoader

        public SecureDexClassLoader createDexClassLoader(String dexPath,
                                                String libraryPath,
                                                ClassLoader parent,
                                                Map<String,URL> packageNameToCertificateMap,
                                                boolean performLazyEvaluation)
        This method returns a SecureDexClassLoader instance in the same way as it is explained in the createDexClassLoader(String, String, ClassLoader, Map). In addition it is possible to specify the mode in which the signature verification process will be carried.

        In particular by setting the performLazyEvaluation parameter on true, a lazy verification process will be chosen. This means that the signature of the single container associated with the target class will be evaluated only when SecureDexClassLoader.loadClass(String) will be invoked . If this check succeeds the target class will be loaded.

        On the other hand, by setting the parameter performLazyEvaluation to false an eager evaluation will be carried out. This means that before returning this object, the signature verification procedure will be carried out on all the provided containers in a CONCURRENT way and all of those that do not succeed in the process will be blocked from loading their classes in the following loadClass() method calls.

        The use of one mode in stead of the other is merely a performance-related choice. If you do not care that much about it, just invoke createDexClassLoader(String, String, ClassLoader, Map) which does not require to provide the performLazyEvaluation parameter and it will perform an Eager evaluation. Otherwise as a general guideline, prefer the lazy mode whenever you think that you won't need to load classes from all the provided containers.

        Parameters:
        dexPath - the list of jar/apk files containing classes and resources; these paths could be either local URLs pointing to a location in the device or URLs that links to a resource stored in the web via HTTP/HTTPS. In the latter case, if Internet connectivity is available, the resource will be imported in a private-application directory before being used.
        libraryPath - the list of directories containing native libraries; it may be null.
        parent - the parent class loader.
        packageNameToCertificateMap - a map that couples each package name to a URL which contains the certificate that must be used to validate all the classes that belong to that package before launching them at run time. Please notice that any URL in this map using HTTP protocol will be enforced to use HTTPS in stead.
        performLazyEvaluation - the mode in which the verification will be handled. True for lazy verification; false for the eager one.
        Returns:
        a SecureDexClassLoader object which can be used to load dynamic code securely and uses a either Lazy or an Eager strategy for container signature verification depending on the last parameter provided to this constructor.
================================================ FILE: docs/javaDoc/it/necst/grabnrun/class-use/SecureDexClassLoader.html ================================================ Uses of Class it.necst.grabnrun.SecureDexClassLoader

Uses of Class
it.necst.grabnrun.SecureDexClassLoader

================================================ FILE: docs/javaDoc/it/necst/grabnrun/class-use/SecureLoaderFactory.html ================================================ Uses of Class it.necst.grabnrun.SecureLoaderFactory

Uses of Class
it.necst.grabnrun.SecureLoaderFactory

No usage of it.necst.grabnrun.SecureLoaderFactory
================================================ FILE: docs/javaDoc/it/necst/grabnrun/package-frame.html ================================================ it.necst.grabnrun

it.necst.grabnrun

================================================ FILE: docs/javaDoc/it/necst/grabnrun/package-summary.html ================================================ it.necst.grabnrun

Package it.necst.grabnrun

  • Class Summary 
    Class Description
    SecureDexClassLoader
    A class that provides an extension of default DexClassLoader provided by the Android system and it is used to load classes from jar and apk container files including a classes.dex entry in a secure way.
    SecureLoaderFactory
    A Factory class that generates instances of classes used to retrieve dynamic code in a secure way at run time.
================================================ FILE: docs/javaDoc/it/necst/grabnrun/package-tree.html ================================================ it.necst.grabnrun Class Hierarchy

Hierarchy For Package it.necst.grabnrun

Class Hierarchy

================================================ FILE: docs/javaDoc/it/necst/grabnrun/package-use.html ================================================ Uses of Package it.necst.grabnrun

Uses of Package
it.necst.grabnrun

================================================ FILE: docs/javaDoc/overview-tree.html ================================================ Class Hierarchy

Hierarchy For All Packages

Package Hierarchies:

Class Hierarchy

================================================ FILE: docs/javaDoc/package-list ================================================ it.necst.grabnrun ================================================ FILE: docs/javaDoc/stylesheet.css ================================================ /* Javadoc style sheet */ /* Overall document style */ body { background-color:#ffffff; color:#353833; font-family:Arial, Helvetica, sans-serif; font-size:76%; margin:0; } a:link, a:visited { text-decoration:none; color:#4c6b87; } a:hover, a:focus { text-decoration:none; color:#bb7a2a; } a:active { text-decoration:none; color:#4c6b87; } a[name] { color:#353833; } a[name]:hover { text-decoration:none; color:#353833; } pre { font-size:1.3em; } h1 { font-size:1.8em; } h2 { font-size:1.5em; } h3 { font-size:1.4em; } h4 { font-size:1.3em; } h5 { font-size:1.2em; } h6 { font-size:1.1em; } ul { list-style-type:disc; } code, tt { font-size:1.2em; } dt code { font-size:1.2em; } table tr td dt code { font-size:1.2em; vertical-align:top; } sup { font-size:.6em; } /* Document title and Copyright styles */ .clear { clear:both; height:0px; overflow:hidden; } .aboutLanguage { float:right; padding:0px 21px; font-size:.8em; z-index:200; margin-top:-7px; } .legalCopy { margin-left:.5em; } .bar a, .bar a:link, .bar a:visited, .bar a:active { color:#FFFFFF; text-decoration:none; } .bar a:hover, .bar a:focus { color:#bb7a2a; } .tab { background-color:#0066FF; background-image:url(resources/titlebar.gif); background-position:left top; background-repeat:no-repeat; color:#ffffff; padding:8px; width:5em; font-weight:bold; } /* Navigation bar styles */ .bar { background-image:url(resources/background.gif); background-repeat:repeat-x; color:#FFFFFF; padding:.8em .5em .4em .8em; height:auto;/*height:1.8em;*/ font-size:1em; margin:0; } .topNav { background-image:url(resources/background.gif); background-repeat:repeat-x; color:#FFFFFF; float:left; padding:0; width:100%; clear:right; height:2.8em; padding-top:10px; overflow:hidden; } .bottomNav { margin-top:10px; background-image:url(resources/background.gif); background-repeat:repeat-x; color:#FFFFFF; float:left; padding:0; width:100%; clear:right; height:2.8em; padding-top:10px; overflow:hidden; } .subNav { background-color:#dee3e9; border-bottom:1px solid #9eadc0; float:left; width:100%; overflow:hidden; } .subNav div { clear:left; float:left; padding:0 0 5px 6px; } ul.navList, ul.subNavList { float:left; margin:0 25px 0 0; padding:0; } ul.navList li{ list-style:none; float:left; padding:3px 6px; } ul.subNavList li{ list-style:none; float:left; font-size:90%; } .topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { color:#FFFFFF; text-decoration:none; } .topNav a:hover, .bottomNav a:hover { text-decoration:none; color:#bb7a2a; } .navBarCell1Rev { background-image:url(resources/tab.gif); background-color:#a88834; color:#FFFFFF; margin: auto 5px; border:1px solid #c9aa44; } /* Page header and footer styles */ .header, .footer { clear:both; margin:0 20px; padding:5px 0 0 0; } .indexHeader { margin:10px; position:relative; } .indexHeader h1 { font-size:1.3em; } .title { color:#2c4557; margin:10px 0; } .subTitle { margin:5px 0 0 0; } .header ul { margin:0 0 25px 0; padding:0; } .footer ul { margin:20px 0 5px 0; } .header ul li, .footer ul li { list-style:none; font-size:1.2em; } /* Heading styles */ div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { background-color:#dee3e9; border-top:1px solid #9eadc0; border-bottom:1px solid #9eadc0; margin:0 0 6px -8px; padding:2px 5px; } ul.blockList ul.blockList ul.blockList li.blockList h3 { background-color:#dee3e9; border-top:1px solid #9eadc0; border-bottom:1px solid #9eadc0; margin:0 0 6px -8px; padding:2px 5px; } ul.blockList ul.blockList li.blockList h3 { padding:0; margin:15px 0; } ul.blockList li.blockList h2 { padding:0px 0 20px 0; } /* Page layout container styles */ .contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { clear:both; padding:10px 20px; position:relative; } .indexContainer { margin:10px; position:relative; font-size:1.0em; } .indexContainer h2 { font-size:1.1em; padding:0 0 3px 0; } .indexContainer ul { margin:0; padding:0; } .indexContainer ul li { list-style:none; } .contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { font-size:1.1em; font-weight:bold; margin:10px 0 0 0; color:#4E4E4E; } .contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { margin:10px 0 10px 20px; } .serializedFormContainer dl.nameValue dt { margin-left:1px; font-size:1.1em; display:inline; font-weight:bold; } .serializedFormContainer dl.nameValue dd { margin:0 0 0 1px; font-size:1.1em; display:inline; } /* List styles */ ul.horizontal li { display:inline; font-size:0.9em; } ul.inheritance { margin:0; padding:0; } ul.inheritance li { display:inline; list-style:none; } ul.inheritance li ul.inheritance { margin-left:15px; padding-left:15px; padding-top:1px; } ul.blockList, ul.blockListLast { margin:10px 0 10px 0; padding:0; } ul.blockList li.blockList, ul.blockListLast li.blockList { list-style:none; margin-bottom:25px; } ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { padding:0px 20px 5px 10px; border:1px solid #9eadc0; background-color:#f9f9f9; } ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { padding:0 0 5px 8px; background-color:#ffffff; border:1px solid #9eadc0; border-top:none; } ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { margin-left:0; padding-left:0; padding-bottom:15px; border:none; border-bottom:1px solid #9eadc0; } ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { list-style:none; border-bottom:none; padding-bottom:0; } table tr td dl, table tr td dl dt, table tr td dl dd { margin-top:0; margin-bottom:1px; } /* Table styles */ .contentContainer table, .classUseContainer table, .constantValuesContainer table { border-bottom:1px solid #9eadc0; width:100%; } .contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table { width:100%; } .contentContainer .description table, .contentContainer .details table { border-bottom:none; } .contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{ vertical-align:top; padding-right:20px; } .contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast, .contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast, .contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne, .contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne { padding-right:3px; } .overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption { position:relative; text-align:left; background-repeat:no-repeat; color:#FFFFFF; font-weight:bold; clear:none; overflow:hidden; padding:0px; margin:0px; } caption a:link, caption a:hover, caption a:active, caption a:visited { color:#FFFFFF; } .overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span { white-space:nowrap; padding-top:8px; padding-left:8px; display:block; float:left; background-image:url(resources/titlebar.gif); height:18px; } .overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd { width:10px; background-image:url(resources/titlebar_end.gif); background-repeat:no-repeat; background-position:top right; position:relative; float:left; } ul.blockList ul.blockList li.blockList table { margin:0 0 12px 0px; width:100%; } .tableSubHeadingColor { background-color: #EEEEFF; } .altColor { background-color:#eeeeef; } .rowColor { background-color:#ffffff; } .overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td { text-align:left; padding:3px 3px 3px 7px; } th.colFirst, th.colLast, th.colOne, .constantValuesContainer th { background:#dee3e9; border-top:1px solid #9eadc0; border-bottom:1px solid #9eadc0; text-align:left; padding:3px 3px 3px 7px; } td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { font-weight:bold; } td.colFirst, th.colFirst { border-left:1px solid #9eadc0; white-space:nowrap; } td.colLast, th.colLast { border-right:1px solid #9eadc0; } td.colOne, th.colOne { border-right:1px solid #9eadc0; border-left:1px solid #9eadc0; } table.overviewSummary { padding:0px; margin-left:0px; } table.overviewSummary td.colFirst, table.overviewSummary th.colFirst, table.overviewSummary td.colOne, table.overviewSummary th.colOne { width:25%; vertical-align:middle; } table.packageSummary td.colFirst, table.overviewSummary th.colFirst { width:25%; vertical-align:middle; } /* Content styles */ .description pre { margin-top:0; } .deprecatedContent { margin:0; padding:10px 0; } .docSummary { padding:0; } /* Formatting effect styles */ .sourceLineNo { color:green; padding:0 30px 0 0; } h1.hidden { visibility:hidden; overflow:hidden; font-size:.9em; } .block { display:block; margin:3px 0 0 0; } .strong { font-weight:bold; } ================================================ FILE: docs/repackaging.rst ================================================ Repackaging tool ================ In this section you will learn how to configure and use the repackaging tool to have your applications rewritten automatically to use the Grab'n Run library. The repackaging tool allows you to: * Rewrite your application to use Grab'n Run secure API instead of the standard Android ones. This process is automatic and requires only a couple of settings from your side. * Granular control on the security policy that you want your application to follow at run time when performing dynamic code loading (e.g., validate all the dynamically loaded code against one certificate, validate each container against a different certificate, decide whether to provide a default trusted certificate for all the not specified entries). This tool relies on `Androguard `_ to decoded, decompile, and rebuild the application provided as input. A prerequisite for using the tool is that your local machine must be able to have Internet connectivity since it will be necessary for the tool to download the source containers declared as potential sources for dynamic code loading unless they result directly accessible on the file-system of your machine. Another prerequisite is that you have already successfully installed `apktool `_ on your local machine. Use --- .. highlight:: bash 1. Open a terminal and move to the repackaging tool script *repackPOC* directory and then install the required dependencies:: $ cd /repackPOC $ pip install -r requirements.txt 2. Run the script:: $ python repackagingTool.py 3. For a list of the optional arguments:: $ python repackagingTool.py -h Configuration ------------- .. highlight:: java Before having the repackaging tool executed, you will have to go through a couple of windows to configure how you want your application to be patched. In particular: 1. You have to select which application, in the form of an APK container, you want to patch. 2. You have to provide the JAR or APK containers used as sources for dynamic code loading. 3. You need to specify a security policy that will be used to evaluate whether the containers used as sources are genuine at runtime. You can customize these settings easily thanks to a simple UI presented whenever the script is started. Step 1: Select the application to patch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Select the application you want to patch to use the secure Grab'n Run APIs. Notice that this application must be a regular APK file, which is stored locally on your machine. It is not required for this container to be aligned, or signed, but notice that you will *have to* sign, and then align the final application generated by the script in order to have it installed on the user's devices. If you are not familiar on how to *sign*, and *align* an APK, you may want to check the third bullet point of the "Quick example of use" section in the ``README`` file of the Grab'n Run repository on GitHub. Step 2: Select the containers sources for DCL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Next step is listing all the JAR, or APK containers used by your application as sources for dynamic code loading. Each container can be either stored locally (in this case indicate the absolute path on the file system), or remotely on an endpoint (in this case simply type the URL pointing to the file, and notice that both HTTP and HTTPS protocol are supported). .. warning:: In case of a JAR contianer, verify that you have already translated its content into Dalvik bytecode. Containers that have been gone through this process present a specific entry named ``classes.dex``. If you provide a container without such an entry, the repackaging tool will simply ignore it. The screenshot below shows the first screen of the UI with an example of a feasible configuration for Step 1 and Step 2. .. image:: images/RepackWin1.png Step 3: Configure the security policy for the source containers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once you confirm the settings in the first window, you will be prompted with a new screen to decide against which certificate each source container should be verified by Grab'n Run. At the moment we support three policies: a. Evaluate all the containers against one certificate. b. Evaluate each container against a different certificate. c. Provide a validation mapping, which has on the left side the prefix of the package name of the involved classes, and on the right side the corresponding certificate to use for the evaluation. The three screenshots below show an example of a valid configuration for each of the three policy. Switching from one to another is as simple as picking a different value in the drop-down menu box on top of the UI. .. image:: images/RepackWin2.png .. image:: images/RepackWin3.png .. image:: images/RepackWin4.png Some further considerations for this step: * You must provide each certificate through a remote reference to a secure endpoint containing such resource. The use of HTTPS protocol for the endpoint is required, and, if this is not the case, the repackaging tool will enforce it. * For the first two policies you can select as source containers either archives stored locally on your machine (use the absolute path of these resources on the file-system), or a remote endpoint containing such container (use its URL). In the latter case the repackaging tool will take care, when started, to retrieve these containers for further analysis. For these two policies, you can optionally also provide a default certificate that will be used for evaluating any other source container, which was not listed in the previous step but is used by your application at run time. * For the third policy the most restrictive package name prefix will be applied during the evaluation: This means that if your application wants to load code for a class, whose full name is ``com.example.myapp.MyClass``, and you have two entries in your mapping, one for ``com.example`` and the other for ``com.example.myapp``, the certificate associated to the latter one will be used since this entry has a longer prefix matching the name of the class to load. You should consider to use the last policy only if you are really aware of how the system works (see :doc:`tutorial`, and :doc:`complementary` for further details on the mapping process); in general, using one of the two first policies is already enough for most of the use cases, and it avoids pain from your side since the tool handles automatically the process of generating a validation mapping from your settings. Step 4: Gotta patch them all! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once you enter your settings and you press the "*Finish*" button, the repackaging tool will start its execution. If no error is raised, the patched APK will be available in the main folder where you launched the script from terminal (take extra care of having the original application in a different folder unless you want it to be overwritten by the patched version). I hope you will find this tool useful and I am eager to hear your feedbacks :) ================================================ FILE: docs/security.rst ================================================ Why should I use Grab'n Run? ============================ A significant question that every developer faces every time that (s)he adds a new library to his/her project is the following: "*Is it worthy to add this library? Does it provide something really necessary to my project?*" In this specific case those two questions can be reformulated as follows: "*Aren't Android API already able to handle dynamic class loading? Why should I use for example* ``SecureDexClassLoader`` *in stead of the regular* ``DexClassLoader`` *? Does it really enhance the standard class with something relevant?*". To answer all of these questions let us consider the case of choosing ``SecureDexClassLoader``, one of the classes provided by **Grab'n Run**, in stead of `DexClassLoader `_, the standard class provided by the Android API, to *dynamically load* **.dex classes** into your Android application at run time. First of all ``SecureDexClassLoader`` provides a couple of slight but significant **improvements** over the standard class in terms of **functionalities**: * ``SecureDexClassLoader`` lets you retrieve *dynamically* also classes from *.jar* and *.apk* containers which are **not located directly on the phone** running the application as long as you simply provide a **valid remote URL** for the resource, while ``DexClassLoader`` is only able to cache classes from containers stored on the phone. * ``SecureDexClassLoader`` is a **thread-safe** library and so, after that you have created your ``SecureDexClassLoader`` instance on the main thread of your application, you can launch different threads, each one performing dynamic class loading on the very same ``SecureDexClassLoader`` instance **without** incurring in nasty **race conditions** and **concurrencies exceptions**. In addition and above all ``SecureDexClassLoader`` ensures relevant **security features** on classes that you dynamically load that are not possible to check or implemented with ``DexClassLoader`` like: * **Fetch remote code in a secure way**: ``SecureDexClassLoader`` retrieves remote code either via HTTP or HTTPS protocol. In both cases it **always verifies** and validates the downloaded containers **before actually loading classes** inside of them. * **Store containers in secure application-private locations**: `SecureDexClassLoader`` also **prevents** your application from being a possible target of **code injection attacks**. This attack becomes feasible whenever you use the standard ``DexClassLoader`` and you provide as an optimized cache folder for *dex* files a directory which is located in a **world writable area** of your phone (i.e. external storage) or you decide to load classes from a container which is, once again, stored in a world writable folder. ``SecureDexClassLoader`` on the other hand manages this situation for you by choosing *application-private directories* for caching *dex* files and storing containers and certificates. This strategy represents an **effective** way to make the **attack infeasible**. * **Developer authentication**: for each package containing classes to be loaded dynamically it is possible to ensure authentication of the developer who coded those classes though a *check of the signature on the container* of the classes against the *certificate of the developer* (which could possibly be even *self-signed*). **Non-signed** classes or those who were not signed by that required certificate will be rejected and **prevented from being loaded**. * **Integrity**: during the *signature verification* process whenever one of the entries inside the container results to be *incorrectly signed*, ``SecureDexClassLoader`` recognized a **possible tampered or repackaged container** and it prevents your application from running the code of any classes inside this invalid and possible malicious container. And these improvements come with a **convenient overhead** on the **performance** :) This is possible since ``SecureDexClassLoader`` was implemented with an accurate **caching system** that, from one side, *prevents* your application **from continuously downloading** the same *jar* and *apk* **containers and certificates** and, from the other side, **avoid** it from **verifying every time** *the signature and the integrity* of already **checked containers**. Moreover, for even *more performance concerned developers*, it is also possible to set the **strategy** which is going to be used by ``SecureDexClassLoader`` to **validate classes** before attempting to load them. In particular **two** options are provided: 1. **Lazy Strategy**: this mode implies that the **signature and integrity** of each container will be **evaluated only when** the ``loadClass()`` method will be invoked on *one of the classes*, whose package name is linked to this container. An ideal case of use for this mode is when you have quite a lot of containers and just a couple of classes to load, which may also vary from one execution to another and so validating all the containers in this case may be a waste of time. 2. **Eager Strategy**: in this mode the process of **signature and integrity** will be carried out on **all** the containers **immediately and concurrently** before returning an instance of ``SecureDexClassLoader``. This choice implies that you will have to pay an **initial penalty (but still reduced since the verification process is driven concurrently among the containers)** on time of execution but then the time required for a ``loadClass()`` operation becomes almost equal to the corresponding operation performed with standard ``DexClassLoader``. **By default eager strategy** is applied but developers can *pick* the *lazy version* by adding a final ``true`` attribute to the ``createDexClassLoader()`` method invocation in ``SecureLoaderFactory``. An example of use is shown in the following snippet of code (this is just a *slight modification* of one of the calls that you may have seen in :doc:`tutorial` ):: SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( jarContainerPath, null, getClass().getClassLoader(), packageNamesToCertMap, true); ================================================ FILE: docs/tutorial.rst ================================================ Quick start and tutorial ======================== In this section you will see how to *retrieve and include Grab'n Run library* into your project (either by using Android Studio ot the Android Development Tool). After this setup step a **brief tutorial** will explain how to use classes in the library to **secure** the *dynamic code loading operations*. Since this section is **introductory** and more descriptive, it should be read by those who are not familiar with this library or more in general with *class loading* in Android. On the other hand the :doc:`complementary` section provides a more complete and detailed view on *Grab'n Run* library and its insights, while :doc:`example` shows a simple use case of the concepts introduced here. Quick Setup ----------- Setting up GNR as an **additional library** for your *Android application* is very easy: Android Studio (AS) ~~~~~~~~~~~~~~~~~~~ .. highlight:: groovy 1. Modify the *build.gradle* file in the *app* module of your Android project by adding the following *compile* line in the *dependencies* body:: dependencies { // Grab'n Run will be imported from JCenter. // Verify that the string "jcenter()" is included in your repositories block! compile 'it.necst.grabnrun:grabnrun:1.0.4' } 2. Resync your project to apply changes. Android Development Tool (ADT) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Download the latest `version `_ of the *JAR* container of Grab'n Run. 2. Include the *JAR* in the **libs** subfolder of your Android project. Adding missing permissions (Both AS and ADT) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. highlight:: xml Finally it is required to modify the *Android Manifest* of your application by adding a couple of required permissions if they are not already in place:: ... .. highlight:: java Tutorial -------- This tutorial assumes that you have **already retrieved Grab'n Run and linked it** to one of your existing Android projects. Using standard DexClassLoader to load code dynamically ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Let us pretend that you want to dynamically load an external class through `DexClassLoader `_, a class in the *Android API* used to load classes from *jar* and *apk* files containing a **classes.dex** entry. This is a convenient way to execute code not installed as part of an application package. Let's assume, for example, that you want to load an instance of ``com.example.MyClass`` located in the container *exampleJar.jar*, stored in the *Download* folder of the sd_card on the target phone. Note that this scenario may potentially lead to a **code injection** attack when you use the standard ``DexClassLoader`` since you are choosing to load code from a container which is stored in a **world writable location** of your phone. Notice that this kind of attack would be prevented with ``SecureDexClassLoader``. Anyway a snippet of code to achieve this task is the following:: MyClass myClassInstance = null; String jarContainerPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download/exampleJar.jar"; File dexOutputDir = getDir("dex", MODE_PRIVATE); DexClassLoader mDexClassLoader = new DexClassLoader( jarContainerPath, dexOutputDir.getAbsolutePath(), null, getClass().getClassLoader()); try { Class loadedClass = mDexClassLoader.loadClass("com.example.MyClass"); myClassInstance = (MyClass) loadedClass.newInstance(); // Do something with the loaded object myClassInstance // i.e. myClassInstance.doSomething(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } The String ``jarContainerPath`` contains the path to *examplejar*, while ``dexOutputDir`` is an **application-private**, writable directory to cache optimized *dex* classes into *examplejar*. As reported in ``DexClassLoader`` documentation, you can retrieve ``dexOutputDir`` in different ways but it is fundamental that this cache folder is application-private; otherwise your application may be subjected to **code injection attacks**. And by the way this kind of attack is *prevented* if you choose to use ``SecureDexClassLoader`` as explained later on in this guide. The object ``mDexClassLoader`` is then initialized as a ``DexClassLoader`` instance, which loads all the classes into *examplejar* and caches their optimized version into ``dexOutputDir``. No native library is included since the third parameter of the constructor is ``null`` and the `ClassLoader `_ of the current activity is passed as parent class loader. Finally the designated class is, at first, loaded by invoking the ``loadClass()`` method on ``mDexClassLoader`` with the **full class name** provided as a parameter and, secondly, instantiated through the ``newInstance()`` method and the forced casting to ``MyClass``. The three different **catch blocks** are used to handle different exceptions that may be raised during the process. **Package Name** In Java every class is associated to a **package name**. A **package** is a *grouping of related classes, interfaces and enumerations* providing **access protection** and **name space management**. In particular in *Grab'n Run* packages names are accepted if and only if they are *a sequence of at least two not-empty, dot-separated words, which starts and ends with a word, not with a dot*. This implies that the following are all examples of **invalid** package names: ``com``, ``.com.application``, ``com..application``, ``com.application.``, while **suitable** package names are ``com.application`` or ``it.polimi.necst.gnr``. As you will see later on in this tutorial, package names perform a **relevant functionality** in **GNR** system since they *link containers to be verified with the certificate used to do so*. .. warning:: Notice that a **full class name** is required to successfully load a class and so the **complete package name** separated by dots must **precede** the **class name**. Referred to the example, full class name is ``com.example.MyClass`` and not just the short class name ``MyClass``, which would produce a failure in the class loading operation. In particular if it is the case that a short class name is provided in stead of a full one, it is likely that a ``ClassNotFoundException`` will be raised at runtime. This snippet of code is perfectly fine and working but it is **not completely secure** since neither integrity on the container of the classes, neither authentication on the developer of the container are checked before executing the code. And here comes ``SecureDexClassLoader`` to solve these issues. .. _Using SecureDexClassLoader to load dynamic code securely: Using SecureDexClassLoader to load dynamic code securely ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to improve the security of the snippet of code shown in `Using standard DexClassLoader to load code dynamically`_ a new version of the code is presented through the use of ``SecureDexClassLoader`` and ``SecureLoaderFactory``. At first you should create a ``SecureLoaderFactory`` object as shown here:: SecureLoaderFactory mSecureLoaderFactory = new SecureLoaderFactory(this); This is an helper class necessary to generate a ``SecureDexClassLoader`` object. But before performing this step you have to initialize and provide to ``mSecureLoaderFactory`` an **associative map** which links all the package names of the classes that you want to dynamically load to one *developer certificate*, which is stored at a **secure web location** (i.e. an HTTPS link) and which was previously used to sign the *jar* or *apk* container which holds those classes. **Developer Certificate** a certificate, which in Android can be even *self-signed*, used to sign all the entries contained in a *jar* or in an *apk* container. Notice that in the Android environment in order to run an application on a smart phone or to publish it on a store, the *signing step* is **mandatory** and can be used to check that an *apk* was actually written and approved by the issuer of the certificate. For more details on signing applications and certificate, please check `here `_. So in this example we assume that all the classes belonging to the package ``com.example`` have been signed with a self-signed certificate, stored at ``https://something.com/example_cert.pem``. Since here you just want to load ``com.example.MyClass`` the following snippet of code is enough:: Map packageNamesToCertMap = new HashMap(); try { packageNamesToCertMap.put( "com.example", new URL("https://something.com/example_cert.pem")); } catch (MalformedURLException e) { // The previous URL used for the packageNamesToCertMap entry was a malformed one. Log.e("Error", "A malformed URL was provided for a remote certificate location"); } .. note:: Any *self-signed certificate* can be used to validate classes to load as long as it is not expired and it suits the standard `X509 Certificate `_ format. The only exception is represented by the **Android Debug Certificate**, a certificate used to sign applications before running them in debug mode and not safe to use during production phase. ``SecureDexClassLoader`` has been instructed to automatically reject class loading for classes whose package name has been associated for signature verification to the **Android Debug Certificate** and so **DO NOT USE IT** to check the signature of your containers. .. note:: You may want to insert more than one entry into the associative map. This is useful whenever you want to use the same ``SecureDexClassLoader`` to load classes which belong to different packages. Still remember that each package name can only be associated with **one and only one** certificate location. Pushing into the associative map an entry with an already existing package name will simply overwrite the previously chosen location of the certificate for that package name. .. warning:: For each entry of the map only an **HTTPS** link will be accepted. This is necessary in order to **avoid MITM (Man-In-The-Middle)** attacks while retrieving the *trusted* certificate. In case that an **HTTP** link is inserted, ``SecureLoaderFactory`` will enforce *HTTPS protocol* on it and in any case whenever no certificate is found at the provided URL, no dynamic class loading will succeed for any class of the related package so **take care to verify** that certificate URL is correctly spelled and working via **HTTPS** protocol. Now it comes the time to initialize a ``SecureDexClassLoader`` object through the method ``createDexClassLoader()`` of ``SecureLoaderFactory``:: SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( jarContainerPath, null, getClass().getClassLoader(), packageNamesToCertMap); ``mSecureDexClassLoader`` will be able to load the classes whose container path is listed in ``jarContainerPath`` and it will use the ``packageNamesToCertMap`` to retrieve all the required certificate from the web and import them into an application private certificate folder. Also notice that in this case no directory to cache output classes is needed since ``SecureDexClassLoader`` will automatically reserve such a folder. .. warning:: As stated in the `API documentation `_ ``jarContainerPath`` may link many *different containers* separated by ``:`` and for such a reason the **developer is responsible** of filling the associative map of the certificates location accordingly with all the entries needed to cover all the package names of the classes to be loaded. .. note:: ``DexClassLoader``, the standard class from Android API, is able to parse and import only those *jar* and *apk* containers listed in ``jarContainerPath`` which are directly saved on the mobile device storage. In addition to this ``SecureDexClassLoader`` is also capable of **downloading remote containers** from the web (i.e. **HTTP or HTTPS URL**) and to import them into an application-private directory to avoid code injections from attackers. Example:: jarContainerPath = "http://something.com/dev/exampleJar.jar"; This ``jarContainerPath`` will retrieve no resource when used in the constructor of ``DexClassLoader`` but it is perfectly fine as a first parameter of the ``mSecureLoaderFactory.createDexClassLoader()`` call, as long as a *jar* container is actually stored at the remote location. Finally you can use the resulting ``mSecureDexClassLoader`` to load the desired class in a similar fashion to ``DexClassLoader``:: try { Class loadedClass = mSecureDexClassLoader.loadClass("com.example.MyClass"); // Check whether the signature verification process succeeds if (loadedClass == null) { // One of the security constraints was violated so no class // loading was allowed.. } else { // Class loading was successful and performed in a safe way. myClassInstance = (MyClass) loadedClass.newInstance(); // Do something with the loaded object myClassInstance // i.e. myClassInstance.doSomething(); } } catch (ClassNotFoundException e) { // This exception will be raised when the container of the target class // is genuine but this class file is missing.. e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } It is important to notice that, differently from ``DexClassLoader``, the ``mSecureDexClassLoader.loadClass()`` call will return ``null`` whenever **at least one of the following security constraints is violated**: * The *package name* of the class used as a parameter of ``loadClass()`` was **not previously included in the associative map** and so it do not exist any certificate that could be used to validate this class. * The *package name* of the class used as a parameter of ``loadClass()`` was previously included in the associative map but the **related certificate** was **not found** (URL with no certificate file attached or no connectivity) or **not valid** (i.e. expired certificate, use of the Android Debug Certificate). * The *container file* of the required class was **not signed**. * The *container file* of the required class was **not signed with the certificate associated** to the package name of the class. [Missing trusted certificate] * At least one of the **entry** of the *container file* do **not match its signature** even if the certificate used to sign the container file is the trusted one. [Possibility of **repackaged container**] For all of these reasons you should always check and pay attention when a **null** pointer is returned after a ``mSecureDexClassLoader.loadClass()`` call since this is a clear clue to establish either a wrong set up of ``SecureLoaderFactoty`` and ``SecureDexClassLoader`` or a security violation. *Informative and debug messages* will be generated in the logs by the classes of the Grab'n Run library in order to help you figure out what it is happening. .. note:: Every time that ``SecureDexClassLoader`` finds out a (possibly repackaged) **invalid container**, it will immediately **delete** this file from its **application-private directory**. Nevertheless if this container is *stored on your device* it may be a good idea for you, as a developer, after having double checked that you have properly set up ``SecureDexClassLoader``, to **look for a fresh copy** of the container or at least **not to trust** and delete this container from the phone. Please notice, on the other hand, that the three exceptions caught in the try-catch block surrounding the ``loadClass()`` method behaves and are thrown in the same way as it would happen with ``DexClassLoader``. Finally for clarity the **full snippet of code** presented in this section is reported here:: MyClass myClassInstance = null; jarContainerPath = "http://something.com/dev/exampleJar.jar"; try { Map packageNamesToCertMap = new HashMap(); packageNamesToCertMap.put( "com.example", new URL("https://something.com/example_cert.pem")); SecureLoaderFactory mSecureLoaderFactory = new SecureLoaderFactory(this); SecureDexClassLoader mSecureDexClassLoader = mSecureLoaderFactory.createDexClassLoader( jarContainerPath, null, getClass().getClassLoader(), packageNamesToCertMap); Class loadedClass = mSecureDexClassLoader.loadClass("com.example.MyClass"); // Check whether the signature verification process succeeds if (loadedClass == null) { // One of the security constraints was violated so no class // loading was allowed.. } else { // Class loading was successful and performed in a safe way. myClassInstance = (MyClass) loadedClass.newInstance(); // Do something with the loaded object myClassInstance // i.e. myClassInstance.doSomething(); } } catch (ClassNotFoundException e) { // This exception will be raised when the container of the target class // is genuine but this class file is missing.. e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (MalformedURLException e) { // The previous URL used for the packageNamesToCertMap entry was a malformed one. Log.e("Error", "A malformed URL was provided for a remote certificate location"); } Wiping out cached containers and certificates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to *improve performance* and offer the possibility to *partially work also when connectivity is limited*, ``SecureDexClassLoader`` will store certificates retrieved from the web and all containers into specific **application-private directories**. Every time that a **resource** (container or certificate) is needed to load or verify a class, ``SecureDexClassLoader`` will at first look for it inside its private directories and then, if no match is found, possibly attempt to download it from the web or found it at a specified location on the device (this last option is applicable only for containers). .. It was also stated into `Using SecureDexClassLoader to load dynamic code securely`_ that, differently from .. ``DexClassLoader``, ``SecureDexClassLoader`` is also able to **download and import remote containers** into an .. *application-private folder*. Even if these **caching features** may come really useful and *speed up* significantly ``SecureDexClassLoader`` execution, it would be also nice for the developer to have the possibility to **choose** whether a **fresh or cached copy** of either a certificate or a container should be used for the *dynamic loading operations*. And that is the reason why ``SecureDexClassLoader`` provides a method called ``wipeOutPrivateAppCachedData()`` to manage this choice. To present this method let us consider again the previous scenario shown in `Using SecureDexClassLoader to load dynamic code securely`_: after having tried to load ``com.example.MyClass``, if you want to *delete both the cached certificates and the containers* used by the related ``mSecureDexClassLoader``, in order to impose for the next loading operation the retrieval of **fresh resources**, the call to perform is the following:: mSecureDexClassLoader.wipeOutPrivateAppCachedData(true, true); .. warning:: After that you *have erased at least one cached resource between the certificates and the containers*, ``mSecureDexClassLoader`` will always return ``null`` for **consistency reason** to any invocation of the ``loadClass()`` method. So it will be **necessary** for you to require a **new** ``SecureDexClassLoader`` instance to ``SecureLoaderFactory`` through the invocation of the ``createDexClassLoader()`` method before being able to dynamically and securely load other classes. ================================================ FILE: downloads/1.0/gnr-1.0.jar.sha1 ================================================ 26de8ca9e32987d5d5094c432ad7480b09b134b4 gnr-1.0.jar ================================================ FILE: downloads/1.0.1/gnr-1.0.1.aar.sha1 ================================================ 10e18e6c5e14ebfbb075a746334d1722040c59f6 gnr-1.0.1.aar ================================================ FILE: downloads/1.0.1/gnr-1.0.1.jar.sha1 ================================================ c56ebdfc50ae227aa85f0aaf2d4559dadce076e3 gnr-1.0.1.jar ================================================ FILE: downloads/1.0.2/gnr-1.0.2.aar.sha1 ================================================ 2d1d9bc079ae9908ce1f7b8c826ee8f0657aa40b gnr-1.0.2.aar ================================================ FILE: downloads/1.0.2/gnr-1.0.2.jar.sha1 ================================================ 330385bd0e67a8b0b83048577d995c916aae7de2 gnr-1.0.2.jar ================================================ FILE: downloads/1.0.3/grabnrun-1.0.3.aar.sha1 ================================================ b6b10ea1c67856374830a07080a02dcbe973ba6d ================================================ FILE: downloads/1.0.3/grabnrun-1.0.3.jar.sha1 ================================================ 8802180428e8783339a77484bfa45a74021c5b54 grabnrun-1.0.3.jar ================================================ FILE: downloads/1.0.4/grabnrun-1.0.4.aar.sha1 ================================================ cc06e36eeb7104b5cc0fa555c668990b027bf53a ================================================ FILE: downloads/1.0.4/grabnrun-1.0.4.jar.sha1 ================================================ 9e849b9adbf0ca3c48ac8d71704753a885a8ede2 grabnrun-1.0.4.jar ================================================ FILE: example/ADT/.classpath ================================================ ================================================ FILE: example/ADT/.gitignore ================================================ /.settings/ /bin/ /gen/ ================================================ FILE: example/ADT/.project ================================================ ExampleAppGNR com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: example/ADT/AndroidManifest.xml ================================================ ================================================ FILE: example/ADT/lint.xml ================================================ ================================================ FILE: example/ADT/proguard-project.txt ================================================ # To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: example/ADT/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-19 android.library=false ================================================ FILE: example/ADT/res/layout/activity_dex_class_sample.xml ================================================