首页
社区
课程
招聘
[原创]SSDT x64win7sp1内核系统调用分析
发表于: 2019-5-11 19:11 7838

[原创]SSDT x64win7sp1内核系统调用分析

2019-5-11 19:11
7838
大家好我是 火哥,交流QQ群:1026716399(新群),希望多支持哈
我用IDA 来看代码

在syscall进入内核后 第一句话就会调用 swapgs指令 来替换GS段的base(这是保护模式段的知识,不懂请搜索看雪段的相关文章)
此时的GS段的内容指向了一个KPCR结构,结构比较长,我就不在文章中贴出来了。可以用windbg查看 dt _KPCR
然后把R3的RSP寄存器 也就是堆栈的值 保存起来,并且替换成内核的堆栈
 大家可以看到 下面连续好几个push,这是在保存现场,此现场是用一个 KTrap_frame的结构来维护的
kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
   +0x000 P1Home           : Uint8B
   +0x008 P2Home           : Uint8B
   +0x010 P3Home           : Uint8B
   +0x018 P4Home           : Uint8B
   +0x020 P5               : Uint8B
   +0x028 PreviousMode     : Char
   +0x029 PreviousIrql     : UChar
   +0x02a FaultIndicator   : UChar
   +0x02b ExceptionActive  : UChar
   +0x02c MxCsr            : Uint4B
   +0x030 Rax              : Uint8B
   +0x038 Rcx              : Uint8B
   +0x040 Rdx              : Uint8B
   +0x048 R8               : Uint8B
   +0x050 R9               : Uint8B
   +0x058 R10              : Uint8B
   +0x060 R11              : Uint8B
   +0x068 GsBase           : Uint8B
   +0x068 GsSwap           : Uint8B
   +0x070 Xmm0             : _M128A
   +0x080 Xmm1             : _M128A
   +0x090 Xmm2             : _M128A
   +0x0a0 Xmm3             : _M128A
   +0x0b0 Xmm4             : _M128A
   +0x0c0 Xmm5             : _M128A
   +0x0d0 FaultAddress     : Uint8B
   +0x0d0 ContextRecord    : Uint8B
   +0x0d0 TimeStampCKCL    : Uint8B
   +0x0d8 Dr0              : Uint8B
   +0x0e0 Dr1              : Uint8B
   +0x0e8 Dr2              : Uint8B
   +0x0f0 Dr3              : Uint8B
   +0x0f8 Dr6              : Uint8B
   +0x100 Dr7              : Uint8B
   +0x108 DebugControl     : Uint8B
   +0x110 LastBranchToRip  : Uint8B
   +0x118 LastBranchFromRip : Uint8B
   +0x120 LastExceptionToRip : Uint8B
   +0x128 LastExceptionFromRip : Uint8B
   +0x108 LastBranchControl : Uint8B
   +0x110 LastBranchMSR    : Uint4B
   +0x130 SegDs            : Uint2B
   +0x132 SegEs            : Uint2B
   +0x134 SegFs            : Uint2B
   +0x136 SegGs            : Uint2B
   +0x138 TrapFrame        : Uint8B
   +0x140 Rbx              : Uint8B
   +0x148 Rdi              : Uint8B
   +0x150 Rsi              : Uint8B
   +0x158 Rbp              : Uint8B
   +0x160 ErrorCode        : Uint8B
   +0x160 ExceptionFrame   : Uint8B
   +0x160 TimeStampKlog    : Uint8B
   +0x168 Rip              : Uint8B
   +0x170 SegCs            : Uint2B
   +0x172 Fill0            : UChar
   +0x173 Logging          : UChar
   +0x174 Fill1            : [2] Uint2B
   +0x178 EFlags           : Uint4B
   +0x17c Fill2            : Uint4B
   +0x180 Rsp              : Uint8B
   +0x188 SegSs            : Uint2B
   +0x18a Fill3            : Uint2B
   +0x18c CodePatchCycle   : Int4B

大家可以看到 第一个值 是push 0x2B 那么也就是 在0x188的位置 压入,当前Rsp指向了0x188 这是线程堆栈被分配的时候 就指向在申请堆栈空间的-4位置
然后连续几个PUSH 也就是在压入到这个结构中,push rcx是值得注意的。调用syscall会把 调用指令的这个函数的下一行地址 保存在RCX 所以 rcx等于返回地址。
然后Sub rsp,158 瞬间 就到了这个结构的起始地址,这个结构就是这样被创建出来了



值得注意的是 rbp保存是这个结构的腰,到时候会用rbp来计算这个结构的


这一段内容主要是判断 当前是否处于调试,是都的话 要保存当前调试的寄存器以及状态 我们默认不是调试,  用 jz loc_14007f750跳转到下一个逻辑处



