NID: Difference between revisions
CelesteBlue (talk | contribs) |
CelesteBlue (talk | contribs) |
||
Line 213: | Line 213: | ||
= NID Theory = | = NID Theory = | ||
== | == Per library NID suffix == | ||
Theorem (CelesteBlue): When a function/variable NID changes, its name has been changed or its library NID has been changed or both. | Theorem (Graphene): PS Vita function/variable NID suffix is per library. | ||
Proof: see avcodec_us.elf. | |||
Remark: NID suffix is not per module even though it could be set to the same value. It is always the library name that gives the NID suffix, even though the "User" appendix can be confusing. | |||
== Per library function naming == | |||
Theorem (CelesteBlue): When a library name is "SceXForY" then the functions names are usually "sceXForYCommand". | |||
Proof: see [[SceAvcdecForPlayer#sceAvcdecForPlayerDecodeStop]]. | |||
== Function or variable NID change == | |||
Theorem (CelesteBlue): When a PS Vita function/variable NID changes, its name has been changed or its library NID has been changed or both. | |||
Proof: | Proof: | ||
Line 221: | Line 235: | ||
When a typo in function/variable name is fixed, the function/variable NID changes as in: | When a typo in function/variable name is fixed, the function/variable NID changes as in: | ||
* [[SceLowio#sceDsiQeuryResolutionSizeForDriver]] that became [[SceLowio#sceDsiQueryResolutionSizeForDriver]] | * [[SceLowio#sceDsiQeuryResolutionSizeForDriver]] that became [[SceLowio#sceDsiQueryResolutionSizeForDriver]] | ||
== Algorithm for unknown official names == | |||
Conjecture: It is possible that for some libraries, SCE switched from sha1 to sha256 algorithm at some point on PS Vita because everywhere PS3 used sha1, PS Vita and PS4 used instead sha256. It would mean that when bruteforcing the suffix of a library, we are not even sure if the algorithm is still sha1(name+suffix). | |||
Proof: We have no evidence that sha256 is used for any PS Vita NID. | |||
= Remarks = | = Remarks = |
Revision as of 15:20, 24 March 2024
Abbreviation of Numeric Identifier.
Usage
Dynamic linking of modules (by SceKernelModulemgr) is performed based on NIDs of functions/variables instead of names.
For example, a module that needs to import sceDisplayGetFrameBuf will indicate that it needs SceDisplayForDriver:0xEEDA2E54
in its libstub structures.
This solution provides multiple benefits:
- Names of functions and variables are not included in modules. This reveals much less information to attackers.
- Lookup inside a NID table is faster.
- Equality testing is a simple 32-bit comparison instead of a costly
strncmp()
of lengthstrlen(name)
. - A dichotomic search can be performed in
O(log2(n))
if NID tables are sorted.- While NID tables appear to be sorted, this optimization is seemingly not used by SCE.
- Equality testing is a simple 32-bit comparison instead of a costly
Calculation
By default, NIDs are derived from a symbol's name using the following algorithm:
- Compute the SHA-1 hash of the (optionally salted) name:
hash = sha1(name + suffix) = ZZ YY XX WW VV UU TT SS RR QQ PP OO NN MM LL KK JJ II HH GG
suffix
acts as salt and may be a string or raw binary dataname + suffix
corresponds to concatenation in this context- For example,
name="sceFunc"
andsuffix="MySuffix"
results inhash = sha1("sceFuncMySuffix")
- For example,
- Truncate the result to 32 bits:
tr = truncate32(hash) = 0xZZYYXXWW
- Reverse endianness of the truncated result:
NID = swap32(tr) = 0xWWXXYYZZ
Notes:
- On the HENkaku wiki, most kernel functions/variables names have an added "For..." suffix that has to be removed for NID computation.
- In the vitasdk headers, most kernel functions/variables names have an added "k" suffix that has to be removed for NID computation.
- For C++ symbols, derivation is performed using the symbol's mangled name.
libname_nid
is derived using the same suffix as the rest of the library.- Since library names are always known, this makes it (in theory) possible to bruteforce the suffix used for NID derivation of any library.
- The NID of functions and variables can be set to arbitrary values.
- It is possible to encounter NIDs that do not match the "expected" NID found by deriving using this algorithm.
- The following online tool can be used for NID calculations.
Suffixless NIDs
Example
sha1("sceDisplayGetFrameBuf") = 54 2E DA EE DA 61 8E 3F 07 9A C7 46 92 24 6D F1 2A A8 F7 C7 Truncate to 32 bits: 0x542EDAEE Reverse endianness: 0xEEDA2E54 The NID of sceDisplayGetFrameBuf is 0xEEDA2E54.
Known suffixless libraries
Verifying that a library does not use a suffix for NID derivation is trivial: derive a NID based on the library name and check if it matches the libname_nid
field of the libent structure of that library.
List of known suffixless libraries |
---|
Most PSP libraries before some System Software version around 3.50 |
SceKblForKernel |
ScePowerForDriver |
SceDisplayForDriver |
SceHpremoteForDriver |
SceFt2 |
SceKernelForMono |
SceKernelForVM |
SceRtabi |
Plaintext Suffix NIDs
Example
The SceIpmi library uses libipmi
as suffix.
//N.B. "SceIpmilibipmi" is "SceIpmi" + "libipmi sha1("SceIpmilibipmi") = DB 4E E3 F4 E9 A8 6C 3F 79 4B 5A 28 CF 26 07 36 14 42 70 B0 Truncate to 32 bits: 0xDB4EE3F4 Reverse endianness: 0xF4E34EDB NID of the SceIpmi library is 0xF4E34EDB.
For C++ exports, the NID is derived from the mangled name.
//IPMI::Client::Config::estimateClientMemorySize() =mangling=> _ZN4IPMI6Client6Config24estimateClientMemorySizeEv sha1("_ZN4IPMI6Client6Config24estimateClientMemorySizeEvlibipmi") = 31 5C 25 4E FE AE B4 34 CA B5 9F 43 03 3D 62 BC 11 6F FC AB Truncate to 32 bits: 0x315C254E Reverse endianness: 0x4E255C31 The NID of IPMI::Client::Config::estimateClientMemorySize() is 0x4E255C31.
Known plaintext suffixes
Plaintext suffixes follow patterns across some modules.
List of libraries with a known plaintext suffix | |
---|---|
Library name | Suffix |
Library name | |
SceAvcdecForPlayer | SceAvcdecForPlayer |
SceAudiodecUser | SceAudiodecUser |
SceAudioencUser | SceAudioencUser |
SceCodecEngineUser | SceCodecEngineUser |
SceJpegUser | SceJpegUser |
SceJpegEncUser | SceJpegEncUser |
SceLibMonoBridge | SceLibMonoBridge |
SceVideodecUser | SceVideodecUser |
SceVideodecAsyncUser | SceVideodecAsyncUser |
SceVideodecLowDelayUser | SceVideodecLowDelayUser |
SceVideodecRecoveryPointUser | SceVideodecRecoveryPointUser |
SceVideoencUser | SceVideoencUser |
Library name + User | |
SceAtrac | SceAtracUser |
SceG729 | SceG729User |
SceSas (in SceSasUser module) | SceSasUser |
Library name without Sce | |
SceWebUIPlugin | WebUIPlugin |
SceAppSettings | AppSettings |
SceBackupRestore | BackupRestore |
SceDbRecovery | DbRecovery |
SceLibLocationPermission | LibLocationPermission |
libXXX | |
SceLibMtp | libmtp |
SceIpmi | libipmi |
lib + Library name | |
ScePsp2Compat | libScePsp2Compat |
SceWebKit | libSceWebKit |
Others | |
All PS3 libraries except NONAME ones | 0xbc5eba9e042504905b64274994d9c41f |
All libraries in libpaf.suprx (ScePaf module) |
PAF |
All libraries in libpaf_web_map_view.suprx |
PAF_WEB_MAP_VIEW |
All libraries in paflib.suprx (some SCE downloadable apps like LiveTweet, Flickr) |
ScePafLib |
Binary Suffix NIDs
Used for PS Vita NONAME exports and PS3 named exports.
Example
sha1("module_start" + vita_NONAME_lib_nid_suffix) = 96 D1 5C 93 65 10 32 1C 7D 60 7B 4D FC 06 BC 73 06 3E 25 61 Truncate to 32 bits: 0x96D15C93 Reverse endianness: 0x935CD196 The NID of module_start is 0x935CD196.
Known binary suffixes
// Default suffix for all PS3 NIDs derivations, except NONAME library. const char PS3_default_nid_suffix[] = { 0x67, 0x59, 0x65, 0x99, 0x04, 0x25, 0x04, 0x90, 0x56, 0x64, 0x27, 0x49, 0x94, 0x89, 0x74, 0x1a }; // Suffix for PSP2 NONAME library NIDs derivation. const char PSP2_NONAME_lib_nid_suffix[] = { 0xc1, 0xb8, 0x86, 0xaf, 0x5c, 0x31, 0x84, 0x64, 0x67, 0xe7, 0xba, 0x5e, 0x2c, 0xff, 0xd6, 0x4a };
NID Theory
Per library NID suffix
Theorem (Graphene): PS Vita function/variable NID suffix is per library.
Proof: see avcodec_us.elf.
Remark: NID suffix is not per module even though it could be set to the same value. It is always the library name that gives the NID suffix, even though the "User" appendix can be confusing.
Per library function naming
Theorem (CelesteBlue): When a library name is "SceXForY" then the functions names are usually "sceXForYCommand".
Proof: see SceAvcdecForPlayer#sceAvcdecForPlayerDecodeStop.
Function or variable NID change
Theorem (CelesteBlue): When a PS Vita function/variable NID changes, its name has been changed or its library NID has been changed or both.
Proof:
When a typo in function/variable name is fixed, the function/variable NID changes as in:
Algorithm for unknown official names
Conjecture: It is possible that for some libraries, SCE switched from sha1 to sha256 algorithm at some point on PS Vita because everywhere PS3 used sha1, PS Vita and PS4 used instead sha256. It would mean that when bruteforcing the suffix of a library, we are not even sure if the algorithm is still sha1(name+suffix).
Proof: We have no evidence that sha256 is used for any PS Vita NID.
Remarks
- See article by dots-tb
- In PS Vita System Software version 0.990, SceSqliteVsh and SceSqlite modules shared the same suffix despite having nothing in common.
- In PS Vita System Software version 0.990, SceLibMtp ?module? was named libmtp. Later the library name was changed to SceLibMtp, but NID suffix remained the same.
- JSStringCreateWithUTF8CString -> SHA1 match with javascriptcore_5487D441
- javascriptcore is also known as libSceJsc.