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 ; 调用函数地址表中对应的函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2020-03-04 MemoryModule(没写)