Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

重载内核实现绕过一切钩子-附详细文档 重载内核实现绕过一切钩子的驱动源代码-附详细文档 1:将内核文件映射到我内核空间去; 2:path KiFastCallEntry重定向 立即下载

目录(?)[+]

为什么要写这篇文章

1.      因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。

2.      碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Hook,主要就是Hook到这个函数

3.      刚刚做完毕业设计,对使用中断来实现系统调用的方式记忆犹新。

 

以上原因导致我最近眼前总是出现系统调用这个词,脑海中总是出现系统调用的实现方式,所以决定写篇文章清理一下思维。本文所有举例如无明确指明,均是在Windows XP SP3系统中获得。

 

本文的目的是探索一下Windows目前的系统调用的实现架构,介绍一种中规中矩的获取KiFastCallEntry函数地址的方法,但是在介绍之前还是要把该解释的解释清除。

 

Windows API和系统调用的关系

肯定会有人说Windows API就是系统调用,系统调用就是Windwos API,是这样的么?负责任的说:不是这样的!

先从广义上来说,Windows API是对于整个Windows操作系统自身的程序代码之外的应用程序来说的,而系统调用是Windows内核对于非内核程序代码之外的Windows系统程序代码来说的。也就是说系统调用要比Windows API低一个层次。一个Windows API是一个函数,这个函数可能会使用系统调用,请注意是可能,因为并不是所有的API都需要进入内核去完成这个API的功能。

 

Windows内核实现文件和应用层文件

在一个安装完成的Windows操作系统中可见并有效的内核实现文件是

C:\Windows\System32\ntoskrnl.exe

C:\Windows\System32\ntkrnlpa.exe

请注意有两个内核文件,其中第二个比第一个的名字少了os多了个pa,省去的os没有任何意义,但是多出来的pa所代表的意思是PAE(物理地址扩展),这是X86CPU的一个硬件特性,Windows启动之后根据当前系统设置是否开启了PAE特性会自动选择把其中一个作为内核加载到内存中。

为什么加了这么多限定词,因为ntoskrnl.exe这个文件名并不一定是这个文件的真实名称,可以从文件属性中看到

ntoskrnl.exe原始文件名为可能为ntoskrnl.exe或者ntkrnlmp.exe

ntkrnlpa.exe原始文件名为可能为ntkrnlpa.exe或者ntkrpamp.exe

可以发现其中的不同之处就是mp,mp就是Multi-processor(多处理器,也可以理解为多核,因为IA-32架构对多核处理器的编程和多处理器的编程是相似的机制)。为什么会出现这中情况呢?因为这完全是由计算机硬件的不同配置导致的。当安装Windows操作系统的时候,Windows安装程序会自动检测机器的CPU特性,根据CPU的核心数来确定使用哪一套内核。如果是单核心就只复制ntkrnlpa.exe和ntoskrnl.exe到系统目录下,如果是多核心就复制ntkrnlpamp.exe和ntoskrnlmp.exe到系统目录下,所以如果你有一台单核心CPU的机器,有一天你换了双核的CPU却没有重新安装操作系统,那么你就不会在看到熟悉的Windows启动画面了。类似这两个文件的还有一个文件C:\Windows\System32\hal.dll,这是Windows的硬件抽象层程序文件,这个就不做具体介绍了。额外补充一个不同的硬件配置所需要的文件列表:

 

Standard PC

hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

Advanced Configuration and Power Interface (ACPI) PC

halacpi.dll---->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

ACPI Uniprocessor PC

halaacpi.dll--->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

MPS Uniprocessor PC

halapic.dll---->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

ACPI Multiprocessor PC

halmacpi.dll--->hal.dll 
ntkrpamp.exe--->ntkrnlpa.exe 
ntkrnlmp.exe---->ntoskrnl.exe

Compag SystemPro Multiprocessor or 100% Compatible

halsp.dll---->hal.dll 
ntkrpamp.exe--->ntkrnlpa.exe 
ntkrnlmp.exe--->ntoskrnl.exe

MPS Multiprocessor PC

halmps.dll----->hal.dll 
ntkrpamp.exe----->ntkrnlpa.exe 
ntkrnlmp.exe--->ntoskrnl.exe

Silicon Graphics Visual Workstation

halsp.dll---->hal.dll 
ntkrpamp.exe----->ntkrnlpa.exe 
ntkrnlmp.exe---->ntoskrnl.exe

 

