# 海康萤石智能门锁的网关分析（3）

在上一篇中，我们完成了固件编辑和重打包工作。在我们自己修改的固件中，海康萤石的智能网关上电启动之后会运行telnetd，此后我们只要通过telnet远程连接网关即可使用shell，不需要再连接不稳定的串口了。&#x20;

继续上一篇的内容，我们从本篇开始分析智能网关里面的关键应用，研究一下智能网关到底与服务器通信了什么内容。

## **程序逆向分析**

### 2.1 预处理

在海康萤石智能网关中执行ps指令，查看所有正在运行的程序，通过简单的排除法，就可以确定我们要分析主程序是：’/dav/davinci’（达芬奇？达文西？），如下图所示：

![图2-1 固件中运行的所有进程](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKfn2cOFcbEI1MKaXZ%2Fimage.png?alt=media\&token=9e0a47ff-916b-4126-aa2b-af664160594d)

通过逆向分析davinci程序，我们可以发现该程序是有运行日志的，只是把不重要的日志屏蔽了(debug、verbose等)，只输出了较为严重的日志内容(fatal、error等)。那么我们修改几条指令，使其跳过对日志严重程度的判断，如下图：

![图2-2 patch日志输出代码](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKfq13Gfiuup2ziarM%2Fimage.png?alt=media\&token=bd9f907a-4919-4b21-9d51-5b012750d767)

除了输出日志的函数需要patch之外，还有另一个函数也需要做一些调整。davinci在启动之后，初始化了一个线程操作看门狗，该线程会不断向/dev/watchdog进行写操作。如果一段时间内/dev/watchdog没有收到任何数据，那么整个设备就会重启。由于我们计划调试davinci程序，如果在调试过程中，触发断点导致看门狗线程挂起，那么整个系统就会重启。为此，我们先把该线程patch掉，然后再弄一个写入/dev/watchdog的小脚本，用以专门喂狗防止重启。相关位置的代码截图如下：

![图2-3 patch watchdog相关代码](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKft6SAZAsJkrm-6Cz%2Fimage.png?alt=media\&token=a6548ed1-7b93-4ba0-bc0f-06349177236d)

喂狗的小脚本内容如下：

![图2-4 喂狗小脚本](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKfwUm-55F-P53-vk5%2Fimage.png?alt=media\&token=b6b098ff-1ab3-4597-bc48-d8f58cf69746)

相信脚本内容一眼就能够看懂，所以我们不做太多的解释了。此外，还有个guard.sh也是用于检测davinci程序是否运行的，但它不影响我们的操作，所以就不讨论该脚本了，有兴趣的读者可以去看看。&#x20;

完成上述操作之后，就可以把被patch的davinci上传至海康萤石的智能网关，此处我们不再采用烧录固件的方法，因为过于麻烦。通过翻阅该设备的文件系统，可以在设备中发现tftp程序，这是一个使用tftp协议传输文件的程序，可以用它从tftpd服务器上传或下载文件。我们使用从这个链接下载到的tftpd程序：<http://tftpd32.jounin.net/tftpd64\\_download.html，运行后，调整tftpd服务器的文件目录和监听网卡，如下图：>

![图2-5 配置tftpd程序](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKg0qvEgP76ATZmhrG%2Fimage.png?alt=media\&token=de39101e-e7e4-4ce1-befe-5b634a363246)

上图中，被patch的davinci程序就在红框标识的目录中。然后在智能网关设备中使用tftp程序获取相关文件即可，相关命令截图如下：

![图2-6 使用tftp下载文件](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKg3hkdUhAU2oPSb2u%2Fimage.png?alt=media\&token=6edd36da-c9f1-49e3-82ac-f3041b92c40d)

待相关文件下载到海康萤石的设备中之后，就可以运行FeedWatchdog.sh脚本开始喂狗，然后终止原本的davinci进程，接着删除/home/pidfile文件，该文件相当于互斥体，用于控制davinci仅运行了一次，最后启动我们自己的davinci\_1进程，相关命令如下：

![图2-7 启动patch之后的davinci进程](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKg9Jtd2RQ6CSQZlk-%2Fimage.png?alt=media\&token=a87bf93d-c5aa-43db-8630-98a675e3a8b2)

待程序运行一段时间之后，就可以查看程序的运行日志，然后通过日志分析程序的各种行为。&#x20;

### 2.2 日志分析&#x20;

待程序运行一段时间之后，就会在‘/applog/devlog’目录下生成日志文件，每个文件500KB左右，如下图所示：

