NID: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
No edit summary
 
(12 intermediate revisions by the same user not shown)
Line 7: Line 7:
= Usage =
= Usage =


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


For example, a module that needs to import [[SceDisplay#sceDisplayGetFrameBufForDriver|sceDisplayGetFrameBuf]] will indicate that it needs <code>SceDisplayForDriver:0xEEDA2E54</code> in [[Modules#Imports|its libstub structures]].
For example, a module that needs to import [[SceDisplay#sceDisplayGetFrameBufForDriver|sceDisplayGetFrameBuf]] will indicate that it needs <code>SceDisplayForDriver:0xEEDA2E54</code> in [[Modules#Imports|its libstub structures]].
Line 21: Line 21:


By default, NIDs are derived from a symbol's name using the following algorithm:
By default, NIDs are derived from a symbol's name using the following algorithm:
# Compute 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>
# Compute the SHA-1 hash of the (optionally salted) name: <code>hash = sha1(name + nid_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>nid_suffix</code> acts as salt and may be a string or raw binary data
#* <code>name + suffix</code> corresponds to concatenation in this context
#* <code>name + nid_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>
#** For example, <code>name="sceFunc"</code> and <code>nid_suffix="MySuffix"</code> results in <code>hash = sha1("sceFuncMySuffix")</code>
# Truncate the result to 32 bits: <code>tr = truncate32(hash) = 0xZZYYXXWW</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>
# Reverse endianness of the truncated result: <code>NID = swap32(tr) = 0xWWXXYYZZ</code>
Line 32: Line 32:
* In the vitasdk headers, most kernel functions/variables names have an added "k" prefix that has to be removed for NID computation.
* In the vitasdk headers, most kernel functions/variables names have an added "k" prefix that has to be removed for NID computation.
* For C++ symbols, derivation is performed using the symbol's mangled name.
* For C++ symbols, 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.
* <code>libname_nid</code> is derived using the same NID 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.
** 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.
* 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.
** 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.


== Suffixless NIDs ==
== Suffixless NIDs ==
Line 57: Line 56:
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 <code>libname_nid</code> field of the [[Modules#Exports|libent]] structure of that library.
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 <code>libname_nid</code> field of the [[Modules#Exports|libent]] structure of that library.


{| class="wikitable mw-collapsible mw-collapsed"
{| class="wikitable mw-collapsible"
|-
|-
! List of known suffixless libraries
! List of known suffixless libraries
|-
|-
| Most PSP libraries before some System Software version around 3.50
| Most PSP libraries before some PSP System Software version around 3.50
|-
| [[SceLibcParam]] (some usermode SELFs)
|-
| SceKblForKernel ([[NSKBL]] module)
|-
| SceIdStorageForDriver ([[SceIdStorage]] module)
|-
| SceIdStorage ([[SceIdStorage]] module)
|-
| ScePowerForDriver ([[ScePower]] module)
|-
| SceLedForDriver ([[ScePower]] module)
|-
| ScePower ([[ScePower]] module)
|-
| SceDisplayForDriver ([[SceDisplay]] module)
|-
| SceHpremoteForDriver ([[SceHpremote]] module)
|-
| SceFios2KernelForDriver ([[SceFios2Kernel]] module)
|-
| SceFt2 ([[SceLibft2]] module)
|-
| SceLibSsp ([[SceLibKernel]] module)
|-
| SceRtabi ([[SceLibKernel]] module)
|-
|-
| SceKblForKernel
| SceKernelForVM ([[SceLibKernel]] module)
|-
|-
| ScePowerForDriver
| SceKernelForMono ([[SceLibKernel]] module)
|-
|-
| SceDisplayForDriver
| SceCommonGuiDialog ([[SceCommonGuiDialog]] module)
|-
|-
| SceHpremoteForDriver
| gaikai_player ([[gaikai_player]] module)
|-
|-
| SceFt2
| SceFace
|-
|-
| SceKernelForMono
| SceSmart
|-
|-
| SceKernelForVM
| SceVoice
|-
|-
| SceRtabi
| SceVoiceQoS
|}
|}


Line 111: Line 136:
Plaintext suffixes follow patterns across some modules.
Plaintext suffixes follow patterns across some modules.


{| class="wikitable mw-collapsible mw-collapsed"
{| class="wikitable mw-collapsible"
|-
|-
! colspan="2" | List of libraries with a known plaintext suffix
! colspan="2" | List of libraries with a known plaintext suffix
Line 119: Line 144:
! colspan="2" | libname
! colspan="2" | libname
|-
|-
| ?SceAvcodecUser? || ?SceAvcodecUser?
| SceAvcdecForPlayer ([[SceAvcdecForPlayer]] module) || SceAvcdecForPlayer
|-
|-
| SceAvcdecForPlayer || SceAvcdecForPlayer
| SceAudiodecUser ([[SceAvcodecUser]] module) || SceAudiodecUser
|-
|-
| SceAudiodecUser || SceAudiodecUser
| SceAudioencUser ([[SceAvcodecUser]] module) || SceAudioencUser
|-
|-
| SceAudioencUser || SceAudioencUser
| SceCodecEnginePerf ([[SceCodecEnginePerf]] module) || SceCodecEnginePerf
|-
|-
| SceCodecEngineUser || SceCodecEngineUser
| SceCodecEngineUser ([[SceAvcodecUser]] module) || SceCodecEngineUser
|-
|-
| SceJpegUser || SceJpegUser
| SceJpegUser ([[SceAvcodecUser]] module) || SceJpegUser
|-
|-
| SceJpegEncUser || SceJpegEncUser
| SceJpegEncUser ([[SceAvcodecUser]] module) || SceJpegEncUser
|-
|-
| SceLibMonoBridge || SceLibMonoBridge
| SceLibMonoBridge ([[SceLibMonoBridge]] module) || SceLibMonoBridge
|-
|-
| SceVideodecUser || SceVideodecUser
| SceVideodecUser ([[SceAvcodecUser]] module) || SceVideodecUser
|-
|-
| SceVideodecAsyncUser || SceVideodecAsyncUser
| SceVideodecAsyncUser ([[SceAvcodecUser]] module) || SceVideodecAsyncUser
|-
|-
| SceVideodecLowDelayUser || SceVideodecLowDelayUser
| SceVideodecLowDelayUser ([[SceAvcodecUser]] module) || SceVideodecLowDelayUser
|-
|-
| SceVideodecRecoveryPointUser || SceVideodecRecoveryPointUser
| SceVideodecRecoveryPointUser ([[SceAvcodecUser]] module) || SceVideodecRecoveryPointUser
|-
|-
| SceVideoencUser || SceVideoencUser
| SceVideoencUser ([[SceAvcodecUser]] module) || SceVideoencUser
|-
|-
! colspan="2" | libname + "User"
! colspan="2" | libname + "User"
|-
|-
| SceAtrac || SceAtracUser
| SceAtrac ([[SceAtrac]] module) || SceAtracUser
|-
|-
| SceG729 || SceG729User
| SceG729 ([[SceLibG729]] module) || SceG729User
|-
|-
| SceSas (in SceSasUser module) || SceSasUser
| SceSas ([[SceSasUser]] module) || SceSasUser
|-
|-
! colspan="2" | "Sce"^-1 + libname
! colspan="2" | "Sce"^-1 + libname
|-
|-
| SceWebUIPlugin || WebUIPlugin
| SceWebUIPlugin ([[SceWebUIPlugin]] module) || WebUIPlugin
|-
| SceAppSettings ([[SceAppSettings]] module) || AppSettings
|-
|-
| SceAppSettings || AppSettings
| SceBackupRestore ([[SceBackupRestore]] module) || BackupRestore
|-
|-
| SceBackupRestore || BackupRestore
| SceDbRecovery ([[SceDbRecovery]] module) || DbRecovery
|-
|-
| SceDbRecovery || DbRecovery
| SceLibLocationPermission ([[SceLibLocationPermission]] module) || LibLocationPermission
|-
|-
| SceLibLocationPermission || LibLocationPermission
| SceNpWebApiCommonDialog ([[SceCommonDialog]] module) || NpWebApiCommonDialog
|-
|-
! colspan="2" | "lib" + downcase(shortened(libname))
! colspan="2" | "lib" + libname
|-
|-
| SceLibMtp || libmtp
| ScePsp2Compat ([[ScePsp2Compat]] module) || libScePsp2Compat
|-
|-
| [[SceShellSvc#SceIpmi|SceIpmi]] || libipmi
| SceWebKit ([[SceWebKit]] module) || libSceWebKit
|-
|-
! colspan="2" | "lib" + libname
! colspan="2" | "lib" + downcase("Sce"^-1 + libname)
|-
|-
| ScePsp2Compat || libScePsp2Compat
| SceLibMtp ([[SceLibMtp]] module) || libmtp
|-
|-
| SceWebKit || libSceWebKit
| [[SceShellSvc#SceIpmi|SceIpmi]] ([[SceShellSvc]] module) || libipmi
|-
|-
! colspan="2" | uppercase(camel_case("Sce"^-1 + libname))
! colspan="2" | uppercase(snake_case("Sce"^-1 + libname))
|-
|-
| All libraries in <code>libpaf.suprx</code> ([[ScePaf]] module) || PAF
| All libraries in <code>libpaf.suprx</code> ([[ScePaf]] module) || PAF
Line 223: Line 250:
= NID Theory =
= NID Theory =


== Per library NID suffix ==
== Basics ==


Theorem (Graphene): Every PS Vita function/variable NID suffix is per library.
Lemma: Library and function/variable NIDs depend on name.


Proof: see avcodec_us.elf.
Proof: All known algorithms use the function/variable/library name as a parameter.
 
Lemma: Library and function/variable NIDs can depend on other things than name.
 
Proof: Some known algorithms append a salt suffix to the name.
 
== Per-library NID suffix ==
 
Theorem: Every PS Vita function/variable NID suffix is common to the whole library and the library itself has this NID suffix.
 
Proof:
 
0. See avcodec_us.elf.
 
1. For old PS Vita libraries there was no NID suffix, nor for the functions. Ex: [[ScePower#ScePowerForDriver]].
 
2. All known functions/variables NID suffixes also apply to their respective library.


Remark: NID suffix is not per module even though module name could be the same as the suffix. For example the "User" appendix in suffix and/or in module name and/or in library name can be confusing.
Remark: NID suffix is not per module even though module name could be the same as the suffix. For example the "User" appendix in suffix and/or in module name and/or in library name can be confusing.


== Per library function naming ==
Theorem: Libraries of a given module do not necessarily have the same NID suffix.


Theorem (CelesteBlue): When a PS Vita library name is "SceXForY" then the functions names are usually "sceXForYCommand".
Proof: In [[SceDisplay]] module, [[SceDisplay#SceDisplayForDriver]] library is suffixless whilst [[SceDisplay#SceDisplay]] library has a non-void suffix.


Proof: see [[SceAvcdecForPlayer#sceAvcdecForPlayerDecodeStop]] function inside [[SceAvcdecForPlayer#SceAvcdecForPlayer]] library.
Theorem: At least before SDK 3.630.011, PS Vita function/variable NID is not generated from something library-related other than library name.


== Function or variable NID change ==
Proof: Some ForDriver and ForKernel libraries have different library NIDs but same function NID and same function name prefix (without ForDriver, ForKernel, etc... suffix).
 
Example 1: [[SceKernelThreadMgr#sceKernelGetMutexInfo_089]]
 
Example 2: Some functions have been moved from one library to another but the function names have not changed.


Lemma (CelesteBlue): When a PS Vita function/variable NID changes, its name has been changed or its library NID has been changed or both.
== Per-library function naming convention ==


Theorem (CelesteBlue): If a PS Vita function NID changes but its library NID does not change, then the function has been renamed.
Theorem: When a PS Vita library name is "SceXForY" (resp. "SceXY") where X and Y are camel case strings, then the functions names are usually "sceXForYCommand" (resp. "sceXCommandY").


Proof:
Proof:


When a typo in function/variable name is fixed, the function/variable NID changes as in:
Example 1: see [[SceAvcdecForPlayer#sceAvcdecForPlayerDecodeStop]] function inside [[SceAvcdecForPlayer#SceAvcdecForPlayer]] library.
* [[SceLowio#sceDsiQeuryResolutionSizeForDriver]] that became [[SceLowio#sceDsiQueryResolutionSizeForDriver]]
 
Example 2: see functions inside [[SceFios2Kernel#SceFios2Kernel02]] library.


== Algorithm for unknown official names ==
== Algorithm for unknown official names ==
Line 254: Line 302:
Proof: We have no evidence that sha256 is used for any PS Vita NID.
Proof: We have no evidence that sha256 is used for any PS Vita NID.


== 3.63 NIDs change ==
== Function or variable NID change ==


Lemma : SCE changed many library NIDs since SDK 3.630.011.
Lemma: When a PS Vita function/variable NID changes, its name has been changed or its library NID has been changed or both.


Proof: a non-exhaustive list is:
Theorem: If a PS Vita function NID changes but its library NID does not change, then the function has been renamed.
 
Proof: When a typo in function/variable name is fixed, the function/variable NID changes as in:
* [[SceLowio#sceDsiQeuryResolutionSizeForDriver]] that became [[SceLowio#sceDsiQueryResolutionSizeForDriver]]
 
== SDK 3.63 library NIDs change ==
 
Lemma: SCE changed many PS Vita library NIDs since SDK 3.630.011, after SDK 3.610.011.
 
Proof: [[SceKernelModulemgr#SceModulemgrForKernel]] library NID changed since FW 3.63, but libname, libver and all its library information have not changed.
 
A non-exhaustive list of affected libraries is:
<pre>
<pre>
SceExcpmgrForKernel
SceExcpmgrForKernel
Line 269: Line 328:
SceModulemgrForKernel
SceModulemgrForKernel
</pre>
</pre>
Theorem: If a library NID changes without changing name, then all its functions/variables NIDs change. Moreover, it is likely that the algorithm is hash(name+lib_suffix) and that the only modification was the library suffix.
Proof: every function/variable NIDs whose library NID changed since SDK 3.630.000 while keeping library name, was also changed.
= Tools =
* https://github.com/TeamFAPS/PS-RE-tools/tree/main/ps-nids-extract can be used to extract NIDs from binaries (usually ELF files, except NSKBL).
* The [https://creepnt.stream/vita/nid_help.html following online tool] can be used for NID calculations.
* hashcat can be used for bruteforce.


= Remarks =
= Remarks =

Latest revision as of 23:42, 31 March 2024

Abbreviation of Numeric Identifier.

The function NID is a value that is statically assigned by a toolchain in relation to a function exported in a library so that it is unique within that library. The function name can be determined by searching for the symbol name with the same value as the function NID from the program file before the symbol information has been stripped.

In PS Vita, each library has its own NID. In PSP, libraries did not have NIDs so they were parsed by name.

Usage

Dynamic linking of modules (by SceKernelModulemgr module) 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 length strlen(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.

Calculation

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

  1. Compute the SHA-1 hash of the (optionally salted) name: hash = sha1(name + nid_suffix) = ZZ YY XX WW VV UU TT SS RR QQ PP OO NN MM LL KK JJ II HH GG
    • nid_suffix acts as salt and may be a string or raw binary data
    • name + nid_suffix corresponds to concatenation in this context
      • For example, name="sceFunc" and nid_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:

  • 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" prefix 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 NID 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.

Suffixless NIDs

Example

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 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 PSP System Software version around 3.50
SceLibcParam (some usermode SELFs)
SceKblForKernel (NSKBL module)
SceIdStorageForDriver (SceIdStorage module)
SceIdStorage (SceIdStorage module)
ScePowerForDriver (ScePower module)
SceLedForDriver (ScePower module)
ScePower (ScePower module)
SceDisplayForDriver (SceDisplay module)
SceHpremoteForDriver (SceHpremote module)
SceFios2KernelForDriver (SceFios2Kernel module)
SceFt2 (SceLibft2 module)
SceLibSsp (SceLibKernel module)
SceRtabi (SceLibKernel module)
SceKernelForVM (SceLibKernel module)
SceKernelForMono (SceLibKernel module)
SceCommonGuiDialog (SceCommonGuiDialog module)
gaikai_player (gaikai_player module)
SceFace
SceSmart
SceVoice
SceVoiceQoS

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
libname
SceAvcdecForPlayer (SceAvcdecForPlayer module) SceAvcdecForPlayer
SceAudiodecUser (SceAvcodecUser module) SceAudiodecUser
SceAudioencUser (SceAvcodecUser module) SceAudioencUser
SceCodecEnginePerf (SceCodecEnginePerf module) SceCodecEnginePerf
SceCodecEngineUser (SceAvcodecUser module) SceCodecEngineUser
SceJpegUser (SceAvcodecUser module) SceJpegUser
SceJpegEncUser (SceAvcodecUser module) SceJpegEncUser
SceLibMonoBridge (SceLibMonoBridge module) SceLibMonoBridge
SceVideodecUser (SceAvcodecUser module) SceVideodecUser
SceVideodecAsyncUser (SceAvcodecUser module) SceVideodecAsyncUser
SceVideodecLowDelayUser (SceAvcodecUser module) SceVideodecLowDelayUser
SceVideodecRecoveryPointUser (SceAvcodecUser module) SceVideodecRecoveryPointUser
SceVideoencUser (SceAvcodecUser module) SceVideoencUser
libname + "User"
SceAtrac (SceAtrac module) SceAtracUser
SceG729 (SceLibG729 module) SceG729User
SceSas (SceSasUser module) SceSasUser
"Sce"^-1 + libname
SceWebUIPlugin (SceWebUIPlugin module) WebUIPlugin
SceAppSettings (SceAppSettings module) AppSettings
SceBackupRestore (SceBackupRestore module) BackupRestore
SceDbRecovery (SceDbRecovery module) DbRecovery
SceLibLocationPermission (SceLibLocationPermission module) LibLocationPermission
SceNpWebApiCommonDialog (SceCommonDialog module) NpWebApiCommonDialog
"lib" + libname
ScePsp2Compat (ScePsp2Compat module) libScePsp2Compat
SceWebKit (SceWebKit module) libSceWebKit
"lib" + downcase("Sce"^-1 + libname)
SceLibMtp (SceLibMtp module) libmtp
SceIpmi (SceShellSvc module) libipmi
uppercase(snake_case("Sce"^-1 + libname))
All libraries in libpaf.suprx (ScePaf module) PAF
All libraries in libpaf_web_map_view.suprx (ScePafWebMapView module) PAF_WEB_MAP_VIEW
?modulename?
All libraries in paflib.suprx (some SCE downloadable apps like LiveTweet, Flickr) ScePafLib
No pattern
All PS3 libraries except NONAME ones 0xbc5eba9e042504905b64274994d9c41f

Binary Suffix NIDs

Used for PS Vita NONAME exports and PS3 named exports.

Example

sha1("module_start" + psvita_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

Basics

Lemma: Library and function/variable NIDs depend on name.

Proof: All known algorithms use the function/variable/library name as a parameter.

Lemma: Library and function/variable NIDs can depend on other things than name.

Proof: Some known algorithms append a salt suffix to the name.

Per-library NID suffix

Theorem: Every PS Vita function/variable NID suffix is common to the whole library and the library itself has this NID suffix.

Proof:

0. See avcodec_us.elf.

1. For old PS Vita libraries there was no NID suffix, nor for the functions. Ex: ScePower#ScePowerForDriver.

2. All known functions/variables NID suffixes also apply to their respective library.

Remark: NID suffix is not per module even though module name could be the same as the suffix. For example the "User" appendix in suffix and/or in module name and/or in library name can be confusing.

Theorem: Libraries of a given module do not necessarily have the same NID suffix.

Proof: In SceDisplay module, SceDisplay#SceDisplayForDriver library is suffixless whilst SceDisplay#SceDisplay library has a non-void suffix.

Theorem: At least before SDK 3.630.011, PS Vita function/variable NID is not generated from something library-related other than library name.

Proof: Some ForDriver and ForKernel libraries have different library NIDs but same function NID and same function name prefix (without ForDriver, ForKernel, etc... suffix).

Example 1: SceKernelThreadMgr#sceKernelGetMutexInfo_089

Example 2: Some functions have been moved from one library to another but the function names have not changed.

Per-library function naming convention

Theorem: When a PS Vita library name is "SceXForY" (resp. "SceXY") where X and Y are camel case strings, then the functions names are usually "sceXForYCommand" (resp. "sceXCommandY").

Proof:

Example 1: see SceAvcdecForPlayer#sceAvcdecForPlayerDecodeStop function inside SceAvcdecForPlayer#SceAvcdecForPlayer library.

Example 2: see functions inside SceFios2Kernel#SceFios2Kernel02 library.

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.

Function or variable NID change

Lemma: When a PS Vita function/variable NID changes, its name has been changed or its library NID has been changed or both.

Theorem: If a PS Vita function NID changes but its library NID does not change, then the function has been renamed.

Proof: When a typo in function/variable name is fixed, the function/variable NID changes as in:

SDK 3.63 library NIDs change

Lemma: SCE changed many PS Vita library NIDs since SDK 3.630.011, after SDK 3.610.011.

Proof: SceKernelModulemgr#SceModulemgrForKernel library NID changed since FW 3.63, but libname, libver and all its library information have not changed.

A non-exhaustive list of affected libraries is:

SceExcpmgrForKernel
SceSysmemForKernel
SceCpuForKernel
SceDebugForKernel
SceUartForKernel
SceThreadmgrForKernel
SceProcessmgrForKernel
SceModulemgrForKernel

Theorem: If a library NID changes without changing name, then all its functions/variables NIDs change. Moreover, it is likely that the algorithm is hash(name+lib_suffix) and that the only modification was the library suffix.

Proof: every function/variable NIDs whose library NID changed since SDK 3.630.000 while keeping library name, was also changed.

Tools

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.