系统调用
系统调用分为两种,一种是新款cpu提供的指令(systemcall )称之为快速调用 ,另一种是通过int2e中断提权调用(目前使用很少为了兼容老cpu).
INT2E 调用
int2e走ntoskrnl.exe 中的KxUnexpectedInterrupt0函数
但是我逆了发现 如果你的cpu符合快速调用环境,你的int2E就不会执行,我尝试了用windbg下了断点但是断不下来我强行再内部下断经常会被编号为(d1)的时钟中断断下,但是跟进去发现了有个地方判断在KPRCB+3140h地方有个大小为256个指针函数(中断表)[mov rsi, [rsi+rax*8+3140h]],rax就是中断索引号 rsi是_KPRCB,(d1)是有值的而(2e)是0.
后面有一大段流程就没有继续逆了.
快速调用
32位系统走的是sysenter/sysexit指令
sysenter
IF in IA-32e mode
THEN
RSP ← IA32_SYSENTER_ESP;
RIP ← IA32_SYSENTER_EIP;
ELSE
ESP ← IA32_SYSENTER_ESP[31:0];
EIP ← IA32_SYSENTER_EIP[31:0];
FI;
CS.Selector ← IA32_SYSENTER_CS[15:0] AND FFFCH;
(* Operating system provides CS; RPL forced to 0 *)
SS.Selector ← CS.Selector + 8;
sysexit
IF operand size is 64-bit
THEN (* Return to 64-bit mode *)
RSP ← RCX;
RIP ← RDX;
ELSE (* Return to protected mode or compatibility mode *)
RSP ← ECX;
RIP ← EDX;
FI;
IF operand size is 64-bit (* Operating system provides CS; RPL forced to 3 *)
THEN CS.Selector ← IA32_SYSENTER_CS[15:0] + 32;
ELSE CS.Selector ← IA32_SYSENTER_CS[15:0] + 16;//这里加了16
FI;
CS.Selector ← CS.Selector OR 3; (* RPL forced to 3 *)
SS.Selector ← CS.Selector + 8;//上面有加16
测试
Syscall 64位系统
syscall通过从IA32_LSTAR(MSR 地址:C0000081H) MSR加载RIP(syscall的下一条指令地址会保存到RCX).RFLAGS保存到R11寄存器,然后用IA32_FMASK MSR(MSR 地址:C0000084H)屏蔽RFLAGS的值,更具体的说是清除在IA32_FMASK MSR中设置的每一位.
syscall会从IA32_STAR[47:32]中加载CS和SS.
syscall不会保存堆栈指针(RSP) window10 把rsp存储到_KPCR结构体中
RCX ← RIP;保存syscall下一条指令地址到RCX
RIP ← IA32_LSTAR;RIP=IA32_LSTAR
R11 ← RFLAGS;R11=RFLAGS
RFLAGS ← RFLAGS AND NOT(IA32_FMASK);//根据IA32_FMASK屏蔽RFLAGS的相关位
CS.Selector ← IA32_STAR[47:32] AND FFFCH;确保CS的RPL为0
SS.Selector ← IA32_STAR[47:32] + 8;
sysret
RIP=RCX
RFLAGS=R11
返回32位代码:CS=CS_Selector|3 SS=(CS_Selector+8)|3
返回64位代码:CS=(CS_Selector+16)|3 SS=(CS_Selector+8)|3
返回时不会修改(ESP or RSP)
IF (operand size is 64-bit)//如果是64位
{
THEN (* Return to 64-Bit Mode *)
RIP ← RCX;
}
ELSE
{
(* Return to Compatibility Mode *)
RIP ← ECX;
}
RFLAGS ← (R11 & 3C7FD7H) | 2; (* Clear RF, VM, reserved bits; set bit 2 *)
IF (operand size is 64-bit)
{
THEN CS.Selector ← IA32_STAR[63:48]+16;
}
ELSE
{
CS.Selector ← IA32_STAR[63:48];
}
CS.Selector ← CS.Selector OR 3; (* RPL forced to 3 *)
SS.Selector ← (IA32_STAR[63:48]+8) OR 3;
Syscall win10x64 下执行流程
系统调用主要是靠维护Trap_Farmer结构体.
关键部分代码
快速调用 由于指令不会把cs ss压栈 由函数KiSystemCall64 设置的
初始化Trap_Farmer结构体
获取服务号,并判断找哪张表 如果服务号大于0x1000找shadow那张表
选择哪张ssdt表 分为3中一种是带图形 一种是不带图形 还有一种过滤过的表
通过ssdt表基址加上 ssdt表内的偏移表里的偏移右移4位(因为低4位是栈里的参数超过4个参数的会放到栈里) 公式 ([偏移表+服务号*4]>>4)+函数表首地址==函数地址
拷贝函数所需要的参数 末尾sub r11,rax 是因为刚好copy一个参数字节码是8
拷贝完跳转到内核函数
执行完接下来有一些了检查这里就先跳过
返回地址放到RCX R11放的是eflag
win10 x64 SSDT结构介绍
fffff806`730dbf90 是函数表首地址 函数表表项 ([偏移表+服务号*4]>>4)+函数表首地址==函数地址 右移4位代表栈上参数数量.
00000000`000001d7 是函数表函数数量
fffff806`730dc6f0 是函数表末尾地址
typedef struct _KeServiceDescriptorTableShadow
{
PVOID64 FuncTable;
DWORD64 Resave;
DWORD64 FuncNumb;
DWORD64 FuncTableOverAdress;
}KeServiceDescriptorTableShadow, * PKeServiceDescriptorTableShadow;