不论什么配置,一旦系统安装完成后,对我们来说可见的内核文件就只有两个ntoskrnl.exe和ntkrnlpa.exe。这两个文件中的代码就是运行于RING0下的内核代码,他们里面所包含了真正的系统调用的代码。我们用Dependency Walker看一下:

(P1)

 

可以看到很多函数,他们之中有些是系统调用,会和RING3的程序代码有联系,有些仅仅是内核中的函数,只跟内核中其他的代码有联系。有一点需要说,在用Windbg调试内核的时候,无论系统使用的是哪个内核文件,Windbg都会把这个内核文件的符号(模块名)识别为nt。所以如果我们要查看内核中的NtOpenFile函数的反汇编,只需要输入一下命令

u nt!NtNtOpenFile

如下图:

(P2)

下面再说包含Windows API的文件,这个就非常多了,最基础的User32.dll,Ntdll.dll,Kernel.dll这三个文件包含了Windows系统相关的绝大多数API,当然还有其他函数簇比如包含socket函数簇的ws2_32.dll等等,这些dll中都导出了大量的API函数以及结构。这些函数都是运行在RING3层的代码,有些会跟内核层中的代码发生联系,有写也不会,就是上面提到的Windows API不一定会使用系统调用。比如我们举个简单的例子,拿CharNextA这个Windows API来说,这个API是在User32.dll中实现的。我们可以反汇编一下看看这个API的具体实现。

(P3)

可以看到这个函数在ret之前只有一个跳转je并且目标代码仍然在本函数内,而且没有任何中断或者快速系统调用,所以这个函数并没有离开RING3层,也就是说当你编写一个程序调用了这个API之后,这个API并没有把你的程序流程带入RING0的内核层代码。

 

Windows API使用系统调用的方法

通过中断实现系统调用

Windows API如果设涉及到系统调用就要由RING3进入RING0,这就牵扯到了X86保护模式下有特权级变化的控制转移。在早期的CPU中(Pentium II之前),没有快速系统调用这个机制,所以能用来进行特权级变化的控制转移的机制只有通过中断实现,保护模式下的中断的实现方式是通过IDT表来实现,IDT表中存放的是一种特殊的X86段描述符——门描述符,门描述符的格式如下

(P4)

可以看到其中有一个Selector字段和一个Offset字段,并且是不连续的,这里只介绍这两个字段的含义,其他字段的含义这里不再赘述,有兴趣的话可以自己去看下保护模式相关资料。说到底这个门描述符的作用就是描述一个程序段,对我们来说重要的就是Selector和Offset字段了,因为Selector可以帮我们找到它所描述的程序的【段】,Offset就是程序在【段】内的【偏移】,有了【段】和【偏移】就可以确定程序的线性地址。那么我们来试着找一找Windows通过中断来实现系统调用时候的流程!不会用Windbg的程序员不是好的狙击手。

首先用Windbg打开一个Calc.exe或者其他的普通应用程序,然后键入命令:

u ntdll!KiIntSystemCall

(P5)

如果有疑问为什么直接来到这个函数,现在先不忙解释,后面再说。可以看到这个函数中

int 2Eh

这一句汇编代码,我们知道了系统调用了2E号中断,从而进入了系统内核,知道了中断号下面我们要做的就是找到这个中断的服务程序,也就是RING3进入到RING0之后的第一条指令在哪里。下面就进入内核调试模式。通过

!pcr

查找IDT的线性地址

(P6)

找到了IDT的线性地址:0x8003f400,前面说过IDT中存放的是门描述符,每一个门描述符占用8个字节,所以我们要找的第2e个门描述符的地址应该为0x8003f400+2e*8,然后我们通过如下命令:

dq /c 1 8003f400+2e*8

查看内存内容:

(P7)

看到第一行的八个字节就是我们要找的2e号中断所对应的门描述符。根据门描述符的格式计算,得到这个门描述符中包含的

Offset【偏移】 = 0x8053e4a1

Selector = 0x0008

【偏移】已经找到了,下面就剩【段】了,【段】可以通过Selector【选择子】找到,这里需要说下【选择子】,选择子占用2个字节,格式如下

(P8)

