编译华芸ADM系统设备驱动
华芸的ADM系统默认支持e1000和e1000e网卡,它也有igb的网卡驱动,但启动时没有加载。为了让创建的启动盘能够支持更多类型的网卡,我为大家编译了几个网卡驱动,并写了一段启动加载脚本作为例子。
先从简单的启动加载脚本说起。启动脚本要放入/etc/init.d目录。由patch.gz通过grub补丁到系统中。文件名:S10extmodules。它的内容如下:
#!/bin/sh
#
# Load the external modules....(by laojifuli)
#
case "$1" in
start)
echo "Starting extmodules...."
# Supports all 82575/6, 82580, I350, I354, and I210/I211 based gigabit network connections
modprobe igb
sleep 1
depmod # Update the module dependencies for the currently running kernel.
# Supports VMware vmxnet3 virtual NIC driver
#insmod /lib/modules/`uname -r`/vmxnet3.ko
modprobe vmxnet3
sleep 1
# Supports Virtio network driver
#for x in failover net_failover virtio_net; do
# insmod /lib/modules/`uname -r`/"$x.ko"
#done
#sleep 1
# Supports RealTek RTL-8139 Fast Ethernet driver
for x in mii 8139cp; do
#insmod /lib/modules/`uname -r`/"$x.ko"
modprobe "$x"
done
sleep 1
NETDEVICES="$(awk -F: '/eth.:|tr.:/{print $1}' /proc/net/dev 2>/dev/null)"
for DEVICE in $NETDEVICES; do
ifconfig $DEVICE | grep -q "inet addr"
if [ "$?" != 0 ]; then
ifconfig $DEVICE up
sleep 1
fi
done
;;
stop)
echo "Stopping extmodules...."
# Unlaod all 82575/6, 82580, I350, I354, and I210/I211 based gigabit network connections
rmmod igb
# Unlaod VMware vmxnet3 virtual NIC driver
rmmod vmxnet3
# Unlaod Virtio network driver
rmmod failover net_failover virtio_net
# RealTek RTL-8139 Fast Ethernet driver
rmmod mii 8139too
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
再谈编译网卡驱动的问题。
以下是我在编译华芸ADM系统的设备驱动时遇到的问题和解决的办法。如果你不需要自己编译驱动,这一讲的内容可以忽略。
实际上的设定如下:
VERSION = 5
PATCHLEVEL = 13
SUBLEVEL = x
TRUESUBLEVEL = 19
EXTRAVERSION =
NAME = Opossums on Parade
ASUSTOR = "asustor"
当然还有一些其它改动。从这里我们可以看到,华芸ADM的Linux内核是从5.13.19版本衍生而来的。华芸是一间很著名的公司,它也非常遵守GPL的规定。它的衍生版本,也为我们提供了必要的Linux内核信息。并不像有些公司,会故意隐瞒一些信息。所以对于华芸ADM的这个衍生版本,我们才可以编译一些自定义的设备驱动。但编译自定义的设备驱动并不是只要又源代码就可以的简单的事情。因此,我才要在这了专门讨论一下关于编译网卡驱动的问题。
编译设备驱动前需要先编译内核。一般情况是:最好能够获得内核编译的“.config”文件。华芸的ADM系统也提供了。这个文件可以从运行的系统中的:/proc/config.gz 得到。华芸的ko模块的版本签名(vermagic)为5.13.x SMP mod_unload modversions。它对应于“.config”文件中的设置:
CONFIG_SMP := y
CONFIG_MODVERSIONS := y
CONFIG_MODULE_SRCVERSION_ALL := y
尽管华芸提供了编译内核的详细信息。CONFIG_CC_VERSION_TEXT="x86_64-asustor_x64_g3_2020.12.24-linux-gnu-gcc (crosstool-NG 1.24.0) 7.4.0"。但由于它使用的gcc版本7.4.0是比较古老的版本,如果我们用其它的gcc版本编译内核,就有可能造成编译出来的设备驱动与华芸ADM的运行版本不匹配的问题。所以我才要在这里专门讲一讲。
关于CONFIG_MODVERSIONS与Module.symvers的本质:
在编译 vmlinux 时,最后会利用 modpost 来解析 vmlinux.o 对象文件,并将基本内核导出的所有符号都记录到文件 Module.symvers 中去。如果没有打开 CONFIG_MODVERSIONS 选项,那么你看到的 Module.symvers 文件中第一列符号 CRC 校验值都是 0x00000000 。如果打开该选项,那么第一列就会显示出各个符号的 CRC 校验值,如:
0x2d6c0f40 put_mnt_ns vmlinux EXPORT_SYMBOL
0x6c386a8c clear_bdi_congested vmlinux EXPORT_SYMBOL
… …
一旦设置过这个配置选项,就意味着打开了内核的Module versioning功能。Module versioning 功能应用在我们使用模块的场合。如果 Module versioning 功能被打开的话,它会以每个导出符号的 C 原型声明作为输入,计算出对应的CRC校验值,保存在文件 Module.symvers 中。如此一来,内核在后面要加载使用模块的时候,会两相比较模块中的CRC值和保存下来的CRC值,如果发现不相等,内核就拒绝加载这个模块。华芸ADM的Linux内核衍生版就打开了内核的Module versioning功能。这就使得我们编译自定义的设备驱动时,要保持严格的一致性。否则模块就会被内核拒绝加载。
让我们来了解一下Linux内核模块加载时的检查步骤:
首先, 会进行模块签名验证,然后才是版本检查。
版本检查又分为 vermagic 检查和 CRC校验检查, 这又和内核的编译选项”CONFIG_MODVERSIONS”相关
kernel 打开 CONFIG_MODVERSIONS, module 不打开 CONFIG_MODVERSIONS : 将不会检查CRC, 但是会完整匹配vermagic, 但是因为两者的vermagic中“modversions”的差别, 模块将不能加载成功
kernel 打开 CONFIG_MODVERSIONS, module 打开 CONFIG_MODVERSIONS, 将会检查CRC, 然后匹配vermagic的第一个空格后的部分, 例如, 若vermagic为“5.13.x SMP mod_unload modversions”, 则只会使用” SMP mod_unload modversions来匹配”, 即SMP, 模块卸载等关键特性还是需要进行检查
kernel 不打开 CONFIG_MODVERSIONS, module 打开 CONFIG_MODVERSIONS, 将会完整匹配vermagic, 但是因为两者的vermagic中“modversions”的差别, 模块将不能加载成功
kernel 不打开 CONFIG_MODVERSIONS, module 不打开 CONFIG_MODVERSIONS, 完整匹配vermagic
因为华芸的ADM系统打开了CONFIG_MODVERSIONS。因此版本检查包括 vermagic 检查和 CRC校验检查。是属于相对严格的检查。如果编译设备驱动时使用的gcc版本不同,将直接影响到CRC校验,编译出来的ko模块就不能用。
这就涉及到了一个问题,就是如何从华芸的ADM运行系统中提取出”CONFIG_MODVERSIONS”要求的CRC值呢?也就是:关于如何从srtipped vmlinux系统文件里获取标号crc的问题。
从srtipped vmlinux系统文件里获取标号crc的是可以实现的,但实现起来非常麻烦。需要用c语言写一段如下程序,即可bump出一个Module.symvers文件。使用这个文件,就可以直接编译出可以用于ADM 的NAS系统内核5.13.x的模块了。因为逆向工程的需要,我针对华芸的ADM编写了一个专门用于bump出一个Module.symvers文件的程序。但这次的龙年大礼包不会提供这个专门的程序。
为了方便坛友们将来自己编译设备驱动,我在这次的【龙年大礼包】里为大家提供了一个内核模块toolkit.ko文件,为用户提供接口去搜索标号的crc。但这个内核模块每次只能搜索一个标号的crc值。
重要提示: Intel 的 CPU 将特权级别分为 4 个级别。toolkit.ko是内核模块,拥有对CPU的ring0 级别的特权。Linux将ring0用于内核,将ring3用于普通进程。没有在ring0上运行的进程代码,也没有在ring3上运行的内核代码。从ring3必须使用80h软中断只有一个进入内核的入口点,它允许从其所在区域跳转用户代码到内核代码所在的区域。这个特权级别比root特权的控制更强。当然自己认为,我写的toolkit.ko模块肯定是安全的(如果需要源代码可以联系我)。但是,我要提醒大家千万不要随便加载来源不明的第三方内核模块。危险!危险!危险!重要的话连说三遍。尽管我的模块是安全的,但也仅仅是为了逆向工程的教学目的。我也不建议大家将它用于生产系统。非必要不要加载,用完后尽快卸载。
在这里我为大家提供了一个内核模块toolkit.ko中。搜索标号的方案是采用一个灵活的方案。可以让用户根据需要搜索标号。利用了Linux内核提供了两个函数可以解决这个问题。
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
typedef bool (*find_symbol_t)(struct find_symbol_arg *fsa);
Linux2.6以前的版本,这两个函数的接口是暴露给编程模块的,编程时可以直接使用。但现在的版本,可能是因为安全的原因吧,这两个函数一般是再不暴露出来的。但我们仍然可以使用暴露的 register_kprobe() 函数注册这两个函数来获得它在内核的地址,并来使用它。
因为toolkit.ko模块是内核程序,它与用户程序需要一个交互的接口。有很多种方法提供这样的接口。在【龙年大礼包】里我使用 /proc/find_symbol 虚拟文件系统来提供用户接口。用户可以使用控制台命令:
1. modprobe toolkit (加载toolkit,创建 /proc/find_symbol 虚拟文件系统用户接口)
2. cat /proc/find_symbol (第一次读入虚拟文件,将显示帮助信息。)
3. echo \"module_layout\" > /proc/find_symbol (向虚拟文件系统用户接口请求“module_layout”的符号信息。)
4. cat /proc/find_symbol (从虚拟文件系统用户接口读出请求的符号信息)
5. rmmod toolkit (卸载 toolkit)
我的这个toolkit程序中,对从用户数据区复制到内核区的数据有严格的限制。限定为只取前64个字节。如果你试图向/proc/find_symbol虚拟文件系统用户接口发送大量的数据,实施buffer overflow攻击,我的程序将不予理睬,数据会滞留在用户数据区。将影响你的正常使用该工具。这一点请务必注意。
当然,也可以用脚本,或编程语言来使用虚拟文件系统接口。虽然这个toolkit.ko内核模块每次只能搜索一个标号的crc值,如果使用脚本或编程语言的话,就可以通过loop循环的方法,一次获取多个标号的crc值。
很高兴能与大家分享此次的成果。本教程中详细讲解了破解和启动盘的制作过程中各种细节技术详情。
此次的【龙年大礼包】是对华芸x86-64的全系列的破解逆向工程教学。详细讲解了如何在Linux逆向工程的手工破解的基础上,来实现全部通过程序化的做逆向工程破解。更为重要的是详细讲解了这一过程的设计思想,和设计理念。针对华芸的ADM系统,建立一个可扩展的逆向工程破解平台。为实现因华芸ADM系统升级,再做破解升级提供方便更新。并针对华芸的ADM系统破解,提供一些相应的工具程序。
文章的最后,老骥伏枥要再次郑重声明:撰写本文与制作【龙年大礼包】的目的是为了探索,研究,学习嵌入式linux逆向工程技术。禁止利用本文提供的技术和使用本教程的工具盘从事任何非法商业牟利性活动。
参考文献:
此文绝对是本人【原创】。如果你对本文的观点有不同意见,可以回帖喷我,本人从不固步自封,固持己见。