[code] [blog] [VNC] [GPS Tracker]

Ulefone armor 3wJune 21 2020 15:49:14

The phone I'm currently using is a Ulefone Armor 3W. It's a very capable device with a 10.000mah battery that will last days if not weeks, a 8-core CPU and storage comparable to a laptop if you add a suitable microSD card. I'm using a 512gb card from AliExpress: https://www.aliexpress.com/item/32990982253.html
For all it's good qualities it's got a few bad ones as well - it's quite power hungry when used normally - even though it has a big battery. It's got the semi-spyware AdupsFota installed as it's system updater, and there's a few unneccesary apps installed. This post will be about how I've modified the firmware of this phone to make it more useful to me for daily use. If you want to repeat these steps I recommend you run linux. If instead you just want to download the firmware and flash it - just scroll to the bottom of the page.

Installing TWRP

Installing TWRP was fairly easy - I found an image on 4pda.ru and downloaded it and flashed it using fastboot and the commands "fastboot oem unlock" and "fastboot flashing unlock" for a tutorial Click here. You can find the recovery image called "recovery.img" in the firmware zip file at the bottom of this post.
There is one thing keep in mind: if you do not switch the system image before booting you will need to ensure that you reboot to the recovery - otherwise the stock ROM will replace the recovery with the stock recovery again and you will need to flash it all over.
The recovery image was in russian - so I've used Carliv's image kitchen to unpack it and simply overwrote the russian language file with the English one to make it display everything in English. Here's a tutorial on how to use Image Kitchen: Click.
Furthermore there's no support for the touch-screen in this TWRP Image - so you will have to use the USB-C to USB dongle that came with your phone to attach an USB mouse to click around in TWRP.

Patching the kernel

The Armor 3W, being android 8.1 has dm-verity enabled by default. This means that if you just overwrite files on the /system partition - it will fail to verify and in the best case it'll continue using the old filesystem - in the worst case it'll fail to boot. Luckily for us the kernel partition can be extracted with TWRP. After looking at it with a hex editor I saw the mount options right there in the kernel file - and replaced the word "verify" with spaces - meaning that /system can now be modified without dm-verity getting in the way :) In the firmware archive below you can find this patched kernel image - which you can also flash using fastboot. After patching the kernel I simply used TWRP to root the device. This is what the kernel image looks like in a hex editor, do you see the "verify" mount option?

Power management

Since this phone is quite power hungry I've added a few tweaks to make the phone run slower - but more power efficient. The first thing is that I modified the /vendor/etc/init/hw/init.mt6771.rc file with the following settings:

on property:sys.boot_completed=1
    exec u:r:magisk:s0 root root -- /system/bin/slow
    exec u:r:magisk:s0 root root -- /system/bin/setenforce 0

To test the performance of this modification I've added the /bin/batusage script with the following code:

printf %.10f\\n "$(( $( su -c cat /sys/class/power_supply/battery/current_now ) 
 *  $( su -c cat /sys/class/power_supply/battery/voltage_now ) ))e-12"

After a reboot - it turns out the power my phone uses has more than halved. It *is* painfully slow at these settings though. So - we need to add a few scripts to either conserve power or speed up the phone. I made the scripts /bin/fast and /bin/slow for this. Their contents are the following:

Armor_3W:/ # cat /bin/slow
echo "Setting CPU to low power consumption."

