Teddy Ruxpin

From Exploitee.rs

"Although the information we release has been verified and shown to work to the best our knowledge, we cant be held accountable for bricked devices or roots gone wrong."

TeddyRuxpin.jpg

Teardown

Hardware

Software

BLE Info

SNX Rom

/**
 * Teddy Ruxpin SNXROM BIN format
 * 
 * Note: Byte-order is little-endian unless stated.
 */

#define uint32_t unsigned int
#define uint16_t unsigned short
#define uint8_t unsigned char

#define char16_t unsigned short
#define char8_t unsigned char

/**
 * This header appears at the start of the file.
 */
struct SNXROMHeader {
    char16_t SNXROM[6]; // always "SNXROM"
    uint8_t unknown[28]; // all 0xFF
    uint32_t _unknown; // always 0x400
    uint32_t assetTableLength; // Size of the asset table. (Multiply by 4 for bytes)
    uint8_t __unknown[464]; // all 0xFF
    /**
     * assetTablePointers[0] normally points to Metadata. (Idle BIN does not have any metadata though).
     * 
     * Then in order, follows pointers to:
     * Left Eye Bitmaps
     * Right Eye Bitmaps
     * Audio Headers
     */ 
    uint32_t assetTablePointers[];
};

/**
 * General information about this BIN file
 */ 
struct ROMMetadata {
    uint16_t unknown; // always 0x0
    /**
     * 0 - Intro "Hi. My name is Teddy Ruxpin. Can you and I be friends?"
     * 1 - All About Bears
     * 2 - The Airship
     * 3 - Captured by MudBlups
     * 4 - Wooly and The Wizard
     * 5 - The Missing Princess
     * 6 - Grubby's Romance
     * 7 - The Day Teddy Met Grubby
     * 8 - Teddy Ruxpin's Birthday
     * 9 - Teddy Ruxpin's Christmas
     * 10 - Teddy Ruxpin Lullabies
     * 11 - Double Grubby
     * 12 - The Story of the Faded Fobs
     * 14 - Teddy Ruxpin Summertime
     * 15 - Grundo Springtime Singtime
     */
    uint16_t storyId;
    uint16_t numberOfEyeAnimations;
    uint16_t numberOfEyeBitmaps;
    uint16_t numberOfVideoSequences;
    uint16_t numberOfAudioBlocks;
    /**
     * ROM file size = (fileSizeUpper) << 16 + fileSizeLower;
     * 
     * In Stories 12, 13 & 15, this value is incorrectly copied from Story 11.
     */ 
    uint16_t fileSizeUpper;
    uint16_t fileSizeLower;
    uint8_t _unknown[16]; // all 0xFF    
    /**
     * In order, follows:
     * - EyeAnimationMetadata
     * - VideoAudioSequence
     */ 
    MetadataObject metadataObjects[];
};

typedef struct MetadataObject {    
} MetadataObject;

/**
 * An eye animation is defined by using sequencing a number of eye bitmap;
 * specifying a start and a number of frames.
 * 
 * eyeId is based on it's offset in assetTablePointers.
 */  
typedef struct EyeAnimationMetadata : MetadataObject {    
    /**
     * These identifiers start at 0xB to avoid collision 
     * with other identifiers in the mark table.
     */ 
    uint16_t animationId;
    uint16_t startEyeId;
    uint16_t numberOfEyeFrames;
    uint8_t _unknown[26]; // all 0xFF    
} EyeAnimationMetadata;

/**
 * An video audio sequence is defined by sequencing a number of audio blocks;
 * specifying a start and a number of blocks.
 * 
 * (Most videos usually only have 1 associated audio block).
 */ 
typedef struct VideoAudioSequence : MetadataObject {
    uint16_t videoId;
    uint16_t startAudioId;
    uint16_t numberOfAudioBlocks;
    uint8_t _unknown[26]; // all 0xFF
};

/**
 * A bitmap which represents a single eye.
 * Pixel encoding is RGB565.
 * Pixel order starts from top-left.
 * Each Bitmap is 128x128.
 */
struct EyeBitmap {
    uint16_t pixels[16384];
};

struct AudioHeader {
    char8_t AU[2]; // always "AU"
    uint16_t sampleRate; // always 16,000Hz
    /**
     * (compressed) bit rate = bitRate * 10
     */ 
    uint16_t bitRate; // always 3200 (32 kbps)
    uint16_t channels; // always 1 (mono)    
    uint32_t totalAudioFrames;
    /**     
     * size (in bytes) = sizeOfAudioBinary * 2
     * 
     * Also at 32 kbps, each block is 80 bytes, 
     * so this is also equal to totalAudioFrames * 80
     * 
     * Note: Some 0xFFs will normally pad audio binary data afterwards.
     */ 
    uint32_t sizeOfAudioBinary;
    uint16_t markFlag; // always 1 (enabled)
    uint16_t silenceFlag; // always 0 (disabled)
    uint16_t _unknown; // always 0x0
    uint16_t __unknown; // always 0xFFFF
    uint16_t ___unknown; // always 0x0
    /**
     * Audio binary data proceeds this header struct.
     * Use the header size to figure its starting address.
     */  
    uint16_t headerSize;
    MarkTable markTable;
};

/**
 * A table which coordinates eye animations and mouth movement, with audio.
 */
typedef struct MarkTable {
    /**
     * size (in bytes) = tableLength * 2
     */  
    uint16_t tableLength;
    
    /**
     * Entries in the table are sequential.
     * Each entry has a duration (milliseconds) and an identifier.
     * The duration represents a period of time that elapses before the next action.
     * 
     * If the duration is equal or below 32,767 ms, then the entry is as follows:
     * uint16_t duration;
     * uint16_t identifier;
     * 
     * If the duration exceeds 32,767 ms, then the entry is 6 bytes is as follows:
     * uint16_t durationUpper;
     * uint16_t durationLower;
     * uint16_t identifier;
     * 
     * Where:
     * - durationUpper must have MSB set (i.e. durationUpper & 0x8000 === durationUpper is true)
     * - duration = (durationUpper & 0x7FFF) << 16 + durationLower;
     * 
     * Identifiers:
     * - 0x00 mouth closed
     * - 0x01 mouth half open
     * - 0x02 mouth fully open
     * - >= 0x03 matches an animationId
     * - >= 0x60 (To be confirmed)
     */  
    uint16_t tableWords[];

} MarkTable;

Video

Audio