![图2-8 程序运行时生成的日志](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgDgood2X1fGI8Pf3%2Fimage.png?alt=media\&token=328a0110-1186-4b7d-95e3-ef5e0ddf1ab2)

用tftp程序将日志取回，然后打开程序日志，在日志中搜索litedev.ys7.com，这个地址是智能网关上电之后第一个访问的地址，我们在本专题第9篇，也就是分析海康萤石智能网关的第一篇中介绍过。搜索结果如下图：

![图2-9 与litedev.ys7.com有关的日志](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgHVmHkDEN7GnQy06%2Fimage.png?alt=media\&token=087860b5-bec0-494d-bb9a-0f68057b4aeb)

上图中，我们可以看到由litedev.ys7.com解析而来的ip地址：115.231.107.14，这与我们用wireshark抓包时得到的结果是相同的。&#x20;

继续翻看日志，在距离图2-8不远的地方，可以看到另一条日志，看起来像是与海康萤石MQTT服务器相关的日志内容，截图如下：

![图2-10 与MQTT服务器有关的日志](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgKtr1yHHzz_uIVO3%2Fimage.png?alt=media\&token=35a60a3b-0b2b-40e2-a85a-c2f6eb259a4a)

从图中，我们可以看到另一个ip地址：101.71.30.172，该地址同样与我们wireshark抓包的结果吻合。MQTT通信协议是构建于TCP/IP协议之上的一种轻量级通信协议，经常出现在IoT设备系统中设备端与云端的通信过程中。&#x20;

结合这两条日志内容和wireshark的抓包结果，我们可以进一步确认设备的工作流程：与litedev.ys7.com通信，获取了MQTT服务器的地址；然后与MQTT服务器通信，实现设备的逻辑功能。&#x20;

在图2-9和图2-10中，我们分别用红框标识了一个关键字符串。在海康萤石智能网关的文件系统中，二进制搜索其中一个字符串“lbs\_connect”，确认该字符串出现在libmicrokernel.so.1中。用IDA加载该so文件，可以发现此动态链接库中，有一个函数名字即为lbs\_connect，查找该函数的交叉引用，可以看到有多处代码调用了此函数，我们随便找一处点开看下，如下图所示：

![图2-11 调用lbs\_connect函数](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgQ93mewNSg__7hBP%2Fimage.png?alt=media\&token=6d1398c5-113d-4fde-bbdf-ecde0363b264)

可以看到在lbs\_connect函数返回成功之后，就会调用send\_authentication\_i函数。这个函数看起来就是加密和认证相关的函数。

## **程序调试**

找到了关键点之后，就需要进一步分析这些函数的功能和作用了。在本专题之前的文章中，我们都是纯静态分析，所以在本篇中，我们就不再单纯地进行静态分析，而是想办法调试一下这个程序。

对于嵌入式Linux操作系统，我们通常选用gdb和gdbserver作为调试工具。gdb是一个应用非常广泛的调试器，在以后的文章中也会反复出现，其全称是GNU Project Debugger，其官网是<https://www.gnu.org/software/gdb/；gdbserver是gdb的一部分，常用于解决交叉编译环境下的远程调试问题。我们可以直接在设备上使用gdb进行本地调试，但gdb程序体积比较大，而且直接在设备上运行gdb会有很多不方便的地方，所以我们选择通过gdbserver进行远程调试。为了完成调试工作，我们首先需要一个可以运行在海康萤石智能网关设备上的gdbserver程序。>

在此前关于海康萤石智能网关分析的第二篇文章中，我们下载了MT7688 SDK相关的资料。在进一步翻阅相关的资料之后，我们发现官方MT7688开发板是内置了gdbserver程序。因此，我们下载了官方提供的固件包，并用binwalk提取了固件内容，最后找到了gdbserver程序。但此gdbserver程序运行之后没有任何输出，推测是官方定制了gdbserver的代码，导致我们无法使用该程序调试，截图如下：

![图3-1 官方gdbserver无法使用](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgXtT3IWTTm28UhW2%2Fimage.png?alt=media\&token=3049c49f-80db-4fed-a1c3-4e9963421da5)

所以，就只能去找一找有没有其他可以正常运行在海康萤石智能网关中的gdbserver程序了，毕竟自己编译一个有点太麻烦了。幸运的是，在rapid7官方github账户上有一些已经编译好的gdbserver程序，链接如下：[https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver，](https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver%EF%BC%8C) 我们选择下载mipsle版本的gdbserver。截图如下：