echo schedutil | su -c "tee /sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
echo schedutil | su -c "tee /sys/devices/system/cpu/cpufreq/policy4/scaling_governor"
echo 1  | su -c "tee /sys/devices/system/cpu/cpu0/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu1/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu2/online"
echo 0 | su -c "tee /sys/devices/system/cpu/cpu3/online"
echo 0 | su -c "tee /sys/devices/system/cpu/cpu4/online"
echo 0 | su -c "tee /sys/devices/system/cpu/cpu5/online"
echo 0 | su -c "tee /sys/devices/system/cpu/cpu6/online"
echo 0 | su -c "tee /sys/devices/system/cpu/cpu7/online"
echo 1600000 | su -c "tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
echo 1600000 | su -c "tee /sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq"
echo 1600000 | su -c "tee /sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq"
echo 800000 | su -c "tee /sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq"
echo 800000 | su -c "tee /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq"
echo 800000 | su -c "tee /sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq"
echo 800000 | su -c "tee /sys/devices/system/cpu/cpu6/cpufreq/scaling_max_freq"
echo 800000 | su -c "tee /sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq"
echo 1600000 | su -c "tee /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq"
echo -1 | su -c "tee /proc/fliperfs/perf_ddr3"
echo 5 | su -c "tee /proc/sys/vm/laptop_mode"
echo 3000 | su -c "tee /proc/sys/vm/dirty_writeback_centisecs"
echo 3000 | su -c "tee /proc/sys/vm/dirty_expire_centisecs"
echo 80 | su -c "tee /proc/sys/vm/dirty_ratio"
echo 20 | su -c "tee /proc/sys/vm/dirty_background_ratio"

Armor_3W:/ # cat /bin/fast
echo "Setting CPU to high performance."

echo performance | su -c "tee /sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
echo performance | su -c "tee /sys/devices/system/cpu/cpufreq/policy4/scaling_governor"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu0/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu1/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu2/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu3/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu4/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu5/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu6/online"
echo 1 | su -c "tee /sys/devices/system/cpu/cpu7/online"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu6/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq"
echo 2106000 | su -c "tee /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq"
echo 0 | su -c "tee /proc/sys/vm/laptop_mode"
echo 1 | su -c "tee /proc/fliperfs/perf_ddr3" 
Furthermore we empty the files /vendor/etc/power_whitelist_cfg.xml and /vendor/etc/powerscntbl.cfg so that the vendor installed overclocking tool does not mess with our power-saving results. To make all these modifications it's convenient to use nano. Simply download a nano binary and set your environment to point to the correct terminal via the file /system/etc/mkshrc - the file that gets run every time ADB Is connected.

Cleaning up system apps

This part speaks for itself - from this ROM I've removed all system apps that weren't completely neccessary. This to reduce Google's ability to track the phone - but also to reduce power usage and make the UI more efficient. The play store was removed and replaced with the open-source F-droid.

Patching services.jar for signature spoofing

This was by far the most time consuming and difficult part in setting up this phone - so bear with me. You will need the gentoo package "apktools" as well as VdexExtractor. You can then follow this guide to deodex ( remove the vdex files ) your services.jar. Once you have a services.jar with a full classes.dex you can proceed to the next step. Place the services.jar somewhere, run "apktool d services.jar" and go to the output folder of apktool. Apktool will dissasemble your services.jar binary into smali files - which can be modified to patch the java binaries.

I made the following modifications:

Patch PackageManagerServiceUtils.smali, replacing the following methods:

