Author: GeneBlue
0X01 前言
核心驅動是漏洞的高發區,了解Android驅動代碼的編寫是分析、利用驅動漏洞的基礎。本文以一個“hello”驅動為例,簡單介紹核心驅動編寫、編譯的基本過程,包括核心子產品的内建編譯和動态加載方式的編譯。
0X02 編寫
在 ./goldsifh/drivers 檔案夾下建立hello目錄,在hello目錄中建立hello.c檔案:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GeneBlue");
MODULE_DESCRIPTION("Hello Kernel Device");
MODULE_VERSION("1.0");
#define
long hello_ioctl(struct file *filp, //ioctl函數
unsigned int cmd,
unsigned long{
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 = { //裝置的操作函數指針表
unlocked_ioctl: hello_ioctl
};
static struct miscdevice hello_device = { //注冊為misc裝置的基本屬性
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裝置
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); //裝置解除安裝
if(ret)
printk("Hello module exit");
}
module_init(hello_begin); //子產品初始化函數
module_exit(hello_exit); //子產品解除安裝函數
寫驅動子產品時都要包含
module.h 頭檔案,該頭檔案定義了一些編寫子產品時常用宏或函數; kernel.h
提供常用的核心函數,如printk(); fs.h 提供檔案表和檔案結構,如file_operations;
miscdevice.h 提供注冊為misc裝置的常用函數。
0X03 編譯
在編譯之前,要確定下載下傳下來的核心代碼已經可以順利地編譯運作,具體可以參考這裡。
在hello目錄中,要增加Makefile配置檔案用于編譯。在Makefile中添加:
obj-y += hello.o
表示内建編譯,即直接編譯到核心檔案zImage中。然後在
goldfish/drivers/Makefile 中包含建立的驅動裝置
obj-y += hello/
這樣,再次編譯核心後,驅動裝置即可包含在核心中。
有的時候,我們需要在手機中編寫可動态加載的驅動子產品,可動态加載子產品非常便于調試,在
kmsg中可直接看到調試資訊,這個時候需要重新編譯手機核心,開啟核心的動态加載屬性。在編譯的核心的時候,使用
make
指令,并在menuconfig中做如下配置:
如果不開啟該選項就直接 insmod 加載hello.ko,一般情況下都會報如下錯誤:
insmod: init_module 'hello.ko' failed (Function not
[内建編譯的情況]--編譯完核心之後,還需要将核心拷貝到aosp的源碼中,替換掉預設的核心檔案,在我的Android源碼中預設的核心檔案存放在如下路徑中:
/android-4.4.4_r1/device/lge/hammerhead-kernel/zImage-dtb
編譯Android源碼生成新的boot.img檔案,然後隻要将boot.img刷入到手機即可。
完成核心的準備工作之後,下面就要編譯動态加載子產品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:
注意,Makefile中要加上 CFLAGS_MODULE=-fno-pic 選項,不然insmod加載編譯好的 hello.ko relocation節
會錯誤:
insmod: init_module 'hello.ko' failed (Exec format error)
kmsg:
<3>[ 1646.589131] hello: unknown relocation: 27
最後,使用 make
指令即可編譯生成正确的 hello.ko 檔案。
0X04 運作
使用模拟器來加載新編好的核心,并在
adb shell root權限下檢視新編的驅動:
# root權限下
# ll /dev | grep hello
# dmesg | grep Hello
這樣,一個最簡單的裝置驅動已經可以正确運作了。
将 hello.ko 檔案
push 到手機中,root權限下用
insmod 來加載即可。
# 加載核心子產品
# insmod hello.ko
# 檢視加載的核心子產品
# lsmod
0X05 參考
- 在Ubuntu上為Android系統編寫Linux核心驅動程式
-
Hello
world kernel module for android & unknown relocation: 27 when insmod