'Firmware Downgrade with SPI Rescue' question
Closed this issue · 8 comments
Hi. I am going to play with this awesome project. But before, I would like to clarify some things.
Whether I correctly understood, to downgrade the EC image, I have to download the "11.0.0 (RP1A.200720.009, Sep 2020)" image, unpack it, mount the 'vendor' partition, extract the 'ec.rec' from there and then push it to the device by means of the fastboot tool?
UPDATE: Just found that the EC version which has required bugs is in the "11.0.0 RQ1A.210105.003, Jan 2021" factory image. ec.bin from that image exposes such string:
brick_v0.0.8232-b1e3ea340 2020-09-25 16:57:52 wfrichar
which is matched to the reported one.
The log of flashing the ec image:
$ fastboot stage ec.rec
Sending 'ec.rec' (185 KB) OKAY [ 0.119s]
Finished. Total time: 0.210s
$ fastboot oem citadel rescue
(bootloader) Recovering citadel - it may take a couple of minutes
OKAY [ 28.708s]
Finished. Total time: 28.710s
At the first glance, the image was written successfully. Are there options to verify from the userspace that the required image indeed runs?
The /vendor/bin/hw/citadel_updater command doesn't work for this purpose.
blueline:/data/local/tmp # /vendor/bin/hw/citadel_updater -l
ERROR: Unable to connect
ERROR: execute_command failed(1)!
AOSP has such comment/code:
// Citadel info (only enabled on -eng and -userdebug builds)
if (!PropertiesHelper::IsUserBuild()) {
RunCommandToFd(fd, "Citadel ID", {"/vendor/bin/hw/citadel_updater", "--id"});
RunCommandToFd(fd, "Citadel VER", {"/vendor/bin/hw/citadel_updater", "-lv"});
RunCommandToFd(fd, "Citadel SELFTEST", {"/vendor/bin/hw/citadel_updater", "--selftest"});
}
Could you, please, describe in more details how the firmware update based on the nugget task works. The presentation describes briefly how the firmware is updated by means of the nugget task. The unclear part is what app (from the userspace level) triggers firmware updating?
Thanks.
It seems that you were successful in downgrading the firmware. You can also check this by running:
$ fastboot oem citadel version
On userspace side, the script /vendor/bin/hw/init_citadel
will try to update the firmware if the version embedded in the system in more recent (it uses citadel_updater
). See my answer to issue #3 to overcome this.
Now it returns:
$ fastboot oem citadel version
(bootloader) Citadel version:
(bootloader) Chip: Google Citadel C2-PVT
(bootloader) Board: 0
(bootloader) RO_A: 0.0.3/d55cc99c ok
(bootloader) RO_B: * 0.0.3/874a9517 ok
(bootloader) RW_A: 0.0.3/brick_v0.0.8232-b1e3ea340 ok
(bootloader) RW_B: * 0.0.3/brick_v0.0.8232-b1e3ea340 ok
OKAY [ 0.084s]
Finished. Total time: 0.086s
Ah the system updated the firmware anyway and both slot are now using the downgraded version. To use our exploit, you should run the slot A. So you need either a lower Android version (one that embed a firmware older than the one you want to downgrade to). Or simply patch your Android vendor image and rename the init_citadel
script.
I will try to rename the init_citadel
first as it is simpler for me to do. Does this mean the exploit is adopted for the memory addresses in the range 0x44000 - 0x70000 (I didn't learn the exploit yet as I have been trying to setup a working environment).
It is still not clear for me the concept of choosing the specific RO -> RW chain. Namely, how the BootROM choose what RO_ image to run (A or B). And after that whether, say, RO_A can launch RW_B image? Or RO_A can launch only RW_A but RO_B only RW_B?
Just learned the state immediately after flashing the ec.rec. Active RW_B was invalidated.
$ fastboot oem citadel version
(bootloader) Citadel version:
(bootloader) Chip: Google Citadel C2-PVT
(bootloader) Board: 0
(bootloader) RO_A: 0.0.3/d55cc99c ok
(bootloader) RO_B: * 0.0.3/874a9517 ok
(bootloader) RW_A: * 0.0.3/brick_v0.0.8232-b1e3ea340 ok
(bootloader) RW_B: Error
OKAY [ 0.148s]
Finished. Total time: 0.148s
Yes, we based our exploit on RW_A image (offset ad addresses). The loaders and the bootrom will check the magic number, the version and the signature of the next image. It starts with the most recent one, and if the verification fails for some reasons, it tries the second one.
Current runtime state from the already booted Android is
Chip: Google Citadel C2-PVT
Board: 0
RO_A: 0.0.3/d55cc99c ok
RO_B: * 0.0.3/874a9517 ok
RW_A: * 0.0.3/brick_v0.0.8232-b1e3ea340 ok
RW_B: Error
It answers some my questions. The one thing is still unclear is whether the nugget-task based update (initiated via init_citadel) is able to activate and then jump on the just activated image when the Android was already booted up? In my case it was the RW_B image.
Yes, nugget task can update the firmware. However, this update feature will replace the magic number from the image header. The result is that the loader won't try to boot on the image. To enable the image, there is a specific nugget command that requires the user password.