diff options
-rw-r--r-- | assets/pictochat-msg-crop-lork2.png | bin | 0 -> 3794 bytes | |||
-rw-r--r-- | assets/pictochat-msg-crop.png | bin | 0 -> 1374 bytes | |||
-rw-r--r-- | assets/pictochat-msg-height-1-4.png | bin | 0 -> 2272 bytes | |||
-rw-r--r-- | assets/pictochat-msg-height-5-draw.png | bin | 0 -> 1185 bytes | |||
-rw-r--r-- | assets/pictochat-msg-pattern.png | bin | 0 -> 3878 bytes | |||
-rw-r--r-- | assets/ws-msg-pattern.png | bin | 0 -> 162965 bytes | |||
-rw-r--r-- | docs/notes.md | 69 | ||||
-rwxr-xr-x | experiments/pixel-sequence/draw | 31 | ||||
-rw-r--r-- | wireshark/nifi.lua | 7 | ||||
-rw-r--r-- | wireshark/pictochat.lua | 14 | ||||
-rw-r--r-- | wireshark/readme.md | 4 | ||||
-rwxr-xr-x | wireshark/wireshark | 8 |
12 files changed, 125 insertions, 8 deletions
diff --git a/assets/pictochat-msg-crop-lork2.png b/assets/pictochat-msg-crop-lork2.png Binary files differnew file mode 100644 index 0000000..a4e6390 --- /dev/null +++ b/assets/pictochat-msg-crop-lork2.png diff --git a/assets/pictochat-msg-crop.png b/assets/pictochat-msg-crop.png Binary files differnew file mode 100644 index 0000000..f332f78 --- /dev/null +++ b/assets/pictochat-msg-crop.png diff --git a/assets/pictochat-msg-height-1-4.png b/assets/pictochat-msg-height-1-4.png Binary files differnew file mode 100644 index 0000000..25d22a5 --- /dev/null +++ b/assets/pictochat-msg-height-1-4.png diff --git a/assets/pictochat-msg-height-5-draw.png b/assets/pictochat-msg-height-5-draw.png Binary files differnew file mode 100644 index 0000000..1910d83 --- /dev/null +++ b/assets/pictochat-msg-height-5-draw.png diff --git a/assets/pictochat-msg-pattern.png b/assets/pictochat-msg-pattern.png Binary files differnew file mode 100644 index 0000000..db19ad2 --- /dev/null +++ b/assets/pictochat-msg-pattern.png diff --git a/assets/ws-msg-pattern.png b/assets/ws-msg-pattern.png Binary files differnew file mode 100644 index 0000000..d1f08ef --- /dev/null +++ b/assets/ws-msg-pattern.png diff --git a/docs/notes.md b/docs/notes.md index 21eef78..657383e 100644 --- a/docs/notes.md +++ b/docs/notes.md @@ -81,16 +81,81 @@ sufficiently advanced local multiplayer emulation. source: <https://git.pipeframe.xyz/fork/melonDS> -### Findings - - melonDS @ Config > Wifi settings "Local multiplayer features do not use the same network protocols as online play" - comment @ src/Wifi.cpp:46 "multiplayer host TX sequence" - references to `RFTransfer_Type{2,3}` @ <https://www.problemkaputt.de/gbatek.htm#dswifirfchip> - nintendo ds ni-fi protocol @ <https://web.archive.org/web/20090202194241/http://masscat.afraid.org/ninds/proto_info.php> - melonDS emulates actual 802.11b frames - the protocol does not appear to be encrypted: + ![](../assets/ws-no-encrypt.png) + the string `lork` is visible as plain text in the hexdump (offset 0x0056), which appears to be some kind of 16-bit encoding of the username set on the emulator used to capture these packets +- The messages are not sent as single packets. The nifi protocol appears to set + up a constant stream, and messages are sent across multiple frames. +- PictoChat does not appear to send messages when you are in a chat room by + yourself, so local multiplayer / nifi emulation is required for capturing + message content + +### Message sizing/cropping + +- PictoChat automatically crops messages to the smallest height (at the fixed + intervals shown as notebook lines in the edit field on the bottom screen). + Message content can be on the line itself without causing the cropping + algorithm to 'allocate' more space; the allocation only happens if any of the + pixels on the line *below* the colored line are used. The method used to crop + the messages also ensures that the username label in the top left does not + obstruct or remove any content. + + ![](../assets/pictochat-msg-height-1-4.png) + ![](../assets/pictochat-msg-height-5-draw.png) +- Message content is likely only cropped when displaying + + ![](../assets/pictochat-msg-crop.png) + ![](../assets/pictochat-msg-crop-lork2.png) + + The above image was obtained after the following steps: + - Fill in the top row of the message with the black pen, ensuring the entire + notebook line is colored in as well + - Send message (displayed as top message) + - Copy message + - Erase small portion of black area on the right side (displayed as bottom message) + + Notable observations: + - The message content has a 1 pixel border (padding/margin) on all sides + (except the bottom and corners) that can not be filled in. The bottom + border is correctly displayed for received messages, but the edit field has + an additional row of pixels that directly touch the message border on the + bottom. + - When any message is cloned, additional pixels that were masked on the top + screen become visible again in the edit field. This includes the bottom row + of pixels, as well as the two rows of pixels shown in the single line + message picture. + +### Message content + +![](../assets/pictochat-msg-pattern.png) +![](../assets/ws-msg-pattern.png) + +- All messages with interesting content have NIFI header type 1 (CMD). +- PictoChat messages appear to be sent over frames of length 0xf6 (246) + regardless of actual message size. +- All frames appear to be sent exactly 5 times. 'New' frames have a value of + 0xe004 at offset 0x0026, while resends have a value of 0xf000 instead. +- There are a lot of messages with length 0xaa (170), these appear to include a + random 32-bit value at offset 0x0046. +- The message content (suspected bitmap-like format) appears to be sent + unencrypted (patterns of 0x0 and 0x1 nibbles clearly visible in hexdump). + +## Unsure/notes + +- Is the endianness of the DS properly emulated? +- Is the NIFI magic value also present in physical frames or is this something + MelonDS did? +- The DS implemented WEP(?) encryption for connecting to home network + routers/APs, but is this encryption also used when the WiFi module is used in + local multiplayer mode? Does this even matter inside the emulator? + diff --git a/experiments/pixel-sequence/draw b/experiments/pixel-sequence/draw new file mode 100755 index 0000000..c26ac27 --- /dev/null +++ b/experiments/pixel-sequence/draw @@ -0,0 +1,31 @@ +#!/bin/sh + +# pray that the mouse is in the edit field once this timer runs out +sleep 3 + +pattern=' +1010 +11001100 +1111000011110000 +11111111000000001111111100000000 +' +pattern="$(echo "$pattern" | tr -d '\n' | sed 's/./\0 /g')" + +for pixel in $pattern ; do + # shift mouse 1 pixel right + xdotool mousemove_relative 1 0 + + # skip 0's in $pattern + [ $pixel -ne 1 ] && continue + + # drag mouse 1px down to create pixel + xdotool mousedown 1 + sleep 0.05 + xdotool mousemove_relative 0 5 + sleep 0.05 + xdotool mouseup 1 + sleep 0.05 + xdotool mousemove_relative 0 -5 + sleep 0.05 +done + diff --git a/wireshark/nifi.lua b/wireshark/nifi.lua index d81ff31..2bc96a6 100644 --- a/wireshark/nifi.lua +++ b/wireshark/nifi.lua @@ -1,6 +1,3 @@ --- NOTE: my system is little-endian, so the .pcap files and this decoder expect --- little endian - local nifi = Proto("nifi", "Nintendo DS ni-fi") nifi.fields.magic = ProtoField.uint32("nifi.magic", "Magic", base.HEX) nifi.fields.senderid = ProtoField.int32("nifi.senderid", "SenderID", base.DEC) @@ -21,7 +18,7 @@ local nifi_type_enum_field = Field.new("nifi.type.enum") function nifi.dissector(buffer, pinfo, tree) -- check magic ("NIFI") if buffer(0, 4):uint() ~= 0x4e494649 then return end - local nifi_tree = tree:add(nifi, buffer(), "Ni-Fi data") + local nifi_tree = tree:add(nifi, buffer(0, 24), "Ni-Fi data") nifi_tree:add(nifi.fields.magic, buffer(0, 4)) nifi_tree:add_le(nifi.fields.senderid, buffer(4, 4)) @@ -36,5 +33,7 @@ function nifi.dissector(buffer, pinfo, tree) pinfo.cols.protocol = nifi.name pinfo.cols.src = nifi_senderid_field().display pinfo.cols.info = "type:" .. nifi_type_enum_field().display + + return 24 end diff --git a/wireshark/pictochat.lua b/wireshark/pictochat.lua new file mode 100644 index 0000000..5eb8089 --- /dev/null +++ b/wireshark/pictochat.lua @@ -0,0 +1,14 @@ +local pc = Proto("pictochat", "Nintendo DS PictoChat") + +function pc.dissector(buffer, pinfo, tree) + + local pc_tree = tree:add(pc, buffer(), "PictoChat Message") + + pinfo.cols.protocol = pc.name + +end + +-- no worky +local nifi = DissectorTable.get("nifi.length") +nifi:add('>0', pc) + diff --git a/wireshark/readme.md b/wireshark/readme.md new file mode 100644 index 0000000..dfebf83 --- /dev/null +++ b/wireshark/readme.md @@ -0,0 +1,4 @@ +## notes + +- my system is little-endian, so the .pcap files and this decoder expect little + endian diff --git a/wireshark/wireshark b/wireshark/wireshark index 42c37a5..ee24518 100755 --- a/wireshark/wireshark +++ b/wireshark/wireshark @@ -1,5 +1,9 @@ #!/bin/sh -# simple wrapper to load nifi.lua script as DLT_USER0 dissecter +# simple wrapper to load lua scripts for DLT_USER0 here="$(dirname "$0")" -exec wireshark -X "lua_script:$here/nifi.lua" -o 'uat:user_dlts:"User 0 (DLT=147)","nifi","","","",""' "$@" +exec wireshark \ + -X "lua_script:$here/nifi.lua" \ + -X "lua_script:$here/pictochat.lua" \ + -o 'uat:user_dlts:"User 0 (DLT=147)","nifi","","","",""' \ + "$@" |