首页
论坛
课程
招聘
内核学习-系统调用上
2021-7-20 20:44 1564

内核学习-系统调用上

2021-7-20 20:44
1564

双机调试配置参看我的另一篇文章[原创]内核学习-双机调试环境搭建-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com,基于xp sp3系统

系统调用的学习

在这里插入图片描述

 

分析ReadProcessMemory了解系统调用

一:分析ReadProcessMemory

ida打开kernel32.dll(ReadProcessMemory函数在这个dll里)

 

在这里插入图片描述

 

参数压栈,call NTReadVirtualMemory,跳转至loc_7C802204

 

loc_7C802204调用了sub_7C8093FD

 

在这里插入图片描述

 

sub_7C8093FD内部调用了另一个函数RtlNtStatusToDosError

 

在这里插入图片描述

 

这个函数的作用是设置错误号

 

从sub_7C8093FD出来后,将eax清零,跳转到loc_7C8021F9

 

在这里插入图片描述

 

返回

 

 

当调用ReadProcessMemory失败时,返回结果为0,若NtReadVirtualMemory返回结果大于等于0,返回结果为1

 

ReadProcessMemory函数在kernel32.dll中只是调用了NtReadVirtualMemory,然后设置了返回值

二:分析NtReadVirtualMemory

在ntdll.dll中,Ntdll.dll:大多数API都会通过这个DLL进入内核(0环)

 

在这里插入图片描述
在这里插入图片描述

1
2
3
4
.text:7C92D9E0                 mov     eax, 0BAh       系统调用号,对应操作系统内核中某个函数的编号
.text:7C92D9E5                 mov     edx, 7FFE0300h  函数地址,该函数决定了我们用什么方式进0
.text:7C92D9EA                 call    dword ptr [edx]
.text:7C92D9EC                 retn    14h

真正读取进程内存的函数在0环实现,我们所用的函数只是系统提供给我们的函数接口

三:进入0环的两种方式

在这里插入图片描述

基本概念:

_KUSER_SHARED_DATA结构体

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
nt!_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       : ntdll.dll!KiFastSystemCall()/ ntdll.dll!KiIntSystemCall()
   +0x304 SystemCallReturn : Uint4B
   +0x308 SystemCallPad    : [3] Uint8B
   +0x320 TickCount        : _KSYSTEM_TIME
   +0x320 TickCountQuad    : Uint8B
   +0x330 Cookie           : Uint4B

该数据结构是三环与零环的共享内存。

 

它们使用固定的地址值映射,_KUSER_SHARED_DATA结构区域在User层Kernel层地址分别为:
User:0x7ffe0000
Kernnel:0xffdf0000

 

指向的是同一个物理页,但是在user层是只读,在kernel层是可读可写的。

 

此结构体由操作系统负责初始化,其偏移 0x300 处有一个 SystemCall 属性,是个函数指针。

sysenter/sysexit指令

sysenter 指令可用于特权级 3 的用户代码调用特权级 0 的系统内核代码,而 SYSEXIT 指令则用于特权级 0 的系统代码返回用户空间中。sysenter 指令可以在 3,2,1 这三个特权级别调用(Linux 中只用到了特权级 3),而 SYSEXIT 指令只能从特权级 0 调用。

 

描述:当操作系统初始化时,其会通过CPUID指令查询当前CPU是否支持快速调用,如果支持则这里填写通过快速调用进入零环,否则通过中断进入零环。

 

可以设置eax=1,执行cpuid指令,处理器的特征信息被放在ecx和edx寄存器中,其中edx包含了一个SEP位(第11位),该位指明了当前处理器知否支持sysenter/sysexit指令,SEP=1,说明当前CPU支持 sysenter / sysexit 指令。以此来自行查看前处理器是否支持sysenter/sysexit指令。

 

当CPU支持快读调用,SystemCall 指向 ntdll.dll!KiFastSystemCall()
当CPU不支持快速调用,SystemCall 指向 ntdll.dll!KiIntSystemCall()

R3------>R0

  1. CS的权限由3变为0,意味着需要新的CS
  2. SS与CS的权限永远一致,需要新的SS
  3. 权限发生切换的时候,堆栈也一定会切换,需要新的ESP
  4. 进0环后会修改EIP

(1)int 2e

分析KiIntSystemCall

 

所有的API进内核时,统一的中断号为0x2e

 

在执行KiIntSystemCall函数前,系统调用号已被写入EAX

分析 INT 0x2E

在IDT表中找到0x2E号门描述符:2E 右移3位(或者乘8)得到 0x170,加上 r idtr获取的IDT基址,可以计算出 2E号中断对应的描述符:8053ee000008e481

 

门描述符:8053ee000008e481
指向地址:8053e481

 

 

CS:门描述符的段选择子部分(0008)(系统代码段)

 

查看eip

1
kd> u 8053e481

在这里插入图片描述

 

 

 

TSS描述符是 80008b04`200020ab,所以TSS的地址就是 80042000

 

 

所以ESP = 8054acf0, SS= 0010

 

小结:

  1. 固定中断号为0x2E
  2. CS/EIP由门描述符提供,ESP/SS由TSS提供
  3. 进入0环后执行的内核函数:NT!KiSystemService

进0环后,原来的寄存器存在哪里?

进入0环后执行的内核函数NT!KiSystemService

 

(2)sysenter

mov edx,esp 三环栈顶值传给edx,此时eax中已经是系统调用号
sysenter指令 寄存器数据传递

 

sysenter 是从 MSR 寄存器里读取 CS,ESP,EIP(MSR寄存器里的值,则是系统启动时就已经填好)

 

相关的MSR寄存器的值

 

 

可以通过RDMSR/WRMST来进行读写(操作系统使用WRMST写该寄存器):

1
2
3
kd> rdmsr 174 //查看CS
kd> rdmsr 175 //查看ESP
kd> rdmsr 176 //查看EIP

查看eip所在地址的反汇编:

 

 

 

SS= IA32_SYSENTER_CS + 8

四:小结

3环进0环的两种方式,分别是中断门和快速调用,CPU支持快速调用,那么_KUSER_SHARED_DATA 结构体的 SystemCall 属性指向的函数是 KiFastSystemCall,执行 KiFastSystemCall,使用快速调用的方式进0环;如果不支持,那么SystemCall 指向的函数是KiIntSystemCall,执行 KiIntSystemCall,使用中断门的方式进0环。

 

KiFastSystemCall:KiIntSystemCall:

 

 

两个函数的共同点:

 

1.更改4个寄存器:SS CS EIP ESP,进入0环。

 

两个函数的区别:

 

1.快速调用不需要访问内存,而中断门需要读TSS和IDT表

 

2.int 0x2e 和 sysenter 指令进0环后,分别调用了两个函数 KiSystemService 和 KiFastCallEntry。

五:填充_KTRAP_FRAME结构体

中断门

int 0x2e进0环后调用函数KiSystemService

分析KiSystemService

_Trap_Frame 和0环栈密切相关。用户定义中断进0环,涉及提权时,CPU会把5个寄存器的值压入0环堆栈。EIP CS SS EFLAG ESP

 

线程切换时会修改TSS表,确保每个线程执行时,TSS里的ESP,SS都对应当前线程。

 

基本概念:

 

_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
nt!_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

_KPCR
KPCR(Processor Control Region)是CPU控制区的意思,每个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
nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : Ptr32 _KPCR
   +0x020 Prcb             : Ptr32 _KPRCB
   +0x024 Irql             : UChar
   +0x028 IRR              : Uint4B
   +0x02c IrrActive        : Uint4B
   +0x030 IDR              : Uint4B
   +0x034 KdVersionBlock   : Ptr32 Void
   +0x038 IDT              : Ptr32 _KIDTENTRY
   +0x03c GDT              : Ptr32 _KGDTENTRY
   +0x040 TSS              : Ptr32 _KTSS
   +0x044 MajorVersion     : Uint2B
   +0x046 MinorVersion     : Uint2B
   +0x048 SetMember        : Uint4B
   +0x04c StallScaleFactor : Uint4B
   +0x050 DebugActive      : UChar
   +0x051 Number           : UChar
   +0x052 Spare0           : UChar
   +0x053 SecondLevelCacheAssociativity : UChar
   +0x054 VdmAlert         : Uint4B
   +0x058 KernelReserved   : [14] Uint4B
   +0x090 SecondLevelCacheSize : Uint4B
   +0x094 HalReserved      : [16] Uint4B
   +0x0d4 InterruptMode    : Uint4B
   +0x0d8 Spare1           : UChar
   +0x0dc KernelReserved2  : [17] Uint4B
   +0x120 PrcbData         : _KPRCB

_NT_TIB
主要存储了SEH结构化异常链表和一个指向自己的指针。

1
2
3
4
5
6
7
8
9
nt!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +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
nt!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD
   +0x010 Number           : Char
   +0x011 Reserved         : Char
   +0x012 BuildType        : Uint2B
   +0x014 SetMember        : Uint4B
   +0x018 CpuType          : Char
   +0x019 CpuID            : Char
   +0x01a CpuStep          : Uint2B
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] Uint4B
   +0x37c HalReserved      : [16] Uint4B
   +0x3bc PrcbPad0         : [92] UChar
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8] UChar
   +0x4a0 NpxThread        : Ptr32 _KTHREAD
   +0x4a4 InterruptCount   : Uint4B
   +0x4a8 KernelTime       : Uint4B
   +0x4ac UserTime         : Uint4B
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   +0x4b8 InterruptTime    : Uint4B
   +0x4bc AdjustDpcThreshold : Uint4B
   +0x4c0 PageColor        : Uint4B
   +0x4c4 SkipTick         : Uint4B
   +0x4c8 MultiThreadSetBusy : UChar
   +0x4c9 Spare2           : [3] UChar
   +0x4cc ParentNode       : Ptr32 _KNODE
   +0x4d0 MultiThreadProcessorSet : Uint4B
   +0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
   +0x4d8 ThreadStartCount : [2] Uint4B
   +0x4e0 CcFastReadNoWait : Uint4B
   +0x4e4 CcFastReadWait   : Uint4B
   +0x4e8 CcFastReadNotPossible : Uint4B
   +0x4ec CcCopyReadNoWait : Uint4B
   +0x4f0 CcCopyReadWait   : Uint4B
   +0x4f4 CcCopyReadNoWaitMiss : Uint4B
   +0x4f8 KeAlignmentFixupCount : Uint4B
   +0x4fc KeContextSwitches : Uint4B
   +0x500 KeDcacheFlushCount : Uint4B
   +0x504 KeExceptionDispatchCount : Uint4B
   +0x508 KeFirstLevelTbFills : Uint4B
   +0x50c KeFloatingEmulationCount : Uint4B
   +0x510 KeIcacheFlushCount : Uint4B
   +0x514 KeSecondLevelTbFills : Uint4B
   +0x518 KeSystemCalls    : Uint4B
   +0x51c SpareCounter0    : [1] Uint4B
   +0x520 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x7a0 PacketBarrier    : Uint4B
   +0x7a4 ReverseStall     : Uint4B
   +0x7a8 IpiFrame         : Ptr32 Void
   +0x7ac PrcbPad2         : [52] UChar
   +0x7e0 CurrentPacket    : [3] Ptr32 Void
   +0x7ec TargetSet        : Uint4B
   +0x7f0 WorkerRoutine    : Ptr32     void
   +0x7f4 IpiFrozen        : Uint4B
   +0x7f8 PrcbPad3         : [40] UChar
   +0x820 RequestSummary   : Uint4B
   +0x824 SignalDone       : Ptr32 _KPRCB
   +0x828 PrcbPad4         : [56] UChar
   +0x860 DpcListHead      : _LIST_ENTRY
   +0x868 DpcStack         : Ptr32 Void
   +0x86c DpcCount         : Uint4B
   +0x870 DpcQueueDepth    : Uint4B
   +0x874 DpcRoutineActive : Uint4B
   +0x878 DpcInterruptRequested : Uint4B
   +0x87c DpcLastCount     : Uint4B
   +0x880 DpcRequestRate   : Uint4B
   +0x884 MaximumDpcQueueDepth : Uint4B
   +0x888 MinimumDpcRate   : Uint4B
   +0x88c QuantumEnd       : Uint4B
   +0x890 PrcbPad5         : [16] UChar
   +0x8a0 DpcLock          : Uint4B
   +0x8a4 PrcbPad6         : [28] UChar
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : Ptr32 Void
   +0x8e4 LookasideIrpFloat : Int4B
   +0x8e8 SpareFields0     : [6] Uint4B
   +0x900 VendorString     : [13] UChar
   +0x90d InitialApicId    : UChar
   +0x90e LogicalProcessorsPerPhysicalProcessor : UChar
   +0x910 MHz              : Uint4B
   +0x914 FeatureBits      : Uint4B
   +0x918 UpdateSignature  : _LARGE_INTEGER
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE

_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
nt!_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

 

存储的是线程相关的状态

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
nt!_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
KiSystemService 函数如何初始化 _KTRAP_FRAME

中断门进0环后,新的ESP指向偏移 0x068(Eip)处!!!!!!

 

在这里插入图片描述

 

通过中断门的方式进入内核的时候,SS CS EIP ESP EFLAG的值已经存在 _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
.text:00407631 ; =============== S U B R O U T I N E =======================================
.text:00407631
.text:00407631
.text:00407631 _KiSystemService proc near              ; CODE XREF: ZwAcceptConnectPort(x,x,x,x,x,x)+Cp
.text:00407631                                        ; ZwAccessCheck(x,x,x,x,x,x,x,x)+Cp ...
.text:00407631
.text:00407631 var_104         = dword ptr -104h
.text:00407631 var_100         = dword ptr -100h
.text:00407631 var_D0          = dword ptr -0D0h
.text:00407631 var_CC          = dword ptr -0CCh
.text:00407631 var_C8          = dword ptr -0C8h
.text:00407631 var_B0          = dword ptr -0B0h
.text:00407631 var_AC          = dword ptr -0ACh
.text:00407631 var_A8          = dword ptr -0A8h
.text:00407631 var_A3          = byte ptr -0A3h
.text:00407631 var_73          = byte ptr -73h
.text:00407631 arg_0           = dword ptr  4
.text:00407631 arg_64          = dword ptr  68h
.text:00407631 arg_69          = byte ptr  6Dh
.text:00407631
.text:00407631                 push    0               ; _KTRAP_FRAME  0x064 ErrCode 错误码置为0
.text:00407633                 push    ebp             ; 保存3环寄存器的值
.text:00407634                 push    ebx
.text:00407635                 push    esi
.text:00407636                 push    edi
.text:00407637                push    fs
.text:00407639                 mov     ebx, 30h          ;30h段选择子 0011 0000:索引为6,GDT表,运行级别为0
.text:0040763E                 mov     fs, bx          ; 设置 fs 为 0x30
.text:0040763E                                          ; 根据段选择子查GDT表得到对应的段描述符 ffc093df`f0000001
.text:0040763E                                          ; fs.base = ffdff000,指向当前CPU的KPCR结构
.text:00407640                assume fs:nothing
.text:00407640                 push    dword ptr ds:0FFDFF000h ; 保存旧的 ExceptionList,然后把新的清成-1,_KPCR+0X00->_NT_TIB->ExecotionList
.text:00407646                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh
.text:00407650               mov     esi, ds:0FFDFF124h ; esi 指向 CurrentThread(0FFDFF124h:_KPCR+0x124=_KPCR+0x120+0x004->_KPRCB+0X004->CurrentThread)
.text:00407656                 push    dword ptr [esi+140h] ; 保存 CurrentThread.PreviousMode
.text:00407656                                        ; PreviousMode = 0 表示从0环调用过来
.text:00407656                                         ; PreviousMode != 0 表示从3环调用过来
.text:0040765C                 sub     esp, 48h        ; esp 指向 _KTRAP_FRAME
.text:0040765F                 mov     ebx, [esp+68h+arg_0];arg_0:4,[esp+6c]->Segcs(三环原来的cs的值)
.text:00407663                 and     ebx, 1          ;0环最低位为03环最低位为1
.text:00407666                 mov     [esi+140h], bl  ; 旧CS 与 1 的结果存入 PreviousMode
.text:0040766C                 mov     ebp, esp        ; ebp 指向 _KTRAP_FRAME
.text:0040766E                mov     ebx, [esi+134h]    ;_ETHREAD+0x00+0x134->_KTHERAD+0x134-> TrapFrame
.text:00407674                 mov     [ebp+3Ch], ebx  ; [ebp+3Ch]:_KTRAP_FRAME.Edx , ebx是指向原来的TrapFrame
.text:00407677                 mov     [esi+134h], ebp ;_ETHREAD+0x00+0x134->_KTHERAD+0x134-> TrapFrame 指向当前 _KTRAP_FRAME
.text:0040767D                cld                     ; df = 0
.text:0040767E                 mov     ebx, [ebp+60h]  ;[ebp+60h]:_KTRAP_FRAME.EBP(3环ebp) ,ebp 指向 _KTRAP_FRAME
.text:00407681                 mov     edi, [ebp+68h]  ;[ebp+68h]:_KTRAP_FRAME.EIP(3环eip)
.text:00407684                mov     [ebp+0Ch], edx  ; _KTRAP_FRAME.DbgArgPointer = edx
.text:00407684                                         ; 这一步是保存3环API参数指针
.text:00407687                mov     dword ptr [ebp+8], 0BADB0D00h; _KTRAP_FRAME.DbgArgMark
.text:0040768E                mov     [ebp+0], ebx    ; _KTRAP_FRAME.DbgEbp = _KTRAP_FRAME.Ebp
.text:00407691                mov     [ebp+4], edi    ; _KTRAP_FRAME.DbgEip = _KTRAP_FRAME.Eip
.text:00407694                test    byte ptr [esi+2Ch], 0FFh;_ETHREAD+0x00+0x2c->_KTHERAD+0x2c->DebugActive ,
.text:00407698                jnz     Dr_kss_a        ; 测试 CurrentThread.DebugActive
.text:0040769E                                        ; 如果处于调试状态(结果不为-1),跳转,跳转后的代码主要是保存调试相关的寄存器(DR0-DR7)到 _KTRAP_FRAME.DR0-_KTRAP_FRAME.DR7
.text:0040769E
.text:0040769E loc_4664EF:                             ; CODE XREF: Dr_kss_a+10j
.text:0040769E                                         ; Dr_kss_a+7Cj
.text:0040769E                 sti                     ; 关闭中断
.text:0040769F                jmp     loc_407781
.text:0040769F _KiSystemService endp

解析:00407631 --00407637:设置_KTRAP_FRAME结构体的下图中的成员

 

在这里插入图片描述

 

00407639 :fs.base = ffdff000,指向当前CPU的KPCR结构

 

在这里插入图片描述

 

在3环fs指向TEB结构,进入0环,fs指向KPCR结构体(通过段描述符),

 

00407650:esi 指向CurrentThread(当前cpu所执行线程的_ETHREAD)

 

00407656 : push dword ptr [esi+140h]:_ETHREAD+0x00+0x140->_KTHERAD+0x140-> PreviousMode(原来的先前模式)

 

00407640 压栈 ExceptionList->ExceptionList

 

00407656 压栈 PreviousMode->PreviousPreviousMode

 

在这里插入图片描述

 

0040765C:sub esp, 48h ;提升48h后 esp指向 _KTRAP_FRAME

 

在这里插入图片描述

 

00407698 jnz Dr_kss_a;保存调试相关的寄存器(DR0-DR7)到 _KTRAP_FRAME.DR0-_KTRAP_FRAME.DR7

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
.text:0040752C Dr_kss_a        proc near               ; CODE XREF: _KiSystemService+67↓j
.text:0040752C                 test    dword ptr [ebp+70h], 20000h
.text:00407533                 jnz     short loc_407542
.text:00407535                 test    dword ptr [ebp+6Ch], 1
.text:0040753C                 jz      loc_40769E
.text:00407542
.text:00407542 loc_407542:                             ; CODE XREF: Dr_kss_a+7↑j
.text:00407542                 mov     ebx, dr0
.text:00407545                 mov     ecx, dr1
.text:00407548                 mov     edi, dr2
.text:0040754B                 mov     [ebp+18h], ebx
.text:0040754E                 mov     [ebp+1Ch], ecx
.text:00407551                 mov     [ebp+20h], edi
.text:00407554                 mov     ebx, dr3
.text:00407557                 mov     ecx, dr6
.text:0040755A                 mov     edi, dr7
.text:0040755D                 mov     [ebp+24h], ebx
.text:00407560                 mov     [ebp+28h], ecx
.text:00407563                 xor     ebx, ebx
.text:00407565                 mov     [ebp+2Ch], edi
.text:00407568                 mov     dr7, ebx
.text:0040756B                 mov     edi, large fs:20h
.text:00407572                 mov     ebx, [edi+2F8h]
.text:00407578                 mov     ecx, [edi+2FCh]
.text:0040757E                 mov     dr0, ebx
.text:00407581                 mov     dr1, ecx
.text:00407584                 mov     ebx, [edi+300h]
.text:0040758A                 mov     ecx, [edi+304h]
.text:00407590                 mov     dr2, ebx
.text:00407593                 mov     dr3, ecx
.text:00407596                 mov     ebx, [edi+308h]
.text:0040759C                 mov     ecx, [edi+30Ch]
.text:004075A2                 mov     dr6, ebx
.text:004075A5                 mov     dr7, ecx
.text:004075A8                 jmp     loc_40769E
.text:004075A8 Dr_kss_a        endp
.text:004075A8
.text:004075A8 ; ---------------------------------------------------------------------------
.text:004075AD                 align 10h
.text:004075B0
.text:004075B0 ; =============== S U B R O U T I N E =======================================

0040769F jmp loc_407781;可以发现跳转到了_KiFastCallEntry函数内部(不同的方式保存寄存器,但是最后执行的代码是一样的),因为_KiIntSystemCall与KiFastSystemCall对于寄存器的处理不同,所以需要使用_KiFastCallEntry,KiSystemService两个函数填充_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
.text:004076F0 ; =============== S U B R O U T I N E =======================================
.text:004076F0
.text:004076F0
.text:004076F0 _KiFastCallEntry proc near              ; DATA XREF: _KiTrap01+6F↓o
.text:004076F0                                         ; KiLoadFastSyscallMachineSpecificRegisters(x)+24↓o
.text:004076F0
.text:004076F0 var_B           = byte ptr -0Bh
.text:004076F0
.text:004076F0 ; FUNCTION CHUNK AT .text:004076C8 SIZE 00000023 BYTES
.text:004076F0 ; FUNCTION CHUNK AT .text:00407990 SIZE 00000014 BYTES
.text:004076F0
.text:004076F0                 mov     ecx, 23h
.text:004076F5                 push    30h
.text:004076F7                 pop     fs
.text:004076F9                 mov     ds, ecx
.text:004076FB                 mov     es, ecx
.text:004076FD                 mov     ecx, ds:0FFDFF040h
.text:00407703                 mov     esp, [ecx+4]
.text:00407706                 push    23h
.text:00407708                 push    edx
.text:00407709                 pushf
.text:0040770A
.text:0040770A loc_40770A:                             ; CODE XREF: _KiFastCallEntry2+22↑j
.text:0040770A                 push    2
.text:0040770C                 add     edx, 8
.text:0040770F                 popf
.text:00407710                 or      [esp+0Ch+var_B], 2
.text:00407715                 push    1Bh
.text:00407717                 push    dword ptr ds:0FFDF0304h
.text:0040771D                 push    0
.text:0040771F                 push    ebp
.text:00407720                 push    ebx
.text:00407721                 push    esi
.text:00407722                 push    edi
.text:00407723                 mov     ebx, ds:0FFDFF01Ch
.text:00407729                 push    3Bh
.text:0040772B                 mov     esi, [ebx+124h]
.text:00407731                 push    dword ptr [ebx]
.text:00407733                 mov     dword ptr [ebx], 0FFFFFFFFh
.text:00407739                 mov     ebp, [esi+18h]
.text:0040773C                 push    1
.text:0040773E                 sub     esp, 48h
.text:00407741                 sub     ebp, 29Ch
.text:00407747                 mov     byte ptr [esi+140h], 1
.text:0040774E                 cmp     ebp, esp
.text:00407750                 jnz     loc_4076C8
.text:00407756                 and     dword ptr [ebp+2Ch], 0
.text:0040775A                 test    byte ptr [esi+2Ch], 0FFh
.text:0040775E                 mov     [esi+134h], ebp
.text:00407764                 jnz     Dr_FastCallDrSave
.text:0040776A
.text:0040776A loc_40776A:                             ; CODE XREF: Dr_FastCallDrSave+10↑j
.text:0040776A                                         ; Dr_FastCallDrSave+7C↑j
.text:0040776A                 mov     ebx, [ebp+60h]
.text:0040776D                 mov     edi, [ebp+68h]
.text:00407770                 mov     [ebp+0Ch], edx
.text:00407773                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:0040777A                 mov     [ebp+0], ebx
.text:0040777D                 mov     [ebp+4], edi
.text:00407780                 sti
.text:00407781
.text:00407781 loc_407781:                             ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00407781                                         ; _KiSystemService+6E↑j
.text:00407781                 mov     edi, eax
.text:00407783                 shr     edi, 8
.text:00407786                 and     edi, 30h
.text:00407789                 mov     ecx, edi
.text:0040778B                 add     edi, [esi+0E0h]
.text:00407791                 mov     ebx, eax
.text:00407793                 and     eax, 0FFFh
.text:00407798                 cmp     eax, [edi+8]
.text:0040779B                 jnb     _KiBBTUnexpectedRange
.text:004077A1                 cmp     ecx, 10h
.text:004077A4                 jnz     short loc_4077C0
.text:004077A6                 mov     ecx, ds:0FFDFF018h
.text:004077AC                 xor     ebx, ebx
.text:004077AE
.text:004077AE loc_4077AE:                             ; DATA XREF: _KiTrap0E+110↓o
.text:004077AE                 or      ebx, [ecx+0F70h]
.text:004077B4                 jz      short loc_4077C0
.text:004077B6                 push    edx
.text:004077B7                 push    eax
.text:004077B8                 call    ds:_KeGdiFlushUserBatch
.text:004077BE                 pop     eax
.text:004077BF                 pop     edx
.text:004077C0
.text:004077C0 loc_4077C0:                             ; CODE XREF: _KiFastCallEntry+B4↑j
.text:004077C0                                         ; _KiFastCallEntry+C4↑j
.text:004077C0                 inc     dword ptr ds:0FFDFF638h
.text:004077C6                 mov     esi, edx
.text:004077C8                 mov     ebx, [edi+0Ch]
.text:004077CB                 xor     ecx, ecx
.text:004077CD                 mov     cl, [eax+ebx]
.text:004077D0                 mov     edi, [edi]
.text:004077D2                 mov     ebx, [edi+eax*4]
.text:004077D5                 sub     esp, ecx
.text:004077D7                 shr     ecx, 2
.text:004077DA                 mov     edi, esp
.text:004077DC                 cmp     esi, ds:_MmUserProbeAddress
.text:004077E2                 jnb     loc_407990
.text:004077E8
.text:004077E8 loc_4077E8:                             ; CODE XREF: _KiFastCallEntry+2A4↓j
.text:004077E8                                         ; DATA XREF: _KiTrap0E+106↓o
.text:004077E8                 rep movsd
.text:004077EA                 call    ebx
.text:004077EC
.text:004077EC loc_4077EC:                             ; CODE XREF: _KiFastCallEntry+2AF↓j
.text:004077EC                                         ; DATA XREF: _KiTrap0E+126↓o ...
.text:004077EC                 mov     esp, ebp
.text:004077EE
.text:004077EE loc_4077EE:                             ; CODE XREF: _KiBBTUnexpectedRange+38↑j
.text:004077EE                                         ; _KiBBTUnexpectedRange+43↑j
.text:004077EE                 mov     ecx, ds:0FFDFF124h
.text:004077F4                 mov     edx, [ebp+3Ch]
.text:004077F7                 mov     [ecx+134h], edx
.text:004077F7 _KiFastCallEntry endp
.text:004077F7
.text:004077FD
.text:004077FD ; =============== S U B R O U T I N E =======================================

