技术 内核相关 系统调用 ZEROKO14 2023-11-24 2023-11-24 API函数的调用过程 Application Programming Interface,简称API函数。
Windows有多少个API:主要是存放在C:/WINDOWS/system32下的所有dll
几个重要的DLL
Kernel32.dll :最核心的功能模块,比如管理内存,进程,线程相关的函数等。
User32.dll :是Windows用户界面相关应用程序接口,如创建窗口和发送消息等。
GDI32.dll :全称是Graphical Device Interface(图形设备接口),包含用于画图和显示文本的函数。比如要显示一个程序窗口,就调用其中的函数来画这个窗口
Ntdll.dll :大多数API都会通过这个DLL进入内核(0环)
3环部分 分析ReadProcessMemory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 .text:7 C8021D0 ; Exported entry 682. ReadProcessMemory .text:7 C8021D0 .text:7 C8021D0 ; =============== S U B R O U T I N E ======================================= .text:7 C8021D0 .text:7 C8021D0 ; Attributes: bp-based frame .text:7 C8021D0 .text:7 C8021D0 ; BOOL __stdcall ReadProcessMemory (HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead) .text:7C8021D0 public _ReadProcessMemory@20 .text:7C8021D0 _ReadProcessMemory@20 proc near ; CODE XREF: GetProcessVersion(x)+2F 12F↓p .text:7 C8021D0 ; GetProcessVersion(x)+2F 14E↓p ... .text:7 C8021D0 .text:7 C8021D0 hProcess = dword ptr 8 .text:7 C8021D0 lpBaseAddress = dword ptr 0 Ch .text:7 C8021D0 lpBuffer = dword ptr 10 h .text:7 C8021D0 nSize = dword ptr 14 h .text:7 C8021D0 lpNumberOfBytesRead= dword ptr 18 h .text:7 C8021D0 .text:7 C8021D0 mov edi, edi .text:7 C8021D2 push ebp .text:7 C8021D3 mov ebp, esp .text:7 C8021D5 lea eax, [ebp+nSize] .text:7 C8021D8 push eax ; NumberOfBytesRead .text:7 C8021D9 push [ebp+nSize] ; NumberOfBytesToRead .text:7 C8021DC push [ebp+lpBuffer] ; Buffer .text:7 C8021DF push [ebp+lpBaseAddress] ; BaseAddress .text:7 C8021E2 push [ebp+hProcess] ; ProcessHandle .text:7 C8021E5 call ds:__imp__NtReadVirtualMemory@20 ; NtReadVirtualMemory(x,x,x,x,x) .text:7 C8021EB mov ecx, [ebp+lpNumberOfBytesRead] .text:7 C8021EE test ecx, ecx .text:7 C8021F0 jnz short loc_7C8021FD .text:7 C8021F2 .text:7 C8021F2 loc_7C8021F2: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+32 ↓j .text:7 C8021F2 test eax, eax .text:7 C8021F4 jl short loc_7C802204 .text:7 C8021F6 xor eax, eax .text:7 C8021F8 inc eax .text:7 C8021F9 .text:7 C8021F9 loc_7C8021F9: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+3 C↓j .text:7 C8021F9 pop ebp .text:7 C8021FA retn 14 h .text:7 C8021FD ; --------------------------------------------------------------------------- .text:7 C8021FD .text:7 C8021FD loc_7C8021FD: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+20 ↑j .text:7 C8021FD mov edx, [ebp+nSize] .text:7 C802200 mov [ecx], edx .text:7 C802202 jmp short loc_7C8021F2 .text:7 C802204 ; --------------------------------------------------------------------------- .text:7 C802204 .text:7 C802204 loc_7C802204: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+24 ↑j .text:7 C802204 push eax ; Status .text:7 C802205 call _BaseSetLastNTError@4 ; BaseSetLastNTError(x) .text:7 C80220A xor eax, eax .text:7 C80220C jmp short loc_7C8021F9 .text:7 C80220C _ReadProcessMemory@20 endp
ReadProcessMemory->NtReadVirtualMemory
ntdll.dll中的NtReadVirtualMemory函数
1 2 3 4 5 6 7 8 9 .text:7 C92D9E0 ; __stdcall NtReadVirtualMemory (x, x, x, x, x) .text:7C92D9E0 public _NtReadVirtualMemory@20 .text:7C92D9E0 _NtReadVirtualMemory@20 proc near ; CODE XREF: LdrFindCreateProcessManifest(x,x,x,x,x)+1 CC↓p .text:7 C92D9E0 ; LdrCreateOutOfProcessImage(x,x,x,x)+7 C↓p ... .text:7 C92D9E0 mov eax, 0B Ah ; NtReadVirtualMemory .text:7 C92D9E5 mov edx, 7F FE0300h .text:7 C92D9EA call dword ptr [edx] .text:7 C92D9EC retn 14 h .text:7 C92D9EC _NtReadVirtualMemory@20 endp
NtReadVirtualMemory就是提供一个编号,找到一个函数,通过这个函数进零环。
7FFE0300h这个地址存放着系统调用进零环的函数地址
课后练习: 自己编写WriteProcessMemory函数(不使用任何DLL,直接调用0环函数),并在代码中使用。
重写API的意义:自己实现API,可避免三环恶意挂钩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <Windows.h> void __stdcall myWriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten ) { __asm { push lpNumberOfBytesWritten; push nSize; push lpBuffer; push lpBaseAddress; push hProcess; mov eax,0x115 ; lea edx,dword ptr [esp]; int 0x2E ; add esp,0x14 ; } } void main () { int a=300 ; SIZE_T haveRead; HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,NULL ,1520 ); myWriteProcessMemory(hProcess,(LPVOID)0x12ff7c ,&a,4 ,&haveRead); system("pause" ); }
目标修改进程:
3环进0环 _KUSER_SHARED_DATA结构
在User层和Kernel层分别定义了一个_KUSER_SHARED_DATA结构区域,用于User层和Kernel层共享 某些数据。
它们使用固定的地址值映射,_KUSER_SHARED_DATA结构区域在User和Kernel层地址分别为:
User层地址为:0x7FFE0000
Kernel层地址为:0xFFDF0000
0x7FFE0000和0xFFDF0000指向的是同一个物理页,但User层只读,Kernel可写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 ntdll!_KUSER_SHARED_DATA +0x000 TickCountLow : 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 ] Uint2B +0x238 MaxStackTraceDepth : Uint4B +0x23c CryptoExponent : Uint4B +0x240 TimeZoneId : Uint4B +0x244 Reserved2 : [8 ] Uint4B +0x264 NtProductType : _NT_PRODUCT_TYPE +0x268 ProductTypeIsValid : UChar +0x26c NtMajorVersion : Uint4B +0x270 NtMinorVersion : Uint4B +0x274 ProcessorFeatures : [64 ] UChar +0x2b4 Reserved1 : Uint4B +0x2b8 Reserved3 : Uint4B +0x2bc TimeSlip : Uint4B +0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE +0x2c8 SystemExpirationDate : _LARGE_INTEGER +0x2d0 SuiteMask : Uint4B +0x2d4 KdDebuggerEnabled : UChar +0x2d5 NXSupportPolicy : UChar +0x2d8 ActiveConsoleId : Uint4B +0x2dc DismountCount : Uint4B +0x2e0 ComPlusPackage : Uint4B +0x2e4 LastSystemRITEventTickCount : Uint4B +0x2e8 NumberOfPhysicalPages : Uint4B +0x2ec SafeBootMode : UChar +0x2f0 TraceLogging : Uint4B +0x2f8 TestRetInstruction : Uint8B +0x300 SystemCall : Uint4B +0x304 SystemCallReturn : Uint4B +0x308 SystemCallPad : [3 ] Uint8B +0x320 TickCount : _KSYSTEM_TIME +0x320 TickCountQuad : Uint8B +0x330 Cookie : Uint4B ntdll!_KUSER_SHARED_DATA +0x000 TickCountLow : 0xb752 +0x004 TickCountMultiplier : 0xfa00000 +0x008 InterruptTime : _KSYSTEM_TIME +0x014 SystemTime : _KSYSTEM_TIME +0x020 TimeZoneBias : _KSYSTEM_TIME +0x02c ImageNumberLow : 0x14c +0x02e ImageNumberHigh : 0x14c +0x030 NtSystemRoot : [260 ] 0x43 +0x238 MaxStackTraceDepth : 0 +0x23c CryptoExponent : 0 +0x240 TimeZoneId : 0 +0x244 Reserved2 : [8 ] 0 +0x264 NtProductType : 1 ( NtProductWinNt ) +0x268 ProductTypeIsValid : 0x1 '' +0x26c NtMajorVersion : 5//NT内核的主版本号 +0x270 NtMinorVersion : 1//NT内核的次版本号 +0x274 ProcessorFeatures : [64] "" +0x2b4 Reserved1 : 0x7ffeffff +0x2b8 Reserved3 : 0x80000000 +0x2bc TimeSlip : 0 +0x2c0 AlternativeArchitecture : 0 ( StandardDesign ) +0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0 +0x2d0 SuiteMask : 0x110 +0x2d4 KdDebuggerEnabled : 0x3 ' ' +0x2d5 NXSupportPolicy : 0x2 '' +0x2d8 ActiveConsoleId : 0 +0x2dc DismountCount : 0 +0x2e0 ComPlusPackage : 0xffffffff +0x2e4 LastSystemRITEventTickCount : 0xadbe8 +0x2e8 NumberOfPhysicalPages : 0x1ff6a +0x2ec SafeBootMode : 0 ' ' +0x2f0 TraceLogging : 0 +0x2f8 TestRetInstruction : 0xc3 +0x300 SystemCall : 0x7c92e4f0 +0x304 SystemCallReturn : 0x7c92e4f4 +0x308 SystemCallPad : [3 ] 0 +0x320 TickCount : _KSYSTEM_TIME +0x320 TickCountQuad : 0 +0x330 Cookie : 0xbde19661
0x7FFE0300存储的到底是什么?
两种情况:是否支持快速调用
当通过eax=1来执行cpuid指令时 ,处理器的特征信息被放在ecx和edx寄存器中,其中edx包含了一个SEP位(0开始第11位),该位指明了 当前处理器是否支持systenter/sysexit指令
1==支持——>ntdll.dll!KiFastSystemCall()
0==不支持—>ntdll.dll!KiIntSystemCall()
0x7FFE0300存储的就是上诉两个函数地址之一
3环进0环需要更改哪些寄存器
CS的权限由3变为0,意味着需要新的CS
SS与CS的权限永远一致,因此需要新的SS
权限发生切换的时候,堆栈也一定会切换,需要新的ESP
进0环后代码的位置,因此需要EIP
p.s. windbg进入指定进程空间命令:
1 .process 0 xXXXXXXXX(!process 0 0 遍历出来的每个PROCESS的第一个数值)
KiFastSystemCall与KiIntSystemCall的区别 KiIntSystemCall 1 2 3 4 5 6 7 8 9 10 11 12 .text:7 C92E500 ; _DWORD __stdcall KiIntSystemCall () .text:7C92E500 public _KiIntSystemCall@0 .text:7C92E500 _KiIntSystemCall@0 proc near ; DATA XREF: .text:off_7C923428↑o .text:7 C92E500 .text:7 C92E500 arg_4 = byte ptr 8 .text:7 C92E500 .text:7 C92E500 lea edx, [esp+arg_4] .text:7 C92E504 int 2 Eh ; DOS 2 + internal - EXECUTE COMMAND .text:7 C92E504 ; DS:SI -> counted CR-terminated command string .text:7 C92E506 retn .text:7 C92E506 _KiIntSystemCall@0 endp
分析INT 0x2E进0环
在IDT表中找到0x2E
分析CS/SS/ESP/EIP
ee表明是个中断门描述符,CS是0x0008,EIP为0x8053E481
分析EIP是什么
1 2 3 4 5 6 7 8 9 10 11 kd> u 8053e481 nt!KiSystemService: 8053e481 6 a00 push 0 8053e483 55 push ebp8053e484 53 push ebx8053e485 56 push esi8053e486 57 push edi8053e487 0f a0 push fs8053e489 bb30000000 mov ebx,30 h8053e48 e 668 ee3 mov fs,bx
此时KiSystemService函数才真正是内核函数
KiFastSystemCall 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 .text:7 C92E4F0 ; _DWORD __stdcall KiFastSystemCall () .text:7C92E4F0 public _KiFastSystemCall@0 .text:7C92E4F0 _KiFastSystemCall@0 proc near ; DATA XREF: .text:off_7C923428↑o .text:7 C92E4F0 mov edx, esp .text:7 C92E4F2 sysenter .text:7 C92E4F2 _KiFastSystemCall@0 endp .text:7 C92E4F2 .text:7 C92E4F4 ; Exported entry 42. KiFastSystemCallRet .text:7 C92E4F4 .text:7 C92E4F4 ; =============== S U B R O U T I N E ======================================= .text:7 C92E4F4 .text:7 C92E4F4 .text:7 C92E4F4 ; _DWORD __stdcall KiFastSystemCallRet () .text:7C92E4F4 public _KiFastSystemCallRet@0 .text:7C92E4F4 _KiFastSystemCallRet@0 proc near ; DATA XREF: .text:off_7C923428↑o .text:7 C92E4F4 retn .text:7 C92E4F4 _KiFastSystemCallRet@0 endp
什么叫快速调用?
中断门进0环,需要的CS,EIP在IDT表中,需要查内存(SS与ESP由TSS提供)
而CPU如果支持sysenter指令时,操作系统会提前将CS/SS/ESP/EIP的值存储在MSR寄存器 中,sysenter指令执行时,CPU会将MSR寄存器中的值直接写入相关寄存器,没有读内存的过程,所以叫快速调用,但本质都是切换CS,SS,ESP,EIP。
分析sysenter进0环
在执行sysenter指令之前,操作系统必须指定0环的CS段,SS段,EIP以及ESP 。sysenter是由CPU设计规定并操作的
MSR
地址
IA32_SYSENTER_CS
174H
IA32_SYSENTER_ESP
175H
IA32_SYSENTER_EIP
176H
SS 是通过【IA32_SYSENTER_CS+8】的段选择子来计算出来的。即CS是0x08指向的段,SS就是gdt中0x08指向的段描述符的下一个段描述符。
vt,MSR结构非常重要。
intel文档上说该指令是为了快速的系统调用(从ring3 到ring0),在执行sysenter之前了,必须要设置好ring0中的代码段、入口函数地址、ring0栈所在的段、栈指针,设置方式是写下列MSRs:
IA32_SYSENTER_CS:32bit,前16个字节为代码段选择符,其确定的索引+1为栈段的索引,所以在全局描述符表中这两个必须相连。
IA32_SYSENTER_EIP:32bit,入口指令地址。
IA32_SYSENTER_ESP:32bit,内核栈地址。
可以通过RDMSR/WRMST来进行读写(操作系统使用WRMST写该寄存器):
参考:Intel白皮书第二卷(搜索sysenter)
当执行SYSENTER ,处理器会做下面的动作:
从IA32_SYSENTER_CS从取出段选择子加载到CS中。
从IA32_SYSENTER_EIP取出指令指针放到EIP中
将IA32_SYSENTER_CS的值加上8,将其结果加载到SS中。
从IA32_SYSENTER_ESP取出堆栈指针放到ESP寄存器中
上述步骤相当于切换到0环的_KiFastCallEntry函数
EIP指向的代码:
1 2 3 4 5 6 7 8 9 10 11 kd> u 8053e540 nt!KiFastCallEntry: 8053e540 b923000000 mov ecx,23 h8053e545 6 a30 push 30 h8053e547 0f a1 pop fs8053e549 8 ed9 mov ds,cx8053e54 b 8 ec1 mov es,cx8053e54 d 8b 0d40f0dfff mov ecx,dword ptr ds:[0F FDFF040h]8053e553 8b 6104 mov esp,dword ptr [ecx+4 ]8053e556 6 a23 push 23 h
可见,进入了KiFastCallEntry内核函数。
API进零环的两种方式总结
API通过中断门 进0环
固定中断号为0x2E
CS/EIP由门描述符提供,ESP/SS由TSS提供
进入0环后执行的内核函数:NT!KiStstemService
API通过sysenter 指令进入0环
CS/ESP/EIP由MSR寄存器提供(SS是算出来的)(实际上逆向时ESP还是由TSS中来)
进入0环后执行的内核函数:NT!KiFastCallEntry
winXP内核模块:ntoskrnl.exe(10-10-12分页)/ntkrnlpa.exe(2-9-9-12分页)
KiFastSystemCall方式三环进0环,TerminateThread API进入流程(未记录返回部分):
思考 自己实现通过中断门直接调用内核函数
通过IDA找到KiStstemService和KiFastCallEntry函数并分析
进0环后,原来的寄存器存在哪里?
如何根据系统调用号(eax中存储)找到要执行的内核函数?
调用时参数时存储到3环的堆栈,如何传递给内核函数?
两种调用方式分别是如何返回到3环的
后续的章节会展开讲上面的点。
内核结构体介绍
储存3环寄存器信息结构体:_Ktrap_frame结构体
描述线程相关信息结构体:_ETHREAD和_KTHREAD
描述当前CPU状态的结构体:_KPCR
_Ktrap_frame结构体 陷阱帧
无论是通过sysenter还是通过中断门进入零环,三环所有寄存器都会存在这个结构中 。
该结构是零环结构体,由操作系统进行维护 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 kd> dt _Ktrap_frame ntdll!_KTRAP_FRAME +0x000 DbgEbp : Uint4B +0x004 DbgEip : Uint4B +0x008 DbgArgMark : Uint4B +0x00c DbgArgPointer : Uint4B +0x010 TempSegCs : Uint4B +0x014 TempEsp : Uint4B +0x018 Dr0 : Uint4B +0x01c Dr1 : Uint4B +0x020 Dr2 : Uint4B +0x024 Dr3 : Uint4B +0x028 Dr6 : Uint4B +0x02c Dr7 : Uint4B +0x030 SegGs : Uint4B +0x034 SegEs : Uint4B +0x038 SegDs : Uint4B +0x03c Edx : Uint4B +0x040 Ecx : Uint4B +0x044 Eax : Uint4B +0x048 PreviousPreviousMode : Uint4B +0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x050 SegFs : Uint4B +0x054 Edi : Uint4B +0x058 Esi : Uint4B +0x05c Ebx : Uint4B +0x060 Ebp : Uint4B +0x064 ErrCode : Uint4B +0x068 Eip : Uint4B +0x06c SegCs : Uint4B +0x070 EFlags : Uint4B +0x074 HardwareEsp : Uint4B +0x078 HardwareSegSs : Uint4B +0x07c V86Es : Uint4B +0x080 V86Ds : Uint4B +0x084 V86Fs : Uint4B +0x088 V86Gs : Uint4B
KiFastSystemCall由0x78开始往上压栈。(sysenter)
KiIntSystemCall由0x64开始往上压栈。(中断)
THREAD线程相关的结构体
_ETHREAD结构体 每个线程在零环都有一个对应的_ETHREAD结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ntdll!_ETHREAD +0x000 Tcb : _KTHREAD +0x1c0 CreateTime : _LARGE_INTEGER +0x1c0 NestedFaultCount : Pos 0 , 2 Bits +0x1c0 ApcNeeded : Pos 2 , 1 Bit +0x1c8 ExitTime : _LARGE_INTEGER +0x1c8 LpcReplyChain : _LIST_ENTRY +0x1c8 KeyedWaitChain : _LIST_ENTRY +0x1d0 ExitStatus : Int4B +0x1d0 OfsChain : Ptr32 Void +0x1d4 PostBlockList : _LIST_ENTRY +0x1dc TerminationPort : Ptr32 _TERMINATION_PORT +0x1dc ReaperLink : Ptr32 _ETHREAD +0x1dc KeyedWaitValue : Ptr32 Void +0x1e0 ActiveTimerListLock : Uint4B +0x1e4 ActiveTimerListHead : _LIST_ENTRY +0x1ec Cid : _CLIENT_ID +0x1f4 LpcReplySemaphore : _KSEMAPHORE +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE +0x208 LpcReplyMessage : Ptr32 Void +0x208 LpcWaitingOnPort : Ptr32 Void +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION +0x210 IrpList : _LIST_ENTRY +0x218 TopLevelIrp : Uint4B +0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT +0x220 ThreadsProcess : Ptr32 _EPROCESS +0x224 StartAddress : Ptr32 Void +0x228 Win32StartAddress : Ptr32 Void +0x228 LpcReceivedMessageId : Uint4B +0x22c ThreadListEntry : _LIST_ENTRY +0x234 RundownProtect : _EX_RUNDOWN_REF +0x238 ThreadLock : _EX_PUSH_LOCK +0x23c LpcReplyMessageId : Uint4B +0x240 ReadClusterSize : Uint4B +0x244 GrantedAccess : Uint4B +0x248 CrossThreadFlags : Uint4B +0x248 Terminated : Pos 0 , 1 Bit +0x248 DeadThread : Pos 1 , 1 Bit +0x248 HideFromDebugger : Pos 2 , 1 Bit +0x248 ActiveImpersonationInfo : Pos 3 , 1 Bit +0x248 SystemThread : Pos 4 , 1 Bit +0x248 HardErrorsAreDisabled : Pos 5 , 1 Bit +0x248 BreakOnTermination : Pos 6 , 1 Bit +0x248 SkipCreationMsg : Pos 7 , 1 Bit +0x248 SkipTerminationMsg : Pos 8 , 1 Bit +0x24c SameThreadPassiveFlags : Uint4B +0x24c ActiveExWorker : Pos 0 , 1 Bit +0x24c ExWorkerCanWaitUser : Pos 1 , 1 Bit +0x24c MemoryMaker : Pos 2 , 1 Bit +0x250 SameThreadApcFlags : Uint4B +0x250 LpcReceivedMsgIdValid : Pos 0 , 1 Bit +0x250 LpcExitThreadCalled : Pos 1 , 1 Bit +0x250 AddressSpaceOwner : Pos 2 , 1 Bit +0x254 ForwardClusterOnly : UChar +0x255 DisablePageFaultClustering : UChar
_KTHREAD结构体 _ETHRAD结构体中的子结构体,存储的都是相对比较重要的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 ntdll!_KTHREAD +0x000 Header : _DISPATCHER_HEADER +0x010 MutantListHead : _LIST_ENTRY +0x018 InitialStack : Ptr32 Void +0x01c StackLimit : Ptr32 Void +0x020 Teb : Ptr32 Void +0x024 TlsArray : Ptr32 Void +0x028 KernelStack : Ptr32 Void +0x02c DebugActive : UChar +0x02d State : UChar +0x02e Alerted : [2 ] UChar +0x030 Iopl : UChar +0x031 NpxState : UChar +0x032 Saturation : Char +0x033 Priority : Char +0x034 ApcState : _KAPC_STATE +0x04c ContextSwitches : Uint4B +0x050 IdleSwapBlock : UChar +0x051 Spare0 : [3 ] UChar +0x054 WaitStatus : Int4B +0x058 WaitIrql : UChar +0x059 WaitMode : Char +0x05a WaitNext : UChar +0x05b WaitReason : UChar +0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK +0x060 WaitListEntry : _LIST_ENTRY +0x060 SwapListEntry : _SINGLE_LIST_ENTRY +0x068 WaitTime : Uint4B +0x06c BasePriority : Char +0x06d DecrementCount : UChar +0x06e PriorityDecrement : Char +0x06f Quantum : Char +0x070 WaitBlock : [4 ] _KWAIT_BLOCK +0x0d0 LegoData : Ptr32 Void +0x0d4 KernelApcDisable : Uint4B +0x0d8 UserAffinity : Uint4B +0x0dc SystemAffinityActive : UChar +0x0dd PowerState : UChar +0x0de NpxIrql : UChar +0x0df InitialNode : UChar +0x0e0 ServiceTable : Ptr32 Void +0x0e4 Queue : Ptr32 _KQUEUE +0x0e8 ApcQueueLock : Uint4B +0x0f0 Timer : _KTIMER +0x118 QueueListEntry : _LIST_ENTRY +0x120 SoftAffinity : Uint4B +0x124 Affinity : Uint4B +0x128 Preempted : UChar +0x129 ProcessReadyQueue : UChar +0x12a KernelStackResident : UChar +0x12b NextProcessor : UChar +0x12c CallbackStack : Ptr32 Void +0x130 Win32Thread : Ptr32 Void +0x134 TrapFrame : Ptr32 _KTRAP_FRAME +0x138 ApcStatePointer : [2 ] Ptr32 _KAPC_STATE +0x140 PreviousMode : Char +0x141 EnableStackSwap : UChar +0x142 LargeStack : UChar +0x143 ResourceIndex : UChar +0x144 KernelTime : Uint4B +0x148 UserTime : Uint4B +0x14c SavedApcState : _KAPC_STATE +0x164 Alertable : UChar +0x165 ApcStateIndex : UChar +0x166 ApcQueueable : UChar +0x167 AutoAlignment : UChar +0x168 StackBase : Ptr32 Void +0x16c SuspendApc : _KAPC +0x19c SuspendSemaphore : _KSEMAPHORE +0x1b0 ThreadListEntry : _LIST_ENTRY +0x1b8 FreezeCount : Char +0x1b9 SuspendCount : Char +0x1ba IdealProcessor : UChar +0x1bb DisableBoost : UChar
CPU相关结构体 CPU相关windbg指令 查看CPU数量
表示一核
查看KPRCB存在哪里
如果有两个核,那么就会出现两个地址,上图由于只有一个核所以还有一个地址。
120为kpcr中KPRCB的对应位置,0xffdff120-0x120就是_kpcr结构体的地址。
p.s. 在0环中,FS段描述符指向的就是KPCR结构首地址,写死在gdtr+0x30位置。
查看kpcr指令:
1 dt _kpcr 0xffdff120 -0x120
_KPCR结构体
KPCR 也叫CPU控制区(Processor Control Region)
每一个CPU核都有一个_KPCR结构体来描述当前CPU所处的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 kd> dt _kpcr 0xffdff120 -0x120 nt!_KPCR +0x000 NtTib : _NT_TIB +0x01c SelfPcr : 0xffdff000 _KPCR +0x020 Prcb : 0xffdff120 _KPRCB +0x024 Irql : 0 '' +0x028 IRR : 0 +0x02c IrrActive : 0 +0x030 IDR : 0xffffffff +0x034 KdVersionBlock : 0x80546ab8 Void +0x038 IDT : 0x8003f400 _KIDTENTRY//当前核的IDT +0x03c GDT : 0x8003f000 _KGDTENTRY//当前核的GDT +0x040 TSS : 0x80042000 _KTSS//当前核的TSS +0x044 MajorVersion : 1 +0x046 MinorVersion : 1 +0x048 SetMember : 1 +0x04c StallScaleFactor : 0xd49 +0x050 DebugActive : 0 ' '//调试激活位 +0x051 Number : 0 ' ' +0x052 Spare0 : 0 '' +0x053 SecondLevelCacheAssociativity : 0 ' ' +0x054 VdmAlert : 0 +0x058 KernelReserved : [14 ] 0 +0x090 SecondLevelCacheSize : 0 +0x094 HalReserved : [16 ] 0 +0x0d4 InterruptMode : 0 +0x0d8 Spare1 : 0 '' +0x0dc KernelReserved2 : [17] 0 +0x120 PrcbData : _KPRCB ntdll!_NT_TIB +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD //当前线程内核异常链表(SEH) +0x004 StackBase : Ptr32 Void //当前线程堆栈的基址 +0x008 StackLimit : Ptr32 Void //当前线程堆栈的大小 +0x00c SubSystemTib : Ptr32 Void +0x010 FiberData : Ptr32 Void +0x010 Version : Uint4B +0x014 ArbitraryUserPointer : Ptr32 Void +0x018 Self : Ptr32 _NT_TIB //指向自己头部,目的为了方便查找
_KPRCB结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 kd> dt _KPRCB ffdff000+0x120 ntdll!_KPRCB +0x000 MinorVersion : 1 +0x002 MajorVersion : 1 +0x004 CurrentThread : 0x80553740 _KTHREAD +0x008 NextThread : (null) +0x00c IdleThread : 0x80553740 _KTHREAD +0x010 Number : 0 '' +0x011 Reserved : 0 ' ' +0x012 BuildType : 2 +0x014 SetMember : 1 +0x018 CpuType : 6 '' +0x019 CpuID : 1 ' ' +0x01a CpuStep : 0x3c03 +0x01c ProcessorState : _KPROCESSOR_STATE +0x33c KernelReserved : [16 ] 0 +0x37c HalReserved : [16 ] 0 +0x3bc PrcbPad0 : [92 ] "" +0x418 LockQueue : [16 ] _KSPIN_LOCK_QUEUE +0x498 PrcbPad1 : [8 ] "" +0x4a0 NpxThread : 0x81d10af0 _KTHREAD +0x4a4 InterruptCount : 0x34e1 +0x4a8 KernelTime : 0x1aaf +0x4ac UserTime : 0xa1 +0x4b0 DpcTime : 0x16 +0x4b4 DebugDpcTime : 0 +0x4b8 InterruptTime : 0x79 +0x4bc AdjustDpcThreshold : 0x14 +0x4c0 PageColor : 0 +0x4c4 SkipTick : 0 +0x4c8 MultiThreadSetBusy : 0 '' +0x4c9 Spare2 : [3] "" +0x4cc ParentNode : 0x80553e00 _KNODE +0x4d0 MultiThreadProcessorSet : 1 +0x4d4 MultiThreadSetMaster : (null) +0x4d8 ThreadStartCount : [2] 0 +0x4e0 CcFastReadNoWait : 0 +0x4e4 CcFastReadWait : 0 +0x4e8 CcFastReadNotPossible : 0 +0x4ec CcCopyReadNoWait : 0 +0x4f0 CcCopyReadWait : 0 +0x4f4 CcCopyReadNoWaitMiss : 0 +0x4f8 KeAlignmentFixupCount : 0 +0x4fc KeContextSwitches : 0x1a44d +0x500 KeDcacheFlushCount : 0 +0x504 KeExceptionDispatchCount : 0x290 +0x508 KeFirstLevelTbFills : 0 +0x50c KeFloatingEmulationCount : 0 +0x510 KeIcacheFlushCount : 0 +0x514 KeSecondLevelTbFills : 0 +0x518 KeSystemCalls : 0x24189b//系统调用次数 +0x51c SpareCounter0 : [1] 0 +0x520 PPLookasideList : [16] _PP_LOOKASIDE_LIST +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST +0x7a0 PacketBarrier : 0 +0x7a4 ReverseStall : 0 +0x7a8 IpiFrame : (null) +0x7ac PrcbPad2 : [52] "" +0x7e0 CurrentPacket : [3] (null) +0x7ec TargetSet : 0 +0x7f0 WorkerRoutine : (null) +0x7f4 IpiFrozen : 0 +0x7f8 PrcbPad3 : [40] "" +0x820 RequestSummary : 0 +0x824 SignalDone : (null) +0x828 PrcbPad4 : [56] "" +0x860 DpcListHead : _LIST_ENTRY [ 0x80553da4 - 0x80553da4 ] +0x868 DpcStack : 0xf8ac2000 Void +0x86c DpcCount : 0x2058 +0x870 DpcQueueDepth : 1 +0x874 DpcRoutineActive : 0 +0x878 DpcInterruptRequested : 0 +0x87c DpcLastCount : 0x2058 +0x880 DpcRequestRate : 0 +0x884 MaximumDpcQueueDepth : 1 +0x888 MinimumDpcRate : 3 +0x88c QuantumEnd : 0 +0x890 PrcbPad5 : [16] "" +0x8a0 DpcLock : 0 +0x8a4 PrcbPad6 : [28] "" +0x8c0 CallDpc : _KDPC +0x8e0 ChainedInterruptList : (null) +0x8e4 LookasideIrpFloat : 0n1438 +0x8e8 SpareFields0 : [6] 0 +0x900 VendorString : [13] "GenuineIntel"//CPU厂商名称 +0x90d InitialApicId : 0 ' ' +0x90e LogicalProcessorsPerPhysicalProcessor : 0x1 '' +0x910 MHz : 0xd47 +0x914 FeatureBits : 0xa0013fff +0x918 UpdateSignature : _LARGE_INTEGER 0x00000025`00000000 +0x920 NpxSaveArea : _FX_SAVE_AREA +0xb30 PowerState : _PROCESSOR_POWER_STATE
分析KiStstemService和KiFastCallEntry KiStstemService和KiFastCallEntry从两个口进来,最终执行的代码是一样的。
开始的时候,这两函数都在填充_Ktrap_frame结构体以保存三环的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 kd> uf 8053e481 Flow analysis was incomplete, some code may be missing nt!KiBBTUnexpectedRange: 8053e332 83f 910 cmp ecx,10 h8053e335 7539 jne nt!KiBBTUnexpectedRange+0x3e (8053e370 ) Branchnt!KiBBTUnexpectedRange+0x5 : 8053e337 52 push edx8053e338 53 push ebx8053e339 e8e2530800 call nt!PsConvertToGuiThread (805 c3720)8053e33 e 0b c0 or eax,eax8053e340 58 pop eax8053e341 5 a pop edx8053e342 8b ec mov ebp,esp8053e344 89 ae34010000 mov dword ptr [esi+134 h],ebp8053e34 a 0f 847d020000 je nt!KiFastCallEntry+0x8d (8053e5 cd) Branchnt!KiBBTUnexpectedRange+0x1e : 8053e350 8 d15703f5580 lea edx,[nt!KeServiceDescriptorTableShadow+0x10 (80553f 70)]8053e356 8b 4a08 mov ecx,dword ptr [edx+8 ]8053e359 8b 12 mov edx,dword ptr [edx]8053e35 b 8 d148a lea edx,[edx+ecx*4 ]8053e35 e 25f f0f0000 and eax,0F FFh8053e363 03 d0 add edx,eax8053e365 0f be02 movsx eax,byte ptr [edx]8053e368 0b c0 or eax,eax8053e36 a 0f 8eca020000 jle nt!KiFastCallEntry+0xfa (8053e63 a) Branchnt!KiBBTUnexpectedRange+0x3e : 8053e370 b81c0000c0 mov eax,0 C000001Ch8053e375 e9c0020000 jmp nt!KiFastCallEntry+0xfa (8053e63 a) Branch nt!Dr_kss_a: 8053e37 c f7457000000200 test dword ptr [ebp+70 h],20000 h8053e383 750 d jne nt!Dr_kss_a+0x16 (8053e392 ) Branchnt!Dr_kss_a+0x9 : 8053e385 f7456c01000000 test dword ptr [ebp+6 Ch],1 8053e38 c 0f 845d010000 je nt!KiSystemService+0x6e (8053e4 ef) Branchnt!Dr_kss_a+0x16 : 8053e392 0f 21c3 mov ebx,dr08053e395 0f 21c9 mov ecx,dr18053e398 0f 21d7 mov edi,dr28053e39 b 895 d18 mov dword ptr [ebp+18 h],ebx8053e39 e 894 d1c mov dword ptr [ebp+1 Ch],ecx8053e3 a1 897 d20 mov dword ptr [ebp+20 h],edi8053e3 a4 0f 21db mov ebx,dr38053e3 a7 0f 21f1 mov ecx,dr68053e3 aa 0f 21ff mov edi,dr78053e3 ad 895 d24 mov dword ptr [ebp+24 h],ebx8053e3 b0 894 d28 mov dword ptr [ebp+28 h],ecx8053e3 b3 33 db xor ebx,ebx8053e3 b5 897 d2c mov dword ptr [ebp+2 Ch],edi8053e3 b8 0f 23fb mov dr7,ebx8053e3 bb 648b 3d20000000 mov edi,dword ptr fs:[20 h]8053e3 c2 8b 9ff8020000 mov ebx,dword ptr [edi+2F 8h]8053e3 c8 8b 8ffc020000 mov ecx,dword ptr [edi+2F Ch]8053e3 ce 0f 23c3 mov dr0,ebx8053e3 d1 0f 23c9 mov dr1,ecx8053e3 d4 8b 9f00030000 mov ebx,dword ptr [edi+300 h]8053e3 da 8b 8f04030000 mov ecx,dword ptr [edi+304 h]8053e3 e0 0f 23d3 mov dr2,ebx8053e3 e3 0f 23d9 mov dr3,ecx8053e3 e6 8b 9f08030000 mov ebx,dword ptr [edi+308 h]8053e3 ec 8b 8f0c030000 mov ecx,dword ptr [edi+30 Ch]8053e3 f2 0f 23f3 mov dr6,ebx8053e3 f5 0f 23f9 mov dr7,ecx8053e3 f8 e9f2000000 jmp nt!KiSystemService+0x6e (8053e4 ef) Branch nt!KiSystemService: 8053e481 6 a00 push 0 8053e483 55 push ebp8053e484 53 push ebx8053e485 56 push esi8053e486 57 push edi8053e487 0f a0 push fs8053e489 bb30000000 mov ebx,30 h8053e48 e 668 ee3 mov fs,bx8053e491 ff3500f0dfff push dword ptr ds:[0F FDFF000h]8053e497 c70500f0dfffffffffff mov dword ptr ds:[0F FDFF000h],0F FFFFFFFh8053e4 a1 8b 3524f1dfff mov esi,dword ptr ds:[0F FDFF124h]8053e4 a7 ffb640010000 push dword ptr [esi+140 h]8053e4 ad 83 ec48 sub esp,48 h8053e4 b0 8b 5c246c mov ebx,dword ptr [esp+6 Ch]8053e4 b4 83e301 and ebx,1 8053e4 b7 889e40010000 mov byte ptr [esi+140 h],bl8053e4 bd 8b ec mov ebp,esp8053e4 bf 8b 9e34010000 mov ebx,dword ptr [esi+134 h]8053e4 c5 895 d3c mov dword ptr [ebp+3 Ch],ebx8053e4 c8 89 ae34010000 mov dword ptr [esi+134 h],ebp8053e4 ce fc cld8053e4 cf 8b 5d60 mov ebx,dword ptr [ebp+60 h]8053e4 d2 8b 7d68 mov edi,dword ptr [ebp+68 h]8053e4 d5 89550 c mov dword ptr [ebp+0 Ch],edx8053e4 d8 c74508000ddbba mov dword ptr [ebp+8 ],0B ADB0D00h8053e4 df 895 d00 mov dword ptr [ebp],ebx8053e4 e2 897 d04 mov dword ptr [ebp+4 ],edi8053e4 e5 f6462cff test byte ptr [esi+2 Ch],0F Fh8053e4 e9 0f 858dfeffff jne nt!Dr_kss_a (8053e37 c) Branch nt!KiSystemService+0x6e : 8053e4 ef fb sti8053e4 f0 e9d8000000 jmp nt!KiFastCallEntry+0x8d (8053e5 cd) Branch nt!KiFastCallEntry2+0x24 : 8053e519 8b 0d40f0dfff mov ecx,dword ptr ds:[0F FDFF040h]8053e51 f 8b 6104 mov esp,dword ptr [ecx+4 ]8053e522 6 a00 push 0 8053e524 6 a00 push 0 8053e526 6 a00 push 0 8053e528 6 a00 push 0 8053e52 a 6 a23 push 23 h8053e52 c 6 a00 push 0 8053e52 e 6802020200 push 20202 h8053e533 6 a1b push 1B h8053e535 6 a00 push 0 8053e537 e9f8150000 jmp nt!KiTrap06 (8053f b34) Branchnt!KiFastCallEntry2+0x47 : 8053e53 c ebdb jmp nt!KiFastCallEntry2+0x24 (8053e519 ) Branchnt!KiFastCallEntry: 8053e540 b923000000 mov ecx,23 h8053e545 6 a30 push 30 h8053e547 0f a1 pop fs8053e549 8 ed9 mov ds,cx8053e54 b 8 ec1 mov es,cx8053e54 d 8b 0d40f0dfff mov ecx,dword ptr ds:[0F FDFF040h]8053e553 8b 6104 mov esp,dword ptr [ecx+4 ]8053e556 6 a23 push 23 h8053e558 52 push edx8053e559 9 c pushfd8053e55 a 6 a02 push 2 8053e55 c 83 c208 add edx,8 8053e55 f 9 d popfd 8053e560 804 c240102 or byte ptr [esp+1 ],2 8053e565 6 a1b push 1B h8053e567 ff350403dfff push dword ptr ds:[0F FDF0304h]8053e56 d 6 a00 push 0 8053e56 f 55 push ebp8053e570 53 push ebx8053e571 56 push esi8053e572 57 push edi8053e573 8b 1d1cf0dfff mov ebx,dword ptr ds:[0F FDFF01Ch]8053e579 6 a3b push 3B h8053e57 b 8b b324010000 mov esi,dword ptr [ebx+124 h]8053e581 ff33 push dword ptr [ebx]8053e583 c703ffffffff mov dword ptr [ebx],0F FFFFFFFh8053e589 8b 6e18 mov ebp,dword ptr [esi+18 h]8053e58 c 6 a01 push 1 8053e58 e 83 ec48 sub esp,48 h8053e591 81 ed9c020000 sub ebp,29 Ch8053e597 c6864001000001 mov byte ptr [esi+140 h],1 8053e59 e 3b ec cmp ebp,esp8053e5 a0 759 a jne nt!KiFastCallEntry2+0x47 (8053e53 c) Branchnt!KiFastCallEntry+0x62 : 8053e5 a2 83652 c00 and dword ptr [ebp+2 Ch],0 8053e5 a6 f6462cff test byte ptr [esi+2 Ch],0F Fh8053e5 aa 89 ae34010000 mov dword ptr [esi+134 h],ebp8053e5 b0 0f 854afeffff jne nt!Dr_FastCallDrSave (8053e400 ) Branchnt!KiFastCallEntry+0x76 : 8053e5 b6 8b 5d60 mov ebx,dword ptr [ebp+60 h]8053e5 b9 8b 7d68 mov edi,dword ptr [ebp+68 h]8053e5 bc 89550 c mov dword ptr [ebp+0 Ch],edx8053e5 bf c74508000ddbba mov dword ptr [ebp+8 ],0B ADB0D00h8053e5 c6 895 d00 mov dword ptr [ebp],ebx8053e5 c9 897 d04 mov dword ptr [ebp+4 ],edi8053e5 cc fb sti nt!KiFastCallEntry+0x8d : 8053e5 cd 8b f8 mov edi,eax8053e5 cf c1ef08 shr edi,8 8053e5 d2 83e730 and edi,30 h8053e5 d5 8b cf mov ecx,edi8053e5 d7 03b ee0000000 add edi,dword ptr [esi+0E0 h]8053e5 dd 8b d8 mov ebx,eax8053e5 df 25f f0f0000 and eax,0F FFh8053e5 e4 3b 4708 cmp eax,dword ptr [edi+8 ]8053e5 e7 0f 8345fdffff jae nt!KiBBTUnexpectedRange (8053e332 ) Branch
KiFastCallEntry单独分析:
系统调用目标内核函数后续跳转
系统服务表 上一章是关于进入0环后,3环的各种寄存器都会保留到_Trap_Frame结构体中
这一章是关于
如何根据系统服务号(eax中存储)找到要执行的内核函数
调用时参数时存储的3环的堆栈,如何传递给内核函数
系统服务号盘点
系统服务表(SystemServiceTable)
ServiceTable指向的是函数地址表
COUNT当前函数地址表中的地址被调用了多少次
ServiceLimit当前函数地址表中一共有多少个函数
ArgmentTable指向的是函数参数表,函数参数表中存的是相对应每个函数的参数的【字节数】 ,函数参数表的每个成员只有1个字节 。
函数地址1就对应参数个数1,一一对应。
winXP只有两张系统服务表
第一张是Ntoskrl.exe中的常用函数
第二张是Win32k.sys中的常用函数(User32.dll的底层都是使用GDI32.dll,GDI32.dll底层又是Win32k.sys)
两张系统服务表挨着放到一起,每张系统服务表占16个字节,4个4字节成员。
SystemServiceTable系统服务表的地址在_KTHREAD中0xE0偏移处存着
系统服务号如何索引
系统服务号下标为12的位 :如果是0,就在第一张系统服务表,为1就在第二张系统服务表。
系统服务号的低12位 :就是函数地址表和函数参数表中的索引。
目标函数地址=dword ptr ds:[函数地址表地址+(0~11位索引)*4]
目标函数参数总字节数=byte ptr ds:[函数参数表地址+(0~11位索引)*1]
系统是怎么通过系统调用号查找函数的:
继续分析KiFastCallEntry和KiSystemService后续部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 nt!KiFastCallEntry+0x8d : 8053e5 cd 8b f8 mov edi,eax8053e5 cf c1ef08 shr edi,8 8053e5 d2 83e730 and edi,30 h8053e5 d5 8b cf mov ecx,edi8053e5 d7 03b ee0000000 add edi,dword ptr [esi+0E0 h]8053e5 dd 8b d8 mov ebx,eax8053e5 df 25f f0f0000 and eax,0F FFh8053e5 e4 3b 4708 cmp eax,dword ptr [edi+8 ]8053e5 e7 0f 8345fdffff jae nt!KiBBTUnexpectedRange (8053e332 ) Branchnt!KiFastCallEntry+0xad : 8053e5 ed 83f 910 cmp ecx,10 h8053e5 f0 751 a jne nt!KiFastCallEntry+0xcc (8053e60 c) Branchnt!KiFastCallEntry+0xb2 : 8053e5 f2 8b 0d18f0dfff mov ecx,dword ptr ds:[0F FDFF018h]8053e5 f8 33 db xor ebx,ebx8053e5 fa 0b 99700f0000 or ebx,dword ptr [ecx+0F 70h]8053e600 740 a je nt!KiFastCallEntry+0xcc (8053e60 c) Branchnt!KiFastCallEntry+0xc2 : 8053e602 52 push edx8053e603 50 push eax8053e604 ff15e43f5580 call dword ptr [nt!KeGdiFlushUserBatch (80553f e4)]8053e60 a 58 pop eax8053e60 b 5 a pop edxnt!KiFastCallEntry+0xcc : 8053e60 c ff0538f6dfff inc dword ptr ds:[0F FDFF638h]8053e612 8b f2 mov esi,edx8053e614 8b 5f0c mov ebx,dword ptr [edi+0 Ch]8053e617 33 c9 xor ecx,ecx8053e619 8 a0c18 mov cl,byte ptr [eax+ebx]8053e61 c 8b 3f mov edi,dword ptr [edi]8053e61 e 8b 1c87 mov ebx,dword ptr [edi+eax*4 ]8053e621 2b e1 sub esp,ecx8053e623 c1e902 shr ecx,2 8053e626 8b fc mov edi,esp8053e628 3b 35d4995580 cmp esi,dword ptr [nt!MmUserProbeAddress (805599 d4)]8053e62 e 0f 83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7 dc) Branchnt!KiFastCallEntry+0xf4 : 8053e634 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]8053e636 ffd3 call ebxnt!KiFastCallEntry+0xf8 : 8053e638 8b e5 mov esp,ebpnt!KiFastCallEntry+0xfa : 8053e63 a 8b 0d24f1dfff mov ecx,dword ptr ds:[0F FDFF124h]8053e640 8b 553c mov edx,dword ptr [ebp+3 Ch]8053e643 899134010000 mov dword ptr [ecx+134 h],edx8053e649 fa cli8053e64 a f7457000000200 test dword ptr [ebp+70 h],20000 h8053e651 7506 jne nt!KiServiceExit+0x10 (8053e659 ) Branchnt!KiServiceExit+0xa : 8053e653 f6456c01 test byte ptr [ebp+6 Ch],1 8053e657 7457 je nt!KiServiceExit+0x67 (8053e6 b0) Branchnt!KiServiceExit+0x10 : 8053e659 8b 1d24f1dfff mov ebx,dword ptr ds:[0F FDFF124h]8053e65 f c6432e00 mov byte ptr [ebx+2 Eh],0 8053e663 807b 4a00 cmp byte ptr [ebx+4 Ah],0 8053e667 7447 je nt!KiServiceExit+0x67 (8053e6 b0) Branchnt!KiServiceExit+0x20 : 8053e669 8b dd mov ebx,ebp8053e66 b 894344 mov dword ptr [ebx+44 h],eax8053e66 e c743503b000000 mov dword ptr [ebx+50 h],3B h8053e675 c7433823000000 mov dword ptr [ebx+38 h],23 h8053e67 c c7433423000000 mov dword ptr [ebx+34 h],23 h8053e683 c7433000000000 mov dword ptr [ebx+30 h],0 8053e68 a b901000000 mov ecx,1 8053e68 f ff15f4864d80 call dword ptr [nt!_imp_KfRaiseIrql (804 d86f4)]8053e695 50 push eax8053e696 fb sti8053e697 53 push ebx8053e698 6 a00 push 0 8053e69 a 6 a01 push 1 8053e69 c e88d03fcff call nt!KiDeliverApc (804f ea2e)8053e6 a1 59 pop ecx8053e6 a2 ff151c874d80 call dword ptr [nt!_imp_KfLowerIrql (804 d871c)]8053e6 a8 8b 4344 mov eax,dword ptr [ebx+44 h]8053e6 ab fa cli8053e6 ac ebab jmp nt!KiServiceExit+0x10 (8053e659 ) Branchnt!KiServiceExit+0x67 : 8053e6 b0 8b 54244c mov edx,dword ptr [esp+4 Ch]8053e6 b4 648b 1d50000000 mov ebx,dword ptr fs:[50 h]8053e6 bb 64891500000000 mov dword ptr fs:[0 ],edx8053e6 c2 8b 4c2448 mov ecx,dword ptr [esp+48 h]8053e6 c6 648b 3524010000 mov esi,dword ptr fs:[124 h]8053e6 cd 888e40010000 mov byte ptr [esi+140 h],cl8053e6 d3 f7c3ff000000 test ebx,0F Fh8053e6 d9 7579 jne nt!KiSystemCallExit2+0x17 (8053e754 ) Branchnt!KiServiceExit+0x92 : 8053e6 db f744247000000200 test dword ptr [esp+70 h],20000 h8053e6 e3 0f 85eb080000 jne nt!Kei386EoiHelper+0x12c (8053 efd4) Branchnt!KiServiceExit+0xa0 : 8053e6 e9 66f 744246cf8ff test word ptr [esp+6 Ch],0F FF8h8053e6 f0 0f 84b4000000 je nt!KiSystemCallExit2+0x6d (8053e7 aa) Branchnt!KiServiceExit+0xad : 8053e6 f6 66837 c246c1b cmp word ptr [esp+6 Ch],1B h 8053e6 fc 660f ba64246c00 bt word ptr [esp+6 Ch],0 8053e703 f5 cmc8053e704 0f 878e000000 ja nt!KiSystemCallExit2+0x5b (8053e798 ) Branchnt!KiServiceExit+0xc1 : 8053e70 a 66837 d6c08 cmp word ptr [ebp+6 Ch],8 8053e70 f 7405 je nt!KiServiceExit+0xcd (8053e716 ) Branchnt!KiServiceExit+0xc8 : 8053e711 8 d6550 lea esp,[ebp+50 h]8053e714 0f a1 pop fsnt!KiServiceExit+0xcd : 8053e716 8 d6554 lea esp,[ebp+54 h]8053e719 5f pop edi8053e71 a 5 e pop esi8053e71 b 5b pop ebx8053e71 c 5 d pop ebp8053e71 d 66817 c24088000 cmp word ptr [esp+8 ],80 h8053e724 0f 87c6080000 ja nt!Kei386EoiHelper+0x148 (8053 eff0) Branchnt!KiServiceExit+0xe1 : 8053e72 a 83 c404 add esp,4 8053e72 d f744240401000000 test dword ptr [esp+4 ],1 8053e735 7506 jne nt!KiSystemCallExit2 (8053e73 d) Branchnt!KiSystemCallExitBranch+0x2 : 8053e737 5 a pop edx8053e738 59 pop ecx8053e739 9 d popfd8053e73 a ffe2 jmp edxnt!KiSystemCallExit: 8053e73 c cf iretdnt!KiSystemCallExit2: 8053e73 d f644240901 test byte ptr [esp+9 ],1 8053e742 75f 8 jne nt!KiSystemCallExit (8053e73 c) Branchnt!KiSystemCallExit2+0x7 : 8053e744 5 a pop edx8053e745 83 c404 add esp,4 8053e748 80642401f d and byte ptr [esp+1 ],0F Dh8053e74 d 9 d popfd8053e74 e 59 pop ecx8053e74 f fb sti8053e750 0f 35 sysexit8053e752 cf iretdnt!KiSystemCallExit2+0x17 : 8053e754 f7457000000200 test dword ptr [ebp+70 h],20000 h8053e75 b 750 d jne nt!KiSystemCallExit2+0x2d (8053e76 a) Branchnt!KiSystemCallExit2+0x20 : 8053e75 d f7456c01000000 test dword ptr [ebp+6 Ch],1 8053e764 0f 8471ffffff je nt!KiServiceExit+0x92 (8053e6 db) Branchnt!KiSystemCallExit2+0x2d : 8053e76 a 33 db xor ebx,ebx8053e76 c 8b 7518 mov esi,dword ptr [ebp+18 h]8053e76 f 8b 7d1c mov edi,dword ptr [ebp+1 Ch]8053e772 0f 23fb mov dr7,ebx8053e775 0f 23c6 mov dr0,esi8053e778 8b 5d20 mov ebx,dword ptr [ebp+20 h]8053e77 b 0f 23cf mov dr1,edi8053e77 e 0f 23d3 mov dr2,ebx8053e781 8b 7524 mov esi,dword ptr [ebp+24 h]8053e784 8b 7d28 mov edi,dword ptr [ebp+28 h]8053e787 8b 5d2c mov ebx,dword ptr [ebp+2 Ch]8053e78 a 0f 23de mov dr3,esi8053e78 d 0f 23f7 mov dr6,edi8053e790 0f 23fb mov dr7,ebx8053e793 e943ffffff jmp nt!KiServiceExit+0x92 (8053e6 db) Branchnt!KiSystemCallExit2+0x5b : 8053e798 8b 442444 mov eax,dword ptr [esp+44 h]8053e79 c 83 c430 add esp,30 h8053e79 f 0f a9 pop gs8053e7 a1 07 pop es8053e7 a2 1f pop ds8053e7 a3 5 a pop edx8053e7 a4 59 pop ecx8053e7 a5 e967ffffff jmp nt!KiServiceExit+0xc8 (8053e711 ) Branchnt!KiSystemCallExit2+0x6d : 8053e7 aa 8b 5c2410 mov ebx,dword ptr [esp+10 h]8053e7 ae 895 c246c mov dword ptr [esp+6 Ch],ebx8053e7 b2 8b 5c2414 mov ebx,dword ptr [esp+14 h]8053e7 b6 83 eb0c sub ebx,0 Ch8053e7 b9 895 c2464 mov dword ptr [esp+64 h],ebx8053e7 bd 8b 742470 mov esi,dword ptr [esp+70 h]8053e7 c1 897308 mov dword ptr [ebx+8 ],esi8053e7 c4 8b 74246c mov esi,dword ptr [esp+6 Ch]8053e7 c8 897304 mov dword ptr [ebx+4 ],esi8053e7 cb 8b 742468 mov esi,dword ptr [esp+68 h]8053e7 cf 8933 mov dword ptr [ebx],esi8053e7 d1 83 c454 add esp,54 h8053e7 d4 5f pop edi8053e7 d5 5 e pop esi8053e7 d6 5b pop ebx8053e7 d7 5 d pop ebp8053e7 d8 8b 2424 mov esp,dword ptr [esp]8053e7 db cf iretdnt!KiSystemCallExit2+0x9f : 8053e7 dc f6456c01 test byte ptr [ebp+6 Ch],1 8053e7 e0 0f 844efeffff je nt!KiFastCallEntry+0xf4 (8053e634 ) Branchnt!KiSystemCallExit2+0xa9 : 8053e7 e6 b8050000c0 mov eax,0 C0000005h8053e7 eb e948feffff jmp nt!KiFastCallEntry+0xf8 (8053e638 ) Branchnt!Kei386EoiHelper+0x12c : 8053 efd4 83 c43c add esp,3 Ch8053 efd7 5 a pop edx8053 efd8 59 pop ecx8053 efd9 58 pop eax8053 efda 8 d6554 lea esp,[ebp+54 h]8053 efdd 5f pop edi8053 efde 5 e pop esi8053 efdf 5b pop ebx8053 efe0 5 d pop ebp8053 efe1 66817 c24088000 cmp word ptr [esp+8 ],80 h8053 efe8 7706 ja nt!Kei386EoiHelper+0x148 (8053 eff0) Branchnt!Kei386EoiHelper+0x142 : 8053 efea 83 c404 add esp,4 8053 efed cf iretdnt!Kei386EoiHelper+0x148 : 8053 eff0 66837 c240200 cmp word ptr [esp+2 ],0 8053 eff6 74f 2 je nt!Kei386EoiHelper+0x142 (8053 efea) Branchnt!Kei386EoiHelper+0x150 : 8053 eff8 66833 c2400 cmp word ptr [esp],0 8053 effd 75 eb jne nt!Kei386EoiHelper+0x142 (8053 efea) Branchnt!Kei386EoiHelper+0x157 : 8053 efff c12c2410 shr dword ptr [esp],10 h8053f 003 66 c7442402f800 mov word ptr [esp+2 ],0F 8h8053f 00a 660f b22424 lss sp,dword ptr [esp]8053f 00f 0f b7e4 movzx esp,sp8053f 012 cf iretd
系统调用号使用流程图
SSDT 上一章通过_kthread的0xE0偏移找到SST
其实还可以通过其他方式来访问系统服务表
就是SSDT
SSDT:System Services Descriptor Table,系统服务描述符表 。
其他两种方式查看SST 第一种方式 这种方式只能看第一张SST
1 dd KeServiceDescriptorTable
ntkrnlpa.exe或ntoskrnl.exe导出的,代码中声明一下就可以使用
KeServiceDescriptorTable是ntkrnlpa.exe或ntoskrnl.exe导出的全局变量
第二种方式 这种方式两张SST都有
1 dd KeServiceDescriptorTableShadow
KeServiceDescriptorTableShadow是Win32k.sys导出的
代码中要自己通过内存搜索的方式到Win32k.sys的导出表中找到他的地址。
课后练习 在SSDT表中追加一个函数地址(NtReadVirtualMemory),自己编写API的3环部分调用这个新增的函数(注意使用2-9-9-12分页,因为10-10-12分页会有蓝屏现象(调用返回还没涉及)
R0代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <ntddk.h> VOID DriverUnload (PDRIVER_OBJECT driver) { DbgPrint("停止运行了\n" ); } typedef struct _SST { ULONG ServiceTable; ULONG Count; ULONG ServiceLimit; ULONG ArgmentTable; }SST; extern ULONG KeServiceDescriptorTable;NTSTATUS DriverEntry (PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg) { pdriver->DriverUnload = DriverUnload; SST* sst1 = (SST*)KeServiceDescriptorTable; ULONG num = sst1->ServiceLimit; ULONG ftAddr = sst1->ServiceTable; ULONG ftArgAddr = sst1->ArgmentTable; DbgPrint("原来共有%d个函数\n" , num); DbgPrint("修改的函数地址位置:%p\n" , (*(ULONG*)sst1) + num * 4 ); DbgPrint("修改的函数参数位置:%p\n" , (*(ULONG*)((ULONG)sst1 + 0xC )) + num); __asm { pushad; mov eax, dword ptr ds : [ftArgAddr] ; mov ecx, dword ptr ds : [num] ; mov edx, 0xBA ; mov bl, byte ptr ds : [eax + edx] ; lea edi, dword ptr ds : [eax + ecx] ; mov byte ptr ds : [edi] , bl; mov eax, dword ptr ds : [ftAddr] ; shl edx, 2 ; mov ebx, dword ptr ds : [eax + edx] ; shl ecx, 2 ; lea edi, dword ptr ds : [eax + ecx] ; mov dword ptr ds : [edi] , ebx; mov eax, dword ptr ds : [sst1] ; add eax, 0x8 ; add dword ptr ds : [eax] , 1 ; popad; } return STATUS_SUCCESS; }
R3代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <Windows.h> void __stdcall myReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead ) { __asm { push lpNumberOfBytesRead; push nSize; push lpBuffer; push lpBaseAddress; push hProcess; mov eax,0x11c ; lea edx,dword ptr [esp]; int 0x2E ; add esp,0x14 ; } } void main () { int a=300 ; SIZE_T haveRead; HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,NULL ,1552 ); myReadProcessMemory(hProcess,(LPVOID)0x12ff7c ,&a,4 ,&haveRead); printf ("old a:300 new a after readMemory:%d" ,a); system("pause" ); }
修改后函数个数:
关于API调用返回的问题:学完APC后再分析
SSDT HOOK
优点:挂起来很容易,并且非常稳定
缺点:容易被发现,容易被绕过,只能HOOK系统服务表里的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct _KSYSTEM_SERVICE_TABLE //对应SST { PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; PULONG ParamTableBase; } KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE; typedef struct _KSERVICE_TABLE_DESCRIPTOR //对应SSDT { KSYSTEM_SERVICE_TABLE ntoskrnl; KSYSTEM_SERVICE_TABLE win32k; KSYSTEM_SERVICE_TABLE notUsed1; KSYSTEM_SERVICE_TABLE notUsed2; }KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR; extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
通过页表基址修改页属性 SSDT所在物理页是只读的,如果要修改别的进程(修改自己进程无所谓),先要修改页属性为可写的,两种方法
第一种办法 用我们学过的知识,通过页表基址直接修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if (RCR4 & 0x00000020 ){ KdPrint(("2-9-9-12分页 %p\n" ,RCR4)); KdPrint(("PTE1 %p\n" ,*(DWORD*)(0xC0000000 + ((HookFunAddr >> 9 ) & 0x007FFFF8 )))); *(DWORD64*)(0xC0000000 + ((HookFunAddr >> 9 ) & 0x007FFFF8 )) |= 0x02 ; KdPrint(("PTE1 %p\n" ,*(DWORD*)(0xC0000000 + ((HookFunAddr >> 9 ) & 0x007FFFF8 )))); } else { KdPrint(("10-10-12分页\n" )); KdPrint(("PTE1 %p\n" ,*(DWORD*)(0xC0000000 + ((HookFunAddr >> 10 ) & 0x003FFFFC )))); *(DWORD*)(0xC0000000 + ((HookFunAddr >> 10 ) & 0x003FFFFC )) |= 0x02 ; KdPrint(("PTE2 %p\n" ,*(DWORD*)(0xC0000000 + ((HookFunAddr >> 10 ) & 0x003FFFFC )))); }
这种方式的好处是不用关心是单核还是多核
第二种方法 通过修改CR0寄存器的WP位
由于修改的CR0寄存器每个核都有一个,这个修改的过程中,如果发生核的切换(cli只是线程无法切换了)多核还是可能切换,导致WP位并未修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 VOID PageProtectOn () { __asm{ mov eax,cr0 or eax,10000 h mov cr0,eax sti } } VOID PageProtectOff () { __asm{ cli mov eax,cr0 and eax,not 10000 h mov cr0,eax } } PageProtectOff(); PageProtectOn();
改代码的一瞬间如果并未有核的切换就没问题。不然就会出问题。
SSDT HOOK实验 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 #include <ntddk.h> typedef struct _KSYSTEM_SERVICE_TABLE //对应SST { PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; PULONG ParamTableBase; } KSYSTEM_SERVICE_TABLE, * PKSYSTEM_SERVICE_TABLE; typedef struct _KSERVICE_TABLE_DESCRIPTOR //对应SSDT { KSYSTEM_SERVICE_TABLE ntoskrnl; KSYSTEM_SERVICE_TABLE win32k; KSYSTEM_SERVICE_TABLE notUsed1; KSYSTEM_SERVICE_TABLE notUsed2; }KSERVICE_TABLE_DESCRIPTOR, * PKSERVICE_TABLE_DESCRIPTOR; extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;VOID PageProtectOn () { __asm { mov eax, cr0 or eax, 10000 h mov cr0, eax sti } } VOID PageProtectOff () { __asm { cli mov eax, cr0 and eax, not 10000 h mov cr0, eax } } ULONG oldNtReadVirtualMemoryAdd = NULL ; NTSTATUS __stdcall MYNtReadVirtualMemory ( HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength) { DbgPrint("someOne use NtReadVirtualMemory---SSDT HOOK\n" ); NTSTATUS result = 0 ; __asm { push ReturnLength; push BufferLength; push Buffer; push BaseAddress; push ProcessHandle; call oldNtReadVirtualMemoryAdd; mov result, eax; } return result; } VOID DriverUnload (PDRIVER_OBJECT driver) { if (oldNtReadVirtualMemoryAdd) { PageProtectOff(); KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBA ] = oldNtReadVirtualMemoryAdd; PageProtectOn(); oldNtReadVirtualMemoryAdd = NULL ; } DbgPrint("停止运行了\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg) { pdriver->DriverUnload = DriverUnload; oldNtReadVirtualMemoryAdd = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBA ]; DbgPrint("修改位置为:%p\n" , &(KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBA ])); DbgPrint("原函数地址为:%p\n" , oldNtReadVirtualMemoryAdd); PageProtectOff(); KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBA ] = MYNtReadVirtualMemory; PageProtectOn(); DbgPrint("修改后的函数地址为:%p\n" , KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBA ]); return STATUS_SUCCESS; }
如图,SSDT HOOK成功实现,但也被pc hunter轻易发现。
SSDT HOOK隐藏 先做自己的进程,非全局
首先找到自己的进程,进程遍历
遍历线程
替换_KTHREAD的0xE0存的SSDT表
定时器
后续回头做
系统调用第二天1小时28分逆向调用返回。(未完就绪)
_KiFastCallEntry由三部分组成
创建_KTRAP_FRAME结构备份三环信息
根据系统调用号调用内核中的服务过程
通过1步骤备份的_KTRAP_FRAME结构体返回3环(_KiServiceExit)
ZW系列内核函数和NT系列内核函数的区别 在ring3层,这两组函数确实是同一个函数,用u命令对NtReadFile以及ZwReadFile反汇编发现,他们的起始地址是一样的。调用ntdll.dll这个动态库的函数时,声明成这两种形式都可以,不过按照微软的说法,声明成Nt函数更恰当些,Zw开头的函数表示的是内核函数。熟悉ntdll.dll这个动态库的人都知道,其实这个库里面的函数都是stub函数,并不做实际功能,只是系统调用进入内核的入口。
到了ring0层情况就不同了,两种形式的函数是不同的函数,Nt开头的函数是真正执行功能的函数。应用层所用的系统API都会通过int 2e或者sysenter指令切换到内核,然后调用内核导出的Nt系列函数。分析SSDT表即可以得出这个结论。
而对于内核态的Zw开头的函数,通过汇编也可以发现,它的结构与ntdll.dll里面的函数类似,最后都会调用对应的内核nt函数,只不过已经在内核态,就没有int 2e这种切换状态的指令,也没有陷阱帧,但调用形式差不多,都是通过调用号来从SSDT中找到实现功能的Nt函数。微软建议内核开发者使用Zw系列的函数,因为这些函数多了一些参数检查的代码。