![图3-2 rapid7官方github页面中的embedded-tools仓库](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgbWXArbPkvBu78Xu%2Fimage.png?alt=media\&token=ad3f5ff8-ccf0-41fe-8f95-989afcd0173a)

下载完毕之后，通过tftp下载至海康萤石智能网关的设备中，并尝试执行此程序。截图如下：

![图3-3 执行gdbserver.mipsle程序](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgf1ERGnbSgib0afR%2Fimage.png?alt=media\&token=fb683da0-c5e3-4541-bf77-8e1b595d0165)

程序没有报错，看来是可以顺利执行的。接下来就用此程序开始调试吧。&#x20;

首先，使用 gdbserver启动davinci。如果直接用 gdbserver附加davinci进程，很可能会错过davinci程序与服务器通信的认证过程。所以我们直接使用gdbserver启动程序，这样一来，在远程调试器连接之前，davinci程序将处于挂起状态。命令如下：

![图3-4 通过gdbserver启动程序](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgibXEaaZzYKvVI5J%2Fimage.png?alt=media\&token=fcb5cf7e-0dec-475d-ac35-5f839f3d0ed1)

此时，gdbserver就开始监听23946端口，等待远程调试器的连接。&#x20;

接下来，我们可以选择gdb或IDA作为远程调试器连接gdbserver。IDA提供图形界面，可以帮助我们理解程序的逻辑；但gdb要更稳定，可以有效避免IDA调试时出现的奇怪错误。我们这里直接选择gdb作为远程调试器，在后续的文章中会有介绍用IDA作为调试器的例子。&#x20;

由于我们需要调试的是MIPS指令集的程序，而gdb默认情况下，仅支持调试与当前环境采用相同指令集的程序（i386），所以我们需要安装可以调试MIPS指令集的gdb程序。安装方法比较简单，直接输入sudo apt install gdb-multiarch即可。还可以给gdb程序加一个pwndbg插件，用于辅助我们的调试工作，该插件的官方地址是：<https://github.com/pwndbg/pwndbg，只需要下载下来，然后运行./setup.sh即可。此插件并非必需品，但是推荐装上。&#x20>;

完成gdb的配置工作之后，就可以使用gdb连接gdbserver开始远程调试了。gdb的调试命令非常多，可以直接搜索到很多整理好的常用命令，在这里，我们就遇见什么指令就解释什么指令吧。运行gdb-multiarch，截图如下：

![图3-5 运行gdb-multiarch程序](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgourZ93TyV_mDfAM%2Fimage.png?alt=media\&token=0790a226-2278-4e0e-b12c-eab20fab7aa0)

上图中，我们分别设置architecture为MIPS，读取davinci的符号文件，在main函数设置断点，并连接远程的gdbserver，关键位置已用绿框圈出。然后，我们用快捷键c（continue），让程序开始执行，截图如下：

![图3-6 程序运行到main时中断](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgsXuIs4YjT6j3A69%2Fimage.png?alt=media\&token=d4a0e30d-70ca-409a-a520-476c54c2c047)

上图中，红框部分表示触发了main函数中的断点。此时，我们加载libmicrokernel.so.1的符号文件，同样用file命令，就不截图了。然后，我们在lbs\_connect函数下个断点，并继续执行程序，如下图：

![图3-7 在lbs\_connect函数下断点](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgvxy7gYvApCaUgWE%2Fimage.png?alt=media\&token=854e52a8-ec86-46bb-89f2-544c9c67763d)

稍等片刻，就会看到程序断在lbs\_connect函数中，等待我们的调试命令，截图如下：

![图3-8 程序命中lbs\_connect断点](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MdKcOvqFrr00ixch-eO%2F-MdKgyh3RZqEBLBPj7-1%2Fimage.png?alt=media\&token=c7ea4315-1120-4e7f-a518-acb9d9d4ad24)

从图中可以看到，程序是从lbs\_redirect调用过来的，可以在外层函数下断点，继续调试，帮助我们理解程序的逻辑，但是本篇内容先到此为止。

## **小结**

从本篇起，我们开始分析海康萤石智能网关的固件程序。在我们的分析过程中，程序的日志给我们提供了很多帮助。借助日志的输出内容，我们很快定位到了通信加密相关的代码。接着为了进一步研究设备是如何认证和加密的，我们尝试使用gdb和gdbserver调试固件中的程序。关于进一步的分析内容将在下一篇分析中展开讨论。
