Toda mi ambición es ser libre toda mi vida.
腾达模拟过程文档
腾达模拟过程文档

腾达模拟过程文档

1. US_AC10V1.0RTL_V15.03.06.45_multi_TDE01
固件分析
使用binwalk分析并解包固件:

固件包含Squashfs文件系统和LZMA压缩格式的数据;
解包之后通过分析文件系统的etc-ro/init.d/目录来分析http服务的启动过程:

但是etc-ro/init.d/目录下的rcS文件并没有与http服务启动相关的代码:

直接搜索字符串查找http程序:
grep -r HTTP

搜索出来的二进制程序都在bin目录下,其中有两个程序可能和http服务有关:httpd和dhttpd;使用file和readelf命令查看系统架构:

arch:mipsel;
使用qemu运行这两个程序,根据运行结果进一步确定web程序:
cp $(whereis qemu-mipsel-static) ./
sudo chroot . ./qemu-mipsel-static ./bin/httpd
sudo chroot . ./qemu-mipsel-static ./bin/dhttpd

httpd是http程序,uhttpd是goahead的调试程序;
模拟启动
通过上面的分析,发现httpd程序运行会报错,通过搜索报错字符串或者动态调试可以找到报错的原因;
使用IDA分析httpd程序,搜索Initialize AP MIB failed !字符串,查看交叉引用,发现是apmib_init()函数执行返回0程序才会打印错误字符串;

查找apmib_init()函数在哪个库文件的方法是先查看httpd程序加载了哪些库文件,然后使用nm或者objdump -x命令查看so文件的符号表,即可找到定义apmib_init()函数的库文件;如果so文件没有符号表,可以使用grep搜索字符串apmib_init,也可以找到对应的so文件;

最后可以找到apmib_init()函数在libapmib.so文件中定义:

下面分析apmib_init()函数的具体功能,尝试修复固件的运行环境:
apmib_init()函数分析:
apmib_init()函数在libapmib.so文件中定义:

通过分析,要让apmib_hwconf(),apmib_dsconf()和apmib_csconf()这三个函数的返回值都为非零才能让apmib_init()函数返回1。下面分析这三个函数。
apmib_hwconf()函数:
apmib_hwconf()函数首先会调用sub_497C函数读取/var/flash_mib文件中的内容,就是hw setting header;然后会比较hw setting header;

通过动态调试可以得到比较的三种hw setting header的内容,分别是
off_A1B0:H6
off_A1B4:Hf
off_A1B8:Hu

分析memcmp后面的代码,如果/var/flash_mib文件中的hw setting header和上面三种的其中一种相同就会使fdata为0,然后后面的if判断为假后就会跳到114行继续执行,这里要尽可能使代码的执行流程简单,也就是执行的代码少,所以这里先在/var/flash_mib文件中写入H6作为hw setting header;

可以看到程序再次去调用sub_497C函数读取/var/flash_mib文件,然后将读取到的数据放到hsHeader结构体中,然后就会比较hsHeader的前两个字节是不是为off_A1B0:H6,说明/var/flash_mib文件中的前两个字节要是H6,否则就会报错;

hsHeader大小为6个字节,同时还有csHeader和dsHeader,这两个在后面会用到。接着往下分析,128行会检查v24的值是否为1,并检查word_24D2C的值是否大于等于0xE14u。可以看到如果if的条件满足接下来不远处就有一个return指令,并且返回值不为0,所以先尝试让if条件为真。v24是在121行进行赋值,并且值来自于byte_24D2A,而byte_24D2A又是hsHeader的一部分,所以v24的值可控,word_24D2C也是hsHeader结构体的一个数据域,也是可控的,而hsHeader结构体的内容又来自于/var/flash_mib文件,所以可以构造/var/flash_mib文件的前六个字节就可以控制程序的执行流。因为hsHeader中有不可见字符,所以需要有echo命令往/var/flash_mib文件中添加内容。
echo ‘H601\x0E\x14’ >> /var/flash_mib
继续往下分析,调用sub_6994函数,创建共享内存,能够正常执行并返回非零值(共享内存的起始地址)。

然后程序在131行会判断v16和v25的值,因为v16是函数的返回值,是非零的,而v25作为sub_6994函数的参数,会在函数中被设置为1,所以if条件判断为真,接着会判断fdata的值,因为fdata为0,所以会返回v16,是共享内存的基地址,非零,条件满足。

结合上面的分析,可以构造/var/flash_mib文件:

apmib_dsconf()函数:
apmib_dsconf()函数和apmib_hwconf()函数分析起来差不多,区别是apmib_hwconf()函数从/var/flash_mib文件0x4000的位置开始读取内容,并且读取8个字节,因为dsHeader的大小是8个字节。

继续构造/var/flash_mib文件:

apmib_csconf()函数:
apmib_csconf()函数分析流程也一样,区别是apmib_csconf()函数从/var/flash_mib文件0xA000的位置开始读取内容

最终构造的/var/flash_mib文件:

构造好/var/flash_mib文件之后运行httpd程序:

没有之前的报错Initialize AP MIB failed !,但是发现程序卡住,通过动态调试,发现是check_network()函数检查不通过,导致出现死循环,一直sleep;

解决办法,是配置br0网卡(这是在后面配置完br0虚拟网卡之后发现的);配置好网卡后,再次运行程序:

程序能够继续运行,但是报错connect cfm failed!;搜索报错的字符串,定位到相关代码:

发现是ConnectCfm()函数返回为0导致的,下面分析ConnectCfm()函数:
ConnectCfm()函数:
ConnectCfm()函数在libCfm.so文件中定义:

主要是ConnectServer()函数,要让其返回一个大于0的数:

参考Qiling框架,在本地开启一个listen:
再次运行程序:

可以看到没有报错,但是程序最后获取的IP是一个错误的IP,原因出在网卡上,需要添加br0虚拟网卡。具体分析如下:

添加br0虚拟网卡可参考:
IOT环境搭建–如何使用qemu运行各种指令架构程序
添加好网卡之后再次运行:

可以看到程序获取到正确的IP地址。用浏览器访问IP,响应404;

出现这种情况的原因有两种:一种是文件系统中没有网页文件(如.html,.htm,.js等文件);一种是web的根目录没设置好;
先查看文件系统中有没有网页文件:

可以看到文件系统中存在网页文件,而且web根目录是webroot_ro。推测可能是web的根目录没设置对。之前在分析etc/init.d/rcS文件的时候发现其中有对web目录的操作:

rcS程序在初始化的时候将webroot_ro目录下的所有网页文件复制到webroot目录中,webroot才是真正的web根目录。同时,在httpd程序中也可以发现webroot:

可以删除文件系统根目录下的webroot文件,然后创建webroot目录,将webroot_ro目录中的所有文件复制到webroot中,再次运行程序,浏览器访问:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注