class: center
???
As I watched this person play, I realized that the game only gave you a limited number of moves and that you had to buy more if you didn't finish the puzzle in your allotted moves. I thought this was absurd and wondered if I could find a way to get extra lives or lollipop hammers for free. As it turns out, I could.
Unfortunately, once you strip out the IAP from Candy Crush, it becomes a pretty mediocre match 3 game.
class:center, middle
???
We start with discussing the motivation for this talk and why you should care about the topic.
???
Basically, IAP is a really big deal that makes a lot of money.
Sources: Gartner; TechCrunch
???
As it turns out, people are more than happy to burn money on timewaster games like Clash of Clans and Candy Crush. Lots and lots of money.
???
???
Accounts for popular Android and iOS MMORPG, Chaos & Order Online, sell for $100 USD a pop!
class:center,middle
Implementing IAB is confusing so developers make mistakes that can be exploited to break their apps.
Google provides a simple application as a reference for developers to use for their own implementations.
package com.example.android.trivialdrivesample.util;
[...]
/**
*
* @author Bruno Oliveira (Google)
*
*/
public class IabHelper {}
Candy Crush:
package com.king.store.billingutil;
class IabHelper$2$1
Marvel Battles:
package com.explodingbarrel.iap.util;
class IabHelper$2$1
Unsurprisingly, cracked binaries exist for most top-grossing Android apps that bypass the IAB process.
???
http://www.makeuseof.com/tag/cracked-android-apps-and-games-read-this-before-downloading/
class:center,middle
String classToHook = "<name of class to hook>";
MS.hookClassLoad(classToHook, new MS.ClassLoadHook() {
public void classLoaded(Class<?> hookedClass)
});
MS.hookMethod(hookedClass, hookedMethod,
new MS.MethodAlteration() {
public Object invoked(Object _this, Object... args)
throws Throwable {
* return invoke(_this, args);
}
});
public void launchPurchaseFlow(Activity paramActivity,
String paramString, int paramInt,
IabHelper.OnIabPurchaseFinishedListener
paramOnIabPurchaseFinishedListener)
{
launchPurchaseFlow(paramActivity, paramString, paramInt,
* paramOnIabPurchaseFinishedListener, "" <--- Missing token!);
}
Candy Crush:
*localObject3 = "Constructing buy intent for ";
localObject1 = localObject1.append(localObject3);
localObject1 = localObject1.append(paramString1);
localObject3 = ", item type: ";
*logDebug(localObject1);
Pandora:
*localObject4 = localObject1.append("signature verification ");
if (bool3)
{
localObject1 = "succeeded";
localObject1 = localObject4.append(localObject1).
append(" for request ID ");
* Logger.error((String)localObject3, (String)localObject1);
}
Transaction signature verification for the transaction occurs on the client side instead of on the server.
Candy Crush:
public static boolean verifyPurchase(String paramString1,
String paramString2, String paramString3)
public static boolean verify(PublicKey paramPublicKey,
String paramString1, String paramString2)
Pandora:
protected boolean verifySignature(String paramString1,
String paramString2, String paramString3)
{ return Kiwi.isSignedByKiwi(paramString1 + "-" +
paramString2, paramString3); }
Clash of Clans:
public static boolean b(String paramString1, String paramString2,
String paramString3)
class:center,middle
String classToHook = "com.king.core.billingutil.IabHelper";
MS.hookClassLoad(classToHook, new MS.ClassLoadHook() {
public void classLoaded(Class<?> hookedClass) {
Logging.ClassLoaded(logTag, hookedClass);
} else if (hookedMethod.getName().equals("handleActivityResult")){
Intent intent = new Intent();
* intent.putExtra("RESPONSE_CODE", 0);
intent.putExtra("INAPP_DATA_SIGNATURE", "fake_sig");
JSONObject purchase = new JSONObject();
purchase.put("orderId", "12999763169054705758.1316213752962757");
purchase.put("packageName", "com.king.candycrushsaga");
* purchase.put("productId", sku);
purchase.put("purchaseTime", System.currentTimeMillis());
purchase.put("purchaseState", 0);
purchase.put("purchaseToken", "fake_token");
intent.putExtra("INAPP_PURCHASE_DATA", purchase.toString());
return invoke(_this, args[0], -1, intent);
classToHook = "com.king.core.billingutil.Security";
MS.hookClassLoad(classToHook, new MS.ClassLoadHook() {
public void classLoaded(Class<?> hookedClass) {
Logging.ClassLoaded(logTag, hookedClass);
Logging.LogClassDeclaredMethods(logTag, hookedClass);
for (Method method : hookedClass.getDeclaredMethods()) {
* if (method.getName().equals("verify")
* || method.getName().equals("verifyPurchase")) {
try {
final Method hookedMethod = method;
MS.hookMethod(hookedClass, hookedMethod,
new MS.MethodAlteration() {
public Object invoked(Object _this,
Object... args)
throws Throwable {
* return true;
}
});
class:middle,center
class:middle,center
It will often make sense to keep track of content or game variables on a dev server, not the client.
Obfuscation will not stop a determined attacker but it may convince them to crack a different app instead.
.center[***Questions?***]
.center[![](./img/iab_front.png)]
Alfredo Ramirez
@bonds0097
www.github.com/bonds0097