Changes

Jump to navigation Jump to search

Splatoon 2/Save

7,286 bytes added, 20:11, 26 June 2019
m
SaveDataCmn
{{WIP}}
 
Splatoon 2 saves its data in '''<code>save.dat</code>'''.
* '''[https://leanny.github.io/SplatHeX.html SplatHeX]''': a full fledged save editor for Windows.
* '''[https://github.com/3096/effective-spoon/releases/tag/rewrite Splatsave]''': an open source program that decrypts and re-encrypts <code>save.dat</code>.
== Revisions ==
Since release, there has been '''57''' revisions to this file:
{| class="wikitable" border="1"
|-
! VerVersion
! Added On
! Save Size
| 4.0.0
| 0x88D90
| Introduced save body shuffleand new key look-up table. Content is the same as Ver 3.|-| 5| 4.2.0| 0x88D90| Same look-up table as Ver 4, but removed shuffling. Content is still the same as Ver 3.|-| 6| 4.3.0| 0x88D90| Internal version. Does not appear in actual saved files. Mostly likely it's the same encoding as before but converted added abilities.|-| 7| 4.3. 0| 0x88D90| Introduced new key look-up tableand now shuffles twice, before and after encryption. Content is presumably still the same as Ver 3.|-| 8| 4.3.1| 0x88D90| Introduced additional encryption for each shuffle blocks. Shuffling now uses bit reversed/flipped CRC32 checksum as seed. Content is still the same as Ver 3.
|}
The encryption used on the save body is '''AES-128 CBC'''. The key is generated
using a <code>[[Sead/Pseudorandom Number Generator‎|sead::Random</code> ]] object initialized from a 16 byte seed stored
in the save footer, in which also stores the initialization vector and the CMAC
for authentication. The CMAC key is generated from the same
<code>sead::Random</code> object after the encryption key. The key is generated by <code>Cmn::SaveDataFactory::Impl::IEncodedAllAccessor::createKey</code>.
The For version 4, a shuffling process for save body takes was added to take place after it the save body gets encrypted. This shuffling is not present in version five, but is encrypteddone twice in version 7 and onward, with a shuffle before the body encryption as well. In save version 8, the shuffling doubles as an added layer of encryption. The For determining the block sizes to shuffle, the game constructs constructs a new <code>sead::Random</code> object . In version 4 and 7, this <code>sead::Random</code> object is initialized simply with the CRC32 checksum from the save header; in version 8, rather, the checksum is bit-reversed before being used for the after-encryption shuffle, and bit-reversed, plus bit-flipped for the before-encryption shuffle. It The game then uses this the <code>sead::Random</code> object to generate block sizes larger than
1/16 of body size and smaller than 1/8 of body size (or total remaining size,
in case the remaining size is smaller than 1/8 of body size). When the
remaining size is smaller than 1/16 of body size, it is added as the size of
the last block. The body size for version 8, despite following the same general principal, goes an extra step to make sure that all the generated block sizes are multiple of 0x10, for the added "shuffle encryption" purpose. The game then uses <code>sead::PtrArrayImpl::shuffle</code> with the same previous <code>sead::Random</code> object to complete the shuffle. While in version 4 and 7, the shuffling is done by simply copying over the block buffers, the version 8 save creates more <code>sead::Random</code> objects for each block, initialized with the respective block size. The game uses these <code>sead::Random</code> objects to generate the IV used for block encryption, and then chains the object into <code>Cmn::SaveDataFactory::Impl::IEncodedAllAccessor::createKey</code>, the same key generation function used in "whole-body" encryption, to create the encryption key. Lastly, all the blocks are encrypted into their shuffled position with the existing AES-128 CBC algorithm.
== save.dat file structure File Structure =='''Save === Header:'''===
{| class="wikitable" border="1"
|-
| 0
|}
----'''Save === Body Structure'''===
{| class="wikitable" border="1"
|-
| SaveDataMsnOcta
|}
----'''=== SaveDataCmn(0x10):'''===
{| class="wikitable" border="1"
|-
| 0x10
| 4
| Inkling PlayerModelType (Gender, basically)
| |0: Woomy | 1: Ngyes | 6: Story Octoling (Rev 0 and 1 only)
|-
| 0x14
| 4
| Inkling PlayerHairId
| See Mush/HairInfo.byml
|-
| 0x18
| 4
| Inkling PlayerBottomId
| See Mush/BottomInfo.byml
|-
| 0x1C
| 4
| Inkling PlayerSkinColorId
| 0 to 6, 0 being lightest and 6 darkest
|-
| 0x20
| 4
| Inkling PlayerEyeColorId
| [https://pm1.narvii.com/6517/c094628ac4f3c695a65c14ca30099219a5c35f61_hq.jpg 0 to 13, each value represents a color]
|-
| 0x13038
| 4
| (EquippedShoeId)Equipped Shoe Id
| See Mush/GearInfo_Shoes.byml
|-
| 0x1303C
| 4
| (EquippedClothesId)Equipped Clothes Id
| See Mush/GearInfo_Clothes.byml
|-
| 0x13040
| 4
| (EquippedHeadGearId)Equipped HeadGear Id
| See Mush/GearInfo_Head.byml
|-
| 0x4
| 4
| Gear Level (Total # of unlocked abilities - including main slot)
| 1, 2, 3, or 4
|-
| 0x8
| 4
| Gear Slots Unlocked (Total # of ability slots - including main slot)
| 1, 2, 3, or 4
|-
| 0xC
| 4
| (Main slot ability id)| To be filled inSee SkillInfo.byml
|-
| 0x10
| 4
| (Sub slot#1 ability id)| To be filled inSee SkillInfo.byml
|-
| 0x14
| 4
| (Sub slot#1 2 ability id)| To be filled inSee SkillInfo.byml
|-
| 0x18
| 4
| (Sub slot#1 3 ability id)| To be filled inSee SkillInfo.byml
|-
| 0x1C
| 4
| unkCurrent Experience| Value between 0 and [maxexp -1]
|-
| 0x20
| 0x8
| Last Time (Last used time?)Equipped
| UNIX Epoch time
|-
|}
SkillChip (Ability ChuncksChunks) Inventory part:
{| class="wikitable" border="1"
|-
| 0x8
| 0x200
| (SkillChip (a.k.a. Ability ChuncksChunks) Inventory)
|}
| 0x0
| 4
| (SkillId?)Skill ID| To be filled inSee SkillInfo.byml
|-
| 0x4
| 4
| (Skill chip amount)
| 696
|}
| 0x0
| 4
| (Ticket Id) (for what kind of food or drink)Type ID| To be filled in0 = +50% Exp, 1 = +100% Exp, 2 = +50% Money, 3 = +100% Money, 4 = Skill Drink, 5 = +150% Exp, 6 = +150% Money
|-
| 0x4
| 4
| (Boosted skill id for drinks) (-1 for food tickets)| To be filled inSee SkillInfo.byml
|-
| 0xC
| 4
| (Ticket amount)
| 69
|}
| 0x25544
| 0x25554
| 0x40x1
| CtrlOption (Handheld motion ctrl flag)
| 1 for enabled
|-
| 0x255480x25545| 0x255580x25555| 0x400x1| CtrlOption (Handheld motion invert Y-axis)| 1 for enabled|-| 0x25546| 0x25556| 0x1| CtrlOption (Handheld motion invert X-axis)| 1 for enabled|-| 0x25547| 0x25557| 0x41
| CtrlOption (unk)
| A buncha 0s?
| 0x25590
| 0x255A0
| 0x40x1
| CtrlOption (TV/Tabletop motion ctrl flag)
| 1 for enabled
|-
| 0x255940x25591| 0x255A40x255A1| 0x400x1| CtrlOption (TV/Tabletop invert Y-axis)| 1 for enabled|-| 0x25592| 0x255A2| 0x1| CtrlOption (TV/Tabletop invert X-axis)| 1 for enabled|-| 0x25593| 0x255A3| 0x41
| CtrlOption (unk)
| A buncha 0s?
| 0x255F8
| 0x8
| OnlinePlayPenalty Time (penalty start end time?)
| UNIX Epoch time
|-
| 0x25890
| 0x258A0
| 0x44580x54
| unk (Haven't looked into yet)
|
|-
| 0x29CE80x258E4| 0x29CF80x258F4| 0x15280x1| unk (Padding?)Color Lock| A buncha 0?1 for enabled|-| 0x258E5|}0x258F5----| 0x1'''SaveDataVss(0x2B220):'''| Coconut Post Display{| class="wikitable" border="1"for enabled
|-
! Offset| 0x258E6! Absolute Offset| 0x258F6! Size| 0x2BEA! Description! Value| unk (Haven't looked into yet)
|-
| 0x00x284D0| 0x2B2200x284E0
| 4
| PlayerRank Octoling PlayerModelType (Not rankGender, but level. They call it rank in the code.basically)| Looks like level 1 is `0` and level |2 is `1`, etc): Female Veemo| 3: Male Veemo
|-
| 0x40x284D4| 0x2B2240x284E4
| 4
| ExperienceOctoling PlayerHairId| To be filled inSee Mush/HairInfo.byml
|-
| 0x80x284D8| 0x2B2280x284E8
| 4
| StarRankOctoling PlayerBottomId| To be filled inSee Mush/BottomInfo.byml
|-
| 0x140x284DC| 0x2B2340x284EC
| 4
| (TicketBoostRemaining)Octoling PlayerSkinColorId| 200 to 6, 0 being lightest and 6 darkest
|-
| 0x87680x284E0| 0x339880x284F0
| 4
| (X Power Rainmaker)Octoling PlayerEyeColorId| 2770[https://pm1.2 (Float)narvii.com/6517/c094628ac4f3c695a65c14ca30099219a5c35f61_hq.jpg 0 to 13, each value represents a color]
|-
| 0x87B00x284E4| 0x339D00x284F4
| 4
| Is Octoling| 1 if yes|-| 0x284E8| 0x284F8| 0x2D2C| unk (X Power SplatzoneHaven't looked into yet)| 2809} === SaveDataVss ==={| class="wikitable"! Offset !! Absolute Offset !! Size !! Description !! Value|-| 0x0 || 0x2B220 || 4 || PlayerRank (Not rank, but level.7 They call it rank in the code.) || Looks like level 1 is 0 and level 2 is 1, etc|-| 0x4 || 0x2B224 || 4 || Experience || To be filled in|-| 0x8 || 0x2B228 || 4 || StarRank || To be filled in|-| 0x14 || 0x2B234 || 4 || (FloatTicketBoostRemaining)|| 20|-| 0x18 || 0x2B238 || 4 || Rainmaker rank || 0 = C-, 1 = C, 2 = C+, etc
|-
| 0x87F80x24 || 0x2B244 || 4 || Splat Zones rank || See above|-| 0x30 || 0x2B250 || 4 || Tower Control rank || See above|-| 0x3C || 0x2B25C || 4 || Clam Blitz rank || See above|-| 0x60 || 0x2B280 || 4 || Turf War MMR/Power || 1969.6 (Float)|-| 0x64 || 0x2B284 || 4 || Turf War Glicko2 rating deviation || 69.6 (Float)|-| 0x68 || 0x2B288 || 4 || Turf War Glicko2 volatility || 0.06 (Float)|-| 0x6C || 0x2B28C || 4 || Turf War calculation state (?) || 1|-| 0x70 || 0x2B290 || 4 || Rainmaker MMR/Power || 1969.6 (Float)|-| 0x74 || 0x2B294 || 4 || Rainmaker Glicko2 rating deviation || 69.6 (Float)|-| 0x78 || 0x2B298 || 4 || Rainmaker Glicko2 volatility || 0.06 (Float)|-| 0x7C || 0x2B29C || 4 || Rainmaker calculation state (?) || 1|-| 0x80 || 0x2B2A0 || 4 || Splat Zones MMR/Power || 1969.6 (Float)|-| 0x84 || 0x2B2A4 || 4 || Splat Zones Glicko2 rating deviation || 69.6 (Float)|-| 0x88 || 0x2B2A8 || 4 || Splat Zones Glicko2 volatility || 0.06 (Float)|-| 0x8C || 0x2B2AC || 4 || Splat Zones calculation state (?) || 1|-| 0x90 || 0x2B2B0 || 4 || Tower Control MMR/Power || 1969.6 (Float)|-| 0x94 || 0x2B2B4 || 4 || Tower Control Glicko2 rating deviation || 69.6 (Float)|-| 0x98 || 0x2B2B8 || 4 || Tower Control Glicko2 volatility || 0.06 (Float)|-| 0x9C || 0x2B2BC || 4 || Tower Control calculation state (?) || 1|-| 0xA0 || 0x2B2C0 || 4 || Clam Blitz MMR/Power || 1969.6 (Float)|-| 0xA4 || 0x2B2C4 || 4 || Clam Blitz Glicko2 rating deviation || 69.6 (Float)|-| 0xA8 || 0x2B2C8 || 4 || Clam Blitz Glicko2 volatility || 0.06 (Float)| 0x33A18-| 0xAC || 0x2B2CC || 4|| Tower Control calculation state (?) || 1| -| 0x260 || 0x2B480 || 0x2800 || Pair League Battle results || TagScore Array (32)|-| 0x2A60 || 0x2DC80 || 0x2800 || Team League Battle results || TagScore Array (32)|-| 0x5260 || 0x30480 || 0x2C0 || ??? || LeagueScore Array (8)|-| 0x5520 || 0x30740 || 0x2C0 || ??? || LeagueScore Array (8)|-| 0x57E0 || 0x30A00 || 0x2C0 || ??? || LeagueScore Array (8)|-| 0x5AA0 || 0x30CC0 || 0x2C0 || ??? || LeagueScore Array (8)|-| 0x5EB0 || 0x310D0 || 0x28A0 || Plaza NPCs (?) || PlayerInfo Array (25)|-| 0x8768 || 0x33988 || 4 || Rainmaker X Power || 2270.2 (Float)|-| 0x87B0 || 0x339D0 || 4 || Splat Zones X Power || 2309.7 (Float)|-| 0x87F8 || 0x33A18 || 4 || Tower ControlX Power || 2301.4 (Float)| 2801-| 0x8840 || 0x33A60 || 4 || Clam Blitz X Power || 2297.1 (Float)|} Structure of Entry (TagPlayers):{| class="wikitable"! Offset !! Size !! Description !! Value|-| 0x0 || 8 || Player 1 NEX Unique ID || Needs investigation|-| 0x8 || 0x28 || Player 1 system info || PlayerSystemInfo|-| 0x30 || 8 || Player 2 NEX Unique ID || Needs investigation|-| 0x38 || 0x28 || Player 2 system info || PlayerSystemInfo|-| 0x60 || 8 || Player 3 NEX Unique ID || Needs investigation|-| 0x68 || 0x28 || Player 3 system info || PlayerSystemInfo|-| 0x90 || 8 || Player 4 NEX Unique ID || Needs investigation|-| 0x98 || 0x28 || Player 4 system info || PlayerSystemInfo|} Structure of Entry (PlayerSystemInfo):{| class="wikitable"! Offset !! Size !! Description !! Value|-| 0x8 || 0x14 || In-game name || UTF-16LE|} Structure of Entry (FloatPlayerInfo):{| class="wikitable"! Offset !! Size !! Description !! Value|-| 0x16 || 0x14 || In-game name || UTF-16LE|-| 0x40 || 4 || PlayerHairId || See Mush/HairInfo.byml|-| 0x44 || 4 || PlayerSkinColorId || 0 to 6, 0 being lightest and 6 darkest|-| 0x48 || 4 || PlayerEyeColorId || 0 to 13, each value represents a color|-| 0x64 || 0x20 || ??? || Gear|-| 0x84 || 0x20 || ??? || Gear|-| 0xA4 || 0x20 || ??? || Gear|-| 0xC4 || 4 || Tank || See Mush/TankInfo.byml|-| 0xC8 || 4 || PlayerBottomId || See Mush/BottomInfo.byml|-| 0xDC || 4 || Level || Looks like level 1 is 0 and level 2 is 1, etc|-| 0xE0 || 4 || Stars || |-| 0xE4 || 4 || Rainmaker rank || 0 = C-, 1 = C, 2 = C+, etc|-| 0xE8 || 4 || Splat Zones rank || See above|-| 0xEC || 4 || Tower Control rank || See above
|-
| 0x88400xF0 | 0x33A60| 4| (X Power | Clam Blitz)rank || 2797.1 (Float)See above
|}
----'''=== SaveDataLocal(0x37970):'''===----'''=== SaveDataMsn(0x3AD58):'''===
{| class="wikitable" border="1"
|-
| 0x3CBC8
| 4
| (MechanicalFishSardinium)
| 69
|}
----'''=== SaveDataShop(0x40BD0):'''===----=== SaveDataCoop ==='''SaveDataCoop(0x438D0?):'''=== SaveDataFest ===----=== SaveDataStats ===More to be added here...=== SaveDataMsnOcta ===----'''Save === Footer:'''<br />===
Used for save crypto (as of ver 4)
{| class="wikitable" border="1"
| AES-CMAC
|}
 
[[Category:Splatoon 2]]
4
edits

Navigation menu