[LG V20 Guides, News, & Discussion] runningnak3d:
First, please don't make the mods come in a clean this thread. Just because I am 99% convinced that it can't be done, doesn't mean that I am right.

Look at my post history concerning H918 ARB1 devices getting root. I had so many ups and downs with that. I was absolutely convinced it couldn't be done because I knew how flashing with laf worked, but then I was absolutely convinced I had it, but I was wrong, and then wash / rinse / repeat about 7 more times -- it was a total roller-coaster.

With that said, I am opening this post to describe what I know to be the process, and ideas as to how it can be circumvented, but maybe I or someone else will see something completely outside the box.

So, I decompiled the classes.dex from TMO_Simlock.apk (don't let the name fool you, it is actually to UNLOCK), and decompiled the modem firmware.

I was wrong about the fact that the modem queries their server on every boot. It reads an SFS registry key:

This is the structure of the message that is sent to the server, and what is received:

public class TrustletProtocol
implements w
{
private static final int END_TIME_SIZE_BYTES = 4;
private static final int EXPIRY_TIME_OFFSET_BYTES = 332;
private static final int HMAC_SIZE_BYTES = 32;
private static final int IMEI_SIZE_BYTES = 16;
private static final int MAC_SIZE_BYTES = 32;
private static final int MILLS_PER_SECOND = 1000;
private static final int RESPONSE_MESSAGE_LENGTH_OFFSET = 2;
private static final int SERVER_ERROR_MESSAGE_LENGTH_OFFSET = 12;
private static final int SERVER_ERROR_MESSAGE_OFFSET = 16;
public static final String SERVER_URL = "https://unlock.t-mobile.com/unlock/unlock";
private static final int SIGNATURE_SIZE_BYTES = 256;
private static final int SIMLOCK_SETTINGS_LENGTH_BYTES = 4;
private static final int SIMLOCK_SETTINGS_VERSION_MAJOR_OFFSET = 0;
private static final int SIMLOCK_SETTINGS_VERSION_MINOR_OFFSET = 2;
private static final int START_TIME_SIZE_BYTES = 8;
private static final String TAG = TrustletProtocol.class.getName();
private static final int UNLOCK_REQUEST_FIXME = 4;
private static final int UNLOCK_REQUEST_PARTIAL = 3;
private static final int UNLOCK_REQUEST_PERMANENT = 2;
private static final int UNLOCK_REQUEST_RESERVED = 0;
private static final int UNLOCK_REQUEST_TEMPORARY = 1;
private static final byte UNLOCK_SERVER_RESPONSE_TYPE = 40;
private static boolean mSimLockJniLoaded = false;
private n mHttp;
private long mLockedUntil;
private boolean mRebootRequired = false;
private boolean mUseAttestation = true;
private String serverMessage;

The serverMessage is the key that is written to the SFS registry. For those that don't know, the SFS is a protected filesystem that runs in the TrustZone context. You can VIEW it (well at least some (most?) in /persist or /persist-lg, but if you think: "Oh I am just going to go change that as root" watch how quick you (at best) have a broken phone, and at worst, have a brick.

While I was wrong about the modem firmware checking the unlock site on every boot, that was due to looking at the code to quickly. What actually happen is:

Unlock app submits a request -- this request is signed with an RSA cert.

Unlock gets a reply. If you are allowed to unlock, then a key (which is RSA signed) gets written to some untrusted location (haven't found it yet, but knowing where is pointless. Hell it could be written to /data).

A flag gets set instructing the modem to write this key to SFS

When you reboot your phone, the modem (which runs in the TZ so CAN write to SFS) writes the key

Your phone is now unlocked.

I only see one way to make this work -- fool the unlock server into giving you a key.

Even if we could perform a TZ attack so that we could write to SFS, we wouldn't have a SIGNED key.

Now, how do we go about fooling the unlock server into handing us a key? The unlock app has checks that prevent it from doing anything if running on a rooted phone. I don't know how, but even Magisk hide doesn't fix it. I am guessing that it checks if the bootloader is unlocked since I uninstalled Magisk and it still would not do anything (it should return an error that my phone is already unlocked).

Anyway, this can be patched out, and we can get it to run, or hell, figure out the exact message structure that is sent to the server, get a key, and then figure out where it needs to be written, and what flag needs to be set to have the modem write it to SFS (easier to just hack the app :) ).

Something else interesting in the app:

public void onCreate(SQLiteDatabase paramSQLiteDatabase)
{
s.a(b, "Crating database for provider: create table history(_id integer primary key autoincrement, action text not null, status integer, stamp integer, until integer, result text not null);");
paramSQLiteDatabase.execSQL("create table history(_id integer primary key autoincrement, action text not null, status integer, stamp integer, until integer, result text not null);");
}

It creates a SQLite database with a single table called 'history'. It looks like this keeps a log of attempts to SIM unlock and the status, and if it is a temp unlock, the time stamp.

I am fairly certain this is useless, just found it interesting. Even with a temp unlock, there must be a key in SFS.

Ideas folks? Before someone says: "Intercept the traffic and make our own key" I will refer you back to the fact that it is RSA signed and we don't have the cert.

-- Brian