Android内核模块编译执行
Author: GeneBlue
0X01 前言
内核驱动是漏洞的高发区,了解Android驱动代码的编写是分析、利用驱动漏洞的基础。本文以一个“hello”驱动为例,简单介绍内核驱动编写、编译的基本过程,包括内核模块的内建编译和动态加载方式的编译。
0X02 编写
在 ./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函数
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 = { //设备的操作函数指针表
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
命令,并在menuconfig中做如下配置:


如果不开启该选项就直接 insmod 加载hello.ko,一般情况下都会报如下错误:
insmod: init_module 'hello.ko' failed (Function not implemented)
[内建编译的情况]--编译完内核之后,还需要将内核拷贝到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:
rm *.o *.ko *.mod.c *.order *.symvers
注意,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
Android内核模块编译执行的更多相关文章
- Android反编译(三)之重签名
Android反编译(三) 之重签名 [目录] 1.原理 2.工具与准备工作 3.操作步骤 4.装X技巧 5.问题 1.原理 1).APK签名的要点 a.所有的应用程序都必须有数字证书 ,Androi ...
- Android反编译(一)之反编译JAVA源码
Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具 dex2jar http://code.go ...
- Android 反编译
Android 反编译 步骤:1.下载apktool 工具,这一步 主要是反编译 xml 文件. 步骤:2 把xx.smali 文件转为java 工具 (单个) 图形界面 下载dex2jar 和xj ...
- ApkDec android反编译工具
转自:http://www.newasp.net/soft/70498.html 下载 ApkDec是一款免费的绿色APK反编译工具 forandroid ,由android开发者社区开发. ApkD ...
- Android 反编译工具简介
Android 反编译工具: 所需工具:1 apktool : 用于获取资源文件 2 dex2Jar : 用于将classes.dex转化成jar文件 2 jd-gui: 将jar文件转化成java文 ...
- android 单独编译某个模块
第一次下载好Android源代码工程后,我们通常是在Android源代码工程目录下执行make命令,经过漫长的等待之后,就可以得到Android系统镜像system.img了.以后如果我们修改了And ...
- 【转】Android源代码编译命令m/mm/mmm/make分析--不错
原文网址:http://blog.csdn.net/luoshengyang/article/details/19023609 在前文中,我们分析了Android编译环境的初始化过程.Android编 ...
- android的编译和运行过程深入分析
android的编译和运行过程深入分析 作者: 字体:[增加 减小] 类型:转载 首先来看一下使用Java语言编写的Android应用程序从源码到安装包的整个过程,此过程对了解android的编译和运 ...
- Android 自动编译、打包生成apk文件 3 - 使用SDK Ant方式
相关文章列表: < Android 自动编译.打包生成apk文件 1 - 命令行方式> < Android 自动编译.打包生成apk文件 2 - 使用原生Ant方式> &l ...
随机推荐
- docker swarm模式跨主机连接
一.前言 当我们开发好微服务之后,考虑到灵活快速持续部署的需要,通常会考虑将其Docker镜像化并在Docker环境下运行.由于微服务个数通常会较多,把所有微服务部署在一台docker主机上是不现实的 ...
- NIO三大组件之Selector选择器
什么是选择器 选择器的作用是完成IO的多路复用.一个通道代表一条连接通路,通过选择器可以同时监控多个通道的IO(输入输出)状况.选择器和通道的关系,是监控和被监控的关系. 使用 重要的成员 Selec ...
- 1-认识c指针
1.指针和内存 c程序在编译后,会以三种形式使用内存 1静态/全局内存 静态声明的变量分配在这里,全局变量也使用这部分内存.这些变量在程序开始运行时分配,直到程序终止时才会消失 2.自动内存 这些变量 ...
- 练习1—参数传递、递归调用(Java)
1.方法参数的值传递机制 1.说明 方法:必须由其所在类或对象调用才有意义.若方法含有参数: 形参:方法声明时的参数: 实参:方法调用时实际传给形参的参数值 Java的实参值如何传入方法:Java里方 ...
- 这个Bug的排查之路,真的太有趣了。
这是why哥的第 92 篇原创文章 在<深入理解Java虚拟机>一书中有这样一段代码: public class VolatileTest { public static volat ...
- Python基础之:Python中的异常和错误
目录 简介 Python中的内置异常类 语法错误 异常 异常处理 抛出异常 异常链 自定义异常 finally 简介 和其他的语言一样,Python中也有异常和错误.在 Python 中,所有异常都是 ...
- LinkedList源码个人解读
LinkedList的基本结构是双向链接的直线结构. 链表的构造函数有两个,其中空构造函数什么都没做,就是一个空实现. /** * Constructs an empty list. */ publi ...
- Docker安装完成后启动报错:Failed to start Docker Application Container Engine
报错如下:显示没有启动 先关闭防火墙:防火墙关闭指令请看 <a href="Linux防火墙篇">https://www.cnblogs.com/szx666/p/1 ...
- 【分布式】SpringCloud(3)--Eureka服务注册与发现
1.Eureka概述 1.1.什么是Eureka Eureka是Netflix的一个子模块.基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移. 只需要使用服务的标识符,就可以访问到 ...
- HCL实验8:NAT搭建私有网络
NAT 通过NAT技术,进行私有网络的搭建 拓扑图 先对路由器的端口进行配置 R1 [H3C]sys R1 [R1]INT G0/0 [R1-GigabitEthernet0/0]ip address ...