Dynamic Aspect Oriented Bytecode Instrumentation

As part of my graduate research, I developed a process combining bytecode instrumentation with a relatively unknown programming paradigm known as aspect oriented programming. In a truly synergistic fashion, these ideas produce beautiful results when used in concert. The effect of this research, as demonstrated below, is to have the ability to dynamically alter the behavior of programs written in an interpreted language (think Java, Dalvik, Python & Ruby). So, we can alter any program written in those languages, and bend it in order to change its behavior.

The need to alter

Since the advent of the modern smartphone, circa 2007 (Apple's iPhone), we've seen an ever-increasing amount of personal information available to our devices. Ergo, we impart the trust of goodwill and safe handling to applications we install on them. We trust them with things such as our location, our contact information, internet access.. etc.

While this trust is easy for some to give up, privacy-aware individuals are slow to trust; however, outside these two categories lie the majority - the ill-informed and unaware. In which camp do you find yourself? I, for one, do not want applications from any developer to have more than the absolute BARE-MINIMUM access than necessary for the application to function. I do not want my flashlight app to have access to my GPS, and I do not want my banking app to have access to any other server than that hosted by Capital One, period. These apps relate examples of over-provisioning, and this study suggests more than 70% of Android apps are guilty of such offenses. No matter what the reasons for this over-provisioning, the simple fact of the matter is that YOU should have control over YOUR DEVICE and therefore, control over YOUR INFORMATION.

It boils down to control. You agree these apps can have everything they want, ad nauseam. You can't curb it. You have no recourse.

FlashlightPermissionsPartial

And you have to agree to give the app access to everything it asks for, or you can't even install it.

Wouldn't it be nice if you could use any app, knowing it can't access your anything on your device unless YOU deem it necessary? Howbout dynamically allowing or disallowing access to particular functions?

This is the perfect proving ground for Aspect Oriented Bytecode Instrumentation.

We use instrumentation to change the app, and aspect programming to design the changes.

(If you're familiar with Aspect Oriented Programming, the next section will bore you. Feel free to skip to the movie!)


Aspect Oriented Programming (AOP) hit stride with the AspectJ project, which launched in 2001. It's the de-facto standard AOP implementation for Java, and that's what I focus on with this project. I highly recommend reading more into how the instrumentation process works, but that is beyond this article. Take me for my word that it simply looks at the program's bytecode and knows how to change it for what you want to do.

AOP, as mentioned earlier, will let us design the changes we want to make. We implement these changes by using two AOP constructs known as pointcuts and advice.

Pointcuts define what we want to change.

Advice defines what we want to do.

When combined, they form a construct called an 'aspect'.

A typical pointcut could look like the following:

pc

In this example, we want to apply our advice (which has not yet been defined) to every part in the program which calls the function "query". We will allow any function with that name, no matter what the return type (denoted with the wildcard "*") and any number of function arguments (".."). The "call" keyword defines what behavior we want to apply advice to. Here, we want to change what happens when the function "query" is called. However, there are other things you can do, such as have the pointcut defined on execution, initialization, etc.

We apply that pointcut with this advice... guess what the goal is:

SImpleAdvice.png

This combination of methods, when combined to an aspect, will cause any query function to fail. This is because we modify the database call to have extra, impossible criteria - the query is appended with "where 0", which if you are familiar with SQL you know this will never yield results.

In fact, this is not just a simple example. This query was essentially what I did to revoke an applications access to the contacts database. I added a few lines to allow for dynamic authorization. Here is the source aspect.

With this toolset, you can do things like the following:

This process has been automated, so that we simply drop an app into a pipeline which performs all the necessary instrumentation. When it comes out the other end, it will be dynamically instrumented to allow for granular control. I know what you're thinking -- Android apps aren't technically Java bytecode, they're Dalvik bytecode! Well, true. But with the help of the nifty tool Dex2Jar, this was a trivial barrier.