Saturday, March 30, 2013

Plague Inc

Synopsis:
---------

Most of my other tutorials deal with registration schemes, and manual ad removal. There's other reasons to reverse software. Let's take for example a game called Plague Inc. I bought this game, and enjoyed playing it while the novelty lasted. One aspect of the game is that they have a lot of unlockable perks, and buyable game types. For shits and giggles, I decided it'd be fun to figure out to see if I could unlock all unlockables and get all game types.


Tools Needed:
-------------

* An android device or emulator with a functional adb connection (ADB setup beyond scope of this tutorial)
* UNIX or unix-like environment with apktool (Use deprecated version 1.4.1)
    (Note: apktool no longer works with baksmali, so you have to use an older version.)
* JDK 1.6
                (Note: 1.7 can be used, but there's an issue with a change of algorithm with the jarsigner, which causes some unneccessary difficulties, namely a "NO_CERTIFICATE_EXISTS" error upon APK installation)

Java 1.7:
---------

Key Creation:
        keytool -genkey -v -keystore testing.keystore -alias testing -keyalg RSA -keysize 2048 -validity 10000

APK Signing:
        jarsigner -verbose -keystore /home/ben/testing.keystore -digestalg SHA1 -sigalg MD5withRSA test.apk testing

Retrieval of APK From Device:
-----------------------------

You first need to establish your adb bridge, make sure your device shows up when you type:
        adb devices

The name of the apk is:
        com.miniclip.plagueinc-1.apk

I'm not sure if that hyphen naming notation is specific to Cyanogenmod or what, but it might be called:
        com.miniclip.plagueinc.apk

With most setups, you should be able to type the following to get the APK:
        adb pull /data/app/com.miniclip.plagueinc-1.apk

So now you have com.miniclip.plagueinc-1.apk in your current directory.


Unbundling:
-----------

First off type:
        apktool

If this gives you command not found, go look up how to do install apktool.


In the directory that contains the target APK file, type the following:
        apktool d com.miniclip.plagueinc-1.apk work


This unbundles an APK into its own directory called 'work'

Go into the 'work' directory, and check out the following tree:

res/   - This directory is where all resources (images, layouts, etc) live.
smali/ - This directory is where disassembled java files go.

Unlockable Discovery:
---------------------

Plague Inc's source files were unobfuscated, and pretty easy to follow. If you look at the application's main activity:
        smali/com/miniclip/plagueinc/PlagueIncActivity.smali


You'll see a lot of references to com/miniclip/nativeJNI, when you look at this directory, you'll see a ton of cocojava classes, with a lot of dollar signs and numbers afterwards. This is a telltale sign of a singleton design. Opening up the cocojava.smali, you start to see some interesting items:

.field public static mTEST_INAPPS:Z

.field protected static mUSE_ADS:Z


I like seeing 'test' in things because often times there's development code left over in applications that allow you to do things most would not allow you to do. I grepped for the use of mTEST_INAPPS, and found a couple of instances:


ben@localdev:~/plagueinc/work/com.miniclip.plagueinc-1/smali/com/miniclip$ grep -R "mTEST_INAPPS" *
nativeJNI/cocojava.smali:.field public static mTEST_INAPPS:Z
nativeJNI/cocojava.smali:    sput-boolean v2, Lcom/miniclip/nativeJNI/cocojava;->mTEST_INAPPS:Z
nativeJNI/cocojava$30.smali:    sget-boolean v0, Lcom/miniclip/nativeJNI/cocojava;->mTEST_INAPPS:Z
nativeJNI/cocojava$29.smali:    sget-boolean v0, Lcom/miniclip/nativeJNI/cocojava;->mTEST_INAPPS:Z
plagueinc/PlagueIncActivity.smali:    sput-boolean v12, Lcom/miniclip/plagueinc/PlagueIncActivity;->mTEST_INAPPS:Z


Ok, so checking out nativeJNI/cocojava$30.smali, I see the following code structure:

   .line 2016  
   :cond_0  
   sget-boolean v0, Lcom/miniclip/nativeJNI/cocojava;->mTEST_INAPPS:Z  
   if-eqz v0, :cond_1  
   .line 2017  
   sget-object v0, Lcom/miniclip/nativeJNI/cocojava;->mContext:Landroid/content/Context;  
   check-cast v0, Lcom/miniclip/nativeJNI/InAppActivity;  
   const-string v1, "android.test.purchased"  
   invoke-virtual {v0, v1}, Lcom/miniclip/nativeJNI/InAppActivity;->requestPurchaseAct(Ljava/lang/String;)V  
   goto :goto_0  
   .line 2019  
   :cond_1  
   sget-object v0, Lcom/miniclip/nativeJNI/cocojava;->mContext:Landroid/content/Context;  




Basically, it's taking the value of this mTEST_INAPPS, if it's 0, it skips a section of code that calls a purchase with a string argument of "android.test.purchased". I want to do this always, so I'm just going to remove the if-eqz which triggers the jump.

Now on to the nativeJNI/cocojava$29.smali:

   .line 1991  
   :cond_0  
   sget-boolean v0, Lcom/miniclip/nativeJNI/cocojava;->mTEST_INAPPS:Z  
   if-eqz v0, :cond_1  
   .line 1992  
   sget-object v0, Lcom/miniclip/nativeJNI/cocojava;->mContext:Landroid/content/Context;  
   check-cast v0, Lcom/miniclip/nativeJNI/InAppActivity;  
   const-string v1, "android.test.purchased"  
   invoke-virtual {v0, v1}, Lcom/miniclip/nativeJNI/InAppActivity;->requestPurchaseActManaged(Ljava/lang/String;)V  
   goto :goto_0  
   .line 1994  
   :cond_1  



Same exact structure, let's go ahead and remove that if-eqz as well. Your job is now done, all doors are now open. A better way to do this would have been to modify the value in the cocojava object.


Rebundling:

You can rebundle the APK by using apktool against the extracted directory

For instance if you have this directory tree:
        com.miniclip.plagueinc-1
        |_ smali
  |_ res
        |_ assets

your directory is com.miniclip.plagueinc-1

You then run the following:
        apktool b com.miniclip.plagueinc-1 hacked.apk

This packages the APK back up. You need to sign it with jarsigner (see signing section) before you can install it by typing:
        adb install hacked.apk

Monday, February 7, 2011

Blog Post Cleanup

I am still here, still alive, and still reversing. I am going to be reworking the blog site a bit to look better especially when posting code. Please be aware I under no circumstances advocate piracy, illegal distribution of cracked binaries, or any other illegal activity. I merely am fascinated by being able to change programs beyond their original operating capacity, and being able to tell what's going on behind the scenes with these apps.

Wednesday, October 6, 2010

yxplayer Registration Bypass - Android App Cracking Tutorial #4

Yxplayer Pro v1.0.2

Requisites:
 apktool - contains baksmali/smali, generally awesome. 
  (http://code.google.com/p/android-apktool/)
 Android SDK installed. 
  (http://developer.android.com/sdk/index.html)
 JDK 6 or above
 ADB Access.
 An Android Device

Synopsis:
 yxplayer is a media player that is capable of playing avi files.

Protections Employed: 
 Serial Number, Nag Mechanisms

Getting the APK:
 I downloaded the apk from my phone after downloading it through the market.

 On my device, I typed the following to get the APK: 
  adb pull /data/app/kr.mobilesoft.yxplayer2-1.apk

Unpacking the APK:
 I then use apktool to decompress and disassemble the package: 
  apktool d kr.mobilesoft.yxplayer2-1.apk yxplayer

Reversing the unpacked APK:
 A fairly standard step, I go to smali where the source code is kept. Then I traverse the source code
 tree to get to the beef of the app. In this case, it's in ./smali/kr/mobilesoft/yxplayer2/

 Right off the batt, I notice the RegisterView.smali, a likely name for the nag screen. Grepping for RegisterView 
 shows the main application yxplayer.smali calling it conditionally.

   sget-object v29, Lkr/mobilesoft/yxplayer2/yxplayer2;->mMediaPlayer:Lkr/mobilesoft/yxplayer2/MediaPlayerApi;  
   invoke-virtual/range {v29 .. v29}, Lkr/mobilesoft/yxplayer2/MediaPlayerApi;->isregistered()I  
   move-result v15  
   .line 561  
   .local v15, ok:I  
   if-nez v15, :cond_9  
   .line 562  
   new-instance v29, Landroid/content/Intent;  
   const-string v30, "kr.mobilesoft.yxplayer2.RegisterView"  
   invoke-direct/range {v29 .. v30}, Landroid/content/Intent;->(Ljava/lang/String;)V  
This is putting the result of yxplayer2.MediaPlayerApi.isregistered() as a boolean into v15, and checking it. cond_9 bypasses the register window, we can modify the code here to jump unconditionally, but why not just make the isregistered() always return true? That is the goal, to fool the app, not just a superficial nag screen removal.
  .method public isregistered()I  
   .locals 1  
   .prologue  
   .line 356  
   invoke-virtual {p0}, Lkr/mobilesoft/yxplayer2/MediaPlayerApi;->mp_isregistered()I  
   move-result v0  
   return v0  
  .end method  
Looks easy enough to do, I'll use the same guts from the translation app tutorial.
  .method public isregistered()I  
   .locals 1  
   const/4 v0, 0x1  
   return v0  
  .end method  
This always returns 1 (true) when the isregistered() method is called. I am now done, time to repack. Repacking the APK: I go to the directory I originally ran apktool in, and do the following: apktool b yxplayer newyxplayer.apk I need to sign this to put it on most android devices, if you have the SDK installed, you should have a debug key: jarsigner -keystore ~/.android/debug.keystore newyxplayer.apk androiddebugkey and enter "android" as the password. NOTE: You won't be able to "upgrade" the app on the device, you MUST uninstall it either on the device, or by typing the following: adb uninstall kr.mobilesoft.yxplayer2 You now have an installable cracked apk, which you can install by typing: adb install newyxplayer.apk All Done!

Sunday, August 8, 2010

Shazam Ad Removal - Android App Cracking Tutorial #3

Shazam Ad Removal

Requisites:
apktool - contains baksmali/smali, generally awesome. (http://code.google.com/p/android-apktool/)
Android SDK installed. (http://developer.android.com/sdk/index.html)
ADB Access.
An Android Device

Shazam allows you to identify songs based on input from your phone's microphone. It probably does
other bullshit but not only is it a free "trial", it also has google ads.

Protection Used: Feature limited free version
Ads Used: google ads

I downloaded the apk from my phone after getting it from the market.
    ben@ben-laptop:~$ adb shell ls /data/app/ |grep shazam
    com.shazam.android.apk
    ben@ben-laptop:~$ adb pull /data/app/com.shazam.android.apk
    1556 KB/s (706767 bytes in 0.443s)

Then I use apktool to decompress and disassemble the package:
  apktool d com.shazam.android.apk shazam_reversing

Then I go into the newly created directory:
  cd shazam_reversing

To remove the ads, I go to res/layout, in there, there's a file called view_advert.xml, rather clever of them to hide it there

I see their file defines a LinearLayout, this is likely expanded on inside the program itself, but let's just make everything
0px instead, shall we?
 
    
  <?xml version="1.0" encoding="UTF-8"?>
  <LinearLayout android:gravity="center_horizontal" android:background="@color/transparent" android:layout_width="0px" android:layout_height="0px" android:layout_alignParentBottom="true"
    xmlns:android="http://schemas.android.com/apk/res/android" />>

OK I think I'm done, let's package everything back up, I go to the directory I originally ran apktool in, and do the following:
  apktool b shazam_reversing newshazam.apk

we need to sign this to put on most android devices, if you have the SDK installed, you should have a debug key
  jarsigner -keystore ~/.android/debug.keystore newshazam.apk androiddebugkey

and enter "android" as the password.

NOTE: You won't be able to "upgrade" the app on the device, you MUST uninstall it either on the device, or by typing the following:
  adb uninstall com.shazam.android

You now have an installable cracked apk, which you can install by typing:
  adb install newshazam.apk

Android Trial Patching - Android App Cracking Tutorial #2

Collins English/French Dictionary Trial Crack

Requisites:
apktool - contains baksmali/smali, generally awesome. (http://code.google.com/p/android-apktool/)
Android SDK installed. (http://developer.android.com/sdk/index.html)
ADB Access.
An Android Device

Collins audio english french dictionary is a translation dictionary with audio capability. It was
chosen due to its method of protection and listing in the "demo" section of the market as a featured
application.

7 day trial

I downloaded the apk from: http://android.mobisystems.com/product.html?p=16&l=1&pid=370&i=1&c=1&sc=9

getting CollinsAudioMltEnFr.apk


Then I use apktool to decompress and disassemble the package:
    apktool d CollinsAudioMltEnFr.apk enfr_dict

Then I go into the newly created directory:
    cd enfr_dict

Searching the directory structure, I see:
  msdict/viewer/engine/LicenseManager.smali

This looks promising!

In this directory, we find enough information to determine that they store registration information in .reginfo in the files directory
sure enough:
    ben@ben-laptop:~/Downloads$ adb shell busybox ls -Al /data/data/com.mobisystems.msdict.embedded.wireless.collins.audiomltenfr/files
    -rw-rw----    1 10106    10106          25 Aug  8 07:52 .reginfo

Deleting this file will start your trial anew, but we're still going to crack this app!

Well, let's stop and look at this file a bit

hexdump -C .reginfo on my linux host results in this:

00000000  00 00 00 01 00 00 00 01  00 00 00 0a 00 00 00 92  |................|
00000010  00 00 00 01 2a 74 bb f9  dd                       |....*t...|


Looking at: /smali/com/mobisystems/msdict/viewer/engine/LicenseManagerBase.smali

search for the following "public load", this is where the filestream for the .reginfo file is read, this will provide good smali reading
practice.

###

.method public load(Ljava/io/InputStream;)V
    .locals 7
    iget-object v0, p0, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase;->_items:Ljava/util/Vector;
    invoke-virtual {v0}, Ljava/util/Vector;->removeAllElements()V
    new-instance v0, Ljava/io/DataInputStream;
    invoke-direct {v0, p1}, Ljava/io/DataInputStream;->(Ljava/io/InputStream;)V
    :try_start_0
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readInt()I
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readInt()I
    move-result v1
    :goto_0
    const/4 v2, 0x1
    sub-int v2, v1, v2
    if-lez v1, :cond_0
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readInt()I
    move-result v1
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readInt()I
    move-result v3
    new-instance v4, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;
    invoke-direct {v4, v1, v3}, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;->(II)V
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readBoolean()Z
    move-result v1
    iput-boolean v1, v4, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;->registered:Z
    invoke-virtual {v0}, Ljava/io/DataInputStream;->readLong()J
    move-result-wide v5
    iput-wide v5, v4, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;->expire_time:J

###


From looking at that file, I can tell the following:
 * It reads 4 ints (4 bytes each), 1 boolean (1 byte, although this is not guaranteed I don't think), and 1 long (8 bytes) 4x4=16 + 1x1=17 + 1x8 = 25 == MY FILESIZE
 * The last parameter is a member named "expire_time"
 * The boolean value says whether or not the application is registered.

So back to the hexdump:

00000000  00 00 00 01 00 00 00 01  00 00 00 0a 00 00 00 92  |................|
00000010  00 00 00 01 2a 74 bb f9  dd                       |....*t...|

int1 = 00 00 00 01
int2 = 00 00 00 01
int3 = 00 00 00 0a
int4 = 00 00 00 92
bool = 00
long = 00 00 01 2a 74 bb f9 dd

So for shits and giggles, I wondered what making the last parameters all F's would do:

Upon starting the app back up, I was greeted with the fact I had 3,242,983 days left on my
trail period. So I think I can make it to the rapture before my trial runs out, but I still have that annoying nag screen, so let's find a different route.





in smali/com/mobisystems/msdict/viewer/engine/LicenseManagerBase.smali I find:

###

.method public isRegistered(II)Z
    .locals 1
    if-nez p1, :cond_0
    const/4 v0, 0x1
    :goto_0
    return v0
    :cond_0
    invoke-virtual {p0, p1, p2}, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase;->getItem(II)Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;
    move-result-object v0
    iget-boolean v0, v0, Lcom/mobisystems/msdict/viewer/engine/LicenseManagerBase$Item;->registered:Z
    goto :goto_0
.end method

###

This is simple, if the passed parameter is NULL, it returns 0 right away. If not, it gets the base item (this piece of software) license
and checks its 'registered' member. This is too damn complex, I'm going to simplify things a bit.

###

.method public isRegistered(II)Z
    .locals 1
    const/4 v0, 0x1
    return v0
.end method

###

It now makes a variable, assigns it '1', and then returns that variable.

OK I think I'm done, let's package everything back up, I go to the directory I originally ran apktool in, and do the following:
    apktool b enfr_dict enfr_dict.apk

we need to sign this to put on most android devices, if you have the SDK installed, you should have a debug key
    jarsigner -keystore ~/.android/debug.keystore enfr_dict.apk androiddebugkey

and enter "android" as the password.

NOTE: You won't be able to "upgrade" the app on the device, you MUST uninstall it either on the device, or by typing the following:
    adb uninstall com.mobisystems.msdict.embedded.wireless.collins.audiomltenfr

You now have an installable cracked apk, which you can install by typing:
    adb install enfr_dict.apk

Saturday, August 7, 2010

Android App Ad Hiding - Android App Cracking Tutorial #1

Advanced Task Manager - Free Ad Removal Tutorial

Requisites:
apktool - contains baksmali/smali, generally awesome. (http://code.google.com/p/android-apktool/)
Android SDK installed. (http://developer.android.com/sdk/index.html)
ADB Access.
An Android Device

Advanced Task Manager allows you to quickly kill off large amounts of processes
It's a generally useful app, however, it has ads. You can pay like $2.99 or something
for it to remove ads, but I'm just going to hide them instead.

Then I pulled the apk off my device:
    adb pull /data/app/com.rechild.advancedtaskkiller.apk .

Then I use apktool to decompress and disassemble the package:
    apktool d com.rechild.advancedtaskkiller.apk atk_reversing

Then I go into the newly created directory:
    cd atk_reversing

Looking at the layouts, and smali directory layout, we can see that google ads are used.

Now here's where we split into 3 possible cracking scenarios.

1. Patch com.google.ads code: This would allow us to have a semi-generic patch
method for ALL apps using com.google.ads. The goal would be to patch the google
ads library so it gives hidden or ads too small to be seen.

2. Patch com.rechild.advancedtaskkiller code: This would allow us to find where Advanced Task Killer calls the
com.google.ads code, and rip it out so it's never actually used.

3. Patch the resources making the ads invisible: This allows us to hide and make the
ads no longer clickable, HOWEVER, they are still downloaded. I find this is an acceptable
trade off for the ease of doing.

We're going to explore #3 today.

The layouts are in astro_reversing/res/layout

There's 2 view XML attributes I want to point out that are immensely useful in ad blocking
    android:visibility
    android:clickable
    android:layout_width
    android:layout_height

These four XML attributes make a world of difference.

grep for com.google.ads in the res/layout directory, and you'll see a hit:
    main.xml:   

That's no good, we can then edit the layout_width and layout_height to be 0px, and it to be unclickable, and for it to be invisible.

I recommend editing the file, but I will demonstrate some sed magic.

for i in *.xml; do sed -i 's/^\(.*com.google.ads.GoogleAdView.*\)wrap_content\(.*\)wrap_content\(.*\)\/>\(.*\)$/\10px\20px\3 android:visibility="invisible" android:clickable="false" \/>\4/g' $i; done;

With this being done, we're ready to repackage up the apk file, we need to go outside where the original apk file is, and type the following to re-package it:
    apktool b atk_reversing newatk.apk

we need to sign this to put on most android devices, if you have the SDK installed, you should have a debug key
    jarsigner -keystore ~/.android/debug.keystore newatk.apk androiddebugkey

and enter "android" as the password.

NOTE: You won't be able to "upgrade" the app on the device, you MUST uninstall it either on the device, or by typing the following:
    adb uninstall com.rechild.advancedtaskkiller

You now have an installable cracked apk, which you can install by typing:
    adb install newatk.apk

Android Reversing Environment Setup

All my instructions are going to be for GNU/Linux. I use ubuntu in particular, so a lot of my instructions will be customized for Ubuntu, although it should be possible from any GNU/Linux distribution, Mac OSX, and even windows also.

The ABSOLUTE very first step should be grabbing the android SDK. This can be done by going to the website: http://developer.android.com/sdk/index.html

and downloading your operating system's version, I'll assume we're running linux again.


  cd ~
  wget http://dl.google.com/android/android-sdk_r06-linux_86.tgz
  tar zvxf  android-sdk_r06-linux_86.tgz

Then we need to make a bin directory in our home since this is where we'll be placing all tools.

  mkdir ~/bin

Now you'll need to add this bin directory to your PATH.

In my ~/.bashrc I have at the very bottom

export PATH=/home/areversing/android-sdk-linux_86/tools:/home/areversing/bin:$PATH

I have the same in my ~/.bash_profile and ~/.bash_login but I'm not quite sure what all is neccessary.

Then you'll need to grab apktool and aapt like so:

  cd ~/bin
  wget http://android-apktool.googlecode.com/files/apktool-1.3.1.tar.bz2
  wget http://android-apktool.googlecode.com/files/apktool-install-linux-2.2_r01-1.tar.bz2
  tar jvxf apktool-1.3.1.tar.bz2
  tar jvxf apktool-install-linux-2.2_r01-1.tar.bz2
  rm *.bz2
 
You should now have apk installed!


Type the following at a newly created console window:
  adb --help
  apktool --help


If both of those do not give you detailed help, you did something wrong.