Last active
September 29, 2025 08:38
-
-
Save TobleMiner/82016ae4c5ec75b5a0a42b2efbfdefc5 to your computer and use it in GitHub Desktop.
Python script to package executable code in a format compatible with the Cisco 801 TinyROM bootloader. Can be used to package and boot a linux image on a Cisco 801
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import os | |
| import struct | |
| import sys | |
| class Chunk(): | |
| def __init__(self, chunk_type): | |
| self.chunk_type = chunk_type | |
| def make_header(self, payload): | |
| return struct.pack('>II', self.chunk_type, len(payload) + 8) | |
| def pack(self): | |
| payload = self.get_payload() | |
| return self.make_header(payload) + payload | |
| class ChunkFilename(Chunk): | |
| def __init__(self, filename): | |
| self.filename = (filename + 11 * ' ')[:11] | |
| super().__init__(0x97) | |
| def get_payload(self): | |
| mystery_prefix = b'\x3e\xe1\xcf\xc9' | |
| payload_name = self.filename.encode('ascii') + b'\x00' | |
| name_pad = ((4 - len(payload_name) % 4) % 4) * b'\00' | |
| mystery_suffix = b'\x01\x00\x00\x00' | |
| return mystery_prefix + payload_name + name_pad + mystery_suffix | |
| class MysteryChunk(Chunk): | |
| def __init__(self): | |
| super().__init__(0x43) | |
| def get_payload(self): | |
| return b'\x00\x02\x00\x00\x00\x26\x91\x04\x01\x00\x02\x86\x00\x02\x00\x00\x00\x40\x00\x00\x00\x00\x09\x54\x00\x0f\x50\x00\x00\xa5\xec\x38\x00\x01\x15\x3c\x00\x4d\xde\xe0' | |
| class MemcpyChunk(Chunk): | |
| def __init__(self, destination_address, data): | |
| self.destination_address = destination_address | |
| self.data = data | |
| super().__init__(0x22) | |
| def get_payload(self): | |
| payload_hdr = struct.pack('>I', self.destination_address) | |
| return payload_hdr + self.data | |
| class SentinelChunk(Chunk): | |
| def __init__(self, entrypoint): | |
| self.entrypoint = entrypoint | |
| super().__init__(0xffffffff) | |
| def get_payload(self): | |
| checksum = 0 # Coveniently supplying a checksum of zero skips checksum validation | |
| return struct.pack('>II', self.entrypoint, checksum) | |
| class ImageBody(): | |
| def __init__(self): | |
| self.chunks = [ ] | |
| def add_chunk(self, chunk): | |
| self.chunks.append(chunk) | |
| def pack(self): | |
| payload = b'' | |
| for chunk in self.chunks: | |
| payload += chunk.pack() | |
| size_header_len = 17 | |
| full_payload_len = size_header_len + len(payload) | |
| size_header = f'\n%% {full_payload_len:08X} %%\r\n'.encode('ascii') | |
| return size_header + payload | |
| class ImageHeader(): | |
| def __init__(self, buildinfo, filename, load_address): | |
| self.buildinfo = buildinfo | |
| self.filename = filename | |
| self.load_address = load_address | |
| def pack(self, body): | |
| image_size = len(body) | |
| max_address = load_address + image_size | |
| header = f'\n{self.buildinfo}\n' | |
| header += f'\n File name: {self.filename}' | |
| header += f'\n RAM size: 0x{max_address:08x} ({max_address:08d})' | |
| header += f'\n Raw size: 0x{max_address:08x} ({max_address:08d})' | |
| header += f'\nImage size: 0x{image_size:08x} ({image_size:07d})' | |
| return header.encode('ascii') | |
| class Image(): | |
| def __init__(self, buildinfo, filename, load_address, entrypoint=None): | |
| payload = None | |
| with open(filename, 'rb') as f: | |
| payload = f.read() | |
| fname = os.path.basename(filename) | |
| self.header = ImageHeader(buildinfo, fname, load_address) | |
| self.body = ImageBody() | |
| self.body.add_chunk(MysteryChunk()) | |
| self.body.add_chunk(ChunkFilename(fname)) | |
| self.body.add_chunk(MemcpyChunk(load_address, payload)) | |
| self.body.add_chunk(SentinelChunk(load_address if entrypoint is None else entrypoint)) | |
| def pack(self): | |
| body_data = self.body.pack() | |
| header_data = self.header.pack(body_data) | |
| return header_data + body_data | |
| payload_file = sys.argv[1] | |
| load_address = int(sys.argv[2], base=16) | |
| image = Image('Build [dchih 1a] -- Sat Jun 7 04:43:00 PDT 2003', payload_file, load_address) | |
| sys.stdout.buffer.write(image.pack()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment