В этом блоге я решил затронуть такую тему, как объекты операционной системы семейства Windows.
Очень часто начинающие программисты, да и обычные пользователи, не могут прийти к пониманию - что есть объект и для чего нужен дескриптор объекта.
Материал даётся с учётом того, читающий данный блог уверенно разбирается в языках программирования C и C++, а также знает основы внутренней архитектуры ОС Windows.
Начнём с определения объекта.
Объект - это структура данных, расположенная в памяти, которая представляет собой ресурсы системы.
Объектами можно считать: файл, поток, токен, окно, таймер и др.
Современные операционные системы (да и процессоры со своими режимами real mode, protected mode и т.д.) устроены таким образом, что приложение не может напрямую обратиться к данным объекта или системному ресурсу.
Каждый объект имеет свой собственный список управления доступом (ACL*), определяющий действия, которые процесс может выполнять над объектом.
*Система проверяет ACL объекта каждый раз, когда приложение создает дескриптор объекта.
Чтобы обратиться к данным объекта нужен некий контейнер, который будет служить своего рода описателем между тем, что хранится в объекте и тем, что запрашивает приложение* от системного ресурса этого объекта.
*Простой пример - чтение виртуальной памяти какого-либо процесса по определенному адресу.
Этим описателем является дескриптор.
Дескриптор - это описатель (контейнер) процесса, который содержит идентификатор процесса, область памяти, где размещен сегмент кода, данные приоритетности процесса, данные о состоянии процесса.
Каждый дескриптор имеет запись во внутренней таблице. Эти записи содержат адреса ресурсов и средства идентификации типа ресурса.
Существуют три группы (категории) объектов:
- User object (пользовательский объект)
- GDI object (объект графического интерфейса (или объект GDI))
- Kernel object (объект ядра)
Система использует пользовательские объекты для управления окнами, объекты GDI для графики, а объекты ядра для управления памятью, выполнения процессов и межпроцессного взаимодействия (IPC).
К пользовательским объектам можно отнести: Hook, Icon, Menu, Window и др.
К объект графического интерфейса относятся: Bitmap, Brush, Font, Pen, Metafile и др.
К объектам ядра - Token, Desktop, Event, File, Heap, Module, Mutex, Pipe, Process, Thread, Semaphore, Window station и др.
Разберёмся в основах каждой категории в отдельности.
User object. Объекты пользовательского интерфейса поддерживают только один дескриптор для каждого объекта.
Процессы не могут наследовать или дублировать дескрипторы пользовательских объектов.
Процессы в одном сеансе (session 1)* не могут ссылаться на дескриптор пользователя в другом сеансе (session 2).
*Более подробно о сессиях (сеансах) можно прочитать в моих предыдущих блогах по исследованию сервиса UI0Detect.
Дескрипторы пользовательских объектов общедоступны для всех процессов.
Любой процесс может использовать дескриптор объекта пользователя при условии, что у процесса есть безопасный доступ (security access) к объекту.
Схематично объект и его дескриптор можно представить следующим образом:

Функция CreateWindow
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
| HWND CreateWindowW(
[in, optional] LPCWSTR lpClassName,
[in, optional] LPCWSTR lpWindowName,
[in] DWORD dwStyle,
[in] int X,
[in] int Y,
[in] int nWidth,
[in] int nHeight,
[in, optional] HWND hWndParent,
[in, optional] HMENU hMenu,
[in, optional] HINSTANCE hInstance,
[in, optional] LPVOID lpParam
); |
|
создает объект окна (Window object) и возвращает дескриптор объекта (Handle).
Как можно видеть Window object хранится в ресурсах системы (в данном случае в виртуальной памяти).
После создания объекта окна приложение может использовать дескриптор окна (Handle) для отображения и\или изменения окна.
Дескриптор остается действительным до тех пор, пока объект окна не будет уничтожен функцией DestroyWindow.
Типичным примером пользовательского объекта могут служить данные процесса уровня UserMode.
В таком случае, объектом выступает структура _PEB (реверс ядра (lkd> dt nt!_PEB) Windows 11 сборка 10.0.22000.318, формат данной структуры меняется от версии к версии ОС Windows)
| C++ | 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
| typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union {
BOOLEAN BitField;
struct {
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PSLIST_HEADER AtlThunkSListPtr;
PVOID IFEOKey;
union {
ULONG CrossProcessFlags;
struct {
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ProcessImagesHotPatched : 1;
ULONG ReservedBits0 : 24;
};
};
union {
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
ULONG TlsExpansionCounter;
PRTL_BITMAP TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData;
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID* ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
SIZE_T ActiveProcessAffinityMask;
ULONG GdiHandleBuffer[60];
PVOID PostProcessInitRoutine;
PRTL_BITMAP TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo;
UNICODE_STRING CSDVersion;
PACTIVATION_CONTEXT_DATA ActivationContextData;
PASSEMBLY_STORAGE_MAP ProcessAssemblyStorageMap;
PACTIVATION_CONTEXT_DATA SystemDefaultActivationContextData;
PASSEMBLY_STORAGE_MAP SystemAssemblyStorageMap;
SIZE_T MinimumStackCommit;
PVOID SparePointers[2];
PVOID PatchLoaderData;
PCHPEV2_PROCESS_INFO ChpeV2ProcessInfo;
ULONG AppModelFeatureState;
ULONG SpareUlongs[2];
USHORT ActiveCodePage;
USHORT OemCodePage;
USHORT UseCaseMapping;
USHORT UnusedNlsField;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
PVOID EcCodeBitMap;
PVOID pImageHeaderHash;
union {
ULONG TracingFlags;
struct {
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
};
};
SIZE_T CsrServerReadOnlySharedMemoryBase;
SIZE_T TppWorkerpListLock;
LIST_ENTRY TppWorkerpList;
PVOID WaitOnAddressHashTable[128];
PVOID TelemetryCoverageHeader;
ULONG CloudFileFlags;
ULONG CloudFileDiagFlags;
CHAR PlaceholderCompatibilityMode;
CHAR PlaceholderCompatibilityModeReserved[7];
PLEAP_SECOND_DATA LeapSecondData;
union {
ULONG LeapSecondFlags;
struct {
ULONG SixtySecondEnabled : 1;
ULONG Reserved : 31;
};
};
ULONG NtGlobalFlag2;
SIZE_T ExtendedFeatureDisableMask;
} PEB, * PPEB; |
|
GDI object. Объекты GDI поддерживают только один дескриптор для каждого объекта.
Дескрипторы объектов GDI являются частными для процесса - только процесс, создавший объект GDI, может использовать дескриптор объекта.
Такие функции как CreateFont создают структуру данных в виртуальной памяти для объекта (в данном случае объект шрифта) и возвращают дескриптор для взаимодействия с созданным объектом.
Дескриптор остается действительным до тех пор, пока объект GDI не будет уничтожен функцией DeleteObject.
Kernel object. Дескрипторы объектов ядра зависят от процесса. То есть процесс должен либо создать объект, либо открыть существующий объект, чтобы получить дескриптор объекта ядра.
Любой процесс может создать новый дескриптор существующего объекта ядра (даже созданного другим процессом) при условии, что процесс знает имя объекта и имеет безопасный доступ (security access) к объекту.
Дескрипторы объектов ядра включают права доступа, которые могут быть разрешены или запрещены процессу.
Приложение определяет права доступа при создании объекта или получении дескриптора существующего объекта.
Каждый тип объекта ядра поддерживает свой собственный набор прав доступа*.
*Например, дескрипторы файлов могут иметь доступ для чтения и\или записи.
Примером объекта ядра могут служить данные процесса уровня KernelMode.
В таком случае, объектом выступает структура _EPROCESS (реверс ядра (lkd> dt nt!_EPROCESS) Windows 11 сборка 10.0.22000.318, формат данной структуры меняется от версии к версии ОС Windows)
| C++ | 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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
| typedef struct _EPROCESS
{
KPROCESS Pcb;
EX_PUSH_LOCK ProcessLock;
PVOID UniqueProcessId;
LIST_ENTRY ActiveProcessLinks;
EX_RUNDOWN_REF RundownProtect;
union {
ULONG Flags2;
struct {
ULONG JobNotReallyActive : 1;
ULONG AccountingFolded : 1;
ULONG NewProcessReported : 1;
ULONG ExitProcessReported : 1;
ULONG ReportCommitChanges : 1;
ULONG LastReportMemory : 1;
ULONG ForceWakeCharge : 1;
ULONG CrossSessionCreate : 1;
ULONG NeedsHandleRundown : 1;
ULONG RefTraceEnabled : 1;
ULONG PicoCreated : 1;
ULONG EmptyJobEvaluated : 1;
ULONG DefaultPagePriority : 3;
ULONG PrimaryTokenFrozen : 1;
ULONG ProcessVerifierTarget : 1;
ULONG RestrictSetThreadContext : 1;
ULONG AffinityPermanent : 1;
ULONG AffinityUpdateEnable : 1;
ULONG PropagateNode : 1;
ULONG ExplicitAffinity : 1;
ULONG ProcessExecutionState : 2;
ULONG EnableReadVmLogging : 1;
ULONG EnableWriteVmLogging : 1;
ULONG FatalAccessTerminationRequested : 1;
ULONG DisableSystemAllowedCpuSet : 1;
ULONG ProcessStateChangeRequest : 2;
ULONG ProcessStateChangeInProgress : 1;
ULONG InPrivate : 1;
};
};
union {
ULONG Flags;
struct {
ULONG CreateReported : 1;
ULONG NoDebugInherit : 1;
ULONG ProcessExiting : 1;
ULONG ProcessDelete : 1;
ULONG ManageExecutableMemoryWrites : 1;
ULONG VmDeleted : 1;
ULONG OutswapEnabled : 1;
ULONG Outswapped : 1;
ULONG FailFastOnCommitFail : 1;
ULONG Wow64VaSpace4Gb : 1;
ULONG AddressSpaceInitialized : 2;
ULONG SetTimerResolution : 1;
ULONG BreakOnTermination : 1;
ULONG DeprioritizeViews : 1;
ULONG WriteWatch : 1;
ULONG ProcessInSession : 1;
ULONG OverrideAddressSpace : 1;
ULONG HasAddressSpace : 1;
ULONG LaunchPrefetched : 1;
ULONG Background : 1;
ULONG VmTopDown : 1;
ULONG ImageNotifyDone : 1;
ULONG PdeUpdateNeeded : 1;
ULONG VdmAllowed : 1;
ULONG ProcessRundown : 1;
ULONG ProcessInserted : 1;
ULONG DefaultIoPriority : 3;
ULONG ProcessSelfDelete : 1;
ULONG SetTimerResolutionLink : 1;
};
};
LARGE_INTEGER CreateTime;
SIZE_T ProcessQuotaUsage[2];
SIZE_T ProcessQuotaPeak[2];
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
LIST_ENTRY SessionProcessLinks;
union {
PVOID ExceptionPortData;
union {
SIZE_T ExceptionPortValue;
struct {
SIZE_T ExceptionPortState : 3;
};
};
};
EX_FAST_REF Token;
SIZE_T MmReserved;
EX_PUSH_LOCK AddressCreationLock;
EX_PUSH_LOCK PageTableCommitmentLock;
PETHREAD RotateInProgress;
PETHREAD ForkInProgress;
PEJOB CommitChargeJob;
RTL_AVL_TREE CloneRoot;
SIZE_T NumberOfPrivatePages;
SIZE_T NumberOfLockedPages;
PVOID Win32Process;
PEJOB Job;
PVOID SectionObject;
PVOID SectionBaseAddress;
ULONG Cookie;
PPAGEFAULT_HISTORY WorkingSetWatch;
PVOID Win32WindowStation;
PVOID InheritedFromUniqueProcessId;
SIZE_T OwnerProcessId;
PPEB Peb;
PMM_SESSION_SPACE Session;
PVOID Spare1;
PEPROCESS_QUOTA_BLOCK QuotaBlock;
PHANDLE_TABLE ObjectTable;
PVOID DebugPort;
PEWOW64PROCESS WoW64Process;
EX_FAST_REF DeviceMap;
PVOID EtwDataSource;
SIZE_T PageDirectoryPte;
PFILE_OBJECT ImageFilePointer;
UCHAR ImageFileName[15];
UCHAR PriorityClass;
PVOID SecurityPort;
SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;
LIST_ENTRY JobLinks;
PVOID HighestUserAddress;
LIST_ENTRY ThreadListHead;
ULONG ActiveThreads;
ULONG ImagePathHash;
ULONG DefaultHardErrorProcessing;
LONG LastThreadExitStatus;
EX_FAST_REF PrefetchTrace;
PVOID LockedPagesList;
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
SIZE_T CommitChargeLimit;
SIZE_T CommitCharge;
SIZE_T CommitChargePeak;
MMSUPPORT_FULL Vm;
LIST_ENTRY MmProcessLinks;
ULONG ModifiedPageCount;
LONG ExitStatus;
RTL_AVL_TREE VadRoot;
PVOID VadHint;
SIZE_T VadCount;
SIZE_T VadPhysicalPages;
SIZE_T VadPhysicalPagesLimit;
ALPC_PROCESS_CONTEXT AlpcContext;
LIST_ENTRY TimerResolutionLink;
PPO_DIAG_STACK_RECORD TimerResolutionStackRecord;
ULONG RequestedTimerResolution;
ULONG SmallestTimerResolutio;
LARGE_INTEGER ExitTime;
PINVERTED_FUNCTION_TABLE InvertedFunctionTable;
EX_PUSH_LOCK InvertedFunctionTableLock;
ULONG ActiveThreadsHighWatermark;
ULONG LargePrivateVadCount;
EX_PUSH_LOCK ThreadListLock;
PVOID WnfContext;
PEJOB ServerSilo;
BYTE SignatureLevel;
BYTE SectionSignatureLevel;
PS_PROTECTION Protection;
union {
ULONG HangCount : 3;
ULONG GhostCount : 3;
ULONG PrefilterException : 1;
};
union {
ULONG Flags3;
struct {
ULONG Minimal : 1;
ULONG ReplacingPageRoot : 1;
ULONG Crashed : 1;
ULONG JobVadsAreTracked : 1;
ULONG VadTrackingDisabled : 1;
ULONG AuxiliaryProcess : 1;
ULONG SubsystemProcess : 1;
ULONG IndirectCpuSets : 1;
ULONG RelinquishedCommit : 1;
ULONG HighGraphicsPriority : 1;
ULONG CommitFailLogged : 1;
ULONG ReserveFailLogged : 1;
ULONG SystemProcess : 1;
ULONG HideImageBaseAddresses : 1;
ULONG AddressPolicyFrozen : 1;
ULONG ProcessFirstResume : 1;
ULONG ForegroundExternal : 1;
ULONG ForegroundSystem : 1;
ULONG HighMemoryPriority : 1;
ULONG EnableProcessSuspendResumeLogging : 1;
ULONG EnableThreadSuspendResumeLogging : 1;
ULONG SecurityDomainChanged : 1;
ULONG SecurityFreezeComplete : 1;
ULONG VmProcessorHost : 1;
ULONG VmProcessorHostTransition : 1;
ULONG AltSyscall : 1;
ULONG TimerResolutionIgnore : 1;
ULONG DisallowUserTerminate : 1;
ULONG EnableProcessRemoteExecProtectVmLogging : 1;
ULONG EnableProcessLocalExecProtectVmLogging : 1;
};
};
LONG DeviceAsid;
PVOID SvmData;
EX_PUSH_LOCK SvmProcessLock;
SIZE_T SvmLock;
LIST_ENTRY SvmProcessDeviceListHead;
SIZE_T LastFreezeInterruptTime;
PPROCESS_DISK_COUNTERS DiskCounters;
PVOID PicoContext;
PVOID EnclaveTable;
SIZE_T EnclaveNumber;
EX_PUSH_LOCK EnclaveLock;
ULONG HighPriorityFaultsAllowed;
PPO_PROCESS_ENERGY_CONTEXT EnergyContext;
PVOID VmContext;
SIZE_T SequenceNumber;
SIZE_T CreateInterruptTime;
SIZE_T CreateUnbiasedInterruptTime;
SIZE_T TotalUnbiasedFrozenTime;
SIZE_T LastAppStateUpdateTime;
union {
SIZE_T LastAppStateUptime : 61;
SIZE_T LastAppState : 3;
};
SIZE_T SharedCommitCharge;
EX_PUSH_LOCK SharedCommitLock;
LIST_ENTRY SharedCommitLinks;
SIZE_T AllowedCpuSets;
SIZE_T DefaultCpuSets;
PSIZE_T AllowedCpuSetsIndirect;
PSIZE_T DefaultCpuSetsIndirect;
PVOID DiskIoAttribution;
PVOID DxgProcess;
ULONG Win32KFilterSet;
USHORT Machine;
USHORT Spare0;
PS_INTERLOCKED_TIMER_DELAY_VALUES ProcessTimerDelay;
ULONG KTimerSets;
ULONG KTimer2Sets;
ULONG ThreadTimerSets;
SIZE_T VirtualTimerListLock;
LIST_ENTRY VirtualTimerListHead;
WNF_STATE_NAME WakeChannel;
PS_PROCESS_WAKE_INFORMATION WakeInfo;
union {
ULONG MitigationFlags;
union {
ULONG MitigationFlagsValues;
};
};
union {
ULONG MitigationFlags2;
union {
ULONG MitigationFlags2Values;
};
};
PVOID PartitionObject;
SIZE_T SecurityDomain;
SIZE_T ParentSecurityDomain;
PVOID CoverageSamplerContext;
PVOID MmHotPatchContext;
KE_IDEAL_PROCESSOR_ASSIGNMENT_BLOCK IdealProcessorAssignmentBlock;
RTL_AVL_TREE DynamicEHContinuationTargetsTree;
EX_PUSH_LOCK DynamicEHContinuationTargetsLock;
PS_DYNAMIC_ENFORCED_ADDRESS_RANGES DynamicEnforcedCetCompatibleRanges;
ULONG DisabledComponentFlags;
LONG PageCombineSequence;
EX_PUSH_LOCK EnableOptionalXStateFeaturesLock;
} EPROCESS, * PEPROCESS; |
|
Стоит отдельно рассмотреть механизмы взаимодействия с файловыми объектами, т.к. система управляет ими немного иначе, чем другими объектами ядра.
Файловые объекты содержат указатель на следующий байт, который должен быть прочитан или записан в файл.
Каждый раз, когда приложение создает новый дескриптор файла, система создает новый файловый объект.
Следовательно, несколько файловых объектов могут ссылаться на один и тот же файл на диске

Только дублированием (или наследованием) нескольких дескрипторов файла, можно ссылаться на один и тот же файловый объект

Дескриптор остается действительным до тех пор, пока файловый объект не будет уничтожен функцией CloseHandle.
Объекты операционной системы. Часть 2: Объект ядра
|