Skip to content

Instantly share code, notes, and snippets.

@osyu
Last active September 4, 2025 04:08
Show Gist options
  • Select an option

  • Save osyu/539562687791dfd0de9c153c0feabcbf to your computer and use it in GitHub Desktop.

Select an option

Save osyu/539562687791dfd0de9c153c0feabcbf to your computer and use it in GitHub Desktop.
Ghidra script to find and rename CRIWARE SDK functions in binaries where they're statically linked
#Finds and renames CRIWARE SDK functions based on their unique error strings.
#@author osyu, robbie01
#@category Symbol
#@keybinding
#@menupath
#@toolbar
import json
import re
from ghidra.app.util import XReferenceUtils
from ghidra.program.model.block import IsolatedEntrySubModel
from ghidra.program.util import DefinedStringIterator
NAME = 'CRI function finder'
ECODE_RX = re.compile(r'^([EW]\d{4,}(?:[a-zA-Z\d]+)?)')
mode = askChoice(NAME, 'Set or dump?', ('set', 'dump'), 'dump')
if mode == 'set':
ren_unk = askChoice(NAME, 'Rename unknowns?', ('yes', 'no'), 'no')
fname = str(askFile('Select ecode dump file', 'Sold!'))
print('%s with file %s' % (mode, fname))
if mode == 'set':
with open(fname, 'r') as f:
ecodes = json.load(f)
submodel = IsolatedEntrySubModel(currentProgram)
else:
ecodes = {}
for string in DefinedStringIterator.forProgram(currentProgram):
match = ECODE_RX.match(string.getValue())
if not match:
continue
ecode = match.group(1)
unknown = False
if mode == 'set' and ecode not in ecodes:
if ren_unk == 'yes':
unknown = True
else:
continue
refs = XReferenceUtils.getXReferences(string, -1)
funcs = set()
for ref in refs:
func = getFunctionContaining(ref.getFromAddress())
if func:
funcs.add(func)
if mode == 'dump':
funcs = [x.name for x in funcs if not x.name.startswith('FUN_')]
if len(funcs) == 0:
continue
if ecode not in ecodes:
ecodes[ecode] = funcs
else:
ecodes[ecode].extend(funcs)
else:
if len(funcs) == 0:
starts = set()
for ref in refs:
blocks = submodel.getCodeBlocksContaining(
ref.getFromAddress(), monitor)
starts.update(x.getFirstStartAddress() for x in blocks)
if unknown:
for start in starts:
funcs.add(createFunction(start, None))
elif len(starts) == 0:
print('* %s exists, but has no refs.\n names: %s' %
(ecode, ecodes[ecode]))
continue
elif len(starts) > 1:
print('* %s has multiple dead refs.\n names: %s\n refs: %s' %
(ecode, ecodes[ecode], starts))
continue
else:
funcs.add(createFunction(next(iter(starts)), None))
if unknown:
for func in funcs:
func.setName('criUnk_%s' % func.getEntryPoint(),
ghidra.program.model.symbol.SourceType.DEFAULT)
continue
elif len(funcs) > 1:
print('* %s matched multiple funcs.\n names: %s\n matches: %s' %
(ecode, ecodes[ecode], funcs))
elif len(ecodes[ecode]) > 1:
print('* %s matched only %s, but has multiple names.\n names: %s' %
(ecode, next(iter(funcs)), ecodes[ecode]))
else:
next(iter(funcs)).setName(ecodes[ecode][0],
ghidra.program.model.symbol.SourceType.DEFAULT)
if mode == 'dump':
with open(fname, 'w') as f:
json.dump(ecodes, f)
@osyu
Copy link
Author

osyu commented Aug 23, 2025

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment