From a2ac7ccb5c8fa14a278ee9eebbfb3ec6750bbdb5 Mon Sep 17 00:00:00 2001 From: mingkuang Date: Sun, 9 Jun 2024 17:28:28 +0800 Subject: [PATCH] =?UTF-8?q?Fea=20#90=EF=BC=8C=E8=A1=A5=E5=85=85=E4=B8=80?= =?UTF-8?q?=E4=BA=9BChrome=20125=20Windows=207=E7=BC=BA=E5=B0=91=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ThunksList.md | 17 +- src/Shared/km.h | 17 + src/Thunks/DllMainCRTStartup.hpp | 10 +- src/Thunks/YY_Thunks.cpp | 52 + src/Thunks/api-ms-win-core-handle.hpp | 503 ++++++++ src/Thunks/api-ms-win-core-registry.hpp | 1098 +++++++++-------- src/Thunks/api-ms-win-core-wow64.hpp | 291 ++++- src/Thunks/api-ms-win-core-xstate.hpp | 507 ++++---- src/Thunks/d3d12.hpp | 31 + .../ext-ms-win-rtcore-ntuser-wmpointer.hpp | 125 ++ .../YY-Thunks.UnitTest.vcxproj | 4 + .../YY-Thunks.UnitTest.vcxproj.filters | 13 +- .../api-ms-win-core-handle.UnitTest.cpp | 244 ++++ 13 files changed, 2111 insertions(+), 801 deletions(-) create mode 100644 src/Thunks/api-ms-win-core-handle.hpp create mode 100644 src/Thunks/d3d12.hpp create mode 100644 src/Thunks/ext-ms-win-rtcore-ntuser-wmpointer.hpp create mode 100644 src/YY-Thunks.UnitTest/api-ms-win-core-handle.UnitTest.cpp diff --git a/ThunksList.md b/ThunksList.md index d77bc4c3..d4c3951e 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -4,6 +4,11 @@ > 开头带`*`的函数并不建议使用,存在一些较大负面影响,仅用于编译通过处理,具体负面影响可参考注释内容。 +## api-ms-win-core-handle-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| CompareObjectHandles | 不存在时,调用NtQueryObject以及DuplicateHandle。 + ## api-ms-win-core-path-l1-1-0.dll | 函数 | Fallback | ---- | ----------- @@ -175,6 +180,11 @@ | ---- | ----------- | D3D11CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 +## d3d12.dll +| 函数 | Fallback +| ---- | ----------- +| D3D12CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 + ## DbgHelp.dll | 函数 | Fallback | ---- | ----------- @@ -518,7 +528,7 @@ | CreateRemoteThreadEx | 不存在时,调用CreateRemoteThread。 | WerRegisterRuntimeExceptionModule | 不存在时,返回S_OK。 | WerUnregisterRuntimeExceptionModule | 不存在时,返回S_OK。 -| Wow64GetThreadContext | 不存在时,返回ERROR_INVALID_PARAMETER。 +| Wow64GetThreadContext | 不存在时,调用GetThreadContext或者返回ERROR_INVALID_PARAMETER。 ## mfplat.dll | 函数 | Fallback @@ -649,6 +659,11 @@ | DisplayConfigGetDeviceInfo | 不存在时,报告没有安装驱动。 | GetDisplayConfigBufferSizes | 不存在时,报告没有安装驱动。 | QueryDisplayConfig | 不存在时,报告没有安装驱动。 +| RegisterPointerDeviceNotifications | 不存在时,假装成功。 +| GetPointerDevices | 不存在时,假装没有触摸设备。 +| GetPointerDevice | 不存在时,假装没有触摸设备。 +| GetPointerPenInfo | 不存在时,假装没有触摸设备。 +| GetPointerType | 不存在时,假装没有触摸设备。 ## userenv.dll | 函数 | Fallback diff --git a/src/Shared/km.h b/src/Shared/km.h index ca3d4080..aec820b4 100644 --- a/src/Shared/km.h +++ b/src/Shared/km.h @@ -106,6 +106,8 @@ #define NtGetCurrentProcess() (HANDLE)-1 +#define NtGetCurrentThread() (HANDLE)-2 + // begin_access #define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_SAME_ACCESS 0x00000002 @@ -1580,6 +1582,21 @@ NtQueryDirectoryFile ( }; + typedef struct _OBJECT_BASIC_INFORMATION + { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; + } OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION; + typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; diff --git a/src/Thunks/DllMainCRTStartup.hpp b/src/Thunks/DllMainCRTStartup.hpp index f543f3cb..0f5554f9 100644 --- a/src/Thunks/DllMainCRTStartup.hpp +++ b/src/Thunks/DllMainCRTStartup.hpp @@ -64,7 +64,7 @@ namespace YY::Thunks::internal static volatile LONG uStatus = 0; static TlsRawItem* volatile pRoot = nullptr; - static ULONG __fastcall GetTlsIndexBufferCount(TEB* _pTeb) + static SIZE_T __fastcall GetTlsIndexBufferCount(TEB* _pTeb) { auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer; if (!_ppThreadLocalStoragePointer) @@ -135,7 +135,7 @@ namespace YY::Thunks::internal if (!_pfnNtQuerySystemInformation) return nullptr; - ULONG _cbBuffer = max(4096, _szBuffer.uBufferLength); + auto _cbBuffer = max(4096, _szBuffer.uBufferLength); ULONG _cbRet = 0; for (;;) { @@ -157,7 +157,7 @@ namespace YY::Thunks::internal auto _pInfo = (SYSTEM_PROCESS_INFORMATION*)_szBuffer.GetBuffer(0); for (;;) { - if (_pInfo->ProcessId == (HANDLE)_uCurrentProcessId) + if (static_cast(reinterpret_cast(_pInfo->ProcessId)) == _uCurrentProcessId) return _pInfo; if (_pInfo->NextEntryDelta == 0) @@ -316,10 +316,10 @@ namespace YY::Thunks::internal { auto& _Thread = _pProcessInfo->Threads[i]; - if (_uCurrentThreadId == (DWORD)_Thread.ClientId.UniqueThread) + if (_uCurrentThreadId == static_cast(reinterpret_cast(_Thread.ClientId.UniqueThread))) continue; - auto _hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, (DWORD)_Thread.ClientId.UniqueThread); + auto _hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, static_cast(reinterpret_cast(_Thread.ClientId.UniqueThread))); if (!_hThread) { continue; diff --git a/src/Thunks/YY_Thunks.cpp b/src/Thunks/YY_Thunks.cpp index 65a41ca1..67cae136 100644 --- a/src/Thunks/YY_Thunks.cpp +++ b/src/Thunks/YY_Thunks.cpp @@ -9,6 +9,7 @@ _APPLY(dwmapi, "dwmapi" , 0 ) \ _APPLY(d3d9, "d3d9" , 0 ) \ _APPLY(d3d11, "d3d11" , 0 ) \ + _APPLY(d3d12, "d3d12" , 0 ) \ _APPLY(dbghelp, "dbghelp" , USING_UNSAFE_LOAD ) \ _APPLY(dxgi, "dxgi" , 0 ) \ _APPLY(dwrite, "dwrite" , 0 ) \ @@ -38,6 +39,7 @@ _APPLY(wevtapi, "wevtapi" , 0 ) \ _APPLY(winhttp, "winhttp" , 0 ) \ _APPLY(zipfldr, "zipfldr" , LOAD_AS_DATA_FILE ) \ + _APPLY(api_ms_win_core_handle_l1_1_0, "api-ms-win-core-handle-l1-1-0" , 0 ) \ _APPLY(api_ms_win_core_realtime_l1_1_1, "api-ms-win-core-realtime-l1-1-1" , 0 ) \ _APPLY(api_ms_win_core_winrt_l1_1_0, "api-ms-win-core-winrt-l1-1-0" , 0 ) \ _APPLY(api_ms_win_core_winrt_string_l1_1_0, "api-ms-win-core-winrt-string-l1-1-0", 0 ) \ @@ -252,6 +254,34 @@ namespace YY::Thunks::internal return internal::MakeVersion(_pPeb->OSMajorVersion, _pPeb->OSMinorVersion); } + const SYSTEM_INFO& GetNativeSystemInfo() + { + static SYSTEM_INFO s_SystemInfo; + // 0: 尚未初始化 + // 1:正在初始化 + // 2:已经初始化完成 + static volatile LONG s_InitOnce; + + auto _nResult = InterlockedCompareExchange(&s_InitOnce, 1, 0); + if (_nResult == 0) + { + // 成功锁定 + ::GetNativeSystemInfo(&s_SystemInfo); + InterlockedExchange(&s_InitOnce, 2); + } + else if (_nResult == 1) + { + // 其他线程正在初始化 + do + { + YieldProcessor(); + + } while (s_InitOnce == 1); + } + + return s_SystemInfo; + } + _Check_return_ _Ret_maybenull_ _Post_writable_byte_size_(_cbBytes) @@ -783,6 +813,28 @@ namespace YY::Thunks::internal return ERROR_SUCCESS; } + static bool __fastcall IsEqualI(const UNICODE_STRING& _Left, const UNICODE_STRING& _Right) + { + if (_Left.Length != _Right.Length) + return false; + + return __wcsnicmp_ascii(_Left.Buffer, _Right.Buffer, _Left.Length / 2) == 0; + } + + static bool __fastcall IsEqual(const UNICODE_STRING& _Left, const UNICODE_STRING& _Right) + { + if (_Left.Length != _Right.Length) + return false; + + return memcmp(_Left.Buffer, _Right.Buffer, _Left.Length) == 0; + } + + template + static constexpr UNICODE_STRING __fastcall MakeStaticUnicodeString(const wchar_t (&_Right)[kLength]) + { + UNICODE_STRING _Result = { (kLength - 1)* sizeof(_Right[0]), kLength * sizeof(_Right[0]), const_cast(_Right) }; + return _Result; + } } } //namespace YY diff --git a/src/Thunks/api-ms-win-core-handle.hpp b/src/Thunks/api-ms-win-core-handle.hpp new file mode 100644 index 00000000..0b703305 --- /dev/null +++ b/src/Thunks/api-ms-win-core-handle.hpp @@ -0,0 +1,503 @@ + +#if defined(YY_Thunks_Implemented) +namespace YY::Thunks +{ + namespace + { +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + static SRWLOCK g_CompareObjectHandles; + + union ObjectStaticBuffer + { + wchar_t Buffer[1024]; + OBJECT_TYPE_INFORMATION TypeInfo; + OBJECT_BASIC_INFORMATION BaseInfo; + OBJECT_NAME_INFORMATION NameInfo; + BY_HANDLE_FILE_INFORMATION FileInformation; + TOKEN_SOURCE TokenSource; + }; + + typedef bool(__fastcall* CompareObjectFunType)(HANDLE _hLeft, ObjectStaticBuffer& _LeftBuffer, HANDLE _hRigth, ObjectStaticBuffer& _RightBuffer); + + struct CompareObjectItem + { + UNICODE_STRING TypeName; + CompareObjectFunType pfnCompareObject; + + template + constexpr CompareObjectItem(const wchar_t(&_szTypeName)[kLength], CompareObjectFunType _pfnCompareObject) + : TypeName(internal::MakeStaticUnicodeString(_szTypeName)) + , pfnCompareObject(_pfnCompareObject) + { + } + }; + + bool __fastcall CompareObjectName(HANDLE _hLeft, ObjectStaticBuffer& _LeftBuffer, HANDLE _hRigth, ObjectStaticBuffer& _RightBuffer) noexcept + { + const auto _pfnNtQueryObject = try_get_NtQueryObject(); + if (!_pfnNtQueryObject) + return false; + + LONG _Status = _pfnNtQueryObject(_hLeft, ObjectNameInformation, &_LeftBuffer, sizeof(_LeftBuffer), nullptr); + if (_Status < 0) + { + return false; + } + _Status = _pfnNtQueryObject(_hRigth, ObjectNameInformation, &_RightBuffer, sizeof(_RightBuffer), nullptr); + if (_Status < 0) + { + return false; + } + + return internal::IsEqual(_LeftBuffer.NameInfo.Name, _RightBuffer.NameInfo.Name); + } + + bool __fastcall CompareProcessId(HANDLE _hLeft, ObjectStaticBuffer& _LeftBuffer, HANDLE _hRigth, ObjectStaticBuffer& _RightBuffer) noexcept + { + decltype(DuplicateHandle)* _pfnDuplicateHandle = nullptr; + decltype(CloseHandle)* _pfnCloseHandle = nullptr; + + auto _uFirstProcessId = GetProcessId(_hLeft); + if (_uFirstProcessId == 0) + { + _pfnDuplicateHandle = try_get_DuplicateHandle(); + _pfnCloseHandle = try_get_CloseHandle(); + if (_pfnDuplicateHandle == nullptr || _pfnCloseHandle == nullptr) + return false; + + HANDLE _hProcessTmp; + if (!_pfnDuplicateHandle(NtGetCurrentProcess(), _hLeft, NtGetCurrentProcess(), &_hProcessTmp, PROCESS_QUERY_INFORMATION, FALSE, 0)) + { + return false; + } + + _uFirstProcessId = GetProcessId(_hProcessTmp); + _pfnCloseHandle(_hProcessTmp); + if (_uFirstProcessId == 0) + return false; + } + + auto _uSecondProcessId = GetProcessId(_hRigth); + if (_uSecondProcessId == 0) + { + if (!_pfnDuplicateHandle) + { + _pfnDuplicateHandle = try_get_DuplicateHandle(); + _pfnCloseHandle = try_get_CloseHandle(); + + if (_pfnDuplicateHandle == nullptr || _pfnCloseHandle == nullptr) + return false; + } + + HANDLE _hProcessTmp; + if (!_pfnDuplicateHandle(NtGetCurrentProcess(), _hRigth, NtGetCurrentProcess(), &_hProcessTmp, PROCESS_QUERY_INFORMATION, FALSE, 0)) + { + return false; + } + + _uSecondProcessId = GetProcessId(_hProcessTmp); + _pfnCloseHandle(_hProcessTmp); + if (_uSecondProcessId == 0) + return false; + } + + return _uFirstProcessId == _uSecondProcessId; + } + + bool __fastcall CompareThreadId(HANDLE _hLeft, ObjectStaticBuffer& _LeftBuffer, HANDLE _hRigth, ObjectStaticBuffer& _RightBuffer) noexcept + { + decltype(DuplicateHandle)* _pfnDuplicateHandle = nullptr; + decltype(CloseHandle)* _pfnCloseHandle = nullptr; + + auto _uFirstThreadId = GetThreadId(_hLeft); + if (_uFirstThreadId == 0) + { + _pfnDuplicateHandle = try_get_DuplicateHandle(); + _pfnCloseHandle = try_get_CloseHandle(); + if (_pfnDuplicateHandle == nullptr || _pfnCloseHandle == nullptr) + return false; + + HANDLE _hHandleTmp; + if (!_pfnDuplicateHandle(NtGetCurrentProcess(), _hLeft, NtGetCurrentProcess(), &_hHandleTmp, THREAD_QUERY_INFORMATION, FALSE, 0)) + { + return false; + } + + _uFirstThreadId = GetThreadId(_hHandleTmp); + _pfnCloseHandle(_hHandleTmp); + if (_uFirstThreadId == 0) + return false; + } + + auto _uSecondThreadId = GetThreadId(_hRigth); + if (_uSecondThreadId == 0) + { + if (!_pfnDuplicateHandle) + { + _pfnDuplicateHandle = try_get_DuplicateHandle(); + _pfnCloseHandle = try_get_CloseHandle(); + + if (_pfnDuplicateHandle == nullptr || _pfnCloseHandle == nullptr) + return false; + } + + HANDLE _hHandleTmp; + if (!_pfnDuplicateHandle(NtGetCurrentProcess(), _hRigth, NtGetCurrentProcess(), &_hHandleTmp, THREAD_QUERY_INFORMATION, FALSE, 0)) + { + return false; + } + + _uSecondThreadId = GetThreadId(_hHandleTmp); + _pfnCloseHandle(_hHandleTmp); + if (_uSecondThreadId == 0) + return false; + } + + return _uFirstThreadId == _uSecondThreadId; + } + + bool __fastcall CompareObjectRef(HANDLE _hFirstObjectHandle, ObjectStaticBuffer& _FirstObjectBuffer, HANDLE _hSecondObjectHandle, ObjectStaticBuffer& _SecondObjectBuffer) noexcept + { + const auto _pfnNtQueryObject = try_get_NtQueryObject(); + if (!_pfnNtQueryObject) + return false; + + const auto _pfnDuplicateHandle = try_get_DuplicateHandle(); + const auto _pfnCloseHandle = try_get_CloseHandle(); + if (_pfnDuplicateHandle == nullptr || _pfnCloseHandle == nullptr) + return false; + + HANDLE _hFirstTmp = NULL; + BOOL _bHandleIsSame = FALSE; + + ::AcquireSRWLockExclusive(&g_CompareObjectHandles); + + do + { + if (!_pfnDuplicateHandle(NtGetCurrentProcess(), _hFirstObjectHandle, NtGetCurrentProcess(), &_hFirstTmp, 0, FALSE, 0)) + { + break; + } + + LONG _Status = _pfnNtQueryObject(_hFirstObjectHandle, ObjectBasicInformation, &_FirstObjectBuffer, sizeof(_FirstObjectBuffer.BaseInfo), nullptr); + + // 实际测试,ObjectBasicInformation 只出现无效句柄错误 + if (_Status < 0) + { + break; + } + + if (_FirstObjectBuffer.BaseInfo.HandleCount == 1) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + break; + } + + _Status = _pfnNtQueryObject(_hSecondObjectHandle, ObjectBasicInformation, &_SecondObjectBuffer, sizeof(_SecondObjectBuffer.BaseInfo), nullptr); + if (_Status < 0) + { + break; + } + + if (_SecondObjectBuffer.BaseInfo.HandleCount != _FirstObjectBuffer.BaseInfo.HandleCount) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + break; + } + + _pfnCloseHandle(_hFirstTmp); + _hFirstTmp = NULL; + + _Status = _pfnNtQueryObject(_hFirstObjectHandle, ObjectBasicInformation, &_FirstObjectBuffer, sizeof(_FirstObjectBuffer.BaseInfo), nullptr); + + // 实际测试,ObjectBasicInformation 只出现无效句柄错误 + if (_Status < 0) + { + break; + } + + if (_FirstObjectBuffer.BaseInfo.HandleCount == 1) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + break; + } + + _Status = _pfnNtQueryObject(_hSecondObjectHandle, ObjectBasicInformation, &_SecondObjectBuffer, sizeof(_SecondObjectBuffer.BaseInfo), nullptr); + if (_Status < 0) + { + break; + } + + if (_SecondObjectBuffer.BaseInfo.HandleCount != _FirstObjectBuffer.BaseInfo.HandleCount) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + break; + } + + _bHandleIsSame = TRUE; + break; + } while (false); + + ::ReleaseSRWLockExclusive(&g_CompareObjectHandles); + + if (_hFirstTmp) + _pfnCloseHandle(_hFirstTmp); + + return _bHandleIsSame; + } + + bool __fastcall CompareFileHandle(HANDLE _hFirstObjectHandle, ObjectStaticBuffer& _FirstObjectBuffer, HANDLE _hSecondObjectHandle, ObjectStaticBuffer& _SecondObjectBuffer) noexcept + { + // 提高判断效率,因为CompareObjectRef存在阻塞。 + // 如果是同一个对象,那么必然是同一个文件。当然是同一个文件不一定就是同一个对象。 + const auto _bRet1 = GetFileInformationByHandle(_hFirstObjectHandle, &_FirstObjectBuffer.FileInformation); + const auto _bRet2 = GetFileInformationByHandle(_hSecondObjectHandle, &_SecondObjectBuffer.FileInformation); + + if (_bRet1 != _bRet2) + return false; + + if (_bRet1) + { + if (_FirstObjectBuffer.FileInformation.dwVolumeSerialNumber != _SecondObjectBuffer.FileInformation.dwVolumeSerialNumber + || _FirstObjectBuffer.FileInformation.nFileIndexHigh != _SecondObjectBuffer.FileInformation.nFileIndexHigh + || _FirstObjectBuffer.FileInformation.nFileIndexLow != _SecondObjectBuffer.FileInformation.nFileIndexLow) + { + return false; + } + } + + return CompareObjectRef(_hFirstObjectHandle, _FirstObjectBuffer, _hSecondObjectHandle, _SecondObjectBuffer); + } +#endif + } +} +#endif + +namespace YY::Thunks +{ + +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + + // 最低受支持的客户端 Windows 2000 专业版 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows 2000 Server[桌面应用 | UWP 应用] + // 虽然2000就支持,但是为了实现CompareObjectHandles,目前需要处理一下关闭。 + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + CloseHandle, + _In_ _Post_ptr_invalid_ HANDLE _hObject + ) + { + const auto _pfnCloseHandle = try_get_CloseHandle(); + const auto _pfnCompareObjectHandles = try_get_CompareObjectHandles(); + + if (_pfnCompareObjectHandles == nullptr && _hObject && _hObject != INVALID_HANDLE_VALUE) + { + ::AcquireSRWLockShared(&g_CompareObjectHandles); + } + // 空指针故意崩溃 + auto _bRet = _pfnCloseHandle(_hObject); + + if (_pfnCompareObjectHandles == nullptr && _hObject && _hObject != INVALID_HANDLE_VALUE) + { + auto _lStatus = GetLastError(); + ::ReleaseSRWLockShared(&g_CompareObjectHandles); + SetLastError(_lStatus); + } + + return _bRet; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + + // 最低受支持的客户端 Windows 2000 专业版 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows 2000 Server[桌面应用 | UWP 应用] + // 虽然2000就支持,但是为了实现CompareObjectHandles,目前需要处理一下关闭。 + __DEFINE_THUNK( + kernel32, + 28, + BOOL, + WINAPI, + DuplicateHandle, + _In_ HANDLE _hSourceProcessHandle, + _In_ HANDLE _hSourceHandle, + _In_ HANDLE _hTargetProcessHandle, + _Outptr_ LPHANDLE _phTargetHandle, + _In_ DWORD _fDesiredAccess, + _In_ BOOL _bInheritHandle, + _In_ DWORD _uOptions + ) + { + const auto _pfnDuplicateHandle = try_get_DuplicateHandle(); + const auto _pfnCompareObjectHandles = try_get_CompareObjectHandles(); + + bool _bNeedLock = false; + if (_pfnCompareObjectHandles) + { + // 无须加锁 + } + if (_hTargetProcessHandle == NtGetCurrentProcess() || GetProcessId(_hTargetProcessHandle) == GetCurrentProcessId()) + { + _bNeedLock = true; + } + else if ((DUPLICATE_CLOSE_SOURCE & _uOptions) + && (_hSourceProcessHandle == NtGetCurrentProcess() || GetProcessId(_hSourceProcessHandle) == GetCurrentProcessId())) + { + _bNeedLock = true; + } + + if (_bNeedLock) + { + ::AcquireSRWLockShared(&g_CompareObjectHandles); + } + + // 空指针故意崩溃 + auto _bRet = _pfnDuplicateHandle(_hSourceProcessHandle, _hSourceHandle, _hTargetProcessHandle, _phTargetHandle, _fDesiredAccess, _bInheritHandle, _uOptions); + + if (_bNeedLock) + { + auto _lStatus = GetLastError(); + ::ReleaseSRWLockShared(&g_CompareObjectHandles); + SetLastError(_lStatus); + } + return _bRet; + } +#endif + +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + + // 最低受支持的客户端 Windows 10 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2016[桌面应用 | UWP 应用] + __DEFINE_THUNK( + api_ms_win_core_handle_l1_1_0, + 8, + BOOL, + WINAPI, + CompareObjectHandles, + _In_ HANDLE _hFirstObjectHandle, + _In_ HANDLE _hSecondObjectHandle + ) + { + if (const auto _pfnCompareObjectHandles = try_get_CompareObjectHandles()) + { + return _pfnCompareObjectHandles(_hFirstObjectHandle, _hSecondObjectHandle); + } + + ObjectStaticBuffer _FirstObjectBuffer; + ObjectStaticBuffer _SecondObjectBuffer; + + if (_hFirstObjectHandle == _hSecondObjectHandle) + { + if (NtGetCurrentProcess() == _hFirstObjectHandle + || NtGetCurrentThread() == _hFirstObjectHandle) + { + return TRUE; + } + + const auto _pfnNtQueryObject = try_get_NtQueryObject(); + if (!_pfnNtQueryObject) + return FALSE; + + // 用来检测句柄是否合法 + LONG _Status = _pfnNtQueryObject(_hFirstObjectHandle, ObjectBasicInformation, &_FirstObjectBuffer, sizeof(_FirstObjectBuffer.BaseInfo), nullptr); + if (_Status < 0) + { + return FALSE; + } + return TRUE; + } + + const auto _pfnNtQueryObject = try_get_NtQueryObject(); + if (!_pfnNtQueryObject) + return FALSE; + + + LONG _Status = _pfnNtQueryObject(_hFirstObjectHandle, ObjectBasicInformation, &_FirstObjectBuffer, sizeof(_FirstObjectBuffer.BaseInfo), nullptr); + + // 实际测试,ObjectBasicInformation 只出现无效句柄错误 + if (_Status < 0) + { + return FALSE; + } + + if (_FirstObjectBuffer.BaseInfo.HandleCount == 1) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + return FALSE; + } + + _Status = _pfnNtQueryObject(_hSecondObjectHandle, ObjectBasicInformation, &_SecondObjectBuffer, sizeof(_SecondObjectBuffer.BaseInfo), nullptr); + if (_Status < 0) + { + return FALSE; + } + + if (_SecondObjectBuffer.BaseInfo.HandleCount == 1) + { + // 引用计数为 1,这肯定不可能与另外一个句柄是同一个内核对象 + return FALSE; + } + + if (_FirstObjectBuffer.BaseInfo.NameInfoSize != _SecondObjectBuffer.BaseInfo.NameInfoSize + || _FirstObjectBuffer.BaseInfo.TypeInfoSize != _SecondObjectBuffer.BaseInfo.TypeInfoSize) + { + return FALSE; + } + + _Status = _pfnNtQueryObject(_hFirstObjectHandle, ObjectTypeInformation, &_FirstObjectBuffer, sizeof(_FirstObjectBuffer), nullptr); + if (_Status < 0) + { + return FALSE; + } + _Status = _pfnNtQueryObject(_hSecondObjectHandle, ObjectTypeInformation, &_SecondObjectBuffer, sizeof(_SecondObjectBuffer), nullptr); + if (_Status < 0) + { + return FALSE; + } + + // 同一个内核句柄,必然拥有相同的TypeName。 + if (!internal::IsEqual(_FirstObjectBuffer.TypeInfo.TypeName, _SecondObjectBuffer.TypeInfo.TypeName)) + { + return FALSE; + } + + // 我们不直接比较句柄的Name,因为某些句柄获取Name会导致阻塞。 + // 下面这个表格存储了所有仅比较Name就可以确定是否是同一内核对象。 + static const CompareObjectItem s_CompareObjectTable[] = + { + { L"Event", &CompareObjectName }, + { L"Process", &CompareProcessId }, + { L"Thread", &CompareThreadId }, + { L"Section", &CompareObjectName }, + { L"Mutant", &CompareObjectName }, + { L"Semaphore", &CompareObjectName }, + { L"File", &CompareFileHandle }, + { L"WindowStation", &CompareObjectName }, + { L"Desktop", &CompareObjectName }, + { L"Directory", &CompareObjectName }, + { L"Timer", &CompareObjectName }, + { L"KeyedEvent", &CompareObjectName }, + }; + + for (auto& _CompareObject : s_CompareObjectTable) + { + if (internal::IsEqualI(_FirstObjectBuffer.TypeInfo.TypeName, _CompareObject.TypeName)) + { + return _CompareObject.pfnCompareObject(_hFirstObjectHandle, _FirstObjectBuffer, _hSecondObjectHandle, _SecondObjectBuffer); + } + } + + __WarningMessage__("Token: OpenProcessToken 返回同一个内核对象,但是没有Name。"); + + // 某些句柄无法直接判断Name,即使名称相同在内核中也不完全是同一个内核对象。 + // 而引用计数一样,那么可以说明他们是同一个对象。但是需要注意的是该方法比较缓慢,因为需要加锁!!! + // Key : 重复打开时不是同一个内核对象 + // CreateIoCompletionPort : 无法获取名称 + return CompareObjectRef(_hFirstObjectHandle, _FirstObjectBuffer, _hSecondObjectHandle, _SecondObjectBuffer); + } +#endif +} diff --git a/src/Thunks/api-ms-win-core-registry.hpp b/src/Thunks/api-ms-win-core-registry.hpp index b9563529..648000fc 100644 --- a/src/Thunks/api-ms-win-core-registry.hpp +++ b/src/Thunks/api-ms-win-core-registry.hpp @@ -1,396 +1,349 @@  -namespace YY +namespace YY::Thunks { - namespace Thunks - { - #if (YY_Thunks_Support_Version < NTDDI_WS03SP1) - //Windows XP Professional x64 Edition, Windows Server 2003 with SP1 - __DEFINE_THUNK( - advapi32, - 16, - LSTATUS, - APIENTRY, - RegDeleteKeyExW, - _In_ HKEY hKey, - _In_ LPCWSTR lpSubKey, - _In_ REGSAM samDesired, - _Reserved_ DWORD Reserved - ) + //Windows XP Professional x64 Edition, Windows Server 2003 with SP1 + __DEFINE_THUNK( + advapi32, + 16, + LSTATUS, + APIENTRY, + RegDeleteKeyExW, + _In_ HKEY hKey, + _In_ LPCWSTR lpSubKey, + _In_ REGSAM samDesired, + _Reserved_ DWORD Reserved + ) + { + if(auto const pRegDeleteKeyExW = try_get_RegDeleteKeyExW()) { - if(auto const pRegDeleteKeyExW = try_get_RegDeleteKeyExW()) - { - return pRegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved); - } + return pRegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved); + } - return RegDeleteKeyW(hKey, lpSubKey); - } + return RegDeleteKeyW(hKey, lpSubKey); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WS03SP1) - //Windows XP Professional x64 Edition, Windows Server 2003 with SP1 - __DEFINE_THUNK( - advapi32, - 16, - LSTATUS, - APIENTRY, - RegDeleteKeyExA, - _In_ HKEY hKey, - _In_ LPCSTR lpSubKey, - _In_ REGSAM samDesired, - _Reserved_ DWORD Reserved - ) + //Windows XP Professional x64 Edition, Windows Server 2003 with SP1 + __DEFINE_THUNK( + advapi32, + 16, + LSTATUS, + APIENTRY, + RegDeleteKeyExA, + _In_ HKEY hKey, + _In_ LPCSTR lpSubKey, + _In_ REGSAM samDesired, + _Reserved_ DWORD Reserved + ) + { + if (auto const pRegDeleteKeyExA = try_get_RegDeleteKeyExA()) { - if (auto const pRegDeleteKeyExA = try_get_RegDeleteKeyExA()) - { - return pRegDeleteKeyExA(hKey, lpSubKey, samDesired, Reserved); - } - - return RegDeleteKeyA(hKey, lpSubKey); + return pRegDeleteKeyExA(hKey, lpSubKey, samDesired, Reserved); } -#endif - - -#if (YY_Thunks_Support_Version < NTDDI_WIN6) - - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 24, - LSTATUS, - APIENTRY, - RegSetKeyValueW, - _In_ HKEY hKey, - _In_opt_ LPCWSTR lpSubKey, - _In_opt_ LPCWSTR lpValueName, - _In_ DWORD dwType, - _In_reads_bytes_opt_(cbData) LPCVOID lpData, - _In_ DWORD cbData - ) - { - //Empty? - if (lpSubKey == nullptr || *lpSubKey == L'\0') - { - return RegSetValueExW(hKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); - } - else - { - HKEY hSubKey; - auto lStatus = RegCreateKeyExW(hKey, lpSubKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &hSubKey, nullptr); - - if (lStatus == ERROR_SUCCESS) - { - lStatus = RegSetValueExW(hSubKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); - - RegCloseKey(hSubKey); - } - return lStatus; - } - } + return RegDeleteKeyA(hKey, lpSubKey); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 24, - LSTATUS, - APIENTRY, - RegSetKeyValueA, - _In_ HKEY hKey, - _In_opt_ LPCSTR lpSubKey, - _In_opt_ LPCSTR lpValueName, - _In_ DWORD dwType, - _In_reads_bytes_opt_(cbData) LPCVOID lpData, - _In_ DWORD cbData - ) + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 24, + LSTATUS, + APIENTRY, + RegSetKeyValueW, + _In_ HKEY hKey, + _In_opt_ LPCWSTR lpSubKey, + _In_opt_ LPCWSTR lpValueName, + _In_ DWORD dwType, + _In_reads_bytes_opt_(cbData) LPCVOID lpData, + _In_ DWORD cbData + ) + { + //Empty? + if (lpSubKey == nullptr || *lpSubKey == L'\0') { - //Empty? - if (lpSubKey == nullptr || *lpSubKey == '\0') - { - return RegSetValueExA(hKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); - } - else - { - HKEY hSubKey; - auto lStatus = RegCreateKeyExA(hKey, lpSubKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &hSubKey, nullptr); - - if (lStatus == ERROR_SUCCESS) - { - lStatus = RegSetValueExA(hSubKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); - - RegCloseKey(hSubKey); - } - - return lStatus; - } + return RegSetValueExW(hKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); } -#endif - - -#if (YY_Thunks_Support_Version < NTDDI_WIN6) - - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 12, - LSTATUS, - APIENTRY, - RegDeleteKeyValueW, - _In_ HKEY hKey, - _In_opt_ LPCWSTR lpSubKey, - _In_opt_ LPCWSTR lpValueName - ) + else { HKEY hSubKey; - auto lStatus = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey); + auto lStatus = RegCreateKeyExW(hKey, lpSubKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &hSubKey, nullptr); if (lStatus == ERROR_SUCCESS) { - lStatus = RegDeleteValueW(hSubKey, lpValueName); + lStatus = RegSetValueExW(hSubKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); + RegCloseKey(hSubKey); } return lStatus; } + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 12, - LSTATUS, - APIENTRY, - RegDeleteKeyValueA, - _In_ HKEY hKey, - _In_opt_ LPCSTR lpSubKey, - _In_opt_ LPCSTR lpValueName - ) + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 24, + LSTATUS, + APIENTRY, + RegSetKeyValueA, + _In_ HKEY hKey, + _In_opt_ LPCSTR lpSubKey, + _In_opt_ LPCSTR lpValueName, + _In_ DWORD dwType, + _In_reads_bytes_opt_(cbData) LPCVOID lpData, + _In_ DWORD cbData + ) + { + //Empty? + if (lpSubKey == nullptr || *lpSubKey == '\0') + { + return RegSetValueExA(hKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); + } + else { HKEY hSubKey; - auto lStatus = RegOpenKeyExA(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey); + auto lStatus = RegCreateKeyExA(hKey, lpSubKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &hSubKey, nullptr); if (lStatus == ERROR_SUCCESS) { - lStatus = RegDeleteValueA(hSubKey, lpValueName); + lStatus = RegSetValueExA(hSubKey, lpValueName, 0, dwType, (const BYTE*)lpData, cbData); + RegCloseKey(hSubKey); } return lStatus; } + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 8, - LSTATUS, - APIENTRY, - RegDeleteTreeW, - _In_ HKEY hKey, - _In_opt_ LPCWSTR lpSubKey - ) + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 12, + LSTATUS, + APIENTRY, + RegDeleteKeyValueW, + _In_ HKEY hKey, + _In_opt_ LPCWSTR lpSubKey, + _In_opt_ LPCWSTR lpValueName + ) + { + HKEY hSubKey; + auto lStatus = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey); + + if (lStatus == ERROR_SUCCESS) { - return SHDeleteKeyW(hKey, lpSubKey); + lStatus = RegDeleteValueW(hSubKey, lpValueName); + RegCloseKey(hSubKey); } + + return lStatus; + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista, Windows Server 2008 - __DEFINE_THUNK( - advapi32, - 8, - LSTATUS, - APIENTRY, - RegDeleteTreeA, - _In_ HKEY hKey, - _In_opt_ LPCSTR lpSubKey - ) + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 12, + LSTATUS, + APIENTRY, + RegDeleteKeyValueA, + _In_ HKEY hKey, + _In_opt_ LPCSTR lpSubKey, + _In_opt_ LPCSTR lpValueName + ) + { + HKEY hSubKey; + auto lStatus = RegOpenKeyExA(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey); + + if (lStatus == ERROR_SUCCESS) { - return SHDeleteKeyA(hKey, lpSubKey); + lStatus = RegDeleteValueA(hSubKey, lpValueName); + RegCloseKey(hSubKey); } + + return lStatus; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 8, + LSTATUS, + APIENTRY, + RegDeleteTreeW, + _In_ HKEY hKey, + _In_opt_ LPCWSTR lpSubKey + ) + { + return SHDeleteKeyW(hKey, lpSubKey); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + //Windows Vista, Windows Server 2008 + __DEFINE_THUNK( + advapi32, + 8, + LSTATUS, + APIENTRY, + RegDeleteTreeA, + _In_ HKEY hKey, + _In_opt_ LPCSTR lpSubKey + ) + { + return SHDeleteKeyA(hKey, lpSubKey); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WS03SP1) - //Windows Vista, Windows XP Professional x64 Edition, Windows Server 2008, Windows Server 2003 with SP1 - __DEFINE_THUNK( - advapi32, - 28, - LSTATUS, - APIENTRY, - RegGetValueW, - HKEY hkey, - LPCWSTR lpSubKey, - LPCWSTR lpValue, - DWORD dwFlags, - LPDWORD pdwType, - PVOID pvData, - LPDWORD pcbData - ) - { + //Windows Vista, Windows XP Professional x64 Edition, Windows Server 2008, Windows Server 2003 with SP1 + __DEFINE_THUNK( + advapi32, + 28, + LSTATUS, + APIENTRY, + RegGetValueW, + HKEY hkey, + LPCWSTR lpSubKey, + LPCWSTR lpValue, + DWORD dwFlags, + LPDWORD pdwType, + PVOID pvData, + LPDWORD pcbData + ) + { #if (YY_Thunks_Support_Version >= NTDDI_WINXPSP2) - return SHRegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); + return SHRegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); #else - if (auto const pRegGetValueW = try_get_RegGetValueW()) - { - return pRegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); - } + if (auto const pRegGetValueW = try_get_RegGetValueW()) + { + return pRegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); + } - if (pvData && pcbData == nullptr - || (dwFlags & RRF_RT_ANY) == 0) - { - return ERROR_INVALID_PARAMETER; - } + if (pvData && pcbData == nullptr + || (dwFlags & RRF_RT_ANY) == 0) + { + return ERROR_INVALID_PARAMETER; + } - LSTATUS lStatus; + LSTATUS lStatus; - if (lpSubKey&&*lpSubKey) - { - lStatus = RegOpenKeyExW(hkey, lpSubKey, 0, KEY_QUERY_VALUE, &hkey); - if (lStatus != ERROR_SUCCESS) - return lStatus; - } + if (lpSubKey&&*lpSubKey) + { + lStatus = RegOpenKeyExW(hkey, lpSubKey, 0, KEY_QUERY_VALUE, &hkey); + if (lStatus != ERROR_SUCCESS) + return lStatus; + } - DWORD dwType; - DWORD cbData = pvData && pcbData ? *pcbData : 0; - const auto cbDataBackup = cbData; + DWORD dwType; + DWORD cbData = pvData && pcbData ? *pcbData : 0; + const auto cbDataBackup = cbData; - lStatus = RegQueryValueExW(hkey, lpValue, nullptr, &dwType, (LPBYTE)pvData, &cbData); + lStatus = RegQueryValueExW(hkey, lpValue, nullptr, &dwType, (LPBYTE)pvData, &cbData); - DWORD cbDataFix; - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) + DWORD cbDataFix; + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + if (dwType == REG_MULTI_SZ) { - if (dwType == REG_MULTI_SZ) - { - //连续2个 null 结尾 - cbDataFix = cbData + sizeof(*lpValue) * 2; - } - else if (dwType == REG_SZ) + //连续2个 null 结尾 + cbDataFix = cbData + sizeof(*lpValue) * 2; + } + else if (dwType == REG_SZ) + { + //一个null 结尾 + cbDataFix = cbData + sizeof(*lpValue); + } + else if (dwType == REG_EXPAND_SZ) + { + if (dwFlags & RRF_NOEXPAND) { //一个null 结尾 cbDataFix = cbData + sizeof(*lpValue); } - else if (dwType == REG_EXPAND_SZ) + else { - if (dwFlags & RRF_NOEXPAND) - { - //一个null 结尾 - cbDataFix = cbData + sizeof(*lpValue); - } - else - { - //需要展开 - cbDataFix = pvData && pcbData ? *pcbData : 0; - lStatus = SHQueryValueExW(hkey, lpValue, nullptr, &dwType, pvData, &cbDataFix); + //需要展开 + cbDataFix = pvData && pcbData ? *pcbData : 0; + lStatus = SHQueryValueExW(hkey, lpValue, nullptr, &dwType, pvData, &cbDataFix); - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) - { - cbData = cbDataFix; - } + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + cbData = cbDataFix; } } - else - { - cbDataFix = cbData; - } } - - if (lpSubKey&&*lpSubKey) + else { - RegCloseKey(hkey); + cbDataFix = cbData; } + } + if (lpSubKey&&*lpSubKey) + { + RegCloseKey(hkey); + } - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) - { - if (pdwType) - *pdwType = dwType; - - //检测类型是否支持 - switch (dwType) - { - case REG_NONE: - case REG_SZ: - case REG_EXPAND_SZ: - case REG_BINARY: - case REG_DWORD: - if ((dwFlags & (1 << dwType)) == 0) - { - lStatus = ERROR_UNSUPPORTED_TYPE; - break; - } - else if (pvData && lStatus == ERROR_SUCCESS) - { - //当函数成功时,保证字符串正常 NULL 结尾 - if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) - { - //保证1个 NULL 结尾 - - - //sizeof(wchar_t) 边界对齐 - if (cbData % sizeof(*lpValue)) - { - if (cbData >= cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } - - ((byte*)pvData)[cbData] = 0; - - ++cbData; - } - - - auto cStringMin = cbData / sizeof(*lpValue); - - - auto pString = (wchar_t*)pvData; - - if (cStringMin == 0 || pString[cStringMin - 1]) - { - if (cbData + sizeof(*lpValue) > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } - pString[cStringMin++] = L'\0'; - } + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + if (pdwType) + *pdwType = dwType; - cbDataFix = cStringMin * sizeof(*lpValue); - } - } + //检测类型是否支持 + switch (dwType) + { + case REG_NONE: + case REG_SZ: + case REG_EXPAND_SZ: + case REG_BINARY: + case REG_DWORD: + if ((dwFlags & (1 << dwType)) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; break; - case REG_MULTI_SZ: - if ((dwFlags & RRF_RT_REG_MULTI_SZ) == 0) - { - lStatus = ERROR_UNSUPPORTED_TYPE; - } - else if (pvData && lStatus == ERROR_SUCCESS) + } + else if (pvData && lStatus == ERROR_SUCCESS) + { + //当函数成功时,保证字符串正常 NULL 结尾 + if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) { - //保证最后一个字符串 NULL 结尾 并且 包含 NULL 结束符 + //保证1个 NULL 结尾 + //sizeof(wchar_t) 边界对齐 if (cbData % sizeof(*lpValue)) @@ -406,11 +359,13 @@ namespace YY ++cbData; } + auto cStringMin = cbData / sizeof(*lpValue); + auto pString = (wchar_t*)pvData; - if (cStringMin == 0) + if (cStringMin == 0 || pString[cStringMin - 1]) { if (cbData + sizeof(*lpValue) > cbDataBackup) { @@ -420,217 +375,231 @@ namespace YY pString[cStringMin++] = L'\0'; } - else if (pString[cStringMin - 1]) - { - if (cbData + sizeof(*lpValue) * 2 > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } - pString[cStringMin++] = L'\0'; + cbDataFix = cStringMin * sizeof(*lpValue); + } + } + break; + case REG_MULTI_SZ: + if ((dwFlags & RRF_RT_REG_MULTI_SZ) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; + } + else if (pvData && lStatus == ERROR_SUCCESS) + { + //保证最后一个字符串 NULL 结尾 并且 包含 NULL 结束符 - pString[cStringMin++] = L'\0'; + //sizeof(wchar_t) 边界对齐 + if (cbData % sizeof(*lpValue)) + { + if (cbData >= cbDataBackup) + { + lStatus = ERROR_MORE_DATA; + break; } - else if (cStringMin >= 2 && pString[cStringMin - 2]) + + ((byte*)pvData)[cbData] = 0; + + ++cbData; + } + + auto cStringMin = cbData / sizeof(*lpValue); + + auto pString = (wchar_t*)pvData; + + if (cStringMin == 0) + { + if (cbData + sizeof(*lpValue) > cbDataBackup) { - if (cbData + sizeof(*lpValue) > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } + lStatus = ERROR_MORE_DATA; + break; + } - pString[cStringMin++] = L'\0'; + pString[cStringMin++] = L'\0'; + } + else if (pString[cStringMin - 1]) + { + if (cbData + sizeof(*lpValue) * 2 > cbDataBackup) + { + lStatus = ERROR_MORE_DATA; + break; } - cbDataFix = cStringMin * sizeof(*lpValue); + pString[cStringMin++] = L'\0'; + + pString[cStringMin++] = L'\0'; } - break; - case REG_QWORD: - if ((dwFlags & RRF_RT_REG_QWORD) == 0) + else if (cStringMin >= 2 && pString[cStringMin - 2]) { - lStatus = ERROR_UNSUPPORTED_TYPE; + if (cbData + sizeof(*lpValue) > cbDataBackup) + { + lStatus = ERROR_MORE_DATA; + break; + } + + pString[cStringMin++] = L'\0'; } - break; - default: - if((dwFlags & RRF_RT_ANY) != RRF_RT_ANY) - lStatus = ERROR_UNSUPPORTED_TYPE; - break; + + cbDataFix = cStringMin * sizeof(*lpValue); + } + break; + case REG_QWORD: + if ((dwFlags & RRF_RT_REG_QWORD) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; } + break; + default: + if((dwFlags & RRF_RT_ANY) != RRF_RT_ANY) + lStatus = ERROR_UNSUPPORTED_TYPE; + break; + } - if (pcbData) - *pcbData = cbDataFix; + if (pcbData) + *pcbData = cbDataFix; - } + } - if ((RRF_ZEROONFAILURE & dwFlags) != 0 && lStatus) + if ((RRF_ZEROONFAILURE & dwFlags) != 0 && lStatus) + { + //全0填充 + if (pvData && cbDataBackup) { - //全0填充 - if (pvData && cbDataBackup) - { - memset(pvData, 0, cbDataBackup); - } + memset(pvData, 0, cbDataBackup); } + } - return lStatus; + return lStatus; #endif - } + } #endif #if (YY_Thunks_Support_Version < NTDDI_WS03SP1) - //Windows Vista, Windows XP Professional x64 Edition, Windows Server 2008, Windows Server 2003 with SP1 - __DEFINE_THUNK( - advapi32, - 28, - LSTATUS, - APIENTRY, - RegGetValueA, - HKEY hkey, - LPCSTR lpSubKey, - LPCSTR lpValue, - DWORD dwFlags, - LPDWORD pdwType, - PVOID pvData, - LPDWORD pcbData - ) - { + //Windows Vista, Windows XP Professional x64 Edition, Windows Server 2008, Windows Server 2003 with SP1 + __DEFINE_THUNK( + advapi32, + 28, + LSTATUS, + APIENTRY, + RegGetValueA, + HKEY hkey, + LPCSTR lpSubKey, + LPCSTR lpValue, + DWORD dwFlags, + LPDWORD pdwType, + PVOID pvData, + LPDWORD pcbData + ) + { #if (YY_Thunks_Support_Version >= NTDDI_WINXPSP2) - return SHRegGetValueA(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); + return SHRegGetValueA(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); #else - if (auto const pRegGetValueA = try_get_RegGetValueA()) - { - return pRegGetValueA(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); - } + if (auto const pRegGetValueA = try_get_RegGetValueA()) + { + return pRegGetValueA(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); + } - if (pvData && pcbData == nullptr - || (dwFlags & RRF_RT_ANY) == 0) - { - return ERROR_INVALID_PARAMETER; - } + if (pvData && pcbData == nullptr + || (dwFlags & RRF_RT_ANY) == 0) + { + return ERROR_INVALID_PARAMETER; + } - LSTATUS lStatus; + LSTATUS lStatus; - if (lpSubKey&&*lpSubKey) - { - lStatus = RegOpenKeyExA(hkey, lpSubKey, 0, KEY_QUERY_VALUE, &hkey); - if (lStatus != ERROR_SUCCESS) - return lStatus; - } + if (lpSubKey&&*lpSubKey) + { + lStatus = RegOpenKeyExA(hkey, lpSubKey, 0, KEY_QUERY_VALUE, &hkey); + if (lStatus != ERROR_SUCCESS) + return lStatus; + } - DWORD dwType; - DWORD cbData = pvData && pcbData ? *pcbData : 0; - const auto cbDataBackup = cbData; + DWORD dwType; + DWORD cbData = pvData && pcbData ? *pcbData : 0; + const auto cbDataBackup = cbData; - lStatus = RegQueryValueExA(hkey, lpValue, nullptr, &dwType, (LPBYTE)pvData, &cbData); + lStatus = RegQueryValueExA(hkey, lpValue, nullptr, &dwType, (LPBYTE)pvData, &cbData); - DWORD cbDataFix; - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) + DWORD cbDataFix; + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + if (dwType == REG_MULTI_SZ) { - if (dwType == REG_MULTI_SZ) - { - //连续2个 null 结尾 - cbDataFix = cbData + sizeof(*lpValue) * 2; - } - else if (dwType == REG_SZ) + //连续2个 null 结尾 + cbDataFix = cbData + sizeof(*lpValue) * 2; + } + else if (dwType == REG_SZ) + { + //一个null 结尾 + cbDataFix = cbData + sizeof(*lpValue); + } + else if (dwType == REG_EXPAND_SZ) + { + if (dwFlags & RRF_NOEXPAND) { //一个null 结尾 cbDataFix = cbData + sizeof(*lpValue); } - else if (dwType == REG_EXPAND_SZ) + else { - if (dwFlags & RRF_NOEXPAND) - { - //一个null 结尾 - cbDataFix = cbData + sizeof(*lpValue); - } - else - { - //需要展开 - cbDataFix = pvData && pcbData ? *pcbData : 0; - lStatus = SHQueryValueExA(hkey, lpValue, nullptr, &dwType, pvData, &cbDataFix); + //需要展开 + cbDataFix = pvData && pcbData ? *pcbData : 0; + lStatus = SHQueryValueExA(hkey, lpValue, nullptr, &dwType, pvData, &cbDataFix); - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) - { - cbData = cbDataFix; - } + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + cbData = cbDataFix; } } - else - { - cbDataFix = cbData; - } } - - if (lpSubKey&&*lpSubKey) + else { - RegCloseKey(hkey); + cbDataFix = cbData; } + } + if (lpSubKey&&*lpSubKey) + { + RegCloseKey(hkey); + } - if (lStatus == ERROR_SUCCESS - || lStatus == ERROR_MORE_DATA) - { - if (pdwType) - *pdwType = dwType; - - //检测类型是否支持 - switch (dwType) - { - case REG_NONE: - case REG_SZ: - case REG_EXPAND_SZ: - case REG_BINARY: - case REG_DWORD: - if ((dwFlags & (1<< dwType)) == 0) - { - lStatus = ERROR_UNSUPPORTED_TYPE; - } - else if (pvData && lStatus == ERROR_SUCCESS) - { - //当函数成功时,保证字符串正常 NULL 结尾 - if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) - { - //保证1个 NULL 结尾 - auto cStringMin = cbData; - - - auto pString = (char*)pvData; - - if (cStringMin == 0 || pString[cStringMin - 1]) - { - if (cbData + sizeof(*lpValue) > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } - pString[cStringMin++] = '\0'; - } + if (lStatus == ERROR_SUCCESS + || lStatus == ERROR_MORE_DATA) + { + if (pdwType) + *pdwType = dwType; - cbDataFix = cStringMin * sizeof(*lpValue); - } - } - break; - case REG_MULTI_SZ: - if ((dwFlags & RRF_RT_REG_MULTI_SZ) == 0) - { - lStatus = ERROR_UNSUPPORTED_TYPE; - } - else + //检测类型是否支持 + switch (dwType) + { + case REG_NONE: + case REG_SZ: + case REG_EXPAND_SZ: + case REG_BINARY: + case REG_DWORD: + if ((dwFlags & (1<< dwType)) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; + } + else if (pvData && lStatus == ERROR_SUCCESS) + { + //当函数成功时,保证字符串正常 NULL 结尾 + if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) { - //保证最后一个字符串 NULL 结尾 并且 包含 NULL 结束符 - + //保证1个 NULL 结尾 auto cStringMin = cbData; + auto pString = (char*)pvData; - if (cStringMin == 0) + if (cStringMin == 0 || pString[cStringMin - 1]) { if (cbData + sizeof(*lpValue) > cbDataBackup) { @@ -640,114 +609,175 @@ namespace YY pString[cStringMin++] = '\0'; } - else if (pString[cStringMin - 1]) - { - if (cbData + sizeof(*lpValue) * 2 > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } - pString[cStringMin++] = '\0'; + cbDataFix = cStringMin * sizeof(*lpValue); + } + } + break; + case REG_MULTI_SZ: + if ((dwFlags & RRF_RT_REG_MULTI_SZ) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; + } + else + { + //保证最后一个字符串 NULL 结尾 并且 包含 NULL 结束符 - pString[cStringMin++] = '\0'; - } - else if (cStringMin >= 2 && pString[cStringMin - 2]) + auto cStringMin = cbData; + + auto pString = (char*)pvData; + + if (cStringMin == 0) + { + if (cbData + sizeof(*lpValue) > cbDataBackup) { - if (cbData + sizeof(*lpValue) > cbDataBackup) - { - lStatus = ERROR_MORE_DATA; - break; - } + lStatus = ERROR_MORE_DATA; + break; + } - pString[cStringMin++] = '\0'; + pString[cStringMin++] = '\0'; + } + else if (pString[cStringMin - 1]) + { + if (cbData + sizeof(*lpValue) * 2 > cbDataBackup) + { + lStatus = ERROR_MORE_DATA; + break; } - cbDataFix = cStringMin * sizeof(*lpValue); + pString[cStringMin++] = '\0'; + + pString[cStringMin++] = '\0'; } - break; - case REG_QWORD: - if ((dwFlags & RRF_RT_REG_QWORD) == 0) + else if (cStringMin >= 2 && pString[cStringMin - 2]) { - lStatus = ERROR_UNSUPPORTED_TYPE; + if (cbData + sizeof(*lpValue) > cbDataBackup) + { + lStatus = ERROR_MORE_DATA; + break; + } + + pString[cStringMin++] = '\0'; } - break; - default: - if((dwFlags & RRF_RT_ANY) != RRF_RT_ANY) - lStatus = ERROR_UNSUPPORTED_TYPE; - break; + + cbDataFix = cStringMin * sizeof(*lpValue); + } + break; + case REG_QWORD: + if ((dwFlags & RRF_RT_REG_QWORD) == 0) + { + lStatus = ERROR_UNSUPPORTED_TYPE; } + break; + default: + if((dwFlags & RRF_RT_ANY) != RRF_RT_ANY) + lStatus = ERROR_UNSUPPORTED_TYPE; + break; + } - if (pcbData) - *pcbData = cbDataFix; + if (pcbData) + *pcbData = cbDataFix; - } + } - if ((RRF_ZEROONFAILURE & dwFlags) != 0 && lStatus) + if ((RRF_ZEROONFAILURE & dwFlags) != 0 && lStatus) + { + //全0填充 + if (pvData && cbDataBackup) { - //全0填充 - if (pvData && cbDataBackup) - { - memset(pvData, 0, cbDataBackup); - } + memset(pvData, 0, cbDataBackup); } + } - return lStatus; + return lStatus; #endif - } + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista [desktop apps only] - //Windows Server 2008 [desktop apps only] - __DEFINE_THUNK( - advapi32, - 12, - LSTATUS, - APIENTRY, - RegCopyTreeW, - _In_ HKEY hKeySrc, - _In_opt_ LPCWSTR lpSubKey, - _In_ HKEY hKeyDest - ) + //Windows Vista [desktop apps only] + //Windows Server 2008 [desktop apps only] + __DEFINE_THUNK( + advapi32, + 12, + LSTATUS, + APIENTRY, + RegCopyTreeW, + _In_ HKEY hKeySrc, + _In_opt_ LPCWSTR lpSubKey, + _In_ HKEY hKeyDest + ) + { + if (auto const pRegCopyTreeW = try_get_RegCopyTreeW()) { - if (auto const pRegCopyTreeW = try_get_RegCopyTreeW()) - { - return pRegCopyTreeW(hKeySrc, lpSubKey, hKeyDest); - } - - return SHCopyKeyW(hKeySrc, lpSubKey, hKeyDest, 0); + return pRegCopyTreeW(hKeySrc, lpSubKey, hKeyDest); } + + return SHCopyKeyW(hKeySrc, lpSubKey, hKeyDest, 0); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) - //Windows Vista [desktop apps only] - //Windows Server 2008 [desktop apps only] - __DEFINE_THUNK( - advapi32, - 12, - LSTATUS, - APIENTRY, - RegCopyTreeA, - _In_ HKEY hKeySrc, - _In_opt_ LPCSTR lpSubKey, - _In_ HKEY hKeyDest - ) + //Windows Vista [desktop apps only] + //Windows Server 2008 [desktop apps only] + __DEFINE_THUNK( + advapi32, + 12, + LSTATUS, + APIENTRY, + RegCopyTreeA, + _In_ HKEY hKeySrc, + _In_opt_ LPCSTR lpSubKey, + _In_ HKEY hKeyDest + ) + { + if (auto const pRegCopyTreeA = try_get_RegCopyTreeA()) { - if (auto const pRegCopyTreeA = try_get_RegCopyTreeA()) - { - return pRegCopyTreeA(hKeySrc, lpSubKey, hKeyDest); - } - - return SHCopyKeyA(hKeySrc, lpSubKey, hKeyDest, 0); + return pRegCopyTreeA(hKeySrc, lpSubKey, hKeyDest); } + + return SHCopyKeyA(hKeySrc, lpSubKey, hKeyDest, 0); + } #endif - }//namespace Thunks -} //namespace YY \ No newline at end of file +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + + // 最低受支持的客户端 Windows 2000 Professional [仅限桌面应用] + // 最低受支持的服务器 Windows 2000 Server[仅限桌面应用] + // 虽然2000就支持,但是为了实现CompareObjectHandles,目前需要处理一下关闭。 + __DEFINE_THUNK( + advapi32, + 4, + LSTATUS, + APIENTRY, + RegCloseKey, + _In_ HKEY _hKey + ) + { + auto const _pfnRegCloseKey = try_get_RegCloseKey(); + const auto _pfnCompareObjectHandles = try_get_CompareObjectHandles(); + + // 伪句柄不用加锁 + if (_pfnCompareObjectHandles == nullptr && _hKey && (uintptr_t(_hKey) & uintptr_t(0x80000000)) == 0) + { + ::AcquireSRWLockShared(&g_CompareObjectHandles); + } + + // 空指针故意崩溃 + auto _lStatus = _pfnRegCloseKey(_hKey); + + if (_pfnCompareObjectHandles == nullptr && _hKey && (uintptr_t(_hKey) & uintptr_t(0x80000000)) == 0) + { + ::ReleaseSRWLockShared(&g_CompareObjectHandles); + } + + return _lStatus; + } +#endif +} //namespace YY::Thunks diff --git a/src/Thunks/api-ms-win-core-wow64.hpp b/src/Thunks/api-ms-win-core-wow64.hpp index b26064de..b5970b9a 100644 --- a/src/Thunks/api-ms-win-core-wow64.hpp +++ b/src/Thunks/api-ms-win-core-wow64.hpp @@ -202,9 +202,9 @@ namespace YY::Thunks #endif -#if (YY_Thunks_Support_Version < NTDDI_WS03) +#if (YY_Thunks_Support_Version < NTDDI_WIN6) - // 实际看到Vista就有,推测这个接口是x64系统时代添加的。 + // Windows XP x64确认没有这个接口 __DEFINE_THUNK( kernel32, 8, @@ -220,8 +220,291 @@ namespace YY::Thunks return _pfnWow64GetThreadContext(_hThread, _pContext); } - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + /* + | 系统 | 线程类型 | 结果 + | ------ | -------- | --- + | x86 | x86 | ERROR_INVALID_PARAMETER + | x64 | x86 | ERROR_SUCCESS + | x64 | x64 | ERROR_INVALID_PARAMETER + */ + +#if defined(_X86_) + // 如果系统也是 x86这必然不可能处于Wow64 + if (internal::GetNativeSystemInfo().wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + static_assert(sizeof(CONTEXT) == sizeof(*_pContext)); + return GetThreadContext(_hThread, (CONTEXT*)_pContext); +#elif defined(_AMD64_) + if (!_pContext) + { + SetLastError(ERROR_NOACCESS); + return FALSE; + } + + if ((_pContext->ContextFlags & (~(WOW64_CONTEXT_ALL | WOW64_CONTEXT_XSTATE))) != 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + // 判断线程是否是 WOW64线程 + const auto _pfnNtQueryInformationThread = try_get_NtQueryInformationThread(); + if (!_pfnNtQueryInformationThread) + { + SetLastError(ERROR_FUNCTION_FAILED); + return FALSE; + } + + THREAD_BASIC_INFORMATION ThreadBasicInfo; + LONG Status = _pfnNtQueryInformationThread(_hThread, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), nullptr); + if (Status < 0) + { + internal::BaseSetLastNTError(Status); + return FALSE; + } + + // 当前进程肯定不是Wow64 + if (static_cast(reinterpret_cast(ThreadBasicInfo.ClientId.UniqueProcess)) == GetCurrentProcessId()) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + union + { + struct + { + DWORD Unknow; + WOW64_CONTEXT ThreadContext; + } RemoteWow64ThreadContext; + + CONTEXT Context64; + } ContextBuffer = {}; + + CONTEXT& _Context64 = ContextBuffer.Context64; + _Context64.ContextFlags = CONTEXT_CONTROL | (_pContext->ContextFlags & 0x1F /*WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS | WOW64_CONTEXT_FLOATING_POINT | WOW64_CONTEXT_DEBUG_REGISTERS*/); + + if (_pContext->ContextFlags & 0x20 /*WOW64_CONTEXT_EXTENDED_REGISTERS*/) + { + _Context64.ContextFlags |= CONTEXT_FLOATING_POINT; + } + + // 这里忽略Windows XP必然不支持 WOW64_CONTEXT_XSTATE + if (!GetThreadContext(_hThread, &_Context64)) + { + return FALSE; + } + + if (_Context64.SegCs == 0x23u) + { + // 当前正处于WOW64执行中,这时取到的上下文就是 WOW64上下文 + // 我们可以直接将 CONTEXT 转换到 WOW64_CONTEXT + if ((_pContext->ContextFlags & WOW64_CONTEXT_DEBUG_REGISTERS) == WOW64_CONTEXT_DEBUG_REGISTERS) + { + _pContext->Dr0 = static_cast(_Context64.Dr0); + _pContext->Dr1 = static_cast(_Context64.Dr1); + _pContext->Dr2 = static_cast(_Context64.Dr2); + _pContext->Dr3 = static_cast(_Context64.Dr3); + _pContext->Dr6 = static_cast(_Context64.Dr6); + _pContext->Dr7 = static_cast(_Context64.Dr7); + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_FLOATING_POINT) == WOW64_CONTEXT_FLOATING_POINT) + { + _pContext->FloatSave.ControlWord = _Context64.FltSave.ControlWord; + _pContext->FloatSave.StatusWord = _Context64.FltSave.StatusWord; + _pContext->FloatSave.TagWord = _Context64.FltSave.TagWord; + _pContext->FloatSave.ErrorOffset = _Context64.FltSave.ErrorOffset; + _pContext->FloatSave.ErrorSelector = _Context64.FltSave.ErrorSelector; + _pContext->FloatSave.DataOffset = _Context64.FltSave.DataOffset; + _pContext->FloatSave.DataSelector = _Context64.FltSave.DataSelector; + _pContext->FloatSave.Cr0NpxState = 0; + + constexpr auto kFloatRegisterByteSize = sizeof(_pContext->FloatSave.RegisterArea) / _countof(_Context64.FltSave.FloatRegisters); + for (size_t i = 0; i != _countof(_Context64.FltSave.FloatRegisters); ++i) + { + memcpy(_pContext->FloatSave.RegisterArea + i * kFloatRegisterByteSize, &_Context64.FltSave.FloatRegisters[i], kFloatRegisterByteSize); + } + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_SEGMENTS) == WOW64_CONTEXT_SEGMENTS) + { + _pContext->SegGs = 0x2Bu; + _pContext->SegFs = 0x53u; + _pContext->SegEs = 0x2Bu; + _pContext->SegDs = 0x2Bu; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_INTEGER) == WOW64_CONTEXT_INTEGER) + { + _pContext->Edi = static_cast(_Context64.Rdi); + _pContext->Esi = static_cast(_Context64.Rsi); + _pContext->Ebx = static_cast(_Context64.Rbx); + _pContext->Edx = static_cast(_Context64.Rdx); + _pContext->Ecx = static_cast(_Context64.Rcx); + _pContext->Eax = static_cast(_Context64.Rax); + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_CONTROL) == WOW64_CONTEXT_CONTROL) + { + _pContext->Ebp = static_cast(_Context64.Rbp); + _pContext->Eip = static_cast(_Context64.Rip); + _pContext->SegCs = 0x23u; + _pContext->EFlags = _Context64.EFlags & 0x3F0DD5u | 0x202u; + _pContext->Esp = static_cast(_Context64.Rsp); + _pContext->SegSs = 0x2Bu; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_EXTENDED_REGISTERS) == WOW64_CONTEXT_EXTENDED_REGISTERS) + { + struct DECLSPEC_ALIGN(16) _XSAVE_FORMAT_WOW64 + { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + + M128A XmmRegisters[8]; + }; + + memcpy(_pContext->ExtendedRegisters, &_Context64.FltSave, sizeof(_XSAVE_FORMAT_WOW64)); + } + + return TRUE; + } + else if (_Context64.SegCs == 0x33u) + { + // 虽然大多数 x86程序地址最大只有2G,但是开启大地址时也可以达到接近4G + // 如果RSP大于32位上限,那么这明显就是一个64位程序。 + if (_Context64.Rsp > 0xffff0000ull) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + auto _hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, static_cast(reinterpret_cast(ThreadBasicInfo.ClientId.UniqueProcess))); + if (_hProcess == NULL) + { + return FALSE; + } + + LSTATUS _lStatus = ERROR_SUCCESS; + + do + { + void* _pRemoteThreadWow64Context = nullptr; + + auto _pRemoteThreadTeb = (TEB*)ThreadBasicInfo.TebBaseAddress; + // TEB->TlsSlots[1](TEB + 0x1488)指向一个 WOW64_CONTEXT,具体可以参考 wow64cpu.dll!CpuGetContext + static_assert((UFIELD_OFFSET(TEB, TlsSlots) + 1 * sizeof(TEB::TlsSlots[0])) == 0x1488, ""); + if (!ReadProcessMemory(_hProcess, &_pRemoteThreadTeb->TlsSlots[1], &_pRemoteThreadWow64Context, sizeof(_pRemoteThreadWow64Context), nullptr)) + { + _lStatus = ERROR_FUNCTION_FAILED; + break; + } + if (!_pRemoteThreadWow64Context) + { + _lStatus = ERROR_INVALID_PARAMETER; + break; + } + + memset(&ContextBuffer.RemoteWow64ThreadContext, 0, sizeof(ContextBuffer.RemoteWow64ThreadContext)); + if (!ReadProcessMemory(_hProcess, _pRemoteThreadWow64Context, &ContextBuffer.RemoteWow64ThreadContext, sizeof(ContextBuffer.RemoteWow64ThreadContext), nullptr)) + { + _lStatus = ERROR_FUNCTION_FAILED; + break; + } + + auto& _Wow64ThreadContext = ContextBuffer.RemoteWow64ThreadContext.ThreadContext; + if ((_Wow64ThreadContext.ContextFlags & WOW64_CONTEXT_i386) == 0) + { + _lStatus = ERROR_INVALID_PARAMETER; + break; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_DEBUG_REGISTERS) == WOW64_CONTEXT_DEBUG_REGISTERS) + { + _pContext->Dr0 = _Wow64ThreadContext.Dr0; + _pContext->Dr1 = _Wow64ThreadContext.Dr1; + _pContext->Dr2 = _Wow64ThreadContext.Dr2; + _pContext->Dr3 = _Wow64ThreadContext.Dr3; + _pContext->Dr6 = _Wow64ThreadContext.Dr6; + _pContext->Dr7 = _Wow64ThreadContext.Dr7; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_FLOATING_POINT) == WOW64_CONTEXT_FLOATING_POINT) + { + memcpy(&_pContext->FloatSave, &_Wow64ThreadContext.FloatSave, sizeof(_Wow64ThreadContext.FloatSave)); + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_SEGMENTS) == WOW64_CONTEXT_SEGMENTS) + { + _pContext->SegGs = 0x2Bu; + _pContext->SegFs = 0x53u; + _pContext->SegEs = 0x2Bu; + _pContext->SegDs = 0x2Bu; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_INTEGER) == WOW64_CONTEXT_INTEGER) + { + _pContext->Edi = _Wow64ThreadContext.Edi; + _pContext->Esi = _Wow64ThreadContext.Esi; + _pContext->Ebx = _Wow64ThreadContext.Ebx; + _pContext->Edx = _Wow64ThreadContext.Edx; + _pContext->Ecx = _Wow64ThreadContext.Ecx; + _pContext->Eax = _Wow64ThreadContext.Eax; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_CONTROL) == WOW64_CONTEXT_CONTROL) + { + _pContext->Ebp = _Wow64ThreadContext.Ebp; + _pContext->Eip = _Wow64ThreadContext.Eip; + _pContext->SegCs = 0x23u; + _pContext->EFlags = _Wow64ThreadContext.EFlags & 0x3F0DD5u | 0x202u; + _pContext->Esp = _Wow64ThreadContext.Esp; + _pContext->SegSs = 0x2Bu; + } + + if ((_pContext->ContextFlags & WOW64_CONTEXT_EXTENDED_REGISTERS) == WOW64_CONTEXT_EXTENDED_REGISTERS) + { + memcpy(_pContext->ExtendedRegisters, _Wow64ThreadContext.ExtendedRegisters, sizeof(_Wow64ThreadContext.ExtendedRegisters)); + } + + } while (false); + CloseHandle(_hProcess); + + if (_lStatus) + { + SetLastError(_lStatus); + return FALSE; + } + else + { + return TRUE; + } + } + else + { + // 非预期值。 + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +#else +#error ???? +#endif } #endif } //namespace YY::Thunks diff --git a/src/Thunks/api-ms-win-core-xstate.hpp b/src/Thunks/api-ms-win-core-xstate.hpp index 00f02995..cd10e0fb 100644 --- a/src/Thunks/api-ms-win-core-xstate.hpp +++ b/src/Thunks/api-ms-win-core-xstate.hpp @@ -1,347 +1,350 @@ -namespace YY +namespace YY::Thunks { - namespace Thunks - { #if (YY_Thunks_Support_Version < NTDDI_WIN6SP1) - // 最低受支持的客户端 Windows 7 SP1[桌面应用 | UWP 应用] - // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] - __DEFINE_THUNK( - kernel32, - 0, - DWORD64, - WINAPI, - GetEnabledXStateFeatures, - VOID - ) + // 最低受支持的客户端 Windows 7 SP1[桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 0, + DWORD64, + WINAPI, + GetEnabledXStateFeatures, + VOID + ) + { + if (auto const _pfnGetEnabledXStateFeatures = try_get_GetEnabledXStateFeatures()) { - if (auto const _pfnGetEnabledXStateFeatures = try_get_GetEnabledXStateFeatures()) - { - return _pfnGetEnabledXStateFeatures(); - } - - static DWORD64 s_uXState = 0; - if (s_uXState) - { - return s_uXState; - } + return _pfnGetEnabledXStateFeatures(); + } - DWORD64 _uXState = XSTATE_MASK_LEGACY_FLOATING_POINT; - if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) - { - _uXState |= XSTATE_MASK_LEGACY_SSE; - } + static DWORD64 s_uXState = 0; + if (s_uXState) + { + return s_uXState; + } - s_uXState = _uXState; - return _uXState; + DWORD64 _uXState = XSTATE_MASK_LEGACY_FLOATING_POINT; + if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) + { + _uXState |= XSTATE_MASK_LEGACY_SSE; } + + s_uXState = _uXState; + return _uXState; + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6SP1) - // 最低受支持的客户端 Windows 7 SP1 [仅限桌面应用] - // 最低受支持的服务器 Windows Server 2008 R2 SP1[仅限桌面应用] - __DEFINE_THUNK( - kernel32, - 12, - BOOL, - WINAPI, - SetXStateFeaturesMask, - _Inout_ PCONTEXT Context, - _In_ DWORD64 FeatureMask - ) + // 最低受支持的客户端 Windows 7 SP1 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2008 R2 SP1[仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 12, + BOOL, + WINAPI, + SetXStateFeaturesMask, + _Inout_ PCONTEXT Context, + _In_ DWORD64 FeatureMask + ) + { + if (auto const _pfnSetXStateFeaturesMask = try_get_SetXStateFeaturesMask()) { - if (auto const _pfnSetXStateFeaturesMask = try_get_SetXStateFeaturesMask()) - { - return _pfnSetXStateFeaturesMask(Context, FeatureMask); - } - const auto _uSupportFeatures = GetEnabledXStateFeatures(); + return _pfnSetXStateFeaturesMask(Context, FeatureMask); + } + const auto _uSupportFeatures = GetEnabledXStateFeatures(); - if (FeatureMask & (~_uSupportFeatures)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - else - { - return TRUE; - } + if (FeatureMask & (~_uSupportFeatures)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + else + { + return TRUE; } + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6SP1) - // 最低受支持的客户端 Windows 7 SP1 [桌面应用 |UWP 应用] - // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] - __DEFINE_THUNK( - kernel32, - 12, - PVOID, - WINAPI, - LocateXStateFeature, - _In_ PCONTEXT Context, - _In_ DWORD FeatureId, - _Out_opt_ PDWORD Length - ) + // 最低受支持的客户端 Windows 7 SP1 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 12, + PVOID, + WINAPI, + LocateXStateFeature, + _In_ PCONTEXT Context, + _In_ DWORD FeatureId, + _Out_opt_ PDWORD Length + ) + { + if (auto const _pfnLocateXStateFeature = try_get_LocateXStateFeature()) { - if (auto const _pfnLocateXStateFeature = try_get_LocateXStateFeature()) - { - return _pfnLocateXStateFeature(Context, FeatureId, Length); - } + return _pfnLocateXStateFeature(Context, FeatureId, Length); + } #if defined(_X86_) - auto& _XSave = *(XSAVE_FORMAT*)Context->ExtendedRegisters; - constexpr auto kThreadContext = CONTEXT_i386; + auto& _XSave = *(XSAVE_FORMAT*)Context->ExtendedRegisters; + constexpr auto kThreadContext = CONTEXT_i386; #elif defined(_AMD64_) - auto& _XSave = Context->FltSave; - constexpr auto kThreadContext = CONTEXT_AMD64; + auto& _XSave = Context->FltSave; + constexpr auto kThreadContext = CONTEXT_AMD64; #else #error unknow OS. #endif - if (kThreadContext & Context->ContextFlags) + if (kThreadContext & Context->ContextFlags) + { + if (XSTATE_LEGACY_FLOATING_POINT == FeatureId) { - if (XSTATE_LEGACY_FLOATING_POINT == FeatureId) + if (Length) { - if (Length) - { - *Length = UFIELD_OFFSET(XSAVE_FORMAT, XmmRegisters); - } - return &_XSave; + *Length = UFIELD_OFFSET(XSAVE_FORMAT, XmmRegisters); } - else if (XSTATE_LEGACY_SSE == FeatureId) + return &_XSave; + } + else if (XSTATE_LEGACY_SSE == FeatureId) + { + if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) { - if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) + if (Length) { - if (Length) - { - *Length = sizeof(_XSave.XmmRegisters); - } - return &_XSave.XmmRegisters; + *Length = sizeof(_XSave.XmmRegisters); } + return &_XSave.XmmRegisters; } } - - if (Length) - *Length = 0; - return nullptr; } + + if (Length) + *Length = 0; + return nullptr; + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6SP1) - // 最低受支持的客户端 Windows 7 SP1 [桌面应用 |UWP 应用] - // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] - __DEFINE_THUNK( - kernel32, - 16, - BOOL, - WINAPI, - InitializeContext, - _Out_writes_bytes_opt_(*ContextLength) PVOID Buffer, - _In_ DWORD ContextFlags, - _Out_ PCONTEXT* Context, - _Inout_ PDWORD ContextLength - ) + // 最低受支持的客户端 Windows 7 SP1 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2 SP1[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 16, + BOOL, + WINAPI, + InitializeContext, + _Out_writes_bytes_opt_(*ContextLength) PVOID Buffer, + _In_ DWORD ContextFlags, + _Out_ PCONTEXT* Context, + _Inout_ PDWORD ContextLength + ) + { + if (auto const _pfnInitializeContext = try_get_InitializeContext()) { - if (auto const _pfnInitializeContext = try_get_InitializeContext()) - { - return _pfnInitializeContext(Buffer, ContextFlags, Context, ContextLength); - } - - constexpr auto kSupportContextFlags = CONTEXT_ALL | CONTEXT_EXCEPTION_ACTIVE | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING; + return _pfnInitializeContext(Buffer, ContextFlags, Context, ContextLength); + } - if (ContextFlags & (~kSupportContextFlags)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + constexpr auto kSupportContextFlags = CONTEXT_ALL | CONTEXT_EXCEPTION_ACTIVE | CONTEXT_SERVICE_ACTIVE | CONTEXT_EXCEPTION_REQUEST | CONTEXT_EXCEPTION_REPORTING; - if (Buffer == nullptr || *ContextLength < sizeof(CONTEXT)) - { - *ContextLength = sizeof(CONTEXT); - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; - } + if (ContextFlags & (~kSupportContextFlags)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - auto _pContext = reinterpret_cast(Buffer); - _pContext->ContextFlags = ContextFlags; + if (Buffer == nullptr || *ContextLength < sizeof(CONTEXT)) + { *ContextLength = sizeof(CONTEXT); - *Context = _pContext; - return TRUE; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; } + + auto _pContext = reinterpret_cast(Buffer); + _pContext->ContextFlags = ContextFlags; + *ContextLength = sizeof(CONTEXT); + *Context = _pContext; + return TRUE; + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN10_FE) - // 最低受支持的客户端 Windows 10内部版本 20348 - // 最低受支持的服务器 Windows 10内部版本 20348 - __DEFINE_THUNK( - kernel32, - 24, - BOOL, - WINAPI, - InitializeContext2, - _Out_writes_bytes_opt_(*ContextLength) PVOID Buffer, - _In_ DWORD ContextFlags, - _Out_ PCONTEXT* Context, - _Inout_ PDWORD ContextLength, - _In_ ULONG64 XStateCompactionMask - ) + // 最低受支持的客户端 Windows 10内部版本 20348 + // 最低受支持的服务器 Windows 10内部版本 20348 + __DEFINE_THUNK( + kernel32, + 24, + BOOL, + WINAPI, + InitializeContext2, + _Out_writes_bytes_opt_(*ContextLength) PVOID Buffer, + _In_ DWORD ContextFlags, + _Out_ PCONTEXT* Context, + _Inout_ PDWORD ContextLength, + _In_ ULONG64 XStateCompactionMask + ) + { + if (auto const _pfnInitializeContext2 = try_get_InitializeContext2()) { - if (auto const _pfnInitializeContext2 = try_get_InitializeContext2()) - { - return _pfnInitializeContext2(Buffer, ContextFlags, Context, ContextLength, XStateCompactionMask); - } - - return InitializeContext(Buffer, ContextFlags, Context, ContextLength); + return _pfnInitializeContext2(Buffer, ContextFlags, Context, ContextLength, XStateCompactionMask); } + + return InitializeContext(Buffer, ContextFlags, Context, ContextLength); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6SP1) - // 最低受支持的客户端 Windows 7 SP1 [仅限桌面应用] - // 最低受支持的服务器 Windows Server 2008 R2 SP1[仅限桌面应用] - __DEFINE_THUNK( - kernel32, - 12, - BOOL, - WINAPI, - CopyContext, - _Inout_ PCONTEXT _pDestination, - _In_ DWORD _uContextFlags, - _In_ PCONTEXT _pSource - ) + // 最低受支持的客户端 Windows 7 SP1 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2008 R2 SP1[仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 12, + BOOL, + WINAPI, + CopyContext, + _Inout_ PCONTEXT _pDestination, + _In_ DWORD _uContextFlags, + _In_ PCONTEXT _pSource + ) + { + if (auto const _pfnCopyContext = try_get_CopyContext()) { - if (auto const _pfnCopyContext = try_get_CopyContext()) - { - return _pfnCopyContext(_pDestination, _uContextFlags, _pSource); - } + return _pfnCopyContext(_pDestination, _uContextFlags, _pSource); + } #if defined(_X86_) - constexpr auto kThreadContext = CONTEXT_i386; + constexpr auto kThreadContext = CONTEXT_i386; #elif defined(_AMD64_) - constexpr auto kThreadContext = CONTEXT_AMD64; + constexpr auto kThreadContext = CONTEXT_AMD64; #else #error unknow OS. #endif - if ((_uContextFlags & kThreadContext) == 0) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + if ((_uContextFlags & kThreadContext) == 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - if ((CONTEXT_XSTATE & _uContextFlags) == CONTEXT_XSTATE) - { - // internal::BaseSetLastNTError(0xC00000BB); - SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; - } + if ((CONTEXT_XSTATE & _uContextFlags) == CONTEXT_XSTATE) + { + // internal::BaseSetLastNTError(0xC00000BB); + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } - if ((_pSource->ContextFlags & kThreadContext) == 0 || (_pDestination->ContextFlags & kThreadContext) == 0) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + if ((_pSource->ContextFlags & kThreadContext) == 0 || (_pDestination->ContextFlags & kThreadContext) == 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - if ((CONTEXT_DEBUG_REGISTERS & _uContextFlags) == CONTEXT_DEBUG_REGISTERS && (CONTEXT_DEBUG_REGISTERS & _pSource->ContextFlags) == CONTEXT_DEBUG_REGISTERS) - { - _pDestination->ContextFlags |= CONTEXT_DEBUG_REGISTERS; - _pDestination->Dr0 = _pSource->Dr0; - _pDestination->Dr1 = _pSource->Dr1; - _pDestination->Dr2 = _pSource->Dr2; - _pDestination->Dr3 = _pSource->Dr3; - _pDestination->Dr6 = _pSource->Dr6; - _pDestination->Dr7 = _pSource->Dr7; + if ((CONTEXT_DEBUG_REGISTERS & _uContextFlags) == CONTEXT_DEBUG_REGISTERS && (CONTEXT_DEBUG_REGISTERS & _pSource->ContextFlags) == CONTEXT_DEBUG_REGISTERS) + { + _pDestination->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + _pDestination->Dr0 = _pSource->Dr0; + _pDestination->Dr1 = _pSource->Dr1; + _pDestination->Dr2 = _pSource->Dr2; + _pDestination->Dr3 = _pSource->Dr3; + _pDestination->Dr6 = _pSource->Dr6; + _pDestination->Dr7 = _pSource->Dr7; #if defined(_AMD64_) - _pDestination->LastBranchToRip = _pSource->LastBranchToRip; - _pDestination->LastBranchFromRip = _pSource->LastBranchFromRip; - _pDestination->LastExceptionToRip = _pSource->LastExceptionToRip; - _pDestination->LastExceptionFromRip = _pSource->LastExceptionFromRip; + _pDestination->LastBranchToRip = _pSource->LastBranchToRip; + _pDestination->LastBranchFromRip = _pSource->LastBranchFromRip; + _pDestination->LastExceptionToRip = _pSource->LastExceptionToRip; + _pDestination->LastExceptionFromRip = _pSource->LastExceptionFromRip; #endif - } + } - if ((CONTEXT_FLOATING_POINT & _uContextFlags) == CONTEXT_FLOATING_POINT && (CONTEXT_FLOATING_POINT & _pSource->ContextFlags) == CONTEXT_FLOATING_POINT) - { - _pDestination->ContextFlags |= CONTEXT_FLOATING_POINT; + if ((CONTEXT_FLOATING_POINT & _uContextFlags) == CONTEXT_FLOATING_POINT && (CONTEXT_FLOATING_POINT & _pSource->ContextFlags) == CONTEXT_FLOATING_POINT) + { + _pDestination->ContextFlags |= CONTEXT_FLOATING_POINT; #if defined(_X86_) - memcpy(&_pDestination->FloatSave, &_pSource->FloatSave, sizeof(_pSource->FloatSave)); + memcpy(&_pDestination->FloatSave, &_pSource->FloatSave, sizeof(_pSource->FloatSave)); #elif defined(_AMD64_) - _pDestination->MxCsr = _pSource->MxCsr; - memcpy(&_pDestination->FltSave, &_pSource->FltSave, sizeof(_pSource->FltSave)); + _pDestination->MxCsr = _pSource->MxCsr; + memcpy(&_pDestination->FltSave, &_pSource->FltSave, sizeof(_pSource->FltSave)); #else #error unknow OS. #endif - } + } - if ((CONTEXT_SEGMENTS & _uContextFlags) == CONTEXT_SEGMENTS && (CONTEXT_SEGMENTS & _pSource->ContextFlags) == CONTEXT_SEGMENTS) - { - _pDestination->ContextFlags |= CONTEXT_SEGMENTS; - _pDestination->SegGs = _pSource->SegGs; - _pDestination->SegFs = _pSource->SegFs; - _pDestination->SegEs = _pSource->SegEs; - _pDestination->SegDs = _pSource->SegDs; - } + if ((CONTEXT_SEGMENTS & _uContextFlags) == CONTEXT_SEGMENTS && (CONTEXT_SEGMENTS & _pSource->ContextFlags) == CONTEXT_SEGMENTS) + { + _pDestination->ContextFlags |= CONTEXT_SEGMENTS; + _pDestination->SegGs = _pSource->SegGs; + _pDestination->SegFs = _pSource->SegFs; + _pDestination->SegEs = _pSource->SegEs; + _pDestination->SegDs = _pSource->SegDs; + } - if ((CONTEXT_INTEGER & _uContextFlags) == CONTEXT_INTEGER && (CONTEXT_INTEGER & _pSource->ContextFlags) == CONTEXT_INTEGER) - { - _pDestination->ContextFlags |= CONTEXT_INTEGER; + if ((CONTEXT_INTEGER & _uContextFlags) == CONTEXT_INTEGER && (CONTEXT_INTEGER & _pSource->ContextFlags) == CONTEXT_INTEGER) + { + _pDestination->ContextFlags |= CONTEXT_INTEGER; #if defined(_X86_) - _pDestination->Edi = _pSource->Edi; - _pDestination->Esi = _pSource->Esi; - _pDestination->Ebx = _pSource->Ebx; - _pDestination->Edx = _pSource->Edx; - _pDestination->Ecx = _pSource->Ecx; - _pDestination->Eax = _pSource->Eax; + _pDestination->Edi = _pSource->Edi; + _pDestination->Esi = _pSource->Esi; + _pDestination->Ebx = _pSource->Ebx; + _pDestination->Edx = _pSource->Edx; + _pDestination->Ecx = _pSource->Ecx; + _pDestination->Eax = _pSource->Eax; #elif defined(_AMD64_) - _pDestination->Rax = _pSource->Rax; - _pDestination->Rcx = _pSource->Rcx; - _pDestination->Rdx = _pSource->Rdx; - _pDestination->Rbx = _pSource->Rbx; - _pDestination->Rbp = _pSource->Rbp; - _pDestination->Rsi = _pSource->Rsi; - _pDestination->Rdi = _pSource->Rdi; - _pDestination->R8 = _pSource->R8; - _pDestination->R9 = _pSource->R9; - _pDestination->R10 = _pSource->R10; - _pDestination->R11 = _pSource->R11; - _pDestination->R12 = _pSource->R12; - _pDestination->R13 = _pSource->R13; - _pDestination->R14 = _pSource->R14; - _pDestination->R15 = _pSource->R15; + _pDestination->Rax = _pSource->Rax; + _pDestination->Rcx = _pSource->Rcx; + _pDestination->Rdx = _pSource->Rdx; + _pDestination->Rbx = _pSource->Rbx; + _pDestination->Rbp = _pSource->Rbp; + _pDestination->Rsi = _pSource->Rsi; + _pDestination->Rdi = _pSource->Rdi; + _pDestination->R8 = _pSource->R8; + _pDestination->R9 = _pSource->R9; + _pDestination->R10 = _pSource->R10; + _pDestination->R11 = _pSource->R11; + _pDestination->R12 = _pSource->R12; + _pDestination->R13 = _pSource->R13; + _pDestination->R14 = _pSource->R14; + _pDestination->R15 = _pSource->R15; #else #error unknow OS. #endif - } + } - if ((CONTEXT_CONTROL & _uContextFlags) == CONTEXT_CONTROL && (CONTEXT_CONTROL & _pSource->ContextFlags) == CONTEXT_CONTROL) - { - _pDestination->ContextFlags |= CONTEXT_CONTROL; + if ((CONTEXT_CONTROL & _uContextFlags) == CONTEXT_CONTROL && (CONTEXT_CONTROL & _pSource->ContextFlags) == CONTEXT_CONTROL) + { + _pDestination->ContextFlags |= CONTEXT_CONTROL; #if defined(_X86_) - _pDestination->Ebp = _pSource->Ebp; - _pDestination->Eip = _pSource->Eip; - _pDestination->SegCs = _pSource->SegCs; - _pDestination->EFlags = _pSource->EFlags; - _pDestination->Esp = _pSource->Esp; - _pDestination->SegSs = _pSource->SegSs; + _pDestination->Ebp = _pSource->Ebp; + _pDestination->Eip = _pSource->Eip; + _pDestination->SegCs = _pSource->SegCs; + _pDestination->EFlags = _pSource->EFlags; + _pDestination->Esp = _pSource->Esp; + _pDestination->SegSs = _pSource->SegSs; #elif defined(_AMD64_) - _pDestination->SegCs = _pSource->SegCs; - _pDestination->SegSs = _pSource->SegSs; - _pDestination->EFlags = _pSource->EFlags; - _pDestination->Rsp = _pSource->Rsp; - _pDestination->Rip = _pSource->Rip; + _pDestination->SegCs = _pSource->SegCs; + _pDestination->SegSs = _pSource->SegSs; + _pDestination->EFlags = _pSource->EFlags; + _pDestination->Rsp = _pSource->Rsp; + _pDestination->Rip = _pSource->Rip; #else #error unknow OS. #endif - } - - return TRUE; + } + +#if defined(CONTEXT_EXTENDED_REGISTERS) + if ((CONTEXT_EXTENDED_REGISTERS & _uContextFlags) == CONTEXT_EXTENDED_REGISTERS && (CONTEXT_EXTENDED_REGISTERS & _pSource->ContextFlags) == CONTEXT_EXTENDED_REGISTERS) + { + memcpy(_pDestination->ExtendedRegisters, _pSource->ExtendedRegisters, sizeof(_pSource->ExtendedRegisters)); } #endif + return TRUE; } +#endif } diff --git a/src/Thunks/d3d12.hpp b/src/Thunks/d3d12.hpp new file mode 100644 index 00000000..04c8c27f --- /dev/null +++ b/src/Thunks/d3d12.hpp @@ -0,0 +1,31 @@ +#if (YY_Thunks_Support_Version < NTDDI_WIN10) +#include +#endif + +namespace YY::Thunks +{ +#if (YY_Thunks_Support_Version < NTDDI_WIN10) + + // Windows 10 + __DEFINE_THUNK( + d3d12, + 16, + HRESULT, + WINAPI, + D3D12CreateDevice, + _In_opt_ IUnknown* pAdapter, + D3D_FEATURE_LEVEL MinimumFeatureLevel, + _In_ REFIID riid, // Expected: ID3D12Device + _COM_Outptr_opt_ void** ppDevice) + { + if (const auto _pfnD3D12CreateDevice = try_get_D3D12CreateDevice()) + { + return _pfnD3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); + } + + if (ppDevice) + *ppDevice = nullptr; + return E_NOINTERFACE; + } +#endif +} diff --git a/src/Thunks/ext-ms-win-rtcore-ntuser-wmpointer.hpp b/src/Thunks/ext-ms-win-rtcore-ntuser-wmpointer.hpp new file mode 100644 index 00000000..f91a68b6 --- /dev/null +++ b/src/Thunks/ext-ms-win-rtcore-ntuser-wmpointer.hpp @@ -0,0 +1,125 @@ +namespace YY::Thunks +{ +#if (YY_Thunks_Support_Version < NTDDI_WIN8) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + user32, + 8, + BOOL, + WINAPI, + RegisterPointerDeviceNotifications, + _In_ HWND _hWindow, + _In_ BOOL _bNotifyRange + ) + { + if (const auto _pfnRegisterPointerDeviceNotifications = try_get_RegisterPointerDeviceNotifications()) + { + return _pfnRegisterPointerDeviceNotifications(_hWindow, _bNotifyRange); + } + + return TRUE; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN8) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + user32, + 8, + BOOL, + WINAPI, + GetPointerDevices, + _Inout_ UINT32* _uDeviceCount, + _Out_writes_opt_(*_uDeviceCount) POINTER_DEVICE_INFO* _pPointerDevices + ) + { + if (const auto _pfnRGetPointerDevices = try_get_GetPointerDevices()) + { + return _pfnRGetPointerDevices(_uDeviceCount, _pPointerDevices); + } + + SetLastError(ERROR_SYSTEM_DEVICE_NOT_FOUND); + return FALSE; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN8) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + user32, + 8, + BOOL, + WINAPI, + GetPointerDevice, + _In_ HANDLE _hDevice, + _Out_writes_(1) POINTER_DEVICE_INFO* _pPointerDevice + ) + { + if (const auto _pfnGetPointerDevice = try_get_GetPointerDevice()) + { + return _pfnGetPointerDevice(_hDevice, _pPointerDevice); + } + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN8) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + user32, + 8, + BOOL, + WINAPI, + GetPointerPenInfo, + _In_ UINT32 _uPointerId, + _Out_writes_(1) POINTER_PEN_INFO* _pPenInfo + ) + { + if (const auto _pfnGetPointerPenInfo = try_get_GetPointerPenInfo()) + { + return _pfnGetPointerPenInfo(_uPointerId, _pPenInfo); + } + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN8) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用] + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + user32, + 8, + BOOL, + WINAPI, + GetPointerType, + _In_ UINT32 _uPointerId, + _Out_ POINTER_INPUT_TYPE* _pPointerType + ) + { + if (const auto _pfnGetPointerType = try_get_GetPointerType()) + { + return _pfnGetPointerType(_uPointerId, _pPointerType); + } + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +#endif +} diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj index ad4a6fbc..aa4d21c0 100644 --- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj +++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj @@ -175,6 +175,7 @@ + @@ -213,6 +214,7 @@ + @@ -225,6 +227,7 @@ + @@ -238,6 +241,7 @@ + diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters index 3a0d727d..42b57d50 100644 --- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters +++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters @@ -81,6 +81,9 @@ 源文件\UnitTest + + 源文件\UnitTest + @@ -317,19 +320,19 @@ Thunks - + Thunks - + Thunks - + Thunks - + Thunks - + Thunks diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-handle.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-handle.UnitTest.cpp new file mode 100644 index 00000000..a450980d --- /dev/null +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-handle.UnitTest.cpp @@ -0,0 +1,244 @@ +#include "pch.h" +#include "Thunks/api-ms-win-core-handle.hpp" + +namespace api_ms_win_core_handle +{ + TEST_CLASS(CompareObjectHandles) + { + AwaysNullGuard Guard; + + public: + CompareObjectHandles() + { + Guard |= YY::Thunks::aways_null_try_get_CompareObjectHandles; + } + + TEST_METHOD(常规比较) + { + { + constexpr const wchar_t Name[] = L"\\KernelObjects\\CritSecOutOfMemoryEvent"; + auto pNtOpenKeyedEvent = (decltype(NtOpenKeyedEvent)*) GetProcAddress(GetModuleHandleW(L"ntdll"), "NtOpenKeyedEvent"); + + UNICODE_STRING ObjectName = { sizeof(Name) - sizeof(wchar_t),sizeof(Name) - sizeof(wchar_t) ,(PWSTR)Name }; + OBJECT_ATTRIBUTES attr = { sizeof(attr),nullptr,&ObjectName }; + + HANDLE _hHandle1; + pNtOpenKeyedEvent(&_hHandle1, MAXIMUM_ALLOWED, &attr); + + HANDLE _hHandle2; + pNtOpenKeyedEvent(&_hHandle2, MAXIMUM_ALLOWED, &attr); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + HANDLE _hHandle1 = CreateWaitableTimerW(nullptr, FALSE, L"Local\\TestWaitableTimer"); + Assert::IsNotNull(_hHandle1); + + HANDLE _hHandle2 = OpenWaitableTimerW(SYNCHRONIZE, FALSE, L"Local\\TestWaitableTimer"); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 4); + HANDLE _hHandle2; + Assert::IsTrue(DuplicateHandle(NtGetCurrentProcess(), _hHandle1, NtGetCurrentProcess(), &_hHandle2, 0, FALSE, DUPLICATE_SAME_ACCESS)); + auto _hFile1 = CreateFileW(LR"(C:\Windows\System32\ntdll.dll)", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + auto _hHandle3 = CreateIoCompletionPort(_hFile1, _hHandle1, 0, 0); + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + CloseHandle(_hFile1); + } + + { + auto _hHandle1 = OpenDesktopW(L"Default", 0, FALSE, STANDARD_RIGHTS_READ); + auto _hHandle2 = OpenDesktopW(L"Default", 0, FALSE, STANDARD_RIGHTS_READ); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = OpenWindowStationW(nullptr, FALSE, STANDARD_RIGHTS_READ); + auto _hHandle2 = OpenWindowStationW(nullptr, FALSE, STANDARD_RIGHTS_READ); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateFileW(L"C:\\Windows", 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + Assert::AreNotEqual(_hHandle1, INVALID_HANDLE_VALUE); + + auto _hHandle2 = CreateFileW(L"C:\\Windows", 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + Assert::AreNotEqual(_hHandle2, INVALID_HANDLE_VALUE); + + HANDLE _hHandle3; + Assert::IsTrue(DuplicateHandle(NtGetCurrentProcess(), _hHandle1, NtGetCurrentProcess(), &_hHandle3, 0, FALSE, DUPLICATE_SAME_ACCESS)); + + Assert::IsFalse(::CompareObjectHandles(_hHandle1, _hHandle2)); + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle3)); + + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + CloseHandle(_hHandle3); + } + + { + auto _hHandle1 = CreateSemaphoreW(nullptr, 0, 2, L"Local\\TestSemaphore"); + auto _hHandle2 = OpenSemaphoreW(SYNCHRONIZE, FALSE, L"Local\\TestSemaphore"); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateMutexW(nullptr, FALSE, L"Local\\TestMutex"); + auto _hHandle2 = OpenMutexW(SYNCHRONIZE, FALSE, L"Local\\TestMutex"); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateNamedPipeW( + L"\\\\.\\pipe\\TestNamedPipe", + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + 512, + 512, + 0, + NULL); + + auto _hHandle2 = CreateFileW(L"\\\\.\\pipe\\TestNamedPipe",GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, NULL); + HANDLE _hHandle3; + Assert::IsTrue(DuplicateHandle(NtGetCurrentProcess(), _hHandle1, NtGetCurrentProcess(), &_hHandle3, 0, FALSE, DUPLICATE_SAME_ACCESS)); + + //auto _hHandle1 = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READONLY, 0, 4096, L"Local\\TestFileMap"); + //auto _hHandle2 = OpenFileMappingW(FILE_MAP_READ, FALSE, L"Local\\TestFileMap"); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsFalse(::CompareObjectHandles(_hHandle1, _hHandle2)); + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle3)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READONLY, 0, 4096, L"Local\\TestFileMap"); + auto _hHandle2 = OpenFileMappingW(FILE_MAP_READ, FALSE, L"Local\\TestFileMap"); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + HKEY _hHandle1; + auto _lStatus = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE", &_hHandle1); + Assert::AreEqual(_lStatus, ERROR_SUCCESS); + + HKEY _hHandle2; + _lStatus = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE", &_hHandle2); + Assert::AreEqual(_lStatus, ERROR_SUCCESS); + + Assert::IsFalse(::CompareObjectHandles(_hHandle1, _hHandle2)); + + HKEY _hHandle3; + Assert::IsTrue(DuplicateHandle(NtGetCurrentProcess(), _hHandle1, NtGetCurrentProcess(), (HANDLE*)&_hHandle3, 0, FALSE, DUPLICATE_SAME_ACCESS)); + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle3)); + + RegCloseKey(_hHandle1); + RegCloseKey(_hHandle2); + RegCloseKey(_hHandle3); + } + + { + auto _hHandle1 = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId()); + auto _hHandle2 = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId()); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = OpenProcess(SYNCHRONIZE, FALSE, GetCurrentProcessId()); + auto _hHandle2 = OpenProcess(SYNCHRONIZE, FALSE, GetCurrentProcessId()); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + } + + { + auto _hHandle1 = CreateEventW(nullptr, FALSE, FALSE, L"Local\\TestEvent"); + auto _hHandle2 = OpenEventW(SYNCHRONIZE, FALSE, L"Local\\TestEvent"); + auto _hHandle3 = CreateEventW(nullptr, FALSE, FALSE, L"Local\\TestEvend"); + + Assert::IsNotNull(_hHandle1); + Assert::IsNotNull(_hHandle2); + Assert::IsNotNull(_hHandle3); + + Assert::IsTrue(::CompareObjectHandles(_hHandle1, _hHandle2)); + Assert::IsFalse(::CompareObjectHandles(_hHandle1, _hHandle3)); + CloseHandle(_hHandle1); + CloseHandle(_hHandle2); + CloseHandle(_hHandle3); + } + + { + auto _hFile1 = CreateFileW(LR"(C:\Windows\System32\ntdll.dll)", 0, FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, NULL); + auto _hFile2 = CreateFileW(LR"(C:\Windows\System32\ntdll.dll)", 0, FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, NULL); + HANDLE _hFile3; + Assert::IsTrue(DuplicateHandle(NtGetCurrentProcess(), _hFile1, NtGetCurrentProcess(), &_hFile3, 0, FALSE, DUPLICATE_SAME_ACCESS)); + + Assert::IsNotNull(_hFile1); + Assert::IsNotNull(_hFile2); + Assert::IsNotNull(_hFile3); + + Assert::IsFalse(::CompareObjectHandles(_hFile1, _hFile2)); + Assert::IsTrue(::CompareObjectHandles(_hFile1, _hFile3)); + CloseHandle(_hFile1); + CloseHandle(_hFile2); + CloseHandle(_hFile3); + } + } + }; +}