subscribe

bread.codes

code stuff

Linkin-Park-Numb.mp3
--:--
--:--

Proprietary Wireless L3 Protocol From Packet Traces

December 31, 2004

Please Note

This is not my work, but I am hosting it here for archival purposes. The source I am rehosting is here, which is an archival rehost of a website no longer hosting the content, a website which is rehosting parts of a paper from 2005 by the same author entitled Inferring a Proprietary Wireless L3 Protocol From Packet Traces.

This came up in my research for the NDS Download Play protocol and it appears that the only place hosting this content is the WaybackMachine. I am hosting it here for archival purposes. If you are the original author and wish for me to take it down, please contact me at brad@bread.codes.

Archived Content:

Original Note from bottledlight.com: This is a reformatted version of the technical content from Inferring a Proprietary Wireless L3 Protocol From Packet Traces paper, and should probably be split up / otherwise wikified at some point. The ... represents a bit of the original paper that was cut.

There was also an associated presentation to go with the paper.

....

See Wireless Basics for more 802.11 frame information.

Available Game Advertisement

WMB uses beacon frames to advertise available games for download. The beacon frames are normally used to advertise available access points in most 802.11 systems, but there is nothing preventing their use in this capacity. The advertisement data is fragmented and stored partially in each beacon frame as the payload of a custom information element (tag: 0xDD).

The DS Download Play menu only lists games when the beacons are broadcasted on one of the following channels: 1, 3, 4, 5, 7, 9, 10, 11, 13, and 14. However, the DS hosting mechanism only seems to transmit on channels 1, 7, and 13 (apparently selected at random).

All beacon frames transmitted by a DS host have the following format:

802.11 management frame
802.11 beacon header
Supported rates (tagged IE, advertises 1 Mbit and 2 Mbit)
DS parameter set (tagged IE, note: Distribution System, not Nintendo DS)
TIM vector (tagged IE, transmitted as empty)
Custom extension (tagged IE, tag 0xDD)

Nintendo specific beacon fragment format (information element code 0xDD):

OffsetDescription
0x00Manufacturer (00 09 BF)
0x0300
0x040A 00 00 00
0x0801 00 40 00
0x0C24 00 40 00
0x10Randomly generated stream code
0x1270 0B
0x1400 01 08 00
0x1824 00 40 00 (varies from game to game)
0x1CEnd of advertisement flag (00 for non-end, 02 for end packets)
0x1DAlways 00, 01, 02, or 04
0x1ENumber of players already connected
0x1FSequence number (0 .. total_advertisement_length)
0x20Checksum (2 byte little-endian)
0x22Sequence number in non-final packet, # of players in final packet
0x23Total advertisement length – 1 (in beacons)
0x24Payload size in bytes (2 byte little-endian)
0x26Payload begins

The checksum is a custom algorithm, I have included example source in the appendix.

The advertisement fragments are reordered and assembled according to their internal sequence number, to form the overall advertisement payload, as defined below:

OffsetSizeDescription
0x00032Icon palette (16 RGB555 entries)
0x020512Icon tiles (4x4 8x8 4 bit palletized tiles)
0x2201Unknown (0x0B)
0x2211Length of hosting name
0x22220Name of hosting DS (10 UCS-2)
0x2361Max number of players
0x2371Unknown (0x00)
0x23896Game name (48 UCS-2)
0x298192Game description (96 UCS-2)
0x3586400’s if no users are connected
0x3980End of data if no users are connected

The game name and game description are parsed out of the 128 characters stored in the .NDS file banner area. The game name comes from the first line of the banner, and the remaining lines go into the description. No WMB downloads have been observed that had more than 128 characters for these two fields combined, but it should be possible.

The icon format is a standard DS graphics format, constructing the 32x32 icon out of 8x8 pixel tiles, where each pixel is a 4-bit index into a 16-color palette. The 0th palette index is designated as transparent, allowing the background to show through. This also comes from the banner area of the original NDS file.

