Skip to content

Instantly share code, notes, and snippets.

@TobleMiner
Last active September 29, 2025 08:38
Show Gist options
  • Save TobleMiner/82016ae4c5ec75b5a0a42b2efbfdefc5 to your computer and use it in GitHub Desktop.
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
#!/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