Table of Contents

Xbox portal probe

This diagnostic console targets the Xbox One Lego Dimensions portal at USB ID 0E6F:0141 and the Xbox 360 Lego Dimensions portal at USB ID 24C6:FA01. The main library now supports both portals directly; this application remains useful for raw protocol investigation and command testing. The complete transport and initialization sequence is documented in the Xbox One portal protocol and the Xbox 360 portal protocol.

Windows setup

The standard Microsoft driver identifies either portal as an Xbox Gaming Device and does not expose it to libusb. Use Zadig to replace that device's driver with WinUSB for testing. Select the device with hardware ID USB\VID_0E6F&PID_0141 for the Xbox One portal, or USB\VID_24C6&PID_FA01 for the Xbox 360 portal. Changing the driver may prevent the portal from working with an Xbox until the Microsoft driver is restored.

Native libusb library

LibUsbDotNet 3.0.224 (and its transitive UsbDotNet.LibUsbNative dependency, whose bundled native asset is deliberately excluded via ExcludeAssets="native" in the .csproj) does not ship a usable libusb-1.0.dll for this project. On Windows, run:

.\XboxPortalProbe\tools\update-libusb.ps1

This downloads the latest official libusb Windows release and extracts libusb-1.0.dll into XboxPortalProbe\native\, which the .csproj then copies to the build output on every build. That file is not committed to source control (see .gitignore); re-run the script after a fresh clone or whenever you want to pick up a newer libusb release.

On Linux/macOS, install libusb through your system package manager instead (e.g. apt install libusb-1.0-0, brew install libusb); the OS-provided library is used directly and native/libusb-1.0.dll is not applicable there.

Run the probe:

dotnet run --project .\XboxPortalProbe\XboxPortalProbe.csproj

The probe logs every packet received on endpoint 0x81. Commands are sent on endpoint 0x01:

Before claiming interface 0, the probe attempts to select the portal's first USB configuration, matching the real-portal setup performed by the MITM host.

gip-init
gip-auth-done
gip-identify
gip 05 00
wake
message C0 01 FF 00 00
test-color-all
test-list-tags
test-read 00 24
send 01-02-FF
quit

gip-init sends the normal LEGO wake frame wrapped in GIP report 0x21. If wake does not receive a prompt response, it sends authentication-complete and waits for the queued response. An already-authenticated portal responds directly and may not send ANNOUNCE. IDENTIFY and POWER are not required to operate this portal; use gip-identify separately when investigating its GIP descriptors. The separate gip-auth-done command sends only authentication-complete. Incoming reports are decoded, and identical consecutive reports are collapsed.

Chunked responses such as IDENTIFY are acknowledged and reassembled automatically. The probe prints the complete payload after the final chunk.

wake and message wrap normal 32-byte Lego Dimensions frames in GIP report 0x21. Report 0x21 is confirmed in both directions: the portal returns its normal responses and tag events using the same wrapper. send writes the supplied bytes unchanged, which is useful for investigating the Xbox transport.

Type help for named tests covering wake/seed/challenge, every color effect, tag listing and reading, NFC enablement, password mode, model lookup, and tag writing. Tests with tag-specific or destructive data require explicit payloads; in particular, test-write never supplies default bytes.

Xbox 360 investigation

If no Xbox One portal is present, the probe falls back to the Xbox 360 portal at 24C6:FA01. The main library (LegoDimensions.LegoPortal) now supports this portal directly too; this mode remains useful for raw protocol investigation. See the Xbox 360 portal protocol for the verified frame format and concurrency requirements.

The probe claims interface 0 for interrupt endpoints 81/01. Interface 3 (XSM3 security) is never claimed for normal operation - the toypad replies to LEGO application commands (wake, colors, tag reads, tag events) without any authentication. xsm3-auth and the control-in/control-out commands claim interface 3 on demand purely for XSM3 protocol investigation.

All reads and writes happen sequentially on a single thread. A background thread continuously reading while a write happens on another thread was found to silently lose replies on this device/host stack - not a device-side gate.

send <hex>
wake
xinput-led
test-color
test-get-color
test-list-tags
test-read [index page]
test-seed [seed-hex] [nonce-hex]
test-challenge [8-byte-hex]
listen [seconds]
xsm3-auth
control-in <request-type request value index length>
control-out <request-type request value index hex>
quit

All numeric fields are hexadecimal. The portal accepts the standard Xbox 360 capability requests and identifies itself through XSM3 request 81:

control-in c1 81 5b17 0103 1d
494B000017FDB758440233852438032000008082C6240050030001016E

The XSM3 record is checksum-valid and advertises security VID/PID 24C6:5000, while the outer USB device remains 24C6:FA01.

xsm3-auth performs the complete security exchange: identity (81), challenge initialization (82), status polling (86), phase-one response (83), a fresh session-specific verify packet (87), final response validation (83), and acknowledgement (84). The host cryptography is validated against the published Microsoft-controller transaction. The original LEGO portal uses unpublished third-party 0x23/0x24 key material, so its live phase-one response currently fails validation. A captured 87 packet cannot be replayed because it is bound to that authentication session. None of this is required for normal operation.

A real console-to-portal MITM capture confirmed several details of this implementation and the surrounding sequence: xsm3-auth's two 87/86/83 verify rounds (not just one) match a genuine session exactly, byte for byte, including every request's wValue/wLength; the wake command's message ID is simply echoed back rather than required to be 0 (a real console sends 1); and the console also issues two vendor requests (c0 01 0000 0000 0004, c1 01 0100 0000 0014) and a short, unwrapped 3-byte interrupt report (01 03 01, the xinput-led command below) once XSM3 completes and before the LEGO wake, plus a harmless, repeating, always-stalled vendor control-out poll of interface 2 (41 00 001e/001f 0002) throughout the session - that interface is the unused chatpad pass-through and is never claimed by this probe or the main library.

Xbox 360 LEGO messages use report prefix 0B 16 followed by 30 bytes of the standard LEGO frame. The wake command applies this wrapper automatically. An earlier capture had misread this prefix as 0B 14; the corrected value is confirmed by the dopheideb/LEGODimensions toy pad firmware extraction.

test-seed and test-challenge exercise the base LEGO seed/challenge protocol (commands 0xB1/0xB3), independently of Xbox security. The seed/nonce is TEA-encrypted with a global key recovered from the same firmware extraction (PortalTea.cs), and test-challenge independently reproduces the portal's internal RNG (PortalRng.cs, a Bob Jenkins "burtle"-style generator) to verify the device's response byte-for-byte. test-seed must succeed before test-challenge can predict a matching reply.