This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.
It’s already senior year in a blink of an eye, and I’ve been messing around with these class display panels quite a lot. Along the way, I’ve learned quite a few things.
After a long break from tinkering with them—spent too much time on other projects—I’ve made some solid technical progress.
Luckily, our new homeroom teacher has always found it inconvenient that the class display is placed outside, so I decided to dive back in and see what new discoveries I could make.
In one sentence: I reverse-engineered the communication protocol of the class display.
The device itself doesn’t have any obvious vulnerabilities. It runs the main app as the default Launcher, and ADB is disabled. Although it’s technically an Android device, there’s no way to break out of the sandbox.
So I decided to start from reverse-engineering its communication protocol instead.
0x00 Capturing Network Traffic
To reverse-engineer and eventually re-implement the communication protocol, the first step was obviously to capture the network traffic from the display panel.
Attempt 1: Hardware-Level Packet Capture
I brought a OpenWRT router (HG 255D) to school, planning to insert it between the original network cable and the class display—plug the cable into the router, then connect the router to the display—and use tcpdump on the router to capture traffic.
But later I realized—a shaky foundation leads to collapsing walls, as the saying goes. (Yeah, really.)
My computer networking fundamentals weren’t strong enough. I struggled with all the OpenWRT settings. In switch mode, packets wouldn’t get captured at all. If I tried letting the router connect to the network first, I had to set up a DHCP server (our school uses the 10.52.x.x subnet), which brought even more complications. Trying different setups meant constantly moving the router back and forth—way too much hassle. After a month, I “successfully” failed.
Attempt 2: ARP Spoofing
Later, I noticed that both our classroom computers and the class display were on the same subnet. So why not just use ARP spoofing?
I set up a virtual machine with Kali Linux and started ARP spoofing. (The exact process isn’t worth detailing—plenty of guides on Google.)
I hit a small pitfall: I hadn’t used Wireshark much before. At first, I saw a bunch of black-highlighted “TCP Retransmission” entries and thought the TCP connection wasn’t even establishing. After struggling for ages, I accidentally realized the data had actually been captured all along.
Wireshark
0x01 Reverse-Engineering the Protocol
At first, I assumed the display would use HTTP, but turns out it communicates directly over raw TCP.
This was actually my first time reverse-engineering a custom TCP protocol.
The captured packets mainly fall into two types: actual data packets and heartbeat packets.
1 | Data packet: |
The packet formats used by the server and client are quite similar, so I won’t separate them here.
The essence of reverse-engineering? Two words: Guess & Test. (lol)
After repeated trials, I uncovered the packet structure:
- The first 2 bytes are always
4e4d - The next 4 bytes represent the packet length in little-endian; just read the value and read that many bytes after
- Then comes a seemingly fixed sequence:
01000001ffffffffffffffff - Next are little-endian encoded values for year, month, day, hour, minute, second (Why not use a Unix timestamp??)
- The following 5 bytes vary: for client-sent data packets, it’s
0100000000; for heartbeats, it’s1b00000000. Server responses don’t seem to follow this rule - Then comes the actual payload—UTF-8 encoded data in big-endian byte order (Why mix endianness in one packet??). For heartbeats, it’s the device’s serial number (SN); for data packets, it’s JSON
- Finally, a fixed
00byte marks the end
With this understanding, sending and receiving JSON-formatted data became straightforward. The reverse-engineering part got much easier. (Thank goodness they used JSON at the end—otherwise this would’ve been way more painful…)
I’ve written a rough implementation and published it on GitHub: https://github.com/lyc8503/IncichSchoolUtilities
Now, the fun part begins…?
This article is licensed under the CC BY-NC-SA 4.0 license.
Author: lyc8503, Article link: https://blog.lyc8503.net/en/post/incich-third-3/
If this article was helpful or interesting to you, consider buy me a coffee¬_¬
Feel free to comment in English below o/