(2024-03-11) The Graphene Saga: part 1
--------------------------------------
"Two things are infinite, the universe and human stupidity, and I am not yet
completely sure about the universe." — Albert Einstein

When it comes to modern touchscreen smartphones, you don't choose the good
one by filtering out bad ones, you choose the least worst of them among the
pile of total garbage. Sad but true. The Google Pixel line is one of such
"the least worst" examples, because at least they don't have any trojans
preinstalled by the vendor besides trojans from Google itself, which, in
turn, can be mitigated by installing some custom firmware these top-notch
bricks usually have excellent support for.

This is, in essence, how I came to know about GrapheneOS. Its website brags
about security hardening, privacy features and curbing the Google-specific
services to the same privilege level as the rest of the applications, and,
to be honest, it's easier to build a Google-less Android ecosystem if one
keeps it this way. Needless to say, I was interested in such a system ever
since I got myself a Pixel 6, but managed to find time and resources to
install it only recently. And I was... disappointed.

No, I don't give a shit about Google Wallet support at the moment (although
we'll get to that later). But I do care about two things every
privacy-oriented smartphone OS must offer IMO: rootability and IMEI editing.
And, after lurking on Reddit and Graphene's own forum, I was a bit surprised
that its authors (or at least its spokespeople) have been strongly opposing
both of these things. And they used very weak argumentation, to put it
mildly, but we'll get to that later too. Having thrown several rants on
Nostr about this, I decided to act alone and fix what they won't fix at
least for my own installation.

Rooting process and subsequent OTA update patching are wonderfully covered by
the avbroot ([1]) guide, and I recommend everyone wanting to root their
GrapheneOS installation to read it very carefully. The only caveat I need to
warn about is that you need to reboot from fastbootd back to normal fastboot
mode before running fastboot erase avb_custom_key and subsequent fastboot
flash avb_custom_key commands. I wasn't (and still ain't) sure how
GrapheneOS works with custom kernels, so I chose the Magisk route instead of
KernelSU. But then, I came across a different problem: non-working Zygisk.

Yes, of course I want to use this Pixel for some corporate apps that are
behind Intune Company Portal, which is another M$'s privacy invading piece
of crap, but they don't work without it installed. And of course, it detects
root. And, of course, Zygisk framework (which all root-hiding modules
effectively use) doesn't work specifically on Android 14 based GrapheneOS.
And Magisk developers refused to accept the patches adding this support with
even more stupid argumentation:

> GrapheneOS hates root and any modification, No reason to be compatible with
operating systems that hate us.

> ...if its built upon AOSP, they can avoid breaking magisk (because magisk
supports AOSP). if they really break magisk, that means they dont care about
magisk. you should ask them to avoid breaking magisk (or submit their
so-called security changes to AOSP), rather than begging here.

It's hard for me to comment on anything of this. Seems FOSS developers really
have forgotten why they do FOSS. In their quarrels, the only one who really
suffers is the end user. Or are they probably afraid that someone is going
to have a degoogled AND rooted AND hostile work environment ready Android
flavour to just enjoy their devices while being in full control of them?

I tried manually applying those patches myself and spent 3 hours (no kidding)
building Magisk. It built and ran (after I repatched my OTA, of course) but
Zygisk still didn't work (and the modules I run don't to jack shit with
ZygiskNext). Maybe I'll spend some time later to figure this out but, for
the time being, I decided to focus on the next topic: IMEIs. And I don't
even know where to start telling you about them on this Pixel 6.

Well, how about I start by providing several quotations on what GrapheneOS
spokespeople tell us about IMEI changing, the field I've been in for good 5
years already?

> Spoofing the IMEI shown in the OS is not changing the IMEI used for
cellular, and is not useful beyond fooling yourself. Changing the IMEI used
for cellular is not possible with modern cellular radios, which are required
by regulations to prevent changing it. Changing it requires a cellular radio
exploit, which would imply not patching the radio or using a device with an
insecure cellular radio.

> Despite articles and guides online it is not possible to truly change your
IMEI. It is baked into the baseband processor and any changing of it in an
Android perspective is just spoofing the value in the operating system so
system-level applications would see a different number. When using a
cellular network the original IMEI would still broadcast out.

> This thread is completely filled with misinformation and will have to be
removed. It's not clear why people don't listen to our official responses
explaining that changing IMEI does not mean identifiers are not provided to
the cellular network and other things we've explained here.

