水星 Mercury MIPC251C-4 网络摄像头 ONVIF 与 PTZ 云台控制
date
‣
slug
Mercury-MIPC251C-4-Reverse
status
Published
tags
HomeAssistant
summary
最近在 什么值得买 上发现一款水星的网络摄像头, 除了支持云台/夜视功能之外, 还标明支持 onvif 协议. 所以想着买来接入到 HomeAssistat 作为监控使用.
可到手之后发现事情并没有那么简单, 记录如下.
type
Post
概况
最近在 什么值得买 上发现一款水星的网络摄像头, 除了支持云台/夜视功能之外, 还标明支持 onvif 协议. 所以想着买来接入到 HomeAssistat 作为监控使用.
可到手之后发现事情并没有那么简单, 记录如下.
接入 HomeAssistant
按照 HA 的文档 ONVIF Camera 接入无非就是配置文件里写两行配置的事, 但无论是使用默认配置还是尝试后台页面里的几个端口都是添加失败.
最后使用 DSM 的 Surveillance Station 找到了正确的端口, 事后发现其实使用 iSpy 也可以找到正确的端口, 端口是2020.
HA 配置如下:
需要注意的是使用 onvif camera 需要配置
ffmpeg
, 另外可能根据环境不同需要 pip install onvif-zeep-async
ONVIF 与 RTSP 参数
onvif
http://192.168.2.x:2020/onvif/device_service
rtsp 1920x1080
rtsp://admin:pass@192.168.2.x:554/stream1
rtsp 640x480
rtsp://admin:pass@192.168.2.x:554/stream2
PTZ / 云台控制
接入 HA 和 DSM Surveillance Station 之后发现云台不能控制, 看来说的支持 ONVIF 只是可以录制.
剩下的大部分记录如何控制云台.
抓包
Charles 抓包的结果是失败, 应用没有走设置的代理.
反编译 Android App
在尝试了 Charles http 抓包无果之后试着反编译 水星安防App.
然后发现大段
com.tplink.ipc
的代码, 看来水星真的是 TP 的弟弟.应用开了混淆, 挺好…
- 添加本地局域网设备 Fragment
com.tplink.ipc.ui.device.add.DeviceAddByDeviceDetailInputFragment
- 登录
com.tplink.ipc.ui.device.add.DeviceAddByDeviceDetailInputFragment#xcom.tplink.ipc.core.IPCAppContext#devReqAddDevice(java.lang.String, int, java.lang.String, java.lang.String, int, int)
而 devReqAddDevice 执行的 native 方法, 真正的实现在libIPCAppContextJNI.so
看来网络请求是在 JNI 里做的, Charles 抓不到包. 反编译 so 库吃力不讨好, 换方向.
WireShark iOS 抓包
rvictl 可以将 iOS 设备虚拟成一个网络端口, 然后就可以 WireShark 抓包. 好处是这样可以减少一些局域网的干扰.
使用 rvictl 还可以抓 3G/4G 的包, 可以用来抓一些只能在 4G环境下才能复现的问题的包. 同样, 对于一些不支持设置代理的设备, 也可以通过把 iPhone 设置为热点来抓包.
rvictl -s 0000xxxx-00xxxxxxxxxxxxxx
抓包发现 App登录 控制云台的几个步骤的网络请求如下: (1,2两步是根据网页端登录分析出来的)
- 获取 RSA 公钥和 nonce
- 使用公钥加密密码, 登录, 获取 stok
- 发送控制指令
登录
获取 stok
控制
使用获取的 stok post 指令
小结
目前看来想要控制云台/摄像头的关键是获取 stok, 可以通过抓包可以获得, 但是通过观察当设备重启或着过一段时间(?)就就会失效.
获取 stok
这款摄像头虽然有 web 端但是不支持在 web 端控制云台, 所以开始的抓包没有考虑 web 端. 对 web 端分析发现登录验证使用的是同样的逻辑.
步骤如下
- 获取 RSA 公钥 和 nonce (公钥和 nonce 每次都会变化)
- 使用 tp-link 的通用加密方式将
密码 password
加密 为tpPassword
- tpPassword 追加 :nonce 为
tpPassword:nonce
- tpPassword:nonce 使用 公钥加密为
rsaPassword
- rsaPassword 作为密码发送给摄像头验证
对于步骤 2 3 记录如下
tp-link 加密密码为 tpPassword
搜索 RDpbLfCPsJZ7fiv 可以找到这种加密的各种实现.
RSA 加密 tpPassword 为 rsaPassword
其中
a = a.concat(":", $.authRltObj.nonce)
即为追加 noncec.setPublicKey($.authRltObj.key) 设置公钥
后面的 sendAjaxReq 就是发送请求
控制脚本
根据上面的分析写的脚本