Huawei Bootloader packed image format: Lua parsing library

Format of bootloader-*.img files found in factory images of certain Android devices from Huawei:

All image versions can be found in factory images at https://developers.google.com/android/images for the specific device. To avoid having to download an entire ZIP archive when you only need one file from it, install remotezip and use its command line tool to list members in the archive and then to download only the file you want.

File extension

img

KS implementation details

License: CC0-1.0

This page hosts a formal specification of Huawei Bootloader packed image format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Lua source code to parse Huawei Bootloader packed image format

android_bootldr_huawei.lua

-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3

local class = require("class")
require("kaitaistruct")
local stringstream = require("string_stream")
local str_decode = require("string_decode")

-- 
-- Format of `bootloader-*.img` files found in factory images of certain Android devices from Huawei:
-- 
-- * Nexus 6P "angler": [sample][sample-angler] ([other samples][others-angler]),
--   [releasetools.py](https://android.googlesource.com/device/huawei/angler/+/cf92cd8/releasetools.py#29)
-- 
-- [sample-angler]: https://androidfilehost.com/?fid=11410963190603870158 "bootloader-angler-angler-03.84.img"
-- [others-angler]: https://androidfilehost.com/?w=search&s=bootloader-angler&type=files
-- 
-- All image versions can be found in factory images at
-- <https://developers.google.com/android/images> for the specific device. To
-- avoid having to download an entire ZIP archive when you only need one file
-- from it, install [remotezip](https://github.com/gtsystem/python-remotezip) and
-- use its [command line
-- tool](https://github.com/gtsystem/python-remotezip#command-line-tool) to list
-- members in the archive and then to download only the file you want.
-- See also: Source (https://android.googlesource.com/device/huawei/angler/+/673cfb9/releasetools.py)
-- See also: Source (https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_format.h?h=LA.UM.6.1.1&id=a68d284aee85)
-- See also: Source (https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&id=a68d284aee85)
AndroidBootldrHuawei = class.class(KaitaiStruct)

function AndroidBootldrHuawei:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function AndroidBootldrHuawei:_read()
  self.meta_header = AndroidBootldrHuawei.MetaHdr(self._io, self, self._root)
  self.header_ext = self._io:read_bytes((self.meta_header.len_meta_header - 76))
  self._raw_image_header = self._io:read_bytes(self.meta_header.len_image_header)
  local _io = KaitaiStream(stringstream(self._raw_image_header))
  self.image_header = AndroidBootldrHuawei.ImageHdr(_io, self, self._root)
end


AndroidBootldrHuawei.MetaHdr = class.class(KaitaiStruct)

function AndroidBootldrHuawei.MetaHdr:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function AndroidBootldrHuawei.MetaHdr:_read()
  self.magic = self._io:read_bytes(4)
  if not(self.magic == "\060\214\026\206") then
    error("not equal, expected " ..  "\060\214\026\206" .. ", but got " .. self.magic)
  end
  self.version = AndroidBootldrHuawei.Version(self._io, self, self._root)
  self.image_version = str_decode.decode(KaitaiStream.bytes_terminate(self._io:read_bytes(64), 0, false), "ASCII")
  self.len_meta_header = self._io:read_u2le()
  self.len_image_header = self._io:read_u2le()
end


AndroidBootldrHuawei.Version = class.class(KaitaiStruct)

function AndroidBootldrHuawei.Version:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function AndroidBootldrHuawei.Version:_read()
  self.major = self._io:read_u2le()
  self.minor = self._io:read_u2le()
end


AndroidBootldrHuawei.ImageHdr = class.class(KaitaiStruct)

function AndroidBootldrHuawei.ImageHdr:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function AndroidBootldrHuawei.ImageHdr:_read()
  self.entries = {}
  local i = 0
  while not self._io:is_eof() do
    self.entries[i + 1] = AndroidBootldrHuawei.ImageHdrEntry(self._io, self, self._root)
    i = i + 1
  end
end

-- 
-- The C generator program defines `img_header` as a [fixed size
-- array](https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&id=a68d284aee85#n42)
-- of `img_header_entry_t` structs with length `MAX_IMAGES` (which is
-- defined as `16`).
-- 
-- This means that technically there will always be 16 `image_hdr`
-- entries, the first *n* entries being used (filled with real values)
-- and the rest left unused with all bytes zero.
-- 
-- To check if an entry is used, use the `is_used` attribute.

AndroidBootldrHuawei.ImageHdrEntry = class.class(KaitaiStruct)

function AndroidBootldrHuawei.ImageHdrEntry:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function AndroidBootldrHuawei.ImageHdrEntry:_read()
  self.name = str_decode.decode(KaitaiStream.bytes_terminate(self._io:read_bytes(72), 0, false), "ASCII")
  self.ofs_body = self._io:read_u4le()
  self.len_body = self._io:read_u4le()
end

-- 
-- See also: Source (https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&id=a68d284aee85#n119)
AndroidBootldrHuawei.ImageHdrEntry.property.is_used = {}
function AndroidBootldrHuawei.ImageHdrEntry.property.is_used:get()
  if self._m_is_used ~= nil then
    return self._m_is_used
  end

  self._m_is_used =  ((self.ofs_body ~= 0) and (self.len_body ~= 0)) 
  return self._m_is_used
end

AndroidBootldrHuawei.ImageHdrEntry.property.body = {}
function AndroidBootldrHuawei.ImageHdrEntry.property.body:get()
  if self._m_body ~= nil then
    return self._m_body
  end

  if self.is_used then
    local _io = self._root._io
    local _pos = _io:pos()
    _io:seek(self.ofs_body)
    self._m_body = _io:read_bytes(self.len_body)
    _io:seek(_pos)
  end
  return self._m_body
end

-- 
-- partition name.