#Linux第四周学习总结——扒开系统调用的三层皮(上)
Linux第四周学习总结——扒开系统调用的三层皮(上)
一、用户态、内核态和中断
系统调用通过库函数。
1.用户态和内核态
区分(不同的指令执行级别):
- 用户态:在相应的低执行状态下,代码的掌控范围受到限制,只能在对应级别允许的范围内活动
- 内核态:在高执行级别下,代码可以执行特权指令,访问任意的物理地址。
Intel x86 CPU有四种不同的执行级别0—3,Linux只是用了期中的0级和3级分别表示内核态和用户态。

注意逻辑地址和物理地址的区别。逻辑地址是进程地址空间里面的
2.中断
中断处理是从用户态进入内核态主要的方式
系统调用是只是一种特殊的中断

中断指令或向量发生之后发生中断处理程序,刚一开始执行SAVE ALL,即把其他的寄存器的值push到内核堆栈上去,结束之后,把用户态的寄存器的值在popl出来,最后iret,对应着中断信号(int指令),发生时的CPU动作相反。
- 保护现场就是进入中断程序,保存需要用到的寄存器的数据;
- 恢复现场就是退出中断程序,恢复保存寄存器的数据。
中断处理的完整过程:

理解:中断信号(int指令)完成:保存cs:eip的值、当前堆栈段栈顶和当前标志,同时加载了当前中断信号或是系统调用的相关联的中断服务入口到cs:eip里面,把当前对战段和esp也加载到CPU里面。
SAVE ALL完成后若没有发生调度,则接着执行RESTORE_ALL;若发生进程调度,则当前的状态会暂时的保存在系统里面,当下一次发生进程调度切换到当前进程时再接着执行完毕。
二、系统调用概述
1.系统调用的意义:
操作系统为用户态进程与硬件设备进行交互提供的一组接口。可以把用户从底层的硬件变成中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性。
2.API应用程序编程接口:
只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求。
Libc库定义的一些API引用了一些封装例程,目的是发布系统调用,让程序员写代码的时候可以通过函数调用而非汇编指令触发一个系统调用。
3.返回值:
- 大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用;
- -1在多数情况下表示内核不能满足进程的请求;
- Libc中定义的errno变量包含特定的出错码。
4.系统调用的三个层次
应用程序编程接口里封装了一个系统调用,int 0x80中断向量,对应着system_call内核代码的起点,执行完中断服务程序,返回。

系统调用的三个层次依次是:xyz函数(API)、system_ call(中断向量)和 sys_ xyz(中断服务程序)。
5.传参
内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器传递。
系统调用号将xyz和sys_xyz关联起来了。
system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。具体过程:
1.一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把eax寄存器的值置为2(即__NR_fork)。
2.这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号
3.进入sys_call之后,立即将eax的值压入内核堆栈。
寄存器传递参数具有如下限制:
- 每个参数的长度不能超过寄存器的长度,即32位
- 在系统调用号( eax)之外,参数的个数不能超过6个( ebx,ecx, edx, esi, edi, ebp)
- 参数个数超过6个则把某一个寄存器作为指针指向一块内存,进入内核态之后可以访问所有的地址空间,通过那块内存传递参数。
三、使用库函数API和C代码中嵌入汇编代码触发系统调用
1. 内嵌汇编语法:
__asm__(
汇编语句模板:
输入部分:
输出部分:
破坏描述部分:);
这部分内容前几周已经讲过,这里不再重复。

2. 用汇编方式出发系统调用获取系统当前时间


汇编代码分析:
#include <stdio.h>
#include <time.h>
int main()
{
time_t tt;//int型数值
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t"//将ebx寄存器清零,系统调用传递第一个参数使用ebx,这里是null
"mov $0xd,%%eax\n\t"//将0xd放入eax中,0xd为13,传递系统调用号13
"int $0x80\n\t"
"mov %%eax,$0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(tt)
);
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
用户态进程向内核态传递了系统调用号。
四、实验——使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本次实验我选择了24号系统调用,获取当前用户uid(用户ID)。
实验过程:
使用库函数API方式:

使用C代码中嵌入汇编代码方式:

编译运行:

