linux应用调试之自制系统调用、编写进程查看器(一)
2017-06-11 08:20
337 查看
转自http://liu1227787871.blog.163.com/blog/static/20536319720126135157567/
一、原理
要想自制系统调用,当然首相要做的就是明白系统调用的过程:
我们拿open函数来举个例子:当用户空间执行open函数时,会通过glibc函数库的作用最终去调用sys_open函数,sys_open函数最终又会调用我们具体注册的open函数!那么这里最主要的就是glibc函数库干了些什么呢?其实它的作用就是当用户空间执行open函数时,会去执行一条swi
#val指令,这条指令会使cpu发生异常,并跳转到异常向量入口:vector_swi处去执行,之后的代码会根据引发异常的指令取出其中的参数,并根据这个参数调用对应的处理函数!sys_open、sys_read、sys_write这些函数是放在一个数组里面的,就是根据取出的这个val值为下标找到sys_open函数!
说的有点乱,我们来理一理:app调用open->swi #val->引发cpu异常->跳转到异常向量入口处->根据引发异常的指令调用对应的处理函数!
那么我们自制系统调用的话,需要实现两点:
1、写一个应用函数:swi #val
2、在内核里面仿sys_xxx写一个函数,放入数组!
前者用于引发异常,后者用于具体实现!
二、实现
1、内核函数
(1)在arch/arm/kernel/call.S文件里面的CALL()列表的最后添加一项,如:CALL(sys_hello)
这里是用来调用sys_hello
(2)在fs/read_write.c文件里加入如下代码:
asmlinkage void sys_hello(const char __user * buf, size_t count)
{
char ker_buf[100];
if(buf)
{
// 目的是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0
copy_from_user(ker_buf,buf,(count<100) ? count:100);
ker_buf[99]='\0';
printk("sys_hello:%s\n",ker_buf);
}
}
这里是sys_hello的具体实现
(3)在include/Linux/syscalls.h文件里加入如下代码:
asmlinkage void sys_hello(const char __user * buf, size_t count);
这是对函数sys_hello的声明
以上我们分别实现了函数的定义、声明和调用!这样内核里面的工作就完成了!
2、应用程序
#include <errno.h>
#include <unistd.h>
#define __NR_SYSCALL_BASE 0x900000
void hello(char *buf, int count)
{
/* swi */
//这里C 语言调用汇编会使用asm();
asm ("mov r0, %0\n" /* save the argment in r0 */
"mov r1, %1\n" /* save the argment in r1 */
"swi %2\n" /* do the system call */执行swi指令进入内核态
:
: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE
+ 352)
: "r0", "r1");
}
int main(int argc, char **argv)
{
printf("in app, call hello\n");
hello("www.100ask.net", 15);//这个函数会进行系统调用
return 0;
}
当我们用原来的内核启动的时候,打印信息如下:
in app, call hello
当我们用新内核启动的时候,打印信息如下:
in app, call hello
sys_hello:www.100ask.NET
成功了!
在本节里面我们只是实现了一个系统调用,至于系统调用在应用调试里面如何应用,我们下一节里面会详细讲解!
一、原理
要想自制系统调用,当然首相要做的就是明白系统调用的过程:
我们拿open函数来举个例子:当用户空间执行open函数时,会通过glibc函数库的作用最终去调用sys_open函数,sys_open函数最终又会调用我们具体注册的open函数!那么这里最主要的就是glibc函数库干了些什么呢?其实它的作用就是当用户空间执行open函数时,会去执行一条swi
#val指令,这条指令会使cpu发生异常,并跳转到异常向量入口:vector_swi处去执行,之后的代码会根据引发异常的指令取出其中的参数,并根据这个参数调用对应的处理函数!sys_open、sys_read、sys_write这些函数是放在一个数组里面的,就是根据取出的这个val值为下标找到sys_open函数!
说的有点乱,我们来理一理:app调用open->swi #val->引发cpu异常->跳转到异常向量入口处->根据引发异常的指令调用对应的处理函数!
那么我们自制系统调用的话,需要实现两点:
1、写一个应用函数:swi #val
2、在内核里面仿sys_xxx写一个函数,放入数组!
前者用于引发异常,后者用于具体实现!
二、实现
1、内核函数
(1)在arch/arm/kernel/call.S文件里面的CALL()列表的最后添加一项,如:CALL(sys_hello)
这里是用来调用sys_hello
(2)在fs/read_write.c文件里加入如下代码:
asmlinkage void sys_hello(const char __user * buf, size_t count)
{
char ker_buf[100];
if(buf)
{
// 目的是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0
copy_from_user(ker_buf,buf,(count<100) ? count:100);
ker_buf[99]='\0';
printk("sys_hello:%s\n",ker_buf);
}
}
这里是sys_hello的具体实现
(3)在include/Linux/syscalls.h文件里加入如下代码:
asmlinkage void sys_hello(const char __user * buf, size_t count);
这是对函数sys_hello的声明
以上我们分别实现了函数的定义、声明和调用!这样内核里面的工作就完成了!
2、应用程序
#include <errno.h>
#include <unistd.h>
#define __NR_SYSCALL_BASE 0x900000
void hello(char *buf, int count)
{
/* swi */
//这里C 语言调用汇编会使用asm();
asm ("mov r0, %0\n" /* save the argment in r0 */
"mov r1, %1\n" /* save the argment in r1 */
"swi %2\n" /* do the system call */执行swi指令进入内核态
:
: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE
+ 352)
: "r0", "r1");
}
int main(int argc, char **argv)
{
printf("in app, call hello\n");
hello("www.100ask.net", 15);//这个函数会进行系统调用
return 0;
}
当我们用原来的内核启动的时候,打印信息如下:
in app, call hello
当我们用新内核启动的时候,打印信息如下:
in app, call hello
sys_hello:www.100ask.NET
成功了!
在本节里面我们只是实现了一个系统调用,至于系统调用在应用调试里面如何应用,我们下一节里面会详细讲解!
相关文章推荐
- 应用调试之自制系统调用、编写进程查看器(二)
- 应用程序调试(四)————自制系统调用、编写进程查看器
- linux应用调试之使用strace命令跟踪系统调用
- 学习笔记 --- LINUX 应用调试之添加系统调用
- 应用调试之自制系统调用
- 学习笔记 --- LINUX 应用调试之使用strace命令追踪系统调用
- 分享在Linux下编译Android源代码并修改调试系统自带应用的方法
- Linux 2.6 劫持系统调用 隐藏进程
- 分享在Linux下编译Android源代码并修改调试系统自带应用的方法
- Linux系统调用--进程管理(1)
- Linux 2.6 劫持系统调用 隐藏进程
- Linux进程相关系统调用(一)
- Linux进程相关系统调用(二)
- Linux下C编程,进程通信之标准流管道通信(即系统调用)
- 调试_应用的系统调用跟踪
- 分享在Linux下编译Android源代码并修改调试系统自带应用的方法
- Linux系统进程控制编程(五)——popen函数调用
- Linux进程间通讯所使用的系统调用函数
- linux下使用系统调用实现进程后台运行
- Linux编写新的系统调用(内核版本3.2.18)