0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

AOSP源码定制-内核驱动编写

哆啦安全 来源:gakki的童养夫 作者:新垣结衣唯一丈夫 2024-04-23 11:15 次阅读

AOSP源码定制-内核驱动编写

介绍

有时候为了分析一些壳的检测,需要在内核层面对读写相关的操作进行监控,每次去修改对应的内核源码编译重刷过于耗时耗力,这里就来尝试编写一个内核驱动,载入后监控读写。

前提

已经同步对应版本的内核源码并编译,这里不赘述。

真机测试并root。

开启配置

比起直接改源码,编译模块载入模块,不需要反复修改源码并刷入内核,相比较用frida等框架更不容易检测(就是因为frida检测才用这个)。

先为编译配置开启内核可加载、卸载等选项:

CONFIG_MODULES=Y

CONFIG_STRICT_MEMORY_RWX=N / CONFIG_DEBUG_RODATA=N

CONFIG_DEVMEM=Y

CONFIG_DEVKMEM=Y

CONFIG_KALLSYMS=Y

CONFIG_KALLSYMS_ALL=Y

CONFIG_HAVE_KPROBES=Y

CONFIG_HAVE_KRETPROBES=Y

CONFIG_HAVE_FUNCTION_TRACER=Y

CONFIG_HAVE_FUNCTION_GRAPH_TRACER=Y

CONFIG_TRACING=Y

CONFIG_FTRACE=Y

在内核源码目录下执行命令(前面编译过一次,会有导入过系统变量):

make menuconfig

然后出现一个图像化的配置页面。

wKgZomYnJ9eAQ_IeAAEK9MOQbVk021.png

通过"/",打开搜索页面,查找上面对应的配置所在位置,以CONFIG_DEVKMEM为例,可以看到会给出定义路径。

wKgZomYnJ9eAYMMFAACHVn-Ju1g953.png

去对应路径找到这个目录,drivers/char/Kconfig。

wKgZomYnJ9eAVrDQAAFj1oVZ0nU074.png

找到定义的位置,改成y即可。按照配置改好,重新编译内核,后面就可以开始编写驱动模块了

编译第一个内核驱动

这里我们编译一个内核模块有两种模式,一种是直接编译进内核,另一种是编译成单独的ko文件通过insmod,rmmod命令来加载与卸载。这里我们讲的是单独编译成ko文件。 在内核目录下创建一个modules目录,用于存放编写各类驱动模块。 先来写个helloworld模块进行测试。

wKgZomYnJ9eAebBOAABEvmCwNig012.png

简单加个代码测试,驱动代码编写有格式规范:

#include

#include

#include

static int __init hello_init(void){

printk(KERN_ALERT "Hello World! ");

return 0;

}

static void __exit hello_exit(void){

printk(KERN_ALERT "Bye ");

}

module_init(hello_init);

module_exit(hello_exit);

编写Makefile:

# 设置内核源码编译的输出目录

KERNEL_OUT=/home/fukuyama/sourceCode/msm/out

# 设置arm64交叉编译链工具路径

TOOLCHAIN=/home/fukuyama/sourceCode/Android8/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-

# 设置arm32交叉编译链工具路径

TOOLCHAIN32=/home/fukuyama/sourceCode/Android8/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-

# 设置模块

obj-m := helloworld.o

# 编译命令配置

all:

make ARCH=arm64 CROSS_COMPILE_ARM32=$(TOOLCHAIN32) CROSS_COMPILE=$(TOOLCHAIN) -C $(KERNEL_OUT) M=$(shell pwd) modules

# 清理编译命令

clean:

make -C $(KERNEL_OUT) M=$(shell pwd) cleancd

直接make编译:

wKgZomYnJ9eAFW1-AADdF1-Rn6M190.png

编译完后,adb 推送到 data/local/tmp目录,然后insmod执行模块查看内核日志输出即可:

wKgZomYnJ9eAVdhCAAGm2dZMjWo642.png

可以看到已经有输出了,卸载模块也有输出,证明模块已经生效了。

编写监控模块

比如要监控open和read,我们需要获取到syscalltable的基址。

echo 0 > /proc/sys/kernel/kptr_restrict

cat /proc/kallsyms

wKgZomYnJ9eAaIt2AABT-LKPSI8098.png

然后编写代码,增加了uid大于10000筛选:

#include "linux/kernel.h"

#include "linux/init.h"

#include "linux/module.h"

#include "linux/moduleparam.h"

#include "asm/unistd.h"

#include "linux/slab.h"

#include "linux/sched.h"

#include "linux/uaccess.h"

#include

void ** sys_call_table64 = (void**)0xffffffc001000000;