选择子是真正可以存放在保护模式下的段寄存器中的结构,既然它被放在段寄存器中,那么通过它必然能够找到段的信息,保护模式下的段是通过段描述符来描述的,描述符的具体分类有三种:存储段描述符,系统段描述符,门描述符,这里只介绍存储段描述符,其他的请自行查阅保护模式相关资料。存储段描述符格式如下:

(P9)

可以看到存储段描述里包含了基址,界限和属性。对我们来说只要找到基址就行了。存储段描述符是保存在GDT中的,而选择子则包含了【描述符索引】即这个选择子所指向的描述符在GDT中的索引号,比如我们刚才计算得到的选择子Selector = 0x0008,其中索引号为1,就是说我们要找的段的段描述符在GDT中的第1项。由此可知,我们要找到【段】还需要找到段描述符,这个算法跟从IDT中找门描述符是一样的,先找到GDT的地址,从刚才的!pcr命令执行结果看到GDT = 0x8003f000,一个描述符占用8个字节,我们要找第一个描述符,计算得到描述符的地址为:0x8003f000+8*1,执行命令

dq /c 1 8003f000+1*8

得到结果:

(P10)

根据上述存储段描述符的格式计算得到该段的基地址为0x000000所以费劲千辛万苦找到了【段】=0x00000,现在【段】和【偏移】都找到了,那么我们要找的一个线性地址就找到了:

【段】:【偏移】 = 0x8053e4a1

反汇编看看这个地址的代码!

u 8053e4a1

得到结果:

(P11)

是这个函数nt!KiSystemService。为了验证我们没有计算错误,可以用Windbg直接显示2E号中断所对应的中断服务程序,执行命令:

!idt 2e

(P12)

可以看到通过脑力算出的结果与Windbg dump出来的结果是一样的,证明了我们的算法是没有问题的。

这样我们先总结一下使用中断实现系统调用时候RING3和RING3的函数接续:

NtDll!KiIntSystemCall > Nt!KiSystemService

使用快速系统调用机制

从Pentium II系列开始的CPU引入了快速系统调用这一特性,增加了两条指令SYSENTER和SYSEXIT(AMD CPU中的指令为SYSCALL和SYSRET)。这一机制的实现就是专门用于解决操作系统的系统调用的性能问题的,这种机制实现的控制转移比中断系统要快很多,因为转移的目标地址是存放在MSR寄存器内,而中断实现的系统调用目标地址存放在内存中的IDT中,所以能提高执行速度。

下面看一下在应用层是在哪里调用了这条指令的:

(P13)

可以看到在ntdll!KiFastSystemCall中有这条指令。

SYSENTER指令的工作机制是在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针:

1. IA32_SYSENTER_CS:一个32位值。低16位是0层的代码段的选择子。该值同时用来计算0层的堆栈的选择子。

2. IA32_SYSENTER_EIP:包含一个32位的0层的代码指针,指向第一条指令。

3. IA32_SYSENTER_ESP:包含一个32位的0层的堆栈指针。

MSR寄存器可以通过指令RDMSR/WRMSR来进行读写。寄存器地址如下表。这些地址值在以后的intel 64和IA32处理器中是固定不变的。

MSR

地址

IA32_SYSENTER_CS

174H

IA32_SYSENTER_ESP

175H

IA32_SYSENTER_EIP

176H

当执行SYSENTER,处理器会做下面的动作:

1.从IA32_SYSENTER_CS从取出段选择子加载到CS中。

2.从IA32_SYSENTER_EIP取出指令指针放到EIP中

3.将IA32_SYSENTER_CS的值加上8,将其结果加载到SS中。

4.从IA32_SYSENTER_ESP取出堆栈指针放到ESP寄存器中

5.切换到0层。

6.若EFLAGS中VM标志已被置,则清除VM标志。

7.开始执行选择的系统过程。

 

     又看到了【选择子】,了解了执行流程,下面还可以手工一步步计算出SYSENTER指令行执行CPU取出的第一条内核指令到底在哪里。有了上面的计算过程,这次计算就不需要写的很详细了,目标还是要找到【段】和【偏移】,很明显【偏移】放在MSR的176号地址中,Windbg用如下指令读取MSR:

      rdmsr 176

(P14)

【偏移】 = 0x8053e60

下面找【段】,依然是通过选择子来计算,选择子在MSR的174号地址中存放

     rdmsr 174

(P15)

【选择子】 = 0x0008,跟之前的选择子一样,这里就不用再去计算了,从刚才的结果中知道这个选择子指向的描述符所描述的内存基址是线性地址0x0000

