用户态切换到内核态(May 22)

来源:互联网 发布:c语言中产生随机数 编辑:程序博客网 时间:2024/05/01 08:17

一般来讲,从用户态切换到内核态主要通过以下方式:

1. 系统调用(Windows:int 0x2e, Linux: int $0x80)

2. 中断

3. 异常

4. 代码里直接int 0x3(调试断点)

5. 汇编指令 sysenter/sysexit


1. 系统调用:

Windows:

NTSTATUS STDCALL NtReadFile(..........)--9个参数

__declspec(naked) __stdcall NtReadFile(int dummy0, int dummy1, int dummy2)

{

__asm{

  push ebp    //上一级调用函数的ebp压栈, esp指向返回值地址, esp+4指向参数块的起始地址

  move ebp, esp //ebp =esp, esp+4指向返回值地址, esp+8指向参数块的起始地址

  move eax, 152 //系统调用号是152

  lea edx,8[ebp] //ebp+4 是返回值的地址,ebp+8是参数块的起始地址,因为stacall是表示从右向左通过堆栈传递参数,所以ebp+8是第一个参数, ebp+12是第二个参数...

  int 0x2E //进入内核

  pop ebp //ebp出栈

  ret 9

}

}

×××__stacall是表示参数从右向左压入堆栈, 同时函数本身清理堆栈;函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸

×××__cdecl是表示参数从右向左压入堆栈, 同时函数本身不清理堆栈,调用者清理堆栈

***__fastcall约定将函数的从左边开始的两个4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈


Linux:

int sethostname(cost char *name, size_t len);  //2个参数

36 sethostname.o: file format elf32i386
37
38 Disassembly of section .text:
39
40 00000000 <sethostname>: //esp指向函数返回地址, esp+4指向第一个函数参数(name)的地址, esp+8指向第二个函数参数(len)的地址
41 0: 89 da mov %ebx,%edx             //将ebx的内容移到edx中
42 2: 8b 4c 24 08 mov 0x8(%esp,1),%ecx  //将第二个函数参数的地址赋给ecx寄存器
43 6: 8b 5c 24 04 mov 0x4(%esp,1),%ebx //将第二个函数参数的地址赋给ebx寄存器
44 a: b8 4a 00 00 00 mov $0x4a,%eax       //0x4a是sethostname的系统调用号, 将它存入eax寄存器
45 f: cd 80 int $0x80                    //中断指令, 进入内核执行系统调用
46 11: 89 d3 mov %edx,%ebx   //恢复edx的内容
47 13: 3d 01 f0 ff ff cmp $0xfffff001,%eax //eax中保存系统调用的返回值, 如果eax的内容实在0xfffff001-0xffffffff(-1~ -4095)之间则出错
48 18: 0f 83 fc ff ff ff jae 1a <sethostname+0x1a>  //转向__syscall_error
49 1e: c3 ret


*** Linux内核在系统调用时是通过寄存器而不是堆栈传递参数的




0 0
原创粉丝点击