Nintendo MSBT Label checksum

News and discussions about new, recent and work-in-progress security vulnerabilities affecting games and game-related software
soneek
Posts: 15
Joined: Sun Jan 25, 2015 1:31 am

Nintendo MSBT Label checksum

Post by soneek »

Hello all. I've been doing some research on how to add valid text entries to .msbt files in Nintendo games. There is a label section (LBL1) in each msbt, with 0x65 (101) groups. There are labels for each text entry that all lie in 1 of these 101 groups. There's a checksum on the ASCII characters of each label, and that checksum determines the proper group number for that label. If not stored in the proper group, the game just won't read it. I've tested and verified this with Smash Bros. for Wii U.

I've gotten as far as getting the valid checksum for labels with 3 characters or less, and here's a Python function to generate it.

Code: Select all

def group_for_3(label):
    group = 0
    for i in range(len(label)):
        group += 59**(i) * ord(label[-1-i])
    return group % 101


I also have a full script I used to generate valid group numbers for song related labels in the Smash Bros. sound.msbt files for 3DS and Wii U. There are some default values that I was able to add generated checksums of "000", potentially up to "ZZZ" for, since this was part of a music expansion project I worked on for the game.

Code: Select all

def base10toN(num, base):
    """Change ``num'' to given base
    Upto base 36 is supported."""

    converted_string, modstring = "", ""
    currentnum = num
    if not 1 < base < 37:
        raise ValueError("base must be between 2 and 36")
    if not num:
        return '000'
    while currentnum:
        mod = currentnum % base
        currentnum = currentnum // base
        converted_string = chr(48 + mod + 7*(mod > 10)) + converted_string
    return converted_string.replace(":", "A").zfill(3)

def group_for_3(label):
    group = 0
    for i in range(len(label)):
        group += 59**(i) * ord(label[-1-i])
    return group % 101

# End of label ID numbers for v208 Smash U
currentID = 5212
# Adding 0 to 1001 base 36
for i in range(1001):
   labelID = base10toN(i, 36)
   # Group for MsndN_SOUND is 1, so we can calculate the 3 char checksum and add, then modulo
   print("\t%s:[\"%s\", \"%s\", %s]," % (currentID, "MsndN_SOUND" + labelID, "", (1 + group_for_3(labelID)) % 101))
   currentID += 1
   # Group for MsndN2_SOUND is 3, so we can calculate the 3 char checksum and add, then modulo
   print("\t%s:[\"%s\", \"%s\", %s]," % (currentID, "MsndN2_SOUND" + labelID, "", (3 + group_for_3(labelID)) % 101))
   currentID += 1
   # Group for MsndO_SOUND is 36, so we can calculate the 3 char checksum and add, then modulo
   print("\t%s:[\"%s\", \"%s\", %s]," % (currentID, "MsndO_SOUND" + labelID, "", (36 + group_for_3(labelID)) % 101))
   currentID += 1
   # Group for MsndW_SOUND is 15, so we can calculate the 3 char checksum and add, then modulo
   print("\t%s:[\"%s\", \"%s\", %s]," % (currentID, "MsndW_SOUND" + labelID, "", (15 + group_for_3(labelID)) % 101))
   currentID += 1
   # Group for MsndS_SOUND is 42, so we can calculate the 3 char checksum and add, then modulo
   print("\t%s:[\"%s\", \"%s\", %s]," % (currentID, "MsndS_SOUND" + labelID, "", (42 + group_for_3(labelID)) % 101))
   currentID += 1


I've attached msbt files from Smash U for reference, and here's a list of labels, and corresponding group numbers I've generated from a large collection of msbt files to use as a reference. If anyone can help calculate the checksum for a label of ANY size, it would be a huge help to me and anyone else that needs to add entries to msbt files.

http://smashcustommusic.com/~soneek/msbtlabelgroups.txt

I generally suck at explaining things, so let me know if any more info is needed.
n97t7f7b57f
Posts: 27
Joined: Tue Apr 21, 2015 2:15 pm

Re: Nintendo MSBT Label checksum

Post by n97t7f7b57f »

found in src of MSBTeditor
Hope it helps

Code: Select all

public uint LabelChecksum(string label)
      {
         uint group = 0;

         for (int i = 0; i < label.Length; i++)
         {
            group *= 0x492;
            group += label[i];
            group &= 0xFFFFFFFF;
         }

         return group % LBL1.NumberOfGroups;
      }