syscalltable hook for Android arm64

终于克服了拖延症写下了第一笔,前段时间看了Hooking Android System Calls for Pleasure and Benefit,于是就自己尝试着写了一下,综合了其他的思路改用动态获取sys_call_table的方法。思路简单,主要记录下遇到的问题。

定制内核

首先,为了必须使Kernel支持LKM,上文中给出的方法是在编译内核make defconfig之后,修改源码目录中的.config文件。这种方法修改的选项make时会被override。

1
2
3
4
5
scripts/kconfig/conf --silentoldconfig Kconfig
.config:214:warning: override: reassigning to symbol MODULES
#
# configuration written to .config
#

回去看.config文件的已经被恢复,实际上选项并没有生效。更简单的方法是修改

1
arch/platform(arm/arm64/……)/Kconfig

在其中将MODULES,MODULE_UNLOAD添加到default y项中

1
2
3
4
5
6
7
8
9
10
11
12
config ARM
bool
default y
select MODULES
select MODULE_UNLOAD
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_WANT_IPC_PARSE_VERSION
……
……

定位sys_call_table

sys_call_table地址的获取方法有多种,如上文采用的/proc/kallsym读取的方法,还以从system.map读。这些方法原理已经已经很多,就不多说了。
这里我采用的是用sys_close偏移定位的方法。这种方法的原理是从PAGE_OFFSET开始暴力查找,从每一个地址找NR_close偏移处存储的是否是sys_close来判断当前地址是否是sys_call_table。测试过程中arm一切正常,但是在arm64下却会crash。经过一段时间的排查发现。arm64下由于进行arm兼容,多了一张compat_sys_call_table的表。在内存中它们的位置关系如下。
compat_sys_call_in_memory
两张表中存储sys_close的相同,查找程序会先找到compat表中的sys_close,并且由于arm与arm64的系统调用号不同(查看对应的unistd.h确定),所以找到的地址既不是compat_sys_call_table也不是sys_call_table。根据内存的情况,扩展原来的定位方法,首先用arm的调用号确定compat_sys_call_table地址,在跳过这个地址继续暴力查找,用arm64的调用号确定sys_call_table的地址。

测试环境:android kernel 3.10 arm64
丑陋Code:ASyScallHookFrame