Windows内核情景分析 内核发起系统调用的过程

从内核中发起系统调用

系统调用一般是来自于用户空间,但是系统有时也会在内核进行系统调用。内核中无法直接调用NtReadFile一类的函数。

  1. 这一方面是因为Windows内核并不导出这些函数
  2. 另一方面,这些函数调用时是需要系统调用框架/自陷框架,而从内核直接调用显然没有这样一个框架

所以这就是为什么在内核中只能通过ZwReadFile一类函数进行系统调用的原因。这里真的是非常的鞭辟入里!!!,让我豁然开朗Zw前缀函数的意义所在

那么下面就来看看ZwReadFile所做的事情吧

ZwReadFile的系统调用过程

在这里插入图片描述
依旧是eax存放调用号,edx指向堆栈上的参数块。因为是在内核,所以无需保存CS,SS,ESP等寄存器映像。之所以压入一个KGDT_R0_CODE是因为在最后验证的时候取的是[esp + 4],这是为了保证跟从用户空间发出的系统调用保持兼容。

到了要系统调用的返回的时候,即在TRAP_EPILOG的末尾处,上次并没有看CS & 1 == 0时候的分支。那里会有一个验证,会取CS的段选择子,然后&1,来判断PreviousMode是否之前来自用户空间,我们下面来详细看看。
在这里插入图片描述当程序返回执行到这,堆栈上面的情况应该是KiSystemService的返回地址,CS段选择子(KGDT_R0_CODE),EFLAGS,正好跟分支的出栈的情况一一对应。

类似于ZwReadFile的中介函数大概有两百多个,它们在内核也只是类似于stub的函数体,其内部并没有真正实现的代码,仍然是跳到了SSDT的相关调用例程里,那里才是Nt和Zw函数真正索引且提供服务的地方。
这种函数是由ReactOS提供了生成的工具。这个工具根据sysfunc.lst生成用户空间的中介函数NtReadFile和内核版的中介函数ZwReadFile。

先讲内核版本中介函数ZwReadFile的生成模板代码。
在这里插入图片描述
作为中介函数,传递两个参数即可实现相应的模板,一个是调用号,第二个是ret 平衡堆栈需要的参数个数
类似的,虽然书上未说,但是我们把用户模式下的模板先自己写一个加深印象。

//NtReadFile测试 9个参数 调用号为153
#include "stdafx.h"
#include <Windows.h>

#define USER_MODE_STUB_X86(functionName, callNum, retArg) \
	#functionName"(int dummy0, int dummy1, int dummy2)\n" \
	"{\n"\
	"\tasm {\n"\
	"\t\tpush ebp\n" \
	"\t\tmov ebp, esp\n" \
	"\t\tmov eax, "#callNum"\n" \
	"\t\tlea edx, [esp + 8]\n" \
	"\t\tint 0x2e\n" \
	"\t\tmov esp,ebp\n" \
	"\t\tpop ebp\n" \
	"\t\tret "#retArg"\n" \
	"\t}\n" \
	"}\n"
	
//NtReadFile测试 9个参数 调用号为153
int _tmain(int argc, _TCHAR* argv[])
{
	printf("%s\n", USER_MODE_STUB_X86(NtReadFile, 153, 9));
	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值