├── README.md ├── introduce.png ├── obsolete version.zip ├── study ├── fiber_code_w7.cpp ├── fiber_def_w7.h ├── fiber_support_w7.cpp └── srw_cv.png ├── xpext_ver3 ├── common.h ├── k32_file.cpp ├── k32_miscellaneous.cpp ├── k32_processor.cpp ├── k32_processthread.cpp ├── main.cpp ├── nk_conditionvariable.cpp ├── nk_criticalsection.cpp ├── nk_runonce.cpp ├── nt_def.h ├── nt_errorcode.cpp ├── nt_miscellaneous.cpp ├── nt_privilege.cpp ├── nt_srwlock.cpp └── utility.cpp ├── xpext_ver4 ├── common.h ├── k32_file.cpp ├── k32_miscellaneous.cpp ├── k32_processor.cpp ├── k32_processthread.cpp ├── main.cpp ├── nk_conditionvariable.cpp ├── nk_criticalsection.cpp ├── nk_fiber.cpp ├── nk_runonce.cpp ├── nt_def.h ├── nt_errorcode.cpp ├── nt_miscellaneous.cpp ├── nt_privilege.cpp ├── nt_srwlock.cpp └── utility.cpp ├── xpextk_ver1 ├── main.cpp ├── processor.cpp └── tickcount.cpp └── xpextk_ver2 ├── main.cpp ├── processinfo.cpp ├── processor.cpp └── tickcount.cpp /README.md: -------------------------------------------------------------------------------- 1 | ## xpext - Windows XP API补全计划 2 | ### 已完成: 3 | #### nk_criticalsection.cpp 4 | InitializeCriticalSectionEx(仅接口) 5 | #### nt_srwlock.cpp 6 | InitializeSRWLock 7 | AcquireSRWLockExclusive 8 | AcquireSRWLockShared 9 | ReleaseSRWLockExclusive 10 | ReleaseSRWLockShared 11 | TryAcquireSRWLockExclusive 12 | TryAcquireSRWLockShared 13 | #### nk_conditionvariable.cpp 14 | InitializeConditionVariable 15 | SleepConditionVariableCS 16 | SleepConditionVariableSRW 17 | WakeConditionVariable 18 | WakeAllConditionVariable 19 | #### nk_runonce.cpp 20 | InitOnceInitialize 21 | InitOnceBeginInitialize 22 | InitOnceComplete 23 | InitOnceExecuteOnce 24 | #### k32_processthread.cpp 25 | GetThreadId 26 | GetProcessId 27 | GetProcessIdOfThread 28 | SetThreadErrorMode(仅接口) 29 | GetThreadErrorMode(仅接口) 30 | QueryFullProcessImageNameA 31 | QueryFullProcessImageNameW 32 | InitializeProcThreadAttributeList(仅接口) 33 | UpdateProcThreadAttribute(仅接口) 34 | DeleteProcThreadAttributeList(仅接口) 35 | #### k32_processor.cpp 36 | GetCurrentProcessorNumber 37 | GetCurrentProcessorNumberEx 38 | GetActiveProcessorGroupCount 39 | GetMaximumProcessorGroupCount 40 | GetActiveProcessorCount 41 | GetMaximumProcessorCount 42 | #### k32_miscellaneous.cpp 43 | GetTickCount64 44 | RaiseFailFastException 45 | #### k32_file.cpp 46 | GetFileInformationByHandleEx 47 | SetFileInformationByHandle 48 | GetFinalPathNameByHandleA 49 | GetFinalPathNameByHandleW 50 | CreateSymbolicLinkA 51 | CreateSymbolicLinkW 52 | #### nk_fiber.cpp 53 | ConvertThreadToFiberEx 54 | IsThreadAFiber 55 | ConvertThreadToFiber(增强) 56 | CreateFiberEx(增强) 57 | CreateFiber(增强) 58 | DeleteFiber(增强) 59 | ConvertFiberToThread(增强) 60 | SwitchToFiber(增强) 61 | FlsAlloc 62 | FlsFree 63 | FlsGetValue 64 | FlsSetValue 65 | 66 | ### 近期计划: 67 | GetSystemInfo 68 | GetVersion 69 | GetVersionEx 70 | VerifyVersionInfoA/W 71 | GetProductInfo 72 | 制作PE编辑工具 73 | 74 | ### 分析中: 75 | GetErrorMode 76 | ws2_32.inet_ntop 77 | ws2_32.inet_pton 78 | ws2_32.WSAPoll 79 | CreateEventExA/W 80 | CreateMutexExA/W 81 | CreateSemaphoreExA/W 82 | PathCchCanonicalizeEx(Win8+) 83 | PathCchCombineEx(Win8+) 84 | advapi32.RegGetValueA/W 85 | advapi32.RegSetKeyValueA/W 86 | advapi32.RegDeleteKeyValueA/W 87 | mpr.WNetRestoreConnectionA 88 | 运行时TLS动态分配槽的问题 89 | Wow64DisableWow64FsRedirection 90 | Wow64EnableWow64FsRedirection 91 | Wow64RevertWow64FsRedirection 92 | AddDllDirectory 93 | RemoveDllDirectory 94 | SetDefaultDllDirectories 95 | LoadLibraryEx的LOAD_LIBRARY_SEARCH_USER_DIRS标记 96 | ReOpenFile 97 | CreateFile2(Win8+) 98 | user32.SetProcessDPIAware 99 | CompareStringEx 100 | PsSetCreateProcessNotifyRoutineEx 101 | shell32.SHGetKnownFolderPath 102 | 103 | ### 暂时无法实现: 104 | QueryThreadCycleTime 105 | QueryProcessCycleTime 106 | CreateProcess应用ProcThreadAttribute 107 | ThreadPool相关API 108 | NtXXXKeyedEvent允许句柄传入NULL 109 | IoConnectInterruptEx和MSIX 110 | CreateRemoteThreadEx 111 | Core Audio系列API 112 | NTFS的transacted 113 | NtQueryObject用在某些对象上会卡死 114 | 完成端口的CloseHandle可以直接唤醒线程并返回-1 115 | CancelIoEx 116 | GetOverlappedResultEx 117 | normaliz.dll 118 | SetLastError断点 119 | 120 | ### 更新说明: 121 | ver4 2021.06.12 122 | 增加fiber相关API,以及一些其他API 123 | 内核模块尝试新功能 124 | 在study文件夹里给出一些代码中难以描述的信息 125 | 将废弃的代码打包成zip文件 126 | ver3 2021.05.11 127 | 增加一些文件相关的API,修复ver2中BaseSetLastNTError的严重bug 128 | 由于Github展示代码的算法不完善,从ver3开始代码文件全部使用BOM+UTF8编码 129 | 由于Github目录操作设计太差,从ver3开始新版和旧版都放在根目录下,以最新版本号为准 130 | ver2 2021.05.02 131 | 添加内核支持模块xpextk 132 | 增加RunOnce系列API,以及一些其他API 133 | 项目名由ntext改为xpext,调整代码结构,重新编排文件名 134 | ver1 2021.03.21 135 | 确定了基本框架和实现方向 136 | 增加Condition Variable系列API,以及一些其他API 137 | 调整SRW Lock,使之与Condition Variable一致 138 | ver0 2020.05.29 139 | 初版,SRW Lock系列API 140 | 141 | ### 其它说明: 142 | 代码是开源出来参考的,希望能得到反馈,更正错误,你编译了也没用 143 | 将来会通过私人工具修改PE文件,重定向API调用,在release里提供 144 | 某些功能需要内核驱动辅助实现,请使用reg文件将驱动设为开机启动 145 | 146 | ### 有什么用? 147 | The procedure entry point XXX could not be located in the dynamic link library XXX.dll 148 | ![Entry Point Not Found](https://github.com/zeroclear/ntext/raw/master/introduce.png) 149 | 150 | ### 相关项目: 151 | [SharedReadWriteLock](https://github.com/anydream/SharedReadWriteLock) 152 | [YY-Thunks - 让兼容 Windows 更轻松](https://github.com/Chuyu-Team/YY-Thunks) 153 | [PHP 7 and PHP 5.6 for Windows XP/2003](https://github.com/source-power/php7-for-windows2003) 154 | [win7lib](https://github.com/TheDeadFish/win7lib) 155 | [wine](https://github.com/wine-mirror/wine) 156 | [ReactOS](https://github.com/reactos/reactos) 157 | [NTOSKRNL Emu_Extender](https://github.com/MovAX0xDEAD/NTOSKRNL_Emu) 158 | [CreateProcessInternal](https://github.com/MeeSong/Reverse-Engineering) 159 | [ExtendedXP-Core-Api-implementation](https://github.com/DibyaTheXPFan/ExtendedXP-Core-Api-implementation) 160 | -------------------------------------------------------------------------------- /introduce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroclear/xpext/9b5c2edbdadcd416989612fd72c72fbaa802b3eb/introduce.png -------------------------------------------------------------------------------- /obsolete version.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroclear/xpext/9b5c2edbdadcd416989612fd72c72fbaa802b3eb/obsolete version.zip -------------------------------------------------------------------------------- /study/fiber_def_w7.h: -------------------------------------------------------------------------------- 1 |  2 | #define WIN32_NO_STATUS 3 | #include 4 | #undef WIN32_NO_STATUS 5 | #include 6 | 7 | #pragma comment(lib,"E:\\WDK\\lib\\win7\\i386\\ntdll.lib") 8 | 9 | typedef struct _UNICODE_STRING { 10 | USHORT Length; 11 | USHORT MaximumLength; 12 | PWSTR Buffer; 13 | } UNICODE_STRING, *PUNICODE_STRING; 14 | 15 | typedef struct _FLS_CALLBACK_INFO 16 | { 17 | PFLS_CALLBACK_FUNCTION CallbackFunc; 18 | RTL_SRWLOCK FlsCbLock; 19 | } FLS_CALLBACK_INFO; 20 | 21 | typedef struct _RTL_BITMAP { 22 | ULONG SizeOfBitmap; 23 | PULONG Buffer; 24 | } RTL_BITMAP, *PRTL_BITMAP; 25 | 26 | typedef struct _PEB 27 | { 28 | UCHAR InheritedAddressSpace; //+0x000 29 | UCHAR ReadImageFileExecOptions; //+0x001 30 | UCHAR BeingDebugged; //+0x002 31 | 32 | union 33 | { 34 | UCHAR BitField; //+0x003 35 | struct 36 | { 37 | UCHAR ImageUsesLargePages:1; 38 | UCHAR IsProtectedProcess:1; 39 | UCHAR IsLegacyProcess:1; 40 | UCHAR IsImageDynamicallyRelocated:1; 41 | UCHAR SkipPatchingUser32Forwarders:1; 42 | UCHAR SpareBits:3; 43 | }; 44 | }; 45 | 46 | PVOID Mutant; //+0x004 47 | PVOID ImageBaseAddress; //+0x008 48 | PVOID Ldr; //+0x00c PEB_LDR_DATA* 49 | PVOID ProcessParameters; //+0x010 RTL_USER_PROCESS_PARAMETERS* 50 | PVOID SubSystemData; //+0x014 51 | PVOID ProcessHeap; //+0x018 52 | RTL_CRITICAL_SECTION* FastPebLock; //+0x01c 53 | PVOID AtlThunkSListPtr; //+0x020 54 | PVOID IFEOKey; //+0x024 55 | 56 | union 57 | { 58 | ULONG CrossProcessFlags; //+0x028 59 | struct 60 | { 61 | ULONG ProcessInJob:1; //+0x028 62 | ULONG ProcessInitializing:1; //+0x028 63 | ULONG ProcessUsingVEH:1; //+0x028 64 | ULONG ProcessUsingVCH:1; //+0x028 65 | ULONG ProcessUsingFTH:1; //+0x028 66 | ULONG ReservedBits0:27; //+0x028 67 | }; 68 | }; 69 | 70 | PVOID KernelCallbackTable; //+0x02c 71 | PVOID UserSharedInfoPtr; //+0x02c 72 | ULONG SystemReserved[1]; //+0x030 73 | ULONG AtlThunkSListPtr32; //+0x034 74 | PVOID ApiSetMap; //+0x038 75 | ULONG TlsExpansionCounter; //+0x03c 76 | PVOID TlsBitmap; //+0x040 77 | ULONG TlsBitmapBits[2]; //+0x044 78 | PVOID ReadOnlySharedMemoryBase; //+0x04c 79 | PVOID HotpatchInformation; //+0x050 80 | PVOID* ReadOnlyStaticServerData; //+0x054 81 | PVOID AnsiCodePageData; //+0x058 82 | PVOID OemCodePageData; //+0x05c 83 | PVOID UnicodeCaseTableData; //+0x060 84 | ULONG NumberOfProcessors; //+0x064 85 | ULONG NtGlobalFlag; //+0x068 86 | LARGE_INTEGER CriticalSectionTimeout; //+0x070 87 | ULONG HeapSegmentReserve; //+0x078 88 | ULONG HeapSegmentCommit; //+0x07c 89 | ULONG HeapDeCommitTotalFreeThreshold; //+0x080 90 | ULONG HeapDeCommitFreeBlockThreshold; //+0x084 91 | ULONG NumberOfHeaps; //+0x088 92 | ULONG MaximumNumberOfHeaps; //+0x08c 93 | PVOID* ProcessHeaps; //+0x090 94 | PVOID GdiSharedHandleTable; //+0x094 95 | PVOID ProcessStarterHelper; //+0x098 96 | ULONG GdiDCAttributeList; //+0x09c 97 | RTL_CRITICAL_SECTION* LoaderLock; //+0x0a0 98 | ULONG OSMajorVersion; //+0x0a4 99 | ULONG OSMinorVersion; //+0x0a8 100 | USHORT OSBuildNumber; //+0x0ac 101 | USHORT OSCSDVersion; //+0x0ae 102 | ULONG OSPlatformId; //+0x0b0 103 | ULONG ImageSubsystem; //+0x0b4 104 | ULONG ImageSubsystemMajorVersion; //+0x0b8 105 | ULONG ImageSubsystemMinorVersion; //+0x0bc 106 | ULONG ActiveProcessAffinityMask; //+0x0c0 107 | ULONG GdiHandleBuffer[34]; //+0x0c4 108 | PVOID PostProcessInitRoutine; //+0x14c 109 | PVOID TlsExpansionBitmap; //+0x150 110 | ULONG TlsExpansionBitmapBits[32]; //+0x154 111 | ULONG SessionId; //+0x1d4 112 | ULARGE_INTEGER AppCompatFlags; //+0x1d8 113 | ULARGE_INTEGER AppCompatFlagsUser; //+0x1e0 114 | PVOID pShimData; //+0x1e8 115 | PVOID AppCompatInfo; //+0x1ec 116 | UNICODE_STRING CSDVersion; //+0x1f0 117 | PVOID ActivationContextData; //+0x1f8 ACTIVATION_CONTEXT_DATA* 118 | PVOID ProcessAssemblyStorageMap; //+0x1fc ASSEMBLY_STORAGE_MAP* 119 | PVOID SystemDefaultActivationContextData; //+0x200 ACTIVATION_CONTEXT_DATA* 120 | PVOID SystemAssemblyStorageMap; //+0x204 ASSEMBLY_STORAGE_MAP* 121 | ULONG MinimumStackCommit; //+0x208 122 | FLS_CALLBACK_INFO* FlsCallback; //+0x20c 123 | LIST_ENTRY FlsListHead; //+0x210 124 | RTL_BITMAP* FlsBitmap; //+0x218 125 | ULONG FlsBitmapBits[4]; //+0x21c 126 | ULONG FlsHighIndex; //+0x22c 127 | PVOID WerRegistrationData; //+0x230 128 | PVOID WerShipAssertPtr; //+0x234 129 | PVOID pContextData; //+0x238 130 | PVOID pImageHeaderHash; //+0x23c 131 | 132 | union 133 | { 134 | ULONG TracingFlags; //+0x240 135 | struct 136 | { 137 | ULONG HeapTracingEnabled:1; //+0x240 138 | ULONG CritSecTracingEnabled:1; //+0x240 139 | ULONG SpareTracingBits:30; //+0x240 140 | }; 141 | }; 142 | } PEB; 143 | 144 | typedef struct _CLIENT_ID { 145 | HANDLE UniqueProcess; 146 | HANDLE UniqueThread; 147 | } CLIENT_ID, *PCLIENT_ID; 148 | 149 | typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME 150 | { 151 | _RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; 152 | PVOID ActivationContext; //ACTIVATION_CONTEXT* 153 | ULONG Flags; 154 | } RTL_ACTIVATION_CONTEXT_STACK_FRAME; 155 | 156 | typedef struct _ACTIVATION_CONTEXT_STACK 157 | { 158 | RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; 159 | LIST_ENTRY FrameListCache; 160 | ULONG Flags; 161 | ULONG NextCookieSequenceNumber; 162 | ULONG StackId; 163 | } ACTIVATION_CONTEXT_STACK; 164 | 165 | typedef struct _GDI_TEB_BATCH 166 | { 167 | ULONG Offset; 168 | ULONG hDC; 169 | ULONG Buffer[310]; 170 | } GDI_TEB_BATCH; 171 | 172 | typedef struct _TEB 173 | { 174 | NT_TIB NtTib; //+0x000 175 | PVOID EnvironmentPointer; //+0x01c 176 | CLIENT_ID ClientId; //+0x020 177 | PVOID ActiveRpcHandle; //+0x028 178 | PVOID ThreadLocalStoragePointer; //+0x02c 179 | PEB* ProcessEnvironmentBlock; //+0x030 180 | ULONG LastErrorValue; //+0x034 181 | ULONG CountOfOwnedCriticalSections; //+0x038 182 | PVOID CsrClientThread; //+0x03c 183 | PVOID Win32ThreadInfo; //+0x040 184 | ULONG User32Reserved[26]; //+0x044 185 | ULONG UserReserved[5]; //+0x0ac 186 | PVOID WOW32Reserved; //+0x0c0 187 | ULONG CurrentLocale; //+0x0c4 188 | ULONG FpSoftwareStatusRegister; //+0x0c8 189 | PVOID SystemReserved1[54]; //+0x0cc 190 | LONG ExceptionCode; //+0x1a4 191 | ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; //+0x1a8 192 | UCHAR SpareBytes[36]; //+0x1ac 193 | ULONG TxFsContext; //+0x1d0 194 | GDI_TEB_BATCH GdiTebBatch; //+0x1d4 195 | _CLIENT_ID RealClientId; //+0x6b4 196 | PVOID GdiCachedProcessHandle; //+0x6bc 197 | ULONG GdiClientPID; //+0x6c0 198 | ULONG GdiClientTID; //+0x6c4 199 | PVOID GdiThreadLocalInfo; //+0x6c8 200 | ULONG Win32ClientInfo[62]; //+0x6cc 201 | PVOID glDispatchTable[233]; //+0x7c4 202 | ULONG glReserved1[29]; //+0xb68 203 | PVOID glReserved2; //+0xbdc 204 | PVOID glSectionInfo; //+0xbe0 205 | PVOID glSection; //+0xbe4 206 | PVOID glTable; //+0xbe8 207 | PVOID glCurrentRC; //+0xbec 208 | PVOID glContext; //+0xbf0 209 | ULONG LastStatusValue; //+0xbf4 210 | UNICODE_STRING StaticUnicodeString; //+0xbf8 211 | WCHAR StaticUnicodeBuffer[261]; //+0xc00 212 | PVOID DeallocationStack; //+0xe0c 213 | PVOID TlsSlots[64]; //+0xe10 214 | LIST_ENTRY TlsLinks; //+0xf10 215 | PVOID Vdm; //+0xf18 216 | PVOID ReservedForNtRpc; //+0xf1c 217 | PVOID DbgSsReserved[2]; //+0xf20 218 | ULONG HardErrorMode; //+0xf28 219 | PVOID Instrumentation[9]; //+0xf2c 220 | GUID ActivityId; //+0xf50 221 | PVOID SubProcessTag; //+0xf60 222 | PVOID EtwLocalData; //+0xf64 223 | PVOID EtwTraceData; //+0xf68 224 | PVOID WinSockData; //+0xf6c 225 | ULONG GdiBatchCount; //+0xf70 226 | PROCESSOR_NUMBER CurrentIdealProcessor; //+0xf74 227 | ULONG IdealProcessorValue; //+0xf74 228 | UCHAR ReservedPad0; //+0xf74 229 | UCHAR ReservedPad1; //+0xf75 230 | UCHAR ReservedPad2; //+0xf76 231 | UCHAR IdealProcessor; //+0xf77 232 | ULONG GuaranteedStackBytes; //+0xf78 233 | PVOID ReservedForPerf; //+0xf7c 234 | PVOID ReservedForOle; //+0xf80 235 | ULONG WaitingOnLoaderLock; //+0xf84 236 | PVOID SavedPriorityState; //+0xf88 237 | ULONG SoftPatchPtr1; //+0xf8c 238 | PVOID ThreadPoolData; //+0xf90 239 | PVOID* TlsExpansionSlots; //+0xf94 240 | ULONG MuiGeneration; //+0xf98 241 | ULONG IsImpersonating; //+0xf9c 242 | PVOID NlsCache; //+0xfa0 243 | PVOID pShimData; //+0xfa4 244 | ULONG HeapVirtualAffinity; //+0xfa8 245 | PVOID CurrentTransactionHandle; //+0xfac 246 | PVOID ActiveFrame; //+0xfb0 TEB_ACTIVE_FRAME* 247 | PVOID FlsData; //+0xfb4 248 | PVOID PreferredLanguages; //+0xfb8 249 | PVOID UserPrefLanguages; //+0xfbc 250 | PVOID MergedPrefLanguages; //+0xfc0 251 | ULONG MuiImpersonation; //+0xfc4 252 | 253 | union 254 | { 255 | USHORT CrossTebFlags; //+0xfc8 256 | struct 257 | { 258 | USHORT SpareCrossTebBits:16; 259 | }; 260 | }; 261 | 262 | union 263 | { 264 | USHORT SameTebFlags; //+0xfca 265 | struct 266 | { 267 | USHORT SafeThunkCall:1; //XP Teb+0xFB4 268 | USHORT InDebugPrint:1; 269 | USHORT HasFiberData:1; //XP Teb+0xF76 270 | USHORT SkipThreadAttach:1; 271 | USHORT WerInShipAssertCode:1; 272 | USHORT RanProcessInit:1; 273 | USHORT ClonedThread:1; 274 | USHORT SuppressDebugMsg:1; 275 | USHORT DisableUserStackWalk:1; 276 | USHORT RtlExceptionAttached:1; 277 | USHORT InitialThread:1; 278 | USHORT SpareSameTebBits:5; 279 | }; 280 | }; 281 | 282 | PVOID TxnScopeEnterCallback; //+0xfcc 283 | PVOID TxnScopeExitCallback; //+0xfd0 284 | PVOID TxnScopeContext; //+0xfd4 285 | ULONG LockCount; //+0xfd8 286 | ULONG SpareUlong0; //+0xfdc 287 | PVOID ResourceRetValue; //+0xfe0 288 | } TEB; 289 | 290 | typedef struct _INITIAL_TEB { 291 | struct 292 | { 293 | PVOID OldStackBase; 294 | PVOID OldStackLimit; 295 | } OldInitialTeb; 296 | PVOID StackBase; 297 | PVOID StackLimit; 298 | PVOID StackAllocationBase; 299 | } INITIAL_TEB, *PINITIAL_TEB; 300 | 301 | typedef enum _PROCESSINFOCLASS { 302 | ProcessThreadStackAllocation = 41, 303 | } PROCESSINFOCLASS; 304 | 305 | typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION 306 | { 307 | ULONG ReserveSize; 308 | ULONG ZeroBits; 309 | PVOID StackBase; 310 | } PROCESS_STACK_ALLOCATION_INFORMATION; 311 | 312 | typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX 313 | { 314 | ULONG ExtraType; 315 | ULONG Zero1; 316 | ULONG Zero2; 317 | ULONG Zero3; 318 | PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo; 319 | } PROCESS_STACK_ALLOCATION_INFORMATION_EX; 320 | 321 | typedef struct _SYSTEM_BASIC_INFORMATION { 322 | ULONG Reserved; 323 | ULONG TimerResolution; 324 | ULONG PageSize; 325 | ULONG NumberOfPhysicalPages; 326 | ULONG LowestPhysicalPageNumber; 327 | ULONG HighestPhysicalPageNumber; 328 | ULONG AllocationGranularity; 329 | ULONG_PTR MinimumUserModeAddress; 330 | ULONG_PTR MaximumUserModeAddress; 331 | ULONG_PTR ActiveProcessorsAffinityMask; 332 | CCHAR NumberOfProcessors; 333 | } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; 334 | 335 | typedef struct _BASE_STATIC_SERVER_DATA 336 | { 337 | //UNICODE_STRING WindowsDirectory; //+0 338 | //UNICODE_STRING WindowsSystemDirectory; //+8 339 | //UNICODE_STRING NamedObjectDirectory; //+10 340 | //USHORT WindowsMajorVersion; //+18 341 | //USHORT WindowsMinorVersion; //+1A 342 | //USHORT BuildNumber; //+1C 343 | //USHORT CSDNumber; //+1E 344 | //USHORT RCNumber; //+20 345 | //WCHAR CSDVersion[128]; //+22 346 | SYSTEM_BASIC_INFORMATION SysInfo; //+124 347 | //ULONG Reserved; //+124 348 | //ULONG TimerResolution; //+128 349 | //ULONG PageSize; //+12C 350 | //ULONG NumberOfPhysicalPages; //+130 351 | //ULONG LowestPhysicalPageNumber; //+134 352 | //ULONG HighestPhysicalPageNumber; //+138 353 | //ULONG AllocationGranularity; //+13C 354 | //ULONG_PTR MinimumUserModeAddress; //+140 355 | //ULONG_PTR MaximumUserModeAddress; //+144 356 | //ULONG_PTR ActiveProcessorsAffinityMask; //+148 357 | //CCHAR NumberOfProcessors; //+14C 358 | //+150 359 | //SYSTEM_TIMEOFDAY_INFORMATION TimeOfDay; 360 | //PVOID IniFileMapping; 361 | //NLS_USER_INFO NlsUserInfo; 362 | //BOOLEAN DefaultSeparateVDM; 363 | //BOOLEAN IsWowTaskReady; 364 | //UNICODE_STRING WindowsSys32x86Directory; 365 | //BOOLEAN fTermsrvAppInstallMode; 366 | //TIME_ZONE_INFORMATION tziTermsrvClientTimeZone; 367 | //KSYSTEM_TIME ktTermsrvClientBias; 368 | //ULONG TermsrvClientTimeZoneId; 369 | //BOOLEAN LUIDDeviceMapsEnabled; 370 | //ULONG TermsrvClientTimeZoneChangeNum; 371 | } BASE_STATIC_SERVER_DATA, *PBASE_STATIC_SERVER_DATA; 372 | 373 | typedef struct _EXCEPTION_REGISTRATION_RECORD 374 | { 375 | _EXCEPTION_REGISTRATION_RECORD* Next; 376 | EXCEPTION_DISPOSITION* Handler; 377 | } EXCEPTION_REGISTRATION_RECORD; 378 | 379 | extern "C" 380 | { 381 | PVOID NTAPI 382 | RtlAllocateHeap( 383 | IN PVOID HeapHandle, 384 | IN ULONG Flags, 385 | IN SIZE_T Size 386 | ); 387 | 388 | BOOLEAN NTAPI 389 | RtlFreeHeap( 390 | IN PVOID HeapHandle, 391 | IN ULONG Flags, 392 | IN PVOID HeapBase 393 | ); 394 | 395 | NTSTATUS NTAPI 396 | NtAllocateVirtualMemory( 397 | __in HANDLE ProcessHandle, 398 | __inout PVOID *BaseAddress, 399 | __in ULONG_PTR ZeroBits, 400 | __inout PSIZE_T RegionSize, 401 | __in ULONG AllocationType, 402 | __in ULONG Protect 403 | ); 404 | 405 | NTSTATUS NTAPI 406 | NtFreeVirtualMemory( 407 | __in HANDLE ProcessHandle, 408 | __inout PVOID *BaseAddress, 409 | __inout PSIZE_T RegionSize, 410 | __in ULONG FreeType 411 | ); 412 | 413 | NTSTATUS NTAPI NtProtectVirtualMemory( 414 | __in HANDLE ProcessHandle, 415 | __inout PVOID * BaseAddress, 416 | __inout PSIZE_T RegionSize, 417 | __in ULONG NewProtectWin32, 418 | __out PULONG OldProtect 419 | ); 420 | 421 | NTSTATUS NTAPI 422 | NtSetInformationProcess( 423 | IN HANDLE ProcessHandle, 424 | IN PROCESSINFOCLASS ProcessInformationClass, 425 | IN PVOID ProcessInformation, 426 | IN ULONG ProcessInformationLength 427 | ); 428 | 429 | VOID NTAPI 430 | RtlInitializeBitMap( 431 | IN PRTL_BITMAP BitMapHeader, 432 | IN PULONG BitMapBuffer, 433 | IN ULONG SizeOfBitMap 434 | ); 435 | 436 | VOID NTAPI 437 | RtlSetBits( 438 | IN PRTL_BITMAP BitMapHeader, 439 | IN ULONG StartingIndex, 440 | IN ULONG NumberToSet 441 | ); 442 | 443 | VOID NTAPI 444 | RtlClearBits( 445 | IN PRTL_BITMAP BitMapHeader, 446 | IN ULONG StartingIndex, 447 | IN ULONG NumberToClear 448 | ); 449 | 450 | ULONG NTAPI 451 | RtlFindClearBitsAndSet( 452 | IN PRTL_BITMAP BitMapHeader, 453 | IN ULONG NumberToFind, 454 | IN ULONG HintIndex 455 | ); 456 | 457 | BOOLEAN NTAPI 458 | RtlAreBitsSet( 459 | IN PRTL_BITMAP BitMapHeader, 460 | IN ULONG StartingIndex, 461 | IN ULONG Length 462 | ); 463 | 464 | PVOID NTAPI RtlDecodePointer(PVOID Ptr); 465 | LONG NTAPI RtlUnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInformation); 466 | VOID NTAPI RtlSetLastWin32Error(DWORD Win32ErrorCode); 467 | ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status); 468 | PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(PVOID ImageBase); 469 | VOID NTAPI RtlInitializeSRWLock(RTL_SRWLOCK* SRWLock); 470 | VOID NTAPI RtlAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock); 471 | VOID NTAPI RtlReleaseSRWLockExclusive(RTL_SRWLOCK* SRWLock); 472 | VOID NTAPI RtlAcquireSRWLockShared(RTL_SRWLOCK* SRWLock); 473 | VOID NTAPI RtlReleaseSRWLockShared(RTL_SRWLOCK* SRWLock); 474 | }; 475 | 476 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 477 | #define RtlGetProcessHeap() (NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap) 478 | 479 | extern DWORD BaseDllTag; 480 | extern BASE_STATIC_SERVER_DATA* BaseStaticServerData; 481 | 482 | //XP有 Win7有 483 | DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus); 484 | 485 | //XP没有 Win7有 486 | VOID NTAPI RtlInitializeExceptionChain(EXCEPTION_REGISTRATION_RECORD* ExceptionRegistrationRecord); 487 | 488 | //XP没有 Win7有(未导出) 489 | VOID NTAPI RtlpInitializeActivationContextStack(ACTIVATION_CONTEXT_STACK* ActivationContextStack); 490 | //XP没有 Win7有 491 | NTSTATUS NTAPI RtlAllocateActivationContextStack(ACTIVATION_CONTEXT_STACK** ActivationContextStackOut); 492 | //XP没有 Win7有 493 | VOID NTAPI RtlFreeActivationContextStack(ACTIVATION_CONTEXT_STACK* ActivationContextStack); 494 | //XP有 Win7有 495 | VOID NTAPI RtlReleaseActivationContext(PVOID ActivationContext); 496 | //XP没有 Win7有(未导出) 497 | VOID NTAPI RtlpFreeActivationContextStackFrame(ACTIVATION_CONTEXT_STACK* ActivationContextStack,RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame); 498 | 499 | //XP没有 Win7有 500 | NTSTATUS NTAPI RtlCreateUserStack(ULONG StackCommitSize,ULONG StackReserveSize,ULONG ZeroBits,ULONG CommitAlign,ULONG ReserveAlign,INITIAL_TEB* InitialTeb); 501 | //XP没有 Win7有 502 | VOID NTAPI RtlFreeUserStack(PVOID Address); 503 | //XP有 Win7有 504 | NTSTATUS NTAPI RtlExitUserThread(ULONG ExitCode); -------------------------------------------------------------------------------- /study/fiber_support_w7.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "fiber_def_w7.h" 3 | 4 | DWORD BaseDllTag=0; 5 | BASE_STATIC_SERVER_DATA* BaseStaticServerData=NULL; 6 | ULONG RtlpProcessECVDisabled=0xFFFFFFFF; 7 | PVOID RtlpUnhandledExceptionFilter=NULL; 8 | 9 | typedef LONG (NTAPI*FN_RtlUnhandledExceptionFilter)(EXCEPTION_POINTERS*); 10 | 11 | EXCEPTION_REGISTRATION_RECORD* NTAPI RtlpGetRegistrationHead() 12 | { 13 | return NtCurrentTeb()->NtTib.ExceptionList; 14 | } 15 | 16 | PVOID NTAPI RtlpGetExceptionFilter() 17 | { 18 | PVOID fnRtlUnhandledExceptionFilter=RtlDecodePointer(RtlpUnhandledExceptionFilter); 19 | if (fnRtlUnhandledExceptionFilter==NULL) 20 | fnRtlUnhandledExceptionFilter=(PVOID)RtlUnhandledExceptionFilter; 21 | return fnRtlUnhandledExceptionFilter; 22 | } 23 | 24 | BOOL NTAPI FinalExceptionHandler(EXCEPTION_RECORD* ExceptionRecord,EXCEPTION_REGISTRATION_RECORD* RegistrationRecord,CONTEXT* ContextRecord,PVOID Unknown) 25 | { 26 | BOOL Result=TRUE; 27 | EXCEPTION_POINTERS ExceptionInformation; 28 | if (RegistrationRecord==RtlpGetRegistrationHead()) 29 | { 30 | ExceptionInformation.ExceptionRecord=ExceptionRecord; 31 | ExceptionInformation.ContextRecord=ContextRecord; 32 | FN_RtlUnhandledExceptionFilter fnRtlUnhandledExceptionFilter=(FN_RtlUnhandledExceptionFilter)RtlpGetExceptionFilter(); 33 | if (fnRtlUnhandledExceptionFilter(&ExceptionInformation)==0xFFFFFFFF) 34 | Result=FALSE; 35 | } 36 | return Result; 37 | } 38 | 39 | VOID NTAPI RtlInitializeExceptionChain(EXCEPTION_REGISTRATION_RECORD* ExceptionRegistrationRecord) 40 | { 41 | if (RtlpProcessECVDisabled!=1) 42 | { 43 | ExceptionRegistrationRecord->Next=(EXCEPTION_REGISTRATION_RECORD*)0xFFFFFFFF; 44 | ExceptionRegistrationRecord->Handler=(EXCEPTION_DISPOSITION*)FinalExceptionHandler; 45 | TEB* Teb=NtCurrentTeb(); 46 | if (Teb->NtTib.ExceptionList==(EXCEPTION_REGISTRATION_RECORD*)0xFFFFFFFF) 47 | { 48 | Teb->NtTib.ExceptionList=ExceptionRegistrationRecord; 49 | Teb->RtlExceptionAttached=TRUE; 50 | } 51 | } 52 | } 53 | 54 | VOID NTAPI RtlpInitializeActivationContextStack(ACTIVATION_CONTEXT_STACK* ActivationContextStack) 55 | { 56 | ActivationContextStack->Flags=0; 57 | ActivationContextStack->ActiveFrame=NULL; 58 | LIST_ENTRY* ListHead=&(ActivationContextStack->FrameListCache); 59 | ListHead->Blink=ListHead; 60 | ListHead->Flink=ListHead; 61 | ActivationContextStack->NextCookieSequenceNumber=1; 62 | ActivationContextStack->StackId=GetTickCount(); 63 | } 64 | 65 | NTSTATUS NTAPI RtlAllocateActivationContextStack(ACTIVATION_CONTEXT_STACK** ActivationContextStackOut) 66 | { 67 | if (*ActivationContextStackOut!=NULL) 68 | return STATUS_SUCCESS; 69 | ACTIVATION_CONTEXT_STACK* ActivationContextStack=(ACTIVATION_CONTEXT_STACK*) 70 | RtlAllocateHeap(RtlGetProcessHeap(),0,sizeof(ACTIVATION_CONTEXT_STACK)); 71 | if (ActivationContextStack==NULL) 72 | return STATUS_NO_MEMORY; 73 | RtlpInitializeActivationContextStack(ActivationContextStack); 74 | *ActivationContextStackOut=ActivationContextStack; 75 | return STATUS_SUCCESS; 76 | } 77 | 78 | VOID NTAPI RtlFreeActivationContextStack(ACTIVATION_CONTEXT_STACK* ActivationContextStack) 79 | { 80 | if (ActivationContextStack==NULL) 81 | return ; 82 | RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame=ActivationContextStack->ActiveFrame; 83 | if (ActiveFrame!=NULL) 84 | { 85 | do 86 | { 87 | RTL_ACTIVATION_CONTEXT_STACK_FRAME* PreviousActiveFrame=ActiveFrame->Previous; 88 | if (ActiveFrame->Flags&1) 89 | RtlReleaseActivationContext(ActiveFrame->ActivationContext); 90 | if (ActiveFrame->Flags&8) 91 | RtlpFreeActivationContextStackFrame(ActivationContextStack,ActiveFrame); 92 | ActiveFrame=PreviousActiveFrame; 93 | } while (ActiveFrame!=NULL); 94 | } 95 | ActivationContextStack->ActiveFrame=NULL; 96 | 97 | LIST_ENTRY* CacheHead=&ActivationContextStack->FrameListCache; 98 | LIST_ENTRY* CacheEntry=CacheHead->Flink; 99 | if (CacheEntry!=CacheHead) 100 | { 101 | do 102 | { 103 | BYTE* CacheBody=(BYTE*)CacheEntry-8; //CONTAINING_RECORD 104 | LIST_ENTRY* NextEntry=CacheEntry->Flink; 105 | LIST_ENTRY* BackEntry=CacheEntry->Blink; 106 | BackEntry->Flink=NextEntry; 107 | NextEntry->Blink=BackEntry; 108 | RtlFreeHeap(RtlGetProcessHeap(),0,CacheBody); 109 | CacheEntry=NextEntry; 110 | } while (CacheEntry!=CacheHead); 111 | } 112 | RtlFreeHeap(RtlGetProcessHeap(),0,ActivationContextStack); 113 | } 114 | 115 | VOID NTAPI RtlReleaseActivationContext(PVOID ActivationContext) 116 | { 117 | //ACTIVATION_CONTEXT* ActivationContext; 118 | 119 | //XP 120 | //RtlpUninitializeAssemblyStorageMap 121 | //RtlFreeHeap 122 | 123 | //Win7 124 | //g_SxsTrackReleaseStacks 125 | //RtlCaptureStackBackTrace 126 | //g_SxsKeepActivationContextsAlive 127 | //RtlpFreeActivationContext 128 | //RtlpMoveActCtxToFreeList 129 | } 130 | 131 | VOID NTAPI RtlpFreeActivationContextStackFrame(ACTIVATION_CONTEXT_STACK* ActivationContextStack,RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame) 132 | { 133 | //显然,它和RtlpAllocateActivationContextStackFrame和RtlpInitializeActivationContextStackFrameList是一起的 134 | //ActivationContextStack->FrameListCache的结构无从得知 135 | 136 | //RtlRaiseException 137 | //RtlFreeHeap 138 | } 139 | 140 | 141 | /* 142 | //loc_83E1ED4E: 143 | NTSTATUS NTAPI NtSetInformationProcess41(HANDLE ProcessHandle,PROCESSINFOCLASS ProcessInformationClass,PVOID ProcessInformation,ULONG ProcessInformationLength) 144 | { 145 | if (ProcessInformationClass!=ProcessThreadStackAllocation) 146 | return STATUS_INVALID_INFO_CLASS; 147 | 148 | //HANDLE var_34=ProcessHandle; 149 | //PVOID var_38=ProcessInformation; 150 | //PROCESSINFOCLASS var_edx=ProcessInformationClass; 151 | KPROCESSOR_MODE PreviousMode=KeGetCurrentThread()->PreviousMode; //KTHREAD 152 | 153 | if (ProcessHandle!=(HANDLE)0xFFFFFFFF) 154 | return STATUS_INVALID_PARAMETER; 155 | 156 | PROCESS_STACK_ALLOCATION_INFORMATION* Info; //esi 157 | PROCESS_STACK_ALLOCATION_INFORMATION_EX* InfoEx; //esi 158 | PROCESS_STACK_ALLOCATION_INFORMATION_EX InfoExDup; //var_220 159 | PVOID* StackBase=NULL; //var_50 160 | ULONG ExtraType; //edi 161 | 162 | if (ProcessInformationLength==sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX)) 163 | { 164 | InfoEx=(PROCESS_STACK_ALLOCATION_INFORMATION_EX*)ProcessInformation; 165 | if (PreviousMode==UserMode) 166 | { 167 | __try 168 | { 169 | memcpy(&InfoExDup,InfoEx,sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX)); 170 | } 171 | __except(EXCEPTION_EXECUTE_HANDLER) 172 | { 173 | return GetExceptionCode(); 174 | } 175 | StackBase=&InfoEx->AllocInfo.StackBase; 176 | InfoEx=&InfoExDup; 177 | } 178 | ExtraType=InfoEx->ExtraType; 179 | if (ExtraType>0x10 || (InfoEx->Zero1|InfoEx->Zero2|InfoEx->Zero3)!=0) 180 | return STATUS_INVALID_PARAMETER; 181 | Info=&InfoEx->AllocInfo; 182 | } 183 | else if (ProcessInformationLength==sizeof(PROCESS_STACK_ALLOCATION_INFORMATION)) 184 | { 185 | ExtraType=0; 186 | Info=(PROCESS_STACK_ALLOCATION_INFORMATION*)ProcessInformation; 187 | if (PreviousMode==UserMode) 188 | { 189 | __try 190 | { 191 | InfoExDup.AllocInfo.ReserveSize=Info->ReserveSize;; 192 | InfoExDup.AllocInfo.ZeroBits=Info->ZeroBits; 193 | } 194 | __except(EXCEPTION_EXECUTE_HANDLER) 195 | { 196 | return GetExceptionCode(); 197 | } 198 | StackBase=&Info->StackBase; 199 | Info=&InfoExDup.AllocInfo; 200 | } 201 | } 202 | else 203 | { 204 | return STATUS_INFO_LENGTH_MISMATCH; 205 | } 206 | 207 | if (Info->ReserveSize==0) 208 | return STATUS_INVALID_PARAMETER; 209 | 210 | LARGE_INTEGER CurrentTime; 211 | KeQuerySystemTime(&CurrentTime); 212 | ULONG64 tc=__rdtsc(); 213 | ULONG Adjust=((tc+CurrentTime.QuadPart)&0x1F)+1; //var_4C 214 | ULONG AllocationSize=Info->ReserveSize; //var_160 215 | 216 | NTSTATUS Result; 217 | PKTHREAD Thread=KeGetCurrentThread(); 218 | PKPROCESS Process=Thread->ApcState.Process; 219 | if (Process->Flags2&0x20000) //StackRandomizationDisabled 220 | { 221 | Result=STATUS_UNSUCCESSFUL; 222 | } 223 | else if (Info->ZeroBits!=0 && Info->ZeroBits>21) 224 | { 225 | Result=STATUS_UNSUCCESSFUL; 226 | } 227 | else 228 | { 229 | //如果条件允许,寻找一块合适的区域,返回地址,以此地址为基分配内存 230 | Result=MiScanUserAddressSpace(0,AllocationSize,Adjust,Info->ZeroBits,&Info->StackBase); //fastcall 231 | if (NT_SUCCESS(Result)) 232 | Result=ZwAllocateVirtualMemory((HANDLE)0xFFFFFFFF,&Info->StackBase,Info->ZeroBits,&Info->ReserveSize,ExtraType|MEM_RESERVE,PAGE_READWRITE); 233 | } 234 | 235 | //如果出现错误,随便分配一块内存 236 | if (!NT_SUCCESS(Result)) 237 | { 238 | Info->StackBase=NULL; 239 | Result=ZwAllocateVirtualMemory((HANDLE)0xFFFFFFFF,&Info->StackBase,Info->ZeroBits,&AllocationSize,ExtraType|MEM_RESERVE,PAGE_READWRITE); 240 | } 241 | 242 | if (NT_SUCCESS(Result)) 243 | { 244 | if (PreviousMode==UserMode) 245 | { 246 | __try 247 | { 248 | *StackBase=Info->StackBase; 249 | } 250 | __except(EXCEPTION_EXECUTE_HANDLER) 251 | { 252 | return GetExceptionCode(); 253 | } 254 | } 255 | } 256 | return Result; 257 | } 258 | */ 259 | 260 | NTSTATUS NTAPI RtlCreateUserStack(ULONG StackCommitSize,ULONG StackReserveSize,ULONG ZeroBits,ULONG CommitAlign,ULONG ReserveAlign,INITIAL_TEB* InitialTeb) 261 | { 262 | //应该是这个函数可以接受ExtraType,而不是BaseStaticServerData->SysInfo.PageSize自带 263 | BYTE ExtraType=(CommitAlign>>24)&0xFF; //var_19 264 | CommitAlign=CommitAlign&0x00FFFFFF; //ebx 265 | if (ExtraType>0x10) 266 | return STATUS_INVALID_PARAMETER; 267 | if (CommitAlign==0) 268 | return STATUS_INVALID_PARAMETER; 269 | if (ReserveAlign==0) 270 | return STATUS_INVALID_PARAMETER; 271 | if (ReserveAlignProcessEnvironmentBlock; //var_3C 276 | NTSTATUS Result; //var_24 277 | if (StackCommitSize==0 || StackReserveSize==0) //edi, esi 278 | { 279 | ULONG var_34; 280 | ULONG var_38; 281 | Result=STATUS_SUCCESS; 282 | __try 283 | { 284 | IMAGE_NT_HEADERS* ImageHeader=RtlImageNtHeader(Peb->ImageBaseAddress); 285 | if (ImageHeader==NULL) 286 | { 287 | Result=STATUS_INVALID_IMAGE_FORMAT; 288 | } 289 | else 290 | { 291 | var_34=ImageHeader->OptionalHeader.SizeOfStackCommit; 292 | var_38=ImageHeader->OptionalHeader.SizeOfStackReserve; 293 | } 294 | } 295 | __except(EXCEPTION_CONTINUE_SEARCH) 296 | { 297 | Result=GetExceptionCode(); 298 | } 299 | if (!NT_SUCCESS(Result)) 300 | return Result; 301 | if (StackCommitSize==0) 302 | StackCommitSize=var_34; 303 | if (StackReserveSize==0) 304 | StackReserveSize=var_38; 305 | } 306 | if (StackCommitSize==0) 307 | StackCommitSize=16*1024; 308 | if (StackCommitSize>=StackReserveSize) 309 | StackReserveSize=(StackCommitSize+0x000FFFFF)&0xFFF00000; 310 | 311 | StackCommitSize=StackCommitSize+CommitAlign-1; 312 | StackCommitSize=StackCommitSize & ~(CommitAlign-1); 313 | 314 | StackReserveSize=StackReserveSize+ReserveAlign-1; 315 | StackReserveSize=StackReserveSize & ~(ReserveAlign-1); 316 | 317 | ULONG MinimumStackCommit; //var_48 318 | __try 319 | { 320 | MinimumStackCommit=Peb->MinimumStackCommit; 321 | } 322 | __except(EXCEPTION_CONTINUE_SEARCH) 323 | { 324 | return GetExceptionCode(); 325 | } 326 | if (MinimumStackCommit!=0 && StackCommitSizeOldInitialTeb.OldStackBase=NULL; 350 | InitialTeb->OldInitialTeb.OldStackLimit=NULL; 351 | //分配内存指针,从低地址到高地址 352 | InitialTeb->StackAllocationBase=StackAllocationInfo.AllocInfo.StackBase; 353 | //栈内存指针,从高地址到低地址 354 | InitialTeb->StackBase=(UCHAR*)StackAllocationInfo.AllocInfo.StackBase+StackReserveSize; 355 | 356 | //可以只提交一部分内存用做栈,剩下部分不实际使用 357 | PVOID CommitAddress=(UCHAR*)StackAllocationInfo.AllocInfo.StackBase+StackReserveSize-StackCommitSize; 358 | BOOL IsProtect; 359 | if (StackReserveSize-StackCommitSizeStackAllocationBase); 373 | return Result; 374 | } 375 | 376 | InitialTeb->StackLimit=CommitAddress; 377 | if (IsProtect) 378 | { 379 | ULONG OldProtect; 380 | ULONG ProtectSize=GuardSize; 381 | Result=NtProtectVirtualMemory((HANDLE)0xFFFFFFFF,&CommitAddress,&ProtectSize,PAGE_GUARD|PAGE_READWRITE,&OldProtect); 382 | if (!NT_SUCCESS(Result)) 383 | { 384 | RtlFreeUserStack(InitialTeb->StackAllocationBase); 385 | return Result; 386 | } 387 | //设为PAGE_GUARD的部分不能使用 388 | InitialTeb->StackLimit=(UCHAR*)InitialTeb->StackLimit+ProtectSize; 389 | } 390 | return STATUS_SUCCESS; 391 | } 392 | 393 | VOID NTAPI RtlFreeUserStack(PVOID Address) 394 | { 395 | ULONG FreeSize=0; 396 | NtFreeVirtualMemory((HANDLE)0xFFFFFFFF,&Address,&FreeSize,MEM_RELEASE); 397 | } 398 | 399 | VOID NTAPI LdrShutdownThread() 400 | { 401 | /* 402 | FLS_DATA_INFO* FlsData=NtCurrentTeb()->FlsData; 403 | if (FlsData!=NULL) 404 | RtlProcessFlsData(FlsData);*/ 405 | 406 | //RtlIsCurrentThreadAttachExempt 407 | //RtlEnterCriticalSection 408 | //LdrpImageHasTls 409 | //RtlActivateActivationContextUnsafeFast 410 | //LdrpCallTlsInitializers 411 | //LdrpCallInitRoutine 412 | //RtlDeactivateActivationContextUnsafeFast 413 | //RtlLeaveCriticalSection 414 | //LdrpFreeTls 415 | //RtlFreeHeap 416 | //RtlFreeThreadActivationContextStack 417 | } 418 | 419 | VOID NTAPI LdrShutdownProcess() 420 | { 421 | /* 422 | FLS_DATA_INFO* FlsData=NtCurrentTeb()->FlsData; 423 | if (FlsData!=NULL) 424 | RtlProcessFlsData(FlsData);*/ 425 | 426 | //LdrpLogDbgPrint 427 | //RtlDecodeSystemPointer 428 | //RtlEnterCriticalSection 429 | //RtlpHeapIsLocked 430 | //RtlpInitializeActivationContextStack 431 | //RtlpInitializeActivationContextStackFrameList 432 | //LdrpImageHasTls 433 | //RtlActivateActivationContextUnsafeFast 434 | //LdrpCallTlsInitializers 435 | //LdrpCallInitRoutine 436 | //RtlDeactivateActivationContextUnsafeFast 437 | //SbtLogExeTerminating 438 | //RtlDetectHeapLeaks 439 | //SbCleanupTrace 440 | //EtwShutdownProcess 441 | //RtlLeaveCriticalSection 442 | } 443 | 444 | NTSTATUS NTAPI RtlExitUserThread(ULONG ExitCode) 445 | { 446 | //XP 447 | //LdrShutdownThread 448 | //NtTerminateThread 449 | 450 | //Win7 451 | /* 452 | ULONG IsLastThread=FALSE; 453 | NTSTATUS Result=NtQueryInformationThread(NtCurrentThread(),ThreadAmILastThread,&IsLastThread,4); 454 | if (!NT_SUCCESS(Result) || IsLastThread==FALSE) 455 | { 456 | LdrShutdownThread(); 457 | TpCheckTerminateWorker(NULL); 458 | NtTerminateThread((HANDLE)0,ExitCode); 459 | } 460 | RtlExitUserProcess(ExitStatus); 461 | */ 462 | _asm int 3; 463 | return STATUS_SUCCESS; 464 | } 465 | 466 | NTSTATUS NTAPI RtlExitUserProcess(NTSTATUS ExitStatus) 467 | { 468 | /* 469 | EtwShutdownProcess(0); 470 | RtlEnterCriticalSection(&LdrpLoaderLock); 471 | RtlEnterCriticalSection(&FastPebLock); 472 | RtlLockHeap(RtlGetProcessHeap()); 473 | ExitStatus=NtTerminateProcess((HANDLE)0,ExitStatus); 474 | RtlUnlockHeap(RtlGetProcessHeap()); 475 | RtlLeaveCriticalSection(&FastPebLock); 476 | RtlLeaveCriticalSection(&LdrpLoaderLock); 477 | if (NT_SUCCESS(ExitStatus)) 478 | { 479 | RtlReportSilentProcessExit(NtCurrentProcess(),ExitStatus); 480 | LdrShutdownProcess(); 481 | NtTerminateProcess(NtCurrentProcess(),ExitStatus); 482 | } 483 | else 484 | { 485 | NterminateThread(NtCurrentThread(),ExitStatus); 486 | } 487 | */ 488 | return STATUS_SUCCESS; 489 | } 490 | 491 | DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus) 492 | { 493 | //xpext的所有函数使用xpext.BaseSetLastNTError 494 | //相比kernel32.BaseSetLastNTError,可以转换的Status更全 495 | DWORD dwWin32Error=RtlNtStatusToDosError(NtStatus); 496 | //XP在此处使用KERNEL32.SetLastError,而Win7使用NTDLL.RtlSetLastWin32Error 497 | //原因参见xpext.RtlSetLastWin32Error,这里统一使用xpext.RtlSetLastWin32Error 498 | RtlSetLastWin32Error(dwWin32Error); 499 | return dwWin32Error; 500 | } -------------------------------------------------------------------------------- /study/srw_cv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroclear/xpext/9b5c2edbdadcd416989612fd72c72fbaa802b3eb/study/srw_cv.png -------------------------------------------------------------------------------- /xpext_ver3/common.h: -------------------------------------------------------------------------------- 1 |  2 | #include "nt_def.h" 3 | #include 4 | 5 | #define XPEXT_INTERNAL 6 | #define XPEXT_EXTERNAL 7 | #define XPEXT_UNIMPLEMENT 8 | 9 | //main.cpp - init and hardcode 10 | //utility.cpp - custom function 11 | extern HANDLE GlobalKeyedEventHandle; 12 | extern BYTE* LdrpShutdownInProgress; //pointer 13 | extern DWORD* BaseDllTag; //pointer 14 | 15 | HANDLE NTAPI OpenGlobalKeyedEvent(); 16 | void NTAPI CloseGlobalKeyedEvent(HANDLE hKeyedEvent); 17 | PVOID WINAPI FindDllBase(WCHAR* szName); 18 | //void SetReplaceHook(); 19 | //void RecoverReplaceHook(); 20 | //void SetFilterHook(); 21 | //void RecoverFilterHook(); 22 | 23 | 24 | //nt_privilege.cpp 25 | XPEXT_INTERNAL NTSTATUS NTAPI RtlpOpenThreadToken(ACCESS_MASK DesiredAccess,PHANDLE TokenHandle); 26 | XPEXT_EXTERNAL NTSTATUS NTAPI RtlAcquirePrivilege(PULONG Privilege,ULONG NumPriv,ULONG Flags,PVOID *ReturnedState); 27 | XPEXT_EXTERNAL VOID NTAPI RtlReleasePrivilege(PVOID ReturnedState); 28 | 29 | //nt_errorcode.cpp 30 | XPEXT_EXTERNAL ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status); 31 | XPEXT_EXTERNAL ULONG NTAPI RtlNtStatusToDosErrorNoTeb(NTSTATUS StatusCode); 32 | 33 | //nt_miscellaneous.cpp 34 | XPEXT_INTERNAL BOOL NTAPI RtlpWaitCouldDeadlock(); 35 | XPEXT_INTERNAL void NTAPI RtlBackoff(DWORD* pCount); 36 | XPEXT_INTERNAL BOOL NTAPI RtlIsAnyDebuggerPresent(); 37 | XPEXT_INTERNAL int NTAPI RtlpTerminateFailureFilter(NTSTATUS ExceptionCode,EXCEPTION_POINTERS* ms_exc_ptr); 38 | XPEXT_INTERNAL void NTAPI RtlReportCriticalFailure(DWORD ExceptionCode,ULONG_PTR ExceptionParam1); 39 | XPEXT_EXTERNAL void NTAPI RtlSetLastWin32Error(DWORD Win32ErrorCode); 40 | XPEXT_EXTERNAL NTSTATUS NTAPI RtlInitAnsiStringEx(PANSI_STRING DestinationString,PCSTR szSourceString); 41 | 42 | //nk_criticalsection.cpp 43 | BOOL WINAPI K32InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags); 44 | 45 | typedef struct _SYNCITEM 46 | { 47 | _SYNCITEM* back; //上个插入的节点 48 | _SYNCITEM* first; //第一个插入的节点 49 | _SYNCITEM* next; //下个插入的节点 50 | DWORD count; //共享计数 51 | DWORD attr; //节点属性 52 | RTL_SRWLOCK* lock; 53 | } SYNCITEM; 54 | 55 | typedef size_t SYNCSTATUS; 56 | 57 | //M-mask F-flag SYNC-common 58 | #define SYNC_Exclusive 1 //当前是独占锁在等待,而不是共享锁 59 | #define SYNC_Spinning 2 //当前线程即将休眠,而不是休眠中或唤醒后 60 | #define SYNC_SharedLock 4 //条件变量使用共享锁等待,而不是独占锁 61 | 62 | #define SRWM_FLAG 0x0000000F 63 | #define SRWM_ITEM 0xFFFFFFF0 //64位系统应该改成0xFFFFFFFFFFFFFFF0 64 | #define SRWM_COUNT SRWM_ITEM 65 | 66 | #define SRWF_Free 0 //空闲 67 | #define SRWF_Hold 1 //有线程拥有了锁 68 | #define SRWF_Wait 2 //有线程正在等待 69 | #define SRWF_Link 4 //修改链表的操作进行中 70 | #define SRWF_Many 8 //独占请求之前有多个共享锁并存 71 | 72 | #define CVM_COUNT 0x00000007 73 | #define CVM_FLAG 0x0000000F 74 | #define CVM_ITEM 0xFFFFFFF0 75 | 76 | #define CVF_Full 7 //唤醒申请已满,全部唤醒 77 | #define CVF_Link 8 //修改链表的操作进行中 78 | 79 | #define SRW_COUNT_BIT 4 80 | #define SRW_HOLD_BIT 0 81 | #define SYNC_SPIN_BIT 1 //从0开始数 82 | 83 | //nt_srwlock.cpp 84 | XPEXT_INTERNAL void NTAPI RtlpInitSRWLock(PEB* pPEB); 85 | XPEXT_EXTERNAL void NTAPI RtlInitializeSRWLock(RTL_SRWLOCK* SRWLock); 86 | XPEXT_INTERNAL void NTAPI RtlpWakeSRWLock(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus); 87 | XPEXT_INTERNAL void NTAPI RtlpOptimizeSRWLockList(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus); 88 | XPEXT_EXTERNAL void NTAPI RtlAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock); 89 | XPEXT_EXTERNAL void NTAPI RtlAcquireSRWLockShared(RTL_SRWLOCK* SRWLock); 90 | XPEXT_EXTERNAL void NTAPI RtlReleaseSRWLockExclusive(RTL_SRWLOCK* SRWLock); 91 | XPEXT_EXTERNAL void NTAPI RtlReleaseSRWLockShared(RTL_SRWLOCK* SRWLock); 92 | XPEXT_EXTERNAL BOOL NTAPI RtlTryAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock); 93 | XPEXT_EXTERNAL BOOL NTAPI RtlTryAcquireSRWLockShared(RTL_SRWLOCK* SRWLock); 94 | 95 | //nk_conditionvariable.cpp 96 | XPEXT_INTERNAL void NTAPI RtlpInitConditionVariable(PEB* pPeb); 97 | XPEXT_EXTERNAL void NTAPI RtlInitializeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 98 | XPEXT_INTERNAL BOOL NTAPI RtlpQueueWaitBlockToSRWLock(SYNCITEM* Item,RTL_SRWLOCK* SRWLock,BOOL IsSharedLock); 99 | XPEXT_INTERNAL void NTAPI RtlpWakeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCSTATUS OldStatus,int WakeCount); 100 | XPEXT_INTERNAL BOOL NTAPI RtlpWakeSingle(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCITEM* Item); 101 | XPEXT_INTERNAL void NTAPI RtlpOptimizeConditionVariableWaitList(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCSTATUS OldStatus); 102 | XPEXT_INTERNAL NTSTATUS NTAPI RtlSleepConditionVariableCS(RTL_CONDITION_VARIABLE* ConditionVariable,RTL_CRITICAL_SECTION* CriticalSection,LARGE_INTEGER* Timeout); 103 | XPEXT_INTERNAL NTSTATUS NTAPI RtlSleepConditionVariableSRW(RTL_CONDITION_VARIABLE* ConditionVariable,RTL_SRWLOCK* SRWLock,LARGE_INTEGER* Timeout,ULONG Flags); 104 | XPEXT_EXTERNAL void NTAPI RtlWakeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 105 | XPEXT_EXTERNAL void NTAPI RtlWakeAllConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 106 | XPEXT_EXTERNAL BOOL WINAPI K32SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable,PCRITICAL_SECTION CriticalSection,DWORD dwMilliseconds); 107 | XPEXT_EXTERNAL BOOL WINAPI K32SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable,PSRWLOCK SRWLock,DWORD dwMilliseconds,ULONG Flags); 108 | 109 | typedef struct _RUNONCEITEM 110 | { 111 | _RUNONCEITEM* next; 112 | } RUNONCEITEM; 113 | 114 | typedef size_t RUNONCESTATUS; 115 | 116 | #define RUNONCEM_ITEM 0xFFFFFFFC 117 | #define RUNONCEM_FLAG 0x00000003 118 | 119 | //注意,RUNONCESTATUS里的FLAG和参数里的Flags是两回事 120 | //参数里的Flags是操作选项,这个FLAG是RunOnce对象的状态 121 | #define RUNONCEF_NoRequest 0 122 | #define RUNONCEF_SyncPend 1 123 | #define RUNONCEF_Complete 2 124 | #define RUNONCEF_AsyncPend 3 125 | 126 | //nk_runonce.cpp 127 | XPEXT_INTERNAL RUNONCESTATUS NTAPI RtlpRunOnceWaitForInit(RUNONCESTATUS OldStatus,RTL_RUN_ONCE* RunOnce); 128 | XPEXT_INTERNAL void NTAPI RtlpRunOnceWakeAll(RTL_RUN_ONCE* RunOnce); 129 | XPEXT_EXTERNAL void NTAPI RtlRunOnceInitialize2(RTL_RUN_ONCE* RunOnce); 130 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceBeginInitialize2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID* Context); 131 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceComplete2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID Context); 132 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceExecuteOnce2(RTL_RUN_ONCE* RunOnce,RTL_RUN_ONCE_INIT_FN InitFn,PVOID Parameter,PVOID* Context); 133 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce,DWORD dwFlags,PBOOL fPending,LPVOID* lpContext); 134 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceExecuteOnce(LPINIT_ONCE lpInitOnce,PINIT_ONCE_FN InitFn,LPVOID lpParameter,LPVOID* lpContext); 135 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceComplete(LPINIT_ONCE lpInitOnce,DWORD dwFlags,LPVOID lpContext); 136 | 137 | //k32_processthread.cpp 138 | XPEXT_EXTERNAL DWORD WINAPI K32GetThreadId(HANDLE Thread); 139 | XPEXT_EXTERNAL DWORD WINAPI K32GetProcessId(HANDLE Process); 140 | XPEXT_EXTERNAL DWORD WINAPI K32GetProcessIdOfThread(HANDLE Thread); 141 | XPEXT_EXTERNAL void WINAPI K32DeleteProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); 142 | XPEXT_UNIMPLEMENT BOOL WINAPI K32InitializeProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwAttributeCount,DWORD dwFlags,PSIZE_T lpSize); 143 | XPEXT_UNIMPLEMENT BOOL WINAPI K32UpdateProcThreadAttribute(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwFlags, 144 | DWORD_PTR Attribute,PVOID lpValue,SIZE_T cbSize,PVOID lpPreviousValue,PSIZE_T lpReturnSize); 145 | 146 | //k32_processor.cpp 147 | XPEXT_EXTERNAL WORD WINAPI K32GetActiveProcessorGroupCount(); 148 | XPEXT_EXTERNAL WORD WINAPI K32GetMaximumProcessorGroupCount(); 149 | XPEXT_EXTERNAL DWORD WINAPI K32GetActiveProcessorCount(WORD GroupNumber); 150 | XPEXT_EXTERNAL DWORD WINAPI K32GetMaximumProcessorCount(WORD GroupNumber); 151 | XPEXT_EXTERNAL DWORD WINAPI RtlGetCurrentProcessorNumber(); 152 | XPEXT_EXTERNAL void WINAPI RtlGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER ProcNumber); 153 | 154 | //k32_miscellaneous.cpp 155 | XPEXT_EXTERNAL ULONGLONG WINAPI K32GetTickCount64(); 156 | XPEXT_EXTERNAL VOID WINAPI K32RaiseFailFastException(PEXCEPTION_RECORD pExceptionRecord,PCONTEXT pContextRecord,DWORD dwFlags); 157 | XPEXT_INTERNAL DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus); 158 | XPEXT_INTERNAL LARGE_INTEGER* WINAPI BaseFormatTimeOut(LARGE_INTEGER* pTimeOut,DWORD dwMilliseconds); 159 | 160 | //k32_file.cpp 161 | XPEXT_EXTERNAL BOOL WINAPI K32GetFileInformationByHandleEx(HANDLE hFile,FILE_INFO_BY_HANDLE_CLASS InformationByHandleClass,LPVOID lpFileInformation,DWORD dwBufferSize); 162 | XPEXT_INTERNAL BOOL WINAPI Win32Rename(HANDLE hFile,LPVOID lpFileInformation,DWORD dwBufferSize); 163 | XPEXT_EXTERNAL BOOL WINAPI K32SetFileInformationByHandle(HANDLE hFile,FILE_INFO_BY_HANDLE_CLASS InformationByHandleClass,LPVOID lpFileInformation,DWORD dwBufferSize); 164 | XPEXT_INTERNAL BOOL WINAPI BasepGetObjectNTName(HANDLE hFile,LPWSTR* pszNameOut); 165 | XPEXT_INTERNAL BOOL WINAPI BasepGetFileNameInformation(HANDLE hFile,FILE_INFORMATION_CLASS FileInformationClass,LPWSTR* pszNameOut); 166 | XPEXT_INTERNAL BOOL WINAPI BasepGetVolumeDosLetterNameFromNTName(WCHAR* NTName,LPWSTR* pszNameOut); 167 | XPEXT_INTERNAL BOOL WINAPI BasepGetVolumeGUIDFromNTName(WCHAR* NTName,LPWSTR* pszNameOut); 168 | XPEXT_EXTERNAL DWORD WINAPI K32GetFinalPathNameByHandleW(HANDLE hFile,LPWSTR lpszFilePath,DWORD cchFilePath,DWORD dwFlags); 169 | XPEXT_EXTERNAL DWORD WINAPI K32GetFinalPathNameByHandleA(HANDLE hFile,LPSTR lpszFilePath,DWORD cchFilePath,DWORD dwFlags); 170 | XPEXT_INTERNAL WCHAR* WINAPI GetFullPath(LPCWSTR lpFileName); 171 | XPEXT_EXTERNAL BOOLEAN WINAPI K32CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName,LPCWSTR lpTargetFileName,DWORD dwFlags); 172 | XPEXT_INTERNAL BOOL WINAPI Basep8BitStringToDynamicUnicodeString(UNICODE_STRING* OutUnicode,LPCSTR InputAnsi); 173 | XPEXT_EXTERNAL BOOLEAN WINAPI K32CreateSymbolicLinkA(LPCSTR lpSymlinkFileName,LPCSTR lpTargetFileName,DWORD dwFlags); 174 | 175 | 176 | -------------------------------------------------------------------------------- /xpext_ver3/k32_miscellaneous.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | typedef unsigned __int64 QWORD; 5 | 6 | /* 7 | 系统开机到现在的时间=系统开机到现在的tick数*一个tick持续的时间 8 | 一个tick持续的时间可能不是整数,所以用TickCountMultiplier和Divisor联合表示 9 | 在我的XP上,TickCountMultiplier为0x0FA00000,Divisor则为固定的0x01000000,即15.625ms 10 | 因此GetTickCount的返回值总是15.625的倍数,这就是MSDN上说的误差的原因 11 | 12 | GetTickCount返回的毫秒数上限为0xFFFFFFFF,约等于49.7天,但实际的计算结果可以多一些 13 | 以每个tick持续15.625毫秒为例,可以算出最大776.7天,接近36位,把这个值按__int64返回,可以满足大多数需求 14 | 实际上,一个tick持续的时间理论上是8位(Multiplier为32位,Divisor为24位) 15 | 假如Windows把一个tick的持续时间拉满(我是说假如,这种情况不可能出现),算出来的时间上限是40位 16 | 17 | 尽管如此,我还是没选择这个方案,而是在xpextk.sys里模仿Win7的做法,真正更新了KUserSharedData::TickCount 18 | 19 | DWORD WINAPI GetTickCount_XP() 20 | { 21 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 22 | QWORD TickCount=KUserSharedData->TickCountLow*KUserSharedData->TickCountMultiplier; 23 | return (DWORD)(TickCount>>24); 24 | } 25 | 26 | DWORD WINAPI GetTickCount_Win7x32() 27 | { 28 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 29 | while (KUserSharedData->TickCount.High1Time!=KUserSharedData->TickCount.High2Time) //同步 30 | _mm_pause(); 31 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 32 | //High1Time是高32位,计算前应该先左移32位,但是后面tick转单位要右移24位,合起来就是左移8位 33 | //DWORD HighPart=(KUserSharedData->TickCount.High1Time<<32)*KUserSharedData->TickCountMultiplier>>24; 34 | DWORD HighPart=(KUserSharedData->TickCount.High1Time<<8)*KUserSharedData->TickCountMultiplier; 35 | return (DWORD)LowPart+HighPart; 36 | } 37 | 38 | ULONGLONG WINAPI GetTickCount64_Win7x32() 39 | { 40 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 41 | while (KUserSharedData->TickCount.High1Time!=KUserSharedData->TickCount.High2Time) 42 | _mm_pause(); 43 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 44 | QWORD HighPart=KUserSharedData->TickCount.High1Time*KUserSharedData->TickCountMultiplier; 45 | HighPart=HighPart*0x100; //乘0x100等价于左移8位,原汇编调用了ntdll._allmul() 46 | return HighPart+LowPart; 47 | } 48 | 49 | ULONGLONG WINAPI GetTickCount64_Win7x64() 50 | { 51 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 52 | QWORD TickCount=*(QWORD*)&KUserSharedData->TickCount; 53 | QWORD HighPart=(TickCount>>32)*KUserSharedData->TickCountMultiplier<<8; 54 | QWORD LowPart=(DWORD)TickCount*KUserSharedData->TickCountMultiplier>>24; 55 | return HighPart+LowPart; 56 | } 57 | */ 58 | 59 | //需要xpextk.sys支持 60 | ULONGLONG WINAPI K32GetTickCount64() 61 | { 62 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 63 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 64 | QWORD HighPart=KUserSharedData->TickCount.High1Time*KUserSharedData->TickCountMultiplier<<8; 65 | return LowPart+HighPart; 66 | } 67 | 68 | //UINT GetErrorMode(); 69 | //GetErrorMode=0x7C80ACDD 70 | //导出就可以了 71 | 72 | VOID WINAPI K32RaiseFailFastException(PEXCEPTION_RECORD pExceptionRecord,PCONTEXT pContextRecord,DWORD dwFlags) 73 | { 74 | EXCEPTION_RECORD ExceptionRecord; 75 | CONTEXT ContextRecord; 76 | DWORD MessageBoxResult; 77 | DWORD ReturnAddress; 78 | //参数1在栈上的地址是ebp+8,这个位置再-4就是函数返回地址在栈中的位置 79 | ReturnAddress=*((DWORD*)&pExceptionRecord-1); 80 | 81 | if (pExceptionRecord==NULL) 82 | { 83 | memset(&ExceptionRecord,0,sizeof(EXCEPTION_RECORD)); //sizeof(EXCEPTION_RECORD)==80 84 | ExceptionRecord.ExceptionCode=STATUS_FAIL_FAST_EXCEPTION; 85 | ExceptionRecord.ExceptionFlags=EXCEPTION_NONCONTINUABLE; 86 | ExceptionRecord.ExceptionAddress=(PVOID)ReturnAddress; //[ebp+4] 87 | pExceptionRecord=&ExceptionRecord; 88 | } 89 | else 90 | { 91 | pExceptionRecord->ExceptionFlags|=EXCEPTION_NONCONTINUABLE; 92 | if (dwFlags&FAIL_FAST_GENERATE_EXCEPTION_ADDRESS) 93 | pExceptionRecord->ExceptionAddress=(PVOID)ReturnAddress; 94 | } 95 | 96 | if (pContextRecord==NULL) 97 | { 98 | memset(&ContextRecord,0,sizeof(CONTEXT)); //sizeof(CONTEXT)==0x2CC 99 | RtlCaptureContext(&ContextRecord); 100 | pContextRecord=&ContextRecord; 101 | } 102 | 103 | /* 104 | //这个函数调用了EtwEventWriteNoRegistration,GUID是{E46EEAD8-0C54-4489-9898-8FA79D059E0E} 105 | NTSTATUS Result=SignalStartWerSvc(); 106 | if (NT_SUCCESS(Result)) 107 | { 108 | //这个函数调用了NtWaitForSingleObject,Event是"\\KernelObjects\\SystemErrorPortReady" 109 | Result=WaitForWerSvc(); 110 | if (NT_SUCCESS(Result) && Result!=STATUS_TIMEOUT) 111 | { 112 | if (*(BYTE*)0x7FFE02F0==1) //KUSER_SHARED_DATA::DbgErrorPortPresent 113 | { 114 | NtRaiseException(pExceptionRecord,pContextRecord,FALSE); 115 | return ; 116 | } 117 | } 118 | } 119 | */ 120 | 121 | if (!(dwFlags&FAIL_FAST_NO_HARD_ERROR_DLG)) 122 | NtRaiseHardError(pExceptionRecord->ExceptionCode|0x10000000,0,0,0,1,&MessageBoxResult); 123 | TerminateProcess(GetCurrentProcess(),pExceptionRecord->ExceptionCode); 124 | } 125 | 126 | 127 | DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus) 128 | { 129 | //xpext的所有函数使用xpext.BaseSetLastNTError 130 | //相比kernel32.BaseSetLastNTError,可以转换的Status更全 131 | DWORD dwWin32Error=RtlNtStatusToDosError(NtStatus); 132 | //XP在此处使用KERNEL32.SetLastError,而Win7使用NTDLL.RtlSetLastWin32Error 133 | //原因参见xpext.RtlSetLastWin32Error,这里统一使用xpext.RtlSetLastWin32Error 134 | RtlSetLastWin32Error(dwWin32Error); 135 | return dwWin32Error; 136 | } 137 | 138 | LARGE_INTEGER* WINAPI BaseFormatTimeOut(LARGE_INTEGER* pTimeOut,DWORD dwMilliseconds) 139 | { 140 | if (dwMilliseconds==INFINITE) 141 | return NULL; 142 | pTimeOut->QuadPart=-10000*dwMilliseconds; 143 | return pTimeOut; 144 | } -------------------------------------------------------------------------------- /xpext_ver3/k32_processor.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | 现代操作系统拥有设备热插拔的能力(plug and play),可以在运行时动态配置硬件 6 | 其中就包括CPU核心的增加和移除,禁用和启用 7 | 因此,系统启动时检测到的最大CPU个数,并不一定是绝对的上限 8 | 也不一定是现存的CPU个数,也不一定是可用的CPU个数,这些都可能在运行时变化 9 | Win7对此提供了一定的支持,预留一些空间,在CPU可用核心增加时更新ActiveCount 10 | 而XP完全不支持,它的CPU核心总数=最大数量=可用数量 11 | 12 | 可以通过设置CPU亲和性(affinity)让线程只运行在指定的核心上 13 | Windows使用一个DWORD_PTR表示核心的掩码,如二进制00000010仅允许运行在第1个核心上 14 | 而00001101表示允许运行在核心0、核心2和核心3上,这是一种高效实用的方案 15 | 但在32位系统上DWORD_PTR仅能表示32个核心,64位系统上也只能表示64个核心 16 | 为了解决这一问题,引入了CPU组的设定,将64个CPU核心编成一组,以组号+索引确定CPU 17 | 32位的和Win7以前的操作系统不支持CPU组,默认使用第0组,最多32个或64个核心 18 | 就此衍生出一批能指定CPU组的API,但旧API仍然兼容,只能操作默认的第0组 19 | 20 | SetThreadGroupAffinity 21 | GetThreadGroupAffinity 22 | GetProcessGroupAffinity 23 | GetLogicalProcessorInformation 24 | GetLogicalProcessorInformationEx 25 | NtQuerySystemInformationEx 26 | ... 27 | */ 28 | 29 | WORD WINAPI K32GetActiveProcessorGroupCount() 30 | { 31 | return 1; 32 | } 33 | 34 | WORD WINAPI K32GetMaximumProcessorGroupCount() 35 | { 36 | return 1; 37 | } 38 | 39 | DWORD WINAPI K32GetActiveProcessorCount(WORD GroupNumber) 40 | { 41 | if (GroupNumber!=0) 42 | return 0; 43 | SYSTEM_BASIC_INFORMATION SysInfo; 44 | NTSTATUS Result=NtQuerySystemInformation(SystemBasicInformation,&SysInfo,sizeof(SysInfo),NULL); 45 | if (!NT_SUCCESS(Result)) 46 | return 0; 47 | DWORD CoreCount=0; 48 | for (int i=0;i<32;i++) 49 | { 50 | CoreCount+=(SysInfo.ActiveProcessorsAffinityMask&1); 51 | SysInfo.ActiveProcessorsAffinityMask>>=1; 52 | } 53 | return CoreCount; 54 | } 55 | 56 | DWORD WINAPI K32GetMaximumProcessorCount(WORD GroupNumber) 57 | { 58 | if (GroupNumber!=0) 59 | return 0; 60 | SYSTEM_BASIC_INFORMATION SysInfo; 61 | NTSTATUS Result=NtQuerySystemInformation(SystemBasicInformation,&SysInfo,sizeof(SysInfo),NULL); 62 | if (!NT_SUCCESS(Result)) 63 | return 0; 64 | return SysInfo.NumberOfProcessors; 65 | } 66 | 67 | //需要xpextk.sys支持 68 | //编号被设置在GDT的第8项的14到19位上,在Ring3用lsl指令读取 69 | //0x3B:索引=7,表=GDT,RPL=Ring3 70 | _declspec(naked) 71 | DWORD WINAPI RtlGetCurrentProcessorNumber() 72 | { 73 | _asm 74 | { 75 | mov ecx, 0x3B; 76 | lsl eax, ecx; 77 | shr eax, 0x0E; 78 | retn ; 79 | } 80 | } 81 | 82 | _declspec(naked) 83 | void WINAPI RtlGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER ProcNumber) 84 | { 85 | _asm 86 | { 87 | mov edi, edi; 88 | push ebp; 89 | mov ebp, esp; 90 | mov edx, dword ptr ss:[ebp+8]; //ProcNumber 91 | xor eax, eax; 92 | mov [edx], ax; //ProcNumber->Group 93 | mov ecx, 0x3B; 94 | lsl eax, ecx; 95 | shr eax, 0x0E; 96 | mov [edx+2], al; //ProcNumber->Number 97 | mov byte ptr [edx+3], 0; //ProcNumber->Reserved 98 | pop ebp; 99 | retn 4; 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /xpext_ver3/k32_processthread.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | DWORD WINAPI K32GetThreadId(HANDLE Thread) 5 | { 6 | THREAD_BASIC_INFORMATION ThreadInformation; 7 | NTSTATUS Result=NtQueryInformationThread(Thread,ThreadBasicInformation,&ThreadInformation,sizeof(ThreadInformation),NULL); 8 | if (!NT_SUCCESS(Result)) 9 | { 10 | BaseSetLastNTError(Result); 11 | return 0; 12 | } 13 | return (DWORD)ThreadInformation.ClientId.UniqueThread; 14 | } 15 | 16 | DWORD WINAPI K32GetProcessId(HANDLE Process) 17 | { 18 | PROCESS_BASIC_INFORMATION ProcessInformation; 19 | NTSTATUS Result=NtQueryInformationProcess(Process,ProcessBasicInformation,&ProcessInformation,sizeof(ProcessInformation),NULL); 20 | if (!NT_SUCCESS(Result)) 21 | { 22 | BaseSetLastNTError(Result); 23 | return 0; 24 | } 25 | return (DWORD)ProcessInformation.UniqueProcessId; 26 | } 27 | 28 | DWORD WINAPI K32GetProcessIdOfThread(HANDLE Thread) 29 | { 30 | THREAD_BASIC_INFORMATION ThreadInformation; 31 | NTSTATUS Result=NtQueryInformationThread(Thread,ThreadBasicInformation,&ThreadInformation,sizeof(ThreadInformation),NULL); 32 | if (!NT_SUCCESS(Result)) 33 | { 34 | BaseSetLastNTError(Result); 35 | return 0; 36 | } 37 | return (DWORD)ThreadInformation.ClientId.UniqueProcess; 38 | } 39 | 40 | void WINAPI K32DeleteProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) 41 | { 42 | //原函数真的什么都没做 43 | return ; 44 | } 45 | 46 | BOOL WINAPI K32InitializeProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwAttributeCount,DWORD dwFlags,PSIZE_T lpSize) 47 | { 48 | 49 | return TRUE; 50 | } 51 | 52 | BOOL WINAPI K32UpdateProcThreadAttribute(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwFlags, 53 | DWORD_PTR Attribute,PVOID lpValue,SIZE_T cbSize,PVOID lpPreviousValue,PSIZE_T lpReturnSize) 54 | { 55 | 56 | return TRUE; 57 | } -------------------------------------------------------------------------------- /xpext_ver3/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | #pragma comment(lib,"E:\\WDK\\lib\\wxp\\i386\\ntdll.lib") 4 | 5 | //发布时记得注明系统dll版本,每个版本的dll偏移都不一样 6 | #define BASE_NT 0x7C920000 7 | #define BASE_K32 0x7C800000 8 | 9 | //进程退出时,将此值设为TRUE,阻止退出期间进行的各种新建行为 10 | BYTE* LdrpShutdownInProgress; 11 | //由RtlCreateTagHeap创建的堆,用来分配临时数据 12 | //BaseDllTag=RtlCreateTagHeap(HeapHandle,0,"BASEDLL!","TMP"); 13 | //Win7中,此标记移至KernelBaseGlobalData+0x2c处 14 | DWORD* BaseDllTag; 15 | //XP的KeyedEvent需要用到句柄,出于各种考虑,这里用一个新的 16 | HANDLE GlobalKeyedEventHandle; 17 | 18 | void XPEXT_InitDll() 19 | { 20 | DWORD dwNtBaseNow=(DWORD)FindDllBase(L"ntdll.dll"); 21 | LdrpShutdownInProgress=(BYTE*)(0x7C99B0C4-BASE_NT+dwNtBaseNow); 22 | DWORD dwK32BaseNow=(DWORD)FindDllBase(L"kernel32.dll"); 23 | BaseDllTag=(DWORD*)(0x7C8856D4-BASE_K32+dwK32BaseNow); 24 | GlobalKeyedEventHandle=OpenGlobalKeyedEvent(); 25 | RtlpInitSRWLock(NtCurrentTeb()->ProcessEnvironmentBlock); 26 | RtlpInitConditionVariable(NtCurrentTeb()->ProcessEnvironmentBlock); 27 | } 28 | 29 | void XPEXT_UninitDll() 30 | { 31 | CloseGlobalKeyedEvent(GlobalKeyedEventHandle); 32 | } 33 | 34 | BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) 35 | { 36 | switch (fdwReason) 37 | { 38 | case DLL_PROCESS_ATTACH: 39 | OutputDebugString(L"xpext loaded: ver 1.0\r\n"); 40 | XPEXT_InitDll(); 41 | break; 42 | case DLL_PROCESS_DETACH: 43 | XPEXT_UninitDll(); 44 | OutputDebugString(L"xpext unload: ver 1.0\r\n"); 45 | break; 46 | case DLL_THREAD_ATTACH: 47 | break; 48 | case DLL_THREAD_DETACH: 49 | break; 50 | } 51 | return TRUE; 52 | } -------------------------------------------------------------------------------- /xpext_ver3/nk_criticalsection.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | NTSTATUS NTAPI RtlInitializeCriticalSectionExW7(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags) 6 | { 7 | DWORD& RtlFailedCriticalDebugAllocations=*(DWORD*)0x77F9CCA8; 8 | CRITICAL_SECTION& RtlCriticalSectionLock=*(CRITICAL_SECTION*)0x77F97118; 9 | LIST_ENTRY& RtlCriticalSectionList=*(LIST_ENTRY*)0x77F97560; 10 | 11 | if (Flags&RTL_CRITICAL_SECTION_FLAG_RESERVED) 12 | return STATUS_INVALID_PARAMETER_3; 13 | if (dwSpinCount&0xFF000000!=0) //dwSpinCount>0x00FFFFFF 14 | return STATUS_INVALID_PARAMETER_2; 15 | 16 | if (Flags&RTL_CRITICAL_SECTION_FLAG_STATIC_INIT) 17 | return STATUS_SUCCESS; 18 | 19 | lpCriticalSection->LockCount=-1; 20 | lpCriticalSection->RecursionCount=0; 21 | lpCriticalSection->OwningThread=NULL; 22 | lpCriticalSection->LockSemaphore=NULL; 23 | 24 | if (GetNumberOfProcessors()>1) 25 | { 26 | if (Flags&RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN) 27 | lpCriticalSection->SpinCount=dwSpinCount&0x00FFFFFF; 28 | //在Win7里,CRITICAL_SECTION::SpinCount前面几位可以带额外的标记,但XP不支持 29 | else 30 | lpCriticalSection->SpinCount=0x020007D0; 31 | } 32 | else 33 | { 34 | lpCriticalSection->SpinCount=0; 35 | } 36 | 37 | if (Flags&RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) 38 | { 39 | lpCriticalSection->DebugInfo=(PRTL_CRITICAL_SECTION_DEBUG)-1; 40 | } 41 | else 42 | { 43 | PRTL_CRITICAL_SECTION_DEBUG info=RtlpAllocateDebugInfo(); 44 | if (info==NULL) 45 | { 46 | lpCriticalSection->DebugInfo=(PRTL_CRITICAL_SECTION_DEBUG)-1; 47 | _InterlockedAdd(&RtlFailedCriticalDebugAllocations,1); 48 | } 49 | else 50 | { 51 | lpCriticalSection->DebugInfo=info; 52 | info->Type=RTL_CRITSECT_TYPE; 53 | info->ContentionCount=0; 54 | info->EntryCount=0; 55 | info->CriticalSection=lpCriticalSection; 56 | info->Flags=0; 57 | DWORD dwIndex=RtlLogStackBackTraceEx(1); 58 | info->CreatorBackTraceIndex=LOWORD(dwIndex); 59 | info->CreatorBackTraceIndexHigh=HIWORD(dwIndex); 60 | 61 | RtlEnterCriticalSection(&RtlCriticalSectionLock); 62 | LIST_ENTRY* pCur=&info->ProcessLocksList; 63 | pCur->Flink=&RtlCriticalSectionList; 64 | pCur->Blink=RtlCriticalSectionList.Blink; 65 | RtlCriticalSectionList.Blink->Flink=pCur; 66 | RtlCriticalSectionList.Blink=pCur; 67 | RtlLeaveCriticalSection(&RtlCriticalSectionLock); 68 | } 69 | } 70 | 71 | //这段代码不仅XP里没有,在Win7里我也不知道它是什么意思 72 | //KUSER_SHARED_DATA::UserModeGlobalLogger[1] 73 | HANDLE TraceHandle=(HANDLE)*(BYTE*)0x7FFE0382; 74 | if (TraceHandle!=NULL) 75 | { 76 | //PEB::TracingFlags.CritSecTracingEnabled 77 | if (GetPEB()->TracingFlags&2) 78 | { 79 | struct TRACEDATA 80 | { 81 | BYTE d1[6]; 82 | WORD d2; 83 | BYTE d3[24]; 84 | DWORD d4; 85 | DWORD d5; 86 | } td; 87 | td.d2=0x1723; 88 | td.d4=lpCriticalSection->SpinCount; 89 | td.d5=(DWORD)lpCriticalSection; 90 | NtTraceEvent(TraceHandle,0x00010402,8,&td); 91 | } 92 | } 93 | 94 | return STATUS_SUCCESS; 95 | } 96 | 97 | NTSTATUS NTAPI RtlInitializeCriticalSectionAndSpinCountXP(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount) 98 | { 99 | HANDLE& GlobalKeyedEventHandle=*(HANDLE*)0x7C99B15C; 100 | CRITICAL_SECTION& RtlCriticalSectionLock=*(CRITICAL_SECTION*)0x7C99B140; 101 | BOOL& RtlpCritSectInitialized=*(BOOL*)0x7C99B160; 102 | LIST_ENTRY& RtlCriticalSectionList=*(LIST_ENTRY*)0x7C99B168; 103 | 104 | lpCriticalSection->LockCount=-1; 105 | lpCriticalSection->RecursionCount=0; 106 | lpCriticalSection->OwningThread=NULL; 107 | lpCriticalSection->LockSemaphore=NULL; 108 | 109 | if (GetNumberOfProcessors()>1) 110 | lpCriticalSection->SpinCount=dwSpinCount&0x00FFFFFF; 111 | else 112 | lpCriticalSection->SpinCount=0; 113 | 114 | if (GlobalKeyedEventHandle==NULL) 115 | { 116 | UNICODE_STRING name; 117 | RtlInitUnicodeString(&name,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 118 | OBJECT_ATTRIBUTES oa; 119 | oa.Length=0x18; 120 | oa.RootDirectory=NULL; 121 | oa.ObjectName=&name; 122 | oa.Attributes=0; 123 | oa.SecurityDescriptor=NULL; 124 | oa.SecurityQualityOfService=NULL; 125 | //借用栈上的空间暂存返回值 126 | NTSTATUS result=NtOpenKeyedEvent((PHANDLE)&lpCriticalSection,0x02000000,&oa); 127 | if (!NT_SUCCESS(result)) 128 | return result; 129 | DWORD old=InterlockedCompareExchange((DWORD*)&GlobalKeyedEventHandle,(DWORD)lpCriticalSection|1,0); 130 | if (old!=0) 131 | NtClose((HANDLE)lpCriticalSection); 132 | } 133 | 134 | PRTL_CRITICAL_SECTION_DEBUG info=RtlpAllocateDebugInfo(); 135 | if (info==NULL) 136 | return STATUS_NO_MEMORY; 137 | info->Type=RTL_CRITSECT_TYPE; 138 | info->ContentionCount=0; 139 | info->EntryCount=0; 140 | info->CriticalSection=lpCriticalSection; 141 | lpCriticalSection->DebugInfo=info; 142 | DWORD dwIndex=RtlLogStackBackTrace(); 143 | info->CreatorBackTraceIndex=LOWORD(dwIndex); 144 | 145 | if (&RtlCriticalSectionLock!=NULL && RtlpCritSectInitialized==TRUE) 146 | { 147 | RtlEnterCriticalSection(&RtlCriticalSectionLock); 148 | LIST_ENTRY* pCur=&info->ProcessLocksList; 149 | pCur->Flink=&RtlCriticalSectionList; 150 | pCur->Blink=RtlCriticalSectionList.Blink; 151 | RtlCriticalSectionList.Blink->Flink=pCur; 152 | RtlCriticalSectionList.Blink=pCur; 153 | RtlLeaveCriticalSection(&RtlCriticalSectionLock); 154 | } 155 | else 156 | { 157 | //进程启动时,会调用RtlInitializeCriticalSectionAndSpinCount初始化RtlCriticalSectionLock 158 | //但是此时RtlCriticalSectionLock还没有初始化成功,于是就有了这段不加锁的代码 159 | LIST_ENTRY* pCur=&info->ProcessLocksList; 160 | pCur->Flink=&RtlCriticalSectionList; 161 | pCur->Blink=RtlCriticalSectionList.Blink; 162 | RtlCriticalSectionList.Blink->Flink=pCur; 163 | RtlCriticalSectionList.Blink=pCur; 164 | } 165 | 166 | return STATUS_SUCCESS; 167 | } 168 | */ 169 | 170 | BOOL WINAPI K32InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags) 171 | { 172 | NTSTATUS RtlStatus=STATUS_SUCCESS; 173 | if (Flags&RTL_CRITICAL_SECTION_FLAG_RESERVED) 174 | RtlStatus=STATUS_INVALID_PARAMETER_3; 175 | if (dwSpinCount&0xFF000000) //dwSpinCount>0x00FFFFFF 176 | RtlStatus=STATUS_INVALID_PARAMETER_2; 177 | if (NT_SUCCESS(RtlStatus)) 178 | { 179 | if (Flags&RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN) 180 | dwSpinCount=dwSpinCount&0x00FFFFFF; 181 | else 182 | dwSpinCount=2000; 183 | //RTL_CRITICAL_SECTION_FLAG_STATIC_INIT的效果是不初始化直接返回 184 | //RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO的效果是不分配DebugInfo的内存 185 | //由于不知道XP是否支持这些行为,稳妥起见不应用标记 186 | RtlStatus=RtlInitializeCriticalSectionAndSpinCount(lpCriticalSection,dwSpinCount); 187 | } 188 | if (NT_SUCCESS(RtlStatus)) 189 | return TRUE; 190 | BaseSetLastNTError(RtlStatus); 191 | return FALSE; 192 | } 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /xpext_ver3/nk_runonce.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | Windows 7 SP1 32位 6.1.7601.17514 6 | @清泠 2021.4.18 7 | 8 | 在kernel32里,这几个函数叫InitOnceXXX 9 | 在ntdll里,这几个函数叫RtlRunOnceXXX 10 | 不知道为什么,winnt.h里定义了RtlRunOnceXXX 11 | 我只好将它们重命名为RtlRunOnceXXX2 12 | 13 | 我认为没个十年脑血栓设计不出来这种接口 14 | 把简单的事情复杂化,提高了学习成本,还不一定好用 15 | 使用这几个函数,要仔细阅读MSDN上的文档,注意其中的各种限制 16 | 17 | 然而这几个函数做的事类似如下伪代码: 18 | 19 | //同步模式 20 | TYPE* g_obj=NULL; 21 | 22 | TYPE* GetObject() 23 | { 24 | EnterLock(); 25 | if (g_obj==NULL) 26 | g_obj=CreateObject(); 27 | LeaveLock(); 28 | return g_obj; 29 | } 30 | 31 | void UseObject() 32 | { 33 | TYPE* obj=GetObject(); 34 | obj->DoWork(); 35 | } 36 | 37 | //异步模式 38 | TYPE* g_obj=NULL; 39 | 40 | TYPE* GetObject() 41 | { 42 | return g_obj; 43 | } 44 | 45 | void UpdateObject() 46 | { 47 | TYPE* obj=CreateObject(); 48 | EnterLock(); 49 | if (g_obj==NULL) 50 | g_obj=obj; 51 | LeaveLock(); 52 | if (g_obj!=obj) 53 | DestroyObject(obj); 54 | } 55 | 56 | void UseObject() 57 | { 58 | TYPE* obj=GetObject(); 59 | if (obj==NULL) 60 | { 61 | UpdateObject(); 62 | obj=GetObject(); 63 | } 64 | obj->DoWork(); 65 | } 66 | 67 | 简单的说,是在多线程环境下创建一个单例对象(Singleton Object) 68 | 如果对象不存在,就新建一个,此后所有线程都用这个对象 69 | 否则,对象已经被其它线程创建,就使用现存的对象 70 | (这里说创建对象只是方便描述,实际上也可以是执行一些初始化代码) 71 | 72 | 这些函数有两种使用模式:同步模式和异步模式 73 | 同步模式下,第一个调用的线程执行创建,随后的线程等待 74 | 第一个线程创建完毕,其它线程被唤醒,取回已创建的对象 75 | 异步模式下,如果对象没有创建,所有线程一起创建对象 76 | 第一个创建完成的线程将对象指针更新,此后所有线程都使用这个对象 77 | 然后晚一步的线程需要销毁自己创建一半的对象 78 | 79 | 其中RtlRunOnceExecuteOnce是同步模式对 80 | RtlRunOnceBeginInitialize和RtlRunOnceComplete的封装 81 | 具体使用方式与我的描述有所差异,可以参考微软给出的使用示例: 82 | https://docs.microsoft.com/en-us/windows/win32/sync/using-one-time-initialization 83 | */ 84 | 85 | RUNONCESTATUS NTAPI RtlpRunOnceWaitForInit(RUNONCESTATUS OldStatus,RTL_RUN_ONCE* RunOnce) 86 | { 87 | //栈上的数据都是按4字节对齐的,不需要__declspec(align(4)) 88 | //因为item在栈上,且大小为4字节,编译器生成汇编时用了个优化 89 | //将OldStatus的值存在ecx里,将栈上的OldStatus的位置拿来当item 90 | RUNONCEITEM item; 91 | //将自己的节点插入链表,并进入等待 92 | //只有同步模式且未完成才需要等待,状态必然为sync+pend 93 | RUNONCESTATUS NewStatus=(((RUNONCESTATUS)&item)&(RUNONCEM_ITEM+RUNONCEF_SyncPend))|RUNONCEF_SyncPend; 94 | do 95 | { 96 | item.next=(RUNONCEITEM*)(OldStatus&RUNONCEM_ITEM); 97 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 98 | if (CurrStatus==OldStatus) 99 | { 100 | //XP不支持第一个参数传入NULL 101 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 102 | CurrStatus=(RUNONCESTATUS)RunOnce->Ptr; 103 | } 104 | OldStatus=CurrStatus; 105 | } while ((OldStatus&RUNONCEM_FLAG)==RUNONCEF_SyncPend); 106 | return OldStatus; 107 | } 108 | 109 | void NTAPI RtlpRunOnceWakeAll(RTL_RUN_ONCE* RunOnce) 110 | { 111 | //唤醒next链上的所有节点 112 | RUNONCEITEM* item=(RUNONCEITEM*)((RUNONCESTATUS)RunOnce->Ptr&RUNONCEM_ITEM); 113 | if (item!=NULL) 114 | { 115 | do 116 | { 117 | //暂存next,防止唤醒后失效 118 | RUNONCEITEM* next=item->next; 119 | //XP不支持第一个参数传入NULL 120 | NtReleaseKeyedEvent(GlobalKeyedEventHandle,item,FALSE,NULL); 121 | item=next; 122 | } while (item!=NULL); 123 | } 124 | } 125 | 126 | //void WINAPI K32InitOnceInitialize(LPINIT_ONCE InitOnce) 127 | void NTAPI RtlRunOnceInitialize2(RTL_RUN_ONCE* RunOnce) 128 | { 129 | RunOnce->Ptr=NULL; 130 | } 131 | 132 | NTSTATUS NTAPI RtlRunOnceBeginInitialize2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID* Context) 133 | { 134 | //Flags仅允许INIT_ONCE_CHECK_ONLY和INIT_ONCE_ASYNC 135 | if ((Flags&~(INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC))!=0) //0xFFFFFFFC 136 | return STATUS_INVALID_PARAMETER_2; 137 | //flags为3时,flags&(flags-1)=3&2=2 138 | //flags为2时,flags&(flags-1)=2&1=0 139 | //flags为1时,flags&(flags-1)=1&0=0 140 | //flags为0时,and必为0 141 | //即不允许两种Flag同时出现 142 | //但MSDN上说This parameter can have a value of 0, or one or more of the following flags. 143 | if (Flags & (Flags-1)) 144 | return STATUS_INVALID_PARAMETER_2; 145 | 146 | RUNONCESTATUS OldStatus=(RUNONCESTATUS)RunOnce->Ptr; 147 | //原汇编用栈上的Flags的位置存储Result 148 | NTSTATUS Result=STATUS_SUCCESS; 149 | //已有线程完成创建,返回现有的 150 | if ((OldStatus&RUNONCEM_FLAG)==RUNONCEF_Complete) 151 | { 152 | //强制更新内存缓存,令其它核心收到结果,避免无谓的等待 153 | //在Win7 x86下是xchg eax, [ebp+arg_0],在x64下是lock or [rsp+0], 0 154 | //这一句没执行实际的更改,别被惯性思维骗了 155 | InterlockedExchange((size_t*)&RunOnce,Flags); 156 | if (Context!=NULL) 157 | *(size_t*)Context=OldStatus&RUNONCEM_ITEM; 158 | return Result; 159 | } 160 | //创建还没完成,取回失败 161 | if (Flags&RTL_RUN_ONCE_CHECK_ONLY) 162 | return STATUS_UNSUCCESSFUL; 163 | 164 | BOOL IsSyncMode=((Flags&RTL_RUN_ONCE_ASYNC)==0); 165 | 166 | while (1) 167 | { 168 | BYTE StatusFlag=OldStatus&RUNONCEM_FLAG; 169 | //自己是第一个调用的线程,根据Flags设置好sync或async,返回pending,允许进行创建 170 | if (StatusFlag==RUNONCEF_NoRequest) 171 | { 172 | //若指定了RTL_RUN_ONCE_ASYNC,设为Async+Pend,否则为Sync+Pend 173 | //这些反复横跳的迷惑行为可能是编译器基于位域生成的 174 | RUNONCESTATUS NewStatus=(((!IsSyncMode)<<1)|RUNONCEF_SyncPend)&RUNONCEM_FLAG; 175 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 176 | if (CurrStatus==OldStatus) 177 | { 178 | Result=STATUS_PENDING; 179 | return Result; 180 | } 181 | OldStatus=CurrStatus; 182 | } 183 | //这一系列调用是sync模式,且已有线程进行创建,等待其完成 184 | //这种情况OldStatus可能含有等待的节点链表 185 | else if (StatusFlag==RUNONCEF_SyncPend) 186 | { 187 | //指定的async模式和之前的sync模式冲突 188 | if (IsSyncMode==FALSE) 189 | { 190 | Result=STATUS_INVALID_PARAMETER_2; 191 | return Result; 192 | } 193 | OldStatus=RtlpRunOnceWaitForInit(OldStatus,RunOnce); 194 | } 195 | //这一系列调用是async模式,返回pending允许进行创建 196 | else if (StatusFlag==RUNONCEF_AsyncPend) 197 | { 198 | //指定的sync模式和之前的async模式冲突 199 | if (IsSyncMode) 200 | Result=STATUS_INVALID_PARAMETER_2; 201 | else 202 | Result=STATUS_PENDING; 203 | return Result; 204 | } 205 | //已有线程完成创建,返回现有的 206 | //这种情况OldStatus含有context 207 | else if (StatusFlag==RUNONCEF_Complete) 208 | { 209 | if (Context!=NULL) 210 | *(size_t*)Context=OldStatus&RUNONCEM_ITEM; 211 | return Result; 212 | } 213 | //不知道为什么,原汇编代码使用OldStatus确定Async+Pend的情况 214 | //if (StatusFlag==RUNONCEF_NoRequest) ... 215 | //else if (StatusFlag==RUNONCEF_SyncPend) ... 216 | //else if (OldStatus==RUNONCEF_AsyncPend) ... 217 | //else ... 218 | //而Complete的情况,由于OldStatus含有context,没法直接比较 219 | //因此在判断完其它3种情况后,放在了else里 220 | } 221 | return Result; 222 | } 223 | 224 | NTSTATUS NTAPI RtlRunOnceComplete2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID Context) 225 | { 226 | //Flags仅允许RTL_RUN_ONCE_ASYNC和RTL_RUN_ONCE_INIT_FAILED 227 | if ((Flags&~(RTL_RUN_ONCE_ASYNC|RTL_RUN_ONCE_INIT_FAILED))!=0) //0xFFFFFFF9 228 | return STATUS_INVALID_PARAMETER_2; 229 | //flags为6时,flags&(flags-1)=6&5=4 230 | //flags为4时,flags&(flags-1)=4&3=0 231 | //flags为2时,flags&(flags-1)=2&1=0 232 | //flags为0时,and必为0 233 | //即不允许两种Flag同时出现 234 | if (Flags & (Flags-1)) 235 | return STATUS_INVALID_PARAMETER_2; 236 | 237 | //原汇编代码是这样的: 238 | //DWORD NewFlags=((~(Flags>>1))^Flags)&3^Flags; 239 | //结构为(target ^ complement) & range ^ complement 240 | //意为以range中为1的位为准,保留target中对应的位, 241 | //剩下的位用complement中对应的位填充 242 | //由于后面的代码只用到最低2位,所以等价于我这几行代码 243 | //我想说,分开用两个变量能死么?看来不仅设计接口的人脑子不正常 244 | //写代码的人也是个脑瘫,或是说他们根本就是一个人? 245 | BOOL IsSuccess=!(Flags&RTL_RUN_ONCE_INIT_FAILED); 246 | BOOL IsSyncMode=!(Flags&RTL_RUN_ONCE_ASYNC); 247 | DWORD NewFlags=(IsSuccess<<1)|IsSyncMode; 248 | 249 | if (Context!=NULL) 250 | { 251 | //失败模式不允许设置Context 252 | if ((NewFlags & 2)==0) 253 | return STATUS_INVALID_PARAMETER_3; 254 | //Context必须DWORD对齐(或空出最后RTL_RUN_ONCE_CTX_RESERVED_BITS位) 255 | if (((size_t)Context & 3)!=0) 256 | return STATUS_INVALID_PARAMETER_3; 257 | } 258 | 259 | RUNONCESTATUS OldStatus=(RUNONCESTATUS)RunOnce->Ptr; 260 | //若是失败模式,NewFlags & 2为0,Context也为0,合成NoRequest状态 261 | //若是成功模式,NewFlags & 2为1,Context是结果,合成Complete状态 262 | RUNONCESTATUS NewStatus=(NewFlags & 2) | (size_t)Context; 263 | 264 | BYTE StatusFlag=OldStatus&RUNONCEM_FLAG; 265 | if (StatusFlag==RUNONCEF_SyncPend) 266 | { 267 | //指定的async模式和之前的sync模式冲突 268 | if ((NewFlags & 1)==0) 269 | return STATUS_INVALID_PARAMETER_2; 270 | RUNONCESTATUS CurrStatus=InterlockedExchange((RUNONCESTATUS*)RunOnce,NewStatus); 271 | //sync模式只能有一个线程操作,其他线程修改状态是出问题了 272 | if ((CurrStatus&RUNONCEM_FLAG)!=RUNONCEF_SyncPend) 273 | return STATUS_INVALID_OWNER; 274 | //借用栈上Flags的空间临时构建了一个RTL_RUN_ONCE 275 | //而在Win7 x64上,编译器直接展开RtlpRunOnceWakeAll,省去了这一步 276 | RTL_RUN_ONCE temp; 277 | temp.Ptr=(PVOID)CurrStatus; 278 | RtlpRunOnceWakeAll(&temp); 279 | return STATUS_SUCCESS; 280 | } 281 | else if (StatusFlag==RUNONCEF_AsyncPend) 282 | { 283 | //指定的sync模式和之前的async模式冲突 284 | if ((NewFlags & 1)!=0) 285 | return STATUS_INVALID_PARAMETER_2; 286 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 287 | //其他线程已经提交成功,使用此结果 288 | if (CurrStatus!=OldStatus) 289 | return STATUS_OBJECT_NAME_COLLISION; 290 | //本线程提交成功 291 | return STATUS_SUCCESS; 292 | } 293 | else 294 | { 295 | //对RUNONCEF_NoRequest来说,禁止不申请直接提交结果 296 | //对RUNONCEF_Complete来说,结果已经提交,不允许覆盖 297 | return STATUS_UNSUCCESSFUL; 298 | } 299 | } 300 | 301 | NTSTATUS NTAPI RtlRunOnceExecuteOnce2(RTL_RUN_ONCE* RunOnce,RTL_RUN_ONCE_INIT_FN InitFn,PVOID Parameter,PVOID* Context) 302 | { 303 | //原汇编代码将栈上的Context的最高字节拿来记录错误信息 304 | BYTE ErrorInfo; 305 | //如果本线程是第一个调用的,返回STATUS_PENDING,允许对象创建 306 | //如果本线程不是第一个调用的,会在函数内等待,直到第一个线程创建完成 307 | NTSTATUS Result=RtlRunOnceBeginInitialize2(RunOnce,0,Context); 308 | if (NT_SUCCESS(Result)) 309 | { 310 | //本线程是第一个线程,调用回调函数创建对象,成功后提交对象指针 311 | if (Result==STATUS_PENDING) 312 | { 313 | if (InitFn(RunOnce,Parameter,Context)==TRUE) 314 | { 315 | //原汇编代码直接使用Context来存储ContextData 316 | PVOID ContextData=NULL; 317 | if (Context!=NULL) 318 | ContextData=*Context; 319 | //创建成功,参数2传入0,将状态设为Complete,并将结果存入status里 320 | Result=RtlRunOnceComplete2(RunOnce,0,ContextData); 321 | if (NT_SUCCESS(Result)) 322 | { 323 | Result=STATUS_SUCCESS; 324 | } 325 | else 326 | { 327 | ErrorInfo=1; 328 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 329 | } 330 | } 331 | else 332 | { 333 | //创建失败,参数2传递RTL_RUN_ONCE_INIT_FAILED 334 | //将导致状态设为NoRequest,并唤醒其它线程 335 | Result=RtlRunOnceComplete2(RunOnce,RTL_RUN_ONCE_INIT_FAILED,NULL); 336 | if (NT_SUCCESS(Result)) 337 | { 338 | Result=STATUS_UNSUCCESSFUL; 339 | } 340 | else 341 | { 342 | ErrorInfo=2; 343 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 344 | } 345 | } 346 | } 347 | else //Result==STATUS_SUCCESS 348 | { 349 | //其它线程已经创建好了对象,放在Context里,返回直接使用 350 | Result=STATUS_SUCCESS; 351 | } 352 | } 353 | else 354 | { 355 | ErrorInfo=0; 356 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 357 | } 358 | return Result; 359 | } 360 | 361 | 362 | BOOL WINAPI K32InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce,DWORD dwFlags,PBOOL fPending,LPVOID* lpContext) 363 | { 364 | NTSTATUS Result=RtlRunOnceBeginInitialize2(lpInitOnce,dwFlags,lpContext); 365 | if (!NT_SUCCESS(Result)) 366 | { 367 | BaseSetLastNTError(Result); 368 | return FALSE; 369 | } 370 | *fPending=(Result==STATUS_PENDING); 371 | return TRUE; 372 | } 373 | 374 | BOOL WINAPI K32InitOnceExecuteOnce(LPINIT_ONCE lpInitOnce,PINIT_ONCE_FN InitFn,LPVOID lpParameter,LPVOID* lpContext) 375 | { 376 | NTSTATUS Result=RtlRunOnceExecuteOnce2(lpInitOnce,(PRTL_RUN_ONCE_INIT_FN)InitFn,lpParameter,lpContext); 377 | //返回值只有两种结果:STATUS_SUCCESS和STATUS_UNSUCCESSFUL 378 | //其余情况全部ZwTerminateProcess,就没必要SetLastError了 379 | return NT_SUCCESS(Result); 380 | } 381 | 382 | BOOL WINAPI K32InitOnceComplete(LPINIT_ONCE lpInitOnce,DWORD dwFlags,LPVOID lpContext) 383 | { 384 | NTSTATUS Result=RtlRunOnceComplete2(lpInitOnce,dwFlags,lpContext); 385 | if (!NT_SUCCESS(Result)) 386 | { 387 | BaseSetLastNTError(Result); 388 | return FALSE; 389 | } 390 | return TRUE; 391 | } -------------------------------------------------------------------------------- /xpext_ver3/nt_miscellaneous.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | BOOL NTAPI RtlpWaitCouldDeadlock() 5 | { 6 | //byte_77F978A8极有可能是LdrpShutdownInProgress 7 | //进程退出时,各种资源即将被销毁,继续等待将会出现错误的结果 8 | return *LdrpShutdownInProgress!=0; 9 | } 10 | 11 | //通过延时来暂时退避竞争 12 | void NTAPI RtlBackoff(DWORD* pCount) 13 | { 14 | DWORD nBackCount=*pCount; 15 | if (nBackCount==0) 16 | { 17 | if (NtCurrentTeb()->ProcessEnvironmentBlock->NumberOfProcessors==1) 18 | return ; 19 | nBackCount=0x40; 20 | nBackCount*=2; 21 | } 22 | else 23 | { 24 | if (nBackCount<0x1FFF) 25 | nBackCount=nBackCount+nBackCount; 26 | } 27 | nBackCount=(__rdtsc()&(nBackCount-1))+nBackCount; 28 | //Win7原代码借用参数来计数,省去局部变量 29 | pCount=0; 30 | while ((DWORD)pCountProcessEnvironmentBlock->BeingDebugged==TRUE) || 41 | ((pKuserSharedData->KdDebuggerEnabled&3)==3); 42 | } 43 | 44 | int NTAPI RtlpTerminateFailureFilter(NTSTATUS ExceptionCode,EXCEPTION_POINTERS* ms_exc_ptr) 45 | { 46 | //这个函数负责向系统报告异常并退出进程,由于太过复杂,这里不使用 47 | //RtlReportException(ms_exc_ptr->ExceptionRecord,ms_exc_ptr->ContextRecord,0); 48 | NtTerminateProcess((HANDLE)0xFFFFFFFF,ExceptionCode); 49 | return EXCEPTION_EXECUTE_HANDLER; 50 | } 51 | 52 | void NTAPI RtlReportCriticalFailure(DWORD ExceptionCode,ULONG_PTR ExceptionParam1) 53 | { 54 | __try 55 | { 56 | if (RtlIsAnyDebuggerPresent()) 57 | { 58 | //DPFLTR_DEFAULT_ID 59 | DbgPrintEx(0x65,0,"Critical error detected %lx\n",ExceptionCode); 60 | _asm int 3; 61 | } 62 | } 63 | __except(RtlpTerminateFailureFilter(GetExceptionCode(),GetExceptionInformation())) 64 | { 65 | return ; 66 | } 67 | EXCEPTION_RECORD ExceptionRecord; 68 | ExceptionRecord.ExceptionCode=ExceptionCode; 69 | ExceptionRecord.ExceptionFlags=EXCEPTION_NONCONTINUABLE; 70 | ExceptionRecord.ExceptionRecord=NULL; 71 | ExceptionRecord.ExceptionAddress=RtlRaiseException; 72 | ExceptionRecord.NumberParameters=1; 73 | ExceptionRecord.ExceptionInformation[0]=ExceptionParam1; 74 | RtlRaiseException(&ExceptionRecord); 75 | } 76 | 77 | /* 78 | Windows XP: 79 | kernel32.SetLastError={BreakPoint}+{LastErrorSet} 80 | kernel32.BaseSetLastNTError=ntdll.RtlNtStatusToDosError+kernel32.SetLastError 81 | sdk.SetLastError=ntdll.RtlRestoreLastWin32Error 82 | ntdll.RtlRestoreLastWin32Error={LastErrorSet} 83 | ntdll.RtlSetLastWin32ErrorAndNtStatusFromNtStatus=ntdll.RtlNtStatusToDosError+{LastErrorSet} 84 | Windows 7: 85 | kernel32.SetLastError=jmp ntdll.RtlRestoreLastWin32Error 86 | kernel32.BaseSetLastNTError=ntdll.RtlNtStatusToDosError+ntdll.RtlSetLastWin32Error 87 | sdk.SetLastError=kernel32.SetLastError 88 | ntdll.RtlSetLastWin32Error=ntdll.RtlRestoreLastWin32Error={BreakPoint}+{LastErrorSet} 89 | ntdll.RtlSetLastWin32ErrorAndNtStatusFromNtStatus=ntdll.RtlNtStatusToDosError+ntdll.RtlSetLastWin32Error 90 | 91 | XP的SetLastError分两种,一种是kernel32内部使用的kernel32.SetLastError,具有断点功能 92 | 另一种是sdk里供开发者使用的,实际是ntdll.RtlRestoreLastWin32Error,没有断点功能 93 | Win7则对此作出了统一,无论什么样的SetLastError,最后都调用ntdll.RtlSetLastWin32Error,总有断点功能 94 | 95 | 本来想模仿Win7,把kernel32.SetLastError给Hook了,令其跳转到我的xpext.RtlSetLastWin32Error 96 | 但是这样只能修改kernel32内部的调用,其它软件对ntdll.RtlRestoreLastWin32Error的调用还是没效果 97 | 更进一步的做法是令kernel32.SetLastError跳转到ntdll.RtlRestoreLastWin32Error 98 | 然后令ntdll.RtlRestoreLastWin32Error跳转到xpext.RtlSetLastWin32Error,统一使用我的函数 99 | 但是仔细想想,就这么个破断点,正常人八辈子用不到,没必要大费周章搞Hook,影响系统稳定性 100 | 最终的决定是,xpext内部的函数使用xpext.RtlSetLastWin32Error,其他软件不做修改,保持原来的调用 101 | */ 102 | 103 | DWORD g_dwLastErrorToBreakOn=0; 104 | 105 | void NTAPI RtlSetLastWin32Error(DWORD Win32ErrorCode) 106 | { 107 | if (g_dwLastErrorToBreakOn!=0 && Win32ErrorCode==g_dwLastErrorToBreakOn) 108 | _asm int 3; 109 | TEB* CurrentTeb=NtCurrentTeb(); 110 | if (CurrentTeb->LastErrorValue!=Win32ErrorCode) //这个判断有意义吗? 111 | CurrentTeb->LastErrorValue=Win32ErrorCode; 112 | } 113 | 114 | NTSTATUS NTAPI RtlInitAnsiStringEx(PANSI_STRING DestinationString,PCSTR szSourceString) 115 | { 116 | DestinationString->Length=0; 117 | DestinationString->MaximumLength=0; 118 | DestinationString->Buffer=(PCHAR)szSourceString; 119 | if (szSourceString==NULL) 120 | return STATUS_SUCCESS; 121 | int Len=strlen(szSourceString); 122 | if (Len>65534) 123 | return STATUS_NAME_TOO_LONG; 124 | DestinationString->Length=Len; 125 | DestinationString->MaximumLength=Len+1; 126 | return STATUS_SUCCESS; 127 | } 128 | -------------------------------------------------------------------------------- /xpext_ver3/nt_privilege.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | extern "C" 5 | { 6 | NTSTATUS NTAPI 7 | NtOpenThreadTokenEx( 8 | IN HANDLE ThreadHandle, 9 | IN ACCESS_MASK DesiredAccess, 10 | IN BOOLEAN OpenAsSelf, 11 | IN ULONG HandleAttributes, 12 | OUT PHANDLE TokenHandle 13 | ); 14 | 15 | NTSTATUS NTAPI 16 | NtOpenProcessTokenEx( 17 | IN HANDLE ProcessHandle, 18 | IN ACCESS_MASK DesiredAccess, 19 | IN ULONG HandleAttributes, 20 | OUT PHANDLE TokenHandle 21 | ); 22 | 23 | NTSTATUS NTAPI 24 | NtAdjustPrivilegesToken ( 25 | IN HANDLE TokenHandle, 26 | IN BOOLEAN DisableAllPrivileges, 27 | IN PTOKEN_PRIVILEGES NewState OPTIONAL, 28 | IN ULONG BufferLength OPTIONAL, 29 | OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, 30 | OUT PULONG ReturnLength 31 | ); 32 | 33 | NTSTATUS NTAPI 34 | NtDuplicateToken( 35 | IN HANDLE ExistingTokenHandle, 36 | IN ACCESS_MASK DesiredAccess, 37 | IN POBJECT_ATTRIBUTES ObjectAttributes, 38 | IN BOOLEAN EffectiveOnly, 39 | IN TOKEN_TYPE TokenType, 40 | OUT PHANDLE NewTokenHandle 41 | ); 42 | }; 43 | 44 | NTSTATUS NTAPI RtlpOpenThreadToken(ACCESS_MASK DesiredAccess,PHANDLE TokenHandle) 45 | { 46 | NTSTATUS Result=NtOpenThreadTokenEx(NtCurrentThread(),DesiredAccess,TRUE,OBJ_KERNEL_HANDLE,TokenHandle); 47 | if (!NT_SUCCESS(Result)) 48 | Result=NtOpenThreadTokenEx(NtCurrentThread(),DesiredAccess,FALSE,OBJ_KERNEL_HANDLE,TokenHandle); 49 | return Result; 50 | } 51 | 52 | enum PRIVILEGE_LUID_INDEX 53 | { 54 | SeCreateTokenPrivilege=2, 55 | SeAssignPrimaryTokenPrivilege=3, 56 | SeLockMemoryPrivilege=4, 57 | SeIncreaseQuotaPrivilege=5, 58 | SeUnsolicitedInputPrivilege=6, //Unsolicited Input is obsolete and unused. 59 | SeMachineAccountPrivilege=6, 60 | SeTcbPrivilege=7, 61 | SeSecurityPrivilege=8, 62 | SeTakeOwnershipPrivilege=9, 63 | SeLoadDriverPrivilege=10, 64 | SeSystemProfilePrivilege=11, 65 | SeSystemtimePrivilege=12, 66 | SeProfileSingleProcessPrivilege=13, 67 | SeIncreaseBasePriorityPrivilege=14, 68 | SeCreatePagefilePrivilege=15, 69 | SeCreatePermanentPrivilege=16, 70 | SeBackupPrivilege=17, 71 | SeRestorePrivilege=18, 72 | SeShutdownPrivilege=19, 73 | SeDebugPrivilege=20, 74 | SeAuditPrivilege=21, 75 | SeSystemEnvironmentPrivilege=22, 76 | SeChangeNotifyPrivilege=23, 77 | SeRemoteShutdownPrivilege=24, 78 | SeUndockPrivilege=25, 79 | SeSyncAgentPrivilege=26, 80 | SeEnableDelegationPrivilege=27, 81 | SeManageVolumePrivilege=28, 82 | SeImpersonatePrivilege=29, 83 | SeCreateGlobalPrivilege=30, 84 | MaxPrivilegeLuidIndex_XP=31, 85 | 86 | SeTrustedCredManAccessPrivilege=31, 87 | SeRelabelPrivilege=32, 88 | SeIncreaseWorkingSetPrivilege=33, 89 | SeTimeZonePrivilege=34, 90 | SeCreateSymbolicLinkPrivilege=35, 91 | MaxPrivilegeLuidIndex_W7=36, 92 | }; 93 | 94 | //RtlAcquirePrivilege和RtlReleasePrivilege大部分照搬了ReactOS的rtltypes.h和priv.c(Latest commit c2c66af on 3 Oct 2017) 95 | //细节有所改动,不同之处以Win7为准(ntdll.dll x86 6.1.7601.17514) 96 | #define RTL_ACQUIRE_PRIVILEGE_IMPERSONATE 1 97 | #define RTL_ACQUIRE_PRIVILEGE_PROCESS 2 98 | 99 | typedef struct _RTL_ACQUIRE_STATE 100 | { 101 | HANDLE Token; 102 | HANDLE OldImpersonationToken; 103 | PTOKEN_PRIVILEGES OldPrivileges; 104 | PTOKEN_PRIVILEGES NewPrivileges; 105 | ULONG Flags; 106 | UCHAR OldPrivBuffer[1024]; 107 | } RTL_ACQUIRE_STATE, *PRTL_ACQUIRE_STATE; 108 | 109 | NTSTATUS 110 | NTAPI 111 | RtlAcquirePrivilege(IN PULONG Privilege, 112 | IN ULONG NumPriv, 113 | IN ULONG Flags, 114 | OUT PVOID *ReturnedState) 115 | { 116 | //ULONG ReturnLength由AdjustSize代替,NTSTATUS IntStatus不用了 117 | //C++03支持循环内定义i,OldSize合并到AdjustSize 118 | PRTL_ACQUIRE_STATE State; 119 | NTSTATUS Status; 120 | //ULONG i, OldSize; 121 | ULONG AdjustSize; 122 | SECURITY_QUALITY_OF_SERVICE Sqos; 123 | OBJECT_ATTRIBUTES ObjectAttributes; 124 | HANDLE ImpersonationToken, ProcessToken; 125 | 126 | //ReactOS里用的是RtlGetProcessHeap(),全部替换成HeapHandle 127 | //另外,在Win7原版的调用中,RtlAllocateHeap的Flags是NtdllBaseTag+0x140000 128 | //NtdllBaseTag=RtlCreateTagHeap(LdrpHeap,0,"NTDLL!","!Process"); 129 | //可以理解为RtlCreateTagHeap创建了一个子堆,然后返回Index<<18 130 | //NtdllBaseTag是第一个创建的,索引为0,后续的子堆,用NtdllBaseTag+(Index<<18)就能访问 131 | //而真正的Flags在低位,与Index相加组合,并不冲突 132 | PVOID HeapHandle=NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap; 133 | 134 | //DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege, NumPriv, Flags, ReturnedState); 135 | 136 | /* Validate flags */ 137 | if (Flags & ~(RTL_ACQUIRE_PRIVILEGE_PROCESS | RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)) 138 | { 139 | return STATUS_INVALID_PARAMETER; 140 | } 141 | 142 | /* If user wants to acquire privileges for the process, we have to impersonate him */ 143 | if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 144 | { 145 | Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 146 | } 147 | 148 | /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough) 149 | * new privileges (big enough, after old privileges memory area) 150 | */ 151 | State = (PRTL_ACQUIRE_STATE)RtlAllocateHeap(HeapHandle, 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) + 152 | (NumPriv - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)); 153 | if (!State) 154 | { 155 | return STATUS_NO_MEMORY; 156 | } 157 | 158 | /* Only zero a bit of the memory (will be faster that way) */ 159 | State->Token = 0; 160 | State->OldImpersonationToken = 0; 161 | State->Flags = 0; 162 | //State->OldPrivileges = NULL; 163 | 164 | /* Check whether we have already an active impersonation */ 165 | if (NtCurrentTeb()->IsImpersonating) 166 | { 167 | //ReactOS的判断和Win7汇编代码正好相反,以Win7为准 168 | /* Check whether we want to impersonate */ 169 | if ((Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)==0) 170 | { 171 | /* That's all fine, just get the token. 172 | * We need access for: adjust (obvious...) but also 173 | * query, to be able to query old privileges 174 | */ 175 | Status = RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &State->Token); 176 | if (!NT_SUCCESS(Status)) 177 | { 178 | RtlFreeHeap(HeapHandle, 0, State); 179 | return Status; 180 | } 181 | } 182 | else 183 | { 184 | /* Otherwise, we have to temporary disable active impersonation. 185 | * Get previous impersonation token to save it 186 | */ 187 | Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken); 188 | if (!NT_SUCCESS(Status)) 189 | { 190 | RtlFreeHeap(HeapHandle, 0, State); 191 | return Status; 192 | } 193 | 194 | /* Remember the fact we had an active impersonation */ 195 | State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 196 | 197 | //Win7专门用var_10完成,实际上重复用这一个就够了 198 | ImpersonationToken=NULL; 199 | /* Revert impersonation (ie, give 0 as handle) */ 200 | Status = NtSetInformationThread(NtCurrentThread(), 201 | ThreadImpersonationToken, 202 | &ImpersonationToken, 203 | sizeof(HANDLE)); 204 | } 205 | } 206 | 207 | /* If we have no token yet (which is likely) */ 208 | if (!State->Token) //IsImpersonating为FALSE时,Token必然为NULL,流程与汇编一致 209 | { 210 | /* If we are asked to use process, then do */ 211 | if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 212 | { 213 | //ReactOS使用NtOpenProcessToken,而Win7使用NtOpenProcessTokenEx,全部替换 214 | Status = NtOpenProcessTokenEx(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 215 | OBJ_KERNEL_HANDLE, &State->Token); 216 | if (!NT_SUCCESS(Status)) 217 | { 218 | goto Cleanup; 219 | } 220 | 221 | //ReactOS漏了 222 | State->Flags|=RTL_ACQUIRE_PRIVILEGE_PROCESS; 223 | } 224 | else 225 | { 226 | /* Otherwise, we have to impersonate. 227 | * Open token for duplication 228 | */ 229 | Status = NtOpenProcessTokenEx(NtCurrentProcess(), TOKEN_DUPLICATE, OBJ_KERNEL_HANDLE, &ProcessToken); 230 | 231 | InitializeObjectAttributes(&ObjectAttributes, 232 | NULL, 233 | 0, 234 | NULL, 235 | NULL); 236 | 237 | ObjectAttributes.SecurityQualityOfService = &Sqos; 238 | Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 239 | Sqos.ImpersonationLevel = SecurityDelegation; 240 | Sqos.ContextTrackingMode = 1; 241 | Sqos.EffectiveOnly = FALSE; 242 | 243 | //ReactOS的代码相比Win7少了NtOpenProcessTokenEx结果的判断 244 | //这里整理成Win7汇编的形式 245 | if (NT_SUCCESS(Status)) 246 | { 247 | /* Duplicate */ 248 | Status = NtDuplicateToken(ProcessToken, 249 | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, 250 | &ObjectAttributes, 251 | FALSE, 252 | TokenImpersonation, 253 | &ImpersonationToken); 254 | 255 | if (NT_SUCCESS(Status)) 256 | { 257 | /* Assign our duplicated token to current thread */ 258 | Status = NtSetInformationThread(NtCurrentThread(), 259 | ThreadImpersonationToken, 260 | &ImpersonationToken, 261 | sizeof(HANDLE)); 262 | 263 | if (NT_SUCCESS(Status)) 264 | { 265 | /* Save said token and the fact we have impersonated */ 266 | State->Token = ImpersonationToken; 267 | } 268 | else 269 | { 270 | NtClose(ImpersonationToken); 271 | } 272 | } 273 | NtClose(ProcessToken); 274 | } 275 | 276 | if (!NT_SUCCESS(Status)) 277 | { 278 | goto Cleanup; 279 | } 280 | 281 | State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 282 | } 283 | } 284 | 285 | /* Properly set the privileges pointers: 286 | * OldPrivileges points to the static memory in struct (= OldPrivBuffer) 287 | * NewPrivileges points to the dynamic memory after OldPrivBuffer 288 | * There's NO overflow risks (OldPrivileges is always used with its size) 289 | */ 290 | State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer; 291 | State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + (sizeof(State->OldPrivBuffer) / sizeof(State->OldPrivBuffer[0]))); 292 | 293 | /* 294 | RTL_ACQUIRE_STATE::Token; +0 295 | RTL_ACQUIRE_STATE::OldImpersonationToken; +4 296 | RTL_ACQUIRE_STATE::OldPrivileges; +8 297 | RTL_ACQUIRE_STATE::NewPrivileges; +C 298 | RTL_ACQUIRE_STATE::Flags; +10 299 | RTL_ACQUIRE_STATE::OldPrivBuffer[1024]; +14 300 | TOKEN_PRIVILEGES NewPrivilegesBuffer; +414 301 | { 302 | TOKEN_PRIVILEGES::PrivilegeCount; +0 303 | TOKEN_PRIVILEGES::Privileges[0]::Luid::LowPart; +4 304 | TOKEN_PRIVILEGES::Privileges[0]::Luid::HighPart; +8 305 | TOKEN_PRIVILEGES::Privileges[0]::Attributes; +C 306 | TOKEN_PRIVILEGES::Privileges[1]::Luid::LowPart; +10 307 | TOKEN_PRIVILEGES::Privileges[1]::Luid::HighPart; +14 308 | TOKEN_PRIVILEGES::Privileges[1]::Attributes; +18 309 | ... 310 | } 311 | */ 312 | 313 | /* Assign all the privileges to be acquired */ 314 | State->NewPrivileges->PrivilegeCount = NumPriv; 315 | for (ULONG i = 0; i < NumPriv; ++i) 316 | { 317 | State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i]; 318 | State->NewPrivileges->Privileges[i].Luid.HighPart = 0; 319 | State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; 320 | } 321 | 322 | /* Start privileges adjustements */ 323 | //ReactOS版与Win7结构差距太大,剩下的部分按汇编改写 324 | AdjustSize=sizeof(State->OldPrivBuffer); 325 | Status = NtAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges, 326 | AdjustSize, State->OldPrivileges, &AdjustSize); 327 | /* This is returned when OldPrivileges buffer is too small */ 328 | if (Status==STATUS_BUFFER_TOO_SMALL) 329 | { 330 | while (1) 331 | { 332 | /* Try to allocate a new one, big enough to hold data */ 333 | State->OldPrivileges=(PTOKEN_PRIVILEGES)RtlAllocateHeap(HeapHandle,0,AdjustSize); 334 | if (State->OldPrivileges==NULL) 335 | { 336 | /* If we failed, properly set status: we failed because of the lack of memory */ 337 | Status=STATUS_NO_MEMORY; 338 | break; 339 | } 340 | Status = NtAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges, 341 | AdjustSize, State->OldPrivileges, &AdjustSize); 342 | if (Status!=STATUS_BUFFER_TOO_SMALL) 343 | { 344 | break; 345 | } 346 | RtlFreeHeap(HeapHandle,0,State->OldPrivileges); 347 | } 348 | } 349 | 350 | /* If we failed to assign at least one privilege */ 351 | if (Status==STATUS_NOT_ALL_ASSIGNED) 352 | { 353 | /* If there was actually only one privilege to acquire, use more accurate status */ 354 | if (NumPriv==1) 355 | Status=STATUS_PRIVILEGE_NOT_HELD; 356 | else 357 | Status=STATUS_SUCCESS; 358 | } 359 | /* Fail if needed, otherwise return our state to caller */ 360 | if (NT_SUCCESS(Status)) 361 | { 362 | *ReturnedState=State; 363 | //DPRINT("RtlAcquirePrivilege succeed!\n"); 364 | return STATUS_SUCCESS; 365 | } 366 | 367 | /* If we allocated our own buffer for old privileges, release it */ 368 | if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 369 | { 370 | RtlFreeHeap(HeapHandle, 0, State->OldPrivileges); 371 | } 372 | /* Release token */ 373 | //if (State->Token) 374 | NtClose(State->Token); 375 | 376 | Cleanup: 377 | /* Do we have to restore previously active impersonation? */ 378 | if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 379 | { 380 | //IntStatus = 381 | NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 382 | &State->OldImpersonationToken, sizeof(HANDLE)); 383 | //if (!NT_SUCCESS(IntStatus)) RtlRaiseStatus(IntStatus); 384 | if (State->OldImpersonationToken!=NULL) 385 | { 386 | NtClose(State->OldImpersonationToken); 387 | } 388 | } 389 | /* And free our state buffer */ 390 | RtlFreeHeap(HeapHandle, 0, State); 391 | 392 | //DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status); 393 | return Status; 394 | } 395 | 396 | VOID 397 | NTAPI 398 | RtlReleasePrivilege(IN PVOID ReturnedState) 399 | { 400 | NTSTATUS Status; 401 | PRTL_ACQUIRE_STATE State = (PRTL_ACQUIRE_STATE)ReturnedState; 402 | 403 | //DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState); 404 | 405 | //ReactOS里用的是RtlGetProcessHeap(),全部替换成HeapHandle 406 | PVOID HeapHandle=NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap; 407 | 408 | /* If we had an active impersonation before we acquired privileges 409 | * Or if we have impersonated, quit it 410 | */ 411 | //if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) {NtSetInformationThread()...} 412 | //else {NtAdjustPrivilegesToken()...} 413 | //ReactOS和Win7的代码理论上是等价的,这里改成了Win7的形式 414 | //!(Flags&1)对应0和2,(Flags&1)&&(Flags&2)对应3 415 | if ((State->Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)==0 || (State->Flags&RTL_ACQUIRE_PRIVILEGE_PROCESS)!=0) 416 | { 417 | /* Otherwise, restore old state */ 418 | NtAdjustPrivilegesToken(State->Token, FALSE, 419 | State->OldPrivileges, 0, NULL, NULL); 420 | } 421 | //(Flags&1)对应1 422 | if (State->Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 423 | { 424 | /* Restore it for the current thread */ 425 | Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 426 | &State->OldImpersonationToken, sizeof(HANDLE)); 427 | //if (!NT_SUCCESS(Status)) 428 | //{ 429 | // RtlRaiseStatus(Status); 430 | //} 431 | 432 | /* And close the token if needed */ 433 | if (State->OldImpersonationToken) 434 | NtClose(State->OldImpersonationToken); 435 | } 436 | 437 | /* If we used a different buffer for old privileges, just free it */ 438 | if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 439 | { 440 | //DPRINT("Releasing old privileges: %p\n", State->OldPrivileges); 441 | RtlFreeHeap(HeapHandle, 0, State->OldPrivileges); 442 | } 443 | 444 | /* Release token and free state */ 445 | NtClose(State->Token); 446 | RtlFreeHeap(HeapHandle, 0, State); 447 | } 448 | -------------------------------------------------------------------------------- /xpext_ver3/nt_srwlock.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | Windows 7 SP1 32位 6.1.7601.17514 6 | @清泠 2020.6.5 7 | 8 | SRW的分析 9 | 空闲状态,独占请求和共享请求都能获取锁 10 | 独占状态,独占请求和共享请求都不能获取锁 11 | 共享状态,仅共享请求能获取锁,独占请求不能获取锁 12 | 理论上,如果当前是共享锁,后续的所有共享请求都可以获取锁 13 | 但是为了防止写入线程出现饥饿状态,应用了相对公平的算法 14 | 一旦出现独占请求,后续的所有共享请求都要等待 15 | 16 | SRWLOCK是一个容器,保存着这个锁的全部信息 17 | SRWLOCK::Ptr的前28位保存了等待链表的头部(或共享计数) 18 | 后4位使用align(16)空出,用于保存状态 19 | 链表节点在栈上分配,函数休眠返回前一直有效,返回时自动释放 20 | 每次只允许一个线程编辑链表,用SRWF_Link标记控制 21 | 新线程进入等待状态时,把旧链表头部设为自己的back节点 22 | 自身当做新的链表头部,替换旧的链表头部,完成插入 23 | newi->back=status; 24 | status=&newi; 25 | 所以顺着status的back一直向前查找,是按时间由近到远加入的节点 26 | 即插入的一端为last,也是头部;另一端为first,是尾部 27 | last沿back一直走能找到first,first沿next一直走能找到last 28 | 29 | 因为first节点足够重要,last节点会保存first指针,加速后续操作 30 | 第一个插入的节点,其first指针指向自身,它既是first也是last 31 | 之后插入的节点,会沿着back找之前的节点,把最近处的first指针复制过来 32 | if (curr->first!=NULL) 33 | last->first=curr->first; 34 | 刚开始链表没有next字段,在传递first指针的时候会遍历并补全next字段 35 | curr->back->next=curr; 36 | curr=curr->back; 37 | 这两个步骤合称优化,在插入新节点时执行 38 | 39 | 唤醒节点从first端开始,因为这边的线程等待时间最久 40 | 如果只唤醒一个线程,会从链表中删除这个节点,并断开next链接 41 | 删除作用在last节点的first字段上,因为删除时总从这里找first节点 42 | 优化会在这里停下,然后复制过去,也不会受到影响 43 | wake=last->first; 44 | last->first=last->first->next; 45 | wake->next=NULL; 46 | 如果需要唤醒的情况比较复杂,就会唤醒所有节点 47 | 此时status置0,从first开始,沿next链依次唤醒线程 48 | 然后这些线程争夺锁,抢到锁的返回,抢不到的再次休眠 49 | 50 | 为方便理解,我还画了张图srw_cv.png 51 | */ 52 | 53 | DWORD SRWLockSpinCount=0x400; 54 | 55 | void NTAPI RtlpInitSRWLock(PEB* pPEB) 56 | { 57 | if (pPEB->NumberOfProcessors==1) 58 | SRWLockSpinCount=0; 59 | } 60 | 61 | void NTAPI RtlInitializeSRWLock(RTL_SRWLOCK* SRWLock) 62 | { 63 | SRWLock->Ptr=NULL; 64 | } 65 | 66 | void NTAPI RtlpWakeSRWLock(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus) 67 | { 68 | SYNCSTATUS CurrStatus; 69 | SYNCITEM* last; 70 | SYNCITEM* first; 71 | while (1) 72 | { 73 | //已经有线程抢先获取了锁,取消唤醒操作 74 | if (OldStatus&SRWF_Hold) //编译器将while(...)编译成if (...) do {} while(...) 75 | { 76 | do 77 | { 78 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus-SRWF_Link,OldStatus); //清除链表操作标记 79 | //状态被其它线程更新,设置状态失败 80 | //本次分析失效,更新状态重新分析 81 | //下面有大量类似代码,不再重复说明 82 | if (CurrStatus==OldStatus) 83 | return ; 84 | OldStatus=CurrStatus; 85 | } while (OldStatus&SRWF_Hold); 86 | } 87 | 88 | last=(SYNCITEM*)(OldStatus&SRWM_ITEM); 89 | first=last->first; 90 | if (first==NULL) 91 | { 92 | SYNCITEM* curr=last; 93 | do 94 | { 95 | curr->back->next=curr; //补全链表 96 | curr=curr->back; //遍历链表 97 | first=curr->first; //更新查找结果 98 | } while (first==NULL); //找一个有效的first 99 | //first指针提前到最近的地方 100 | //优化链表里没有这个判断,大概是插入多个节点需要优化时,first一定不为last 101 | if (last!=curr) 102 | last->first=first; 103 | } 104 | 105 | //如果后续还有节点等待,且这个是独占请求 106 | if ((first->next!=NULL) && (first->attr&SYNC_Exclusive)) 107 | { 108 | last->first=first->next; //从链表中删除这个节点(删除和优化每次都用最近的first指针) 109 | first->next=NULL; //first从原链表脱离 110 | _InterlockedAnd((long*)SRWLock,(~SRWF_Link)); //链表操作全部完成,去掉标记 111 | break; 112 | } 113 | //否则,可能只有这一个节点等待,或这个是共享请求,全部唤醒 114 | else 115 | { 116 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,0,OldStatus); //将状态重置为空闲 117 | if (OldStatus==CurrStatus) 118 | break; 119 | last->first=first; //将找到的first放到最近的位置 120 | OldStatus=CurrStatus; 121 | } 122 | } 123 | 124 | //依次唤醒线程,可能仅有first一个,也可能是first链上的全部 125 | //如果是全部唤醒,接下来线程会再次争夺锁,抢不到的再次循环,构建链表并阻塞 126 | //好处是省掉了各种情况的分析,后面几个共享锁将成功获得锁,直到遇到独占锁 127 | do 128 | { 129 | //抢到锁的线程会返回,栈上的item失效,必须先保存next 130 | SYNCITEM* next=first->next; 131 | //如果有SYNC_Spinning标记,表示还在自旋等待,即将进入休眠 132 | //下面的lock btr将其置0,目标线程发现后跳过休眠 133 | //如果没有SYNC_Spinning标记,说明目标线程清掉了此标记,正式进入休眠 134 | //下面的lock btr没有影响,本线程负责将目标线程唤醒 135 | //需要注意的是,NtReleaseKeyedEvent发现key并没有休眠时,会阻塞当前线程 136 | //直到有线程用此key调用了NtWaitForKeyedEvent,才会唤醒,因此不会丢失通知 137 | if (InterlockedBitTestAndReset((LONG*)&(first->attr),SYNC_SPIN_BIT)==0) 138 | NtReleaseKeyedEvent(GlobalKeyedEventHandle,first,FALSE,NULL); 139 | first=next; //遍历链表 140 | } while (first!=NULL); 141 | } 142 | 143 | void NTAPI RtlpOptimizeSRWLockList(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus) 144 | { 145 | if (OldStatus&SRWF_Hold) 146 | { 147 | do 148 | { 149 | SYNCITEM* last=(SYNCITEM*)(OldStatus&SRWM_ITEM); 150 | if (last!=NULL) 151 | { 152 | SYNCITEM* curr=last; 153 | while (curr->first==NULL) 154 | { 155 | curr->back->next=curr; //补全链表 156 | curr=curr->back; //遍历链表 157 | } 158 | last->first=curr->first; //将first放到离容器入口最近的位置,加速下次查找 159 | } 160 | //链表操作结束,清除标记 161 | SYNCSTATUS CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus-SRWF_Link,OldStatus); 162 | if (CurrStatus==OldStatus) 163 | return ; 164 | OldStatus=CurrStatus; 165 | } while (OldStatus&SRWF_Hold); 166 | } 167 | //有人释放了锁,停止优化,改为唤醒 168 | RtlpWakeSRWLock(SRWLock,OldStatus); 169 | } 170 | 171 | void NTAPI RtlAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock) 172 | { 173 | //volatile 174 | __declspec(align(16)) SYNCITEM item; 175 | BOOL IsOptimize; 176 | SYNCSTATUS NewStatus; 177 | DWORD dwBackOffCount=0; 178 | 179 | //如果当前状态为空闲,直接获取锁 180 | //甚至某个线程刚释放锁,仅清除了Hold标记,其它线程还没来得及获取锁 181 | //本线程也可以趁机获取锁,设置标记,令唤醒操作取消或唤醒后再次进入等待 182 | if (InterlockedBitTestAndSet((LONG*)SRWLock,SRW_HOLD_BIT)==0) 183 | return ; 184 | 185 | SYNCSTATUS OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 186 | SYNCSTATUS CurrStatus; 187 | while (1) 188 | { 189 | //如果当前已有线程持有锁,本线程将构建节点,将自己加入链表 190 | if (OldStatus&SRWF_Hold) 191 | { 192 | if (RtlpWaitCouldDeadlock()) 193 | { 194 | //GetCurrentProcess(),STATUS_THREAD_IS_TERMINATING 195 | NtTerminateProcess((HANDLE)0xFFFFFFFF,0xC000004B); 196 | } 197 | 198 | item.attr=SYNC_Exclusive|SYNC_Spinning; 199 | item.next=NULL; 200 | IsOptimize=FALSE; 201 | 202 | //如果有线程已经在前面等待了,就把之前的节点设为back 203 | if (OldStatus&SRWF_Wait) 204 | { 205 | item.first=NULL; 206 | item.count=0; 207 | item.back=(SYNCITEM*)(OldStatus&SRWM_ITEM); 208 | NewStatus=((SYNCSTATUS)&item)|(OldStatus&SRWF_Many)|(SRWF_Link|SRWF_Wait|SRWF_Hold); 209 | 210 | if (!(OldStatus&SRWF_Link)) //当前没人操作链表,就优化链表 211 | IsOptimize=TRUE; 212 | } 213 | //如果本线程是第一个等待的线程,first指向自己 214 | //查找时以first指针为准,不需要设置back 215 | else 216 | { 217 | item.first=&item; 218 | //如果锁的拥有者以独占方式持有,共享计数为0 219 | //如果锁的拥有者以共享方式持有,共享计数为1或更多 220 | item.count=OldStatus>>SRW_COUNT_BIT; 221 | if (item.count>1) 222 | NewStatus=((SYNCSTATUS)&item)|(SRWF_Many|SRWF_Wait|SRWF_Hold); 223 | else 224 | NewStatus=((SYNCSTATUS)&item)|(SRWF_Wait|SRWF_Hold); 225 | } 226 | //提交新状态 227 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 228 | if (CurrStatus==OldStatus) 229 | { 230 | if (IsOptimize) 231 | RtlpOptimizeSRWLockList(SRWLock,NewStatus); 232 | //进入内核的代价太高,先进行一段自旋等待 233 | for (int i=SRWLockSpinCount;i>0;i--) 234 | { 235 | if (!(item.attr&SYNC_Spinning)) //其它线程可能唤醒本线程,清除标记 236 | break; 237 | _mm_pause(); 238 | } 239 | //如果一直没能等到唤醒,就进入内核休眠 240 | if (InterlockedBitTestAndReset((LONG*)(&item.attr),SYNC_SPIN_BIT)) 241 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 242 | //被唤醒后再次循环检测条件 243 | OldStatus=CurrStatus; 244 | } 245 | else 246 | { 247 | //线程处于激烈的竞争中,退避一段时间 248 | RtlBackoff(&dwBackOffCount); 249 | OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 250 | } 251 | } 252 | //别的线程可能做了什么,反正现在没有线程持有锁了,尝试获取锁 253 | else 254 | { 255 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus+SRWF_Hold,OldStatus); 256 | if (CurrStatus==OldStatus) 257 | return ; 258 | RtlBackoff(&dwBackOffCount); 259 | OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 260 | } 261 | } 262 | } 263 | 264 | void NTAPI RtlAcquireSRWLockShared(RTL_SRWLOCK* SRWLock) 265 | { 266 | //volatile 267 | __declspec(align(16)) SYNCITEM item; 268 | BOOL IsOptimize; 269 | DWORD dwBackOffCount=0; 270 | 271 | SYNCSTATUS NewStatus; 272 | SYNCSTATUS CurrStatus; 273 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,(1<0;i--) 322 | { 323 | if (!(item.attr&SYNC_Spinning)) 324 | break; 325 | _mm_pause(); 326 | } 327 | 328 | if (InterlockedBitTestAndReset((LONG*)&(item.attr),SYNC_SPIN_BIT)) 329 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 330 | OldStatus=CurrStatus; 331 | } 332 | else 333 | { 334 | RtlBackoff(&dwBackOffCount); 335 | OldStatus=(SYNCSTATUS)SRWLock->Ptr; 336 | } 337 | } 338 | else 339 | { 340 | //某个线程刚释放锁,仅清除了Hold标记,其它线程还没来得及获取锁 341 | //本线程可以趁机获取锁,设置标记,令唤醒操作取消或唤醒后再次抢占锁 342 | //这里有点小问题,如果刚刚是独占锁释放,即使后续是共享请求 343 | //也有可能取消唤醒操作,而不是和当前的共享线程一起获取锁 344 | if (OldStatus&SRWF_Wait) 345 | NewStatus=OldStatus+SRWF_Hold; 346 | //当前处于共享状态,可以获取锁,增加共享计数 347 | else 348 | NewStatus=(OldStatus+(1<Ptr; 354 | } 355 | } 356 | } 357 | 358 | void NTAPI RtlReleaseSRWLockExclusive(RTL_SRWLOCK* SRWLock) 359 | { 360 | //去掉Hold标记 361 | SYNCSTATUS OldStatus=InterlockedExchangeAdd((SYNCSTATUS*)SRWLock,-SRWF_Hold); 362 | if (!(OldStatus&SRWF_Hold)) 363 | RtlRaiseStatus(0xC0000264); //STATUS_RESOURCE_NOT_OWNED 364 | //有线程在等待,且没有线程正在操作链表,执行唤醒操作 365 | //否则当前操作链表的线程检测到状态改变,执行唤醒操作 366 | if ((OldStatus&SRWF_Wait) && !(OldStatus&SRWF_Link)) 367 | { 368 | OldStatus-=SRWF_Hold; 369 | SYNCSTATUS CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus+SRWF_Link,OldStatus); 370 | if (OldStatus==CurrStatus) 371 | RtlpWakeSRWLock(SRWLock,OldStatus+SRWF_Link); 372 | } 373 | } 374 | 375 | void NTAPI RtlReleaseSRWLockShared(RTL_SRWLOCK* SRWLock) 376 | { 377 | SYNCSTATUS CurrStatus,NewStatus; 378 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,0,((1<first==NULL) 415 | curr=curr->back; 416 | curr=curr->first; 417 | 418 | //共享计数-1,如果共享计数大于0,说明现在仍有线程占有共享锁 419 | DWORD count=InterlockedDecrement(&curr->count); 420 | if (count>0) 421 | return ; 422 | } 423 | 424 | //共享锁完全释放,唤醒下个等待者 425 | while (1) 426 | { 427 | NewStatus=OldStatus&(~(SRWF_Many|SRWF_Hold)); 428 | //有线程在操作链表,让它去唤醒吧 429 | if (OldStatus&SRWF_Link) 430 | { 431 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 432 | if (CurrStatus==OldStatus) 433 | return ; 434 | } 435 | else 436 | { 437 | NewStatus|=SRWF_Link; 438 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 439 | if (CurrStatus==OldStatus) 440 | { 441 | RtlpWakeSRWLock(SRWLock,NewStatus); 442 | return ; 443 | } 444 | } 445 | OldStatus=CurrStatus; 446 | } 447 | } 448 | 449 | BOOL NTAPI RtlTryAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock) 450 | { 451 | BOOL IsLocked=InterlockedBitTestAndSet((LONG*)SRWLock,SRW_HOLD_BIT); 452 | return !(IsLocked==TRUE); 453 | } 454 | 455 | BOOL NTAPI RtlTryAcquireSRWLockShared(RTL_SRWLOCK* SRWLock) 456 | { 457 | DWORD dwBackOffCount=0; 458 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,(1<Ptr; 475 | } 476 | } 477 | 478 | 479 | -------------------------------------------------------------------------------- /xpext_ver3/utility.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | //自定义的便利功能 5 | 6 | /* 7 | 在XP下,内核会调用ExpKeyedEventInitialization创建KeyedEvent对象。 8 | 每次进程启动时,会调用RtlInitializeCriticalSectionAndSpinCount, 9 | 对RtlCriticalSectionLock进行初始化,这个函数还会顺带调用NtOpenKeyedEvent, 10 | 打开KeyedEvent对象的句柄。 11 | 12 | 但是Vista以后的系统对KeyedEvent做了改进,NtWaitForKeyedEvent和 13 | NtReleaseKeyedEvent不再需要句柄,直接传递NULL就能生效。因此进程启动时, 14 | 不再需要打开KeyedEvent对象的句柄。 15 | 16 | NTSTATUS ExpKeyedEventInitialization() 17 | { 18 | ... 19 | HANDLE Handle; 20 | UNICODE_STRING DestinationString; 21 | //前面必须有\\KernelObjects\\,否则返回STATUS_OBJECT_PATH_SYNTAX_BAD 22 | RtlInitUnicodeString(&DestinationString,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 23 | OBJECT_ATTRIBUTES oa; 24 | oa.Length=0x18; 25 | oa.RootDirectory=NULL; 26 | oa.ObjectName=&DestinationString; 27 | oa.Attributes=0x10; //OBJ_PERMANENT,如果在ring3,会返回STATUS_PRIVILEGE_NOT_HELD 28 | oa.SecurityDescriptor=NULL; 29 | oa.SecurityQualityOfService=NULL; 30 | NTSTATUS Error=ZwCreateKeyedEvent(&Handle,0xF0003,&oa,0); //EVENT_ALL_ACCESS&(~SYNCHRONIZE) 31 | if (NT_SUCCESS(Error)) 32 | Error=ZwClose(Handle); //大概是永久对象的存在和引用计数无关了 33 | return Error; 34 | }*/ 35 | 36 | HANDLE NTAPI OpenGlobalKeyedEvent() 37 | { 38 | UNICODE_STRING Name; 39 | RtlInitUnicodeString(&Name,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 40 | OBJECT_ATTRIBUTES oa; 41 | oa.Length=0x18; 42 | oa.RootDirectory=NULL; 43 | oa.ObjectName=&Name; 44 | oa.Attributes=0; 45 | oa.SecurityDescriptor=NULL; 46 | oa.SecurityQualityOfService=NULL; 47 | HANDLE hKeyedEvent=NULL; 48 | NtOpenKeyedEvent(&hKeyedEvent,0x2000000,&oa); //MAXIMUM_ALLOWED 49 | return hKeyedEvent; 50 | } 51 | 52 | void NTAPI CloseGlobalKeyedEvent(HANDLE hKeyedEvent) 53 | { 54 | if (hKeyedEvent!=NULL) 55 | NtClose(GlobalKeyedEventHandle); 56 | } 57 | 58 | PVOID WINAPI FindDllBase(WCHAR* szName) 59 | { 60 | UNICODE_STRING usName; 61 | RtlInitUnicodeString(&usName,szName); 62 | PEB* pPeb=NtCurrentTeb()->ProcessEnvironmentBlock; 63 | LIST_ENTRY* Head=&pPeb->Ldr->InLoadOrderModuleList; 64 | LIST_ENTRY* Curr=Head->Flink; 65 | while (Curr->Flink!=Head) 66 | { 67 | LDR_DATA_TABLE_ENTRY* Entry=CONTAINING_RECORD(Curr,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks); 68 | if (RtlCompareUnicodeString(&Entry->BaseDllName,&usName,TRUE)==0) 69 | return Entry->DllBase; 70 | Curr=Curr->Flink; 71 | } 72 | return NULL; 73 | } 74 | 75 | void SetReplaceHook(PVOID TargetAddr,PVOID NewAddr,DWORD* OldData) 76 | { 77 | 78 | } 79 | 80 | void RecoverReplaceHook() 81 | { 82 | 83 | } 84 | 85 | void SetFilterHook() 86 | { 87 | 88 | } 89 | 90 | void RecoverFilterHook() 91 | { 92 | 93 | } -------------------------------------------------------------------------------- /xpext_ver4/common.h: -------------------------------------------------------------------------------- 1 |  2 | #include "nt_def.h" 3 | #include 4 | 5 | #define XPEXT_INTERNAL 6 | #define XPEXT_EXTERNAL 7 | #define XPEXT_UNIMPLEMENT 8 | 9 | //main.cpp - init and hardcode 10 | //utility.cpp - custom function 11 | extern HANDLE GlobalKeyedEventHandle; 12 | extern BYTE* LdrpShutdownInProgress; //pointer 13 | extern DWORD* BaseDllTag; //pointer 14 | typedef NTSTATUS (WINAPI*TypeBaseCreateStack)(HANDLE,DWORD,DWORD,INITIAL_TEB*); 15 | extern TypeBaseCreateStack BaseCreateStack; 16 | 17 | HANDLE NTAPI OpenGlobalKeyedEvent(); 18 | void NTAPI CloseGlobalKeyedEvent(HANDLE hKeyedEvent); 19 | PVOID WINAPI FindDllBase(WCHAR* szName); 20 | //void SetReplaceHook(); 21 | //void RecoverReplaceHook(); 22 | //void SetFilterHook(); 23 | //void RecoverFilterHook(); 24 | 25 | 26 | //nt_privilege.cpp 27 | XPEXT_INTERNAL NTSTATUS NTAPI RtlpOpenThreadToken(ACCESS_MASK DesiredAccess,PHANDLE TokenHandle); 28 | XPEXT_EXTERNAL NTSTATUS NTAPI RtlAcquirePrivilege(PULONG Privilege,ULONG NumPriv,ULONG Flags,PVOID *ReturnedState); 29 | XPEXT_EXTERNAL VOID NTAPI RtlReleasePrivilege(PVOID ReturnedState); 30 | 31 | //nt_errorcode.cpp 32 | XPEXT_EXTERNAL ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status); 33 | XPEXT_EXTERNAL ULONG NTAPI RtlNtStatusToDosErrorNoTeb(NTSTATUS StatusCode); 34 | 35 | //nt_miscellaneous.cpp 36 | XPEXT_INTERNAL BOOL NTAPI RtlpWaitCouldDeadlock(); 37 | XPEXT_INTERNAL void NTAPI RtlBackoff(DWORD* pCount); 38 | XPEXT_INTERNAL BOOL NTAPI RtlIsAnyDebuggerPresent(); 39 | XPEXT_INTERNAL int NTAPI RtlpTerminateFailureFilter(NTSTATUS ExceptionCode,EXCEPTION_POINTERS* ms_exc_ptr); 40 | XPEXT_INTERNAL void NTAPI RtlReportCriticalFailure(DWORD ExceptionCode,ULONG_PTR ExceptionParam1); 41 | XPEXT_EXTERNAL void NTAPI RtlSetLastWin32Error(DWORD Win32ErrorCode); 42 | XPEXT_EXTERNAL NTSTATUS NTAPI RtlInitAnsiStringEx(PANSI_STRING DestinationString,PCSTR szSourceString); 43 | 44 | //nk_criticalsection.cpp 45 | BOOL WINAPI K32InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags); 46 | 47 | typedef struct _SYNCITEM 48 | { 49 | _SYNCITEM* back; //上个插入的节点 50 | _SYNCITEM* first; //第一个插入的节点 51 | _SYNCITEM* next; //下个插入的节点 52 | DWORD count; //共享计数 53 | DWORD attr; //节点属性 54 | RTL_SRWLOCK* lock; 55 | } SYNCITEM; 56 | 57 | typedef size_t SYNCSTATUS; 58 | 59 | //M-mask F-flag SYNC-common 60 | #define SYNC_Exclusive 1 //当前是独占锁在等待,而不是共享锁 61 | #define SYNC_Spinning 2 //当前线程即将休眠,而不是休眠中或唤醒后 62 | #define SYNC_SharedLock 4 //条件变量使用共享锁等待,而不是独占锁 63 | 64 | #define SRWM_FLAG 0x0000000F 65 | #define SRWM_ITEM 0xFFFFFFF0 //64位系统应该改成0xFFFFFFFFFFFFFFF0 66 | #define SRWM_COUNT SRWM_ITEM 67 | 68 | #define SRWF_Free 0 //空闲 69 | #define SRWF_Hold 1 //有线程拥有了锁 70 | #define SRWF_Wait 2 //有线程正在等待 71 | #define SRWF_Link 4 //修改链表的操作进行中 72 | #define SRWF_Many 8 //独占请求之前有多个共享锁并存 73 | 74 | #define CVM_COUNT 0x00000007 75 | #define CVM_FLAG 0x0000000F 76 | #define CVM_ITEM 0xFFFFFFF0 77 | 78 | #define CVF_Full 7 //唤醒申请已满,全部唤醒 79 | #define CVF_Link 8 //修改链表的操作进行中 80 | 81 | #define SRW_COUNT_BIT 4 82 | #define SRW_HOLD_BIT 0 83 | #define SYNC_SPIN_BIT 1 //从0开始数 84 | 85 | //nt_srwlock.cpp 86 | XPEXT_INTERNAL void NTAPI RtlpInitSRWLock(PEB* pPEB); 87 | XPEXT_EXTERNAL void NTAPI RtlInitializeSRWLock(RTL_SRWLOCK* SRWLock); 88 | XPEXT_INTERNAL void NTAPI RtlpWakeSRWLock(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus); 89 | XPEXT_INTERNAL void NTAPI RtlpOptimizeSRWLockList(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus); 90 | XPEXT_EXTERNAL void NTAPI RtlAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock); 91 | XPEXT_EXTERNAL void NTAPI RtlAcquireSRWLockShared(RTL_SRWLOCK* SRWLock); 92 | XPEXT_EXTERNAL void NTAPI RtlReleaseSRWLockExclusive(RTL_SRWLOCK* SRWLock); 93 | XPEXT_EXTERNAL void NTAPI RtlReleaseSRWLockShared(RTL_SRWLOCK* SRWLock); 94 | XPEXT_EXTERNAL BOOL NTAPI RtlTryAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock); 95 | XPEXT_EXTERNAL BOOL NTAPI RtlTryAcquireSRWLockShared(RTL_SRWLOCK* SRWLock); 96 | 97 | //nk_conditionvariable.cpp 98 | XPEXT_INTERNAL void NTAPI RtlpInitConditionVariable(PEB* pPeb); 99 | XPEXT_EXTERNAL void NTAPI RtlInitializeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 100 | XPEXT_INTERNAL BOOL NTAPI RtlpQueueWaitBlockToSRWLock(SYNCITEM* Item,RTL_SRWLOCK* SRWLock,BOOL IsSharedLock); 101 | XPEXT_INTERNAL void NTAPI RtlpWakeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCSTATUS OldStatus,int WakeCount); 102 | XPEXT_INTERNAL BOOL NTAPI RtlpWakeSingle(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCITEM* Item); 103 | XPEXT_INTERNAL void NTAPI RtlpOptimizeConditionVariableWaitList(RTL_CONDITION_VARIABLE* ConditionVariable,SYNCSTATUS OldStatus); 104 | XPEXT_INTERNAL NTSTATUS NTAPI RtlSleepConditionVariableCS(RTL_CONDITION_VARIABLE* ConditionVariable,RTL_CRITICAL_SECTION* CriticalSection,LARGE_INTEGER* Timeout); 105 | XPEXT_INTERNAL NTSTATUS NTAPI RtlSleepConditionVariableSRW(RTL_CONDITION_VARIABLE* ConditionVariable,RTL_SRWLOCK* SRWLock,LARGE_INTEGER* Timeout,ULONG Flags); 106 | XPEXT_EXTERNAL void NTAPI RtlWakeConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 107 | XPEXT_EXTERNAL void NTAPI RtlWakeAllConditionVariable(RTL_CONDITION_VARIABLE* ConditionVariable); 108 | XPEXT_EXTERNAL BOOL WINAPI K32SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable,PCRITICAL_SECTION CriticalSection,DWORD dwMilliseconds); 109 | XPEXT_EXTERNAL BOOL WINAPI K32SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable,PSRWLOCK SRWLock,DWORD dwMilliseconds,ULONG Flags); 110 | 111 | typedef struct _RUNONCEITEM 112 | { 113 | _RUNONCEITEM* next; 114 | } RUNONCEITEM; 115 | 116 | typedef size_t RUNONCESTATUS; 117 | 118 | #define RUNONCEM_ITEM 0xFFFFFFFC 119 | #define RUNONCEM_FLAG 0x00000003 120 | 121 | //注意,RUNONCESTATUS里的FLAG和参数里的Flags是两回事 122 | //参数里的Flags是操作选项,这个FLAG是RunOnce对象的状态 123 | #define RUNONCEF_NoRequest 0 124 | #define RUNONCEF_SyncPend 1 125 | #define RUNONCEF_Complete 2 126 | #define RUNONCEF_AsyncPend 3 127 | 128 | //nk_runonce.cpp 129 | XPEXT_INTERNAL RUNONCESTATUS NTAPI RtlpRunOnceWaitForInit(RUNONCESTATUS OldStatus,RTL_RUN_ONCE* RunOnce); 130 | XPEXT_INTERNAL void NTAPI RtlpRunOnceWakeAll(RTL_RUN_ONCE* RunOnce); 131 | XPEXT_EXTERNAL void NTAPI RtlRunOnceInitialize2(RTL_RUN_ONCE* RunOnce); 132 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceBeginInitialize2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID* Context); 133 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceComplete2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID Context); 134 | XPEXT_INTERNAL NTSTATUS NTAPI RtlRunOnceExecuteOnce2(RTL_RUN_ONCE* RunOnce,RTL_RUN_ONCE_INIT_FN InitFn,PVOID Parameter,PVOID* Context); 135 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce,DWORD dwFlags,PBOOL fPending,LPVOID* lpContext); 136 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceExecuteOnce(LPINIT_ONCE lpInitOnce,PINIT_ONCE_FN InitFn,LPVOID lpParameter,LPVOID* lpContext); 137 | XPEXT_EXTERNAL BOOL WINAPI K32InitOnceComplete(LPINIT_ONCE lpInitOnce,DWORD dwFlags,LPVOID lpContext); 138 | 139 | //k32_processthread.cpp 140 | XPEXT_EXTERNAL DWORD WINAPI K32GetThreadId(HANDLE Thread); 141 | XPEXT_EXTERNAL DWORD WINAPI K32GetProcessId(HANDLE Process); 142 | XPEXT_EXTERNAL DWORD WINAPI K32GetProcessIdOfThread(HANDLE Thread); 143 | XPEXT_EXTERNAL DWORD WINAPI K32GetThreadErrorMode(); 144 | XPEXT_EXTERNAL BOOL WINAPI K32SetThreadErrorMode(DWORD dwNewMode,LPDWORD lpOldMode); 145 | XPEXT_EXTERNAL BOOL WINAPI K32QueryFullProcessImageNameW(HANDLE hProcess,DWORD dwFlags,LPWSTR lpExeName,PDWORD lpdwSize); 146 | XPEXT_EXTERNAL BOOL WINAPI K32QueryFullProcessImageNameA(HANDLE hProcess,DWORD dwFlags,LPSTR lpExeName,PDWORD lpdwSize); 147 | XPEXT_EXTERNAL void WINAPI K32DeleteProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); 148 | XPEXT_EXTERNAL BOOL WINAPI K32InitializeProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwAttributeCount,DWORD dwFlags,PSIZE_T lpSize); 149 | XPEXT_EXTERNAL BOOL WINAPI K32UpdateProcThreadAttribute(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,DWORD dwFlags, 150 | DWORD_PTR Attribute,PVOID lpValue,SIZE_T cbSize,PVOID lpPreviousValue,PSIZE_T lpReturnSize); 151 | 152 | //k32_processor.cpp 153 | XPEXT_EXTERNAL WORD WINAPI K32GetActiveProcessorGroupCount(); 154 | XPEXT_EXTERNAL WORD WINAPI K32GetMaximumProcessorGroupCount(); 155 | XPEXT_EXTERNAL DWORD WINAPI K32GetActiveProcessorCount(WORD GroupNumber); 156 | XPEXT_EXTERNAL DWORD WINAPI K32GetMaximumProcessorCount(WORD GroupNumber); 157 | XPEXT_EXTERNAL DWORD WINAPI RtlGetCurrentProcessorNumber(); 158 | XPEXT_EXTERNAL void WINAPI RtlGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER ProcNumber); 159 | 160 | //k32_miscellaneous.cpp 161 | XPEXT_EXTERNAL ULONGLONG WINAPI K32GetTickCount64(); 162 | XPEXT_EXTERNAL VOID WINAPI K32RaiseFailFastException(PEXCEPTION_RECORD pExceptionRecord,PCONTEXT pContextRecord,DWORD dwFlags); 163 | XPEXT_INTERNAL DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus); 164 | XPEXT_INTERNAL LARGE_INTEGER* WINAPI BaseFormatTimeOut(LARGE_INTEGER* pTimeOut,DWORD dwMilliseconds); 165 | 166 | //k32_file.cpp 167 | XPEXT_EXTERNAL BOOL WINAPI K32GetFileInformationByHandleEx(HANDLE hFile,FILE_INFO_BY_HANDLE_CLASS InformationByHandleClass,LPVOID lpFileInformation,DWORD dwBufferSize); 168 | XPEXT_INTERNAL BOOL WINAPI Win32Rename(HANDLE hFile,LPVOID lpFileInformation,DWORD dwBufferSize); 169 | XPEXT_EXTERNAL BOOL WINAPI K32SetFileInformationByHandle(HANDLE hFile,FILE_INFO_BY_HANDLE_CLASS InformationByHandleClass,LPVOID lpFileInformation,DWORD dwBufferSize); 170 | XPEXT_INTERNAL BOOL WINAPI BasepGetObjectNTName(HANDLE hFile,LPWSTR* pszNameOut); 171 | XPEXT_INTERNAL BOOL WINAPI BasepGetFileNameInformation(HANDLE hFile,FILE_INFORMATION_CLASS FileInformationClass,LPWSTR* pszNameOut); 172 | XPEXT_INTERNAL BOOL WINAPI BasepGetVolumeDosLetterNameFromNTName(WCHAR* NTName,LPWSTR* pszNameOut); 173 | XPEXT_INTERNAL BOOL WINAPI BasepGetVolumeGUIDFromNTName(WCHAR* NTName,LPWSTR* pszNameOut); 174 | XPEXT_EXTERNAL DWORD WINAPI K32GetFinalPathNameByHandleW(HANDLE hFile,LPWSTR lpszFilePath,DWORD cchFilePath,DWORD dwFlags); 175 | XPEXT_EXTERNAL DWORD WINAPI K32GetFinalPathNameByHandleA(HANDLE hFile,LPSTR lpszFilePath,DWORD cchFilePath,DWORD dwFlags); 176 | XPEXT_INTERNAL WCHAR* WINAPI GetFullPath(LPCWSTR lpFileName); 177 | XPEXT_EXTERNAL BOOLEAN WINAPI K32CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName,LPCWSTR lpTargetFileName,DWORD dwFlags); 178 | XPEXT_INTERNAL BOOL WINAPI Basep8BitStringToDynamicUnicodeString(UNICODE_STRING* OutUnicode,LPCSTR InputAnsi); 179 | XPEXT_EXTERNAL BOOLEAN WINAPI K32CreateSymbolicLinkA(LPCSTR lpSymlinkFileName,LPCSTR lpTargetFileName,DWORD dwFlags); 180 | 181 | //nk_fiber.cpp 182 | XPEXT_EXTERNAL LPVOID WINAPI K32ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); 183 | XPEXT_EXTERNAL LPVOID WINAPI K32ConvertThreadToFiber(LPVOID lpParameter); 184 | XPEXT_EXTERNAL LPVOID WINAPI K32CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); 185 | XPEXT_EXTERNAL LPVOID WINAPI K32CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); 186 | XPEXT_EXTERNAL void WINAPI K32DeleteFiber(LPVOID lpFiber); 187 | XPEXT_EXTERNAL BOOL WINAPI K32ConvertFiberToThread(); 188 | XPEXT_EXTERNAL BOOL WINAPI K32IsThreadAFiber(); 189 | XPEXT_EXTERNAL void WINAPI K32SwitchToFiber(LPVOID lpFiber); 190 | XPEXT_INTERNAL void WINAPI LdrpInitializeFiber(); 191 | XPEXT_INTERNAL void WINAPI ExitFiberThread(DWORD dwExitCode); 192 | XPEXT_INTERNAL NTSTATUS NTAPI RtlFlsAlloc(PFLS_CALLBACK_FUNCTION CallbackFunc,PULONG IndexOut); 193 | XPEXT_INTERNAL NTSTATUS NTAPI RtlFlsFree(ULONG Index); 194 | XPEXT_INTERNAL NTSTATUS NTAPI RtlProcessFlsData(PVOID FlsData); 195 | XPEXT_EXTERNAL DWORD WINAPI K32FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); 196 | XPEXT_EXTERNAL BOOL WINAPI K32FlsFree(DWORD dwFlsIndex); 197 | XPEXT_EXTERNAL PVOID WINAPI K32FlsGetValue(DWORD dwFlsIndex); 198 | XPEXT_EXTERNAL BOOL WINAPI K32FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); 199 | 200 | -------------------------------------------------------------------------------- /xpext_ver4/k32_miscellaneous.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | typedef unsigned __int64 QWORD; 5 | 6 | /* 7 | 系统开机到现在的时间=系统开机到现在的tick数*一个tick持续的时间 8 | 一个tick持续的时间可能不是整数,所以用TickCountMultiplier和Divisor联合表示 9 | 在我的XP上,TickCountMultiplier为0x0FA00000,Divisor则为固定的0x01000000,即15.625ms 10 | 因此GetTickCount的返回值总是15.625的倍数,这就是MSDN上说的误差的原因 11 | 12 | GetTickCount返回的毫秒数上限为0xFFFFFFFF,约等于49.7天,但实际的计算结果可以多一些 13 | 以每个tick持续15.625毫秒为例,可以算出最大776.7天,接近36位,把这个值按__int64返回,可以满足大多数需求 14 | 实际上,一个tick持续的时间理论上是8位(Multiplier为32位,Divisor为24位) 15 | 假如Windows把一个tick的持续时间拉满(我是说假如,这种情况不可能出现),算出来的时间上限是40位 16 | 17 | 尽管如此,我还是没选择这个方案,而是在xpextk.sys里模仿Win7的做法,真正更新了KUserSharedData::TickCount 18 | 19 | DWORD WINAPI GetTickCount_XP() 20 | { 21 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 22 | QWORD TickCount=KUserSharedData->TickCountLow*KUserSharedData->TickCountMultiplier; 23 | return (DWORD)(TickCount>>24); 24 | } 25 | 26 | DWORD WINAPI GetTickCount_Win7x32() 27 | { 28 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 29 | while (KUserSharedData->TickCount.High1Time!=KUserSharedData->TickCount.High2Time) //同步 30 | _mm_pause(); 31 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 32 | //High1Time是高32位,计算前应该先左移32位,但是后面tick转单位要右移24位,合起来就是左移8位 33 | //DWORD HighPart=(KUserSharedData->TickCount.High1Time<<32)*KUserSharedData->TickCountMultiplier>>24; 34 | DWORD HighPart=(KUserSharedData->TickCount.High1Time<<8)*KUserSharedData->TickCountMultiplier; 35 | return (DWORD)LowPart+HighPart; 36 | } 37 | 38 | ULONGLONG WINAPI GetTickCount64_Win7x32() 39 | { 40 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 41 | while (KUserSharedData->TickCount.High1Time!=KUserSharedData->TickCount.High2Time) 42 | _mm_pause(); 43 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 44 | QWORD HighPart=KUserSharedData->TickCount.High1Time*KUserSharedData->TickCountMultiplier; 45 | HighPart=HighPart*0x100; //乘0x100等价于左移8位,原汇编调用了ntdll._allmul() 46 | return HighPart+LowPart; 47 | } 48 | 49 | ULONGLONG WINAPI GetTickCount64_Win7x64() 50 | { 51 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 52 | QWORD TickCount=*(QWORD*)&KUserSharedData->TickCount; 53 | QWORD HighPart=(TickCount>>32)*KUserSharedData->TickCountMultiplier<<8; 54 | QWORD LowPart=(DWORD)TickCount*KUserSharedData->TickCountMultiplier>>24; 55 | return HighPart+LowPart; 56 | } 57 | */ 58 | 59 | //需要xpextk.sys支持 60 | ULONGLONG WINAPI K32GetTickCount64() 61 | { 62 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0x7FFE0000; 63 | QWORD LowPart=(KUserSharedData->TickCount.LowPart*KUserSharedData->TickCountMultiplier)>>24; 64 | QWORD HighPart=KUserSharedData->TickCount.High1Time*KUserSharedData->TickCountMultiplier<<8; 65 | return LowPart+HighPart; 66 | } 67 | 68 | //UINT GetErrorMode(); 69 | //GetErrorMode=0x7C80ACDD 70 | //导出就可以了 71 | 72 | VOID WINAPI K32RaiseFailFastException(PEXCEPTION_RECORD pExceptionRecord,PCONTEXT pContextRecord,DWORD dwFlags) 73 | { 74 | EXCEPTION_RECORD ExceptionRecord; 75 | CONTEXT ContextRecord; 76 | DWORD MessageBoxResult; 77 | DWORD ReturnAddress; 78 | //参数1在栈上的地址是ebp+8,这个位置再-4就是函数返回地址在栈中的位置 79 | ReturnAddress=*((DWORD*)&pExceptionRecord-1); 80 | 81 | if (pExceptionRecord==NULL) 82 | { 83 | memset(&ExceptionRecord,0,sizeof(EXCEPTION_RECORD)); //sizeof(EXCEPTION_RECORD)==80 84 | ExceptionRecord.ExceptionCode=STATUS_FAIL_FAST_EXCEPTION; 85 | ExceptionRecord.ExceptionFlags=EXCEPTION_NONCONTINUABLE; 86 | ExceptionRecord.ExceptionAddress=(PVOID)ReturnAddress; //[ebp+4] 87 | pExceptionRecord=&ExceptionRecord; 88 | } 89 | else 90 | { 91 | pExceptionRecord->ExceptionFlags|=EXCEPTION_NONCONTINUABLE; 92 | if (dwFlags&FAIL_FAST_GENERATE_EXCEPTION_ADDRESS) 93 | pExceptionRecord->ExceptionAddress=(PVOID)ReturnAddress; 94 | } 95 | 96 | if (pContextRecord==NULL) 97 | { 98 | memset(&ContextRecord,0,sizeof(CONTEXT)); //sizeof(CONTEXT)==0x2CC 99 | RtlCaptureContext(&ContextRecord); 100 | pContextRecord=&ContextRecord; 101 | } 102 | 103 | /* 104 | //这个函数调用了EtwEventWriteNoRegistration,GUID是{E46EEAD8-0C54-4489-9898-8FA79D059E0E} 105 | NTSTATUS Result=SignalStartWerSvc(); 106 | if (NT_SUCCESS(Result)) 107 | { 108 | //这个函数调用了NtWaitForSingleObject,Event是"\\KernelObjects\\SystemErrorPortReady" 109 | Result=WaitForWerSvc(); 110 | if (NT_SUCCESS(Result) && Result!=STATUS_TIMEOUT) 111 | { 112 | if (*(BYTE*)0x7FFE02F0==1) //KUSER_SHARED_DATA::DbgErrorPortPresent 113 | { 114 | NtRaiseException(pExceptionRecord,pContextRecord,FALSE); 115 | return ; 116 | } 117 | } 118 | } 119 | */ 120 | 121 | if (!(dwFlags&FAIL_FAST_NO_HARD_ERROR_DLG)) 122 | NtRaiseHardError(pExceptionRecord->ExceptionCode|0x10000000,0,0,0,1,&MessageBoxResult); 123 | TerminateProcess(GetCurrentProcess(),pExceptionRecord->ExceptionCode); 124 | } 125 | 126 | 127 | DWORD WINAPI BaseSetLastNTError(NTSTATUS NtStatus) 128 | { 129 | //xpext的所有函数使用xpext.BaseSetLastNTError 130 | //相比kernel32.BaseSetLastNTError,可以转换的Status更全 131 | DWORD dwWin32Error=RtlNtStatusToDosError(NtStatus); 132 | //XP在此处使用KERNEL32.SetLastError,而Win7使用NTDLL.RtlSetLastWin32Error 133 | //原因参见xpext.RtlSetLastWin32Error,这里统一使用xpext.RtlSetLastWin32Error 134 | RtlSetLastWin32Error(dwWin32Error); 135 | return dwWin32Error; 136 | } 137 | 138 | LARGE_INTEGER* WINAPI BaseFormatTimeOut(LARGE_INTEGER* pTimeOut,DWORD dwMilliseconds) 139 | { 140 | if (dwMilliseconds==INFINITE) 141 | return NULL; 142 | pTimeOut->QuadPart=-10000*dwMilliseconds; 143 | return pTimeOut; 144 | } -------------------------------------------------------------------------------- /xpext_ver4/k32_processor.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | 现代操作系统拥有设备热插拔的能力(plug and play),可以在运行时动态配置硬件 6 | 其中就包括CPU核心的增加和移除,禁用和启用 7 | 因此,系统启动时检测到的最大CPU个数,并不一定是绝对的上限 8 | 也不一定是现存的CPU个数,也不一定是可用的CPU个数,这些都可能在运行时变化 9 | Win7对此提供了一定的支持,预留一些空间,在CPU可用核心增加时更新ActiveCount 10 | 而XP完全不支持,它的CPU核心总数=最大数量=可用数量 11 | 12 | 可以通过设置CPU亲和性(affinity)让线程只运行在指定的核心上 13 | Windows使用一个DWORD_PTR表示核心的掩码,如二进制00000010仅允许运行在第1个核心上 14 | 而00001101表示允许运行在核心0、核心2和核心3上,这是一种高效实用的方案 15 | 但在32位系统上DWORD_PTR仅能表示32个核心,64位系统上也只能表示64个核心 16 | 为了解决这一问题,引入了CPU组的设定,将64个CPU核心编成一组,以组号+索引确定CPU 17 | 32位的和Win7以前的操作系统不支持CPU组,默认使用第0组,最多32个或64个核心 18 | 就此衍生出一批能指定CPU组的API,但旧API仍然兼容,只能操作默认的第0组 19 | 20 | SetThreadGroupAffinity 21 | GetThreadGroupAffinity 22 | GetProcessGroupAffinity 23 | GetLogicalProcessorInformation 24 | GetLogicalProcessorInformationEx 25 | NtQuerySystemInformationEx 26 | ... 27 | */ 28 | 29 | WORD WINAPI K32GetActiveProcessorGroupCount() 30 | { 31 | return 1; 32 | } 33 | 34 | WORD WINAPI K32GetMaximumProcessorGroupCount() 35 | { 36 | return 1; 37 | } 38 | 39 | DWORD WINAPI K32GetActiveProcessorCount(WORD GroupNumber) 40 | { 41 | if (GroupNumber!=0) 42 | return 0; 43 | SYSTEM_BASIC_INFORMATION SysInfo; 44 | NTSTATUS Result=NtQuerySystemInformation(SystemBasicInformation,&SysInfo,sizeof(SysInfo),NULL); 45 | if (!NT_SUCCESS(Result)) 46 | return 0; 47 | DWORD CoreCount=0; 48 | for (int i=0;i<32;i++) 49 | { 50 | CoreCount+=(SysInfo.ActiveProcessorsAffinityMask&1); 51 | SysInfo.ActiveProcessorsAffinityMask>>=1; 52 | } 53 | return CoreCount; 54 | } 55 | 56 | DWORD WINAPI K32GetMaximumProcessorCount(WORD GroupNumber) 57 | { 58 | if (GroupNumber!=0) 59 | return 0; 60 | SYSTEM_BASIC_INFORMATION SysInfo; 61 | NTSTATUS Result=NtQuerySystemInformation(SystemBasicInformation,&SysInfo,sizeof(SysInfo),NULL); 62 | if (!NT_SUCCESS(Result)) 63 | return 0; 64 | return SysInfo.NumberOfProcessors; 65 | } 66 | 67 | //需要xpextk.sys支持 68 | //编号被设置在GDT的第8项的14到19位上,在Ring3用lsl指令读取 69 | //0x3B:索引=7,表=GDT,RPL=Ring3 70 | _declspec(naked) 71 | DWORD WINAPI RtlGetCurrentProcessorNumber() 72 | { 73 | _asm 74 | { 75 | mov ecx, 0x3B; 76 | lsl eax, ecx; 77 | shr eax, 0x0E; 78 | retn ; 79 | } 80 | } 81 | 82 | _declspec(naked) 83 | void WINAPI RtlGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER ProcNumber) 84 | { 85 | _asm 86 | { 87 | mov edi, edi; 88 | push ebp; 89 | mov ebp, esp; 90 | mov edx, dword ptr ss:[ebp+8]; //ProcNumber 91 | xor eax, eax; 92 | mov [edx], ax; //ProcNumber->Group 93 | mov ecx, 0x3B; 94 | lsl eax, ecx; 95 | shr eax, 0x0E; 96 | mov [edx+2], al; //ProcNumber->Number 97 | mov byte ptr [edx+3], 0; //ProcNumber->Reserved 98 | pop ebp; 99 | retn 4; 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /xpext_ver4/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | #pragma comment(lib,"E:\\WDK\\lib\\wxp\\i386\\ntdll.lib") 4 | 5 | //发布时记得注明系统dll版本,每个版本的dll偏移都不一样 6 | #define BASE_NT 0x7C920000 7 | #define BASE_K32 0x7C800000 8 | 9 | //进程退出时,将此值设为TRUE,阻止退出期间进行的各种新建行为 10 | BYTE* LdrpShutdownInProgress; 11 | //由RtlCreateTagHeap创建的堆,用来分配临时数据 12 | //BaseDllTag=RtlCreateTagHeap(HeapHandle,0,"BASEDLL!","TMP"); 13 | //Win7中,此标记移至KernelBaseGlobalData+0x2c处 14 | DWORD* BaseDllTag; 15 | //XP的KeyedEvent需要用到句柄,出于各种考虑,这里用一个新的 16 | HANDLE GlobalKeyedEventHandle; 17 | //Win7使用RtlCreateUserStack,XP使用BaseCreateStack,但没有导出 18 | TypeBaseCreateStack BaseCreateStack; 19 | 20 | void XPEXT_InitDll() 21 | { 22 | DWORD dwNtBaseNow=(DWORD)FindDllBase(L"ntdll.dll"); 23 | LdrpShutdownInProgress=(BYTE*)(0x7C99B0C4-BASE_NT+dwNtBaseNow); 24 | DWORD dwK32BaseNow=(DWORD)FindDllBase(L"kernel32.dll"); 25 | BaseDllTag=(DWORD*)(0x7C8856D4-BASE_K32+dwK32BaseNow); 26 | GlobalKeyedEventHandle=OpenGlobalKeyedEvent(); 27 | BaseCreateStack=(TypeBaseCreateStack)(0x7C8102AC-BASE_K32+dwK32BaseNow); 28 | RtlpInitSRWLock(NtCurrentTeb()->ProcessEnvironmentBlock); 29 | RtlpInitConditionVariable(NtCurrentTeb()->ProcessEnvironmentBlock); 30 | LdrpInitializeFiber(); 31 | } 32 | 33 | void XPEXT_UninitDll() 34 | { 35 | CloseGlobalKeyedEvent(GlobalKeyedEventHandle); 36 | } 37 | 38 | BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) 39 | { 40 | switch (fdwReason) 41 | { 42 | case DLL_PROCESS_ATTACH: 43 | OutputDebugString(L"xpext loaded: ver 1.0\r\n"); 44 | XPEXT_InitDll(); 45 | break; 46 | case DLL_PROCESS_DETACH: 47 | XPEXT_UninitDll(); 48 | OutputDebugString(L"xpext unload: ver 1.0\r\n"); 49 | break; 50 | case DLL_THREAD_ATTACH: 51 | break; 52 | case DLL_THREAD_DETACH: 53 | break; 54 | } 55 | return TRUE; 56 | } -------------------------------------------------------------------------------- /xpext_ver4/nk_criticalsection.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | NTSTATUS NTAPI RtlInitializeCriticalSectionExW7(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags) 6 | { 7 | DWORD& RtlFailedCriticalDebugAllocations=*(DWORD*)0x77F9CCA8; 8 | CRITICAL_SECTION& RtlCriticalSectionLock=*(CRITICAL_SECTION*)0x77F97118; 9 | LIST_ENTRY& RtlCriticalSectionList=*(LIST_ENTRY*)0x77F97560; 10 | 11 | if (Flags&RTL_CRITICAL_SECTION_FLAG_RESERVED) 12 | return STATUS_INVALID_PARAMETER_3; 13 | if (dwSpinCount&0xFF000000!=0) //dwSpinCount>0x00FFFFFF 14 | return STATUS_INVALID_PARAMETER_2; 15 | 16 | if (Flags&RTL_CRITICAL_SECTION_FLAG_STATIC_INIT) 17 | return STATUS_SUCCESS; 18 | 19 | lpCriticalSection->LockCount=-1; 20 | lpCriticalSection->RecursionCount=0; 21 | lpCriticalSection->OwningThread=NULL; 22 | lpCriticalSection->LockSemaphore=NULL; 23 | 24 | if (GetNumberOfProcessors()>1) 25 | { 26 | if (Flags&RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN) 27 | lpCriticalSection->SpinCount=dwSpinCount&0x00FFFFFF; 28 | //在Win7里,CRITICAL_SECTION::SpinCount前面几位可以带额外的标记,但XP不支持 29 | else 30 | lpCriticalSection->SpinCount=0x020007D0; 31 | } 32 | else 33 | { 34 | lpCriticalSection->SpinCount=0; 35 | } 36 | 37 | if (Flags&RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) 38 | { 39 | lpCriticalSection->DebugInfo=(PRTL_CRITICAL_SECTION_DEBUG)-1; 40 | } 41 | else 42 | { 43 | PRTL_CRITICAL_SECTION_DEBUG info=RtlpAllocateDebugInfo(); 44 | if (info==NULL) 45 | { 46 | lpCriticalSection->DebugInfo=(PRTL_CRITICAL_SECTION_DEBUG)-1; 47 | _InterlockedAdd(&RtlFailedCriticalDebugAllocations,1); 48 | } 49 | else 50 | { 51 | lpCriticalSection->DebugInfo=info; 52 | info->Type=RTL_CRITSECT_TYPE; 53 | info->ContentionCount=0; 54 | info->EntryCount=0; 55 | info->CriticalSection=lpCriticalSection; 56 | info->Flags=0; 57 | DWORD dwIndex=RtlLogStackBackTraceEx(1); 58 | info->CreatorBackTraceIndex=LOWORD(dwIndex); 59 | info->CreatorBackTraceIndexHigh=HIWORD(dwIndex); 60 | 61 | RtlEnterCriticalSection(&RtlCriticalSectionLock); 62 | LIST_ENTRY* pCur=&info->ProcessLocksList; 63 | pCur->Flink=&RtlCriticalSectionList; 64 | pCur->Blink=RtlCriticalSectionList.Blink; 65 | RtlCriticalSectionList.Blink->Flink=pCur; 66 | RtlCriticalSectionList.Blink=pCur; 67 | RtlLeaveCriticalSection(&RtlCriticalSectionLock); 68 | } 69 | } 70 | 71 | //这段代码不仅XP里没有,在Win7里我也不知道它是什么意思 72 | //KUSER_SHARED_DATA::UserModeGlobalLogger[1] 73 | HANDLE TraceHandle=(HANDLE)*(BYTE*)0x7FFE0382; 74 | if (TraceHandle!=NULL) 75 | { 76 | //PEB::TracingFlags.CritSecTracingEnabled 77 | if (GetPEB()->TracingFlags&2) 78 | { 79 | struct TRACEDATA 80 | { 81 | BYTE d1[6]; 82 | WORD d2; 83 | BYTE d3[24]; 84 | DWORD d4; 85 | DWORD d5; 86 | } td; 87 | td.d2=0x1723; 88 | td.d4=lpCriticalSection->SpinCount; 89 | td.d5=(DWORD)lpCriticalSection; 90 | NtTraceEvent(TraceHandle,0x00010402,8,&td); 91 | } 92 | } 93 | 94 | return STATUS_SUCCESS; 95 | } 96 | 97 | NTSTATUS NTAPI RtlInitializeCriticalSectionAndSpinCountXP(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount) 98 | { 99 | HANDLE& GlobalKeyedEventHandle=*(HANDLE*)0x7C99B15C; 100 | CRITICAL_SECTION& RtlCriticalSectionLock=*(CRITICAL_SECTION*)0x7C99B140; 101 | BOOL& RtlpCritSectInitialized=*(BOOL*)0x7C99B160; 102 | LIST_ENTRY& RtlCriticalSectionList=*(LIST_ENTRY*)0x7C99B168; 103 | 104 | lpCriticalSection->LockCount=-1; 105 | lpCriticalSection->RecursionCount=0; 106 | lpCriticalSection->OwningThread=NULL; 107 | lpCriticalSection->LockSemaphore=NULL; 108 | 109 | if (GetNumberOfProcessors()>1) 110 | lpCriticalSection->SpinCount=dwSpinCount&0x00FFFFFF; 111 | else 112 | lpCriticalSection->SpinCount=0; 113 | 114 | if (GlobalKeyedEventHandle==NULL) 115 | { 116 | UNICODE_STRING name; 117 | RtlInitUnicodeString(&name,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 118 | OBJECT_ATTRIBUTES oa; 119 | oa.Length=0x18; 120 | oa.RootDirectory=NULL; 121 | oa.ObjectName=&name; 122 | oa.Attributes=0; 123 | oa.SecurityDescriptor=NULL; 124 | oa.SecurityQualityOfService=NULL; 125 | //借用栈上的空间暂存返回值 126 | NTSTATUS result=NtOpenKeyedEvent((PHANDLE)&lpCriticalSection,0x02000000,&oa); 127 | if (!NT_SUCCESS(result)) 128 | return result; 129 | DWORD old=InterlockedCompareExchange((DWORD*)&GlobalKeyedEventHandle,(DWORD)lpCriticalSection|1,0); 130 | if (old!=0) 131 | NtClose((HANDLE)lpCriticalSection); 132 | } 133 | 134 | PRTL_CRITICAL_SECTION_DEBUG info=RtlpAllocateDebugInfo(); 135 | if (info==NULL) 136 | return STATUS_NO_MEMORY; 137 | info->Type=RTL_CRITSECT_TYPE; 138 | info->ContentionCount=0; 139 | info->EntryCount=0; 140 | info->CriticalSection=lpCriticalSection; 141 | lpCriticalSection->DebugInfo=info; 142 | DWORD dwIndex=RtlLogStackBackTrace(); 143 | info->CreatorBackTraceIndex=LOWORD(dwIndex); 144 | 145 | if (&RtlCriticalSectionLock!=NULL && RtlpCritSectInitialized==TRUE) 146 | { 147 | RtlEnterCriticalSection(&RtlCriticalSectionLock); 148 | LIST_ENTRY* pCur=&info->ProcessLocksList; 149 | pCur->Flink=&RtlCriticalSectionList; 150 | pCur->Blink=RtlCriticalSectionList.Blink; 151 | RtlCriticalSectionList.Blink->Flink=pCur; 152 | RtlCriticalSectionList.Blink=pCur; 153 | RtlLeaveCriticalSection(&RtlCriticalSectionLock); 154 | } 155 | else 156 | { 157 | //进程启动时,会调用RtlInitializeCriticalSectionAndSpinCount初始化RtlCriticalSectionLock 158 | //但是此时RtlCriticalSectionLock还没有初始化成功,于是就有了这段不加锁的代码 159 | LIST_ENTRY* pCur=&info->ProcessLocksList; 160 | pCur->Flink=&RtlCriticalSectionList; 161 | pCur->Blink=RtlCriticalSectionList.Blink; 162 | RtlCriticalSectionList.Blink->Flink=pCur; 163 | RtlCriticalSectionList.Blink=pCur; 164 | } 165 | 166 | return STATUS_SUCCESS; 167 | } 168 | */ 169 | 170 | BOOL WINAPI K32InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount,DWORD Flags) 171 | { 172 | NTSTATUS RtlStatus=STATUS_SUCCESS; 173 | if (Flags&RTL_CRITICAL_SECTION_FLAG_RESERVED) 174 | RtlStatus=STATUS_INVALID_PARAMETER_3; 175 | if (dwSpinCount&0xFF000000) //dwSpinCount>0x00FFFFFF 176 | RtlStatus=STATUS_INVALID_PARAMETER_2; 177 | if (NT_SUCCESS(RtlStatus)) 178 | { 179 | if (Flags&RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN) 180 | dwSpinCount=dwSpinCount&0x00FFFFFF; 181 | else 182 | dwSpinCount=2000; 183 | //RTL_CRITICAL_SECTION_FLAG_STATIC_INIT的效果是不初始化直接返回 184 | //RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO的效果是不分配DebugInfo的内存 185 | //由于不知道XP是否支持这些行为,稳妥起见不应用标记 186 | RtlStatus=RtlInitializeCriticalSectionAndSpinCount(lpCriticalSection,dwSpinCount); 187 | } 188 | if (NT_SUCCESS(RtlStatus)) 189 | return TRUE; 190 | BaseSetLastNTError(RtlStatus); 191 | return FALSE; 192 | } 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /xpext_ver4/nk_runonce.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | Windows 7 SP1 32位 6.1.7601.17514 6 | @清泠 2021.4.18 7 | 8 | 在kernel32里,这几个函数叫InitOnceXXX 9 | 在ntdll里,这几个函数叫RtlRunOnceXXX 10 | 不知道为什么,winnt.h里定义了RtlRunOnceXXX 11 | 我只好将它们重命名为RtlRunOnceXXX2 12 | 13 | 我认为没个十年脑血栓设计不出来这种接口 14 | 把简单的事情复杂化,提高了学习成本,还不一定好用 15 | 使用这几个函数,要仔细阅读MSDN上的文档,注意其中的各种限制 16 | 17 | 然而这几个函数做的事类似如下伪代码: 18 | 19 | //同步模式 20 | TYPE* g_obj=NULL; 21 | 22 | TYPE* GetObject() 23 | { 24 | EnterLock(); 25 | if (g_obj==NULL) 26 | g_obj=CreateObject(); 27 | LeaveLock(); 28 | return g_obj; 29 | } 30 | 31 | void UseObject() 32 | { 33 | TYPE* obj=GetObject(); 34 | obj->DoWork(); 35 | } 36 | 37 | //异步模式 38 | TYPE* g_obj=NULL; 39 | 40 | TYPE* GetObject() 41 | { 42 | return g_obj; 43 | } 44 | 45 | void UpdateObject() 46 | { 47 | TYPE* obj=CreateObject(); 48 | EnterLock(); 49 | if (g_obj==NULL) 50 | g_obj=obj; 51 | LeaveLock(); 52 | if (g_obj!=obj) 53 | DestroyObject(obj); 54 | } 55 | 56 | void UseObject() 57 | { 58 | TYPE* obj=GetObject(); 59 | if (obj==NULL) 60 | { 61 | UpdateObject(); 62 | obj=GetObject(); 63 | } 64 | obj->DoWork(); 65 | } 66 | 67 | 简单的说,是在多线程环境下创建一个单例对象(Singleton Object) 68 | 如果对象不存在,就新建一个,此后所有线程都用这个对象 69 | 否则,对象已经被其它线程创建,就使用现存的对象 70 | (这里说创建对象只是方便描述,实际上也可以是执行一些初始化代码) 71 | 72 | 这些函数有两种使用模式:同步模式和异步模式 73 | 同步模式下,第一个调用的线程执行创建,随后的线程等待 74 | 第一个线程创建完毕,其它线程被唤醒,取回已创建的对象 75 | 异步模式下,如果对象没有创建,所有线程一起创建对象 76 | 第一个创建完成的线程将对象指针更新,此后所有线程都使用这个对象 77 | 然后晚一步的线程需要销毁自己创建一半的对象 78 | 79 | 其中RtlRunOnceExecuteOnce是同步模式对 80 | RtlRunOnceBeginInitialize和RtlRunOnceComplete的封装 81 | 具体使用方式与我的描述有所差异,可以参考微软给出的使用示例: 82 | https://docs.microsoft.com/en-us/windows/win32/sync/using-one-time-initialization 83 | */ 84 | 85 | RUNONCESTATUS NTAPI RtlpRunOnceWaitForInit(RUNONCESTATUS OldStatus,RTL_RUN_ONCE* RunOnce) 86 | { 87 | //栈上的数据都是按4字节对齐的,不需要__declspec(align(4)) 88 | //因为item在栈上,且大小为4字节,编译器生成汇编时用了个优化 89 | //将OldStatus的值存在ecx里,将栈上的OldStatus的位置拿来当item 90 | RUNONCEITEM item; 91 | //将自己的节点插入链表,并进入等待 92 | //只有同步模式且未完成才需要等待,状态必然为sync+pend 93 | RUNONCESTATUS NewStatus=(((RUNONCESTATUS)&item)&(RUNONCEM_ITEM+RUNONCEF_SyncPend))|RUNONCEF_SyncPend; 94 | do 95 | { 96 | item.next=(RUNONCEITEM*)(OldStatus&RUNONCEM_ITEM); 97 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 98 | if (CurrStatus==OldStatus) 99 | { 100 | //XP不支持第一个参数传入NULL 101 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 102 | CurrStatus=(RUNONCESTATUS)RunOnce->Ptr; 103 | } 104 | OldStatus=CurrStatus; 105 | } while ((OldStatus&RUNONCEM_FLAG)==RUNONCEF_SyncPend); 106 | return OldStatus; 107 | } 108 | 109 | void NTAPI RtlpRunOnceWakeAll(RTL_RUN_ONCE* RunOnce) 110 | { 111 | //唤醒next链上的所有节点 112 | RUNONCEITEM* item=(RUNONCEITEM*)((RUNONCESTATUS)RunOnce->Ptr&RUNONCEM_ITEM); 113 | if (item!=NULL) 114 | { 115 | do 116 | { 117 | //暂存next,防止唤醒后失效 118 | RUNONCEITEM* next=item->next; 119 | //XP不支持第一个参数传入NULL 120 | NtReleaseKeyedEvent(GlobalKeyedEventHandle,item,FALSE,NULL); 121 | item=next; 122 | } while (item!=NULL); 123 | } 124 | } 125 | 126 | //void WINAPI K32InitOnceInitialize(LPINIT_ONCE InitOnce) 127 | void NTAPI RtlRunOnceInitialize2(RTL_RUN_ONCE* RunOnce) 128 | { 129 | RunOnce->Ptr=NULL; 130 | } 131 | 132 | NTSTATUS NTAPI RtlRunOnceBeginInitialize2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID* Context) 133 | { 134 | //Flags仅允许INIT_ONCE_CHECK_ONLY和INIT_ONCE_ASYNC 135 | if ((Flags&~(INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC))!=0) //0xFFFFFFFC 136 | return STATUS_INVALID_PARAMETER_2; 137 | //flags为3时,flags&(flags-1)=3&2=2 138 | //flags为2时,flags&(flags-1)=2&1=0 139 | //flags为1时,flags&(flags-1)=1&0=0 140 | //flags为0时,and必为0 141 | //即不允许两种Flag同时出现 142 | //但MSDN上说This parameter can have a value of 0, or one or more of the following flags. 143 | if (Flags & (Flags-1)) 144 | return STATUS_INVALID_PARAMETER_2; 145 | 146 | RUNONCESTATUS OldStatus=(RUNONCESTATUS)RunOnce->Ptr; 147 | //原汇编用栈上的Flags的位置存储Result 148 | NTSTATUS Result=STATUS_SUCCESS; 149 | //已有线程完成创建,返回现有的 150 | if ((OldStatus&RUNONCEM_FLAG)==RUNONCEF_Complete) 151 | { 152 | //强制更新内存缓存,令其它核心收到结果,避免无谓的等待 153 | //在Win7 x86下是xchg eax, [ebp+arg_0],在x64下是lock or [rsp+0], 0 154 | //这一句没执行实际的更改,别被惯性思维骗了 155 | InterlockedExchange((size_t*)&RunOnce,Flags); 156 | if (Context!=NULL) 157 | *(size_t*)Context=OldStatus&RUNONCEM_ITEM; 158 | return Result; 159 | } 160 | //创建还没完成,取回失败 161 | if (Flags&RTL_RUN_ONCE_CHECK_ONLY) 162 | return STATUS_UNSUCCESSFUL; 163 | 164 | BOOL IsSyncMode=((Flags&RTL_RUN_ONCE_ASYNC)==0); 165 | 166 | while (1) 167 | { 168 | BYTE StatusFlag=OldStatus&RUNONCEM_FLAG; 169 | //自己是第一个调用的线程,根据Flags设置好sync或async,返回pending,允许进行创建 170 | if (StatusFlag==RUNONCEF_NoRequest) 171 | { 172 | //若指定了RTL_RUN_ONCE_ASYNC,设为Async+Pend,否则为Sync+Pend 173 | //这些反复横跳的迷惑行为可能是编译器基于位域生成的 174 | RUNONCESTATUS NewStatus=(((!IsSyncMode)<<1)|RUNONCEF_SyncPend)&RUNONCEM_FLAG; 175 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 176 | if (CurrStatus==OldStatus) 177 | { 178 | Result=STATUS_PENDING; 179 | return Result; 180 | } 181 | OldStatus=CurrStatus; 182 | } 183 | //这一系列调用是sync模式,且已有线程进行创建,等待其完成 184 | //这种情况OldStatus可能含有等待的节点链表 185 | else if (StatusFlag==RUNONCEF_SyncPend) 186 | { 187 | //指定的async模式和之前的sync模式冲突 188 | if (IsSyncMode==FALSE) 189 | { 190 | Result=STATUS_INVALID_PARAMETER_2; 191 | return Result; 192 | } 193 | OldStatus=RtlpRunOnceWaitForInit(OldStatus,RunOnce); 194 | } 195 | //这一系列调用是async模式,返回pending允许进行创建 196 | else if (StatusFlag==RUNONCEF_AsyncPend) 197 | { 198 | //指定的sync模式和之前的async模式冲突 199 | if (IsSyncMode) 200 | Result=STATUS_INVALID_PARAMETER_2; 201 | else 202 | Result=STATUS_PENDING; 203 | return Result; 204 | } 205 | //已有线程完成创建,返回现有的 206 | //这种情况OldStatus含有context 207 | else if (StatusFlag==RUNONCEF_Complete) 208 | { 209 | if (Context!=NULL) 210 | *(size_t*)Context=OldStatus&RUNONCEM_ITEM; 211 | return Result; 212 | } 213 | //不知道为什么,原汇编代码使用OldStatus确定Async+Pend的情况 214 | //if (StatusFlag==RUNONCEF_NoRequest) ... 215 | //else if (StatusFlag==RUNONCEF_SyncPend) ... 216 | //else if (OldStatus==RUNONCEF_AsyncPend) ... 217 | //else ... 218 | //而Complete的情况,由于OldStatus含有context,没法直接比较 219 | //因此在判断完其它3种情况后,放在了else里 220 | } 221 | return Result; 222 | } 223 | 224 | NTSTATUS NTAPI RtlRunOnceComplete2(RTL_RUN_ONCE* RunOnce,DWORD Flags,PVOID Context) 225 | { 226 | //Flags仅允许RTL_RUN_ONCE_ASYNC和RTL_RUN_ONCE_INIT_FAILED 227 | if ((Flags&~(RTL_RUN_ONCE_ASYNC|RTL_RUN_ONCE_INIT_FAILED))!=0) //0xFFFFFFF9 228 | return STATUS_INVALID_PARAMETER_2; 229 | //flags为6时,flags&(flags-1)=6&5=4 230 | //flags为4时,flags&(flags-1)=4&3=0 231 | //flags为2时,flags&(flags-1)=2&1=0 232 | //flags为0时,and必为0 233 | //即不允许两种Flag同时出现 234 | if (Flags & (Flags-1)) 235 | return STATUS_INVALID_PARAMETER_2; 236 | 237 | //原汇编代码是这样的: 238 | //DWORD NewFlags=((~(Flags>>1))^Flags)&3^Flags; 239 | //结构为(target ^ complement) & range ^ complement 240 | //意为以range中为1的位为准,保留target中对应的位, 241 | //剩下的位用complement中对应的位填充 242 | //由于后面的代码只用到最低2位,所以等价于我这几行代码 243 | //我想说,分开用两个变量能死么?看来不仅设计接口的人脑子不正常 244 | //写代码的人也是个脑瘫,或是说他们根本就是一个人? 245 | BOOL IsSuccess=!(Flags&RTL_RUN_ONCE_INIT_FAILED); 246 | BOOL IsSyncMode=!(Flags&RTL_RUN_ONCE_ASYNC); 247 | DWORD NewFlags=(IsSuccess<<1)|IsSyncMode; 248 | 249 | if (Context!=NULL) 250 | { 251 | //失败模式不允许设置Context 252 | if ((NewFlags & 2)==0) 253 | return STATUS_INVALID_PARAMETER_3; 254 | //Context必须DWORD对齐(或空出最后RTL_RUN_ONCE_CTX_RESERVED_BITS位) 255 | if (((size_t)Context & 3)!=0) 256 | return STATUS_INVALID_PARAMETER_3; 257 | } 258 | 259 | RUNONCESTATUS OldStatus=(RUNONCESTATUS)RunOnce->Ptr; 260 | //若是失败模式,NewFlags & 2为0,Context也为0,合成NoRequest状态 261 | //若是成功模式,NewFlags & 2为1,Context是结果,合成Complete状态 262 | RUNONCESTATUS NewStatus=(NewFlags & 2) | (size_t)Context; 263 | 264 | BYTE StatusFlag=OldStatus&RUNONCEM_FLAG; 265 | if (StatusFlag==RUNONCEF_SyncPend) 266 | { 267 | //指定的async模式和之前的sync模式冲突 268 | if ((NewFlags & 1)==0) 269 | return STATUS_INVALID_PARAMETER_2; 270 | RUNONCESTATUS CurrStatus=InterlockedExchange((RUNONCESTATUS*)RunOnce,NewStatus); 271 | //sync模式只能有一个线程操作,其他线程修改状态是出问题了 272 | if ((CurrStatus&RUNONCEM_FLAG)!=RUNONCEF_SyncPend) 273 | return STATUS_INVALID_OWNER; 274 | //借用栈上Flags的空间临时构建了一个RTL_RUN_ONCE 275 | //而在Win7 x64上,编译器直接展开RtlpRunOnceWakeAll,省去了这一步 276 | RTL_RUN_ONCE temp; 277 | temp.Ptr=(PVOID)CurrStatus; 278 | RtlpRunOnceWakeAll(&temp); 279 | return STATUS_SUCCESS; 280 | } 281 | else if (StatusFlag==RUNONCEF_AsyncPend) 282 | { 283 | //指定的sync模式和之前的async模式冲突 284 | if ((NewFlags & 1)!=0) 285 | return STATUS_INVALID_PARAMETER_2; 286 | RUNONCESTATUS CurrStatus=InterlockedCompareExchange((RUNONCESTATUS*)RunOnce,NewStatus,OldStatus); 287 | //其他线程已经提交成功,使用此结果 288 | if (CurrStatus!=OldStatus) 289 | return STATUS_OBJECT_NAME_COLLISION; 290 | //本线程提交成功 291 | return STATUS_SUCCESS; 292 | } 293 | else 294 | { 295 | //对RUNONCEF_NoRequest来说,禁止不申请直接提交结果 296 | //对RUNONCEF_Complete来说,结果已经提交,不允许覆盖 297 | return STATUS_UNSUCCESSFUL; 298 | } 299 | } 300 | 301 | NTSTATUS NTAPI RtlRunOnceExecuteOnce2(RTL_RUN_ONCE* RunOnce,RTL_RUN_ONCE_INIT_FN InitFn,PVOID Parameter,PVOID* Context) 302 | { 303 | //原汇编代码将栈上的Context的最高字节拿来记录错误信息 304 | BYTE ErrorInfo; 305 | //如果本线程是第一个调用的,返回STATUS_PENDING,允许对象创建 306 | //如果本线程不是第一个调用的,会在函数内等待,直到第一个线程创建完成 307 | NTSTATUS Result=RtlRunOnceBeginInitialize2(RunOnce,0,Context); 308 | if (NT_SUCCESS(Result)) 309 | { 310 | //本线程是第一个线程,调用回调函数创建对象,成功后提交对象指针 311 | if (Result==STATUS_PENDING) 312 | { 313 | if (InitFn(RunOnce,Parameter,Context)==TRUE) 314 | { 315 | //原汇编代码直接使用Context来存储ContextData 316 | PVOID ContextData=NULL; 317 | if (Context!=NULL) 318 | ContextData=*Context; 319 | //创建成功,参数2传入0,将状态设为Complete,并将结果存入status里 320 | Result=RtlRunOnceComplete2(RunOnce,0,ContextData); 321 | if (NT_SUCCESS(Result)) 322 | { 323 | Result=STATUS_SUCCESS; 324 | } 325 | else 326 | { 327 | ErrorInfo=1; 328 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 329 | } 330 | } 331 | else 332 | { 333 | //创建失败,参数2传递RTL_RUN_ONCE_INIT_FAILED 334 | //将导致状态设为NoRequest,并唤醒其它线程 335 | Result=RtlRunOnceComplete2(RunOnce,RTL_RUN_ONCE_INIT_FAILED,NULL); 336 | if (NT_SUCCESS(Result)) 337 | { 338 | Result=STATUS_UNSUCCESSFUL; 339 | } 340 | else 341 | { 342 | ErrorInfo=2; 343 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 344 | } 345 | } 346 | } 347 | else //Result==STATUS_SUCCESS 348 | { 349 | //其它线程已经创建好了对象,放在Context里,返回直接使用 350 | Result=STATUS_SUCCESS; 351 | } 352 | } 353 | else 354 | { 355 | ErrorInfo=0; 356 | RtlReportCriticalFailure(Result,(ULONG_PTR)&ErrorInfo); 357 | } 358 | return Result; 359 | } 360 | 361 | 362 | BOOL WINAPI K32InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce,DWORD dwFlags,PBOOL fPending,LPVOID* lpContext) 363 | { 364 | NTSTATUS Result=RtlRunOnceBeginInitialize2(lpInitOnce,dwFlags,lpContext); 365 | if (!NT_SUCCESS(Result)) 366 | { 367 | BaseSetLastNTError(Result); 368 | return FALSE; 369 | } 370 | *fPending=(Result==STATUS_PENDING); 371 | return TRUE; 372 | } 373 | 374 | BOOL WINAPI K32InitOnceExecuteOnce(LPINIT_ONCE lpInitOnce,PINIT_ONCE_FN InitFn,LPVOID lpParameter,LPVOID* lpContext) 375 | { 376 | NTSTATUS Result=RtlRunOnceExecuteOnce2(lpInitOnce,(PRTL_RUN_ONCE_INIT_FN)InitFn,lpParameter,lpContext); 377 | //返回值只有两种结果:STATUS_SUCCESS和STATUS_UNSUCCESSFUL 378 | //其余情况全部ZwTerminateProcess,就没必要SetLastError了 379 | return NT_SUCCESS(Result); 380 | } 381 | 382 | BOOL WINAPI K32InitOnceComplete(LPINIT_ONCE lpInitOnce,DWORD dwFlags,LPVOID lpContext) 383 | { 384 | NTSTATUS Result=RtlRunOnceComplete2(lpInitOnce,dwFlags,lpContext); 385 | if (!NT_SUCCESS(Result)) 386 | { 387 | BaseSetLastNTError(Result); 388 | return FALSE; 389 | } 390 | return TRUE; 391 | } -------------------------------------------------------------------------------- /xpext_ver4/nt_miscellaneous.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | BOOL NTAPI RtlpWaitCouldDeadlock() 5 | { 6 | //byte_77F978A8极有可能是LdrpShutdownInProgress 7 | //进程退出时,各种资源即将被销毁,继续等待将会出现错误的结果 8 | return *LdrpShutdownInProgress!=0; 9 | } 10 | 11 | //通过延时来暂时退避竞争 12 | void NTAPI RtlBackoff(DWORD* pCount) 13 | { 14 | DWORD nBackCount=*pCount; 15 | if (nBackCount==0) 16 | { 17 | if (NtCurrentTeb()->ProcessEnvironmentBlock->NumberOfProcessors==1) 18 | return ; 19 | nBackCount=0x40; 20 | nBackCount*=2; 21 | } 22 | else 23 | { 24 | if (nBackCount<0x1FFF) 25 | nBackCount=nBackCount+nBackCount; 26 | } 27 | nBackCount=(__rdtsc()&(nBackCount-1))+nBackCount; 28 | //Win7原代码借用参数来计数,省去局部变量 29 | pCount=0; 30 | while ((DWORD)pCountProcessEnvironmentBlock->BeingDebugged==TRUE) || 41 | ((pKuserSharedData->KdDebuggerEnabled&3)==3); 42 | } 43 | 44 | int NTAPI RtlpTerminateFailureFilter(NTSTATUS ExceptionCode,EXCEPTION_POINTERS* ms_exc_ptr) 45 | { 46 | //这个函数负责向系统报告异常并退出进程,由于太过复杂,这里不使用 47 | //RtlReportException(ms_exc_ptr->ExceptionRecord,ms_exc_ptr->ContextRecord,0); 48 | NtTerminateProcess((HANDLE)0xFFFFFFFF,ExceptionCode); 49 | return EXCEPTION_EXECUTE_HANDLER; 50 | } 51 | 52 | void NTAPI RtlReportCriticalFailure(DWORD ExceptionCode,ULONG_PTR ExceptionParam1) 53 | { 54 | __try 55 | { 56 | if (RtlIsAnyDebuggerPresent()) 57 | { 58 | //DPFLTR_DEFAULT_ID 59 | DbgPrintEx(0x65,0,"Critical error detected %lx\n",ExceptionCode); 60 | _asm int 3; 61 | } 62 | } 63 | __except(RtlpTerminateFailureFilter(GetExceptionCode(),GetExceptionInformation())) 64 | { 65 | return ; 66 | } 67 | EXCEPTION_RECORD ExceptionRecord; 68 | ExceptionRecord.ExceptionCode=ExceptionCode; 69 | ExceptionRecord.ExceptionFlags=EXCEPTION_NONCONTINUABLE; 70 | ExceptionRecord.ExceptionRecord=NULL; 71 | ExceptionRecord.ExceptionAddress=RtlRaiseException; 72 | ExceptionRecord.NumberParameters=1; 73 | ExceptionRecord.ExceptionInformation[0]=ExceptionParam1; 74 | RtlRaiseException(&ExceptionRecord); 75 | } 76 | 77 | /* 78 | Windows XP: 79 | kernel32.SetLastError={BreakPoint}+{LastErrorSet} 80 | kernel32.BaseSetLastNTError=ntdll.RtlNtStatusToDosError+kernel32.SetLastError 81 | sdk.SetLastError=ntdll.RtlRestoreLastWin32Error 82 | ntdll.RtlRestoreLastWin32Error={LastErrorSet} 83 | ntdll.RtlSetLastWin32ErrorAndNtStatusFromNtStatus=ntdll.RtlNtStatusToDosError+{LastErrorSet} 84 | Windows 7: 85 | kernel32.SetLastError=jmp ntdll.RtlRestoreLastWin32Error 86 | kernel32.BaseSetLastNTError=ntdll.RtlNtStatusToDosError+ntdll.RtlSetLastWin32Error 87 | sdk.SetLastError=kernel32.SetLastError 88 | ntdll.RtlSetLastWin32Error=ntdll.RtlRestoreLastWin32Error={BreakPoint}+{LastErrorSet} 89 | ntdll.RtlSetLastWin32ErrorAndNtStatusFromNtStatus=ntdll.RtlNtStatusToDosError+ntdll.RtlSetLastWin32Error 90 | 91 | XP的SetLastError分两种,一种是kernel32内部使用的kernel32.SetLastError,具有断点功能 92 | 另一种是sdk里供开发者使用的,实际是ntdll.RtlRestoreLastWin32Error,没有断点功能 93 | Win7则对此作出了统一,无论什么样的SetLastError,最后都调用ntdll.RtlSetLastWin32Error,总有断点功能 94 | 95 | 本来想模仿Win7,把kernel32.SetLastError给Hook了,令其跳转到我的xpext.RtlSetLastWin32Error 96 | 但是这样只能修改kernel32内部的调用,其它软件对ntdll.RtlRestoreLastWin32Error的调用还是没效果 97 | 更进一步的做法是令kernel32.SetLastError跳转到ntdll.RtlRestoreLastWin32Error 98 | 然后令ntdll.RtlRestoreLastWin32Error跳转到xpext.RtlSetLastWin32Error,统一使用我的函数 99 | 但是仔细想想,就这么个破断点,正常人八辈子用不到,没必要大费周章搞Hook,影响系统稳定性 100 | 最终的决定是,xpext内部的函数使用xpext.RtlSetLastWin32Error,其他软件不做修改,保持原来的调用 101 | */ 102 | 103 | DWORD g_dwLastErrorToBreakOn=0; 104 | 105 | void NTAPI RtlSetLastWin32Error(DWORD Win32ErrorCode) 106 | { 107 | if (g_dwLastErrorToBreakOn!=0 && Win32ErrorCode==g_dwLastErrorToBreakOn) 108 | _asm int 3; 109 | TEB* CurrentTeb=NtCurrentTeb(); 110 | if (CurrentTeb->LastErrorValue!=Win32ErrorCode) //这个判断有意义吗? 111 | CurrentTeb->LastErrorValue=Win32ErrorCode; 112 | } 113 | 114 | NTSTATUS NTAPI RtlInitAnsiStringEx(PANSI_STRING DestinationString,PCSTR szSourceString) 115 | { 116 | DestinationString->Length=0; 117 | DestinationString->MaximumLength=0; 118 | DestinationString->Buffer=(PCHAR)szSourceString; 119 | if (szSourceString==NULL) 120 | return STATUS_SUCCESS; 121 | int Len=strlen(szSourceString); 122 | if (Len>65534) 123 | return STATUS_NAME_TOO_LONG; 124 | DestinationString->Length=Len; 125 | DestinationString->MaximumLength=Len+1; 126 | return STATUS_SUCCESS; 127 | } 128 | -------------------------------------------------------------------------------- /xpext_ver4/nt_privilege.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | extern "C" 5 | { 6 | NTSTATUS NTAPI 7 | NtOpenThreadTokenEx( 8 | IN HANDLE ThreadHandle, 9 | IN ACCESS_MASK DesiredAccess, 10 | IN BOOLEAN OpenAsSelf, 11 | IN ULONG HandleAttributes, 12 | OUT PHANDLE TokenHandle 13 | ); 14 | 15 | NTSTATUS NTAPI 16 | NtOpenProcessTokenEx( 17 | IN HANDLE ProcessHandle, 18 | IN ACCESS_MASK DesiredAccess, 19 | IN ULONG HandleAttributes, 20 | OUT PHANDLE TokenHandle 21 | ); 22 | 23 | NTSTATUS NTAPI 24 | NtAdjustPrivilegesToken ( 25 | IN HANDLE TokenHandle, 26 | IN BOOLEAN DisableAllPrivileges, 27 | IN PTOKEN_PRIVILEGES NewState OPTIONAL, 28 | IN ULONG BufferLength OPTIONAL, 29 | OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, 30 | OUT PULONG ReturnLength 31 | ); 32 | 33 | NTSTATUS NTAPI 34 | NtDuplicateToken( 35 | IN HANDLE ExistingTokenHandle, 36 | IN ACCESS_MASK DesiredAccess, 37 | IN POBJECT_ATTRIBUTES ObjectAttributes, 38 | IN BOOLEAN EffectiveOnly, 39 | IN TOKEN_TYPE TokenType, 40 | OUT PHANDLE NewTokenHandle 41 | ); 42 | }; 43 | 44 | NTSTATUS NTAPI RtlpOpenThreadToken(ACCESS_MASK DesiredAccess,PHANDLE TokenHandle) 45 | { 46 | NTSTATUS Result=NtOpenThreadTokenEx(NtCurrentThread(),DesiredAccess,TRUE,OBJ_KERNEL_HANDLE,TokenHandle); 47 | if (!NT_SUCCESS(Result)) 48 | Result=NtOpenThreadTokenEx(NtCurrentThread(),DesiredAccess,FALSE,OBJ_KERNEL_HANDLE,TokenHandle); 49 | return Result; 50 | } 51 | 52 | enum PRIVILEGE_LUID_INDEX 53 | { 54 | SeCreateTokenPrivilege=2, 55 | SeAssignPrimaryTokenPrivilege=3, 56 | SeLockMemoryPrivilege=4, 57 | SeIncreaseQuotaPrivilege=5, 58 | SeUnsolicitedInputPrivilege=6, //Unsolicited Input is obsolete and unused. 59 | SeMachineAccountPrivilege=6, 60 | SeTcbPrivilege=7, 61 | SeSecurityPrivilege=8, 62 | SeTakeOwnershipPrivilege=9, 63 | SeLoadDriverPrivilege=10, 64 | SeSystemProfilePrivilege=11, 65 | SeSystemtimePrivilege=12, 66 | SeProfileSingleProcessPrivilege=13, 67 | SeIncreaseBasePriorityPrivilege=14, 68 | SeCreatePagefilePrivilege=15, 69 | SeCreatePermanentPrivilege=16, 70 | SeBackupPrivilege=17, 71 | SeRestorePrivilege=18, 72 | SeShutdownPrivilege=19, 73 | SeDebugPrivilege=20, 74 | SeAuditPrivilege=21, 75 | SeSystemEnvironmentPrivilege=22, 76 | SeChangeNotifyPrivilege=23, 77 | SeRemoteShutdownPrivilege=24, 78 | SeUndockPrivilege=25, 79 | SeSyncAgentPrivilege=26, 80 | SeEnableDelegationPrivilege=27, 81 | SeManageVolumePrivilege=28, 82 | SeImpersonatePrivilege=29, 83 | SeCreateGlobalPrivilege=30, 84 | MaxPrivilegeLuidIndex_XP=31, 85 | 86 | SeTrustedCredManAccessPrivilege=31, 87 | SeRelabelPrivilege=32, 88 | SeIncreaseWorkingSetPrivilege=33, 89 | SeTimeZonePrivilege=34, 90 | SeCreateSymbolicLinkPrivilege=35, 91 | MaxPrivilegeLuidIndex_W7=36, 92 | }; 93 | 94 | //RtlAcquirePrivilege和RtlReleasePrivilege大部分照搬了ReactOS的rtltypes.h和priv.c(Latest commit c2c66af on 3 Oct 2017) 95 | //细节有所改动,不同之处以Win7为准(ntdll.dll x86 6.1.7601.17514) 96 | #define RTL_ACQUIRE_PRIVILEGE_IMPERSONATE 1 97 | #define RTL_ACQUIRE_PRIVILEGE_PROCESS 2 98 | 99 | typedef struct _RTL_ACQUIRE_STATE 100 | { 101 | HANDLE Token; 102 | HANDLE OldImpersonationToken; 103 | PTOKEN_PRIVILEGES OldPrivileges; 104 | PTOKEN_PRIVILEGES NewPrivileges; 105 | ULONG Flags; 106 | UCHAR OldPrivBuffer[1024]; 107 | } RTL_ACQUIRE_STATE, *PRTL_ACQUIRE_STATE; 108 | 109 | NTSTATUS 110 | NTAPI 111 | RtlAcquirePrivilege(IN PULONG Privilege, 112 | IN ULONG NumPriv, 113 | IN ULONG Flags, 114 | OUT PVOID *ReturnedState) 115 | { 116 | //ULONG ReturnLength由AdjustSize代替,NTSTATUS IntStatus不用了 117 | //C++03支持循环内定义i,OldSize合并到AdjustSize 118 | PRTL_ACQUIRE_STATE State; 119 | NTSTATUS Status; 120 | //ULONG i, OldSize; 121 | ULONG AdjustSize; 122 | SECURITY_QUALITY_OF_SERVICE Sqos; 123 | OBJECT_ATTRIBUTES ObjectAttributes; 124 | HANDLE ImpersonationToken, ProcessToken; 125 | 126 | //ReactOS里用的是RtlGetProcessHeap(),全部替换成HeapHandle 127 | //另外,在Win7原版的调用中,RtlAllocateHeap的Flags是NtdllBaseTag+0x140000 128 | //NtdllBaseTag=RtlCreateTagHeap(LdrpHeap,0,"NTDLL!","!Process"); 129 | //可以理解为RtlCreateTagHeap创建了一个子堆,然后返回Index<<18 130 | //NtdllBaseTag是第一个创建的,索引为0,后续的子堆,用NtdllBaseTag+(Index<<18)就能访问 131 | //而真正的Flags在低位,与Index相加组合,并不冲突 132 | PVOID HeapHandle=NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap; 133 | 134 | //DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege, NumPriv, Flags, ReturnedState); 135 | 136 | /* Validate flags */ 137 | if (Flags & ~(RTL_ACQUIRE_PRIVILEGE_PROCESS | RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)) 138 | { 139 | return STATUS_INVALID_PARAMETER; 140 | } 141 | 142 | /* If user wants to acquire privileges for the process, we have to impersonate him */ 143 | if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 144 | { 145 | Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 146 | } 147 | 148 | /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough) 149 | * new privileges (big enough, after old privileges memory area) 150 | */ 151 | State = (PRTL_ACQUIRE_STATE)RtlAllocateHeap(HeapHandle, 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) + 152 | (NumPriv - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)); 153 | if (!State) 154 | { 155 | return STATUS_NO_MEMORY; 156 | } 157 | 158 | /* Only zero a bit of the memory (will be faster that way) */ 159 | State->Token = 0; 160 | State->OldImpersonationToken = 0; 161 | State->Flags = 0; 162 | //State->OldPrivileges = NULL; 163 | 164 | /* Check whether we have already an active impersonation */ 165 | if (NtCurrentTeb()->IsImpersonating) 166 | { 167 | //ReactOS的判断和Win7汇编代码正好相反,以Win7为准 168 | /* Check whether we want to impersonate */ 169 | if ((Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)==0) 170 | { 171 | /* That's all fine, just get the token. 172 | * We need access for: adjust (obvious...) but also 173 | * query, to be able to query old privileges 174 | */ 175 | Status = RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &State->Token); 176 | if (!NT_SUCCESS(Status)) 177 | { 178 | RtlFreeHeap(HeapHandle, 0, State); 179 | return Status; 180 | } 181 | } 182 | else 183 | { 184 | /* Otherwise, we have to temporary disable active impersonation. 185 | * Get previous impersonation token to save it 186 | */ 187 | Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken); 188 | if (!NT_SUCCESS(Status)) 189 | { 190 | RtlFreeHeap(HeapHandle, 0, State); 191 | return Status; 192 | } 193 | 194 | /* Remember the fact we had an active impersonation */ 195 | State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 196 | 197 | //Win7专门用var_10完成,实际上重复用这一个就够了 198 | ImpersonationToken=NULL; 199 | /* Revert impersonation (ie, give 0 as handle) */ 200 | Status = NtSetInformationThread(NtCurrentThread(), 201 | ThreadImpersonationToken, 202 | &ImpersonationToken, 203 | sizeof(HANDLE)); 204 | } 205 | } 206 | 207 | /* If we have no token yet (which is likely) */ 208 | if (!State->Token) //IsImpersonating为FALSE时,Token必然为NULL,流程与汇编一致 209 | { 210 | /* If we are asked to use process, then do */ 211 | if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS) 212 | { 213 | //ReactOS使用NtOpenProcessToken,而Win7使用NtOpenProcessTokenEx,全部替换 214 | Status = NtOpenProcessTokenEx(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 215 | OBJ_KERNEL_HANDLE, &State->Token); 216 | if (!NT_SUCCESS(Status)) 217 | { 218 | goto Cleanup; 219 | } 220 | 221 | //ReactOS漏了 222 | State->Flags|=RTL_ACQUIRE_PRIVILEGE_PROCESS; 223 | } 224 | else 225 | { 226 | /* Otherwise, we have to impersonate. 227 | * Open token for duplication 228 | */ 229 | Status = NtOpenProcessTokenEx(NtCurrentProcess(), TOKEN_DUPLICATE, OBJ_KERNEL_HANDLE, &ProcessToken); 230 | 231 | InitializeObjectAttributes(&ObjectAttributes, 232 | NULL, 233 | 0, 234 | NULL, 235 | NULL); 236 | 237 | ObjectAttributes.SecurityQualityOfService = &Sqos; 238 | Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 239 | Sqos.ImpersonationLevel = SecurityDelegation; 240 | Sqos.ContextTrackingMode = 1; 241 | Sqos.EffectiveOnly = FALSE; 242 | 243 | //ReactOS的代码相比Win7少了NtOpenProcessTokenEx结果的判断 244 | //这里整理成Win7汇编的形式 245 | if (NT_SUCCESS(Status)) 246 | { 247 | /* Duplicate */ 248 | Status = NtDuplicateToken(ProcessToken, 249 | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, 250 | &ObjectAttributes, 251 | FALSE, 252 | TokenImpersonation, 253 | &ImpersonationToken); 254 | 255 | if (NT_SUCCESS(Status)) 256 | { 257 | /* Assign our duplicated token to current thread */ 258 | Status = NtSetInformationThread(NtCurrentThread(), 259 | ThreadImpersonationToken, 260 | &ImpersonationToken, 261 | sizeof(HANDLE)); 262 | 263 | if (NT_SUCCESS(Status)) 264 | { 265 | /* Save said token and the fact we have impersonated */ 266 | State->Token = ImpersonationToken; 267 | } 268 | else 269 | { 270 | NtClose(ImpersonationToken); 271 | } 272 | } 273 | NtClose(ProcessToken); 274 | } 275 | 276 | if (!NT_SUCCESS(Status)) 277 | { 278 | goto Cleanup; 279 | } 280 | 281 | State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE; 282 | } 283 | } 284 | 285 | /* Properly set the privileges pointers: 286 | * OldPrivileges points to the static memory in struct (= OldPrivBuffer) 287 | * NewPrivileges points to the dynamic memory after OldPrivBuffer 288 | * There's NO overflow risks (OldPrivileges is always used with its size) 289 | */ 290 | State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer; 291 | State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + (sizeof(State->OldPrivBuffer) / sizeof(State->OldPrivBuffer[0]))); 292 | 293 | /* 294 | RTL_ACQUIRE_STATE::Token; +0 295 | RTL_ACQUIRE_STATE::OldImpersonationToken; +4 296 | RTL_ACQUIRE_STATE::OldPrivileges; +8 297 | RTL_ACQUIRE_STATE::NewPrivileges; +C 298 | RTL_ACQUIRE_STATE::Flags; +10 299 | RTL_ACQUIRE_STATE::OldPrivBuffer[1024]; +14 300 | TOKEN_PRIVILEGES NewPrivilegesBuffer; +414 301 | { 302 | TOKEN_PRIVILEGES::PrivilegeCount; +0 303 | TOKEN_PRIVILEGES::Privileges[0]::Luid::LowPart; +4 304 | TOKEN_PRIVILEGES::Privileges[0]::Luid::HighPart; +8 305 | TOKEN_PRIVILEGES::Privileges[0]::Attributes; +C 306 | TOKEN_PRIVILEGES::Privileges[1]::Luid::LowPart; +10 307 | TOKEN_PRIVILEGES::Privileges[1]::Luid::HighPart; +14 308 | TOKEN_PRIVILEGES::Privileges[1]::Attributes; +18 309 | ... 310 | } 311 | */ 312 | 313 | /* Assign all the privileges to be acquired */ 314 | State->NewPrivileges->PrivilegeCount = NumPriv; 315 | for (ULONG i = 0; i < NumPriv; ++i) 316 | { 317 | State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i]; 318 | State->NewPrivileges->Privileges[i].Luid.HighPart = 0; 319 | State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; 320 | } 321 | 322 | /* Start privileges adjustements */ 323 | //ReactOS版与Win7结构差距太大,剩下的部分按汇编改写 324 | AdjustSize=sizeof(State->OldPrivBuffer); 325 | Status = NtAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges, 326 | AdjustSize, State->OldPrivileges, &AdjustSize); 327 | /* This is returned when OldPrivileges buffer is too small */ 328 | if (Status==STATUS_BUFFER_TOO_SMALL) 329 | { 330 | while (1) 331 | { 332 | /* Try to allocate a new one, big enough to hold data */ 333 | State->OldPrivileges=(PTOKEN_PRIVILEGES)RtlAllocateHeap(HeapHandle,0,AdjustSize); 334 | if (State->OldPrivileges==NULL) 335 | { 336 | /* If we failed, properly set status: we failed because of the lack of memory */ 337 | Status=STATUS_NO_MEMORY; 338 | break; 339 | } 340 | Status = NtAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges, 341 | AdjustSize, State->OldPrivileges, &AdjustSize); 342 | if (Status!=STATUS_BUFFER_TOO_SMALL) 343 | { 344 | break; 345 | } 346 | RtlFreeHeap(HeapHandle,0,State->OldPrivileges); 347 | } 348 | } 349 | 350 | /* If we failed to assign at least one privilege */ 351 | if (Status==STATUS_NOT_ALL_ASSIGNED) 352 | { 353 | /* If there was actually only one privilege to acquire, use more accurate status */ 354 | if (NumPriv==1) 355 | Status=STATUS_PRIVILEGE_NOT_HELD; 356 | else 357 | Status=STATUS_SUCCESS; 358 | } 359 | /* Fail if needed, otherwise return our state to caller */ 360 | if (NT_SUCCESS(Status)) 361 | { 362 | *ReturnedState=State; 363 | //DPRINT("RtlAcquirePrivilege succeed!\n"); 364 | return STATUS_SUCCESS; 365 | } 366 | 367 | /* If we allocated our own buffer for old privileges, release it */ 368 | if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 369 | { 370 | RtlFreeHeap(HeapHandle, 0, State->OldPrivileges); 371 | } 372 | /* Release token */ 373 | //if (State->Token) 374 | NtClose(State->Token); 375 | 376 | Cleanup: 377 | /* Do we have to restore previously active impersonation? */ 378 | if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 379 | { 380 | //IntStatus = 381 | NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 382 | &State->OldImpersonationToken, sizeof(HANDLE)); 383 | //if (!NT_SUCCESS(IntStatus)) RtlRaiseStatus(IntStatus); 384 | if (State->OldImpersonationToken!=NULL) 385 | { 386 | NtClose(State->OldImpersonationToken); 387 | } 388 | } 389 | /* And free our state buffer */ 390 | RtlFreeHeap(HeapHandle, 0, State); 391 | 392 | //DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status); 393 | return Status; 394 | } 395 | 396 | VOID 397 | NTAPI 398 | RtlReleasePrivilege(IN PVOID ReturnedState) 399 | { 400 | NTSTATUS Status; 401 | PRTL_ACQUIRE_STATE State = (PRTL_ACQUIRE_STATE)ReturnedState; 402 | 403 | //DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState); 404 | 405 | //ReactOS里用的是RtlGetProcessHeap(),全部替换成HeapHandle 406 | PVOID HeapHandle=NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap; 407 | 408 | /* If we had an active impersonation before we acquired privileges 409 | * Or if we have impersonated, quit it 410 | */ 411 | //if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) {NtSetInformationThread()...} 412 | //else {NtAdjustPrivilegesToken()...} 413 | //ReactOS和Win7的代码理论上是等价的,这里改成了Win7的形式 414 | //!(Flags&1)对应0和2,(Flags&1)&&(Flags&2)对应3 415 | if ((State->Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)==0 || (State->Flags&RTL_ACQUIRE_PRIVILEGE_PROCESS)!=0) 416 | { 417 | /* Otherwise, restore old state */ 418 | NtAdjustPrivilegesToken(State->Token, FALSE, 419 | State->OldPrivileges, 0, NULL, NULL); 420 | } 421 | //(Flags&1)对应1 422 | if (State->Flags&RTL_ACQUIRE_PRIVILEGE_IMPERSONATE) 423 | { 424 | /* Restore it for the current thread */ 425 | Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, 426 | &State->OldImpersonationToken, sizeof(HANDLE)); 427 | //if (!NT_SUCCESS(Status)) 428 | //{ 429 | // RtlRaiseStatus(Status); 430 | //} 431 | 432 | /* And close the token if needed */ 433 | if (State->OldImpersonationToken) 434 | NtClose(State->OldImpersonationToken); 435 | } 436 | 437 | /* If we used a different buffer for old privileges, just free it */ 438 | if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges) 439 | { 440 | //DPRINT("Releasing old privileges: %p\n", State->OldPrivileges); 441 | RtlFreeHeap(HeapHandle, 0, State->OldPrivileges); 442 | } 443 | 444 | /* Release token and free state */ 445 | NtClose(State->Token); 446 | RtlFreeHeap(HeapHandle, 0, State); 447 | } 448 | -------------------------------------------------------------------------------- /xpext_ver4/nt_srwlock.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | /* 5 | Windows 7 SP1 32位 6.1.7601.17514 6 | @清泠 2020.6.5 7 | 8 | SRW的分析 9 | 空闲状态,独占请求和共享请求都能获取锁 10 | 独占状态,独占请求和共享请求都不能获取锁 11 | 共享状态,仅共享请求能获取锁,独占请求不能获取锁 12 | 理论上,如果当前是共享锁,后续的所有共享请求都可以获取锁 13 | 但是为了防止写入线程出现饥饿状态,应用了相对公平的算法 14 | 一旦出现独占请求,后续的所有共享请求都要等待 15 | 16 | SRWLOCK是一个容器,保存着这个锁的全部信息 17 | SRWLOCK::Ptr的前28位保存了等待链表的头部(或共享计数) 18 | 后4位使用align(16)空出,用于保存状态 19 | 链表节点在栈上分配,函数休眠返回前一直有效,返回时自动释放 20 | 每次只允许一个线程编辑链表,用SRWF_Link标记控制 21 | 新线程进入等待状态时,把旧链表头部设为自己的back节点 22 | 自身当做新的链表头部,替换旧的链表头部,完成插入 23 | newi->back=status; 24 | status=&newi; 25 | 所以顺着status的back一直向前查找,是按时间由近到远加入的节点 26 | 即插入的一端为last,也是头部;另一端为first,是尾部 27 | last沿back一直走能找到first,first沿next一直走能找到last 28 | 29 | 因为first节点足够重要,last节点会保存first指针,加速后续操作 30 | 第一个插入的节点,其first指针指向自身,它既是first也是last 31 | 之后插入的节点,会沿着back找之前的节点,把最近处的first指针复制过来 32 | if (curr->first!=NULL) 33 | last->first=curr->first; 34 | 刚开始链表没有next字段,在传递first指针的时候会遍历并补全next字段 35 | curr->back->next=curr; 36 | curr=curr->back; 37 | 这两个步骤合称优化,在插入新节点时执行 38 | 39 | 唤醒节点从first端开始,因为这边的线程等待时间最久 40 | 如果只唤醒一个线程,会从链表中删除这个节点,并断开next链接 41 | 删除作用在last节点的first字段上,因为删除时总从这里找first节点 42 | 优化会在这里停下,然后复制过去,也不会受到影响 43 | wake=last->first; 44 | last->first=last->first->next; 45 | wake->next=NULL; 46 | 如果需要唤醒的情况比较复杂,就会唤醒所有节点 47 | 此时status置0,从first开始,沿next链依次唤醒线程 48 | 然后这些线程争夺锁,抢到锁的返回,抢不到的再次休眠 49 | 50 | 为方便理解,我还画了张图srw_cv.png 51 | */ 52 | 53 | DWORD SRWLockSpinCount=0x400; 54 | 55 | void NTAPI RtlpInitSRWLock(PEB* pPEB) 56 | { 57 | if (pPEB->NumberOfProcessors==1) 58 | SRWLockSpinCount=0; 59 | } 60 | 61 | void NTAPI RtlInitializeSRWLock(RTL_SRWLOCK* SRWLock) 62 | { 63 | SRWLock->Ptr=NULL; 64 | } 65 | 66 | void NTAPI RtlpWakeSRWLock(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus) 67 | { 68 | SYNCSTATUS CurrStatus; 69 | SYNCITEM* last; 70 | SYNCITEM* first; 71 | while (1) 72 | { 73 | //已经有线程抢先获取了锁,取消唤醒操作 74 | if (OldStatus&SRWF_Hold) //编译器将while(...)编译成if (...) do {} while(...) 75 | { 76 | do 77 | { 78 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus-SRWF_Link,OldStatus); //清除链表操作标记 79 | //状态被其它线程更新,设置状态失败 80 | //本次分析失效,更新状态重新分析 81 | //下面有大量类似代码,不再重复说明 82 | if (CurrStatus==OldStatus) 83 | return ; 84 | OldStatus=CurrStatus; 85 | } while (OldStatus&SRWF_Hold); 86 | } 87 | 88 | last=(SYNCITEM*)(OldStatus&SRWM_ITEM); 89 | first=last->first; 90 | if (first==NULL) 91 | { 92 | SYNCITEM* curr=last; 93 | do 94 | { 95 | curr->back->next=curr; //补全链表 96 | curr=curr->back; //遍历链表 97 | first=curr->first; //更新查找结果 98 | } while (first==NULL); //找一个有效的first 99 | //first指针提前到最近的地方 100 | //优化链表里没有这个判断,大概是插入多个节点需要优化时,first一定不为last 101 | if (last!=curr) 102 | last->first=first; 103 | } 104 | 105 | //如果后续还有节点等待,且这个是独占请求 106 | if ((first->next!=NULL) && (first->attr&SYNC_Exclusive)) 107 | { 108 | last->first=first->next; //从链表中删除这个节点(删除和优化每次都用最近的first指针) 109 | first->next=NULL; //first从原链表脱离 110 | _InterlockedAnd((long*)SRWLock,(~SRWF_Link)); //链表操作全部完成,去掉标记 111 | break; 112 | } 113 | //否则,可能只有这一个节点等待,或这个是共享请求,全部唤醒 114 | else 115 | { 116 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,0,OldStatus); //将状态重置为空闲 117 | if (OldStatus==CurrStatus) 118 | break; 119 | last->first=first; //将找到的first放到最近的位置 120 | OldStatus=CurrStatus; 121 | } 122 | } 123 | 124 | //依次唤醒线程,可能仅有first一个,也可能是first链上的全部 125 | //如果是全部唤醒,接下来线程会再次争夺锁,抢不到的再次循环,构建链表并阻塞 126 | //好处是省掉了各种情况的分析,后面几个共享锁将成功获得锁,直到遇到独占锁 127 | do 128 | { 129 | //抢到锁的线程会返回,栈上的item失效,必须先保存next 130 | SYNCITEM* next=first->next; 131 | //如果有SYNC_Spinning标记,表示还在自旋等待,即将进入休眠 132 | //下面的lock btr将其置0,目标线程发现后跳过休眠 133 | //如果没有SYNC_Spinning标记,说明目标线程清掉了此标记,正式进入休眠 134 | //下面的lock btr没有影响,本线程负责将目标线程唤醒 135 | //需要注意的是,NtReleaseKeyedEvent发现key并没有休眠时,会阻塞当前线程 136 | //直到有线程用此key调用了NtWaitForKeyedEvent,才会唤醒,因此不会丢失通知 137 | if (InterlockedBitTestAndReset((LONG*)&(first->attr),SYNC_SPIN_BIT)==0) 138 | NtReleaseKeyedEvent(GlobalKeyedEventHandle,first,FALSE,NULL); 139 | first=next; //遍历链表 140 | } while (first!=NULL); 141 | } 142 | 143 | void NTAPI RtlpOptimizeSRWLockList(RTL_SRWLOCK* SRWLock,SYNCSTATUS OldStatus) 144 | { 145 | if (OldStatus&SRWF_Hold) 146 | { 147 | do 148 | { 149 | SYNCITEM* last=(SYNCITEM*)(OldStatus&SRWM_ITEM); 150 | if (last!=NULL) 151 | { 152 | SYNCITEM* curr=last; 153 | while (curr->first==NULL) 154 | { 155 | curr->back->next=curr; //补全链表 156 | curr=curr->back; //遍历链表 157 | } 158 | last->first=curr->first; //将first放到离容器入口最近的位置,加速下次查找 159 | } 160 | //链表操作结束,清除标记 161 | SYNCSTATUS CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus-SRWF_Link,OldStatus); 162 | if (CurrStatus==OldStatus) 163 | return ; 164 | OldStatus=CurrStatus; 165 | } while (OldStatus&SRWF_Hold); 166 | } 167 | //有人释放了锁,停止优化,改为唤醒 168 | RtlpWakeSRWLock(SRWLock,OldStatus); 169 | } 170 | 171 | void NTAPI RtlAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock) 172 | { 173 | //volatile 174 | __declspec(align(16)) SYNCITEM item; 175 | BOOL IsOptimize; 176 | SYNCSTATUS NewStatus; 177 | DWORD dwBackOffCount=0; 178 | 179 | //如果当前状态为空闲,直接获取锁 180 | //甚至某个线程刚释放锁,仅清除了Hold标记,其它线程还没来得及获取锁 181 | //本线程也可以趁机获取锁,设置标记,令唤醒操作取消或唤醒后再次进入等待 182 | if (InterlockedBitTestAndSet((LONG*)SRWLock,SRW_HOLD_BIT)==0) 183 | return ; 184 | 185 | SYNCSTATUS OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 186 | SYNCSTATUS CurrStatus; 187 | while (1) 188 | { 189 | //如果当前已有线程持有锁,本线程将构建节点,将自己加入链表 190 | if (OldStatus&SRWF_Hold) 191 | { 192 | if (RtlpWaitCouldDeadlock()) 193 | { 194 | //GetCurrentProcess(),STATUS_THREAD_IS_TERMINATING 195 | NtTerminateProcess((HANDLE)0xFFFFFFFF,0xC000004B); 196 | } 197 | 198 | item.attr=SYNC_Exclusive|SYNC_Spinning; 199 | item.next=NULL; 200 | IsOptimize=FALSE; 201 | 202 | //如果有线程已经在前面等待了,就把之前的节点设为back 203 | if (OldStatus&SRWF_Wait) 204 | { 205 | item.first=NULL; 206 | item.count=0; 207 | item.back=(SYNCITEM*)(OldStatus&SRWM_ITEM); 208 | NewStatus=((SYNCSTATUS)&item)|(OldStatus&SRWF_Many)|(SRWF_Link|SRWF_Wait|SRWF_Hold); 209 | 210 | if (!(OldStatus&SRWF_Link)) //当前没人操作链表,就优化链表 211 | IsOptimize=TRUE; 212 | } 213 | //如果本线程是第一个等待的线程,first指向自己 214 | //查找时以first指针为准,不需要设置back 215 | else 216 | { 217 | item.first=&item; 218 | //如果锁的拥有者以独占方式持有,共享计数为0 219 | //如果锁的拥有者以共享方式持有,共享计数为1或更多 220 | item.count=OldStatus>>SRW_COUNT_BIT; 221 | if (item.count>1) 222 | NewStatus=((SYNCSTATUS)&item)|(SRWF_Many|SRWF_Wait|SRWF_Hold); 223 | else 224 | NewStatus=((SYNCSTATUS)&item)|(SRWF_Wait|SRWF_Hold); 225 | } 226 | //提交新状态 227 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 228 | if (CurrStatus==OldStatus) 229 | { 230 | if (IsOptimize) 231 | RtlpOptimizeSRWLockList(SRWLock,NewStatus); 232 | //进入内核的代价太高,先进行一段自旋等待 233 | for (int i=SRWLockSpinCount;i>0;i--) 234 | { 235 | if (!(item.attr&SYNC_Spinning)) //其它线程可能唤醒本线程,清除标记 236 | break; 237 | _mm_pause(); 238 | } 239 | //如果一直没能等到唤醒,就进入内核休眠 240 | if (InterlockedBitTestAndReset((LONG*)(&item.attr),SYNC_SPIN_BIT)) 241 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 242 | //被唤醒后再次循环检测条件 243 | OldStatus=CurrStatus; 244 | } 245 | else 246 | { 247 | //线程处于激烈的竞争中,退避一段时间 248 | RtlBackoff(&dwBackOffCount); 249 | OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 250 | } 251 | } 252 | //别的线程可能做了什么,反正现在没有线程持有锁了,尝试获取锁 253 | else 254 | { 255 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus+SRWF_Hold,OldStatus); 256 | if (CurrStatus==OldStatus) 257 | return ; 258 | RtlBackoff(&dwBackOffCount); 259 | OldStatus=(SYNCSTATUS)(SRWLock->Ptr); 260 | } 261 | } 262 | } 263 | 264 | void NTAPI RtlAcquireSRWLockShared(RTL_SRWLOCK* SRWLock) 265 | { 266 | //volatile 267 | __declspec(align(16)) SYNCITEM item; 268 | BOOL IsOptimize; 269 | DWORD dwBackOffCount=0; 270 | 271 | SYNCSTATUS NewStatus; 272 | SYNCSTATUS CurrStatus; 273 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,(1<0;i--) 322 | { 323 | if (!(item.attr&SYNC_Spinning)) 324 | break; 325 | _mm_pause(); 326 | } 327 | 328 | if (InterlockedBitTestAndReset((LONG*)&(item.attr),SYNC_SPIN_BIT)) 329 | NtWaitForKeyedEvent(GlobalKeyedEventHandle,&item,FALSE,NULL); 330 | OldStatus=CurrStatus; 331 | } 332 | else 333 | { 334 | RtlBackoff(&dwBackOffCount); 335 | OldStatus=(SYNCSTATUS)SRWLock->Ptr; 336 | } 337 | } 338 | else 339 | { 340 | //某个线程刚释放锁,仅清除了Hold标记,其它线程还没来得及获取锁 341 | //本线程可以趁机获取锁,设置标记,令唤醒操作取消或唤醒后再次抢占锁 342 | //这里有点小问题,如果刚刚是独占锁释放,即使后续是共享请求 343 | //也有可能取消唤醒操作,而不是和当前的共享线程一起获取锁 344 | if (OldStatus&SRWF_Wait) 345 | NewStatus=OldStatus+SRWF_Hold; 346 | //当前处于共享状态,可以获取锁,增加共享计数 347 | else 348 | NewStatus=(OldStatus+(1<Ptr; 354 | } 355 | } 356 | } 357 | 358 | void NTAPI RtlReleaseSRWLockExclusive(RTL_SRWLOCK* SRWLock) 359 | { 360 | //去掉Hold标记 361 | SYNCSTATUS OldStatus=InterlockedExchangeAdd((SYNCSTATUS*)SRWLock,-SRWF_Hold); 362 | if (!(OldStatus&SRWF_Hold)) 363 | RtlRaiseStatus(0xC0000264); //STATUS_RESOURCE_NOT_OWNED 364 | //有线程在等待,且没有线程正在操作链表,执行唤醒操作 365 | //否则当前操作链表的线程检测到状态改变,执行唤醒操作 366 | if ((OldStatus&SRWF_Wait) && !(OldStatus&SRWF_Link)) 367 | { 368 | OldStatus-=SRWF_Hold; 369 | SYNCSTATUS CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,OldStatus+SRWF_Link,OldStatus); 370 | if (OldStatus==CurrStatus) 371 | RtlpWakeSRWLock(SRWLock,OldStatus+SRWF_Link); 372 | } 373 | } 374 | 375 | void NTAPI RtlReleaseSRWLockShared(RTL_SRWLOCK* SRWLock) 376 | { 377 | SYNCSTATUS CurrStatus,NewStatus; 378 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,0,((1<first==NULL) 415 | curr=curr->back; 416 | curr=curr->first; 417 | 418 | //共享计数-1,如果共享计数大于0,说明现在仍有线程占有共享锁 419 | DWORD count=InterlockedDecrement(&curr->count); 420 | if (count>0) 421 | return ; 422 | } 423 | 424 | //共享锁完全释放,唤醒下个等待者 425 | while (1) 426 | { 427 | NewStatus=OldStatus&(~(SRWF_Many|SRWF_Hold)); 428 | //有线程在操作链表,让它去唤醒吧 429 | if (OldStatus&SRWF_Link) 430 | { 431 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 432 | if (CurrStatus==OldStatus) 433 | return ; 434 | } 435 | else 436 | { 437 | NewStatus|=SRWF_Link; 438 | CurrStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,NewStatus,OldStatus); 439 | if (CurrStatus==OldStatus) 440 | { 441 | RtlpWakeSRWLock(SRWLock,NewStatus); 442 | return ; 443 | } 444 | } 445 | OldStatus=CurrStatus; 446 | } 447 | } 448 | 449 | BOOL NTAPI RtlTryAcquireSRWLockExclusive(RTL_SRWLOCK* SRWLock) 450 | { 451 | BOOL IsLocked=InterlockedBitTestAndSet((LONG*)SRWLock,SRW_HOLD_BIT); 452 | return !(IsLocked==TRUE); 453 | } 454 | 455 | BOOL NTAPI RtlTryAcquireSRWLockShared(RTL_SRWLOCK* SRWLock) 456 | { 457 | DWORD dwBackOffCount=0; 458 | SYNCSTATUS OldStatus=InterlockedCompareExchange((SYNCSTATUS*)SRWLock,(1<Ptr; 475 | } 476 | } 477 | 478 | 479 | -------------------------------------------------------------------------------- /xpext_ver4/utility.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "common.h" 3 | 4 | //自定义的便利功能 5 | 6 | /* 7 | 在XP下,内核会调用ExpKeyedEventInitialization创建KeyedEvent对象。 8 | 每次进程启动时,会调用RtlInitializeCriticalSectionAndSpinCount, 9 | 对RtlCriticalSectionLock进行初始化,这个函数还会顺带调用NtOpenKeyedEvent, 10 | 打开KeyedEvent对象的句柄。 11 | 12 | 但是Vista以后的系统对KeyedEvent做了改进,NtWaitForKeyedEvent和 13 | NtReleaseKeyedEvent不再需要句柄,直接传递NULL就能生效。因此进程启动时, 14 | 不再需要打开KeyedEvent对象的句柄。 15 | 16 | NTSTATUS ExpKeyedEventInitialization() 17 | { 18 | ... 19 | HANDLE Handle; 20 | UNICODE_STRING DestinationString; 21 | //前面必须有\\KernelObjects\\,否则返回STATUS_OBJECT_PATH_SYNTAX_BAD 22 | RtlInitUnicodeString(&DestinationString,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 23 | OBJECT_ATTRIBUTES oa; 24 | oa.Length=0x18; 25 | oa.RootDirectory=NULL; 26 | oa.ObjectName=&DestinationString; 27 | oa.Attributes=0x10; //OBJ_PERMANENT,如果在ring3,会返回STATUS_PRIVILEGE_NOT_HELD 28 | oa.SecurityDescriptor=NULL; 29 | oa.SecurityQualityOfService=NULL; 30 | NTSTATUS Error=ZwCreateKeyedEvent(&Handle,0xF0003,&oa,0); //EVENT_ALL_ACCESS&(~SYNCHRONIZE) 31 | if (NT_SUCCESS(Error)) 32 | Error=ZwClose(Handle); //大概是永久对象的存在和引用计数无关了 33 | return Error; 34 | }*/ 35 | 36 | HANDLE NTAPI OpenGlobalKeyedEvent() 37 | { 38 | UNICODE_STRING Name; 39 | RtlInitUnicodeString(&Name,L"\\KernelObjects\\CritSecOutOfMemoryEvent"); 40 | OBJECT_ATTRIBUTES oa; 41 | oa.Length=0x18; 42 | oa.RootDirectory=NULL; 43 | oa.ObjectName=&Name; 44 | oa.Attributes=0; 45 | oa.SecurityDescriptor=NULL; 46 | oa.SecurityQualityOfService=NULL; 47 | HANDLE hKeyedEvent=NULL; 48 | NtOpenKeyedEvent(&hKeyedEvent,0x2000000,&oa); //MAXIMUM_ALLOWED 49 | return hKeyedEvent; 50 | } 51 | 52 | void NTAPI CloseGlobalKeyedEvent(HANDLE hKeyedEvent) 53 | { 54 | if (hKeyedEvent!=NULL) 55 | NtClose(GlobalKeyedEventHandle); 56 | } 57 | 58 | PVOID WINAPI FindDllBase(WCHAR* szName) 59 | { 60 | UNICODE_STRING usName; 61 | RtlInitUnicodeString(&usName,szName); 62 | PEB* pPeb=NtCurrentTeb()->ProcessEnvironmentBlock; 63 | LIST_ENTRY* Head=&pPeb->Ldr->InLoadOrderModuleList; 64 | LIST_ENTRY* Curr=Head->Flink; 65 | while (Curr->Flink!=Head) 66 | { 67 | LDR_DATA_TABLE_ENTRY* Entry=CONTAINING_RECORD(Curr,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks); 68 | if (RtlCompareUnicodeString(&Entry->BaseDllName,&usName,TRUE)==0) 69 | return Entry->DllBase; 70 | Curr=Curr->Flink; 71 | } 72 | return NULL; 73 | } 74 | 75 | void SetReplaceHook(PVOID TargetAddr,PVOID NewAddr,DWORD* OldData) 76 | { 77 | 78 | } 79 | 80 | void RecoverReplaceHook() 81 | { 82 | 83 | } 84 | 85 | void SetFilterHook() 86 | { 87 | 88 | } 89 | 90 | void RecoverFilterHook() 91 | { 92 | 93 | } -------------------------------------------------------------------------------- /xpextk_ver1/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | 4 | void InitTickCount64Helper(); 5 | void UninitTickCount64Helper(); 6 | void InitProcessorIdHelper(); 7 | void UninitProcessorIdHelper(); 8 | 9 | VOID DriverUnload(DRIVER_OBJECT* DriverObject) 10 | { 11 | UninitTickCount64Helper(); 12 | UninitProcessorIdHelper(); 13 | 14 | DbgPrint("Unload success\n"); 15 | } 16 | 17 | NTSTATUS DriverEntry(DRIVER_OBJECT* DriverObject,PUNICODE_STRING RegistryPath) 18 | { 19 | DbgPrint("Enter DriverEntry\n"); 20 | for (int i=0;iMajorFunction[i]=NULL; 22 | DriverObject->DriverUnload=DriverUnload; 23 | 24 | InitTickCount64Helper(); 25 | InitProcessorIdHelper(); 26 | 27 | DbgPrint("Leave DriverEntry\n"); 28 | return STATUS_SUCCESS; 29 | } 30 | -------------------------------------------------------------------------------- /xpextk_ver1/processor.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | 4 | /* 5 | 想要知道线程当前运行在哪个CPU核心上,每个核心就需要一块关联的空间,用来记录和读取ID 6 | 可用的选择大概只有CPU的GDT、IDT、MSR,以及操作系统的KPCR,64个核心需要6bit存储 7 | Win7在KPCR记录了CPU每个核心的编号以及组号,供内核相关API查询 8 | 但是KCPR在Ring0,Ring3想访问就要经过复杂的系统调用,Ring3需要寻找更高效的方案 9 | 10 | 与内核中的其它表不同,Ring3可以通过lsl指令获得段界限,于是Win7选择在GDT记录ID 11 | 如果一个段的长度很短,段界限就用不到更高的位,空出来的部分可以用来记录CPU编号 12 | 存放TEB的那个段就满足要求,它体积不大,索引固定,Ring3代码总是能访问到 13 | 在前面增加几位,让段界限比实际大一些,并没有什么问题,我们修改它就能完成目标 14 | 要做的就是在Ring0将GDT的第8项的14到19位设置上编号,在Ring3用lsl指令读取 15 | 16 | Win7以后的64位系统将CPU编组,还需要记录组号(32位组号总为0) 17 | 组号是一个WORD,应该为16bit,可能是CPU总数也用WORD表示,组号=65536/64=1024个,需要10bit 18 | Win7 x64将组号记录在段界限的低10位,再加上高6位的CPU编号,只剩下中间4位可用 19 | 不过64位CPU设计发生了变化,段地址默认从0开始,覆盖全部地址空间,不再检查段界限 20 | 得益于这项机制,Win7 x64的GDT总数减少,TEB所在段也进行调整,换到了索引10 21 | 22 | 我没能找到Win7内核实现的汇编代码,仅仅是从GetCurrentProcessorNumberEx的汇编推测而来 23 | 理论上是这样的,但是PCHunter对GDT的识别有问题,显示不正常 24 | */ 25 | 26 | #pragma pack(1) 27 | typedef struct _GDTR 28 | { 29 | USHORT Limit; 30 | ULONG Base; 31 | } GDTR; 32 | 33 | typedef struct _GDT 34 | { 35 | USHORT Limit0_15; 36 | USHORT Base0_15; 37 | UCHAR Base16_23; 38 | UCHAR Type:4; 39 | UCHAR S:1; 40 | UCHAR DPL:2; 41 | UCHAR P:1; 42 | UCHAR Limit16_19:4; 43 | UCHAR AVL:1; 44 | UCHAR L:1; 45 | UCHAR D_B:1; 46 | UCHAR G:1; 47 | UCHAR Base24_31; 48 | } GDT; 49 | 50 | typedef struct _SELECTOR 51 | { 52 | USHORT RPL:2; 53 | USHORT TI:1; 54 | USHORT Index:13; 55 | } SELECTOR; 56 | #pragma pack() 57 | 58 | void InitProcessorIdHelper() 59 | { 60 | ULONG core=KeNumberProcessors; 61 | if (core>32) 62 | core=32; 63 | for (ULONG i=0;i>2)&0x0F; 74 | } 75 | KeRevertToUserAffinityThread(); 76 | } 77 | 78 | void UninitProcessorIdHelper() 79 | { 80 | ULONG core=KeNumberProcessors; 81 | if (core>32) 82 | core=32; 83 | for (ULONG i=0;i 3 | 4 | /* 5 | Windows时间的最小单元是100ns,一个tick持续多个单元的时间 6 | 当时钟中断发生时,相对上一次中断又流逝了一些时间 7 | 系统从当前tick减去经过的时间,剩余的时间记录在KiTickOffset 8 | 如果剩余时间小于0,代表时间经过了一个tick,当前tick结束 9 | 此时需要更新tick数,统计线程工作时间,计算线程时间片(quantum) 10 | 环境允许的情况下,还会调用KiTimeUpdateNotifyRoutine(Win7不再支持) 11 | 最后,为KiTickOffset补充KeMaximumIncrement个时间单元,进入下个tick 12 | (Win2003的代码里,会根据时间计算出经过了几个tick,而非总是加1个) 13 | 如果剩余时间大于0,会处理一些DPC的内容,这里就不管了 14 | 15 | 更新tick时,首先更新KeTickCount,这是个64位的值,足够记录数万年 16 | 但GetTickCount不使用这个值,而是KUSER_SHARED_DATA里的值 17 | Win7下是偏移0x320的TickCount字段,同样也是64位 18 | XP下是偏移0的TickCountLow,只有32位,系统运行一段时间后溢出归零 19 | 因为GetTickCount返回也是32位的,一个周期只有49.7天,系统会在溢出后略微调整 20 | 21 | 只要在KeUpdateSystemTime更新TickCountLow时,同时更新TickCount,就能实现功能 22 | 方案1是改ntoskrnl.exe的文件,效果稳定,但麻烦且通用性差 23 | 方案2是设置一个Timer,定时把KeTickCount复制过去,最简单但异步操作精度太差 24 | 方案3是使用KiTimeUpdateNotifyRoutine,但它只有一个位置,可能被某些特殊软件占用 25 | (注意,判断函数非空和调用函数是分开的,而且没有加锁,清空回调指针有极低概率蓝屏) 26 | 27 | 尽管Windows通过一些算法,同一时间只允许一个核心执行KeUpdateSystemTime 28 | 但是仍有异步的情况发生,比如用户修改时间,也会调整KeTickCount 29 | 更新tick为了效率没有使用锁,可能导致KSYSTEM_TIME的Low和High1两个字段不同步 30 | 所以Win7 32位引入High2Time,值与High1Time相同,在最后写入 31 | 如果读取时,High2Time和High1Time不同,说明写入没有完成,或线程间覆盖写入 32 | GetTickCount稍等一会,循环再次读取,两者相同时,就代表结果正常了 33 | XP使用的计时器是老式的RTC,精度远不如新式的HPET计时器,没必要在意误差了 34 | 至于Win7 64位,64位的操作数可以一次性写完两个字段,不需要这种同步方式 35 | */ 36 | 37 | /* 38 | VOID __fastcall KeUpdateSystemTime_Win7_32(KIRQL OldIrql,LONG Increment,KTRAP_FRAME* TrFrame) 39 | { 40 | //... 41 | LONG MasterOffset=InterlockedExchangeAdd(&Kprcb->MasterOffset,-Increment); 42 | MasterOffset=MasterOffset-Increment; 43 | if (MasterOffset<=0) 44 | { 45 | ULONG SpinCount=0; 46 | while (KeTickCount.High1Time!=KeTickCount.High2Time) 47 | { 48 | SpinCount++; 49 | //HvlLongSpinCountMask=0xFFFFFFFF 50 | if ((SpinCount&HvlLongSpinCountMask)==0 && (HvlEnlightenments&0x40)) 51 | HvlNotifyLongSpinWait(SpinCount); 52 | _mm_pause(); 53 | } 54 | ULONGLONG TickCount=*(ULONGLONG*)&KeTickCount; 55 | TickCount++; 56 | KeTickCount.High2Time=(ULONG)(TickCount>>32); 57 | *(ULONGLONG*)&KeTickCount=TickCount; 58 | 59 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 60 | KUserSharedData->TickCount.High2Time=(ULONG)(TickCount>>32); 61 | *(ULONGLONG*)&KUserSharedData->TickCount=TickCount; 62 | 63 | Kprcb->MasterOffset=KeMaximumIncrement+MasterOffset; 64 | } 65 | //... 66 | } 67 | 68 | VOID __stdcall KeUpdateSystemTime_XP(KIRQL OldIrql,ULONG Vector,KTRAP_FRAME* TrFramePtr) 69 | { 70 | //XPSP1\NT\base\hals\halacpi\i386\ixclock.asm 71 | LONG TimeIncrement=eax; 72 | KTRAP_FRAME* TrFrame=ebp; 73 | LONG Zero=ebx; 74 | 75 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 76 | ULONGLONG InterruptTime=*(ULONGLONG*)&KUserSharedData->InterruptTime; 77 | InterruptTime=InterruptTime+TimeIncrement; 78 | KUserSharedData->InterruptTime.High2Time=(ULONG)(InterruptTime>>32); 79 | *(ULONGLONG*)&KUserSharedData->InterruptTime=InterruptTime; 80 | 81 | ULONG OldTime=KeTickCount->LowPart; 82 | KiTickOffset=KiTickOffset-TimeIncrement; 83 | if (KiTickOffset<=0) 84 | { 85 | ULONGLONG SystemTime=*(ULONGLONG*)&KUserSharedData->SystemTime; 86 | SystemTime=SystemTime+KeTimeAdjustment; 87 | KUserSharedData->SystemTime.High2Time=(ULONG)(SystemTime>>32); 88 | *(ULONGLONG*)&KUserSharedData->SystemTime=SystemTime; 89 | 90 | ULONGLONG TickCount=*(ULONGLONG*)&KeTickCount; 91 | TickCount++; 92 | KeTickCount.High2Time=(ULONG)(TickCount>>32); 93 | *(ULONGLONG*)&KeTickCount=TickCount; 94 | 95 | if (KUserSharedData->TickCountLowDeprecated+1==0) //TickCountLow溢出 96 | ExpTickCountAdjustmentCount++; 97 | 98 | KUserSharedData->TickCountLowDeprecated=KeTickCount.LowPart+ 99 | ExpTickCountAdjustment*ExpTickCountAdjustmentCount; 100 | //... 101 | } 102 | 103 | //中间的部分是做一些DPC相关的操作,可参考NT5代码,这里不写了 104 | //Win2K3\NT\base\ntos\ke\ia64\clock.c 105 | //XPSP1\NT\base\ntos\ke\ia64\clock.c 106 | 107 | if (KiTickOffset<=0) 108 | { 109 | KiTickOffset=KiTickOffset+KeMaximumIncrement; 110 | KeUpdateRunTime(OldIrql); 111 | _asm cli; 112 | HalEndSystemInterrupt(); 113 | } 114 | else 115 | { 116 | KeGetCurrentPrcb()->InterruptCount++; 117 | _asm cli; 118 | HalEndSystemInterrupt(); 119 | } 120 | } 121 | 122 | VOID __stdcall KeUpdateRunTime_XP(KIRQL OldIrql) 123 | { 124 | KTRAP_FRAME* TrFrame=ebp; 125 | //KPRCB在KPCR偏移0x120处,这里直接用KPRCB 126 | KPRCB* Prcb=KeGetCurrentPrcb(); 127 | Prcb->InterruptCount++; 128 | KTHREAD* Thread=Prcb->CurrentThread; 129 | KPROCESS* Process=Thread->ApcState.Process; 130 | if (TrFrame->EFlags&0x00020000 //Virtual 8086 Mode 131 | || TrFrame->SegCs&1) 132 | { 133 | //edx=1 134 | Prcb->UserTime++; 135 | Thread->UserTime++; 136 | InterlockedIncrement((LONG*)&Process->UserTime); 137 | //lea ecx, [ecx+0] 138 | if (KiTimeUpdateNotifyRoutine!=NULL) 139 | KiTimeUpdateNotifyRoutine(PsGetCurrentThreadId()); //ecx=ETHREAD::UniqueThread 140 | } 141 | else 142 | { 143 | //edx=0 144 | Prcb->KernelTime++; 145 | if (OldIrql==DISPATCH_LEVEL && Prcb->DpcRoutineActive!=0) 146 | { 147 | Prcb->DpcTime++; 148 | } 149 | else if (OldIrql>DISPATCH_LEVEL) 150 | { 151 | Prcb->InterruptTime++; 152 | } 153 | else //OldIrqlDpcRoutineActive==0) 154 | { 155 | Thread->KernelTime++; 156 | InterlockedIncrement((LONG*)&Process->KernelTime); 157 | if (KiTimeUpdateNotifyRoutine!=NULL) 158 | KiTimeUpdateNotifyRoutine(PsGetCurrentThreadId()); 159 | } 160 | } 161 | //... 162 | } 163 | */ 164 | 165 | typedef VOID (__fastcall*FNTIMEUPDATECALLBACK)(HANDLE ThreadId); 166 | extern "C" NTSYSAPI VOID __fastcall KeSetTimeUpdateNotifyRoutine(FNTIMEUPDATECALLBACK TimeUpdateCallback); 167 | KSYSTEM_TIME* KeTickCountAddr=NULL; 168 | 169 | //测试阶段,先采用KiTimeUpdateNotifyRoutine 170 | VOID __fastcall KeTimeUpdateCallback(HANDLE ThreadId) 171 | { 172 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 173 | ULONGLONG TickCount=*(ULONGLONG*)KeTickCountAddr; 174 | KUserSharedData->TickCount.High2Time=(ULONG)(TickCount>>32); 175 | *(ULONGLONG*)&KUserSharedData->TickCount=TickCount; 176 | } 177 | 178 | void InitTickCount64Helper() 179 | { 180 | UNICODE_STRING SymbolName; 181 | RtlInitUnicodeString(&SymbolName,L"KeTickCount"); 182 | KeTickCountAddr=(KSYSTEM_TIME*)MmGetSystemRoutineAddress(&SymbolName); 183 | DbgPrint("KeTickCount Address:%08X\n",KeTickCountAddr); 184 | KeSetTimeUpdateNotifyRoutine(KeTimeUpdateCallback); 185 | } 186 | 187 | void UninitTickCount64Helper() 188 | { 189 | ULONG* AsmAddr=(ULONG*)((ULONG)KeSetTimeUpdateNotifyRoutine+2); 190 | ULONG* KiTimeUpdateNotifyRoutine=(ULONG*)*AsmAddr; 191 | DbgPrint("KiTimeUpdateNotifyRoutine:%08X\n",KiTimeUpdateNotifyRoutine); 192 | *KiTimeUpdateNotifyRoutine=NULL; 193 | } 194 | -------------------------------------------------------------------------------- /xpextk_ver2/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | 4 | void InitTickCount64Helper(); 5 | void UninitTickCount64Helper(); 6 | void InitProcessorIdHelper(); 7 | void UninitProcessorIdHelper(); 8 | void InitProcessInfoSsdtHook(); 9 | void UninitProcessInfoSsdtHook(); 10 | 11 | VOID DriverUnload(DRIVER_OBJECT* DriverObject) 12 | { 13 | UninitTickCount64Helper(); 14 | UninitProcessorIdHelper(); 15 | UninitProcessInfoSsdtHook(); 16 | 17 | DbgPrint("Unload success\n"); 18 | } 19 | 20 | NTSTATUS DriverEntry(DRIVER_OBJECT* DriverObject,PUNICODE_STRING RegistryPath) 21 | { 22 | DbgPrint("Enter DriverEntry\n"); 23 | for (int i=0;iMajorFunction[i]=NULL; 25 | DriverObject->DriverUnload=DriverUnload; 26 | 27 | InitTickCount64Helper(); 28 | InitProcessorIdHelper(); 29 | InitProcessInfoSsdtHook(); 30 | 31 | DbgPrint("Leave DriverEntry\n"); 32 | return STATUS_SUCCESS; 33 | } -------------------------------------------------------------------------------- /xpextk_ver2/processinfo.cpp: -------------------------------------------------------------------------------- 1 |  2 | //#include 3 | #include 4 | 5 | //XP没有导出PsReferenceProcessFilePointer和MmGetFileObjectForSection 6 | //这里使用XP的代码,Win7代码略有不同 7 | _declspec(naked) 8 | PVOID __stdcall MmGetFileObjectForSection(PVOID SectionObject) 9 | { 10 | _asm 11 | { 12 | mov edi, edi; 13 | push ebp; 14 | mov ebp, esp; 15 | mov eax, [ebp+8]; //SECTION_OBJECT* SectionObject; 16 | mov eax, [eax+14h]; //SEGMENT_OBJECT* Segment; 17 | mov eax, [eax]; //CONTROL_AREA* BaseAddress; 18 | mov eax, [eax+24h]; //FILE_OBJECT* FilePointer; 19 | pop ebp; 20 | retn 4; 21 | } 22 | } 23 | 24 | NTSTATUS 25 | NTAPI 26 | PsReferenceProcessFilePointer( 27 | PEPROCESS Process, 28 | FILE_OBJECT** OutFileObject 29 | ) 30 | { 31 | EX_RUNDOWN_REF* RundownProtect=(EX_RUNDOWN_REF*)((UCHAR*)Process+0x80); 32 | if (!ExAcquireRundownProtection(RundownProtect)) 33 | return STATUS_UNSUCCESSFUL; 34 | PVOID SectionObject=*(PVOID*)((UCHAR*)Process+0x138); 35 | if (SectionObject==NULL) 36 | { 37 | ExReleaseRundownProtection(RundownProtect); 38 | return STATUS_UNSUCCESSFUL; 39 | } 40 | FILE_OBJECT* FileObject=(FILE_OBJECT*)MmGetFileObjectForSection(SectionObject); 41 | *OutFileObject=FileObject; 42 | ObfReferenceObject(FileObject); 43 | ExReleaseRundownProtection(RundownProtect); 44 | return STATUS_SUCCESS; 45 | } 46 | 47 | NTSTATUS NTAPI NtQueryInformationProcess43( 48 | HANDLE ProcessHandle, 49 | PROCESSINFOCLASS ProcessInformationClass, 50 | PVOID ProcessInformation, 51 | ULONG ProcessInformationLength, 52 | PULONG ReturnLength 53 | ) 54 | { 55 | //ProcessImageFileName通过ObQueryNameString(FileObject)获得文件名 56 | //ProcessImageFileNameWin32通过IoQueryFileDosDeviceName(FileObject)获得文件名 57 | 58 | //PreviousMode在XP的偏移是0x140,在Win7的偏移是0x13A 59 | KPROCESSOR_MODE PreviousMode=*(KPROCESSOR_MODE*)((UCHAR*)KeGetCurrentThread()+0x140); 60 | PEPROCESS Process; 61 | //XP不支持PROCESS_QUERY_LIMITED_INFORMATION(0x1000),使用PROCESS_QUERY_INFORMATION(0x400)代替 62 | NTSTATUS Result=ObReferenceObjectByHandle(ProcessHandle,0x400,*PsProcessType,PreviousMode,(PVOID*)&Process,NULL); 63 | if (!NT_SUCCESS(Result)) 64 | return Result; 65 | FILE_OBJECT* FileObject; 66 | Result=PsReferenceProcessFilePointer(Process,&FileObject); 67 | ObfDereferenceObject(Process); 68 | if (!NT_SUCCESS(Result)) 69 | return Result; 70 | OBJECT_NAME_INFORMATION* FileName; 71 | Result=IoQueryFileDosDeviceName(FileObject,&FileName); 72 | ObfDereferenceObject(FileObject); 73 | if (!NT_SUCCESS(Result)) 74 | return Result; 75 | //这里用MaximumLength而不是Length,可能是因为要复制结尾的\0 76 | ULONG RequireSize=FileName->Name.MaximumLength+sizeof(UNICODE_STRING); 77 | __try 78 | { 79 | if (ProcessInformationLengthLength=FileName->Name.Length; 87 | OutName->MaximumLength=FileName->Name.MaximumLength; 88 | if (FileName->Name.MaximumLength>0) 89 | { 90 | OutName->Buffer=(WCHAR*)((UCHAR*)ProcessInformation+sizeof(UNICODE_STRING)); 91 | memcpy(OutName->Buffer,FileName->Name.Buffer,FileName->Name.MaximumLength); 92 | } 93 | else 94 | { 95 | OutName->Buffer=NULL; 96 | } 97 | } 98 | if (ReturnLength!=NULL) 99 | *ReturnLength=RequireSize; 100 | } 101 | __except(EXCEPTION_EXECUTE_HANDLER) 102 | { 103 | return GetExceptionCode(); 104 | } 105 | ExFreePool(FileName); 106 | return Result; 107 | } 108 | 109 | typedef NTSTATUS (NTAPI* TypeNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG); 110 | TypeNtQueryInformationProcess NtQueryInformationProcessOld; 111 | 112 | NTSTATUS NTAPI NtQueryInformationProcessExtend( 113 | HANDLE ProcessHandle, 114 | PROCESSINFOCLASS ProcessInformationClass, 115 | PVOID ProcessInformation, 116 | ULONG ProcessInformationLength, 117 | PULONG ReturnLength 118 | ) 119 | { 120 | if (ProcessInformationClass!=ProcessImageFileNameWin32) 121 | { 122 | return NtQueryInformationProcessOld(ProcessHandle,ProcessInformationClass, 123 | ProcessInformation,ProcessInformationLength,ReturnLength); 124 | } 125 | else 126 | { 127 | return NtQueryInformationProcess43(ProcessHandle,ProcessInformationClass, 128 | ProcessInformation,ProcessInformationLength,ReturnLength); 129 | } 130 | } 131 | 132 | typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE 133 | { 134 | PVOID* ServiceTable; //函数地址表 135 | PULONG InvokeCountTable; 136 | ULONG ServiceLimit; //函数的个数 137 | PUCHAR ParamSizeTable; //栈中参数总长表 138 | } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR; 139 | 140 | extern "C" KSERVICE_TABLE_DESCRIPTOR* KeServiceDescriptorTable; 141 | 142 | void InitProcessInfoSsdtHook() 143 | { 144 | NtQueryInformationProcessOld=(TypeNtQueryInformationProcess)KeServiceDescriptorTable[0].ServiceTable[154]; 145 | KeServiceDescriptorTable[0].ServiceTable[154]=NtQueryInformationProcessExtend; 146 | DbgPrint("Original NtQueryInformationProcess:%08X\n",NtQueryInformationProcessOld); 147 | } 148 | 149 | void UninitProcessInfoSsdtHook() 150 | { 151 | DbgPrint("Current NtQueryInformationProcess:%08X\n",KeServiceDescriptorTable[0].ServiceTable[154]); 152 | KeServiceDescriptorTable[0].ServiceTable[154]=NtQueryInformationProcessOld; 153 | } -------------------------------------------------------------------------------- /xpextk_ver2/processor.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | 4 | /* 5 | 想要知道线程当前运行在哪个CPU核心上,每个核心就需要一块关联的空间,用来记录和读取ID 6 | 可用的选择大概只有CPU的GDT、IDT、MSR,以及操作系统的KPCR,64个核心需要6bit存储 7 | Win7在KPCR记录了CPU每个核心的编号以及组号,供内核相关API查询 8 | 但是KCPR在Ring0,Ring3想访问就要经过复杂的系统调用,Ring3需要寻找更高效的方案 9 | 10 | 与内核中的其它表不同,Ring3可以通过lsl指令获得段界限,于是Win7选择在GDT记录ID 11 | 如果一个段的长度很短,段界限就用不到更高的位,空出来的部分可以用来记录CPU编号 12 | 存放TEB的那个段就满足要求,它体积不大,索引固定,Ring3代码总是能访问到 13 | 在前面增加几位,让段界限比实际大一些,并没有什么问题,我们修改它就能完成目标 14 | 要做的就是在Ring0将GDT的第8项的14到19位设置上编号,在Ring3用lsl指令读取 15 | 16 | Win7以后的64位系统将CPU编组,还需要记录组号(32位组号总为0) 17 | 组号是一个WORD,应该为16bit,可能是CPU总数也用WORD表示,组号=65536/64=1024个,需要10bit 18 | Win7 x64将组号记录在段界限的低10位,再加上高6位的CPU编号,只剩下中间4位可用 19 | 不过64位CPU设计发生了变化,段地址默认从0开始,覆盖全部地址空间,不再检查段界限 20 | 得益于这项机制,Win7 x64的GDT总数减少,TEB所在段也进行调整,换到了索引10 21 | 22 | 我没能找到Win7内核实现的汇编代码,仅仅是从GetCurrentProcessorNumberEx的汇编推测而来 23 | 理论上是这样的,但是PCHunter对GDT的识别有问题,显示不正常 24 | */ 25 | 26 | #pragma pack(1) 27 | typedef struct _GDTR 28 | { 29 | USHORT Limit; 30 | ULONG Base; 31 | } GDTR; 32 | 33 | typedef struct _GDT 34 | { 35 | USHORT Limit0_15; 36 | USHORT Base0_15; 37 | UCHAR Base16_23; 38 | UCHAR Type:4; 39 | UCHAR S:1; 40 | UCHAR DPL:2; 41 | UCHAR P:1; 42 | UCHAR Limit16_19:4; 43 | UCHAR AVL:1; 44 | UCHAR L:1; 45 | UCHAR D_B:1; 46 | UCHAR G:1; 47 | UCHAR Base24_31; 48 | } GDT; 49 | 50 | typedef struct _SELECTOR 51 | { 52 | USHORT RPL:2; 53 | USHORT TI:1; 54 | USHORT Index:13; 55 | } SELECTOR; 56 | #pragma pack() 57 | 58 | void InitProcessorIdHelper() 59 | { 60 | ULONG core=KeNumberProcessors; 61 | if (core>32) 62 | core=32; 63 | for (ULONG i=0;i>2)&0x0F; 74 | } 75 | KeRevertToUserAffinityThread(); 76 | } 77 | 78 | void UninitProcessorIdHelper() 79 | { 80 | ULONG core=KeNumberProcessors; 81 | if (core>32) 82 | core=32; 83 | for (ULONG i=0;i 3 | 4 | /* 5 | Windows时间的最小单元是100ns,一个tick持续多个单元的时间 6 | 当时钟中断发生时,相对上一次中断又流逝了一些时间 7 | 系统从当前tick减去经过的时间,剩余的时间记录在KiTickOffset 8 | 如果剩余时间小于0,代表时间经过了一个tick,当前tick结束 9 | 此时需要更新tick数,统计线程工作时间,计算线程时间片(quantum) 10 | 环境允许的情况下,还会调用KiTimeUpdateNotifyRoutine(Win7不再支持) 11 | 最后,为KiTickOffset补充KeMaximumIncrement个时间单元,进入下个tick 12 | (Win2003的代码里,会根据时间计算出经过了几个tick,而非总是加1个) 13 | 如果剩余时间大于0,会处理一些DPC的内容,这里就不管了 14 | 15 | 更新tick时,首先更新KeTickCount,这是个64位的值,足够记录数万年 16 | 但GetTickCount不使用这个值,而是KUSER_SHARED_DATA里的值 17 | Win7下是偏移0x320的TickCount字段,同样也是64位 18 | XP下是偏移0的TickCountLow,只有32位,系统运行一段时间后溢出归零 19 | 因为GetTickCount返回也是32位的,一个周期只有49.7天,系统会在溢出后略微调整 20 | 21 | 只要在KeUpdateSystemTime更新TickCountLow时,同时更新TickCount,就能实现功能 22 | 方案1是改ntoskrnl.exe的文件,效果稳定,但麻烦且通用性差 23 | 方案2是设置一个Timer,定时把KeTickCount复制过去,最简单但异步操作精度太差 24 | 方案3是使用KiTimeUpdateNotifyRoutine,但它只有一个位置,可能被某些特殊软件占用 25 | (注意,判断函数非空和调用函数是分开的,而且没有加锁,清空回调指针有极低概率蓝屏) 26 | 27 | 尽管Windows通过一些算法,同一时间只允许一个核心执行KeUpdateSystemTime 28 | 但是仍有异步的情况发生,比如用户修改时间,也会调整KeTickCount 29 | 更新tick为了效率没有使用锁,可能导致KSYSTEM_TIME的Low和High1两个字段不同步 30 | 所以Win7 32位引入High2Time,值与High1Time相同,在最后写入 31 | 如果读取时,High2Time和High1Time不同,说明写入没有完成,或线程间覆盖写入 32 | GetTickCount稍等一会,循环再次读取,两者相同时,就代表结果正常了 33 | XP使用的计时器是老式的RTC,精度远不如新式的HPET计时器,没必要在意误差了 34 | 至于Win7 64位,64位的操作数可以一次性写完两个字段,不需要这种同步方式 35 | */ 36 | 37 | /* 38 | VOID __fastcall KeUpdateSystemTime_Win7_32(KIRQL OldIrql,LONG Increment,KTRAP_FRAME* TrFrame) 39 | { 40 | //... 41 | LONG MasterOffset=InterlockedExchangeAdd(&Kprcb->MasterOffset,-Increment); 42 | MasterOffset=MasterOffset-Increment; 43 | if (MasterOffset<=0) 44 | { 45 | ULONG SpinCount=0; 46 | while (KeTickCount.High1Time!=KeTickCount.High2Time) 47 | { 48 | SpinCount++; 49 | //HvlLongSpinCountMask=0xFFFFFFFF 50 | if ((SpinCount&HvlLongSpinCountMask)==0 && (HvlEnlightenments&0x40)) 51 | HvlNotifyLongSpinWait(SpinCount); 52 | _mm_pause(); 53 | } 54 | ULONGLONG TickCount=*(ULONGLONG*)&KeTickCount; 55 | TickCount++; 56 | KeTickCount.High2Time=(ULONG)(TickCount>>32); 57 | *(ULONGLONG*)&KeTickCount=TickCount; 58 | 59 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 60 | KUserSharedData->TickCount.High2Time=(ULONG)(TickCount>>32); 61 | *(ULONGLONG*)&KUserSharedData->TickCount=TickCount; 62 | 63 | Kprcb->MasterOffset=KeMaximumIncrement+MasterOffset; 64 | } 65 | //... 66 | } 67 | 68 | VOID __stdcall KeUpdateSystemTime_XP(KIRQL OldIrql,ULONG Vector,KTRAP_FRAME* TrFramePtr) 69 | { 70 | //XPSP1\NT\base\hals\halacpi\i386\ixclock.asm 71 | LONG TimeIncrement=eax; 72 | KTRAP_FRAME* TrFrame=ebp; 73 | LONG Zero=ebx; 74 | 75 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 76 | ULONGLONG InterruptTime=*(ULONGLONG*)&KUserSharedData->InterruptTime; 77 | InterruptTime=InterruptTime+TimeIncrement; 78 | KUserSharedData->InterruptTime.High2Time=(ULONG)(InterruptTime>>32); 79 | *(ULONGLONG*)&KUserSharedData->InterruptTime=InterruptTime; 80 | 81 | ULONG OldTime=KeTickCount->LowPart; 82 | KiTickOffset=KiTickOffset-TimeIncrement; 83 | if (KiTickOffset<=0) 84 | { 85 | ULONGLONG SystemTime=*(ULONGLONG*)&KUserSharedData->SystemTime; 86 | SystemTime=SystemTime+KeTimeAdjustment; 87 | KUserSharedData->SystemTime.High2Time=(ULONG)(SystemTime>>32); 88 | *(ULONGLONG*)&KUserSharedData->SystemTime=SystemTime; 89 | 90 | ULONGLONG TickCount=*(ULONGLONG*)&KeTickCount; 91 | TickCount++; 92 | KeTickCount.High2Time=(ULONG)(TickCount>>32); 93 | *(ULONGLONG*)&KeTickCount=TickCount; 94 | 95 | if (KUserSharedData->TickCountLowDeprecated+1==0) //TickCountLow溢出 96 | ExpTickCountAdjustmentCount++; 97 | 98 | KUserSharedData->TickCountLowDeprecated=KeTickCount.LowPart+ 99 | ExpTickCountAdjustment*ExpTickCountAdjustmentCount; 100 | //... 101 | } 102 | 103 | //中间的部分是做一些DPC相关的操作,可参考NT5代码,这里不写了 104 | //Win2K3\NT\base\ntos\ke\ia64\clock.c 105 | //XPSP1\NT\base\ntos\ke\ia64\clock.c 106 | 107 | if (KiTickOffset<=0) 108 | { 109 | KiTickOffset=KiTickOffset+KeMaximumIncrement; 110 | KeUpdateRunTime(OldIrql); 111 | _asm cli; 112 | HalEndSystemInterrupt(); 113 | } 114 | else 115 | { 116 | KeGetCurrentPrcb()->InterruptCount++; 117 | _asm cli; 118 | HalEndSystemInterrupt(); 119 | } 120 | } 121 | 122 | VOID __stdcall KeUpdateRunTime_XP(KIRQL OldIrql) 123 | { 124 | KTRAP_FRAME* TrFrame=ebp; 125 | //KPRCB在KPCR偏移0x120处,这里直接用KPRCB 126 | KPRCB* Prcb=KeGetCurrentPrcb(); 127 | Prcb->InterruptCount++; 128 | KTHREAD* Thread=Prcb->CurrentThread; 129 | KPROCESS* Process=Thread->ApcState.Process; 130 | if (TrFrame->EFlags&0x00020000 //Virtual 8086 Mode 131 | || TrFrame->SegCs&1) 132 | { 133 | //edx=1 134 | Prcb->UserTime++; 135 | Thread->UserTime++; 136 | InterlockedIncrement((LONG*)&Process->UserTime); 137 | //lea ecx, [ecx+0] 138 | if (KiTimeUpdateNotifyRoutine!=NULL) 139 | KiTimeUpdateNotifyRoutine(PsGetCurrentThreadId()); //ecx=ETHREAD::UniqueThread 140 | } 141 | else 142 | { 143 | //edx=0 144 | Prcb->KernelTime++; 145 | if (OldIrql==DISPATCH_LEVEL && Prcb->DpcRoutineActive!=0) 146 | { 147 | Prcb->DpcTime++; 148 | } 149 | else if (OldIrql>DISPATCH_LEVEL) 150 | { 151 | Prcb->InterruptTime++; 152 | } 153 | else //OldIrqlDpcRoutineActive==0) 154 | { 155 | Thread->KernelTime++; 156 | InterlockedIncrement((LONG*)&Process->KernelTime); 157 | if (KiTimeUpdateNotifyRoutine!=NULL) 158 | KiTimeUpdateNotifyRoutine(PsGetCurrentThreadId()); 159 | } 160 | } 161 | //... 162 | } 163 | */ 164 | 165 | typedef VOID (__fastcall*FNTIMEUPDATECALLBACK)(HANDLE ThreadId); 166 | extern "C" NTSYSAPI VOID __fastcall KeSetTimeUpdateNotifyRoutine(FNTIMEUPDATECALLBACK TimeUpdateCallback); 167 | KSYSTEM_TIME* KeTickCountAddr=NULL; 168 | 169 | //测试阶段,先采用KiTimeUpdateNotifyRoutine 170 | VOID __fastcall KeTimeUpdateCallback(HANDLE ThreadId) 171 | { 172 | KUSER_SHARED_DATA* KUserSharedData=(KUSER_SHARED_DATA*)0xFFDF0000; 173 | ULONGLONG TickCount=*(ULONGLONG*)KeTickCountAddr; 174 | KUserSharedData->TickCount.High2Time=(ULONG)(TickCount>>32); 175 | *(ULONGLONG*)&KUserSharedData->TickCount=TickCount; 176 | } 177 | 178 | void InitTickCount64Helper() 179 | { 180 | UNICODE_STRING SymbolName; 181 | RtlInitUnicodeString(&SymbolName,L"KeTickCount"); 182 | KeTickCountAddr=(KSYSTEM_TIME*)MmGetSystemRoutineAddress(&SymbolName); 183 | DbgPrint("KeTickCount Address:%08X\n",KeTickCountAddr); 184 | KeSetTimeUpdateNotifyRoutine(KeTimeUpdateCallback); 185 | } 186 | 187 | void UninitTickCount64Helper() 188 | { 189 | ULONG* AsmAddr=(ULONG*)((ULONG)KeSetTimeUpdateNotifyRoutine+2); 190 | ULONG* KiTimeUpdateNotifyRoutine=(ULONG*)*AsmAddr; 191 | DbgPrint("KiTimeUpdateNotifyRoutine:%08X\n",KiTimeUpdateNotifyRoutine); 192 | *KiTimeUpdateNotifyRoutine=NULL; 193 | } --------------------------------------------------------------------------------