I recently came up against an Android application which gates certain functionality behind detecting a ‘compatible’ Android device – which mine was not. My usual approach, on a rooted device, would be to use XPrivacyLua to spoof the device information returned to the application, but this particular application also disables itself if a rooted device is detected, so this is not trivial. A suitable approach in this case is to modify the application itself and patch out the relevant code.

Firstly, we obtain the APK file of the application:

$ adb shell pm path com.example.app
package:/path/to/base.apk

$ adb pull /path/to/base.apk
/path/to/base.apk: 1 file pulled, 0 skipped. xxx MB/s (xxx bytes in xxxs)

We can then use apktool to extract the APK file and disassemble the code:

$ apktool decode --no-res --output /path/to/disassembly base.apk
I: Using Apktool 2.7.0 on base.apk
I: Copying raw resources...
I: Baksmaling classes.dex...
I: Baksmaling classes2.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
I: Copying META-INF/services directory

Details of the device are exposed in the android.os.Build class, or, in the Java internal field descriptors syntax, Landroid/os/Build;. We can simply then grep for references to this class to identify the code responsible for reading the device information:

$ grep -R 'Landroid/os/Build;' /path/to/disassembly
/path/to/disassembly/smali/a/b.smali:    sget-object v0, Landroid/os/Build;->MODEL:Ljava/lang/String;

We can then manually edit this file and patch out the sget-object instruction to instead load our desired device information, for example, by replacing the line with:

const-string v0, "Pixel 8"

We could even apply this everywhere automatically, for example:

$ find /path/to/disassembly -name '*.smali' -print0 | xargs -0 sed 's#sget-object \([pv][0-9]\+\), Landroid/os/Build;->MODEL:Ljava/lang/String;#const-string \1, "Pixel 8"#g'

We can repeat this as required for other fields of android.os.Build such as MANUFACTURER and DEVICE.

With the required changes made, we can then rebuild the APK file with apktool:

$ apktool build --output patched.apk /path/to/disassembly
I: Using Apktool 2.7.0
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether sources has changed...
I: Smaling smali_classes2 folder into classes2.dex...
I: Checking whether resources has changed...
I: Copying raw resources...
I: Copying libs... (/kotlin)
I: Copying libs... (/META-INF/services)
I: Building apk file...
I: Copying unknown files/dir...
I: Built apk into: patched.apk

We can then sign the APK file (for example, with uber-apk-signer) and install it to the target device.