汇编代码调用系统调用的工作过程分析:
首先将ebx寄存器清零,表示无参数传入;
然后将0x18放入eax,表示需要调用的系统调用号24;
执行int 0x80来执行系统调用;
之后eax寄存器保存了返回值,将它赋值给输出uid变量。
完成整个汇编代码的系统调用。
总结:
在Linux系统中是通过激活0x80中断来触发系统调用的,需要调用的系统调用号实现赋值给eax存储器,如果有传入参数可赋值给ebx寄存器,如果多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。
虽然Intel X86 CPU有4种执行级别0~3,但是在Linux系统中仅使用了0和3级,分别表示内核态和用户态。一些涉及底层、硬件、核心的操作必须在内核态下才允许执行,为操作系统程序和驱动程序专享,普通程序仅能执行在用户态下。如果普通程序需要涉及内核态的操作,就需要通过系统调用来实现。这样做的好处是屏蔽平台相关操作降低了软件开发难度,增强了系统安全性,使程序具有更好的移植性(Linux系统及其他Unix系统遵循统一标准,系统调用基本一样)。
另外,我想问一下老师,为什么我的API方法运行结果最后会多出来一个%?
参考资料:
http://www.iteedu.com/os/linux/linuxprgm/linuxcfunctions/user/getuid.php
#Linux第四周学习总结——扒开系统调用的三层皮(上)的更多相关文章
- 20135337朱荟潼 Linux第四周学习总结——扒开系统调用的三层皮(上)
朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 知识点梳理 一.用 ...
- LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”
LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...
- LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)
LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...
- Linux第五周学习总结——扒开系统调用的三层皮(下
Linux第五周学习总结--扒开系统调用的三层皮(下) 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/co ...
- 《Linux内核分析》第五周学习总结 扒开系统调用的三层皮(下)
扒开系统调用的三层皮(下) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给Men ...
- linux 内核 第四周 扒开系统调用的三层皮 上
姬梦馨 原创作品 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断处理过程 用户通过库函数与系统调用联系起来:库函数帮我们把系 ...
- 20135337朱荟潼 Linux第五周学习总结——扒开系统调用的三层皮(下)
朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 一.学习内容 (一 ...
- Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥
(一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用 ...
- 《Linux内核分析》第四周学习总结 扒开系统调用的三成皮(上)
第四周 扒开系统调用的三层皮(上) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一. ...
随机推荐
- 【Hibernate步步为营】--核心对象+持久对象全析(一)
引言 上篇博客对Hibernate进行了基本的解析.并分析了它的一些特性. Hibernate可以如此的流行也是由于它有诸多长处,不论什么事物都有两面性.Hibernate尽管流行.可 ...
- 解决The SDK platform-tools version ((23)) is too old to check APIs compiled with API 23
用2.0的Android Studio bate版 打开项目,在包名的地方会出现一条红线,但是似乎不影响代码的正确性. 看着好不爽啊,我倒是还没运行就找办法解决掉了.就是说是否影响程序正常运行我是不 ...
- 深入C#学习系列一:序列化(Serialize)、反序列化(Deserialize)
序列化概述: 序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读取或反序列化对象 ...
- centos6.4安装 zabbix agent
1.防火墙设置 允许zabbix-agent的10050端口通过 iptables -A INPUT -p tcp --dport 10050 -j ACCEPT 2.安装zabbix agent ...
- PRML1-引言
本系列是根据<pattern recognition and machine learning>一书写的,算是读书笔记?算是吧.因为是从自己角度出发,所以其实很大程度上自己看得懂,估计别人 ...
- Hadoop中ssh+IP、ssh+别名免秘钥登录配置
1.为什么要进行 SSH 无密码验证配置? Hadoop运行过程中需要管理远端Hadoop守护进程,在Hadoop启动以后,NameNode是通过SSH(Secure Shell)来启动和停止各个Da ...
- Codeforces round 1106
Div 2 536 题目链接 我还是太菜了.jpg E 傻逼DP直接做 我居然调了1.5h 我真的是太菜了.jpg 堆+扫描线直接维护每个位置的贪心结果 然后要么使用干扰 要么就接受贪心的结果 #in ...
- Python3入门(七)——模块
在Python中,一个.py文件就称之为一个模块(Module).(例如main.py就称之为main模块) 为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package). ...
- 大数据入门第二十一天——scala入门(一)并发编程Actor
注:我们现在学的Scala Actor是scala 2.10.x版本及以前版本的Actor. Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor,老版本的Actor已经废弃 一. ...
- 20155227《网络对抗》Exp5 MSF基础应用
20155227<网络对抗>Exp5 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode exploit:把实现设置好的东西送到要攻击的主机里. ...