Skip to content

Commit 26c3150

Browse files
antR0rt1z2
andcommitted
chore: Move to update-extractor.py for Huawei's UPDATE.APP
From: https://github.com/R0rt1z2/hisi-playground/blob/main/update-extractor.py Co-authored-by: Roger Ortiz <[email protected]>
1 parent 7547fdb commit 26c3150

File tree

3 files changed

+110
-127
lines changed

3 files changed

+110
-127
lines changed

extractor.sh

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ otadump="$toolsdir/otadump"
8080
sdat2img="$toolsdir/sdat2img.py"
8181
ozipdecrypt="$toolsdir/oppo_ozip_decrypt/ozipdecrypt.py"
8282
lpunpack="$toolsdir/lpunpack"
83-
splituapp="$toolsdir/splituapp"
83+
update_extractor="$toolsdir/update-extractor.py"
8484
pacextractor="$toolsdir/pacExtractor.py"
8585
nb0_extract="$toolsdir/nb0-extract"
8686
kdz_extract="$toolsdir/unkdz.py"
@@ -561,27 +561,22 @@ elif [[ $(7z l -ba "${romzip}" | grep ".*.rar\|.*.zip") ]]; then
561561
"$LOCALDIR/extractor.sh" "$tmpdir"/zipfiles/"$file" "${outdir}"
562562
done
563563
exit
564-
elif [[ $(7z l -ba "${romzip}" | grep "UPDATE.APP") ]]; then
565-
echo "Huawei UPDATE.APP detected"
566-
7z x "${romzip}" UPDATE.APP
567-
python3 "$splituapp" -f "UPDATE.APP" -l super preas preavs || (
568-
for partition in $PARTITIONS; do
569-
python3 "$splituapp" -f "UPDATE.APP" -l "${partition/.img/}" || echo "$partition not found in UPDATE.APP"
570-
done)
571-
if [ -f super.img ]; then
572-
($simg2img super.img super_* super.img.raw || mv super.img super.img.raw) 2>/dev/null
564+
elif 7z l -ba "${romzip}" | grep -q "UPDATE.APP"; then
565+
echo "[INFO] Huawei 'UPDATE.APP' detected"
573566

574-
for partition in $PARTITIONS; do
575-
($lpunpack --partition="$partition"_a super.img.raw || $lpunpack --partition="$partition" super.img.raw) 2>/dev/null
576-
if [ -f "$partition"_a.img ]; then
577-
mv "$partition"_a.img "$partition".img
578-
else
579-
foundpartitions=$(7z l -ba "${romzip}" | gawk '{ print $NF }' | grep "$partition".img)
580-
7z e -y "${romzip}" "$foundpartitions" dummypartition 2>/dev/null >> "$tmpdir"/zip.log
581-
fi
582-
done
583-
rm -rf super.img.raw
584-
fi
567+
# Gather and extract 'UPDATE.APP' from archive
568+
7z x "${romzip}" UPDATE.APP >> "$tmpdir"/zip.log
569+
python "${update_extractor}" -e UPDATE.APP -o ${PWD} > /dev/null
570+
571+
# Change partition's name to lowercase
572+
for f in $(find . -name '*.img'); do
573+
mv ${f} ${f,,}
574+
done
575+
576+
# Extract 'super.img' if present
577+
[ -f super.img ] &&
578+
echo "[INFO] Extracting 'super.img'..." \
579+
superimage
585580
fi
586581

587582
for partition in $PARTITIONS; do

tools/splituapp

Lines changed: 0 additions & 106 deletions
This file was deleted.

tools/update-extractor.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from io import BytesIO
2+
from pathlib import Path
3+
from struct import unpack
4+
from argparse import ArgumentParser
5+
from typing import List
6+
7+
MAGIC = b'\x55\xAA\x5A\xA5'
8+
9+
CHUNK_SIZE = 0x400 # 1024 bytes
10+
ALIGNMENT = 4 # Alignment bytes
11+
12+
class Partition:
13+
def __init__(self, start: int, hdr_sz: int, unk1: int, hw_id: int, seq: int,
14+
size: int, date: str, time: str, ftype: str, blank1: bytes,
15+
hdr_crc: int, block_size: int, blank2: bytes, checksum: bytes,
16+
data: bytes, end: int):
17+
self.start = start
18+
self.hdr_sz = hdr_sz
19+
self.unk1 = unk1
20+
self.hw_id = hw_id
21+
self.seq = seq
22+
self.size = size
23+
self.date = date
24+
self.time = time
25+
self.type = ftype
26+
self.blank1 = blank1
27+
self.hdr_crc = hdr_crc
28+
self.block_size = block_size
29+
self.blank2 = blank2
30+
self.checksum = checksum
31+
self.data = data
32+
self.end = end
33+
34+
@classmethod
35+
def from_file(cls, file, offset: int = 0):
36+
hdr_sz, unk1, hw_id, seq, size = unpack('<LLQLL', file.read(24))
37+
date, time, type = file.read(16).decode().strip('\x00'), \
38+
file.read(16).decode().strip('\x00'), file.read(16).decode().strip('\x00')
39+
blank1, hdr_crc, block_size, blank2, checksum = file.read(16), file.read(2).hex(), \
40+
file.read(2).hex(), file.read(2), file.read(hdr_sz - 98)
41+
42+
data = file.read(size) if size > 0 else b''
43+
44+
file.seek((ALIGNMENT - file.tell() % ALIGNMENT) % ALIGNMENT, 1)
45+
return cls(offset, hdr_sz, unk1, hw_id, seq, size, date, time, type, blank1,
46+
hdr_crc, block_size, blank2, checksum, data, file.tell())
47+
48+
class UpdateExtractor:
49+
def __init__(self, package: Path, output: Path):
50+
self.package = package.open('rb')
51+
self.output = output
52+
self.partitions: List[Partition] = []
53+
54+
self.parse_partitions()
55+
56+
def parse_partitions(self):
57+
while True:
58+
buffer = self.package.read(4)
59+
if not buffer: break
60+
61+
if buffer == MAGIC:
62+
self.partitions.append(Partition.from_file(
63+
self.package, self.package.tell()
64+
))
65+
66+
def extract(self, name: str = None):
67+
self.output.mkdir(exist_ok=True)
68+
for partition in self.partitions:
69+
if name is not None and partition.type != name:
70+
continue
71+
with open('%s/%s.img' % (self.output,
72+
partition.type), 'wb') as f:
73+
f.write(partition.data)
74+
75+
def main():
76+
parser = ArgumentParser()
77+
parser.add_argument('package', help='UPDATE.APP package.', type=Path)
78+
parser.add_argument('-e', '--extract', help='Extract partitions to files.', action='store_true')
79+
parser.add_argument('-o', '--output', help='Output folder.', default='output', type=Path)
80+
parser.add_argument('-p', '--partition', help='Partition name to extract.', type=str, default=None)
81+
args = parser.parse_args()
82+
83+
extractor = UpdateExtractor(
84+
args.package, args.output)
85+
86+
for partition in extractor.partitions:
87+
print("%s (%d bytes) @ %s - %s" % (partition.type, partition.size,
88+
hex(partition.start), hex(partition.end)))
89+
90+
if args.extract:
91+
extractor.extract(args.partition)
92+
93+
if __name__ == '__main__':
94+
main()

0 commit comments

Comments
 (0)