hashnames
Tool
tools/triage/hashnames.py(program, Triage). Name hashed strings: find which hash function a game uses for its names, and which name each hash constant stands for.
Run it with ./gameframe run hashnames ARGS or python3 tools/triage/hashnames.py. Source on GitHub.
Its own help
This is the help text in the tool itself, as ./gameframe tool hashnames prints it.
text
Name hashed strings: find which hash function a game uses for its names, and which name each
hash constant stands for.
Usage: hashnames.py PATH [--names FILE] [--names-from BINARY ...] [--aligned] [--value 0xHEX ...] [--all]
hashnames.py --hash STRING every hash of one string, to compare by hand
Many engines keep names as 32-bit hashes: class ids, resource names in an archive, event
types, animation channels, settings. The binary then holds the hash where the name would be,
as an immediate in the code (`cmp eax, 0x8f3a12c4`) or in a table. If the names are still in
the program somewhere (debug messages, a registration call, a file of names), hashing every
string with every common function finds the matches. The function with far more matches than
chance is the game's hash function, and each match names one constant.
PATH is a binary, a data file, or a folder whose files are all searched. Some games compute
their hashes when they start, so the hashes are only in the data files: search the data folder,
and take the names from the program with --names-from. The candidates are the printable strings
in PATH and in each --names-from BINARY (ASCII and UTF-16), and the lines of --names FILE (a list
from a modding wiki, a file listing, another game on the engine). With --names-from, the
strings of PATH itself are left out: data files are full of text that is not a name. With
--aligned, only values at offsets divisible by 4 are read, as in most structured data. Each is
tried as it is, in lower case and in upper case. The functions are CRC-32 (and CRC-32 without
its final inversion), FNV-1 and FNV-1a (32-bit), djb2, djb2 with xor, sdbm, the Java string
hash (x31) and the ELF hash. Strings are also hashed as UTF-16LE for CRC-32 and FNV-1a.
The first table counts how often each function's hashes occur, and compares the count with
chance. A real hash often occurs many times (a type id in the header of every resource). Only a
function well above chance is listed in full (--all lists every function). With --value, only
the given constants are searched for, which needs no luck: each is named or reported unknown.
A hash not found here may use a seed, a different case rule (only the file name, slashes
turned round) or a function not listed; constants.py names the function from its constants in
the code. Standard library only.Named by
Skills: re-trace.
Agents: re-identifier.