今天开始我们来分析系统api进0环的过程
先写一个应用程序然后我们调用一个readprocessmemory的系统api
注意编译为release版x64环境下的应用程序
首先使用x64dbg来调试这个进程寻找到readprocessmemory的地方看一下
可以看到他是调用了ZwReadVirtualMemory,我们鼠标选中后会看到是ntdll中的导出函数,我们跟进去看一下
可以看到ZwReadVirtualMemory的代码很短只有几行,先是传入3F给eax然后他会检查0x7ffe0308的位置是否为1然后调用syscall指令否则执行int 2e,如果大家看过winxp内核的话就会觉得很熟悉,因为xp中也差不多是这样的流程只不过是直接调用0x7ffe0300的位置然后判断怎么执行而且执行sysenter和int 2e的调用没有放在同一个函数里而已
syscall让我想起了sysenter指令那么我们可以推测这俩指令是不是差不多的作用
而且不知道大家有没有学过x86的内核,在x86里也是使用了0x7ffe0000这个位置来作为一个叫做KUSER_SHARED_DATA的数据结构共享给0环和3环一起用我们可不可以认为Windows为了保持兼容所以这个位置还是跟之前一样的作用呢
现在我们发现了两个要去验证的问题
首先来验证一下0x7ffe0000的位置
通过windbg可以看到这个结构体仍旧在使用,而且308的位置 是一个叫做SystemCall 的指针
我们在回顾刚才的代码思考一下很明显x64里没有像xp一样直接跳到0x7ffe0308的位置去执行而是判断了一下这个位置是否为1,然后根据这个位置判断cpu是否支持syscall指令,然后通过int 2e进0环
3环进0环的3环部分流程大体明白了我们再看一下syscall是干嘛的,在白皮书的5.8.8章有详细介绍
与sysenter/sysexit类似,syscall和sysret是一对配套指令, 是快速在R3和R0之间转换的指令。
总结一下syscall主要会做下面几个事情
页表隔离机制是为了解决cpu的熔断bug而在软件层面做出的保护机制,他的主要动作就是在应用层和内核层使用的cr3变为两个不同的cr3,在xp的机制是一个进程一个cr3而现在是一个进程两个cr3分别给应用层用和给内核用,也就是在应用进内核的时候会进行cr3的切换因为现在的内存页面映射不在是像xp一样将高2G完整的映射到所有的进程中,下面贴出一个图来说明
如上图所示,在内核使用的cr3中会将内核所有的内容映射进去并将应用数据改为不可执行的属性映射进来
在应用层只会映射内核文件中的KVASCODE段的内容,这部分内容主是跳板代码,在这部分代码中切换cr3保存现场等,切换完cr3之后就进入到了真正的内核cr3所映射的整体中然后在jmp这类的跳转到真正的内核代码中去执行然后在返回回来切换cr3之后ret
这样做就可以隔离掉内核和应用层防止借助于cpu的熔断直接读取内核数据
下面我们找一个中断进0环看一下代码是怎么样的
我们在windbg中看一下int3中断的代码
ida的注释中我加了详细的解释,就不再文章中赘述了
现在我们了解了kpti机制和syscall的动作,下面我们就可以真正的去看系统api调用的代码了
之前我们知道syscall进0环时候的cs是存在IA32_STAR这个位置的
我们到windbg里看一下msr寄存器的值
fffff803`7520d400这个地址我们反汇编一下可以发现KiSystemCall64这个函数就是我们进0环时候的地址
那下面我们看一下先来看一下KiSystemCall64Shadow的代码是什么
ntoskrnl - 单处理器,不支持PAE
ntkrnlpa - 单处理器,支持PAE
ntkrnlmp - 多处理器,不支持PAE
ntkrpamp - 多处理器,支持PAE
上面是内核文件名字的区别大家根据自己的环境去找内核文件进行逆向分析,关于符号的话可以设置内核符号表地址或者直接load pdb文件都可以
然后alt+t全局搜索KiSystemCall64就可以找到跳板函数和真正的函数了
KiSystemCall64Shadow:
进来之后就看到切换gs然后保存现场到代码
然后在往下看就会跳到KiSystemServiceUser这个函数里,注意到这个函数的时候已经不是KVASCODE段了,而是跳到了.text段,说明已经进入到了真正的内核中而不是跳板代码
我们再来看一下这个函数
下面的过程就跟xp系统里的流程差不多了,判断是不是GDI线程如果是的话用Shdow表并且要转换线程位GDI线程,这部分我们不看我们现在直接看调用函数的位置
在中间过程里KiSystemServiceCopyStart这边函数负责复制参数,有兴趣的可以看一下
大家可以再看一下KiSystemCall64函数会发现这两个函数长得差不多而且也是走的KiSystemServiceUser这个函数,我这边就不带大家看了
可以发现系统api的过程大致如下:
实验内容:驱动实现遍历ssdt表并打印出来,目前我们还没办法hookssdt表因为Windows系统有pg机制
(关于ssdt表的结构等知识大家到网上搜一下就有了,跟xp时候基本一样)
驱动代码我过两天会贴出来,国庆结束了这几天会比较忙
另外说一下我其实本来是想着在页机制的研究那章写页表隔离机制和如何找自映射的,不过后来在做这套教程的时候又觉得不太合适,我也是一边找自己之前自学时候的笔记一边回顾去整理出来可能发出来的文章并没有跟之前说的文章顺序一致不过最后所有的内容肯定都会有的
这是我提前整理出的目录结构,现在在一点一点填充内容,后面会慢慢发出来的
DWORD32 testVal
=
111
;
int
main() {
HANDLE h
=
GetCurrentProcess();
DWORD32 t;
size_t
len
;
ReadProcessMemory(h, &testVal, &t,
4
, &
len
);
printf(
"%d\r\n"
, t);
return
0
;
}
DWORD32 testVal
=
111
;
int
main() {
HANDLE h
=
GetCurrentProcess();
DWORD32 t;
size_t
len
;
ReadProcessMemory(h, &testVal, &t,
4
, &
len
);
printf(
"%d\r\n"
, t);
return
0
;
}
nt!DbgBreakPointWithStatus:
fffff801`
476036b0
cc
int
3
0
: kd> dt _KUSER_SHARED_DATA
ntdll!_KUSER_SHARED_DATA
+
0x000
TickCountLowDeprecated : Uint4B
+
0x004
TickCountMultiplier : Uint4B
+
0x008
InterruptTime : _KSYSTEM_TIME
+
0x014
SystemTime : _KSYSTEM_TIME
+
0x020
TimeZoneBias : _KSYSTEM_TIME
+
0x02c
ImageNumberLow : Uint2B
+
0x02e
ImageNumberHigh : Uint2B
+
0x030
NtSystemRoot : [
260
] Wchar
+
0x238
MaxStackTraceDepth : Uint4B
+
0x23c
CryptoExponent : Uint4B
+
0x240
TimeZoneId : Uint4B
+
0x244
LargePageMinimum : Uint4B
+
0x248
AitSamplingValue : Uint4B
+
0x24c
AppCompatFlag : Uint4B
+
0x250
RNGSeedVersion : Uint8B
+
0x258
GlobalValidationRunlevel : Uint4B
+
0x25c
TimeZoneBiasStamp : Int4B
+
0x260
NtBuildNumber : Uint4B
+
0x264
NtProductType : _NT_PRODUCT_TYPE
+
0x268
ProductTypeIsValid : UChar
+
0x269
Reserved0 : [
1
] UChar
+
0x26a
NativeProcessorArchitecture : Uint2B
+
0x26c
NtMajorVersion : Uint4B
+
0x270
NtMinorVersion : Uint4B
+
0x274
ProcessorFeatures : [
64
] UChar
+
0x2b4
Reserved1 : Uint4B
+
0x2b8
Reserved3 : Uint4B
+
0x2bc
TimeSlip : Uint4B
+
0x2c0
AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+
0x2c4
BootId : Uint4B
+
0x2c8
SystemExpirationDate : _LARGE_INTEGER
+
0x2d0
SuiteMask : Uint4B
+
0x2d4
KdDebuggerEnabled : UChar
+
0x2d5
MitigationPolicies : UChar
+
0x2d5
NXSupportPolicy : Pos
0
,
2
Bits
+
0x2d5
SEHValidationPolicy : Pos
2
,
2
Bits
+
0x2d5
CurDirDevicesSkippedForDlls : Pos
4
,
2
Bits
+
0x2d5
Reserved : Pos
6
,
2
Bits
+
0x2d6
CyclesPerYield : Uint2B
+
0x2d8
ActiveConsoleId : Uint4B
+
0x2dc
DismountCount : Uint4B
+
0x2e0
ComPlusPackage : Uint4B
+
0x2e4
LastSystemRITEventTickCount : Uint4B
+
0x2e8
NumberOfPhysicalPages : Uint4B
+
0x2ec
SafeBootMode : UChar
+
0x2ed
VirtualizationFlags : UChar
+
0x2ee
Reserved12 : [
2
] UChar
+
0x2f0
SharedDataFlags : Uint4B
+
0x2f0
DbgErrorPortPresent : Pos
0
,
1
Bit
+
0x2f0
DbgElevationEnabled : Pos
1
,
1
Bit
+
0x2f0
DbgVirtEnabled : Pos
2
,
1
Bit
+
0x2f0
DbgInstallerDetectEnabled : Pos
3
,
1
Bit
+
0x2f0
DbgLkgEnabled : Pos
4
,
1
Bit
+
0x2f0
DbgDynProcessorEnabled : Pos
5
,
1
Bit
+
0x2f0
DbgConsoleBrokerEnabled : Pos
6
,
1
Bit
+
0x2f0
DbgSecureBootEnabled : Pos
7
,
1
Bit
+
0x2f0
DbgMultiSessionSku : Pos
8
,
1
Bit
+
0x2f0
DbgMultiUsersInSessionSku : Pos
9
,
1
Bit
+
0x2f0
DbgStateSeparationEnabled : Pos
10
,
1
Bit
+
0x2f0
SpareBits : Pos
11
,
21
Bits
+
0x2f4
DataFlagsPad : [
1
] Uint4B
+
0x2f8
TestRetInstruction : Uint8B
+
0x300
QpcFrequency : Int8B
+
0x308
SystemCall : Uint4B
+
0x30c
Reserved2 : Uint4B
+
0x310
SystemCallPad : [
2
] Uint8B
+
0x320
TickCount : _KSYSTEM_TIME
+
0x320
TickCountQuad : Uint8B
+
0x320
ReservedTickCountOverlay : [
3
] Uint4B
+
0x32c
TickCountPad : [
1
] Uint4B
+
0x330
Cookie : Uint4B
+
0x334
CookiePad : [
1
] Uint4B
+
0x338
ConsoleSessionForegroundProcessId : Int8B
+
0x340
TimeUpdateLock : Uint8B
+
0x348
BaselineSystemTimeQpc : Uint8B
+
0x350
BaselineInterruptTimeQpc : Uint8B
+
0x358
QpcSystemTimeIncrement : Uint8B
+
0x360
QpcInterruptTimeIncrement : Uint8B
+
0x368
QpcSystemTimeIncrementShift : UChar
+
0x369
QpcInterruptTimeIncrementShift : UChar
+
0x36a
UnparkedProcessorCount : Uint2B
+
0x36c
EnclaveFeatureMask : [
4
] Uint4B
+
0x37c
TelemetryCoverageRound : Uint4B
+
0x380
UserModeGlobalLogger : [
16
] Uint2B
+
0x3a0
ImageFileExecutionOptions : Uint4B
+
0x3a4
LangGenerationCount : Uint4B
+
0x3a8
Reserved4 : Uint8B
+
0x3b0
InterruptTimeBias : Uint8B
+
0x3b8
QpcBias : Uint8B
+
0x3c0
ActiveProcessorCount : Uint4B
+
0x3c4
ActiveGroupCount : UChar
+
0x3c5
Reserved9 : UChar
+
0x3c6
QpcData : Uint2B
+
0x3c6
QpcBypassEnabled : UChar
+
0x3c7
QpcShift : UChar
+
0x3c8
TimeZoneBiasEffectiveStart : _LARGE_INTEGER
+
0x3d0
TimeZoneBiasEffectiveEnd : _LARGE_INTEGER
+
0x3d8
XState : _XSTATE_CONFIGURATION
+
0x710
FeatureConfigurationChangeStamp : _KSYSTEM_TIME
+
0x71c
Spare : Uint4B
nt!DbgBreakPointWithStatus:
fffff801`
476036b0
cc
int
3
0
: kd> dt _KUSER_SHARED_DATA
ntdll!_KUSER_SHARED_DATA
+
0x000
TickCountLowDeprecated : Uint4B
+
0x004
TickCountMultiplier : Uint4B
+
0x008
InterruptTime : _KSYSTEM_TIME
+
0x014
SystemTime : _KSYSTEM_TIME
+
0x020
TimeZoneBias : _KSYSTEM_TIME
+
0x02c
ImageNumberLow : Uint2B
+
0x02e
ImageNumberHigh : Uint2B
+
0x030
NtSystemRoot : [
260
] Wchar
+
0x238
MaxStackTraceDepth : Uint4B
+
0x23c
CryptoExponent : Uint4B
+
0x240
TimeZoneId : Uint4B
+
0x244
LargePageMinimum : Uint4B
+
0x248
AitSamplingValue : Uint4B
+
0x24c
AppCompatFlag : Uint4B
+
0x250
RNGSeedVersion : Uint8B
+
0x258
GlobalValidationRunlevel : Uint4B
+
0x25c
TimeZoneBiasStamp : Int4B
+
0x260
NtBuildNumber : Uint4B
+
0x264
NtProductType : _NT_PRODUCT_TYPE
+
0x268
ProductTypeIsValid : UChar
+
0x269
Reserved0 : [
1
] UChar
+
0x26a
NativeProcessorArchitecture : Uint2B
+
0x26c
NtMajorVersion : Uint4B
+
0x270
NtMinorVersion : Uint4B
+
0x274
ProcessorFeatures : [
64
] UChar
+
0x2b4
Reserved1 : Uint4B
+
0x2b8
Reserved3 : Uint4B
+
0x2bc
TimeSlip : Uint4B
+
0x2c0
AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+
0x2c4
BootId : Uint4B
+
0x2c8
SystemExpirationDate : _LARGE_INTEGER
+
0x2d0
SuiteMask : Uint4B
+
0x2d4
KdDebuggerEnabled : UChar
+
0x2d5
MitigationPolicies : UChar
+
0x2d5
NXSupportPolicy : Pos
0
,
2
Bits
+
0x2d5
SEHValidationPolicy : Pos
2
,
2
Bits
+
0x2d5
CurDirDevicesSkippedForDlls : Pos
4
,
2
Bits
+
0x2d5
Reserved : Pos
6
,
2
Bits
+
0x2d6
CyclesPerYield : Uint2B
+
0x2d8
ActiveConsoleId : Uint4B
+
0x2dc
DismountCount : Uint4B
+
0x2e0
ComPlusPackage : Uint4B
+
0x2e4
LastSystemRITEventTickCount : Uint4B
+
0x2e8
NumberOfPhysicalPages : Uint4B
+
0x2ec
SafeBootMode : UChar
+
0x2ed
VirtualizationFlags : UChar
+
0x2ee
Reserved12 : [
2
] UChar
+
0x2f0
SharedDataFlags : Uint4B
+
0x2f0
DbgErrorPortPresent : Pos
0
,
1
Bit
+
0x2f0
DbgElevationEnabled : Pos
1
,
1
Bit
+
0x2f0
DbgVirtEnabled : Pos
2
,
1
Bit
+
0x2f0
DbgInstallerDetectEnabled : Pos
3
,
1
Bit
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!