├── .gitattributes ├── .gitignore ├── LICENSE ├── M2TeamCommonLibrary.sln └── M2TeamCommonLibrary ├── M2.Base.cpp ├── M2.Base.h ├── M2.NSudo.h ├── M2.SDK.h ├── M2MessageDialogResource.h ├── M2MessageDialogResource.rc ├── M2TeamCommonLibrary.vcxitems ├── M2TeamCommonLibrary.vcxitems.filters ├── M2Win32GUIHelpers.cpp ├── M2Win32GUIHelpers.h ├── M2WindowsHelpers.cpp ├── M2WindowsHelpers.h └── MINT.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) M2-Team and Contributors. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.329 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "M2TeamCommonLibrary", "M2TeamCommonLibrary\M2TeamCommonLibrary.vcxitems", "{956CAD19-1F11-4656-8664-6837AA67CD87}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documents", "Documents", "{AF6177FD-314C-44B4-A3D0-552F08FD3545}" 9 | ProjectSection(SolutionItems) = preProject 10 | LICENSE = LICENSE 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionProperties) = preSolution 15 | HideSolutionNode = FALSE 16 | EndGlobalSection 17 | GlobalSection(ExtensibilityGlobals) = postSolution 18 | SolutionGuid = {0FF7B3A9-96BE-4CEF-BB1A-104BBE844B1D} 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2.Base.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 项目:M2-SDK 3 | 描述:M2-SDK 基本定义实现 4 | 文件名:M2.Base.cpp 5 | 许可协议:看顶层目录的 License.txt 6 | 建议的最低 Windows SDK 版本:10.0.10586 7 | 提示:无 8 | 9 | Project: M2-SDK 10 | Description: Implemention of Base M2-SDK Definitions 11 | Filename: M2.Base.cpp 12 | License: See License.txt in the top level directory 13 | Recommend Minimum Windows SDK Version: 10.0.10586 14 | Tips: N/A 15 | ******************************************************************************/ 16 | 17 | #include "M2.Windows.h" // Windows API 基本定义 18 | #include "M2.Base.h" // M2-SDK 基本定义 19 | 20 | namespace M2 21 | { 22 | // 创建事件对象, 不内联考虑到大量使用本函数时实现函数复用以节约空间 23 | NTSTATUS WINAPI M2CreateEvent( 24 | _Out_ PHANDLE phEvent, 25 | _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, 26 | _In_ BOOL bManualReset, 27 | _In_ BOOL bInitialState, 28 | _In_opt_ LPCWSTR lpName) 29 | { 30 | OBJECT_ATTRIBUTES ObjectAttributes; 31 | UNICODE_STRING NtFileName; 32 | 33 | M2InitObjectAttributes(ObjectAttributes); 34 | 35 | if (lpEventAttributes && 36 | lpEventAttributes->nLength == sizeof(SECURITY_ATTRIBUTES)) 37 | { 38 | if (lpEventAttributes->bInheritHandle) 39 | ObjectAttributes.Attributes = OBJ_INHERIT; 40 | ObjectAttributes.SecurityDescriptor = 41 | lpEventAttributes->lpSecurityDescriptor; 42 | } 43 | 44 | if (lpName) 45 | { 46 | M2InitUnicodeString(NtFileName, (PWSTR)lpName); 47 | ObjectAttributes.ObjectName = &NtFileName; 48 | } 49 | 50 | return NtCreateEvent( 51 | phEvent, 52 | EVENT_ALL_ACCESS, 53 | &ObjectAttributes, 54 | bManualReset ? NotificationEvent : SynchronizationEvent, 55 | (BOOLEAN)bInitialState); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2.Base.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 项目:M2-SDK 3 | 描述:M2-SDK 基本定义 4 | 文件名:M2.Base.h 5 | 许可协议:看顶层目录的 License.txt 6 | 建议的最低 Windows SDK 版本:10.0.10586 7 | 提示:无 8 | 9 | Project: M2-SDK 10 | Description: Base M2-SDK Definitions 11 | Filename: M2.Base.h 12 | License: See License.txt in the top level directory 13 | Recommend Minimum Windows SDK Version: 10.0.10586 14 | Tips: N/A 15 | ******************************************************************************/ 16 | 17 | #pragma once 18 | 19 | #ifndef _M2_BASE_ 20 | #define _M2_BASE_ 21 | 22 | #ifdef __cplusplus 23 | 24 | namespace M2 25 | { 26 | // 初始化OBJECT_ATTRIBUTES结构 27 | FORCEINLINE void M2InitObjectAttributes( 28 | _Out_ OBJECT_ATTRIBUTES& ObjectAttributes, 29 | _In_ PUNICODE_STRING ObjectName = nullptr, 30 | _In_ ULONG Attributes = 0, 31 | _In_ HANDLE RootDirectory = nullptr, 32 | _In_ PVOID SecurityDescriptor = nullptr, 33 | _In_ PVOID SecurityQualityOfService = nullptr) 34 | { 35 | ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); 36 | ObjectAttributes.RootDirectory = RootDirectory; 37 | ObjectAttributes.ObjectName = ObjectName; 38 | ObjectAttributes.Attributes = Attributes; 39 | ObjectAttributes.SecurityDescriptor = SecurityDescriptor; 40 | ObjectAttributes.SecurityQualityOfService = SecurityQualityOfService; 41 | } 42 | 43 | // 初始化SECURITY_QUALITY_OF_SERVICE结构 44 | FORCEINLINE void M2InitSecurityQuailtyOfService( 45 | _Out_ SECURITY_QUALITY_OF_SERVICE& SecurityQuailtyOfService, 46 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 47 | _In_ SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode, 48 | _In_ BOOLEAN EffectiveOnly) 49 | { 50 | SecurityQuailtyOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 51 | SecurityQuailtyOfService.ImpersonationLevel = ImpersonationLevel; 52 | SecurityQuailtyOfService.ContextTrackingMode = ContextTrackingMode; 53 | SecurityQuailtyOfService.EffectiveOnly = EffectiveOnly; 54 | } 55 | 56 | // 初始化CLIENT_ID结构 57 | FORCEINLINE void M2InitClientID( 58 | _Out_ CLIENT_ID& ClientID, 59 | _In_opt_ DWORD ProcessID, 60 | _In_opt_ DWORD ThreadID) 61 | { 62 | ClientID.UniqueProcess = UlongToHandle(ProcessID); 63 | ClientID.UniqueThread = UlongToHandle(ThreadID); 64 | } 65 | 66 | // 获取KUSER_SHARED_DATA结构 67 | FORCEINLINE PKUSER_SHARED_DATA M2GetKUserSharedData() 68 | { 69 | return ((PKUSER_SHARED_DATA const)0x7ffe0000); 70 | } 71 | 72 | // 获取当前系统会话号 73 | FORCEINLINE DWORD M2GetCurrentSessionID() 74 | { 75 | return M2GetKUserSharedData()->ActiveConsoleId; 76 | } 77 | 78 | // GetLastError()的未公开内联实现 79 | FORCEINLINE DWORD M2GetLastError() 80 | { 81 | return NtCurrentTeb()->LastErrorValue; 82 | } 83 | 84 | // SetLastError()的未公开内联实现 85 | FORCEINLINE VOID M2SetLastError(_In_ DWORD dwErrCode) 86 | { 87 | if (NtCurrentTeb()->LastErrorValue != dwErrCode) 88 | NtCurrentTeb()->LastErrorValue = dwErrCode; 89 | } 90 | 91 | // 在默认堆上分配内存 92 | FORCEINLINE PVOID M2HeapAlloc( 93 | _In_ SIZE_T Size) 94 | { 95 | return RtlAllocateHeap(RtlProcessHeap(), 0, Size); 96 | } 97 | 98 | // 在默认堆上释放内存 99 | FORCEINLINE VOID M2HeapFree( 100 | _In_ PVOID BaseAddress) 101 | { 102 | RtlFreeHeap(RtlProcessHeap(), 0, BaseAddress); 103 | } 104 | 105 | // 分配初始化为零的内存 106 | FORCEINLINE PVOID M2AllocZeroedMemory( 107 | _In_ size_t Size) 108 | { 109 | return RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, Size); 110 | } 111 | 112 | // 初始化UNICODE_STRING结构 113 | template 114 | FORCEINLINE void M2InitUnicodeString( 115 | _Out_ UNICODE_STRING &Destination, 116 | _In_opt_ StringType Source) 117 | { 118 | Destination.Length = 119 | (USHORT)(Source ? (wcslen(Source) * sizeof(WCHAR)) : 0); 120 | Destination.MaximumLength = 121 | (USHORT)(Source ? ((wcslen(Source) + 1) * sizeof(WCHAR)) : 0); 122 | Destination.Buffer = 123 | (PWCH)(Source ? Source : nullptr); 124 | } 125 | 126 | // 初始化STRING结构 127 | template 128 | FORCEINLINE void M2InitString( 129 | _Out_ STRING &Destination, 130 | _In_opt_ StringType Source) 131 | { 132 | Destination.Length = 133 | (USHORT)(Source ? (strlen(Source) * sizeof(CHAR)) : 0); 134 | Destination.MaximumLength = 135 | (USHORT)(Source ? ((strlen(Source) + 1) * sizeof(CHAR)) : 0); 136 | Destination.Buffer = 137 | (PCHAR)(Source ? Source : nullptr); 138 | } 139 | 140 | // 通过直接访问PEB结构获取当前进程模块,以替代GetModuleHandleW(NULL) 141 | FORCEINLINE HMODULE M2GetCurrentModuleHandle() 142 | { 143 | return reinterpret_cast(NtCurrentPeb()->ImageBaseAddress); 144 | } 145 | 146 | // 加载特定模块到当前进程内存 147 | FORCEINLINE NTSTATUS M2LoadModule( 148 | _Out_ PVOID &ModuleHandle, 149 | _In_ LPCWSTR ModuleFileName) 150 | { 151 | UNICODE_STRING usDllName; 152 | M2InitUnicodeString(usDllName, ModuleFileName); 153 | return LdrLoadDll(nullptr, nullptr, &usDllName, &ModuleHandle); 154 | } 155 | 156 | // 释放已加载到内存的特定模块或减少引用计数 157 | FORCEINLINE NTSTATUS M2FreeModule( 158 | _Out_ PVOID ModuleHandle) 159 | { 160 | return LdrUnloadDll(ModuleHandle); 161 | } 162 | 163 | // 获取已加载到内存的特定模块的句柄 164 | FORCEINLINE NTSTATUS M2GetModuleHandle( 165 | _Out_ PVOID &ModuleHandle, 166 | _In_ LPCWSTR ModuleFileName) 167 | { 168 | UNICODE_STRING usDllName; 169 | M2InitUnicodeString(usDllName, ModuleFileName); 170 | return LdrGetDllHandleEx( 171 | 0, nullptr, nullptr, &usDllName, &ModuleHandle); 172 | } 173 | 174 | // 获取特定模块的特定导出函数地址 175 | template 176 | FORCEINLINE NTSTATUS M2GetProcedureAddress( 177 | _Out_ ProcedureType &ProcedureAddress, 178 | _In_ PVOID ModuleHandle, 179 | _In_ LPCSTR ProcedureName) 180 | { 181 | ANSI_STRING asProcedureName; 182 | M2InitString(asProcedureName, ProcedureName); 183 | return LdrGetProcedureAddress( 184 | ModuleHandle, 185 | &asProcedureName, 186 | 0, 187 | (PVOID*)(&ProcedureAddress)); 188 | } 189 | 190 | // 获取特定模块的特定导出函数地址 191 | template 192 | FORCEINLINE NTSTATUS M2GetProcedureAddress( 193 | _Out_ ProcedureType &ProcedureAddress, 194 | _In_ PVOID ModuleHandle, 195 | _In_ ULONG ProcedureNumber) 196 | { 197 | return LdrGetProcedureAddress( 198 | ModuleHandle, 199 | nullptr, 200 | ProcedureNumber, 201 | (PVOID*)(&ProcedureAddress)); 202 | } 203 | 204 | // 创建事件对象, 不内联考虑到大量使用本函数时实现函数复用以节约空间 205 | NTSTATUS WINAPI M2CreateEvent( 206 | _Out_ PHANDLE phEvent, 207 | _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, 208 | _In_ BOOL bManualReset, 209 | _In_ BOOL bInitialState, 210 | _In_opt_ LPCWSTR lpName); 211 | 212 | // 按范围取值 213 | template 214 | inline T M2GetValueByRange(T Value, T Min, T Max) 215 | { 216 | return ((Value > Min) ? ((Value > Max) ? Max : Value) : Min); 217 | } 218 | 219 | // 在默认堆上分配内存 220 | template 221 | FORCEINLINE NTSTATUS M2HeapAlloc( 222 | _In_ SIZE_T Size, 223 | _Out_ PtrType &BaseAddress) 224 | { 225 | BaseAddress = (PtrType)RtlAllocateHeap(RtlProcessHeap(), 0, Size); 226 | return (BaseAddress ? STATUS_SUCCESS : STATUS_NO_MEMORY); 227 | } 228 | 229 | // 内存指针模板类 230 | template class CPtr 231 | { 232 | public: 233 | // 分配内存 234 | bool Alloc(_In_ size_t Size) 235 | { 236 | if (m_Ptr) this->Free(); 237 | m_Ptr = malloc(Size); 238 | return (m_Ptr != nullptr); 239 | } 240 | 241 | // 释放内存 242 | void Free() 243 | { 244 | free(m_Ptr); 245 | m_Ptr = nullptr; 246 | } 247 | 248 | // 获取内存指针 249 | operator PtrType() const 250 | { 251 | return (PtrType)m_Ptr; 252 | } 253 | 254 | // 获取内存指针(->运算符) 255 | PtrType operator->() const 256 | { 257 | return (PtrType)m_Ptr; 258 | } 259 | 260 | // 设置内存指针 261 | CPtr& operator=(_In_ PtrType Ptr) 262 | { 263 | if (Ptr != m_Ptr) // 如果值相同返回自身,否则赋新值 264 | { 265 | if (m_Ptr) this->Free(); // 如果内存已分配则释放 266 | m_Ptr = Ptr; // 设置内存指针 267 | } 268 | return *this; // 返回自身 269 | } 270 | 271 | // 退出时释放内存 272 | ~CPtr() 273 | { 274 | if (m_Ptr) this->Free(); 275 | } 276 | 277 | private: 278 | //指针内部变量 279 | void *m_Ptr = nullptr; 280 | }; 281 | 282 | // 忽略未调用参数警告 283 | template void UnReferencedParameter(const T&) {} 284 | 285 | 286 | 287 | //************************************************************************* 288 | // Windows 10未文档化DPI支持相关定义 289 | // Windows 10 DPI Support Definations 290 | //************************************************************************* 291 | #if _MSC_VER >= 1200 292 | #pragma warning(push) 293 | // 从“type of expression”到“type required”的不安全转换(等级 3) 294 | #pragma warning(disable:4191) 295 | #endif 296 | 297 | typedef INT(WINAPI *PFN_EnablePerMonitorDialogScaling)(); 298 | typedef BOOL(WINAPI *PFN_EnableChildWindowDpiMessage)(HWND, BOOL); 299 | typedef BOOL(WINAPI *PFN_NtUserEnableChildWindowDpiMessage)(HWND, BOOL); 300 | 301 | /* 302 | EnablePerMonitorDialogScaling函数为指定对话框启用Per-Monitor DPI Aware支 303 | 持。 304 | The EnablePerMonitorDialogScaling function enables the Per-Monitor DPI 305 | Aware for the specified dialog. 306 | 307 | 你需要在Windows 10 Threshold 1 及以后的版本使用该函数。 308 | You need to use this function in Windows 10 Threshold 1 or later. 309 | */ 310 | FORCEINLINE INT EnablePerMonitorDialogScaling() 311 | { 312 | PVOID pDllHandle = nullptr; 313 | PFN_EnablePerMonitorDialogScaling pFunc = nullptr; 314 | 315 | if (!NT_SUCCESS(M2GetModuleHandle(pDllHandle, L"user32.dll"))) 316 | return -1; 317 | if (!NT_SUCCESS(M2GetProcedureAddress(pFunc, pDllHandle, 2577))) 318 | return -1; 319 | 320 | return pFunc(); 321 | } 322 | 323 | /* 324 | EnableChildWindowDpiMessage函数启用指定子窗口的DPI消息。 325 | The EnableChildWindowDpiMessage function enables the dpi messages from the 326 | specified child window. 327 | 328 | 你需要在Windows 10 Threshold 1 和 Windows Threshold 2使用该函数。Windows 329 | 10 Redstone 1 及以后的版本需要使用NtUserEnableChildWindowDpiMessage。 330 | You need to use this function in Windows 10 Threshold 1 and Windows 10 331 | Threshold 2. You need to use NtUserEnableChildWindowDpiMessage in Windows 332 | 10 Redstone 1 or later. 333 | */ 334 | FORCEINLINE BOOL EnableChildWindowDpiMessage( 335 | _In_ HWND hWnd, 336 | _In_ BOOL bEnable) 337 | { 338 | PVOID pDllHandle = nullptr; 339 | PFN_EnableChildWindowDpiMessage pFunc = nullptr; 340 | 341 | if (!NT_SUCCESS(M2GetModuleHandle(pDllHandle, L"user32.dll"))) 342 | return -1; 343 | if (!NT_SUCCESS(M2GetProcedureAddress( 344 | pFunc, pDllHandle, "EnableChildWindowDpiMessage"))) 345 | return -1; 346 | 347 | return pFunc(hWnd, bEnable); 348 | } 349 | 350 | /* 351 | NtUserEnableChildWindowDpiMessage函数启用指定子窗口的DPI消息。 352 | The NtUserEnableChildWindowDpiMessage function enables the dpi messages 353 | from the specified child window. 354 | 355 | 你需要在Windows 10 Redstone 1 及以后的版本使用该函数。 356 | You need to use this function in Windows 10 Redstone 1 or later. 357 | */ 358 | FORCEINLINE BOOL NtUserEnableChildWindowDpiMessage( 359 | _In_ HWND hWnd, 360 | _In_ BOOL bEnable) 361 | { 362 | PVOID pDllHandle = nullptr; 363 | PFN_NtUserEnableChildWindowDpiMessage pFunc = nullptr; 364 | 365 | if (!NT_SUCCESS(M2GetModuleHandle(pDllHandle, L"win32u.dll"))) 366 | return -1; 367 | if (!NT_SUCCESS(M2GetProcedureAddress( 368 | pFunc, pDllHandle, "NtUserEnableChildWindowDpiMessage"))) 369 | return -1; 370 | 371 | return (pFunc ? pFunc(hWnd, bEnable) : -1); 372 | } 373 | 374 | #if _MSC_VER >= 1200 375 | #pragma warning(pop) 376 | #endif 377 | 378 | //************************************************************************* 379 | // COM对象模板 380 | // COM Object Template 381 | //************************************************************************* 382 | #if _MSC_VER >= 1200 383 | #pragma warning(push) 384 | #pragma warning(disable:4820) // 字节填充添加在数据成员后(等级 4) 385 | #endif 386 | 387 | #define COM_INTERFACE_ENTRY(Interface) \ 388 | if (__uuidof(Interface) == riid) \ 389 | { \ 390 | *ppvObject = (Interface*)this; \ 391 | AddRef(); \ 392 | return S_OK; \ 393 | } 394 | 395 | #define COM_INTERFACE_MAP_BEGIN \ 396 | FORCEINLINE HRESULT InternalQueryInterface( \ 397 | REFIID riid, \ 398 | void __RPC_FAR *__RPC_FAR *ppvObject) \ 399 | { 400 | 401 | #define COM_INTERFACE_MAP_END \ 402 | COM_INTERFACE_ENTRY(IUnknown); \ 403 | return E_NOINTERFACE; \ 404 | } 405 | 406 | // 单线程COM对象模板类 407 | template 408 | class CComObject : public Interface 409 | { 410 | private: 411 | ULONG m_ulRef; 412 | 413 | public: 414 | // 构造函数 415 | CComObject() :m_ulRef(1) 416 | { 417 | } 418 | 419 | // 析构函数 420 | virtual ~CComObject() 421 | { 422 | } 423 | 424 | // 查询接口 425 | virtual HRESULT STDMETHODCALLTYPE QueryInterface( 426 | REFIID riid, 427 | void __RPC_FAR *__RPC_FAR *ppvObject) 428 | { 429 | return ((BaseClass*)this)->InternalQueryInterface(riid, ppvObject); 430 | } 431 | 432 | // 增加引用计数 433 | virtual ULONG STDMETHODCALLTYPE AddRef() 434 | { 435 | return InterlockedIncrement(&m_ulRef); 436 | } 437 | 438 | // 释放引用计数 439 | virtual ULONG STDMETHODCALLTYPE Release() 440 | { 441 | ULONG dwRet = InterlockedDecrement(&m_ulRef); 442 | 443 | // 如果释放计数后等于0释放自身 444 | if (dwRet == 0) delete (BaseClass*)this; 445 | 446 | // 否则返回当前计数 447 | return dwRet; 448 | } 449 | }; 450 | 451 | #if _MSC_VER >= 1200 452 | #pragma warning(pop) 453 | #endif 454 | 455 | } 456 | 457 | #endif 458 | 459 | #endif 460 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2.NSudo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 项目:M2-SDK 3 | 描述:NSudo库 4 | 文件名:M2.NSudo.h 5 | 基于项目:无 6 | 许可协议:看顶层目录的 License.txt 7 | 建议的Windows SDK版本:10.0.10586及以后 8 | 9 | Project: M2-SDK 10 | Description: NSudo Library 11 | Filename: M2.NSudo.h 12 | License: See License.txt in the top level directory 13 | Recommend Minimum Windows SDK Version: 10.0.10586 14 | ******************************************************************************/ 15 | 16 | #pragma once 17 | 18 | #ifndef _M2_NSUDO_ 19 | #define _M2_NSUDO_ 20 | 21 | // 为编译通过而禁用的微软.Net Framework SDK存在的警告 22 | #if _MSC_VER >= 1200 23 | #pragma warning(push) 24 | // 字节填充添加在数据成员后(等级 4) 25 | #pragma warning(disable:4820) 26 | // 不带范围的枚举的前向声明必须具有基础类型(假定为 int)(等级 4) 27 | #pragma warning(disable:4471) 28 | #endif 29 | 30 | #include 31 | #import "mscorlib.tlb" raw_interfaces_only \ 32 | high_property_prefixes("_get","_put","_putref") \ 33 | rename("ReportEvent", "InteropServices_ReportEvent") 34 | 35 | #if _MSC_VER >= 1200 36 | #pragma warning(pop) 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | using namespace M2; 42 | #endif 43 | 44 | /* 45 | SuDuplicateToken函数通过现有的访问令牌创建一个主令牌或模仿令牌。 46 | The SuDuplicateToken function creates a primary token or an impersonation 47 | token via an existing access token. 48 | 49 | 该函数是DuplicateTokenEx API的一个等价实现。 50 | This function is an equivalent implementation of DuplicateTokenEx API. 51 | */ 52 | static NTSTATUS WINAPI SuDuplicateToken( 53 | _In_ HANDLE hExistingToken, 54 | _In_ DWORD dwDesiredAccess, 55 | _In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes, 56 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 57 | _In_ TOKEN_TYPE TokenType, 58 | _Outptr_ PHANDLE phNewToken) 59 | { 60 | SECURITY_QUALITY_OF_SERVICE SQOS; 61 | OBJECT_ATTRIBUTES ObjectAttributes; 62 | 63 | M2InitSecurityQuailtyOfService( 64 | SQOS, ImpersonationLevel, FALSE, FALSE); 65 | M2InitObjectAttributes( 66 | ObjectAttributes, nullptr, 0, nullptr, nullptr, &SQOS); 67 | 68 | if (lpTokenAttributes && 69 | lpTokenAttributes->nLength == sizeof(SECURITY_ATTRIBUTES)) 70 | { 71 | ObjectAttributes.Attributes = 72 | (ULONG)(lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0); 73 | ObjectAttributes.SecurityDescriptor = 74 | lpTokenAttributes->lpSecurityDescriptor; 75 | } 76 | 77 | return NtDuplicateToken( 78 | hExistingToken, 79 | dwDesiredAccess, 80 | &ObjectAttributes, 81 | FALSE, 82 | TokenType, 83 | phNewToken); 84 | } 85 | 86 | /* 87 | SuOpenProcess函数打开一个存在的本机进程对象。 88 | The SuOpenProcess function opens an existing local process object. 89 | 90 | 该函数是OpenProcess API的一个等价实现。 91 | This function is an equivalent implementation of OpenProcess API. 92 | */ 93 | static NTSTATUS WINAPI SuOpenProcess( 94 | _Out_ PHANDLE phProcess, 95 | _In_ DWORD dwDesiredAccess, 96 | _In_ BOOL bInheritHandle, 97 | _In_ DWORD dwProcessId) 98 | { 99 | OBJECT_ATTRIBUTES ObjectAttributes; 100 | CLIENT_ID ClientID; 101 | 102 | M2InitClientID(ClientID, dwProcessId, 0); 103 | M2InitObjectAttributes(ObjectAttributes); 104 | 105 | ObjectAttributes.Attributes = 106 | (ULONG)(bInheritHandle ? OBJ_INHERIT : 0); 107 | 108 | return NtOpenProcess( 109 | phProcess, dwDesiredAccess, &ObjectAttributes, &ClientID); 110 | } 111 | 112 | /* 113 | SuOpenProcessToken函数根据进程ID打开一个进程的关联令牌。 114 | The SuOpenProcessToken function opens the access token associated with a 115 | process via ProcessID. 116 | */ 117 | static NTSTATUS WINAPI SuOpenProcessToken( 118 | _In_ DWORD dwProcessId, 119 | _In_ DWORD DesiredAccess, 120 | _Outptr_ PHANDLE TokenHandle) 121 | { 122 | NTSTATUS status = STATUS_SUCCESS; 123 | HANDLE hProcess = nullptr; 124 | 125 | status = SuOpenProcess( 126 | &hProcess, MAXIMUM_ALLOWED, FALSE, dwProcessId); 127 | if (NT_SUCCESS(status)) 128 | { 129 | status = NtOpenProcessToken( 130 | hProcess, DesiredAccess, TokenHandle); 131 | NtClose(hProcess); 132 | } 133 | 134 | return status; 135 | } 136 | 137 | /* 138 | SuOpenSessionToken函数根据已登陆的用户的会话ID获取主访问令牌。您需要在 139 | LocalSystem账户且开启SE_TCB_NAME特权的访问令牌上下文下调用该函数。 140 | The SuOpenSessionToken function obtains the primary access token of the 141 | logged-on user specified by the session ID. To call this function 142 | successfully, the calling application must be running within the context 143 | of the LocalSystem account and have the SE_TCB_NAME privilege. 144 | 145 | 该函数是WTSQueryUserToken API的一个等价实现。 146 | This function is an equivalent implementation of WTSQueryUserToken API. 147 | */ 148 | static HRESULT WINAPI SuOpenSessionToken( 149 | _In_ ULONG SessionId, 150 | _Out_ PHANDLE phToken) 151 | { 152 | WINSTATIONUSERTOKEN WSUT = { 0 }; 153 | DWORD ReturnLength = 0; 154 | 155 | // 初始化 LastError 156 | M2SetLastError(ERROR_SUCCESS); 157 | 158 | // 获取线程令牌 159 | if (WinStationQueryInformationW( 160 | SERVERNAME_CURRENT, 161 | SessionId, 162 | WinStationUserToken, 163 | &WSUT, 164 | sizeof(WINSTATIONUSERTOKEN), 165 | &ReturnLength)) 166 | { 167 | // 如果执行成功则返回令牌句柄 168 | *phToken = WSUT.UserToken; 169 | } 170 | 171 | return __HRESULT_FROM_WIN32(M2GetLastError()); 172 | } 173 | 174 | /* 175 | SuStartService函数通过服务名启动服务并返回服务状态。 176 | The SuStartService function starts a service and return service status via 177 | service name. 178 | */ 179 | static HRESULT WINAPI SuStartService( 180 | _In_ LPCWSTR lpServiceName, 181 | _Out_ LPSERVICE_STATUS_PROCESS lpServiceStatus) 182 | { 183 | SC_HANDLE hSCM = nullptr; 184 | SC_HANDLE hService = nullptr; 185 | DWORD nBytesNeeded = 0; 186 | DWORD nOldCheckPoint = 0; 187 | ULONGLONG nCurrentTick = 0; 188 | ULONGLONG nLastTick = 0; 189 | bool bStartServiceWCalled = false; 190 | bool bSleepCalled = false; 191 | bool bFinished = false; 192 | bool bSucceed = false; 193 | 194 | // 初始化 LastError 195 | M2SetLastError(ERROR_SUCCESS); 196 | 197 | hSCM = OpenSCManagerW( 198 | nullptr, 199 | nullptr, 200 | SC_MANAGER_CONNECT); 201 | if (!hSCM) goto FuncEnd; 202 | 203 | hService = OpenServiceW( 204 | hSCM, 205 | lpServiceName, 206 | SERVICE_QUERY_STATUS | SERVICE_START); 207 | if (!hService) goto FuncEnd; 208 | 209 | while (QueryServiceStatusEx( 210 | hService, 211 | SC_STATUS_PROCESS_INFO, 212 | (LPBYTE)lpServiceStatus, 213 | sizeof(SERVICE_STATUS_PROCESS), 214 | &nBytesNeeded)) 215 | { 216 | switch (lpServiceStatus->dwCurrentState) 217 | { 218 | case SERVICE_STOPPED: 219 | if (!bStartServiceWCalled) 220 | { 221 | bStartServiceWCalled = true; 222 | bFinished = (!StartServiceW(hService, 0, nullptr)); 223 | } 224 | else bFinished = true; 225 | break; 226 | case SERVICE_STOP_PENDING: 227 | case SERVICE_START_PENDING: 228 | nCurrentTick = NtGetTickCount64(); 229 | 230 | if (!bSleepCalled) 231 | { 232 | nLastTick = nCurrentTick; 233 | nOldCheckPoint = lpServiceStatus->dwCheckPoint; 234 | 235 | bSleepCalled = true; 236 | 237 | // 等待250ms(借鉴.Net服务操作类的实现) 238 | LARGE_INTEGER Interval; 239 | Interval.QuadPart = 250LL * -10000LL; 240 | NtDelayExecution(FALSE, &Interval); 241 | } 242 | else 243 | { 244 | // 如果校验点增加则继续循环,否则检测是否超时 245 | if (lpServiceStatus->dwCheckPoint > nOldCheckPoint) 246 | { 247 | bSleepCalled = false; 248 | } 249 | else 250 | { 251 | ULONGLONG nDiff = nCurrentTick - nLastTick; 252 | if (nDiff > lpServiceStatus->dwWaitHint) 253 | { 254 | M2SetLastError(ERROR_TIMEOUT); 255 | bFinished = true; 256 | } 257 | else 258 | { 259 | // 未超时则继续循环 260 | bSleepCalled = false; 261 | } 262 | } 263 | } 264 | break; 265 | default: 266 | bSucceed = true; 267 | bFinished = true; 268 | break; 269 | } 270 | 271 | if (bFinished) break; 272 | } 273 | 274 | // 如果服务启动失败则清空状态信息 275 | if (!bSucceed) 276 | memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS_PROCESS)); 277 | 278 | FuncEnd: 279 | if (hService) CloseServiceHandle(hService); 280 | if (hSCM) CloseServiceHandle(hSCM); 281 | return __HRESULT_FROM_WIN32(M2GetLastError()); 282 | } 283 | 284 | /* 285 | SuOpenServiceProcessToken函数根据服务名打开一个服务进程的关联令牌。 286 | The SuOpenServiceProcessToken function opens the access token associated 287 | with a service process via service name. 288 | */ 289 | static HRESULT WINAPI SuOpenServiceProcessToken( 290 | _In_ LPCWSTR lpServiceName, 291 | _In_ DWORD DesiredAccess, 292 | _Outptr_ PHANDLE TokenHandle) 293 | { 294 | HRESULT hr = S_OK; 295 | NTSTATUS status = STATUS_SUCCESS; 296 | SERVICE_STATUS_PROCESS ssStatus; 297 | 298 | hr = SuStartService(lpServiceName, &ssStatus); 299 | if (SUCCEEDED(hr)) 300 | { 301 | status = SuOpenProcessToken( 302 | ssStatus.dwProcessId, DesiredAccess, TokenHandle); 303 | hr = __HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); 304 | } 305 | 306 | return hr; 307 | } 308 | 309 | /* 310 | SuOpenCurrentProcessToken函数打开当前进程的关联令牌。 311 | The SuOpenCurrentProcessToken function opens the access token associated 312 | with current process. 313 | */ 314 | static NTSTATUS WINAPI SuOpenCurrentProcessToken( 315 | _Out_ PHANDLE phProcessToken, 316 | _In_ DWORD DesiredAccess) 317 | { 318 | return NtOpenProcessToken( 319 | NtCurrentProcess(), DesiredAccess, phProcessToken); 320 | } 321 | 322 | 323 | /* 324 | SuGetCurrentProcessSessionID获取当前进程的会话ID。 325 | The SuGetCurrentProcessSessionID function obtains the Session ID of the 326 | current process. 327 | */ 328 | static NTSTATUS SuGetCurrentProcessSessionID(PDWORD SessionID) 329 | { 330 | NTSTATUS status = STATUS_SUCCESS; 331 | HANDLE hToken = INVALID_HANDLE_VALUE; 332 | DWORD ReturnLength = 0; 333 | 334 | status = SuOpenCurrentProcessToken(&hToken, MAXIMUM_ALLOWED); 335 | if (NT_SUCCESS(status)) 336 | { 337 | status = NtQueryInformationToken( 338 | hToken, 339 | TokenSessionId, 340 | SessionID, 341 | sizeof(DWORD), 342 | &ReturnLength); 343 | } 344 | 345 | return status; 346 | } 347 | 348 | /* 349 | SuSetThreadToken函数给线程分配一个模拟令牌。该函数还可以使一个线程停止使用 350 | 模拟令牌。 351 | The SuSetThreadToken function assigns an impersonation token to a thread. 352 | The function can also cause a thread to stop using an impersonation token. 353 | 354 | 该函数是SetThreadToken API的一个等价实现。 355 | This function is an equivalent implementation of SetThreadToken API. 356 | */ 357 | static NTSTATUS WINAPI SuSetThreadToken( 358 | _In_opt_ PHANDLE phThread, 359 | _In_ HANDLE hToken) 360 | { 361 | return NtSetInformationThread( 362 | (phThread != nullptr) ? *phThread : NtCurrentThread(), 363 | ThreadImpersonationToken, 364 | &hToken, 365 | sizeof(HANDLE)); 366 | } 367 | 368 | /* 369 | SuSetCurrentThreadToken函数给当前线程分配一个模拟令牌。该函数还可以使当前线 370 | 程停止使用模拟令牌。 371 | The SuSetCurrentThreadToken function assigns an impersonation token to the 372 | current thread. The function can also cause the current thread to stop 373 | using an impersonation token. 374 | */ 375 | static NTSTATUS WINAPI SuSetCurrentThreadToken( 376 | _In_ HANDLE hToken) 377 | { 378 | return SuSetThreadToken(nullptr, hToken); 379 | } 380 | 381 | /* 382 | SuRevertToSelf函数终止客户端应用程序模拟。 383 | The SuRevertToSelf function terminates the impersonation of a client 384 | application. 385 | 386 | 该函数是RevertToSelf API的一个等价实现。 387 | This function is an equivalent implementation of RevertToSelf API. 388 | */ 389 | static NTSTATUS WINAPI SuRevertToSelf() 390 | { 391 | return SuSetCurrentThreadToken(nullptr); 392 | } 393 | 394 | /* 395 | SuSetTokenPrivileges函数启用或禁用指定的访问令牌特权。启用或禁用一个访问令 396 | 牌的特权需要TOKEN_ADJUST_PRIVILEGES访问权限。 397 | The SuSetTokenPrivileges function enables or disables privileges in the 398 | specified access token. Enabling or disabling privileges in an access 399 | token requires TOKEN_ADJUST_PRIVILEGES access. 400 | */ 401 | static NTSTATUS WINAPI SuSetTokenPrivileges( 402 | _In_ HANDLE TokenHandle, 403 | _In_opt_ PTOKEN_PRIVILEGES NewState) 404 | { 405 | return NtAdjustPrivilegesToken( 406 | TokenHandle, FALSE, NewState, 0, nullptr, nullptr); 407 | } 408 | 409 | /* 410 | 访问令牌特权定义 411 | The definitions of the Token Privileges 412 | */ 413 | typedef enum _TOKEN_PRIVILEGES_LIST 414 | { 415 | SeMinWellKnownPrivilege = 2, 416 | SeCreateTokenPrivilege = 2, 417 | SeAssignPrimaryTokenPrivilege, 418 | SeLockMemoryPrivilege, 419 | SeIncreaseQuotaPrivilege, 420 | SeMachineAccountPrivilege, 421 | SeTcbPrivilege, 422 | SeSecurityPrivilege, 423 | SeTakeOwnershipPrivilege, 424 | SeLoadDriverPrivilege, 425 | SeSystemProfilePrivilege, 426 | SeSystemtimePrivilege, 427 | SeProfileSingleProcessPrivilege, 428 | SeIncreaseBasePriorityPrivilege, 429 | SeCreatePagefilePrivilege, 430 | SeCreatePermanentPrivilege, 431 | SeBackupPrivilege, 432 | SeRestorePrivilege, 433 | SeShutdownPrivilege, 434 | SeDebugPrivilege, 435 | SeAuditPrivilege, 436 | SeSystemEnvironmentPrivilege, 437 | SeChangeNotifyPrivilege, 438 | SeRemoteShutdownPrivilege, 439 | SeUndockPrivilege, 440 | SeSyncAgentPrivilege, 441 | SeEnableDelegationPrivilege, 442 | SeManageVolumePrivilege, 443 | SeImpersonatePrivilege, 444 | SeCreateGlobalPrivilege, 445 | SeTrustedCredManAccessPrivilege, 446 | SeRelabelPrivilege, 447 | SeIncreaseWorkingSetPrivilege, 448 | SeTimeZonePrivilege, 449 | SeCreateSymbolicLinkPrivilege, 450 | SeMaxWellKnownPrivilege = SeCreateSymbolicLinkPrivilege 451 | } TOKEN_PRIVILEGES_LIST, *PTOKEN_PRIVILEGES_LIST; 452 | 453 | /* 454 | 访问令牌完整性级别定义 455 | The definitions of the Token Integrity Levels 456 | */ 457 | typedef enum _TOKEN_INTEGRITY_LEVELS_LIST 458 | { 459 | // S-1-16-0 460 | UntrustedLevel = SECURITY_MANDATORY_UNTRUSTED_RID, 461 | 462 | // S-1-16-4096 463 | LowLevel = SECURITY_MANDATORY_LOW_RID, 464 | 465 | // S-1-16-8192 466 | MediumLevel = SECURITY_MANDATORY_MEDIUM_RID, 467 | 468 | // S-1-16-8448 469 | MediumPlusLevel = SECURITY_MANDATORY_MEDIUM_PLUS_RID, 470 | 471 | // S-1-16-12288 472 | HighLevel = SECURITY_MANDATORY_HIGH_RID, 473 | 474 | // S-1-16-16384 475 | SystemLevel = SECURITY_MANDATORY_SYSTEM_RID, 476 | 477 | // S-1-16-20480 478 | ProtectedLevel = SECURITY_MANDATORY_PROTECTED_PROCESS_RID 479 | } TOKEN_INTEGRITY_LEVELS_LIST, *PTOKEN_INTEGRITY_LEVELS_LIST; 480 | 481 | /* 482 | SuSetTokenPrivilege函数启用或禁用指定的访问令牌的指定特权。启用或禁用一个访 483 | 问令牌的特权需要TOKEN_ADJUST_PRIVILEGES访问权限。 484 | The SuSetTokenPrivilege function enables or disables the specified 485 | privilege in the specified access token. Enabling or disabling privileges 486 | in an access token requires TOKEN_ADJUST_PRIVILEGES access. 487 | */ 488 | static NTSTATUS WINAPI SuSetTokenPrivilege( 489 | _In_ HANDLE hExistingToken, 490 | _In_ TOKEN_PRIVILEGES_LIST Privilege, 491 | _In_ bool bEnable) 492 | { 493 | TOKEN_PRIVILEGES TP; 494 | TP.PrivilegeCount = 1; 495 | TP.Privileges[0].Luid.LowPart = Privilege; 496 | TP.Privileges[0].Attributes = (DWORD)(bEnable ? SE_PRIVILEGE_ENABLED : 0); 497 | 498 | return SuSetTokenPrivileges(hExistingToken, &TP); 499 | } 500 | 501 | /* 502 | SuSetTokenAllPrivileges函数启用或禁用指定的访问令牌的所有特权。启用或禁用一 503 | 个访问令牌的特权需要TOKEN_ADJUST_PRIVILEGES访问权限。 504 | The SuSetTokenAllPrivileges function enables or disables all privileges in 505 | the specified access token. Enabling or disabling privileges in an access 506 | token requires TOKEN_ADJUST_PRIVILEGES access. 507 | */ 508 | static NTSTATUS WINAPI SuSetTokenAllPrivileges( 509 | _In_ HANDLE hExistingToken, 510 | _In_ bool bEnable) 511 | { 512 | NTSTATUS status = STATUS_SUCCESS; 513 | PTOKEN_PRIVILEGES pTPs = nullptr; 514 | DWORD Length = 0; 515 | 516 | // 获取特权信息大小 517 | NtQueryInformationToken( 518 | hExistingToken, TokenPrivileges, nullptr, 0, &Length); 519 | 520 | // 分配内存 521 | status = M2HeapAlloc(Length, pTPs); 522 | if (NT_SUCCESS(status)) 523 | { 524 | // 获取特权信息 525 | status = NtQueryInformationToken( 526 | hExistingToken, 527 | TokenPrivileges, 528 | pTPs, 529 | Length, 530 | &Length); 531 | if (NT_SUCCESS(status)) 532 | { 533 | // 设置特权信息 534 | for (DWORD i = 0; i < pTPs->PrivilegeCount; i++) 535 | pTPs->Privileges[i].Attributes = 536 | (DWORD)(bEnable ? SE_PRIVILEGE_ENABLED : 0); 537 | 538 | // 开启全部特权 539 | status = SuSetTokenPrivileges(hExistingToken, pTPs); 540 | } 541 | 542 | // 释放内存 543 | M2HeapFree(pTPs); 544 | } 545 | 546 | return status; 547 | } 548 | 549 | // sizeof(SID_IDENTIFIER_AUTHORITY) 550 | const SIZE_T SIA_Length = sizeof(SID_IDENTIFIER_AUTHORITY); 551 | 552 | // SECURITY_NT_AUTHORITY 553 | static SID_IDENTIFIER_AUTHORITY SIA_NT = SECURITY_NT_AUTHORITY; 554 | 555 | // SECURITY_WORLD_SID_AUTHORITY 556 | static SID_IDENTIFIER_AUTHORITY SIA_World = SECURITY_WORLD_SID_AUTHORITY; 557 | 558 | // SECURITY_APP_PACKAGE_AUTHORITY 559 | static SID_IDENTIFIER_AUTHORITY SIA_App = SECURITY_APP_PACKAGE_AUTHORITY; 560 | 561 | // SECURITY_MANDATORY_LABEL_AUTHORITY 562 | static SID_IDENTIFIER_AUTHORITY SIA_IL = SECURITY_MANDATORY_LABEL_AUTHORITY; 563 | 564 | /* 565 | SuSetTokenIntegrityLevel函数为指定的访问令牌设置完整性标签。 566 | The SuSetTokenIntegrityLevel function sets the integrity level for the 567 | specified access token. 568 | */ 569 | static NTSTATUS WINAPI SuSetTokenIntegrityLevel( 570 | _In_ HANDLE TokenHandle, 571 | _In_ TOKEN_INTEGRITY_LEVELS_LIST IL) 572 | { 573 | NTSTATUS status = STATUS_SUCCESS; 574 | TOKEN_MANDATORY_LABEL TML; 575 | 576 | // 初始化SID 577 | status = RtlAllocateAndInitializeSid( 578 | &SIA_IL, 1, IL, 0, 0, 0, 0, 0, 0, 0, &TML.Label.Sid); 579 | if (NT_SUCCESS(status)) 580 | { 581 | // 初始化TOKEN_MANDATORY_LABEL 582 | TML.Label.Attributes = SE_GROUP_INTEGRITY; 583 | 584 | // 设置令牌对象 585 | status = NtSetInformationToken( 586 | TokenHandle, TokenIntegrityLevel, &TML, sizeof(TML)); 587 | 588 | // 释放SID 589 | RtlFreeSid(TML.Label.Sid); 590 | } 591 | 592 | return status; 593 | } 594 | 595 | /* 596 | SuIsLogonSid函数判断指定的SID是否为登录SID。 597 | The SuIsLogonSid function determines whether the specified SID is a logon 598 | SID. 599 | */ 600 | static bool WINAPI SuIsLogonSid( 601 | _In_ PSID pSid) 602 | { 603 | // 获取pSid的SID_IDENTIFIER_AUTHORITY结构 604 | PSID_IDENTIFIER_AUTHORITY pSidAuth = RtlIdentifierAuthoritySid(pSid); 605 | 606 | // 如果不符合SID_IDENTIFIER_AUTHORITY结构长度,则返回false 607 | if (memcmp(pSidAuth, &SIA_NT, SIA_Length)) return false; 608 | 609 | // 判断SID是否属于Logon SID 610 | return (*RtlSubAuthorityCountSid(pSid) == SECURITY_LOGON_IDS_RID_COUNT 611 | && *RtlSubAuthoritySid(pSid, 0) == SECURITY_LOGON_IDS_RID); 612 | } 613 | 614 | /* 615 | SuSetKernelObjectIntegrityLevel函数为指定的内核对象设置完整性标签。 616 | The SuSetKernelObjectIntegrityLevel function sets the integrity level for 617 | the specified kernel object. 618 | */ 619 | static NTSTATUS WINAPI SuSetKernelObjectIntegrityLevel( 620 | _In_ HANDLE Object, 621 | _In_ TOKEN_INTEGRITY_LEVELS_LIST IL) 622 | { 623 | const size_t AclLength = 88; 624 | NTSTATUS status = STATUS_SUCCESS; 625 | PSID pSID = nullptr; 626 | PACL pAcl = nullptr; 627 | SECURITY_DESCRIPTOR SD; 628 | HANDLE hNewHandle = nullptr; 629 | 630 | // 复制句柄 631 | status = NtDuplicateObject( 632 | NtCurrentProcess(), 633 | Object, 634 | NtCurrentProcess(), 635 | &hNewHandle, 636 | DIRECTORY_ALL_ACCESS, 637 | 0, 638 | 0); 639 | if (!NT_SUCCESS(status)) goto FuncEnd; 640 | 641 | //初始化SID 642 | status = RtlAllocateAndInitializeSid( 643 | &SIA_IL, 1, IL, 0, 0, 0, 0, 0, 0, 0, &pSID); 644 | if (!NT_SUCCESS(status)) goto FuncEnd; 645 | 646 | //分配ACL结构内存 647 | status = M2HeapAlloc(AclLength, pAcl); 648 | if (!NT_SUCCESS(status)) goto FuncEnd; 649 | 650 | // 创建SD 651 | status = RtlCreateSecurityDescriptor( 652 | &SD, SECURITY_DESCRIPTOR_REVISION); 653 | if (!NT_SUCCESS(status)) goto FuncEnd; 654 | 655 | // 创建ACL 656 | status = RtlCreateAcl(pAcl, AclLength, ACL_REVISION); 657 | if (!NT_SUCCESS(status)) goto FuncEnd; 658 | 659 | // 添加完整性ACE 660 | status = RtlAddMandatoryAce( 661 | pAcl, ACL_REVISION, 0, pSID, 662 | SYSTEM_MANDATORY_LABEL_ACE_TYPE, OBJECT_TYPE_CREATE); 663 | if (!NT_SUCCESS(status)) goto FuncEnd; 664 | 665 | // 设置SACL 666 | status = RtlSetSaclSecurityDescriptor(&SD, TRUE, pAcl, FALSE); 667 | if (!NT_SUCCESS(status)) goto FuncEnd; 668 | 669 | // 设置内核对象 670 | status = NtSetSecurityObject( 671 | hNewHandle, LABEL_SECURITY_INFORMATION, &SD); 672 | 673 | FuncEnd: 674 | M2HeapFree(pAcl); 675 | RtlFreeSid(pSID); 676 | NtClose(hNewHandle); 677 | 678 | return status; 679 | } 680 | 681 | /* 682 | SuCreateLUAToken函数从一个现有的访问令牌创建一个新的LUA访问令牌。 683 | The SuCreateLUAToken function creates a new LUA access token from an 684 | existing access token. 685 | */ 686 | static NTSTATUS WINAPI SuCreateLUAToken( 687 | _Out_ PHANDLE TokenHandle, 688 | _In_ HANDLE ExistingTokenHandle) 689 | { 690 | NTSTATUS status = STATUS_SUCCESS; 691 | DWORD Length = 0; 692 | BOOL EnableTokenVirtualization = TRUE; 693 | TOKEN_OWNER Owner = { 0 }; 694 | TOKEN_DEFAULT_DACL NewTokenDacl = { 0 }; 695 | PTOKEN_USER pTokenUser = nullptr; 696 | PTOKEN_DEFAULT_DACL pTokenDacl = nullptr; 697 | PSID pAdminSid = nullptr; 698 | PACCESS_ALLOWED_ACE pTempAce = nullptr; 699 | 700 | //创建受限令牌 701 | status = NtFilterToken( 702 | ExistingTokenHandle, LUA_TOKEN, 703 | nullptr, nullptr, nullptr, TokenHandle); 704 | if (!NT_SUCCESS(status)) goto FuncEnd; 705 | 706 | // 设置令牌完整性 707 | status = SuSetTokenIntegrityLevel( 708 | *TokenHandle, TOKEN_INTEGRITY_LEVELS_LIST::MediumLevel); 709 | if (!NT_SUCCESS(status)) goto FuncEnd; 710 | 711 | // 获取令牌对应的用户账户SID信息大小 712 | status = NtQueryInformationToken( 713 | *TokenHandle, TokenUser, nullptr, 0, &Length); 714 | if (status != STATUS_BUFFER_TOO_SMALL) goto FuncEnd; 715 | 716 | // 为令牌对应的用户账户SID信息分配内存 717 | status = M2HeapAlloc(Length, pTokenUser); 718 | if (!NT_SUCCESS(status)) goto FuncEnd; 719 | 720 | // 获取令牌对应的用户账户SID信息 721 | status = NtQueryInformationToken( 722 | *TokenHandle, TokenUser, pTokenUser, Length, &Length); 723 | if (!NT_SUCCESS(status)) goto FuncEnd; 724 | 725 | // 设置令牌Owner为当前用户 726 | Owner.Owner = pTokenUser->User.Sid; 727 | status = NtSetInformationToken( 728 | *TokenHandle, TokenOwner, &Owner, sizeof(TOKEN_OWNER)); 729 | if (!NT_SUCCESS(status)) goto FuncEnd; 730 | 731 | // 获取令牌的DACL信息大小 732 | status = NtQueryInformationToken( 733 | *TokenHandle, TokenDefaultDacl, nullptr, 0, &Length); 734 | if (status != STATUS_BUFFER_TOO_SMALL) goto FuncEnd; 735 | 736 | // 为令牌的DACL信息分配内存 737 | status = M2HeapAlloc(Length, pTokenDacl); 738 | if (!NT_SUCCESS(status)) goto FuncEnd; 739 | 740 | // 获取令牌的DACL信息 741 | status = NtQueryInformationToken( 742 | *TokenHandle, TokenDefaultDacl, pTokenDacl, Length, &Length); 743 | if (!NT_SUCCESS(status)) goto FuncEnd; 744 | 745 | // 获取管理员组SID 746 | status = RtlAllocateAndInitializeSid( 747 | &SIA_NT, 2, 748 | SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 749 | 0, 0, 0, 0, 0, 0, &pAdminSid); 750 | if (!NT_SUCCESS(status)) goto FuncEnd; 751 | 752 | // 计算新ACL大小 753 | Length = pTokenDacl->DefaultDacl->AclSize; 754 | Length += RtlLengthSid(pTokenUser->User.Sid); 755 | Length += sizeof(ACCESS_ALLOWED_ACE); 756 | 757 | // 分配ACL结构内存 758 | status = M2HeapAlloc(Length, NewTokenDacl.DefaultDacl); 759 | if (!NT_SUCCESS(status)) goto FuncEnd; 760 | 761 | // 创建ACL 762 | status = RtlCreateAcl( 763 | NewTokenDacl.DefaultDacl, 764 | Length, pTokenDacl->DefaultDacl->AclRevision); 765 | if (!NT_SUCCESS(status)) goto FuncEnd; 766 | 767 | // 添加ACE 768 | status = RtlAddAccessAllowedAce( 769 | NewTokenDacl.DefaultDacl, 770 | pTokenDacl->DefaultDacl->AclRevision, 771 | GENERIC_ALL, 772 | pTokenUser->User.Sid); 773 | if (!NT_SUCCESS(status)) goto FuncEnd; 774 | 775 | // 复制ACE 776 | for (ULONG i = 0; 777 | NT_SUCCESS(RtlGetAce(pTokenDacl->DefaultDacl, i, (PVOID*)&pTempAce)); 778 | ++i) 779 | { 780 | if (RtlEqualSid(pAdminSid, &pTempAce->SidStart)) continue; 781 | 782 | RtlAddAce( 783 | NewTokenDacl.DefaultDacl, 784 | pTokenDacl->DefaultDacl->AclRevision, 0, 785 | pTempAce, pTempAce->Header.AceSize); 786 | } 787 | 788 | // 设置令牌DACL 789 | Length += sizeof(TOKEN_DEFAULT_DACL); 790 | status = NtSetInformationToken( 791 | *TokenHandle, TokenDefaultDacl, &NewTokenDacl, Length); 792 | if (!NT_SUCCESS(status)) goto FuncEnd; 793 | 794 | // 开启LUA虚拟化 795 | status = NtSetInformationToken( 796 | *TokenHandle, 797 | TokenVirtualizationEnabled, 798 | &EnableTokenVirtualization, 799 | sizeof(BOOL)); 800 | if (!NT_SUCCESS(status)) goto FuncEnd; 801 | 802 | FuncEnd: // 扫尾 803 | 804 | if (NewTokenDacl.DefaultDacl) M2HeapFree(NewTokenDacl.DefaultDacl); 805 | if (pAdminSid) RtlFreeSid(pAdminSid); 806 | if (pTokenDacl) M2HeapFree(pTokenDacl); 807 | if (pTokenUser) M2HeapFree(pTokenUser); 808 | if (!NT_SUCCESS(status)) 809 | { 810 | NtClose(*TokenHandle); 811 | *TokenHandle = INVALID_HANDLE_VALUE; 812 | } 813 | 814 | return status; 815 | } 816 | 817 | /* 818 | 内部使用的AppContainer对象列表 819 | The list of the AppContainer Objects for Internal use. 820 | */ 821 | const enum SuAppContainerHandleList 822 | { 823 | RootDirectory, // 主目录对象 824 | RpcDirectory, // RPC目录对象 825 | GlobalSymbolicLink, // Global符号链接 826 | LocalSymbolicLink, // Local符号链接 827 | SessionSymbolicLink, // Session符号链接 828 | NamedPipe //命名管道 829 | }; 830 | 831 | /* 832 | SuBuildAppContainerSecurityDescriptor函数从为创建一个新的AppContainer访问令 833 | 牌构建一个新的安全标识符结构。 834 | The SuBuildAppContainerSecurityDescriptor function builds a new Security 835 | Descriptor struct for creating a new AppContainer access token. 836 | */ 837 | NTSTATUS WINAPI SuBuildAppContainerSecurityDescriptor( 838 | _In_ PSECURITY_DESCRIPTOR ExistingSecurityDescriptor, 839 | _In_ PSID SandBoxSid, 840 | _In_ PSID UserSid, 841 | _In_ bool IsRpcControl, 842 | _Out_ PSECURITY_DESCRIPTOR *NewSecurityDescriptor) 843 | { 844 | NTSTATUS status = STATUS_SUCCESS; 845 | DWORD ReturnLength = 0; 846 | BOOLEAN DaclPresent = FALSE; 847 | BOOLEAN DaclDefaulted = FALSE; 848 | PACL pAcl = nullptr; 849 | PACL pNewAcl = nullptr; 850 | PSID AdminSid = nullptr; 851 | PSID RestrictedSid = nullptr; 852 | PSID WorldSid = nullptr; 853 | bool bUserSidExist = false; 854 | PACCESS_ALLOWED_ACE pTempAce = nullptr; 855 | 856 | //生成受限组SID结构 857 | status = RtlAllocateAndInitializeSid( 858 | &SIA_NT, 1, SECURITY_RESTRICTED_CODE_RID, 859 | 0, 0, 0, 0, 0, 0, 0, &RestrictedSid); 860 | if (!NT_SUCCESS(status)) goto FuncEnd; 861 | 862 | //生成管理员组SID结构 863 | status = RtlAllocateAndInitializeSid( 864 | &SIA_NT, 2, SECURITY_BUILTIN_DOMAIN_RID, 865 | DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminSid); 866 | if (!NT_SUCCESS(status)) goto FuncEnd; 867 | 868 | //生成Everyone组SID结构 869 | status = RtlAllocateAndInitializeSid( 870 | &SIA_World, 1, SECURITY_WORLD_RID, 871 | 0, 0, 0, 0, 0, 0, 0, &WorldSid); 872 | if (!NT_SUCCESS(status)) goto FuncEnd; 873 | 874 | //获取现有对象的ACL 875 | status = RtlGetDaclSecurityDescriptor( 876 | ExistingSecurityDescriptor, &DaclPresent, &pAcl, &DaclDefaulted); 877 | if (!NT_SUCCESS(status)) goto FuncEnd; 878 | 879 | //计算新ACL大小 880 | ReturnLength = pAcl->AclSize; 881 | ReturnLength += RtlLengthSid(SandBoxSid) * 2; 882 | ReturnLength += RtlLengthSid(UserSid) * 2; 883 | ReturnLength += RtlLengthSid(RestrictedSid); 884 | ReturnLength += RtlLengthSid(AdminSid); 885 | ReturnLength += RtlLengthSid(WorldSid); 886 | ReturnLength += sizeof(ACCESS_ALLOWED_ACE) * 7; 887 | 888 | //分配ACL结构内存 889 | status = M2HeapAlloc(ReturnLength, pNewAcl); 890 | if (!NT_SUCCESS(status)) goto FuncEnd; 891 | 892 | //创建ACL 893 | status = RtlCreateAcl(pNewAcl, ReturnLength, pAcl->AclRevision); 894 | if (!NT_SUCCESS(status)) goto FuncEnd; 895 | 896 | //复制ACE 897 | for (ULONG i = 0; NT_SUCCESS(RtlGetAce(pAcl, i, (PVOID*)&pTempAce)); i++) 898 | { 899 | //检测登陆SID并对权限做出修改 900 | if (SuIsLogonSid(&pTempAce->SidStart) 901 | && !(pTempAce->Header.AceFlags & INHERIT_ONLY_ACE)) 902 | { 903 | pTempAce->Mask = DIRECTORY_ALL_ACCESS; 904 | } 905 | 906 | //如果不是是rpc句柄则跳过管理员和Everyone的SID添加 907 | if (!IsRpcControl 908 | && (RtlEqualSid(&pTempAce->SidStart, AdminSid) 909 | || RtlEqualSid(&pTempAce->SidStart, RestrictedSid) 910 | || RtlEqualSid(&pTempAce->SidStart, WorldSid))) continue; 911 | 912 | //如果是用户SID存在则标记 913 | if (RtlEqualSid(&pTempAce->SidStart, UserSid)) 914 | bUserSidExist = true; 915 | 916 | //添加ACE 917 | RtlAddAce(pNewAcl, pAcl->AclRevision, 0, 918 | pTempAce, pTempAce->Header.AceSize); 919 | } 920 | 921 | //添加ACE(特殊) - 沙盒SID 922 | status = RtlAddAccessAllowedAce( 923 | pNewAcl, 924 | pAcl->AclRevision, 925 | DIRECTORY_ALL_ACCESS, 926 | SandBoxSid); 927 | if (!NT_SUCCESS(status)) goto FuncEnd; 928 | 929 | //添加ACE(InheritNone) - 沙盒SID 930 | status = RtlAddAccessAllowedAceEx( 931 | pNewAcl, 932 | pAcl->AclRevision, 933 | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, 934 | GENERIC_ALL, 935 | SandBoxSid); 936 | if (!NT_SUCCESS(status)) goto FuncEnd; 937 | 938 | if (!bUserSidExist) 939 | { 940 | //添加ACE(特殊) - 用户SID 941 | status = RtlAddAccessAllowedAce( 942 | pNewAcl, 943 | pAcl->AclRevision, 944 | DIRECTORY_ALL_ACCESS, 945 | UserSid); 946 | if (!NT_SUCCESS(status)) goto FuncEnd; 947 | 948 | //添加ACE(InheritNone) - 用户SID 949 | status = RtlAddAccessAllowedAceEx( 950 | pNewAcl, 951 | pAcl->AclRevision, 952 | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, 953 | GENERIC_ALL, 954 | UserSid); 955 | if (!NT_SUCCESS(status)) goto FuncEnd; 956 | } 957 | 958 | if (IsRpcControl) 959 | { 960 | //添加ACE(InheritNone) - 管理员SID 961 | status = RtlAddAccessAllowedAceEx( 962 | pNewAcl, 963 | pAcl->AclRevision, 964 | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, 965 | GENERIC_ALL, 966 | AdminSid); 967 | if (!NT_SUCCESS(status)) goto FuncEnd; 968 | 969 | //添加ACE(InheritNone) - 受限SID 970 | status = RtlAddAccessAllowedAceEx( 971 | pNewAcl, 972 | pAcl->AclRevision, 973 | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, 974 | GENERIC_READ | GENERIC_EXECUTE, 975 | RestrictedSid); 976 | if (!NT_SUCCESS(status)) goto FuncEnd; 977 | 978 | //添加ACE(InheritNone) - Everyone SID 979 | status = RtlAddAccessAllowedAceEx( 980 | pNewAcl, 981 | pAcl->AclRevision, 982 | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, 983 | GENERIC_READ | GENERIC_EXECUTE, 984 | WorldSid); 985 | if (!NT_SUCCESS(status)) goto FuncEnd; 986 | } 987 | 988 | //分配SD结构内存 989 | status = M2HeapAlloc( 990 | sizeof(SECURITY_DESCRIPTOR), *NewSecurityDescriptor); 991 | if (!NT_SUCCESS(status)) goto FuncEnd; 992 | 993 | //创建SD 994 | status = RtlCreateSecurityDescriptor( 995 | *NewSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 996 | if (!NT_SUCCESS(status)) goto FuncEnd; 997 | 998 | //设置SD 999 | status = RtlSetDaclSecurityDescriptor( 1000 | *NewSecurityDescriptor, DaclPresent, pNewAcl, DaclDefaulted); 1001 | if (!NT_SUCCESS(status)) goto FuncEnd; 1002 | 1003 | FuncEnd: 1004 | RtlFreeSid(WorldSid); 1005 | RtlFreeSid(AdminSid); 1006 | RtlFreeSid(RestrictedSid); 1007 | return status; 1008 | } 1009 | 1010 | #define PIPE_ALL_ACCESS (SYNCHRONIZE \ 1011 | | STANDARD_RIGHTS_REQUIRED \ 1012 | | PIPE_ACCESS_INBOUND \ 1013 | | PIPE_ACCESS_OUTBOUND \ 1014 | | PIPE_ACCESS_DUPLEX) 1015 | 1016 | /* 1017 | SuCreateAppContainerToken函数从一个现有的访问令牌创建一个新的AppContainer访 1018 | 问令牌。 1019 | The SuCreateAppContainerToken function creates a new AppContainer access 1020 | token from an existing access token. 1021 | */ 1022 | NTSTATUS WINAPI SuCreateAppContainerToken( 1023 | _Out_ PHANDLE TokenHandle, 1024 | _In_ HANDLE ExistingTokenHandle, 1025 | _In_ PSECURITY_CAPABILITIES SecurityCapabilities) 1026 | { 1027 | NTSTATUS status = STATUS_SUCCESS; 1028 | PVOID pNTDLL = nullptr; 1029 | UNICODE_STRING usNTDLL = { 0 }; 1030 | ANSI_STRING asFuncName = { 0 }; 1031 | decltype(NtCreateLowBoxToken) *pNtCreateLowBoxToken = nullptr; 1032 | decltype(NtCreateDirectoryObjectEx) *pNtCreateDirectoryObjectEx = nullptr; 1033 | DWORD ReturnLength = 0; 1034 | DWORD TokenSessionID = 0; 1035 | wchar_t Buffer[MAX_PATH]; 1036 | UNICODE_STRING usBNO = RTL_CONSTANT_STRING(L"\\BaseNamedObjects"); 1037 | OBJECT_ATTRIBUTES ObjectAttributes; 1038 | UNICODE_STRING usACNO = { 0 }; 1039 | UNICODE_STRING usRpcControl = RTL_CONSTANT_STRING(L"\\RPC Control"); 1040 | UNICODE_STRING usRpcControl2 = RTL_CONSTANT_STRING(L"RPC Control"); 1041 | UNICODE_STRING usRootDirectory = { 0 }; 1042 | UNICODE_STRING usGlobal = RTL_CONSTANT_STRING(L"Global"); 1043 | UNICODE_STRING usLocal = RTL_CONSTANT_STRING(L"Local"); 1044 | UNICODE_STRING usSession = RTL_CONSTANT_STRING(L"Session"); 1045 | UNICODE_STRING usBNO1 = RTL_CONSTANT_STRING(L"\\BaseNamedObjects"); 1046 | PACCESS_ALLOWED_ACE pTempAce = nullptr; 1047 | UNICODE_STRING usNamedPipe = { 0 }; 1048 | IO_STATUS_BLOCK IoStatusBlock; 1049 | UNICODE_STRING usAppContainerSID = { 0 }; 1050 | HANDLE hBaseNamedObjects = nullptr; 1051 | PSECURITY_DESCRIPTOR pSD = nullptr; 1052 | PTOKEN_USER pTokenUser = nullptr; 1053 | PSECURITY_DESCRIPTOR pDirectorySD = nullptr; 1054 | PSECURITY_DESCRIPTOR pRpcControlSD = nullptr; 1055 | HANDLE hAppContainerNamedObjects = nullptr; 1056 | HANDLE hRpcControl = nullptr; 1057 | HANDLE HandleList[6] = { nullptr }; 1058 | 1059 | // 获取ntdll.dll地址 1060 | M2InitUnicodeString(usNTDLL, L"ntdll.dll"); 1061 | status = LdrGetDllHandleEx(0, nullptr, nullptr, &usNTDLL, &pNTDLL); 1062 | if (!NT_SUCCESS(status)) goto FuncEnd; 1063 | 1064 | // 获取NtCreateLowBoxToken地址 1065 | M2InitString(asFuncName, "NtCreateLowBoxToken"); 1066 | status = LdrGetProcedureAddress( 1067 | pNTDLL, &asFuncName, 0, 1068 | reinterpret_cast(&pNtCreateLowBoxToken)); 1069 | if (!NT_SUCCESS(status)) goto FuncEnd; 1070 | 1071 | // 获取NtCreateDirectoryObjectEx地址 1072 | M2InitString(asFuncName, "NtCreateDirectoryObjectEx"); 1073 | status = LdrGetProcedureAddress( 1074 | pNTDLL, &asFuncName, 0, 1075 | reinterpret_cast(&pNtCreateDirectoryObjectEx)); 1076 | if (!NT_SUCCESS(status)) goto FuncEnd; 1077 | 1078 | // 获取令牌会话ID 1079 | status = NtQueryInformationToken( 1080 | ExistingTokenHandle, 1081 | TokenSessionId, 1082 | &TokenSessionID, 1083 | sizeof(DWORD), 1084 | &ReturnLength); 1085 | if (!NT_SUCCESS(status)) goto FuncEnd; 1086 | 1087 | // 把SID转换为Unicode字符串 1088 | status = RtlConvertSidToUnicodeString( 1089 | &usAppContainerSID, SecurityCapabilities->AppContainerSid, TRUE); 1090 | if (!NT_SUCCESS(status)) goto FuncEnd; 1091 | 1092 | // 如果SessionID不为0,则生成对应会话的路径 1093 | if (TokenSessionID) 1094 | { 1095 | StringCbPrintfW( 1096 | Buffer, sizeof(Buffer), 1097 | L"\\Sessions\\%ld\\BaseNamedObjects", TokenSessionID); 1098 | 1099 | M2InitUnicodeString(usBNO, Buffer); 1100 | } 1101 | 1102 | // 初始化用于打开BaseNamedObjects目录对象的OBJECT_ATTRIBUTES结构 1103 | M2InitObjectAttributes(ObjectAttributes, &usBNO); 1104 | 1105 | // 打开BaseNamedObjects目录对象 1106 | status = NtOpenDirectoryObject( 1107 | &hBaseNamedObjects, 1108 | READ_CONTROL | DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 1109 | &ObjectAttributes); 1110 | if (!NT_SUCCESS(status)) goto FuncEnd; 1111 | 1112 | // 获取BaseNamedObjects目录安全标识符信息大小 1113 | NtQuerySecurityObject( 1114 | hBaseNamedObjects, DACL_SECURITY_INFORMATION, 1115 | nullptr, 0, &ReturnLength); 1116 | 1117 | // 为安全标识符分配内存 1118 | status = M2HeapAlloc(ReturnLength, pSD); 1119 | if (!NT_SUCCESS(status)) goto FuncEnd; 1120 | 1121 | // 获取BaseNamedObjects目录安全标识符信息 1122 | status = NtQuerySecurityObject( 1123 | hBaseNamedObjects, DACL_SECURITY_INFORMATION, 1124 | pSD, ReturnLength, &ReturnLength); 1125 | if (!NT_SUCCESS(status)) goto FuncEnd; 1126 | 1127 | // 获取令牌用户信息大小 1128 | status = NtQueryInformationToken( 1129 | ExistingTokenHandle, TokenUser, 1130 | nullptr, 0, &ReturnLength); 1131 | if (status != STATUS_BUFFER_TOO_SMALL) goto FuncEnd; 1132 | 1133 | // 为令牌用户信息分配内存 1134 | status = M2HeapAlloc(ReturnLength, pTokenUser); 1135 | if (!NT_SUCCESS(status)) goto FuncEnd; 1136 | 1137 | // 获取令牌用户信息 1138 | status = NtQueryInformationToken( 1139 | ExistingTokenHandle, TokenUser, 1140 | pTokenUser, ReturnLength, &ReturnLength); 1141 | if (!NT_SUCCESS(status)) goto FuncEnd; 1142 | 1143 | // 创建AppContainer对象目录安全标识符 1144 | status = SuBuildAppContainerSecurityDescriptor( 1145 | pSD, 1146 | SecurityCapabilities->AppContainerSid, 1147 | pTokenUser->User.Sid, 1148 | false, 1149 | &pDirectorySD); 1150 | if (!NT_SUCCESS(status)) goto FuncEnd; 1151 | 1152 | // 创建AppContainer RPC对象目录安全标识符 1153 | status = SuBuildAppContainerSecurityDescriptor( 1154 | pSD, 1155 | SecurityCapabilities->AppContainerSid, 1156 | pTokenUser->User.Sid, 1157 | true, 1158 | &pRpcControlSD); 1159 | if (!NT_SUCCESS(status)) goto FuncEnd; 1160 | 1161 | // 初始化AppContainerNamedObjects对象目录路径字符串 1162 | StringCbPrintfW( 1163 | Buffer, sizeof(Buffer), 1164 | L"\\Sessions\\%ld\\AppContainerNamedObjects", TokenSessionID); 1165 | 1166 | // 初始化AppContainerNamedObjects对象目录路径UNICODE_STRING结构 1167 | M2InitUnicodeString(usACNO, Buffer); 1168 | 1169 | // 初始化用于打开AppContainerNamedObjects目录对象的OBJECT_ATTRIBUTES结构 1170 | M2InitObjectAttributes(ObjectAttributes, &usACNO); 1171 | 1172 | // 打开AppContainerNamedObjects目录对象 1173 | status = NtOpenDirectoryObject( 1174 | &hAppContainerNamedObjects, 1175 | DIRECTORY_QUERY | DIRECTORY_TRAVERSE | 1176 | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY, 1177 | &ObjectAttributes); 1178 | if (!NT_SUCCESS(status)) goto FuncEnd; 1179 | 1180 | // 初始化用于创建AppContainer目录对象的OBJECT_ATTRIBUTES结构 1181 | M2InitObjectAttributes( 1182 | ObjectAttributes, 1183 | &usAppContainerSID, 1184 | OBJ_INHERIT | OBJ_OPENIF, 1185 | hAppContainerNamedObjects, 1186 | pDirectorySD); 1187 | 1188 | // 创建AppContainer目录对象 1189 | status = pNtCreateDirectoryObjectEx( 1190 | &HandleList[SuAppContainerHandleList::RootDirectory], 1191 | DIRECTORY_QUERY | DIRECTORY_TRAVERSE | 1192 | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY, 1193 | &ObjectAttributes, 1194 | hBaseNamedObjects, 1195 | 1); 1196 | if (!NT_SUCCESS(status)) goto FuncEnd; 1197 | 1198 | // 设置AppContainer目录对象完整性标签为低 1199 | status = SuSetKernelObjectIntegrityLevel( 1200 | HandleList[SuAppContainerHandleList::RootDirectory], 1201 | TOKEN_INTEGRITY_LEVELS_LIST::LowLevel); 1202 | if (!NT_SUCCESS(status)) goto FuncEnd; 1203 | 1204 | // 初始化用于打开RPC Control目录对象的OBJECT_ATTRIBUTES结构 1205 | M2InitObjectAttributes(ObjectAttributes, &usRpcControl); 1206 | 1207 | // 打开RPC Control目录对象 1208 | status = NtOpenDirectoryObject( 1209 | &hRpcControl, 1210 | DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 1211 | &ObjectAttributes); 1212 | if (!NT_SUCCESS(status)) goto FuncEnd; 1213 | 1214 | // 初始化用于创建AppContainer RPC Control目录对象的OBJECT_ATTRIBUTES结构 1215 | M2InitObjectAttributes( 1216 | ObjectAttributes, 1217 | &usRpcControl2, 1218 | OBJ_INHERIT | OBJ_OPENIF, 1219 | HandleList[SuAppContainerHandleList::RootDirectory], 1220 | pRpcControlSD); 1221 | 1222 | // 创建AppContainer RPC Control目录对象 1223 | status = pNtCreateDirectoryObjectEx( 1224 | &HandleList[SuAppContainerHandleList::RpcDirectory], 1225 | DIRECTORY_QUERY | DIRECTORY_TRAVERSE | 1226 | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY, 1227 | &ObjectAttributes, 1228 | hRpcControl, 1229 | 1); 1230 | if (!NT_SUCCESS(status)) goto FuncEnd; 1231 | 1232 | // 设置AppContainer RPC Control目录对象完整性标签为低 1233 | status = SuSetKernelObjectIntegrityLevel( 1234 | HandleList[SuAppContainerHandleList::RpcDirectory], 1235 | TOKEN_INTEGRITY_LEVELS_LIST::LowLevel); 1236 | if (!NT_SUCCESS(status)) goto FuncEnd; 1237 | 1238 | // 初始化AppContainer目录对象字符串 1239 | StringCbPrintfW( 1240 | Buffer, sizeof(Buffer), 1241 | L"\\Sessions\\%d\\AppContainerNamedObjects\\%ws", 1242 | TokenSessionID, 1243 | usAppContainerSID.Buffer, usAppContainerSID.Length); 1244 | 1245 | // 初始化AppContainer目录对象的UNICODE_STRING结构 1246 | M2InitUnicodeString(usRootDirectory, Buffer); 1247 | 1248 | // 初始化用于创建Global符号链接对象的OBJECT_ATTRIBUTES结构 1249 | M2InitObjectAttributes( 1250 | ObjectAttributes, 1251 | &usGlobal, 1252 | OBJ_INHERIT | OBJ_OPENIF, 1253 | HandleList[SuAppContainerHandleList::RootDirectory], 1254 | pDirectorySD); 1255 | 1256 | // 在AppContainer目录对象下创建Global符号链接对象 1257 | status = NtCreateSymbolicLinkObject( 1258 | &HandleList[SuAppContainerHandleList::GlobalSymbolicLink], 1259 | SYMBOLIC_LINK_ALL_ACCESS, 1260 | &ObjectAttributes, 1261 | &usBNO1); 1262 | if (!NT_SUCCESS(status)) goto FuncEnd; 1263 | 1264 | // 初始化用于创建Local符号链接对象的OBJECT_ATTRIBUTES结构 1265 | M2InitObjectAttributes( 1266 | ObjectAttributes, 1267 | &usLocal, 1268 | OBJ_INHERIT | OBJ_OPENIF, 1269 | HandleList[SuAppContainerHandleList::RootDirectory], 1270 | pDirectorySD); 1271 | 1272 | // 在AppContainer目录对象下创建Local符号链接对象 1273 | status = NtCreateSymbolicLinkObject( 1274 | &HandleList[SuAppContainerHandleList::LocalSymbolicLink], 1275 | SYMBOLIC_LINK_ALL_ACCESS, 1276 | &ObjectAttributes, 1277 | &usRootDirectory); 1278 | if (!NT_SUCCESS(status)) goto FuncEnd; 1279 | 1280 | // 初始化用于创建Session符号链接对象的OBJECT_ATTRIBUTES结构 1281 | M2InitObjectAttributes( 1282 | ObjectAttributes, 1283 | &usSession, 1284 | OBJ_INHERIT | OBJ_OPENIF, 1285 | HandleList[SuAppContainerHandleList::RootDirectory], 1286 | pDirectorySD); 1287 | 1288 | // 在AppContainer目录对象下创建Session符号链接对象 1289 | status = NtCreateSymbolicLinkObject( 1290 | &HandleList[SuAppContainerHandleList::SessionSymbolicLink], 1291 | SYMBOLIC_LINK_ALL_ACCESS, 1292 | &ObjectAttributes, 1293 | &usRootDirectory); 1294 | if (!NT_SUCCESS(status)) goto FuncEnd; 1295 | 1296 | // 初始化AppContainer命名管道路径字符串 1297 | StringCbPrintfW( 1298 | Buffer, sizeof(Buffer), 1299 | L"\\Device\\NamedPipe\\Sessions\\%d\\AppContainerNamedObjects\\%ws", 1300 | TokenSessionID, 1301 | usAppContainerSID.Buffer, usAppContainerSID.Length); 1302 | 1303 | for (ULONG i = 0; 1304 | NT_SUCCESS(RtlGetAce( 1305 | ((SECURITY_DESCRIPTOR*)pDirectorySD)->Dacl, 1306 | i, 1307 | (PVOID*)&pTempAce)); 1308 | ++i) 1309 | { 1310 | DWORD LowMask = LOWORD(pTempAce->Mask); 1311 | 1312 | // 清零pTempAce->Mask低16位 1313 | pTempAce->Mask &= ~0xFFFF; 1314 | 1315 | if (FILE_CREATE_PIPE_INSTANCE == (LowMask & FILE_CREATE_PIPE_INSTANCE)) 1316 | pTempAce->Mask |= SYNCHRONIZE | FILE_WRITE_DATA; 1317 | 1318 | if (FILE_READ_EA == (LowMask & FILE_READ_EA)) 1319 | pTempAce->Mask |= SYNCHRONIZE | FILE_CREATE_PIPE_INSTANCE; 1320 | } 1321 | 1322 | // 初始化AppContainer命名管道UNICODE_STRING结构 1323 | M2InitUnicodeString(usNamedPipe, Buffer); 1324 | 1325 | // 初始化创建AppContainer命名管道的OBJECT_ATTRIBUTES结构 1326 | M2InitObjectAttributes( 1327 | ObjectAttributes, 1328 | &usNamedPipe, 1329 | OBJ_INHERIT | OBJ_CASE_INSENSITIVE, 1330 | nullptr, 1331 | pDirectorySD, 1332 | nullptr); 1333 | 1334 | // 创建AppContainer命名管道 1335 | status = NtCreateFile( 1336 | &HandleList[SuAppContainerHandleList::NamedPipe], 1337 | PIPE_ALL_ACCESS, 1338 | &ObjectAttributes, 1339 | &IoStatusBlock, 1340 | nullptr, 1341 | FILE_ATTRIBUTE_NORMAL, 1342 | FILE_SHARE_READ | FILE_SHARE_WRITE, 1343 | FILE_OPEN_IF, 1344 | FILE_DIRECTORY_FILE, 1345 | nullptr, 1346 | 0); 1347 | if (!NT_SUCCESS(status)) goto FuncEnd; 1348 | 1349 | // 初始化用于创建AppContainer令牌对象的OBJECT_ATTRIBUTES结构 1350 | M2InitObjectAttributes(ObjectAttributes); 1351 | 1352 | // 创建AppContainer令牌 1353 | status = pNtCreateLowBoxToken( 1354 | TokenHandle, 1355 | ExistingTokenHandle, 1356 | MAXIMUM_ALLOWED, 1357 | &ObjectAttributes, 1358 | SecurityCapabilities->AppContainerSid, 1359 | SecurityCapabilities->CapabilityCount, 1360 | SecurityCapabilities->Capabilities, 1361 | 6, 1362 | HandleList); 1363 | 1364 | FuncEnd: // 结束处理 1365 | 1366 | for (size_t i = 0; i < 6; ++i) NtClose(HandleList[i]); 1367 | NtClose(hRpcControl); 1368 | NtClose(hAppContainerNamedObjects); 1369 | M2HeapFree(pRpcControlSD); 1370 | M2HeapFree(pDirectorySD); 1371 | M2HeapFree(pTokenUser); 1372 | M2HeapFree(pSD); 1373 | NtClose(hBaseNamedObjects); 1374 | RtlFreeUnicodeString(&usAppContainerSID); 1375 | 1376 | return status; 1377 | } 1378 | 1379 | /* 1380 | SuGenerateRandomAppContainerSid函数生成一个随机AppContainer SID 1381 | The SuGenerateRandomAppContainerSid function generates a random AppContainer 1382 | SID. 1383 | */ 1384 | void WINAPI SuGenerateRandomAppContainerSid( 1385 | _Out_ PSID *RandomAppContainerSid) 1386 | { 1387 | LARGE_INTEGER PerfCounter, PerfFrequency; 1388 | 1389 | // 获取性能计数器数值 1390 | NtQueryPerformanceCounter(&PerfCounter, &PerfFrequency); 1391 | 1392 | //生成种子 1393 | ULONG seed = (ULONG)(PerfCounter.QuadPart - PerfFrequency.QuadPart); 1394 | 1395 | RtlAllocateAndInitializeSid( 1396 | &SIA_App, 1397 | SECURITY_APP_PACKAGE_RID_COUNT, 1398 | SECURITY_APP_PACKAGE_BASE_RID, 1399 | (DWORD)RtlRandomEx(&seed), 1400 | (DWORD)RtlRandomEx(&seed), 1401 | (DWORD)RtlRandomEx(&seed), 1402 | (DWORD)RtlRandomEx(&seed), 1403 | (DWORD)RtlRandomEx(&seed), 1404 | (DWORD)RtlRandomEx(&seed), 1405 | (DWORD)RtlRandomEx(&seed), 1406 | RandomAppContainerSid); 1407 | } 1408 | 1409 | /* 1410 | SuGenerateAppContainerCapabilities函数生成一个AppContainer能力列表.你应该调 1411 | 用M2HeapFree释放你生成的能力列表。 1412 | The SuGenerateAppContainerCapabilities function generates an AppContainer 1413 | capabilities list. You should call M2HeapFree to free the memory the list 1414 | which you generated. 1415 | */ 1416 | NTSTATUS WINAPI SuGenerateAppContainerCapabilities( 1417 | _Out_ PSID_AND_ATTRIBUTES *Capabilities, 1418 | _In_ DWORD *CapabilitiyRIDs, 1419 | _In_ DWORD CapabilityCount) 1420 | { 1421 | NTSTATUS status = STATUS_SUCCESS; 1422 | 1423 | //设置参数及分配内存 1424 | status = M2HeapAlloc( 1425 | CapabilityCount * sizeof(SID_AND_ATTRIBUTES), *Capabilities); 1426 | if (!NT_SUCCESS(status)) goto Error; 1427 | 1428 | //获取能力SID 1429 | for (DWORD i = 0; i < CapabilityCount; i++) 1430 | { 1431 | (*Capabilities)[i].Attributes = SE_GROUP_ENABLED; 1432 | status = RtlAllocateAndInitializeSid( 1433 | &SIA_App, 1434 | SECURITY_BUILTIN_CAPABILITY_RID_COUNT, 1435 | SECURITY_CAPABILITY_BASE_RID, CapabilitiyRIDs[i], 1436 | 0, 0, 0, 0, 0, 0, 1437 | &(*Capabilities)[i].Sid); 1438 | if (!NT_SUCCESS(status)) goto Error; 1439 | } 1440 | 1441 | return status; 1442 | 1443 | Error: // 错误处理 1444 | 1445 | if (*Capabilities) 1446 | { 1447 | for (DWORD i = 0; i < CapabilityCount; i++) 1448 | if ((*Capabilities)[i].Sid) RtlFreeSid((*Capabilities)[i].Sid); 1449 | 1450 | M2HeapFree(*Capabilities); 1451 | *Capabilities = nullptr; 1452 | } 1453 | 1454 | return status; 1455 | } 1456 | 1457 | /* 1458 | SuCLRExecuteAssembly函数执行指定的.Net程序集。入口方法格式为: 1459 | The SuCLRExecuteAssembly function executes the specified .Net Assembly. 1460 | The format of the entry method: 1461 | 1462 | static int pwzMethodName(String pwzArgument); 1463 | */ 1464 | static HRESULT WINAPI SuCLRExecuteAssembly( 1465 | _In_ LPCWSTR pwzVersion, 1466 | _In_ LPCWSTR pwzAssemblyPath, 1467 | _In_ LPCWSTR pwzTypeName, 1468 | _In_ LPCWSTR pwzMethodName, 1469 | _In_ LPCWSTR pwzArgument) 1470 | { 1471 | HRESULT hr = E_NOTIMPL; 1472 | 1473 | ICLRMetaHost *pMetaHost = nullptr; 1474 | ICLRRuntimeInfo *pRuntimeInfo = nullptr; 1475 | 1476 | // ICorRuntimeHost和ICLRRuntimeHost是CLR 4.0支持的两个CLR宿主接口 1477 | // 以下是使用.Net v2.0提供的ICLRRuntimeHost接口以支持CLR 2.0新功能的示例 1478 | // ICLRRuntimeHost不支持加载.NET v1.x运行时. 1479 | ICLRRuntimeHost *pClrRuntimeHost = nullptr; 1480 | 1481 | // The static method in the .NET class to invoke. 1482 | DWORD pReturnValue = 0; 1483 | 1484 | // 1485 | // 加载并启动.NET运行时. 1486 | // 1487 | 1488 | wprintf(L"Load and start the .NET runtime %s \n", pwzVersion); 1489 | 1490 | PVOID pDllModule = nullptr; 1491 | 1492 | NTSTATUS status = STATUS_SUCCESS; 1493 | CLRCreateInstanceFnPtr pCLRCreateInstance = nullptr; 1494 | 1495 | status = M2LoadModule(pDllModule, L"mscoree.dll"); 1496 | if (!NT_SUCCESS(status)) 1497 | { 1498 | hr = __HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); 1499 | goto Cleanup; 1500 | } 1501 | 1502 | status = M2GetProcedureAddress( 1503 | pCLRCreateInstance, pDllModule, "CLRCreateInstance"); 1504 | if (!NT_SUCCESS(status)) 1505 | { 1506 | hr = __HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); 1507 | goto Cleanup; 1508 | } 1509 | 1510 | hr = pCLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); 1511 | if (FAILED(hr)) 1512 | { 1513 | wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr); 1514 | goto Cleanup; 1515 | } 1516 | 1517 | // 获取对应CLR版本的ICLRRuntimeInfo接口 1518 | hr = pMetaHost->GetRuntime(pwzVersion, IID_PPV_ARGS(&pRuntimeInfo)); 1519 | if (FAILED(hr)) 1520 | { 1521 | wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr); 1522 | goto Cleanup; 1523 | } 1524 | 1525 | // 检测特定版本的运行时是否可以加载入当前进程 1526 | BOOL fLoadable = FALSE; 1527 | hr = pRuntimeInfo->IsLoadable(&fLoadable); 1528 | if (FAILED(hr)) 1529 | { 1530 | wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr); 1531 | goto Cleanup; 1532 | } 1533 | 1534 | if (!fLoadable) 1535 | { 1536 | wprintf(L".NET runtime %s cannot be loaded\n", pwzVersion); 1537 | goto Cleanup; 1538 | } 1539 | 1540 | // 加载特定版本CLR到当前进程,并获取ICLRRuntimeHost接口 1541 | hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, 1542 | IID_PPV_ARGS(&pClrRuntimeHost)); 1543 | if (FAILED(hr)) 1544 | { 1545 | wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr); 1546 | goto Cleanup; 1547 | } 1548 | 1549 | // 启动CLR. 1550 | hr = pClrRuntimeHost->Start(); 1551 | if (FAILED(hr)) 1552 | { 1553 | wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr); 1554 | goto Cleanup; 1555 | } 1556 | 1557 | wprintf(L"Load the assembly %s\n", pwzAssemblyPath); 1558 | 1559 | // 调用pwzAssemblyPath程序集pwzTypeName类的方法并在pReturnValue返回运行结果 1560 | // 方法格式为 static int pwzMethodName(String pwzArgument) 1561 | hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( 1562 | pwzAssemblyPath, 1563 | pwzTypeName, 1564 | pwzMethodName, 1565 | pwzArgument, 1566 | &pReturnValue); 1567 | if (FAILED(hr)) 1568 | { 1569 | wprintf(L"Failed to call %s w/hr 0x%08lx\n", pwzMethodName, hr); 1570 | goto Cleanup; 1571 | } 1572 | 1573 | // Print the call result of the static method. 1574 | wprintf(L"Call %s.%s(\"%s\") => %d\n", pwzTypeName, pwzMethodName, 1575 | pwzArgument, (int)pReturnValue); 1576 | 1577 | Cleanup: 1578 | 1579 | if (pMetaHost) 1580 | { 1581 | pMetaHost->Release(); 1582 | pMetaHost = nullptr; 1583 | } 1584 | if (pRuntimeInfo) 1585 | { 1586 | pRuntimeInfo->Release(); 1587 | pRuntimeInfo = nullptr; 1588 | } 1589 | if (pClrRuntimeHost) 1590 | { 1591 | pClrRuntimeHost->Release(); 1592 | pClrRuntimeHost = nullptr; 1593 | } 1594 | 1595 | if (pDllModule) 1596 | { 1597 | M2FreeModule(pDllModule); 1598 | pDllModule = nullptr; 1599 | } 1600 | 1601 | return hr; 1602 | } 1603 | 1604 | /* 1605 | SuCreateProcess函数创建一个新进程和对应的主线程 1606 | The SuCreateProcess function creates a new process and its primary thread. 1607 | */ 1608 | static HRESULT WINAPI SuCreateProcess( 1609 | _In_opt_ HANDLE hToken, 1610 | _In_opt_ LPCWSTR lpApplicationName, 1611 | _Inout_opt_ LPWSTR lpCommandLine, 1612 | _In_ DWORD dwCreationFlags, 1613 | _In_opt_ LPVOID lpEnvironment, 1614 | _In_opt_ LPCWSTR lpCurrentDirectory, 1615 | _In_ LPSTARTUPINFOW lpStartupInfo, 1616 | _Out_ LPPROCESS_INFORMATION lpProcessInformation) 1617 | { 1618 | HRESULT hr = S_OK; 1619 | 1620 | if (!CreateProcessAsUserW( 1621 | hToken, 1622 | lpApplicationName, 1623 | lpCommandLine, 1624 | nullptr, 1625 | nullptr, 1626 | FALSE, 1627 | dwCreationFlags, 1628 | lpEnvironment, 1629 | lpCurrentDirectory, 1630 | lpStartupInfo, 1631 | lpProcessInformation)) 1632 | { 1633 | if (!CreateProcessWithTokenW( 1634 | hToken, 1635 | LOGON_WITH_PROFILE, 1636 | lpApplicationName, 1637 | lpCommandLine, 1638 | dwCreationFlags, 1639 | lpEnvironment, 1640 | lpCurrentDirectory, 1641 | lpStartupInfo, 1642 | lpProcessInformation)) 1643 | { 1644 | hr = __HRESULT_FROM_WIN32(M2GetLastError()); 1645 | } 1646 | } 1647 | 1648 | return hr; 1649 | } 1650 | 1651 | class CSuProcessSnapshot 1652 | { 1653 | public: 1654 | /* 1655 | 初始化进程快照 1656 | Initialize the Process Snapshot 1657 | */ 1658 | CSuProcessSnapshot( 1659 | _Out_ PNTSTATUS Status) 1660 | { 1661 | *Status = this->Refresh(); 1662 | } 1663 | 1664 | /* 1665 | 反初始化进程快照 1666 | Uninitialize the Process Snapshot 1667 | */ 1668 | ~CSuProcessSnapshot() 1669 | { 1670 | if (lpBuffer) M2HeapFree(lpBuffer); 1671 | } 1672 | 1673 | /* 1674 | 刷新进程快照 1675 | Refresh the Process Snapshot 1676 | */ 1677 | NTSTATUS Refresh() 1678 | { 1679 | NTSTATUS status = STATUS_SUCCESS; 1680 | DWORD dwLength = 0; 1681 | 1682 | do 1683 | { 1684 | // 获取进程信息大小 1685 | status = NtQuerySystemInformation( 1686 | SystemProcessInformation, 1687 | nullptr, 1688 | 0, 1689 | &dwLength); 1690 | if (status != STATUS_INFO_LENGTH_MISMATCH) break; 1691 | 1692 | // 为令牌信息分配内存,如果失败则返回 1693 | status = M2HeapAlloc( 1694 | dwLength, 1695 | lpBuffer); 1696 | if (!NT_SUCCESS(status)) break; 1697 | 1698 | // 获取进程信息 1699 | status = NtQuerySystemInformation( 1700 | SystemProcessInformation, 1701 | lpBuffer, 1702 | dwLength, 1703 | &dwLength); 1704 | 1705 | // 设置遍历开始地址 1706 | pTemp = (ULONG_PTR)(PVOID)lpBuffer; 1707 | 1708 | } while (false); 1709 | 1710 | return status; 1711 | } 1712 | 1713 | /* 1714 | 遍历进程快照 1715 | Enumerate the Process Snapshot 1716 | */ 1717 | bool Next( 1718 | _Out_ PSYSTEM_PROCESS_INFORMATION *pSPI) 1719 | { 1720 | *pSPI = (PSYSTEM_PROCESS_INFORMATION)pTemp; 1721 | 1722 | // 如果*pSPI=0或下个结构偏移=0时则pTemp=0,否则pTemp=下个结构地址 1723 | if (!*pSPI || !(*pSPI)->NextEntryOffset) pTemp = 0; 1724 | else pTemp += (*pSPI)->NextEntryOffset; 1725 | 1726 | // 返回执行结果 1727 | return (*pSPI != nullptr); 1728 | } 1729 | 1730 | private: 1731 | PVOID lpBuffer; 1732 | ULONG_PTR pTemp = 0; 1733 | }; 1734 | 1735 | 1736 | #if _MSC_VER >= 1200 1737 | #pragma warning(push) 1738 | #pragma warning(disable:4355) // "this": 用于基成员初始值设定项列表 1739 | #endif 1740 | 1741 | /* 1742 | 进程列表遍历迭代器 1743 | Iterator for enumerate the process list 1744 | 1745 | 用法 Usage 1746 | for (auto pSPI : CM2EnumProcess(status)) { } 1747 | 1748 | status 是初始化遍历返回值(可选) 1749 | status is the return value for initialization (Optional) 1750 | */ 1751 | class CM2EnumProcess 1752 | { 1753 | public: 1754 | class CM2EnumProcessIterator 1755 | { 1756 | private: 1757 | CM2EnumProcess* m_EnumProcess; 1758 | 1759 | public: 1760 | FORCEINLINE CM2EnumProcessIterator( 1761 | _In_ CM2EnumProcess* FindFile) : 1762 | m_EnumProcess(FindFile) 1763 | { 1764 | 1765 | } 1766 | 1767 | FORCEINLINE ~CM2EnumProcessIterator() 1768 | { 1769 | 1770 | } 1771 | 1772 | FORCEINLINE void operator++() 1773 | { 1774 | // 如果pSPI和下个结构偏移都存在,则继续循环,否则清零 1775 | if (m_EnumProcess->pSPI && m_EnumProcess->pSPI->NextEntryOffset) 1776 | { 1777 | ULONG_PTR NextSPI = reinterpret_cast(m_EnumProcess->pSPI); 1778 | NextSPI += m_EnumProcess->pSPI->NextEntryOffset; 1779 | m_EnumProcess->pSPI = reinterpret_cast(NextSPI); 1780 | } 1781 | else 1782 | { 1783 | m_EnumProcess->pSPI = nullptr; 1784 | } 1785 | } 1786 | 1787 | // 根据迭代器循环特性,使用不等于操作符遍历目录 1788 | FORCEINLINE bool operator!=(const CM2EnumProcessIterator& Item) 1789 | { 1790 | UNREFERENCED_PARAMETER(Item); 1791 | return (m_EnumProcess->pSPI != nullptr); 1792 | } 1793 | 1794 | FORCEINLINE PSYSTEM_PROCESS_INFORMATION operator*() 1795 | { 1796 | return m_EnumProcess->pSPI; 1797 | } 1798 | }; 1799 | 1800 | private: 1801 | CM2EnumProcessIterator Iterator; 1802 | PVOID lpBuffer; 1803 | PSYSTEM_PROCESS_INFORMATION pSPI; 1804 | 1805 | public: 1806 | // 初始化文件遍历, 不内联考虑到大量使用本迭代器时实现函数复用以节约空间 1807 | DECLSPEC_NOINLINE CM2EnumProcess( 1808 | _Out_ NTSTATUS* InitStatus = nullptr) : 1809 | Iterator(this), 1810 | lpBuffer(nullptr), 1811 | pSPI(nullptr) 1812 | 1813 | { 1814 | NTSTATUS status = STATUS_SUCCESS; 1815 | DWORD dwLength = 0; 1816 | 1817 | do 1818 | { 1819 | // 获取进程信息大小 1820 | status = NtQuerySystemInformation( 1821 | SystemProcessInformation, 1822 | nullptr, 1823 | 0, 1824 | &dwLength); 1825 | if (status != STATUS_INFO_LENGTH_MISMATCH) break; 1826 | 1827 | // 为令牌信息分配内存,如果失败则返回 1828 | status = M2HeapAlloc( 1829 | dwLength, 1830 | lpBuffer); 1831 | if (!NT_SUCCESS(status)) break; 1832 | 1833 | // 获取进程信息 1834 | status = NtQuerySystemInformation( 1835 | SystemProcessInformation, 1836 | lpBuffer, 1837 | dwLength, 1838 | &dwLength); 1839 | if (!NT_SUCCESS(status)) break; 1840 | 1841 | // 设置遍历开始地址 1842 | pSPI = reinterpret_cast(lpBuffer); 1843 | 1844 | } while (false); 1845 | 1846 | if (InitStatus) *InitStatus = status; 1847 | } 1848 | 1849 | FORCEINLINE ~CM2EnumProcess() 1850 | { 1851 | if (lpBuffer) M2HeapFree(lpBuffer); 1852 | } 1853 | 1854 | FORCEINLINE CM2EnumProcessIterator& begin() 1855 | { 1856 | return Iterator; 1857 | } 1858 | 1859 | FORCEINLINE CM2EnumProcessIterator& end() 1860 | { 1861 | return Iterator; 1862 | } 1863 | }; 1864 | 1865 | #if _MSC_VER >= 1200 1866 | #pragma warning(pop) 1867 | #endif 1868 | 1869 | /* 1870 | SuGetSystemTokenCopy函数获取一个当前会话SYSTEM用户令牌的副本。 1871 | The SuGetSystemTokenCopy function obtains a copy of current session SYSTEM 1872 | user token. 1873 | */ 1874 | static NTSTATUS WINAPI SuGetSystemTokenCopy( 1875 | _In_ DWORD dwDesiredAccess, 1876 | _In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes, 1877 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 1878 | _In_ TOKEN_TYPE TokenType, 1879 | _Outptr_ PHANDLE phToken) 1880 | { 1881 | NTSTATUS status = STATUS_SUCCESS; 1882 | DWORD dwWinLogonPID = (DWORD)-1; 1883 | DWORD dwSessionID = (DWORD)-1; 1884 | HANDLE hProcessToken = nullptr; 1885 | 1886 | do 1887 | { 1888 | // 获取当前进程令牌会话ID 1889 | status = SuGetCurrentProcessSessionID(&dwSessionID); 1890 | if (!NT_SUCCESS(status)) break; 1891 | 1892 | // 遍历进程寻找winlogon进程并获取PID 1893 | for (auto pSPI : CM2EnumProcess(&status)) 1894 | { 1895 | if (pSPI->SessionId != dwSessionID) continue; 1896 | if (pSPI->ImageName.Buffer == nullptr) continue; 1897 | 1898 | if (wcscmp(L"winlogon.exe", pSPI->ImageName.Buffer) == 0) 1899 | { 1900 | dwWinLogonPID = HandleToUlong(pSPI->UniqueProcessId); 1901 | break; 1902 | } 1903 | } 1904 | 1905 | // 如果初始化进程遍历失败,则返回错误 1906 | if (!NT_SUCCESS(status)) break; 1907 | 1908 | // 如果没找到进程,则返回错误 1909 | if (dwWinLogonPID == -1) 1910 | { 1911 | status = STATUS_NOT_FOUND; 1912 | break; 1913 | } 1914 | 1915 | // 获取当前会话winlogon进程令牌 1916 | status = SuOpenProcessToken( 1917 | dwWinLogonPID, MAXIMUM_ALLOWED, &hProcessToken); 1918 | if (!NT_SUCCESS(status)) break; 1919 | 1920 | // 复制令牌 1921 | status = SuDuplicateToken( 1922 | hProcessToken, 1923 | dwDesiredAccess, 1924 | lpTokenAttributes, 1925 | ImpersonationLevel, 1926 | TokenType, 1927 | phToken); 1928 | if (!NT_SUCCESS(status)) break; 1929 | 1930 | } while (false); 1931 | 1932 | NtClose(hProcessToken); 1933 | 1934 | return status; 1935 | } 1936 | 1937 | /* 1938 | SuGetServiceProcessTokenCopy函数根据服务名获取一个服务进程令牌的副本。 1939 | The SuGetServiceProcessTokenCopy function obtains a copy of service process 1940 | token via service name. 1941 | */ 1942 | static HRESULT WINAPI SuGetServiceProcessTokenCopy( 1943 | _In_ LPCWSTR lpServiceName, 1944 | _In_ DWORD dwDesiredAccess, 1945 | _In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes, 1946 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 1947 | _In_ TOKEN_TYPE TokenType, 1948 | _Outptr_ PHANDLE phToken) 1949 | { 1950 | HRESULT hr = S_OK; 1951 | NTSTATUS status = STATUS_SUCCESS; 1952 | HANDLE hToken = nullptr; 1953 | 1954 | // 打开服务进程令牌 1955 | hr = SuOpenServiceProcessToken( 1956 | lpServiceName, MAXIMUM_ALLOWED, &hToken); 1957 | if (SUCCEEDED(hr)) 1958 | { 1959 | // 复制令牌 1960 | status = SuDuplicateToken( 1961 | hToken, 1962 | dwDesiredAccess, 1963 | lpTokenAttributes, 1964 | ImpersonationLevel, 1965 | TokenType, 1966 | phToken); 1967 | hr = __HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); 1968 | 1969 | NtClose(hToken); 1970 | } 1971 | 1972 | return hr; 1973 | } 1974 | 1975 | /* 1976 | SuGetSessionTokenCopy函数根据服务名获取一个服务进程令牌的副本。 1977 | The SuGetSessionTokenCopy function obtains a copy of Session token via 1978 | Session ID. 1979 | */ 1980 | static HRESULT WINAPI SuGetSessionTokenCopy( 1981 | _In_ DWORD dwSessionID, 1982 | _In_ DWORD dwDesiredAccess, 1983 | _In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes, 1984 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 1985 | _In_ TOKEN_TYPE TokenType, 1986 | _Outptr_ PHANDLE phToken) 1987 | { 1988 | HRESULT hr = S_OK; 1989 | NTSTATUS status = STATUS_SUCCESS; 1990 | HANDLE hToken = nullptr; 1991 | 1992 | // 打开会话令牌 1993 | hr = SuOpenSessionToken(dwSessionID, &hToken); 1994 | if (SUCCEEDED(hr)) 1995 | { 1996 | // 复制令牌 1997 | status = SuDuplicateToken( 1998 | hToken, 1999 | dwDesiredAccess, 2000 | lpTokenAttributes, 2001 | ImpersonationLevel, 2002 | TokenType, 2003 | phToken); 2004 | hr = __HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); 2005 | 2006 | NtClose(hToken); 2007 | } 2008 | 2009 | return hr; 2010 | } 2011 | 2012 | /* 2013 | SuGetProcessTokenCopy函数根据进程ID获取一个进程令牌的副本。 2014 | The SuGetProcessTokenCopy function obtains a copy of process token via 2015 | Process ID. 2016 | */ 2017 | static NTSTATUS WINAPI SuGetProcessTokenCopy( 2018 | _In_ DWORD dwProcessID, 2019 | _In_ DWORD dwDesiredAccess, 2020 | _In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes, 2021 | _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 2022 | _In_ TOKEN_TYPE TokenType, 2023 | _Outptr_ PHANDLE phToken) 2024 | { 2025 | NTSTATUS status = STATUS_SUCCESS; 2026 | HANDLE hToken = nullptr; 2027 | 2028 | // 打开进程令牌 2029 | status = SuOpenProcessToken(dwProcessID, MAXIMUM_ALLOWED, &hToken); 2030 | if (NT_SUCCESS(status)) 2031 | { 2032 | // 复制令牌 2033 | status = SuDuplicateToken( 2034 | hToken, 2035 | dwDesiredAccess, 2036 | lpTokenAttributes, 2037 | ImpersonationLevel, 2038 | TokenType, 2039 | phToken); 2040 | 2041 | NtClose(hToken); 2042 | } 2043 | 2044 | return status; 2045 | } 2046 | 2047 | /* 2048 | SuImpersonateAsSystem函数给当前线程分配一个SYSTEM用户模拟令牌。该函数还可以 2049 | 使当前线程停止使用模拟令牌。 2050 | The SuImpersonateAsSystem function assigns an SYSTEM user impersonation 2051 | token to the current thread. The function can also cause the current thread 2052 | to stop using an impersonation token. 2053 | */ 2054 | static NTSTATUS WINAPI SuImpersonateAsSystem() 2055 | { 2056 | NTSTATUS status = STATUS_SUCCESS; 2057 | HANDLE hToken = nullptr; 2058 | 2059 | // 获取当前会话SYSTEM用户令牌副本 2060 | status = SuGetSystemTokenCopy( 2061 | MAXIMUM_ALLOWED, 2062 | nullptr, 2063 | SecurityImpersonation, 2064 | TokenImpersonation, 2065 | &hToken); 2066 | if (NT_SUCCESS(status)) 2067 | { 2068 | // 启用令牌全部特权 2069 | status = SuSetTokenAllPrivileges(hToken, true); 2070 | if (NT_SUCCESS(status)) 2071 | { 2072 | // 模拟令牌 2073 | status = SuSetCurrentThreadToken(hToken); 2074 | } 2075 | 2076 | NtClose(hToken); 2077 | } 2078 | 2079 | return status; 2080 | } 2081 | 2082 | #ifdef __cplusplus 2083 | } 2084 | #endif 2085 | 2086 | #endif // !_M2_NSUDO_ 2087 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2.SDK.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 项目:M2-SDK 3 | 描述:M2-SDK 包含用头文件 4 | 文件名:M2.SDK.h 5 | 基于项目:无 6 | 许可协议:看顶层目录的 License.txt 7 | 建议的Windows SDK版本:10.0.10586及以后 8 | 9 | Project: M2-SDK 10 | Description: Header file for including M2-SDK 11 | Filename: M2.SDK.h 12 | License: See License.txt in the top level directory 13 | Recommend Minimum Windows SDK Version: 10.0.10586 14 | ******************************************************************************/ 15 | 16 | #pragma once 17 | 18 | #ifndef _M2_SDK_ 19 | #define _M2_SDK_ 20 | 21 | /* 22 | Windows API 基本定义 23 | Base Windows API Definitions 24 | */ 25 | #include "MINT.h" 26 | 27 | /* 28 | M2-SDK 基本定义 29 | Base M2-SDK Definitions 30 | */ 31 | #include "M2.Base.h" 32 | 33 | /* 34 | NSudo库 35 | NSudo Library 36 | */ 37 | #include "M2.NSudo.h" 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2MessageDialogResource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: M2-Team Common Library 3 | * FILE: M2MessageDialogResource.h 4 | * PURPOSE: Definition for the message dialog resource 5 | * 6 | * LICENSE: The MIT License 7 | * 8 | * DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com) 9 | */ 10 | 11 | #define IDD_MESSAGE_DIALOG 105 12 | #define IDC_MESSAGE_DIALOG_EDIT 1003 13 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2MessageDialogResource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M2TeamArchived/M2TeamCommonLibrary/bcb76ff587da837929cd6a21194d8a9d56909d2b/M2TeamCommonLibrary/M2MessageDialogResource.rc -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2TeamCommonLibrary.vcxitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {956cad19-1f11-4656-8664-6837aa67cd87} 7 | 8 | 9 | 10 | %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2TeamCommonLibrary.vcxitems.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {c3376011-3a37-453f-8b61-e247c38d599a} 6 | 7 | 8 | {78390f38-88c8-4b68-8465-c8bab293c8a9} 9 | 10 | 11 | {3591d6a3-24d5-4139-a102-8b037e3e6ad9} 12 | 13 | 14 | {3c38a529-bf06-4caa-bd26-27c27c375f63} 15 | 16 | 17 | 18 | 19 | M2Win32GUIHelpers 20 | 21 | 22 | LegacyImplementations 23 | 24 | 25 | M2WindowsHelpers 26 | 27 | 28 | 29 | 30 | M2Win32GUIHelpers 31 | 32 | 33 | M2Win32GUIHelpers 34 | 35 | 36 | MINT 37 | 38 | 39 | LegacyImplementations 40 | 41 | 42 | LegacyImplementations 43 | 44 | 45 | LegacyImplementations 46 | 47 | 48 | M2WindowsHelpers 49 | 50 | 51 | 52 | 53 | M2Win32GUIHelpers 54 | 55 | 56 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2Win32GUIHelpers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: M2-Team Common Library 3 | * FILE: M2Win32GUIHelpers.cpp 4 | * PURPOSE: Implementation for the Win32 desktop GUI helper functions 5 | * 6 | * LICENSE: The MIT License 7 | * 8 | * DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com) 9 | */ 10 | 11 | #include "stdafx.h" 12 | 13 | #include 14 | 15 | #include "M2Win32GUIHelpers.h" 16 | #include "M2MessageDialogResource.h" 17 | 18 | /** 19 | * The parameter struct of the message dialog. 20 | */ 21 | struct DIALOG_BOX_PARAM 22 | { 23 | HINSTANCE hInstance; 24 | LPCWSTR lpIconName; 25 | LPCWSTR lpTitle; 26 | LPCWSTR lpContent; 27 | }; 28 | 29 | /** 30 | * The callback function used of the message dialog. 31 | * 32 | * @param hwndDlg A handle to the message dialog. 33 | * @param uMsg The message. 34 | * @param wParam Additional message-specific information. 35 | * @param lParam Additional message-specific information. 36 | * @return Typically, the dialog box procedure should return TRUE if it 37 | * processed the message, and FALSE if it did not. If the dialog box 38 | * procedure returns FALSE, the dialog manager performs the default 39 | * dialog operation in response to the message. 40 | */ 41 | INT_PTR CALLBACK M2MessageDialogDialogCallBack( 42 | _In_ HWND hwndDlg, 43 | _In_ UINT uMsg, 44 | _In_ WPARAM wParam, 45 | _In_ LPARAM lParam) 46 | { 47 | UNREFERENCED_PARAMETER(lParam); 48 | 49 | if (WM_INITDIALOG == uMsg) 50 | { 51 | HICON hIcon = reinterpret_cast(LoadImageW( 52 | reinterpret_cast(lParam)->hInstance, 53 | reinterpret_cast(lParam)->lpIconName, 54 | IMAGE_ICON, 55 | 256, 56 | 256, 57 | LR_SHARED)); 58 | if (nullptr != hIcon) 59 | { 60 | SendMessageW( 61 | hwndDlg, 62 | WM_SETICON, 63 | ICON_SMALL, 64 | reinterpret_cast(hIcon)); 65 | SendMessageW( 66 | hwndDlg, 67 | WM_SETICON, 68 | ICON_BIG, 69 | reinterpret_cast(hIcon)); 70 | } 71 | 72 | SetWindowTextW( 73 | hwndDlg, 74 | reinterpret_cast(lParam)->lpTitle); 75 | SetWindowTextW( 76 | GetDlgItem(hwndDlg, IDC_MESSAGE_DIALOG_EDIT), 77 | reinterpret_cast(lParam)->lpContent); 78 | 79 | return (INT_PTR)TRUE; 80 | } 81 | else if ( 82 | (WM_CLOSE == uMsg) || 83 | (WM_COMMAND == uMsg && IDOK == LOWORD(wParam))) 84 | { 85 | EndDialog(hwndDlg, 0); 86 | } 87 | 88 | return FALSE; 89 | } 90 | 91 | /** 92 | * Creates and shows the message dialog. 93 | * 94 | * @param hInstance A handle to the module which contains the message dialog 95 | * resource. If this parameter is nullptr, then the current 96 | * executable is used. 97 | * @param hWndParent A handle to the window that owns the message dialog. 98 | * @param lpIconName Pointer that references the icon to be displayed in the 99 | * message dialog. If this parameter is nullptr or the 100 | * hInstance parameter is nullptr, no icon will be displayed. 101 | * This parameter must be an integer resource identifier 102 | * passed to the MAKEINTRESOURCE macro. 103 | * @param lpTitle Pointer to the string to be used for the message dialog 104 | * title. This parameter is a null-terminated, Unicode string. 105 | * @param lpContent Pointer to the string to be used for the message dialog 106 | * content. This parameter is a null-terminated, Unicode 107 | * string. 108 | * @return If the function succeeds, the return value is the value of the 109 | * nResult parameter specified in the call to the EndDialog function 110 | * used to terminate the message dialog. If the function fails because 111 | * the hWndParent parameter is invalid, the return value is zero. The 112 | * function returns zero in this case for compatibility with previous 113 | * versions of Windows. If the function fails for any other reason, the 114 | * return value is –1. To get extended error information, call 115 | * GetLastError. 116 | */ 117 | INT_PTR WINAPI M2MessageDialog( 118 | _In_opt_ HINSTANCE hInstance, 119 | _In_opt_ HWND hWndParent, 120 | _In_opt_ LPCWSTR lpIconName, 121 | _In_ LPCWSTR lpTitle, 122 | _In_ LPCWSTR lpContent) 123 | { 124 | DIALOG_BOX_PARAM Param = { hInstance, lpIconName,lpTitle,lpContent }; 125 | 126 | M2EnablePerMonitorDialogScaling(); 127 | 128 | return DialogBoxParamW( 129 | hInstance, 130 | MAKEINTRESOURCEW(IDD_MESSAGE_DIALOG), 131 | hWndParent, 132 | M2MessageDialogDialogCallBack, 133 | reinterpret_cast(&Param)); 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2Win32GUIHelpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: M2-Team Common Library 3 | * FILE: M2Win32GUIHelpers.h 4 | * PURPOSE: Definition for the Win32 desktop GUI helper functions 5 | * 6 | * LICENSE: The MIT License 7 | * 8 | * DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com) 9 | */ 10 | 11 | #pragma once 12 | 13 | #ifndef _M2_WIN32_GUI_HELPERS_ 14 | #define _M2_WIN32_GUI_HELPERS_ 15 | 16 | #include "M2WindowsHelpers.h" 17 | 18 | /** 19 | * Creates and shows the message dialog. 20 | * 21 | * @param hInstance A handle to the module which contains the message dialog 22 | * resource. If this parameter is nullptr, then the current 23 | * executable is used. 24 | * @param hWndParent A handle to the window that owns the message dialog. 25 | * @param lpIconName Pointer that references the icon to be displayed in the 26 | * message dialog. If this parameter is nullptr or the 27 | * hInstance parameter is nullptr, no icon will be displayed. 28 | * This parameter must be an integer resource identifier 29 | * passed to the MAKEINTRESOURCE macro. 30 | * @param lpTitle Pointer to the string to be used for the message dialog 31 | * title. This parameter is a null-terminated, Unicode string. 32 | * @param lpContent Pointer to the string to be used for the message dialog 33 | * content. This parameter is a null-terminated, Unicode 34 | * string. 35 | * @return If the function succeeds, the return value is the value of the 36 | * nResult parameter specified in the call to the EndDialog function 37 | * used to terminate the message dialog. If the function fails because 38 | * the hWndParent parameter is invalid, the return value is zero. The 39 | * function returns zero in this case for compatibility with previous 40 | * versions of Windows. If the function fails for any other reason, the 41 | * return value is –1. To get extended error information, call 42 | * GetLastError. 43 | */ 44 | INT_PTR WINAPI M2MessageDialog( 45 | _In_opt_ HINSTANCE hInstance, 46 | _In_opt_ HWND hWndParent, 47 | _In_opt_ LPCWSTR lpIconName, 48 | _In_ LPCWSTR lpTitle, 49 | _In_ LPCWSTR lpContent); 50 | 51 | #endif // _M2_WIN32_GUI_HELPERS_ 52 | -------------------------------------------------------------------------------- /M2TeamCommonLibrary/M2WindowsHelpers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: M2-Team Common Library 3 | * FILE: M2WindowsHelpers.cpp 4 | * PURPOSE: Implementation for the Windows helper functions 5 | * 6 | * LICENSE: The MIT License 7 | * 8 | * DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com) 9 | */ 10 | 11 | #include "stdafx.h" 12 | 13 | #include "M2WindowsHelpers.h" 14 | 15 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 16 | #include 17 | #endif 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus_winrt 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | using Microsoft::WRL::ComPtr; 33 | using Microsoft::WRL::MakeAndInitialize; 34 | using Microsoft::WRL::RuntimeClass; 35 | using Microsoft::WRL::RuntimeClassFlags; 36 | using Microsoft::WRL::RuntimeClassType; 37 | #endif 38 | 39 | #pragma region Error 40 | 41 | /** 42 | * Retrieves the calling thread's last-error code value. The last-error code is 43 | * maintained on a per-thread basis. Multiple threads do not overwrite each 44 | * other's last-error code. 45 | * 46 | * @return The calling thread's last-error code which is converted to an 47 | * HRESULT value. 48 | */ 49 | HRESULT M2GetLastHRESULTError() 50 | { 51 | return HRESULT_FROM_WIN32(GetLastError()); 52 | } 53 | 54 | /** 55 | * Retrieves the calling thread's last-error code value if you can be sure that 56 | * the last call was failed. The last-error code is maintained on a per-thread 57 | * basis. Multiple threads do not overwrite each other's last-error code. 58 | * 59 | * @return The calling thread's last-error code. 60 | */ 61 | DWORD M2GetLastErrorKnownFailedCall() 62 | { 63 | DWORD LastError = GetLastError(); 64 | return (LastError != ERROR_SUCCESS) ? LastError : ERROR_FUNCTION_FAILED; 65 | } 66 | 67 | /** 68 | * Retrieves the calling thread's last-error code value if you can be sure that 69 | * the last call was failed. The last-error code is maintained on a per-thread 70 | * basis. Multiple threads do not overwrite each other's last-error code. 71 | * 72 | * @return The calling thread's last-error code which is converted to an 73 | * HRESULT value. 74 | */ 75 | HRESULT M2GetLastHRESULTErrorKnownFailedCall() 76 | { 77 | return HRESULT_FROM_WIN32(M2GetLastErrorKnownFailedCall()); 78 | } 79 | 80 | #ifdef __cplusplus_winrt 81 | 82 | /** 83 | * Throw the appropriate Platform::Exception for the given HRESULT. 84 | * 85 | * @param hr The error HRESULT that is represented by the exception. 86 | * @return This function does not return a value, but will throw 87 | * Platform::Exception. 88 | */ 89 | __declspec(noreturn) void M2ThrowPlatformException(HRESULT hr) 90 | { 91 | throw Platform::Exception::CreateException(hr); 92 | } 93 | 94 | /** 95 | * Throw the appropriate Platform::Exception for the given HRESULT. 96 | * 97 | * @param hr The error HRESULT that is represented by the exception. 98 | * @return This function does not return a value, but will throw 99 | * Platform::Exception if it is a failed HRESULT value. 100 | */ 101 | void M2ThrowPlatformExceptionIfFailed(HRESULT hr) 102 | { 103 | if (FAILED(hr)) 104 | { 105 | M2ThrowPlatformException(hr); 106 | } 107 | } 108 | 109 | /** 110 | * Convert C++/CX exceptions in the callable code into HRESULTs. 111 | * 112 | * @return The function will return HRESULT. 113 | */ 114 | HRESULT M2ThrownPlatformExceptionToHResult() 115 | { 116 | try 117 | { 118 | throw; 119 | } 120 | catch (Platform::Exception ^ ex) 121 | { 122 | return ex->HResult; 123 | } 124 | catch (std::bad_alloc const&) 125 | { 126 | return E_OUTOFMEMORY; 127 | } 128 | catch (...) 129 | { 130 | return E_UNEXPECTED; 131 | } 132 | } 133 | 134 | #endif 135 | 136 | #pragma endregion 137 | 138 | #pragma region String 139 | 140 | /** 141 | * Converts from the UTF-8 string to the UTF-16 string. 142 | * 143 | * @param UTF8String The UTF-8 string you want to convert. 144 | * @return A converted UTF-16 string. 145 | */ 146 | std::wstring M2MakeUTF16String(const std::string& UTF8String) 147 | { 148 | std::wstring UTF16String; 149 | 150 | int UTF16StringLength = MultiByteToWideChar( 151 | CP_UTF8, 152 | 0, 153 | UTF8String.data(), 154 | (int)UTF8String.size(), 155 | nullptr, 156 | 0); 157 | if (UTF16StringLength > 0) 158 | { 159 | UTF16String.resize(UTF16StringLength); 160 | MultiByteToWideChar( 161 | CP_UTF8, 162 | 0, 163 | UTF8String.data(), 164 | (int)UTF8String.size(), 165 | &UTF16String[0], 166 | UTF16StringLength); 167 | } 168 | 169 | return UTF16String; 170 | } 171 | 172 | /** 173 | * Converts from the UTF-16 string to the UTF-8 string. 174 | * 175 | * @param UTF16String The UTF-16 string you want to convert. 176 | * @return A converted UTF-8 string. 177 | */ 178 | std::string M2MakeUTF8String(const std::wstring& UTF16String) 179 | { 180 | std::string UTF8String; 181 | 182 | int UTF8StringLength = WideCharToMultiByte( 183 | CP_UTF8, 184 | 0, 185 | UTF16String.data(), 186 | (int)UTF16String.size(), 187 | nullptr, 188 | 0, 189 | nullptr, 190 | nullptr); 191 | if (UTF8StringLength > 0) 192 | { 193 | UTF8String.resize(UTF8StringLength); 194 | WideCharToMultiByte( 195 | CP_UTF8, 196 | 0, 197 | UTF16String.data(), 198 | (int)UTF16String.size(), 199 | &UTF8String[0], 200 | UTF8StringLength, 201 | nullptr, 202 | nullptr); 203 | } 204 | 205 | return UTF8String; 206 | } 207 | 208 | /** 209 | * Write formatted data to a string. 210 | * 211 | * @param Format Format-control string. 212 | * @param ... Optional arguments to be formatted. 213 | * @return A formatted string if successful, "N/A" otherwise. 214 | */ 215 | std::wstring M2FormatString( 216 | _In_z_ _Printf_format_string_ wchar_t const* const Format, 217 | ...) 218 | { 219 | // Check the argument list. 220 | if (nullptr != Format) 221 | { 222 | va_list ArgList = nullptr; 223 | va_start(ArgList, Format); 224 | 225 | // Get the length of the format result. 226 | size_t nLength = static_cast(_vscwprintf(Format, ArgList)) + 1; 227 | 228 | // Allocate for the format result. 229 | std::wstring Buffer(nLength + 1, L'\0'); 230 | 231 | // Format the string. 232 | int nWritten = _vsnwprintf_s( 233 | &Buffer[0], 234 | Buffer.size(), 235 | nLength, 236 | Format, 237 | ArgList); 238 | 239 | va_end(ArgList); 240 | 241 | if (nWritten > 0) 242 | { 243 | // If succeed, resize to fit and return result. 244 | Buffer.resize(nWritten); 245 | return Buffer; 246 | } 247 | } 248 | 249 | // If failed, return "N/A". 250 | return L"N/A"; 251 | } 252 | 253 | /** 254 | * Parses a command line string and returns an array of the command line 255 | * arguments, along with a count of such arguments, in a way that is similar to 256 | * the standard C run-time. 257 | * 258 | * @param CommandLine A string that contains the full command line. If this 259 | * parameter is an empty string the function returns an 260 | * array with only one empty string. 261 | * @return An array of the command line arguments, along with a count of such 262 | * arguments. 263 | */ 264 | std::vector M2SpiltCommandLine( 265 | const std::wstring& CommandLine) 266 | { 267 | // Initialize the SplitArguments. 268 | std::vector SplitArguments; 269 | 270 | wchar_t c = L'\0'; 271 | int copy_character; /* 1 = copy char to *args */ 272 | unsigned numslash; /* num of backslashes seen */ 273 | 274 | std::wstring Buffer; 275 | Buffer.reserve(CommandLine.size()); 276 | 277 | /* first scan the program name, copy it, and count the bytes */ 278 | wchar_t* p = const_cast(CommandLine.c_str()); 279 | 280 | // A quoted program name is handled here. The handling is much simpler than 281 | // for other arguments. Basically, whatever lies between the leading 282 | // double-quote and next one, or a terminal null character is simply 283 | // accepted. Fancier handling is not required because the program name must 284 | // be a legal NTFS/HPFS file name. Note that the double-quote characters are 285 | // not copied, nor do they contribute to character_count. 286 | bool InQuotes = false; 287 | do 288 | { 289 | if (*p == '"') 290 | { 291 | InQuotes = !InQuotes; 292 | c = *p++; 293 | continue; 294 | } 295 | 296 | // Copy character into argument: 297 | Buffer.push_back(*p); 298 | 299 | c = *p++; 300 | } while (c != '\0' && (InQuotes || (c != ' ' && c != '\t'))); 301 | 302 | if (c == '\0') 303 | { 304 | p--; 305 | } 306 | else 307 | { 308 | Buffer.resize(Buffer.size() - 1); 309 | } 310 | 311 | // Save te argument. 312 | SplitArguments.push_back(Buffer); 313 | 314 | InQuotes = false; 315 | 316 | // Loop on each argument 317 | for (;;) 318 | { 319 | if (*p) 320 | { 321 | while (*p == ' ' || *p == '\t') 322 | ++p; 323 | } 324 | 325 | // End of arguments 326 | if (*p == '\0') 327 | break; 328 | 329 | // Initialize the argument buffer. 330 | Buffer.clear(); 331 | 332 | // Loop through scanning one argument: 333 | for (;;) 334 | { 335 | copy_character = 1; 336 | 337 | // Rules: 2N backslashes + " ==> N backslashes and begin/end quote 338 | // 2N + 1 backslashes + " ==> N backslashes + literal " N 339 | // backslashes ==> N backslashes 340 | numslash = 0; 341 | 342 | while (*p == '\\') 343 | { 344 | // Count number of backslashes for use below 345 | ++p; 346 | ++numslash; 347 | } 348 | 349 | if (*p == '"') 350 | { 351 | // if 2N backslashes before, start/end quote, otherwise copy 352 | // literally: 353 | if (numslash % 2 == 0) 354 | { 355 | if (InQuotes && p[1] == '"') 356 | { 357 | p++; // Double quote inside quoted string 358 | } 359 | else 360 | { 361 | // Skip first quote char and copy second: 362 | copy_character = 0; // Don't copy quote 363 | InQuotes = !InQuotes; 364 | } 365 | } 366 | 367 | numslash /= 2; 368 | } 369 | 370 | // Copy slashes: 371 | while (numslash--) 372 | { 373 | Buffer.push_back(L'\\'); 374 | } 375 | 376 | // If at end of arg, break loop: 377 | if (*p == '\0' || (!InQuotes && (*p == ' ' || *p == '\t'))) 378 | break; 379 | 380 | // Copy character into argument: 381 | if (copy_character) 382 | { 383 | Buffer.push_back(*p); 384 | } 385 | 386 | ++p; 387 | } 388 | 389 | // Save te argument. 390 | SplitArguments.push_back(Buffer); 391 | } 392 | 393 | return SplitArguments; 394 | } 395 | 396 | /** 397 | * Parses a command line string and get more friendly result. 398 | * 399 | * @param CommandLine A string that contains the full command line. If this 400 | * parameter is an empty string the function returns an 401 | * array with only one empty string. 402 | * @param OptionPrefixes One or more of the prefixes of option we want to use. 403 | * @param OptionParameterSeparators One or more of the separators of option we 404 | * want to use. 405 | * @param ApplicationName The application name. 406 | * @param OptionsAndParameters The options and parameters. 407 | * @param UnresolvedCommandLine The unresolved command line. 408 | */ 409 | void M2SpiltCommandLineEx( 410 | const std::wstring & CommandLine, 411 | const std::vector & OptionPrefixes, 412 | const std::vector & OptionParameterSeparators, 413 | std::wstring & ApplicationName, 414 | std::map & OptionsAndParameters, 415 | std::wstring & UnresolvedCommandLine) 416 | { 417 | ApplicationName.clear(); 418 | OptionsAndParameters.clear(); 419 | UnresolvedCommandLine.clear(); 420 | 421 | size_t arg_size = 0; 422 | for (auto& SplitArgument : M2SpiltCommandLine(CommandLine)) 423 | { 424 | // We need to process the application name at the beginning. 425 | if (ApplicationName.empty()) 426 | { 427 | // For getting the unresolved command line, we need to cumulate 428 | // length which including spaces. 429 | arg_size += SplitArgument.size() + 1; 430 | 431 | // Save 432 | ApplicationName = SplitArgument; 433 | } 434 | else 435 | { 436 | bool IsOption = false; 437 | size_t OptionPrefixLength = 0; 438 | 439 | for (auto& OptionPrefix : OptionPrefixes) 440 | { 441 | if (0 == _wcsnicmp( 442 | SplitArgument.c_str(), 443 | OptionPrefix.c_str(), 444 | OptionPrefix.size())) 445 | { 446 | IsOption = true; 447 | OptionPrefixLength = OptionPrefix.size(); 448 | } 449 | } 450 | 451 | if (IsOption) 452 | { 453 | // For getting the unresolved command line, we need to cumulate 454 | // length which including spaces. 455 | arg_size += SplitArgument.size() + 1; 456 | 457 | // Get the option name and parameter. 458 | 459 | wchar_t* OptionStart = &SplitArgument[0] + OptionPrefixLength; 460 | wchar_t* ParameterStart = nullptr; 461 | 462 | for (auto& OptionParameterSeparator 463 | : OptionParameterSeparators) 464 | { 465 | wchar_t* Result = wcsstr( 466 | OptionStart, 467 | OptionParameterSeparator.c_str()); 468 | if (nullptr == Result) 469 | { 470 | continue; 471 | } 472 | 473 | Result[0] = L'\0'; 474 | ParameterStart = Result + OptionParameterSeparator.size(); 475 | 476 | break; 477 | } 478 | 479 | // Save 480 | OptionsAndParameters[(OptionStart ? OptionStart : L"")] = 481 | (ParameterStart ? ParameterStart : L""); 482 | } 483 | else 484 | { 485 | // Get the approximate location of the unresolved command line. 486 | // We use "(arg_size - 1)" to ensure that the program path 487 | // without quotes can also correctly parse. 488 | wchar_t* search_start = 489 | const_cast(CommandLine.c_str()) + (arg_size - 1); 490 | 491 | // Get the unresolved command line. Search for the beginning of 492 | // the first parameter delimiter called space and exclude the 493 | // first space by adding 1 to the result. 494 | wchar_t* command = wcsstr(search_start, L" ") + 1; 495 | 496 | // Omit the space. (Thanks to wzzw.) 497 | while (command && *command == L' ') 498 | { 499 | ++command; 500 | } 501 | 502 | // Save 503 | if (command) 504 | { 505 | UnresolvedCommandLine = command; 506 | } 507 | 508 | break; 509 | } 510 | } 511 | } 512 | } 513 | 514 | #ifdef CPPWINRT_VERSION 515 | 516 | /** 517 | * Finds a sub string from a source string. 518 | * 519 | * @param SourceString The source string. 520 | * @param SubString The sub string. 521 | * @param IgnoreCase Determines whether to ignore case. 522 | * @return Returns true if successful, or false otherwise. 523 | */ 524 | bool M2FindSubString( 525 | winrt::hstring const& SourceString, 526 | winrt::hstring const& SubString, 527 | bool IgnoreCase) 528 | { 529 | return (::FindNLSStringEx( 530 | nullptr, 531 | (IgnoreCase ? NORM_IGNORECASE : 0) | FIND_FROMSTART, 532 | SourceString.c_str(), 533 | SourceString.size(), 534 | SubString.c_str(), 535 | SubString.size(), 536 | nullptr, 537 | nullptr, 538 | nullptr, 539 | 0) >= 0); 540 | } 541 | 542 | /** 543 | * Converts a numeric value into a string that represents the number expressed 544 | * as a size value in byte, bytes, kibibytes, mebibytes, gibibytes, tebibytes, 545 | * pebibytes or exbibytes, depending on the size. 546 | * 547 | * @param ByteSize The numeric byte size value to be converted. 548 | * @return Returns a winrt::hstring object which represents the converted 549 | * string. 550 | */ 551 | winrt::hstring M2ConvertByteSizeToString( 552 | uint64_t ByteSize) 553 | { 554 | const wchar_t* Systems[] = 555 | { 556 | L"Byte", 557 | L"Bytes", 558 | L"KiB", 559 | L"MiB", 560 | L"GiB", 561 | L"TiB", 562 | L"PiB", 563 | L"EiB" 564 | }; 565 | 566 | size_t nSystem = 0; 567 | double result = static_cast(ByteSize); 568 | 569 | if (ByteSize > 1) 570 | { 571 | for ( 572 | nSystem = 1; 573 | nSystem < sizeof(Systems) / sizeof(*Systems); 574 | ++nSystem) 575 | { 576 | if (1024.0 > result) 577 | break; 578 | 579 | result /= 1024.0; 580 | } 581 | 582 | result = static_cast(result * 100) / 100.0; 583 | } 584 | 585 | return winrt::to_hstring(result) + L" " + Systems[nSystem]; 586 | } 587 | 588 | #endif 589 | 590 | #ifdef __cplusplus_winrt 591 | 592 | /** 593 | * Converts from the C++/CX string to the UTF-16 string. 594 | * 595 | * @param PlatformString The C++/CX string you want to convert. 596 | * @return The return value is the UTF-16 string. 597 | */ 598 | std::wstring M2MakeUTF16String(Platform::String^ PlatformString) 599 | { 600 | return std::wstring(PlatformString->Data(), PlatformString->Length()); 601 | } 602 | 603 | /** 604 | * Converts from the C++/CX string to the UTF-8 string. 605 | * 606 | * @param PlatformString The C++/CX string you want to convert. 607 | * @return The return value is the UTF-8 string. 608 | */ 609 | std::string M2MakeUTF8String(Platform::String^ PlatformString) 610 | { 611 | std::string UTF8String; 612 | 613 | int UTF8StringLength = WideCharToMultiByte( 614 | CP_UTF8, 615 | 0, 616 | PlatformString->Data(), 617 | static_cast(PlatformString->Length()), 618 | nullptr, 619 | 0, 620 | nullptr, 621 | nullptr); 622 | if (UTF8StringLength > 0) 623 | { 624 | UTF8String.resize(UTF8StringLength); 625 | WideCharToMultiByte( 626 | CP_UTF8, 627 | 0, 628 | PlatformString->Data(), 629 | static_cast(PlatformString->Length()), 630 | &UTF8String[0], 631 | UTF8StringLength, 632 | nullptr, 633 | nullptr); 634 | } 635 | 636 | return UTF8String; 637 | } 638 | 639 | /** 640 | * Converts from the UTF-8 string to the C++/CX string. 641 | * 642 | * @param UTF16String The UTF-16 string you want to convert. 643 | * @return The return value is the C++/CX string. 644 | */ 645 | Platform::String^ M2MakeCXString(const std::wstring& UTF16String) 646 | { 647 | return ref new Platform::String( 648 | UTF16String.c_str(), static_cast(UTF16String.size())); 649 | } 650 | 651 | /** 652 | * Finds a sub string from a source string. 653 | * 654 | * @param SourceString The source string. 655 | * @param SubString The sub string. 656 | * @param IgnoreCase Determines whether to ignore case. 657 | * @return Returns true if successful, or false otherwise. 658 | */ 659 | bool M2FindSubString( 660 | Platform::String^ SourceString, 661 | Platform::String^ SubString, 662 | bool IgnoreCase) 663 | { 664 | return (::FindNLSStringEx( 665 | nullptr, 666 | (IgnoreCase ? NORM_IGNORECASE : 0) | FIND_FROMSTART, 667 | SourceString->Data(), 668 | SourceString->Length(), 669 | SubString->Data(), 670 | SubString->Length(), 671 | nullptr, 672 | nullptr, 673 | nullptr, 674 | 0) >= 0); 675 | } 676 | 677 | /** 678 | * Converts a numeric value into a string that represents the number expressed 679 | * as a size value in byte, bytes, kibibytes, mebibytes, gibibytes, tebibytes, 680 | * pebibytes or exbibytes, depending on the size. 681 | * 682 | * @param ByteSize The numeric byte size value to be converted. 683 | * @return Returns a Platform::String object which represents the converted 684 | * string. 685 | */ 686 | Platform::String ^ M2ConvertByteSizeToString(uint64 ByteSize) 687 | { 688 | double result = static_cast(ByteSize); 689 | 690 | if (0.0 == result) 691 | { 692 | return L"0 Byte"; 693 | } 694 | 695 | const wchar_t* Systems[] = 696 | { 697 | L"Bytes", 698 | L"KiB", 699 | L"MiB", 700 | L"GiB", 701 | L"TiB", 702 | L"PiB", 703 | L"EiB" 704 | }; 705 | 706 | size_t nSystem = 0; 707 | for (; nSystem < sizeof(Systems) / sizeof(*Systems); ++nSystem) 708 | { 709 | if (1024.0 > result) 710 | break; 711 | 712 | result /= 1024.0; 713 | } 714 | 715 | Platform::String^ ByteSizeString = 716 | (static_cast(result * 100) / 100.0).ToString(); 717 | 718 | return ByteSizeString + Platform::StringReference(Systems[nSystem]); 719 | } 720 | 721 | #endif 722 | 723 | #pragma endregion 724 | 725 | #pragma region Performance 726 | 727 | /** 728 | * Retrieves the number of milliseconds that have elapsed since the system was 729 | * started. 730 | * 731 | * @return The number of milliseconds. 732 | */ 733 | ULONGLONG M2GetTickCount() 734 | { 735 | LARGE_INTEGER Frequency = { 0 }, PerformanceCount = { 0 }; 736 | 737 | if (QueryPerformanceFrequency(&Frequency)) 738 | { 739 | if (QueryPerformanceCounter(&PerformanceCount)) 740 | { 741 | return (PerformanceCount.QuadPart * 1000 / Frequency.QuadPart); 742 | } 743 | } 744 | 745 | return GetTickCount64(); 746 | } 747 | 748 | #pragma endregion 749 | 750 | #pragma region Thread 751 | 752 | /** 753 | * Creates a thread to execute within the virtual address space of the calling 754 | * process. 755 | * 756 | * @param lpThreadAttributes A pointer to a SECURITY_ATTRIBUTES structure that 757 | * determines whether the returned handle can be 758 | * inherited by child processes. 759 | * @param dwStackSize The initial size of the stack, in bytes. 760 | * @param lpStartAddress A pointer to the application-defined function to be 761 | * executed by the thread. 762 | * @param lpParameter A pointer to a variable to be passed to the thread. 763 | * @param dwCreationFlags The flags that control the creation of the thread. 764 | * @param lpThreadId A pointer to a variable that receives the thread 765 | * identifier. 766 | * @return HRESULT. If the function succeeds, the return value is S_OK. 767 | * @remark For more information, see CreateThread. 768 | */ 769 | HRESULT M2CreateThread( 770 | _Out_ PHANDLE lpThreadHandle, 771 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 772 | _In_ SIZE_T dwStackSize, 773 | _In_ LPTHREAD_START_ROUTINE lpStartAddress, 774 | _In_opt_ __drv_aliasesMem LPVOID lpParameter, 775 | _In_ DWORD dwCreationFlags, 776 | _Out_opt_ LPDWORD lpThreadId) 777 | { 778 | // sanity check for lpThreadId 779 | assert(sizeof(DWORD) == sizeof(unsigned)); 780 | 781 | typedef unsigned(__stdcall * routine_type)(void*); 782 | 783 | // _beginthreadex calls CreateThread which will set the last error 784 | // value before it returns. 785 | *lpThreadHandle = reinterpret_cast(_beginthreadex( 786 | lpThreadAttributes, 787 | static_cast(dwStackSize), 788 | reinterpret_cast(lpStartAddress), 789 | lpParameter, 790 | dwCreationFlags, 791 | reinterpret_cast(lpThreadId))); 792 | 793 | return (*lpThreadHandle) ? S_OK : M2GetLastHRESULTErrorKnownFailedCall(); 794 | } 795 | 796 | /** 797 | * Retrieves the number of logical processors in the current group. 798 | * 799 | * @return The number of logical processors in the current group. 800 | */ 801 | DWORD M2GetNumberOfHardwareThreads() 802 | { 803 | SYSTEM_INFO SystemInfo = { 0 }; 804 | GetNativeSystemInfo(&SystemInfo); 805 | return SystemInfo.dwNumberOfProcessors; 806 | } 807 | 808 | #pragma endregion 809 | 810 | #pragma region Memory 811 | 812 | /** 813 | * Allocates a block of memory from a heap. The allocated memory is not 814 | * movable. 815 | * 816 | * @param lpNewMem A pointer to the allocated memory block. 817 | * @param hHeap A handle to the heap from which the memory will be allocated. 818 | * @param dwFlags The heap allocation options. 819 | * @param dwBytes The number of bytes to be allocated. 820 | * @return HRESULT. If the function succeeds, the return value is S_OK. 821 | * @remark For more information, see HeapAlloc. 822 | */ 823 | HRESULT M2HeapAlloc( 824 | _Out_ PVOID* lpNewMem, 825 | _In_ HANDLE hHeap, 826 | _In_ DWORD dwFlags, 827 | _In_ SIZE_T dwBytes) 828 | { 829 | *lpNewMem = HeapAlloc(hHeap, dwFlags, dwBytes); 830 | return *lpNewMem ? S_OK : __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 831 | } 832 | 833 | /** 834 | * Reallocates a block of memory from a heap. This function enables you to 835 | * resize a memory block and change other memory block properties. The 836 | * allocated memory is not movable. 837 | * 838 | * @param lpNewMem A pointer to the allocated memory block. 839 | * @param hHeap A handle to the heap from which the memory is to be 840 | * reallocated. 841 | * @param dwFlags The heap reallocation options. 842 | * @param lpMem A pointer to the block of memory that the function reallocates. 843 | * @param dwBytes The new size of the memory block, in bytes. 844 | * @return HRESULT. If the function succeeds, the return value is S_OK. If the 845 | * function fails, the original memory is not freed, and the original 846 | * handle and pointer are still valid. 847 | * @remark For more information, see HeapReAlloc. 848 | */ 849 | HRESULT M2HeapReAlloc( 850 | _Out_ PVOID* lpNewMem, 851 | _Inout_ HANDLE hHeap, 852 | _In_ DWORD dwFlags, 853 | _In_ LPVOID lpMem, 854 | _In_ SIZE_T dwBytes) 855 | { 856 | *lpNewMem = HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes); 857 | return *lpNewMem ? S_OK : __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 858 | } 859 | 860 | /** 861 | * Frees a memory block allocated from a heap by the M2HeapAlloc and 862 | * M2HeapReAlloc function. 863 | * 864 | * @param hHeap A handle to the heap whose memory block is to be freed. 865 | * @param dwFlags The heap free options. 866 | * @param lpMem A pointer to the memory block to be freed. 867 | * @return HRESULT. If the function succeeds, the return value is S_OK. 868 | * @remark For more information, see HeapFree. 869 | */ 870 | HRESULT M2HeapFree( 871 | _Inout_ HANDLE hHeap, 872 | _In_ DWORD dwFlags, 873 | _In_ LPVOID lpMem) 874 | { 875 | if (!HeapFree(hHeap, dwFlags, lpMem)) 876 | return M2GetLastHRESULTErrorKnownFailedCall(); 877 | 878 | return S_OK; 879 | } 880 | 881 | /** 882 | * Allocates a block of memory from the default heap of the calling process. 883 | * The allocated memory will be initialized to zero. The allocated memory is 884 | * not movable. 885 | * 886 | * @param AllocatedMemoryBlock A pointer to the allocated memory block. 887 | * @param MemoryBlockSize The number of bytes to be allocated. 888 | * @return HRESULT. If the function succeeds, the return value is S_OK. 889 | */ 890 | HRESULT M2AllocMemory( 891 | _Out_ PVOID* AllocatedMemoryBlock, 892 | _In_ SIZE_T MemoryBlockSize) 893 | { 894 | return M2HeapAlloc( 895 | AllocatedMemoryBlock, 896 | GetProcessHeap(), 897 | HEAP_ZERO_MEMORY, 898 | MemoryBlockSize); 899 | } 900 | 901 | /** 902 | * Reallocates a block of memory from the default heap of the calling process. 903 | * If the reallocation request is for a larger size, the additional region of 904 | * memory beyond the original size be initialized to zero. This function 905 | * enables you to resize a memory block and change other memory block 906 | * properties. The allocated memory is not movable. 907 | * 908 | * @param NewAllocatedMemoryBlock A pointer to the allocated memory block. 909 | * @param OldAllocatedMemoryBlock A pointer to the block of memory that the 910 | * function reallocates. This pointer is 911 | * returned by an earlier call to the 912 | * M2AllocMemory or M2ReAllocMemory function. 913 | * @param NewMemoryBlockSize The new size of the memory block, in bytes. A 914 | * memory block's size can be increased or decreased 915 | * by using this function. 916 | * @return HRESULT. If the function succeeds, the return value is S_OK. If the 917 | * function fails, the original memory is not freed, and the original 918 | * handle and pointer are still valid. 919 | */ 920 | HRESULT M2ReAllocMemory( 921 | _Out_ PVOID* NewAllocatedMemoryBlock, 922 | _In_ PVOID OldAllocatedMemoryBlock, 923 | _In_ SIZE_T NewMemoryBlockSize) 924 | { 925 | return M2HeapReAlloc( 926 | NewAllocatedMemoryBlock, 927 | GetProcessHeap(), 928 | HEAP_ZERO_MEMORY, 929 | OldAllocatedMemoryBlock, 930 | NewMemoryBlockSize); 931 | } 932 | 933 | /** 934 | * Frees a memory block allocated from a heap by the M2AllocMemory and 935 | * M2ReAllocMemory function. 936 | * 937 | * @param AllocatedMemoryBlock A pointer to the memory block to be freed. This 938 | * pointer is returned by the M2AllocMemory or M2ReAllocMemory function. If 939 | * this pointer is nullptr, the behavior is undefined. 940 | * @return HRESULT. If the function succeeds, the return value is S_OK. 941 | */ 942 | HRESULT M2FreeMemory( 943 | _In_ PVOID AllocatedMemoryBlock) 944 | { 945 | return M2HeapFree(GetProcessHeap(), 0, AllocatedMemoryBlock); 946 | } 947 | 948 | #pragma endregion 949 | 950 | #pragma region AccessToken 951 | 952 | /** 953 | * Enables or disables privileges in the specified access token. Enabling or 954 | * disabling privileges in an access token requires TOKEN_ADJUST_PRIVILEGES 955 | * access. 956 | * 957 | * @param TokenHandle A handle to the access token that contains the privileges 958 | * to be modified. The handle must have 959 | * TOKEN_ADJUST_PRIVILEGES access to the token. If the 960 | * PreviousState parameter is not NULL, the handle must also 961 | * have TOKEN_QUERY access. 962 | * @param DisableAllPrivileges Specifies whether the function disables all of 963 | * the token's privileges. If this value is TRUE, 964 | * the function disables all privileges and ignores 965 | * the NewState parameter. If it is FALSE, the 966 | * function modifies privileges based on the 967 | * information pointed to by the NewState 968 | * parameter. 969 | * @param NewState A pointer to a TOKEN_PRIVILEGES structure that specifies an 970 | * array of privileges and their attributes. If 971 | * DisableAllPrivileges is TRUE, the function ignores this 972 | * parameter. 973 | * @param BufferLength Specifies the size, in bytes, of the buffer pointed to 974 | * by the PreviousState parameter. This parameter can be 975 | * zero if the PreviousState parameter is NULL. 976 | * @param PreviousState A pointer to a buffer that the function fills with a 977 | * TOKEN_PRIVILEGES structure that contains the previous 978 | * state of any privileges that the function modifies. 979 | * This parameter can be NULL. 980 | * @param ReturnLength A pointer to a variable that receives the required size, 981 | * in bytes, of the buffer pointed to by the PreviousState 982 | * parameter. This parameter can be NULL if PreviousState 983 | * is NULL. 984 | * @return HRESULT. If the function succeeds, the return value is S_OK. 985 | * @remark For more information, see AdjustTokenPrivileges. 986 | */ 987 | HRESULT M2AdjustTokenPrivileges( 988 | _In_ HANDLE TokenHandle, 989 | _In_ BOOL DisableAllPrivileges, 990 | _In_opt_ PTOKEN_PRIVILEGES NewState, 991 | _In_ DWORD BufferLength, 992 | _Out_opt_ PTOKEN_PRIVILEGES PreviousState, 993 | _Out_opt_ PDWORD ReturnLength) 994 | { 995 | BOOL Result = AdjustTokenPrivileges( 996 | TokenHandle, 997 | DisableAllPrivileges, 998 | NewState, 999 | BufferLength, 1000 | PreviousState, 1001 | ReturnLength); 1002 | 1003 | DWORD LastError = GetLastError(); 1004 | 1005 | if (!Result && LastError == ERROR_SUCCESS) 1006 | LastError = ERROR_FUNCTION_FAILED; 1007 | 1008 | return HRESULT_FROM_WIN32(LastError); 1009 | } 1010 | 1011 | /** 1012 | * Retrieves a specified type of information about an access token. The calling 1013 | * process must have appropriate access rights to obtain the information. 1014 | * 1015 | * @param TokenHandle A handle to an access token from which information is 1016 | * retrieved. 1017 | * @param TokenInformationClass Specifies a value from the 1018 | * TOKEN_INFORMATION_CLASS enumerated type to 1019 | * identify the type of information the function 1020 | * retrieves. 1021 | * @param TokenInformation A pointer to a buffer the function fills with the 1022 | * requested information. 1023 | * @param TokenInformationLength Specifies the size, in bytes, of the buffer 1024 | * pointed to by the TokenInformation parameter. 1025 | * @param ReturnLength A pointer to a variable that receives the number of 1026 | * bytes needed for the buffer pointed to by the 1027 | * TokenInformation parameter. 1028 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1029 | * @remark For more information, see GetTokenInformation. 1030 | */ 1031 | HRESULT M2GetTokenInformation( 1032 | _In_ HANDLE TokenHandle, 1033 | _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 1034 | _Out_opt_ LPVOID TokenInformation, 1035 | _In_ DWORD TokenInformationLength, 1036 | _Out_ PDWORD ReturnLength) 1037 | { 1038 | if (GetTokenInformation( 1039 | TokenHandle, 1040 | TokenInformationClass, 1041 | TokenInformation, 1042 | TokenInformationLength, 1043 | ReturnLength)) 1044 | { 1045 | return S_OK; 1046 | } 1047 | 1048 | return M2GetLastHRESULTErrorKnownFailedCall(); 1049 | } 1050 | 1051 | /** 1052 | * Opens the access token associated with a process. 1053 | * 1054 | * @param TokenHandle A pointer to a handle that identifies the newly opened 1055 | * access token when the function returns. 1056 | * @param TokenSource The source information of access token associated with a 1057 | * process. 1058 | * @param DesiredAccess Specifies an access mask that specifies the requested 1059 | * types of access to the access token. These requested 1060 | * access types are compared with the discretionary access 1061 | * control list (DACL) of the token to determine which 1062 | * accesses are granted or denied. 1063 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1064 | */ 1065 | HRESULT M2OpenProcessToken( 1066 | _Out_ PHANDLE TokenHandle, 1067 | _In_ PM2_PROCESS_ACCESS_TOKEN_SOURCE TokenSource, 1068 | _In_ DWORD DesiredAccess) 1069 | { 1070 | *TokenHandle = INVALID_HANDLE_VALUE; 1071 | 1072 | if (!TokenSource) 1073 | return __HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); 1074 | 1075 | HANDLE ProcessHandle = INVALID_HANDLE_VALUE; 1076 | 1077 | switch (TokenSource->Type) 1078 | { 1079 | case M2_PROCESS_TOKEN_SOURCE_TYPE::Current: 1080 | ProcessHandle = GetCurrentProcess(); 1081 | break; 1082 | case M2_PROCESS_TOKEN_SOURCE_TYPE::Handle: 1083 | ProcessHandle = TokenSource->ProcessHandle; 1084 | break; 1085 | case M2_PROCESS_TOKEN_SOURCE_TYPE::ProcessId: 1086 | ProcessHandle = OpenProcess( 1087 | MAXIMUM_ALLOWED, FALSE, TokenSource->ProcessId); 1088 | if (!ProcessHandle) 1089 | return M2GetLastHRESULTErrorKnownFailedCall(); 1090 | break; 1091 | default: 1092 | return __HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); 1093 | } 1094 | 1095 | if (OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle)) 1096 | return S_OK; 1097 | 1098 | return M2GetLastHRESULTErrorKnownFailedCall(); 1099 | } 1100 | 1101 | /** 1102 | * Retrieves a specified type of information about an access token. The calling 1103 | * process must have appropriate access rights to obtain the information. 1104 | * 1105 | * @param OutputInformation A pointer to a buffer the function fills with the 1106 | * requested information. When you have finished using 1107 | * the information, free it by calling the 1108 | * M2FreeMemory function. You should also set the 1109 | * pointer to NULL. 1110 | * @param TokenHandle A handle to an access token from which information is 1111 | * retrieved. 1112 | * @param TokenInformationClass Specifies a value from the 1113 | * TOKEN_INFORMATION_CLASS enumerated type to 1114 | * identify the type of information the function 1115 | * retrieves. 1116 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1117 | * @remark For more information, see GetTokenInformation. 1118 | */ 1119 | HRESULT M2GetTokenInformation( 1120 | _Out_ PVOID* OutputInformation, 1121 | _In_ HANDLE TokenHandle, 1122 | _In_ TOKEN_INFORMATION_CLASS TokenInformationClass) 1123 | { 1124 | *OutputInformation = nullptr; 1125 | 1126 | DWORD Length = 0; 1127 | 1128 | HRESULT hr = M2GetTokenInformation( 1129 | TokenHandle, 1130 | TokenInformationClass, 1131 | nullptr, 1132 | 0, 1133 | &Length); 1134 | if (hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) 1135 | { 1136 | hr = M2AllocMemory(OutputInformation, Length); 1137 | if (SUCCEEDED(hr)) 1138 | { 1139 | hr = M2GetTokenInformation( 1140 | TokenHandle, 1141 | TokenInformationClass, 1142 | *OutputInformation, 1143 | Length, 1144 | &Length); 1145 | if (FAILED(hr)) 1146 | { 1147 | hr = M2FreeMemory(*OutputInformation); 1148 | } 1149 | } 1150 | } 1151 | 1152 | return hr; 1153 | } 1154 | 1155 | #pragma endregion 1156 | 1157 | #pragma region COM 1158 | 1159 | /** 1160 | * Creates a single uninitialized object of the class associated with a 1161 | * specified CLSID. 1162 | * 1163 | * @param lpszCLSID The string representation of the CLSID. 1164 | * @param pUnkOuter If NULL, indicates that the object is not being created as 1165 | * part of an aggregate. If non-NULL, pointer to the aggregate 1166 | * object's IUnknown interface (the controlling IUnknown). 1167 | * @param dwClsContext Context in which the code that manages the newly created 1168 | * object will run. The values are taken from the 1169 | * enumeration CLSCTX. 1170 | * @param lpszIID A pointer to the string representation of the IID. 1171 | * @param ppv Address of pointer variable that receives the interface pointer 1172 | * requested in riid. Upon successful return, *ppv contains the 1173 | * requested interface pointer. Upon failure, *ppv contains NULL. 1174 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1175 | * @remark For more information, see CoCreateInstance. 1176 | */ 1177 | HRESULT M2CoCreateInstance( 1178 | _In_ LPCWSTR lpszCLSID, 1179 | _In_opt_ LPUNKNOWN pUnkOuter, 1180 | _In_ DWORD dwClsContext, 1181 | _In_ LPCWSTR lpszIID, 1182 | _Out_ LPVOID* ppv) 1183 | { 1184 | CLSID clsid; 1185 | IID iid; 1186 | 1187 | HRESULT hr = CLSIDFromString(lpszCLSID, &clsid); 1188 | if (SUCCEEDED(hr)) 1189 | { 1190 | hr = IIDFromString(lpszIID, &iid); 1191 | if (SUCCEEDED(hr)) 1192 | { 1193 | hr = CoCreateInstance(clsid, pUnkOuter, dwClsContext, iid, ppv); 1194 | } 1195 | } 1196 | 1197 | return hr; 1198 | } 1199 | 1200 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 1201 | 1202 | /** 1203 | * Determines whether the interface id have the correct interface name. 1204 | * 1205 | * @param InterfaceID A pointer to the string representation of the IID. 1206 | * @param InterfaceName A pointer to the interface name string. 1207 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1208 | */ 1209 | HRESULT M2CoCheckInterfaceName( 1210 | _In_ LPCWSTR InterfaceID, 1211 | _In_ LPCWSTR InterfaceName) 1212 | { 1213 | HKEY hKey = nullptr; 1214 | HRESULT hr = M2RegCreateKey( 1215 | HKEY_CLASSES_ROOT, 1216 | (std::wstring(L"Interface\\") + InterfaceID).c_str(), 1217 | 0, 1218 | nullptr, 1219 | 0, 1220 | KEY_READ, 1221 | nullptr, 1222 | &hKey, 1223 | nullptr); 1224 | if (SUCCEEDED(hr)) 1225 | { 1226 | wchar_t* InterfaceTypeName = nullptr; 1227 | hr = M2RegQueryStringValue(&InterfaceTypeName, hKey, nullptr); 1228 | if (SUCCEEDED(hr)) 1229 | { 1230 | if (0 != _wcsicmp(InterfaceTypeName, InterfaceName)) 1231 | { 1232 | hr = E_NOINTERFACE; 1233 | } 1234 | } 1235 | 1236 | RegCloseKey(hKey); 1237 | } 1238 | 1239 | return hr; 1240 | } 1241 | 1242 | #endif 1243 | 1244 | #ifdef CPPWINRT_VERSION 1245 | 1246 | /** 1247 | * Creates a GUID, a unique 128-bit integer used for CLSIDs and interface 1248 | * identifiers. 1249 | * 1250 | * @return The function will return GUID struct. 1251 | */ 1252 | GUID M2CreateGuid() 1253 | { 1254 | GUID guid = { 0 }; 1255 | winrt::check_hresult(CoCreateGuid(&guid)); 1256 | return guid; 1257 | } 1258 | 1259 | #endif 1260 | 1261 | #ifdef __cplusplus_winrt 1262 | 1263 | /** 1264 | * Retrieves the raw pointer from the provided IBuffer object. 1265 | * 1266 | * @param Buffer The IBuffer object you want to retrieve the raw pointer. 1267 | * @return If the function succeeds, the return value is the raw pointer from 1268 | * the provided IBuffer object. If the function fails, the return value 1269 | * is nullptr. 1270 | * @remark The lifetime of the returned buffer is controlled by the lifetime of 1271 | * the buffer object that's passed to this method. When the buffer has 1272 | * been released, the pointer becomes invalid and must not be used. 1273 | */ 1274 | byte* M2GetPointer(Windows::Storage::Streams::IBuffer^ Buffer) 1275 | { 1276 | byte* pBuffer = nullptr; 1277 | Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; 1278 | IInspectable* pBufferABIObject = M2GetInspectable(Buffer); 1279 | if (SUCCEEDED(pBufferABIObject->QueryInterface(&pBufferByteAccess))) 1280 | { 1281 | pBufferByteAccess->Buffer(&pBuffer); 1282 | pBufferByteAccess->Release(); 1283 | } 1284 | 1285 | return pBuffer; 1286 | } 1287 | 1288 | class BufferReference : public RuntimeClass< 1289 | RuntimeClassFlags, 1290 | ABI::Windows::Storage::Streams::IBuffer, 1291 | Windows::Storage::Streams::IBufferByteAccess> 1292 | { 1293 | private: 1294 | UINT32 m_Capacity; 1295 | UINT32 m_Length; 1296 | byte* m_Pointer; 1297 | 1298 | public: 1299 | virtual ~BufferReference() 1300 | { 1301 | } 1302 | 1303 | STDMETHODIMP RuntimeClassInitialize( 1304 | byte* Pointer, UINT32 Capacity) 1305 | { 1306 | m_Capacity = Capacity; 1307 | m_Length = Capacity; 1308 | m_Pointer = Pointer; 1309 | return S_OK; 1310 | } 1311 | 1312 | // IBufferByteAccess::Buffer 1313 | STDMETHODIMP Buffer(byte** value) 1314 | { 1315 | *value = m_Pointer; 1316 | return S_OK; 1317 | } 1318 | 1319 | // IBuffer::get_Capacity 1320 | STDMETHODIMP get_Capacity(UINT32* value) 1321 | { 1322 | *value = m_Capacity; 1323 | return S_OK; 1324 | } 1325 | 1326 | // IBuffer::get_Length 1327 | STDMETHODIMP get_Length(UINT32* value) 1328 | { 1329 | *value = m_Length; 1330 | return S_OK; 1331 | } 1332 | 1333 | // IBuffer::put_Length 1334 | STDMETHODIMP put_Length(UINT32 value) 1335 | { 1336 | if (value > m_Capacity) 1337 | return E_INVALIDARG; 1338 | m_Length = value; 1339 | return S_OK; 1340 | } 1341 | }; 1342 | 1343 | // Retrieves the IBuffer object from the provided raw pointer. 1344 | // Parameters: 1345 | // Pointer: The raw pointer you want to retrieve the IBuffer object. 1346 | // Capacity: The size of raw pointer you want to retrieve the IBuffer object. 1347 | // Return value: 1348 | // If the function succeeds, the return value is the IBuffer object from the 1349 | // provided raw pointer. If the function fails, the return value is nullptr. 1350 | // Warning: 1351 | // The lifetime of the returned IBuffer object is controlled by the lifetime 1352 | // of the raw pointer that's passed to this method. When the raw pointer has 1353 | // been released, the IBuffer object becomes invalid and must not be used. 1354 | Windows::Storage::Streams::IBuffer^ M2MakeIBuffer( 1355 | byte* Pointer, 1356 | UINT32 Capacity) 1357 | { 1358 | using Windows::Storage::Streams::IBuffer; 1359 | 1360 | IBuffer^ buffer = nullptr; 1361 | 1362 | ComPtr bufferReference; 1363 | if (SUCCEEDED(MakeAndInitialize( 1364 | &bufferReference, Pointer, Capacity))) 1365 | { 1366 | buffer = reinterpret_cast(bufferReference.Get()); 1367 | } 1368 | 1369 | return buffer; 1370 | } 1371 | 1372 | /** 1373 | * Creates a GUID, a unique 128-bit integer used for CLSIDs and interface 1374 | * identifiers. 1375 | * 1376 | * @return The function will return Platform::Guid object. 1377 | */ 1378 | Platform::Guid M2CreateGuid() 1379 | { 1380 | GUID guid = { 0 }; 1381 | M2ThrowPlatformExceptionIfFailed(CoCreateGuid(&guid)); 1382 | return Platform::Guid(guid); 1383 | } 1384 | 1385 | #endif 1386 | 1387 | #pragma endregion 1388 | 1389 | #pragma region File 1390 | 1391 | /** 1392 | * Retrieves file system attributes for a specified file or directory. 1393 | * 1394 | * @param FileHandle A handle to the file that contains the information to be 1395 | * retrieved. This handle should not be a pipe handle. 1396 | * @param FileAttributes The attributes of the specified file or directory. 1397 | * For a list of attribute values and their descriptions, 1398 | * see File Attribute Constants. If the function fails, 1399 | * the return value is INVALID_FILE_ATTRIBUTES. 1400 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1401 | */ 1402 | HRESULT M2GetFileAttributes( 1403 | _In_ HANDLE FileHandle, 1404 | _Out_ PDWORD FileAttributes) 1405 | { 1406 | FILE_BASIC_INFO BasicInfo; 1407 | 1408 | if (GetFileInformationByHandleEx( 1409 | FileHandle, 1410 | FileBasicInfo, 1411 | &BasicInfo, 1412 | sizeof(FILE_BASIC_INFO))) 1413 | { 1414 | *FileAttributes = BasicInfo.FileAttributes; 1415 | return S_OK; 1416 | } 1417 | else 1418 | { 1419 | *FileAttributes = INVALID_FILE_ATTRIBUTES; 1420 | return M2GetLastHRESULTErrorKnownFailedCall(); 1421 | } 1422 | } 1423 | 1424 | /** 1425 | * Sets the attributes for a file or directory. 1426 | * 1427 | * @param FileHandle A handle to the file for which to change information. This 1428 | * handle must be opened with the appropriate permissions for 1429 | * the requested change. This handle should not be a pipe 1430 | * handle. 1431 | * @param FileAttributes The file attributes to set for the file. This 1432 | * parameter can be one or more values, combined using 1433 | * the bitwise - OR operator. However, all other values 1434 | * override FILE_ATTRIBUTE_NORMAL. For more information, 1435 | * see the SetFileAttributes function. 1436 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1437 | */ 1438 | HRESULT M2SetFileAttributes( 1439 | _In_ HANDLE FileHandle, 1440 | _In_ DWORD FileAttributes) 1441 | { 1442 | FILE_BASIC_INFO BasicInfo = { 0 }; 1443 | BasicInfo.FileAttributes = 1444 | FileAttributes & ( 1445 | FILE_SHARE_READ | 1446 | FILE_SHARE_WRITE | 1447 | FILE_SHARE_DELETE | 1448 | FILE_ATTRIBUTE_ARCHIVE | 1449 | FILE_ATTRIBUTE_TEMPORARY | 1450 | FILE_ATTRIBUTE_OFFLINE | 1451 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | 1452 | FILE_ATTRIBUTE_NO_SCRUB_DATA) | 1453 | FILE_ATTRIBUTE_NORMAL; 1454 | 1455 | if (SetFileInformationByHandle( 1456 | FileHandle, 1457 | FileBasicInfo, 1458 | &BasicInfo, 1459 | sizeof(FILE_BASIC_INFO))) 1460 | { 1461 | return S_OK; 1462 | } 1463 | else 1464 | { 1465 | return M2GetLastHRESULTErrorKnownFailedCall(); 1466 | } 1467 | } 1468 | 1469 | /** 1470 | * Retrieves the size of the specified file. 1471 | * 1472 | * @param FileHandle A handle to the file that contains the information to be 1473 | * retrieved. This handle should not be a pipe handle. 1474 | * @param FileSize A pointer to a ULONGLONG value that receives the file size, 1475 | * in bytes. 1476 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1477 | * @remark The way to get a file handle for this operation: 1478 | * HANDLE hFile = CreateFileW( 1479 | * lpFileName, 1480 | * GENERIC_READ | SYNCHRONIZE, 1481 | * FILE_SHARE_READ, 1482 | * nullptr, 1483 | * OPEN_EXISTING, 1484 | * FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 1485 | * nullptr); 1486 | */ 1487 | HRESULT M2GetFileSize( 1488 | _In_ HANDLE FileHandle, 1489 | _Out_ PULONGLONG FileSize) 1490 | { 1491 | FILE_STANDARD_INFO StandardInfo; 1492 | 1493 | if (GetFileInformationByHandleEx( 1494 | FileHandle, 1495 | FileStandardInfo, 1496 | &StandardInfo, 1497 | sizeof(FILE_STANDARD_INFO))) 1498 | { 1499 | *FileSize = static_cast( 1500 | StandardInfo.EndOfFile.QuadPart); 1501 | return S_OK; 1502 | } 1503 | else 1504 | { 1505 | *FileSize = 0; 1506 | return M2GetLastHRESULTErrorKnownFailedCall(); 1507 | } 1508 | } 1509 | 1510 | /** 1511 | * Retrieves the amount of space that is allocated for the file. 1512 | * 1513 | * @param FileHandle A handle to the file that contains the information to be 1514 | * retrieved. This handle should not be a pipe handle. 1515 | * @param AllocationSize A pointer to a ULONGLONG value that receives the 1516 | * amount of space that is allocated for the file, in 1517 | * bytes. 1518 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1519 | * @remark The way to get a file handle for this operation: 1520 | * HANDLE hFile = CreateFileW( 1521 | * lpFileName, 1522 | * GENERIC_READ | SYNCHRONIZE, 1523 | * FILE_SHARE_READ, 1524 | * nullptr, 1525 | * OPEN_EXISTING, 1526 | * FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 1527 | * nullptr); 1528 | */ 1529 | HRESULT M2GetFileAllocationSize( 1530 | _In_ HANDLE FileHandle, 1531 | _Out_ PULONGLONG AllocationSize) 1532 | { 1533 | FILE_STANDARD_INFO StandardInfo; 1534 | 1535 | if (GetFileInformationByHandleEx( 1536 | FileHandle, 1537 | FileStandardInfo, 1538 | &StandardInfo, 1539 | sizeof(FILE_STANDARD_INFO))) 1540 | { 1541 | *AllocationSize = static_cast( 1542 | StandardInfo.AllocationSize.QuadPart); 1543 | return S_OK; 1544 | } 1545 | else 1546 | { 1547 | *AllocationSize = 0; 1548 | return M2GetLastHRESULTErrorKnownFailedCall(); 1549 | } 1550 | } 1551 | 1552 | /** 1553 | * Deletes an existing file. 1554 | * 1555 | * @param FileHandle The handle of the file to be deleted.. This handle must be 1556 | * opened with the appropriate permissions for the requested 1557 | * change. This handle should not be a pipe handle. 1558 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1559 | * @remark The way to get a file handle for this operation: 1560 | * HANDLE hFile = CreateFileW( 1561 | * lpFileName, 1562 | * SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 1563 | * FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1564 | * nullptr, 1565 | * OPEN_EXISTING, 1566 | * FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 1567 | * nullptr); 1568 | */ 1569 | HRESULT M2DeleteFile( 1570 | _In_ HANDLE FileHandle) 1571 | { 1572 | FILE_DISPOSITION_INFO DispostionInfo; 1573 | DispostionInfo.DeleteFile = TRUE; 1574 | 1575 | if (SetFileInformationByHandle( 1576 | FileHandle, 1577 | FileDispositionInfo, 1578 | &DispostionInfo, 1579 | sizeof(FILE_DISPOSITION_INFO))) 1580 | { 1581 | return S_OK; 1582 | } 1583 | else 1584 | { 1585 | return M2GetLastHRESULTErrorKnownFailedCall(); 1586 | } 1587 | } 1588 | 1589 | /** 1590 | * Deletes an existing file, even the file have the readonly attribute. 1591 | * 1592 | * @param FileHandle The handle of the file to be deleted.. This handle must be 1593 | * opened with the appropriate permissions for the requested 1594 | * change. This handle should not be a pipe handle. 1595 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1596 | * @remark The way to get a file handle for this operation: 1597 | * HANDLE hFile = CreateFileW( 1598 | * lpFileName, 1599 | * SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 1600 | * FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1601 | * nullptr, 1602 | * OPEN_EXISTING, 1603 | * FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 1604 | * nullptr); 1605 | */ 1606 | HRESULT M2DeleteFileIgnoreReadonlyAttribute( 1607 | _In_ HANDLE FileHandle) 1608 | { 1609 | HRESULT hr = S_OK; 1610 | DWORD OldAttribute = 0; 1611 | 1612 | // Save old attributes. 1613 | hr = M2GetFileAttributes( 1614 | FileHandle, 1615 | &OldAttribute); 1616 | if (!SUCCEEDED(hr)) return hr; 1617 | 1618 | // Remove readonly attribute. 1619 | hr = M2SetFileAttributes( 1620 | FileHandle, 1621 | OldAttribute & (-1 ^ FILE_ATTRIBUTE_READONLY)); 1622 | if (!SUCCEEDED(hr)) return hr; 1623 | 1624 | // Delete the file. 1625 | hr = M2DeleteFile(FileHandle); 1626 | if (!SUCCEEDED(hr)) 1627 | { 1628 | // Restore attributes if failed. 1629 | hr = M2SetFileAttributes( 1630 | FileHandle, 1631 | OldAttribute); 1632 | } 1633 | 1634 | return hr; 1635 | } 1636 | 1637 | #pragma endregion 1638 | 1639 | #pragma region Module 1640 | 1641 | /** 1642 | * Retrieves the address of an exported function or variable from the specified 1643 | * dynamic-link library (DLL). 1644 | * 1645 | * @param lpProcAddress The address of the exported function or variable. 1646 | * @param hModule A handle to the DLL module that contains the function or 1647 | * variable. The LoadLibrary, LoadLibraryEx, LoadPackagedLibrary 1648 | * or GetModuleHandle function returns this handle. This 1649 | * function does not retrieve addresses from modules that were 1650 | * loaded using the LOAD_LIBRARY_AS_DATAFILE flag. For more 1651 | * information, see LoadLibraryEx. 1652 | * @param lpProcName The function or variable name, or the function's ordinal 1653 | * value. If this parameter is an ordinal value, it must be 1654 | * in the low-order word; the high-order word must be zero. 1655 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1656 | */ 1657 | HRESULT M2GetProcAddress( 1658 | _Out_ FARPROC* lpProcAddress, 1659 | _In_ HMODULE hModule, 1660 | _In_ LPCSTR lpProcName) 1661 | { 1662 | *lpProcAddress = GetProcAddress(hModule, lpProcName); 1663 | return (!*lpProcAddress) ? S_OK : M2GetLastHRESULTErrorKnownFailedCall(); 1664 | } 1665 | 1666 | /** 1667 | * Retrieves the path of the executable file of the current process. 1668 | * 1669 | * @return If the function succeeds, the return value is the path of the 1670 | * executable file of the current process. If the function fails, the 1671 | * return value is an empty string. 1672 | */ 1673 | std::wstring M2GetCurrentProcessModulePath() 1674 | { 1675 | std::wstring result(MAX_PATH, L'\0'); 1676 | GetModuleFileNameW(nullptr, &result[0], (DWORD)(result.capacity())); 1677 | result.resize(wcslen(result.c_str())); 1678 | return result; 1679 | } 1680 | 1681 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 1682 | 1683 | /** 1684 | * Loads the specified module with the optimization of the mitigation of DLL 1685 | * preloading attacks into the address space of the calling process safely. The 1686 | * specified module may cause other modules to be loaded. 1687 | * 1688 | * @param phLibModule A handle to the loaded module. 1689 | * @param lpLibFileName A string that specifies the file name of the module to 1690 | * load. 1691 | * @param hFile This parameter is reserved for future use. It must be NULL. 1692 | * @param dwFlags The action to be taken when loading the module. 1693 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1694 | * @remark For more information, see LoadLibraryEx. 1695 | */ 1696 | HRESULT M2LoadLibrary( 1697 | _Out_ HMODULE* phLibModule, 1698 | _In_ LPCWSTR lpLibFileName, 1699 | _Reserved_ HANDLE hFile, 1700 | _In_ DWORD dwFlags) 1701 | { 1702 | *phLibModule = LoadLibraryExW(lpLibFileName, hFile, dwFlags); 1703 | return *phLibModule ? S_OK : M2GetLastHRESULTErrorKnownFailedCall(); 1704 | } 1705 | 1706 | /** 1707 | * Obtain the best matching resource with the specified type and name in the 1708 | * specified module. 1709 | * 1710 | * @param lpResourceInfo The resource info which contains the pointer and size. 1711 | * @param hModule A handle to the module whose portable executable file or an 1712 | * accompanying MUI file contains the resource. If this 1713 | * parameter is NULL, the function searches the module used to 1714 | * create the current process. 1715 | * @param lpType The resource type. Alternately, rather than a pointer, this 1716 | * parameter can be MAKEINTRESOURCE(ID), where ID is the integer 1717 | * identifier of the given resource type. 1718 | * @param lpName The name of the resource. Alternately, rather than a pointer, 1719 | * this parameter can be MAKEINTRESOURCE(ID), where ID is the 1720 | * integer identifier of the resource. 1721 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1722 | */ 1723 | HRESULT M2LoadResource( 1724 | _Out_ PM2_RESOURCE_INFO lpResourceInfo, 1725 | _In_opt_ HMODULE hModule, 1726 | _In_ LPCWSTR lpType, 1727 | _In_ LPCWSTR lpName) 1728 | { 1729 | if (!lpResourceInfo) 1730 | return E_INVALIDARG; 1731 | 1732 | lpResourceInfo->Size = 0; 1733 | lpResourceInfo->Pointer = nullptr; 1734 | 1735 | HRSRC ResourceFind = FindResourceExW( 1736 | hModule, lpType, lpName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); 1737 | if (!ResourceFind) 1738 | return M2GetLastHRESULTErrorKnownFailedCall(); 1739 | 1740 | lpResourceInfo->Size = SizeofResource(hModule, ResourceFind); 1741 | 1742 | HGLOBAL ResourceLoad = LoadResource(hModule, ResourceFind); 1743 | if (!ResourceLoad) 1744 | return M2GetLastHRESULTErrorKnownFailedCall(); 1745 | 1746 | lpResourceInfo->Pointer = LockResource(ResourceLoad); 1747 | 1748 | return S_OK; 1749 | } 1750 | 1751 | /** 1752 | * Loads the specified module with the optimization of the mitigation of DLL 1753 | * preloading attacks into the address space of the calling process safely. The 1754 | * specified module may cause other modules to be loaded. 1755 | * 1756 | * @param ModuleHandle If the function succeeds, this parameter's value is a 1757 | * handle to the loaded module. You should read the 1758 | * documentation about LoadLibraryEx API for further 1759 | * information. 1760 | * @param LibraryFileName A string that specifies the file name of the module 1761 | * to load. You should read the documentation about 1762 | * LoadLibraryEx API for further information. 1763 | * @param Flags The action to be taken when loading the module. You should read 1764 | * the documentation about LoadLibraryEx API for further 1765 | * information. 1766 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1767 | */ 1768 | HRESULT M2LoadLibraryEx( 1769 | _Out_ HMODULE* ModuleHandle, 1770 | _In_ LPCWSTR LibraryFileName, 1771 | _In_ DWORD Flags) 1772 | { 1773 | HRESULT hr = M2LoadLibrary(ModuleHandle, LibraryFileName, nullptr, Flags); 1774 | if (SUCCEEDED(hr)) 1775 | { 1776 | if ((Flags & LOAD_LIBRARY_SEARCH_SYSTEM32) && 1777 | (hr == __HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) 1778 | { 1779 | if (!wcschr(LibraryFileName, L'\\')) 1780 | { 1781 | std::wstring SystemDirectoryPath; 1782 | hr = M2GetSystemDirectory(SystemDirectoryPath); 1783 | if (SUCCEEDED(hr)) 1784 | { 1785 | hr = M2LoadLibrary( 1786 | ModuleHandle, 1787 | (SystemDirectoryPath + LibraryFileName).c_str(), 1788 | nullptr, 1789 | Flags); 1790 | } 1791 | } 1792 | } 1793 | } 1794 | 1795 | return hr; 1796 | } 1797 | 1798 | #endif 1799 | 1800 | #pragma endregion 1801 | 1802 | #pragma region Registry 1803 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 1804 | 1805 | /** 1806 | * Creates the specified registry key. If the key already exists, the function 1807 | * opens it. Note that key names are not case sensitive. 1808 | * 1809 | * @param hKey A handle to an open registry key. 1810 | * @param lpSubKey The name of a subkey that this function opens or creates 1811 | * @param Reserved This parameter is reserved and must be zero. 1812 | * @param lpClass The user-defined class type of this key. 1813 | * @param dwOptions This parameter can be one of the following values: 1814 | * REG_OPTION_BACKUP_RESTORE, REG_OPTION_CREATE_LINK, 1815 | * REG_OPTION_NON_VOLATILE, REG_OPTION_VOLATILE. 1816 | * @param samDesired A mask that specifies the access rights for the key to be 1817 | * created. 1818 | * @param lpSecurityAttributes A pointer to a SECURITY_ATTRIBUTES structure 1819 | * that determines whether the returned handle can 1820 | * be inherited by child processes. 1821 | * @param phkResult A pointer to a variable that receives a handle to the 1822 | * opened or created key. 1823 | * @param lpdwDisposition A pointer to a variable that receives one of the 1824 | * following disposition values. 1825 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1826 | * @remark For more information, see RegCreateKeyEx. 1827 | */ 1828 | HRESULT M2RegCreateKey( 1829 | _In_ HKEY hKey, 1830 | _In_ LPCWSTR lpSubKey, 1831 | _Reserved_ DWORD Reserved, 1832 | _In_opt_ LPWSTR lpClass, 1833 | _In_ DWORD dwOptions, 1834 | _In_ REGSAM samDesired, 1835 | _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes, 1836 | _Out_ PHKEY phkResult, 1837 | _Out_opt_ LPDWORD lpdwDisposition) 1838 | { 1839 | return HRESULT_FROM_WIN32(RegCreateKeyExW( 1840 | hKey, 1841 | lpSubKey, 1842 | Reserved, 1843 | lpClass, 1844 | dwOptions, 1845 | samDesired, 1846 | lpSecurityAttributes, 1847 | phkResult, 1848 | lpdwDisposition)); 1849 | } 1850 | 1851 | /** 1852 | * Retrieves the type and data for the specified value name associated with an 1853 | * open registry key. 1854 | * 1855 | * @param hKey A handle to an open registry key. 1856 | * @param lpValueName The name of the registry value. 1857 | * @param lpReserved This parameter is reserved and must be NULL. 1858 | * @param lpType A pointer to a variable that receives a code indicating the 1859 | * type of data stored in the specified value. 1860 | * @param lpData A pointer to a buffer that receives the value's data. 1861 | * @param lpcbData A pointer to a variable that specifies the size of the 1862 | * buffer pointed to by the lpData parameter, in bytes. 1863 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1864 | * @remark For more information, see RegQueryValueEx. 1865 | */ 1866 | HRESULT M2RegQueryValue( 1867 | _In_ HKEY hKey, 1868 | _In_opt_ LPCWSTR lpValueName, 1869 | _Reserved_ LPDWORD lpReserved, 1870 | _Out_opt_ LPDWORD lpType, 1871 | _Out_opt_ LPBYTE lpData, 1872 | _Inout_opt_ LPDWORD lpcbData) 1873 | { 1874 | return HRESULT_FROM_WIN32(RegQueryValueExW( 1875 | hKey, 1876 | lpValueName, 1877 | lpReserved, 1878 | lpType, 1879 | lpData, 1880 | lpcbData)); 1881 | } 1882 | 1883 | /** 1884 | * Retrieves the type and data for the specified value name associated with an 1885 | * open registry key. 1886 | * 1887 | * @param hKey A handle to an open registry key. 1888 | * @param lpValueName The name of the value to be set. 1889 | * @param Reserved This parameter is reserved and must be zero. 1890 | * @param dwType The type of data pointed to by the lpData parameter. 1891 | * @param lpData The data to be stored. 1892 | * @param cbData The size of the information pointed to by the lpData 1893 | * parameter, in bytes. 1894 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1895 | * @remark For more information, see RegSetValueEx. 1896 | */ 1897 | HRESULT M2RegSetValue( 1898 | _In_ HKEY hKey, 1899 | _In_opt_ LPCWSTR lpValueName, 1900 | _Reserved_ DWORD Reserved, 1901 | _In_ DWORD dwType, 1902 | _In_opt_ CONST BYTE* lpData, 1903 | _In_ DWORD cbData) 1904 | { 1905 | return HRESULT_FROM_WIN32(RegSetValueExW( 1906 | hKey, 1907 | lpValueName, 1908 | Reserved, 1909 | dwType, 1910 | lpData, 1911 | cbData)); 1912 | } 1913 | 1914 | /** 1915 | * Retrieves the string type data for the specified value name associated with 1916 | * an open registry key. 1917 | * 1918 | * @param hKey A handle to an open registry key. 1919 | * @param lpValueName The name of the registry value. 1920 | * @param lpData A pointer to a buffer that receives the value's data. When you 1921 | * have finished using the information, free it by calling the 1922 | * M2FreeMemory function. You should also set the pointer to 1923 | * NULL. 1924 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1925 | * @remark For more information, see RegQueryValueEx. 1926 | */ 1927 | HRESULT M2RegQueryStringValue( 1928 | _Out_ LPWSTR* lpData, 1929 | _In_ HKEY hKey, 1930 | _In_opt_ LPCWSTR lpValueName) 1931 | { 1932 | *lpData = nullptr; 1933 | 1934 | DWORD cbData = 0; 1935 | HRESULT hr = M2RegQueryValue( 1936 | hKey, 1937 | lpValueName, 1938 | nullptr, 1939 | nullptr, 1940 | nullptr, 1941 | &cbData); 1942 | if (SUCCEEDED(hr)) 1943 | { 1944 | hr = M2AllocMemory(reinterpret_cast(lpData), cbData); 1945 | if (SUCCEEDED(hr)) 1946 | { 1947 | DWORD Type = 0; 1948 | hr = M2RegQueryValue( 1949 | hKey, 1950 | lpValueName, 1951 | nullptr, 1952 | &Type, 1953 | reinterpret_cast(*lpData), 1954 | &cbData); 1955 | if (SUCCEEDED(hr) && REG_SZ != Type) 1956 | hr = __HRESULT_FROM_WIN32(ERROR_ILLEGAL_ELEMENT_ADDRESS); 1957 | 1958 | if (FAILED(hr)) 1959 | hr = M2FreeMemory(*lpData); 1960 | } 1961 | } 1962 | 1963 | return hr; 1964 | } 1965 | 1966 | #endif 1967 | #pragma endregion 1968 | 1969 | #pragma region Service 1970 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 1971 | 1972 | /** 1973 | * Starts a service if not started and retrieves the current status of the 1974 | * specified service. 1975 | * 1976 | * @param lpServiceName The name of the service to be started. This is the name 1977 | * specified by the lpServiceName parameter of the 1978 | * CreateService function when the service object was 1979 | * created, not the service display name that is shown by 1980 | * user interface applications to identify the service. 1981 | * The maximum string length is 256 characters. The 1982 | * service control manager database preserves the case of 1983 | * the characters, but service name comparisons are always 1984 | * case insensitive. Forward-slash (/) and backslash () 1985 | * are invalid service name characters. 1986 | * @param lpServiceStatus Contains process status information for a service. 1987 | * @return HRESULT. If the function succeeds, the return value is S_OK. 1988 | */ 1989 | HRESULT M2StartService( 1990 | _In_ LPCWSTR lpServiceName, 1991 | _Out_ LPSERVICE_STATUS_PROCESS lpServiceStatus) 1992 | { 1993 | memset(lpServiceStatus, 0, sizeof(LPSERVICE_STATUS_PROCESS)); 1994 | 1995 | M2::CServiceHandle hSCM; 1996 | M2::CServiceHandle hService; 1997 | 1998 | DWORD nBytesNeeded = 0; 1999 | DWORD nOldCheckPoint = 0; 2000 | ULONGLONG nLastTick = 0; 2001 | bool bStartServiceWCalled = false; 2002 | 2003 | hSCM = OpenSCManagerW( 2004 | nullptr, 2005 | nullptr, 2006 | SC_MANAGER_CONNECT); 2007 | if (!hSCM) 2008 | return M2GetLastHRESULTErrorKnownFailedCall(); 2009 | 2010 | hService = OpenServiceW( 2011 | hSCM, 2012 | lpServiceName, 2013 | SERVICE_QUERY_STATUS | SERVICE_START); 2014 | if (!hService) 2015 | return M2GetLastHRESULTErrorKnownFailedCall(); 2016 | 2017 | while (QueryServiceStatusEx( 2018 | hService, 2019 | SC_STATUS_PROCESS_INFO, 2020 | reinterpret_cast(lpServiceStatus), 2021 | sizeof(SERVICE_STATUS_PROCESS), 2022 | &nBytesNeeded)) 2023 | { 2024 | if (SERVICE_STOPPED == lpServiceStatus->dwCurrentState) 2025 | { 2026 | // Failed if the service had stopped again. 2027 | if (bStartServiceWCalled) 2028 | return E_FAIL; 2029 | 2030 | if (!StartServiceW(hService, 0, nullptr)) 2031 | return M2GetLastHRESULTErrorKnownFailedCall(); 2032 | 2033 | bStartServiceWCalled = true; 2034 | } 2035 | else if ( 2036 | SERVICE_STOP_PENDING == lpServiceStatus->dwCurrentState || 2037 | SERVICE_START_PENDING == lpServiceStatus->dwCurrentState) 2038 | { 2039 | ULONGLONG nCurrentTick = GetTickCount64(); 2040 | 2041 | if (!nLastTick) 2042 | { 2043 | nLastTick = nCurrentTick; 2044 | nOldCheckPoint = lpServiceStatus->dwCheckPoint; 2045 | 2046 | // Same as the .Net System.ServiceProcess, wait 250ms. 2047 | SleepEx(250, FALSE); 2048 | } 2049 | else 2050 | { 2051 | // Check the timeout if the checkpoint is not increased. 2052 | if (lpServiceStatus->dwCheckPoint <= nOldCheckPoint) 2053 | { 2054 | ULONGLONG nDiff = nCurrentTick - nLastTick; 2055 | if (nDiff > lpServiceStatus->dwWaitHint) 2056 | { 2057 | return __HRESULT_FROM_WIN32(ERROR_TIMEOUT); 2058 | } 2059 | } 2060 | 2061 | // Continue looping. 2062 | nLastTick = 0; 2063 | } 2064 | } 2065 | else 2066 | { 2067 | break; 2068 | } 2069 | } 2070 | 2071 | return S_OK; 2072 | } 2073 | 2074 | #endif 2075 | #pragma endregion 2076 | 2077 | #pragma region Environment 2078 | 2079 | /** 2080 | * Expands environment-variable strings and replaces them with the values 2081 | * defined for the current user. 2082 | * 2083 | * @param ExpandedString The expanded string. 2084 | * @param VariableName The environment-variable string you need to expand. 2085 | * @return HRESULT. If the function succeeds, the return value is S_OK. 2086 | */ 2087 | HRESULT M2ExpandEnvironmentStrings( 2088 | std::wstring& ExpandedString, 2089 | const std::wstring& VariableName) 2090 | { 2091 | HRESULT hr = S_OK; 2092 | 2093 | do 2094 | { 2095 | DWORD Length = ExpandEnvironmentStringsW( 2096 | VariableName.c_str(), 2097 | nullptr, 2098 | 0); 2099 | if (0 == Length) 2100 | { 2101 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2102 | break; 2103 | } 2104 | 2105 | ExpandedString.resize(Length - 1); 2106 | 2107 | Length = ExpandEnvironmentStringsW( 2108 | VariableName.c_str(), 2109 | &ExpandedString[0], 2110 | static_cast(ExpandedString.size() + 1)); 2111 | if (0 == Length) 2112 | { 2113 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2114 | break; 2115 | } 2116 | if (ExpandedString.size() != Length - 1) 2117 | { 2118 | hr = E_UNEXPECTED; 2119 | break; 2120 | } 2121 | 2122 | } while (false); 2123 | 2124 | if (FAILED(hr)) 2125 | { 2126 | ExpandedString.clear(); 2127 | } 2128 | 2129 | return hr; 2130 | } 2131 | 2132 | /** 2133 | * Retrieves the path of the system directory. 2134 | * 2135 | * @param SystemFolderPath The string of the path of the system directory. 2136 | * @return HRESULT. If the function succeeds, the return value is S_OK. 2137 | */ 2138 | HRESULT M2GetSystemDirectory( 2139 | std::wstring& SystemFolderPath) 2140 | { 2141 | HRESULT hr = S_OK; 2142 | 2143 | do 2144 | { 2145 | UINT Length = GetSystemDirectoryW( 2146 | nullptr, 2147 | 0); 2148 | if (0 == Length) 2149 | { 2150 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2151 | break; 2152 | } 2153 | 2154 | SystemFolderPath.resize(Length - 1); 2155 | 2156 | Length = GetSystemDirectoryW( 2157 | &SystemFolderPath[0], 2158 | static_cast(Length)); 2159 | if (0 == Length) 2160 | { 2161 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2162 | break; 2163 | } 2164 | if (SystemFolderPath.size() != Length) 2165 | { 2166 | hr = E_UNEXPECTED; 2167 | break; 2168 | } 2169 | 2170 | } while (false); 2171 | 2172 | if (FAILED(hr)) 2173 | { 2174 | SystemFolderPath.clear(); 2175 | } 2176 | 2177 | return hr; 2178 | } 2179 | 2180 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 2181 | 2182 | /** 2183 | * Retrieves the path of the shared Windows directory on a multi-user system. 2184 | * 2185 | * @param WindowsFolderPath The string of the path of the shared Windows 2186 | * directory on a multi-user system. 2187 | * @return HRESULT. If the function succeeds, the return value is S_OK. 2188 | */ 2189 | HRESULT M2GetWindowsDirectory( 2190 | std::wstring& WindowsFolderPath) 2191 | { 2192 | HRESULT hr = S_OK; 2193 | 2194 | do 2195 | { 2196 | UINT Length = GetSystemWindowsDirectoryW( 2197 | nullptr, 2198 | 0); 2199 | if (0 == Length) 2200 | { 2201 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2202 | break; 2203 | } 2204 | 2205 | WindowsFolderPath.resize(Length - 1); 2206 | 2207 | Length = GetSystemWindowsDirectoryW( 2208 | &WindowsFolderPath[0], 2209 | static_cast(Length)); 2210 | if (0 == Length) 2211 | { 2212 | hr = M2GetLastHRESULTErrorKnownFailedCall(); 2213 | break; 2214 | } 2215 | if (WindowsFolderPath.size() != Length) 2216 | { 2217 | hr = E_UNEXPECTED; 2218 | break; 2219 | } 2220 | 2221 | } while (false); 2222 | 2223 | if (FAILED(hr)) 2224 | { 2225 | WindowsFolderPath.clear(); 2226 | } 2227 | 2228 | return hr; 2229 | } 2230 | 2231 | /** 2232 | * Enables the Per-Monitor DPI Aware for the specified dialog using the 2233 | * internal API from Windows. 2234 | * 2235 | * @return INT. If failed. returns -1. 2236 | * @remarks You need to use this function in Windows 10 Threshold 1 or Windows 2237 | * 10 Threshold 2. 2238 | */ 2239 | INT M2EnablePerMonitorDialogScaling() 2240 | { 2241 | // Fix for Windows Vista and Server 2008. 2242 | if (!IsWindowsVersionOrGreater(10, 0, 0)) return -1; 2243 | 2244 | typedef INT(WINAPI * PFN_EnablePerMonitorDialogScaling)(); 2245 | 2246 | HMODULE hModule = nullptr; 2247 | PFN_EnablePerMonitorDialogScaling pFunc = nullptr; 2248 | 2249 | hModule = GetModuleHandleW(L"user32.dll"); 2250 | if (!hModule) return -1; 2251 | 2252 | if (FAILED(M2GetProcAddress( 2253 | pFunc, hModule, reinterpret_cast(2577)))) 2254 | return -1; 2255 | 2256 | return pFunc(); 2257 | } 2258 | 2259 | /** 2260 | * Queries the dots per inch (dpi) of a display. 2261 | * 2262 | * @param hmonitor Handle of the monitor being queried. 2263 | * @param dpiType The type of DPI being queried. Possible values are from the 2264 | * MONITOR_DPI_TYPE enumeration. 2265 | * @param dpiX The value of the DPI along the X axis. This value always refers 2266 | * to the horizontal edge, even when the screen is rotated. 2267 | * @param dpiY The value of the DPI along the Y axis. This value always refers 2268 | * to the vertical edge, even when the screen is rotated. 2269 | * @return HRESULT. If the function succeeds, the return value is S_OK. 2270 | */ 2271 | HRESULT M2GetDpiForMonitor( 2272 | _In_ HMONITOR hmonitor, 2273 | _In_ MONITOR_DPI_TYPE dpiType, 2274 | _Out_ UINT* dpiX, 2275 | _Out_ UINT* dpiY) 2276 | { 2277 | HMODULE hModule = nullptr; 2278 | HRESULT hr = M2LoadLibraryEx( 2279 | &hModule, 2280 | L"SHCore.dll", 2281 | LOAD_LIBRARY_SEARCH_SYSTEM32); 2282 | if (SUCCEEDED(hr)) 2283 | { 2284 | decltype(GetDpiForMonitor)* pFunc = nullptr; 2285 | hr = M2GetProcAddress(pFunc, hModule, "GetDpiForMonitor"); 2286 | if (SUCCEEDED(hr)) 2287 | { 2288 | hr = pFunc(hmonitor, dpiType, dpiX, dpiY); 2289 | } 2290 | 2291 | FreeLibrary(hModule); 2292 | } 2293 | 2294 | return hr; 2295 | } 2296 | 2297 | #endif 2298 | 2299 | #pragma endregion 2300 | 2301 | #pragma region WinRT 2302 | 2303 | #ifdef CPPWINRT_VERSION 2304 | 2305 | /** 2306 | * Execute function on the UI thread with normal priority. 2307 | * 2308 | * @param agileCallback The function you want to execute. 2309 | * @return The return value is Windows::Foundation::IAsyncAction^. 2310 | */ 2311 | winrt::IAsyncAction M2ExecuteOnUIThread( 2312 | winrt::DispatchedHandler const& agileCallback) 2313 | { 2314 | using winrt::Windows::ApplicationModel::Core::CoreApplication; 2315 | using winrt::Windows::UI::Core::CoreDispatcherPriority; 2316 | 2317 | return CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync( 2318 | CoreDispatcherPriority::Normal, agileCallback); 2319 | } 2320 | 2321 | namespace M2 2322 | { 2323 | void NotifyPropertyChangedBase::RaisePropertyChanged( 2324 | std::wstring_view const& PropertyName) 2325 | { 2326 | this->m_PropertyChanged( 2327 | *this, winrt::PropertyChangedEventArgs(PropertyName)); 2328 | } 2329 | 2330 | winrt::event_token NotifyPropertyChangedBase::PropertyChanged( 2331 | winrt::PropertyChangedEventHandler const& value) 2332 | { 2333 | return this->m_PropertyChanged.add(value); 2334 | } 2335 | 2336 | void NotifyPropertyChangedBase::PropertyChanged( 2337 | winrt::event_token const& token) 2338 | { 2339 | this->m_PropertyChanged.remove(token); 2340 | } 2341 | } 2342 | 2343 | #endif 2344 | 2345 | #ifdef __cplusplus_winrt 2346 | 2347 | /** 2348 | * Handle the completed asynchronous call. 2349 | * 2350 | * @param Async The completed asynchronous call you want to handle. 2351 | * @return Return the HRESULT determined by the asynchronous call. 2352 | */ 2353 | HRESULT M2AsyncHandleCompleted(Platform::Object^ Async) 2354 | { 2355 | HRESULT hr = S_OK; 2356 | ABI::Windows::Foundation::IAsyncInfo* asyncInfo = nullptr; 2357 | 2358 | hr = M2GetInspectable(Async)->QueryInterface(&asyncInfo); 2359 | if (SUCCEEDED(hr)) 2360 | { 2361 | // Get the error code. 2362 | AsyncStatus asyncStatus; 2363 | hr = asyncInfo->get_Status(&asyncStatus); 2364 | if (SUCCEEDED(hr)) 2365 | { 2366 | if (AsyncStatus::Completed == asyncStatus) 2367 | { 2368 | // Just return S_OK if succeeded. 2369 | hr = S_OK; 2370 | } 2371 | else if (AsyncStatus::Started == asyncStatus) 2372 | { 2373 | // Cancel the asynchronous call and return error code if 2374 | // the status is still Started, the timeout interval has 2375 | // been elapsed. 2376 | hr = asyncInfo->Cancel(); 2377 | if (SUCCEEDED(hr)) hr = __HRESULT_FROM_WIN32(ERROR_TIMEOUT); 2378 | } 2379 | else if (AsyncStatus::Canceled == asyncStatus) 2380 | { 2381 | // If the status is Cancelled, return the error code. 2382 | hr = E_ABORT; 2383 | } 2384 | else 2385 | { 2386 | HRESULT hrTemp; 2387 | 2388 | // If the status is other value, return the error code. 2389 | hr = asyncInfo->get_ErrorCode(&hrTemp); 2390 | if (SUCCEEDED(hr)) hr = hrTemp; 2391 | } 2392 | } 2393 | 2394 | asyncInfo->Release(); 2395 | } 2396 | 2397 | return hr; 2398 | } 2399 | 2400 | /** 2401 | * Execute function on the UI thread with normal priority. 2402 | * 2403 | * @param agileCallback The function you want to execute. 2404 | * @return The return value is Windows::Foundation::IAsyncAction^. 2405 | */ 2406 | Windows::Foundation::IAsyncAction^ M2ExecuteOnUIThread( 2407 | Windows::UI::Core::DispatchedHandler^ agileCallback) 2408 | { 2409 | using Windows::ApplicationModel::Core::CoreApplication; 2410 | using Windows::UI::Core::CoreDispatcherPriority; 2411 | 2412 | return CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync( 2413 | CoreDispatcherPriority::Normal, agileCallback); 2414 | } 2415 | 2416 | #endif 2417 | 2418 | #pragma endregion 2419 | 2420 | --------------------------------------------------------------------------------