天天看點

Android核心子產品編譯執行

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​​

繼續閱讀