所以我们要找的目标线性地址为【段】:【偏移】 = 0x8053e60

下面反汇编一下这个地址:

(P16)

看到是函数Nt!KiFastCallEntry。

总结一下使用快速系统调用机制的时候RING3和RING3的函数接续:

NtDll!KiFastSystemCall > Nt!KiFastCallEntry

完整的Windows API使用系统调用的过程

在XP系统之前,Windows只实现了一种系统调用的方式,那就是通过INT 2E号中断来实现的,所以从RING3到RING0之后的第一个函数一定是nt!KiSystemService,这个函数就是核心的系统调用分派函数,但是XP开始,Windows系统开始使用快速系统调用这一机制了,但是并没有失去对中断方式的支持,所以XP之后的系统都是两种实现方式共存的。具体做法我们可以用Windbg来继续探索,下面的工作就要在RING3来做了,因为我们要分析一个完整的Windows API使用系统调用的过程。在这之前需要先说一下有关Nt*和Zw*函数的问题。在应用层的Ntdll.dll中有大量的Nt开头的函数和Zw开头的函数,并且都是配对出现,他们所指向的地址都是相同的,所以他们的实现是完全相同的,只不过是别名问题。我们可以用Depdency Walker查看他们的入口地址发现都是相同的,也可以用Windbg反汇编看,关于这一点没什么好说的了,网上很多资料都有说。那我们就可以随便选择一个Nt开头的函数来进行分析,或者Zw开头的都是一样的。内核中也存在这样的函数,但是Nt开头的函数是真正的函数实现,Zw开头的函数是通过nt!KiSystemService函数最终调用的Nt开头的函数。我们选择NtOpenFile函数,需要说明的是这个函数是未导出的,我们在编程的时候使用的是kernel32.dll中导出的OpenFile或者OpenFile,最终是要进入NtOpenFile,从KERNEL32.dll到Ntdll.dll的过程省略。先反汇编NtOpenFile看看:

(P17)

看到在NtOpenFile函数中红色标注的代码,把一个内存中的一个dwrod取到了edx中,这个内存的符号为SharedUserData!SystemCallStub,然后跳转到edx中的值,所以edx中应该是一个函数的地址,我们看一下这个地址是什么

(P18)

看到这个地址中存放的地址是0x7c92e510,反汇编这个地址

(P19)

看到SharedUserData!SystemCallStub保存的是快速系统调用的入口函数的地址,其中通过sysenter进入内核,进入内核之后的过程上面已经介绍过了。

现在就可以总结一下一个Windows API如果使用了系统调用之后的流程了:

无论在何处直接调用了RING3的API并且需要使用系统调用,最终都会通过Ntdll.dll这个函数来进入内核,例如一个函数OpenXXX,无论其在哪个DLL实现,最终都要进入Ntdll.dll这个函数中的NtOpenXXX,在该函数中的内容就是读取一个用户共享数据区中的一个变量SytemCallStub,这个变量的值就是包含实现特权级变化的控制转移代码的函数入口,其实就是ntdll!KiFastSystemCall的地址,在这个函数中使用了SYSENTER指令,可以直接进入内核的nt!KiFastCallEntry,这个函数会调用nt!KiSystemService这个函数,这个函数的任务是查找SSDT中对应系统调用号的系统调用的实现地址nt!NtOpenXXX。

 

本来我是想做一个推测:在XP系统中通过中断方式实现系统调用的代码仍然存在,那么我们能不能根据需要选择我们希望使用的系统调用的实现方式呢?产生这个想法的原因是Windows并没有直接把实现特权级变化的控制转移代码的函数入口硬编码到每一个API中,而是使用了一个变量—SharedUserData!SytemCallStub中,既然这样实现肯定是为了可以方便切换这个函数的地址,在现在的XP以及更新的操作系统中,这个变量中存放的是ntdll!KiFastSystemCall,就是通过快速系统调用的方式来实现系统调用,那么如果我们修改这个变量的值,使其等于ntdll!KiIntSystemCall的话,是不是就可以改变整个系统的系统调用方式为中断方式呢?关于这个猜想还我还没有做下验证,打算过几天再验证。

 

nt!KiFastCallEntry函数地址的获取

下面说一下nt!KiFastCallEntry这个函数,无论通过何种系统调用的实现方式,都会调用这个函数来进行系统调用,所以这个函数也就成了一是十分重要的领地,就相当于兵家必争之地,无论是安全软件还是恶意软件。但是这个这个函数地址的获取还是有一点技巧的。

在这里先说一下XXX安全卫士的获取nt!KiFastCallEntry这个函数地址的方式,因为网上有人分析过它的实现方式,并且被大量转载,所以这里只是简单的提一下。我们已知的信息是,Windows的凡是涉及系统调用的API在内核中的调用顺序是:

快速系统调用:nt!KiFastCallEntry->Nt*

中断方式系统调用:nt!KiSystemService-> nt!KiFastCallEntry->Nt*

所以为了过滤系统调用,只要Hook住nt!KiFastCallEntry这个函数就一定能拦截所有的系统调用。XXX安全卫士的做法是先Hook住了一个nt!NtSetEvent函数,当进入这个函数的时候利用栈回溯,找到当前函数的返回地址,这个地址一定是在上层函数内的,得到这个地址就以后,就可以根据特征码搜索需要Inline Hook的目标地址了。借助nt!ZwCreateFile函数来动态跟踪分析,如下图:

(P20)

很多人说这种方法巧妙,通过栈回溯找到目标函数地址域内的一地址,然后特征码匹配,为何不直接找到函数入口然后直接特征码匹配呢?栈回溯的方法固然看起来很巧妙,可是如果内核中对nt!KiFastCallEntry函数启用了FPO(帧指针优化),那这种方法就完全被挫败了,所以这种方法并不能称为完美。

 

网上也有很多其他方法来获取nt!KiFastCallEntry函数入口地址,有暴力搜索的,也有通过MSR寄存器的。通过MSR寄存器读取的确是一种中规中矩的方法,但是看过不少代码,都是建立在一个假设上:nt!KiFastCallEntry的段基址一定是线性地址0x00开始。这些代码都直接忽略了对MSR 174号地址内的段选择子的处理,完整的做法应该利用本文中之前的方法计算段和偏移求得nt!KiFastCallEntry的入口地址,由于汇编语言处理这些计算相对方便,所以本人用汇编实现了一个得到nt!KiFastCallEntry函数地址的函数。代码如下:

 

[html]  view plain copy
  1. #define IA32_SYSENTER_CS 174H  
  2. #define IA32_SYSENTER_ESP 175H  
  3. #define IA32_SYSENTER_EIP 176H  
  4.   
  5. ULONG GetAddressOfKiFastCallEntry()  
  6. {  
  7.     ULONG dwAddress = 0;  
  8.     __asm  
  9.     {  
  10.         jmp func_main  
  11. vgdtr:  
  12.         _emit 0x00  
  13.         _emit 0x00  
  14.         _emit 0x00  
  15.         _emit 0x00  
  16.         _emit 0x00  
  17.         _emit 0x00  
  18.         _emit 0x00  
  19.         _emit 0x00  
  20.   
  21. func_main:  
  22.         push eax  
  23.         push ebx  
  24.         push ecx  
  25.         push edx  
  26.         mov ecx, 0x174  
  27.         rdmsr  
  28.         mov ebx, eax        //Selector offset  
  29.           
  30.         sgdt vgdtr  
  31.         mov edx, vgdtr  
  32.         add edx, 0x02  
  33.         mov eax, [edx]      //GDT base  
  34.         add ebx, eax        //Selector base  
  35.   
  36.         mov edx, ebx  
  37.         add edx, 0x07  
  38.         mov eax, [edx]  
  39.         shl eax, 24;  
  40.         mov edx, ebx  
  41.         add edx, 0x02  
  42.         mov ecx, [edx]  
  43.         and ecx, 0x00FFFFFF  
  44.         add eax, ecx        //Address CodeSegment  
  45.         mov ebx, eax  
  46.   
  47.         mov ecx, 0x176  
  48.         rdmsr  
  49.         add eax, ebx  
  50.   
  51.         mov dwAddress, eax  
  52.   
  53.         pop edx  
  54.         pop ecx  
  55.         pop ebx  
  56.         pop eax  
  57.     }  
  58.   
  59.     return dwAddress;  
  60. }   

 

测试用驱动代码及结果如下图:

(P21)

(P22)

这个结果和我们用Windbg查看得到的是一样的。

 

