之前一直在考虑,不同的内核源码编译出来的ko文件,区别到底是什么?
能不能不编译内核加载内核模块呢?最近逆向分析了linux内核ko模块的结构,事实证明,是可以的。
我在这里给大家分享一些我的心得。
首先分析一个最简单的hello.ko,Makefile就不写了,因为需要尽可能简单,加一行去除调试信息的objcopy -g hello.ko就好。
hello.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init hello_init(void){
printk(KERN_EMERG "\nhello init.\n");
return 0;
}
static void __exit hello_exit(void){
printk(KERN_EMERG "\nhello exit.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
可以看到编译后的ko文件只有2.4Kb。
我这里准备好一个基于arm架构板子交叉编译好的linux3.6.33的linux内核,正经的烧进去,后续简称now kernel。
在胡乱修改make menuconfig的模块结构之后,重新在另一个无关的目录编译另外一个linux内核,后续简称fake kernel。
首先我先把基于fake kernel编译的hello.ko拷贝到我的板子上正在使用的now kernel上,然后执行:insmod hello.ko。
结果什么都没有发生,没有报错,没有执行,没有打印???
首先确定了一点,不基于同一套内核源码编译的内核模块是无法直接加载的。那是什么导致了加载失败呢?我们先用二进制编辑器打开刚刚编译的ko文件。
可以看到内核ko文件就是个标准的elf格式的文件,那么我们用readelf读一下ko文件的结构。
readelf -a hello.ko
ELF Header:
Magic: 7f 45 4c 46 01 01 01 6100 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: ARM
ABIVersion: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of p headers: 904 (bytes into file)
Flags: 0x600, GNU EABI, software FP, VFP
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of p headers: 40 (bytes)
Number of p headers: 19
Section header string table index: 16
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[0] NULL 00000000 000000 000000 00 0 0 0
[1] .text PROGBITS 00000000 000034 000000 00 AX 0 0 1
[2] .exit.text PROGBITS 00000000 000034 00001c 00 AX 0 0 4
[3] .rel.exit.text REL 00000000 000904 000010 08 17 2 4
[4] .init.text PROGBITS 00000000 000050 000020 00 AX 0 0 4
[5] .rel.init.text REL 00000000 000914 000010 08 17 4 4
[6] .modinfo PROGBITS 00000000 000070 000060 00 A 0 0 4
[7] .rodata.str1.4 PROGBITS 00000000 0000d0 000028 01 AMS 0 0 4
[8] .data P