Skip to content

Instantly share code, notes, and snippets.

@skochinsky
Created March 2, 2026 21:03
Show Gist options
  • Select an option

  • Save skochinsky/0afc52430460f01db75525a3c6b136c1 to your computer and use it in GitHub Desktop.

Select an option

Save skochinsky/0afc52430460f01db75525a3c6b136c1 to your computer and use it in GitHub Desktop.
legacy ARM compiler's ORC to ELF converter
"""
Origin unknown (local timestamp 04/06/2020)
"""
def derive_key(n):
from cryptography.hazmat.backends import default_backend
import cryptography.hazmat.primitives.hashes as hashes
digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
digest.update(n.to_bytes(4, "little"))
return digest.finalize()
def derive_section_row_key(write_addr, rown):
c = write_addr * 0x4C - 1 + rown * 0x140
return derive_key(c)
def derive_symtab_row_key(nent, rown):
c = (nent * 4 - rown) * 0x520
return derive_key(c)
def scramble_memory_buf(buf, keystream, encrypt):
bufsize = len(buf)
indicies = list(range(0, len(buf)))
# Create an array of selections from an index vector
transpose_table = [
indicies.pop(keystream[(idx - 1) % len(keystream)] % len(indicies))
for idx in reversed(range(len(buf)))
]
output = [0] * len(buf)
for idx in range(len(buf)):
if encrypt:
output[transpose_table[idx]] = buf[idx]
else:
output[idx] = buf[transpose_table[idx]]
return output
def scramble_section_row(buf, write_addr, rown, encrypt):
assert len(buf) == 0x28
keystream = derive_section_row_key(write_addr, rown)
return scramble_memory_buf(buf, keystream, encrypt)
def scramble_symtab_row(buf, nent, rown, encrypt):
assert len(buf) == 0x10
keystream = derive_symtab_row_key(nent, rown)
return scramble_memory_buf(buf, keystream, encrypt)
def decode_file(fname, sym_shuffle_after):
d = open(fname, "rb").read()
new_d = bytearray(d)
new_d[:4] = b"\x7FELF"
new_d[0x12:0x14] = b"\x28\x00"
e_shoff = int.from_bytes(d[0x20:0x24], "little")
e_shentsize = int.from_bytes(d[0x2E:0x30], "little")
e_shnum = int.from_bytes(d[0x30:0x32], "little")
symtab = None
for i in range(e_shnum):
ba = e_shoff + i * e_shentsize
rowd = d[ba: ba + e_shentsize]
unscramble = scramble_section_row(rowd, e_shoff, i, True)
#print(" ".join("%02x" % i for i in unscramble))
new_d[ba: ba+e_shentsize] = unscramble
sh_type = int.from_bytes(unscramble[0x4:0x8], "little")
# if symtab
if sh_type == 2:
sh_offset = int.from_bytes(unscramble[0x10:0x14], "little")
sh_size = int.from_bytes(unscramble[0x14:0x18], "little")
symtab = sh_offset, sh_size
print("symtab at %08x size = %08x" % (sh_offset, sh_size))
if symtab is not None:
symtab_base, symtab_size = symtab
assert symtab_size % 0x10 == 0
nmemb = symtab_size // 0x10
for idx in range(nmemb):
ba = symtab_base + 0x10 * idx
row = d[ba:ba+0x10]
if idx > sym_shuffle_after:
row = scramble_symtab_row(row, nmemb, idx, True)
new_d[ba:ba+0x10]=row
#print(" ".join("%02x" % i for i in row))
open(fname + ".elf", "wb").write(new_d)
import sys
decode_file(sys.argv[1], 14)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment