8000 firehose: add OPPO/OnePlus VIP (verified image protection) support by 2loch-ness6 · Pull Request #829 · bkerler/edl · GitHub
[go: up one dir, main page]

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,34 @@ to get back the 0x9008 mode :
- ```edl e misc --memory=ufs --lun=0``` -> to erase the partition misc on lun 0
- ```edl gpt . --genxml --memory=ufs``` -> dump gpt_main[lun].bin/gpt_backup[lun].bin and write rawprogram[lun].xml to current directory (".")

### For OPPO/OnePlus devices with VIP (verified image protection)

Newer OPPO/OnePlus/Realme devices (SM8650 and up) run a "VIP" protected programmer. It ignores
every read, write and erase until the host has handed it the signed digest table that ships with
the firmware, and it then wants a label naming a partition of that table on every access. Without
it the log stops at:

```
firehose - INFO: VIP is enabled, receiving the partition info of size 36864
firehose - [LIB]: ERROR: label cannot be null
```

Take the digest table (```Digest.elf```, sometimes ```Digest.mbn```) and the signature (```Sign.bin```,
256 bytes padded to 4096) from the OPPO/OnePlus firmware and pass them:

- ```edl printgpt --memory=ufs --lun=0 --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --skipinitialread``` -> to print the gpt of a VIP protected device
- ```edl r abl_b abl_b.img --memory=ufs --lun=4 --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --skipinitialread``` -> to dump a partition, the label is taken from the partition name
- ```edl rl dumps --memory=ufs --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --skipinitialread``` -> to dump all partitions, one label per partition
- ```edl w abl_b abl_b.img --memory=ufs --lun=4 --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --skipinitialread``` -> to write a partition
- ```edl wl dumps --memory=ufs --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --skipinitialread``` -> to write a whole dump directory
- ```edl rs 517223 256 abl_b.img --memory=ufs --lun=4 --vip --vip-digest=Digest.elf --vip-sign=Sign.bin --vip-label=abl_b``` -> to read raw sectors. There is no partition name to fall back on here, so the label has to be given with ```--vip-label```

Notes:

- ```--vip-sign``` is optional: without it the handshake stops after the digest table, which is all that some programmers ask for.
- ```--skipinitialread``` skips the probe read of ```configure()```, recommended on VIP targets: a refused probe leaves a response behind that spoils the next read.
- The digest table is the access list of the target. Partitions that are not in it, or that are listed with ```r:0```, answer ```ERROR: not get permission```/```not allowed on external network```. The target prints the entry it matched, e.g. ```INFO: entry:misc, w:1, r:0, e:1, c:0, s:0, start:0x2008, num:0x100```.

### QFIL emulation (credits to LyuOnLine):

- For flashing full image:
Expand Down Expand Up @@ -313,13 +341,13 @@ For Oneplus 6T, enter *#801#* on dialpad, set Engineer Mode and Serial to on and
## Issues

- Secure loader with SDM660 on Xiaomi not yet supported (EDL authentification)
- VIP Programming not supported (Contributions are welcome !)
- EFS directory write and file read has to be added (Contributions are welcome !)


## Tested with

- Oneplus 3T/5/6T/7T/8/8t/9/Nord CE/N10/N100 (Read-Only), BQ X, BQ X5, BQ X2, Gigaset ME Pure, ZTE MF210, ZTE MF920V, Sierra Wireless EM7455, Netgear MR1100-10EUS, Netgear MR5100
- Oneplus 12 (CPH2581, SM8650, UFS) via VIP digest table: printgpt, partition read and partition write
- SIMCOM SIM8905E

Published under GPLv3 license
Expand Down
45 changes: 44 additions & 1 deletion edl.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@
--skip=partnames Skip reading partition with names "partname1,partname2,etc."
--genxml Generate rawprogram[lun].xml
--devicemodel=value Set device model
--vip Enable the OPPO/OnePlus VIP handshake
--vip-digest=filename Signed digest table (Digest.elf / Digest.mbn) for VIP targets
--vip-sign=filename Signature (Sign.bin) sent after the EnableVip verify step
--vip-label=label Partition label used to authorise reads/writes on VIP targets
--skipinitialread Skip the first storage sector read done by configure
--portname=portname Set serial port name (/dev/ttyUSB0 for Linux/MAC; \\\\.\\COM1 for Windows)
--serial Use serial port (port autodetection)
--slot Set active slot for setactiveslot [a or b]
Expand All @@ -148,7 +153,45 @@
from edlclient.Library.utils import LogBase
from edlclient.Library.utils import is_windows

args = docopt(__doc__, version='3')

# Options that apply to every command but are not part of the per command usage
# patterns below. docopt only accepts options which occur in the usage pattern of
# the command that is invoked, so these are pulled out of argv here and merged
# into the parsed arguments, instead of being repeated in every usage line.
GLOBAL_OPTIONS = {
"--vip": False, # enable the OPPO/OnePlus VIP handshake
"--vip-digest": None, # signed digest table (Digest.elf / Digest.mbn)
"--vip-sign": None, # signature (Sign.bin)
"--vip-label": None, # partition label used to authorise reads and writes
"--skipinitialread": False, # do not probe the storage in configure()
}


def extract_global_options(argv, defaults):
"""Split argv into docopt arguments and the GLOBAL_OPTIONS values."""
values = dict(defaults)
filtered = [argv[0]]
index = 1
while index < len(argv):
arg = argv[index]
name = arg.split("=", 1)[0]
if name not in defaults:
filtered.append(arg)
elif arg == name:
if isinstance(defaults[name], bool):
values[name] = True
elif index + 1 < len(argv):
index += 1
values[name] = argv[index]
else:
values[name] = arg.split("=", 1)[1]
index += 1
return filtered, values


_args, _extra_args = extract_global_options(sys.argv, GLOBAL_OPTIONS)
args = docopt(__doc__, argv=_args[1:], version='3')
args.update(_extra_args)

print("Qualcomm Sahara / Firehose Client V3.62 (c) B.Kerler 2018-2025.")

Expand Down
Loading
0