这篇文章写的有点长,而且知识有点砸碎希望各位看过之后能理解。

Voicebox本地部署:模型下载与离线模式实战指南 在本地语音处理场景中,模型下载失败和离线运行需求是开发者最常遇到的两大难题。理解语音工具的本地推理原理,关键在于掌握模型文件与程序逻辑的分离管理:模型独立下载,程序负责推理,输出留在本机。这种架构带来显著的技术价值——数据不出本地、不依赖公网、批量任务不中断。无论是语音识别转写、语音合成,还是集成到自动化脚本中,本地离线模式都能在隐私敏感或网络不稳定环境下稳定运行。对开发者而言,先解决模型文件的完整获取,再验证离线启动流程,就能绕过“无法下载模型”的常见坑。本文从环境准备、模型放置、服务启动到接口调用,提供 阅读详情

相关推荐

手把手教你搞定MT6701磁编码器的SSI通信与CRC-6校验(附避坑代码)

本文详细介绍了MT6701磁编码器的SSI通信与CRC-6校验的实现方法,包括硬件连接、时序配置、数据读取和专用CRC-6算法。通过提供避坑代码和常见问题解决方案,帮助开发者快速掌握磁编芯片的调试技巧,确保通信稳定可靠。

weixin_30872337的博客 220

KiFastCallEntry() 机制分析

本文转自:http://www.mouseos.com/windows/kernel/KiFastCallEntry.html 1. 概述 从 windows xp 和 windows 2003 开始使用了快速切入内核的方式提供系统服务例程的调用。 KiFastCallEntry() 的实现是直接使用汇编语言,C 语言不能直接表达某些操作。我从 windows 2003

无本之木 1386

Label Studio + SAM2分割半自动标注与yolo11训练

Label Studio + SAM2分割半自动标注与yolo11训练

schFallingCloud 1408

NtOpenFile

OBJECT_ATTRIBUTES vObjectAttributes; UNICODE_STRING ustrObjectName; WCHAR ptcsName[MAX_PATH] = { 0 }; //WCHAR ptcsNameRet[MAX_PATH] = L"\\??\\"; WCHAR ptcsNameRet[MAX_PATH] = L"\\??\\c:\\dl\\1...

如鹿渴慕泉水的专栏 1155

OLED的字模提取(保姆级)---基于PCtoLCD2013

做为一个刚刚开始接触编程不久的白菜,这个OLED想做一个信息显示,可是商家给我的例程里就是88,816两种字体的格式,我的屏幕是0.91寸的8*16的字体显示上感觉特别丢丢儿小,我就想整个大的,哎,只怪直接学习习惯不好,总是学一半,绕了好大一圈,才搞好,想写一篇博客,时刻提醒踏实学习,第一次写博客,小白一枚,勿喷。。 OLED屏幕驱动程序功能 我们对Markdown编辑器进行了一些功能拓展与语法支...

qq_44886611的博客 7782

什么是plm系统?-数字化转型网

当今世界,产品研发能力是企业在激烈的市场竞争中保持战略优势的核心竞争力之一。如何有效地缩短产品研发周期、改善产品服务的设计迭代流程、有效降低产品的研发成本,也是企业面临的主要问题之一。PLM(Product Lifecycle Management,产品生命周期管理)在优化产品研发的全管理流程、增强企业产品的市场竞争力方面具有关键的作用。

cxo17757154043的博客 883

浅析Windows系统调用——2种切换到内核模式的方法

首先总结2种切换到内核模式方法的各自流程,以 Windows API WriteFile() 调用为例:内存法(中断法):(用户模式)WriteFile() -> ntdll!NtWriteFile() -> ntdll!KiIntSystemCall() -> int 2Eh -> 查找 IDT (中断描述符表)的内存地址,偏移0x2E处 ->...

weixin_34391445的博客 1336

集成电路模拟版图入门-版图基础学习笔记(一)

集成电路设计模拟版图入门笔记,了解版图的定义、意义、工具、设计流程。认识版图及版图组成的两大部件,版图编辑器有哪些,电路图编辑器,了解工艺厂商等。

weixin_52955333的博客 2万+

获取内核函数的原始地址

本文以获取NtReadVirtualMemory讲述当该函数被HOOK后如何获取到正确的地址为例,解析获取原始内核函数地址的一种思路。思路虽然比较笨拙,但是也不失为一种解决办法。    图片:1.bmp  上图中NtReadVirtualMemory函数被hook了,如果我们从SSDT表获取函数的地址,则获取到的函数地址为0XA1277AFE而不是原始的函数地址0x805884F7,并且

