NID: Difference between revisions
(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 };