API函数的调用过程(系统服务表)

前言:作为API函数的调用过程(系统服务表)的学习笔记

前面的一篇笔记中分析了进入0环之后的保存现场,然后这里继续来学习如何调用0环的函数的分析过程

其中还要分析如下两个点

1、如何根据系统服务号(eax中存储)找到要执行的内核函数

2、调用时参数是存储到3环的堆栈,如何传递给内核函数

系统服务表SystemServiceTable

系统服务表是如下图所示,其中分为两个两张系统服务表,一个是指向Ntoskrl.exe相关的内核函数,一个是指向Win32k.sys相关的内核函数

SystemServiceTable系统服务表的位置

通过_KTHREAD结构体能够找到相关的系统服务表的位置

dt _KTHREAD

0环如何判断要调用的函数在哪个表

首先要知道的进入0环之前,eax会保存要调用0环函数的服务号,edx保存调用的地址,如下图所示

然后在寻找要调用的函数在系统服务表中就需要用到三环传入的eax的服务号,其中要用到的就是低13位,在第13位(下标12位)则是通过0或者1来判断要找的是哪个系统服务表

0环如何找到要执行的函数与参数个数

eax中的低12位用在寻找相关要执行的函数和参数的个数,如下图所示

细节分析学习

比如ReadVirtualMemory传入的eax值为0x0BA,拆分结果为 -> 0000 1011 1010

右移8位的话此时的值就是 -> 0000,再接着跟0x30与运算

00 0000 & 11 0000 结果就是0

如果为0的话那么找到的系统服务表就是跟ntoskrnl.exe相关的

01 0000 & 11 0000 结果就是 0x10

而如果为1的话,那么的系统服务表就是跟gdi32.dll相关的

为什么这么运算呢?其实这个0x10很巧妙的,你可以看下系统服务表的大小正好是0x10,所以说如果是跟gdi32.dll相关的,那么整好跳过0x10个字节,正好就到了第二张系统服务表的位置了

寻找过程

.text:00406932 loc_406932: ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00406932 ; _KiSystemService+71↑j
.text:00406932 mov edi, eax ; edi = 当前要调用的内核函数的服务号
.text:00406934 shr edi, 8 ; edi = 要调用的函数服务号 >> 8
.text:00406937 and edi, 30h ; edi &= 0x30
.text:0040693A mov ecx, edi ; 上面运算完的结果赋值给ecx
.text:0040693C add edi, [esi+0E0h] ; 获得对应的系统服务表的基址,_KTHREAD+E0
.text:00406942 mov ebx, eax ; ebx = 当前要调用的内核函数的服务号
.text:00406944 and eax, 0FFFh ; eax &= 0xfff
.text:00406949 cmp eax, [edi+8] ; 判断当前要调用的服务号的值是否超过了当前指定系统服务表中的serviceLimit的数量
.text:0040694C jnb _KiBBTUnexpectedRange
.text:00406952 cmp ecx, 10h ; 判断是第一张系统服务表,还是第二张系统服务表
.text:00406955 jnz short loc_406972 ; 第二张不跳,第一张跳
.text:00406957 mov ecx, large fs:18h
.text:0040695E xor ebx, ebx
.text:00406960
.text:00406960 ; __stdcall KiSystemServiceAccessTeb()
.text:00406960 _KiSystemServiceAccessTeb@0: ; DATA XREF: KiPreprocessAccessViolation(x,x,x)+3D↓o
.text:00406960 or ebx, [ecx+0F70h]
.text:00406966 jz short loc_406972
.text:00406968 push edx
.text:00406969 push eax
.text:0040696A call ds:_KeGdiFlushUserBatch
.text:00406970 pop eax
.text:00406971 pop edx
.text:00406972
.text:00406972 loc_406972: ; CODE XREF: _KiSystemService+184↑j
.text:00406972 ; _KiSystemService+195↑j
.text:00406972 inc large dword ptr fs:638h ; 找到_KPRCB的KeSystemCalls
.text:00406979 mov esi, edx ; esi保存三环的参数地址
.text:0040697B mov ebx, [edi+0Ch] ; ebx保存系统服务表中的ArgmentTable字段
.text:0040697E xor ecx, ecx
.text:00406980 mov cl, [eax+ebx] ; 函数的服务号加上ArgmentTable的基址就相当于找到对应函数的参数个数
.text:00406983 mov edi, [edi] ; edi保存系统服务表中的ServiceTable字段
.text:00406985 mov ebx, [edi+eax*4] ; ServiceTable+4*函数服务号,相当于找到函数地址表中对应的函数地址
.text:00406988 sub esp, ecx ; ESP提升栈定,大小为对应的参数个数大小,这里的ecx是要执行的参数的字节大小
.text:0040698A shr ecx, 2 ; 参数个数/4,计算如果一次拷贝4字节的话,那么要拷贝的次数
.text:0040698D mov edi, esp ; edi指向函数参数的位置
.text:0040698F test byte ptr [ebp+72h], 2
.text:00406993 jnz short loc_40699B
.text:00406995 test byte ptr [ebp+6Ch], 1
.text:00406999 jz short _KiSystemServiceCopyArguments@0 ; KiSystemServiceCopyArguments()
.text:0040699B
.text:0040699B loc_40699B: ; CODE XREF: _KiSystemService+1C2↑j
.text:0040699B cmp esi, ds:_MmUserProbeAddress
.text:004069A1 jnb loc_406B4F
.text:004069A7
.text:004069A7 ; __stdcall KiSystemServiceCopyArguments()
.text:004069A7 _KiSystemServiceCopyArguments@0: ; CODE XREF: _KiSystemService+1C8↑j
.text:004069A7 ; DATA XREF: KiPreprocessAccessViolation(x,x,x):loc_4628DF↓o
.text:004069A7 rep movsd ; 将esi中保存的三环的函数参数地址依次拷贝到edi中(esi中准备保存的是0环的函数参数地址)
.text:004069A9 call ebx ; 调用函数地址表中对应的函数
posted @   zpchcbd  阅读(408)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2020-03-04 MemoryModule(没写)
点击右上角即可分享
微信分享提示