.method public static verifySignatures(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$SigningDetails;ZZ)Z
    .locals 1
    .param p0, "pkgSetting"    # Lcom/android/server/pm/PackageSetting;
    .param p1, "disabledPkgSetting"    # Lcom/android/server/pm/PackageSetting;
    .param p2, "parsedSignatures"    # Landroid/content/pm/PackageParser$SigningDetails;
    .param p3, "compareCompat"    # Z
    .param p4, "compareRecover"    # Z
    .annotation system Ldalvik/annotation/Throws;
        value = {
    .end annotation

    const/4 v0, 0x1
    return v0
.end method

.method public static compareSignatures([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)I
    .locals 1
    .param p0, "s1"    # [Landroid/content/pm/Signature;
    .param p1, "s2"    # [Landroid/content/pm/Signature;

    const/4 v0, 0x0
    return v0
.end method

Patch PermissionManagerService.smali replacing the following method
.method private grantSignaturePermission(Ljava/lang/String;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/permission/BasePermission;Lcom/android/server/pm/permission/PermissionsState;)Z
    .locals 1
    .param p1, "perm"    # Ljava/lang/String;
    .param p2, "pkg"    # Landroid/content/pm/PackageParser$Package;
    .param p3, "bp"    # Lcom/android/server/pm/permission/BasePermission;
    .param p4, "origPermissions"    # Lcom/android/server/pm/permission/PermissionsState;
    const/4 v0, 0x1
    return v0
.end method

Add a null check to KeySetManagerService:
.method public removeAppKeySetDataLPw(Ljava/lang/String;)V
    .locals 7
    .param p1, "packageName"    # Ljava/lang/String;

    .line 578
    iget-object v0, p0, Lcom/android/server/pm/KeySetManagerService;->mPackages:Landroid/util/ArrayMap;

    invoke-virtual {v0, p1}, Landroid/util/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Lcom/android/server/pm/PackageSetting;

    .line 579
    .local v0, "pkg":Lcom/android/server/pm/PackageSetting;

     if-eqz v0, :cond_1

    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;->()V

    const-string/jumbo v2, "pkg name: "

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    const-string v2, "does not have a corresponding entry in mPackages."

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

    invoke-static {v0, v1}, Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    .line 581
    iget-object v1, v0, Lcom/android/server/pm/PackageSetting;->keySetData:Lcom/android/server/pm/PackageKeySetData;

    invoke-virtual {v1}, Lcom/android/server/pm/PackageKeySetData;->getProperSigningKeySet()J

    move-result-wide v1

    .line 582
    .local v1, "signingKeySetId":J
    invoke-direct {p0, v1, v2}, Lcom/android/server/pm/KeySetManagerService;->decrementKeySetLPw(J)V

    .line 583
    iget-object v3, v0, Lcom/android/server/pm/PackageSetting;->keySetData:Lcom/android/server/pm/PackageKeySetData;

    invoke-virtual {v3}, Lcom/android/server/pm/PackageKeySetData;->getAliases()Landroid/util/ArrayMap;

    move-result-object v3

    .line 584
    .local v3, "definedKeySets":Landroid/util/ArrayMap;, "Landroid/util/ArrayMap;"
    const/4 v4, 0x0

    .line 584
    .local v4, "i":I
    invoke-virtual {v3}, Landroid/util/ArrayMap;->size()I

    move-result v5

    if-ge v4, v5, :cond_0

    .line 585
    invoke-virtual {v3, v4}, Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object;

    move-result-object v5

    check-cast v5, Ljava/lang/Long;

    invoke-virtual {v5}, Ljava/lang/Long;->longValue()J

    move-result-wide v5

    invoke-direct {p0, v5, v6}, Lcom/android/server/pm/KeySetManagerService;->decrementKeySetLPw(J)V

    .line 584
    add-int/lit8 v4, v4, 0x1

    goto :goto_0

    .line 589
    .end local v4    # "i":I
    invoke-direct {p0, v0}, Lcom/android/server/pm/KeySetManagerService;->clearPackageKeySetDataLPw(Lcom/android/server/pm/PackageSetting;)V


    .line 590
.end method 

This github repository contains the java sources for this package, it was very useful to be able to see the actual Java code instead of just the smali. This page with dalvik VM opcodes is also useful when modifying smali files.
With these patches applied you can install any package over any other package - regardless of signature. Now all we need to do is spoof the GSF to always have the system signature. For me the Tingle android patcher worked really well for this. It's a very simple vdex modification to just set the signature to the system signature.

And that's it - you're done - rebuild the package with "apktool b" and install it to your /system/framework/services.jar file. You should now have signature spoofing enabled on your ROM. This allows you to use the microG framework - which is much lighter and has much less tracking than the original GSF. You can also use it to run something like this: https://medium.com/@Malinskiy/reliable-testing-test-butler-and-rooted-devices-2c40cf0bf2dc.

File Armor_3W.7z
Size 1.22GB
crc32 2552965352
md5 c6314779f900003c2977fe1d90f4ecad
sha512 899dddb03532e1bacfcbf9aac0c19dbcb782d1636604ba2b7294bee8d8243ba4b7ec4708d3eba824121985e20b0d06a2a3e1333a1ee8d88f07352686279cd862