From 0b8d7c18930a36b29fd93199db67bfd978ac1e86 Mon Sep 17 00:00:00 2001 From: mingkuang Date: Sun, 12 May 2024 18:37:24 +0800 Subject: [PATCH] =?UTF-8?q?Fea=20#66,=20.NET=208/9=E9=80=82=E9=85=8D?= =?UTF-8?q?=EF=BC=8C=E6=89=A9=E5=85=85BCrypt=E7=9B=B8=E5=85=B3=E5=87=BD?= =?UTF-8?q?=E6=95=B0=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptGetProperty=20?= =?UTF-8?q?=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptCreateHash=20=20=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20BCryptDestroyHash=20=20=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20BCryptHashData=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCr?= =?UTF-8?q?yptFinishHash=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptDeriveKeyP?= =?UTF-8?q?BKDF2=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptDeriveKeyCapi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ThunksList.md | 23 +- src/Thunks/bcrypt.hpp | 1068 ++++++++++++++++- src/YY-Thunks.UnitTest/Iphlpapi.UnitTest.cpp | 50 +- .../api-ms-win-core-fibers.UnitTest.cpp | 10 +- ...i-ms-win-core-kernel32-legacy.UnitTest.cpp | 8 +- .../api-ms-win-core-localization.UnitTest.cpp | 15 +- .../api-ms-win-core-path.UnitTest.cpp | 60 +- .../api-ms-win-core-synch.UnitTest.cpp | 26 +- .../api-ms-win-core-threadpool.UnitTest.cpp | 145 ++- .../api-ms-win-power-base.UnitTest.cpp | 6 +- src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp | 181 ++- src/YY-Thunks.UnitTest/pch.h | 34 + src/YY-Thunks.UnitTest/shell32.UnitTest.cpp | 18 +- 13 files changed, 1431 insertions(+), 213 deletions(-) diff --git a/ThunksList.md b/ThunksList.md index d5a38d5..0ee7dff 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -30,6 +30,13 @@ | PathAllocCombine | 不存在时,调用PathCchCombineEx。 | PathAllocCanonicalize | 不存在时,调用PathCchCanonicalizeEx。 +## api-ms-win-core-realtime-l1-1-1.dll +| 函数 | Fallback +| ---- | ----------- +| QueryUnbiasedInterruptTimePrecise | 不存在时,调用QueryUnbiasedInterruptTime。 +| QueryInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。 +| QueryInterruptTimePrecise | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。 + ## api-ms-win-core-winrt-l1-1-0.dll | 函数 | Fallback | ---- | ----------- @@ -85,9 +92,16 @@ ## bcrypt.dll | 函数 | Fallback | ---- | ----------- -| BCryptOpenAlgorithmProvider | 内部实现。 -| BCryptCloseAlgorithmProvider | 内部实现。 -| BCryptGenRandom | 不存在时调用,RtlGenRandom。 +| BCryptOpenAlgorithmProvider | 不存在时,调用CryptAcquireContextW。 +| BCryptCloseAlgorithmProvider | 不存在时,调用CryptReleaseContext。 +| BCryptGenRandom | 不存在时,调用RtlGenRandom。 +| BCryptGetProperty | 不存在时,内部实现。 +| BCryptCreateHash | 不存在时,调用CryptCreateHash。 +| BCryptDestroyHash | 不存在时,调用CryptDestroyHash。 +| BCryptHashData | 不存在时,调用CryptHashData。 +| BCryptFinishHash | 不存在时,调用CryptGetHashParam。 +| BCryptDeriveKeyPBKDF2 | 不存在时,调用CryptCreateHash、CryptHashData。 +| BCryptDeriveKeyCapi | 不存在时,调用CryptCreateHash、CryptHashData。 ## bcryptprimitives.dll | 函数 | Fallback @@ -335,10 +349,7 @@ | GetQueuedCompletionStatusEx | 不存在时,调用 GetQueuedCompletionStatus。 | FindFirstFileEx(W/A) | Windows XP、Vista兼容 FIND_FIRST_EX_LARGE_FETCH、FindExInfoStandard参数。 | GetProcessGroupAffinity | 不存在时,始终认为只有一组CPU。 -| QueryInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。 -| QueryInterruptTimePrecise | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。 | QueryUnbiasedInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值模拟UnbiasedInterruptTime。 -| QueryUnbiasedInterruptTimePrecise | 不存在时,调用QueryUnbiasedInterruptTime。 | FindStringOrdinal | 不存在时,调用CompareStringOrdinal。 | GetEnabledXStateFeatures | 不存在时,调用IsProcessorFeaturePresent。 | SetXStateFeaturesMask | 不存在时,内部实现。 diff --git a/src/Thunks/bcrypt.hpp b/src/Thunks/bcrypt.hpp index 45c23d8..ba3c65d 100644 --- a/src/Thunks/bcrypt.hpp +++ b/src/Thunks/bcrypt.hpp @@ -12,52 +12,547 @@ namespace YY #ifdef YY_Thunks_Implemented + struct BCryptHash; + struct BCryptAlgorithm; + struct BCryptMapItem; + typedef NTSTATUS(__fastcall* OpenAlgorithmProviderType)( + _In_ const BCryptMapItem* _pCryptMapItem, + _In_ ULONG _fFlags, + _Outptr_ BCryptAlgorithm** _ppAlgorithm); + struct BCryptMapItem { - LPCWSTR szAlgId; LPCWSTR szProvider; + LPCWSTR szAlgName; + DWORD cbAlgId; DWORD uProvType; - DWORD uCalg; + DWORD uAlgId; + OpenAlgorithmProviderType pfnOpenAlgorithmProviderType; + + template + constexpr BCryptMapItem(const wchar_t (&_szAlgName)[_cchAlgId], LPCWSTR _szProvider, DWORD _uProvType, DWORD _uAlgId, OpenAlgorithmProviderType _pOpenAlgorithmProvider) + : szProvider(_szProvider) + , szAlgName(_szAlgName) + , cbAlgId(sizeof(_szAlgName)) + , uProvType(_uProvType) + , uAlgId(_uAlgId) + , pfnOpenAlgorithmProviderType(_pOpenAlgorithmProvider) + { + } }; - const BCRYPT_ALG_HANDLE hRngHandle = reinterpret_cast(0xF0); + class BCryptObject + { + static constexpr auto kBCryptObjectMagic = 0x998u; - static const BCryptMapItem* __fastcall BCryptAlgIdToCryptoAPIProvType(_In_ LPCWSTR _szAlgId) - { - if (!_szAlgId) - return nullptr; + DWORD uMagic = kBCryptObjectMagic; + ULONG uRef = 1u; - static const BCryptMapItem g_Map[] = - { - // 加密算法 - // { L"AES", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_AES }, - // { L"DES", MS_DEF_DSS_PROV_W, PROV_DSS, CALG_DES }, - // { L"RC2", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC2 }, - // { L"RC4", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC4 }, - - // 生成随机数算法 - { BCRYPT_RNG_ALGORITHM, nullptr, 0 }, - { BCRYPT_RNG_FIPS186_DSA_ALGORITHM, nullptr, 0 }, - { BCRYPT_RNG_DUAL_EC_ALGORITHM, nullptr, 0 }, - - // Hash算法 - // { L"MD2", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_MD2 }, - // { L"MD4", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_MD4 }, - // { L"MD5", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_MD5 }, - // { L"SHA1", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_SHA1 }, - // { L"SHA256", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_SHA_256 }, - // { L"SHA384", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_SHA_384 }, - // { L"SHA512", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_SHA_512 }, - }; - - for (auto& _Item : g_Map) - { - if (__wcsnicmp_ascii(_szAlgId, _Item.szAlgId, (size_t)-1) == 0) - return &_Item; - } + public: + DWORD uAlgId = 0; + bool bCanFree = true; - return nullptr; - } + BCryptObject(DWORD _uAlgId) + : uAlgId(_uAlgId) + { + } + + virtual ~BCryptObject() + { + // 故意修改,便于 IsBCrypyAlgHandle 时判断有效性。 + uMagic = 0; + } + + bool IsValid() const + { + return uMagic == kBCryptObjectMagic; + } + + DWORD GetClass() const + { + return GET_ALG_CLASS(uAlgId); + } + + bool IsHash() + { + return GetClass() == ALG_CLASS_HASH; + } + + void AddRef() + { + InterlockedIncrement(&uRef); + } + + void Release() + { + if (InterlockedDecrement(&uRef) == 0) + { + this->~BCryptObject(); + if (bCanFree) + { + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + HeapFree(_hProcessHeap, 0, this); + } + } + } + + virtual NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) = 0; + }; + + struct BCryptAlgorithm : public BCryptObject + { + const BCryptMapItem* pMapItem = nullptr; + ULONG fOpenAlgorithmFlags = 0; + + BCryptAlgorithm() + : BCryptObject(0) + { + } + + bool IsRng() const + { + return pMapItem->uAlgId == 0; + } + + bool CanCreateHash() const + { + return GET_ALG_CLASS(pMapItem->uAlgId) == ALG_CLASS_HASH; + } + + DWORD __fastcall GetHashLength() const + { + constexpr auto kByteBits = 32 / sizeof(UINT32); + + switch (pMapItem->uAlgId) + { + case CALG_MD2: + return 32 / kByteBits; + break; + case CALG_MD4: + return 128 / kByteBits; + break; + case CALG_MD5: + return 128 / kByteBits; + break; + case CALG_SHA1: + return 160 / kByteBits; + break; + case CALG_SHA_256: + return 256 / kByteBits; + break; + case CALG_SHA_384: + return 384 / kByteBits; + break; + case CALG_SHA_512: + return 512 / kByteBits; + break; + default: + return 0; + break; + } + } + + NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) override + { + if (__wcsnicmp_ascii(BCRYPT_ALGORITHM_NAME, pszProperty, -1) == 0) + { + *pcbResult = pMapItem->cbAlgId; + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < pMapItem->cbAlgId) + { + return STATUS_BUFFER_TOO_SMALL; + } + + memcpy(pbOutput, pMapItem->szAlgName, pMapItem->cbAlgId); + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_PROVIDER_HANDLE, pszProperty, -1) == 0) + { + *pcbResult = sizeof(BCRYPT_ALG_HANDLE); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(BCRYPT_ALG_HANDLE)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pcbResult) = this; + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + virtual + NTSTATUS + WINAPI + CreateHash( + _Outptr_ BCryptHash** ppHash, + _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, + _In_ ULONG cbHashObject, + _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, // optional + _In_ ULONG cbSecret, // optional + _In_ ULONG dwFlags) + { + return STATUS_NOT_SUPPORTED; + } + }; + + struct BCryptAlgorithmByCryptoAPI : BCryptAlgorithm + { + HCRYPTPROV hProv = NULL; + + ~BCryptAlgorithmByCryptoAPI() + { + if (hProv) + CryptReleaseContext(hProv, 0); + } + + template + static NTSTATUS __fastcall Create(_In_ const BCryptMapItem* _pMapItem, _In_ ULONG _fOpenAlgorithmFlags, _Outptr_ BCryptAlgorithm** _ppAlgorithm) + { + *_ppAlgorithm = nullptr; + + HCRYPTPROV _hProv; + if (!CryptAcquireContextW(&_hProv, nullptr, _pMapItem->szProvider, _pMapItem->uProvType, CRYPT_VERIFYCONTEXT)) + return STATUS_INVALID_PARAMETER; + + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + auto _pBCryptAlgorithm = (BCryptAlgorithmT*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptAlgorithmT)); + if (!_pBCryptAlgorithm) + { + CryptReleaseContext(_hProv, 0); + return STATUS_NO_MEMORY; + } + + new (_pBCryptAlgorithm) BCryptAlgorithmT(); + _pBCryptAlgorithm->pMapItem = _pMapItem; + _pBCryptAlgorithm->hProv = _hProv; + _pBCryptAlgorithm->fOpenAlgorithmFlags = _fOpenAlgorithmFlags; + *_ppAlgorithm = _pBCryptAlgorithm; + return STATUS_SUCCESS; + } + }; + + struct BCryptHash : public BCryptObject + { + BCryptAlgorithmByCryptoAPI* pAlgorithm = nullptr; + ULONG dwFlags = 0; + HCRYPTKEY hPubKey = NULL; + HCRYPTHASH hHash = NULL; + + BCryptHash(_In_ BCryptAlgorithmByCryptoAPI* _pAlgorithm) + : BCryptObject(_pAlgorithm->pMapItem->uAlgId) + , pAlgorithm(_pAlgorithm) + { + pAlgorithm->AddRef(); + } + + ~BCryptHash() + { + if(hPubKey) + CryptDestroyKey(hPubKey); + + if(hHash) + CryptDestroyHash(hHash); + + if (pAlgorithm) + pAlgorithm->Release(); + } + + NTSTATUS WINAPI Init( + _In_reads_bytes_opt_(_cbSecret) PUCHAR _pbSecret, // optional + _In_ ULONG _cbSecret, // optional + _In_ ULONG _dwFlags) + { + if (pAlgorithm->fOpenAlgorithmFlags & BCRYPT_ALG_HANDLE_HMAC_FLAG) + { + // https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/example-c-program--importing-a-plaintext-key + struct _PLAINTEXTKEYBLOB : public BLOBHEADER + { + DWORD dwKeySize; + BYTE rgbKeyData[2]; + }; + + const auto _cbKeyBlob = sizeof(_PLAINTEXTKEYBLOB) + _cbSecret; + auto _pKeyBlob = static_cast<_PLAINTEXTKEYBLOB*>(_malloca(_cbKeyBlob)); + if (!_pKeyBlob) + { + return STATUS_NO_MEMORY; + } + _pKeyBlob->bType = PLAINTEXTKEYBLOB; + _pKeyBlob->bVersion = CUR_BLOB_VERSION; + _pKeyBlob->reserved = 0; + _pKeyBlob->aiKeyAlg = CALG_RC2; + memcpy(_pKeyBlob->rgbKeyData, _pbSecret, _cbSecret); + if (_cbSecret >= 2) + { + _pKeyBlob->dwKeySize = _cbSecret; + } + else + { + // 长度小于 2字节时 CryptImportKey 会失败,特殊处理一下 + _pKeyBlob->dwKeySize = 2; + if (_cbSecret == 0) + { + _pKeyBlob->rgbKeyData[0] = 0; + } + _pKeyBlob->rgbKeyData[1] = 0; + } + + auto _bResult = CryptImportKey(pAlgorithm->hProv, reinterpret_cast(_pKeyBlob), _cbKeyBlob, NULL, CRYPT_IPSEC_HMAC_KEY, &hPubKey); + // 避免密钥泄漏,所以立即将内存值清空!!! + memset(_pKeyBlob, 0, _cbKeyBlob); + _freea(_pKeyBlob); + + if (!_bResult) + { + return STATUS_INVALID_PARAMETER; + } + + if (!CryptCreateHash(pAlgorithm->hProv, CALG_HMAC, hPubKey, 0, &hHash)) + { + return STATUS_INVALID_PARAMETER; + } + + HMAC_INFO _HMacInfo = { pAlgorithm->pMapItem->uAlgId }; + if (!CryptSetHashParam(hHash, HP_HMAC_INFO, reinterpret_cast(&_HMacInfo), 0)) + { + return STATUS_INVALID_PARAMETER; + } + } + else + { + if (!CryptCreateHash(pAlgorithm->hProv, pAlgorithm->pMapItem->uAlgId, NULL, 0, &hHash)) + { + return STATUS_INVALID_PARAMETER; + } + } + + dwFlags = _dwFlags; + return STATUS_SUCCESS; + } + + NTSTATUS + WINAPI + HashData( + _In_reads_bytes_(cbInput) PUCHAR pbInput, + _In_ ULONG cbInput, + _In_ ULONG dwFlags) + { + if (!CryptHashData(hHash, pbInput, cbInput, 0)) + return STATUS_INVALID_PARAMETER; + return STATUS_SUCCESS; + } + + NTSTATUS + WINAPI + FinishHash( + _Out_writes_bytes_all_(cbOutput) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _In_ ULONG dwFlags) + { + const auto _cbTargetHashLength = pAlgorithm->GetHashLength(); + if (cbOutput < _cbTargetHashLength) + { + return STATUS_BUFFER_TOO_SMALL; + } + else if (cbOutput != _cbTargetHashLength) + { + return STATUS_INVALID_PARAMETER; + } + + STATUS_INVALID_PARAMETER; + if (!CryptGetHashParam(hHash, HP_HASHVAL, pbOutput, &cbOutput, 0)) + return STATUS_INVALID_PARAMETER; + + return STATUS_SUCCESS; + } + + NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) override + { + return pAlgorithm->GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + } + }; + + struct BCryptAlgorithmHash : public BCryptAlgorithmByCryptoAPI + { + NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) override + { + if (__wcsnicmp_ascii(BCRYPT_OBJECT_LENGTH, pszProperty, -1) == 0) + { + *pcbResult = sizeof(BCryptHash); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(BCryptHash)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = sizeof(BCryptHash); + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_HASH_LENGTH, pszProperty, -1) == 0) + { + *pcbResult = sizeof(DWORD); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(DWORD)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = GetHashLength(); + return STATUS_SUCCESS; + } + + return BCryptAlgorithm::GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + } + + + NTSTATUS + WINAPI + CreateHash( + _Outptr_ BCryptHash** ppHash, + _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, + _In_ ULONG cbHashObject, + _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, // optional + _In_ ULONG cbSecret, // optional + _In_ ULONG dwFlags) + { + BCryptHash* _pBCryptHash = reinterpret_cast(pbHashObject); + if (_pBCryptHash) + { + if (cbHashObject < sizeof(BCryptHash)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + new (_pBCryptHash) BCryptHash(this); + _pBCryptHash->bCanFree = false; + } + else + { + if (cbHashObject != 0) + { + return STATUS_INVALID_PARAMETER; + } + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + _pBCryptHash = (BCryptHash*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptHash)); + if (!_pBCryptHash) + { + return STATUS_NO_MEMORY; + } + + new (_pBCryptHash) BCryptHash(this); + } + + auto _Status = _pBCryptHash->Init(pbSecret, cbSecret, dwFlags); + if (_Status) + { + _pBCryptHash->Release(); + return _Status; + } + *ppHash = _pBCryptHash; + return STATUS_SUCCESS; + } + }; + + struct BCryptAlgorithmRng : public BCryptAlgorithm + { + static NTSTATUS __fastcall Create(_In_ const BCryptMapItem* _pMapItem, _In_ ULONG _fOpenAlgorithmFlags, _Outptr_ BCryptAlgorithm** _ppAlgorithm) + { + *_ppAlgorithm = nullptr; + + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + auto _pBCryptAlgorithm = (BCryptAlgorithmRng*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptAlgorithmRng)); + if (!_pBCryptAlgorithm) + { + return STATUS_NO_MEMORY; + } + + new (_pBCryptAlgorithm) BCryptAlgorithmRng(); + _pBCryptAlgorithm->pMapItem = _pMapItem; + _pBCryptAlgorithm->fOpenAlgorithmFlags = _fOpenAlgorithmFlags; + *_ppAlgorithm = _pBCryptAlgorithm; + return STATUS_SUCCESS; + } + }; + + + template + bool __fastcall Is(void* _pSrc); + + template<> + bool __fastcall Is(void* _pSrc) + { + auto _BCryptObject = reinterpret_cast(_pSrc); + return _BCryptObject != nullptr && _BCryptObject->IsValid(); + } + + template<> + bool __fastcall Is(void* _pSrc) + { + if (!Is(_pSrc)) + return false; + + return reinterpret_cast(_pSrc)->GetClass() == 0; + } + + template<> + bool __fastcall Is(void* _pSrc) + { + if (!Is(_pSrc)) + return false; + + return reinterpret_cast(_pSrc)->IsRng(); + } + + template<> + bool __fastcall Is(void* _pSrc) + { + if (!Is(_pSrc)) + return false; + + return reinterpret_cast(_pSrc)->IsHash(); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) @@ -76,28 +571,50 @@ namespace YY _In_ ULONG _fFlags ) { - if (auto _pfnBCryptOpenAlgorithmProvider = try_get_BCryptOpenAlgorithmProvider()) + if (const auto _pfnBCryptOpenAlgorithmProvider = try_get_BCryptOpenAlgorithmProvider()) { return _pfnBCryptOpenAlgorithmProvider(_phAlgorithm, _szAlgId, _szImplementation, _fFlags); } UNREFERENCED_PARAMETER(_szImplementation); - UNREFERENCED_PARAMETER(_fFlags); - auto _pItem = BCryptAlgIdToCryptoAPIProvType(_szAlgId); - if (!_pItem) - return STATUS_NOT_FOUND; - if (_pItem->uCalg == 0) - { - // 此外对于Windows XP内部其实只有一种随机算法,所以没必要真的开辟资源 - // 返回一个标识性的常量即可。 - *_phAlgorithm = hRngHandle; - return STATUS_SUCCESS; - } - else - { - return STATUS_NOT_FOUND; - } + if (_phAlgorithm == nullptr || _szAlgId == nullptr || (_fFlags & ~BCRYPT_ALG_HANDLE_HMAC_FLAG)) + { + return STATUS_INVALID_PARAMETER; + } + + static const BCryptMapItem g_Map[] = + { + // 加密算法 + // { L"AES", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_AES }, + // { L"DES", MS_DEF_DSS_PROV_W, PROV_DSS, CALG_DES }, + // { L"RC2", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC2 }, + // { L"RC4", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC4 }, + + // 生成随机数算法 + { BCRYPT_RNG_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, + { BCRYPT_RNG_FIPS186_DSA_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, + { BCRYPT_RNG_DUAL_EC_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, + + // Hash算法 + { L"MD2", nullptr, PROV_RSA_AES, CALG_MD2, &BCryptAlgorithmByCryptoAPI::Create }, + { L"MD4", nullptr, PROV_RSA_AES, CALG_MD4, &BCryptAlgorithmByCryptoAPI::Create }, + { L"MD5", nullptr, PROV_RSA_AES, CALG_MD5, &BCryptAlgorithmByCryptoAPI::Create }, + { L"SHA1", nullptr, PROV_RSA_AES, CALG_SHA1, &BCryptAlgorithmByCryptoAPI::Create }, + { L"SHA256", nullptr, PROV_RSA_AES, CALG_SHA_256, &BCryptAlgorithmByCryptoAPI::Create }, + { L"SHA384", nullptr, PROV_RSA_AES, CALG_SHA_384, &BCryptAlgorithmByCryptoAPI::Create }, + { L"SHA512", nullptr, PROV_RSA_AES, CALG_SHA_512, &BCryptAlgorithmByCryptoAPI::Create }, + }; + + for (auto& _Item : g_Map) + { + if (__wcsnicmp_ascii(_szAlgId, _Item.szAlgName, (size_t)-1) == 0) + { + return _Item.pfnOpenAlgorithmProviderType(&_Item, _fFlags, reinterpret_cast(_phAlgorithm)); + } + } + + return STATUS_NOT_FOUND; } #endif @@ -119,12 +636,14 @@ namespace YY return _pfnBCryptCloseAlgorithmProvider(_hAlgorithm, _fFlags); } - UNREFERENCED_PARAMETER(_fFlags); + if (_fFlags) + return STATUS_INVALID_PARAMETER; - if(_hAlgorithm == hRngHandle) - return STATUS_SUCCESS; - else - return STATUS_INVALID_HANDLE; + if (!Is(_hAlgorithm)) + return STATUS_INVALID_HANDLE; + + reinterpret_cast(_hAlgorithm)->Release(); + return STATUS_SUCCESS; } #endif @@ -161,8 +680,10 @@ namespace YY } else { - if (_hAlgorithm != hRngHandle) - return STATUS_INVALID_PARAMETER; + if (!Is(_hAlgorithm)) + { + return STATUS_INVALID_HANDLE; + } } // 此函数内部其实就是用了Crypt API,所以针对Windows XP就直接使用它了。 @@ -179,5 +700,432 @@ namespace YY return STATUS_UNSUCCESSFUL; } #endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 24, + NTSTATUS, + WINAPI, + BCryptGetProperty, + _In_ BCRYPT_HANDLE hObject, + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG *pcbResult, + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptGetProperty = try_get_BCryptGetProperty()) + { + return _pfnBCryptGetProperty(hObject, pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + } + + if(pszProperty == nullptr || dwFlags) + return STATUS_INVALID_PARAMETER; + + if (!Is(hObject)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(hObject)->GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 28, + NTSTATUS, + WINAPI, + BCryptCreateHash, + _Inout_ BCRYPT_ALG_HANDLE hAlgorithm, + _Out_ BCRYPT_HASH_HANDLE *phHash, + _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, + _In_ ULONG cbHashObject, + _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, // optional + _In_ ULONG cbSecret, // optional + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptCreateHash = try_get_BCryptCreateHash()) + { + return _pfnBCryptCreateHash(hAlgorithm, phHash, pbHashObject, cbHashObject, pbSecret, cbSecret, dwFlags); + } + + if ((cbHashObject && pbHashObject == nullptr) || dwFlags || phHash == nullptr) + { + return STATUS_INVALID_PARAMETER; + } + + if (!Is(hAlgorithm)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(hAlgorithm)->CreateHash(reinterpret_cast(phHash), pbHashObject, cbHashObject, pbSecret, cbSecret, dwFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 16, + NTSTATUS, + WINAPI, + BCryptHashData, + _Inout_ BCRYPT_HASH_HANDLE hHash, + _In_reads_bytes_(cbInput) PUCHAR pbInput, + _In_ ULONG cbInput, + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptHashData = try_get_BCryptHashData()) + { + return _pfnBCryptHashData(hHash, pbInput, cbInput, dwFlags); + } + + if(dwFlags) + return STATUS_INVALID_PARAMETER; + + if (!Is(hHash)) + return STATUS_INVALID_HANDLE; + + return reinterpret_cast(hHash)->HashData(pbInput, cbInput, dwFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 16, + NTSTATUS, + WINAPI, + BCryptFinishHash, + _Inout_ BCRYPT_HASH_HANDLE hHash, + _Out_writes_bytes_all_(cbOutput) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptFinishHash = try_get_BCryptFinishHash()) + { + return _pfnBCryptFinishHash(hHash, pbOutput, cbOutput, dwFlags); + } + + if(dwFlags) + return STATUS_INVALID_PARAMETER; + + if (!Is(hHash)) + return STATUS_INVALID_HANDLE; + + return reinterpret_cast(hHash)->FinishHash(pbOutput, cbOutput, dwFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 4, + NTSTATUS, + WINAPI, + BCryptDestroyHash, + _Inout_ BCRYPT_HASH_HANDLE hHash) + { + if (const auto _pfnBCryptDestroyHash = try_get_BCryptDestroyHash()) + { + return _pfnBCryptDestroyHash(hHash); + } + + if (!Is(hHash)) + return STATUS_INVALID_PARAMETER; + + reinterpret_cast(hHash)->Release(); + return STATUS_SUCCESS; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN7) + + // 最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 40, + NTSTATUS, + WINAPI, + BCryptDeriveKeyPBKDF2, + _In_ BCRYPT_ALG_HANDLE hPrf, + _In_reads_bytes_opt_( cbPassword ) PUCHAR pbPassword, + _In_ ULONG cbPassword, + _In_reads_bytes_opt_( cbSalt ) PUCHAR pbSalt, + _In_ ULONG cbSalt, + _In_ ULONGLONG cIterations, + _Out_writes_bytes_( cbDerivedKey ) PUCHAR pbDerivedKey, + _In_ ULONG cbDerivedKey, + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptDeriveKeyPBKDF2 = try_get_BCryptDeriveKeyPBKDF2()) + { + return _pfnBCryptDeriveKeyPBKDF2(hPrf, pbPassword, cbPassword, pbSalt, cbSalt, cIterations, pbDerivedKey, cbDerivedKey, dwFlags); + } + + // 实现来自 bcrypt.GetPBKDF2Block + if ((pbPassword == nullptr && cbPassword) || (pbSalt == nullptr && cbSalt) || cIterations == 0 || pbDerivedKey == nullptr || cbDerivedKey == 0) + { + return STATUS_INVALID_PARAMETER; + } + + --cIterations; + + ULONG _cbResult = 0; + + // Windows 7 开始才支持BCRYPT_IS_KEYED_HASH,因此这里就不做判断了,跟微软原版存在略微差异。 + + DWORD _uHashLength = 0; + int _Status = ::BCryptGetProperty(hPrf, BCRYPT_HASH_LENGTH, reinterpret_cast(&_uHashLength), sizeof(_uHashLength), &_cbResult, 0); + if (_Status < 0) + { + return _Status; + } + constexpr auto kMaxHashLength = 512 / 8; + if (kMaxHashLength < _uHashLength) + { + return STATUS_INVALID_PARAMETER; + } + + DWORD _uObjectLength = 0; + _Status = ::BCryptGetProperty(hPrf, BCRYPT_OBJECT_LENGTH, reinterpret_cast(&_uObjectLength), sizeof(_uObjectLength), &_cbResult, 0); + if (_Status < 0) + { + return _Status; + } + + auto _pObjectHashBuffer = (PUCHAR)_malloca(_uObjectLength); + if (!_pObjectHashBuffer) + { + return STATUS_NO_MEMORY; + } + + BCRYPT_HASH_HANDLE hHash = nullptr; + for (DWORD _uBlockCount = 1; cbDerivedKey; ++_uBlockCount) + { + _Status = ::BCryptCreateHash(hPrf, &hHash, _pObjectHashBuffer, _uObjectLength, pbPassword, cbPassword, 0); + if (_Status < 0) + goto __END; + _Status = ::BCryptHashData(hHash, pbSalt, cbSalt, 0); + if (_Status < 0) + goto __END; + + // 将 _uBlockCount 的字节序颠倒(大端模式) + DWORD _uReverseBytes = (_uBlockCount << 24); + _uReverseBytes |= (_uBlockCount << 8) & 0x00FF0000; + _uReverseBytes |= (_uBlockCount >> 8) & 0x0000FF00; + _uReverseBytes |= (_uBlockCount >> 24); + + _Status = ::BCryptHashData(hHash, (PUCHAR)&_uReverseBytes, sizeof(_uReverseBytes), 0); + if (_Status < 0) + goto __END; + + BYTE _TempHash[kMaxHashLength]; + _Status = ::BCryptFinishHash(hHash, _TempHash, _uHashLength, 0); + if (_Status < 0) + goto __END; + ::BCryptDestroyHash(hHash); + hHash = NULL; + + BYTE _BlockHash[kMaxHashLength]; + memcpy(_BlockHash, _TempHash, _uHashLength); + + for (auto _uIterationCount = cIterations; _uIterationCount; --_uIterationCount) + { + _Status = ::BCryptCreateHash(hPrf, &hHash, _pObjectHashBuffer, _uObjectLength, pbPassword, cbPassword, 0); + if (_Status < 0) + goto __END; + + _Status = ::BCryptHashData(hHash, _TempHash, _uHashLength, 0); + if (_Status < 0) + goto __END; + + _Status = ::BCryptFinishHash(hHash, _TempHash, _uHashLength, 0); + if (_Status < 0) + goto __END; + + ::BCryptDestroyHash(hHash); + hHash = NULL; + + for (auto i = 0; i != _uHashLength; ++i) + { + _BlockHash[i] ^= _TempHash[i]; + } + } + + if (cbDerivedKey > _uHashLength) + { + memcpy(pbDerivedKey, _BlockHash, _uHashLength); + pbDerivedKey += _uHashLength; + cbDerivedKey -= _uHashLength; + } + else + { + memcpy(pbDerivedKey, _BlockHash, cbDerivedKey); + break; + } + } + + _Status = STATUS_SUCCESS; + + __END: + + if(hHash) + ::BCryptDestroyHash(hHash); + return _Status; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN7) + + // 最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 40, + NTSTATUS, + WINAPI, + BCryptDeriveKeyCapi, + _In_ BCRYPT_HASH_HANDLE hHash, + _In_opt_ BCRYPT_ALG_HANDLE hTargetAlg, + _Out_writes_bytes_( cbDerivedKey ) PUCHAR pbDerivedKey, + _In_ ULONG cbDerivedKey, + _In_ ULONG dwFlags + ) + { + if (const auto _pfnBCryptDeriveKeyCapi = try_get_BCryptDeriveKeyCapi()) + { + return _pfnBCryptDeriveKeyCapi(hHash, hTargetAlg, pbDerivedKey, cbDerivedKey, dwFlags); + } + + if (dwFlags != 0 || (pbDerivedKey == nullptr && cbDerivedKey)) + { + return STATUS_INVALID_PARAMETER; + } + + ULONG _cbResult = 0; + DWORD _uHashLength = 0; + int _Status = ::BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&_uHashLength, sizeof(_uHashLength), &_cbResult, 0); + if (_Status < 0) + return _Status; + + constexpr auto kMaxHashLength = 512 / 8; + if (kMaxHashLength < _uHashLength || _uHashLength * 2 < cbDerivedKey) + { + return STATUS_INVALID_PARAMETER; + } + + UCHAR _Hash[kMaxHashLength * 2]; + _Status = BCryptFinishHash(hHash, _Hash, _uHashLength, 0); + if (_Status < 0) + return _Status; + + auto v19 = _uHashLength < cbDerivedKey; + + wchar_t szAlgorithmNameBuffer[4]; + if (hTargetAlg && cbDerivedKey == 16 && _uHashLength < 32 + && BCryptGetProperty(hTargetAlg, BCRYPT_ALGORITHM_NAME, (PUCHAR)szAlgorithmNameBuffer, sizeof(szAlgorithmNameBuffer), &_cbResult, 0) >= 0 + && __wcsnicmp_ascii(szAlgorithmNameBuffer, L"AES", -1) == 0) + { + v19 = true; + } + + if (!v19) + { + memcpy(pbDerivedKey, _Hash, cbDerivedKey); + return STATUS_SUCCESS; + } + + UCHAR Dst[kMaxHashLength]; + UCHAR pbInput[kMaxHashLength]; + + memset(Dst, 0x36, kMaxHashLength); + memset(pbInput, 0x5C, kMaxHashLength); + + for (DWORD i = 0; i != _uHashLength; ++i) + { + Dst[i] ^= _Hash[i]; + pbInput[i] ^= _Hash[i]; + } + + BCRYPT_ALG_HANDLE hProvider; + _Status = BCryptGetProperty(hHash, BCRYPT_PROVIDER_HANDLE, (PUCHAR)&hProvider, sizeof(hProvider), &_cbResult, 0); + if (_Status < 0) + return _Status; + + BCRYPT_HASH_HANDLE hHash2 = NULL; + do + { + _Status = BCryptCreateHash(hProvider, &hHash2, nullptr, 0, nullptr, 0, 0); + if (_Status < 0) + return _Status; + + _Status = BCryptHashData(hHash2, Dst, sizeof(Dst), 0); + if (_Status < 0) + goto __End; + + _Status = BCryptFinishHash(hHash2, _Hash, _uHashLength, 0); + if (_Status < 0) + goto __End; + BCryptDestroyHash(hHash2); + hHash2 = NULL; + + _Status = BCryptCreateHash(hProvider, &hHash2, nullptr, 0, nullptr, 0, 0); + if (_Status < 0) + return _Status; + + _Status = BCryptHashData(hHash2, pbInput, sizeof(pbInput), 0); + if (_Status < 0) + goto __End; + + _Status = BCryptFinishHash(hHash2, _Hash + _uHashLength, _uHashLength, 0); + if (_Status < 0) + goto __End; + BCryptDestroyHash(hHash2); + hHash2 = NULL; + + memcpy(pbDerivedKey, _Hash, cbDerivedKey); + return STATUS_SUCCESS; + + } while (false); + + __End: + if (hHash2) + BCryptDestroyHash(hHash2); + + return _Status; + } +#endif } } diff --git a/src/YY-Thunks.UnitTest/Iphlpapi.UnitTest.cpp b/src/YY-Thunks.UnitTest/Iphlpapi.UnitTest.cpp index 8cbea5b..1513b24 100644 --- a/src/YY-Thunks.UnitTest/Iphlpapi.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/Iphlpapi.UnitTest.cpp @@ -6,12 +6,14 @@ namespace Iphlpapi { TEST_CLASS(GetIfTable2) { + AwaysNullGuard Guard; + public: GetIfTable2() { - YY::Thunks::aways_null_try_get_GetIfEntry2 = true; - YY::Thunks::aways_null_try_get_GetIfTable2 = true; - YY::Thunks::aways_null_try_get_FreeMibTable = true; + Guard |= YY::Thunks::aways_null_try_get_GetIfEntry2; + Guard |= YY::Thunks::aways_null_try_get_GetIfTable2; + Guard |= YY::Thunks::aways_null_try_get_FreeMibTable; } TEST_METHOD(GetIfTable2简单验证) @@ -49,17 +51,13 @@ namespace Iphlpapi ULONG64 NetLuidIndex; }; + AwaysNullGuard Guard; + public: ConvertInterfaceNameToLuid() { - YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidA = true; - YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidW = true; - } - - ~ConvertInterfaceNameToLuid() - { - YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidA = false; - YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidW = false; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidA = true; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceNameToLuidW = true; } TEST_METHOD(输入验证) @@ -163,17 +161,13 @@ namespace Iphlpapi ULONG64 NetLuidIndex; }; + AwaysNullGuard Guard; + public: ConvertInterfaceLuidToName() { - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA = true; - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameW = true; - } - - ~ConvertInterfaceLuidToName() - { - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA = false; - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameW = false; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameW; } TEST_METHOD(输入验证) @@ -239,21 +233,15 @@ namespace Iphlpapi TEST_CLASS(if_nametoindex与if_indextoname) { + AwaysNullGuard Guard; + public: if_nametoindex与if_indextoname() { - YY::Thunks::aways_null_try_get_if_nametoindex = true; - YY::Thunks::aways_null_try_get_if_indextoname = true; - YY::Thunks::aways_null_try_get_ConvertInterfaceIndexToLuid = true; - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA = true; - } - - ~if_nametoindex与if_indextoname() - { - YY::Thunks::aways_null_try_get_if_nametoindex = false; - YY::Thunks::aways_null_try_get_if_indextoname = false; - YY::Thunks::aways_null_try_get_ConvertInterfaceIndexToLuid = false; - YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA = false; + Guard |= YY::Thunks::aways_null_try_get_if_nametoindex; + Guard |= YY::Thunks::aways_null_try_get_if_indextoname; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceIndexToLuid; + Guard |= YY::Thunks::aways_null_try_get_ConvertInterfaceLuidToNameA; } TEST_METHOD(交叉验证) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp index 7be4464..95389e9 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp @@ -8,13 +8,15 @@ namespace api_ms_win_core_fibers { TEST_CLASS(FlsGet_SetValue) { + AwaysNullGuard Guard; + public: FlsGet_SetValue() { - YY::Thunks::aways_null_try_get_FlsAlloc = true; - YY::Thunks::aways_null_try_get_FlsFree = true; - YY::Thunks::aways_null_try_get_FlsGetValue = true; - YY::Thunks::aways_null_try_get_FlsSetValue = true; + Guard |= YY::Thunks::aways_null_try_get_FlsAlloc; + Guard |= YY::Thunks::aways_null_try_get_FlsFree; + Guard |= YY::Thunks::aways_null_try_get_FlsGetValue; + Guard |= YY::Thunks::aways_null_try_get_FlsSetValue; } TEST_METHOD(单线程验证) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-kernel32-legacy.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-kernel32-legacy.UnitTest.cpp index 61f2b43..4fbaa4e 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-kernel32-legacy.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-kernel32-legacy.UnitTest.cpp @@ -10,12 +10,14 @@ namespace api_ms_win_core_kernel32_legacy { TEST_CLASS(PowerRequest) { + AwaysNullGuard Guard; + public: PowerRequest() { - YY::Thunks::aways_null_try_get_PowerCreateRequest = true; - YY::Thunks::aways_null_try_get_PowerSetRequest = true; - YY::Thunks::aways_null_try_get_PowerClearRequest = true; + Guard |= YY::Thunks::aways_null_try_get_PowerCreateRequest; + Guard |= YY::Thunks::aways_null_try_get_PowerSetRequest; + Guard |= YY::Thunks::aways_null_try_get_PowerClearRequest; } TEST_METHOD(Set然后Clear) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp index 5dd37d4..d5f9aea 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp @@ -7,17 +7,14 @@ namespace api_ms_win_core_localization { TEST_CLASS(LocaleNameToLCID) { + AwaysNullGuard Guard; + public: LocaleNameToLCID() { YY::Thunks::aways_null_try_get_LocaleNameToLCID = true; } - ~LocaleNameToLCID() - { - YY::Thunks::aways_null_try_get_LocaleNameToLCID = false; - } - TEST_METHOD(映射表验证) { // Map of locale name to LCID. @@ -416,10 +413,12 @@ namespace api_ms_win_core_localization TEST_CLASS(GetThreadPreferredUILanguages) { + AwaysNullGuard Guard; + public: GetThreadPreferredUILanguages() { - YY::Thunks::aways_null_try_get_GetThreadPreferredUILanguages = true; + Guard |= YY::Thunks::aways_null_try_get_GetThreadPreferredUILanguages; } TEST_METHOD(无效参数验证) @@ -604,10 +603,12 @@ namespace api_ms_win_core_localization TEST_CLASS(ResolveLocaleName) { + AwaysNullGuard Guard; + public: ResolveLocaleName() { - YY::Thunks::aways_null_try_get_ResolveLocaleName = true; + Guard |= YY::Thunks::aways_null_try_get_ResolveLocaleName; } TEST_METHOD(中性语言验证) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-path.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-path.UnitTest.cpp index ad18560..db626fb 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-path.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-path.UnitTest.cpp @@ -11,10 +11,12 @@ namespace api_ms_win_core_path { TEST_CLASS(PathIsUNCEx) { + AwaysNullGuard Guard; + public: PathIsUNCEx() { - YY::Thunks::aways_null_try_get_PathIsUNCEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathIsUNCEx; } TEST_METHOD(传统UNC路径分割) @@ -53,10 +55,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchIsRoot) { + AwaysNullGuard Guard; + public: PathCchIsRoot() { - YY::Thunks::aways_null_try_get_PathCchIsRoot = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchIsRoot; } TEST_METHOD(Dos路径测试) @@ -138,10 +142,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchAddBackslashEx) { + AwaysNullGuard Guard; + public: PathCchAddBackslashEx() { - YY::Thunks::aways_null_try_get_PathCchAddBackslashEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchAddBackslashEx; } TEST_METHOD(基础功能测试) @@ -197,10 +203,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchRemoveBackslashEx) { + AwaysNullGuard Guard; + public: PathCchRemoveBackslashEx() { - YY::Thunks::aways_null_try_get_PathCchRemoveBackslashEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchRemoveBackslashEx; } TEST_METHOD(Dos路径测试) @@ -592,10 +600,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchSkipRoot) { + AwaysNullGuard Guard; + public: PathCchSkipRoot() { - YY::Thunks::aways_null_try_get_PathCchSkipRoot = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchSkipRoot; } TEST_METHOD(Dos路径) @@ -870,10 +880,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchStripToRoot) { + AwaysNullGuard Guard; + public: PathCchStripToRoot() { - YY::Thunks::aways_null_try_get_PathCchStripToRoot = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchStripToRoot; } TEST_METHOD(Dos路径测试) @@ -1114,10 +1126,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchRemoveFileSpec) { + AwaysNullGuard Guard; + public: PathCchRemoveFileSpec() { - YY::Thunks::aways_null_try_get_PathCchRemoveFileSpec = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchRemoveFileSpec; } TEST_METHOD(Dos路径测试) @@ -1446,10 +1460,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchFindExtension) { + AwaysNullGuard Guard; + public: PathCchFindExtension() { - YY::Thunks::aways_null_try_get_PathCchFindExtension = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchFindExtension; } TEST_METHOD(常规后缀提取) @@ -1532,10 +1548,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchAddExtension) { + AwaysNullGuard Guard; + public: PathCchAddExtension() { - YY::Thunks::aways_null_try_get_PathCchAddExtension = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchAddExtension; } TEST_METHOD(常规的添加) @@ -1710,10 +1728,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchRenameExtension) { + AwaysNullGuard Guard; + public: PathCchRenameExtension() { - YY::Thunks::aways_null_try_get_PathCchRenameExtension = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchRenameExtension; } TEST_METHOD(添加后缀) @@ -1790,10 +1810,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchRemoveExtension) { + AwaysNullGuard Guard; + public: PathCchRemoveExtension() { - YY::Thunks::aways_null_try_get_PathCchRemoveExtension = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchRemoveExtension; } TEST_METHOD(基础功能验证) @@ -1824,10 +1846,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchCanonicalizeEx) { + AwaysNullGuard Guard; + public: PathCchCanonicalizeEx() { - YY::Thunks::aways_null_try_get_PathCchCanonicalizeEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchCanonicalizeEx; } TEST_METHOD(基础功能验证) @@ -1934,10 +1958,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchCombineEx) { + AwaysNullGuard Guard; + public: PathCchCombineEx() { - YY::Thunks::aways_null_try_get_PathCchCombineEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchCombineEx; } TEST_METHOD(基础功能验证) @@ -2023,10 +2049,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchAppendEx) { + AwaysNullGuard Guard; + public: PathCchAppendEx() { - YY::Thunks::aways_null_try_get_PathCchAppendEx = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchAppendEx; } TEST_METHOD(基础功能验证) @@ -2110,10 +2138,12 @@ namespace api_ms_win_core_path TEST_CLASS(PathCchStripPrefix) { + AwaysNullGuard Guard; + public: PathCchStripPrefix() { - YY::Thunks::aways_null_try_get_PathCchStripPrefix = true; + Guard |= YY::Thunks::aways_null_try_get_PathCchStripPrefix; } TEST_METHOD(Dos路径) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp index 63c710d..bd23c5c 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp @@ -6,11 +6,13 @@ namespace api_ms_win_core_synch { TEST_CLASS(WaitOnAddress) { + AwaysNullGuard Guard; + public: WaitOnAddress() { - YY::Thunks::aways_null_try_get_WaitOnAddress = true; - YY::Thunks::aways_null_try_get_WakeByAddressSingle = true; + Guard |= YY::Thunks::aways_null_try_get_WaitOnAddress; + Guard |= YY::Thunks::aways_null_try_get_WakeByAddressSingle; } TEST_METHOD(结果本身不同) @@ -39,11 +41,13 @@ namespace api_ms_win_core_synch TEST_CLASS(WakeByAddressSingle) { + AwaysNullGuard Guard; + public: WakeByAddressSingle() { - YY::Thunks::aways_null_try_get_WaitOnAddress = true; - YY::Thunks::aways_null_try_get_WakeByAddressSingle = true; + Guard |= YY::Thunks::aways_null_try_get_WaitOnAddress; + Guard |= YY::Thunks::aways_null_try_get_WakeByAddressSingle; } TEST_METHOD(只唤醒了一个线程) @@ -109,11 +113,13 @@ namespace api_ms_win_core_synch TEST_CLASS(WakeByAddressAll) { + AwaysNullGuard Guard; + public: WakeByAddressAll() { - YY::Thunks::aways_null_try_get_WaitOnAddress = true; - YY::Thunks::aways_null_try_get_WakeByAddressAll = true; + Guard |= YY::Thunks::aways_null_try_get_WaitOnAddress; + Guard |= YY::Thunks::aways_null_try_get_WakeByAddressAll; } TEST_METHOD(唤醒所有线程) @@ -168,12 +174,14 @@ namespace api_ms_win_core_synch TEST_CLASS(TryAcquireSRWLockExclusive) { + AwaysNullGuard Guard; + public: TryAcquireSRWLockExclusive() { - YY::Thunks::aways_null_try_get_TryAcquireSRWLockExclusive = true; - YY::Thunks::aways_null_try_get_AcquireSRWLockExclusive = true; - YY::Thunks::aways_null_try_get_ReleaseSRWLockExclusive = true; + Guard |= YY::Thunks::aways_null_try_get_TryAcquireSRWLockExclusive; + Guard |= YY::Thunks::aways_null_try_get_AcquireSRWLockExclusive; + Guard |= YY::Thunks::aways_null_try_get_ReleaseSRWLockExclusive; } TEST_METHOD(首次肯定成功) diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp index 0ebbc96..8cf9300 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp @@ -6,15 +6,17 @@ namespace api_ms_win_core_threadpool { TEST_CLASS(SubmitThreadpoolWork) { + AwaysNullGuard Guard; + public: SubmitThreadpoolWork() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_SetEventWhenCallbackReturns = true; - YY::Thunks::aways_null_try_get_ReleaseSemaphoreWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_SetEventWhenCallbackReturns; + Guard |= YY::Thunks::aways_null_try_get_ReleaseSemaphoreWhenCallbackReturns; } TEST_METHOD(一般行为验证) @@ -57,10 +59,12 @@ namespace api_ms_win_core_threadpool TEST_CLASS(TrySubmitThreadpoolCallback) { + AwaysNullGuard Guard; + public: TrySubmitThreadpoolCallback() { - YY::Thunks::aways_null_try_get_TrySubmitThreadpoolCallback = true; + Guard |= YY::Thunks::aways_null_try_get_TrySubmitThreadpoolCallback; } TEST_METHOD(一般行为验证) @@ -107,13 +111,15 @@ namespace api_ms_win_core_threadpool TEST_CLASS(WaitForThreadpoolWorkCallbacks) { + AwaysNullGuard Guard; + public: WaitForThreadpoolWorkCallbacks() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; - YY::Thunks::aways_null_try_get_WaitForThreadpoolWorkCallbacks = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_WaitForThreadpoolWorkCallbacks; } TEST_METHOD(一般行为验证) @@ -180,12 +186,14 @@ namespace api_ms_win_core_threadpool TEST_CLASS(SetThreadpoolTimer) { + AwaysNullGuard Guard; + public: SetThreadpoolTimer() { - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; } TEST_METHOD(当DueTime数值为0时) @@ -399,13 +407,15 @@ namespace api_ms_win_core_threadpool TEST_CLASS(WaitForThreadpoolTimerCallbacks) { + AwaysNullGuard Guard; + public: WaitForThreadpoolTimerCallbacks() { - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_WaitForThreadpoolTimerCallbacks = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_WaitForThreadpoolTimerCallbacks; } @@ -470,19 +480,20 @@ namespace api_ms_win_core_threadpool TEST_CLASS(SetEventWhenCallbackReturns) { + AwaysNullGuard Guard; + public: SetEventWhenCallbackReturns() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; - YY::Thunks::aways_null_try_get_SetEventWhenCallbackReturns = true; - //YY::Thunks::aways_null_try_get_ReleaseSemaphoreWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_SetEventWhenCallbackReturns; } struct UserData @@ -559,18 +570,20 @@ namespace api_ms_win_core_threadpool TEST_CLASS(ReleaseSemaphoreWhenCallbackReturns) { + AwaysNullGuard Guard; + public: ReleaseSemaphoreWhenCallbackReturns() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; - YY::Thunks::aways_null_try_get_ReleaseSemaphoreWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_ReleaseSemaphoreWhenCallbackReturns; } struct UserData @@ -654,18 +667,20 @@ namespace api_ms_win_core_threadpool TEST_CLASS(ReleaseMutexWhenCallbackReturns) { + AwaysNullGuard Guard; + public: ReleaseMutexWhenCallbackReturns() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; - YY::Thunks::aways_null_try_get_ReleaseMutexWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_ReleaseMutexWhenCallbackReturns; } struct UserData @@ -749,18 +764,20 @@ namespace api_ms_win_core_threadpool TEST_CLASS(LeaveCriticalSectionWhenCallbackReturns) { + AwaysNullGuard Guard; + public: LeaveCriticalSectionWhenCallbackReturns() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; - YY::Thunks::aways_null_try_get_LeaveCriticalSectionWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_LeaveCriticalSectionWhenCallbackReturns; } struct UserData @@ -877,18 +894,20 @@ namespace api_ms_win_core_threadpool TEST_CLASS(FreeLibraryWhenCallbackReturns) { + AwaysNullGuard Guard; + public: FreeLibraryWhenCallbackReturns() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWork = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWork = true; - YY::Thunks::aways_null_try_get_SubmitThreadpoolWork = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWork; + Guard |= YY::Thunks::aways_null_try_get_SubmitThreadpoolWork; - YY::Thunks::aways_null_try_get_CreateThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolTimer = true; - YY::Thunks::aways_null_try_get_SetThreadpoolTimer = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolTimer; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolTimer; - YY::Thunks::aways_null_try_get_FreeLibraryWhenCallbackReturns = true; + Guard |= YY::Thunks::aways_null_try_get_FreeLibraryWhenCallbackReturns; } struct UserData @@ -1016,12 +1035,14 @@ namespace api_ms_win_core_threadpool TEST_CLASS(SetThreadpoolWait) { + AwaysNullGuard Guard; + public: SetThreadpoolWait() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWait = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWait = true; - YY::Thunks::aways_null_try_get_SetThreadpoolWait = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWait; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWait; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolWait; } @@ -1301,13 +1322,15 @@ namespace api_ms_win_core_threadpool TEST_CLASS(WaitForThreadpoolWaitCallbacks) { + AwaysNullGuard Guard; + public: WaitForThreadpoolWaitCallbacks() { - YY::Thunks::aways_null_try_get_CreateThreadpoolWait = true; - YY::Thunks::aways_null_try_get_CloseThreadpoolWait = true; - YY::Thunks::aways_null_try_get_SetThreadpoolWait = true; - YY::Thunks::aways_null_try_get_WaitForThreadpoolWaitCallbacks = true; + Guard |= YY::Thunks::aways_null_try_get_CreateThreadpoolWait; + Guard |= YY::Thunks::aways_null_try_get_CloseThreadpoolWait; + Guard |= YY::Thunks::aways_null_try_get_SetThreadpoolWait; + Guard |= YY::Thunks::aways_null_try_get_WaitForThreadpoolWaitCallbacks; } TEST_METHOD(一般行为验证) @@ -1367,4 +1390,4 @@ namespace api_ms_win_core_threadpool } } }; -} \ No newline at end of file +} diff --git a/src/YY-Thunks.UnitTest/api-ms-win-power-base.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-power-base.UnitTest.cpp index 06e4943..3e81328 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-power-base.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-power-base.UnitTest.cpp @@ -5,11 +5,13 @@ namespace api_ms_win_power_base { TEST_CLASS(PowerRegisterSuspendResumeNotification) { + AwaysNullGuard Guard; + public: PowerRegisterSuspendResumeNotification() { - YY::Thunks::aways_null_try_get_PowerRegisterSuspendResumeNotification = true; - YY::Thunks::aways_null_try_get_PowerUnregisterSuspendResumeNotification = true; + Guard |= YY::Thunks::aways_null_try_get_PowerRegisterSuspendResumeNotification; + Guard |= YY::Thunks::aways_null_try_get_PowerUnregisterSuspendResumeNotification; } TEST_METHOD(创建然后关闭) diff --git a/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp b/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp index a5aa924..8c1c2d8 100644 --- a/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp @@ -6,12 +6,14 @@ namespace bcrypt { TEST_CLASS(BCryptGenRandom) { + AwaysNullGuard Guard; + public: BCryptGenRandom() { - YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider = true; - YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider = true; - YY::Thunks::aways_null_try_get_BCryptGenRandom = true; + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenRandom; } TEST_METHOD(BCRYPT_USE_SYSTEM_PREFERRED_RNG模式) @@ -43,4 +45,177 @@ namespace bcrypt } }; + TEST_CLASS(BCryptHash) + { + AwaysNullGuard Guard; + public: + BCryptHash() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenRandom; + Guard |= YY::Thunks::aways_null_try_get_BCryptCreateHash; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyHash; + Guard |= YY::Thunks::aways_null_try_get_BCryptHashData; + Guard |= YY::Thunks::aways_null_try_get_BCryptFinishHash; + } + + template + static void TestHash(_In_z_ LPCWSTR _szAlgId, _In_ ULONG _fFlags, _In_ const byte (&_pTargetSha)[kTargetShaLength], const char* _szKey = nullptr) + { + BCRYPT_ALG_HANDLE _hAlg = nullptr; + int _Status = ::BCryptOpenAlgorithmProvider(&_hAlg, _szAlgId, nullptr, _fFlags); + Assert::IsTrue(_Status >= 0); + Assert::IsNotNull(_hAlg); + BCRYPT_HASH_HANDLE _hHash = nullptr; + _Status = ::BCryptCreateHash(_hAlg, &_hHash, nullptr, 0, (PUCHAR)_szKey, _szKey ? strlen(_szKey) : 0, 0); + Assert::IsTrue(_Status >= 0); + Assert::IsNotNull(_hHash); + + _Status = ::BCryptHashData(_hHash, reinterpret_cast("123"), 3, 0); + Assert::IsTrue(_Status >= 0); + + byte _ShaCurrent[kTargetShaLength] = {}; + _Status = ::BCryptFinishHash(_hHash, _ShaCurrent, sizeof(_ShaCurrent), 0); + Assert::IsTrue(_Status >= 0); + + Assert::IsTrue(memcmp(_ShaCurrent, _pTargetSha, sizeof(kTargetShaLength)) == 0); + + _Status = ::BCryptDestroyHash(_hHash); + Assert::IsTrue(_Status >= 0); + _Status = ::BCryptCloseAlgorithmProvider(_hAlg, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(MD5) + { + static const byte kTargetSha[16] = { 0x20, 0x2c, 0xb9, 0x62, 0xac, 0x59, 0x07, 0x5b, 0x96, 0x4b, 0x07, 0x15, 0x2d, 0x23, 0x4b, 0x70 }; + + TestHash(BCRYPT_MD5_ALGORITHM, 0, kTargetSha); + } + + TEST_METHOD(Sha1) + { + static const byte kTargetSha[20] = { 0x40, 0xbd, 0x00, 0x15, 0x63, 0x08, 0x5f, 0xc3, 0x51, 0x65, 0x32, 0x9e, 0xa1, 0xff, 0x5c, 0x5e, 0xcb, 0xdb, 0xbe, 0xef }; + + TestHash(BCRYPT_SHA1_ALGORITHM, 0, kTargetSha); + } + + TEST_METHOD(Sha256) + { + static const byte kTargetSha[32] = { 0xa6, 0x65, 0xa4, 0x59, 0x20, 0x42, 0x2f, 0x9d, 0x41, 0x7e, 0x48, 0x67, 0xef, 0xdc, 0x4f, 0xb8, 0xa0, 0x4a, 0x1f, 0x3f, 0xff, 0x1f, 0xa0, 0x7e, 0x99, 0x8e, 0x86, 0xf7, 0xf7, 0xa2, 0x7a, 0xe3 }; + + TestHash(BCRYPT_SHA256_ALGORITHM, 0, kTargetSha); + } + + TEST_METHOD(HMAC_Sha1) + { + struct TestInfo + { + const char* pKey; + byte TargetSha1[20]; + }; + + static const TestInfo s_Info[] = + { + {"", { 0x65, 0x8a, 0x09, 0x01, 0x62, 0x35, 0x68, 0xea, 0x5c, 0x36, 0x31, 0xcf, 0x61, 0x93, 0xa0, 0x23, 0xd6, 0x57, 0xae, 0x4f }}, + {"1", { 0x9e, 0x72, 0xd6, 0x6a, 0x7e, 0xe6, 0xf0, 0x1a, 0xbd, 0x7e, 0xd7, 0x6c, 0xcf, 0x94, 0xfb, 0x3e, 0x70, 0xf4, 0x0e, 0x45 }}, + {"456", { 0xc9, 0x4a, 0x24, 0x9b, 0x57, 0xc0, 0x62, 0xba, 0x17, 0x5d, 0xb6, 0x43, 0x41, 0x24, 0x22, 0xe8, 0xc3, 0x91, 0x63, 0x54 }}, + }; + + for (auto& _Item : s_Info) + { + TestHash(BCRYPT_SHA1_ALGORITHM, BCRYPT_ALG_HANDLE_HMAC_FLAG, _Item.TargetSha1, _Item.pKey); + } + } + }; + + TEST_CLASS(BCryptDeriveKey) + { + AwaysNullGuard Guard; + public: + BCryptDeriveKey() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptDeriveKeyPBKDF2; + Guard |= YY::Thunks::aways_null_try_get_BCryptDeriveKeyCapi; + } + + TEST_METHOD(PBKDF2) + { + { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + auto _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); + Assert::IsTrue(_Status >= 0); + + UCHAR _DerivedKey[20] = {}; + _Status = ::BCryptDeriveKeyPBKDF2(hAlgorithm, (PUCHAR)"123", 3, (PUCHAR)"123456789", 9, 4, _DerivedKey, sizeof(_DerivedKey), 0); + Assert::IsTrue(_Status >= 0); + + static const UCHAR kTargetDerivedKey[] = { 0x04, 0x11, 0xaf, 0x2e, 0x9e, 0x1e, 0xfd, 0x17, 0x7c, 0xc2, 0x06, 0x6a, 0xa0, 0x74, 0xf5, 0x79, 0x44, 0x32, 0x8b, 0x3f }; + static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); + Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + } + + { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + auto _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); + Assert::IsTrue(_Status >= 0); + + UCHAR _DerivedKey[30] = {}; + _Status = ::BCryptDeriveKeyPBKDF2(hAlgorithm, (PUCHAR)"123", 3, (PUCHAR)"123456789", 9, 4, _DerivedKey, sizeof(_DerivedKey), 0); + Assert::IsTrue(_Status >= 0); + + static const UCHAR kTargetDerivedKey[] = { 0x04, 0x11, 0xaf, 0x2e, 0x9e, 0x1e, 0xfd, 0x17, 0x7c, 0xc2, 0x06, 0x6a, 0xa0, 0x74, 0xf5, 0x79, 0x44, 0x32, 0x8b, 0x3f, 0x3e, 0xe7, 0x6a, 0xbd, 0x09, 0x02, 0xd0, 0xed, 0x9c, 0xa0 }; + static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); + Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + } + } + + TEST_METHOD(Capi) + { + { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + auto _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_HASH_HANDLE _hHash = nullptr; + _Status = ::BCryptCreateHash(hAlgorithm, &_hHash, nullptr, 0, nullptr, 0, 0); + Assert::IsTrue(_Status >= 0); + Assert::IsNotNull(_hHash); + + _Status = ::BCryptHashData(_hHash, (PUCHAR)"123", 3, 0); + Assert::IsTrue(_Status >= 0); + + UCHAR _DerivedKey[20] = {}; + _Status = ::BCryptDeriveKeyCapi(_hHash, nullptr, _DerivedKey, sizeof(_DerivedKey), 0); + Assert::IsTrue(_Status >= 0); + + static const UCHAR kTargetDerivedKey[] = { 0x40, 0xbd, 0x00, 0x15, 0x63, 0x08, 0x5f, 0xc3, 0x51, 0x65, 0x32, 0x9e, 0xa1, 0xff, 0x5c, 0x5e, 0xcb, 0xdb, 0xbe, 0xef }; + static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); + Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + } + + { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + auto _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_HASH_HANDLE _hHash = nullptr; + _Status = ::BCryptCreateHash(hAlgorithm, &_hHash, nullptr, 0, nullptr, 0, 0); + Assert::IsTrue(_Status >= 0); + Assert::IsNotNull(_hHash); + + _Status = ::BCryptHashData(_hHash, (PUCHAR)"123", 3, 0); + Assert::IsTrue(_Status >= 0); + + UCHAR _DerivedKey[22] = {}; + _Status = ::BCryptDeriveKeyCapi(_hHash, nullptr, _DerivedKey, sizeof(_DerivedKey), 0); + Assert::IsTrue(_Status >= 0); + + static const UCHAR kTargetDerivedKey[22] = { 0xaa, 0x9f, 0x40, 0x19, 0x05, 0xa0, 0x89, 0x0a, 0x1d, 0xdc, 0xe2, 0xcf, 0x2c, 0x7d, 0x98, 0x58, 0x95, 0x50, 0xeb, 0xbd, 0x3d, 0x0a }; + static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); + Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + } + } + }; } diff --git a/src/YY-Thunks.UnitTest/pch.h b/src/YY-Thunks.UnitTest/pch.h index 69426a0..1a56a69 100644 --- a/src/YY-Thunks.UnitTest/pch.h +++ b/src/YY-Thunks.UnitTest/pch.h @@ -21,6 +21,7 @@ #include "CppUnitTest.h" #include +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; @@ -29,4 +30,37 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework; EXTERN_C _RETURN_ _CONVENTION_ _FUNCTION(__VA_ARGS__); \ __if_not_exists(_FUNCTION) +class AwaysNullGuard +{ +private: + std::vector GuardAddress; + +public: + + ~AwaysNullGuard() + { + for (auto& _pValue : GuardAddress) + { + *_pValue = false; + } + } + + void Add(bool& _bValue) + { + if (_bValue) + { + // 已经是true + return; + } + _bValue = true; + GuardAddress.push_back(&_bValue); + } + + void operator|=(bool& _bValue) + { + Add(_bValue); + } +}; + + #endif //PCH_H diff --git a/src/YY-Thunks.UnitTest/shell32.UnitTest.cpp b/src/YY-Thunks.UnitTest/shell32.UnitTest.cpp index 1672986..9e71a0c 100644 --- a/src/YY-Thunks.UnitTest/shell32.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/shell32.UnitTest.cpp @@ -7,15 +7,12 @@ namespace shell32 { TEST_CLASS(SHGetKnownFolderPath) { + AwaysNullGuard Guard; + public: SHGetKnownFolderPath() { - YY::Thunks::aways_null_try_get_SHGetKnownFolderPath = true; - } - - ~SHGetKnownFolderPath() - { - YY::Thunks::aways_null_try_get_SHGetKnownFolderPath = false; + Guard |= YY::Thunks::aways_null_try_get_SHGetKnownFolderPath; } TEST_METHOD(基本验证) @@ -55,15 +52,12 @@ namespace shell32 { TEST_CLASS(SHGetKnownFolderIDList) { + AwaysNullGuard Guard; + public: SHGetKnownFolderIDList() { - YY::Thunks::aways_null_try_get_SHGetKnownFolderIDList = true; - } - - ~SHGetKnownFolderIDList() - { - YY::Thunks::aways_null_try_get_SHGetKnownFolderIDList = false; + Guard |= YY::Thunks::aways_null_try_get_SHGetKnownFolderIDList; } TEST_METHOD(基本验证)