Android8添加arm64系统调用

Author:Gary
Date:2019-8-7
Android版本:android 8.1.0_r1
内核版本:Linux 4.4.88
参考文章:
https://blog.csdn.net/rikeyone/article/details/79929032
https://blog.csdn.net/m0_37340681/article/details/89704825
https://blog.csdn.net/zhbpd/article/details/80988421

0.先参考其他文章提前下载好并编译成功android以及kernel的源码

一.添加内核系统调用

1.函数声明

在include/linux/syscalls.h文件末尾添加函数声明

asmlinkage long sys_tnfs_transfer_pid(int);

2.函数实现

可以在一个已存在的C文件中添加或者新建一个C文件添加,这里在kernel文件夹下创建文件并实现系统调用:

SYSCALL_DEFINE1(tnfs_transfer_pid, int, pid)
{
	return pid*2
}

还需要修改kernel/Makefile文件,在obj-y中添加<c文件名>.o编译选项

3. 添加系统调用号

32位系统中是在arch/arm/include/uapi/asm/unistd.h中添加系统调用号,但是64位中该文件是个只include了asm-generic/unistd.h的空文件,所以系统调用号是在该文件下定义的;但该文件也只是一个同样类似的文件,所以最终系统调用号是在include/uapi/asm-generic/unistd.h中定义;同时也可以看到该系统调用定义与android的系统调用定义文件bionic/libc/kernel/uapi/asm-generic/unistd.h相匹配。
修改include/uapi/asm-generic/unistd.h文件,原内容:

#define __NR_fork 1079
#ifdef CONFIG_MMU
__SYSCALL(__NR_fork, sys_fork)
#else
__SYSCALL(__NR_fork, sys_ni_syscall)
#endif /* CONFIG_MMU */
#undef __NR_syscalls
#define __NR_syscalls (__NR_fork+1)

修改为:

#define __NR_fork 1079
#ifdef CONFIG_MMU
__SYSCALL(__NR_fork, sys_fork)
#else
__SYSCALL(__NR_fork, sys_ni_syscall)
#endif /* CONFIG_MMU */

//Gary Add
#define __NR_tnfs_transfer_pid 1080
__SYSCALL(__NR_tnfs_transfer_pid, sys_tnfs_transfer_pid)
//Gary Add End

#undef __NR_syscalls
#define __NR_syscalls (__NR_tnfs_transfer_pid+1)

不同于32位系统,这里同时也把系统调用计数也修改了。
添加32位系统调用号arch/arm64/include/asm/unistd32.h:

//Gary Add
#define __NR_tnfs_transfer_pid 390
__SYSCALL(__NR_tnfs_transfer_pid, sys_tnfs_transfer_pid)
//Gary Add End

增加调用计数arch/arm64/include/asm/unistd.h:

#define __NR_compat_syscalls		390

修改为

#define __NR_compat_syscalls		391

4. 编译

编译成功刷入即可

二.Android源码修改

1.声明系统调用

在bionic/libc/SYSCALLS.TXT中添加系统调用的声明:

ssize_t tnfs_transfer_pid(int) arm64

添加完这句话后只需要到/bionic/libc/tools/目录运行脚本python gensyscalls.py自动生成汇编入口文件。

2.添加映射表

在/bionic/libc/libc.map.txt中添加一行函数名即可:

LIBC {
  global:
	tnfs_transfer_pid;
    __assert;

然后同上一条一样运行脚本python genversion-scripts.py即可自动生成map文件

3.添加调用号

在文件中添加调用号,注意要与之前内核添加的调用号一致。在文件bionic/libc/kernel/uapi/asm-generic/unistd.h中修改:

#undef __NR_syscalls
#define __NR_syscalls (__NR_fork + 1)
#endif
#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT) 
#define __NR_fcntl __NR3264_fcntl

为:

#undef __NR_syscalls
#define __NR_syscalls (__NR_fork + 2)
#endif
#define __NR_tnfs_transfer_pid 1080
#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT)
#define __NR_fcntl __NR3264_fcntl   

4.测试程序:

在Zygote的初始化线程函数中添加一个测试代码如下:

  	#include <android/log.h>
	#include <unistd.h>
    extern "C" long tnfs_transfer_pid(int);
    ..............
    static pid_t ForkAndSpecializeCommon(.................
    ..............
    ..............
    if (pid == 0) {
    	const char * processName = env->GetStringUTFChars(java_se_name ,NULL);
    	__android_log_print(ANDROID_LOG_DEBUG, "[GaryAdd]", "Process name:%s,syscall_test:%ld", processName,tnfs_transfer(5));

5.编译刷入

以上方法我在测试时遇到了一些问题,仅供参考。如果需要从应用层往内核中传输自己的数据可以使用ioctl系统调用,虽然不规范但是方便简单,方法如下:

1. 修改内核ioctl系统调用

修改fs/ioctl.c文件,在文件末尾修改ioctl系统调用:

#define TNFS_FD -110
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
	int error;
	struct fd f;
	
	if((int)fd == TNFS_FD){
		printk("[syscall ioctl]Get pid:%d\n",cmd);
		return cmd*2;
	}

	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	error = security_file_ioctl(f.file, cmd, arg);
	if (!error)
		error = do_vfs_ioctl(f.file, fd, cmd, arg);
	fdput(f);
	return error;
}

这里fd定为负数是为了避免与本来的调用冲突,不过这样有不规范的地方就是如果fd会很大的话可能仍旧会与-110的补码冲突,虽然概率极低。

2.在Android层调用ioctl

ioctl定义在<unistd.h>中,第一个参数为句柄,第二个参数为你需要传递的参数,第三个是一个指针可以不要。这里在Zygote中添加,每次新建线程就能看到一次调用。

#include <android/log.h>
#define TNFS_FD -110
static pid_t ForkAndSpecializeCommon(
...............
	if (pid == 0) {
		const char * processName = env->GetStringUTFChars(java_se_name ,NULL);
		__android_log_print(ANDROID_LOG_DEBUG, "[GaryAdd]", "Process name:%s,syscall_test:%d", processName,ioctl(TNFS_FD ,5));

3.编译刷入

在这里插入图片描述
可以看到调用成功,会返回传入的参数的两倍回来。但是有的进程也并没有调用成功,是因为64位中有个兼容的ioctl接口,在fs/compat_ioctl.c里面,将里面的ioctl系统调用也按同样的方式修改即可。修改后可以达到100%的拦截。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章