Difference between revisions of "NID"
(Created page with "== NID == Executing sha1 by adding a suffix to the module name or function name optionally, and the first 32 bits of data obtained example 1 [https://wiki.henkaku.xyz/vita...") |
(Make page meatier) |
||
Line 1: | Line 1: | ||
− | + | Abbreviation of '''N'''umeric '''Id'''entifier. | |
− | |||
+ | == Usage == | ||
+ | Dynamic linking of modules (by [[SceKernelModulemgr]]) is performed based on NIDs of functions/variables instead of names. | ||
− | example | + | For example, a module that wants to import [[SceDisplay#sceDisplayGetFrameBufForDriver|sceDisplayGetFrameBuf]] will indicate that it needs <code>SceDisplayForDriver:0xEEDA2E54</code> in [[Modules#Imports|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 costy <code>strncmp()</code>. | ||
+ | ** A dichotomic search can be performed in <code>O(log2(n))</code> if NID tables are sorted. | ||
+ | *** While NID tables appear to be sorted, this optimization is seemingly not used by SCE. | ||
− | < | + | == Calculation == |
− | + | By default, NIDs are derived from a symbol's name using the following algorithm: | |
− | + | # Calculate the SHA-1 hash of the (optionally salted) name: <code>hash = sha1(name + suffix) = ZZ YY XX WW VV UU TT SS RR QQ PP OO NN MM LL KK JJ II HH GG </code> | |
+ | #* <code>suffix</code> acts as salt and may be a string or raw binary data | ||
+ | #* <code>name + suffix</code> corresponds to concatenation in this context | ||
+ | #** For example, <code>name="sceFunc"</code> and <code>suffix="MySuffix"</code> results in <code>hash = sha1("sceFuncMySuffix")</code> | ||
+ | # Truncate the result to 32 bits: <code>tr = truncate32(hash) = 0xZZYYXXWW</code> | ||
+ | # Reverse endianness of the truncated result: <code>NID = swap32(tr) = 0xWWXXYYZZ</code> | ||
+ | |||
+ | Notes: | ||
+ | * For C++, derivation is performed using the symbol's mangled name. | ||
+ | * <code>libname_nid</code> 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 [https://creepnt.stream/vita/nid_help.html following online tool] can be used for NID calculations. | ||
+ | |||
+ | === Example 1: suffixless === | ||
+ | |||
+ | [[SceDisplay#sceDisplayGetFrameBufForDriver|sceDisplayGetFrameBuf]] | ||
+ | |||
+ | <source lang="c"> | ||
+ | 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. | ||
</source> | </source> | ||
+ | ==== Known suffixless libraries ==== | ||
+ | Verifying is a library doesn't use a suffix for NID derivation is trivial: derive a NID based on the library name and check if it matches the <code>libname_nid</code> field of the [[Modules#Exports|libent]] structure of that library. | ||
+ | {| class="wikitable mw-collapsible mw-collapsed" | ||
+ | |- | ||
+ | ! List of known suffixless libraries | ||
+ | |- | ||
+ | | SceDisplayForDriver | ||
+ | |- | ||
+ | | SceFt2 | ||
+ | |- | ||
+ | | SceKernelForMono | ||
+ | |- | ||
+ | | SceKernelForVM | ||
+ | |- | ||
+ | | SceRtabi | ||
+ | |} | ||
− | + | === Example 2: plaintext suffix === | |
− | [ | + | The [[SceShellSvc#SceIpmi|SceIpmi]] library uses <code>libipmi</code> as suffix. |
− | <source lang=" | + | <source lang="c"> |
− | + | //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. | ||
</source> | </source> | ||
+ | For C++ exports, the NID is derived from the mangled name. | ||
+ | <source lang="cpp"> | ||
+ | //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. | ||
+ | </source> | ||
+ | ==== Known plaintext suffixes ==== | ||
+ | |||
+ | Plaintext suffixes follow patterns across some modules. | ||
+ | |||
+ | {| class="wikitable mw-collapsible mw-collapsed" | ||
+ | |- | ||
+ | ! colspan="2" | List of libraries with a known plaintext suffix | ||
+ | |- | ||
+ | ! Library name !! Suffix | ||
+ | |- | ||
+ | ! colspan="2" | 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 | ||
+ | |- | ||
+ | ! colspan="2" | Library name + User | ||
+ | |- | ||
+ | | SceAtrac || SceAtracUser | ||
+ | |- | ||
+ | | SceG729 || SceG729User | ||
+ | |- | ||
+ | ! colspan="2" | Library name without Sce | ||
+ | |- | ||
+ | | SceWebUIPlugin || WebUIPlugin | ||
+ | |- | ||
+ | | SceAppSettings || AppSettings | ||
+ | |- | ||
+ | | SceBackupRestore || BackupRestore | ||
+ | |- | ||
+ | | SceDbRecovery || DbRecovery | ||
+ | |- | ||
+ | | SceLibLocationPermission || LibLocationPermission | ||
+ | |- | ||
+ | ! colspan="2" | libXXX | ||
+ | |- | ||
+ | | SceLibMtp || libmtp | ||
+ | |- | ||
+ | | [[SceShellSvc#SceIpmi|SceIpmi]] || libipmi | ||
+ | |- | ||
+ | ! colspan="2" | lib + Library name | ||
+ | |- | ||
+ | | ScePsp2Compat || libScePsp2Compat | ||
+ | |- | ||
+ | | SceWebKit || libSceWebKit | ||
+ | |- | ||
+ | ! colspan="2" | Others | ||
+ | |- | ||
+ | | All libraries in <code>libpaf.suprx</code> || PAF | ||
+ | |} | ||
+ | |||
+ | === Example 3: binary suffix === | ||
+ | |||
+ | Used for [[Modules#NONAME_exports|NONAME exports]]. | ||
+ | |||
+ | <source lang="c"> | ||
+ | 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. | ||
+ | </source> | ||
− | + | ==== Known binary suffixes ==== | |
+ | The following suffixes are used by SCE for NID derivation: | ||
− | <source lang=" | + | <source lang="c"> |
− | const char | + | //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 | 0x67, 0x59, 0x65, 0x99, 0x04, 0x25, 0x04, 0x90, 0x56, 0x64, 0x27, 0x49, 0x94, 0x89, 0x74, 0x1a | ||
}; | }; | ||
− | const char | + | //Suffix for PS3 NONAME library NIDs derivation. |
+ | const char PS3_NONAME_lib_nid_suffix[] = { | ||
0xbc, 0x5e, 0xba, 0x9e, 0x04, 0x25, 0x04, 0x90, 0x5b, 0x64, 0x27, 0x49, 0x94, 0xd9, 0xc4, 0x1f | 0xbc, 0x5e, 0xba, 0x9e, 0x04, 0x25, 0x04, 0x90, 0x5b, 0x64, 0x27, 0x49, 0x94, 0xd9, 0xc4, 0x1f | ||
}; | }; | ||
− | const char | + | //Suffix for Vita NONAME library NIDs derivation. |
+ | const char vita_NONAME_lib_nid_suffix[] = { | ||
0xc1, 0xb8, 0x86, 0xaf, 0x5c, 0x31, 0x84, 0x64, 0x67, 0xe7, 0xba, 0x5e, 0x2c, 0xff, 0xd6, 0x4a | 0xc1, 0xb8, 0x86, 0xaf, 0x5c, 0x31, 0x84, 0x64, 0x67, 0xe7, 0xba, 0x5e, 0x2c, 0xff, 0xd6, 0x4a | ||
}; | }; | ||
</source> | </source> |
Revision as of 23:04, 10 August 2023
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 wants 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 costy
strncmp()
. - 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 costy
Calculation
By default, NIDs are derived from a symbol's name using the following algorithm:
- Calculate 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:
- For C++, 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.
Example 1: suffixless
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 is a library doesn't 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 |
---|
SceDisplayForDriver |
SceFt2 |
SceKernelForMono |
SceKernelForVM |
SceRtabi |
Example 2: plaintext suffix
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 |
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 libraries in libpaf.suprx |
PAF |
Example 3: binary suffix
Used for NONAME exports.
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
The following suffixes are used by SCE for NID derivation:
//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 PS3 NONAME library NIDs derivation.
const char PS3_NONAME_lib_nid_suffix[] = {
0xbc, 0x5e, 0xba, 0x9e, 0x04, 0x25, 0x04, 0x90, 0x5b, 0x64, 0x27, 0x49, 0x94, 0xd9, 0xc4, 0x1f
};
//Suffix for Vita NONAME library NIDs derivation.
const char vita_NONAME_lib_nid_suffix[] = {
0xc1, 0xb8, 0x86, 0xaf, 0x5c, 0x31, 0x84, 0x64, 0x67, 0xe7, 0xba, 0x5e, 0x2c, 0xff, 0xd6, 0x4a
};