And then they blocked the threads and accused everyone else of "spreading
misinformation", uh-huh. When they were the only ones actually spreading it.
No, I don't rule out the possibility that they genuinely believe in what
they say (i.e. that the IMEI sent to the network is still burned into some
OTP areas like it's still 2007 out there) but they provide absolutely no
proof to their claims. Oh, well. Regulations. I know how they "work". I know
that certification process doesn't check whether the IMEI actually is
writeable or not. What really happens afterwards (if the certification
process even gets to this point, which I suspect it often doesn't, they are
usually only interested in proper radio frequency ranges and output power)
is that the vendor demonstrates that there's no way to edit those
identifiers in the stock production OS config. That's it.

I don't work in the telecom industry at all but I know all of this. They
supposedly work on a large enough telecom project and believe in whatever
Big Brother feeds into their brains. And yes, I do happen to have a cellular
carrier who displays the model of the phone on the personal account page. So
I can easily check which IMEI the network really sees. This is, in fact, my
only source of truth, not what's displayed in *#06# etc. So, this was the
moment I decided to prove that the IMEIs seen by the network are indeed
editable in Pixel 6 and to publicly demonstrate how wrong these Graphene
forum warriors are.

Now, here's the real kicker: as soon as Pixels switched from Qualcomm to
Tensor chipsets, they also had to switch the baseband module. Guess what
they chose? Exynos! Ta-da! To be more precise, Pixel 6 has Exynos 5123, but
it doesn't quite matter to me, I had never explored any of them before. So,
from the bits and pieces, I collected three important facts: 1) IMEIs are
stored in /mnt/vendor/efs/nv_protected.bin (and the .md5 file is salted so
no way of restoring it manually), 2) AT commands are sent by forwarding them
to /dev/umts_router, 3) there are AT+GOOGSETNV and AT+GOOGGETNV commands
with some already known syntax and examples on GitHub. That's friggin' it.
Everything else was to be found out without any external help.

Of course, first I decided to dump everything found under /mnt/vendor, and I
noticed it also contained the bare modem firmware binary image. Luckily, it
didn't contain any compression or obfuscation, so I could search for some AT
commands and NV item names. And indeed, three of them (yes, three) turned
out to be related to IMEIs: CAL.Common.Imei, CAL.Common.Imei_2nd and
DS_CAL.Common.Imei. The third one, I guess, was supposed to be used if the
device has the second physical SIM slot in addition to eSIM, but of course,
this is never the case for Pixel 6. Interestingly, the IMEI value for this
non-existing slot matches the old Nokia 6310. A very unexpected tribute.

Anyway, I found out how to write IMEIs to the "live" EFS (mapped to that
nv_protected.bin file, and the .md5 is updated automatically, so no need to
worry about it). The IMEI format is byte by byte BCD, normal order,
zero-padded at the last byte (after the check digit). You must write 9 bytes
(from 0 to 8), the last one being always 00. E.g. the
AT+GOOGSETNV="CAL.Common.Imei",0,"35" command writes the first two digits of
IMEI1 (35) to the first byte, and AT+GOOGSETNV="CAL.Common.Imei_2nd",5,"82"
writes the 6th digit pair 82 to IMEI2. You get the idea. I even employed a
newly found AT+GOOGFLUSHNV command to make sure the items are written.
However, it wouldn't be a flagship smartphone if everything were that
simple. These values get overwritten upon reboot (or AT+GOOGNVRESET, for
that matter).

Where are they overwritten from? I really don't know yet. Not
/mnt/vendor/efs_backup for sure. Not other (nv_normal.bin) EFS values. Not
the metadata partition. Probably the devinfo partition, but it can't control
everything, can it? This is something I really need to research further.
However, for the time being, I decided to check whether the new IMEIs could
be seen by the network without rebooting. For that, I remembered the old
good AT+CFUN command. To my surprise, only AT+CFUN=4,1 actually did seem to
work: 4 means cellular flight mode, 1, as I found out elsewhere, means
"modem state save" or something like this. Well, state save was exactly what
I needed. And then I turned the radio back on with AT+CFUN=1. And guess
what... It worked! My carrier did show my active phone as Nokia 6310 in the
account page. Well, who's a fool now?

Of course, when trying to automate all this, I went through a lot of trial
and error and it still doesn't seem very stable (I really need to switch to
a more reliable way of interacting with /dev/umts_router than just echo and
cat), but a general approach to getting temporary IMEIs (that is, the ones
working until reboot) is quite clear for the time being. I'm going to post
some work-in-progress documentation about what I have found so far. In the
LuxDocs section, of course. But the quest for persistent IMEI editing on
these devices has just begun.

--- Luxferre ---

[1]: https://github.com/chenxiaolong/avbroot