在这里 首先会保存 rcx 也就是第一个参数,然后还有函数的编号,也就是 eax(这里没法说清楚,rcx为什么是第一个参数,eax为什么是函数编号,要想弄明白得去分析分析R3 参数 传递,我这里就不做阐述,如果有需要,我下次在发帖……………………)

然后RSP 是什么? 是不是我们的trap_frame结构啊,把他保存到当前线程中,rbx为什么是当前线程?注意我的第一个图,最后一句,GS:188就是当前线程了。
想弄清楚里面所有的东西,需要有积累,可以加我的群,大家一起交流。

下面就是我们的重点了。
首先把函数编号,存到edi 然后做运算,首先逻辑右移7位,然后逻辑与0x20 为什么是0x20? 因为我们的SSDT表 是一个结构数组,这个数组在x64下的每个元素是0x20个字节,所以在这里 是在求 当前 函数 在那个结构中,也就是计算结构的偏移
也就是说现在 edi 存放是结构的偏移,eax逻辑与上0xFFF,为什么是0xFFF? 因为在windows中 函数编号 大于0x1000就代表 是GUI SSDT的寻找,所以0xfff往上的编号 都是额外的作用,不能作用于函数的索引上。计算过后 eax中才是真正的函数编号 也可以认为是索引,我们在来看下一段


首先把SSDT和SSDT_Shadow分别存放到 r10,r11寄存中,然后判断线程是否是GUI线程,如果是GUI线程,那么就要在 SSDT_Shadow中查找,否则在SSDT中查找,



取结构中的函数最大个数 与 当前的函数编号去比较,如果大于(这边还会有一些条件,大家感兴趣的话自己去分析) 这里就会报错了



先获得函数表,在获得函数偏移(我这里为什么说是偏移?继续)
把R11存到RAX,备份一份 等下要用
然后把r11算术右移 4位(什么是算术右移?请百度)
R10我们都分析过了。他就是函数表,用函数表+函数偏移 等于真正的函数,此时的R10就是函数了
从上面我们可以得出算法

ULONG funcOffset = SSDT[结构索引][函数索引];
funcOffset = funcOffset & 0x80000000 ?   funcOffset >> 4 :   (funcOffset >> 4) | 0xF0000000;
ULONG64 funcAddress = SSDT[结构索引].函数表 +  funcOffset;


判断一下 是第一个结构还是第二个结构,如果是第一个结构 就跳走了,如果是第二个结构 就代表是GUI结构,那么要做相对应的刷新,统计 等操作



做完之后也会调用到这里来

我们之前说 eax要备份过,也就是函数的原始偏移,那么大家看第一句话, 就是拿原始偏移的 &0xf  取低4位
如果获取到值为空 就直接调用函数,否则  就往下走
在把低4位 左移3位,  这些是什么意思勒, 其实就是求 当前这个函数的参数,我们都知道 x64下都是 fastcall调用约定,之后4个寄存器 rcx,rdx,r8,r9用来保存参数,那么如果参数大于了4个 都是放到堆栈中,其实这里就是 求 除了保存在4个寄存器中额外的参数,要把这些参数从R3的堆栈 copy到R0的堆栈中,相信我这么一说大家就明白了,那么这下面几句就是 为了 复制参数做的操作,另外还判断了 是R0调用 还是R3调用



这里大家可以自行的分析下上面的代码 就会明白的我说的了
最后这一句就是call R10了。这就是一个调用过程。
我在最后 没有和大家说 是如何返回到R3的。我不想篇幅太长,如果网友们很热心,或者觉得火哥分析的还不错,都支持的话。我在出下一章吧。
以上内容是原创分析,目前分析有我这么详细的文章没有看到。希望大家来朵鲜花

最后在啰嗦下哈。
火哥,交流QQ群:1026716399(新群),希望多支持哈




[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 3
支持
分享
最新回复 (7)
雪    币: 711
活跃值: (253)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
前排打酱油
2019-5-11 19:35
0
雪    币: 12848
活跃值: (9108)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
3
最好加上KiSystemCall64Shadow的分析
2019-5-11 19:48
0
雪    币: 178
活跃值: (1238)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
hzqst 最好加上KiSystemCall64Shadow的分析
下次我在发一贴 
2019-5-11 20:09
0
雪    币: 634
活跃值: (1149)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
我从开成人用品店铺,到做内核经历一波三折
2019-5-11 21:00
0
雪    币: 2055
活跃值: (486)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
我从开成人用品店铺,到做内核经历一波三折
2019-5-12 13:17
0
雪    币: 1598
活跃值: (3165)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
hackflame 下次我在发一贴
这是那个山总?
2019-5-12 18:44
0
雪    币: 178
活跃值: (1238)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
if_816554 这是那个山总?
你是不是听山总故事长大的
2019-5-12 20:16
0
游客
登录 | 注册 方可回帖
返回
//