Bypassing JailMonkey for chicken wings🍗

2023-11-03

Recently my friend switched to Android from an iphone. We installed LineageOS ROM, everything works except the KFC app!. For some reasons KFC thinks people shouldn’t order if they are using a custom ROM. kfc_jailbroken

Let’s see how to patch the apk to remove this limitation.

We will use the following tools

Decompile the apk

apktool d -r kfc.apk

The -r flag is for don’t decode resource. We are going to modify the smali, so no need to decode the resource.

Let’s search for ‘jailbroken’

smali/com/gantix/JailMonkey/JailMonkeyModule.smali
51:    const-string v3, "isJailBroken"

smali/com/cardinalcommerce/a/t3.smali
90:    const-string v3, "The device is jailbroken."
2810:    const-string v1, "IsJailbroken"

smali_classes3/com/google/firebase/crashlytics/h/l/u$b.smali
110:    const-string v1, " jailbroken"

smali_classes3/com/google/firebase/crashlytics/h/l/u.smali
232:    const-string v1, ", jailbroken="

smali_classes3/com/google/firebase/crashlytics/h/l/d0/g.smali
3531:    const-string v3, "jailbroken"

smali_classes3/com/google/firebase/crashlytics/h/l/a$t.smali
75:    const-string v0, "jailbroken"

smali/com/gantix/JailMonkey/JailMonkeyModule.smali looks interesting.

JailMonkey is a a React Native library for identifying if phone is rooted.

Load the apk in jadx and find the file.

    @Override // com.facebook.react.bridge.BaseJavaModule
    public Map<String, Object> getConstants() {
        ReactApplicationContext reactApplicationContext = getReactApplicationContext();
        HashMap hashMap = new HashMap();
        hashMap.put("isJailBroken", Boolean.valueOf(C4990d.m23531a(reactApplicationContext)));
        hashMap.put("hookDetected", Boolean.valueOf(C4984a.m23538c(reactApplicationContext)));
        hashMap.put("canMockLocation", Boolean.valueOf(C4986a.m23537a(reactApplicationContext)));
        hashMap.put("isOnExternalStorage", Boolean.valueOf(C4983a.m23541a(reactApplicationContext)));
        hashMap.put("AdbEnabled", Boolean.valueOf(C4982a.m23542a(reactApplicationContext)));
        return hashMap;
    }

Basically this is a hashmap with values of all the triggers. We just need to make the isJailBroken key false, but I’m making all the keys false.

Patch

diff after modifying JailMonkeyModule.smali.

     invoke-direct {v1}, Ljava/util/HashMap;-><init>()V

+    const/4 v2, 0x0

-    invoke-static {v0}, Lcom/gantix/JailMonkey/f/d;->a(Landroid/content/Context;)Z
 
-    move-result v2
-
-    invoke-static {v2}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
-
-    move-result-object v2

     const-string v3, "isJailBroken"
 
     invoke-interface {v1, v3, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 
-    invoke-static {v0}, Lcom/gantix/JailMonkey/c/a;->c(Landroid/content/Context;)Z
-
-    move-result v2
-
-    invoke-static {v2}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
-
-    move-result-object v2
-
     const-string v3, "hookDetected"
 
     invoke-interface {v1, v3, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 
-    invoke-static {v0}, Lcom/gantix/JailMonkey/e/a;->a(Landroid/content/Context;)Z
-
-    move-result v2
-
-    invoke-static {v2}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
-
-    move-result-object v2
-
     const-string v3, "canMockLocation"
 
     invoke-interface {v1, v3, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 
-    invoke-static {v0}, Lcom/gantix/JailMonkey/b/a;->a(Landroid/content/Context;)Z
-
-    move-result v2
-
-    invoke-static {v2}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
-
-    move-result-object v2
-
     const-string v3, "isOnExternalStorage"
 
     invoke-interface {v1, v3, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 
-    invoke-static {v0}, Lcom/gantix/JailMonkey/a/a;->a(Landroid/content/Context;)Z
-
-    move-result v0
-
-    invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
-
-    move-result-object v0
-
-    const-string v2, "AdbEnabled"
+    const-string v3, "AdbEnabled"
 
-    invoke-interface {v1, v2, v0}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+    invoke-interface {v1, v3, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 
     return-object v1
 .end method

I removed the function calls that return the status, since we are making them false anyway.

Build and Sign

apktool b kfc && uber-apk-signer -a kfc/dist

Profit

Now we can eat kfc peacefully. Kfc allows ordering from their website, but what’s the fun in that.