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%的攔截。

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