The obvious first move for reverse-engineering a WiFi protocol is to watch the traffic the app
actually sends. That's harder on iOS without a jailbreak, so I found an Android build of the same
app family instead — same vendor stack, same camera, and WiFi framing that shouldn't care what
phone OS is asking for it. I installed a capture tool called PCAPdroid, which sniffs traffic on
Android without root by routing it through a local VPN interface, connected to the camera's AP, and
recorded a session.
The capture was baffling. Instead of anything that looked like a video protocol, I saw a small
heartbeat-looking packet (fe1a…) going out over UDP :8000, and a TCP connection attempt to
:10005 that came back RST — refused outright. No sign of a sustained video stream anywhere. My
first read of this was that the camera itself was in some kind of dead or locked state, refusing the
connection the app needed.
That read was wrong, for two independent reasons, and it took a while to untangle both:
1. It was a bad capture, not a working one. The session I recorded happened to be one where the
app itself never got a picture up either — so of course the traffic looked broken. I was
reverse-engineering a failure, not the protocol.
2. The capture tool couldn't see the video path at all, even on a good session. PCAPdroid's
no-root mode works by presenting a VPN interface and letting Android route app traffic through
it. But the camera app doesn't send its video traffic through the device's default route — it
explicitly binds its camera sockets to the WiFi network object (Network.bindSocket, an Android
API for pinning a socket to a specific physical interface). That bind happens *underneath* the
VPN layer, so the video traffic never passes through PCAPdroid's tunnel in the first place. I
wasn't looking at a locked-down camera; I was looking through a window that the real traffic
physically couldn't reach.
In other words: two layers of "this isn't the real thing" stacked on top of each other, and both
had to be recognized before the capture became useful for anything. Lesson taken forward: confirm
you're capturing a working session, and confirm your capture tool can actually see the traffic
you're chasing, before trusting what it shows you.
With that resolved, a cleaner capture (and some digging into the app's bundled native libraries)
turned up something interesting: the app ships two entirely different camera SDKs. One,
libjh_wifi.so, belongs to a "JoyHonest" GP/GK camera family — its own command set (JHCMD), its
own port (UDP :20000), and its own separate MJPEG-over-HTTP endpoint on :8080. It looked like a
complete, plausible protocol in its own right, and for a while it was the leading theory.
It was a dead end. Testing against the MS5 directly, none of the JoyHonest ports or commands got a
response — the MS5 simply isn't driven by that SDK. It's bundled in the app because the app supports
a whole family of the vendor's cameras, and the JoyHonest path belongs to a different product line.
Confirming that and setting it aside completely was necessary before the real path forward became
visible.
Yurii
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.