Tuesday, April 2, 2019

Tool Release: android-setools

I haven't been the best about updating my tools or blog in the past 12 months, I know. Behind the scenes, however, I've continued to perform embedded device research (not just Android!), and still try to maintain a toolset that works. In 2018, I  spoke at ANYCON on my continued research on SEAndroid. For those unfamiliar, this has been a focus of mine since 2016 when I realized how much of an impact SEAndroid was having on the threat landscape of Android devices. In 2017, I started creating tools to process and navigate the SEAndroid details from a given device (part of my dtf project, which hasn't gotten much love lately). I realized fairly quickly that the process of analyzing the SEAndroid policy on a given device unexpectedly tricky. In fact, I still have to reference the extremely verbose answer provided by StackOverflow user WhiteWinterWolf when answering the question: How can I parse v30 SELinux policies for Android?

Why does that matter today? Because it's still not easy.

Parsing SEAndroid, How Hard Can It Be?

It's not easy because Google has decided to fork the SELinux project and alter the project to suit the needs of the Android operating system. There's nothing inherently wrong with this and the features added by Google make a lot of sense. The problem is that they don't expect anyone else to build the tools to interact with their fork of SELinux (called "setools"). This is unfortunate, because this is exactly what I want to do when analyzing the policy from a new device that I did not develop.

"setools" as a project provides a number of utilities that operate on the binary SELinux policy file. These utilities (implemented as a Python module with SWIG bindings) allow you to diff policies ("sediff"), extract metadata ("seinfo"), and run queries to answer questions about the policy ("sesearch"). "sesearch" is extremely useful for determining powerful contexts, locating mis-configurations, and a general understanding of the given policy. I think it's sufficient to say that these tools are required if your goal is to understand a device's SELinux policy or stage a more serious attack.

I recently needed to rebuild my Android device testing environment and realized - I'm going to need to follow WhiteWinterWolfs tutorial on how to build the tools again. To summarize his lengthy response, you need to:
  1. Create and configure a Ubuntu VM where you will build Android. The current approved version of Ubuntu for building is Ubuntu 4.04 LTS, which is not suitable for actual testing.
  2. Clone the Android Open Source Project ("AOSP") for a version of Android. This can ultimately consume 30-60 GB of storage space post-build and takes hours to clone. Also, WhiteWinterWolfs answer references the now defunct Cyanogenmod and Android 6.0 branches. This is also not ideal for modern devices, as Android made some breaking changes in 7.0.
  3. Build portions of Android, then specifically build and install the SELinux components. This is not something most users will end up doing, which results in 2 problems:
    • This is something usually Google would do, so you're going to have to probably patch and troubleshoot as you slowly build the tools. For 7.0 or newer, you actually will need to patch/modify broken files, since they do not compile normally.
    • This installs the newly-ported SELinux libraries locally. Remember that I mentioned Google recommends building with 14.04? This means you either need to use 14.04 as a base (bad idea), or somehow move them to a newer distribution. Also not a great idea.
  4. Download and compile an old "beta" version of "setools" 4.0.0, which will link against the currently installed SELinux binaries (which you built in Step 3). This version is now 2+ years old, and will not work for devices 7.0 forward.
After hours of troubleshooting, building, and banging your head against a wall, you can finally start answering questions about the SEAndroid policy of your test device offline, but it's not a great workflow. I wanted something better, which is the reason for this post.

The Solution: android-setools

Since I recently went through the process of recreating the environment to generate the tools I needed (which includes "sesearch", "seinfo", and "sediff"), I decided to take a more long-term approach. This time around, I took note of what each step in WhiteWinterWolf's tutorial was actually doing, and brainstormed a way to make the process more streamlined. The result was a Debian package ("DEB") along with a Makefile that streamlines the process, and drops the lengthy dependencies needed. The project is called "android-setools", and it's currently on my Github.

With "android-setools", you no longer need to build an Android building environment, clone the AOSP tree, or patch random files until things compile correctly. You can simply install a few building dependencies, clone my repo, and use the Makefile to get started. The build is also tested through Ubuntu 18.04, so you can do it from your main test environment. Finally, since I needed both pre-7.0 and 7.0+ to work, I included make tasks for both of these situations. You unfortunately cannot use both at the same time (suggestions welcome), but at least rebuilding is easy and painless. Once built, you can use "sesearch", "sediff", seinfo", and others just like you normally would for standard SELinux policies.

I've provided instructions to use the tool in the README.md file for the project. While the solution is not perfect, it will definitely reduce the time needed to prep an environment to probably 5 minutes. Questions, feedback, or bug fixes are of course welcome on the Github's issue tracker. I hope this utility will be helpful for people and good luck navigating through SEAndroid!

Saturday, October 21, 2017

Tool Release: sefcontext-parser / sefparse

Recently I've been diving deeper into SEAndroid and building tools to map out a given device's policy, mostly for identifying vulnerabilities. This content has made its way into dtf modules.

As I was preparing my slides for ArcticCon 2017, I realized that I was missing the ability to parse the new compiled "file_contexts" format that was introduced in Android Nougat. Before Nougat, this file was text-based and writing a parser was trivial. This newer format is a little more involved, but is still documented by Google. This file is still typically found in the rootfs ("/"), but has been renamed from "file_contexts" to "file_contexts.bin".

There are already some existing tools out there for parsing this format, notability here, here, and here, but some are part of an existing project and all (that I could find) are written in C. With dtf, I'm trying to stay away from using compiled tools, in favor of a more cross-platform friendly Python/Java combination. This inspired me to code up a quick parser in Python, which is now available from my GitHub. It has also been merged into dtf and will automatically perform the decoding when processing the SE database.

There should be enough information in the README to get curious users started, and running the tool is straight forward. Any issues or feature requests can be submitted on the project's Issues tracker. 

Monday, December 14, 2015

Attacking Bound Services on Android

Many times when exploring a new Android device, I encounter exported Services that expose a Binder interface, known as "bound Services".  Unlike an unbound Service, we can't just use the `am` command to interact with the Service; rather, we'll need to actually create an Android application.  Creating a client to connect to a bound Service can be tricky even with the Service's source code, and without it can be even more confusing. There are plenty of blogs and tutorials that talk about creating bound Services, but I couldn't find any focus on interacting with bound Services from an attacker's perspective (no source).

In this post I'll create an application that exposes a bound Service, show you how to find and interpret bound Services in an application's disassembled Smali code, and present a tool to automate AIDL reconstruction.  This post will not be an in depth description of bound Services.

Creating the Bound Service in Java

First, we'll create an application, "com.jakev.boundserver" that defines our exported bound Service. This bound Service will support a single method, called "exec()", that accepts a command as a String, and executes it, and returns the output (please do not actually add this to your applications). The source code for this project (and APK) can be downloaded from the links at the end of this post.

We'll create the bound Service in 3 steps:
  • Declaring the new component in the "AndroidManifest.xml"
  • Creating the Android Interface Definition Language ("AIDL") interface
  • Creating a new Service class and implementing the "onBind()" method

In our AndroidManifest.xml we declare a new exported Service, ".ITestService":



Next, we create our AIDL interface, called "com.jakev.boundserver.aidl.TestInterface".  As described above, our "exec()" method will accept a single String argument, and return a String value:


Last, we create our Service class "com.jakev.boudserver.ITestService.java".  We need to implement the "onBind()" method, and return an instance to our "TestInterface" interface created above:


In order to interact with this Service, we'll need to create an application and include the AIDL file above.  As a developer, we'd probably distribute a JAR library that contains the AIDL file "TestInterface.aidl" and other supporting classes so that others can develop applications to interface with our new Service. As an attacker, we will likely not have this luxury.

Exploring the Service APK

Let's assume we find the "com.jakev.boundserver" application installed on a device, and stumble on this exported ".ITestService" Service.  We don't have the source code for the application; we just have the APK.  Let's pull the application and unpack it with `apktool`:


As a first step, let's look our ".ITestService" Service class, found at "smali/com/jakev/boundserver/ITestService.smali".  The "onBind()" method is pretty straightforward, and we can see that the Service is instantiating an inner class, "ITestService$1", and returning it.  This is due to the way we called the "new TestInterface.Stub() { }" above.


Opening "smali/com/jakev/boundserver/ITestService$1.smali" shows that the class is implementing a class "com.jakev.boundserver.aidl.TestInterface$Stub", which we have not looked at yet.  In the virtual methods section we see the actual implementation of the "exec()" method.  As a reverse engineer, you'd likely start with this method for determining the capabilities of the "exec()" method.


Next, let's look at what happened to our AIDL file.  There are now 3 different classes, called "TestInterface.smali", "TestInterface$Stub.smali", and "TestInterface$Stub$Proxy.smali", shown below.


Android Studio was nice enough to generate these for us when we built our application. There are plenty of papers that talk about the exact role of each of these, so I wont spend a lot of time talking about that.  The key takeaways here are:

  • The "TestInterface" class will always implement the "android.os.IInterface" class. It contains an abstract definition of each of the Binder methods.
  • The "TestInterface$Stub" class will always implement the "android.os.Binder" class, and contains the Binder transaction identifiers stored as fields.  The naming convention looks like "TRANSACTION_{methodName}".  These are the same ID fields used when calling services with the `service` command-line utility.
  • The "TestInterface$Stub$Proxy" class doesn't implement or extend any class, but contains the return type and parameter information for each Binder method.
You can use the following searches for if you're looking at a new application and want to enumerate Binder interfaces and their method implementation:

Finding any AIDL classes:
grep -r "super.*IInterface" ./smali

Finding implementation of AIDL:
grep -r "super.*${AIDL class from above}" ./smali

With these pieces of information, we can reconstruct the AIDL, and include this in our client application. You can do this manually, or you can use a tool I've created called 'GenerateAIDL.jar' that uses the DexLib2 library to parse an application's DEX code and outputs AIDL files that you can quickly add to your Service client.


If we open this file, we should see a AIDL interface similar to the one we created above:


Keep in mind this is just a trivial example.  There likely will be more than one method (and possibly some imported libraries) in a real-world example.

Attacking Bound Services

Now we're going to use the AIDL we just generated above to create a client application, "com.jakev.serverclient" that interacts with the ".ITestService".  I've tried to make this project as generic as possible, so it can be reused with ease.

The first step is to actually create/import our AIDL.  We want to add the AIDL we generated above to the proper folder, being mindful of the package name:


Next, we'll modify the "MainActivty" class I've created as a template.  First, add the AIDL above as an import, and add an object of this class called "service":


Next, change the class name of the Intent created in the "initService()" method, to the service you're interacting with:


Finally, we modify the "onServiceConnect()" method of our local "ServiceConnection" class to actually interact with the bound Service.  In this example, we're calling the "exec()" method, and supplying the "id" command, then recording this value in the Android logs.


If we build, install, and run our client application, we should see the output of the `id` command in the logs:


Conclusions

Given the correct permissions, an attacker can interact with bound Services just like other components.  It is important to inventory your application and confirm that the components that are exported are the ones you actually want exported.  For any component that performs sensitive actions (such as executing commands!!), make sure you apply the correct permissions.

Resources

  • http://stackoverflow.com/questions/15330233/remote-service-with-aidl-file-serviceconnection-never-called
  • http://developer.android.com/reference/android/content/ServiceConnection.html
  • http://developer.android.com/guide/components/bound-services.html
  • http://developer.android.com/guide/components/aidl.html
  • https://newcircle.com/s/post/48/implementing_remote_interface_using_aidl

Downloads

Friday, May 29, 2015

Hooking SQLCipher with Xposed

Recently, a coworker of mine approached me regarding an Android application that was using the SQLCipher library.  For those unfamiliar with SQLCipher, it provides "transparent, secure 256-bit AES encryption" of Android SQLite3 databases, which is something that many security professionals recommend (myself included).  In order to see the actual data inside the database, it is often necessary to obtain the password used to perform the encryption, which can be tricky if it is not just in plain-text in the APK.

@MDSecLabs wrote a blog post a little over a year ago that describes how the SQLCipher library works, and how it is possible to obtain database encryption keys using the CydiaSubstrate, a hooking framework.  They also provide a Cydia "tweak" that can be used to steal the SQLCipher encryption key used by an application (for testing purposes), which is exactly what my coworker was interested in!

Unfortunately, the CydiaSubstrate doesn't always work on all devices (in my experience), and doesn't overall seem as maintained as the Xposed framework, which accomplishes roughly the same goal.  After downgrading his test device from Lollipop (to Jelly Bean) and installing the MDSec Cydia tweak, he was still unable to get the secret key to print in the log buffers, even though the test application provided by MDSec worked fine.  What gives?

It turns out that the SQLCipher library has changed a bit since MDSec created their tweak, and there are now new overloaded variants of the "openOrCreateDatabase" method, which is what MDSec is attempting to hook (you can see the current methods here).  Depending on how the application you're testing uses the SQLCipher API, you may see the key printed in the logs.

I did some quick Googling and did not see an Xposed version of the MDSec tweak, so I decided to write my own variation.  To use it, you'll need a rooted device and the Xposed framework installed.  You can download the APK from my GitHub.

Now, you can install the APK, reboot your device, and use your SQLCipher enabled app as you normally would. In a different window, check the logcat buffers for the secret key used by the application.  Here are the contents of the log buffers when running the MDSec MyEncryptedApp test application.


Thanks to MDSec for doing the research in determine the appropriate method to hook and for creating the Cydia tweak.  If anyone has any questions or feature requests, feel free to reach out to me!

Links

Monday, February 3, 2014

Is Facebook Really Reading your Text Messages?

The Internet was abuzz last week with news concerning Facebook's recently added permission to access your text messages from their Android application.  This didn't seem to sit well with a lot of people, and now people are afraid to update the application or are choosing to remove the mobile application altogether.  I was shocked to find at least half a dozen news articles talking about how Facebook is now "reading your texts, pictures, and calendars," with absolutely no technical backing besides the fact the application now asks for the permission.  In fact, the only thing remotely close to technical was Facebook's response to whole thing, where they explain why their app does this:


But of course in the midst of all the NSA and related news, everyone put their tinfoil hats on and is a bit skeptical on the whole deal.  I do think it's fine to question things like this, but there does need to be some closure on the whole thing.  I decided to take a look at the Facebook mobile app and see whats really going on.

Before going any further I'd like to make a few things clear.  First, I don't work for Facebook, and I'm not trying to bash them in any way.  I also have no malicious intent of exposing the company; I'm simply trying to demonstrate on a technical level what this change means.  If you're someone who doesn't care for all the technical fun stuff, skip right to the conclusions section.

So with that, let's get started!

I first downloaded the most recent version of the Facebook mobile application (version 5.0.0.26.31) to a test device, and then pulled the application to my testing machine.  A quick check confirmed that this application does in fact ask to read SMS messages:


What does this mean?  This means that the application is permitted to access the Android ContentProvider URLs "content://sms", "content://mms," and "content://mms-sms," the databases containing your SMS and MMS data.  It does not allow the application to intercept incoming text messages or send them (regardless of what Kaspersky claims).  These actions require the permissions "android.permission.RECEIVE_SMS" and "android.permission.SEND_SMS," respectively.  This application did not ask for permission to do these actions.

I unpacked the APK with apktool and was surprised to find that the application did not obfuscate the class names.  It did obfuscate class fields and methods (standard issue ProGuard), probably to save space.  It also did not appear to use any string encryption or obfuscation, which made my job a lot easier.

As a first test, I wanted to install a modified version of the APK with debugging, so I changed the "android:debuggable" attribute to "true" in the "AndroidManifest.xml" file.


When I attempted to rebuild the APK, I was greeted by a bunch of resource repackaging errors, due to missing dependencies in the "framework-res.apk" I was using to repack the application.  This is pretty common in large applications that are developed with proprietary resources.  I won't go into the details (you can learn more here), but with a few changes to the "/res/values/styles.xml" file I was able to rebuild it successfully.

I then installed the new APK and attempted to launch the application, and was presented with a message indicating that the application has crashed.  I checked the Android logs and saw this error:


The message was strange, since I don't recall that being a feature of Android.  I did a quick string search for the error and found that in the method "c()V" of the class "smali/com/facebook/katana/app/FacebookApplicationImpl.smali" there was a quick check to make sure the "android:debuggable" flag was not set to true, which is actually a good security feature!  If the flag was set to true, the application threw a RuntimeException and the application crashed.


To get by this, I simply removed the check, and repackaged the application.


The application could now be installed without errors.

I switched gears and started running some searches on the application's disassembled class files.  Since I knew the application was not encrypting strings, searches for "mms","sms," "sms/inbox", "content://sms" should have returned something interesting.  Instead, I found absolutely nothing interesting. Weird.  I considered maybe the application asked for the permission, but didn't use it (yet), but that seemed unlikely.

I decided to rerun the app on my device and check the logs. As the app loaded, I noticed something very interesting - the application was copying additional DEX files, and loading them!


I've personally never seen this, but it appears that the application copied three additional XZ compressed assets, uncompressed them, and then used a DexClassLoader to load them.  These 3 DEX files also contained "canary" checks, but it was still possible to modify the classes and rebuild.  Here are the files:


I decompressed and disassembled all three, and realized there were now over 10,000 new classes to search through.   I repeated my search above, and this time found something a bit more interesting.


We now have a few leads to look at.  In particular, we have the class "/secondary-2/com/facebook/confirmation/task/ReadSmsConfirmAccountBackgroundTask.smali" and the classes "/secondary-1/android_src/provider/Telephony*.smali."  I'll start with the class "ReadSmsConfirmAccountBackgroundTask.smali."

The file "/secondary-2/com/facebook/confirmation/task/ReadSmsConfirmAccountBackgroundTask.smali" contained the string "content://sms/inbox," which proceeded a query to the SMS content provider.  This was a good starting point.


This class is actually quite large, and makes several obfuscated calls to other classes.  I rewrote the class in Java to help me understand what was going on.  For this post, I'll just write some (oversimplified) pseudo-code:


Even though this example is oversimplified, it still demonstrates what the method does.  This method iterates over your text messages, first checking the date (to make sure it's within a threshold), then checks the address to make sure it's from a Facebook sender, and finally it performs a regex on the body.  It adds all potential confirmation codes entries to a list and returns them (note that "m.group(1)" will only return the confirmation code, not the message body).  I did not analyze what the Facebook application does with the values more than two method calls up.

Now the question is: when does this get called?  To help me figure this out, I added a quick Log statement to the method that queries the SMS database.  For the entirety of my testing, I ran the command "adb logcat | grep "TESTING".  If the Facebook app tried to read your SMS, I should see it in the logs.


In addition, I ran my tests from a dev version of CobraDroidJB, which reported all ContentProvider queries to a designated log buffer (commit).  I then tried just about ever combination of logging in, logging in with two factor, logging in from an unrecognized device, etc.  No evidence that our watched method above was called, or that the SMS/MMS databases were accessed.  I tried it from two devices, and a test version of CobraDroidJB; the results were the same in all cases.  I even installed and logged into the Facebook Messaging application just in case that mattered.


This was me adding my phone number and confirming it.


Even though I used the "Login Approvals"  setting which required a confirmation code, I would have to manually enter it.  You can even see in the second picture that I have the unread text message (with my code!).



In my testing, I was unable to make Facebook access my SMS or MMS.  I'm not saying its not possible, but I tried several different devices and settings and was unable to make the app call this particular method.

Not satisfied, I dug around the code surrounding the SMS query method and found mentions of a property called "read_sms_bg_account_confirmation" which seemed interesting.  This parameter is stored in the Sqlite3 database file "/data/data/com.facebook.katana/databases/prefs_db," and is not populated until a user authenticated to Facebook.  No matter what my account settings were, this value was always set to 0 (the "2" is the type).


Even when I manually set this value to 1, the application still did not read my SMS.  At this point I decided to call it a day.  If reading my SMS was a "feature" of the new app, it was pretty difficult to use this "feature."

The second instance of the strings "sms" found in the secondary DEX files was the file "/secondary-1/android_src/provider/Telephony$MmsSms.smali".  This class contained static SMS and MMS URI strings for other classes to use.  Here is what the class "Telephony" might look like in Java:


Did any other class actually use this class?  It depends.  I looked at two iterations of the Facebook Mobile application version 5.0.0.26.31 - One from a GingerBread device which was version code 1056406, and one from a JellyBean device which was version code 1056414.  If you installed 5.0.0.26.31/1056406, the application contained the class "/secondary-2/com/facebook/contacts/upload/events/ContactInteractionEventsFetcher.smali," which accessed the "Telephony" class above; however, if you used the more recent 5.0.0.26.31/1056414, no classes used this class.  In my testing of version code 1056406, I was not able to get this class to be called, so I believe this was testing, deprecated, or experimental code.

Conclusions

Overall, the media coverage on this topic is quite misleading and borderline fear mongering.  Here are some facts:
  • The Facebook application did contain code to access your SMS and MMS messages.
  • The application contained code to search the SMS database between select time-frames, for select senders, and 4-10 length numbers in the message body.  Only the matched number was returned (not the whole text message).
  • Some versions of the application did contain additional code to read your SMS/MMS database for a specified phone number.
  • The Facebook application does not routinely read your SMS.
I'm not entirely convinced this feature is completely implemented. If it is implemented, it would seem difficult to cause the application to actually use it.  If anyone has experience with this feature and can say "yes, it definitely is enabled," I would love to hear it!

I also want to point out this analysis only pertains to a single version of the application.  Facebook may very well decide to use this permission in the future, so remember that!  They could also add class name and string obfuscation, which would make reverse engineering the application significantly more difficult.

Monday, July 29, 2013

An Introduction to CobraDroid 1.0

I'm finally happy to say that the beta for my ongoing project called "CobraDroid" is fully released!  The project was actually released back in March on my website, but the source was just pushed to GitHub recently.  I wanted to talk a little about what CobraDroid is, what it can do for analysts, and what you can expect in the upcoming months.

What Can CobraDroid 1.0 Beta Do?

CobraDroid is a modified Android emulator image designed for individuals who want to perform application security assessments or analyze malware for the Android platform. It is not a service where you upload an application and receive a summary of activity, and it is not a black-box (there are plenty of those out there).  It should help you with performing your analysis, but keep in mind it will not perform all the analysis for you. It is released under the Apache Software License 2.0, so you are free to download, modify, and use the source.  The beta is mostly a teaser for what is to come, but it includes:
  • Configurable radio values (MIED, MDN, IMSI, SIM card serial number, and voicemail number)
  • Dynamically configurable “build.prop” values
  • Configurable SSL certificate validation bypassing 
  • Enhanced proxy capabilities
  • Additional user-space utilities
This should be enough to get you started, and already provides more functionality than the standard Android emulator.

What's Next?

The beta version of CobraDroid 1.0 is still lacking in terms of functionality and features.  Luckily, I've been hard at work on lots of new features.  I don't want to give away all the fun, but from a high level you can expect 1.0 to include:
  • A newer, hand-ported kernel (say goodbye to the 2.6.29 Goldfish kernel)
  • Full Bash shell + Busybox
  • Application specific packet-capturing
  • Java bytecode instrumentation
  • Mercury and LiME integration 
  • ..and more!
Many of these features are actually already implemented, but in a state of QA.  CobraDroid 1.0 should be ready to roll by the end of the summer, so stay tuned!

BruCON 2013

If by chance you are attending BruCON 2013, come check out my talk on CobraDroid and see a demo of the tool!  Hopefully I'll be presenting the tool in the states soon as well sometime soon.

If you are interested in trying CobraDroid, check out the getting started page.  Of course, feedback and comments are always welcome.

-jakev

Monday, April 15, 2013

Fixing Resource Identifiers in Disassembled Apps

If you have ever attempted to reverse an Android application, you've probably noticed that resource identifiers (think "R" values) show up as cryptic constants in disassembled smali code. This can be frustrating when attempting to reverse and understand the application's flow.  A rather contrived example of this issue is demonstrated below.

Imagine we write an application with a single activity. This activity simply inflates and shows a defined layout, which I've called "my_layout".


We defined this layout in our "res/layout/" directory. Its contents are not really important, but they are listed below anyways.


Once we start reversing this application, we will likely use apktool (or just baksmali) to disassemble the DEX bytecode. If we then examine the disassembled "ExampleActivity.smali" file, we notice that the "onCreate" method looks as follows:


What does the value 0x7f03 mean? What I didn't show before was that while we were coding away, Eclipse was helping us by bridging the gap between our resource files and our Java sources with the "R" class. This class creates an anonymous class for each resource type, and sets an integer value for every resource we define. We can then access our resources in our Java code with the syntax like "R.layout.my_layout", or "R.string.secret_message".  When compiled, this value is replaced with the integer value.

To make the mapping, we could inspect the various R$*.smali anonymous classes, but there is actually a better place to find these value. These values also appear in the "res/values/public.xml" file created by the Android application packaging tool ("aapt") during the build.


Since "public.xml" is an XML file, we can parse it using python with relative ease. This is where "fix_resources.py" comes in. "fix_resources.py" will parse the "public.xml" file, then search for instances of resource identifiers in our smali sources.  It will append a useful string on these lines, to make our job a little easier.


It will also resolve any string-type resource identifiers from the "res/values/strings.xml" file.  Let's say that we changed our "onCreate" method to copy a string from a resource file (no idea why you would want to do this), and print the value to the log:


Now, when we run apktool and "fix_resources.py" on our app, we will see that "fix_resources.py" has actually included the string's value in the code (it will truncate the string if it is too long).


I don't expect many applications to use this technique to obfuscate or hide sensitive strings, but overall "fix_resources.py" is a quick and painless way to add some addition annotations to your disassembled code.  Because the modifications are comments, apktool/smali will have no problem repackaging the code if you want to modify and rebuild the application.

"fix_resources.py" requires the lxml python module to run, but it's a pretty straightforward install.  You can grab the "fix_resources.py" script from my GitHub account.  Feel free to report any bugs or comments with the code!

-jakev