Authentication process

Once a user B chooses a download offered by a host A, the following standard 802.11 authentication process observed.

  1. Host A advertises a game in beacon frames as described above
  2. Client B sends an authentication request (sequence 1) to A
  3. Host A replies with an ACK
  4. Host A sends an authentication reply (sequence 2) to B
  5. Client B replies with an association request
  6. Host A replies with an ACK
  7. Host A sends an association response
  8. Client B responds with an ACK

After this, the two are associated, and will remain so until the transfer is complete or one is idle for several seconds, at which point they will de-associate. For more information on the association process, see the 802.11 standard.

Download process

After authentication:

  1. Host sends Pings (type 0x01, replies are 0x00, 0x07)
  2. Host sends RSA frame (type 0x03, replies 0x08)
  3. Host sends NDS header (type 0x04, replies 0x09)
  4. Host sends ARM9 binary (type 0x04, replies 0x09)
  5. Host sends ARM7 binary (type 0x04, replies 0x09)
  6. Host terminates transfer (type 0x05, no replies)

The WMB protocol ostensibly implements layers 3 to 7 of the OSI network model, but does not define a new type of network addresses. However, it does define a couple of special broadcast-like MAC addresses within the assigned Nintendo namespace (00:09:BF).

The three channels or flows used for all communications after the MAC broadcast beacons take the form 03:09:BF:00:00:xx, where xx is:

  • 00 for the main data flow, from host to client
  • 10 for the client to host replies
  • 03 for the feedback flow, host to client (acknowledges the replies)

Observed commands:

CommandDescription
0x01Ping / Name request
0x03RSA signature frame
0x04Data packet
0x05Post-idle / unknown

Observed replies

Reply IDDescription
0x00Pong (ping reply)
0x07Name reply
0x08RSA frame reply
0x09Data packet reply

The host does something unusual with the 802.11 sequence control field, each packet sent out on the 00 flow has a sequence control number 2 greater than the previous one, even if they are sent sequentially. When the host acknowledges a reply (on flow 03) from the client about a particular packet, it uses the sequence number one after the original packet number it sent out on 00. This is the root of one of the major problems in finding a PC card that can transmit WMB packets, as very few cards provide user control over it. Even when a card is capable of ‘raw’ 802.11 transmission, it typically takes care of the sequence control field in hardware or firmware, filling it with a constantly incrementing number.

Host-to-client packets (on the 0x00 flow)

0123456..e-3e-2e-1e-0
06010200SizeFlagsPayload000200

Notes:

  • The size field is in terms of half-words (16 bits), and includes the flags byte along with the payload (so a size of 0x03 represents a flag byte, a command byte, and 4 bytes of payload).
  • When flags is 0x11, the first byte of the payload is a command. There seems to be no important data when flags is not 0x11 (seen occasionally as 0x01), and ignoring them still results in a complete dump.

The Ping messages (type 0x00) have a payload size of 0x03, but always contain zeroes in the payload. They seem to be used only to keep the connection alive while waiting for the host DS to start the transfer, to prevent a time-out de-association.

The RSA frame format (type 0x03) sends a table of information about the game being downloaded (most of it redundant with the NDS header, see Appendix), as well as the RSA signature for the DS. I have not looked into computing the signature, as homebrew developers are not privy to Nintendo’s private key, making signing a fruitless activity, but it is my understanding that the signature is a 128 byte public key and an 8 byte SHA-1 message digest over the NDS header, ARM9 binary, and ARM7 binary. Notably: the RSA frame itself is not included as part of the data being signed, bringing up various security issues and making Nintendo’s firmware engineers look amateurish at best.

There are several abortive sendings of empty RSA frames with a size field of 0x03, before the real frame is sent (always with a size field of 0x75).

RSA signature frame payload (type 0x03)

