Last active
September 4, 2025 04:08
-
-
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
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
| #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) |
Author
Update for 11.4: replace DefinedDataIterator with DefinedStringIterator, and replace DefinedDataIterator.definedStrings with DefinedStringIterator.forProgram
Author
Thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The CRIWARE SDK has unique error code strings in almost all of its functions. This script creates a dump correlating those strings to known function names (from a CRIWARE dynamic library's export table), and then uses that dump to apply the names to a binary where the SDK is statically linked (and thus doesn't have the names already available).
Usage:
cri_ware_unity.dll), and open it in Ghidradumpmode to create a JSON dump of functionssetmode using the dump fileRename unknowns?, selectingyeswill rename all unknown functions that reference a CRI-format error code string using the formatcriUnk_<address>