#define SURPRESS_WARNING __attribute__((unused))

#define LL unsigned long long

// int mm_uid = 10067;

// module_param(mm_uid, int, 0664);

SURPRESS_WARNING int getCurrentPid(void)

{

int pid = get_current()->pid;

return pid;

}

SURPRESS_WARNING LL isUserPid(void)

{

const struct cred * m_cred = current_cred();

kuid_t uid = m_cred->uid;

int m_uid = uid.val;

if(m_uid >10000)

{

return true;

}

return false;

}

SURPRESS_WARNING asmlinkage LL (*old_openat64)(int dirfd, const char __user* pathname, int flags, umode_t modex);

SURPRESS_WARNING LL new_openat64(int dirfd, const char __user* pathname, int flags, umode_t modex)

{

const struct cred * m_cred = current_cred();

kuid_t uid = m_cred->uid;

int m_uid = uid.val;

LL ret = -1;

ret = old_openat64(dirfd, pathname, flags, modex);

if(isUserPid())

{

char bufname[256] = {0};

strncpy_from_user(bufname, pathname, 255);

if(strstr("/sdcard/trace.txt",bufname)){

}else{

printk("myLog::openat64 pathname:[%s] ret:[%llu] current->pid:[%d] current->uid:[%d] ", bufname,ret , getCurrentPid(),m_uid);

}

}

return ret;

}

SURPRESS_WARNING asmlinkage LL (*old_read)(unsigned int fd, char __user *buf, size_t count);

SURPRESS_WARNING LL new_read(unsigned int fd, char __user *buf, size_t count)

{

const struct cred * m_cred = current_cred();

kuid_t uid = m_cred->uid;

int m_uid = uid.val;

LL ret = -1;

ret = old_read(fd, buf, count);

if(isUserPid())

{

char bufname[256] = {0};

strncpy_from_user(bufname, buf, 24);

printk("myLog::read fd:[%d] context:[%s] current->pid:[%d] current->uid:[%d] ", fd,bufname, getCurrentPid(),m_uid);

}

return ret;

}

SURPRESS_WARNING int hook_init(void){

printk("myLog::hook init success ");

if(sys_call_table64){

old_openat64 = (void*)(sys_call_table64[__NR_openat]);

printk("myLog::old_openat64 : %p ", old_openat64);

sys_call_table64[__NR_openat] = (void*)new_openat64;

old_read = (void*)(sys_call_table64[__NR_read]);

printk("myLog::old_read : %p ", old_read);

sys_call_table64[__NR_read] = (void*)new_read;

printk("myLog::hook init end ");

}

else{

printk("mylog::fail to find sys_call_table ");

}

return 0;

}

int __init myInit(void){

printk("myLog::hooksyscall Loaded1 ");

hook_init();

return 0;

}

void __exit myExit(void){

if(sys_call_table64){

printk("myLog::cleanup start ");

sys_call_table64[__NR_openat] = (void*)old_openat64;

sys_call_table64[__NR_read] = (void*)old_read;

printk("myLog::cleanup finish ");

}

printk("myLog::hooksyscall Quited ");

}

module_init(myInit);

module_exit(myExit);

载入后查看效果:

wKgZomYnJ9iAULZoAAEqeS9vezE172.png

已经有监控输出了。 为了对上面的监控更加细化,修改补充一部分uid的限制:

......

void ** sys_call_table64 = (void**)0xffffffc001000000;

#define SURPRESS_WARNING __attribute__((unused))

#define LL unsigned long long

int mm_uid = 10067;

module_param(mm_uid, int, 0664);

......

SURPRESS_WARNING LL isUserPid(void)

{

const struct cred * m_cred = current_cred();

kuid_t uid = m_cred->uid;

int m_uid = uid.val;

if(m_uid == mm_uid)

{

return true;

}

return false;

}

在启动模块的时候,增加启动参数,只打印对应uid的app读写监控。

insmod helloworld.ko mm_uid=10067

演示略。 只是这个模块好像卸载的时候会死机重启。

总结

简单学习下内核驱动的编写与加载,简化内核监控,还可以补充定制用于绕过一些反调试。

审核编辑:刘清
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Modules
    +关注

    关注

    0

    文章

    10

    浏览量

    7990
  • AOSP
    +关注

    关注

    0

    文章

    16

    浏览量

    6191
  • 内核驱动
    +关注

    关注

    0

    文章

    5

    浏览量

    2644

原文标题:AOSP源码定制-内核驱动编写

