This is a script to unpack Android applications protected by Tencent Legu. It presently works with versions 4.1.0.15, 4.1.0.18, 4.1.0.20, and 4.1.0.31 of Legu, and is easily extendable to unsupported versions. See reverse engineering tips for detailed tips on how to go about finding the keys for a version we don't already have. It's a fun and instructive reverse-engineering exercise.
This is a fork of legu_unpacker_2019 by Romain Thomas, updated to add new encryption methods and keys (and make it all extendable for the future) and replace dependencies that were difficult to get working on modern Python installations.
Original blog post: https://blog.quarkslab.com/a-glimpse-into-tencents-legu-packer.html
The original DEX files are located in assets/0OO00l111l1l
with the following layout:
One can find the details of this structure in the Kaitai file: legu_packed_file.ks
The hashmap embedded in the second part is described in the legu_hashmap.ks file:
The sample com.intotherain.voicechange.apk is a suspicious application that can be unpacked as follows:
$ python ./unpack.py ./samples/com.intotherain.voicechange.apk
[+] Legu version: 4.1.0.15
[+] Password is 'IPk2Hw7AKTuIQBlc'
[+] Number of dex files: 1
[+] Unpacking #1 DEX files ...
[+] dex 0 compressed size: 0x1619a3
[+] dex 0 uncompressed size: 0x5671f8
[+] Unpacking #1 hashmap ...
[+] hashmap 0 compressed size: 0x4399c
[+] hashmap 0 uncompressed size: 0x95558
[+] Unpacking #1 packed methods ...
[+] packed methods 0 compressed_size: 0xf4636
[+] packed methods 0 uncompressed_size: 0x1e3072
[+] Stage 2: Patching DEX files
[+] Unpacked APK: unpacked.apk
The unpacked DEX files are located in the unpacked.apk
file.
- Python >= 3.7
- Kaitai Struct
- LIEF
- pyucl
The apk file created will have incorrect checksums on the classes.dex, which jadx will complain about. You can either disable the checksum check in jadx, or you can do apktool d unpacked.apk && apktool b unpacked
to fix the checksums. I had some trouble fixing the checksums programmatically in the script - if someone wants to figure that out and submit a pull request, I'd appreciate it.
Building the container:
docker build . -t legu-unpacker
Running the container:
docker run --rm -v "$(pwd)":/unpacker legu-unpacker python ./unpack.py ./samples/com.intotherain.voicechange.apk
Untagging the docker image:
docker image rm legu-unpacker