NID: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
(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:
== NID ==
Abbreviation of '''N'''umeric '''Id'''entifier.
Executing sha1 by adding a suffix to the module name or function name optionally, and the first 32 bits of data obtained


== Usage ==


Dynamic linking of modules (by [[SceKernelModulemgr]]) is performed based on NIDs of functions/variables instead of names.


example 1
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]].


[https://wiki.henkaku.xyz/vita/SceDisplay#sceDisplayGetFrameBufForDriver sceDisplayGetFrameBuf]
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.


<source lang="C">
== Calculation ==
sha1("sceDisplayGetFrameBuf", strlen("sceDisplayGetFrameBuf")) : 542edaee da618e3f 079ac746 92246df1 2aa8f7c7
By default, NIDs are derived from a symbol's name using the following algorithm:
swap32(0x542edaee) : sceDisplayGetFrameBuf function nid (0xEEDA2E54)
# 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
=== Example 2: plaintext suffix ===


[https://wiki.henkaku.xyz/vita/Modules#NONAME_exports noname export]
The [[SceShellSvc#SceIpmi|SceIpmi]] library uses <code>libipmi</code> as suffix.


<source lang="C">
<source lang="c">
sha1("module_start" + nid_suffix_psp2_noname_lib, strlen("module_start") + 16) : 96D15C93 6510321C 7D607B4D FC06BC73 063E2561
//N.B. "SceIpmilibipmi" is "SceIpmi" + "libipmi
swap32(0x96D15C93) : module_start function nid (0x935CD196)
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>


sce suffix's
==== Known binary suffixes ====
The following suffixes are used by SCE for NID derivation:


<source lang="C">
<source lang="c">
const char nid_suffix_ps3[] = {
//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 nid_suffix_ps3_noname_lib[] = {
//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 nid_suffix_psp2_noname_lib[] = {
//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.

Calculation

By default, NIDs are derived from a symbol's name using the following algorithm:

  1. 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 data
    • name + suffix corresponds to concatenation in this context
      • For example, name="sceFunc" and suffix="MySuffix" results in hash = sha1("sceFuncMySuffix")
  2. Truncate the result to 32 bits: tr = truncate32(hash) = 0xZZYYXXWW
  3. 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

sceDisplayGetFrameBuf

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
};