Apr 22
Hacking Android apps, part 2: fake contacts
Welcome to the second part of "Hacking Android apps", a follow-on from part 1. In this part, we will modify Viber so that it doesn't access your contact list.
We're going to do this the hard way. Rather than just deleting the offending code, as we did for the shortcut icon code in part 1, we'll instead create a duplicate version of the Android contact provider and then instruct Viber to use that version rather than the original.
Why go to the trouble of creating a fake contact list? Access to the contacts list is highly integrated within Viber: in fact, there are 81 separate access of contact-related data throughout Viber. Deleting the code isn't an option. Instead, we would need to come up with suitable dummy routines for each access to the contact list, which would be annoying.
So, the short answer is "it's easier", but there are other benefits too. You may actually want Viber to have access to part of your contact list. By creating a new, shadow contact list, you can contract exactly what Viber sees.
Finally, a fake contact list is useful for more than just Viber -- we can use it with any other apps which require access to the contact list.
The fake contact list
Android uses a content provider to manage contacts. The content provider runs in the Android system process, so no app can access contacts directly: they must use the content provider API.
The super-high-level-overview version of the content provider API is: applications construct a URL which represents the operation they wish to perform (i.e. to create, read, update, or delete a resource). They then call a contact provider API function to perform the operation.
The contact provider API is quite extensive. Fortunately, Android is open source, so we can re-use the Android contact provide to create a standalone fake contact provider. This is what I did. The standard Android contact provider uses the base URI of com.android.contacts; the fake provider uses the base URI of net.lardcave.fakecontacts.
Technically, this wasn't difficult to implement. The major problem was that the Android contact provider uses quite a lot of API functions which are normally hidden to apps. The new contact provider uses reflection to access some of these functions. Other functions are just reimplemented (in most cases) or deleted.
Download and install the APK:
f you are curious or would like to improve it (it is quite buggy), source is available on Github.
Now you have a fake contacts provider. It is a port of the Android 2.3 contacts provider, so it has the same interface. This is helpful: it means that it can be used to provide fake contacts for any program which uses the standard Android contacts API.
You can add contacts using the Android contact test application, modified to use the net.lardcave.fakecontacts provider rather than the real one. You can download and install that APK here:
The source code is also on Github.
Having ported and installed a fake contacts provider, we can now modify Viber to make use of it.
Using the fake contacts provider
The trickiest part of the whole thing is finding all the uses of the contacts API within Viber. Looking at the contacts API examples, it seems that all API accesses start off with a content URI from somewhere within the android.provider.ContactsContract
class. So a good way to start would be to grep for that:
grep -r android.provider.ContactsContract.*_URI apk/smali/ |wc -l
72
The lines in question all look a bit like this:
sget-object v1, Landroid/provider/ContactsContract$PhoneLookup;->CONTENT_FILTER_URI:Landroid/net/Uri;
In other words, they access static URI objects from the ContactsContract class, or classes within ContactsContract. These will all be URIs which start with content://com.android.contacts
. We want to change these accesses so that they instead return URIs which start with content://net.lardcave.fakecontacts
.
The first thing to do is to provide a class which includes all these static URLs. This class is part of FakeContacts, but we will copy it into Viber as well. It's called net.lardcave.fakecontacts.FakeContract
. Download the class:
Now copy the class to the right location:
mkdir -p apk/smali/net/lardcave/fakecontacts
mv FakeContract.smali apk/smali/net/lardcave/fakecontacts
Now you need to change every URI reference to be a fake URI reference. You could do this manually, but it's far easier to write a program to do it. Download the program:
Now run it in the viber directory:
~/tmp/viber$ python hack_contacts.py
If you re-run the grep, you should now see that all references to contact URIs have been changed.
All that remains is to remove the READ_CONTACTS
and WRITE_CONTACTS
permissions from apk/AndroidManifest.xml. Now Viber can't possibly access the real contact list, even if we missed something.
Re-build the app using APKTool in the same way as before, sign it, and then install it, making sure to over-write the previous one:
adb install -r com.viber.voip.apk
Run Viber. It will request access to your contact list, but will only access the fake one. We're now done. In the final part, I'll cover removing some other unnecessary Viber permissions.