文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    浅谈Linux内核源码的Makefile、Kconfig和.config文件

    Linux内核源码文件繁多,搞不清Makefile、Kconfig、.config间的关系,不了解内核编译体系,编译修改内核有问题无从下手,自己写的
    发表于 10-17 16:19 3870次阅读
    浅谈Linux<b class='flag-5'>内核</b><b class='flag-5'>源码</b>的Makefile、Kconfig和.config文件

    Google AOSP 正式宣布支持HiKey 极大压缩Android SDK开发软件周期

    Android内核源码及板级系统支持,使得开发者们能够轻松创建和调试新的或现有的外围设备驱动程序,甚至进行内核开发等其他更为困难的开发工作,由此OEM厂商的开发困难将大大降低。LeMa
    发表于 03-08 11:38

    Linux内核模块的驱动程序怎么编写

    Linux中的大部分驱动程序,是以模块的形式编写的.这些驱动程序源码可以修改到内核中,也可以把他们编译成模块形势,在需要的时候动态加载.
    发表于 03-24 07:09

    linux自带驱动存放于内核源码

    linux自带驱动存放于内核源码目录具体目录如下1. 按键驱动kernal\drivers\input\keyboard\kernal\drivers\char2. LED
    发表于 11-04 07:13

    编写Linux内核的步骤有哪些

    编译工具链,在此就不再赘述。编写Linux内核需要内核源码内核编译配置文件kernel_config,如下图:具体编译步骤如下:1.解压
    发表于 11-04 07:42

    如何对RK3568环境上的AOSP源码进行调试呢

    如何对RK3568环境上的AOSP源码进行编译呢?如何对RK3568环境上的AOSP源码进行调试呢?
    发表于 03-02 06:25

    VisionFive 2成功集成Android开源项目(AOSP)!

    的开创性合作(https://github.com/android-risc-v, Peter Yoon)。 赛昉团队利用AOSP的开源性质定制了软件,与VisionFive 2的硬件功能保持一致
    发表于 10-16 13:11

    华为鸿蒙系统内核源码分析上册

    鸿蒙內核源码注释中文版【 Gitee仓】给 Harmoηy○S源码逐行加上中文注解,详细阐述设计细节,助你快速精读 Harmonyos内核源码,掌握整个鸿蒙
    发表于 04-09 14:40 17次下载

    openharmony原理 aosp和openharmony关系

    。 OpenHarmony的技术架构是按分层设计来的,从下向上是内核层、系统服务层、框架层和应用层。而系统功能是逐级展开,为系统 子系统 组件。 AOSP为安卓开放源代码项目,AOSP 是基于 Linux 的。可以
    的头像 发表于 06-23 09:35 2917次阅读

    使用Kotlin替代Java重构AOSP应用

    两年前,Android 开源项目 (AOSP) 应用团队开始使用 Kotlin 替代 Java 重构 AOSP 应用。之所以重构主要有两个原因: 一是确保 AOSP 应用能够遵循 Android
    的头像 发表于 09-16 09:26 1837次阅读
    使用Kotlin替代Java重构<b class='flag-5'>AOSP</b>应用

    AOSP Android11系统源码内核源码简析

    AOSP源码中并不包括内核源码,需要单独下载,内核源码有很多版本,比如common是通用的Lin
    的头像 发表于 01-29 09:25 5244次阅读

    获取Linux内核源码的方法

    (ELF1/ELF1S开发板及显示屏)Linux内核是操作系统中最核心的部分,它负责管理计算机硬件资源,并提供对应用程序和其他系统组件的访问接口,控制着计算机的内存、处理器、设备驱动程序和文件系统等
    的头像 发表于 12-13 09:49 631次阅读
    获取Linux<b class='flag-5'>内核</b><b class='flag-5'>源码</b>的方法

    基于Android13的AOSP源码下载及编译指南

    AOSP(Android Open Source Project)是Android操作系统的开源项目,通过下载和编译AOSP源码,您可以获得原始的Android系统,并进行定制和开发。
    的头像 发表于 01-17 09:49 3786次阅读
    基于Android13的<b class='flag-5'>AOSP</b><b class='flag-5'>源码</b>下载及编译指南

    AOSP源码定制-对root定制的补充流程

    前面通过修改build.prop中的指纹以及对su的修改,完成了基础的定制修改,但是碰上一些app还是能被检测到,再进行深入修改。
    的头像 发表于 04-01 11:04 1338次阅读
    <b class='flag-5'>AOSP</b><b class='flag-5'>源码</b><b class='flag-5'>定制</b>-对root<b class='flag-5'>定制</b>的补充流程

    linux驱动程序如何加载进内核

    在Linux系统中,驱动程序是内核与硬件设备之间的桥梁。它们允许内核与硬件设备进行通信,从而实现对硬件设备的控制和管理。 驱动程序的编写
    的头像 发表于 08-30 15:02 396次阅读