Author: GeneBlue
內(nèi)核驅(qū)動是漏洞的高發(fā)區(qū),了解Android驅(qū)動代碼的編寫是分析、利用驅(qū)動漏洞的基礎(chǔ)。本文以一個“hello”驅(qū)動為例,簡單介紹內(nèi)核驅(qū)動編寫、編譯的基本過程,包括內(nèi)核模塊的內(nèi)建編譯和動態(tài)加載方式的編譯。
在 ./goldsifh/drivers 文件夾下新建hello目錄,在hello目錄中新建hello.c文件:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/miscdevice.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("GeneBlue"); MODULE_DESCRIPTION("Hello Kernel Device"); MODULE_VERSION("1.0"); #define CMD_COMMAND 0x1336 long hello_ioctl(struct file *filp, //ioctl函數(shù) unsigned int cmd, unsigned long arg){ switch(cmd){ case CMD_COMMAND: printk("Hello Module hello_ioctl() exced"); break; default: printk("Hello Module unknown ioctl cmd"); } return 0; } struct file_operations hello_fops = { //設(shè)備的操作函數(shù)指針表 unlocked_ioctl: hello_ioctl }; static struct miscdevice hello_device = { //注冊為misc設(shè)備的基本屬性 minor: MISC_DYNAMIC_MINOR, name: "hello", fops: &hello_fops, mode: 777}; static int __init hello_begin(void){ int ret; ret = misc_register(&hello_device); //注冊為misc設(shè)備 if(ret) printk("Failed to register misc device"); else printk("Hello Module successfully loaded"); return ret; } static void __exit hello_exit(void){ int ret = misc_deregister(&hello_device); //設(shè)備卸載 if(ret) printk("Hello module exit"); } module_init(hello_begin); //模塊初始化函數(shù)module_exit(hello_exit); //模塊卸載函數(shù)
寫驅(qū)動模塊時都要包含module.h 頭文件,該頭文件定義了一些編寫模塊時常用宏或函數(shù); kernel.h提供常用的內(nèi)核函數(shù),如printk(); fs.h 提供文件表和文件結(jié)構(gòu),如file_operations;miscdevice.h 提供注冊為misc設(shè)備的常用函數(shù)。
在編譯之前,要確保下載下來的內(nèi)核代碼已經(jīng)可以順利地編譯運(yùn)行,具體可以參考這里。
在hello目錄中,要增加Makefile配置文件用于編譯。在Makefile中添加:
obj-y += hello.o
表示內(nèi)建編譯,即直接編譯到內(nèi)核文件zImage中。然后在 goldfish/drivers/Makefile 中包含新建的驅(qū)動設(shè)備
obj-y += hello/
這樣,再次編譯內(nèi)核后,驅(qū)動設(shè)備即可包含在內(nèi)核中。
有的時候,我們需要在手機(jī)中編寫可動態(tài)加載的驅(qū)動模塊,可動態(tài)加載模塊非常便于調(diào)試,在kmsg中可直接看到調(diào)試信息,這個時候需要重新編譯手機(jī)內(nèi)核,開啟內(nèi)核的動態(tài)加載屬性。在編譯的內(nèi)核的時候,使用
make menuconfig
命令,并在menuconfig中做如下配置:
如果不開啟該選項(xiàng)就直接 insmod 加載hello.ko,一般情況下都會報如下錯誤:
insmod: init_module 'hello.ko' failed (Function not implemented)
[內(nèi)建編譯的情況]--編譯完內(nèi)核之后,還需要將內(nèi)核拷貝到aosp的源碼中,替換掉默認(rèn)的內(nèi)核文件,在我的Android源碼中默認(rèn)的內(nèi)核文件存放在如下路徑中:
/android-4.4.4_r1/device/lge/hammerhead-kernel/zImage-dtb
編譯Android源碼生成新的boot.img文件,然后只要將boot.img刷入到手機(jī)即可。
完成內(nèi)核的準(zhǔn)備工作之后,下面就要編譯動態(tài)加載模塊hello.ko,依然是上述的 hello.c 文件,在任意位置建一個目錄,拷貝hello.c并編寫 Makefile 如下:
obj-m := hello.o KERNELDIR := /home/geneblue/Android/Source/kernel/msm/ PWD :=$(shell pwd) ARCH=arm CROSS_COMPILE=/home/geneblue/Android/Source/tsinghua_aosp/android-4.4.4_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- CC=$(CROSS_COMPILE)gcc LD=$(CROSS_COMPILE)ld CFLAGS_MODULE=-fno-pic modules: make -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules clean: rm *.o *.ko *.mod.c *.order *.symvers
注意,Makefile中要加上 CFLAGS_MODULE=-fno-pic 選項(xiàng),不然insmod加載編譯好的 hello.ko relocation節(jié) 會錯誤:
insmod: init_module 'hello.ko' failed (Exec format error) kmsg: <3>[ 1646.589131] hello: unknown relocation: 27
最后,使用 make 命令即可編譯生成正確的 hello.ko 文件。
使用模擬器來加載新編好的內(nèi)核,并在adb shell 中,root權(quán)限下查看新編的驅(qū)動:
這樣,一個最簡單的設(shè)備驅(qū)動已經(jīng)可以正確運(yùn)行了。
將 hello.ko 文件push 到手機(jī)中,root權(quán)限下用insmod 來加載即可。
聯(lián)系客服