| diagrams | ||
| pics | ||
| tests | ||
| types | ||
| .gitignore | ||
| .mocharc.json | ||
| .prettierrc.yaml | ||
| a.js | ||
| datatypes.ts | ||
| dissector.lua | ||
| frida-hooks.js | ||
| func_replacements.js | ||
| handlers.ts | ||
| hexdump.js | ||
| impl.ts | ||
| loader3.py | ||
| Makefile | ||
| package-lock.json | ||
| package.json | ||
| proto | ||
| README.md | ||
| server.ts | ||
| shim.ts | ||
| tsconfig.json | ||
| utils.js | ||
Re-implementation of the "ilnk" protocol used on some cheap (<$5) IP cameras (sometimes branded as 'X5' or 'A9').
- Bought here.
- Waiting for this A9 camera to validate support.
- App is YsxLite
Per pictures the main chip is TXW817 (chinese, eng, google translate)
The interesting implementation is in libvdp.so, part of the apk bundle.
Protocol reversing was done with a combination of static analysis of the shared object with Ghidra and dynamic analysis with Frida.
The headers reversed with Ghidra are at types/all.h. They are almost not used by this minimal implementation though.
The hooks used with frida are at frida-hooks.js, but it's mostly a playground - some useful functions got deleted once I understood the protocol.
There's also a pretty crappy Wireshark dissector at dissector.lua. You can install it with make install-wireshark-dissector.
Running
To execute the server, run make run; JPEG files and audio.pcm will be created in a folder named captures.
There's no live-stream server built into this project yet.
Protocol
The protocol is weirdly complex, though very little communication is necessary to use the device
The base structure of a packet is:
The payload is command-dependent; most commands have only a literal payload, but the Drw (0xf1d0) command has a framing scheme:
By using the second byte in the payload as a discriminant, we can split the payload into two types of subcommands:
Control packets:
The payload on control packets is "encrypted" when the length is > 5.
Data packets:
Data packets further discriminate based on the first 4 bytes into: Audio Data (0x55aa15a8), Video data.
Session
To establish a session, a few control packets are sent.
---
title: Establish session
---
sequenceDiagram
autonumber
App->>+Cam: [C] LanSearch
Cam->>-App: [C] PunchPkt (SerialNo)
App->>+Cam: [C] P2PRdy
Cam->>-App: [C] P2PRdy
App->>+Cam: [C] ConnectUser
Cam->>-App: [C] ConnectUserAck (Ticket)
loop Every 400-500ms
Cam-->>+App: [C] P2PAlive
App-->>-Cam: [C] P2PAliveAck
end
To start a stream, a single control packet is sent.
The received stream is broken up into 1028 byte payloads, along with a sequence number.
Stitching the payloads together yields JPEG frames for video, and 8KHz A-law PCM for audio.
---
title: Stream audio/video
---
sequenceDiagram
App->>Cam: [C] StreamStart (with Ticket)
loop
Cam-->>+App: [D] Audio/Video Payload
App-->>-Cam: [C] DrwAck
end
Take APK from emulator/sacrificial device
adb shell pm list packages | grep ysx
adb shell pm path com.ysxlite.cam
adb shell pm path com.ysxlite.cam | while read -r line ; do adb pull $(echo $line | cut -d: -f2-) ; done
Push to sacrificial device
adb install-multiple *apk