(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