<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Riley</id>
	<title>Nintendo Switch Brew - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Riley"/>
	<link rel="alternate" type="text/html" href="https://switchbrew.org/wiki/Special:Contributions/Riley"/>
	<updated>2026-05-14T20:45:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=System_Version_Title&amp;diff=4336</id>
		<title>System Version Title</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=System_Version_Title&amp;diff=4336"/>
		<updated>2018-03-27T09:44:46Z</updated>

		<summary type="html">&lt;p&gt;Riley: pretty sure this is what was intended.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The FS for the system-version title(TID 0100000000000809) contains &amp;quot;/file&amp;quot; (and, with [5.0.0+], &amp;quot;/digest&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x1&lt;br /&gt;
| Major&lt;br /&gt;
|-&lt;br /&gt;
| 0x1&lt;br /&gt;
| 0x1&lt;br /&gt;
| Minor&lt;br /&gt;
|-&lt;br /&gt;
| 0x2&lt;br /&gt;
| 0x1&lt;br /&gt;
| Micro&lt;br /&gt;
|-&lt;br /&gt;
| 0x3&lt;br /&gt;
| 0x1&lt;br /&gt;
| Unknown/Build?&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 0x1&lt;br /&gt;
| Revision Number&lt;br /&gt;
|-&lt;br /&gt;
| 0x5&lt;br /&gt;
| 0x3&lt;br /&gt;
| Normally all-zero. Padding?&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 0x20&lt;br /&gt;
| Platform string (&amp;quot;NX&amp;quot; with zeros afterwards)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28&lt;br /&gt;
| 0x40&lt;br /&gt;
| Hex ASCII string. 0x28-bytes(not including NUL-terminator) normally with zeros afterwards. The value of this string differs from [[2.0.0]] and [[2.1.0]].&lt;br /&gt;
|-&lt;br /&gt;
| 0x68&lt;br /&gt;
| 0x18&lt;br /&gt;
| System-version in string form with zeros afterwards. For example: &amp;quot;2.1.0&amp;quot;. This is what is displayed in System settings.&lt;br /&gt;
|-&lt;br /&gt;
| 0x80&lt;br /&gt;
| 0x80&lt;br /&gt;
| ASCII string with zeros / padding afterwards. For example: &amp;quot;NintendoSDK Firmware for NX 2.0.0-15&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Known Versions ==&lt;br /&gt;
=== Retail Firmware Updates ===&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Firmware&lt;br /&gt;
! Version String&lt;br /&gt;
! Hex ASCII String&lt;br /&gt;
! &amp;quot;/digest&amp;quot; contents&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 1.0.0-15&lt;br /&gt;
| 84b8da475a02261c456e6472b403b31416480165&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 2.0.0-15&lt;br /&gt;
| 25233e518f580062b41f45fae7ce56bff261094a&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 2.1.0&lt;br /&gt;
| NintendoSDK Firmware for NX 2.1.0-0&lt;br /&gt;
| e548f82b0aaff5fd18cfd80e7b9bd9808eeb7c99&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 2.2.0&lt;br /&gt;
| NintendoSDK Firmware for NX 2.2.0-1&lt;br /&gt;
| c83b637205048e61e73c870f21271cc3c6364396&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 2.3.0&lt;br /&gt;
| NintendoSDK Firmware for NX 2.3.0-0&lt;br /&gt;
| 3ed3bbc8885b6362f4f244dcecd2b430fa27310e&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 3.0.0-10.0&lt;br /&gt;
| 7fbde2b0bba4d14107bf836e4643043d9f6c8e47&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1&lt;br /&gt;
| NintendoSDK Firmware for NX 3.0.1-0.0&lt;br /&gt;
| a3363e086791370ed89dca69c697b4a8bc443d66&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.2&lt;br /&gt;
| NintendoSDK Firmware for NX 3.0.2-0.0&lt;br /&gt;
| 56bc7f71d0e13179ccb6543bbb33d7f537859e49&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 4.0.0-4.0&lt;br /&gt;
| 875be0f6edc29b23938b7aea50764421b9f217e5&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.1&lt;br /&gt;
| NintendoSDK Firmware for NX 4.0.1-0.0&lt;br /&gt;
| 826588c45cecab1672c46f5de87d83ea6008d583&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 4.1.0&lt;br /&gt;
| NintendoSDK Firmware for NX 4.1.0-0.0&lt;br /&gt;
| 314f9468b704e84e1ffed449dfa6108ba4be221d&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
| 5.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 5.0.0-3.0&lt;br /&gt;
| 66790aa646927601523df36a6750205cd944b3de&lt;br /&gt;
| gW93A#00050000#QRnTiv2kqQV-KO9DAn1Wzz4S2-SDH4Zd10y8Jx5KalI=&lt;br /&gt;
|-&lt;br /&gt;
| 5.0.1&lt;br /&gt;
| NintendoSDK Firmware for NX 5.0.1-0.0&lt;br /&gt;
| 4b51b56242cc388ef487e148048e2c80e25994ad&lt;br /&gt;
| gW93A#00050001#wBt05i54vmIPr7cs44Vvod3M9s5M2Yl2ZVd_pd036MY=&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Other ===&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Firmware&lt;br /&gt;
! Version String&lt;br /&gt;
! Hex ASCII String&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2&lt;br /&gt;
| NintendoSDK Firmware for NX 2.0.0-2&lt;br /&gt;
| 665fafc03935d12eebba8060a135516b021ccbaa&lt;br /&gt;
| Revision of [[Factory Setup|factory firmware]].&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-13&lt;br /&gt;
| NintendoSDK Firmware for NX 2.0.0-13&lt;br /&gt;
| 60b5fa391b0055f50fec362d29ac18395f387412&lt;br /&gt;
| Revision of [[Factory Setup|factory firmware]].&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| NintendoSDK Firmware for NX 3.0.0-10.0&lt;br /&gt;
| 83480e96a810a6c7cd3a8fb58dfb5b53961ac781&lt;br /&gt;
| Revision of [[Factory Setup|factory firmware]].&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Riley</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=NSO0&amp;diff=3529</id>
		<title>NSO0</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=NSO0&amp;diff=3529"/>
		<updated>2018-01-22T18:24:54Z</updated>

		<summary type="html">&lt;p&gt;Riley: bit 3-5, not 4-6&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;NSO is the main executable format.&lt;br /&gt;
&lt;br /&gt;
It starts with the &amp;quot;NSO&amp;quot; header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers):&lt;br /&gt;
&lt;br /&gt;
= NSO Header =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;NSO0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| 4&lt;br /&gt;
| Flags, bit 0-2: section is compressed, bit 3-5: check section hash when loading&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 0x10 * 3&lt;br /&gt;
| SegmentHeader[3]&lt;br /&gt;
|-&lt;br /&gt;
| 0x40&lt;br /&gt;
| 0x20&lt;br /&gt;
| Value of &amp;quot;build id&amp;quot; from ELF&#039;s GNU .note section. Contains variable sized digest, up to 32bytes.&lt;br /&gt;
|-&lt;br /&gt;
| 0x60&lt;br /&gt;
| 0x4 * 3&lt;br /&gt;
| CompressedSize[3]&lt;br /&gt;
|-&lt;br /&gt;
| 0x6c&lt;br /&gt;
| 0x24&lt;br /&gt;
| Padding&lt;br /&gt;
|-&lt;br /&gt;
| 0x90&lt;br /&gt;
| 8&lt;br /&gt;
| .rodata-relative extents of .dynstr&lt;br /&gt;
|-&lt;br /&gt;
| 0x98&lt;br /&gt;
| 8&lt;br /&gt;
| .rodata-relative extents of .dynsym&lt;br /&gt;
|-&lt;br /&gt;
| 0xA0&lt;br /&gt;
| 0x20 * 3&lt;br /&gt;
| SHA256 hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data.&lt;br /&gt;
|-&lt;br /&gt;
| 0x100&lt;br /&gt;
|&lt;br /&gt;
| Compressed sections&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Most data in Switch binaries are standard ELF structures, however some are custom.&lt;br /&gt;
For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header.&lt;br /&gt;
&lt;br /&gt;
== SegmentHeader ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| FileOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| MemoryOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 4&lt;br /&gt;
| DecompressedSize&lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| 4&lt;br /&gt;
| UnkOffset/UnkSize/BssSize&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== .rodata-relative extent ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| RegionRoDataOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| RegionSize&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MOD ==&lt;br /&gt;
All offsets are signed 32bit values relative to the magic field.&lt;br /&gt;
The 32bits at image base + 4 must point to the magic field.&lt;br /&gt;
The MOD structure is designed such that it can be placed at image base and point to itself.&lt;br /&gt;
The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base. If MOD is not located at image base, the value at offset 4 must still point to the MOD magic. In the case of .text being at image base, this implies that the first instruction can only be an unconditional branch over the offset literal.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x00&lt;br /&gt;
| 4&lt;br /&gt;
| ZeroPadding&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| 4&lt;br /&gt;
| MagicOffset. Always 8 (so it works when MOD is at image_base + 0).&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;MOD0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| 4&lt;br /&gt;
| .dynamic offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| .bss start offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| .bss end offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| .eh_frame_hdr start offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| .eh_frame_hdr end offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 4&lt;br /&gt;
| offset to runtime-generated module object. typically equal to .bss base.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Arguments=&lt;br /&gt;
Loader maps memory and writes the [[Loader_services#AddProcessToLaunchQueue|arguments]] to {end of rwdata section specified by last SegmentHeader}. Official processes use argdata_addr = {page-aligned _end}. svcQueryMemory is used by official sw to verify that argdata_addr is mapped RW, since this memory is only mapped when arguments are specified via that command. Afterwards, official sw aligns the argdata_addr to 4-bytes. Structure located at argdata_addr:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0 || 0x4 || This is the total allocated space relative to argdata_addr, used for calculating the max size of the argv ptr array. Normally 0x9000?&lt;br /&gt;
|-&lt;br /&gt;
| 0x4 || 0x4 || This is the total_bytesize of the actual argdata string.&lt;br /&gt;
|-&lt;br /&gt;
| 0x8 || 0x18 || Unused by official sw.&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || See above || Actual argdata string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The copy of the args used with the argv array is written by official processes to actual_argdata_string+actual_argdata_size.&lt;br /&gt;
* argv_ptrarray written by official processes is at (args_copy+actual_argdata_size) + 0x9 &amp;amp; ~0x7.&lt;/div&gt;</summary>
		<author><name>Riley</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=NSO0&amp;diff=3528</id>
		<title>NSO0</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=NSO0&amp;diff=3528"/>
		<updated>2018-01-22T18:18:46Z</updated>

		<summary type="html">&lt;p&gt;Riley: document structure element at offset 0xC&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;NSO is the main executable format.&lt;br /&gt;
&lt;br /&gt;
It starts with the &amp;quot;NSO&amp;quot; header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers):&lt;br /&gt;
&lt;br /&gt;
= NSO Header =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;NSO0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| 4&lt;br /&gt;
| Flags, bit 0-2: section is compressed, bit 4-6: check section hash when loading&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 0x10 * 3&lt;br /&gt;
| SegmentHeader[3]&lt;br /&gt;
|-&lt;br /&gt;
| 0x40&lt;br /&gt;
| 0x20&lt;br /&gt;
| Value of &amp;quot;build id&amp;quot; from ELF&#039;s GNU .note section. Contains variable sized digest, up to 32bytes.&lt;br /&gt;
|-&lt;br /&gt;
| 0x60&lt;br /&gt;
| 0x4 * 3&lt;br /&gt;
| CompressedSize[3]&lt;br /&gt;
|-&lt;br /&gt;
| 0x6c&lt;br /&gt;
| 0x24&lt;br /&gt;
| Padding&lt;br /&gt;
|-&lt;br /&gt;
| 0x90&lt;br /&gt;
| 8&lt;br /&gt;
| .rodata-relative extents of .dynstr&lt;br /&gt;
|-&lt;br /&gt;
| 0x98&lt;br /&gt;
| 8&lt;br /&gt;
| .rodata-relative extents of .dynsym&lt;br /&gt;
|-&lt;br /&gt;
| 0xA0&lt;br /&gt;
| 0x20 * 3&lt;br /&gt;
| SHA256 hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data.&lt;br /&gt;
|-&lt;br /&gt;
| 0x100&lt;br /&gt;
|&lt;br /&gt;
| Compressed sections&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Most data in Switch binaries are standard ELF structures, however some are custom.&lt;br /&gt;
For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header.&lt;br /&gt;
&lt;br /&gt;
== SegmentHeader ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| FileOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| MemoryOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 4&lt;br /&gt;
| DecompressedSize&lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| 4&lt;br /&gt;
| UnkOffset/UnkSize/BssSize&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== .rodata-relative extent ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| RegionRoDataOffset&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| RegionSize&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MOD ==&lt;br /&gt;
All offsets are signed 32bit values relative to the magic field.&lt;br /&gt;
The 32bits at image base + 4 must point to the magic field.&lt;br /&gt;
The MOD structure is designed such that it can be placed at image base and point to itself.&lt;br /&gt;
The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base. If MOD is not located at image base, the value at offset 4 must still point to the MOD magic. In the case of .text being at image base, this implies that the first instruction can only be an unconditional branch over the offset literal.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x00&lt;br /&gt;
| 4&lt;br /&gt;
| ZeroPadding&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| 4&lt;br /&gt;
| MagicOffset. Always 8 (so it works when MOD is at image_base + 0).&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;MOD0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| 4&lt;br /&gt;
| .dynamic offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| .bss start offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| .bss end offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| .eh_frame_hdr start offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| .eh_frame_hdr end offset&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 4&lt;br /&gt;
| offset to runtime-generated module object. typically equal to .bss base.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Arguments=&lt;br /&gt;
Loader maps memory and writes the [[Loader_services#AddProcessToLaunchQueue|arguments]] to {end of rwdata section specified by last SegmentHeader}. Official processes use argdata_addr = {page-aligned _end}. svcQueryMemory is used by official sw to verify that argdata_addr is mapped RW, since this memory is only mapped when arguments are specified via that command. Afterwards, official sw aligns the argdata_addr to 4-bytes. Structure located at argdata_addr:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0 || 0x4 || This is the total allocated space relative to argdata_addr, used for calculating the max size of the argv ptr array. Normally 0x9000?&lt;br /&gt;
|-&lt;br /&gt;
| 0x4 || 0x4 || This is the total_bytesize of the actual argdata string.&lt;br /&gt;
|-&lt;br /&gt;
| 0x8 || 0x18 || Unused by official sw.&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || See above || Actual argdata string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The copy of the args used with the argv array is written by official processes to actual_argdata_string+actual_argdata_size.&lt;br /&gt;
* argv_ptrarray written by official processes is at (args_copy+actual_argdata_size) + 0x9 &amp;amp; ~0x7.&lt;/div&gt;</summary>
		<author><name>Riley</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3495</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3495"/>
		<updated>2018-01-20T15:42:52Z</updated>

		<summary type="html">&lt;p&gt;Riley: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.&lt;br /&gt;
&lt;br /&gt;
=List of Switch System Flaws=&lt;br /&gt;
&lt;br /&gt;
== Hardware == &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== System software ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 Bootloader ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;s stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn&#039;t get initialized until partway into the bootloader&#039;s main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. This would cause a data abort, causing the bootloader to clear the stack and then try to clear the security engine...dereferencing NULL again, over and over in a loop.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Infinite clear-the-stack-then-data-abort loop very early in boot, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
| jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| GetLastThreadInfo UAF&lt;br /&gt;
| GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread.&lt;br /&gt;
| Nothing. There is a theoretical race that might leak from a KThread from a different process, but it&#039;s impossible to trigger practically.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| &lt;br /&gt;
| 15 October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) service serves as an interface between the rest of the system and the secure monitor. Prior to [[4.0.0]], spl exposed only a single service &amp;quot;spl:&amp;quot;, which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders: dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| The [[BCAT_Content_Container]] secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  Prior to [[3.0.0]], pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In [[3.0.0]], sending out of range indexes causes error code 0x60A to be returned.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], Reswitched team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|domain messages]] are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages.&lt;br /&gt;
|&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Riley</name></author>
	</entry>
</feed>