Skip to content

Instantly share code, notes, and snippets.

@Treeki
Created December 27, 2019 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Treeki/e2b5063b75c30f67b0ee9212db49d52b to your computer and use it in GitHub Desktop.
Save Treeki/e2b5063b75c30f67b0ee9212db49d52b to your computer and use it in GitHub Desktop.
quick-and-dirty Psion firmware analysis scripts
import json
with open('/Users/ash/src/psion/all_exports.json', 'r') as f:
all_exports = json.load(f)
del all_exports['EKERN'] #not valid for Windermere
def get_pascal_string(addr):
count = Byte(addr)
return ''.join([chr(Byte(addr + 1 + x)) for x in range(count)])
def scan_file(path, safepath, addr, size):
uid1 = Dword(addr)
uid2 = Dword(addr + 4)
if uid1 in (0x10000079,0x1000007A):
create_struct(addr, -1, 'EXEHeader')
fn1 = Dword(addr + 0x10)
if fn1 > 0:
MakeFunction(fn1)
MakeName(fn1, 'IMG_EntryPoint_' + safepath)
ptA = Dword(addr + 0x38)
ptB_count = Dword(addr + 0x3C)
ptB = Dword(addr + 0x40)
if ptA > 0:
MakeName(ptA, 'IMPORTS_' + safepath)
if ptB > 0:
shortname = path[path.rfind('/')+1:path.rfind('.')]
exports = all_exports.get(shortname.upper())
MakeName(ptB, 'EXPORTS_' + safepath)
create_dword(ptB)
MakeArray(ptB, ptB_count)
op_plain_offset(ptB, 0, 0)
for i in range(ptB_count):
func = Dword(ptB + i * 4)
MakeFunction(func)
if exports:
funcname = exports[str(i+1)]
else:
funcname = 'Export%03d' % (i+1)
annotated_funcname = '%s_%s' % (shortname, funcname)
MakeName(func, str(annotated_funcname))
# MakeName(func, 'FUNC_%03d_%s' % (i, safepath))
# print('!!! unk DLL %08x %s' % (uid2, path))
# elif uid1 == 0x1000007A:
# if uid2 == 0x1000008B:
# print('EXE: ' + path)
# else:
# print('!!! unk EXE %08x %s' % (uid2, path))
def scan_root(pfx, addr):
dir_size = Dword(addr)
addr += 4
dir_end = addr + dir_size
while addr < dir_end:
create_struct(addr, -1, 'File')
obj_size = Dword(addr)
payload_addr = Dword(addr + 4)
flags = Byte(addr + 8)
name = get_pascal_string(addr + 9)
fullname = pfx + name
safename = fullname.replace('/', '__').replace(' ', '')
# print('%08x-%08x :: %08x :: %s' % (payload_addr, payload_addr + obj_size, flags, fullname))
MakeName(addr, 'FS_ENTRY_' + safename)
if flags == 0x10:
MakeName(payload_addr, 'FS_DIR_' + safename)
scan_root(fullname + '/', payload_addr)
else:
scan_file(fullname, safename, payload_addr, obj_size)
if flags == 0:
MakeName(payload_addr, 'FS_PL_0_' + safename)
elif flags == 1:
MakeName(payload_addr, 'FS_PL_1_' + safename)
else:
MakeName(payload_addr, 'wtf__' + safename)
addr += 10 + len(name)
while (addr & 3) != 0:
addr += 1
scan_root('', 0x5081C448)
import os
import struct
import json
libs = {}
# mkdir /tmp/libs
# cd /tmp/libs
# for i in *.LIB; do p=EXP_${i%.LIB}; mkdir -p $p; cd $p; wine ~/src/psion/cpp/cpp/EPOC32/Gcc/Bin/AR.EXE -x ../$i; cd ..; done
tmp_path = '/tmp/libs'
for lib_dirname in os.listdir(tmp_path):
if lib_dirname.startswith('EXP_'):
exports = {}
libs[lib_dirname[4:]] = exports
lib_path = '%s/%s' % (tmp_path, lib_dirname)
for name in os.listdir(lib_path):
if name.endswith('.o') and name.startswith('ds'):
o_path = '%s/%s' % (lib_path, name)
with open(o_path, 'rb') as f:
blob = f.read()
ordinal = struct.unpack_from('<I', blob, 0x13C)[0]
assert((ordinal & 0x80000000) != 0)
ordinal &= 0xFFFFFF
name = blob[0x218:blob.index(b'\0', 0x218)].decode('ascii')
exports[ordinal] = name
with open('all_exports.json', 'w') as f:
json.dump(libs, f, indent=4, sort_keys=True)
# for ordinal in sorted(nums.keys()):
# print('%04d :: %s' % (ordinal, nums[ordinal].decode('ascii')))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment