应用调试(四)系统调用SWI
title: 应用调试(四)系统调用SWI
date: 2019/01/19 18:05:39
toc: true
应用调试(四)系统调用SWI
系统调用
我们App中的open,read等实际上会触发swi异常,触发系统调用sys_open,sys_read等,内核根据swi的值来执行具体的操作
SWI代码片段分析
搜索下vector_swi,找到入口函数arch\arm\kernel\entry-common.S
	.align	5
ENTRY(vector_swi)
	@ 保存现场
	sub	sp, sp, #S_FRAME_SIZE
	stmia	sp, {r0 - r12}			@ Calling r0 - r12
	add	r8, sp, #S_PC
	stmdb	r8, {sp, lr}^			@ Calling sp, lr
	mrs	r8, spsr			@ called from non-FIQ mode, so ok.
	str	lr, [sp, #S_PC]			@ Save calling PC
	str	r8, [sp, #S_PSR]		@ Save CPSR
	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
	zero_fp
	@ 获得swi的指令地址,确保是swi指令
	ldr	scno, [lr, #-4]			@ get SWI instruction
    A710(	and	ip, scno, #0x0f000000		@ check for SWI		)
    A710(	teq	ip, #0x0f000000						)
    A710(	bne	.Larm710bug						)
    @ tbl等于数组表基地址
    get_thread_info tsk
    adr	tbl, sys_call_table		@ load syscall table pointer
    ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
    @清除高8位
    bic	scno, scno, #0xff000000		@ mask off SWI op-code
    @ #define __NR_SYSCALL_BASE	0x900000  这里swi的值实际上是0x900000 0x900001 ...所以要清除这个高位的9
    eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
    @根据索引号,去tbl 这个数组中调用函数
    @ tbl:数组表基地址,  scno:要调用的sys_write()的索引值     lsl #2:左移2位,一个函数指针占据4个字节
    cmp	scno, #NR_syscalls		@ check upper syscall limit
    adr	lr, ret_fast_syscall		@ return address
    ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
这里首先获得swi这条指令的内容,swi指令位于
lr-4,原因如下图
然后分析确保是swi指令,也就是
and ip, scno, #0x0f000000
获得全局的一个存有系统调用函数的数组的地址
通过swi的值去找到这个数组的索引,执行函数
分析sys_write
理论上,应该有sys_write存入这个指针数组,搜索下发现如下arch\arm\kernel\calls.S
/* 0 */		CALL(sys_restart_syscall)
		CALL(sys_exit)
		CALL(sys_fork_wrapper)
		CALL(sys_read)
		CALL(sys_write)
/* 5 */		CALL(sys_open)
......
同时有如下在arch\arm\kernel\entry-common.S,也就是先定义这个CALL,再将上面的定义全部包含进来
	.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
#undef CALL
#define CALL(x) .long x
也就是说,我们可以自己定义一个swi val 在arch\arm\kernel\calls.S 放在最后面
/* 350 */	CALL(sys_timerfd)
		CALL(sys_eventfd)
		CALL(sys_hello)		/* 添加一个自己的系统调用 */
构造sys_hello
仿照sys_write声明定义在include\linux\syscalls.h和fs\read_write.c
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
实现函数如下
asmlinkage void sys_hello(const char __user * buf, size_t count);
asmlinkage void sys_hello(const char __user * buf, size_t count)
{
    char ker_buf[100];
    if(buf)
    { copy_from_user(ker_buf, buf, (count<100)? count : 100);
      ker_buf[99]='\0';
      printk("sys_hello:%s\n",ker_buf);
    }
}
应用程序调用SWI
参考glibc-2.3.6/,这里没去仔细看了,这里有个__brk函数,仿照着写,具体看下注释
#include <errno.h>
#include <unistd.h>
#define __NR_SYSCALL_BASE	0x900000
void hello(char *buf, int count)
{
	/* swi */
asm ("mov r0, %0\n"   /* save the argment in r0 */
	 "mov r1, %1\n"   /* save the argment in r0 */
	 "swi %2\n"   /* do the system call */
	 /* 输出部分,这里不需要输出,但是需要 : 占位*/
	 :
	 /* 输入部分, r表示寄存器 ,使用 %0 表示第一个*/
	 /* %0        %1          i表示立即数,也是就是Immediate  这里就是 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("hello", 6);
	return 0;
}
嵌入汇编语法
参考文件cnblog,这里不去仔细分析了,简单的分析在韦老师视频31课4.1节25分左右
参考linux内核源代码情景分析1.5.2节)
格式如下所示:
- asm( 指令部 : 输出部 : 输入部 : 损坏部 );
 - 如果没有的部分,冒号也不能省略
 
指令部
在指令部中,若出现%0、%1、%2等,则表示指令部后面的第几个变量.
比如上面代码的mov r0, %0\n
其中%0便会对应buf值,而r是一个约束条件字母,r表示任意一个寄存器,在预处理时,便会自动分配一个寄存器,将buf值放入该寄存器里,然后运行mov  r0  (buf对应的寄存器)
输出部
每个输出部的约束条件字母都要加上"=",比如:
int num=5,val;
asm("mov %0,%1\n"
    :"=r"(val)                //指定val是一个输出部,执行mov后,val便等于5
    :"i"(num)                // "i"约束条件字母,表示num是一个立即数
    :      );
输入部
和输出部唯一不同的就是,在约束条件字母前不能加上=
常用的约束条件字母,如下图所示:

损坏部
和输入输出类似,一般用来处理操作的中间过程,因为这些原有的内容都会被损坏,比如上面的hello()里的r0, r1,只是用来当做参数,传递给内核的sys_hello()
测试APP
# mount -t nfs -o nolock,vers=2 192.168.95.222:/home/book/stu /mnt
# cd /mnt/code
# ./test_system_call
in app, call hello
sys_hello:hello   #  这个“hello” 是系统调用打印的
参考
https://www.cnblogs.com/lifexy/p/8075282.html 嵌入式汇编简单介绍
应用调试(四)系统调用SWI的更多相关文章
- 驱动调试(四)oops确定调用树
		
目录 驱动调试(四)oops确定调用树 内核开启调用树 栈指针分析 原理 寄存器别名 基础解释 例子分析 找到PC地址的位置 栈分析 附录:原文的excel title: 驱动调试(四)oops确定调 ...
 - 42.Linux应用调试-初步制作系统调用(用户态->内核态)
		
1首先来讲讲应用程序如何实现系统调用(用户态->内核态)? 我们以应用程序的write()函数为例: 1)首先用户态的write()函数会进入glibc库,里面会将write()转换为swi(S ...
 - Linux内核分析 笔记四 系统调用的三个层次  ——by王玥
		
一.知识点总结 (一)用户态.内核态和中断 1.内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态 2.用户态:在低级别的指令状态下,代码 只能在级别允许的特 ...
 - Socket与系统调用深层分析
		
实验背景: Socket API编程接口之上可以编写基于不同网络协议的应用程序: Socket接口在用户态通过系统调用机制进入内核: 内核中将系统调用作为一个特殊的中断来处理,以socket相关系统调 ...
 - GDB调试系列之了解GDB
		
想要熟练利用GDB进行程序调试,首先要了解什么是GDB. 1. 什么是GDB GDB (the GNU Project Debugger) 是一个可以运行在大多数常见的UNIX架构.Windows.M ...
 - [转]Android逆向之动态调试总结
		
一.在SO中关键函数上下断点 刚学逆向调试时.大多都满足于在SO中某关键函数上下断点.然后通过操作应用程序,去触发这个断点,然后进行调试 详细的步骤可以参见非虫大大的<Android软件安全与逆 ...
 - 使用IntelliJ IDEA(PHPStorm)和xdebug在firefox、chrome中远程调试PHP
		
很多PHP程序员都习惯于使用echo.var_dump和exit来中断和调试web应用程序,本文主要介绍结合xdebug.IntelliJ IDEA.Firefox/chrome/IE来远程调试PHP ...
 - vscode 学习笔记 —— 调试 (以 node 为例)
		
一.建立配置文件 1.选择你的项目 2.选择你项目的语言 3.当前项目路径下生成 .vscode/launch.json { // Use IntelliSense to learn about po ...
 - 如何调试触发器-MSSQL (转帖)
		
调试触发器 //------------------------------------- 作者:四海为圈(原创) //------------------------------------- 1. ...
 
随机推荐
- SQL Server 2008初次启动
			
一.关于安装 SQL Server 数据库的安装,经过自己的安装,总体还是比较容易,没有太多难度,安装包在网上也有很多,在此,就跳过安装的这一步. 二.初次启动SQL Server 安装完成数据库后, ...
 - 拉勾网爬取全国python职位并数据分析薪资,工作经验,学历等信息
			
首先前往拉勾网“爬虫”职位相关页面 确定网页的加载方式是JavaScript加载 通过谷歌浏览器开发者工具分析和寻找网页的真实请求,确定真实数据在position.Ajax开头的链接里,请求方式是PO ...
 - js获取时间相关函数
			
js获取时间函数 var myDate = new Date; var year = myDate.getFullYear();//获取当前年 var yue = myDate.getMonth()+ ...
 - CVE-2018-8120 分析
			
目录 CVE-2018-8120 分析 1.实验环境 1.1.操作系统 1.2.用到的分析工具 2.假如 2.1.我想提权 2.2. 有一个处于内核空间,极少被调用的函数 2.3.R3任意修改R0地址 ...
 - .NET 术语
			
.NET 术语 1. AOT 预编译器.与 JIT 类似,此编译器还可将 IL 转换为机器代码. 与 JIT 编译相比,AOT 编译在应用程序执行前进行并且通常在不同计算机上执行. 由于在运行时 AO ...
 - LeetCode算法题-Max Consecutive Ones(Java实现)
			
这是悦乐书的第242次更新,第255篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第109题(顺位题号是485).给定二进制数组,找到此数组中连续1的最大数量.例如: 输 ...
 - Business Intelligence Tools We Recommend 1/4 – Metabase
			
May 24, 2018 by Arturs Oganesyan-Peel BI is useful. It’s pretty. But it never really matters unless ...
 - Linux systemtap定位系统IO资源使用情况(ok)
			
一.systemtap介绍 SystemTap是一个强大的调试工具,是监控和跟踪运行中的Linux 内核的操作的动态方法,确切的说应该是一门调试语言,因为它有自己的语法,也有解析.编译.运行等过程(准 ...
 - Angular5 路由守卫
			
今年下半年一直很忙,没有多少时间来写博客,很多笔记都记在了本地一起提交到了git上边. 夏末的时候做的两个vue项目中有接触到vue的路由守卫,今天在另外一个angular上,发现路由守卫有异常,导致 ...
 - UUID简记
			
一.概述 wiki上的解释: A universally unique identifier (UUID) is a 128-bit number used to identify informati ...