sysente

sysenter 指令进0环后调用KiFastCallEntry

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
.text:004076F0_KiFastCallEntry:                       ; DATA XREF: KiLoadFastSyscallMachineSpecificRegisters(x)+24o
.text:004076F0                                         ; _KiTrap01+72o
.text:004076F0                mov     ecx, 23h           ;让ecx存储023h(三环描述符)
.text:004076F5                 push    30h
.text:004076F7                 pop     fs              ; fs = 0x30, ffc093df`f0000001, 0环数据段
.text:004076F9                 mov     ds, ecx         ; ds = 0x23, 00cff300`0000ffff, 3环数据段
.text:004076FB                 mov     es, ecx         ; es = 0x23(es辅助ds)
.text:004076FD                 mov     ecx, ds:0FFDFF040h;将TSS地址存储在ecx中 fs:[40h]
.text:00407703                 mov     esp, [ecx+4]    ; esp = _KPCR.TSS.Esp0,切换到0环堆栈
.text:00407706                push    23h             ; _KTRAP_FRAME.HardwareSegSs = 0x23,保存旧ss
.text:00407708                 push    edx             ; _KTRAP_FRAME.HardwareEsp = edx, edx是3环栈顶,参数指针
.text:00407709                pushf                   ; _KTRAP_FRAME.EFlags = EFlags,保存3环eflag寄存器
.text:0040770A
.text:0040770A loc_46655A:                             ; CODE XREF: _KiSystemService+96j
.text:0040770A                 push    2             ;将0环eflag寄存器存储在栈中
.text:0040770C                 add     edx, 8          ; edx 指向3环API参数
.text:0040770F                 popf                    ; EFlags = 0x02,即清空0环所有标志位
.text:0040770F                                          ; 此时 esp 指向 EFlags
.text:0040770F                 or      [esp+0A4h+var_A3], 2 ; _KTRAP_FRAME.EFlags 即3环 EFlags 的 IF = 1
.text:00407715                 push    1Bh             ; _KTRAP_FRAME.SegCs = 0x1B, 3环代码段
.text:00407717                 push    dword ptr ds:0FFDF0304h ; _KTRAP_FRAME.Eip = _KUSER_SHARED_DATA.SystemCallReturn
.text:0040771D                 push    0               ; _KTRAP_FRAME.ErrCode = 0
.text:0040771F                 push    ebp             ; _KTRAP_FRAME.Ebp = ebp
.text:00407720                 push    ebx             ; _KTRAP_FRAME.Ebx = ebx
.text:00407721                 push    esi             ; _KTRAP_FRAME.Esi = esi
.text:00407722                 push    edi             ; _KTRAP_FRAME.Edi = edi
.text:00407723                 mov     ebx, ds:0FFDFF01Ch ; ebx = _KPCR.SelfPcr,即 ebx 指向 _KPCR
.text:00407729                 push    3Bh             ; _KTRAP_FRAME.SegFs = 0x3B
.text:0040772B                 mov     esi, [ebx+124h] ; esi = _KPCR._KPRCB.CurrentThread
.text:00407731                 push    dword ptr [ebx] ; _KTRAP_FRAME.ExceptionList = _KPCR.NtTib.ExceptionList
.text:00407733                 mov     dword ptr [ebx], 0FFFFFFFFh ; _KPCR.NtTib.ExceptionList = -1
.text:00407739                mov     ebp, [esi+18h]  ; ebp = _KPCR._KPRCB.CurrentThread.InitialStack
.text:0040773C                push    1               ; _KTRAP_FRAME.PreviousPreviousMode = 1,表示从3环来
.text:0040773E                 sub     esp, 48h        ; esp 指向 _KTRAP_FRAME
.text:00407741                 sub     ebp, 29Ch
.text:00407747                 mov     byte ptr [esi+140h], 1 ; CurrentThread.PreviousMode = 1,表示从3环调用来
.text:0040774E                 cmp     ebp, esp
.text:00407750                jnz     short loc_46653C ; 如果 ebp != esp,跳转到异常处理
.text:00407750                                        ; 正常情况下,esp,ebp 均指向 _KTRAP_FRAME
.text:00407756                 and     dword ptr [ebp+2Ch], 0 ; _KTRAP_FRAME.Dr7 = 0
.text:0040775A                 test    byte ptr [esi+2Ch], 0FFh
.text:0040775E                 mov     [esi+134h], ebp ; CurrentThread.TrapFrame = ebp,即指向当前 _KTRAP_FRAME
.text:00407764                 jnz     Dr_FastCallDrSave ; 如果DebugActive == 1(被调试),那么跳转到 Dr_FastCallDrSave
.text:00407764                                        ; Dr_FastCallDrSave 的功能是保存调试寄存器
.text:0040776A
.text:0040776A loc_4665B6:                             ; CODE XREF: Dr_FastCallDrSave+10j
.text:0040776A                                         ; Dr_FastCallDrSave+7Cj
.text:0040776A                 mov     ebx, [ebp+60h]
.text:0040776D                 mov     edi, [ebp+68h]
.text:00407770                 mov     [ebp+0Ch], edx  ; _KTRAP_FRAME.DbgArgPointer = edx, 保存3环参数指针
.text:00407773                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:0040777A                 mov     [ebp+0], ebx    ; _KTRAP_FRAME.DbgEbp = _KTRAP_FRAME.Ebp
.text:00040777D                mov     [ebp+4], edi    ; _KTRAP_FRAME.DbgEip = _KTRAP_FRAME.Eip
.text:00407780                sti

小结:

原来的寄存器存储到了 _Trap_Frame 结构体里,3环API参数指针通过EDX传给0环

 

##


[注意] 招人!base上海,课程运营、市场多个坑位等你投递!

最后于 2021-7-20 21:34 被pyikaaaa编辑 ,原因: 修改数据
收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 7917
活跃值: 活跃值 (7255)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
SSH山水画 活跃值 3 2021-7-22 17:38
2
0
又一个海哥子弟横空出世
游客
登录 | 注册 方可回帖
返回