From a7a10e242829fd45bffbf98b3bfea28ac8839a85 Mon Sep 17 00:00:00 2001 From: Craig Heffner <heffnercj@gmail.com> Date: Thu, 31 Mar 2016 13:36:10 -0400 Subject: [PATCH] Added hilink plugin and added hilink signature. --- src/binwalk/magic/firmware | 4 ++++ src/binwalk/plugins/hilink.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/binwalk/plugins/hilink.py diff --git a/src/binwalk/magic/firmware b/src/binwalk/magic/firmware index 16ab354..064e3e8 100644 --- a/src/binwalk/magic/firmware +++ b/src/binwalk/magic/firmware @@ -67,6 +67,10 @@ >31 byte 3 compression type: lzma, >32 string x image name: "%s" +# Hilink encrypts thier firmware with a fixed DES key, so the uImage magic +# bytes are encrypted to the same values every time. +0 ubelong 0xEC1C7558 Encrypted Hilink uImage firmware header + #IMG0 header, found in VxWorks-based Mercury router firmware 0 string IMG0 IMG0 (VxWorks) header, >4 belong <1 {invalid} diff --git a/src/binwalk/plugins/hilink.py b/src/binwalk/plugins/hilink.py new file mode 100644 index 0000000..d193616 --- /dev/null +++ b/src/binwalk/plugins/hilink.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +import struct +import string +import binwalk.core.plugin +import binwalk.core.compat +import binwalk.core.common +try: + # Requires the pycrypto library + from Crypto.Cipher import DES +except ImportError as e: + DES = None + + +class HilinkDecryptor(binwalk.core.plugin.Plugin): + ''' + Plugin to decrypt, validate, and extract Hilink encrypted firmware. + ''' + MODULES = ["Signature"] + + DES_KEY = "H@L9K*(3" + SIGNATURE_DESCRIPTION = "Encrypted Hilink uImage firmware".lower() + + def init(self): + if DES is None: + self.enabled = False + else: + self.enabled = True + + if self.enabled is True and self.module.extractor.enabled is True: + # Add an extraction rule for encrypted Hilink firmware signature results + self.module.extractor.add_rule(regex="^%s" % self.SIGNATURE_DESCRIPTION, + extension="enc", + cmd=self._decrypt_and_extract) + + + def _decrypt_and_extract(self, fname): + ''' + This does the extraction (e.g., it decrypts the image and writes it to a new file on disk). + ''' + with open(fname, "r") as fp_in: + encrypted_data = fp_in.read() + + decrypted_data = self._hilink_decrypt(encrypted_data) + + with open(binwalk.core.common.unique_file_name(fname[:-4], "dec"), "w") as fp_out: + fp_out.write(decrypted_data) + + def _hilink_decrypt(self, encrypted_firmware): + ''' + This does the actual decryption. + ''' + cipher = DES.new(self.DES_KEY, DES.MODE_ECB) + + p1 = encrypted_firmware[0:3] + p2 = encrypted_firmware[3:] + p2 += b"\x00" * (8 - (len(p2) % 8)) + + d1 = p1 + cipher.decrypt(p2) + d1 += b"\x00" * (8 - (len(d1) % 8)) + + return cipher.decrypt(d1) + + def scan(self, result): + ''' + Validate signature results. + ''' + if self.enabled is True: + if result.valid is True: + if result.description.lower().startswith(self.SIGNATURE_DESCRIPTION) is True: + # Read in the first 64 bytes of the suspected encrypted uImage header + fd = self.module.config.open_file(result.file.name, offset=result.offset) + encrypted_header_data = binwalk.core.compat.str2bytes(fd.read(64)) + fd.close() + + # Decrypt the header + decrypted_header_data = self._hilink_decrypt(encrypted_header_data) + + # Pull out the image size and image name fields from the decrypted uImage header + # and add them to the printed description. + result.size = struct.unpack(b">L", decrypted_header_data[12:16])[0] + result.description += ", size: %d" % (result.size) + # NOTE: The description field should be 32 bytes? Hilink seems to use only 24 bytes for this field, + # even though the header size is still 64 bytes? + result.description += ', image name: "%s"' % binwalk.core.compat.bytes2str(decrypted_header_data[32:56]).strip("\x00") + + # Do some basic validation on the decrypted size and image name fields + if result.size > (result.file.size - result.offset): + result.valid = False + if not all(c in string.printable for c in result.description): + result.valid = False + -- libgit2 0.26.0