首页
社区
课程
招聘
[Android Linux Kernel学习记录]一、简单内核逆向步骤
发表于: 2022-5-23 15:32 15838

[Android Linux Kernel学习记录]一、简单内核逆向步骤

2022-5-23 15:32
15838

​ 近年,Android平台的对抗愈发复杂,逆向工作者为了实现四两拨千斤的效果开始在内核层面使用某些功能或拦截用户态交互信息进行降维打击,同时安全工作者也开始利用内核的各种功能进行安全检测以及设备指纹收集,因此对内核的学习已经成为了Android安全工作者的重要选项。但编译内核需要消耗大量时间,且厂商开源的内核代码可能难以编译或较为陈旧,为了能够在不重新编译内核的情况下使用开源的工具如krhook,以及修改内核实现规避某些检测,特开此文记录学习过程。

本文所指的内核为 Android 系统使用的 Linux Kernel,它为Android提供了操作系统支持。

操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等

想要逆向内核首先要提取到内核的二进制文件

这里参照 Ylarod大佬的帖子 https://bbs.pediy.com/thread-271179.htm 提取Boot.img

其中 magiskboot 的获取可以下载https://github.com/topjohnwu/Magisk的Release,在压缩包x86目录下找到magiskboot文件

注意该文件是ELF32类型的,可以在x86(_64)的Linux发行版上运行,亦可使用WSL2

或参照 https://github.com/nforest/droidimg 使用 imgtool / imjtool进行解包

最终我们可以获取到一个kernel文件( imgtool 解包出的文件名为 kernelimage )

拿到这个文件,直接扔进IDA的话并不会被识别,这里参照 https://github.com/nforest/droidimg 操作使用了脚本,但该脚本未能正确识别出信息(可能需要修改)

以二进制文件载入,选择ARM小端代码,此时IDA要求我们提供地址信息

image-20220523140451999

这里有一个知识点,Linux存在一个内核符号表,其中保存了所有Linux中定义的内核符号地址,那么如果可以利用这个符号表的内容,分析起kernel来将事半功倍

查看kallsyms的方法

STEP1.关闭内核指针限制

echo 0 > /proc/sys/kernel/kptr_restrict

STEP2.读取kallsyms文件

/proc/kallsyms

但是该符号表的内容是内存地址,如何将该符号表对应到kernel文件呢?

这里了解一下kernel文件的前世今生并分析一下如何加载该文件

https://source.android.com/devices/bootloader/partitions-images#kernel-images中提到boot分区下的kernel虚拟分区为标准 Linux 格式

那么magiskboot最后提取到的kernel文件就是vmlinux

那么vmlinux应该是什么格式的呢?

vmlinux实际上是由链接后的文件使用objcopy删去一些内容得到的

arch\arm64\kernel\vmlinux.lds.S文件中定义了SECTIONS信息

其中头部为

TEXT_OFFSET 在Makefile中定义为0x80000

HEAD_TEXT 是一个宏,定义在https://elixir.bootlin.com/linux/v4.9.186/source/include/asm-generic/vmlinux.lds.h#L523

https://elixir.bootlin.com/linux/v4.9.186/source/include/linux/init.h#L94 中可以找到

而__HEAD在arch\arm64\kernel\head.S中被使用

image-20220523135912177

对比kernel文件头完全符合。

同时在前面找到了_text = KIMAGE_VADDR + TEXT_OFFSET,也就是说kernel在内存中的地址对应_text的地址

又因为代码段的文件偏移与内存偏移是一致的,所以可以从内核符号表中获取_text 的地址提供给IDA作为起始地址(网上有一些方法设置了文件偏移量是为了跳过前面的对齐数据)

(用这个方法也可以将其他节的地址获取到并定义,如果有这个雅兴)

image-20220523141457319

确认后IDA会提醒我们加载的是一个二进制文件,要提供入口点进行分析

这里我们从内核符号表中获取start_kernel函数的地址并在IDA中跳转到该地址按C转成代码

可以看到IDA已经分析出很多函数了

看一下start_kernel的汇编

image-20220523142032477

对应启动日志是符合的,地址正确

这时我们可以导出完整的符号表并用脚本载入IDA

导出符号表:cat /proc/kallsyms > /sdcard/kallsyms.txt

adb pull到电脑上后在ida python执行如下脚本

(自动创建代码会很卡,没有需求可以注释掉)

有符号加持基本满足分析内核代码的需求了

image-20220523150235003

这样就可以patch内核来实现某些不可告人的目的了(

参考链接:

绕过Android内核模块加载验证

Android系统内核提取及逆向

Kernel initialization

[Linux内核剖析(五)Linux内核的构建过程]

Android Kernel 逆向分析准备

https://github.com/xiaokanghub/Android-Kenerl-boot.img

纸上得来终觉浅,绝知此事要躬行。

初学内核,如有错误敬请斧正,若有指点感激不尽。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
. = KIMAGE_VADDR + TEXT_OFFSET;
.head.text : {
    _text = .;
    HEAD_TEXT
}
. = KIMAGE_VADDR + TEXT_OFFSET;
.head.text : {
    _text = .;
    HEAD_TEXT
}
 
#define HEAD_TEXT  *(.head.text)
#define HEAD_TEXT  *(.head.text)
#define __HEAD        .section    ".head.text","ax"
#define __HEAD        .section    ".head.text","ax"
    __HEAD
_head:
    /*
     * DO NOT MODIFY. Image header expected by Linux boot-loaders.
     */
#ifdef CONFIG_EFI
    /*
     * This add instruction has no meaningful effect except that
     * its opcode forms the magic "MZ" signature required by UEFI.
     */
    add    x13, x18, #0x16
    b    stext
#else
    b    stext                // branch to kernel start, magic
    .long    0                // reserved
#endif
    le64sym    _kernel_offset_le        // Image load offset from start of RAM, little-endian
    le64sym    _kernel_size_le            // Effective size of kernel image, little-endian
    le64sym    _kernel_flags_le        // Informative flags, little-endian
    .quad    0                // reserved
    .quad    0                // reserved
    .quad    0                // reserved
    .byte    0x41                // Magic number, "ARM\x64"
    .byte    0x52
    .byte    0x4d
    .byte    0x64
#ifdef CONFIG_EFI
    .long    pe_header - _head        // Offset to the PE header.
#else
    .word    0                // reserved
#endif
    __HEAD
_head:
    /*

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-5-23 16:27 被DiamondH编辑 ,原因: 修改内容
收藏
免费 8
支持
分享
最新回复 (4)
雪    币: 4600
活跃值: (6846)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习了,谢谢
2022-5-24 09:48
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3

多谢大神分享。

       我最近尝试对android10内核的编译,个人感觉现在android内核很难编译,编译出来得都没有触屏功能,早先那些修改内核缺省配置文件: b1c1_defconfig的方法好像都失效了。即使将那些必须的触屏加入到这个文件,但是根本无法生效,编译生成的新配置文件和最终的编译结果还是原先的,根本没变。楼主有什么好的方法吗?多谢

最后于 2022-6-3 18:14 被david1008编辑 ,原因:
2022-6-3 18:11
0
雪    币: 1114
活跃值: (2094)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
david1008 多谢大神分享。       我最近尝试对android10内核的编译,个人感觉现在android内核很难编译,编译出来得都没有触 ...
很少见到编译出来触屏有问题的?使用的是哪里来的源码呢。一般厂商都提供了设备配置文件
2022-6-5 12:47
0
雪    币: 15
活跃值: (337)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
多谢大佬分享
2022-6-5 21:01
0
游客
登录 | 注册 方可回帖
返回
//