赞
踩
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
在include/linux/syscalls.h文件末尾添加函数声明
asmlinkage long sys_tnfs_transfer_pid(int);
可以在一个已存在的C文件中添加或者新建一个C文件添加,这里在kernel文件夹下创建文件并实现系统调用:
SYSCALL_DEFINE1(tnfs_transfer_pid, int, pid)
{
return pid*2
}
还需要修改kernel/Makefile文件,在obj-y
中添加<c文件名>.o
编译选项
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
编译成功刷入即可
在bionic/libc/SYSCALLS.TXT中添加系统调用的声明:
ssize_t tnfs_transfer_pid(int) arm64
添加完这句话后只需要到/bionic/libc/tools/目录运行脚本python gensyscalls.py
自动生成汇编入口文件。
在/bionic/libc/libc.map.txt中添加一行函数名即可:
LIBC {
global:
tnfs_transfer_pid;
__assert;
然后同上一条一样运行脚本python genversion-scripts.py
即可自动生成map文件
在文件中添加调用号,注意要与之前内核添加的调用号一致。在文件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
在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));
修改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的补码冲突,虽然概率极低。
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));
可以看到调用成功,会返回传入的参数的两倍回来。但是有的进程也并没有调用成功,是因为64位中有个兼容的ioctl接口,在fs/compat_ioctl.c里面,将里面的ioctl系统调用也按同样的方式修改即可。修改后可以达到100%的拦截。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。