sgzwiz的专栏 3305

【个人成长笔记】在Ubuntu中安装RTL8188GU USB无线网卡驱动(Driver for Linux RTL8188GU)

这篇笔记提供了在Ubuntu系统中安装RTL8188GU无线网卡驱动的完整指南。主要内容包括:驱动程序的官方来源(Github链接)、详细安装步骤(通过git下载、编译安装等命令),以及将设备转换为USB网卡模式的关键指令。特别提醒每次开机都需要执行模式转换命令,因为设备默认会以U盘模式启动。文章以简洁的技术文档形式呈现,适合Linux用户快速查阅和操作。

yuhuasheng1997的博客 1827

基于STM32设计的老人防摔倒报警设备(OneNet)_65

本文设计了一种基于STM32单片机的智能老人防摔倒报警设备。该系统结合MPU6050陀螺仪传感器实时监测老人的姿态变化,检测摔倒事件;通过SIM800C通信模块发送短信通知紧急联系人,并将GPS定位信息上传至云端平台,确保家属能够及时了解老人的准确位置。

1万+

Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取 .

为什么要写这篇文章 1.      因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。 2.      碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Hook,主要就是Hook到这个函数 3.      刚刚做完毕业设计,对

求索 971

大模型——Ollama简明教程

在这篇文章中,我们将了解如何使用 Ollama、如何在 Ollama 中创建自己的模型 以及如何使用 Ollama 构建聊天机器人。这是深入研究 Ollama 的第一部分,以及我所学到的有关本地 LLM 的知识以及如何将它们用于基于推理的应用程序。在这篇文章中,你将了解——

1697

Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取 + 一个hook的实现

为什么要写这篇文章 1.      因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。 2.      碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Hook,主要就是Hook到这个函数 3.      刚刚做完毕业设计,对

stonesharp的专栏 3145

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

[转载]Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

原文地址:点击打开链接 为什么要写这篇文章 1.因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。 2.碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Ho...

angbagangzhe065140的博客 129

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

windows驱动读取gdtr_Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

为什么要写这篇文章1.因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。2.碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Hook,主要就是Hook到这个函数3.刚刚做完毕业设计,对使用中断来实...

weixin_31091881的博客 382

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

KiFastCallEntry系统调用拦截与内核重载技术深度分析

基于内核重载和内联挂钩的高级拦截技术。该技术通过在内存中手动加载一份纯净的内核镜像,构建伪造的系统服务描述符表并修改 KiFastCallEntry 的执行流,实现了对系统调用的隐蔽监控与过滤

2401_86176947的博客 686

hook KiFastCallEntry

<br /> <br />//从hookport.sys学到的hook方法,主要是KiFastCallEntry地址的获取及hook的地方思路 //DRIVER.CPP #include "Driver.h" #define MAX_POOL_EXA 0x1000 /************************************************************************ 全局结构变量 *********************

爱杀之爪的矩阵 2643

[转](49)逆向分析 KiSystemService / KiFastCallEntry 调用内核函数部分

一、回顾 前两篇博客,我逆向分析了 KiSystemService 和 KiFastCallEntry 填充_KTRAP_FRAME 结构体的代码,二者大同小异,主要的区别是 sysenter 只改了eip,cs,ss,虽然esp也改了,但是windows不使用,而是从TSS里取esp0;另外sysenter并没有像中断门那样压栈,所以3环的 ss, esp, eflags, cs,eip都要在函数里依次保存到 _KTRAP_FRAME 。 这次课后作业是逆向 KiSystemServ...

weixin_41875267的博客 498

KiFastCallEntry() 函数地址的获取

Windows API和系统调用的关系 肯定会有人说Windows API就是系统调用,系统调用就是Windwos API,是这样的么?负责任的说:不是这样的! 先从广义上来说,Windows API是对于整个Windows操作系统自身的程序代码之外的应用程序来说的,而系统调用是Windows内核对于非内核程序代码之外的Windows系统程序代码来说的。也就是说系统调用要比Window

it技术学习 1652
上一篇: 向正在运行的Linux应用程序注入代码
下一篇: 继续谈下调用约定
linuxheik
博客等级 码龄15年 865粉丝 135原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值