OffsetSizeDescription
0x004ARM9 execute address
0x044ARM7 execute address
0x0840x00
0x0C4Header destination
0x104Header destination
0x144Header size (0x160)
0x1840x00
0x1C4ARM9 destination address
0x204ARM9 destination address
0x244ARM9 binary size
0x2840x00
0x2C40x022C0000
0x304ARM7 destination address
0x344ARM7 binary size
0x3840x01
0x3C136Signature block
0xC4360x00’s
0xE80End of frame payload

Notes:

  • The offsets in the table are from after the command byte, i.e. two bytes into the 234 bytes of payload including the flags.
  • The unknown address 0x022C0000 is probably ARM7 related, by comparison with the duplicated header and ARM9 destination addresses 32 and 16 bytes before it, although it has no known significance according to the NDS header.

The data packets (type 0x04) include a transport-layer sequence number inside of the data packet itself, but no destination offset or other mechanism to allow the packets to be processed out-of-order. The only way to place the data at the correct location in memory is to re-order the packets according to the sequence number and process them sequentially.

Data packet (type 0x04)

0123..End
00[Sequence#]xx..yy

The sequence number is a zero based little-endian number. Each packet only contains data for one of the three destination blocks (header, ARM9, ARM7), so the change-of-destination check only needs to be made on packet boundaries.

Client to Host Replies (on the 0x10 flow)

The replies from client to host are sent on the 0x10 flow. The client uses an incrementing sequence control number for all of its packets, with no unusual trickery. Each reply is sent as a standard 802.11 data frame (typically as a Data + CF-Acknowledgement), consisting of 10 data bytes for the WMB payload. The first two are always 0x04 0x81, with the third byte indicating the type of reply, and the remaining 7 bytes being reply-specific.

One type of packet frequently sent before a download gets underway is what I have termed the Idle or Pong packet (in response to 0x00 ‘Pings’). It has a reply type field of 0x00, and does not contribute any additional information.

Idle / Pong reply (type 0x00)

0123456789
04810000000000000000

The name reply (type 0x07) is sent shortly after association is completed, although I am not certain what triggers it. There are a variable number of pings preceding this reply, but most are replied via Pongs. The name reply sends the user-configured DS name (set in the firmware menu) split over four messages (with the 4th byte of the packet specifying which message fragment this is, 1 based). This can be a total length of 10 UCS-2 characters, although all four messages are still sent if it is shorter (padded with nulls to 10 characters, and then 01 and then nulls until the end of the frame).

Name reply (type 0x07)

0123456789
04810701[Character0][Character1][Character2]
04810702[Character3][Character4][Character5]
04810703[Character6][Character7][Character8]
04810704[Character9]01000000

The RSA frame receipt reply contains no extra information; it only acknowledges receipt of a type 0x03 host packet on the main flow (0x00). Bizarrely, the xx bytes in the table below are not driven to a particular value when replying to an RSA frame, and usually contain the same data as the second (of four) name response frames.

| | | | | | | | | | | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |RSA frame receipt reply (type 0x08) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | 04 | 81 | 08 | xx | xx | xx | xx | xx | xx | xx |

The data packet receipt reply implements is interesting in that it includes both an immediate acknowledgement and something akin to a cumulative acknowledgement. It specifies the transport layer sequence number for both the packet just received, and the highest continuously addressed packet received.

Data packet receipt reply (type 0x09)

0123456789
048109[Last packet][Best packet]000000

Notes:

  • [last packet] is the packet number being acknowledged
  • [best packet] is the highest continuous packet number seen so far
  • Packet IDs are little-endian numbers, like other Nintendo provided data.

Host to client acknowledgements (on the 0x03 flow)

These packets contain four data bytes, but three are always zero. The first seems to be random, with no connection to the acknowledged data. The actual indication of acknowledgement is the sequence control number of the packet. It is set to be one greater than the sequence control number of the initial host packet (sent on flow 0x00) that the client has just responded to, to indicate that the reply was received.

Host-to-client acknowledgement

0123
??000000

Experimental Verification of Protocol

An experiment was setup to test some assumptions about the protocol and verify that clean working dumps of WMB transfers could be made.

  1. The Peanuts program was run on a laptop placed near to a DS running the game Polarium.
  2. The Send a Demo option in the Polarium menu was invoked, and Peanuts was checked to make sure both were operating on the same channel.
  3. Another DS was turned on in a different room, and the hosted Polarium demo was selected in the DS Download Play menu, and the transfer was allowed to complete.
  4. Peanut wrote out a reassembled .NDS file as well as an annotated trace log.
  5. The trace log was checked to make sure the reassembly completed.
  6. The reassembled file was also checked for file integrity with DSgrok.
  7. The WMB program was invoked with the captured demo, and a DS with unmodified firmware (i.e. will reject a game with even a single modified byte due to the RSA signature) was used to download the demo.
  8. The demo ran successfully without the characteristic faded logo lockup indicating a failed signature check, indicating that the capture and reassembly process works, at least for this demo.

Conclusions and Future Work

The NiFi protocol, simply put, isn’t. Although both PictoChat and the DS Download Play have some similarities indicating that the same people wrote both programs (which seems likely considering they are both part of the same firmware), there is not a common layer 3 / 4 protocol shared between them.

The Nintendo DS does not appear to violate the letter of the 802.11 standard. However, most cards are not capable of providing application level control of the sequence number, and many card drivers do not even allow non-IP transmission over 802.11, filtering out incoming packets and providing no interface to send outbound ones.

The RSA signature frame is a curious design decision. They had to send a signature of the binaries across, but the RSA frame also contains duplicated header fields, including execute addresses. Under other circumstances, this would be a trivial waste of space; except that the signature does not cover the RSA frame itself, and it’s fields are preferentially used over the original header! This means that a DS download server can also operate as a software-based passthrough. Arbitrary code cannot be sent, as the binaries are still signed, but execution can be redirected to a flash cartridge in the GBA slot.

... The additional information in the RSA firmware is ignored by newer versions of the firmware, completely preventing the WifiMe soft-passthrough. ...

The passive method of capture currently implemented in Peanut is sufficient when the client DS is sufficiently far away from the host DS to commonly request the same packet several times. By the very nature of wireless systems, packets have a high loss rate, even when the sender (host) and receiver (laptop) are quite close. If even a single packet is completely lost (i.e. the laptop missed it each time it was (re)transmitted to the client), then reassembly is impossible. The client DS gets around this by not acknowledging packets that were dropped, allowing the host to timeout and retransmit. As a passive snooper, we can’t work around this if the client receives the packet and we do not.

Moving to an active capture system, where Peanut pretends to be a client DS will provide flawless captures every time, and could also lead to a program running on the DS, providing WMB style downloads on DS units that do not have FlashMe installed. As most of the machinery associated with being an active client is common to being an active server, hopefully this would also lead to the first homebrew WMB broadcasts from a DS.

...

Appendix

The beacon checksum is a custom algorithm, operating over the payload as half-words. Here is an example of how to compute it.

// The checksum is computed over halfwords for the last 4 bytes // of the ninty beacon header, plus the payload // This func takes length in halfwords uint16 computeBeaconChecksum(uint16 * data, int length) { uint32 sum = 0; for (int j = 0; j < length; j++) sum += *data++; sum = (-((sum >> 16) + (sum & 0xFFFF) + 1)) & 0xFFFF; return sum; }

The .NDS format is the standard format for Nintendo DS programs; it originated on original game cards and also appears to a limited extent in WMB binaries. The WMB process only transfers the first 0x160 bytes of the header, the ARM9 binary, and the ARM7 binary (in that order), ignoring the file name and file allocation tables, the overlay data, and some information stored in the banner (the rest is transmitted partially via the beacon advertisement process).

(No point in duplicating NDS header info here, see the NDS Format page instead.)